mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-22 19:36:21 +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
|
||||
|
||||
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}")
|
||||
end
|
||||
|
|
|
@ -30,6 +30,8 @@ class ActivityPub
|
|||
else
|
||||
scope.block_all_without_callbacks!
|
||||
end
|
||||
|
||||
ActivityPub::SyncListsJob.perform_later(site: site)
|
||||
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
|
||||
|
||||
aasm do
|
||||
state :paused, initial: true, before_enter: :pause_remotely!
|
||||
state :allowed, before_enter: :allow_remotely!
|
||||
state :blocked, before_enter: :block_remotely!
|
||||
state :paused, initial: true
|
||||
state :allowed
|
||||
state :blocked
|
||||
state :reported
|
||||
state :removed
|
||||
|
||||
|
@ -25,19 +25,19 @@ class ActorModeration < ApplicationRecord
|
|||
end
|
||||
|
||||
event :pause do
|
||||
transitions from: %i[allowed blocked reported], to: :paused
|
||||
transitions from: %i[allowed blocked reported], to: :paused, after: :synchronize!
|
||||
end
|
||||
|
||||
# Al permitir una cuenta no se permiten todos los comentarios
|
||||
# pendientes de moderación que ya hizo.
|
||||
event :allow do
|
||||
transitions from: %i[paused blocked reported], to: :allowed
|
||||
transitions from: %i[paused blocked reported], to: :allowed, after: :synchronize!
|
||||
end
|
||||
|
||||
# Al bloquear una cuenta no se bloquean todos los comentarios
|
||||
# pendientes de moderación que hizo.
|
||||
event :block do
|
||||
transitions from: %i[paused allowed], to: :blocked
|
||||
transitions from: %i[paused allowed], to: :blocked, after: :synchronize!
|
||||
end
|
||||
|
||||
# Al reportar, necesitamos asociar una RemoteFlag para poder
|
||||
|
@ -64,24 +64,7 @@ class ActorModeration < ApplicationRecord
|
|||
# Definir eventos en masa
|
||||
include AasmEventsConcern
|
||||
|
||||
def pause_remotely!
|
||||
raise unless
|
||||
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?
|
||||
def synchronize!
|
||||
ActivityPub::SyncListsJob.perform_later(site: site)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,8 +20,8 @@ class FediblockState < ApplicationRecord
|
|||
# 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!
|
||||
state :disabled, initial: true, before_enter: :pause_unique_instances!
|
||||
state :enabled, before_enter: :block_instances!
|
||||
|
||||
error_on_all_events do |e|
|
||||
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
|
||||
# de list_names
|
||||
event :disable do
|
||||
transitions from: :enabled, to: :disabled
|
||||
transitions from: :enabled, to: :disabled, after: :synchronize!
|
||||
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)
|
||||
def block_instances!
|
||||
ActivityPub::InstanceModerationJob.perform_later(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.
|
||||
# Pausar todas las moderaciones de las instancias que no estén
|
||||
# bloqueadas por otros fediblocks.
|
||||
def pause_unique_instances!
|
||||
instance_ids = ActivityPub::Instance.where(hostname: unique_hostnames).ids
|
||||
site.instance_moderations.where(instance_id: instance_ids).pause_all_without_callbacks!
|
||||
end
|
||||
|
||||
def synchronize!
|
||||
ActivityPub::SyncListsJob.perform_later(site: site)
|
||||
end
|
||||
|
||||
# Devuelve los hostnames únicos a esta instancia.
|
||||
#
|
||||
# @return [Array<String>]
|
||||
|
@ -82,30 +77,4 @@ class FediblockState < ApplicationRecord
|
|||
fediblock.hostnames - other_enabled_hostnames
|
||||
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
|
||||
|
|
|
@ -11,14 +11,18 @@ class InstanceModeration < ApplicationRecord
|
|||
belongs_to :instance, class_name: 'ActivityPub::Instance'
|
||||
|
||||
aasm do
|
||||
state :paused, initial: true, before_enter: :pause_remotely!
|
||||
state :allowed, before_enter: :allow_remotely!
|
||||
state :blocked, before_enter: :block_remotely!
|
||||
state :paused, initial: true
|
||||
state :allowed
|
||||
state :blocked
|
||||
|
||||
error_on_all_events do |e|
|
||||
ExceptionNotifier.notify_exception(e, data: { site: site.name, instance: instance.hostname, instance_moderation: id })
|
||||
end
|
||||
|
||||
after_all_events do
|
||||
ActivityPub::SyncListsJob.perform_later(site: site)
|
||||
end
|
||||
|
||||
# Al volver la instancia a pausa no cambiamos el estado de
|
||||
# moderación de actores pre-existente.
|
||||
event :pause do
|
||||
|
@ -40,36 +44,4 @@ class InstanceModeration < ApplicationRecord
|
|||
|
||||
# Definir eventos en masa
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue