5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2025-03-15 03:48:16 +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-12 18:57:36 +00:00
commit 67a096b015
12 changed files with 146 additions and 113 deletions

View file

@ -167,7 +167,7 @@ GEM
devise_invitable (2.0.9)
actionmailer (>= 5.0)
devise (>= 4.6)
distributed-press-api-client (0.4.0rc3)
distributed-press-api-client (0.4.0)
addressable (~> 2.3, >= 2.3.0)
climate_control
dry-schema
@ -627,7 +627,7 @@ DEPENDENCIES
devise
devise-i18n
devise_invitable
distributed-press-api-client (~> 0.4.0rc3)
distributed-press-api-client (~> 0.4.0)
dotenv-rails
down
ed25519

View file

@ -27,7 +27,7 @@ class ActivityPubsController < ApplicationController
authorize activity_pubs
action = params[:activity_pub_action].to_sym
method = :"#{action}!"
method = :"#{action}_all!"
may = :"may_#{action}?"
redirect_to_moderation_queue!
@ -35,6 +35,7 @@ class ActivityPubsController < ApplicationController
return unless ActivityPub.events.include? action
# Crear una sola remote flag por autore
ActivityPub.transaction do
if action == :report
message = remote_flag_params(activity_pubs.first).dig(:remote_flag_attributes, :message)
@ -50,21 +51,9 @@ class ActivityPubsController < ApplicationController
end
end
ActivityPub.transaction do
activity_pubs.find_each do |activity_pub|
next unless activity_pub.public_send(may)
message = activity_pubs.public_send(method) ? :success : :error
activity_pub.public_send(method)
flash[:success] = I18n.t('activity_pubs.action_on_several.success')
rescue Exception => e
ExceptionNotifier.notify_exception(e,
data: { site: site.name, params: params.permit!.to_h,
activity_pub: activity_pub.id })
flash.delete(:success)
flash[:error] = I18n.t('activity_pubs.action_on_several.error')
end
flash[message] = I18n.t("activity_pubs.action_on_several.#{message}")
end
end

View file

@ -37,7 +37,7 @@ class ActorModerationsController < ApplicationController
authorize actor_moderations
action = params[:actor_moderation_action].to_sym
method = :"#{action}!"
method = :"#{action}_all!"
may = :"may_#{action}?"
redirect_to_moderation_queue!
@ -45,21 +45,18 @@ class ActorModerationsController < ApplicationController
return unless ActorModeration.events.include? action
ActorModeration.transaction do
if action == :report
actor_moderations.find_each do |actor_moderation|
next unless actor_moderation.public_send(may)
actor_moderation.update(actor_moderation_params(actor_moderation)) if action == :report
actor_moderation.public_send(method)
flash[:success] = I18n.t('actor_moderations.action_on_several.success')
rescue Exception => e
ExceptionNotifier.notify_exception(e, data: { site: site.name, params: params.permit!.to_h })
flash.delete(:success)
flash[:error] = I18n.t('actor_moderations.action_on_several.error')
actor_moderation.update(actor_moderation_params(actor_moderation))
end
end
message = actor_moderation.public_send(method) ? :success : :error
flash[message] = I18n.t("actor_moderations.action_on_several.#{message}")
end
end
private

View file

@ -10,6 +10,12 @@ class InstanceModerationsController < ApplicationController
instance_moderation.public_send(:"#{event}!") if instance_moderation.public_send(:"may_#{event}?")
flash[:success] = I18n.t("instance_moderations.#{event}.success")
rescue Exception => e
ExceptionNotifier.notify_exception(e, data: { site: site.name, params: params.permit!.to_h })
flash[:error] = I18n.t("instance_moderations.#{event}.error")
ensure
redirect_to_moderation_queue!
end
end
@ -20,17 +26,16 @@ class InstanceModerationsController < ApplicationController
authorize instance_moderations
action = params[:instance_moderation_action].to_sym
method = :"#{action}!"
may = :"may_#{action}?"
method = :"#{action}_all!"
redirect_to_moderation_queue!
return unless InstanceModeration.events.include? action
InstanceModeration.transaction do
instance_moderations.find_each do |instance_moderation|
instance_moderation.public_send(method) if instance_moderation.public_send(may)
end
message = instance_moderations.public_send(method) ? :success : :error
flash[:message] = I18n.t("instance_moderations.action_on_several.#{message}")
end
end

