5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2024-10-09 20:16:56 +00:00

Merge branch 'issue-15109-1' of https://0xacab.org/sutty/sutty into production.panel.sutty.nl

This commit is contained in:
Sutty 2024-03-16 22:21:45 +00:00
commit 489d1d5c5a
9 changed files with 127 additions and 118 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

@ -0,0 +1,16 @@
# frozen_string_literal: true
class ActivityPub
class InboxJob < ApplicationJob
self.priority = 10
# @param :site [Site]
# @param :activity [String]
# @param :action [Symbol]
def perform(site:, activity:, action:)
response = site.social_inbox.inbox.public_send(action, id: activity)
raise response.body unless response.ok?
end
end
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

@ -47,9 +47,9 @@ class ActivityPub < ApplicationRecord
# Todavía no hay una decisión sobre el objeto
state :paused, initial: true
# Le usuarie aprobó el objeto
state :approved, before_enter: :allow_remotely!
state :approved
# Le usuarie rechazó el objeto
state :rejected, before_enter: :reject_remotely!
state :rejected
# Le usuarie reportó el objeto
state :reported
# Le actore eliminó el objeto
@ -84,11 +84,19 @@ class ActivityPub < ApplicationRecord
# webhook a modo de confirmación.
event :approve do
transitions from: %i[paused], to: :approved
after do
ActivityPub::InboxJob.perform_later(site: site, activity: activities.first.uri, action: :accept)
end
end
# La actividad fue rechazada
event :reject do
transitions from: %i[paused], to: :rejected
after do
ActivityPub::InboxJob.perform_later(site: site, activity: activities.first.uri, action: :reject)
end
end
# Solo podemos reportarla luego de rechazarla
@ -103,15 +111,4 @@ class ActivityPub < ApplicationRecord
# Definir eventos en masa
include AasmEventsConcern
# Lo que tenemos que aprobar o rechazar es la última actividad
# disponible, que según el scope por defecto, va a ser la primera de
# la lista.
def reject_remotely!
raise unless site.social_inbox.inbox.reject(id: activities.first.uri).ok?
end
def allow_remotely!
raise unless site.social_inbox.inbox.accept(id: activities.first.uri).ok?
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

View file

@ -109,7 +109,7 @@ es:
instances_btn_box:
text_pause: Moderar caso por caso
text_allow: Permitir todo
text_deny: Bloquear instancia
text_block: Bloquear instancia
profiles_btn_box:
text_pause: Revisar siempre
text_allow: Aprobar siempre