# 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 state :enabled event :enable do transitions from: :disabled, to: :enabled before do # Bloquear todos las instancias de este Fediblock enable_remotely! list_names(fediblock.hostnames) # Al actualizar el estado en masa garantizamos que las # instancias que ya existen queden sincronizadas con el bloqueo # en masa que acabamos de hacer. instance_ids = fediblock.instances.ids site.instance_moderations.where(instance_id: instance_ids).block_all! # Luego esta tarea crea las que falten e ignora las que ya se # bloquearon. ActivityPub::InstanceModerationJob.perform_now(site: site, hostnames: fediblock.hostnames) end 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 before do # 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! end end end private # 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