View file

@ -14,7 +14,6 @@ class ActivityPub
end
instances = ActivityPub::Instance.where(hostname: hostnames)
success = true
Site.transaction do
# Crea todas las moderaciones de instancia con un estado por
@ -22,17 +21,11 @@ class ActivityPub
instances.find_each do |instance|
# Esto bloquea cada una individualmente en la Social Inbox,
# idealmente son pocas instancias las que aparecen.
site.instance_moderations.find_or_create_by(instance: instance).tap do |instance_moderation|
instance_moderation.block! if instance_moderation.may_block?
# Notificar todos los errores sin detener la ejecución
rescue Exception => e
ExceptionNotifier.notify_exception(e, data: { site: site.name, instance_moderation: instance_moderation.id })
success = false
end
end
site.instance_moderations.find_or_create_by(instance: instance)
end
success
site.instance_moderations.where(instance_id: instances.ids).block_all!
end
end
end
end

View file

@ -8,12 +8,12 @@
#
# @see {https://www.w3.org/TR/activitypub/#client-to-server-interactions}
class ActivityPub < ApplicationRecord
include AASM
include AasmEventsConcern
IGNORED_EVENTS = %i[remove]
IGNORED_STATES = %i[removed]
include AASM
include AasmEventsConcern
belongs_to :instance
belongs_to :site
belongs_to :object, polymorphic: true
@ -68,7 +68,7 @@ class ActivityPub < ApplicationRecord
transitions from: %i[paused], to: :approved
before do
raise unless site.social_inbox.inbox.accept(id: object.uri).ok?
allow_remotely!
end
end
@ -77,7 +77,7 @@ class ActivityPub < ApplicationRecord
transitions from: %i[paused approved], to: :rejected
before do
raise unless site.social_inbox.inbox.reject(id: object.uri).ok?
reject_remotely!
end
end
@ -90,4 +90,12 @@ class ActivityPub < ApplicationRecord
end
end
end
def reject_remotely!
raise unless site.social_inbox.inbox.reject(id: object.uri).ok?
end
def allow_remotely!
raise unless site.social_inbox.inbox.accept(id: object.uri).ok?
end
end

View file

@ -2,31 +2,18 @@
# Mantiene la relación entre Site y Actor
class ActorModeration < ApplicationRecord
include AASM
include AasmEventsConcern
IGNORED_EVENTS = %i[remove]
IGNORED_STATES = %i[removed]
include AASM
include AasmEventsConcern
belongs_to :site
belongs_to :remote_flag, optional: true, class_name: 'ActivityPub::RemoteFlag'
belongs_to :actor, class_name: 'ActivityPub::Actor'
accepts_nested_attributes_for :remote_flag
# Bloquea todes les Actores bloqueables
def self.block_all!
self.update_all(aasm_state: 'blocked', updated_at: Time.now)
end
def self.pause_all!
self.update_all(aasm_state: 'paused', updated_at: Time.now)
end
def self.remove_all!
self.update_all(aasm_state: 'removed', updated_at: Time.now)
end
aasm do
state :paused, initial: true
state :allowed
@ -42,19 +29,27 @@ class ActorModeration < ApplicationRecord
end
end
# Al permitir una cuenta se permiten todos los comentarios
# pendientes de moderación que ya hizo.
event :allow do
transitions from: %i[paused blocked reported], to: :allowed
before do
allow_remotely!
site.activity_pubs.paused.where(actor_id: self.actor_id).allow_all!
end
end
# Al bloquear una cuenta se bloquean todos los comentarios
# pendientes de moderación que hizo.
event :block do
transitions from: %i[paused allowed], to: :blocked
before do
block_remotely!
site.activity_pubs.paused.where(actor_id: self.actor_id).reject_all!
end
end
@ -72,6 +67,10 @@ class ActorModeration < ApplicationRecord
# mostrarlo y todas sus actividades.
event :remove do
transitions to: :removed
before do
site.activity_pubs.where(actor_id: self.actor_id).remove_all!
end
end
end

View file

