mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-23 03:56:22 +00:00
feat: sincronizar en segundo plano
This commit is contained in:
parent
b972e53e48
commit
769eae6157
6 changed files with 100 additions and 104 deletions
|
@ -64,7 +64,7 @@ class ActorModerationsController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
message = actor_moderation.public_send(method) ? :success : :error
|
message = actor_moderations.public_send(method) ? :success : :error
|
||||||
|
|
||||||
flash[message] = I18n.t("actor_moderations.action_on_several.#{message}")
|
flash[message] = I18n.t("actor_moderations.action_on_several.#{message}")
|
||||||
end
|
end
|
||||||
|
|
|
@ -30,6 +30,8 @@ class ActivityPub
|
||||||
else
|
else
|
||||||
scope.block_all_without_callbacks!
|
scope.block_all_without_callbacks!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ActivityPub::SyncListsJob.perform_later(site: site)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
70
app/jobs/activity_pub/sync_lists_job.rb
Normal file
70
app/jobs/activity_pub/sync_lists_job.rb
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class ActivityPub
|
||||||
|
# Sincroniza las listas de bloqueo y permitidas con el estado actual
|
||||||
|
# de la base de datos.
|
||||||
|
class SyncListsJob < ApplicationJob
|
||||||
|
# Siempre correr al final
|
||||||
|
self.priority = 100
|
||||||
|
|
||||||
|
attr_reader :logs
|
||||||
|
|
||||||
|
# Ejecuta todas las requests y consolida los posibles errores.
|
||||||
|
#
|
||||||
|
# @param site [Site]
|
||||||
|
def run(site:)
|
||||||
|
@logs = {}
|
||||||
|
|
||||||
|
instance_scope = site.instance_moderations.joins(:instance)
|
||||||
|
actor_scope = site.actor_moderations.joins(:actor)
|
||||||
|
|
||||||
|
blocklist = wildcardize(instance_scope.blocked.pluck(:hostname)) + actor_scope.blocked.distinct.pluck(:mention).compact
|
||||||
|
allowlist = wildcardize(instance_scope.allowed.pluck(:hostname)) + actor_scope.allowed.distinct.pluck(:mention).compact
|
||||||
|
pauselist = wildcardize(instance_scope.paused.pluck(:hostname)) + actor_scope.paused.distinct.pluck(:mention).compact
|
||||||
|
|
||||||
|
if blocklist.present?
|
||||||
|
Rails.logger.info "Bloqueando: #{blocklist.join(', ')}"
|
||||||
|
process(:blocked) { site.social_inbox.allowlist.delete(list: blocklist) }
|
||||||
|
process(:blocked) { site.social_inbox.blocklist.post(list: blocklist) }
|
||||||
|
end
|
||||||
|
|
||||||
|
if allowlist.present?
|
||||||
|
Rails.logger.info "Permitiendo: #{allowlist.join(', ')}"
|
||||||
|
process(:allowed) { site.social_inbox.blocklist.delete(list: allowlist) }
|
||||||
|
process(:allowed) { site.social_inbox.allowlist.post(list: allowlist) }
|
||||||
|
end
|
||||||
|
|
||||||
|
if pauselist.present?
|
||||||
|
Rails.logger.info "Pausando: #{pauselist.join(', ')}"
|
||||||
|
process(:paused) { site.social_inbox.blocklist.delete(list: pauselist) }
|
||||||
|
process(:paused) { site.social_inbox.allowlist.delete(list: pauselist) }
|
||||||
|
end
|
||||||
|
|
||||||
|
# Si alguna falló, reintentar
|
||||||
|
raise if logs.present?
|
||||||
|
rescue Exception => e
|
||||||
|
ExceptionNotifier.notify_exception(e, data: { site: site.name, logs: logs, blocklist: blocklist, allowlist: allowlist, pauselist: pauselist })
|
||||||
|
|
||||||
|
raise
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def process(stage)
|
||||||
|
response = yield
|
||||||
|
|
||||||
|
return if response.ok?
|
||||||
|
|
||||||
|
logs[stage] ||= []
|
||||||
|
logs[stage] << { body: response.body, code: response.code }
|
||||||
|
end
|
||||||
|
|
||||||
|
# @params hostnames [Array<String>]
|
||||||
|
# @return [Array<String>]
|
||||||
|
def wildcardize(hostnames)
|
||||||
|
hostnames.map do |hostname|
|
||||||
|
"@*@#{hostname}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -14,9 +14,9 @@ class ActorModeration < ApplicationRecord
|
||||||
accepts_nested_attributes_for :remote_flag
|
accepts_nested_attributes_for :remote_flag
|
||||||
|
|
||||||
aasm do
|
aasm do
|
||||||
state :paused, initial: true, before_enter: :pause_remotely!
|
state :paused, initial: true
|
||||||
state :allowed, before_enter: :allow_remotely!
|
state :allowed
|
||||||
state :blocked, before_enter: :block_remotely!
|
state :blocked
|
||||||
state :reported
|
state :reported
|
||||||
state :removed
|
state :removed
|
||||||
|
|
||||||
|
@ -25,19 +25,19 @@ class ActorModeration < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
event :pause do
|
event :pause do
|
||||||
transitions from: %i[allowed blocked reported], to: :paused
|
transitions from: %i[allowed blocked reported], to: :paused, after: :synchronize!
|
||||||
end
|
end
|
||||||
|
|
||||||
# Al permitir una cuenta no se permiten todos los comentarios
|
# Al permitir una cuenta no se permiten todos los comentarios
|
||||||
# pendientes de moderación que ya hizo.
|
# pendientes de moderación que ya hizo.
|
||||||
event :allow do
|
event :allow do
|
||||||
transitions from: %i[paused blocked reported], to: :allowed
|
transitions from: %i[paused blocked reported], to: :allowed, after: :synchronize!
|
||||||
end
|
end
|
||||||
|
|
||||||
# Al bloquear una cuenta no se bloquean todos los comentarios
|
# Al bloquear una cuenta no se bloquean todos los comentarios
|
||||||
# pendientes de moderación que hizo.
|
# pendientes de moderación que hizo.
|
||||||
event :block do
|
event :block do
|
||||||
transitions from: %i[paused allowed], to: :blocked
|
transitions from: %i[paused allowed], to: :blocked, after: :synchronize!
|
||||||
end
|
end
|
||||||
|
|
||||||
# Al reportar, necesitamos asociar una RemoteFlag para poder
|
# Al reportar, necesitamos asociar una RemoteFlag para poder
|
||||||
|
@ -64,24 +64,7 @@ class ActorModeration < ApplicationRecord
|
||||||
# Definir eventos en masa
|
# Definir eventos en masa
|
||||||
include AasmEventsConcern
|
include AasmEventsConcern
|
||||||
|
|
||||||
def pause_remotely!
|
def synchronize!
|
||||||
raise unless
|
ActivityPub::SyncListsJob.perform_later(site: site)
|
||||||
actor.mention &&
|
|
||||||
site.social_inbox.allowlist.delete(list: [actor.mention]).ok? &&
|
|
||||||
site.social_inbox.blocklist.delete(list: [actor.mention]).ok?
|
|
||||||
end
|
|
||||||
|
|
||||||
def allow_remotely!
|
|
||||||
raise unless
|
|
||||||
actor.mention &&
|
|
||||||
site.social_inbox.allowlist.post(list: [actor.mention]).ok? &&
|
|
||||||
site.social_inbox.blocklist.delete(list: [actor.mention]).ok?
|
|
||||||
end
|
|
||||||
|
|
||||||
def block_remotely!
|
|
||||||
raise unless
|
|
||||||
actor.mention &&
|
|
||||||
site.social_inbox.allowlist.delete(list: [actor.mention]).ok? &&
|
|
||||||
site.social_inbox.blocklist.post(list: [actor.mention]).ok?
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,8 +20,8 @@ class FediblockState < ApplicationRecord
|
||||||
# Aunque queramos las listas habilitadas por defecto, tenemos que
|
# Aunque queramos las listas habilitadas por defecto, tenemos que
|
||||||
# habilitarlas luego de crearlas para poder generar la lista de
|
# habilitarlas luego de crearlas para poder generar la lista de
|
||||||
# bloqueo en la Social Inbox.
|
# bloqueo en la Social Inbox.
|
||||||
state :disabled, initial: true, before_enter: :disable_remotely_and_pause_instances!
|
state :disabled, initial: true, before_enter: :pause_unique_instances!
|
||||||
state :enabled, before_enter: :enable_remotely_and_block_instances!
|
state :enabled, before_enter: :block_instances!
|
||||||
|
|
||||||
error_on_all_events do |e|
|
error_on_all_events do |e|
|
||||||
ExceptionNotifier.notify_exception(e, data: { site: site.name, fediblock: id })
|
ExceptionNotifier.notify_exception(e, data: { site: site.name, fediblock: id })
|
||||||
|
@ -38,32 +38,27 @@ class FediblockState < ApplicationRecord
|
||||||
# pero esto implica que tenemos que encontrar las que sí y quitarlas
|
# pero esto implica que tenemos que encontrar las que sí y quitarlas
|
||||||
# de list_names
|
# de list_names
|
||||||
event :disable do
|
event :disable do
|
||||||
transitions from: :enabled, to: :disabled
|
transitions from: :enabled, to: :disabled, after: :synchronize!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def enable_remotely_and_block_instances!
|
def block_instances!
|
||||||
# Bloquear todos las instancias de este Fediblock
|
ActivityPub::InstanceModerationJob.perform_later(site: site, hostnames: fediblock.hostnames, perform_remotely: false)
|
||||||
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
|
end
|
||||||
|
|
||||||
def disable_remotely_and_pause_instances!
|
# Pausar todas las moderaciones de las instancias que no estén
|
||||||
# Deshabilitar todas las instancias que no estén habilitadas por
|
# bloqueadas por otros fediblocks.
|
||||||
# otros fediblocks
|
def pause_unique_instances!
|
||||||
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
|
instance_ids = ActivityPub::Instance.where(hostname: unique_hostnames).ids
|
||||||
site.instance_moderations.where(instance_id: instance_ids).pause_all_without_callbacks!
|
site.instance_moderations.where(instance_id: instance_ids).pause_all_without_callbacks!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def synchronize!
|
||||||
|
ActivityPub::SyncListsJob.perform_later(site: site)
|
||||||
|
end
|
||||||
|
|
||||||
# Devuelve los hostnames únicos a esta instancia.
|
# Devuelve los hostnames únicos a esta instancia.
|
||||||
#
|
#
|
||||||
# @return [Array<String>]
|
# @return [Array<String>]
|
||||||
|
@ -82,30 +77,4 @@ class FediblockState < ApplicationRecord
|
||||||
fediblock.hostnames - other_enabled_hostnames
|
fediblock.hostnames - other_enabled_hostnames
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# @param hostnames [Array<String>]
|
|
||||||
# @return [Array<String>]
|
|
||||||
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<String>]
|
|
||||||
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<String>]
|
|
||||||
def enable_remotely!(list)
|
|
||||||
raise unless
|
|
||||||
site.social_inbox.blocklist.post(list: list).ok? &&
|
|
||||||
site.social_inbox.allowlist.delete(list: list).ok?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,14 +11,18 @@ class InstanceModeration < ApplicationRecord
|
||||||
belongs_to :instance, class_name: 'ActivityPub::Instance'
|
belongs_to :instance, class_name: 'ActivityPub::Instance'
|
||||||
|
|
||||||
aasm do
|
aasm do
|
||||||
state :paused, initial: true, before_enter: :pause_remotely!
|
state :paused, initial: true
|
||||||
state :allowed, before_enter: :allow_remotely!
|
state :allowed
|
||||||
state :blocked, before_enter: :block_remotely!
|
state :blocked
|
||||||
|
|
||||||
error_on_all_events do |e|
|
error_on_all_events do |e|
|
||||||
ExceptionNotifier.notify_exception(e, data: { site: site.name, instance: instance.hostname, instance_moderation: id })
|
ExceptionNotifier.notify_exception(e, data: { site: site.name, instance: instance.hostname, instance_moderation: id })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
after_all_events do
|
||||||
|
ActivityPub::SyncListsJob.perform_later(site: site)
|
||||||
|
end
|
||||||
|
|
||||||
# Al volver la instancia a pausa no cambiamos el estado de
|
# Al volver la instancia a pausa no cambiamos el estado de
|
||||||
# moderación de actores pre-existente.
|
# moderación de actores pre-existente.
|
||||||
event :pause do
|
event :pause do
|
||||||
|
@ -40,36 +44,4 @@ class InstanceModeration < ApplicationRecord
|
||||||
|
|
||||||
# Definir eventos en masa
|
# Definir eventos en masa
|
||||||
include AasmEventsConcern
|
include AasmEventsConcern
|
||||||
|
|
||||||
# @return [Array<String>]
|
|
||||||
def actor_ids
|
|
||||||
ActivityPub::Actor.where(instance_id: instance_id).ids
|
|
||||||
end
|
|
||||||
|
|
||||||
# Elimina la instancia de todas las listas
|
|
||||||
#
|
|
||||||
# @return [Boolean]
|
|
||||||
def pause_remotely!
|
|
||||||
raise unless
|
|
||||||
site.social_inbox.blocklist.delete(list: [instance.list_name]).ok? &&
|
|
||||||
site.social_inbox.allowlist.delete(list: [instance.list_name]).ok?
|
|
||||||
end
|
|
||||||
|
|
||||||
# Deja de permitir la instancia
|
|
||||||
#
|
|
||||||
# @return [Boolean]
|
|
||||||
def block_remotely!
|
|
||||||
raise unless
|
|
||||||
site.social_inbox.allowlist.delete(list: [instance.list_name]).ok? &&
|
|
||||||
site.social_inbox.blocklist.post(list: [instance.list_name]).ok?
|
|
||||||
end
|
|
||||||
|
|
||||||
# Permite la instancia
|
|
||||||
#
|
|
||||||
# @return [Boolean]
|
|
||||||
def allow_remotely!
|
|
||||||
raise unless
|
|
||||||
site.social_inbox.blocklist.delete(list: [instance.list_name]).ok? &&
|
|
||||||
site.social_inbox.allowlist.post(list: [instance.list_name]).ok?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue