5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2024-11-21 22:56:22 +00:00

feat: cada sitio tiene un estado de moderación para la instancia

This commit is contained in:
f 2024-02-26 12:27:56 -03:00
parent 64cef8a13e
commit dc11e6efc7
No known key found for this signature in database
14 changed files with 200 additions and 11 deletions

View file

@ -142,7 +142,8 @@ module Api
end
end
# Actor, si no hay instancia, la crea en el momento
# Actor, si no hay instancia, la crea en el momento, junto con
# su estado de moderación.
#
# @return [Actor]
def actor
@ -150,6 +151,8 @@ module Api
unless a.instance
a.instance = ActivityPub::Instance.find_or_create_by(hostname: URI.parse(a.uri).hostname)
site.instance_moderations.find_or_create_by(instance: a.instance)
ActivityPub::InstanceFetchJob.perform_later(site: site, instance: a.instance)
end

View file

@ -0,0 +1,35 @@
# frozen_string_literal: true
# Actualiza la relación entre un sitio y una instancia
class InstanceModerationsController < ApplicationController
before_action :authorize_policy
def pause
instance_moderation.pause!
redirect_to site_moderation_queue_path
end
def allow
instance_moderation.allow!
redirect_to site_moderation_queue_path
end
def block
instance_moderation.block!
redirect_to site_moderation_queue_path
end
private
# @return [InstanceModeration]
def instance_moderation
@instance_moderation ||= site.instance_moderations.find(params[:instance_moderation_id])
end
def authorize_policy
authorize instance_moderation
end
end

View file

@ -8,7 +8,7 @@ class ModerationQueueController < ApplicationController
# @todo cambiar el estado por query
@activity_pubs = site.activity_pubs
@instances = ActivityPub::Instance.where(id: @activity_pubs.distinct.pluck(:instance_id))
@instance_moderations = site.instance_moderations
end
# Perfil remoto de usuarie

View file

@ -13,6 +13,7 @@ class ActivityPub
has_many :activity_pubs
has_many :actors
has_many :instance_moderations
aasm do
state :paused, initial: true

View file

@ -0,0 +1,27 @@
# frozen_string_literal: true
# Mantiene el registro de relaciones entre sitios e instancias
class InstanceModeration < ApplicationRecord
include AASM
belongs_to :site
belongs_to :instance, class_name: 'ActivityPub::Instance'
aasm do
state :paused, initial: true
state :allowed
state :blocked
event :pause do
transitions from: %i[allowed blocked], to: :paused
end
event :allow do
transitions from: %i[paused blocked], to: :allowed
end
event :block do
transitions from: %i[paused allowed], to: :blocked
end
end
end

View file

@ -11,6 +11,7 @@ class Site
has_encrypted :private_key_pem
has_many :activity_pubs
has_many :instance_moderations
before_save :generate_private_key_pem!, unless: :private_key_pem?

View file

@ -0,0 +1,16 @@
# frozen_string_literal: true
# Solo les usuaries pueden moderar instancias
InstanceModerationPolicy = Struct.new(:usuarie, :instance_moderation) do
def pause?
instance_moderation.site.usuarie? usuarie
end
def allow?
pause?
end
def block?
pause?
end
end

View file

@ -1,3 +1,7 @@
-# Componente Botón general Moderación
%button.btn{ href: href, class: local_assigns[:class] }= text
- local_assigns[:method] ||= 'patch'
- local_assigns[:class] = "btn #{local_assigns[:class]}"
-# @todo path es obligatorio
= button_to text, local_assigns[:path], **local_assigns

View file

@ -1,6 +1,6 @@
-# Componente botonera de moderación de Instancias
- btn_class = 'btn btn-secondary'
= render 'components/btn_base', text: t('.text_check'), class: btn_class, href: ''
= render 'components/btn_base', text: t('.text_allow'), class: btn_class, href: ''
= render 'components/btn_base', text: t('.text_deny'), class: btn_class, href: ''
= render 'components/btn_base', path: site_instance_moderation_pause_path(instance_moderation_id: instance_moderation), text: t('.text_check'), class: btn_class, disabled: !instance_moderation.may_pause?
= render 'components/btn_base', path: site_instance_moderation_allow_path(instance_moderation_id: instance_moderation), text: t('.text_allow'), class: btn_class, disabled: !instance_moderation.may_allow?
= render 'components/btn_base', path: site_instance_moderation_block_path(instance_moderation_id: instance_moderation), text: t('.text_deny'), class: btn_class, disabled: !instance_moderation.may_block?

View file