@ -27,5 +27,33 @@ module AasmEventsConcern
def self.states
aasm.states.map(&:name) - self::IGNORED_STATES
end
# Define un método que cambia el estado para todos los objetos del
# scope actual.
#
# @return [Bool] Si hubo al menos un error, devuelve false.
self.events.each do |event|
define_singleton_method(:"#{event}_all!") do
success = true
self.find_each do |object|
object.public_send(:"#{event}!") if object.public_send(:"may_#{event}?")
rescue Exception => e
success = false
notify_exception! e, object
end
success
end
end
# Envía notificación de errores
#
# @param exception [Exception]
# @param record [ApplicationRecord]
def notify_exception!(exception, record)
ExceptionNotifier.notify_exception(exception, data: { site: site.name, record_type: record.class.name, record_id: record.id })
end
end
end

View file

@ -39,12 +39,6 @@ class FediblockState < ApplicationRecord
# Luego esta tarea crea las que falten e ignora las que ya se
# bloquearon.
ActivityPub::InstanceModerationJob.perform_now(site: site, hostnames: fediblock.hostnames)
# Bloquear a todes les Actores de las instancias bloqueadas para
# indicarle a le usuarie que les tiene que desbloquear
# manualmente.
actor_ids = ActivityPub::Actor.where(instance_id: instance_ids).ids
ActorModeration.where(actor_id: actor_ids).paused.block_all!
end
end
@ -66,12 +60,6 @@ class FediblockState < ApplicationRecord
# bloqueadas por otros fediblocks.
instance_ids = ActivityPub::Instance.where(hostname: unique_hostnames).ids
site.instance_moderations.where(instance_id: instance_ids).pause_all!
# Volver a pausar todes les actores de esta instancia que fueron
# bloqueades, a menos que hayan sido bloqueades por otro
# fediblock.
actor_ids = ActivityPub::Actor.where(instance_id: instance_ids).ids
ActorModeration.where(actor_id: actor_ids).blocked.pause_all!
end
end
end

View file

@ -2,35 +2,22 @@
# Mantiene el registro de relaciones entre sitios e instancias
class InstanceModeration < ApplicationRecord
include AASM
include AasmEventsConcern
IGNORED_EVENTS = []
IGNORED_STATES = []
include AASM
include AasmEventsConcern
belongs_to :site
belongs_to :instance, class_name: 'ActivityPub::Instance'
# Traer todas las instancias bloqueables, según la máquina de estados,
# todas las que no estén bloqueadas ya.
scope :may_block, -> { where.not(aasm_state: 'blocked') }
scope :may_pause, -> { where.not(aasm_state: 'paused') }
# Bloquear instancias en masa
def self.block_all!
self.may_block.update_all(aasm_state: 'blocked', updated_at: Time.now)
end
# Pausar instancias en masa
def self.pause_all!
self.may_pause.update_all(aasm_state: 'paused', updated_at: Time.now)
end
aasm do
state :paused, initial: true
state :allowed
state :blocked
# Al volver la instancia a pausa no cambiamos el estado de
# moderación de actores pre-existente.
event :pause do
transitions from: %i[allowed blocked], to: :paused
@ -39,23 +26,36 @@ class InstanceModeration < ApplicationRecord
end
end
# Al permitir, también permitimos todes les actores que no hayan
# tenido acciones de moderación.
event :allow do
transitions from: %i[paused blocked], to: :allowed
before do
allow_remotely!
site.actor_moderations.paused.where(actor_id: actor_ids).allow_all!
end
end
# Al bloquear, también bloqueamos a todes les actores que no hayan
# tenido acciones de moderación.
event :block do
transitions from: %i[paused allowed], to: :blocked
before do
block_remotely!
site.actor_moderations.paused.where(actor_id: actor_ids).block_all!
end
end
end
# @return [Array<String>]
def actor_ids
ActivityPub::Actor.where(instance_id: self.instance_id).ids
end
# Elimina la instancia de todas las listas
#
# @return [Boolean]

View file

