diff --git a/app/models/fediblock_state.rb b/app/models/fediblock_state.rb new file mode 100644 index 00000000..8045e23e --- /dev/null +++ b/app/models/fediblock_state.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +# Relación entre Fediblocks y Sites +class FediblockState < ApplicationRecord + include AASM + + belongs_to :site + belongs_to :fediblock, class_name: 'ActivityPub::Fediblock' + + # El efecto secundario de esta máquina de estados es modificar el + # estado de moderación de cada instancia en el sitio. Nos salteamos + # los hooks de los eventos individuales. + aasm do + # Aunque queramos las listas habilitadas por defecto, tenemos que + # habilitarlas luego de crearlas para poder generar la lista de + # bloqueo en la Social Inbox. + state :disabled, initial: true + state :enabled + + event :enable do + transitions from: :disabled, to: :enabled + + before do + enable_remotely! + end + end + + # Al deshabilitar, las listas pasan a modo pausa. + # + # @todo No cambiar el estado si se habían habilitado manualmente, + # pero esto implica que tenemos que encontrar las que sí y quitarlas + # de list_names + event :disable do + transitions from: :enabled, to: :disabled + + before do + disable_remotely! + end + end + end + + private + + # Obtiene todos los IDs de instancias para poder obtener el estado de + # moderación en el sitio. + # + # @return [Array] + def instance_ids + ActivityPub::Instance.where(hostname: fediblock.instances).pluck(:id) + end + + # @return [Array] + def list_names + @list_names ||= fediblock.instances.map do |instance| + "@*@#{instance}" + end + end + + # Al deshabilitar, las instancias pasan a ser analizadas caso por caso + def disable_remotely! + raise AASM::InvalidTransition unless + site.social_inbox.blocklist.delete(list: list_names).ok? && + site.social_inbox.allowlist.delete(list: list_names).ok? + end + + # Al habilitar, se bloquean todas las instancias de la lista + def enable_remotely! + raise AASM::InvalidTransition unless + site.social_inbox.blocklist.post(list: list_names).ok? && + site.social_inbox.allowlist.delete(list: list_names).ok? + end +end diff --git a/app/models/site/social_distributed_press.rb b/app/models/site/social_distributed_press.rb index 73b284bf..e0d2d4f4 100644 --- a/app/models/site/social_distributed_press.rb +++ b/app/models/site/social_distributed_press.rb @@ -12,6 +12,7 @@ class Site has_many :activity_pubs has_many :instance_moderations + has_many :fediblock_states before_save :generate_private_key_pem!, unless: :private_key_pem? diff --git a/db/migrate/20240227142019_create_fediblock_states.rb b/db/migrate/20240227142019_create_fediblock_states.rb new file mode 100644 index 00000000..c99cf63d --- /dev/null +++ b/db/migrate/20240227142019_create_fediblock_states.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +# La relación entre sitios y fediblocks +class CreateFediblockStates < ActiveRecord::Migration[6.1] + def up + create_table :fediblock_states, id: :uuid do |t| + t.timestamps + + t.belongs_to :site + t.uuid :fediblock_id, index: true + t.string :aasm_state + + t.index %i[site_id fediblock_id], unique: true + end + + # Todas las listas están activas por defecto + DeploySocialDistributedPress.find_each do |deploy| + ActivityPub::Fediblock.find_each do |fediblock| + FediblockState.create(site: deploy.site, fediblock: fediblock, aasm_state: 'disabled').tap do |f| + f.enable! + end + end + end + end + + def down + drop_table :fediblock_states + end +end diff --git a/db/structure.sql b/db/structure.sql index 241039d1..ac897695 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -944,6 +944,20 @@ CREATE SEQUENCE public.distributed_press_publishers_id_seq ALTER SEQUENCE public.distributed_press_publishers_id_seq OWNED BY public.distributed_press_publishers.id; +-- +-- Name: fediblock_states; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.fediblock_states ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, + site_id bigint, + fediblock_id uuid, + aasm_state character varying +); + + -- -- Name: indexed_posts; Type: TABLE; Schema: public; Owner: - -- @@ -1830,6 +1844,14 @@ ALTER TABLE ONLY public.distributed_press_publishers ADD CONSTRAINT distributed_press_publishers_pkey PRIMARY KEY (id); +-- +-- Name: fediblock_states fediblock_states_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.fediblock_states + ADD CONSTRAINT fediblock_states_pkey PRIMARY KEY (id); + + -- -- Name: indexed_posts indexed_posts_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -2176,6 +2198,27 @@ CREATE UNIQUE INDEX index_designs_on_gem ON public.designs USING btree (gem); CREATE UNIQUE INDEX index_designs_on_name ON public.designs USING btree (name); +-- +-- Name: index_fediblock_states_on_fediblock_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_fediblock_states_on_fediblock_id ON public.fediblock_states USING btree (fediblock_id); + + +-- +-- Name: index_fediblock_states_on_site_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_fediblock_states_on_site_id ON public.fediblock_states USING btree (site_id); + + +-- +-- Name: index_fediblock_states_on_site_id_and_fediblock_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_fediblock_states_on_site_id_and_fediblock_id ON public.fediblock_states USING btree (site_id, fediblock_id); + + -- -- Name: index_indexed_posts_on_front_matter; Type: INDEX; Schema: public; Owner: - -- @@ -2571,6 +2614,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20240223170317'), ('20240226133022'), ('20240226134335'), -('20240227134845'); +('20240227134845'), +('20240227142019');