# frozen_string_literal: true # Relación entre Fediblocks y Sites. # # Cuando se habilita un Fediblock, tenemos que asociar todas sus # instancias con el sitio y bloquearlas. Cuando se deshabilita, la # relación ya está creada y se va actualizando. # # @see ActivityPub::FediblockUpdatedJob 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, before_enter: :disable_remotely_and_pause_instances! state :enabled, before_enter: :enable_remotely_and_block_instances! error_on_all_events do |e| ExceptionNotifier.notify_exception(e, data: { site: site.name, fediblock: id }) end event :enable do transitions from: :disabled, to: :enabled end # Al deshabilitar, las listas pasan a modo pausa, a menos que estén # activas en otros listados. # # @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 end end private def enable_remotely_and_block_instances! # Bloquear todos las instancias de este Fediblock enable_remotely! list_names(fediblock.hostnames) # Luego esta tarea crea las que falten e ignora las que ya se # bloquearon. ActivityPub::InstanceModerationJob.perform_now(site: site, hostnames: fediblock.hostnames, perform_remotely: false) end def disable_remotely_and_pause_instances! # Deshabilitar todas las instancias que no estén habilitadas por # otros fediblocks disable_remotely! list_names(unique_hostnames) # Pausar todas las moderaciones de las instancias que no estén # bloqueadas por otros fediblocks. instance_ids = ActivityPub::Instance.where(hostname: unique_hostnames).ids site.instance_moderations.where(instance_id: instance_ids).pause_all_without_callbacks! end # Devuelve los hostnames únicos a esta instancia. # # @return [Array] def unique_hostnames @unique_hostnames ||= begin other_enabled_fediblock_ids = site.fediblock_states.enabled.where.not(id: id).pluck(:fediblock_id) other_enabled_hostnames = ActivityPub::Fediblock .where(id: other_enabled_fediblock_ids) .pluck(:hostnames) .flatten .uniq fediblock.hostnames - other_enabled_hostnames end end # @param hostnames [Array] # @return [Array] def list_names(hostnames) hostnames.map do |hostname| "@*@#{hostname}" end end # Al deshabilitar, las instancias pasan a ser analizadas caso por caso # # @param list [Array] def disable_remotely!(list) raise unless site.social_inbox.blocklist.delete(list: list).ok? && site.social_inbox.allowlist.delete(list: list).ok? end # Al habilitar, se bloquean todas las instancias de la lista # # @param list [Array] def enable_remotely!(list) raise unless site.social_inbox.blocklist.post(list: list).ok? && site.social_inbox.allowlist.delete(list: list).ok? end end