@ -138,14 +138,27 @@ en:
success: "Account paused. All of their comments will need to be moderated individually on the Comments section."
error: "There was an error while pausing the account. We received a report and will be acting on it soon."
allow:
success: "Account allowed. All of their comments will be approved automatically."
success: "Account allowed. All of their comments will be approved automatically. Any pending comments have been approved."
error: "There was an error while allowing the account. We received a report and will be acting on it soon."
block:
success: "Account blocked. All of their comments will be rejected automatically. If you want to report it to their instance, please use the Report button."
success: "Account blocked. All of their comments will be rejected automatically. Any pending comments have been rejected. If you want to report it to their instance, please use the Report button."
error: "There was an error while blocking the account. We received a report and will be acting on it soon."
report:
success: "Account reported."
error: "There was an error while reporting the account. We received a report and will be acting on it soon."
instance_moderations:
action_on_several:
success: "Several instances have changed moderation state. You can find them using the filters on the Instances section."
error: "There was an error while changing moderation state. We received a report and will be acting on it soon."
pause:
success: "Instance paused. All of their comments and accounts will need to be moderated individually."
error: "There was an error while pausing the instance. We received a report and will be acting on it soon."
allow:
success: "Instance allowed. All of their comments and accounts will be approved automatically. Any pending comments and accounts have been also approved."
error: "There was an error while allowing the instance. We received a report and will be acting on it soon."
block:
success: "Instance blocked. All of their comments and accounts will be rejected automatically. Any pending comments and accounts have been also rejected."
error: "There was an error while blocking the instance. We received a report and will be acting on it soon."
fediblock_states:
action_on_several:
success: "Blocklists have been enabled, you can find their instances by filtering by Blocked. Any pending account from these instances has also been blocked. You can approve them individually on the Accounts section."

View file

@ -137,14 +137,27 @@ es:
success: "Cuenta pausada. Todos los comentarios que haga necesitan ser aprobados manualmente en la sección Comentarios."
error: "No se pudo pausar la cuenta. Hemos recibido el reporte y lo estaremos verificando."
allow:
success: "Cuenta permitida. Todos los comentarios que haga serán aprobados inmediatamente."
success: "Cuenta permitida. Todos los comentarios que haga serán aprobados inmediatamente. Todos los comentarios pendientes de moderación fueron aprobados."
error: "No se pudo permitir la cuenta. Hemos recibido el reporte y lo estaremos verificando."
block:
success: "Cuenta bloqueada. Todos los comentarios que haga serán rechazados inmediatamente. Si querés reportarla a su instancia, podés usar el botón Reportar."
success: "Cuenta bloqueada. Todos los comentarios que haga serán rechazados inmediatamente. Todos los comentarios pendientes de moderación fueron rechazados. Si querés reportarla a su instancia, podés usar el botón Reportar."
error: "No se pudo bloquear la cuenta. Hemos recibido el reporte y lo estaremos verificando."
report:
success: "Cuenta reportada a su instancia."
error: "No se pudo reportar la cuenta. Hemos recibido el reporte y lo estaremos verificando."
instance_moderations:
action_on_several:
success: "Se ha modificado el estado de moderación de varias instancias. Podés encontrarlas usando los filtros en la sección Instancias."
error: "Hubo un error al modificar el estado de moderación de varias instancias. Hemos recibido el reporte y lo estaremos verificando."
pause:
success: "Instancia pausada. Todos los comentarios y cuentas de esta instancia necesitan ser aprobados manualmente. No se ha modificado el estado de moderación de cuentas y comentarios pre-existentes."
error: "No se pudo pausar la instancia. Hemos recibido el reporte y lo estaremos verificando."
allow:
success: "Instancia permitida. Todos los comentarios y cuentas pendientes de moderación fueron aprobados y los próximos serán aprobados inmediatamente."
error: "No se pudo permitir la instancia. Hemos recibido el reporte y lo estaremos verificando."
block:
success: "Instancia bloqueada. Todos los comentarios y cuentas serán rechazados inmediatamente. Todos los comentarios y cuentas pendientes de moderación fueron rechazados."
error: "No se pudo bloquear la instancia. Hemos recibido el reporte y lo estaremos verificando."
fediblock_states:
action_on_several:
success: "Se habilitaron las listas de bloqueo, podés encontrar las instancias filtrando por Bloqueadas. Todas las cuentas de estas instancias pendientes de moderación han sido bloqueadas. Podés activarlas individualmente en la sección Cuentas."