5
0
Fork 0
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:
f 2024-03-16 19:05:12 -03:00
parent b972e53e48
commit 769eae6157
No known key found for this signature in database
6 changed files with 100 additions and 104 deletions

View file

@ -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

View file

@ -30,6 +30,8 @@ class ActivityPub
else
scope.block_all_without_callbacks!
end
ActivityPub::SyncListsJob.perform_later(site: site)
end
end
end

View 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

View file

@ -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

View file

@ -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

View file

@ -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