@ -1,13 +1,13 @@
-# Filtros
= render 'components/instances_filters'
- @instances.each do |instance|
- instance_moderations.each do |instance_moderation|
%hr
= render 'moderation_queue/instance', instance: instance
= render 'moderation_queue/instance', instance: instance_moderation.instance
-# Botones moderación
.d-flex.pb-4
= render 'components/instances_btn_box', instance: instance
= render 'components/instances_btn_box', site: site, instance_moderation: instance_moderation
%hr
%h3.mt-5= t('moderation_queue.instances.title')

View file

@ -5,7 +5,7 @@
.col
- summary = t('.instances')
= render 'layouts/details', summary: summary do
= render 'moderation_queue/instances', site: @site, post: @post, moderation_queue: @moderation_queue
= render 'moderation_queue/instances', site: @site, instance_moderations: @instance_moderations
%hr
- summary = t('.accounts')
= render 'layouts/details', summary: summary do

View file

@ -62,6 +62,12 @@ Rails.application.routes.draw do
get 'remote_profile', to: 'moderation_queue#remote_profile'
get 'instances', to: 'moderation_queue#instances'
resources :instance_moderations, only: [] do
patch :pause, to: 'instance_moderations#pause'
patch :allow, to: 'instance_moderations#allow'
patch :block, to: 'instance_moderations#block'
end
# Gestionar artículos según idioma
nested do
scope '/(:locale)', constraint: /[a-z]{2}(-[A-Z]{2})?/ do

View file

@ -0,0 +1,26 @@
# frozen_string_literal: true
# Como la instancia es única para todo el panel, necesitamos llevar
# registro de su relación con cada sitio por separado.
class CreateInstanceModeration < ActiveRecord::Migration[6.1]
def up
create_table :instance_moderations do |t|
t.timestamps
t.belongs_to :site
t.uuid :instance_id, index: true
t.string :aasm_state, null: false, default: 'paused'
t.index %i[site_id instance_id], unique: true
end
ActivityPub.all.find_each do |activity_pub|
InstanceModeration.find_or_create_by(site: activity_pub.site, instance: activity_pub.instance)
end
end
def down
drop_table :instance_moderations
end
end

View file

@ -950,6 +950,39 @@ CREATE TABLE public.indexed_posts (
);
--
-- Name: instance_moderations; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.instance_moderations (
id bigint NOT NULL,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL,
site_id bigint,
instance_id uuid,
aasm_state character varying DEFAULT 'paused'::character varying NOT NULL
);
--
-- Name: instance_moderations_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.instance_moderations_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: instance_moderations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.instance_moderations_id_seq OWNED BY public.instance_moderations.id;
--
-- Name: licencias; Type: TABLE; Schema: public; Owner: -
--
@ -1514,6 +1547,13 @@ ALTER TABLE ONLY public.designs ALTER COLUMN id SET DEFAULT nextval('public.desi
ALTER TABLE ONLY public.distributed_press_publishers ALTER COLUMN id SET DEFAULT nextval('public.distributed_press_publishers_id_seq'::regclass);
--
-- Name: instance_moderations id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.instance_moderations ALTER COLUMN id SET DEFAULT nextval('public.instance_moderations_id_seq'::regclass);
--
-- Name: licencias id; Type: DEFAULT; Schema: public; Owner: -
--
@ -1774,6 +1814,14 @@ ALTER TABLE ONLY public.indexed_posts
ADD CONSTRAINT indexed_posts_pkey PRIMARY KEY (id);
--
-- Name: instance_moderations instance_moderations_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.instance_moderations
ADD CONSTRAINT instance_moderations_pkey PRIMARY KEY (id);
--
-- Name: licencias licencias_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@ -2139,6 +2187,27 @@ CREATE INDEX index_indexed_posts_on_locale ON public.indexed_posts USING btree (
CREATE INDEX index_indexed_posts_on_site_id ON public.indexed_posts USING btree (site_id);
--
-- Name: index_instance_moderations_on_instance_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_instance_moderations_on_instance_id ON public.instance_moderations USING btree (instance_id);
--
-- Name: index_instance_moderations_on_site_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_instance_moderations_on_site_id ON public.instance_moderations USING btree (site_id);
--
-- Name: index_instance_moderations_on_site_id_and_instance_id; Type: INDEX; Schema: public; Owner: -
--
CREATE UNIQUE INDEX index_instance_moderations_on_site_id_and_instance_id ON public.instance_moderations USING btree (site_id, instance_id);
--
-- Name: index_licencias_on_name; Type: INDEX; Schema: public; Owner: -
--
@ -2476,6 +2545,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20240220161414'),
('20240221184007'),
('20240223170317'),
('20240226133022');
('20240226133022'),
('20240226134335');