From b67193fbca8533ee0b798f63ac1b2721484ae790 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 1 Nov 2023 17:02:32 -0300 Subject: [PATCH 001/472] feat: soportar varias instancias de distributed press #14540 --- app/models/deploy_distributed_press.rb | 10 ++++++---- ...6_add_default_to_distributed_press_publisher.rb | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20231101200026_add_default_to_distributed_press_publisher.rb diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 2c892b55..69c162aa 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -101,12 +101,14 @@ class DeployDistributedPress < Deploy # El cliente de la API # - # TODO: cuando soportemos más, tiene que haber una relación entre - # DeployDistributedPress y DistributedPressPublisher. - # # @return [DistributedPressPublisher] def publisher - @publisher ||= DistributedPressPublisher.last + @publisher ||= + if distributed_press_publisher_id + DistributedPressPublisher.find(distributed_press_publisher_id) + else + DistributedPressPublisher.find_by_default(true) + end end # El cliente para actualizar el sitio diff --git a/db/migrate/20231101200026_add_default_to_distributed_press_publisher.rb b/db/migrate/20231101200026_add_default_to_distributed_press_publisher.rb new file mode 100644 index 00000000..ada9392f --- /dev/null +++ b/db/migrate/20231101200026_add_default_to_distributed_press_publisher.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Una instancia es la instancia por defecto +class AddDefaultToDistributedPressPublisher < ActiveRecord::Migration[6.1] + def up + add_column :distributed_press_publishers, :default, :boolean, default: false + + DistributedPressPublisher.last.update(default: true) + end + + def down + remove_column :distributed_press_publishers, :default + end +end From 5540232b7e46aa3ecaa3114d3d2d05079caf4abf Mon Sep 17 00:00:00 2001 From: f Date: Wed, 1 Nov 2023 17:09:32 -0300 Subject: [PATCH 002/472] fix: la instancia puede repetirse --- app/models/distributed_press_publisher.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/distributed_press_publisher.rb b/app/models/distributed_press_publisher.rb index 6139db93..4c3293e3 100644 --- a/app/models/distributed_press_publisher.rb +++ b/app/models/distributed_press_publisher.rb @@ -13,8 +13,8 @@ class DistributedPressPublisher < ApplicationRecord # @return [IO] attr_reader :logger_out - # La instancia es única - validates_uniqueness_of :instance + # La instancia es necesaria pero no única + validates_presence_of :instance # El token es necesario validates_presence_of :token From f5af85a66eaf822c1f6d3b4e987b9e3a909a4d60 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 1 Nov 2023 17:11:31 -0300 Subject: [PATCH 003/472] fix: guardar el id como JSON --- app/models/deploy_distributed_press.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index 69c162aa..58fea294 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -13,7 +13,7 @@ require 'njalla/v1' # Al ser publicado, envía los archivos en un tarball y actualiza la # información. class DeployDistributedPress < Deploy - store :values, accessors: %i[hostname remote_site_id remote_info], coder: JSON + store :values, accessors: %i[hostname remote_site_id remote_info distributed_press_publisher_id], coder: JSON before_create :create_remote_site!, :create_njalla_records! before_destroy :delete_remote_site!, :delete_njalla_records! From e889f29d17b616bb62e5f4ee94bcde68a6d07668 Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 7 Dec 2023 15:37:46 +0100 Subject: [PATCH 004/472] fix: modificado metodo Reload en site.rb #14700 --- app/models/site.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/site.rb b/app/models/site.rb index a8c5e376..10a5e27b 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -396,7 +396,7 @@ class Site < ApplicationRecord def reload super - reload_jekyll! + site.self end def configuration From 61e20a3a133304615b9fdeb81be68f4c2d2aaeaa Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 7 Dec 2023 16:05:20 +0100 Subject: [PATCH 005/472] fix: corregido metodo Reload en site.rb #14700 --- app/models/site.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/models/site.rb b/app/models/site.rb index 10a5e27b..507b51ec 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -395,8 +395,10 @@ class Site < ApplicationRecord end def reload - super - site.self + super.tap do |s| + reload_jekyll! + end + self end def configuration From c66a7660c10c551bba8c6981a201530feb853317 Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 7 Dec 2023 17:24:04 +0100 Subject: [PATCH 006/472] fix: modificado metodo Gateways_urls para que devuelva solamente links en deploy_distributed_press.rb #14550 --- app/models/deploy_distributed_press.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index da8fe209..bfa43441 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -87,7 +87,7 @@ class DeployDistributedPress < Deploy # @return [Array] def gateway_urls remote_info.dig(:distributed_press, :links)&.values&.map do |protocol| - [ protocol[:link], protocol[:gateway] ] + [ protocol[:link]] end&.flatten&.compact&.select do |link| link.include? '://' end || [] From 3d86ad1fbefe69fcd25aefd86b4103632d3cc709 Mon Sep 17 00:00:00 2001 From: jazzari Date: Wed, 10 Jan 2024 15:36:02 -0300 Subject: [PATCH 007/472] fix: quitado espacio sobrante en array #14550 --- app/models/deploy_distributed_press.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/deploy_distributed_press.rb b/app/models/deploy_distributed_press.rb index bfa43441..c74a342f 100644 --- a/app/models/deploy_distributed_press.rb +++ b/app/models/deploy_distributed_press.rb @@ -87,7 +87,7 @@ class DeployDistributedPress < Deploy # @return [Array] def gateway_urls remote_info.dig(:distributed_press, :links)&.values&.map do |protocol| - [ protocol[:link]] + [protocol[:link]] end&.flatten&.compact&.select do |link| link.include? '://' end || [] From 9ce510223e224017eb9337549f73f86bf1303faa Mon Sep 17 00:00:00 2001 From: f Date: Fri, 12 Jan 2024 17:37:37 -0300 Subject: [PATCH 008/472] =?UTF-8?q?feat:=20controladores=20e=20informaci?= =?UTF-8?q?=C3=B3n=20de=20prueba=20#14966?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../moderation_queue_controller.rb | 375 ++++++++++++++++++ app/controllers/posts_controller.rb | 72 ++++ config/routes.rb | 4 + 3 files changed, 451 insertions(+) create mode 100644 app/controllers/moderation_queue_controller.rb diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb new file mode 100644 index 00000000..1aef226f --- /dev/null +++ b/app/controllers/moderation_queue_controller.rb @@ -0,0 +1,375 @@ +# frozen_string_literal: true + +# Cola de moderación de ActivityPub +class ModerationQueueController < ApplicationController + # Cola de moderación viendo todo el sitio + def index + @moderation_queue = [ + +{"@context"=> + ["https://www.w3.org/ns/activitystreams", + {"ostatus"=>"http://ostatus.org#", + "atomUri"=>"ostatus:atomUri", + "inReplyToAtomUri"=>"ostatus:inReplyToAtomUri", + "conversation"=>"ostatus:conversation", + "sensitive"=>"as:sensitive", + "toot"=>"http://joinmastodon.org/ns#", + "votersCount"=>"toot:votersCount", + "Hashtag"=>"as:Hashtag"}], + "id"=>"https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041", + "type"=>"Note", + "summary"=>nil, + "inReplyTo"=>"https://mastodon.mauve.moe/users/mauve/statuses/111461923538534886", + "published"=>"2023-11-23T22:50:10Z", + "url"=>"https://mastodon.mauve.moe/@mauve/111462305634770041", + "attributedTo"=>"https://mastodon.mauve.moe/users/mauve", + "to"=>["https://www.w3.org/ns/activitystreams#Public"], + "cc"=>["https://mastodon.mauve.moe/users/mauve/followers", "https://hypha.coop/about.jsonld"], + "sensitive"=>false, + "atomUri"=>"https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041", + "inReplyToAtomUri"=>"https://mastodon.mauve.moe/users/mauve/statuses/111461923538534886", + "conversation"=>"tag:mastodon.mauve.moe,2023-11-23:objectId=551471:objectType=Conversation", + "content"=> + "

Follow @HyphaCoop@hypha.coop for our announcement post on the 5th!

#P2P #ActivityPub #Fediverse

", + "contentMap"=> + {"en"=> + "

Follow @HyphaCoop@hypha.coop for our announcement post on the 5th!

#P2P #ActivityPub #Fediverse

"}, + "attachment"=>[], + "tag"=> + [{"type"=>"Mention", "href"=>"https://hypha.coop/about.jsonld", "name"=>"@dripline@hypha.coop"}, + {"type"=>"Hashtag", "href"=>"https://mastodon.mauve.moe/tags/p2p", "name"=>"#p2p"}, + {"type"=>"Hashtag", "href"=>"https://mastodon.mauve.moe/tags/activitypub", "name"=>"#activitypub"}, + {"type"=>"Hashtag", "href"=>"https://mastodon.mauve.moe/tags/fediverse", "name"=>"#fediverse"}], + "replies"=> + {"id"=>"https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies", + "type"=>"Collection", + "first"=> + {"type"=>"CollectionPage", + "next"=>"https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies?only_other_accounts=true&page=true", + "partOf"=>"https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies", + "items"=>[]}}}, +{"@context"=>["https://www.w3.org/ns/activitystreams", {"@language"=>"es", "sensitive"=>"as:sensitive"}], + "type"=>"Note", + "id"=>"https://sutty.nl/lanzamiento-de-publicaciones-distribuidas-en-el-fediverso-a-trav%C3%A9s-de-sutty/", + "summary"=>"Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty", + "published"=>"2023-12-04T21:53:05+00:00", + "updated"=>"2023-12-05T20:41:34+00:00", + "attributedTo"=>"https://sutty.nl/about.jsonld", + "to"=>["https://www.w3.org/ns/activitystreams#Public"], + "cc"=>["https://social.distributed.press/v1/@sutty@sutty.nl/followers"], + "inReplyTo"=>"https://hypha.coop/dripline/announcing-dp-social-inbox/", + "sensitive"=>true, + "content"=> + "

Estamos felices y orgulloses de anunciar el lanzamiento de la funcionalidad que permite la publicación en el Fediverso de los artículos de todos los sitios creados a través de Sutty.

Gracias al trabajo conjunto con Distributed Press, Hypha y apoyado por la Filecoin Foundation for the Distributed Web, Sutty hace posible que la seguridad de tu sitio estático se combine con la rápida difusión de tu contenido a través de las redes sociales libres y descentralizadas que constituyen el Fediverso.

Esto se logró a través del desarollo y la integración de dos componentes, trabajados en forma conjunta y colaborativa:

    \n
  1. Social Inbox, desarrollado principalmente Distributed Press. Aporta la funcionalidad de recibir artículos, responder y mencionar otras cuentas en el Fediverso.

  2. \n
  3. Jekyll Activity Pub Plugin, desarrollado principalmente por Sutty. Permite integrar Social Inbox en todos los sitios estáticos generados en Jekyll, admitiendo así la publicación automática de contenido del sitio en el Fediverso.

  4. \n

Sutty integra la funcionalidad completa en su CMS para sitios estáticos en Jekyll, permitiendo gestionarla desde una interfaz en continua mejora de su usabilidad.

Si todavía no estás familiarizade con estos nombres y conceptos, te invitamos a conocer más a continuación, en la sección “Para tecno-curioses”.

Qué significa

    \n
  • Que si creás tu sitio web a través de Sutty, tenés nuevas posibilidades de difundir tus contenidos e interactuar en redes digitales.

  • \n
  • Que tus artículos pueden ser publicados en las redes del Fediverso.

  • \n
  • Que tu sitio tendrá un perfil o usuarie personalizable desde el panel en una instancia de Sutty propia.

  • \n
  • Que les usuaries del Fediverso pueden seguir tus publicaciones.

  • \n
  • Que les usuaries del Fediverso que te sigan podrán leer tus publicaciones, mencionarte y responderte.

  • \n
  • Que podrás interactuar con les usuaries del Fediverse con las opciones de responderles y mencionarles.

  • \n

Qué permite hacer

    \n
  • Activar la publicación en el Fediverso para todos los sitios de Sutty.

  • \n
  • Activar la publicación de los artículos que quieras en el Fediverso.

  • \n
  • Responder comentarios desde los artículos de tu sitio en Sutty.

  • \n
  • Personalizar la cuenta que Sutty crea automáticamente de tu sitio en el Fediverso.

  • \n
  • Reportar o informar de usuaries o instancias abusivos mediante nuestro formulario de contacto.

  • \n

Qué se viene

    \n
  • Mejoras en la integración de las respuestas como comentarios en el sitio.

  • \n
  • Incorporación de menciones desde el panel de Sutty.

  • \n
  • Mejoras en la interfaz general del panel.

  • \n
  • Nuevas implementaciones para una mejor moderación.

  • \n
  • Mejor compatibilidad con diversas redes en el Fediverso (Mastodon+Glitch, Pleroma, Ktistec).

  • \n
  • Mejoras que permitirán diferenciar el contenido a publicar en el Fediverso y en el sitio de Sutty.

  • \n
  • La posibilidad de exportar tu cuenta a una instancia del Fediverso desde tu panel.

  • \n
  • La posibilidad de que Sutty anuncie tu contenido y/o usuarie del Fediverse en forma automática para atraer seguidorxs. (Ahora, podés hacerlo a través de un formulario).

  • \n
  • Acceder a la lista de seguidorxs y seguides desde tu panel.

  • \n
  • Seguir, dejar de seguir, bloquear usuaries y/o instancias del Fediverso desde el panel.

  • \n

¡Quiero usarlo!

Te invitamos a dar tus primeros pasos de la mano de nuestro tutorial.

Para tecno-curioses

Cómo funciona

Los sitios web y las redes sociales parecen ser especies distintas dentro del Universo de Internet. Al mismo tiempo, las redes sociales corporativas y concentradas como Instagram, Facebook, X (ex Twitter), entre otras, demostraron ser hostiles con algunos grupos o colectivos sociales en particular (censurando contenido, persiguiendo pezones, ocultando publicaciones por color de piel y de pelo, etc.) y con todes sus usuaries en general (vendiendo data en forma masiva, violando acuerdos de privacidad, eligiendo diseños de interfaz y uso que generan ansiedad y adicción, etc.). Pese a esto, siguen funcionando como espacios obligados a la hora de publicitar un emprendimiento o difundir noticias urgentes.

El Fediverso es una red federada, descentralizada y distribuida de redes sociales libres, cada una con sus características, preferencias, grupos de usuaries. Están diseñadas para facilitar el diálogo entre todas ellas. Es decir, para que los contenidos puedan ser visibles y se puedan generar respuestas entre usuaries, fomentando una cultura de participación y pluralidad de voces, basadas en estándares de desarrollo libre y que buscan ser éticos antes que con fines de lucro sin fin.

Los sitios web siguen siendo formatos para medios de comunicación que, debido a sus características, favorecen la difusión de contenidos como artículos multimedia. Permiten adecuar un estilo a una identidad visual del medio, mantener secciones y contenido institucional variado, entre otras cosas.

Las redes sociales se destacan por sus características de inmediatez, favoreciendo un flujo dialógico en tiempo real con otros tiempos de atención y características de navegación que lo hacen más breve, rápido, a veces efímero. Los medios de comunicación (personas o emprendimientos mediáticos) suelen utilizarlos para llamar la atención sobre contenidos publicados en sus sitios, apostando a la divulgación rápida y las discusiones que puedan darse entre usuaries.

La funcionalidad que desarrollamos en Sutty contempla los casos de uso en los que un contenido quiera ser compartido a más personas, en menor tiempo, con la posibilidad de generar diálogos. Las particularidades de nuestros sitios y redes sociales libres generan condiciones favorables para la libertad de expresión, que preferimos llamar Derecho a la Comunicación, evadiendo las variadas y cada vez más sofisticadas formas de censura de las plataformas corporativas tradicionales. Un contenido reproducido en varios lugares al mismo tiempo ayuda a su divulgación y es ideal para aquellas voces y discursos contrahegemónicos en la web y su supervivencia al paso del tiempo, preservando la memoria popular.

Cómo funciona el Fediverso en la moderación

El Fediverso intenta funcionar como comunidades en línea interconectadas que se autogobiernan en las formas de cuidados colectivos. Así, cada instancia podría ser algo así como un municipio que aloja diferentes cuentas/usuaries bajo unas reglas consensuadas y que pueden ser puestas en discusión si fuera necesario. De esta forma, es posible regular la circulación de contenidos fascistas y discursos de odio que puedan dañar no solamente la participación de diverses usuaries sino también su salud.

Para ello, cada instancia elige sus formas de moderación y puede excluir otras instancias con denuncias previas de contenidos antidemocráticos, odiantes o contrarios a los valores y cuidados de sus habitantes.

En Sutty en particular, nos interesan las estrategias y los mecanismos de cuidados colectivos, por lo que seguimos diseñando modelos que permitan sostenerlos en nuestras tecnologías. Podés revisar nuestros términos y condiciones, política de privacidad y acuerdos de convivencia para más información.

¿Te interesa participar?

Si sos parte de una organización social, grupo de activismo o colectivo social que pensás que podría beneficiarse de estas características, te invitamos a contactarnos a través de nuestro formulario. Estamos busando mejorar los usos de las tecnologías para ustedes y valoramos sus experiencias.

Otras posibilidades de integración de Social Inbox en sitios estáticos

Si te interesa incorporar esta funcionalidad para otros gestores de sitios estáticos, no dudes en contactarnos. Además, mantenete al tanto de las novedades que compartimos en https://dweb.sutty.nl y en nuestro blog https://sutty.nl/blog

Recomendado para saber más

\n", + "name"=>"Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty", + "contentMap"=> + {"es"=> + "

Estamos felices y orgulloses de anunciar el lanzamiento de la funcionalidad que permite la publicación en el Fediverso de los artículos de todos los sitios creados a través de Sutty.

Gracias al trabajo conjunto con Distributed Press, Hypha y apoyado por la Filecoin Foundation for the Distributed Web, Sutty hace posible que la seguridad de tu sitio estático se combine con la rápida difusión de tu contenido a través de las redes sociales libres y descentralizadas que constituyen el Fediverso.

Esto se logró a través del desarollo y la integración de dos componentes, trabajados en forma conjunta y colaborativa:

    \n
  1. Social Inbox, desarrollado principalmente Distributed Press. Aporta la funcionalidad de recibir artículos, responder y mencionar otras cuentas en el Fediverso.

  2. \n
  3. Jekyll Activity Pub Plugin, desarrollado principalmente por Sutty. Permite integrar Social Inbox en todos los sitios estáticos generados en Jekyll, admitiendo así la publicación automática de contenido del sitio en el Fediverso.

  4. \n

Sutty integra la funcionalidad completa en su CMS para sitios estáticos en Jekyll, permitiendo gestionarla desde una interfaz en continua mejora de su usabilidad.

Si todavía no estás familiarizade con estos nombres y conceptos, te invitamos a conocer más a continuación, en la sección “Para tecno-curioses”.

Qué significa

    \n
  • Que si creás tu sitio web a través de Sutty, tenés nuevas posibilidades de difundir tus contenidos e interactuar en redes digitales.

  • \n
  • Que tus artículos pueden ser publicados en las redes del Fediverso.

  • \n
  • Que tu sitio tendrá un perfil o usuarie personalizable desde el panel en una instancia de Sutty propia.

  • \n
  • Que les usuaries del Fediverso pueden seguir tus publicaciones.

  • \n
  • Que les usuaries del Fediverso que te sigan podrán leer tus publicaciones, mencionarte y responderte.

  • \n
  • Que podrás interactuar con les usuaries del Fediverse con las opciones de responderles y mencionarles.

  • \n

Qué permite hacer

    \n
  • Activar la publicación en el Fediverso para todos los sitios de Sutty.

  • \n
  • Activar la publicación de los artículos que quieras en el Fediverso.

  • \n
  • Responder comentarios desde los artículos de tu sitio en Sutty.

  • \n
  • Personalizar la cuenta que Sutty crea automáticamente de tu sitio en el Fediverso.

  • \n
  • Reportar o informar de usuaries o instancias abusivos mediante nuestro formulario de contacto.

  • \n

Qué se viene

    \n
  • Mejoras en la integración de las respuestas como comentarios en el sitio.

  • \n
  • Incorporación de menciones desde el panel de Sutty.

  • \n
  • Mejoras en la interfaz general del panel.

  • \n
  • Nuevas implementaciones para una mejor moderación.

  • \n
  • Mejor compatibilidad con diversas redes en el Fediverso (Mastodon+Glitch, Pleroma, Ktistec).

  • \n
  • Mejoras que permitirán diferenciar el contenido a publicar en el Fediverso y en el sitio de Sutty.

  • \n
  • La posibilidad de exportar tu cuenta a una instancia del Fediverso desde tu panel.

  • \n
  • La posibilidad de que Sutty anuncie tu contenido y/o usuarie del Fediverse en forma automática para atraer seguidorxs. (Ahora, podés hacerlo a través de un formulario).

  • \n
  • Acceder a la lista de seguidorxs y seguides desde tu panel.

  • \n
  • Seguir, dejar de seguir, bloquear usuaries y/o instancias del Fediverso desde el panel.

  • \n

¡Quiero usarlo!

Te invitamos a dar tus primeros pasos de la mano de nuestro tutorial.

Para tecno-curioses

Cómo funciona

Los sitios web y las redes sociales parecen ser especies distintas dentro del Universo de Internet. Al mismo tiempo, las redes sociales corporativas y concentradas como Instagram, Facebook, X (ex Twitter), entre otras, demostraron ser hostiles con algunos grupos o colectivos sociales en particular (censurando contenido, persiguiendo pezones, ocultando publicaciones por color de piel y de pelo, etc.) y con todes sus usuaries en general (vendiendo data en forma masiva, violando acuerdos de privacidad, eligiendo diseños de interfaz y uso que generan ansiedad y adicción, etc.). Pese a esto, siguen funcionando como espacios obligados a la hora de publicitar un emprendimiento o difundir noticias urgentes.

El Fediverso es una red federada, descentralizada y distribuida de redes sociales libres, cada una con sus características, preferencias, grupos de usuaries. Están diseñadas para facilitar el diálogo entre todas ellas. Es decir, para que los contenidos puedan ser visibles y se puedan generar respuestas entre usuaries, fomentando una cultura de participación y pluralidad de voces, basadas en estándares de desarrollo libre y que buscan ser éticos antes que con fines de lucro sin fin.

Los sitios web siguen siendo formatos para medios de comunicación que, debido a sus características, favorecen la difusión de contenidos como artículos multimedia. Permiten adecuar un estilo a una identidad visual del medio, mantener secciones y contenido institucional variado, entre otras cosas.

Las redes sociales se destacan por sus características de inmediatez, favoreciendo un flujo dialógico en tiempo real con otros tiempos de atención y características de navegación que lo hacen más breve, rápido, a veces efímero. Los medios de comunicación (personas o emprendimientos mediáticos) suelen utilizarlos para llamar la atención sobre contenidos publicados en sus sitios, apostando a la divulgación rápida y las discusiones que puedan darse entre usuaries.

La funcionalidad que desarrollamos en Sutty contempla los casos de uso en los que un contenido quiera ser compartido a más personas, en menor tiempo, con la posibilidad de generar diálogos. Las particularidades de nuestros sitios y redes sociales libres generan condiciones favorables para la libertad de expresión, que preferimos llamar Derecho a la Comunicación, evadiendo las variadas y cada vez más sofisticadas formas de censura de las plataformas corporativas tradicionales. Un contenido reproducido en varios lugares al mismo tiempo ayuda a su divulgación y es ideal para aquellas voces y discursos contrahegemónicos en la web y su supervivencia al paso del tiempo, preservando la memoria popular.

Cómo funciona el Fediverso en la moderación

El Fediverso intenta funcionar como comunidades en línea interconectadas que se autogobiernan en las formas de cuidados colectivos. Así, cada instancia podría ser algo así como un municipio que aloja diferentes cuentas/usuaries bajo unas reglas consensuadas y que pueden ser puestas en discusión si fuera necesario. De esta forma, es posible regular la circulación de contenidos fascistas y discursos de odio que puedan dañar no solamente la participación de diverses usuaries sino también su salud.

Para ello, cada instancia elige sus formas de moderación y puede excluir otras instancias con denuncias previas de contenidos antidemocráticos, odiantes o contrarios a los valores y cuidados de sus habitantes.

En Sutty en particular, nos interesan las estrategias y los mecanismos de cuidados colectivos, por lo que seguimos diseñando modelos que permitan sostenerlos en nuestras tecnologías. Podés revisar nuestros términos y condiciones, política de privacidad y acuerdos de convivencia para más información.

¿Te interesa participar?

Si sos parte de una organización social, grupo de activismo o colectivo social que pensás que podría beneficiarse de estas características, te invitamos a contactarnos a través de nuestro formulario. Estamos busando mejorar los usos de las tecnologías para ustedes y valoramos sus experiencias.

Otras posibilidades de integración de Social Inbox en sitios estáticos

Si te interesa incorporar esta funcionalidad para otros gestores de sitios estáticos, no dudes en contactarnos. Además, mantenete al tanto de las novedades que compartimos en https://dweb.sutty.nl y en nuestro blog https://sutty.nl/blog

Recomendado para saber más

\n"}, + "attachment"=> + [{"type"=>"Document", + "mediaType"=>"image/png", + "url"=>"https://sutty.nl/public/8r7b6ohqy6xzgngxbol6337q8jj9/milestone_2_activity_pub_2.png", + "name"=>"Botones de colores para activar la \"Web Disribuida\" y el \"Fediverso\"."}]} + + + ] + end + + # Perfil remoto de usuarie + def remote_profile + @remote_profile = { + '@context' => + [ + 'https://www.w3.org/ns/activitystreams', + 'https://w3id.org/security/v1', + { + 'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers', + 'toot' => 'http://joinmastodon.org/ns#', + 'featured' => { '@id' => 'toot:featured', '@type' => '@id' }, + 'featuredTags' => { '@id' => 'toot:featuredTags', '@type' => '@id' }, + 'alsoKnownAs' => { '@id' => 'as:alsoKnownAs', '@type' => '@id' }, + 'movedTo' => { '@id' => 'as:movedTo', '@type' => '@id' }, + 'schema' => 'http://schema.org#', + 'PropertyValue' => 'schema:PropertyValue', + 'value' => 'schema:value', + 'discoverable' => 'toot:discoverable', + 'Device' => 'toot:Device', + 'Ed25519Signature' => 'toot:Ed25519Signature', + 'Ed25519Key' => 'toot:Ed25519Key', + 'Curve25519Key' => 'toot:Curve25519Key', + 'EncryptedMessage' => 'toot:EncryptedMessage', + 'publicKeyBase64' => 'toot:publicKeyBase64', + 'deviceId' => 'toot:deviceId', + 'claim' => { '@type' => '@id', '@id' => 'toot:claim' }, + 'fingerprintKey' => { '@type' => '@id', '@id' => 'toot:fingerprintKey' }, + 'identityKey' => { '@type' => '@id', '@id' => 'toot:identityKey' }, + 'devices' => { '@type' => '@id', '@id' => 'toot:devices' }, + 'messageFranking' => 'toot:messageFranking', + 'messageType' => 'toot:messageType', + 'cipherText' => 'toot:cipherText', + 'suspended' => 'toot:suspended', + 'focalPoint' => { '@container' => '@list', '@id' => 'toot:focalPoint' } + } + ], + 'id' => 'https://mastodon.mauve.moe/users/mauve', + 'type' => 'Person', + 'following' => 'https://mastodon.mauve.moe/users/mauve/following', + 'followers' => 'https://mastodon.mauve.moe/users/mauve/followers', + 'inbox' => 'https://mastodon.mauve.moe/users/mauve/inbox', + 'outbox' => 'https://mastodon.mauve.moe/users/mauve/outbox', + 'featured' => 'https://mastodon.mauve.moe/users/mauve/collections/featured', + 'featuredTags' => 'https://mastodon.mauve.moe/users/mauve/collections/tags', + 'preferredUsername' => 'mauve', + 'name' => 'Mauve 👁💜', + 'summary' => + '

Occult Enby that's making local-first software with peer to peer protocols, mesh networks, and the web.

Also exploring what a local-first cyberspace might look like in my spare time.

', + 'url' => 'https://mastodon.mauve.moe/@mauve', + 'manuallyApprovesFollowers' => false, + 'discoverable' => true, + 'published' => '2022-04-25T00:00:00Z', + 'devices' => 'https://mastodon.mauve.moe/users/mauve/collections/devices', + 'alsoKnownAs' => ['https://infosec.exchange/users/RangerMauve'], + 'publicKey' => + { 'id' => 'https://mastodon.mauve.moe/users/mauve#main-key', + 'owner' => 'https://mastodon.mauve.moe/users/mauve', + 'publicKeyPem' => + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxjxu6bRQOjH4caQu7JgZ\numIWFeX0ZdbVnofElev2d9JByqcDoWhmaks3RYdW71RDPNrr0JxqZvUbIw9kQBng\n7iQ9YTcXTdJ/N9CQoB22msffYkEIw4ilehCDXdchNs4aoVAUwI8IhkM0p/itz6gK\n75C3CQv74Y7rHUJC8ob2p4KUwRUyhgzyhp8QWwCAn/RZ28wP8EbjWF9IskMRo9vq\nWUX+Io6hpADRkSwZGoOSW2zxCEBVco6tRmABTte8I0WcAucLyMEyfGMlUvxRew4D\nzAWoEBS8SyqM68vUabbZYLns6kya34tvsf1NkvajDGrfgU3D0LlGX++tOa6N9Pkf\nXwIDAQAB\n-----END PUBLIC KEY-----\n" }, + 'tag' => [], + 'attachment' => + [{ 'type' => 'PropertyValue', 'name' => 'Pronouns', 'value' => 'they/them/it' }, + { 'type' => 'PropertyValue', 'name' => 'Email', 'value' => 'mauve@mauve.moe' }, + { 'type' => 'PropertyValue', + 'name' => 'Matrix', + 'value' => + '@mauve:mauve.moe' }, + { 'type' => 'PropertyValue', 'name' => 'Github/Twitter', 'value' => '@RangerMauve' }], + 'endpoints' => { 'sharedInbox' => 'https://mastodon.mauve.moe/inbox' }, + 'icon' => + { 'type' => 'Image', + 'mediaType' => 'image/png', + 'url' => 'https://mastodon.mauve.moe/system/accounts/avatars/000/000/002/original/e4b910cee121b1b8.png' }, + 'image' => + { 'type' => 'Image', + 'mediaType' => 'image/png', + 'url' => 'https://mastodon.mauve.moe/system/accounts/headers/000/000/002/original/a96f990025091662.png' } + } + end + + # todon.nl está usando /api/v2/instance + # mauve.moe usa /api/v1/instance + def instances + @instances = [ +{"domain"=>"todon.nl", + "title"=>"Todon.nl", + "version"=>"4.2.3", + "source_url"=>"https://github.com/mastodon/mastodon", + "description"=> + "Radicaal linkse anti-autoritaire server. Voor anarchisten, socialisten, (klimaat)activisten, LHBTQIA+, antiracisten, antifascisten, antikapitalisten, intersectionelen, veganisten, mensenrechten, enz.", + "usage"=>{"users"=>{"active_month"=>372}}, + "thumbnail"=> + {"url"=>"https://todon.nl/system/site_uploads/files/000/000/004/@1x/297e509bc8a81f62.png", + "blurhash"=>"UXAw3zN4M|xsoga#WBay9DxntQRmITocofWE", + "versions"=> + {"@1x"=>"https://todon.nl/system/site_uploads/files/000/000/004/@1x/297e509bc8a81f62.png", + "@2x"=>"https://todon.nl/system/site_uploads/files/000/000/004/@2x/297e509bc8a81f62.png"}}, + "languages"=>["en"], + "configuration"=> + {"urls"=>{"streaming"=>"wss://todon.nl", "status"=>"https://status.todon.eu"}, + "accounts"=>{"max_featured_tags"=>10}, + "statuses"=>{"max_characters"=>1312, "max_media_attachments"=>4, "characters_reserved_per_url"=>23}, + "media_attachments"=> + {"supported_mime_types"=> + ["image/jpeg", + "image/png", + "image/gif", + "image/heic", + "image/heif", + "image/webp", + "image/avif", + "video/webm", + "video/mp4", + "video/quicktime", + "video/ogg", + "audio/wave", + "audio/wav", + "audio/x-wav", + "audio/x-pn-wave", + "audio/vnd.wave", + "audio/ogg", + "audio/vorbis", + "audio/mpeg", + "audio/mp3", + "audio/webm", + "audio/flac", + "audio/aac", + "audio/m4a", + "audio/x-m4a", + "audio/mp4", + "audio/3gpp", + "video/x-ms-asf"], + "image_size_limit"=>16777216, + "image_matrix_limit"=>33177600, + "video_size_limit"=>103809024, + "video_frame_rate_limit"=>120, + "video_matrix_limit"=>8294400}, + "polls"=>{"max_options"=>4, "max_characters_per_option"=>50, "min_expiration"=>300, "max_expiration"=>2629746}, + "translation"=>{"enabled"=>true}}, + "registrations"=> + {"enabled"=>false, + "approval_required"=>false, + "message"=> + "

¡No pasarán!

\n\n

Je kunt tijdelijk geen nieuw account op Todon.nl aanvragen.

\n\n\n\n

Ga naar joinmastodon.org of FediDB Network om een andere server te vinden.

\n\n

It is temporary not possible to request on account on Todon.nl.

\n\n\n\n

Go to joinmastodon.org or FediDB Network to find another server.

\n", + "url"=>nil}, + "max_toot_chars"=>1312, + "contact"=> + {"email"=>"todon@posteo.eu", + "account"=> + {"id"=>"1", + "username"=>"admin", + "acct"=>"admin", + "display_name"=>"Admin 🤓 Todon.nl (mod)", + "locked"=>false, + "bot"=>false, + "discoverable"=>false, + "group"=>false, + "created_at"=>"2017-04-28T00:00:00.000Z", + "note"=> + "

This account is used for 🎙 Todon.nl announcements and ⚖️ moderation.

🚫 Don't follow this account when you are not on Todon.nl.

New? First read our 👩‍🏫 Todon 101 👩‍🎓 at https://wiki.todon.eu/todon/101

⚖️ For all our moderators go to https://wiki.todon.nl/todon/moderators

📝 Public toots from this account are in English.

🔕 Criticism is fine, but people who do false accusations are muted.

✉ todon@posteo.eu

#nobot

", + "url"=>"https://todon.nl/@admin", + "uri"=>"https://todon.nl/users/admin", + "avatar"=>"https://todon.nl/system/accounts/avatars/000/000/001/original/2db61726225ed3e6.png", + "avatar_static"=>"https://todon.nl/system/accounts/avatars/000/000/001/original/2db61726225ed3e6.png", + "header"=>"https://todon.nl/system/accounts/headers/000/000/001/original/fb3a846cbc20aa09.png", + "header_static"=>"https://todon.nl/system/accounts/headers/000/000/001/original/fb3a846cbc20aa09.png", + "followers_count"=>3164, + "following_count"=>8, + "statuses_count"=>724, + "last_status_at"=>"2024-01-12", + "noindex"=>true, + "emojis"=>[], + "roles"=>[{"id"=>"3", "name"=>"Admin", "color"=>"#595aff"}], + "fields"=> + [{"name"=>"📜 Terms of Service", + "value"=> + "https://wiki.todon.nl/todon/terms_en", + "verified_at"=>"2018-11-01T14:39:45.465+00:00"}, + {"name"=>"ℹ️ Wiki", + "value"=> + "https://wiki.todon.nl/todon/information", + "verified_at"=>"2018-11-01T14:40:54.679+00:00"}, + {"name"=>"📊 Status", + "value"=> + "https://status.todon.eu", + "verified_at"=>"2023-10-26T20:38:30.185+00:00"}, + {"name"=>"💳️ Donations", + "value"=> + "https://wiki.todon.eu/todon/donations", + "verified_at"=>"2022-11-02T00:06:31.865+00:00"}]}}, + "rules"=> + [{"id"=>"1", + "text"=> + "We do not accept racism (in all its forms, incl. hate against Muslims, antisemitism, apartheid and casteism - see our Terms of Service for our complete definition)."}, + {"id"=>"2", + "text"=> + "We do not accept hate against lesbians, gays, bisexuals, pansexuals, transgenders, non-binary people, intersexual people, queer people in general, etc."}, + {"id"=>"4", "text"=>"Sexism, misogyny and hate against black women (misogynoir)."}, + {"id"=>"6", "text"=>"We do not accept ableism (incl. COVID-19 denial/downplaying and anti-vax) and body-shaming."}, + {"id"=>"8", "text"=>"We do not accept harassment and trolling."}, + {"id"=>"10", "text"=>"We also do not accept other forms of hate speech."}, + {"id"=>"11", "text"=>"We do not accept (sexual) abuse of minors, adults and animals (also not virtual)."}, + {"id"=>"13", "text"=>"We do not accept glorification of violence, calls for murder, death threats, terrorism and militarism."}, + {"id"=>"15", + "text"=> + "We do not accept (neo)colonialism (incl. Zionism), imperialism in all forms and nationalism (above all nationalism of nation states, incl. flags/symbols of those on Todon.*, see our Terms of Service)."}, + {"id"=>"16", "text"=>"We do not accept fascism, right-wing populism, and right-wing and religious extremism."}, + {"id"=>"17", + "text"=>"We do not accept evangelisation and other forms of religious propaganda [local only], and extreme sects and cults."}, + {"id"=>"19", + "text"=> + "We do not accept Marxist-Leninists, Stalinists, Maoists or other followers of extreme authoritarian (so called) communist/socialist ideologies/regimes (aka tankies)."}, + {"id"=>"20", "text"=>"We do not accept capitalists, including so called 'anarcho-capitalists' (aka ancaps) and neoliberals."}, + {"id"=>"21", + "text"=> + "We do not accept anthropogenic climate change denial, downplaying the climate crisis, greenwashing and deceptive climate solutions (like nuclear energy)."}, + {"id"=>"27", "text"=>"We do not accept (right-wing) conspiracy 'theories', hoaxes, fake news and other forms of disinformation."}, + {"id"=>"28", "text"=>"Another rule in our terms of service at wiki.todon.eu/todon/terms_en. Explain in the final step."}]}, +{"uri"=>"mastodon.mauve.moe", + "title"=>"Mauvestodon", + "short_description"=>"Escape ship from centralized social media run by Mauve.", + "description"=>"Chat about random techie and anarchist stuff.", + "email"=>"contact@mauve.moe", + "version"=>"3.5.10", + "urls"=>{"streaming_api"=>"wss://mastodon.mauve.moe"}, + "stats"=>{"user_count"=>12, "status_count"=>3287, "domain_count"=>11625}, + "thumbnail"=>"https://mastodon.mauve.moe/system/site_uploads/files/000/000/001/original/mauvesoftwareinc.png", + "languages"=>["en"], + "registrations"=>false, + "approval_required"=>false, + "invites_enabled"=>true, + "configuration"=> + {"statuses"=>{"max_characters"=>500, "max_media_attachments"=>4, "characters_reserved_per_url"=>23}, + "media_attachments"=> + {"supported_mime_types"=> + ["image/jpeg", + "image/png", + "image/gif", + "video/webm", + "video/mp4", + "video/quicktime", + "video/ogg", + "audio/wave", + "audio/wav", + "audio/x-wav", + "audio/x-pn-wave", + "audio/ogg", + "audio/vorbis", + "audio/mpeg", + "audio/mp3", + "audio/webm", + "audio/flac", + "audio/aac", + "audio/m4a", + "audio/x-m4a", + "audio/mp4", + "audio/3gpp", + "video/x-ms-asf"], + "image_size_limit"=>10485760, + "image_matrix_limit"=>16777216, + "video_size_limit"=>41943040, + "video_frame_rate_limit"=>60, + "video_matrix_limit"=>2304000}, + "polls"=>{"max_options"=>4, "max_characters_per_option"=>50, "min_expiration"=>300, "max_expiration"=>2629746}}, + "contact_account"=> + {"id"=>"1", + "username"=>"admin", + "acct"=>"admin", + "display_name"=>"", + "locked"=>false, + "bot"=>false, + "discoverable"=>true, + "group"=>false, + "created_at"=>"2022-04-25T00:00:00.000Z", + "note"=>"", + "url"=>"https://mastodon.mauve.moe/@admin", + "avatar"=>"https://mastodon.mauve.moe/system/accounts/avatars/000/000/001/original/8c21e71667b48a95.png", + "avatar_static"=>"https://mastodon.mauve.moe/system/accounts/avatars/000/000/001/original/8c21e71667b48a95.png", + "header"=>"https://mastodon.mauve.moe/headers/original/missing.png", + "header_static"=>"https://mastodon.mauve.moe/headers/original/missing.png", + "followers_count"=>0, + "following_count"=>0, + "statuses_count"=>0, + "last_status_at"=>"2023-01-30", + "emojis"=>[], + "fields"=> + [{"name"=>"Alternatel Contact", + "value"=> + "@mauve", + "verified_at"=>nil}]}, + "rules"=>[]} + + + + ] + + end +end diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 057c3068..8b4d975f 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -81,6 +81,78 @@ class PostsController < ApplicationController authorize post breadcrumb post.title.value, site_post_path(site, post, locale: locale), match: :exact breadcrumb 'posts.edit', '' + + @moderation_queue = [ + +{"@context"=> + ["https://www.w3.org/ns/activitystreams", + {"ostatus"=>"http://ostatus.org#", + "atomUri"=>"ostatus:atomUri", + "inReplyToAtomUri"=>"ostatus:inReplyToAtomUri", + "conversation"=>"ostatus:conversation", + "sensitive"=>"as:sensitive", + "toot"=>"http://joinmastodon.org/ns#", + "votersCount"=>"toot:votersCount", + "Hashtag"=>"as:Hashtag"}], + "id"=>"https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041", + "type"=>"Note", + "summary"=>nil, + "inReplyTo"=>"https://mastodon.mauve.moe/users/mauve/statuses/111461923538534886", + "published"=>"2023-11-23T22:50:10Z", + "url"=>"https://mastodon.mauve.moe/@mauve/111462305634770041", + "attributedTo"=>"https://mastodon.mauve.moe/users/mauve", + "to"=>["https://www.w3.org/ns/activitystreams#Public"], + "cc"=>["https://mastodon.mauve.moe/users/mauve/followers", "https://hypha.coop/about.jsonld"], + "sensitive"=>false, + "atomUri"=>"https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041", + "inReplyToAtomUri"=>"https://mastodon.mauve.moe/users/mauve/statuses/111461923538534886", + "conversation"=>"tag:mastodon.mauve.moe,2023-11-23:objectId=551471:objectType=Conversation", + "content"=> + "

Follow @HyphaCoop@hypha.coop for our announcement post on the 5th!

#P2P #ActivityPub #Fediverse

", + "contentMap"=> + {"en"=> + "

Follow @HyphaCoop@hypha.coop for our announcement post on the 5th!

#P2P #ActivityPub #Fediverse

"}, + "attachment"=>[], + "tag"=> + [{"type"=>"Mention", "href"=>"https://hypha.coop/about.jsonld", "name"=>"@dripline@hypha.coop"}, + {"type"=>"Hashtag", "href"=>"https://mastodon.mauve.moe/tags/p2p", "name"=>"#p2p"}, + {"type"=>"Hashtag", "href"=>"https://mastodon.mauve.moe/tags/activitypub", "name"=>"#activitypub"}, + {"type"=>"Hashtag", "href"=>"https://mastodon.mauve.moe/tags/fediverse", "name"=>"#fediverse"}], + "replies"=> + {"id"=>"https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies", + "type"=>"Collection", + "first"=> + {"type"=>"CollectionPage", + "next"=>"https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies?only_other_accounts=true&page=true", + "partOf"=>"https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies", + "items"=>[]}}}, +{"@context"=>["https://www.w3.org/ns/activitystreams", {"@language"=>"es", "sensitive"=>"as:sensitive"}], + "type"=>"Note", + "id"=>"https://sutty.nl/lanzamiento-de-publicaciones-distribuidas-en-el-fediverso-a-trav%C3%A9s-de-sutty/", + "summary"=>"Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty", + "published"=>"2023-12-04T21:53:05+00:00", + "updated"=>"2023-12-05T20:41:34+00:00", + "attributedTo"=>"https://sutty.nl/about.jsonld", + "to"=>["https://www.w3.org/ns/activitystreams#Public"], + "cc"=>["https://social.distributed.press/v1/@sutty@sutty.nl/followers"], + "inReplyTo"=>"https://hypha.coop/dripline/announcing-dp-social-inbox/", + "sensitive"=>true, + "content"=> + "

Estamos felices y orgulloses de anunciar el lanzamiento de la funcionalidad que permite la publicación en el Fediverso de los artículos de todos los sitios creados a través de Sutty.

Gracias al trabajo conjunto con Distributed Press, Hypha y apoyado por la Filecoin Foundation for the Distributed Web, Sutty hace posible que la seguridad de tu sitio estático se combine con la rápida difusión de tu contenido a través de las redes sociales libres y descentralizadas que constituyen el Fediverso.

Esto se logró a través del desarollo y la integración de dos componentes, trabajados en forma conjunta y colaborativa:

    \n
  1. Social Inbox, desarrollado principalmente Distributed Press. Aporta la funcionalidad de recibir artículos, responder y mencionar otras cuentas en el Fediverso.

  2. \n
  3. Jekyll Activity Pub Plugin, desarrollado principalmente por Sutty. Permite integrar Social Inbox en todos los sitios estáticos generados en Jekyll, admitiendo así la publicación automática de contenido del sitio en el Fediverso.

  4. \n

Sutty integra la funcionalidad completa en su CMS para sitios estáticos en Jekyll, permitiendo gestionarla desde una interfaz en continua mejora de su usabilidad.

Si todavía no estás familiarizade con estos nombres y conceptos, te invitamos a conocer más a continuación, en la sección “Para tecno-curioses”.

Qué significa

    \n
  • Que si creás tu sitio web a través de Sutty, tenés nuevas posibilidades de difundir tus contenidos e interactuar en redes digitales.

  • \n
  • Que tus artículos pueden ser publicados en las redes del Fediverso.

  • \n
  • Que tu sitio tendrá un perfil o usuarie personalizable desde el panel en una instancia de Sutty propia.

  • \n
  • Que les usuaries del Fediverso pueden seguir tus publicaciones.

  • \n
  • Que les usuaries del Fediverso que te sigan podrán leer tus publicaciones, mencionarte y responderte.

  • \n
  • Que podrás interactuar con les usuaries del Fediverse con las opciones de responderles y mencionarles.

  • \n

Qué permite hacer

    \n
  • Activar la publicación en el Fediverso para todos los sitios de Sutty.

  • \n
  • Activar la publicación de los artículos que quieras en el Fediverso.

  • \n
  • Responder comentarios desde los artículos de tu sitio en Sutty.

  • \n
  • Personalizar la cuenta que Sutty crea automáticamente de tu sitio en el Fediverso.

  • \n
  • Reportar o informar de usuaries o instancias abusivos mediante nuestro formulario de contacto.

  • \n

Qué se viene

    \n
  • Mejoras en la integración de las respuestas como comentarios en el sitio.

  • \n
  • Incorporación de menciones desde el panel de Sutty.

  • \n
  • Mejoras en la interfaz general del panel.

  • \n
  • Nuevas implementaciones para una mejor moderación.

  • \n
  • Mejor compatibilidad con diversas redes en el Fediverso (Mastodon+Glitch, Pleroma, Ktistec).

  • \n
  • Mejoras que permitirán diferenciar el contenido a publicar en el Fediverso y en el sitio de Sutty.

  • \n
  • La posibilidad de exportar tu cuenta a una instancia del Fediverso desde tu panel.

  • \n
  • La posibilidad de que Sutty anuncie tu contenido y/o usuarie del Fediverse en forma automática para atraer seguidorxs. (Ahora, podés hacerlo a través de un formulario).

  • \n
  • Acceder a la lista de seguidorxs y seguides desde tu panel.

  • \n
  • Seguir, dejar de seguir, bloquear usuaries y/o instancias del Fediverso desde el panel.

  • \n

¡Quiero usarlo!

Te invitamos a dar tus primeros pasos de la mano de nuestro tutorial.

Para tecno-curioses

Cómo funciona

Los sitios web y las redes sociales parecen ser especies distintas dentro del Universo de Internet. Al mismo tiempo, las redes sociales corporativas y concentradas como Instagram, Facebook, X (ex Twitter), entre otras, demostraron ser hostiles con algunos grupos o colectivos sociales en particular (censurando contenido, persiguiendo pezones, ocultando publicaciones por color de piel y de pelo, etc.) y con todes sus usuaries en general (vendiendo data en forma masiva, violando acuerdos de privacidad, eligiendo diseños de interfaz y uso que generan ansiedad y adicción, etc.). Pese a esto, siguen funcionando como espacios obligados a la hora de publicitar un emprendimiento o difundir noticias urgentes.

El Fediverso es una red federada, descentralizada y distribuida de redes sociales libres, cada una con sus características, preferencias, grupos de usuaries. Están diseñadas para facilitar el diálogo entre todas ellas. Es decir, para que los contenidos puedan ser visibles y se puedan generar respuestas entre usuaries, fomentando una cultura de participación y pluralidad de voces, basadas en estándares de desarrollo libre y que buscan ser éticos antes que con fines de lucro sin fin.

Los sitios web siguen siendo formatos para medios de comunicación que, debido a sus características, favorecen la difusión de contenidos como artículos multimedia. Permiten adecuar un estilo a una identidad visual del medio, mantener secciones y contenido institucional variado, entre otras cosas.

Las redes sociales se destacan por sus características de inmediatez, favoreciendo un flujo dialógico en tiempo real con otros tiempos de atención y características de navegación que lo hacen más breve, rápido, a veces efímero. Los medios de comunicación (personas o emprendimientos mediáticos) suelen utilizarlos para llamar la atención sobre contenidos publicados en sus sitios, apostando a la divulgación rápida y las discusiones que puedan darse entre usuaries.

La funcionalidad que desarrollamos en Sutty contempla los casos de uso en los que un contenido quiera ser compartido a más personas, en menor tiempo, con la posibilidad de generar diálogos. Las particularidades de nuestros sitios y redes sociales libres generan condiciones favorables para la libertad de expresión, que preferimos llamar Derecho a la Comunicación, evadiendo las variadas y cada vez más sofisticadas formas de censura de las plataformas corporativas tradicionales. Un contenido reproducido en varios lugares al mismo tiempo ayuda a su divulgación y es ideal para aquellas voces y discursos contrahegemónicos en la web y su supervivencia al paso del tiempo, preservando la memoria popular.

Cómo funciona el Fediverso en la moderación

El Fediverso intenta funcionar como comunidades en línea interconectadas que se autogobiernan en las formas de cuidados colectivos. Así, cada instancia podría ser algo así como un municipio que aloja diferentes cuentas/usuaries bajo unas reglas consensuadas y que pueden ser puestas en discusión si fuera necesario. De esta forma, es posible regular la circulación de contenidos fascistas y discursos de odio que puedan dañar no solamente la participación de diverses usuaries sino también su salud.

Para ello, cada instancia elige sus formas de moderación y puede excluir otras instancias con denuncias previas de contenidos antidemocráticos, odiantes o contrarios a los valores y cuidados de sus habitantes.

En Sutty en particular, nos interesan las estrategias y los mecanismos de cuidados colectivos, por lo que seguimos diseñando modelos que permitan sostenerlos en nuestras tecnologías. Podés revisar nuestros términos y condiciones, política de privacidad y acuerdos de convivencia para más información.

¿Te interesa participar?

Si sos parte de una organización social, grupo de activismo o colectivo social que pensás que podría beneficiarse de estas características, te invitamos a contactarnos a través de nuestro formulario. Estamos busando mejorar los usos de las tecnologías para ustedes y valoramos sus experiencias.

Otras posibilidades de integración de Social Inbox en sitios estáticos

Si te interesa incorporar esta funcionalidad para otros gestores de sitios estáticos, no dudes en contactarnos. Además, mantenete al tanto de las novedades que compartimos en https://dweb.sutty.nl y en nuestro blog https://sutty.nl/blog

Recomendado para saber más

\n", + "name"=>"Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty", + "contentMap"=> + {"es"=> + "

Estamos felices y orgulloses de anunciar el lanzamiento de la funcionalidad que permite la publicación en el Fediverso de los artículos de todos los sitios creados a través de Sutty.

Gracias al trabajo conjunto con Distributed Press, Hypha y apoyado por la Filecoin Foundation for the Distributed Web, Sutty hace posible que la seguridad de tu sitio estático se combine con la rápida difusión de tu contenido a través de las redes sociales libres y descentralizadas que constituyen el Fediverso.

Esto se logró a través del desarollo y la integración de dos componentes, trabajados en forma conjunta y colaborativa:

    \n
  1. Social Inbox, desarrollado principalmente Distributed Press. Aporta la funcionalidad de recibir artículos, responder y mencionar otras cuentas en el Fediverso.

  2. \n
  3. Jekyll Activity Pub Plugin, desarrollado principalmente por Sutty. Permite integrar Social Inbox en todos los sitios estáticos generados en Jekyll, admitiendo así la publicación automática de contenido del sitio en el Fediverso.

  4. \n

Sutty integra la funcionalidad completa en su CMS para sitios estáticos en Jekyll, permitiendo gestionarla desde una interfaz en continua mejora de su usabilidad.

Si todavía no estás familiarizade con estos nombres y conceptos, te invitamos a conocer más a continuación, en la sección “Para tecno-curioses”.

Qué significa

    \n
  • Que si creás tu sitio web a través de Sutty, tenés nuevas posibilidades de difundir tus contenidos e interactuar en redes digitales.

  • \n
  • Que tus artículos pueden ser publicados en las redes del Fediverso.

  • \n
  • Que tu sitio tendrá un perfil o usuarie personalizable desde el panel en una instancia de Sutty propia.

  • \n
  • Que les usuaries del Fediverso pueden seguir tus publicaciones.

  • \n
  • Que les usuaries del Fediverso que te sigan podrán leer tus publicaciones, mencionarte y responderte.

  • \n
  • Que podrás interactuar con les usuaries del Fediverse con las opciones de responderles y mencionarles.

  • \n

Qué permite hacer

    \n
  • Activar la publicación en el Fediverso para todos los sitios de Sutty.

  • \n
  • Activar la publicación de los artículos que quieras en el Fediverso.

  • \n
  • Responder comentarios desde los artículos de tu sitio en Sutty.

  • \n
  • Personalizar la cuenta que Sutty crea automáticamente de tu sitio en el Fediverso.

  • \n
  • Reportar o informar de usuaries o instancias abusivos mediante nuestro formulario de contacto.

  • \n

Qué se viene

    \n
  • Mejoras en la integración de las respuestas como comentarios en el sitio.

  • \n
  • Incorporación de menciones desde el panel de Sutty.

  • \n
  • Mejoras en la interfaz general del panel.

  • \n
  • Nuevas implementaciones para una mejor moderación.

  • \n
  • Mejor compatibilidad con diversas redes en el Fediverso (Mastodon+Glitch, Pleroma, Ktistec).

  • \n
  • Mejoras que permitirán diferenciar el contenido a publicar en el Fediverso y en el sitio de Sutty.

  • \n
  • La posibilidad de exportar tu cuenta a una instancia del Fediverso desde tu panel.

  • \n
  • La posibilidad de que Sutty anuncie tu contenido y/o usuarie del Fediverse en forma automática para atraer seguidorxs. (Ahora, podés hacerlo a través de un formulario).

  • \n
  • Acceder a la lista de seguidorxs y seguides desde tu panel.

  • \n
  • Seguir, dejar de seguir, bloquear usuaries y/o instancias del Fediverso desde el panel.

  • \n

¡Quiero usarlo!

Te invitamos a dar tus primeros pasos de la mano de nuestro tutorial.

Para tecno-curioses

Cómo funciona

Los sitios web y las redes sociales parecen ser especies distintas dentro del Universo de Internet. Al mismo tiempo, las redes sociales corporativas y concentradas como Instagram, Facebook, X (ex Twitter), entre otras, demostraron ser hostiles con algunos grupos o colectivos sociales en particular (censurando contenido, persiguiendo pezones, ocultando publicaciones por color de piel y de pelo, etc.) y con todes sus usuaries en general (vendiendo data en forma masiva, violando acuerdos de privacidad, eligiendo diseños de interfaz y uso que generan ansiedad y adicción, etc.). Pese a esto, siguen funcionando como espacios obligados a la hora de publicitar un emprendimiento o difundir noticias urgentes.

El Fediverso es una red federada, descentralizada y distribuida de redes sociales libres, cada una con sus características, preferencias, grupos de usuaries. Están diseñadas para facilitar el diálogo entre todas ellas. Es decir, para que los contenidos puedan ser visibles y se puedan generar respuestas entre usuaries, fomentando una cultura de participación y pluralidad de voces, basadas en estándares de desarrollo libre y que buscan ser éticos antes que con fines de lucro sin fin.

Los sitios web siguen siendo formatos para medios de comunicación que, debido a sus características, favorecen la difusión de contenidos como artículos multimedia. Permiten adecuar un estilo a una identidad visual del medio, mantener secciones y contenido institucional variado, entre otras cosas.

Las redes sociales se destacan por sus características de inmediatez, favoreciendo un flujo dialógico en tiempo real con otros tiempos de atención y características de navegación que lo hacen más breve, rápido, a veces efímero. Los medios de comunicación (personas o emprendimientos mediáticos) suelen utilizarlos para llamar la atención sobre contenidos publicados en sus sitios, apostando a la divulgación rápida y las discusiones que puedan darse entre usuaries.

La funcionalidad que desarrollamos en Sutty contempla los casos de uso en los que un contenido quiera ser compartido a más personas, en menor tiempo, con la posibilidad de generar diálogos. Las particularidades de nuestros sitios y redes sociales libres generan condiciones favorables para la libertad de expresión, que preferimos llamar Derecho a la Comunicación, evadiendo las variadas y cada vez más sofisticadas formas de censura de las plataformas corporativas tradicionales. Un contenido reproducido en varios lugares al mismo tiempo ayuda a su divulgación y es ideal para aquellas voces y discursos contrahegemónicos en la web y su supervivencia al paso del tiempo, preservando la memoria popular.

Cómo funciona el Fediverso en la moderación

El Fediverso intenta funcionar como comunidades en línea interconectadas que se autogobiernan en las formas de cuidados colectivos. Así, cada instancia podría ser algo así como un municipio que aloja diferentes cuentas/usuaries bajo unas reglas consensuadas y que pueden ser puestas en discusión si fuera necesario. De esta forma, es posible regular la circulación de contenidos fascistas y discursos de odio que puedan dañar no solamente la participación de diverses usuaries sino también su salud.

Para ello, cada instancia elige sus formas de moderación y puede excluir otras instancias con denuncias previas de contenidos antidemocráticos, odiantes o contrarios a los valores y cuidados de sus habitantes.

En Sutty en particular, nos interesan las estrategias y los mecanismos de cuidados colectivos, por lo que seguimos diseñando modelos que permitan sostenerlos en nuestras tecnologías. Podés revisar nuestros términos y condiciones, política de privacidad y acuerdos de convivencia para más información.

¿Te interesa participar?

Si sos parte de una organización social, grupo de activismo o colectivo social que pensás que podría beneficiarse de estas características, te invitamos a contactarnos a través de nuestro formulario. Estamos busando mejorar los usos de las tecnologías para ustedes y valoramos sus experiencias.

Otras posibilidades de integración de Social Inbox en sitios estáticos

Si te interesa incorporar esta funcionalidad para otros gestores de sitios estáticos, no dudes en contactarnos. Además, mantenete al tanto de las novedades que compartimos en https://dweb.sutty.nl y en nuestro blog https://sutty.nl/blog

Recomendado para saber más

\n"}, + "attachment"=> + [{"type"=>"Document", + "mediaType"=>"image/png", + "url"=>"https://sutty.nl/public/8r7b6ohqy6xzgngxbol6337q8jj9/milestone_2_activity_pub_2.png", + "name"=>"Botones de colores para activar la \"Web Disribuida\" y el \"Fediverso\"."}]} + + + ] + + end def update diff --git a/config/routes.rb b/config/routes.rb index 635be07a..664a4ab3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -50,6 +50,10 @@ Rails.application.routes.draw do get 'collaborate', to: 'collaborations#collaborate' post 'collaborate', to: 'collaborations#accept_collaboration' + get 'moderation_queue', to: 'moderation_queue#index' + get 'remote_profile', to: 'moderation_queue#remote_profile' + get 'instances', to: 'moderation_queue#instances' + # Gestionar artículos según idioma nested do scope '/(:locale)', constraint: /[a-z]{2}(-[A-Z]{2})?/ do From 6efae5f8f0448b68107e95092a15c8933c19c5b8 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 12 Jan 2024 17:37:56 -0300 Subject: [PATCH 009/472] feat: correr rubocop y haml-lint sobre los archivos --- Taskfile.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Taskfile.yaml b/Taskfile.yaml index c2d72472..735724f5 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -183,3 +183,15 @@ tasks: - "{{.HAINISH}} gem install bundler-audit" status: - "test -f ../hain/usr/bin/bundler-audit" + rubocop: + desc: "Ruby linting. Call with: go-task rubocop -- -A file.rb" + cmds: + - task: "bundle" + vars: + CLI_ARGS: "exec rubocop {{.CLI_ARGS}}" + haml-lint: + desc: "HAML linting. Call with: go-task haml-lint -- file.haml" + cmds: + - task: "bundle" + vars: + CLI_ARGS: "exec haml-lint {{.CLI_ARGS}}" From e20ef9dd21b75896849ee2279fc2fa2fc3043a2a Mon Sep 17 00:00:00 2001 From: f Date: Fri, 12 Jan 2024 17:44:26 -0300 Subject: [PATCH 010/472] feat: no es necesario pasar los archivos como parametros --- .gitlab-ci.yml | 4 ++-- Taskfile.yaml | 12 ++++-------- bin/modified_files | 2 +- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cb2766d3..9718e770 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -85,7 +85,7 @@ rubocop: - *apk-add - *disable-hainish script: - - "./bin/modified_files | ./bin/with_extension rb | xargs -r go-task bundle -- exec rubocop" + - "go-task rubocop" haml: stage: "test" cache: @@ -96,4 +96,4 @@ haml: - *apk-add - *disable-hainish script: - - "./bin/modified_files | ./bin/with_extension haml | xargs -r go-task bundle -- exec haml-lint" + - "go-task haml-lint" diff --git a/Taskfile.yaml b/Taskfile.yaml index 735724f5..57fb0238 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -184,14 +184,10 @@ tasks: status: - "test -f ../hain/usr/bin/bundler-audit" rubocop: - desc: "Ruby linting. Call with: go-task rubocop -- -A file.rb" + desc: "Ruby linting" cmds: - - task: "bundle" - vars: - CLI_ARGS: "exec rubocop {{.CLI_ARGS}}" + - "./bin/modified_files | ./bin/with_extension rb | xargs -r {{.HAINISH}} bundle exec rubocop {{.CLI_ARGS}}" haml-lint: - desc: "HAML linting. Call with: go-task haml-lint -- file.haml" + desc: "HAML linting" cmds: - - task: "bundle" - vars: - CLI_ARGS: "exec haml-lint {{.CLI_ARGS}}" + - "./bin/modified_files | ./bin/with_extension haml | xargs -r {{.HAINISH}} bundle exec haml-lint {{.CLI_ARGS}}" diff --git a/bin/modified_files b/bin/modified_files index d26e71f3..4d06b4c5 100755 --- a/bin/modified_files +++ b/bin/modified_files @@ -1,7 +1,7 @@ #!/bin/sh set -e -test -n "${CI_MERGE_REQUEST_DIFF_BASE_SHA}" +CI_MERGE_REQUEST_DIFF_BASE_SHA="${CI_MERGE_REQUEST_DIFF_BASE_SHA:-origin/rails}" git diff --name-status ${CI_MERGE_REQUEST_DIFF_BASE_SHA} \ | grep -v "^D" \ From decbd2fb52a82f38dedf4e01f5e5d66075457115 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 12 Jan 2024 17:44:49 -0300 Subject: [PATCH 011/472] chore: rubocop --- .../moderation_queue_controller.rb | 555 +++++++++--------- app/controllers/posts_controller.rb | 131 ++--- 2 files changed, 344 insertions(+), 342 deletions(-) diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index 1aef226f..6d58baf0 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -6,71 +6,70 @@ class ModerationQueueController < ApplicationController def index @moderation_queue = [ -{"@context"=> - ["https://www.w3.org/ns/activitystreams", - {"ostatus"=>"http://ostatus.org#", - "atomUri"=>"ostatus:atomUri", - "inReplyToAtomUri"=>"ostatus:inReplyToAtomUri", - "conversation"=>"ostatus:conversation", - "sensitive"=>"as:sensitive", - "toot"=>"http://joinmastodon.org/ns#", - "votersCount"=>"toot:votersCount", - "Hashtag"=>"as:Hashtag"}], - "id"=>"https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041", - "type"=>"Note", - "summary"=>nil, - "inReplyTo"=>"https://mastodon.mauve.moe/users/mauve/statuses/111461923538534886", - "published"=>"2023-11-23T22:50:10Z", - "url"=>"https://mastodon.mauve.moe/@mauve/111462305634770041", - "attributedTo"=>"https://mastodon.mauve.moe/users/mauve", - "to"=>["https://www.w3.org/ns/activitystreams#Public"], - "cc"=>["https://mastodon.mauve.moe/users/mauve/followers", "https://hypha.coop/about.jsonld"], - "sensitive"=>false, - "atomUri"=>"https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041", - "inReplyToAtomUri"=>"https://mastodon.mauve.moe/users/mauve/statuses/111461923538534886", - "conversation"=>"tag:mastodon.mauve.moe,2023-11-23:objectId=551471:objectType=Conversation", - "content"=> - "

Follow @HyphaCoop@hypha.coop for our announcement post on the 5th!

#P2P #ActivityPub #Fediverse

", - "contentMap"=> - {"en"=> - "

Follow @HyphaCoop@hypha.coop for our announcement post on the 5th!

#P2P #ActivityPub #Fediverse

"}, - "attachment"=>[], - "tag"=> - [{"type"=>"Mention", "href"=>"https://hypha.coop/about.jsonld", "name"=>"@dripline@hypha.coop"}, - {"type"=>"Hashtag", "href"=>"https://mastodon.mauve.moe/tags/p2p", "name"=>"#p2p"}, - {"type"=>"Hashtag", "href"=>"https://mastodon.mauve.moe/tags/activitypub", "name"=>"#activitypub"}, - {"type"=>"Hashtag", "href"=>"https://mastodon.mauve.moe/tags/fediverse", "name"=>"#fediverse"}], - "replies"=> - {"id"=>"https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies", - "type"=>"Collection", - "first"=> - {"type"=>"CollectionPage", - "next"=>"https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies?only_other_accounts=true&page=true", - "partOf"=>"https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies", - "items"=>[]}}}, -{"@context"=>["https://www.w3.org/ns/activitystreams", {"@language"=>"es", "sensitive"=>"as:sensitive"}], - "type"=>"Note", - "id"=>"https://sutty.nl/lanzamiento-de-publicaciones-distribuidas-en-el-fediverso-a-trav%C3%A9s-de-sutty/", - "summary"=>"Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty", - "published"=>"2023-12-04T21:53:05+00:00", - "updated"=>"2023-12-05T20:41:34+00:00", - "attributedTo"=>"https://sutty.nl/about.jsonld", - "to"=>["https://www.w3.org/ns/activitystreams#Public"], - "cc"=>["https://social.distributed.press/v1/@sutty@sutty.nl/followers"], - "inReplyTo"=>"https://hypha.coop/dripline/announcing-dp-social-inbox/", - "sensitive"=>true, - "content"=> - "

Estamos felices y orgulloses de anunciar el lanzamiento de la funcionalidad que permite la publicación en el Fediverso de los artículos de todos los sitios creados a través de Sutty.

Gracias al trabajo conjunto con Distributed Press, Hypha y apoyado por la Filecoin Foundation for the Distributed Web, Sutty hace posible que la seguridad de tu sitio estático se combine con la rápida difusión de tu contenido a través de las redes sociales libres y descentralizadas que constituyen el Fediverso.

Esto se logró a través del desarollo y la integración de dos componentes, trabajados en forma conjunta y colaborativa:

    \n
  1. Social Inbox, desarrollado principalmente Distributed Press. Aporta la funcionalidad de recibir artículos, responder y mencionar otras cuentas en el Fediverso.

  2. \n
  3. Jekyll Activity Pub Plugin, desarrollado principalmente por Sutty. Permite integrar Social Inbox en todos los sitios estáticos generados en Jekyll, admitiendo así la publicación automática de contenido del sitio en el Fediverso.

  4. \n

Sutty integra la funcionalidad completa en su CMS para sitios estáticos en Jekyll, permitiendo gestionarla desde una interfaz en continua mejora de su usabilidad.

Si todavía no estás familiarizade con estos nombres y conceptos, te invitamos a conocer más a continuación, en la sección “Para tecno-curioses”.

Qué significa

    \n
  • Que si creás tu sitio web a través de Sutty, tenés nuevas posibilidades de difundir tus contenidos e interactuar en redes digitales.

  • \n
  • Que tus artículos pueden ser publicados en las redes del Fediverso.

  • \n
  • Que tu sitio tendrá un perfil o usuarie personalizable desde el panel en una instancia de Sutty propia.

  • \n
  • Que les usuaries del Fediverso pueden seguir tus publicaciones.

  • \n
  • Que les usuaries del Fediverso que te sigan podrán leer tus publicaciones, mencionarte y responderte.

  • \n
  • Que podrás interactuar con les usuaries del Fediverse con las opciones de responderles y mencionarles.

  • \n

Qué permite hacer

    \n
  • Activar la publicación en el Fediverso para todos los sitios de Sutty.

  • \n
  • Activar la publicación de los artículos que quieras en el Fediverso.

  • \n
  • Responder comentarios desde los artículos de tu sitio en Sutty.

  • \n
  • Personalizar la cuenta que Sutty crea automáticamente de tu sitio en el Fediverso.

  • \n
  • Reportar o informar de usuaries o instancias abusivos mediante nuestro formulario de contacto.

  • \n

Qué se viene

    \n
  • Mejoras en la integración de las respuestas como comentarios en el sitio.

  • \n
  • Incorporación de menciones desde el panel de Sutty.

  • \n
  • Mejoras en la interfaz general del panel.

  • \n
  • Nuevas implementaciones para una mejor moderación.

  • \n
  • Mejor compatibilidad con diversas redes en el Fediverso (Mastodon+Glitch, Pleroma, Ktistec).

  • \n
  • Mejoras que permitirán diferenciar el contenido a publicar en el Fediverso y en el sitio de Sutty.

  • \n
  • La posibilidad de exportar tu cuenta a una instancia del Fediverso desde tu panel.

  • \n
  • La posibilidad de que Sutty anuncie tu contenido y/o usuarie del Fediverse en forma automática para atraer seguidorxs. (Ahora, podés hacerlo a través de un formulario).

  • \n
  • Acceder a la lista de seguidorxs y seguides desde tu panel.

  • \n
  • Seguir, dejar de seguir, bloquear usuaries y/o instancias del Fediverso desde el panel.

  • \n

¡Quiero usarlo!

Te invitamos a dar tus primeros pasos de la mano de nuestro tutorial.

Para tecno-curioses

Cómo funciona

Los sitios web y las redes sociales parecen ser especies distintas dentro del Universo de Internet. Al mismo tiempo, las redes sociales corporativas y concentradas como Instagram, Facebook, X (ex Twitter), entre otras, demostraron ser hostiles con algunos grupos o colectivos sociales en particular (censurando contenido, persiguiendo pezones, ocultando publicaciones por color de piel y de pelo, etc.) y con todes sus usuaries en general (vendiendo data en forma masiva, violando acuerdos de privacidad, eligiendo diseños de interfaz y uso que generan ansiedad y adicción, etc.). Pese a esto, siguen funcionando como espacios obligados a la hora de publicitar un emprendimiento o difundir noticias urgentes.

El Fediverso es una red federada, descentralizada y distribuida de redes sociales libres, cada una con sus características, preferencias, grupos de usuaries. Están diseñadas para facilitar el diálogo entre todas ellas. Es decir, para que los contenidos puedan ser visibles y se puedan generar respuestas entre usuaries, fomentando una cultura de participación y pluralidad de voces, basadas en estándares de desarrollo libre y que buscan ser éticos antes que con fines de lucro sin fin.

Los sitios web siguen siendo formatos para medios de comunicación que, debido a sus características, favorecen la difusión de contenidos como artículos multimedia. Permiten adecuar un estilo a una identidad visual del medio, mantener secciones y contenido institucional variado, entre otras cosas.

Las redes sociales se destacan por sus características de inmediatez, favoreciendo un flujo dialógico en tiempo real con otros tiempos de atención y características de navegación que lo hacen más breve, rápido, a veces efímero. Los medios de comunicación (personas o emprendimientos mediáticos) suelen utilizarlos para llamar la atención sobre contenidos publicados en sus sitios, apostando a la divulgación rápida y las discusiones que puedan darse entre usuaries.

La funcionalidad que desarrollamos en Sutty contempla los casos de uso en los que un contenido quiera ser compartido a más personas, en menor tiempo, con la posibilidad de generar diálogos. Las particularidades de nuestros sitios y redes sociales libres generan condiciones favorables para la libertad de expresión, que preferimos llamar Derecho a la Comunicación, evadiendo las variadas y cada vez más sofisticadas formas de censura de las plataformas corporativas tradicionales. Un contenido reproducido en varios lugares al mismo tiempo ayuda a su divulgación y es ideal para aquellas voces y discursos contrahegemónicos en la web y su supervivencia al paso del tiempo, preservando la memoria popular.

Cómo funciona el Fediverso en la moderación

El Fediverso intenta funcionar como comunidades en línea interconectadas que se autogobiernan en las formas de cuidados colectivos. Así, cada instancia podría ser algo así como un municipio que aloja diferentes cuentas/usuaries bajo unas reglas consensuadas y que pueden ser puestas en discusión si fuera necesario. De esta forma, es posible regular la circulación de contenidos fascistas y discursos de odio que puedan dañar no solamente la participación de diverses usuaries sino también su salud.

Para ello, cada instancia elige sus formas de moderación y puede excluir otras instancias con denuncias previas de contenidos antidemocráticos, odiantes o contrarios a los valores y cuidados de sus habitantes.

En Sutty en particular, nos interesan las estrategias y los mecanismos de cuidados colectivos, por lo que seguimos diseñando modelos que permitan sostenerlos en nuestras tecnologías. Podés revisar nuestros términos y condiciones, política de privacidad y acuerdos de convivencia para más información.

¿Te interesa participar?

Si sos parte de una organización social, grupo de activismo o colectivo social que pensás que podría beneficiarse de estas características, te invitamos a contactarnos a través de nuestro formulario. Estamos busando mejorar los usos de las tecnologías para ustedes y valoramos sus experiencias.

Otras posibilidades de integración de Social Inbox en sitios estáticos

Si te interesa incorporar esta funcionalidad para otros gestores de sitios estáticos, no dudes en contactarnos. Además, mantenete al tanto de las novedades que compartimos en https://dweb.sutty.nl y en nuestro blog https://sutty.nl/blog

Recomendado para saber más

\n", - "name"=>"Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty", - "contentMap"=> - {"es"=> - "

Estamos felices y orgulloses de anunciar el lanzamiento de la funcionalidad que permite la publicación en el Fediverso de los artículos de todos los sitios creados a través de Sutty.

Gracias al trabajo conjunto con Distributed Press, Hypha y apoyado por la Filecoin Foundation for the Distributed Web, Sutty hace posible que la seguridad de tu sitio estático se combine con la rápida difusión de tu contenido a través de las redes sociales libres y descentralizadas que constituyen el Fediverso.

Esto se logró a través del desarollo y la integración de dos componentes, trabajados en forma conjunta y colaborativa:

    \n
  1. Social Inbox, desarrollado principalmente Distributed Press. Aporta la funcionalidad de recibir artículos, responder y mencionar otras cuentas en el Fediverso.

  2. \n
  3. Jekyll Activity Pub Plugin, desarrollado principalmente por Sutty. Permite integrar Social Inbox en todos los sitios estáticos generados en Jekyll, admitiendo así la publicación automática de contenido del sitio en el Fediverso.

  4. \n

Sutty integra la funcionalidad completa en su CMS para sitios estáticos en Jekyll, permitiendo gestionarla desde una interfaz en continua mejora de su usabilidad.

Si todavía no estás familiarizade con estos nombres y conceptos, te invitamos a conocer más a continuación, en la sección “Para tecno-curioses”.

Qué significa

    \n
  • Que si creás tu sitio web a través de Sutty, tenés nuevas posibilidades de difundir tus contenidos e interactuar en redes digitales.

  • \n
  • Que tus artículos pueden ser publicados en las redes del Fediverso.

  • \n
  • Que tu sitio tendrá un perfil o usuarie personalizable desde el panel en una instancia de Sutty propia.

  • \n
  • Que les usuaries del Fediverso pueden seguir tus publicaciones.

  • \n
  • Que les usuaries del Fediverso que te sigan podrán leer tus publicaciones, mencionarte y responderte.

  • \n
  • Que podrás interactuar con les usuaries del Fediverse con las opciones de responderles y mencionarles.

  • \n

Qué permite hacer

    \n
  • Activar la publicación en el Fediverso para todos los sitios de Sutty.

  • \n
  • Activar la publicación de los artículos que quieras en el Fediverso.

  • \n
  • Responder comentarios desde los artículos de tu sitio en Sutty.

  • \n
  • Personalizar la cuenta que Sutty crea automáticamente de tu sitio en el Fediverso.

  • \n
  • Reportar o informar de usuaries o instancias abusivos mediante nuestro formulario de contacto.

  • \n

Qué se viene

    \n
  • Mejoras en la integración de las respuestas como comentarios en el sitio.

  • \n
  • Incorporación de menciones desde el panel de Sutty.

  • \n
  • Mejoras en la interfaz general del panel.

  • \n
  • Nuevas implementaciones para una mejor moderación.

  • \n
  • Mejor compatibilidad con diversas redes en el Fediverso (Mastodon+Glitch, Pleroma, Ktistec).

  • \n
  • Mejoras que permitirán diferenciar el contenido a publicar en el Fediverso y en el sitio de Sutty.

  • \n
  • La posibilidad de exportar tu cuenta a una instancia del Fediverso desde tu panel.

  • \n
  • La posibilidad de que Sutty anuncie tu contenido y/o usuarie del Fediverse en forma automática para atraer seguidorxs. (Ahora, podés hacerlo a través de un formulario).

  • \n
  • Acceder a la lista de seguidorxs y seguides desde tu panel.

  • \n
  • Seguir, dejar de seguir, bloquear usuaries y/o instancias del Fediverso desde el panel.

  • \n

¡Quiero usarlo!

Te invitamos a dar tus primeros pasos de la mano de nuestro tutorial.

Para tecno-curioses

Cómo funciona

Los sitios web y las redes sociales parecen ser especies distintas dentro del Universo de Internet. Al mismo tiempo, las redes sociales corporativas y concentradas como Instagram, Facebook, X (ex Twitter), entre otras, demostraron ser hostiles con algunos grupos o colectivos sociales en particular (censurando contenido, persiguiendo pezones, ocultando publicaciones por color de piel y de pelo, etc.) y con todes sus usuaries en general (vendiendo data en forma masiva, violando acuerdos de privacidad, eligiendo diseños de interfaz y uso que generan ansiedad y adicción, etc.). Pese a esto, siguen funcionando como espacios obligados a la hora de publicitar un emprendimiento o difundir noticias urgentes.

El Fediverso es una red federada, descentralizada y distribuida de redes sociales libres, cada una con sus características, preferencias, grupos de usuaries. Están diseñadas para facilitar el diálogo entre todas ellas. Es decir, para que los contenidos puedan ser visibles y se puedan generar respuestas entre usuaries, fomentando una cultura de participación y pluralidad de voces, basadas en estándares de desarrollo libre y que buscan ser éticos antes que con fines de lucro sin fin.

Los sitios web siguen siendo formatos para medios de comunicación que, debido a sus características, favorecen la difusión de contenidos como artículos multimedia. Permiten adecuar un estilo a una identidad visual del medio, mantener secciones y contenido institucional variado, entre otras cosas.

Las redes sociales se destacan por sus características de inmediatez, favoreciendo un flujo dialógico en tiempo real con otros tiempos de atención y características de navegación que lo hacen más breve, rápido, a veces efímero. Los medios de comunicación (personas o emprendimientos mediáticos) suelen utilizarlos para llamar la atención sobre contenidos publicados en sus sitios, apostando a la divulgación rápida y las discusiones que puedan darse entre usuaries.

La funcionalidad que desarrollamos en Sutty contempla los casos de uso en los que un contenido quiera ser compartido a más personas, en menor tiempo, con la posibilidad de generar diálogos. Las particularidades de nuestros sitios y redes sociales libres generan condiciones favorables para la libertad de expresión, que preferimos llamar Derecho a la Comunicación, evadiendo las variadas y cada vez más sofisticadas formas de censura de las plataformas corporativas tradicionales. Un contenido reproducido en varios lugares al mismo tiempo ayuda a su divulgación y es ideal para aquellas voces y discursos contrahegemónicos en la web y su supervivencia al paso del tiempo, preservando la memoria popular.

Cómo funciona el Fediverso en la moderación

El Fediverso intenta funcionar como comunidades en línea interconectadas que se autogobiernan en las formas de cuidados colectivos. Así, cada instancia podría ser algo así como un municipio que aloja diferentes cuentas/usuaries bajo unas reglas consensuadas y que pueden ser puestas en discusión si fuera necesario. De esta forma, es posible regular la circulación de contenidos fascistas y discursos de odio que puedan dañar no solamente la participación de diverses usuaries sino también su salud.

Para ello, cada instancia elige sus formas de moderación y puede excluir otras instancias con denuncias previas de contenidos antidemocráticos, odiantes o contrarios a los valores y cuidados de sus habitantes.

En Sutty en particular, nos interesan las estrategias y los mecanismos de cuidados colectivos, por lo que seguimos diseñando modelos que permitan sostenerlos en nuestras tecnologías. Podés revisar nuestros términos y condiciones, política de privacidad y acuerdos de convivencia para más información.

¿Te interesa participar?

Si sos parte de una organización social, grupo de activismo o colectivo social que pensás que podría beneficiarse de estas características, te invitamos a contactarnos a través de nuestro formulario. Estamos busando mejorar los usos de las tecnologías para ustedes y valoramos sus experiencias.

Otras posibilidades de integración de Social Inbox en sitios estáticos

Si te interesa incorporar esta funcionalidad para otros gestores de sitios estáticos, no dudes en contactarnos. Además, mantenete al tanto de las novedades que compartimos en https://dweb.sutty.nl y en nuestro blog https://sutty.nl/blog

Recomendado para saber más

\n"}, - "attachment"=> - [{"type"=>"Document", - "mediaType"=>"image/png", - "url"=>"https://sutty.nl/public/8r7b6ohqy6xzgngxbol6337q8jj9/milestone_2_activity_pub_2.png", - "name"=>"Botones de colores para activar la \"Web Disribuida\" y el \"Fediverso\"."}]} - + { '@context' => + ['https://www.w3.org/ns/activitystreams', + { 'ostatus' => 'http://ostatus.org#', + 'atomUri' => 'ostatus:atomUri', + 'inReplyToAtomUri' => 'ostatus:inReplyToAtomUri', + 'conversation' => 'ostatus:conversation', + 'sensitive' => 'as:sensitive', + 'toot' => 'http://joinmastodon.org/ns#', + 'votersCount' => 'toot:votersCount', + 'Hashtag' => 'as:Hashtag' }], + 'id' => 'https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041', + 'type' => 'Note', + 'summary' => nil, + 'inReplyTo' => 'https://mastodon.mauve.moe/users/mauve/statuses/111461923538534886', + 'published' => '2023-11-23T22:50:10Z', + 'url' => 'https://mastodon.mauve.moe/@mauve/111462305634770041', + 'attributedTo' => 'https://mastodon.mauve.moe/users/mauve', + 'to' => ['https://www.w3.org/ns/activitystreams#Public'], + 'cc' => ['https://mastodon.mauve.moe/users/mauve/followers', 'https://hypha.coop/about.jsonld'], + 'sensitive' => false, + 'atomUri' => 'https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041', + 'inReplyToAtomUri' => 'https://mastodon.mauve.moe/users/mauve/statuses/111461923538534886', + 'conversation' => 'tag:mastodon.mauve.moe,2023-11-23:objectId=551471:objectType=Conversation', + 'content' => + '

Follow @HyphaCoop@hypha.coop for our announcement post on the 5th!

', + 'contentMap' => + { 'en' => + '

Follow @HyphaCoop@hypha.coop for our announcement post on the 5th!

' }, + 'attachment' => [], + 'tag' => + [{ 'type' => 'Mention', 'href' => 'https://hypha.coop/about.jsonld', 'name' => '@dripline@hypha.coop' }, + { 'type' => 'Hashtag', 'href' => 'https://mastodon.mauve.moe/tags/p2p', 'name' => '#p2p' }, + { 'type' => 'Hashtag', 'href' => 'https://mastodon.mauve.moe/tags/activitypub', 'name' => '#activitypub' }, + { 'type' => 'Hashtag', 'href' => 'https://mastodon.mauve.moe/tags/fediverse', 'name' => '#fediverse' }], + 'replies' => + { 'id' => 'https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies', + 'type' => 'Collection', + 'first' => + { 'type' => 'CollectionPage', + 'next' => 'https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies?only_other_accounts=true&page=true', + 'partOf' => 'https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies', + 'items' => [] } } }, + { '@context' => ['https://www.w3.org/ns/activitystreams', { '@language' => 'es', 'sensitive' => 'as:sensitive' }], + 'type' => 'Note', + 'id' => 'https://sutty.nl/lanzamiento-de-publicaciones-distribuidas-en-el-fediverso-a-trav%C3%A9s-de-sutty/', + 'summary' => 'Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty', + 'published' => '2023-12-04T21:53:05+00:00', + 'updated' => '2023-12-05T20:41:34+00:00', + 'attributedTo' => 'https://sutty.nl/about.jsonld', + 'to' => ['https://www.w3.org/ns/activitystreams#Public'], + 'cc' => ['https://social.distributed.press/v1/@sutty@sutty.nl/followers'], + 'inReplyTo' => 'https://hypha.coop/dripline/announcing-dp-social-inbox/', + 'sensitive' => true, + 'content' => + "

Estamos felices y orgulloses de anunciar el lanzamiento de la funcionalidad que permite la publicación en el Fediverso de los artículos de todos los sitios creados a través de Sutty.

Gracias al trabajo conjunto con Distributed Press, Hypha y apoyado por la Filecoin Foundation for the Distributed Web, Sutty hace posible que la seguridad de tu sitio estático se combine con la rápida difusión de tu contenido a través de las redes sociales libres y descentralizadas que constituyen el Fediverso.

Esto se logró a través del desarollo y la integración de dos componentes, trabajados en forma conjunta y colaborativa:

    \n
  1. Social Inbox, desarrollado principalmente Distributed Press. Aporta la funcionalidad de recibir artículos, responder y mencionar otras cuentas en el Fediverso.

  2. \n
  3. Jekyll Activity Pub Plugin, desarrollado principalmente por Sutty. Permite integrar Social Inbox en todos los sitios estáticos generados en Jekyll, admitiendo así la publicación automática de contenido del sitio en el Fediverso.

  4. \n

Sutty integra la funcionalidad completa en su CMS para sitios estáticos en Jekyll, permitiendo gestionarla desde una interfaz en continua mejora de su usabilidad.

Si todavía no estás familiarizade con estos nombres y conceptos, te invitamos a conocer más a continuación, en la sección “Para tecno-curioses”.

Qué significa

    \n
  • Que si creás tu sitio web a través de Sutty, tenés nuevas posibilidades de difundir tus contenidos e interactuar en redes digitales.

  • \n
  • Que tus artículos pueden ser publicados en las redes del Fediverso.

  • \n
  • Que tu sitio tendrá un perfil o usuarie personalizable desde el panel en una instancia de Sutty propia.

  • \n
  • Que les usuaries del Fediverso pueden seguir tus publicaciones.

  • \n
  • Que les usuaries del Fediverso que te sigan podrán leer tus publicaciones, mencionarte y responderte.

  • \n
  • Que podrás interactuar con les usuaries del Fediverse con las opciones de responderles y mencionarles.

  • \n

Qué permite hacer

    \n
  • Activar la publicación en el Fediverso para todos los sitios de Sutty.

  • \n
  • Activar la publicación de los artículos que quieras en el Fediverso.

  • \n
  • Responder comentarios desde los artículos de tu sitio en Sutty.

  • \n
  • Personalizar la cuenta que Sutty crea automáticamente de tu sitio en el Fediverso.

  • \n
  • Reportar o informar de usuaries o instancias abusivos mediante nuestro formulario de contacto.

  • \n

Qué se viene

    \n
  • Mejoras en la integración de las respuestas como comentarios en el sitio.

  • \n
  • Incorporación de menciones desde el panel de Sutty.

  • \n
  • Mejoras en la interfaz general del panel.

  • \n
  • Nuevas implementaciones para una mejor moderación.

  • \n
  • Mejor compatibilidad con diversas redes en el Fediverso (Mastodon+Glitch, Pleroma, Ktistec).

  • \n
  • Mejoras que permitirán diferenciar el contenido a publicar en el Fediverso y en el sitio de Sutty.

  • \n
  • La posibilidad de exportar tu cuenta a una instancia del Fediverso desde tu panel.

  • \n
  • La posibilidad de que Sutty anuncie tu contenido y/o usuarie del Fediverse en forma automática para atraer seguidorxs. (Ahora, podés hacerlo a través de un formulario).

  • \n
  • Acceder a la lista de seguidorxs y seguides desde tu panel.

  • \n
  • Seguir, dejar de seguir, bloquear usuaries y/o instancias del Fediverso desde el panel.

  • \n

¡Quiero usarlo!

Te invitamos a dar tus primeros pasos de la mano de nuestro tutorial.

Para tecno-curioses

Cómo funciona

Los sitios web y las redes sociales parecen ser especies distintas dentro del Universo de Internet. Al mismo tiempo, las redes sociales corporativas y concentradas como Instagram, Facebook, X (ex Twitter), entre otras, demostraron ser hostiles con algunos grupos o colectivos sociales en particular (censurando contenido, persiguiendo pezones, ocultando publicaciones por color de piel y de pelo, etc.) y con todes sus usuaries en general (vendiendo data en forma masiva, violando acuerdos de privacidad, eligiendo diseños de interfaz y uso que generan ansiedad y adicción, etc.). Pese a esto, siguen funcionando como espacios obligados a la hora de publicitar un emprendimiento o difundir noticias urgentes.

El Fediverso es una red federada, descentralizada y distribuida de redes sociales libres, cada una con sus características, preferencias, grupos de usuaries. Están diseñadas para facilitar el diálogo entre todas ellas. Es decir, para que los contenidos puedan ser visibles y se puedan generar respuestas entre usuaries, fomentando una cultura de participación y pluralidad de voces, basadas en estándares de desarrollo libre y que buscan ser éticos antes que con fines de lucro sin fin.

Los sitios web siguen siendo formatos para medios de comunicación que, debido a sus características, favorecen la difusión de contenidos como artículos multimedia. Permiten adecuar un estilo a una identidad visual del medio, mantener secciones y contenido institucional variado, entre otras cosas.

Las redes sociales se destacan por sus características de inmediatez, favoreciendo un flujo dialógico en tiempo real con otros tiempos de atención y características de navegación que lo hacen más breve, rápido, a veces efímero. Los medios de comunicación (personas o emprendimientos mediáticos) suelen utilizarlos para llamar la atención sobre contenidos publicados en sus sitios, apostando a la divulgación rápida y las discusiones que puedan darse entre usuaries.

La funcionalidad que desarrollamos en Sutty contempla los casos de uso en los que un contenido quiera ser compartido a más personas, en menor tiempo, con la posibilidad de generar diálogos. Las particularidades de nuestros sitios y redes sociales libres generan condiciones favorables para la libertad de expresión, que preferimos llamar Derecho a la Comunicación, evadiendo las variadas y cada vez más sofisticadas formas de censura de las plataformas corporativas tradicionales. Un contenido reproducido en varios lugares al mismo tiempo ayuda a su divulgación y es ideal para aquellas voces y discursos contrahegemónicos en la web y su supervivencia al paso del tiempo, preservando la memoria popular.

Cómo funciona el Fediverso en la moderación

El Fediverso intenta funcionar como comunidades en línea interconectadas que se autogobiernan en las formas de cuidados colectivos. Así, cada instancia podría ser algo así como un municipio que aloja diferentes cuentas/usuaries bajo unas reglas consensuadas y que pueden ser puestas en discusión si fuera necesario. De esta forma, es posible regular la circulación de contenidos fascistas y discursos de odio que puedan dañar no solamente la participación de diverses usuaries sino también su salud.

Para ello, cada instancia elige sus formas de moderación y puede excluir otras instancias con denuncias previas de contenidos antidemocráticos, odiantes o contrarios a los valores y cuidados de sus habitantes.

En Sutty en particular, nos interesan las estrategias y los mecanismos de cuidados colectivos, por lo que seguimos diseñando modelos que permitan sostenerlos en nuestras tecnologías. Podés revisar nuestros términos y condiciones, política de privacidad y acuerdos de convivencia para más información.

¿Te interesa participar?

Si sos parte de una organización social, grupo de activismo o colectivo social que pensás que podría beneficiarse de estas características, te invitamos a contactarnos a través de nuestro formulario. Estamos busando mejorar los usos de las tecnologías para ustedes y valoramos sus experiencias.

Otras posibilidades de integración de Social Inbox en sitios estáticos

Si te interesa incorporar esta funcionalidad para otros gestores de sitios estáticos, no dudes en contactarnos. Además, mantenete al tanto de las novedades que compartimos en https://dweb.sutty.nl y en nuestro blog https://sutty.nl/blog

Recomendado para saber más

\n", + 'name' => 'Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty', + 'contentMap' => + { 'es' => + "

Estamos felices y orgulloses de anunciar el lanzamiento de la funcionalidad que permite la publicación en el Fediverso de los artículos de todos los sitios creados a través de Sutty.

Gracias al trabajo conjunto con Distributed Press, Hypha y apoyado por la Filecoin Foundation for the Distributed Web, Sutty hace posible que la seguridad de tu sitio estático se combine con la rápida difusión de tu contenido a través de las redes sociales libres y descentralizadas que constituyen el Fediverso.

Esto se logró a través del desarollo y la integración de dos componentes, trabajados en forma conjunta y colaborativa:

    \n
  1. Social Inbox, desarrollado principalmente Distributed Press. Aporta la funcionalidad de recibir artículos, responder y mencionar otras cuentas en el Fediverso.

  2. \n
  3. Jekyll Activity Pub Plugin, desarrollado principalmente por Sutty. Permite integrar Social Inbox en todos los sitios estáticos generados en Jekyll, admitiendo así la publicación automática de contenido del sitio en el Fediverso.

  4. \n

Sutty integra la funcionalidad completa en su CMS para sitios estáticos en Jekyll, permitiendo gestionarla desde una interfaz en continua mejora de su usabilidad.

Si todavía no estás familiarizade con estos nombres y conceptos, te invitamos a conocer más a continuación, en la sección “Para tecno-curioses”.

Qué significa

    \n
  • Que si creás tu sitio web a través de Sutty, tenés nuevas posibilidades de difundir tus contenidos e interactuar en redes digitales.

  • \n
  • Que tus artículos pueden ser publicados en las redes del Fediverso.

  • \n
  • Que tu sitio tendrá un perfil o usuarie personalizable desde el panel en una instancia de Sutty propia.

  • \n
  • Que les usuaries del Fediverso pueden seguir tus publicaciones.

  • \n
  • Que les usuaries del Fediverso que te sigan podrán leer tus publicaciones, mencionarte y responderte.

  • \n
  • Que podrás interactuar con les usuaries del Fediverse con las opciones de responderles y mencionarles.

  • \n

Qué permite hacer

    \n
  • Activar la publicación en el Fediverso para todos los sitios de Sutty.

  • \n
  • Activar la publicación de los artículos que quieras en el Fediverso.

  • \n
  • Responder comentarios desde los artículos de tu sitio en Sutty.

  • \n
  • Personalizar la cuenta que Sutty crea automáticamente de tu sitio en el Fediverso.

  • \n
  • Reportar o informar de usuaries o instancias abusivos mediante nuestro formulario de contacto.

  • \n

Qué se viene

    \n
  • Mejoras en la integración de las respuestas como comentarios en el sitio.

  • \n
  • Incorporación de menciones desde el panel de Sutty.

  • \n
  • Mejoras en la interfaz general del panel.

  • \n
  • Nuevas implementaciones para una mejor moderación.

  • \n
  • Mejor compatibilidad con diversas redes en el Fediverso (Mastodon+Glitch, Pleroma, Ktistec).

  • \n
  • Mejoras que permitirán diferenciar el contenido a publicar en el Fediverso y en el sitio de Sutty.

  • \n
  • La posibilidad de exportar tu cuenta a una instancia del Fediverso desde tu panel.

  • \n
  • La posibilidad de que Sutty anuncie tu contenido y/o usuarie del Fediverse en forma automática para atraer seguidorxs. (Ahora, podés hacerlo a través de un formulario).

  • \n
  • Acceder a la lista de seguidorxs y seguides desde tu panel.

  • \n
  • Seguir, dejar de seguir, bloquear usuaries y/o instancias del Fediverso desde el panel.

  • \n

¡Quiero usarlo!

Te invitamos a dar tus primeros pasos de la mano de nuestro tutorial.

Para tecno-curioses

Cómo funciona

Los sitios web y las redes sociales parecen ser especies distintas dentro del Universo de Internet. Al mismo tiempo, las redes sociales corporativas y concentradas como Instagram, Facebook, X (ex Twitter), entre otras, demostraron ser hostiles con algunos grupos o colectivos sociales en particular (censurando contenido, persiguiendo pezones, ocultando publicaciones por color de piel y de pelo, etc.) y con todes sus usuaries en general (vendiendo data en forma masiva, violando acuerdos de privacidad, eligiendo diseños de interfaz y uso que generan ansiedad y adicción, etc.). Pese a esto, siguen funcionando como espacios obligados a la hora de publicitar un emprendimiento o difundir noticias urgentes.

El Fediverso es una red federada, descentralizada y distribuida de redes sociales libres, cada una con sus características, preferencias, grupos de usuaries. Están diseñadas para facilitar el diálogo entre todas ellas. Es decir, para que los contenidos puedan ser visibles y se puedan generar respuestas entre usuaries, fomentando una cultura de participación y pluralidad de voces, basadas en estándares de desarrollo libre y que buscan ser éticos antes que con fines de lucro sin fin.

Los sitios web siguen siendo formatos para medios de comunicación que, debido a sus características, favorecen la difusión de contenidos como artículos multimedia. Permiten adecuar un estilo a una identidad visual del medio, mantener secciones y contenido institucional variado, entre otras cosas.

Las redes sociales se destacan por sus características de inmediatez, favoreciendo un flujo dialógico en tiempo real con otros tiempos de atención y características de navegación que lo hacen más breve, rápido, a veces efímero. Los medios de comunicación (personas o emprendimientos mediáticos) suelen utilizarlos para llamar la atención sobre contenidos publicados en sus sitios, apostando a la divulgación rápida y las discusiones que puedan darse entre usuaries.

La funcionalidad que desarrollamos en Sutty contempla los casos de uso en los que un contenido quiera ser compartido a más personas, en menor tiempo, con la posibilidad de generar diálogos. Las particularidades de nuestros sitios y redes sociales libres generan condiciones favorables para la libertad de expresión, que preferimos llamar Derecho a la Comunicación, evadiendo las variadas y cada vez más sofisticadas formas de censura de las plataformas corporativas tradicionales. Un contenido reproducido en varios lugares al mismo tiempo ayuda a su divulgación y es ideal para aquellas voces y discursos contrahegemónicos en la web y su supervivencia al paso del tiempo, preservando la memoria popular.

Cómo funciona el Fediverso en la moderación

El Fediverso intenta funcionar como comunidades en línea interconectadas que se autogobiernan en las formas de cuidados colectivos. Así, cada instancia podría ser algo así como un municipio que aloja diferentes cuentas/usuaries bajo unas reglas consensuadas y que pueden ser puestas en discusión si fuera necesario. De esta forma, es posible regular la circulación de contenidos fascistas y discursos de odio que puedan dañar no solamente la participación de diverses usuaries sino también su salud.

Para ello, cada instancia elige sus formas de moderación y puede excluir otras instancias con denuncias previas de contenidos antidemocráticos, odiantes o contrarios a los valores y cuidados de sus habitantes.

En Sutty en particular, nos interesan las estrategias y los mecanismos de cuidados colectivos, por lo que seguimos diseñando modelos que permitan sostenerlos en nuestras tecnologías. Podés revisar nuestros términos y condiciones, política de privacidad y acuerdos de convivencia para más información.

¿Te interesa participar?

Si sos parte de una organización social, grupo de activismo o colectivo social que pensás que podría beneficiarse de estas características, te invitamos a contactarnos a través de nuestro formulario. Estamos busando mejorar los usos de las tecnologías para ustedes y valoramos sus experiencias.

Otras posibilidades de integración de Social Inbox en sitios estáticos

Si te interesa incorporar esta funcionalidad para otros gestores de sitios estáticos, no dudes en contactarnos. Además, mantenete al tanto de las novedades que compartimos en https://dweb.sutty.nl y en nuestro blog https://sutty.nl/blog

Recomendado para saber más

\n" }, + 'attachment' => + [{ 'type' => 'Document', + 'mediaType' => 'image/png', + 'url' => 'https://sutty.nl/public/8r7b6ohqy6xzgngxbol6337q8jj9/milestone_2_activity_pub_2.png', + 'name' => 'Botones de colores para activar la "Web Disribuida" y el "Fediverso".' }] } ] end @@ -159,217 +158,223 @@ class ModerationQueueController < ApplicationController # mauve.moe usa /api/v1/instance def instances @instances = [ -{"domain"=>"todon.nl", - "title"=>"Todon.nl", - "version"=>"4.2.3", - "source_url"=>"https://github.com/mastodon/mastodon", - "description"=> - "Radicaal linkse anti-autoritaire server. Voor anarchisten, socialisten, (klimaat)activisten, LHBTQIA+, antiracisten, antifascisten, antikapitalisten, intersectionelen, veganisten, mensenrechten, enz.", - "usage"=>{"users"=>{"active_month"=>372}}, - "thumbnail"=> - {"url"=>"https://todon.nl/system/site_uploads/files/000/000/004/@1x/297e509bc8a81f62.png", - "blurhash"=>"UXAw3zN4M|xsoga#WBay9DxntQRmITocofWE", - "versions"=> - {"@1x"=>"https://todon.nl/system/site_uploads/files/000/000/004/@1x/297e509bc8a81f62.png", - "@2x"=>"https://todon.nl/system/site_uploads/files/000/000/004/@2x/297e509bc8a81f62.png"}}, - "languages"=>["en"], - "configuration"=> - {"urls"=>{"streaming"=>"wss://todon.nl", "status"=>"https://status.todon.eu"}, - "accounts"=>{"max_featured_tags"=>10}, - "statuses"=>{"max_characters"=>1312, "max_media_attachments"=>4, "characters_reserved_per_url"=>23}, - "media_attachments"=> - {"supported_mime_types"=> - ["image/jpeg", - "image/png", - "image/gif", - "image/heic", - "image/heif", - "image/webp", - "image/avif", - "video/webm", - "video/mp4", - "video/quicktime", - "video/ogg", - "audio/wave", - "audio/wav", - "audio/x-wav", - "audio/x-pn-wave", - "audio/vnd.wave", - "audio/ogg", - "audio/vorbis", - "audio/mpeg", - "audio/mp3", - "audio/webm", - "audio/flac", - "audio/aac", - "audio/m4a", - "audio/x-m4a", - "audio/mp4", - "audio/3gpp", - "video/x-ms-asf"], - "image_size_limit"=>16777216, - "image_matrix_limit"=>33177600, - "video_size_limit"=>103809024, - "video_frame_rate_limit"=>120, - "video_matrix_limit"=>8294400}, - "polls"=>{"max_options"=>4, "max_characters_per_option"=>50, "min_expiration"=>300, "max_expiration"=>2629746}, - "translation"=>{"enabled"=>true}}, - "registrations"=> - {"enabled"=>false, - "approval_required"=>false, - "message"=> - "

¡No pasarán!

\n\n

Je kunt tijdelijk geen nieuw account op Todon.nl aanvragen.

\n\n\n\n

Ga naar joinmastodon.org of FediDB Network om een andere server te vinden.

\n\n

It is temporary not possible to request on account on Todon.nl.

\n\n\n\n

Go to joinmastodon.org or FediDB Network to find another server.

\n", - "url"=>nil}, - "max_toot_chars"=>1312, - "contact"=> - {"email"=>"todon@posteo.eu", - "account"=> - {"id"=>"1", - "username"=>"admin", - "acct"=>"admin", - "display_name"=>"Admin 🤓 Todon.nl (mod)", - "locked"=>false, - "bot"=>false, - "discoverable"=>false, - "group"=>false, - "created_at"=>"2017-04-28T00:00:00.000Z", - "note"=> - "

This account is used for 🎙 Todon.nl announcements and ⚖️ moderation.

🚫 Don't follow this account when you are not on Todon.nl.

New? First read our 👩‍🏫 Todon 101 👩‍🎓 at https://wiki.todon.eu/todon/101

⚖️ For all our moderators go to https://wiki.todon.nl/todon/moderators

📝 Public toots from this account are in English.

🔕 Criticism is fine, but people who do false accusations are muted.

✉ todon@posteo.eu

#nobot

", - "url"=>"https://todon.nl/@admin", - "uri"=>"https://todon.nl/users/admin", - "avatar"=>"https://todon.nl/system/accounts/avatars/000/000/001/original/2db61726225ed3e6.png", - "avatar_static"=>"https://todon.nl/system/accounts/avatars/000/000/001/original/2db61726225ed3e6.png", - "header"=>"https://todon.nl/system/accounts/headers/000/000/001/original/fb3a846cbc20aa09.png", - "header_static"=>"https://todon.nl/system/accounts/headers/000/000/001/original/fb3a846cbc20aa09.png", - "followers_count"=>3164, - "following_count"=>8, - "statuses_count"=>724, - "last_status_at"=>"2024-01-12", - "noindex"=>true, - "emojis"=>[], - "roles"=>[{"id"=>"3", "name"=>"Admin", "color"=>"#595aff"}], - "fields"=> - [{"name"=>"📜 Terms of Service", - "value"=> - "https://wiki.todon.nl/todon/terms_en", - "verified_at"=>"2018-11-01T14:39:45.465+00:00"}, - {"name"=>"ℹ️ Wiki", - "value"=> - "https://wiki.todon.nl/todon/information", - "verified_at"=>"2018-11-01T14:40:54.679+00:00"}, - {"name"=>"📊 Status", - "value"=> - "https://status.todon.eu", - "verified_at"=>"2023-10-26T20:38:30.185+00:00"}, - {"name"=>"💳️ Donations", - "value"=> - "https://wiki.todon.eu/todon/donations", - "verified_at"=>"2022-11-02T00:06:31.865+00:00"}]}}, - "rules"=> - [{"id"=>"1", - "text"=> - "We do not accept racism (in all its forms, incl. hate against Muslims, antisemitism, apartheid and casteism - see our Terms of Service for our complete definition)."}, - {"id"=>"2", - "text"=> - "We do not accept hate against lesbians, gays, bisexuals, pansexuals, transgenders, non-binary people, intersexual people, queer people in general, etc."}, - {"id"=>"4", "text"=>"Sexism, misogyny and hate against black women (misogynoir)."}, - {"id"=>"6", "text"=>"We do not accept ableism (incl. COVID-19 denial/downplaying and anti-vax) and body-shaming."}, - {"id"=>"8", "text"=>"We do not accept harassment and trolling."}, - {"id"=>"10", "text"=>"We also do not accept other forms of hate speech."}, - {"id"=>"11", "text"=>"We do not accept (sexual) abuse of minors, adults and animals (also not virtual)."}, - {"id"=>"13", "text"=>"We do not accept glorification of violence, calls for murder, death threats, terrorism and militarism."}, - {"id"=>"15", - "text"=> - "We do not accept (neo)colonialism (incl. Zionism), imperialism in all forms and nationalism (above all nationalism of nation states, incl. flags/symbols of those on Todon.*, see our Terms of Service)."}, - {"id"=>"16", "text"=>"We do not accept fascism, right-wing populism, and right-wing and religious extremism."}, - {"id"=>"17", - "text"=>"We do not accept evangelisation and other forms of religious propaganda [local only], and extreme sects and cults."}, - {"id"=>"19", - "text"=> - "We do not accept Marxist-Leninists, Stalinists, Maoists or other followers of extreme authoritarian (so called) communist/socialist ideologies/regimes (aka tankies)."}, - {"id"=>"20", "text"=>"We do not accept capitalists, including so called 'anarcho-capitalists' (aka ancaps) and neoliberals."}, - {"id"=>"21", - "text"=> - "We do not accept anthropogenic climate change denial, downplaying the climate crisis, greenwashing and deceptive climate solutions (like nuclear energy)."}, - {"id"=>"27", "text"=>"We do not accept (right-wing) conspiracy 'theories', hoaxes, fake news and other forms of disinformation."}, - {"id"=>"28", "text"=>"Another rule in our terms of service at wiki.todon.eu/todon/terms_en. Explain in the final step."}]}, -{"uri"=>"mastodon.mauve.moe", - "title"=>"Mauvestodon", - "short_description"=>"Escape ship from centralized social media run by Mauve.", - "description"=>"Chat about random techie and anarchist stuff.", - "email"=>"contact@mauve.moe", - "version"=>"3.5.10", - "urls"=>{"streaming_api"=>"wss://mastodon.mauve.moe"}, - "stats"=>{"user_count"=>12, "status_count"=>3287, "domain_count"=>11625}, - "thumbnail"=>"https://mastodon.mauve.moe/system/site_uploads/files/000/000/001/original/mauvesoftwareinc.png", - "languages"=>["en"], - "registrations"=>false, - "approval_required"=>false, - "invites_enabled"=>true, - "configuration"=> - {"statuses"=>{"max_characters"=>500, "max_media_attachments"=>4, "characters_reserved_per_url"=>23}, - "media_attachments"=> - {"supported_mime_types"=> - ["image/jpeg", - "image/png", - "image/gif", - "video/webm", - "video/mp4", - "video/quicktime", - "video/ogg", - "audio/wave", - "audio/wav", - "audio/x-wav", - "audio/x-pn-wave", - "audio/ogg", - "audio/vorbis", - "audio/mpeg", - "audio/mp3", - "audio/webm", - "audio/flac", - "audio/aac", - "audio/m4a", - "audio/x-m4a", - "audio/mp4", - "audio/3gpp", - "video/x-ms-asf"], - "image_size_limit"=>10485760, - "image_matrix_limit"=>16777216, - "video_size_limit"=>41943040, - "video_frame_rate_limit"=>60, - "video_matrix_limit"=>2304000}, - "polls"=>{"max_options"=>4, "max_characters_per_option"=>50, "min_expiration"=>300, "max_expiration"=>2629746}}, - "contact_account"=> - {"id"=>"1", - "username"=>"admin", - "acct"=>"admin", - "display_name"=>"", - "locked"=>false, - "bot"=>false, - "discoverable"=>true, - "group"=>false, - "created_at"=>"2022-04-25T00:00:00.000Z", - "note"=>"", - "url"=>"https://mastodon.mauve.moe/@admin", - "avatar"=>"https://mastodon.mauve.moe/system/accounts/avatars/000/000/001/original/8c21e71667b48a95.png", - "avatar_static"=>"https://mastodon.mauve.moe/system/accounts/avatars/000/000/001/original/8c21e71667b48a95.png", - "header"=>"https://mastodon.mauve.moe/headers/original/missing.png", - "header_static"=>"https://mastodon.mauve.moe/headers/original/missing.png", - "followers_count"=>0, - "following_count"=>0, - "statuses_count"=>0, - "last_status_at"=>"2023-01-30", - "emojis"=>[], - "fields"=> - [{"name"=>"Alternatel Contact", - "value"=> - "@mauve", - "verified_at"=>nil}]}, - "rules"=>[]} - - + { 'domain' => 'todon.nl', + 'title' => 'Todon.nl', + 'version' => '4.2.3', + 'source_url' => 'https://github.com/mastodon/mastodon', + 'description' => + 'Radicaal linkse anti-autoritaire server. Voor anarchisten, socialisten, (klimaat)activisten, LHBTQIA+, antiracisten, antifascisten, antikapitalisten, intersectionelen, veganisten, mensenrechten, enz.', + 'usage' => { 'users' => { 'active_month' => 372 } }, + 'thumbnail' => + { 'url' => 'https://todon.nl/system/site_uploads/files/000/000/004/@1x/297e509bc8a81f62.png', + 'blurhash' => 'UXAw3zN4M|xsoga#WBay9DxntQRmITocofWE', + 'versions' => + { '@1x' => 'https://todon.nl/system/site_uploads/files/000/000/004/@1x/297e509bc8a81f62.png', + '@2x' => 'https://todon.nl/system/site_uploads/files/000/000/004/@2x/297e509bc8a81f62.png' } }, + 'languages' => ['en'], + 'configuration' => + { 'urls' => { 'streaming' => 'wss://todon.nl', 'status' => 'https://status.todon.eu' }, + 'accounts' => { 'max_featured_tags' => 10 }, + 'statuses' => { 'max_characters' => 1312, 'max_media_attachments' => 4, 'characters_reserved_per_url' => 23 }, + 'media_attachments' => + { 'supported_mime_types' => + ['image/jpeg', + 'image/png', + 'image/gif', + 'image/heic', + 'image/heif', + 'image/webp', + 'image/avif', + 'video/webm', + 'video/mp4', + 'video/quicktime', + 'video/ogg', + 'audio/wave', + 'audio/wav', + 'audio/x-wav', + 'audio/x-pn-wave', + 'audio/vnd.wave', + 'audio/ogg', + 'audio/vorbis', + 'audio/mpeg', + 'audio/mp3', + 'audio/webm', + 'audio/flac', + 'audio/aac', + 'audio/m4a', + 'audio/x-m4a', + 'audio/mp4', + 'audio/3gpp', + 'video/x-ms-asf'], + 'image_size_limit' => 16_777_216, + 'image_matrix_limit' => 33_177_600, + 'video_size_limit' => 103_809_024, + 'video_frame_rate_limit' => 120, + 'video_matrix_limit' => 8_294_400 }, + 'polls' => { 'max_options' => 4, 'max_characters_per_option' => 50, 'min_expiration' => 300, + 'max_expiration' => 2_629_746 }, + 'translation' => { 'enabled' => true } }, + 'registrations' => + { 'enabled' => false, + 'approval_required' => false, + 'message' => + "

¡No pasarán!

\n\n

Je kunt tijdelijk geen nieuw account op Todon.nl aanvragen.

\n\n\n\n

Ga naar joinmastodon.org of FediDB Network om een andere server te vinden.

\n\n

It is temporary not possible to request on account on Todon.nl.

\n\n\n\n

Go to joinmastodon.org or FediDB Network to find another server.

\n", + 'url' => nil }, + 'max_toot_chars' => 1312, + 'contact' => + { 'email' => 'todon@posteo.eu', + 'account' => + { 'id' => '1', + 'username' => 'admin', + 'acct' => 'admin', + 'display_name' => 'Admin 🤓 Todon.nl (mod)', + 'locked' => false, + 'bot' => false, + 'discoverable' => false, + 'group' => false, + 'created_at' => '2017-04-28T00:00:00.000Z', + 'note' => + '

This account is used for 🎙 Todon.nl announcements and ⚖️ moderation.

🚫 Don't follow this account when you are not on Todon.nl.

New? First read our 👩‍🏫 Todon 101 👩‍🎓 at wiki.todon.eu/todon/101

⚖️ For all our moderators go to wiki.todon.nl/todon/moderators

📝 Public toots from this account are in English.

🔕 Criticism is fine, but people who do false accusations are muted.

✉ todon@posteo.eu

', + 'url' => 'https://todon.nl/@admin', + 'uri' => 'https://todon.nl/users/admin', + 'avatar' => 'https://todon.nl/system/accounts/avatars/000/000/001/original/2db61726225ed3e6.png', + 'avatar_static' => 'https://todon.nl/system/accounts/avatars/000/000/001/original/2db61726225ed3e6.png', + 'header' => 'https://todon.nl/system/accounts/headers/000/000/001/original/fb3a846cbc20aa09.png', + 'header_static' => 'https://todon.nl/system/accounts/headers/000/000/001/original/fb3a846cbc20aa09.png', + 'followers_count' => 3164, + 'following_count' => 8, + 'statuses_count' => 724, + 'last_status_at' => '2024-01-12', + 'noindex' => true, + 'emojis' => [], + 'roles' => [{ 'id' => '3', 'name' => 'Admin', 'color' => '#595aff' }], + 'fields' => + [{ 'name' => '📜 Terms of Service', + 'value' => + 'wiki.todon.nl/todon/terms_en', + 'verified_at' => '2018-11-01T14:39:45.465+00:00' }, + { 'name' => 'ℹ️ Wiki', + 'value' => + 'wiki.todon.nl/todon/informatio', + 'verified_at' => '2018-11-01T14:40:54.679+00:00' }, + { 'name' => '📊 Status', + 'value' => + 'status.todon.eu', + 'verified_at' => '2023-10-26T20:38:30.185+00:00' }, + { 'name' => '💳️ Donations', + 'value' => + 'wiki.todon.eu/todon/donations', + 'verified_at' => '2022-11-02T00:06:31.865+00:00' }] } }, + 'rules' => + [{ 'id' => '1', + 'text' => + 'We do not accept racism (in all its forms, incl. hate against Muslims, antisemitism, apartheid and casteism - see our Terms of Service for our complete definition).' }, + { 'id' => '2', + 'text' => + 'We do not accept hate against lesbians, gays, bisexuals, pansexuals, transgenders, non-binary people, intersexual people, queer people in general, etc.' }, + { 'id' => '4', 'text' => 'Sexism, misogyny and hate against black women (misogynoir).' }, + { 'id' => '6', + 'text' => 'We do not accept ableism (incl. COVID-19 denial/downplaying and anti-vax) and body-shaming.' }, + { 'id' => '8', 'text' => 'We do not accept harassment and trolling.' }, + { 'id' => '10', 'text' => 'We also do not accept other forms of hate speech.' }, + { 'id' => '11', + 'text' => 'We do not accept (sexual) abuse of minors, adults and animals (also not virtual).' }, + { 'id' => '13', + 'text' => 'We do not accept glorification of violence, calls for murder, death threats, terrorism and militarism.' }, + { 'id' => '15', + 'text' => + 'We do not accept (neo)colonialism (incl. Zionism), imperialism in all forms and nationalism (above all nationalism of nation states, incl. flags/symbols of those on Todon.*, see our Terms of Service).' }, + { 'id' => '16', + 'text' => 'We do not accept fascism, right-wing populism, and right-wing and religious extremism.' }, + { 'id' => '17', + 'text' => 'We do not accept evangelisation and other forms of religious propaganda [local only], and extreme sects and cults.' }, + { 'id' => '19', + 'text' => + 'We do not accept Marxist-Leninists, Stalinists, Maoists or other followers of extreme authoritarian (so called) communist/socialist ideologies/regimes (aka tankies).' }, + { 'id' => '20', + 'text' => "We do not accept capitalists, including so called 'anarcho-capitalists' (aka ancaps) and neoliberals." }, + { 'id' => '21', + 'text' => + 'We do not accept anthropogenic climate change denial, downplaying the climate crisis, greenwashing and deceptive climate solutions (like nuclear energy).' }, + { 'id' => '27', + 'text' => "We do not accept (right-wing) conspiracy 'theories', hoaxes, fake news and other forms of disinformation." }, + { 'id' => '28', + 'text' => 'Another rule in our terms of service at wiki.todon.eu/todon/terms_en. Explain in the final step.' }] }, + { 'uri' => 'mastodon.mauve.moe', + 'title' => 'Mauvestodon', + 'short_description' => 'Escape ship from centralized social media run by Mauve.', + 'description' => 'Chat about random techie and anarchist stuff.', + 'email' => 'contact@mauve.moe', + 'version' => '3.5.10', + 'urls' => { 'streaming_api' => 'wss://mastodon.mauve.moe' }, + 'stats' => { 'user_count' => 12, 'status_count' => 3287, 'domain_count' => 11_625 }, + 'thumbnail' => 'https://mastodon.mauve.moe/system/site_uploads/files/000/000/001/original/mauvesoftwareinc.png', + 'languages' => ['en'], + 'registrations' => false, + 'approval_required' => false, + 'invites_enabled' => true, + 'configuration' => + { 'statuses' => { 'max_characters' => 500, 'max_media_attachments' => 4, 'characters_reserved_per_url' => 23 }, + 'media_attachments' => + { 'supported_mime_types' => + ['image/jpeg', + 'image/png', + 'image/gif', + 'video/webm', + 'video/mp4', + 'video/quicktime', + 'video/ogg', + 'audio/wave', + 'audio/wav', + 'audio/x-wav', + 'audio/x-pn-wave', + 'audio/ogg', + 'audio/vorbis', + 'audio/mpeg', + 'audio/mp3', + 'audio/webm', + 'audio/flac', + 'audio/aac', + 'audio/m4a', + 'audio/x-m4a', + 'audio/mp4', + 'audio/3gpp', + 'video/x-ms-asf'], + 'image_size_limit' => 10_485_760, + 'image_matrix_limit' => 16_777_216, + 'video_size_limit' => 41_943_040, + 'video_frame_rate_limit' => 60, + 'video_matrix_limit' => 2_304_000 }, + 'polls' => { 'max_options' => 4, 'max_characters_per_option' => 50, 'min_expiration' => 300, + 'max_expiration' => 2_629_746 } }, + 'contact_account' => + { 'id' => '1', + 'username' => 'admin', + 'acct' => 'admin', + 'display_name' => '', + 'locked' => false, + 'bot' => false, + 'discoverable' => true, + 'group' => false, + 'created_at' => '2022-04-25T00:00:00.000Z', + 'note' => '', + 'url' => 'https://mastodon.mauve.moe/@admin', + 'avatar' => 'https://mastodon.mauve.moe/system/accounts/avatars/000/000/001/original/8c21e71667b48a95.png', + 'avatar_static' => 'https://mastodon.mauve.moe/system/accounts/avatars/000/000/001/original/8c21e71667b48a95.png', + 'header' => 'https://mastodon.mauve.moe/headers/original/missing.png', + 'header_static' => 'https://mastodon.mauve.moe/headers/original/missing.png', + 'followers_count' => 0, + 'following_count' => 0, + 'statuses_count' => 0, + 'last_status_at' => '2023-01-30', + 'emojis' => [], + 'fields' => + [{ 'name' => 'Alternatel Contact', + 'value' => + '@mauve', + 'verified_at' => nil }] }, + 'rules' => [] } ] - end end diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 8b4d975f..1bc94ec1 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -84,75 +84,72 @@ class PostsController < ApplicationController @moderation_queue = [ -{"@context"=> - ["https://www.w3.org/ns/activitystreams", - {"ostatus"=>"http://ostatus.org#", - "atomUri"=>"ostatus:atomUri", - "inReplyToAtomUri"=>"ostatus:inReplyToAtomUri", - "conversation"=>"ostatus:conversation", - "sensitive"=>"as:sensitive", - "toot"=>"http://joinmastodon.org/ns#", - "votersCount"=>"toot:votersCount", - "Hashtag"=>"as:Hashtag"}], - "id"=>"https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041", - "type"=>"Note", - "summary"=>nil, - "inReplyTo"=>"https://mastodon.mauve.moe/users/mauve/statuses/111461923538534886", - "published"=>"2023-11-23T22:50:10Z", - "url"=>"https://mastodon.mauve.moe/@mauve/111462305634770041", - "attributedTo"=>"https://mastodon.mauve.moe/users/mauve", - "to"=>["https://www.w3.org/ns/activitystreams#Public"], - "cc"=>["https://mastodon.mauve.moe/users/mauve/followers", "https://hypha.coop/about.jsonld"], - "sensitive"=>false, - "atomUri"=>"https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041", - "inReplyToAtomUri"=>"https://mastodon.mauve.moe/users/mauve/statuses/111461923538534886", - "conversation"=>"tag:mastodon.mauve.moe,2023-11-23:objectId=551471:objectType=Conversation", - "content"=> - "

Follow @HyphaCoop@hypha.coop for our announcement post on the 5th!

#P2P #ActivityPub #Fediverse

", - "contentMap"=> - {"en"=> - "

Follow @HyphaCoop@hypha.coop for our announcement post on the 5th!

#P2P #ActivityPub #Fediverse

"}, - "attachment"=>[], - "tag"=> - [{"type"=>"Mention", "href"=>"https://hypha.coop/about.jsonld", "name"=>"@dripline@hypha.coop"}, - {"type"=>"Hashtag", "href"=>"https://mastodon.mauve.moe/tags/p2p", "name"=>"#p2p"}, - {"type"=>"Hashtag", "href"=>"https://mastodon.mauve.moe/tags/activitypub", "name"=>"#activitypub"}, - {"type"=>"Hashtag", "href"=>"https://mastodon.mauve.moe/tags/fediverse", "name"=>"#fediverse"}], - "replies"=> - {"id"=>"https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies", - "type"=>"Collection", - "first"=> - {"type"=>"CollectionPage", - "next"=>"https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies?only_other_accounts=true&page=true", - "partOf"=>"https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies", - "items"=>[]}}}, -{"@context"=>["https://www.w3.org/ns/activitystreams", {"@language"=>"es", "sensitive"=>"as:sensitive"}], - "type"=>"Note", - "id"=>"https://sutty.nl/lanzamiento-de-publicaciones-distribuidas-en-el-fediverso-a-trav%C3%A9s-de-sutty/", - "summary"=>"Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty", - "published"=>"2023-12-04T21:53:05+00:00", - "updated"=>"2023-12-05T20:41:34+00:00", - "attributedTo"=>"https://sutty.nl/about.jsonld", - "to"=>["https://www.w3.org/ns/activitystreams#Public"], - "cc"=>["https://social.distributed.press/v1/@sutty@sutty.nl/followers"], - "inReplyTo"=>"https://hypha.coop/dripline/announcing-dp-social-inbox/", - "sensitive"=>true, - "content"=> - "

Estamos felices y orgulloses de anunciar el lanzamiento de la funcionalidad que permite la publicación en el Fediverso de los artículos de todos los sitios creados a través de Sutty.

Gracias al trabajo conjunto con Distributed Press, Hypha y apoyado por la Filecoin Foundation for the Distributed Web, Sutty hace posible que la seguridad de tu sitio estático se combine con la rápida difusión de tu contenido a través de las redes sociales libres y descentralizadas que constituyen el Fediverso.

Esto se logró a través del desarollo y la integración de dos componentes, trabajados en forma conjunta y colaborativa:

    \n
  1. Social Inbox, desarrollado principalmente Distributed Press. Aporta la funcionalidad de recibir artículos, responder y mencionar otras cuentas en el Fediverso.

  2. \n
  3. Jekyll Activity Pub Plugin, desarrollado principalmente por Sutty. Permite integrar Social Inbox en todos los sitios estáticos generados en Jekyll, admitiendo así la publicación automática de contenido del sitio en el Fediverso.

  4. \n

Sutty integra la funcionalidad completa en su CMS para sitios estáticos en Jekyll, permitiendo gestionarla desde una interfaz en continua mejora de su usabilidad.

Si todavía no estás familiarizade con estos nombres y conceptos, te invitamos a conocer más a continuación, en la sección “Para tecno-curioses”.

Qué significa

    \n
  • Que si creás tu sitio web a través de Sutty, tenés nuevas posibilidades de difundir tus contenidos e interactuar en redes digitales.

  • \n
  • Que tus artículos pueden ser publicados en las redes del Fediverso.

  • \n
  • Que tu sitio tendrá un perfil o usuarie personalizable desde el panel en una instancia de Sutty propia.

  • \n
  • Que les usuaries del Fediverso pueden seguir tus publicaciones.

  • \n
  • Que les usuaries del Fediverso que te sigan podrán leer tus publicaciones, mencionarte y responderte.

  • \n
  • Que podrás interactuar con les usuaries del Fediverse con las opciones de responderles y mencionarles.

  • \n

Qué permite hacer

    \n
  • Activar la publicación en el Fediverso para todos los sitios de Sutty.

  • \n
  • Activar la publicación de los artículos que quieras en el Fediverso.

  • \n
  • Responder comentarios desde los artículos de tu sitio en Sutty.

  • \n
  • Personalizar la cuenta que Sutty crea automáticamente de tu sitio en el Fediverso.

  • \n
  • Reportar o informar de usuaries o instancias abusivos mediante nuestro formulario de contacto.

  • \n

Qué se viene

    \n
  • Mejoras en la integración de las respuestas como comentarios en el sitio.

  • \n
  • Incorporación de menciones desde el panel de Sutty.

  • \n
  • Mejoras en la interfaz general del panel.

  • \n
  • Nuevas implementaciones para una mejor moderación.

  • \n
  • Mejor compatibilidad con diversas redes en el Fediverso (Mastodon+Glitch, Pleroma, Ktistec).

  • \n
  • Mejoras que permitirán diferenciar el contenido a publicar en el Fediverso y en el sitio de Sutty.

  • \n
  • La posibilidad de exportar tu cuenta a una instancia del Fediverso desde tu panel.

  • \n
  • La posibilidad de que Sutty anuncie tu contenido y/o usuarie del Fediverse en forma automática para atraer seguidorxs. (Ahora, podés hacerlo a través de un formulario).

  • \n
  • Acceder a la lista de seguidorxs y seguides desde tu panel.

  • \n
  • Seguir, dejar de seguir, bloquear usuaries y/o instancias del Fediverso desde el panel.

  • \n

¡Quiero usarlo!

Te invitamos a dar tus primeros pasos de la mano de nuestro tutorial.

Para tecno-curioses

Cómo funciona

Los sitios web y las redes sociales parecen ser especies distintas dentro del Universo de Internet. Al mismo tiempo, las redes sociales corporativas y concentradas como Instagram, Facebook, X (ex Twitter), entre otras, demostraron ser hostiles con algunos grupos o colectivos sociales en particular (censurando contenido, persiguiendo pezones, ocultando publicaciones por color de piel y de pelo, etc.) y con todes sus usuaries en general (vendiendo data en forma masiva, violando acuerdos de privacidad, eligiendo diseños de interfaz y uso que generan ansiedad y adicción, etc.). Pese a esto, siguen funcionando como espacios obligados a la hora de publicitar un emprendimiento o difundir noticias urgentes.

El Fediverso es una red federada, descentralizada y distribuida de redes sociales libres, cada una con sus características, preferencias, grupos de usuaries. Están diseñadas para facilitar el diálogo entre todas ellas. Es decir, para que los contenidos puedan ser visibles y se puedan generar respuestas entre usuaries, fomentando una cultura de participación y pluralidad de voces, basadas en estándares de desarrollo libre y que buscan ser éticos antes que con fines de lucro sin fin.

Los sitios web siguen siendo formatos para medios de comunicación que, debido a sus características, favorecen la difusión de contenidos como artículos multimedia. Permiten adecuar un estilo a una identidad visual del medio, mantener secciones y contenido institucional variado, entre otras cosas.

Las redes sociales se destacan por sus características de inmediatez, favoreciendo un flujo dialógico en tiempo real con otros tiempos de atención y características de navegación que lo hacen más breve, rápido, a veces efímero. Los medios de comunicación (personas o emprendimientos mediáticos) suelen utilizarlos para llamar la atención sobre contenidos publicados en sus sitios, apostando a la divulgación rápida y las discusiones que puedan darse entre usuaries.

La funcionalidad que desarrollamos en Sutty contempla los casos de uso en los que un contenido quiera ser compartido a más personas, en menor tiempo, con la posibilidad de generar diálogos. Las particularidades de nuestros sitios y redes sociales libres generan condiciones favorables para la libertad de expresión, que preferimos llamar Derecho a la Comunicación, evadiendo las variadas y cada vez más sofisticadas formas de censura de las plataformas corporativas tradicionales. Un contenido reproducido en varios lugares al mismo tiempo ayuda a su divulgación y es ideal para aquellas voces y discursos contrahegemónicos en la web y su supervivencia al paso del tiempo, preservando la memoria popular.

Cómo funciona el Fediverso en la moderación

El Fediverso intenta funcionar como comunidades en línea interconectadas que se autogobiernan en las formas de cuidados colectivos. Así, cada instancia podría ser algo así como un municipio que aloja diferentes cuentas/usuaries bajo unas reglas consensuadas y que pueden ser puestas en discusión si fuera necesario. De esta forma, es posible regular la circulación de contenidos fascistas y discursos de odio que puedan dañar no solamente la participación de diverses usuaries sino también su salud.

Para ello, cada instancia elige sus formas de moderación y puede excluir otras instancias con denuncias previas de contenidos antidemocráticos, odiantes o contrarios a los valores y cuidados de sus habitantes.

En Sutty en particular, nos interesan las estrategias y los mecanismos de cuidados colectivos, por lo que seguimos diseñando modelos que permitan sostenerlos en nuestras tecnologías. Podés revisar nuestros términos y condiciones, política de privacidad y acuerdos de convivencia para más información.

¿Te interesa participar?

Si sos parte de una organización social, grupo de activismo o colectivo social que pensás que podría beneficiarse de estas características, te invitamos a contactarnos a través de nuestro formulario. Estamos busando mejorar los usos de las tecnologías para ustedes y valoramos sus experiencias.

Otras posibilidades de integración de Social Inbox en sitios estáticos

Si te interesa incorporar esta funcionalidad para otros gestores de sitios estáticos, no dudes en contactarnos. Además, mantenete al tanto de las novedades que compartimos en https://dweb.sutty.nl y en nuestro blog https://sutty.nl/blog

Recomendado para saber más

\n", - "name"=>"Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty", - "contentMap"=> - {"es"=> - "

Estamos felices y orgulloses de anunciar el lanzamiento de la funcionalidad que permite la publicación en el Fediverso de los artículos de todos los sitios creados a través de Sutty.

Gracias al trabajo conjunto con Distributed Press, Hypha y apoyado por la Filecoin Foundation for the Distributed Web, Sutty hace posible que la seguridad de tu sitio estático se combine con la rápida difusión de tu contenido a través de las redes sociales libres y descentralizadas que constituyen el Fediverso.

Esto se logró a través del desarollo y la integración de dos componentes, trabajados en forma conjunta y colaborativa:

    \n
  1. Social Inbox, desarrollado principalmente Distributed Press. Aporta la funcionalidad de recibir artículos, responder y mencionar otras cuentas en el Fediverso.

  2. \n
  3. Jekyll Activity Pub Plugin, desarrollado principalmente por Sutty. Permite integrar Social Inbox en todos los sitios estáticos generados en Jekyll, admitiendo así la publicación automática de contenido del sitio en el Fediverso.

  4. \n

Sutty integra la funcionalidad completa en su CMS para sitios estáticos en Jekyll, permitiendo gestionarla desde una interfaz en continua mejora de su usabilidad.

Si todavía no estás familiarizade con estos nombres y conceptos, te invitamos a conocer más a continuación, en la sección “Para tecno-curioses”.

Qué significa

    \n
  • Que si creás tu sitio web a través de Sutty, tenés nuevas posibilidades de difundir tus contenidos e interactuar en redes digitales.

  • \n
  • Que tus artículos pueden ser publicados en las redes del Fediverso.

  • \n
  • Que tu sitio tendrá un perfil o usuarie personalizable desde el panel en una instancia de Sutty propia.

  • \n
  • Que les usuaries del Fediverso pueden seguir tus publicaciones.

  • \n
  • Que les usuaries del Fediverso que te sigan podrán leer tus publicaciones, mencionarte y responderte.

  • \n
  • Que podrás interactuar con les usuaries del Fediverse con las opciones de responderles y mencionarles.

  • \n

Qué permite hacer

    \n
  • Activar la publicación en el Fediverso para todos los sitios de Sutty.

  • \n
  • Activar la publicación de los artículos que quieras en el Fediverso.

  • \n
  • Responder comentarios desde los artículos de tu sitio en Sutty.

  • \n
  • Personalizar la cuenta que Sutty crea automáticamente de tu sitio en el Fediverso.

  • \n
  • Reportar o informar de usuaries o instancias abusivos mediante nuestro formulario de contacto.

  • \n

Qué se viene

    \n
  • Mejoras en la integración de las respuestas como comentarios en el sitio.

  • \n
  • Incorporación de menciones desde el panel de Sutty.

  • \n
  • Mejoras en la interfaz general del panel.

  • \n
  • Nuevas implementaciones para una mejor moderación.

  • \n
  • Mejor compatibilidad con diversas redes en el Fediverso (Mastodon+Glitch, Pleroma, Ktistec).

  • \n
  • Mejoras que permitirán diferenciar el contenido a publicar en el Fediverso y en el sitio de Sutty.

  • \n
  • La posibilidad de exportar tu cuenta a una instancia del Fediverso desde tu panel.

  • \n
  • La posibilidad de que Sutty anuncie tu contenido y/o usuarie del Fediverse en forma automática para atraer seguidorxs. (Ahora, podés hacerlo a través de un formulario).

  • \n
  • Acceder a la lista de seguidorxs y seguides desde tu panel.

  • \n
  • Seguir, dejar de seguir, bloquear usuaries y/o instancias del Fediverso desde el panel.

  • \n

¡Quiero usarlo!

Te invitamos a dar tus primeros pasos de la mano de nuestro tutorial.

Para tecno-curioses

Cómo funciona

Los sitios web y las redes sociales parecen ser especies distintas dentro del Universo de Internet. Al mismo tiempo, las redes sociales corporativas y concentradas como Instagram, Facebook, X (ex Twitter), entre otras, demostraron ser hostiles con algunos grupos o colectivos sociales en particular (censurando contenido, persiguiendo pezones, ocultando publicaciones por color de piel y de pelo, etc.) y con todes sus usuaries en general (vendiendo data en forma masiva, violando acuerdos de privacidad, eligiendo diseños de interfaz y uso que generan ansiedad y adicción, etc.). Pese a esto, siguen funcionando como espacios obligados a la hora de publicitar un emprendimiento o difundir noticias urgentes.

El Fediverso es una red federada, descentralizada y distribuida de redes sociales libres, cada una con sus características, preferencias, grupos de usuaries. Están diseñadas para facilitar el diálogo entre todas ellas. Es decir, para que los contenidos puedan ser visibles y se puedan generar respuestas entre usuaries, fomentando una cultura de participación y pluralidad de voces, basadas en estándares de desarrollo libre y que buscan ser éticos antes que con fines de lucro sin fin.

Los sitios web siguen siendo formatos para medios de comunicación que, debido a sus características, favorecen la difusión de contenidos como artículos multimedia. Permiten adecuar un estilo a una identidad visual del medio, mantener secciones y contenido institucional variado, entre otras cosas.

Las redes sociales se destacan por sus características de inmediatez, favoreciendo un flujo dialógico en tiempo real con otros tiempos de atención y características de navegación que lo hacen más breve, rápido, a veces efímero. Los medios de comunicación (personas o emprendimientos mediáticos) suelen utilizarlos para llamar la atención sobre contenidos publicados en sus sitios, apostando a la divulgación rápida y las discusiones que puedan darse entre usuaries.

La funcionalidad que desarrollamos en Sutty contempla los casos de uso en los que un contenido quiera ser compartido a más personas, en menor tiempo, con la posibilidad de generar diálogos. Las particularidades de nuestros sitios y redes sociales libres generan condiciones favorables para la libertad de expresión, que preferimos llamar Derecho a la Comunicación, evadiendo las variadas y cada vez más sofisticadas formas de censura de las plataformas corporativas tradicionales. Un contenido reproducido en varios lugares al mismo tiempo ayuda a su divulgación y es ideal para aquellas voces y discursos contrahegemónicos en la web y su supervivencia al paso del tiempo, preservando la memoria popular.

Cómo funciona el Fediverso en la moderación

El Fediverso intenta funcionar como comunidades en línea interconectadas que se autogobiernan en las formas de cuidados colectivos. Así, cada instancia podría ser algo así como un municipio que aloja diferentes cuentas/usuaries bajo unas reglas consensuadas y que pueden ser puestas en discusión si fuera necesario. De esta forma, es posible regular la circulación de contenidos fascistas y discursos de odio que puedan dañar no solamente la participación de diverses usuaries sino también su salud.

Para ello, cada instancia elige sus formas de moderación y puede excluir otras instancias con denuncias previas de contenidos antidemocráticos, odiantes o contrarios a los valores y cuidados de sus habitantes.

En Sutty en particular, nos interesan las estrategias y los mecanismos de cuidados colectivos, por lo que seguimos diseñando modelos que permitan sostenerlos en nuestras tecnologías. Podés revisar nuestros términos y condiciones, política de privacidad y acuerdos de convivencia para más información.

¿Te interesa participar?

Si sos parte de una organización social, grupo de activismo o colectivo social que pensás que podría beneficiarse de estas características, te invitamos a contactarnos a través de nuestro formulario. Estamos busando mejorar los usos de las tecnologías para ustedes y valoramos sus experiencias.

Otras posibilidades de integración de Social Inbox en sitios estáticos

Si te interesa incorporar esta funcionalidad para otros gestores de sitios estáticos, no dudes en contactarnos. Además, mantenete al tanto de las novedades que compartimos en https://dweb.sutty.nl y en nuestro blog https://sutty.nl/blog

Recomendado para saber más

\n"}, - "attachment"=> - [{"type"=>"Document", - "mediaType"=>"image/png", - "url"=>"https://sutty.nl/public/8r7b6ohqy6xzgngxbol6337q8jj9/milestone_2_activity_pub_2.png", - "name"=>"Botones de colores para activar la \"Web Disribuida\" y el \"Fediverso\"."}]} - + { '@context' => + ['https://www.w3.org/ns/activitystreams', + { 'ostatus' => 'http://ostatus.org#', + 'atomUri' => 'ostatus:atomUri', + 'inReplyToAtomUri' => 'ostatus:inReplyToAtomUri', + 'conversation' => 'ostatus:conversation', + 'sensitive' => 'as:sensitive', + 'toot' => 'http://joinmastodon.org/ns#', + 'votersCount' => 'toot:votersCount', + 'Hashtag' => 'as:Hashtag' }], + 'id' => 'https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041', + 'type' => 'Note', + 'summary' => nil, + 'inReplyTo' => 'https://mastodon.mauve.moe/users/mauve/statuses/111461923538534886', + 'published' => '2023-11-23T22:50:10Z', + 'url' => 'https://mastodon.mauve.moe/@mauve/111462305634770041', + 'attributedTo' => 'https://mastodon.mauve.moe/users/mauve', + 'to' => ['https://www.w3.org/ns/activitystreams#Public'], + 'cc' => ['https://mastodon.mauve.moe/users/mauve/followers', 'https://hypha.coop/about.jsonld'], + 'sensitive' => false, + 'atomUri' => 'https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041', + 'inReplyToAtomUri' => 'https://mastodon.mauve.moe/users/mauve/statuses/111461923538534886', + 'conversation' => 'tag:mastodon.mauve.moe,2023-11-23:objectId=551471:objectType=Conversation', + 'content' => + '

Follow @HyphaCoop@hypha.coop for our announcement post on the 5th!

', + 'contentMap' => + { 'en' => + '

Follow @HyphaCoop@hypha.coop for our announcement post on the 5th!

' }, + 'attachment' => [], + 'tag' => + [{ 'type' => 'Mention', 'href' => 'https://hypha.coop/about.jsonld', 'name' => '@dripline@hypha.coop' }, + { 'type' => 'Hashtag', 'href' => 'https://mastodon.mauve.moe/tags/p2p', 'name' => '#p2p' }, + { 'type' => 'Hashtag', 'href' => 'https://mastodon.mauve.moe/tags/activitypub', 'name' => '#activitypub' }, + { 'type' => 'Hashtag', 'href' => 'https://mastodon.mauve.moe/tags/fediverse', 'name' => '#fediverse' }], + 'replies' => + { 'id' => 'https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies', + 'type' => 'Collection', + 'first' => + { 'type' => 'CollectionPage', + 'next' => 'https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies?only_other_accounts=true&page=true', + 'partOf' => 'https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies', + 'items' => [] } } }, + { '@context' => ['https://www.w3.org/ns/activitystreams', { '@language' => 'es', 'sensitive' => 'as:sensitive' }], + 'type' => 'Note', + 'id' => 'https://sutty.nl/lanzamiento-de-publicaciones-distribuidas-en-el-fediverso-a-trav%C3%A9s-de-sutty/', + 'summary' => 'Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty', + 'published' => '2023-12-04T21:53:05+00:00', + 'updated' => '2023-12-05T20:41:34+00:00', + 'attributedTo' => 'https://sutty.nl/about.jsonld', + 'to' => ['https://www.w3.org/ns/activitystreams#Public'], + 'cc' => ['https://social.distributed.press/v1/@sutty@sutty.nl/followers'], + 'inReplyTo' => 'https://hypha.coop/dripline/announcing-dp-social-inbox/', + 'sensitive' => true, + 'content' => + "

Estamos felices y orgulloses de anunciar el lanzamiento de la funcionalidad que permite la publicación en el Fediverso de los artículos de todos los sitios creados a través de Sutty.

Gracias al trabajo conjunto con Distributed Press, Hypha y apoyado por la Filecoin Foundation for the Distributed Web, Sutty hace posible que la seguridad de tu sitio estático se combine con la rápida difusión de tu contenido a través de las redes sociales libres y descentralizadas que constituyen el Fediverso.

Esto se logró a través del desarollo y la integración de dos componentes, trabajados en forma conjunta y colaborativa:

    \n
  1. Social Inbox, desarrollado principalmente Distributed Press. Aporta la funcionalidad de recibir artículos, responder y mencionar otras cuentas en el Fediverso.

  2. \n
  3. Jekyll Activity Pub Plugin, desarrollado principalmente por Sutty. Permite integrar Social Inbox en todos los sitios estáticos generados en Jekyll, admitiendo así la publicación automática de contenido del sitio en el Fediverso.

  4. \n

Sutty integra la funcionalidad completa en su CMS para sitios estáticos en Jekyll, permitiendo gestionarla desde una interfaz en continua mejora de su usabilidad.

Si todavía no estás familiarizade con estos nombres y conceptos, te invitamos a conocer más a continuación, en la sección “Para tecno-curioses”.

Qué significa

    \n
  • Que si creás tu sitio web a través de Sutty, tenés nuevas posibilidades de difundir tus contenidos e interactuar en redes digitales.

  • \n
  • Que tus artículos pueden ser publicados en las redes del Fediverso.

  • \n
  • Que tu sitio tendrá un perfil o usuarie personalizable desde el panel en una instancia de Sutty propia.

  • \n
  • Que les usuaries del Fediverso pueden seguir tus publicaciones.

  • \n
  • Que les usuaries del Fediverso que te sigan podrán leer tus publicaciones, mencionarte y responderte.

  • \n
  • Que podrás interactuar con les usuaries del Fediverse con las opciones de responderles y mencionarles.

  • \n

Qué permite hacer

    \n
  • Activar la publicación en el Fediverso para todos los sitios de Sutty.

  • \n
  • Activar la publicación de los artículos que quieras en el Fediverso.

  • \n
  • Responder comentarios desde los artículos de tu sitio en Sutty.

  • \n
  • Personalizar la cuenta que Sutty crea automáticamente de tu sitio en el Fediverso.

  • \n
  • Reportar o informar de usuaries o instancias abusivos mediante nuestro formulario de contacto.

  • \n

Qué se viene

    \n
  • Mejoras en la integración de las respuestas como comentarios en el sitio.

  • \n
  • Incorporación de menciones desde el panel de Sutty.

  • \n
  • Mejoras en la interfaz general del panel.

  • \n
  • Nuevas implementaciones para una mejor moderación.

  • \n
  • Mejor compatibilidad con diversas redes en el Fediverso (Mastodon+Glitch, Pleroma, Ktistec).

  • \n
  • Mejoras que permitirán diferenciar el contenido a publicar en el Fediverso y en el sitio de Sutty.

  • \n
  • La posibilidad de exportar tu cuenta a una instancia del Fediverso desde tu panel.

  • \n
  • La posibilidad de que Sutty anuncie tu contenido y/o usuarie del Fediverse en forma automática para atraer seguidorxs. (Ahora, podés hacerlo a través de un formulario).

  • \n
  • Acceder a la lista de seguidorxs y seguides desde tu panel.

  • \n
  • Seguir, dejar de seguir, bloquear usuaries y/o instancias del Fediverso desde el panel.

  • \n

¡Quiero usarlo!

Te invitamos a dar tus primeros pasos de la mano de nuestro tutorial.

Para tecno-curioses

Cómo funciona

Los sitios web y las redes sociales parecen ser especies distintas dentro del Universo de Internet. Al mismo tiempo, las redes sociales corporativas y concentradas como Instagram, Facebook, X (ex Twitter), entre otras, demostraron ser hostiles con algunos grupos o colectivos sociales en particular (censurando contenido, persiguiendo pezones, ocultando publicaciones por color de piel y de pelo, etc.) y con todes sus usuaries en general (vendiendo data en forma masiva, violando acuerdos de privacidad, eligiendo diseños de interfaz y uso que generan ansiedad y adicción, etc.). Pese a esto, siguen funcionando como espacios obligados a la hora de publicitar un emprendimiento o difundir noticias urgentes.

El Fediverso es una red federada, descentralizada y distribuida de redes sociales libres, cada una con sus características, preferencias, grupos de usuaries. Están diseñadas para facilitar el diálogo entre todas ellas. Es decir, para que los contenidos puedan ser visibles y se puedan generar respuestas entre usuaries, fomentando una cultura de participación y pluralidad de voces, basadas en estándares de desarrollo libre y que buscan ser éticos antes que con fines de lucro sin fin.

Los sitios web siguen siendo formatos para medios de comunicación que, debido a sus características, favorecen la difusión de contenidos como artículos multimedia. Permiten adecuar un estilo a una identidad visual del medio, mantener secciones y contenido institucional variado, entre otras cosas.

Las redes sociales se destacan por sus características de inmediatez, favoreciendo un flujo dialógico en tiempo real con otros tiempos de atención y características de navegación que lo hacen más breve, rápido, a veces efímero. Los medios de comunicación (personas o emprendimientos mediáticos) suelen utilizarlos para llamar la atención sobre contenidos publicados en sus sitios, apostando a la divulgación rápida y las discusiones que puedan darse entre usuaries.

La funcionalidad que desarrollamos en Sutty contempla los casos de uso en los que un contenido quiera ser compartido a más personas, en menor tiempo, con la posibilidad de generar diálogos. Las particularidades de nuestros sitios y redes sociales libres generan condiciones favorables para la libertad de expresión, que preferimos llamar Derecho a la Comunicación, evadiendo las variadas y cada vez más sofisticadas formas de censura de las plataformas corporativas tradicionales. Un contenido reproducido en varios lugares al mismo tiempo ayuda a su divulgación y es ideal para aquellas voces y discursos contrahegemónicos en la web y su supervivencia al paso del tiempo, preservando la memoria popular.

Cómo funciona el Fediverso en la moderación

El Fediverso intenta funcionar como comunidades en línea interconectadas que se autogobiernan en las formas de cuidados colectivos. Así, cada instancia podría ser algo así como un municipio que aloja diferentes cuentas/usuaries bajo unas reglas consensuadas y que pueden ser puestas en discusión si fuera necesario. De esta forma, es posible regular la circulación de contenidos fascistas y discursos de odio que puedan dañar no solamente la participación de diverses usuaries sino también su salud.

Para ello, cada instancia elige sus formas de moderación y puede excluir otras instancias con denuncias previas de contenidos antidemocráticos, odiantes o contrarios a los valores y cuidados de sus habitantes.

En Sutty en particular, nos interesan las estrategias y los mecanismos de cuidados colectivos, por lo que seguimos diseñando modelos que permitan sostenerlos en nuestras tecnologías. Podés revisar nuestros términos y condiciones, política de privacidad y acuerdos de convivencia para más información.

¿Te interesa participar?

Si sos parte de una organización social, grupo de activismo o colectivo social que pensás que podría beneficiarse de estas características, te invitamos a contactarnos a través de nuestro formulario. Estamos busando mejorar los usos de las tecnologías para ustedes y valoramos sus experiencias.

Otras posibilidades de integración de Social Inbox en sitios estáticos

Si te interesa incorporar esta funcionalidad para otros gestores de sitios estáticos, no dudes en contactarnos. Además, mantenete al tanto de las novedades que compartimos en https://dweb.sutty.nl y en nuestro blog https://sutty.nl/blog

Recomendado para saber más

\n", + 'name' => 'Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty', + 'contentMap' => + { 'es' => + "

Estamos felices y orgulloses de anunciar el lanzamiento de la funcionalidad que permite la publicación en el Fediverso de los artículos de todos los sitios creados a través de Sutty.

Gracias al trabajo conjunto con Distributed Press, Hypha y apoyado por la Filecoin Foundation for the Distributed Web, Sutty hace posible que la seguridad de tu sitio estático se combine con la rápida difusión de tu contenido a través de las redes sociales libres y descentralizadas que constituyen el Fediverso.

Esto se logró a través del desarollo y la integración de dos componentes, trabajados en forma conjunta y colaborativa:

    \n
  1. Social Inbox, desarrollado principalmente Distributed Press. Aporta la funcionalidad de recibir artículos, responder y mencionar otras cuentas en el Fediverso.

  2. \n
  3. Jekyll Activity Pub Plugin, desarrollado principalmente por Sutty. Permite integrar Social Inbox en todos los sitios estáticos generados en Jekyll, admitiendo así la publicación automática de contenido del sitio en el Fediverso.

  4. \n

Sutty integra la funcionalidad completa en su CMS para sitios estáticos en Jekyll, permitiendo gestionarla desde una interfaz en continua mejora de su usabilidad.

Si todavía no estás familiarizade con estos nombres y conceptos, te invitamos a conocer más a continuación, en la sección “Para tecno-curioses”.

Qué significa

    \n
  • Que si creás tu sitio web a través de Sutty, tenés nuevas posibilidades de difundir tus contenidos e interactuar en redes digitales.

  • \n
  • Que tus artículos pueden ser publicados en las redes del Fediverso.

  • \n
  • Que tu sitio tendrá un perfil o usuarie personalizable desde el panel en una instancia de Sutty propia.

  • \n
  • Que les usuaries del Fediverso pueden seguir tus publicaciones.

  • \n
  • Que les usuaries del Fediverso que te sigan podrán leer tus publicaciones, mencionarte y responderte.

  • \n
  • Que podrás interactuar con les usuaries del Fediverse con las opciones de responderles y mencionarles.

  • \n

Qué permite hacer

    \n
  • Activar la publicación en el Fediverso para todos los sitios de Sutty.

  • \n
  • Activar la publicación de los artículos que quieras en el Fediverso.

  • \n
  • Responder comentarios desde los artículos de tu sitio en Sutty.

  • \n
  • Personalizar la cuenta que Sutty crea automáticamente de tu sitio en el Fediverso.

  • \n
  • Reportar o informar de usuaries o instancias abusivos mediante nuestro formulario de contacto.

  • \n

Qué se viene

    \n
  • Mejoras en la integración de las respuestas como comentarios en el sitio.

  • \n
  • Incorporación de menciones desde el panel de Sutty.

  • \n
  • Mejoras en la interfaz general del panel.

  • \n
  • Nuevas implementaciones para una mejor moderación.

  • \n
  • Mejor compatibilidad con diversas redes en el Fediverso (Mastodon+Glitch, Pleroma, Ktistec).

  • \n
  • Mejoras que permitirán diferenciar el contenido a publicar en el Fediverso y en el sitio de Sutty.

  • \n
  • La posibilidad de exportar tu cuenta a una instancia del Fediverso desde tu panel.

  • \n
  • La posibilidad de que Sutty anuncie tu contenido y/o usuarie del Fediverse en forma automática para atraer seguidorxs. (Ahora, podés hacerlo a través de un formulario).

  • \n
  • Acceder a la lista de seguidorxs y seguides desde tu panel.

  • \n
  • Seguir, dejar de seguir, bloquear usuaries y/o instancias del Fediverso desde el panel.

  • \n

¡Quiero usarlo!

Te invitamos a dar tus primeros pasos de la mano de nuestro tutorial.

Para tecno-curioses

Cómo funciona

Los sitios web y las redes sociales parecen ser especies distintas dentro del Universo de Internet. Al mismo tiempo, las redes sociales corporativas y concentradas como Instagram, Facebook, X (ex Twitter), entre otras, demostraron ser hostiles con algunos grupos o colectivos sociales en particular (censurando contenido, persiguiendo pezones, ocultando publicaciones por color de piel y de pelo, etc.) y con todes sus usuaries en general (vendiendo data en forma masiva, violando acuerdos de privacidad, eligiendo diseños de interfaz y uso que generan ansiedad y adicción, etc.). Pese a esto, siguen funcionando como espacios obligados a la hora de publicitar un emprendimiento o difundir noticias urgentes.

El Fediverso es una red federada, descentralizada y distribuida de redes sociales libres, cada una con sus características, preferencias, grupos de usuaries. Están diseñadas para facilitar el diálogo entre todas ellas. Es decir, para que los contenidos puedan ser visibles y se puedan generar respuestas entre usuaries, fomentando una cultura de participación y pluralidad de voces, basadas en estándares de desarrollo libre y que buscan ser éticos antes que con fines de lucro sin fin.

Los sitios web siguen siendo formatos para medios de comunicación que, debido a sus características, favorecen la difusión de contenidos como artículos multimedia. Permiten adecuar un estilo a una identidad visual del medio, mantener secciones y contenido institucional variado, entre otras cosas.

Las redes sociales se destacan por sus características de inmediatez, favoreciendo un flujo dialógico en tiempo real con otros tiempos de atención y características de navegación que lo hacen más breve, rápido, a veces efímero. Los medios de comunicación (personas o emprendimientos mediáticos) suelen utilizarlos para llamar la atención sobre contenidos publicados en sus sitios, apostando a la divulgación rápida y las discusiones que puedan darse entre usuaries.

La funcionalidad que desarrollamos en Sutty contempla los casos de uso en los que un contenido quiera ser compartido a más personas, en menor tiempo, con la posibilidad de generar diálogos. Las particularidades de nuestros sitios y redes sociales libres generan condiciones favorables para la libertad de expresión, que preferimos llamar Derecho a la Comunicación, evadiendo las variadas y cada vez más sofisticadas formas de censura de las plataformas corporativas tradicionales. Un contenido reproducido en varios lugares al mismo tiempo ayuda a su divulgación y es ideal para aquellas voces y discursos contrahegemónicos en la web y su supervivencia al paso del tiempo, preservando la memoria popular.

Cómo funciona el Fediverso en la moderación

El Fediverso intenta funcionar como comunidades en línea interconectadas que se autogobiernan en las formas de cuidados colectivos. Así, cada instancia podría ser algo así como un municipio que aloja diferentes cuentas/usuaries bajo unas reglas consensuadas y que pueden ser puestas en discusión si fuera necesario. De esta forma, es posible regular la circulación de contenidos fascistas y discursos de odio que puedan dañar no solamente la participación de diverses usuaries sino también su salud.

Para ello, cada instancia elige sus formas de moderación y puede excluir otras instancias con denuncias previas de contenidos antidemocráticos, odiantes o contrarios a los valores y cuidados de sus habitantes.

En Sutty en particular, nos interesan las estrategias y los mecanismos de cuidados colectivos, por lo que seguimos diseñando modelos que permitan sostenerlos en nuestras tecnologías. Podés revisar nuestros términos y condiciones, política de privacidad y acuerdos de convivencia para más información.

¿Te interesa participar?

Si sos parte de una organización social, grupo de activismo o colectivo social que pensás que podría beneficiarse de estas características, te invitamos a contactarnos a través de nuestro formulario. Estamos busando mejorar los usos de las tecnologías para ustedes y valoramos sus experiencias.

Otras posibilidades de integración de Social Inbox en sitios estáticos

Si te interesa incorporar esta funcionalidad para otros gestores de sitios estáticos, no dudes en contactarnos. Además, mantenete al tanto de las novedades que compartimos en https://dweb.sutty.nl y en nuestro blog https://sutty.nl/blog

Recomendado para saber más

\n" }, + 'attachment' => + [{ 'type' => 'Document', + 'mediaType' => 'image/png', + 'url' => 'https://sutty.nl/public/8r7b6ohqy6xzgngxbol6337q8jj9/milestone_2_activity_pub_2.png', + 'name' => 'Botones de colores para activar la "Web Disribuida" y el "Fediverso".' }] } ] - - end def update From 2a2878e4696645aee6c22e2d9301cd69a614db39 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 12 Jan 2024 17:55:15 -0300 Subject: [PATCH 012/472] =?UTF-8?q?refactor:=20cargar=20los=20datos=20desd?= =?UTF-8?q?e=20archivos=20m=C3=A1s=20legibles?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../moderation_queue_controller.rb | 366 +----------------- app/controllers/posts_controller.rb | 70 +--- db/seeds/instances.yaml | 285 ++++++++++++++ db/seeds/moderation_queue.yaml | 153 ++++++++ db/seeds/remote_profile.yaml | 106 +++++ 5 files changed, 548 insertions(+), 432 deletions(-) create mode 100644 db/seeds/instances.yaml create mode 100644 db/seeds/moderation_queue.yaml create mode 100644 db/seeds/remote_profile.yaml diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index 6d58baf0..eb39dae6 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -4,377 +4,17 @@ class ModerationQueueController < ApplicationController # Cola de moderación viendo todo el sitio def index - @moderation_queue = [ - - { '@context' => - ['https://www.w3.org/ns/activitystreams', - { 'ostatus' => 'http://ostatus.org#', - 'atomUri' => 'ostatus:atomUri', - 'inReplyToAtomUri' => 'ostatus:inReplyToAtomUri', - 'conversation' => 'ostatus:conversation', - 'sensitive' => 'as:sensitive', - 'toot' => 'http://joinmastodon.org/ns#', - 'votersCount' => 'toot:votersCount', - 'Hashtag' => 'as:Hashtag' }], - 'id' => 'https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041', - 'type' => 'Note', - 'summary' => nil, - 'inReplyTo' => 'https://mastodon.mauve.moe/users/mauve/statuses/111461923538534886', - 'published' => '2023-11-23T22:50:10Z', - 'url' => 'https://mastodon.mauve.moe/@mauve/111462305634770041', - 'attributedTo' => 'https://mastodon.mauve.moe/users/mauve', - 'to' => ['https://www.w3.org/ns/activitystreams#Public'], - 'cc' => ['https://mastodon.mauve.moe/users/mauve/followers', 'https://hypha.coop/about.jsonld'], - 'sensitive' => false, - 'atomUri' => 'https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041', - 'inReplyToAtomUri' => 'https://mastodon.mauve.moe/users/mauve/statuses/111461923538534886', - 'conversation' => 'tag:mastodon.mauve.moe,2023-11-23:objectId=551471:objectType=Conversation', - 'content' => - '

Follow @HyphaCoop@hypha.coop for our announcement post on the 5th!

', - 'contentMap' => - { 'en' => - '

Follow @HyphaCoop@hypha.coop for our announcement post on the 5th!

' }, - 'attachment' => [], - 'tag' => - [{ 'type' => 'Mention', 'href' => 'https://hypha.coop/about.jsonld', 'name' => '@dripline@hypha.coop' }, - { 'type' => 'Hashtag', 'href' => 'https://mastodon.mauve.moe/tags/p2p', 'name' => '#p2p' }, - { 'type' => 'Hashtag', 'href' => 'https://mastodon.mauve.moe/tags/activitypub', 'name' => '#activitypub' }, - { 'type' => 'Hashtag', 'href' => 'https://mastodon.mauve.moe/tags/fediverse', 'name' => '#fediverse' }], - 'replies' => - { 'id' => 'https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies', - 'type' => 'Collection', - 'first' => - { 'type' => 'CollectionPage', - 'next' => 'https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies?only_other_accounts=true&page=true', - 'partOf' => 'https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies', - 'items' => [] } } }, - { '@context' => ['https://www.w3.org/ns/activitystreams', { '@language' => 'es', 'sensitive' => 'as:sensitive' }], - 'type' => 'Note', - 'id' => 'https://sutty.nl/lanzamiento-de-publicaciones-distribuidas-en-el-fediverso-a-trav%C3%A9s-de-sutty/', - 'summary' => 'Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty', - 'published' => '2023-12-04T21:53:05+00:00', - 'updated' => '2023-12-05T20:41:34+00:00', - 'attributedTo' => 'https://sutty.nl/about.jsonld', - 'to' => ['https://www.w3.org/ns/activitystreams#Public'], - 'cc' => ['https://social.distributed.press/v1/@sutty@sutty.nl/followers'], - 'inReplyTo' => 'https://hypha.coop/dripline/announcing-dp-social-inbox/', - 'sensitive' => true, - 'content' => - "

Estamos felices y orgulloses de anunciar el lanzamiento de la funcionalidad que permite la publicación en el Fediverso de los artículos de todos los sitios creados a través de Sutty.

Gracias al trabajo conjunto con Distributed Press, Hypha y apoyado por la Filecoin Foundation for the Distributed Web, Sutty hace posible que la seguridad de tu sitio estático se combine con la rápida difusión de tu contenido a través de las redes sociales libres y descentralizadas que constituyen el Fediverso.

Esto se logró a través del desarollo y la integración de dos componentes, trabajados en forma conjunta y colaborativa:

    \n
  1. Social Inbox, desarrollado principalmente Distributed Press. Aporta la funcionalidad de recibir artículos, responder y mencionar otras cuentas en el Fediverso.

  2. \n
  3. Jekyll Activity Pub Plugin, desarrollado principalmente por Sutty. Permite integrar Social Inbox en todos los sitios estáticos generados en Jekyll, admitiendo así la publicación automática de contenido del sitio en el Fediverso.

  4. \n

Sutty integra la funcionalidad completa en su CMS para sitios estáticos en Jekyll, permitiendo gestionarla desde una interfaz en continua mejora de su usabilidad.

Si todavía no estás familiarizade con estos nombres y conceptos, te invitamos a conocer más a continuación, en la sección “Para tecno-curioses”.

Qué significa

    \n
  • Que si creás tu sitio web a través de Sutty, tenés nuevas posibilidades de difundir tus contenidos e interactuar en redes digitales.

  • \n
  • Que tus artículos pueden ser publicados en las redes del Fediverso.

  • \n
  • Que tu sitio tendrá un perfil o usuarie personalizable desde el panel en una instancia de Sutty propia.

  • \n
  • Que les usuaries del Fediverso pueden seguir tus publicaciones.

  • \n
  • Que les usuaries del Fediverso que te sigan podrán leer tus publicaciones, mencionarte y responderte.

  • \n
  • Que podrás interactuar con les usuaries del Fediverse con las opciones de responderles y mencionarles.

  • \n

Qué permite hacer

    \n
  • Activar la publicación en el Fediverso para todos los sitios de Sutty.

  • \n
  • Activar la publicación de los artículos que quieras en el Fediverso.

  • \n
  • Responder comentarios desde los artículos de tu sitio en Sutty.

  • \n
  • Personalizar la cuenta que Sutty crea automáticamente de tu sitio en el Fediverso.

  • \n
  • Reportar o informar de usuaries o instancias abusivos mediante nuestro formulario de contacto.

  • \n

Qué se viene

    \n
  • Mejoras en la integración de las respuestas como comentarios en el sitio.

  • \n
  • Incorporación de menciones desde el panel de Sutty.

  • \n
  • Mejoras en la interfaz general del panel.

  • \n
  • Nuevas implementaciones para una mejor moderación.

  • \n
  • Mejor compatibilidad con diversas redes en el Fediverso (Mastodon+Glitch, Pleroma, Ktistec).

  • \n
  • Mejoras que permitirán diferenciar el contenido a publicar en el Fediverso y en el sitio de Sutty.

  • \n
  • La posibilidad de exportar tu cuenta a una instancia del Fediverso desde tu panel.

  • \n
  • La posibilidad de que Sutty anuncie tu contenido y/o usuarie del Fediverse en forma automática para atraer seguidorxs. (Ahora, podés hacerlo a través de un formulario).

  • \n
  • Acceder a la lista de seguidorxs y seguides desde tu panel.

  • \n
  • Seguir, dejar de seguir, bloquear usuaries y/o instancias del Fediverso desde el panel.

  • \n

¡Quiero usarlo!

Te invitamos a dar tus primeros pasos de la mano de nuestro tutorial.

Para tecno-curioses

Cómo funciona

Los sitios web y las redes sociales parecen ser especies distintas dentro del Universo de Internet. Al mismo tiempo, las redes sociales corporativas y concentradas como Instagram, Facebook, X (ex Twitter), entre otras, demostraron ser hostiles con algunos grupos o colectivos sociales en particular (censurando contenido, persiguiendo pezones, ocultando publicaciones por color de piel y de pelo, etc.) y con todes sus usuaries en general (vendiendo data en forma masiva, violando acuerdos de privacidad, eligiendo diseños de interfaz y uso que generan ansiedad y adicción, etc.). Pese a esto, siguen funcionando como espacios obligados a la hora de publicitar un emprendimiento o difundir noticias urgentes.

El Fediverso es una red federada, descentralizada y distribuida de redes sociales libres, cada una con sus características, preferencias, grupos de usuaries. Están diseñadas para facilitar el diálogo entre todas ellas. Es decir, para que los contenidos puedan ser visibles y se puedan generar respuestas entre usuaries, fomentando una cultura de participación y pluralidad de voces, basadas en estándares de desarrollo libre y que buscan ser éticos antes que con fines de lucro sin fin.

Los sitios web siguen siendo formatos para medios de comunicación que, debido a sus características, favorecen la difusión de contenidos como artículos multimedia. Permiten adecuar un estilo a una identidad visual del medio, mantener secciones y contenido institucional variado, entre otras cosas.

Las redes sociales se destacan por sus características de inmediatez, favoreciendo un flujo dialógico en tiempo real con otros tiempos de atención y características de navegación que lo hacen más breve, rápido, a veces efímero. Los medios de comunicación (personas o emprendimientos mediáticos) suelen utilizarlos para llamar la atención sobre contenidos publicados en sus sitios, apostando a la divulgación rápida y las discusiones que puedan darse entre usuaries.

La funcionalidad que desarrollamos en Sutty contempla los casos de uso en los que un contenido quiera ser compartido a más personas, en menor tiempo, con la posibilidad de generar diálogos. Las particularidades de nuestros sitios y redes sociales libres generan condiciones favorables para la libertad de expresión, que preferimos llamar Derecho a la Comunicación, evadiendo las variadas y cada vez más sofisticadas formas de censura de las plataformas corporativas tradicionales. Un contenido reproducido en varios lugares al mismo tiempo ayuda a su divulgación y es ideal para aquellas voces y discursos contrahegemónicos en la web y su supervivencia al paso del tiempo, preservando la memoria popular.

Cómo funciona el Fediverso en la moderación

El Fediverso intenta funcionar como comunidades en línea interconectadas que se autogobiernan en las formas de cuidados colectivos. Así, cada instancia podría ser algo así como un municipio que aloja diferentes cuentas/usuaries bajo unas reglas consensuadas y que pueden ser puestas en discusión si fuera necesario. De esta forma, es posible regular la circulación de contenidos fascistas y discursos de odio que puedan dañar no solamente la participación de diverses usuaries sino también su salud.

Para ello, cada instancia elige sus formas de moderación y puede excluir otras instancias con denuncias previas de contenidos antidemocráticos, odiantes o contrarios a los valores y cuidados de sus habitantes.

En Sutty en particular, nos interesan las estrategias y los mecanismos de cuidados colectivos, por lo que seguimos diseñando modelos que permitan sostenerlos en nuestras tecnologías. Podés revisar nuestros términos y condiciones, política de privacidad y acuerdos de convivencia para más información.

¿Te interesa participar?

Si sos parte de una organización social, grupo de activismo o colectivo social que pensás que podría beneficiarse de estas características, te invitamos a contactarnos a través de nuestro formulario. Estamos busando mejorar los usos de las tecnologías para ustedes y valoramos sus experiencias.

Otras posibilidades de integración de Social Inbox en sitios estáticos

Si te interesa incorporar esta funcionalidad para otros gestores de sitios estáticos, no dudes en contactarnos. Además, mantenete al tanto de las novedades que compartimos en https://dweb.sutty.nl y en nuestro blog https://sutty.nl/blog

Recomendado para saber más

\n", - 'name' => 'Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty', - 'contentMap' => - { 'es' => - "

Estamos felices y orgulloses de anunciar el lanzamiento de la funcionalidad que permite la publicación en el Fediverso de los artículos de todos los sitios creados a través de Sutty.

Gracias al trabajo conjunto con Distributed Press, Hypha y apoyado por la Filecoin Foundation for the Distributed Web, Sutty hace posible que la seguridad de tu sitio estático se combine con la rápida difusión de tu contenido a través de las redes sociales libres y descentralizadas que constituyen el Fediverso.

Esto se logró a través del desarollo y la integración de dos componentes, trabajados en forma conjunta y colaborativa:

    \n
  1. Social Inbox, desarrollado principalmente Distributed Press. Aporta la funcionalidad de recibir artículos, responder y mencionar otras cuentas en el Fediverso.

  2. \n
  3. Jekyll Activity Pub Plugin, desarrollado principalmente por Sutty. Permite integrar Social Inbox en todos los sitios estáticos generados en Jekyll, admitiendo así la publicación automática de contenido del sitio en el Fediverso.

  4. \n

Sutty integra la funcionalidad completa en su CMS para sitios estáticos en Jekyll, permitiendo gestionarla desde una interfaz en continua mejora de su usabilidad.

Si todavía no estás familiarizade con estos nombres y conceptos, te invitamos a conocer más a continuación, en la sección “Para tecno-curioses”.

Qué significa

    \n
  • Que si creás tu sitio web a través de Sutty, tenés nuevas posibilidades de difundir tus contenidos e interactuar en redes digitales.

  • \n
  • Que tus artículos pueden ser publicados en las redes del Fediverso.

  • \n
  • Que tu sitio tendrá un perfil o usuarie personalizable desde el panel en una instancia de Sutty propia.

  • \n
  • Que les usuaries del Fediverso pueden seguir tus publicaciones.

  • \n
  • Que les usuaries del Fediverso que te sigan podrán leer tus publicaciones, mencionarte y responderte.

  • \n
  • Que podrás interactuar con les usuaries del Fediverse con las opciones de responderles y mencionarles.

  • \n

Qué permite hacer

    \n
  • Activar la publicación en el Fediverso para todos los sitios de Sutty.

  • \n
  • Activar la publicación de los artículos que quieras en el Fediverso.

  • \n
  • Responder comentarios desde los artículos de tu sitio en Sutty.

  • \n
  • Personalizar la cuenta que Sutty crea automáticamente de tu sitio en el Fediverso.

  • \n
  • Reportar o informar de usuaries o instancias abusivos mediante nuestro formulario de contacto.

  • \n

Qué se viene

    \n
  • Mejoras en la integración de las respuestas como comentarios en el sitio.

  • \n
  • Incorporación de menciones desde el panel de Sutty.

  • \n
  • Mejoras en la interfaz general del panel.

  • \n
  • Nuevas implementaciones para una mejor moderación.

  • \n
  • Mejor compatibilidad con diversas redes en el Fediverso (Mastodon+Glitch, Pleroma, Ktistec).

  • \n
  • Mejoras que permitirán diferenciar el contenido a publicar en el Fediverso y en el sitio de Sutty.

  • \n
  • La posibilidad de exportar tu cuenta a una instancia del Fediverso desde tu panel.

  • \n
  • La posibilidad de que Sutty anuncie tu contenido y/o usuarie del Fediverse en forma automática para atraer seguidorxs. (Ahora, podés hacerlo a través de un formulario).

  • \n
  • Acceder a la lista de seguidorxs y seguides desde tu panel.

  • \n
  • Seguir, dejar de seguir, bloquear usuaries y/o instancias del Fediverso desde el panel.

  • \n

¡Quiero usarlo!

Te invitamos a dar tus primeros pasos de la mano de nuestro tutorial.

Para tecno-curioses

Cómo funciona

Los sitios web y las redes sociales parecen ser especies distintas dentro del Universo de Internet. Al mismo tiempo, las redes sociales corporativas y concentradas como Instagram, Facebook, X (ex Twitter), entre otras, demostraron ser hostiles con algunos grupos o colectivos sociales en particular (censurando contenido, persiguiendo pezones, ocultando publicaciones por color de piel y de pelo, etc.) y con todes sus usuaries en general (vendiendo data en forma masiva, violando acuerdos de privacidad, eligiendo diseños de interfaz y uso que generan ansiedad y adicción, etc.). Pese a esto, siguen funcionando como espacios obligados a la hora de publicitar un emprendimiento o difundir noticias urgentes.

El Fediverso es una red federada, descentralizada y distribuida de redes sociales libres, cada una con sus características, preferencias, grupos de usuaries. Están diseñadas para facilitar el diálogo entre todas ellas. Es decir, para que los contenidos puedan ser visibles y se puedan generar respuestas entre usuaries, fomentando una cultura de participación y pluralidad de voces, basadas en estándares de desarrollo libre y que buscan ser éticos antes que con fines de lucro sin fin.

Los sitios web siguen siendo formatos para medios de comunicación que, debido a sus características, favorecen la difusión de contenidos como artículos multimedia. Permiten adecuar un estilo a una identidad visual del medio, mantener secciones y contenido institucional variado, entre otras cosas.

Las redes sociales se destacan por sus características de inmediatez, favoreciendo un flujo dialógico en tiempo real con otros tiempos de atención y características de navegación que lo hacen más breve, rápido, a veces efímero. Los medios de comunicación (personas o emprendimientos mediáticos) suelen utilizarlos para llamar la atención sobre contenidos publicados en sus sitios, apostando a la divulgación rápida y las discusiones que puedan darse entre usuaries.

La funcionalidad que desarrollamos en Sutty contempla los casos de uso en los que un contenido quiera ser compartido a más personas, en menor tiempo, con la posibilidad de generar diálogos. Las particularidades de nuestros sitios y redes sociales libres generan condiciones favorables para la libertad de expresión, que preferimos llamar Derecho a la Comunicación, evadiendo las variadas y cada vez más sofisticadas formas de censura de las plataformas corporativas tradicionales. Un contenido reproducido en varios lugares al mismo tiempo ayuda a su divulgación y es ideal para aquellas voces y discursos contrahegemónicos en la web y su supervivencia al paso del tiempo, preservando la memoria popular.

Cómo funciona el Fediverso en la moderación

El Fediverso intenta funcionar como comunidades en línea interconectadas que se autogobiernan en las formas de cuidados colectivos. Así, cada instancia podría ser algo así como un municipio que aloja diferentes cuentas/usuaries bajo unas reglas consensuadas y que pueden ser puestas en discusión si fuera necesario. De esta forma, es posible regular la circulación de contenidos fascistas y discursos de odio que puedan dañar no solamente la participación de diverses usuaries sino también su salud.

Para ello, cada instancia elige sus formas de moderación y puede excluir otras instancias con denuncias previas de contenidos antidemocráticos, odiantes o contrarios a los valores y cuidados de sus habitantes.

En Sutty en particular, nos interesan las estrategias y los mecanismos de cuidados colectivos, por lo que seguimos diseñando modelos que permitan sostenerlos en nuestras tecnologías. Podés revisar nuestros términos y condiciones, política de privacidad y acuerdos de convivencia para más información.

¿Te interesa participar?

Si sos parte de una organización social, grupo de activismo o colectivo social que pensás que podría beneficiarse de estas características, te invitamos a contactarnos a través de nuestro formulario. Estamos busando mejorar los usos de las tecnologías para ustedes y valoramos sus experiencias.

Otras posibilidades de integración de Social Inbox en sitios estáticos

Si te interesa incorporar esta funcionalidad para otros gestores de sitios estáticos, no dudes en contactarnos. Además, mantenete al tanto de las novedades que compartimos en https://dweb.sutty.nl y en nuestro blog https://sutty.nl/blog

Recomendado para saber más

\n" }, - 'attachment' => - [{ 'type' => 'Document', - 'mediaType' => 'image/png', - 'url' => 'https://sutty.nl/public/8r7b6ohqy6xzgngxbol6337q8jj9/milestone_2_activity_pub_2.png', - 'name' => 'Botones de colores para activar la "Web Disribuida" y el "Fediverso".' }] } - - ] + @moderation_queue = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'moderation_queue.yaml'))) end # Perfil remoto de usuarie def remote_profile - @remote_profile = { - '@context' => - [ - 'https://www.w3.org/ns/activitystreams', - 'https://w3id.org/security/v1', - { - 'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers', - 'toot' => 'http://joinmastodon.org/ns#', - 'featured' => { '@id' => 'toot:featured', '@type' => '@id' }, - 'featuredTags' => { '@id' => 'toot:featuredTags', '@type' => '@id' }, - 'alsoKnownAs' => { '@id' => 'as:alsoKnownAs', '@type' => '@id' }, - 'movedTo' => { '@id' => 'as:movedTo', '@type' => '@id' }, - 'schema' => 'http://schema.org#', - 'PropertyValue' => 'schema:PropertyValue', - 'value' => 'schema:value', - 'discoverable' => 'toot:discoverable', - 'Device' => 'toot:Device', - 'Ed25519Signature' => 'toot:Ed25519Signature', - 'Ed25519Key' => 'toot:Ed25519Key', - 'Curve25519Key' => 'toot:Curve25519Key', - 'EncryptedMessage' => 'toot:EncryptedMessage', - 'publicKeyBase64' => 'toot:publicKeyBase64', - 'deviceId' => 'toot:deviceId', - 'claim' => { '@type' => '@id', '@id' => 'toot:claim' }, - 'fingerprintKey' => { '@type' => '@id', '@id' => 'toot:fingerprintKey' }, - 'identityKey' => { '@type' => '@id', '@id' => 'toot:identityKey' }, - 'devices' => { '@type' => '@id', '@id' => 'toot:devices' }, - 'messageFranking' => 'toot:messageFranking', - 'messageType' => 'toot:messageType', - 'cipherText' => 'toot:cipherText', - 'suspended' => 'toot:suspended', - 'focalPoint' => { '@container' => '@list', '@id' => 'toot:focalPoint' } - } - ], - 'id' => 'https://mastodon.mauve.moe/users/mauve', - 'type' => 'Person', - 'following' => 'https://mastodon.mauve.moe/users/mauve/following', - 'followers' => 'https://mastodon.mauve.moe/users/mauve/followers', - 'inbox' => 'https://mastodon.mauve.moe/users/mauve/inbox', - 'outbox' => 'https://mastodon.mauve.moe/users/mauve/outbox', - 'featured' => 'https://mastodon.mauve.moe/users/mauve/collections/featured', - 'featuredTags' => 'https://mastodon.mauve.moe/users/mauve/collections/tags', - 'preferredUsername' => 'mauve', - 'name' => 'Mauve 👁💜', - 'summary' => - '

Occult Enby that's making local-first software with peer to peer protocols, mesh networks, and the web.

Also exploring what a local-first cyberspace might look like in my spare time.

', - 'url' => 'https://mastodon.mauve.moe/@mauve', - 'manuallyApprovesFollowers' => false, - 'discoverable' => true, - 'published' => '2022-04-25T00:00:00Z', - 'devices' => 'https://mastodon.mauve.moe/users/mauve/collections/devices', - 'alsoKnownAs' => ['https://infosec.exchange/users/RangerMauve'], - 'publicKey' => - { 'id' => 'https://mastodon.mauve.moe/users/mauve#main-key', - 'owner' => 'https://mastodon.mauve.moe/users/mauve', - 'publicKeyPem' => - "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxjxu6bRQOjH4caQu7JgZ\numIWFeX0ZdbVnofElev2d9JByqcDoWhmaks3RYdW71RDPNrr0JxqZvUbIw9kQBng\n7iQ9YTcXTdJ/N9CQoB22msffYkEIw4ilehCDXdchNs4aoVAUwI8IhkM0p/itz6gK\n75C3CQv74Y7rHUJC8ob2p4KUwRUyhgzyhp8QWwCAn/RZ28wP8EbjWF9IskMRo9vq\nWUX+Io6hpADRkSwZGoOSW2zxCEBVco6tRmABTte8I0WcAucLyMEyfGMlUvxRew4D\nzAWoEBS8SyqM68vUabbZYLns6kya34tvsf1NkvajDGrfgU3D0LlGX++tOa6N9Pkf\nXwIDAQAB\n-----END PUBLIC KEY-----\n" }, - 'tag' => [], - 'attachment' => - [{ 'type' => 'PropertyValue', 'name' => 'Pronouns', 'value' => 'they/them/it' }, - { 'type' => 'PropertyValue', 'name' => 'Email', 'value' => 'mauve@mauve.moe' }, - { 'type' => 'PropertyValue', - 'name' => 'Matrix', - 'value' => - '@mauve:mauve.moe' }, - { 'type' => 'PropertyValue', 'name' => 'Github/Twitter', 'value' => '@RangerMauve' }], - 'endpoints' => { 'sharedInbox' => 'https://mastodon.mauve.moe/inbox' }, - 'icon' => - { 'type' => 'Image', - 'mediaType' => 'image/png', - 'url' => 'https://mastodon.mauve.moe/system/accounts/avatars/000/000/002/original/e4b910cee121b1b8.png' }, - 'image' => - { 'type' => 'Image', - 'mediaType' => 'image/png', - 'url' => 'https://mastodon.mauve.moe/system/accounts/headers/000/000/002/original/a96f990025091662.png' } - } + @remote_profile = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'remote_profile.yaml'))) end # todon.nl está usando /api/v2/instance # mauve.moe usa /api/v1/instance def instances - @instances = [ - { 'domain' => 'todon.nl', - 'title' => 'Todon.nl', - 'version' => '4.2.3', - 'source_url' => 'https://github.com/mastodon/mastodon', - 'description' => - 'Radicaal linkse anti-autoritaire server. Voor anarchisten, socialisten, (klimaat)activisten, LHBTQIA+, antiracisten, antifascisten, antikapitalisten, intersectionelen, veganisten, mensenrechten, enz.', - 'usage' => { 'users' => { 'active_month' => 372 } }, - 'thumbnail' => - { 'url' => 'https://todon.nl/system/site_uploads/files/000/000/004/@1x/297e509bc8a81f62.png', - 'blurhash' => 'UXAw3zN4M|xsoga#WBay9DxntQRmITocofWE', - 'versions' => - { '@1x' => 'https://todon.nl/system/site_uploads/files/000/000/004/@1x/297e509bc8a81f62.png', - '@2x' => 'https://todon.nl/system/site_uploads/files/000/000/004/@2x/297e509bc8a81f62.png' } }, - 'languages' => ['en'], - 'configuration' => - { 'urls' => { 'streaming' => 'wss://todon.nl', 'status' => 'https://status.todon.eu' }, - 'accounts' => { 'max_featured_tags' => 10 }, - 'statuses' => { 'max_characters' => 1312, 'max_media_attachments' => 4, 'characters_reserved_per_url' => 23 }, - 'media_attachments' => - { 'supported_mime_types' => - ['image/jpeg', - 'image/png', - 'image/gif', - 'image/heic', - 'image/heif', - 'image/webp', - 'image/avif', - 'video/webm', - 'video/mp4', - 'video/quicktime', - 'video/ogg', - 'audio/wave', - 'audio/wav', - 'audio/x-wav', - 'audio/x-pn-wave', - 'audio/vnd.wave', - 'audio/ogg', - 'audio/vorbis', - 'audio/mpeg', - 'audio/mp3', - 'audio/webm', - 'audio/flac', - 'audio/aac', - 'audio/m4a', - 'audio/x-m4a', - 'audio/mp4', - 'audio/3gpp', - 'video/x-ms-asf'], - 'image_size_limit' => 16_777_216, - 'image_matrix_limit' => 33_177_600, - 'video_size_limit' => 103_809_024, - 'video_frame_rate_limit' => 120, - 'video_matrix_limit' => 8_294_400 }, - 'polls' => { 'max_options' => 4, 'max_characters_per_option' => 50, 'min_expiration' => 300, - 'max_expiration' => 2_629_746 }, - 'translation' => { 'enabled' => true } }, - 'registrations' => - { 'enabled' => false, - 'approval_required' => false, - 'message' => - "

¡No pasarán!

\n\n

Je kunt tijdelijk geen nieuw account op Todon.nl aanvragen.

\n\n\n\n

Ga naar joinmastodon.org of FediDB Network om een andere server te vinden.

\n\n

It is temporary not possible to request on account on Todon.nl.

\n\n\n\n

Go to joinmastodon.org or FediDB Network to find another server.

\n", - 'url' => nil }, - 'max_toot_chars' => 1312, - 'contact' => - { 'email' => 'todon@posteo.eu', - 'account' => - { 'id' => '1', - 'username' => 'admin', - 'acct' => 'admin', - 'display_name' => 'Admin 🤓 Todon.nl (mod)', - 'locked' => false, - 'bot' => false, - 'discoverable' => false, - 'group' => false, - 'created_at' => '2017-04-28T00:00:00.000Z', - 'note' => - '

This account is used for 🎙 Todon.nl announcements and ⚖️ moderation.

🚫 Don't follow this account when you are not on Todon.nl.

New? First read our 👩‍🏫 Todon 101 👩‍🎓 at wiki.todon.eu/todon/101

⚖️ For all our moderators go to wiki.todon.nl/todon/moderators

📝 Public toots from this account are in English.

🔕 Criticism is fine, but people who do false accusations are muted.

✉ todon@posteo.eu

', - 'url' => 'https://todon.nl/@admin', - 'uri' => 'https://todon.nl/users/admin', - 'avatar' => 'https://todon.nl/system/accounts/avatars/000/000/001/original/2db61726225ed3e6.png', - 'avatar_static' => 'https://todon.nl/system/accounts/avatars/000/000/001/original/2db61726225ed3e6.png', - 'header' => 'https://todon.nl/system/accounts/headers/000/000/001/original/fb3a846cbc20aa09.png', - 'header_static' => 'https://todon.nl/system/accounts/headers/000/000/001/original/fb3a846cbc20aa09.png', - 'followers_count' => 3164, - 'following_count' => 8, - 'statuses_count' => 724, - 'last_status_at' => '2024-01-12', - 'noindex' => true, - 'emojis' => [], - 'roles' => [{ 'id' => '3', 'name' => 'Admin', 'color' => '#595aff' }], - 'fields' => - [{ 'name' => '📜 Terms of Service', - 'value' => - 'wiki.todon.nl/todon/terms_en', - 'verified_at' => '2018-11-01T14:39:45.465+00:00' }, - { 'name' => 'ℹ️ Wiki', - 'value' => - 'wiki.todon.nl/todon/informatio', - 'verified_at' => '2018-11-01T14:40:54.679+00:00' }, - { 'name' => '📊 Status', - 'value' => - 'status.todon.eu', - 'verified_at' => '2023-10-26T20:38:30.185+00:00' }, - { 'name' => '💳️ Donations', - 'value' => - 'wiki.todon.eu/todon/donations', - 'verified_at' => '2022-11-02T00:06:31.865+00:00' }] } }, - 'rules' => - [{ 'id' => '1', - 'text' => - 'We do not accept racism (in all its forms, incl. hate against Muslims, antisemitism, apartheid and casteism - see our Terms of Service for our complete definition).' }, - { 'id' => '2', - 'text' => - 'We do not accept hate against lesbians, gays, bisexuals, pansexuals, transgenders, non-binary people, intersexual people, queer people in general, etc.' }, - { 'id' => '4', 'text' => 'Sexism, misogyny and hate against black women (misogynoir).' }, - { 'id' => '6', - 'text' => 'We do not accept ableism (incl. COVID-19 denial/downplaying and anti-vax) and body-shaming.' }, - { 'id' => '8', 'text' => 'We do not accept harassment and trolling.' }, - { 'id' => '10', 'text' => 'We also do not accept other forms of hate speech.' }, - { 'id' => '11', - 'text' => 'We do not accept (sexual) abuse of minors, adults and animals (also not virtual).' }, - { 'id' => '13', - 'text' => 'We do not accept glorification of violence, calls for murder, death threats, terrorism and militarism.' }, - { 'id' => '15', - 'text' => - 'We do not accept (neo)colonialism (incl. Zionism), imperialism in all forms and nationalism (above all nationalism of nation states, incl. flags/symbols of those on Todon.*, see our Terms of Service).' }, - { 'id' => '16', - 'text' => 'We do not accept fascism, right-wing populism, and right-wing and religious extremism.' }, - { 'id' => '17', - 'text' => 'We do not accept evangelisation and other forms of religious propaganda [local only], and extreme sects and cults.' }, - { 'id' => '19', - 'text' => - 'We do not accept Marxist-Leninists, Stalinists, Maoists or other followers of extreme authoritarian (so called) communist/socialist ideologies/regimes (aka tankies).' }, - { 'id' => '20', - 'text' => "We do not accept capitalists, including so called 'anarcho-capitalists' (aka ancaps) and neoliberals." }, - { 'id' => '21', - 'text' => - 'We do not accept anthropogenic climate change denial, downplaying the climate crisis, greenwashing and deceptive climate solutions (like nuclear energy).' }, - { 'id' => '27', - 'text' => "We do not accept (right-wing) conspiracy 'theories', hoaxes, fake news and other forms of disinformation." }, - { 'id' => '28', - 'text' => 'Another rule in our terms of service at wiki.todon.eu/todon/terms_en. Explain in the final step.' }] }, - { 'uri' => 'mastodon.mauve.moe', - 'title' => 'Mauvestodon', - 'short_description' => 'Escape ship from centralized social media run by Mauve.', - 'description' => 'Chat about random techie and anarchist stuff.', - 'email' => 'contact@mauve.moe', - 'version' => '3.5.10', - 'urls' => { 'streaming_api' => 'wss://mastodon.mauve.moe' }, - 'stats' => { 'user_count' => 12, 'status_count' => 3287, 'domain_count' => 11_625 }, - 'thumbnail' => 'https://mastodon.mauve.moe/system/site_uploads/files/000/000/001/original/mauvesoftwareinc.png', - 'languages' => ['en'], - 'registrations' => false, - 'approval_required' => false, - 'invites_enabled' => true, - 'configuration' => - { 'statuses' => { 'max_characters' => 500, 'max_media_attachments' => 4, 'characters_reserved_per_url' => 23 }, - 'media_attachments' => - { 'supported_mime_types' => - ['image/jpeg', - 'image/png', - 'image/gif', - 'video/webm', - 'video/mp4', - 'video/quicktime', - 'video/ogg', - 'audio/wave', - 'audio/wav', - 'audio/x-wav', - 'audio/x-pn-wave', - 'audio/ogg', - 'audio/vorbis', - 'audio/mpeg', - 'audio/mp3', - 'audio/webm', - 'audio/flac', - 'audio/aac', - 'audio/m4a', - 'audio/x-m4a', - 'audio/mp4', - 'audio/3gpp', - 'video/x-ms-asf'], - 'image_size_limit' => 10_485_760, - 'image_matrix_limit' => 16_777_216, - 'video_size_limit' => 41_943_040, - 'video_frame_rate_limit' => 60, - 'video_matrix_limit' => 2_304_000 }, - 'polls' => { 'max_options' => 4, 'max_characters_per_option' => 50, 'min_expiration' => 300, - 'max_expiration' => 2_629_746 } }, - 'contact_account' => - { 'id' => '1', - 'username' => 'admin', - 'acct' => 'admin', - 'display_name' => '', - 'locked' => false, - 'bot' => false, - 'discoverable' => true, - 'group' => false, - 'created_at' => '2022-04-25T00:00:00.000Z', - 'note' => '', - 'url' => 'https://mastodon.mauve.moe/@admin', - 'avatar' => 'https://mastodon.mauve.moe/system/accounts/avatars/000/000/001/original/8c21e71667b48a95.png', - 'avatar_static' => 'https://mastodon.mauve.moe/system/accounts/avatars/000/000/001/original/8c21e71667b48a95.png', - 'header' => 'https://mastodon.mauve.moe/headers/original/missing.png', - 'header_static' => 'https://mastodon.mauve.moe/headers/original/missing.png', - 'followers_count' => 0, - 'following_count' => 0, - 'statuses_count' => 0, - 'last_status_at' => '2023-01-30', - 'emojis' => [], - 'fields' => - [{ 'name' => 'Alternatel Contact', - 'value' => - '@mauve', - 'verified_at' => nil }] }, - 'rules' => [] } - - ] + @instances = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'instances.yaml'))) end end diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 1bc94ec1..d572e052 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -38,6 +38,7 @@ class PostsController < ApplicationController @usuarie = site.usuarie? current_usuarie @site_stat = SiteStat.new(site) + @moderation_queue = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'moderation_queue.yaml'))) end def show @@ -81,75 +82,6 @@ class PostsController < ApplicationController authorize post breadcrumb post.title.value, site_post_path(site, post, locale: locale), match: :exact breadcrumb 'posts.edit', '' - - @moderation_queue = [ - - { '@context' => - ['https://www.w3.org/ns/activitystreams', - { 'ostatus' => 'http://ostatus.org#', - 'atomUri' => 'ostatus:atomUri', - 'inReplyToAtomUri' => 'ostatus:inReplyToAtomUri', - 'conversation' => 'ostatus:conversation', - 'sensitive' => 'as:sensitive', - 'toot' => 'http://joinmastodon.org/ns#', - 'votersCount' => 'toot:votersCount', - 'Hashtag' => 'as:Hashtag' }], - 'id' => 'https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041', - 'type' => 'Note', - 'summary' => nil, - 'inReplyTo' => 'https://mastodon.mauve.moe/users/mauve/statuses/111461923538534886', - 'published' => '2023-11-23T22:50:10Z', - 'url' => 'https://mastodon.mauve.moe/@mauve/111462305634770041', - 'attributedTo' => 'https://mastodon.mauve.moe/users/mauve', - 'to' => ['https://www.w3.org/ns/activitystreams#Public'], - 'cc' => ['https://mastodon.mauve.moe/users/mauve/followers', 'https://hypha.coop/about.jsonld'], - 'sensitive' => false, - 'atomUri' => 'https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041', - 'inReplyToAtomUri' => 'https://mastodon.mauve.moe/users/mauve/statuses/111461923538534886', - 'conversation' => 'tag:mastodon.mauve.moe,2023-11-23:objectId=551471:objectType=Conversation', - 'content' => - '

Follow @HyphaCoop@hypha.coop for our announcement post on the 5th!

', - 'contentMap' => - { 'en' => - '

Follow @HyphaCoop@hypha.coop for our announcement post on the 5th!

' }, - 'attachment' => [], - 'tag' => - [{ 'type' => 'Mention', 'href' => 'https://hypha.coop/about.jsonld', 'name' => '@dripline@hypha.coop' }, - { 'type' => 'Hashtag', 'href' => 'https://mastodon.mauve.moe/tags/p2p', 'name' => '#p2p' }, - { 'type' => 'Hashtag', 'href' => 'https://mastodon.mauve.moe/tags/activitypub', 'name' => '#activitypub' }, - { 'type' => 'Hashtag', 'href' => 'https://mastodon.mauve.moe/tags/fediverse', 'name' => '#fediverse' }], - 'replies' => - { 'id' => 'https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies', - 'type' => 'Collection', - 'first' => - { 'type' => 'CollectionPage', - 'next' => 'https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies?only_other_accounts=true&page=true', - 'partOf' => 'https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies', - 'items' => [] } } }, - { '@context' => ['https://www.w3.org/ns/activitystreams', { '@language' => 'es', 'sensitive' => 'as:sensitive' }], - 'type' => 'Note', - 'id' => 'https://sutty.nl/lanzamiento-de-publicaciones-distribuidas-en-el-fediverso-a-trav%C3%A9s-de-sutty/', - 'summary' => 'Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty', - 'published' => '2023-12-04T21:53:05+00:00', - 'updated' => '2023-12-05T20:41:34+00:00', - 'attributedTo' => 'https://sutty.nl/about.jsonld', - 'to' => ['https://www.w3.org/ns/activitystreams#Public'], - 'cc' => ['https://social.distributed.press/v1/@sutty@sutty.nl/followers'], - 'inReplyTo' => 'https://hypha.coop/dripline/announcing-dp-social-inbox/', - 'sensitive' => true, - 'content' => - "

Estamos felices y orgulloses de anunciar el lanzamiento de la funcionalidad que permite la publicación en el Fediverso de los artículos de todos los sitios creados a través de Sutty.

Gracias al trabajo conjunto con Distributed Press, Hypha y apoyado por la Filecoin Foundation for the Distributed Web, Sutty hace posible que la seguridad de tu sitio estático se combine con la rápida difusión de tu contenido a través de las redes sociales libres y descentralizadas que constituyen el Fediverso.

Esto se logró a través del desarollo y la integración de dos componentes, trabajados en forma conjunta y colaborativa:

    \n
  1. Social Inbox, desarrollado principalmente Distributed Press. Aporta la funcionalidad de recibir artículos, responder y mencionar otras cuentas en el Fediverso.

  2. \n
  3. Jekyll Activity Pub Plugin, desarrollado principalmente por Sutty. Permite integrar Social Inbox en todos los sitios estáticos generados en Jekyll, admitiendo así la publicación automática de contenido del sitio en el Fediverso.

  4. \n

Sutty integra la funcionalidad completa en su CMS para sitios estáticos en Jekyll, permitiendo gestionarla desde una interfaz en continua mejora de su usabilidad.

Si todavía no estás familiarizade con estos nombres y conceptos, te invitamos a conocer más a continuación, en la sección “Para tecno-curioses”.

Qué significa

    \n
  • Que si creás tu sitio web a través de Sutty, tenés nuevas posibilidades de difundir tus contenidos e interactuar en redes digitales.

  • \n
  • Que tus artículos pueden ser publicados en las redes del Fediverso.

  • \n
  • Que tu sitio tendrá un perfil o usuarie personalizable desde el panel en una instancia de Sutty propia.

  • \n
  • Que les usuaries del Fediverso pueden seguir tus publicaciones.

  • \n
  • Que les usuaries del Fediverso que te sigan podrán leer tus publicaciones, mencionarte y responderte.

  • \n
  • Que podrás interactuar con les usuaries del Fediverse con las opciones de responderles y mencionarles.

  • \n

Qué permite hacer

    \n
  • Activar la publicación en el Fediverso para todos los sitios de Sutty.

  • \n
  • Activar la publicación de los artículos que quieras en el Fediverso.

  • \n
  • Responder comentarios desde los artículos de tu sitio en Sutty.

  • \n
  • Personalizar la cuenta que Sutty crea automáticamente de tu sitio en el Fediverso.

  • \n
  • Reportar o informar de usuaries o instancias abusivos mediante nuestro formulario de contacto.

  • \n

Qué se viene

    \n
  • Mejoras en la integración de las respuestas como comentarios en el sitio.

  • \n
  • Incorporación de menciones desde el panel de Sutty.

  • \n
  • Mejoras en la interfaz general del panel.

  • \n
  • Nuevas implementaciones para una mejor moderación.

  • \n
  • Mejor compatibilidad con diversas redes en el Fediverso (Mastodon+Glitch, Pleroma, Ktistec).

  • \n
  • Mejoras que permitirán diferenciar el contenido a publicar en el Fediverso y en el sitio de Sutty.

  • \n
  • La posibilidad de exportar tu cuenta a una instancia del Fediverso desde tu panel.

  • \n
  • La posibilidad de que Sutty anuncie tu contenido y/o usuarie del Fediverse en forma automática para atraer seguidorxs. (Ahora, podés hacerlo a través de un formulario).

  • \n
  • Acceder a la lista de seguidorxs y seguides desde tu panel.

  • \n
  • Seguir, dejar de seguir, bloquear usuaries y/o instancias del Fediverso desde el panel.

  • \n

¡Quiero usarlo!

Te invitamos a dar tus primeros pasos de la mano de nuestro tutorial.

Para tecno-curioses

Cómo funciona

Los sitios web y las redes sociales parecen ser especies distintas dentro del Universo de Internet. Al mismo tiempo, las redes sociales corporativas y concentradas como Instagram, Facebook, X (ex Twitter), entre otras, demostraron ser hostiles con algunos grupos o colectivos sociales en particular (censurando contenido, persiguiendo pezones, ocultando publicaciones por color de piel y de pelo, etc.) y con todes sus usuaries en general (vendiendo data en forma masiva, violando acuerdos de privacidad, eligiendo diseños de interfaz y uso que generan ansiedad y adicción, etc.). Pese a esto, siguen funcionando como espacios obligados a la hora de publicitar un emprendimiento o difundir noticias urgentes.

El Fediverso es una red federada, descentralizada y distribuida de redes sociales libres, cada una con sus características, preferencias, grupos de usuaries. Están diseñadas para facilitar el diálogo entre todas ellas. Es decir, para que los contenidos puedan ser visibles y se puedan generar respuestas entre usuaries, fomentando una cultura de participación y pluralidad de voces, basadas en estándares de desarrollo libre y que buscan ser éticos antes que con fines de lucro sin fin.

Los sitios web siguen siendo formatos para medios de comunicación que, debido a sus características, favorecen la difusión de contenidos como artículos multimedia. Permiten adecuar un estilo a una identidad visual del medio, mantener secciones y contenido institucional variado, entre otras cosas.

Las redes sociales se destacan por sus características de inmediatez, favoreciendo un flujo dialógico en tiempo real con otros tiempos de atención y características de navegación que lo hacen más breve, rápido, a veces efímero. Los medios de comunicación (personas o emprendimientos mediáticos) suelen utilizarlos para llamar la atención sobre contenidos publicados en sus sitios, apostando a la divulgación rápida y las discusiones que puedan darse entre usuaries.

La funcionalidad que desarrollamos en Sutty contempla los casos de uso en los que un contenido quiera ser compartido a más personas, en menor tiempo, con la posibilidad de generar diálogos. Las particularidades de nuestros sitios y redes sociales libres generan condiciones favorables para la libertad de expresión, que preferimos llamar Derecho a la Comunicación, evadiendo las variadas y cada vez más sofisticadas formas de censura de las plataformas corporativas tradicionales. Un contenido reproducido en varios lugares al mismo tiempo ayuda a su divulgación y es ideal para aquellas voces y discursos contrahegemónicos en la web y su supervivencia al paso del tiempo, preservando la memoria popular.

Cómo funciona el Fediverso en la moderación

El Fediverso intenta funcionar como comunidades en línea interconectadas que se autogobiernan en las formas de cuidados colectivos. Así, cada instancia podría ser algo así como un municipio que aloja diferentes cuentas/usuaries bajo unas reglas consensuadas y que pueden ser puestas en discusión si fuera necesario. De esta forma, es posible regular la circulación de contenidos fascistas y discursos de odio que puedan dañar no solamente la participación de diverses usuaries sino también su salud.

Para ello, cada instancia elige sus formas de moderación y puede excluir otras instancias con denuncias previas de contenidos antidemocráticos, odiantes o contrarios a los valores y cuidados de sus habitantes.

En Sutty en particular, nos interesan las estrategias y los mecanismos de cuidados colectivos, por lo que seguimos diseñando modelos que permitan sostenerlos en nuestras tecnologías. Podés revisar nuestros términos y condiciones, política de privacidad y acuerdos de convivencia para más información.

¿Te interesa participar?

Si sos parte de una organización social, grupo de activismo o colectivo social que pensás que podría beneficiarse de estas características, te invitamos a contactarnos a través de nuestro formulario. Estamos busando mejorar los usos de las tecnologías para ustedes y valoramos sus experiencias.

Otras posibilidades de integración de Social Inbox en sitios estáticos

Si te interesa incorporar esta funcionalidad para otros gestores de sitios estáticos, no dudes en contactarnos. Además, mantenete al tanto de las novedades que compartimos en https://dweb.sutty.nl y en nuestro blog https://sutty.nl/blog

Recomendado para saber más

\n", - 'name' => 'Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty', - 'contentMap' => - { 'es' => - "

Estamos felices y orgulloses de anunciar el lanzamiento de la funcionalidad que permite la publicación en el Fediverso de los artículos de todos los sitios creados a través de Sutty.

Gracias al trabajo conjunto con Distributed Press, Hypha y apoyado por la Filecoin Foundation for the Distributed Web, Sutty hace posible que la seguridad de tu sitio estático se combine con la rápida difusión de tu contenido a través de las redes sociales libres y descentralizadas que constituyen el Fediverso.

Esto se logró a través del desarollo y la integración de dos componentes, trabajados en forma conjunta y colaborativa:

    \n
  1. Social Inbox, desarrollado principalmente Distributed Press. Aporta la funcionalidad de recibir artículos, responder y mencionar otras cuentas en el Fediverso.

  2. \n
  3. Jekyll Activity Pub Plugin, desarrollado principalmente por Sutty. Permite integrar Social Inbox en todos los sitios estáticos generados en Jekyll, admitiendo así la publicación automática de contenido del sitio en el Fediverso.

  4. \n

Sutty integra la funcionalidad completa en su CMS para sitios estáticos en Jekyll, permitiendo gestionarla desde una interfaz en continua mejora de su usabilidad.

Si todavía no estás familiarizade con estos nombres y conceptos, te invitamos a conocer más a continuación, en la sección “Para tecno-curioses”.

Qué significa

    \n
  • Que si creás tu sitio web a través de Sutty, tenés nuevas posibilidades de difundir tus contenidos e interactuar en redes digitales.

  • \n
  • Que tus artículos pueden ser publicados en las redes del Fediverso.

  • \n
  • Que tu sitio tendrá un perfil o usuarie personalizable desde el panel en una instancia de Sutty propia.

  • \n
  • Que les usuaries del Fediverso pueden seguir tus publicaciones.

  • \n
  • Que les usuaries del Fediverso que te sigan podrán leer tus publicaciones, mencionarte y responderte.

  • \n
  • Que podrás interactuar con les usuaries del Fediverse con las opciones de responderles y mencionarles.

  • \n

Qué permite hacer

    \n
  • Activar la publicación en el Fediverso para todos los sitios de Sutty.

  • \n
  • Activar la publicación de los artículos que quieras en el Fediverso.

  • \n
  • Responder comentarios desde los artículos de tu sitio en Sutty.

  • \n
  • Personalizar la cuenta que Sutty crea automáticamente de tu sitio en el Fediverso.

  • \n
  • Reportar o informar de usuaries o instancias abusivos mediante nuestro formulario de contacto.

  • \n

Qué se viene

    \n
  • Mejoras en la integración de las respuestas como comentarios en el sitio.

  • \n
  • Incorporación de menciones desde el panel de Sutty.

  • \n
  • Mejoras en la interfaz general del panel.

  • \n
  • Nuevas implementaciones para una mejor moderación.

  • \n
  • Mejor compatibilidad con diversas redes en el Fediverso (Mastodon+Glitch, Pleroma, Ktistec).

  • \n
  • Mejoras que permitirán diferenciar el contenido a publicar en el Fediverso y en el sitio de Sutty.

  • \n
  • La posibilidad de exportar tu cuenta a una instancia del Fediverso desde tu panel.

  • \n
  • La posibilidad de que Sutty anuncie tu contenido y/o usuarie del Fediverse en forma automática para atraer seguidorxs. (Ahora, podés hacerlo a través de un formulario).

  • \n
  • Acceder a la lista de seguidorxs y seguides desde tu panel.

  • \n
  • Seguir, dejar de seguir, bloquear usuaries y/o instancias del Fediverso desde el panel.

  • \n

¡Quiero usarlo!

Te invitamos a dar tus primeros pasos de la mano de nuestro tutorial.

Para tecno-curioses

Cómo funciona

Los sitios web y las redes sociales parecen ser especies distintas dentro del Universo de Internet. Al mismo tiempo, las redes sociales corporativas y concentradas como Instagram, Facebook, X (ex Twitter), entre otras, demostraron ser hostiles con algunos grupos o colectivos sociales en particular (censurando contenido, persiguiendo pezones, ocultando publicaciones por color de piel y de pelo, etc.) y con todes sus usuaries en general (vendiendo data en forma masiva, violando acuerdos de privacidad, eligiendo diseños de interfaz y uso que generan ansiedad y adicción, etc.). Pese a esto, siguen funcionando como espacios obligados a la hora de publicitar un emprendimiento o difundir noticias urgentes.

El Fediverso es una red federada, descentralizada y distribuida de redes sociales libres, cada una con sus características, preferencias, grupos de usuaries. Están diseñadas para facilitar el diálogo entre todas ellas. Es decir, para que los contenidos puedan ser visibles y se puedan generar respuestas entre usuaries, fomentando una cultura de participación y pluralidad de voces, basadas en estándares de desarrollo libre y que buscan ser éticos antes que con fines de lucro sin fin.

Los sitios web siguen siendo formatos para medios de comunicación que, debido a sus características, favorecen la difusión de contenidos como artículos multimedia. Permiten adecuar un estilo a una identidad visual del medio, mantener secciones y contenido institucional variado, entre otras cosas.

Las redes sociales se destacan por sus características de inmediatez, favoreciendo un flujo dialógico en tiempo real con otros tiempos de atención y características de navegación que lo hacen más breve, rápido, a veces efímero. Los medios de comunicación (personas o emprendimientos mediáticos) suelen utilizarlos para llamar la atención sobre contenidos publicados en sus sitios, apostando a la divulgación rápida y las discusiones que puedan darse entre usuaries.

La funcionalidad que desarrollamos en Sutty contempla los casos de uso en los que un contenido quiera ser compartido a más personas, en menor tiempo, con la posibilidad de generar diálogos. Las particularidades de nuestros sitios y redes sociales libres generan condiciones favorables para la libertad de expresión, que preferimos llamar Derecho a la Comunicación, evadiendo las variadas y cada vez más sofisticadas formas de censura de las plataformas corporativas tradicionales. Un contenido reproducido en varios lugares al mismo tiempo ayuda a su divulgación y es ideal para aquellas voces y discursos contrahegemónicos en la web y su supervivencia al paso del tiempo, preservando la memoria popular.

Cómo funciona el Fediverso en la moderación

El Fediverso intenta funcionar como comunidades en línea interconectadas que se autogobiernan en las formas de cuidados colectivos. Así, cada instancia podría ser algo así como un municipio que aloja diferentes cuentas/usuaries bajo unas reglas consensuadas y que pueden ser puestas en discusión si fuera necesario. De esta forma, es posible regular la circulación de contenidos fascistas y discursos de odio que puedan dañar no solamente la participación de diverses usuaries sino también su salud.

Para ello, cada instancia elige sus formas de moderación y puede excluir otras instancias con denuncias previas de contenidos antidemocráticos, odiantes o contrarios a los valores y cuidados de sus habitantes.

En Sutty en particular, nos interesan las estrategias y los mecanismos de cuidados colectivos, por lo que seguimos diseñando modelos que permitan sostenerlos en nuestras tecnologías. Podés revisar nuestros términos y condiciones, política de privacidad y acuerdos de convivencia para más información.

¿Te interesa participar?

Si sos parte de una organización social, grupo de activismo o colectivo social que pensás que podría beneficiarse de estas características, te invitamos a contactarnos a través de nuestro formulario. Estamos busando mejorar los usos de las tecnologías para ustedes y valoramos sus experiencias.

Otras posibilidades de integración de Social Inbox en sitios estáticos

Si te interesa incorporar esta funcionalidad para otros gestores de sitios estáticos, no dudes en contactarnos. Además, mantenete al tanto de las novedades que compartimos en https://dweb.sutty.nl y en nuestro blog https://sutty.nl/blog

Recomendado para saber más

\n" }, - 'attachment' => - [{ 'type' => 'Document', - 'mediaType' => 'image/png', - 'url' => 'https://sutty.nl/public/8r7b6ohqy6xzgngxbol6337q8jj9/milestone_2_activity_pub_2.png', - 'name' => 'Botones de colores para activar la "Web Disribuida" y el "Fediverso".' }] } - - ] end def update diff --git a/db/seeds/instances.yaml b/db/seeds/instances.yaml new file mode 100644 index 00000000..bf326832 --- /dev/null +++ b/db/seeds/instances.yaml @@ -0,0 +1,285 @@ +--- +- domain: todon.nl + title: Todon.nl + version: 4.2.3 + source_url: https://github.com/mastodon/mastodon + description: Radicaal linkse anti-autoritaire server. Voor anarchisten, socialisten, + (klimaat)activisten, LHBTQIA+, antiracisten, antifascisten, antikapitalisten, + intersectionelen, veganisten, mensenrechten, enz. + usage: + users: + active_month: 372 + thumbnail: + url: https://todon.nl/system/site_uploads/files/000/000/004/@1x/297e509bc8a81f62.png + blurhash: UXAw3zN4M|xsoga#WBay9DxntQRmITocofWE + versions: + "@1x": https://todon.nl/system/site_uploads/files/000/000/004/@1x/297e509bc8a81f62.png + "@2x": https://todon.nl/system/site_uploads/files/000/000/004/@2x/297e509bc8a81f62.png + languages: + - en + configuration: + urls: + streaming: wss://todon.nl + status: https://status.todon.eu + accounts: + max_featured_tags: 10 + statuses: + max_characters: 1312 + max_media_attachments: 4 + characters_reserved_per_url: 23 + media_attachments: + supported_mime_types: + - image/jpeg + - image/png + - image/gif + - image/heic + - image/heif + - image/webp + - image/avif + - video/webm + - video/mp4 + - video/quicktime + - video/ogg + - audio/wave + - audio/wav + - audio/x-wav + - audio/x-pn-wave + - audio/vnd.wave + - audio/ogg + - audio/vorbis + - audio/mpeg + - audio/mp3 + - audio/webm + - audio/flac + - audio/aac + - audio/m4a + - audio/x-m4a + - audio/mp4 + - audio/3gpp + - video/x-ms-asf + image_size_limit: 16777216 + image_matrix_limit: 33177600 + video_size_limit: 103809024 + video_frame_rate_limit: 120 + video_matrix_limit: 8294400 + polls: + max_options: 4 + max_characters_per_option: 50 + min_expiration: 300 + max_expiration: 2629746 + translation: + enabled: true + registrations: + enabled: false + approval_required: false + message: | +

¡No pasarán!

+ +

Je kunt tijdelijk geen nieuw account op Todon.nl aanvragen.

+ + + +

Ga naar joinmastodon.org of FediDB Network om een andere server te vinden.

+ +

It is temporary not possible to request on account on Todon.nl.

+ + + +

Go to joinmastodon.org or FediDB Network to find another server.

+ url: + max_toot_chars: 1312 + contact: + email: todon@posteo.eu + account: + id: '1' + username: admin + acct: admin + display_name: "Admin \U0001F913 Todon.nl (mod)" + locked: false + bot: false + discoverable: false + group: false + created_at: '2017-04-28T00:00:00.000Z' + note: "

This account is used for \U0001F399 Todon.nl announcements and ⚖️ + moderation.

\U0001F6AB Don't follow this account when you are not + on Todon.nl.

New? First read our \U0001F469‍\U0001F3EB Todon 101 \U0001F469‍\U0001F393 + at https://wiki.todon.eu/todon/101

⚖️ + For all our moderators go to https://wiki.todon.nl/todon/moderators

\U0001F4DD Public toots from this account + are in English.

\U0001F515 Criticism is fine, but people who do false + accusations are muted.

✉ todon@posteo.eu

#nobot

" + url: https://todon.nl/@admin + uri: https://todon.nl/users/admin + avatar: https://todon.nl/system/accounts/avatars/000/000/001/original/2db61726225ed3e6.png + avatar_static: https://todon.nl/system/accounts/avatars/000/000/001/original/2db61726225ed3e6.png + header: https://todon.nl/system/accounts/headers/000/000/001/original/fb3a846cbc20aa09.png + header_static: https://todon.nl/system/accounts/headers/000/000/001/original/fb3a846cbc20aa09.png + followers_count: 3164 + following_count: 8 + statuses_count: 724 + last_status_at: '2024-01-12' + noindex: true + emojis: [] + roles: + - id: '3' + name: Admin + color: "#595aff" + fields: + - name: "\U0001F4DC Terms of Service" + value: wiki.todon.nl/todon/terms_en + verified_at: '2018-11-01T14:39:45.465+00:00' + - name: ℹ️ Wiki + value: wiki.todon.nl/todon/informatio + verified_at: '2018-11-01T14:40:54.679+00:00' + - name: "\U0001F4CA Status" + value: status.todon.eu + verified_at: '2023-10-26T20:38:30.185+00:00' + - name: "\U0001F4B3️ Donations" + value: wiki.todon.eu/todon/donations + verified_at: '2022-11-02T00:06:31.865+00:00' + rules: + - id: '1' + text: We do not accept racism (in all its forms, incl. hate against Muslims, antisemitism, + apartheid and casteism - see our Terms of Service for our complete definition). + - id: '2' + text: We do not accept hate against lesbians, gays, bisexuals, pansexuals, transgenders, + non-binary people, intersexual people, queer people in general, etc. + - id: '4' + text: Sexism, misogyny and hate against black women (misogynoir). + - id: '6' + text: We do not accept ableism (incl. COVID-19 denial/downplaying and anti-vax) + and body-shaming. + - id: '8' + text: We do not accept harassment and trolling. + - id: '10' + text: We also do not accept other forms of hate speech. + - id: '11' + text: We do not accept (sexual) abuse of minors, adults and animals (also not + virtual). + - id: '13' + text: We do not accept glorification of violence, calls for murder, death threats, + terrorism and militarism. + - id: '15' + text: We do not accept (neo)colonialism (incl. Zionism), imperialism in all forms + and nationalism (above all nationalism of nation states, incl. flags/symbols + of those on Todon.*, see our Terms of Service). + - id: '16' + text: We do not accept fascism, right-wing populism, and right-wing and religious + extremism. + - id: '17' + text: We do not accept evangelisation and other forms of religious propaganda + [local only], and extreme sects and cults. + - id: '19' + text: We do not accept Marxist-Leninists, Stalinists, Maoists or other followers + of extreme authoritarian (so called) communist/socialist ideologies/regimes + (aka tankies). + - id: '20' + text: We do not accept capitalists, including so called 'anarcho-capitalists' + (aka ancaps) and neoliberals. + - id: '21' + text: We do not accept anthropogenic climate change denial, downplaying the climate + crisis, greenwashing and deceptive climate solutions (like nuclear energy). + - id: '27' + text: We do not accept (right-wing) conspiracy 'theories', hoaxes, fake news and + other forms of disinformation. + - id: '28' + text: Another rule in our terms of service at wiki.todon.eu/todon/terms_en. Explain + in the final step. +- uri: mastodon.mauve.moe + title: Mauvestodon + short_description: Escape ship from centralized social media run by Mauve. + description: Chat about random techie and anarchist stuff. + email: contact@mauve.moe + version: 3.5.10 + urls: + streaming_api: wss://mastodon.mauve.moe + stats: + user_count: 12 + status_count: 3287 + domain_count: 11625 + thumbnail: https://mastodon.mauve.moe/system/site_uploads/files/000/000/001/original/mauvesoftwareinc.png + languages: + - en + registrations: false + approval_required: false + invites_enabled: true + configuration: + statuses: + max_characters: 500 + max_media_attachments: 4 + characters_reserved_per_url: 23 + media_attachments: + supported_mime_types: + - image/jpeg + - image/png + - image/gif + - video/webm + - video/mp4 + - video/quicktime + - video/ogg + - audio/wave + - audio/wav + - audio/x-wav + - audio/x-pn-wave + - audio/ogg + - audio/vorbis + - audio/mpeg + - audio/mp3 + - audio/webm + - audio/flac + - audio/aac + - audio/m4a + - audio/x-m4a + - audio/mp4 + - audio/3gpp + - video/x-ms-asf + image_size_limit: 10485760 + image_matrix_limit: 16777216 + video_size_limit: 41943040 + video_frame_rate_limit: 60 + video_matrix_limit: 2304000 + polls: + max_options: 4 + max_characters_per_option: 50 + min_expiration: 300 + max_expiration: 2629746 + contact_account: + id: '1' + username: admin + acct: admin + display_name: '' + locked: false + bot: false + discoverable: true + group: false + created_at: '2022-04-25T00:00:00.000Z' + note: '' + url: https://mastodon.mauve.moe/@admin + avatar: https://mastodon.mauve.moe/system/accounts/avatars/000/000/001/original/8c21e71667b48a95.png + avatar_static: https://mastodon.mauve.moe/system/accounts/avatars/000/000/001/original/8c21e71667b48a95.png + header: https://mastodon.mauve.moe/headers/original/missing.png + header_static: https://mastodon.mauve.moe/headers/original/missing.png + followers_count: 0 + following_count: 0 + statuses_count: 0 + last_status_at: '2023-01-30' + emojis: [] + fields: + - name: Alternatel Contact + value: @mauve + verified_at: + rules: [] diff --git a/db/seeds/moderation_queue.yaml b/db/seeds/moderation_queue.yaml new file mode 100644 index 00000000..c7075c7e --- /dev/null +++ b/db/seeds/moderation_queue.yaml @@ -0,0 +1,153 @@ +--- +- "@context": + - https://www.w3.org/ns/activitystreams + - ostatus: http://ostatus.org# + atomUri: ostatus:atomUri + inReplyToAtomUri: ostatus:inReplyToAtomUri + conversation: ostatus:conversation + sensitive: as:sensitive + toot: http://joinmastodon.org/ns# + votersCount: toot:votersCount + Hashtag: as:Hashtag + id: https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041 + type: Note + summary: + inReplyTo: https://mastodon.mauve.moe/users/mauve/statuses/111461923538534886 + published: '2023-11-23T22:50:10Z' + url: https://mastodon.mauve.moe/@mauve/111462305634770041 + attributedTo: https://mastodon.mauve.moe/users/mauve + to: + - https://www.w3.org/ns/activitystreams#Public + cc: + - https://mastodon.mauve.moe/users/mauve/followers + - https://hypha.coop/about.jsonld + sensitive: false + atomUri: https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041 + inReplyToAtomUri: https://mastodon.mauve.moe/users/mauve/statuses/111461923538534886 + conversation: tag:mastodon.mauve.moe,2023-11-23:objectId=551471:objectType=Conversation + content:

Follow @HyphaCoop@hypha.coop for our announcement post on the 5th!

+

+ contentMap: + en:

Follow @HyphaCoop@hypha.coop for our announcement post on the 5th!

+

+ attachment: [] + tag: + - type: Mention + href: https://hypha.coop/about.jsonld + name: "@dripline@hypha.coop" + - type: Hashtag + href: https://mastodon.mauve.moe/tags/p2p + name: "#p2p" + - type: Hashtag + href: https://mastodon.mauve.moe/tags/activitypub + name: "#activitypub" + - type: Hashtag + href: https://mastodon.mauve.moe/tags/fediverse + name: "#fediverse" + replies: + id: https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies + type: Collection + first: + type: CollectionPage + next: https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies?only_other_accounts=true&page=true + partOf: https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies + items: [] +- "@context": + - https://www.w3.org/ns/activitystreams + - "@language": es + sensitive: as:sensitive + type: Note + id: https://sutty.nl/lanzamiento-de-publicaciones-distribuidas-en-el-fediverso-a-trav%C3%A9s-de-sutty/ + summary: Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty + published: '2023-12-04T21:53:05+00:00' + updated: '2023-12-05T20:41:34+00:00' + attributedTo: https://sutty.nl/about.jsonld + to: + - https://www.w3.org/ns/activitystreams#Public + cc: + - https://social.distributed.press/v1/@sutty@sutty.nl/followers + inReplyTo: https://hypha.coop/dripline/announcing-dp-social-inbox/ + sensitive: true + content: | +

Estamos felices y orgulloses de anunciar el lanzamiento de la funcionalidad que permite la publicación en el Fediverso de los artículos de todos los sitios creados a través de Sutty.

Gracias al trabajo conjunto con Distributed Press, Hypha y apoyado por la Filecoin Foundation for the Distributed Web, Sutty hace posible que la seguridad de tu sitio estático se combine con la rápida difusión de tu contenido a través de las redes sociales libres y descentralizadas que constituyen el Fediverso.

Esto se logró a través del desarollo y la integración de dos componentes, trabajados en forma conjunta y colaborativa:

    +
  1. Social Inbox, desarrollado principalmente Distributed Press. Aporta la funcionalidad de recibir artículos, responder y mencionar otras cuentas en el Fediverso.

  2. +
  3. Jekyll Activity Pub Plugin, desarrollado principalmente por Sutty. Permite integrar Social Inbox en todos los sitios estáticos generados en Jekyll, admitiendo así la publicación automática de contenido del sitio en el Fediverso.

  4. +

Sutty integra la funcionalidad completa en su CMS para sitios estáticos en Jekyll, permitiendo gestionarla desde una interfaz en continua mejora de su usabilidad.

Si todavía no estás familiarizade con estos nombres y conceptos, te invitamos a conocer más a continuación, en la sección “Para tecno-curioses”.

Qué significa

    +
  • Que si creás tu sitio web a través de Sutty, tenés nuevas posibilidades de difundir tus contenidos e interactuar en redes digitales.

  • +
  • Que tus artículos pueden ser publicados en las redes del Fediverso.

  • +
  • Que tu sitio tendrá un perfil o usuarie personalizable desde el panel en una instancia de Sutty propia.

  • +
  • Que les usuaries del Fediverso pueden seguir tus publicaciones.

  • +
  • Que les usuaries del Fediverso que te sigan podrán leer tus publicaciones, mencionarte y responderte.

  • +
  • Que podrás interactuar con les usuaries del Fediverse con las opciones de responderles y mencionarles.

  • +

Qué permite hacer

    +
  • Activar la publicación en el Fediverso para todos los sitios de Sutty.

  • +
  • Activar la publicación de los artículos que quieras en el Fediverso.

  • +
  • Responder comentarios desde los artículos de tu sitio en Sutty.

  • +
  • Personalizar la cuenta que Sutty crea automáticamente de tu sitio en el Fediverso.

  • +
  • Reportar o informar de usuaries o instancias abusivos mediante nuestro formulario de contacto.

  • +

Qué se viene

    +
  • Mejoras en la integración de las respuestas como comentarios en el sitio.

  • +
  • Incorporación de menciones desde el panel de Sutty.

  • +
  • Mejoras en la interfaz general del panel.

  • +
  • Nuevas implementaciones para una mejor moderación.

  • +
  • Mejor compatibilidad con diversas redes en el Fediverso (Mastodon+Glitch, Pleroma, Ktistec).

  • +
  • Mejoras que permitirán diferenciar el contenido a publicar en el Fediverso y en el sitio de Sutty.

  • +
  • La posibilidad de exportar tu cuenta a una instancia del Fediverso desde tu panel.

  • +
  • La posibilidad de que Sutty anuncie tu contenido y/o usuarie del Fediverse en forma automática para atraer seguidorxs. (Ahora, podés hacerlo a través de un formulario).

  • +
  • Acceder a la lista de seguidorxs y seguides desde tu panel.

  • +
  • Seguir, dejar de seguir, bloquear usuaries y/o instancias del Fediverso desde el panel.

  • +

¡Quiero usarlo!

Te invitamos a dar tus primeros pasos de la mano de nuestro tutorial.

Para tecno-curioses

Cómo funciona

Los sitios web y las redes sociales parecen ser especies distintas dentro del Universo de Internet. Al mismo tiempo, las redes sociales corporativas y concentradas como Instagram, Facebook, X (ex Twitter), entre otras, demostraron ser hostiles con algunos grupos o colectivos sociales en particular (censurando contenido, persiguiendo pezones, ocultando publicaciones por color de piel y de pelo, etc.) y con todes sus usuaries en general (vendiendo data en forma masiva, violando acuerdos de privacidad, eligiendo diseños de interfaz y uso que generan ansiedad y adicción, etc.). Pese a esto, siguen funcionando como espacios obligados a la hora de publicitar un emprendimiento o difundir noticias urgentes.

El Fediverso es una red federada, descentralizada y distribuida de redes sociales libres, cada una con sus características, preferencias, grupos de usuaries. Están diseñadas para facilitar el diálogo entre todas ellas. Es decir, para que los contenidos puedan ser visibles y se puedan generar respuestas entre usuaries, fomentando una cultura de participación y pluralidad de voces, basadas en estándares de desarrollo libre y que buscan ser éticos antes que con fines de lucro sin fin.

Los sitios web siguen siendo formatos para medios de comunicación que, debido a sus características, favorecen la difusión de contenidos como artículos multimedia. Permiten adecuar un estilo a una identidad visual del medio, mantener secciones y contenido institucional variado, entre otras cosas.

Las redes sociales se destacan por sus características de inmediatez, favoreciendo un flujo dialógico en tiempo real con otros tiempos de atención y características de navegación que lo hacen más breve, rápido, a veces efímero. Los medios de comunicación (personas o emprendimientos mediáticos) suelen utilizarlos para llamar la atención sobre contenidos publicados en sus sitios, apostando a la divulgación rápida y las discusiones que puedan darse entre usuaries.

La funcionalidad que desarrollamos en Sutty contempla los casos de uso en los que un contenido quiera ser compartido a más personas, en menor tiempo, con la posibilidad de generar diálogos. Las particularidades de nuestros sitios y redes sociales libres generan condiciones favorables para la libertad de expresión, que preferimos llamar Derecho a la Comunicación, evadiendo las variadas y cada vez más sofisticadas formas de censura de las plataformas corporativas tradicionales. Un contenido reproducido en varios lugares al mismo tiempo ayuda a su divulgación y es ideal para aquellas voces y discursos contrahegemónicos en la web y su supervivencia al paso del tiempo, preservando la memoria popular.

Cómo funciona el Fediverso en la moderación

El Fediverso intenta funcionar como comunidades en línea interconectadas que se autogobiernan en las formas de cuidados colectivos. Así, cada instancia podría ser algo así como un municipio que aloja diferentes cuentas/usuaries bajo unas reglas consensuadas y que pueden ser puestas en discusión si fuera necesario. De esta forma, es posible regular la circulación de contenidos fascistas y discursos de odio que puedan dañar no solamente la participación de diverses usuaries sino también su salud.

Para ello, cada instancia elige sus formas de moderación y puede excluir otras instancias con denuncias previas de contenidos antidemocráticos, odiantes o contrarios a los valores y cuidados de sus habitantes.

En Sutty en particular, nos interesan las estrategias y los mecanismos de cuidados colectivos, por lo que seguimos diseñando modelos que permitan sostenerlos en nuestras tecnologías. Podés revisar nuestros términos y condiciones, política de privacidad y acuerdos de convivencia para más información.

¿Te interesa participar?

Si sos parte de una organización social, grupo de activismo o colectivo social que pensás que podría beneficiarse de estas características, te invitamos a contactarnos a través de nuestro formulario. Estamos busando mejorar los usos de las tecnologías para ustedes y valoramos sus experiencias.

Otras posibilidades de integración de Social Inbox en sitios estáticos

Si te interesa incorporar esta funcionalidad para otros gestores de sitios estáticos, no dudes en contactarnos. Además, mantenete al tanto de las novedades que compartimos en https://dweb.sutty.nl y en nuestro blog https://sutty.nl/blog

Recomendado para saber más

+ name: Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty + contentMap: + es: | +

Estamos felices y orgulloses de anunciar el lanzamiento de la funcionalidad que permite la publicación en el Fediverso de los artículos de todos los sitios creados a través de Sutty.

Gracias al trabajo conjunto con Distributed Press, Hypha y apoyado por la Filecoin Foundation for the Distributed Web, Sutty hace posible que la seguridad de tu sitio estático se combine con la rápida difusión de tu contenido a través de las redes sociales libres y descentralizadas que constituyen el Fediverso.

Esto se logró a través del desarollo y la integración de dos componentes, trabajados en forma conjunta y colaborativa:

    +
  1. Social Inbox, desarrollado principalmente Distributed Press. Aporta la funcionalidad de recibir artículos, responder y mencionar otras cuentas en el Fediverso.

  2. +
  3. Jekyll Activity Pub Plugin, desarrollado principalmente por Sutty. Permite integrar Social Inbox en todos los sitios estáticos generados en Jekyll, admitiendo así la publicación automática de contenido del sitio en el Fediverso.

  4. +

Sutty integra la funcionalidad completa en su CMS para sitios estáticos en Jekyll, permitiendo gestionarla desde una interfaz en continua mejora de su usabilidad.

Si todavía no estás familiarizade con estos nombres y conceptos, te invitamos a conocer más a continuación, en la sección “Para tecno-curioses”.

Qué significa

    +
  • Que si creás tu sitio web a través de Sutty, tenés nuevas posibilidades de difundir tus contenidos e interactuar en redes digitales.

  • +
  • Que tus artículos pueden ser publicados en las redes del Fediverso.

  • +
  • Que tu sitio tendrá un perfil o usuarie personalizable desde el panel en una instancia de Sutty propia.

  • +
  • Que les usuaries del Fediverso pueden seguir tus publicaciones.

  • +
  • Que les usuaries del Fediverso que te sigan podrán leer tus publicaciones, mencionarte y responderte.

  • +
  • Que podrás interactuar con les usuaries del Fediverse con las opciones de responderles y mencionarles.

  • +

Qué permite hacer

    +
  • Activar la publicación en el Fediverso para todos los sitios de Sutty.

  • +
  • Activar la publicación de los artículos que quieras en el Fediverso.

  • +
  • Responder comentarios desde los artículos de tu sitio en Sutty.

  • +
  • Personalizar la cuenta que Sutty crea automáticamente de tu sitio en el Fediverso.

  • +
  • Reportar o informar de usuaries o instancias abusivos mediante nuestro formulario de contacto.

  • +

Qué se viene

    +
  • Mejoras en la integración de las respuestas como comentarios en el sitio.

  • +
  • Incorporación de menciones desde el panel de Sutty.

  • +
  • Mejoras en la interfaz general del panel.

  • +
  • Nuevas implementaciones para una mejor moderación.

  • +
  • Mejor compatibilidad con diversas redes en el Fediverso (Mastodon+Glitch, Pleroma, Ktistec).

  • +
  • Mejoras que permitirán diferenciar el contenido a publicar en el Fediverso y en el sitio de Sutty.

  • +
  • La posibilidad de exportar tu cuenta a una instancia del Fediverso desde tu panel.

  • +
  • La posibilidad de que Sutty anuncie tu contenido y/o usuarie del Fediverse en forma automática para atraer seguidorxs. (Ahora, podés hacerlo a través de un formulario).

  • +
  • Acceder a la lista de seguidorxs y seguides desde tu panel.

  • +
  • Seguir, dejar de seguir, bloquear usuaries y/o instancias del Fediverso desde el panel.

  • +

¡Quiero usarlo!

Te invitamos a dar tus primeros pasos de la mano de nuestro tutorial.

Para tecno-curioses

Cómo funciona

Los sitios web y las redes sociales parecen ser especies distintas dentro del Universo de Internet. Al mismo tiempo, las redes sociales corporativas y concentradas como Instagram, Facebook, X (ex Twitter), entre otras, demostraron ser hostiles con algunos grupos o colectivos sociales en particular (censurando contenido, persiguiendo pezones, ocultando publicaciones por color de piel y de pelo, etc.) y con todes sus usuaries en general (vendiendo data en forma masiva, violando acuerdos de privacidad, eligiendo diseños de interfaz y uso que generan ansiedad y adicción, etc.). Pese a esto, siguen funcionando como espacios obligados a la hora de publicitar un emprendimiento o difundir noticias urgentes.

El Fediverso es una red federada, descentralizada y distribuida de redes sociales libres, cada una con sus características, preferencias, grupos de usuaries. Están diseñadas para facilitar el diálogo entre todas ellas. Es decir, para que los contenidos puedan ser visibles y se puedan generar respuestas entre usuaries, fomentando una cultura de participación y pluralidad de voces, basadas en estándares de desarrollo libre y que buscan ser éticos antes que con fines de lucro sin fin.

Los sitios web siguen siendo formatos para medios de comunicación que, debido a sus características, favorecen la difusión de contenidos como artículos multimedia. Permiten adecuar un estilo a una identidad visual del medio, mantener secciones y contenido institucional variado, entre otras cosas.

Las redes sociales se destacan por sus características de inmediatez, favoreciendo un flujo dialógico en tiempo real con otros tiempos de atención y características de navegación que lo hacen más breve, rápido, a veces efímero. Los medios de comunicación (personas o emprendimientos mediáticos) suelen utilizarlos para llamar la atención sobre contenidos publicados en sus sitios, apostando a la divulgación rápida y las discusiones que puedan darse entre usuaries.

La funcionalidad que desarrollamos en Sutty contempla los casos de uso en los que un contenido quiera ser compartido a más personas, en menor tiempo, con la posibilidad de generar diálogos. Las particularidades de nuestros sitios y redes sociales libres generan condiciones favorables para la libertad de expresión, que preferimos llamar Derecho a la Comunicación, evadiendo las variadas y cada vez más sofisticadas formas de censura de las plataformas corporativas tradicionales. Un contenido reproducido en varios lugares al mismo tiempo ayuda a su divulgación y es ideal para aquellas voces y discursos contrahegemónicos en la web y su supervivencia al paso del tiempo, preservando la memoria popular.

Cómo funciona el Fediverso en la moderación

El Fediverso intenta funcionar como comunidades en línea interconectadas que se autogobiernan en las formas de cuidados colectivos. Así, cada instancia podría ser algo así como un municipio que aloja diferentes cuentas/usuaries bajo unas reglas consensuadas y que pueden ser puestas en discusión si fuera necesario. De esta forma, es posible regular la circulación de contenidos fascistas y discursos de odio que puedan dañar no solamente la participación de diverses usuaries sino también su salud.

Para ello, cada instancia elige sus formas de moderación y puede excluir otras instancias con denuncias previas de contenidos antidemocráticos, odiantes o contrarios a los valores y cuidados de sus habitantes.

En Sutty en particular, nos interesan las estrategias y los mecanismos de cuidados colectivos, por lo que seguimos diseñando modelos que permitan sostenerlos en nuestras tecnologías. Podés revisar nuestros términos y condiciones, política de privacidad y acuerdos de convivencia para más información.

¿Te interesa participar?

Si sos parte de una organización social, grupo de activismo o colectivo social que pensás que podría beneficiarse de estas características, te invitamos a contactarnos a través de nuestro formulario. Estamos busando mejorar los usos de las tecnologías para ustedes y valoramos sus experiencias.

Otras posibilidades de integración de Social Inbox en sitios estáticos

Si te interesa incorporar esta funcionalidad para otros gestores de sitios estáticos, no dudes en contactarnos. Además, mantenete al tanto de las novedades que compartimos en https://dweb.sutty.nl y en nuestro blog https://sutty.nl/blog

Recomendado para saber más

+ attachment: + - type: Document + mediaType: image/png + url: https://sutty.nl/public/8r7b6ohqy6xzgngxbol6337q8jj9/milestone_2_activity_pub_2.png + name: Botones de colores para activar la "Web Disribuida" y el "Fediverso". diff --git a/db/seeds/remote_profile.yaml b/db/seeds/remote_profile.yaml new file mode 100644 index 00000000..1a670d6b --- /dev/null +++ b/db/seeds/remote_profile.yaml @@ -0,0 +1,106 @@ +--- +"@context": +- https://www.w3.org/ns/activitystreams +- https://w3id.org/security/v1 +- manuallyApprovesFollowers: as:manuallyApprovesFollowers + toot: http://joinmastodon.org/ns# + featured: + "@id": toot:featured + "@type": "@id" + featuredTags: + "@id": toot:featuredTags + "@type": "@id" + alsoKnownAs: + "@id": as:alsoKnownAs + "@type": "@id" + movedTo: + "@id": as:movedTo + "@type": "@id" + schema: http://schema.org# + PropertyValue: schema:PropertyValue + value: schema:value + discoverable: toot:discoverable + Device: toot:Device + Ed25519Signature: toot:Ed25519Signature + Ed25519Key: toot:Ed25519Key + Curve25519Key: toot:Curve25519Key + EncryptedMessage: toot:EncryptedMessage + publicKeyBase64: toot:publicKeyBase64 + deviceId: toot:deviceId + claim: + "@type": "@id" + "@id": toot:claim + fingerprintKey: + "@type": "@id" + "@id": toot:fingerprintKey + identityKey: + "@type": "@id" + "@id": toot:identityKey + devices: + "@type": "@id" + "@id": toot:devices + messageFranking: toot:messageFranking + messageType: toot:messageType + cipherText: toot:cipherText + suspended: toot:suspended + focalPoint: + "@container": "@list" + "@id": toot:focalPoint +id: https://mastodon.mauve.moe/users/mauve +type: Person +following: https://mastodon.mauve.moe/users/mauve/following +followers: https://mastodon.mauve.moe/users/mauve/followers +inbox: https://mastodon.mauve.moe/users/mauve/inbox +outbox: https://mastodon.mauve.moe/users/mauve/outbox +featured: https://mastodon.mauve.moe/users/mauve/collections/featured +featuredTags: https://mastodon.mauve.moe/users/mauve/collections/tags +preferredUsername: mauve +name: "Mauve \U0001F441\U0001F49C" +summary: "

Occult Enby that's making local-first software with peer to peer + protocols, mesh networks, and the web.

Also exploring what a local-first + cyberspace might look like in my spare time.

" +url: https://mastodon.mauve.moe/@mauve +manuallyApprovesFollowers: false +discoverable: true +published: '2022-04-25T00:00:00Z' +devices: https://mastodon.mauve.moe/users/mauve/collections/devices +alsoKnownAs: +- https://infosec.exchange/users/RangerMauve +publicKey: + id: https://mastodon.mauve.moe/users/mauve#main-key + owner: https://mastodon.mauve.moe/users/mauve + publicKeyPem: | + -----BEGIN PUBLIC KEY----- + MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxjxu6bRQOjH4caQu7JgZ + umIWFeX0ZdbVnofElev2d9JByqcDoWhmaks3RYdW71RDPNrr0JxqZvUbIw9kQBng + 7iQ9YTcXTdJ/N9CQoB22msffYkEIw4ilehCDXdchNs4aoVAUwI8IhkM0p/itz6gK + 75C3CQv74Y7rHUJC8ob2p4KUwRUyhgzyhp8QWwCAn/RZ28wP8EbjWF9IskMRo9vq + WUX+Io6hpADRkSwZGoOSW2zxCEBVco6tRmABTte8I0WcAucLyMEyfGMlUvxRew4D + zAWoEBS8SyqM68vUabbZYLns6kya34tvsf1NkvajDGrfgU3D0LlGX++tOa6N9Pkf + XwIDAQAB + -----END PUBLIC KEY----- +tag: [] +attachment: +- type: PropertyValue + name: Pronouns + value: they/them/it +- type: PropertyValue + name: Email + value: mauve@mauve.moe +- type: PropertyValue + name: Matrix + value: @mauve:mauve.moe +- type: PropertyValue + name: Github/Twitter + value: "@RangerMauve" +endpoints: + sharedInbox: https://mastodon.mauve.moe/inbox +icon: + type: Image + mediaType: image/png + url: https://mastodon.mauve.moe/system/accounts/avatars/000/000/002/original/e4b910cee121b1b8.png +image: + type: Image + mediaType: image/png + url: https://mastodon.mauve.moe/system/accounts/headers/000/000/002/original/a96f990025091662.png From 3a44c9629fd87952fe9347d6334bd0d8eb93a17e Mon Sep 17 00:00:00 2001 From: maki Date: Wed, 17 Jan 2024 15:55:31 -0300 Subject: [PATCH 013/472] agregadas traducciones a posts/edit #15002 --- app/views/posts/edit.haml | 2 +- config/locales/en.yml | 4 ++++ config/locales/es.yml | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/views/posts/edit.haml b/app/views/posts/edit.haml index c792ac93..126b811e 100644 --- a/app/views/posts/edit.haml +++ b/app/views/posts/edit.haml @@ -1,6 +1,6 @@ .row.justify-content-center .col-md-8 - = render 'layouts/details', summary: "Post" do + = render 'layouts/details', summary: t('.post') do = render 'posts/form', site: @site, post: @post = render 'layouts/details', summary: t('.moderation_queue') do = render 'posts/moderation_queue', site: @site, post: @post, moderation_queue: @moderation_queue diff --git a/config/locales/en.yml b/config/locales/en.yml index fc9d4894..5a1f31bc 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -221,6 +221,10 @@ en: mutual_aid: Mutual aid contact_us: "Contact us" contact_us_href: "https://sutty.nl/en/#contact" + posts: + edit: + moderation_queue: Moderation Queue + post: Post collaborations: collaborate: submit: Register diff --git a/config/locales/es.yml b/config/locales/es.yml index 4bda4982..3b54fbba 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -221,6 +221,10 @@ es: mutual_aid: Ayuda mutua contact_us: "Contacto" contact_us_href: "https://sutty.nl/#contacto" + posts: + edit: + moderation_queue: Cola de moderación + post: Publicación collaborations: collaborate: submit: Registrarme From 49039c24b7ad16d5791ef606c80858ed7739db6a Mon Sep 17 00:00:00 2001 From: maki Date: Wed, 17 Jan 2024 16:12:04 -0300 Subject: [PATCH 014/472] =?UTF-8?q?agregada=20vista=20de=20remote=20profil?= =?UTF-8?q?e=20b=C3=A1sica=20#15003?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/remote_profile.haml | 1 + 1 file changed, 1 insertion(+) create mode 100644 app/views/moderation_queue/remote_profile.haml diff --git a/app/views/moderation_queue/remote_profile.haml b/app/views/moderation_queue/remote_profile.haml new file mode 100644 index 00000000..537ab91c --- /dev/null +++ b/app/views/moderation_queue/remote_profile.haml @@ -0,0 +1 @@ +%h1= @remote_profile['name'] \ No newline at end of file From ed0c237d60e1bdaa295c50c8bb08c885f1da6e04 Mon Sep 17 00:00:00 2001 From: maki Date: Wed, 17 Jan 2024 16:14:02 -0300 Subject: [PATCH 015/472] agregada partial de details #15000 --- app/views/layouts/_details.haml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 app/views/layouts/_details.haml diff --git a/app/views/layouts/_details.haml b/app/views/layouts/_details.haml new file mode 100644 index 00000000..9d6e04a1 --- /dev/null +++ b/app/views/layouts/_details.haml @@ -0,0 +1,4 @@ +%details + %summary= @summary + + = yield \ No newline at end of file From 4c902c8aaf58807c54522f6ba1a33061f034940f Mon Sep 17 00:00:00 2001 From: jazzari Date: Wed, 17 Jan 2024 16:39:20 -0300 Subject: [PATCH 016/472] feat: agregado clase details a application.scss #15000 --- app/assets/stylesheets/application.scss | 28 +++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 7f62e658..7f7908ca 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -558,3 +558,31 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); } } } +// details styles + +.details summary { + list-style: none; + cursor: default; + position: relative; + + &::after { + content: '▶'; + font-size: 2rem; + position: absolute; + left: 97%; + bottom: 46%; + transform: rotate(55deg); + color: $magenta + } + + &:focus { + background-color: #13FEFE; + color: black + } + } + +.details[open] > summary::after { + transform: rotate(90deg) translatey(-0.1em); + color: $magenta + } + \ No newline at end of file From f098de102eab41d817dc764e59cdbbb1aa367d47 Mon Sep 17 00:00:00 2001 From: maki Date: Wed, 17 Jan 2024 17:16:52 -0300 Subject: [PATCH 017/472] feat: agregadas views de moderation_queue #15001 --- app/views/moderation_queue/index.haml | 2 ++ app/views/posts/_moderation_queue.haml | 0 2 files changed, 2 insertions(+) create mode 100644 app/views/moderation_queue/index.haml create mode 100644 app/views/posts/_moderation_queue.haml diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml new file mode 100644 index 00000000..ce5dda0f --- /dev/null +++ b/app/views/moderation_queue/index.haml @@ -0,0 +1,2 @@ +- @comments.each do |comment| + %h1= comment['id'] \ No newline at end of file diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml new file mode 100644 index 00000000..e69de29b From ad8e5bc8115a908d31a964d357529ef4ce690d53 Mon Sep 17 00:00:00 2001 From: jazzari Date: Wed, 17 Jan 2024 17:37:02 -0300 Subject: [PATCH 018/472] fix: corregido edit in es.yml --- app/views/posts/index.haml | 2 +- app/views/posts/show.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index 374f06ee..69fb2d8f 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -126,7 +126,7 @@ = post.order %td.text-nowrap - if @usuarie || policy(post).edit? - = link_to t('posts.edit'), edit_site_post_path(@site, post.path), class: 'btn btn-secondary btn-block' + = link_to t('posts.edit_post'), edit_site_post_path(@site, post.path), class: 'btn btn-secondary btn-block' - if @usuarie || policy(post).destroy? = link_to t('posts.destroy'), site_post_path(@site, post.path), class: 'btn btn-secondary btn-block', method: :delete, data: { confirm: t('posts.confirm_destroy') } diff --git a/app/views/posts/show.haml b/app/views/posts/show.haml index 10900d67..ec191d87 100644 --- a/app/views/posts/show.haml +++ b/app/views/posts/show.haml @@ -2,7 +2,7 @@ .row.justify-content-center .col-md-8 %article.content.table-responsive-md - = link_to t('posts.edit'), + = link_to t('posts.edit_post'), edit_site_post_path(@site, @post.id), class: 'btn btn-secondary btn-block' From 5d26c6746e6160986e01c03d7bf2cfc7f2afb3db Mon Sep 17 00:00:00 2001 From: maki Date: Wed, 17 Jan 2024 17:37:53 -0300 Subject: [PATCH 019/472] fix: traducciones #15002 --- config/locales/en.yml | 12 +++++++----- config/locales/es.yml | 15 ++++++++++----- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 5a1f31bc..4c03fd30 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,4 +1,7 @@ en: + moderation_queue: + remote_profile: + user: Username dark: Dark dir: ltr en: English @@ -221,10 +224,6 @@ en: mutual_aid: Mutual aid contact_us: "Contact us" contact_us_href: "https://sutty.nl/en/#contact" - posts: - edit: - moderation_queue: Moderation Queue - post: Post collaborations: collaborate: submit: Register @@ -582,7 +581,10 @@ en: categories: 'Everything' index: search: 'Search' - edit: 'Edit' + edit_post: 'Edit' + edit: + moderation_queue: Moderation Queue + post: Post preview: btn: 'Preliminary version' alert: 'Not every article type has a preliminary version' diff --git a/config/locales/es.yml b/config/locales/es.yml index 3b54fbba..cc3590ad 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1,4 +1,7 @@ es: + moderation_queue: + remote_profile: + user: Nombre de usuario dark: Oscuro es: Castellano en: English @@ -221,10 +224,6 @@ es: mutual_aid: Ayuda mutua contact_us: "Contacto" contact_us_href: "https://sutty.nl/#contacto" - posts: - edit: - moderation_queue: Cola de moderación - post: Publicación collaborations: collaborate: submit: Registrarme @@ -524,6 +523,9 @@ es: en: 'inglés' ar: 'árabe' posts: + edit: + moderation_queue: Moderation Queue + post: Post prev: Página anterior next: Página siguiente empty: No hay artículos con estos parámetros de búsqueda. @@ -590,7 +592,10 @@ es: remove_filter_help: 'Quitar este filtro: %{filter}' index: search: 'Buscar' - edit: 'Editar' + edit_post: 'Editar' + edit: + moderation_queue: Cola de moderación + post: Publicación preview: btn: 'Versión preliminar' alert: 'No todos los tipos de artículos poseen vista preliminar :)' From 28ddaca35a972d797a60191abf66a159669a4248 Mon Sep 17 00:00:00 2001 From: jazzari Date: Fri, 19 Jan 2024 13:41:23 -0300 Subject: [PATCH 020/472] fix: corregido details de post edit --- app/assets/stylesheets/application.scss | 2 +- app/views/layouts/_details.haml | 8 ++++---- app/views/posts/edit.haml | 6 ++++-- config/locales/es.yml | 7 ++----- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 7f7908ca..b11be0de 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -570,7 +570,7 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); font-size: 2rem; position: absolute; left: 97%; - bottom: 46%; + bottom: 2%; transform: rotate(55deg); color: $magenta } diff --git a/app/views/layouts/_details.haml b/app/views/layouts/_details.haml index 9d6e04a1..f950b097 100644 --- a/app/views/layouts/_details.haml +++ b/app/views/layouts/_details.haml @@ -1,4 +1,4 @@ -%details - %summary= @summary - - = yield \ No newline at end of file +%details.details.py-2 + %summary + %h3.py-2.text-center= @summary + = yield \ No newline at end of file diff --git a/app/views/posts/edit.haml b/app/views/posts/edit.haml index 126b811e..488056a4 100644 --- a/app/views/posts/edit.haml +++ b/app/views/posts/edit.haml @@ -1,6 +1,8 @@ .row.justify-content-center .col-md-8 - = render 'layouts/details', summary: t('.post') do + - @summary = t('posts.edit.post') + = render 'layouts/details', summary: @summary do = render 'posts/form', site: @site, post: @post - = render 'layouts/details', summary: t('.moderation_queue') do + - @summary = t('posts.edit.moderation_queue') + = render 'layouts/details', summary: @summary do = render 'posts/moderation_queue', site: @site, post: @post, moderation_queue: @moderation_queue diff --git a/config/locales/es.yml b/config/locales/es.yml index cc3590ad..1e4f870c 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -524,8 +524,8 @@ es: ar: 'árabe' posts: edit: - moderation_queue: Moderation Queue - post: Post + moderation_queue: Cola de Moderación + post: Contenido prev: Página anterior next: Página siguiente empty: No hay artículos con estos parámetros de búsqueda. @@ -593,9 +593,6 @@ es: index: search: 'Buscar' edit_post: 'Editar' - edit: - moderation_queue: Cola de moderación - post: Publicación preview: btn: 'Versión preliminar' alert: 'No todos los tipos de artículos poseen vista preliminar :)' From ef7d9d2a1ee7b6fed274f869da2c20da95297915 Mon Sep 17 00:00:00 2001 From: jazzari Date: Fri, 19 Jan 2024 15:06:20 -0300 Subject: [PATCH 021/472] fix: eliminados espacios en blanco en varias lineas --- app/views/posts/edit.haml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/posts/edit.haml b/app/views/posts/edit.haml index 488056a4..5234f257 100644 --- a/app/views/posts/edit.haml +++ b/app/views/posts/edit.haml @@ -1,8 +1,8 @@ .row.justify-content-center .col-md-8 - - @summary = t('posts.edit.post') - = render 'layouts/details', summary: @summary do + - @summary = t('posts.edit.post') + = render 'layouts/details', summary: @summary do = render 'posts/form', site: @site, post: @post - - @summary = t('posts.edit.moderation_queue') + - @summary = t('posts.edit.moderation_queue') = render 'layouts/details', summary: @summary do = render 'posts/moderation_queue', site: @site, post: @post, moderation_queue: @moderation_queue From d895b9c808fbf4f7977f45a6723e4367aa23c17f Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 22 Jan 2024 14:17:24 -0300 Subject: [PATCH 022/472] feat: agregados componentes comentario, botonera y boton_base --- app/assets/stylesheets/application.scss | 4 ++++ app/views/layouts/_details.haml | 2 ++ app/views/moderation_queue/_btn_base.haml | 3 +++ app/views/moderation_queue/_button_box.haml | 14 ++++++++++++++ app/views/moderation_queue/_comment.haml | 4 ++++ app/views/posts/_moderation_queue.haml | 3 +++ config/locales/es.yml | 6 ++++++ 7 files changed, 36 insertions(+) create mode 100644 app/views/moderation_queue/_btn_base.haml create mode 100644 app/views/moderation_queue/_button_box.haml create mode 100644 app/views/moderation_queue/_comment.haml diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index b11be0de..a4446532 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -585,4 +585,8 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); transform: rotate(90deg) translatey(-0.1em); color: $magenta } + +.bg-blue { + background-color: $azul; +} \ No newline at end of file diff --git a/app/views/layouts/_details.haml b/app/views/layouts/_details.haml index f950b097..4fe4d2af 100644 --- a/app/views/layouts/_details.haml +++ b/app/views/layouts/_details.haml @@ -1,3 +1,5 @@ +-# Detail Cola de Moderación + %details.details.py-2 %summary %h3.py-2.text-center= @summary diff --git a/app/views/moderation_queue/_btn_base.haml b/app/views/moderation_queue/_btn_base.haml new file mode 100644 index 00000000..74e9516a --- /dev/null +++ b/app/views/moderation_queue/_btn_base.haml @@ -0,0 +1,3 @@ +-# Componente Botón general Moderación + +%a.btn.rounded.mx-2{role: "button", href: href, class: @class} #{text} \ No newline at end of file diff --git a/app/views/moderation_queue/_button_box.haml b/app/views/moderation_queue/_button_box.haml new file mode 100644 index 00000000..ea038e59 --- /dev/null +++ b/app/views/moderation_queue/_button_box.haml @@ -0,0 +1,14 @@ +-# Componente Botonera de Moderación + +.d-flex.py-2.justify-content-center + -# parámetros de botones + -# text, class, href + - @btn_box_params = [[t('.text_pause'), 'bg-outline-light', 'https://sutty.nl/'], + [t('.text_reject'), 'btn-outline-info blue', 'https://sutty.nl/'], + [t('.text_accept'), 'bg-blue white', 'https://sutty.nl/'], + [t('.text_reply'), 'btn-outline-dark', 'https://sutty.nl/'], + [t('.text_report'), 'btn-outline-danger', 'https://sutty.nl/']] + + - @btn_box_params.each do |btn| + - @class = btn[1] + = render 'moderation_queue/btn_base', href: btn[2], class: @class, text: btn[0] \ No newline at end of file diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml new file mode 100644 index 00000000..051a84b0 --- /dev/null +++ b/app/views/moderation_queue/_comment.haml @@ -0,0 +1,4 @@ +-# Componente Comentario + +%p.py-2 Esta línea es donde irá el cuerpo del comentario += render 'moderation_queue/button_box' \ No newline at end of file diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index e69de29b..77df7353 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -0,0 +1,3 @@ +.flex + %h2.text-center Comentarios + = render 'moderation_queue/comment' \ No newline at end of file diff --git a/config/locales/es.yml b/config/locales/es.yml index 1e4f870c..f9cd1b4f 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -2,6 +2,12 @@ es: moderation_queue: remote_profile: user: Nombre de usuario + button_box: + text_pause: Pausa + text_reject: Rechazar + text_accept: Aceptar Publicación + text_reply: Responder + text_report: Reportar dark: Oscuro es: Castellano en: English From 9fa45b01ac8e8afc29babcc462ab2719e010ca9b Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 22 Jan 2024 15:35:19 -0300 Subject: [PATCH 023/472] =?UTF-8?q?feat:=20agregadas=20traducci=C3=B3n=20i?= =?UTF-8?q?ngl=C3=A9s=20botones=20de=20moderaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/assets/stylesheets/application.scss | 4 +++- app/views/moderation_queue/_btn_base.haml | 2 +- app/views/moderation_queue/_button_box.haml | 6 +++--- config/locales/en.yml | 6 ++++++ 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index a4446532..c0a666ab 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -3,6 +3,7 @@ $white: white; $grey: grey; $cyan: #13fefe; $magenta: #f206f9; +$blue: blue; $colors: ( "black": $black, @@ -14,6 +15,7 @@ $colors: ( // Redefinir variables de Bootstrap $primary: $magenta; $secondary: $black; +$info: $blue; $jumbotron-bg: transparent; $enable-rounded: false; $form-feedback-valid-color: $black; @@ -589,4 +591,4 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); .bg-blue { background-color: $azul; } - \ No newline at end of file + diff --git a/app/views/moderation_queue/_btn_base.haml b/app/views/moderation_queue/_btn_base.haml index 74e9516a..5f4561ef 100644 --- a/app/views/moderation_queue/_btn_base.haml +++ b/app/views/moderation_queue/_btn_base.haml @@ -1,3 +1,3 @@ -# Componente Botón general Moderación -%a.btn.rounded.mx-2{role: "button", href: href, class: @class} #{text} \ No newline at end of file +%a.btn.btn-lg.rounded.mx-2{role: "button", href: href, class: @class} #{text} \ No newline at end of file diff --git a/app/views/moderation_queue/_button_box.haml b/app/views/moderation_queue/_button_box.haml index ea038e59..9a2f5947 100644 --- a/app/views/moderation_queue/_button_box.haml +++ b/app/views/moderation_queue/_button_box.haml @@ -1,10 +1,10 @@ -# Componente Botonera de Moderación -.d-flex.py-2.justify-content-center +.d-inline-flex.py-2.justify-content-center -# parámetros de botones -# text, class, href - - @btn_box_params = [[t('.text_pause'), 'bg-outline-light', 'https://sutty.nl/'], - [t('.text_reject'), 'btn-outline-info blue', 'https://sutty.nl/'], + - @btn_box_params = [[t('.text_pause'), 'btn-outline-secondary disabled', ''], + [t('.text_reject'), 'btn-outline-info', 'https://sutty.nl/'], [t('.text_accept'), 'bg-blue white', 'https://sutty.nl/'], [t('.text_reply'), 'btn-outline-dark', 'https://sutty.nl/'], [t('.text_report'), 'btn-outline-danger', 'https://sutty.nl/']] diff --git a/config/locales/en.yml b/config/locales/en.yml index 4c03fd30..ef14f51f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2,6 +2,12 @@ en: moderation_queue: remote_profile: user: Username + button_box: + text_pause: Pause + text_reject: Reject + text_accept: Accept Publication + text_reply: Reply + text_report: Report dark: Dark dir: ltr en: English From 45d98b316914db31f47c370b547ac5c31f641f74 Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 22 Jan 2024 16:05:57 -0300 Subject: [PATCH 024/472] fix: corregidas clases en botonera --- app/views/moderation_queue/_button_box.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/moderation_queue/_button_box.haml b/app/views/moderation_queue/_button_box.haml index 9a2f5947..99744088 100644 --- a/app/views/moderation_queue/_button_box.haml +++ b/app/views/moderation_queue/_button_box.haml @@ -1,6 +1,6 @@ -# Componente Botonera de Moderación -.d-inline-flex.py-2.justify-content-center +.d-flex.py-2.justify-content-center -# parámetros de botones -# text, class, href - @btn_box_params = [[t('.text_pause'), 'btn-outline-secondary disabled', ''], From 1edf052109c643bceb60aed6c1aaaf162a1e0779 Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 22 Jan 2024 17:38:32 -0300 Subject: [PATCH 025/472] fix: corregido padding en moderation_queue view --- app/views/posts/_moderation_queue.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index 77df7353..4b405bbb 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -1,3 +1,3 @@ .flex - %h2.text-center Comentarios + %h3.text-center.py-2 Comentarios = render 'moderation_queue/comment' \ No newline at end of file From 9cb1e6fd36afc95f912e45f6323e6c0ade9c8c41 Mon Sep 17 00:00:00 2001 From: maki Date: Tue, 23 Jan 2024 16:29:11 -0300 Subject: [PATCH 026/472] =?UTF-8?q?feat:=20index=20de=20cola=20de=20modera?= =?UTF-8?q?ci=C3=B3n,=20con=20metadatos=20pero=20sin=20maquetar=20#15039?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_comment.haml | 7 +++++++ app/views/moderation_queue/index.haml | 6 ++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 051a84b0..f2fb3ac2 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -1,4 +1,11 @@ -# Componente Comentario %p.py-2 Esta línea es donde irá el cuerpo del comentario + + +.row + .col.col-1 + %p "hola" + .col + %p "chau" = render 'moderation_queue/button_box' \ No newline at end of file diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml index ce5dda0f..0881add2 100644 --- a/app/views/moderation_queue/index.haml +++ b/app/views/moderation_queue/index.haml @@ -1,2 +1,4 @@ -- @comments.each do |comment| - %h1= comment['id'] \ No newline at end of file +- @moderation_queue.each do |comment| + + = render 'comment', comment: comment +-# %h1= comment['id'] \ No newline at end of file From 2c7081a57f361c3e6f5479cd68d4659aaed62746 Mon Sep 17 00:00:00 2001 From: jazzari Date: Tue, 23 Jan 2024 17:04:38 -0300 Subject: [PATCH 027/472] feat: agregado componente remote_profile y botonera --- app/views/moderation_queue/_comment.haml | 2 +- .../{_button_box.haml => _comment_button_box.haml} | 0 app/views/moderation_queue/_profile_button_box.haml | 12 ++++++++++++ app/views/moderation_queue/_remote_profile.haml | 5 +++++ app/views/moderation_queue/remote_profile.haml | 4 +++- config/locales/es.yml | 11 +++++++++-- 6 files changed, 30 insertions(+), 4 deletions(-) rename app/views/moderation_queue/{_button_box.haml => _comment_button_box.haml} (100%) create mode 100644 app/views/moderation_queue/_profile_button_box.haml create mode 100644 app/views/moderation_queue/_remote_profile.haml diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 051a84b0..e43e8c42 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -1,4 +1,4 @@ -# Componente Comentario %p.py-2 Esta línea es donde irá el cuerpo del comentario -= render 'moderation_queue/button_box' \ No newline at end of file += render 'moderation_queue/comment_button_box' \ No newline at end of file diff --git a/app/views/moderation_queue/_button_box.haml b/app/views/moderation_queue/_comment_button_box.haml similarity index 100% rename from app/views/moderation_queue/_button_box.haml rename to app/views/moderation_queue/_comment_button_box.haml diff --git a/app/views/moderation_queue/_profile_button_box.haml b/app/views/moderation_queue/_profile_button_box.haml new file mode 100644 index 00000000..d5852ffa --- /dev/null +++ b/app/views/moderation_queue/_profile_button_box.haml @@ -0,0 +1,12 @@ +-# Componente Botonera de Profile + +.d-flex.py-2.justify-content-center + -# parámetros de botones + -# text, class, href + - @btn_box_params = [[t('.text_deny'), 'btn-outline-info', ''], + [t('.text_allow'), 'btn-success', 'https://sutty.nl/'], + [t('.text_report'), 'btn-outline-danger', 'https://sutty.nl/']] + + - @btn_box_params.each do |btn| + - @class = btn[1] + = render 'moderation_queue/btn_base', href: btn[2], class: @class, text: btn[0] \ No newline at end of file diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml new file mode 100644 index 00000000..3a18a24a --- /dev/null +++ b/app/views/moderation_queue/_remote_profile.haml @@ -0,0 +1,5 @@ +.flex.py-2.mx-2.text-center + %h4= t('.profile_name') + ": " + @remote_profile['name'] + %h5= t('.profile_id') + ": " + @remote_profile['id'] + %h5= t('.profile_published') + ": " + @remote_profile['published'] + = render 'moderation_queue/profile_button_box' \ No newline at end of file diff --git a/app/views/moderation_queue/remote_profile.haml b/app/views/moderation_queue/remote_profile.haml index 537ab91c..36613405 100644 --- a/app/views/moderation_queue/remote_profile.haml +++ b/app/views/moderation_queue/remote_profile.haml @@ -1 +1,3 @@ -%h1= @remote_profile['name'] \ No newline at end of file +.flex + %h1.text-center= t('.profile') + = render 'moderation_queue/remote_profile' \ No newline at end of file diff --git a/config/locales/es.yml b/config/locales/es.yml index f9cd1b4f..0f5e314c 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1,8 +1,15 @@ es: moderation_queue: remote_profile: - user: Nombre de usuario - button_box: + profile: Cuentas + profile_name: Nombre de la Cuenta + profile_id: ID + profile_published: Publicada + profile_button_box: + text_deny: Bloquear que te siga + text_allow: Permitir que te siga + text_report: Reportar + comment_button_box: text_pause: Pausa text_reject: Rechazar text_accept: Aceptar Publicación From f78fb436817aa5546cc98ef120013ca291076064 Mon Sep 17 00:00:00 2001 From: maki Date: Tue, 23 Jan 2024 17:13:42 -0300 Subject: [PATCH 028/472] =?UTF-8?q?feat:=20esqueleto=20b=C3=A1sico=20maque?= =?UTF-8?q?tado=20de=20comentario=20para=20cola=20de=20moderaci=C3=B3n=20#?= =?UTF-8?q?15039?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_comment.haml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index f2fb3ac2..766e4a22 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -3,9 +3,16 @@ %p.py-2 Esta línea es donde irá el cuerpo del comentario +.row.border.border-white + .col.col-1.border.border-white + %p= comment['published'] # falta parsear + .col.border.border-white + %a{:href => comment['attributedTo']}= comment['attributedTo'] #falta parsear +.row.border.border-white + %p= "En respuesta a: " + %span + %a{:href => comment['inReplyTo']}= comment['inReplyTo'] +.row.border.border-white + %p= comment['content'] #falta parsear .row - .col.col-1 - %p "hola" - .col - %p "chau" -= render 'moderation_queue/button_box' \ No newline at end of file + = render 'moderation_queue/button_box' \ No newline at end of file From d3e5434a00a703c7c749bbc3ac1e01ca4c1f3854 Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 25 Jan 2024 15:48:25 -0300 Subject: [PATCH 029/472] fix: agregadas traduccion y estilos a componente _comment --- app/views/moderation_queue/_comment.haml | 36 +++++++++++++----------- config/locales/es.yml | 3 ++ 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index d412ce62..1093a26b 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -1,18 +1,20 @@ -# Componente Comentario - -%p.py-2 Esta línea es donde irá el cuerpo del comentario - - -.row.border.border-white - .col.col-1.border.border-white - %p= comment['published'] # falta parsear - .col.border.border-white - %a{:href => comment['attributedTo']}= comment['attributedTo'] #falta parsear -.row.border.border-white - %p= "En respuesta a: " - %span - %a{:href => comment['inReplyTo']}= comment['inReplyTo'] -.row.border.border-white - %p= comment['content'] #falta parsear -.row - = render 'moderation_queue/comment_button_box' +.flex.mx-4.my-5 + .row.no-gutters + .col-1 + %input{type: "checkbox", id: ""} + .col-10 + .row.border.border-white + .col.col-1.border.border-white.mr-2 + %p= comment['published'].to_datetime.strftime('%m/%d/%Y') # falta parsear + .col.border.border-white + %span.mr-3= t('.source_profile') + %a{:href => comment['attributedTo']}= comment['attributedTo'] #falta parsear + .row.border.border-white + %p.mr-3= t('.reply_to') + %span + %a{:href => comment['inReplyTo']}= comment['inReplyTo'] + .row.border.border-white + %p= comment['content'] #falta parsear + .row.d-flex.justify-content-center + = render 'moderation_queue/comment_button_box' diff --git a/config/locales/es.yml b/config/locales/es.yml index 0f5e314c..451d5fa4 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1,5 +1,8 @@ es: moderation_queue: + comment: + source_profile: Cuenta de Origen + reply_to: En respuesta a remote_profile: profile: Cuentas profile_name: Nombre de la Cuenta From f6a93b5bc21722d731cceef54a66c0bb17c2b222 Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 25 Jan 2024 16:15:20 -0300 Subject: [PATCH 030/472] fix: corregida llamada en _moderation_queue para mostrar comentarios en vista posts/edit --- app/controllers/posts_controller.rb | 1 + app/views/moderation_queue/_comment_button_box.haml | 8 ++++---- app/views/moderation_queue/index.haml | 1 - app/views/posts/_moderation_queue.haml | 3 ++- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index d572e052..12b3ab55 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -82,6 +82,7 @@ class PostsController < ApplicationController authorize post breadcrumb post.title.value, site_post_path(site, post, locale: locale), match: :exact breadcrumb 'posts.edit', '' + @moderation_queue = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'moderation_queue.yaml'))) end def update diff --git a/app/views/moderation_queue/_comment_button_box.haml b/app/views/moderation_queue/_comment_button_box.haml index 99744088..13a9c8a3 100644 --- a/app/views/moderation_queue/_comment_button_box.haml +++ b/app/views/moderation_queue/_comment_button_box.haml @@ -4,10 +4,10 @@ -# parámetros de botones -# text, class, href - @btn_box_params = [[t('.text_pause'), 'btn-outline-secondary disabled', ''], - [t('.text_reject'), 'btn-outline-info', 'https://sutty.nl/'], - [t('.text_accept'), 'bg-blue white', 'https://sutty.nl/'], - [t('.text_reply'), 'btn-outline-dark', 'https://sutty.nl/'], - [t('.text_report'), 'btn-outline-danger', 'https://sutty.nl/']] + [t('.text_reject'), 'btn-outline-info', ''], + [t('.text_accept'), 'bg-blue white', ''], + [t('.text_reply'), 'btn-outline-dark', ''], + [t('.text_report'), 'btn-outline-danger', '']] - @btn_box_params.each do |btn| - @class = btn[1] diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml index 0881add2..0c693d26 100644 --- a/app/views/moderation_queue/index.haml +++ b/app/views/moderation_queue/index.haml @@ -1,4 +1,3 @@ - @moderation_queue.each do |comment| = render 'comment', comment: comment --# %h1= comment['id'] \ No newline at end of file diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index 4b405bbb..c754d51d 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -1,3 +1,4 @@ .flex %h3.text-center.py-2 Comentarios - = render 'moderation_queue/comment' \ No newline at end of file + - @moderation_queue.each do |comment| + = render 'moderation_queue/comment', comment: comment \ No newline at end of file From 1eb2230b2afad89701923da7bd4fbe5cc021278d Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 25 Jan 2024 17:05:06 -0300 Subject: [PATCH 031/472] =?UTF-8?q?fix:=20corregida=20posici=C3=B3n=20de?= =?UTF-8?q?=20botonera=20de=20moderacion=20de=20comentarios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_comment.haml | 6 ++---- app/views/moderation_queue/index.haml | 1 + app/views/posts/_moderation_queue.haml | 4 +++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 1093a26b..639a6bae 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -5,10 +5,10 @@ %input{type: "checkbox", id: ""} .col-10 .row.border.border-white - .col.col-1.border.border-white.mr-2 + .col.col-1.border.border-white.mr-5 %p= comment['published'].to_datetime.strftime('%m/%d/%Y') # falta parsear .col.border.border-white - %span.mr-3= t('.source_profile') + %span.mr-2= t('.source_profile') %a{:href => comment['attributedTo']}= comment['attributedTo'] #falta parsear .row.border.border-white %p.mr-3= t('.reply_to') @@ -16,5 +16,3 @@ %a{:href => comment['inReplyTo']}= comment['inReplyTo'] .row.border.border-white %p= comment['content'] #falta parsear - .row.d-flex.justify-content-center - = render 'moderation_queue/comment_button_box' diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml index 0c693d26..63b36a3a 100644 --- a/app/views/moderation_queue/index.haml +++ b/app/views/moderation_queue/index.haml @@ -1,3 +1,4 @@ - @moderation_queue.each do |comment| = render 'comment', comment: comment + = render 'moderation_queue/comment_button_box' \ No newline at end of file diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index c754d51d..2528224f 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -1,4 +1,6 @@ .flex %h3.text-center.py-2 Comentarios - @moderation_queue.each do |comment| - = render 'moderation_queue/comment', comment: comment \ No newline at end of file + = render 'moderation_queue/comment', comment: comment + .row.d-flex.justify-content-center + = render 'moderation_queue/comment_button_box' \ No newline at end of file From 9e8a83b70665885604b287bf025ebb8412b7a116 Mon Sep 17 00:00:00 2001 From: maki Date: Fri, 26 Jan 2024 15:15:48 -0300 Subject: [PATCH 032/472] fix: html de comentarios sanitizado #15039 --- app/views/moderation_queue/_comment.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 639a6bae..d66d1187 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -15,4 +15,4 @@ %span %a{:href => comment['inReplyTo']}= comment['inReplyTo'] .row.border.border-white - %p= comment['content'] #falta parsear + %p= sanitize comment['content'] #falta parsear From 5a6b0373a2dc095a7c9b608ef73b3731c276a583 Mon Sep 17 00:00:00 2001 From: jazzari Date: Fri, 26 Jan 2024 15:23:38 -0300 Subject: [PATCH 033/472] feat: agregado componente caja de filtros de comentarios y compo filtro_base --- app/views/moderation_queue/_comment.haml | 4 ++-- app/views/moderation_queue/_comment_filter_box.haml | 6 ++++++ app/views/moderation_queue/_filter_base.haml | 8 ++++++++ app/views/moderation_queue/index.haml | 1 + app/views/posts/_moderation_queue.haml | 1 + config/locales/es.yml | 4 ++++ 6 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 app/views/moderation_queue/_comment_filter_box.haml create mode 100644 app/views/moderation_queue/_filter_base.haml diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index d66d1187..a3f2499c 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -6,7 +6,7 @@ .col-10 .row.border.border-white .col.col-1.border.border-white.mr-5 - %p= comment['published'].to_datetime.strftime('%m/%d/%Y') # falta parsear + %p= comment['published'].to_datetime.strftime('%m/%d/%Y') .col.border.border-white %span.mr-2= t('.source_profile') %a{:href => comment['attributedTo']}= comment['attributedTo'] #falta parsear @@ -15,4 +15,4 @@ %span %a{:href => comment['inReplyTo']}= comment['inReplyTo'] .row.border.border-white - %p= sanitize comment['content'] #falta parsear + %p= sanitize comment['content'] diff --git a/app/views/moderation_queue/_comment_filter_box.haml b/app/views/moderation_queue/_comment_filter_box.haml new file mode 100644 index 00000000..e9abe602 --- /dev/null +++ b/app/views/moderation_queue/_comment_filter_box.haml @@ -0,0 +1,6 @@ +-# Componente Caja de Filtros + +.d-flex.py-2.justify-content-center + = render 'moderation_queue/filter_base', text: t('.text_checked') + = render 'moderation_queue/filter_base', text: t('.text_show') + = render 'moderation_queue/filter_base', text: t('.text_order') \ No newline at end of file diff --git a/app/views/moderation_queue/_filter_base.haml b/app/views/moderation_queue/_filter_base.haml new file mode 100644 index 00000000..6b62b99d --- /dev/null +++ b/app/views/moderation_queue/_filter_base.haml @@ -0,0 +1,8 @@ +-# Componente Filtro +.dropdown.mx-4 + %button#dropdownMenuButton.btn.btn-outline-secondary.dropdown-toggle{:type => "button", "data-toggle" => "dropdown", "aria-haspopup" => "true", "aria-expanded" => "false"} + %span #{text} + .dropdown-menu{"aria-labelledby" => "dropdownMenuButton"} + %a.dropdown-item{:href => "#"} Action + %a.dropdown-item{:href => "#"} Another action + %a.dropdown-item{:href => "#"} Something else here diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml index 63b36a3a..dbc1297a 100644 --- a/app/views/moderation_queue/index.haml +++ b/app/views/moderation_queue/index.haml @@ -1,3 +1,4 @@ += render 'moderation_queue/comment_filter_box' - @moderation_queue.each do |comment| = render 'comment', comment: comment diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index 2528224f..7daa0c8e 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -1,6 +1,7 @@ .flex %h3.text-center.py-2 Comentarios - @moderation_queue.each do |comment| + = render 'moderation_queue/comment_filter_box' = render 'moderation_queue/comment', comment: comment .row.d-flex.justify-content-center = render 'moderation_queue/comment_button_box' \ No newline at end of file diff --git a/config/locales/es.yml b/config/locales/es.yml index 451d5fa4..d579d55e 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -18,6 +18,10 @@ es: text_accept: Aceptar Publicación text_reply: Responder text_report: Reportar + comment_filter_box: + text_order: Ordenar por + text_show: Ver + text_checked: Con los marcados dark: Oscuro es: Castellano en: English From 4b67968d3b9888ffb50dc7b2f6de499a7780e6c9 Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 29 Jan 2024 13:28:58 -0300 Subject: [PATCH 034/472] fix: corregido botonera de filtros en componente moderation_queue --- app/views/posts/_moderation_queue.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index 7daa0c8e..80a8b11c 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -1,7 +1,7 @@ .flex %h3.text-center.py-2 Comentarios + = render 'moderation_queue/comment_filter_box' - @moderation_queue.each do |comment| - = render 'moderation_queue/comment_filter_box' = render 'moderation_queue/comment', comment: comment .row.d-flex.justify-content-center = render 'moderation_queue/comment_button_box' \ No newline at end of file From 2f803f9ea625b8f0f48b6c2e47c77058930f66a6 Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 29 Jan 2024 13:48:11 -0300 Subject: [PATCH 035/472] fix: corregidas lineas segun CI --- app/views/moderation_queue/_filter_base.haml | 6 +++--- app/views/moderation_queue/_profile_button_box.haml | 2 +- app/views/moderation_queue/_remote_profile.haml | 4 ++-- app/views/moderation_queue/remote_profile.haml | 2 +- app/views/posts/_moderation_queue.haml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/views/moderation_queue/_filter_base.haml b/app/views/moderation_queue/_filter_base.haml index 6b62b99d..0b63e59b 100644 --- a/app/views/moderation_queue/_filter_base.haml +++ b/app/views/moderation_queue/_filter_base.haml @@ -3,6 +3,6 @@ %button#dropdownMenuButton.btn.btn-outline-secondary.dropdown-toggle{:type => "button", "data-toggle" => "dropdown", "aria-haspopup" => "true", "aria-expanded" => "false"} %span #{text} .dropdown-menu{"aria-labelledby" => "dropdownMenuButton"} - %a.dropdown-item{:href => "#"} Action - %a.dropdown-item{:href => "#"} Another action - %a.dropdown-item{:href => "#"} Something else here + %a.dropdown-item{ href: '#' } Action + %a.dropdown-item{ href: '#' } Another action + %a.dropdown-item{ href: '#' } Something else here diff --git a/app/views/moderation_queue/_profile_button_box.haml b/app/views/moderation_queue/_profile_button_box.haml index d5852ffa..1201de05 100644 --- a/app/views/moderation_queue/_profile_button_box.haml +++ b/app/views/moderation_queue/_profile_button_box.haml @@ -9,4 +9,4 @@ - @btn_box_params.each do |btn| - @class = btn[1] - = render 'moderation_queue/btn_base', href: btn[2], class: @class, text: btn[0] \ No newline at end of file + = render 'moderation_queue/btn_base', href: btn[2], class: @class, text: btn[0] diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml index 3a18a24a..273b7bd8 100644 --- a/app/views/moderation_queue/_remote_profile.haml +++ b/app/views/moderation_queue/_remote_profile.haml @@ -1,5 +1,5 @@ .flex.py-2.mx-2.text-center %h4= t('.profile_name') + ": " + @remote_profile['name'] %h5= t('.profile_id') + ": " + @remote_profile['id'] - %h5= t('.profile_published') + ": " + @remote_profile['published'] - = render 'moderation_queue/profile_button_box' \ No newline at end of file + %h5= t('.profile_published') + ": " + @remote_profile['published'].to_datetime.strftime('%m/%d/%Y') + = render 'moderation_queue/profile_button_box' diff --git a/app/views/moderation_queue/remote_profile.haml b/app/views/moderation_queue/remote_profile.haml index 36613405..d1d20f86 100644 --- a/app/views/moderation_queue/remote_profile.haml +++ b/app/views/moderation_queue/remote_profile.haml @@ -1,3 +1,3 @@ .flex %h1.text-center= t('.profile') - = render 'moderation_queue/remote_profile' \ No newline at end of file + = render 'moderation_queue/remote_profile' diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index 80a8b11c..f1b0f7ce 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -4,4 +4,4 @@ - @moderation_queue.each do |comment| = render 'moderation_queue/comment', comment: comment .row.d-flex.justify-content-center - = render 'moderation_queue/comment_button_box' \ No newline at end of file + = render 'moderation_queue/comment_button_box' From 957e79e682e83e57704e43e01d3407f46bbf5df4 Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 29 Jan 2024 15:32:47 -0300 Subject: [PATCH 036/472] fix: corregidas variables en partials --- app/views/moderation_queue/_comment_button_box.haml | 4 ++-- app/views/moderation_queue/_profile_button_box.haml | 4 ++-- app/views/moderation_queue/_remote_profile.haml | 6 +++--- app/views/moderation_queue/remote_profile.haml | 2 +- app/views/posts/_moderation_queue.haml | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/views/moderation_queue/_comment_button_box.haml b/app/views/moderation_queue/_comment_button_box.haml index 13a9c8a3..a22f46d5 100644 --- a/app/views/moderation_queue/_comment_button_box.haml +++ b/app/views/moderation_queue/_comment_button_box.haml @@ -3,12 +3,12 @@ .d-flex.py-2.justify-content-center -# parámetros de botones -# text, class, href - - @btn_box_params = [[t('.text_pause'), 'btn-outline-secondary disabled', ''], + - btn_box_params = [[t('.text_pause'), 'btn-outline-secondary disabled', ''], [t('.text_reject'), 'btn-outline-info', ''], [t('.text_accept'), 'bg-blue white', ''], [t('.text_reply'), 'btn-outline-dark', ''], [t('.text_report'), 'btn-outline-danger', '']] - - @btn_box_params.each do |btn| + - btn_box_params.each do |btn| - @class = btn[1] = render 'moderation_queue/btn_base', href: btn[2], class: @class, text: btn[0] \ No newline at end of file diff --git a/app/views/moderation_queue/_profile_button_box.haml b/app/views/moderation_queue/_profile_button_box.haml index 1201de05..9de64e12 100644 --- a/app/views/moderation_queue/_profile_button_box.haml +++ b/app/views/moderation_queue/_profile_button_box.haml @@ -3,10 +3,10 @@ .d-flex.py-2.justify-content-center -# parámetros de botones -# text, class, href - - @btn_box_params = [[t('.text_deny'), 'btn-outline-info', ''], + - btn_box_params = [[t('.text_deny'), 'btn-outline-info', ''], [t('.text_allow'), 'btn-success', 'https://sutty.nl/'], [t('.text_report'), 'btn-outline-danger', 'https://sutty.nl/']] - - @btn_box_params.each do |btn| + - btn_box_params.each do |btn| - @class = btn[1] = render 'moderation_queue/btn_base', href: btn[2], class: @class, text: btn[0] diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml index 273b7bd8..b665dcf2 100644 --- a/app/views/moderation_queue/_remote_profile.haml +++ b/app/views/moderation_queue/_remote_profile.haml @@ -1,5 +1,5 @@ .flex.py-2.mx-2.text-center - %h4= t('.profile_name') + ": " + @remote_profile['name'] - %h5= t('.profile_id') + ": " + @remote_profile['id'] - %h5= t('.profile_published') + ": " + @remote_profile['published'].to_datetime.strftime('%m/%d/%Y') + %h4= t('.profile_name') + ': ' + remote_profile['name'] + %h5= t('.profile_id') + ': ' + remote_profile['id'] + %h5= t('.profile_published') + ': ' + remote_profile['published'].to_datetime.strftime('%m/%d/%Y') = render 'moderation_queue/profile_button_box' diff --git a/app/views/moderation_queue/remote_profile.haml b/app/views/moderation_queue/remote_profile.haml index d1d20f86..3eab5e35 100644 --- a/app/views/moderation_queue/remote_profile.haml +++ b/app/views/moderation_queue/remote_profile.haml @@ -1,3 +1,3 @@ .flex %h1.text-center= t('.profile') - = render 'moderation_queue/remote_profile' + = render 'moderation_queue/remote_profile', remote_profile: @remote_profile diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index f1b0f7ce..513632cd 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -1,7 +1,7 @@ .flex %h3.text-center.py-2 Comentarios = render 'moderation_queue/comment_filter_box' - - @moderation_queue.each do |comment| + - moderation_queue.each do |comment| = render 'moderation_queue/comment', comment: comment .row.d-flex.justify-content-center = render 'moderation_queue/comment_button_box' From 1b0fb009f49a02dd5c9ed68cf77a81b9ef5d41c7 Mon Sep 17 00:00:00 2001 From: maki Date: Mon, 29 Jan 2024 16:35:53 -0300 Subject: [PATCH 037/472] =?UTF-8?q?feat:=20traer=20informaci=C3=B3n=20de?= =?UTF-8?q?=20perfil=20remoto=20vinculado=20al=20comentario=20#15039?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/moderation_queue_controller.rb | 4 ++++ app/views/moderation_queue/_comment.haml | 2 +- app/views/moderation_queue/index.haml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index eb39dae6..4a65f136 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -5,6 +5,10 @@ class ModerationQueueController < ApplicationController # Cola de moderación viendo todo el sitio def index @moderation_queue = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'moderation_queue.yaml'))) + @remote_profile = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'remote_profile.yaml'))) + @moderation_queue.each do |activity| + activity['attributedTo'] = @remote_profile + end end # Perfil remoto de usuarie diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index a3f2499c..d443802d 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -9,7 +9,7 @@ %p= comment['published'].to_datetime.strftime('%m/%d/%Y') .col.border.border-white %span.mr-2= t('.source_profile') - %a{:href => comment['attributedTo']}= comment['attributedTo'] #falta parsear + %a{:href => comment['attributedTo']}= profile['preferredUsername'] .row.border.border-white %p.mr-3= t('.reply_to') %span diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml index dbc1297a..a3897417 100644 --- a/app/views/moderation_queue/index.haml +++ b/app/views/moderation_queue/index.haml @@ -1,5 +1,5 @@ = render 'moderation_queue/comment_filter_box' - @moderation_queue.each do |comment| - = render 'comment', comment: comment + = render 'comment', comment: comment, profile: @remote_profile = render 'moderation_queue/comment_button_box' \ No newline at end of file From b7630844747b0fb0ec122e2597158ed99cd7093e Mon Sep 17 00:00:00 2001 From: maki Date: Wed, 31 Jan 2024 15:41:12 -0300 Subject: [PATCH 038/472] feat: dummy data #15076 --- app/controllers/application_controller.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 2746ab10..903d3642 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -27,6 +27,15 @@ class ApplicationController < ActionController::Base end private + # Traer datos de muestra de la cola de moderación + def dummy_data + @moderation_queue = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'moderation_queue.yaml'))) + @remote_profile = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'remote_profile.yaml'))) + @instances = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'instances.yaml'))) + @moderation_queue.each do |activity| + activity['attributedTo'] = @remote_profile + end + end def notify_unconfirmed_email return unless current_usuarie @@ -117,4 +126,5 @@ class ApplicationController < ActionController::Base sites_path end + end From b233a74f61ef522d7f4cd99e8ffba1dc8b2f02e7 Mon Sep 17 00:00:00 2001 From: maki Date: Wed, 31 Jan 2024 15:47:19 -0300 Subject: [PATCH 039/472] =?UTF-8?q?fix:=20agregada=20dummy=5Fdata=20en=20e?= =?UTF-8?q?l=20m=C3=A9todo=20edit=20de=20posts=5Fcontroller=20#15076=20#15?= =?UTF-8?q?039?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/posts_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 12b3ab55..8839de52 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -83,6 +83,7 @@ class PostsController < ApplicationController breadcrumb post.title.value, site_post_path(site, post, locale: locale), match: :exact breadcrumb 'posts.edit', '' @moderation_queue = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'moderation_queue.yaml'))) + dummy_data end def update From 836687651e1f922fe71847d5864158fb93a59e5e Mon Sep 17 00:00:00 2001 From: maki Date: Wed, 31 Jan 2024 15:51:53 -0300 Subject: [PATCH 040/472] =?UTF-8?q?fix:=20c=C3=B3digo=20dem=C3=A1s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/posts_controller.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 8839de52..5be56acc 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -82,7 +82,6 @@ class PostsController < ApplicationController authorize post breadcrumb post.title.value, site_post_path(site, post, locale: locale), match: :exact breadcrumb 'posts.edit', '' - @moderation_queue = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'moderation_queue.yaml'))) dummy_data end From 4f6464837ac8a0b8a446353ac4eacb80a1e39d2c Mon Sep 17 00:00:00 2001 From: maki Date: Wed, 31 Jan 2024 15:53:05 -0300 Subject: [PATCH 041/472] fix: a ver si esto arregla --- app/views/posts/_moderation_queue.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index 513632cd..b861d67d 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -2,6 +2,6 @@ %h3.text-center.py-2 Comentarios = render 'moderation_queue/comment_filter_box' - moderation_queue.each do |comment| - = render 'moderation_queue/comment', comment: comment + = render 'moderation_queue/comment', comment: comment, profile: @remote_profile .row.d-flex.justify-content-center = render 'moderation_queue/comment_button_box' From 94a86eca9b61efc7c8b5327f0c08f1893a728c18 Mon Sep 17 00:00:00 2001 From: jazzari Date: Wed, 31 Jan 2024 17:10:34 -0300 Subject: [PATCH 042/472] fix: corregidos colores botonera de comentarios #15028 --- app/views/moderation_queue/_comment_button_box.haml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/moderation_queue/_comment_button_box.haml b/app/views/moderation_queue/_comment_button_box.haml index a22f46d5..bd367e09 100644 --- a/app/views/moderation_queue/_comment_button_box.haml +++ b/app/views/moderation_queue/_comment_button_box.haml @@ -3,10 +3,10 @@ .d-flex.py-2.justify-content-center -# parámetros de botones -# text, class, href - - btn_box_params = [[t('.text_pause'), 'btn-outline-secondary disabled', ''], - [t('.text_reject'), 'btn-outline-info', ''], + - btn_box_params = [[t('.text_pause'), 'btn-secondary', ''], + [t('.text_reject'), 'btn-primary', ''], [t('.text_accept'), 'bg-blue white', ''], - [t('.text_reply'), 'btn-outline-dark', ''], + [t('.text_reply'), 'btn-outline-primary', ''], [t('.text_report'), 'btn-outline-danger', '']] - btn_box_params.each do |btn| From 819ed25e29a2559bcb2a541b3c46cb887e348fc4 Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 1 Feb 2024 12:02:40 -0300 Subject: [PATCH 043/472] fix: eliminadas botoneras de comentarios y remote_profile y unificadas en componente button_box #15028 --- app/controllers/application_controller.rb | 13 +++++++++++++ app/controllers/moderation_queue_controller.rb | 1 + app/controllers/posts_controller.rb | 1 + app/views/moderation_queue/_button_box.haml | 6 ++++++ .../moderation_queue/_comment_button_box.haml | 14 -------------- .../moderation_queue/_profile_button_box.haml | 4 ++-- app/views/moderation_queue/index.haml | 2 +- app/views/posts/_moderation_queue.haml | 2 +- config/locales/es.yml | 2 +- 9 files changed, 26 insertions(+), 19 deletions(-) create mode 100644 app/views/moderation_queue/_button_box.haml delete mode 100644 app/views/moderation_queue/_comment_button_box.haml diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 903d3642..360a9b2d 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -37,6 +37,19 @@ class ApplicationController < ActionController::Base end end + # parámetros de botones + # text: [texto del botón] + # class: [clases css] + # href: [href del botón] + def botoneras_moderation_queue + # botones de comentarios + @comment_btn_params = [[t('moderation_queue.button_box.text_pause'), 'btn-secondary', ''], + [t('moderation_queue.button_box.text_reject'), 'btn-primary', ''], + [t('moderation_queue.button_box.text_accept'), 'bg-blue white', ''], + [t('moderation_queue.button_box.text_reply'), 'btn-outline-primary', ''], + [t('moderation_queue.button_box.text_report'), 'btn-danger', '']] + end + def notify_unconfirmed_email return unless current_usuarie return if current_usuarie.confirmed? diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index 4a65f136..04a31389 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -9,6 +9,7 @@ class ModerationQueueController < ApplicationController @moderation_queue.each do |activity| activity['attributedTo'] = @remote_profile end + botoneras_moderation_queue end # Perfil remoto de usuarie diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 5be56acc..36d17339 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -83,6 +83,7 @@ class PostsController < ApplicationController breadcrumb post.title.value, site_post_path(site, post, locale: locale), match: :exact breadcrumb 'posts.edit', '' dummy_data + botoneras_moderation_queue end def update diff --git a/app/views/moderation_queue/_button_box.haml b/app/views/moderation_queue/_button_box.haml new file mode 100644 index 00000000..a56b2552 --- /dev/null +++ b/app/views/moderation_queue/_button_box.haml @@ -0,0 +1,6 @@ +-# Componente Botonera de Moderación + +.d-flex.py-2.justify-content-center + - comment_btn_params.each do |btn| + - @class = btn[1] + = render 'moderation_queue/btn_base', href: btn[2], class: @class, text: btn[0] \ No newline at end of file diff --git a/app/views/moderation_queue/_comment_button_box.haml b/app/views/moderation_queue/_comment_button_box.haml deleted file mode 100644 index bd367e09..00000000 --- a/app/views/moderation_queue/_comment_button_box.haml +++ /dev/null @@ -1,14 +0,0 @@ --# Componente Botonera de Moderación - -.d-flex.py-2.justify-content-center - -# parámetros de botones - -# text, class, href - - btn_box_params = [[t('.text_pause'), 'btn-secondary', ''], - [t('.text_reject'), 'btn-primary', ''], - [t('.text_accept'), 'bg-blue white', ''], - [t('.text_reply'), 'btn-outline-primary', ''], - [t('.text_report'), 'btn-outline-danger', '']] - - - btn_box_params.each do |btn| - - @class = btn[1] - = render 'moderation_queue/btn_base', href: btn[2], class: @class, text: btn[0] \ No newline at end of file diff --git a/app/views/moderation_queue/_profile_button_box.haml b/app/views/moderation_queue/_profile_button_box.haml index 9de64e12..d15b6ed0 100644 --- a/app/views/moderation_queue/_profile_button_box.haml +++ b/app/views/moderation_queue/_profile_button_box.haml @@ -3,10 +3,10 @@ .d-flex.py-2.justify-content-center -# parámetros de botones -# text, class, href - - btn_box_params = [[t('.text_deny'), 'btn-outline-info', ''], + - comment_btn_params = [[t('.text_deny'), 'btn-outline-info', ''], [t('.text_allow'), 'btn-success', 'https://sutty.nl/'], [t('.text_report'), 'btn-outline-danger', 'https://sutty.nl/']] - - btn_box_params.each do |btn| + - comment_btn_params.each do |btn| - @class = btn[1] = render 'moderation_queue/btn_base', href: btn[2], class: @class, text: btn[0] diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml index a3897417..39ac74a3 100644 --- a/app/views/moderation_queue/index.haml +++ b/app/views/moderation_queue/index.haml @@ -2,4 +2,4 @@ - @moderation_queue.each do |comment| = render 'comment', comment: comment, profile: @remote_profile - = render 'moderation_queue/comment_button_box' \ No newline at end of file + = render 'moderation_queue/button_box', comment_btn_params: @comment_btn_params \ No newline at end of file diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index b861d67d..e4eb422c 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -4,4 +4,4 @@ - moderation_queue.each do |comment| = render 'moderation_queue/comment', comment: comment, profile: @remote_profile .row.d-flex.justify-content-center - = render 'moderation_queue/comment_button_box' + = render 'moderation_queue/button_box', comment_btn_params: @comment_btn_params diff --git a/config/locales/es.yml b/config/locales/es.yml index d579d55e..7850bcf7 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -12,7 +12,7 @@ es: text_deny: Bloquear que te siga text_allow: Permitir que te siga text_report: Reportar - comment_button_box: + button_box: text_pause: Pausa text_reject: Rechazar text_accept: Aceptar Publicación From bbd5426da53c7d3677fcc72f17da0f74b42e519e Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 1 Feb 2024 12:17:51 -0300 Subject: [PATCH 044/472] fix: eliminada botonera remote_profile_box para usar componente general button_box #15028 --- app/controllers/application_controller.rb | 7 ++++++- app/controllers/moderation_queue_controller.rb | 1 + app/views/moderation_queue/_profile_button_box.haml | 12 ------------ app/views/moderation_queue/_remote_profile.haml | 2 +- 4 files changed, 8 insertions(+), 14 deletions(-) delete mode 100644 app/views/moderation_queue/_profile_button_box.haml diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 360a9b2d..bcbf0bc2 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -37,7 +37,7 @@ class ApplicationController < ActionController::Base end end - # parámetros de botones + # parámetros de botones: # text: [texto del botón] # class: [clases css] # href: [href del botón] @@ -48,6 +48,11 @@ class ApplicationController < ActionController::Base [t('moderation_queue.button_box.text_accept'), 'bg-blue white', ''], [t('moderation_queue.button_box.text_reply'), 'btn-outline-primary', ''], [t('moderation_queue.button_box.text_report'), 'btn-danger', '']] + + #botones de remote_profile (cuentas) + @profile_btn_params = [[t('moderation_queue.profile_button_box.text_deny'), 'btn-outline-info', ''], + [t('moderation_queue.profile_button_box.text_allow'), 'btn-success', 'https://sutty.nl/'], + [t('moderation_queue.profile_button_box.text_report'), 'btn-outline-danger', 'https://sutty.nl/']] end def notify_unconfirmed_email diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index 04a31389..5141990e 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -15,6 +15,7 @@ class ModerationQueueController < ApplicationController # Perfil remoto de usuarie def remote_profile @remote_profile = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'remote_profile.yaml'))) + botoneras_moderation_queue end # todon.nl está usando /api/v2/instance diff --git a/app/views/moderation_queue/_profile_button_box.haml b/app/views/moderation_queue/_profile_button_box.haml deleted file mode 100644 index d15b6ed0..00000000 --- a/app/views/moderation_queue/_profile_button_box.haml +++ /dev/null @@ -1,12 +0,0 @@ --# Componente Botonera de Profile - -.d-flex.py-2.justify-content-center - -# parámetros de botones - -# text, class, href - - comment_btn_params = [[t('.text_deny'), 'btn-outline-info', ''], - [t('.text_allow'), 'btn-success', 'https://sutty.nl/'], - [t('.text_report'), 'btn-outline-danger', 'https://sutty.nl/']] - - - comment_btn_params.each do |btn| - - @class = btn[1] - = render 'moderation_queue/btn_base', href: btn[2], class: @class, text: btn[0] diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml index b665dcf2..a8d60c60 100644 --- a/app/views/moderation_queue/_remote_profile.haml +++ b/app/views/moderation_queue/_remote_profile.haml @@ -2,4 +2,4 @@ %h4= t('.profile_name') + ': ' + remote_profile['name'] %h5= t('.profile_id') + ': ' + remote_profile['id'] %h5= t('.profile_published') + ': ' + remote_profile['published'].to_datetime.strftime('%m/%d/%Y') - = render 'moderation_queue/profile_button_box' + = render 'moderation_queue/button_box', comment_btn_params: @profile_btn_params From e9552776af79f8608bed502eef779f609238a532 Mon Sep 17 00:00:00 2001 From: maki Date: Thu, 1 Feb 2024 14:40:14 -0300 Subject: [PATCH 045/472] =?UTF-8?q?feat:=20pantalla=20de=20actividades=20d?= =?UTF-8?q?e=20moderaci=C3=B3n=20dividida=20en=20desplegables=20#15091?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_comments.haml | 5 +++++ app/views/moderation_queue/index.haml | 11 +++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 app/views/moderation_queue/_comments.haml diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml new file mode 100644 index 00000000..39ac74a3 --- /dev/null +++ b/app/views/moderation_queue/_comments.haml @@ -0,0 +1,5 @@ += render 'moderation_queue/comment_filter_box' +- @moderation_queue.each do |comment| + + = render 'comment', comment: comment, profile: @remote_profile + = render 'moderation_queue/button_box', comment_btn_params: @comment_btn_params \ No newline at end of file diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml index 39ac74a3..e2adb13b 100644 --- a/app/views/moderation_queue/index.haml +++ b/app/views/moderation_queue/index.haml @@ -1,5 +1,8 @@ -= render 'moderation_queue/comment_filter_box' -- @moderation_queue.each do |comment| +.row.justify-content-center + .col-md-8 + - @summary = t('posts.edit.moderation_queue') + = render 'layouts/details', summary: @summary do + = render 'moderation_queue/comments', site: @site, post: @post, moderation_queue: @moderation_queue + + - = render 'comment', comment: comment, profile: @remote_profile - = render 'moderation_queue/button_box', comment_btn_params: @comment_btn_params \ No newline at end of file From 683062da02094a362a56bc13751065503b1d8237 Mon Sep 17 00:00:00 2001 From: maki Date: Thu, 1 Feb 2024 14:47:40 -0300 Subject: [PATCH 046/472] =?UTF-8?q?feat:=20textos=20con=20traducciones=20p?= =?UTF-8?q?ara=20los=20t=C3=ADtulos=20de=20los=20details=20de=20actividade?= =?UTF-8?q?s=20de=20moderaci=C3=B3n=20#15091?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/index.haml | 2 +- config/locales/en.yml | 4 ++++ config/locales/es.yml | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml index e2adb13b..8f4ed5fb 100644 --- a/app/views/moderation_queue/index.haml +++ b/app/views/moderation_queue/index.haml @@ -1,6 +1,6 @@ .row.justify-content-center .col-md-8 - - @summary = t('posts.edit.moderation_queue') + - @summary = t('moderation_queue.index.comments') = render 'layouts/details', summary: @summary do = render 'moderation_queue/comments', site: @site, post: @post, moderation_queue: @moderation_queue diff --git a/config/locales/en.yml b/config/locales/en.yml index ef14f51f..9b8bb92b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,5 +1,9 @@ en: moderation_queue: + index: + instances: Instances + accounts: Accounts + comments: Comments remote_profile: user: Username button_box: diff --git a/config/locales/es.yml b/config/locales/es.yml index 7850bcf7..ddf8f7f7 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1,5 +1,9 @@ es: moderation_queue: + index: + instances: Instancias + accounts: Cuentas + comments: Comentarios comment: source_profile: Cuenta de Origen reply_to: En respuesta a From a9efe78c0b93b44fed443c83a363d3e13b6fb60f Mon Sep 17 00:00:00 2001 From: maki Date: Thu, 1 Feb 2024 14:53:25 -0300 Subject: [PATCH 047/472] =?UTF-8?q?feat:=20aparecen=20todos=20los=20detail?= =?UTF-8?q?s=20en=20actividades=20de=20moderaci=C3=B3n,=20con=20los=20t?= =?UTF-8?q?=C3=ADtulos=20correspondientes,=20sin=20contenido=20(salvo=20co?= =?UTF-8?q?mentarios)=20#15091?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_accounts.haml | 0 app/views/moderation_queue/_instances.haml | 0 app/views/moderation_queue/index.haml | 6 ++++++ 3 files changed, 6 insertions(+) create mode 100644 app/views/moderation_queue/_accounts.haml create mode 100644 app/views/moderation_queue/_instances.haml diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml new file mode 100644 index 00000000..e69de29b diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml new file mode 100644 index 00000000..e69de29b diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml index 8f4ed5fb..d89c30b4 100644 --- a/app/views/moderation_queue/index.haml +++ b/app/views/moderation_queue/index.haml @@ -1,5 +1,11 @@ .row.justify-content-center .col-md-8 + - @summary = t('moderation_queue.index.instances') + = render 'layouts/details', summary: @summary do + = render 'moderation_queue/instances', site: @site, post: @post, moderation_queue: @moderation_queue + - @summary = t('moderation_queue.index.accounts') + = render 'layouts/details', summary: @summary do + = render 'moderation_queue/accounts', site: @site, post: @post, moderation_queue: @moderation_queue - @summary = t('moderation_queue.index.comments') = render 'layouts/details', summary: @summary do = render 'moderation_queue/comments', site: @site, post: @post, moderation_queue: @moderation_queue From da1f7f775447e2d8f50dd9973628fb93353c308c Mon Sep 17 00:00:00 2001 From: jazzari Date: Fri, 2 Feb 2024 14:45:25 -0300 Subject: [PATCH 048/472] fix: corregida botonera remote_profile #15080 --- app/controllers/application_controller.rb | 9 +++++---- app/views/moderation_queue/_button_box.haml | 4 ++-- app/views/moderation_queue/_comments.haml | 2 +- app/views/moderation_queue/_remote_profile.haml | 10 +++++++--- app/views/posts/_moderation_queue.haml | 2 +- config/locales/es.yml | 6 ++++-- 6 files changed, 20 insertions(+), 13 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index bcbf0bc2..ba5dd4bd 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -43,16 +43,17 @@ class ApplicationController < ActionController::Base # href: [href del botón] def botoneras_moderation_queue # botones de comentarios - @comment_btn_params = [[t('moderation_queue.button_box.text_pause'), 'btn-secondary', ''], + @btn_params = [[t('moderation_queue.button_box.text_pause'), 'btn-secondary', ''], [t('moderation_queue.button_box.text_reject'), 'btn-primary', ''], [t('moderation_queue.button_box.text_accept'), 'bg-blue white', ''], [t('moderation_queue.button_box.text_reply'), 'btn-outline-primary', ''], [t('moderation_queue.button_box.text_report'), 'btn-danger', '']] #botones de remote_profile (cuentas) - @profile_btn_params = [[t('moderation_queue.profile_button_box.text_deny'), 'btn-outline-info', ''], - [t('moderation_queue.profile_button_box.text_allow'), 'btn-success', 'https://sutty.nl/'], - [t('moderation_queue.profile_button_box.text_report'), 'btn-outline-danger', 'https://sutty.nl/']] + @profile_btn_params = [[t('moderation_queue.profile_button_box.text_approve'), 'btn-success', ''], + [t('moderation_queue.profile_button_box.text_check'), 'btn-outline-success', ''], + [t('moderation_queue.profile_button_box.text_deny'), 'bg-blue white', ''], + [t('moderation_queue.profile_button_box.text_report'), 'btn-danger', '']] end def notify_unconfirmed_email diff --git a/app/views/moderation_queue/_button_box.haml b/app/views/moderation_queue/_button_box.haml index a56b2552..46963b0f 100644 --- a/app/views/moderation_queue/_button_box.haml +++ b/app/views/moderation_queue/_button_box.haml @@ -1,6 +1,6 @@ -# Componente Botonera de Moderación -.d-flex.py-2.justify-content-center - - comment_btn_params.each do |btn| +.d-flex.py-4.justify-content-center + - btn_params.each do |btn| - @class = btn[1] = render 'moderation_queue/btn_base', href: btn[2], class: @class, text: btn[0] \ No newline at end of file diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index 39ac74a3..fb83fbd9 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -2,4 +2,4 @@ - @moderation_queue.each do |comment| = render 'comment', comment: comment, profile: @remote_profile - = render 'moderation_queue/button_box', comment_btn_params: @comment_btn_params \ No newline at end of file + = render 'moderation_queue/button_box', btn_params: @btn_params \ No newline at end of file diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml index a8d60c60..94737a34 100644 --- a/app/views/moderation_queue/_remote_profile.haml +++ b/app/views/moderation_queue/_remote_profile.haml @@ -1,5 +1,9 @@ +-# Componente Remote_Profile + .flex.py-2.mx-2.text-center - %h4= t('.profile_name') + ': ' + remote_profile['name'] - %h5= t('.profile_id') + ': ' + remote_profile['id'] + %h4.mb-2= t('.profile_name') + ': ' + remote_profile['name'] + %h5= t('.profile_id') + ': ' + remote_profile['id'] %h5= t('.profile_published') + ': ' + remote_profile['published'].to_datetime.strftime('%m/%d/%Y') - = render 'moderation_queue/button_box', comment_btn_params: @profile_btn_params + %h5= t('.profile_summary') + ':' + %p= sanitize remote_profile['summary'] + = render 'moderation_queue/button_box', btn_params: @profile_btn_params diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index e4eb422c..b259cf3e 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -4,4 +4,4 @@ - moderation_queue.each do |comment| = render 'moderation_queue/comment', comment: comment, profile: @remote_profile .row.d-flex.justify-content-center - = render 'moderation_queue/button_box', comment_btn_params: @comment_btn_params + = render 'moderation_queue/button_box', btn_params: @btn_params diff --git a/config/locales/es.yml b/config/locales/es.yml index ddf8f7f7..feca0897 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -12,9 +12,11 @@ es: profile_name: Nombre de la Cuenta profile_id: ID profile_published: Publicada + profile_summary: Resumen profile_button_box: - text_deny: Bloquear que te siga - text_allow: Permitir que te siga + text_approve: Aprovar siempre + text_check: Revisar siempre + text_deny: Bloquear text_report: Reportar button_box: text_pause: Pausa From cfae99ca7b3a001c735a45ac207288d8f57f606d Mon Sep 17 00:00:00 2001 From: jazzari Date: Fri, 2 Feb 2024 15:06:36 -0300 Subject: [PATCH 049/472] feat: agregada botonera instancias #15081 --- app/controllers/application_controller.rb | 5 +++++ config/locales/es.yml | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index ba5dd4bd..fd714a41 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -54,6 +54,11 @@ class ApplicationController < ActionController::Base [t('moderation_queue.profile_button_box.text_check'), 'btn-outline-success', ''], [t('moderation_queue.profile_button_box.text_deny'), 'bg-blue white', ''], [t('moderation_queue.profile_button_box.text_report'), 'btn-danger', '']] + + #botones de instances (instancias) + @instances_btn_params = [[t('moderation_queue.instances_button_box.text_check'), 'btn-outline-success', ''], + [t('moderation_queue.instances_button_box.text_allow'), 'btn-success', ''], + [t('moderation_queue.instances_button_box.text_deny'), 'btn-danger', '']] end def notify_unconfirmed_email diff --git a/config/locales/es.yml b/config/locales/es.yml index feca0897..476d75b3 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -28,6 +28,10 @@ es: text_order: Ordenar por text_show: Ver text_checked: Con los marcados + instances_button_box: + text_check: Moderar caso por caso + text_allow: Permitir todo + text_deny: Bloquear instancia dark: Oscuro es: Castellano en: English From 40346df76dd0c047dee905091a8223ec9d35f7a4 Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 5 Feb 2024 12:22:23 -0300 Subject: [PATCH 050/472] fix: movidas arrays de parametros de botones y filtros a helper moderation_queue_helper.rb #15077 --- app/controllers/application_controller.rb | 26 +--------- .../moderation_queue_controller.rb | 2 - app/controllers/posts_controller.rb | 1 - app/helpers/moderation_queue_helper.rb | 47 +++++++++++++++++++ .../moderation_queue/_comment_filter_box.haml | 6 --- app/views/moderation_queue/_comments.haml | 4 +- app/views/moderation_queue/_filter_base.haml | 7 ++- app/views/moderation_queue/_filter_box.haml | 6 +++ .../moderation_queue/_remote_profile.haml | 1 + app/views/posts/_moderation_queue.haml | 4 +- config/locales/es.yml | 7 ++- 11 files changed, 69 insertions(+), 42 deletions(-) create mode 100644 app/helpers/moderation_queue_helper.rb delete mode 100644 app/views/moderation_queue/_comment_filter_box.haml create mode 100644 app/views/moderation_queue/_filter_box.haml diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index fd714a41..f673ee83 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -36,31 +36,7 @@ class ApplicationController < ActionController::Base activity['attributedTo'] = @remote_profile end end - - # parámetros de botones: - # text: [texto del botón] - # class: [clases css] - # href: [href del botón] - def botoneras_moderation_queue - # botones de comentarios - @btn_params = [[t('moderation_queue.button_box.text_pause'), 'btn-secondary', ''], - [t('moderation_queue.button_box.text_reject'), 'btn-primary', ''], - [t('moderation_queue.button_box.text_accept'), 'bg-blue white', ''], - [t('moderation_queue.button_box.text_reply'), 'btn-outline-primary', ''], - [t('moderation_queue.button_box.text_report'), 'btn-danger', '']] - - #botones de remote_profile (cuentas) - @profile_btn_params = [[t('moderation_queue.profile_button_box.text_approve'), 'btn-success', ''], - [t('moderation_queue.profile_button_box.text_check'), 'btn-outline-success', ''], - [t('moderation_queue.profile_button_box.text_deny'), 'bg-blue white', ''], - [t('moderation_queue.profile_button_box.text_report'), 'btn-danger', '']] - - #botones de instances (instancias) - @instances_btn_params = [[t('moderation_queue.instances_button_box.text_check'), 'btn-outline-success', ''], - [t('moderation_queue.instances_button_box.text_allow'), 'btn-success', ''], - [t('moderation_queue.instances_button_box.text_deny'), 'btn-danger', '']] - end - + def notify_unconfirmed_email return unless current_usuarie return if current_usuarie.confirmed? diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index 5141990e..4a65f136 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -9,13 +9,11 @@ class ModerationQueueController < ApplicationController @moderation_queue.each do |activity| activity['attributedTo'] = @remote_profile end - botoneras_moderation_queue end # Perfil remoto de usuarie def remote_profile @remote_profile = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'remote_profile.yaml'))) - botoneras_moderation_queue end # todon.nl está usando /api/v2/instance diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 36d17339..5be56acc 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -83,7 +83,6 @@ class PostsController < ApplicationController breadcrumb post.title.value, site_post_path(site, post, locale: locale), match: :exact breadcrumb 'posts.edit', '' dummy_data - botoneras_moderation_queue end def update diff --git a/app/helpers/moderation_queue_helper.rb b/app/helpers/moderation_queue_helper.rb new file mode 100644 index 00000000..9c0a3ced --- /dev/null +++ b/app/helpers/moderation_queue_helper.rb @@ -0,0 +1,47 @@ +module ModerationQueueHelper + + # parámetros de botones: + # text: [texto del botón] + # class: [clases css] + # href: [href del botón] + def botoneras_moderation_queue + # botones de comentarios + @btn_params = [[t('moderation_queue.button_box.text_pause'), 'btn-secondary', ''], + [t('moderation_queue.button_box.text_reject'), 'btn-primary', ''], + [t('moderation_queue.button_box.text_accept'), 'bg-blue white', ''], + [t('moderation_queue.button_box.text_reply'), 'btn-outline-primary', ''], + [t('moderation_queue.button_box.text_report'), 'btn-danger', '']] + + #botones de remote_profile (cuentas) + @profile_btn_params = [[t('moderation_queue.profile_button_box.text_approve'), 'btn-success', ''], + [t('moderation_queue.profile_button_box.text_check'), 'btn-outline-success', ''], + [t('moderation_queue.profile_button_box.text_deny'), 'bg-blue white', ''], + [t('moderation_queue.profile_button_box.text_report'), 'btn-danger', '']] + + #botones de instances (instancias) + @instances_btn_params = [[t('moderation_queue.instances_button_box.text_check'), 'btn-outline-success', ''], + [t('moderation_queue.instances_button_box.text_allow'), 'btn-success', ''], + [t('moderation_queue.instances_button_box.text_deny'), 'btn-danger', '']] + end + + # parámetros de filtros: + # text: [texto del botón] + # href: [href del botón] + def filtros_moderation_queue + @comment_filter_params = { + t('moderation_queue.filter_box.text_checked') => + [ + [t('moderation_queue.filter_box.submenu_pause'), '/sutty.nl'], + [t('moderation_queue.filter_box.submenu_reject'), '#reject'], + [t('moderation_queue.filter_box.submenu_accept'),'#accept'] + ], + t('moderation_queue.filter_box.text_show') => + [ + [t('moderation_queue.filter_box.submenu_pause'), '#pause'], + [t('moderation_queue.filter_box.submenu_reject'), '#reject'], + [t('moderation_queue.filter_box.submenu_accept'),'#accept'], + [t('moderation_queue.filter_box.submenu_report'), '#report'] + ] + } + end +end \ No newline at end of file diff --git a/app/views/moderation_queue/_comment_filter_box.haml b/app/views/moderation_queue/_comment_filter_box.haml deleted file mode 100644 index e9abe602..00000000 --- a/app/views/moderation_queue/_comment_filter_box.haml +++ /dev/null @@ -1,6 +0,0 @@ --# Componente Caja de Filtros - -.d-flex.py-2.justify-content-center - = render 'moderation_queue/filter_base', text: t('.text_checked') - = render 'moderation_queue/filter_base', text: t('.text_show') - = render 'moderation_queue/filter_base', text: t('.text_order') \ No newline at end of file diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index fb83fbd9..217919bd 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -1,4 +1,6 @@ -= render 'moderation_queue/comment_filter_box' +- filtros_moderation_queue +- botoneras_moderation_queue += render 'moderation_queue/filter_box', filter_params: @comment_filter_params - @moderation_queue.each do |comment| = render 'comment', comment: comment, profile: @remote_profile diff --git a/app/views/moderation_queue/_filter_base.haml b/app/views/moderation_queue/_filter_base.haml index 0b63e59b..01d50641 100644 --- a/app/views/moderation_queue/_filter_base.haml +++ b/app/views/moderation_queue/_filter_base.haml @@ -1,8 +1,7 @@ -# Componente Filtro .dropdown.mx-4 %button#dropdownMenuButton.btn.btn-outline-secondary.dropdown-toggle{:type => "button", "data-toggle" => "dropdown", "aria-haspopup" => "true", "aria-expanded" => "false"} - %span #{text} + %span= text .dropdown-menu{"aria-labelledby" => "dropdownMenuButton"} - %a.dropdown-item{ href: '#' } Action - %a.dropdown-item{ href: '#' } Another action - %a.dropdown-item{ href: '#' } Something else here + - menu.each do |subm| + %a.dropdown-item{ href: subm[1] } subm[0] diff --git a/app/views/moderation_queue/_filter_box.haml b/app/views/moderation_queue/_filter_box.haml new file mode 100644 index 00000000..4ebef670 --- /dev/null +++ b/app/views/moderation_queue/_filter_box.haml @@ -0,0 +1,6 @@ +-# Componente Caja de Filtros + +.d-flex.py-2.justify-content-center + - filter_params.each do |filter, submenu| + = render 'moderation_queue/filter_base', text: filter, menu: submenu + diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml index 94737a34..548e2d5b 100644 --- a/app/views/moderation_queue/_remote_profile.haml +++ b/app/views/moderation_queue/_remote_profile.haml @@ -1,6 +1,7 @@ -# Componente Remote_Profile .flex.py-2.mx-2.text-center + - botoneras_moderation_queue %h4.mb-2= t('.profile_name') + ': ' + remote_profile['name'] %h5= t('.profile_id') + ': ' + remote_profile['id'] %h5= t('.profile_published') + ': ' + remote_profile['published'].to_datetime.strftime('%m/%d/%Y') diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index b259cf3e..34af2ac6 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -1,6 +1,8 @@ .flex %h3.text-center.py-2 Comentarios - = render 'moderation_queue/comment_filter_box' + - botoneras_moderation_queue + - filtros_moderation_queue + = render 'moderation_queue/filter_box', filter_params: @comment_filter_params - moderation_queue.each do |comment| = render 'moderation_queue/comment', comment: comment, profile: @remote_profile .row.d-flex.justify-content-center diff --git a/config/locales/es.yml b/config/locales/es.yml index 476d75b3..20696af0 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -24,10 +24,13 @@ es: text_accept: Aceptar Publicación text_reply: Responder text_report: Reportar - comment_filter_box: - text_order: Ordenar por + filter_box: text_show: Ver text_checked: Con los marcados + submenu_pause: Pausado + submenu_reject: Rechazado + submenu_accept: Aceptado + submenu_report: Reportado instances_button_box: text_check: Moderar caso por caso text_allow: Permitir todo From c668c3ad3f735760fd05a9fce9a49af3c201d78a Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 5 Feb 2024 12:30:13 -0300 Subject: [PATCH 051/472] fix: corregido submenu en partial filter_base #15079 --- app/views/moderation_queue/_filter_base.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/moderation_queue/_filter_base.haml b/app/views/moderation_queue/_filter_base.haml index 01d50641..67bb4b0c 100644 --- a/app/views/moderation_queue/_filter_base.haml +++ b/app/views/moderation_queue/_filter_base.haml @@ -4,4 +4,4 @@ %span= text .dropdown-menu{"aria-labelledby" => "dropdownMenuButton"} - menu.each do |subm| - %a.dropdown-item{ href: subm[1] } subm[0] + %a.dropdown-item{ href: subm[1] }= subm[0] From cfe90c531ea9be1429cf146db39df3ad0528c26e Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 5 Feb 2024 13:03:29 -0300 Subject: [PATCH 052/472] feat: agregado filtros instancias #15083 --- app/helpers/moderation_queue_helper.rb | 16 ++++++++++++++++ app/views/moderation_queue/_accounts.haml | 4 ++++ app/views/moderation_queue/_instances.haml | 6 ++++++ config/locales/es.yml | 2 ++ 4 files changed, 28 insertions(+) diff --git a/app/helpers/moderation_queue_helper.rb b/app/helpers/moderation_queue_helper.rb index 9c0a3ced..16be2a51 100644 --- a/app/helpers/moderation_queue_helper.rb +++ b/app/helpers/moderation_queue_helper.rb @@ -28,6 +28,7 @@ module ModerationQueueHelper # text: [texto del botón] # href: [href del botón] def filtros_moderation_queue + #filtros de comentarios @comment_filter_params = { t('moderation_queue.filter_box.text_checked') => [ @@ -43,5 +44,20 @@ module ModerationQueueHelper [t('moderation_queue.filter_box.submenu_report'), '#report'] ] } + + #filtros de instancias + @instances_filter_params = { + t('moderation_queue.filter_box.text_checked') => + [ + [t('moderation_queue.filter_box.submenu_case'), '#case_by_case'], + [t('moderation_queue.filter_box.submenu_allow'), '#allow'], + [t('moderation_queue.filter_box.submenu_reject'),'#reject'] + ], + t('moderation_queue.filter_box.text_show') => + [ + [t('moderation_queue.filter_box.submenu_allow'), '#allow'], + [t('moderation_queue.filter_box.submenu_reject'), '#reject'] + ] + } end end \ No newline at end of file diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index e69de29b..8ee71e7f 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -0,0 +1,4 @@ +- filtros_moderation_queue +- botoneras_moderation_queue + += render 'moderation_queue/button_box', btn_params: @profile_btn_params \ No newline at end of file diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index e69de29b..a814c1da 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -0,0 +1,6 @@ +- filtros_moderation_queue +- botoneras_moderation_queue + += render 'moderation_queue/filter_box', filter_params: @instances_filter_params + += render 'moderation_queue/button_box', btn_params: @instances_btn_params \ No newline at end of file diff --git a/config/locales/es.yml b/config/locales/es.yml index 20696af0..b4b7b1f4 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -31,6 +31,8 @@ es: submenu_reject: Rechazado submenu_accept: Aceptado submenu_report: Reportado + submenu_case: Moderar caso por caso + submenu_allow: Permitir todo instances_button_box: text_check: Moderar caso por caso text_allow: Permitir todo From 600a87c5ec2d4d4b4af2f9d2c40505b75269bcc8 Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 5 Feb 2024 13:13:06 -0300 Subject: [PATCH 053/472] feat: agregado filtros de cuentas #15102 --- app/views/moderation_queue/_accounts.haml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index 8ee71e7f..ae87a9d7 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -1,4 +1,6 @@ - filtros_moderation_queue - botoneras_moderation_queue += render 'moderation_queue/filter_box', filter_params: @instances_filter_params + = render 'moderation_queue/button_box', btn_params: @profile_btn_params \ No newline at end of file From 58ee39828a4cf048642c931b9c6c9607b6ceecfe Mon Sep 17 00:00:00 2001 From: f Date: Mon, 5 Feb 2024 13:16:57 -0300 Subject: [PATCH 054/472] feat: dropdown #15097 implement #15097 --- .../controllers/dropdown_controller.js | 106 ++++++++++++++++++ app/views/components/_dropdown.haml | 34 ++++++ app/views/components/_dropdown_item.haml | 4 + 3 files changed, 144 insertions(+) create mode 100644 app/javascript/controllers/dropdown_controller.js create mode 100644 app/views/components/_dropdown.haml create mode 100644 app/views/components/_dropdown_item.haml diff --git a/app/javascript/controllers/dropdown_controller.js b/app/javascript/controllers/dropdown_controller.js new file mode 100644 index 00000000..e2b657fd --- /dev/null +++ b/app/javascript/controllers/dropdown_controller.js @@ -0,0 +1,106 @@ +import { Controller } from "stimulus"; + +// https://getbootstrap.com/docs/4.6/components/dropdowns/#single-button +export default class extends Controller { + static targets = ["dropdown", "button", "item"]; + + // Al iniciar el controlador + connect() { + // Llevar la cuenta del item con foco + this.data.set("item", -1); + + // Gestionar las teclas + this.keydownEvent = this.keydown.bind(this); + this.element.addEventListener("keydown", this.keydownEvent); + + // Gestionar el foco + this.focusinEvent = this.focusin.bind(this); + } + + // Al eliminar el controlador (al pasar a otra página) + disconnect() { + // Eliminar la gestión de teclas + this.element.removeEventListener("keydown", this.keydownEvent); + // Eliminar la gestión del foco + document.removeEventListener("focusin", this.focusinEvent); + } + + // Mostrar u ocultar + toggle(event) { + (this.buttonTarget.ariaExpanded === "false") ? this.show() : this.hide(); + } + + // Mostrar + show() { + this.buttonTarget.ariaExpanded = "true"; + this.element.classList.add("show"); + this.dropdownTarget.classList.add("show"); + + // Activar la gestión del foco + document.addEventListener("focusin", this.focusinEvent); + } + + // Ocultar + hide() { + this.buttonTarget.ariaExpanded = "false"; + this.element.classList.remove("show"); + this.dropdownTarget.classList.remove("show"); + // Volver al inicio el foco de items + this.data.set("item", -1); + + // Desactivar la gestión del foco + document.removeEventListener("focusin", this.focusinEvent); + } + + // Gestionar el foco + focusin(event) { + const item = this.itemTargets.find(x => x === event.target); + + // Si el foco se coloca sobre elementos del controlador, no hacer + // nada + if (event.target === this.buttonTarget || item) { + // Si es un item, el comportamiento de las flechas verticales y el + // Tab tiene que ser igual + if (item) this.data.set("item", this.itemTargets.indexOf(item)); + + return; + } + + // De lo contrario, ocultar + this.hide(); + } + + // Gestionar las teclas + keydown(event) { + const initial = parseInt(this.data.get("item")); + let item = initial; + + switch (event.keyCode) { + case 27: + // Esc cierra el menú y devuelve el foco + this.hide(); + this.buttonTarget.focus(); + break; + case 38: + // Moverse hacia arriba con tope en el primer item + if (item > -1) item--; + + break; + case 40: + // Moverse hacia abajo con tope en el último ítem, si el + // dropdown estaba cerrado, abrirlo. + if (item === -1) this.show(); + if (item <= this.itemTargets.length) item++; + + break; + } + + // Si cambió la posición del ítem, darle foco y actualizar el + // contador. + if (initial !== item) { + this.itemTargets[item]?.focus(); + + this.data.set("item", item); + } + } +} diff --git a/app/views/components/_dropdown.haml b/app/views/components/_dropdown.haml new file mode 100644 index 00000000..54ddcffb --- /dev/null +++ b/app/views/components/_dropdown.haml @@ -0,0 +1,34 @@ +-# + @param :text [String] Contenido del botón + @param :button_classes [Array] Clases para el botón + @param :dropdown_classes [Array] Clases para el listado + @yield Un bloque que renderiza components/dropdown_item +- button_classes = local_assigns[:button_classes]&.join(' ') +- dropdown_classes = local_assigns[:dropdown_classes]&.join(' ') + +.btn-group{ + data: { + controller: 'dropdown' + } + } + %button.btn.dropdown-toggle{ + type: 'button', + class: button_classes, + data: { + toggle: 'true', + display: 'static', + action: 'dropdown#toggle', + target: 'dropdown.button' + }, + aria: { + expanded: 'false' + } + } + = text + .dropdown-menu{ + class: dropdown_classes, + data: { + target: 'dropdown.dropdown' + } + } + = yield diff --git a/app/views/components/_dropdown_item.haml b/app/views/components/_dropdown_item.haml new file mode 100644 index 00000000..3f79403d --- /dev/null +++ b/app/views/components/_dropdown_item.haml @@ -0,0 +1,4 @@ +-# + @param :text [String] Contenido del link + @param :path [String] Link += link_to text, path, class: 'dropdown-item', data: { target: 'dropdown.item' } From f9952792987bd12ec81ab4542d5c7647b5c1121d Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 5 Feb 2024 14:51:17 -0300 Subject: [PATCH 055/472] fix: corregidos filtros desplegables de comentarios, cuentas e instancias #15097 --- app/views/moderation_queue/_accounts.haml | 9 ++++++++- app/views/moderation_queue/_comments.haml | 13 +++++++++++-- app/views/moderation_queue/_filter_base.haml | 7 ------- app/views/moderation_queue/_filter_box.haml | 6 ------ app/views/moderation_queue/_instances.haml | 10 ++++++++-- app/views/moderation_queue/_remote_profile.haml | 14 +++++++++++++- app/views/posts/_moderation_queue.haml | 13 +++++++++++-- 7 files changed, 51 insertions(+), 21 deletions(-) delete mode 100644 app/views/moderation_queue/_filter_base.haml delete mode 100644 app/views/moderation_queue/_filter_box.haml diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index ae87a9d7..6a371eff 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -1,6 +1,13 @@ - filtros_moderation_queue - botoneras_moderation_queue -= render 'moderation_queue/filter_box', filter_params: @instances_filter_params +.d-flex.py-2.justify-content-center + = render 'components/dropdown', text: t('moderation_queue.filter_box.text_checked') do + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_case'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_allow'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' + = render 'components/dropdown', text: t('moderation_queue.filter_box.text_show') do + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_allow'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' = render 'moderation_queue/button_box', btn_params: @profile_btn_params \ No newline at end of file diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index 217919bd..3daddf44 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -1,6 +1,15 @@ -- filtros_moderation_queue - botoneras_moderation_queue -= render 'moderation_queue/filter_box', filter_params: @comment_filter_params +.d-flex.py-2.justify-content-center + = render 'components/dropdown', text: t('moderation_queue.filter_box.text_checked') do + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_pause'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_accept'), path: '/' + = render 'components/dropdown', text: t('moderation_queue.filter_box.text_show') do + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_pause'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_accept'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_report'), path: '/' + - @moderation_queue.each do |comment| = render 'comment', comment: comment, profile: @remote_profile diff --git a/app/views/moderation_queue/_filter_base.haml b/app/views/moderation_queue/_filter_base.haml deleted file mode 100644 index 67bb4b0c..00000000 --- a/app/views/moderation_queue/_filter_base.haml +++ /dev/null @@ -1,7 +0,0 @@ --# Componente Filtro -.dropdown.mx-4 - %button#dropdownMenuButton.btn.btn-outline-secondary.dropdown-toggle{:type => "button", "data-toggle" => "dropdown", "aria-haspopup" => "true", "aria-expanded" => "false"} - %span= text - .dropdown-menu{"aria-labelledby" => "dropdownMenuButton"} - - menu.each do |subm| - %a.dropdown-item{ href: subm[1] }= subm[0] diff --git a/app/views/moderation_queue/_filter_box.haml b/app/views/moderation_queue/_filter_box.haml deleted file mode 100644 index 4ebef670..00000000 --- a/app/views/moderation_queue/_filter_box.haml +++ /dev/null @@ -1,6 +0,0 @@ --# Componente Caja de Filtros - -.d-flex.py-2.justify-content-center - - filter_params.each do |filter, submenu| - = render 'moderation_queue/filter_base', text: filter, menu: submenu - diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index a814c1da..15b933d6 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -1,6 +1,12 @@ -- filtros_moderation_queue - botoneras_moderation_queue -= render 'moderation_queue/filter_box', filter_params: @instances_filter_params +.d-flex.py-2.justify-content-center + = render 'components/dropdown', text: t('moderation_queue.filter_box.text_checked') do + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_case'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_allow'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' + = render 'components/dropdown', text: t('moderation_queue.filter_box.text_show') do + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_allow'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' = render 'moderation_queue/button_box', btn_params: @instances_btn_params \ No newline at end of file diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml index 548e2d5b..7256f41d 100644 --- a/app/views/moderation_queue/_remote_profile.haml +++ b/app/views/moderation_queue/_remote_profile.haml @@ -2,7 +2,19 @@ .flex.py-2.mx-2.text-center - botoneras_moderation_queue - %h4.mb-2= t('.profile_name') + ': ' + remote_profile['name'] + + .d-flex.py-2.justify-content-center + = render 'components/dropdown', text: t('moderation_queue.filter_box.text_checked') do + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_pause'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_accept'), path: '/' + = render 'components/dropdown', text: t('moderation_queue.filter_box.text_show') do + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_pause'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_accept'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_report'), path: '/' + + %h4.my-2= t('.profile_name') + ': ' + remote_profile['name'] %h5= t('.profile_id') + ': ' + remote_profile['id'] %h5= t('.profile_published') + ': ' + remote_profile['published'].to_datetime.strftime('%m/%d/%Y') %h5= t('.profile_summary') + ':' diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index 34af2ac6..f805dfe8 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -1,8 +1,17 @@ .flex %h3.text-center.py-2 Comentarios - botoneras_moderation_queue - - filtros_moderation_queue - = render 'moderation_queue/filter_box', filter_params: @comment_filter_params + .d-flex.py-2.justify-content-center + = render 'components/dropdown', text: t('moderation_queue.filter_box.text_checked') do + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_pause'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_accept'), path: '/' + = render 'components/dropdown', text: t('moderation_queue.filter_box.text_show') do + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_pause'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_accept'), path: '/' + = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_report'), path: '/' + - moderation_queue.each do |comment| = render 'moderation_queue/comment', comment: comment, profile: @remote_profile .row.d-flex.justify-content-center From 6374a616d49f725f273da08bd44bbb7b5e209725 Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 5 Feb 2024 15:22:28 -0300 Subject: [PATCH 056/472] feat: agregado componente listas de bloqueo de instancias #15103 --- app/views/moderation_queue/_block_lists.haml | 4 ++++ app/views/moderation_queue/_instances.haml | 6 +++++- config/locales/es.yml | 4 ++++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 app/views/moderation_queue/_block_lists.haml diff --git a/app/views/moderation_queue/_block_lists.haml b/app/views/moderation_queue/_block_lists.haml new file mode 100644 index 00000000..186452fa --- /dev/null +++ b/app/views/moderation_queue/_block_lists.haml @@ -0,0 +1,4 @@ +.flex + .card + .card-body + %h4.text-center.red= t('moderation_queue.instances.block_lists') \ No newline at end of file diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index 15b933d6..57d4be34 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -9,4 +9,8 @@ = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_allow'), path: '/' = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' -= render 'moderation_queue/button_box', btn_params: @instances_btn_params \ No newline at end of file += render 'moderation_queue/button_box', btn_params: @instances_btn_params + +%h3.cyan.mt-5= t('moderation_queue.instances.title') +%p.pb-2= t('moderation_queue.instances.description') += render 'moderation_queue/block_lists' \ No newline at end of file diff --git a/config/locales/es.yml b/config/locales/es.yml index b4b7b1f4..6c608fff 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -37,6 +37,10 @@ es: text_check: Moderar caso por caso text_allow: Permitir todo text_deny: Bloquear instancia + instances: + title: Mis listas de bloqueo + description: Descripción de listas de bloqueo + block_lists: Listas de bloqueo dark: Oscuro es: Castellano en: English From db0364522db129ca62451ef2d81a7f80017f50d6 Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 5 Feb 2024 15:39:53 -0300 Subject: [PATCH 057/472] fix: agregado checkbox a compo listas de bloqueo #15103 --- app/views/moderation_queue/_block_lists.haml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/views/moderation_queue/_block_lists.haml b/app/views/moderation_queue/_block_lists.haml index 186452fa..55dc56d7 100644 --- a/app/views/moderation_queue/_block_lists.haml +++ b/app/views/moderation_queue/_block_lists.haml @@ -1,4 +1,5 @@ .flex .card - .card-body - %h4.text-center.red= t('moderation_queue.instances.block_lists') \ No newline at end of file + .card-body + %input{type: 'checkbox', value: '', class: 'ml-5'} + %h4.d-inline.red.ml-5= t('moderation_queue.instances.block_lists') \ No newline at end of file From b949855f08f6b2dfdc7fed3f0255eabfa2429f43 Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 5 Feb 2024 16:19:35 -0300 Subject: [PATCH 058/472] feat: creado componente lista personalizada de bloqueo de instancias #15104 --- app/views/moderation_queue/_block_instances_textarea.haml | 4 ++++ app/views/moderation_queue/_instances.haml | 3 ++- config/locales/es.yml | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 app/views/moderation_queue/_block_instances_textarea.haml diff --git a/app/views/moderation_queue/_block_instances_textarea.haml b/app/views/moderation_queue/_block_instances_textarea.haml new file mode 100644 index 00000000..42001504 --- /dev/null +++ b/app/views/moderation_queue/_block_instances_textarea.haml @@ -0,0 +1,4 @@ +.form-group + .d-flex.flex-column.mt-5 + %textarea.red.mb-3{name: '', id: '', placeholder: t('moderation_queue.instances.custom_block') } + %button.col-4.offset-md-8.rounded{type: 'submit', class: 'btn btn-primary'}= t('moderation_queue.instances.submit') diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index 57d4be34..c03055fa 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -13,4 +13,5 @@ %h3.cyan.mt-5= t('moderation_queue.instances.title') %p.pb-2= t('moderation_queue.instances.description') -= render 'moderation_queue/block_lists' \ No newline at end of file += render 'moderation_queue/block_lists' += render 'moderation_queue/block_instances_textarea' \ No newline at end of file diff --git a/config/locales/es.yml b/config/locales/es.yml index 6c608fff..96f068f3 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -41,6 +41,8 @@ es: title: Mis listas de bloqueo description: Descripción de listas de bloqueo block_lists: Listas de bloqueo + custom_block: Lista personalizada de bloqueo + submit: Guardar lista de bloqueo dark: Oscuro es: Castellano en: English From fc99ec79d3bd74d01084b25b3c25baa1b5ef2ca2 Mon Sep 17 00:00:00 2001 From: jazzari Date: Tue, 6 Feb 2024 12:57:42 -0300 Subject: [PATCH 059/472] fix: correciones de CI varias --- app/views/layouts/_details.haml | 4 ++-- .../moderation_queue/_block_instances_textarea.haml | 5 +++-- app/views/moderation_queue/_block_lists.haml | 2 +- app/views/moderation_queue/_btn_base.haml | 2 +- app/views/moderation_queue/_button_box.haml | 2 +- app/views/moderation_queue/_comment.haml | 10 +++++----- app/views/moderation_queue/_comments.haml | 2 +- app/views/moderation_queue/_instances.haml | 2 +- app/views/moderation_queue/_remote_profile.haml | 2 +- app/views/moderation_queue/index.haml | 5 +---- app/views/posts/_moderation_queue.haml | 2 +- 11 files changed, 18 insertions(+), 20 deletions(-) diff --git a/app/views/layouts/_details.haml b/app/views/layouts/_details.haml index 4fe4d2af..1fe8d2ec 100644 --- a/app/views/layouts/_details.haml +++ b/app/views/layouts/_details.haml @@ -1,6 +1,6 @@ -# Detail Cola de Moderación %details.details.py-2 - %summary + %summary %h3.py-2.text-center= @summary - = yield \ No newline at end of file + = yield diff --git a/app/views/moderation_queue/_block_instances_textarea.haml b/app/views/moderation_queue/_block_instances_textarea.haml index 42001504..22a63c39 100644 --- a/app/views/moderation_queue/_block_instances_textarea.haml +++ b/app/views/moderation_queue/_block_instances_textarea.haml @@ -1,4 +1,5 @@ .form-group .d-flex.flex-column.mt-5 - %textarea.red.mb-3{name: '', id: '', placeholder: t('moderation_queue.instances.custom_block') } - %button.col-4.offset-md-8.rounded{type: 'submit', class: 'btn btn-primary'}= t('moderation_queue.instances.submit') + %textarea.red.mb-3{ name: '', id: '', placeholder: t('moderation_queue.instances.custom_block') } + %button.col-4.offset-md-8.rounded{ type: 'submit', class: 'btn btn-primary' }= t('moderation_queue.instances.submit') + diff --git a/app/views/moderation_queue/_block_lists.haml b/app/views/moderation_queue/_block_lists.haml index 55dc56d7..669d451a 100644 --- a/app/views/moderation_queue/_block_lists.haml +++ b/app/views/moderation_queue/_block_lists.haml @@ -1,5 +1,5 @@ .flex .card .card-body - %input{type: 'checkbox', value: '', class: 'ml-5'} + %input{ type: 'checkbox', value: '', class: 'ml-5' } %h4.d-inline.red.ml-5= t('moderation_queue.instances.block_lists') \ No newline at end of file diff --git a/app/views/moderation_queue/_btn_base.haml b/app/views/moderation_queue/_btn_base.haml index 5f4561ef..0f9d7c08 100644 --- a/app/views/moderation_queue/_btn_base.haml +++ b/app/views/moderation_queue/_btn_base.haml @@ -1,3 +1,3 @@ -# Componente Botón general Moderación -%a.btn.btn-lg.rounded.mx-2{role: "button", href: href, class: @class} #{text} \ No newline at end of file +%a.btn.btn-lg.rounded.mx-2{role: 'button', href: href, class: @class} #{text} diff --git a/app/views/moderation_queue/_button_box.haml b/app/views/moderation_queue/_button_box.haml index 46963b0f..8971a780 100644 --- a/app/views/moderation_queue/_button_box.haml +++ b/app/views/moderation_queue/_button_box.haml @@ -3,4 +3,4 @@ .d-flex.py-4.justify-content-center - btn_params.each do |btn| - @class = btn[1] - = render 'moderation_queue/btn_base', href: btn[2], class: @class, text: btn[0] \ No newline at end of file + = render 'moderation_queue/btn_base', href: btn[2], class: @class, text: btn[0] diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index d443802d..d3532734 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -2,17 +2,17 @@ .flex.mx-4.my-5 .row.no-gutters .col-1 - %input{type: "checkbox", id: ""} + %input{ type: 'checkbox', id: '' } .col-10 .row.border.border-white .col.col-1.border.border-white.mr-5 %p= comment['published'].to_datetime.strftime('%m/%d/%Y') .col.border.border-white %span.mr-2= t('.source_profile') - %a{:href => comment['attributedTo']}= profile['preferredUsername'] - .row.border.border-white + %a{ href: comment['attributedTo'] }= profile['preferredUsername'] + .row.border.border-white %p.mr-3= t('.reply_to') %span - %a{:href => comment['inReplyTo']}= comment['inReplyTo'] - .row.border.border-white + %a{ href: comment['inReplyTo'] }= comment['inReplyTo'] + .row.border.border-white %p= sanitize comment['content'] diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index 3daddf44..39c8cfae 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -10,7 +10,7 @@ = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_accept'), path: '/' = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_report'), path: '/' -- @moderation_queue.each do |comment| +- moderation_queue.each do |comment| = render 'comment', comment: comment, profile: @remote_profile = render 'moderation_queue/button_box', btn_params: @btn_params \ No newline at end of file diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index c03055fa..811aeaec 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -14,4 +14,4 @@ %h3.cyan.mt-5= t('moderation_queue.instances.title') %p.pb-2= t('moderation_queue.instances.description') = render 'moderation_queue/block_lists' -= render 'moderation_queue/block_instances_textarea' \ No newline at end of file += render 'moderation_queue/block_instances_textarea' diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml index 7256f41d..b50d63e6 100644 --- a/app/views/moderation_queue/_remote_profile.haml +++ b/app/views/moderation_queue/_remote_profile.haml @@ -15,7 +15,7 @@ = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_report'), path: '/' %h4.my-2= t('.profile_name') + ': ' + remote_profile['name'] - %h5= t('.profile_id') + ': ' + remote_profile['id'] + %h5= t('.profile_id') + ': ' + remote_profile['id'] %h5= t('.profile_published') + ': ' + remote_profile['published'].to_datetime.strftime('%m/%d/%Y') %h5= t('.profile_summary') + ':' %p= sanitize remote_profile['summary'] diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml index d89c30b4..1a9838de 100644 --- a/app/views/moderation_queue/index.haml +++ b/app/views/moderation_queue/index.haml @@ -2,13 +2,10 @@ .col-md-8 - @summary = t('moderation_queue.index.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, post: @post, moderation_queue: @moderation_queue - @summary = t('moderation_queue.index.accounts') = render 'layouts/details', summary: @summary do = render 'moderation_queue/accounts', site: @site, post: @post, moderation_queue: @moderation_queue - @summary = t('moderation_queue.index.comments') = render 'layouts/details', summary: @summary do = render 'moderation_queue/comments', site: @site, post: @post, moderation_queue: @moderation_queue - - - diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index f805dfe8..34e30538 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -11,7 +11,7 @@ = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_accept'), path: '/' = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_report'), path: '/' - + - moderation_queue.each do |comment| = render 'moderation_queue/comment', comment: comment, profile: @remote_profile .row.d-flex.justify-content-center From 462d9a698eb69db27ec01bd1d4b2a36c119d9284 Mon Sep 17 00:00:00 2001 From: maki Date: Tue, 6 Feb 2024 13:56:20 -0300 Subject: [PATCH 060/472] para pullear --- app/views/moderation_queue/_accounts.haml | 3 +++ app/views/moderation_queue/_instances.haml | 1 + 2 files changed, 4 insertions(+) diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index e69de29b..5250ae87 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -0,0 +1,3 @@ += render 'moderation_queue/comment_filter_box' +- @moderation_queue.each do |comment| + = render 'account', comment: comment, profile: @remote_profile \ No newline at end of file diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index e69de29b..e279f484 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -0,0 +1 @@ += render 'moderation_queue/comment_filter_box' From c8267c44e85369a9d1ac9319b3816bcc4fa69934 Mon Sep 17 00:00:00 2001 From: maki Date: Tue, 6 Feb 2024 14:08:15 -0300 Subject: [PATCH 061/472] =?UTF-8?q?fix:=20error=20de=20merge=20y=20error?= =?UTF-8?q?=20de=20indentaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_account.haml | 0 app/views/moderation_queue/_accounts.haml | 3 +-- app/views/moderation_queue/_instances.haml | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) create mode 100644 app/views/moderation_queue/_account.haml diff --git a/app/views/moderation_queue/_account.haml b/app/views/moderation_queue/_account.haml new file mode 100644 index 00000000..e69de29b diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index 9300665b..26485119 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -1,6 +1,5 @@ -= render 'moderation_queue/comment_filter_box' - @moderation_queue.each do |comment| - = render 'account', comment: comment, profile: @remote_profile + = render 'account', comment: comment, profile: @remote_profile - filtros_moderation_queue - botoneras_moderation_queue diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index 1d083d27..811aeaec 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -1,4 +1,3 @@ -= render 'moderation_queue/comment_filter_box' - botoneras_moderation_queue .d-flex.py-2.justify-content-center From 6b0d2ded91f2dbbb7286457ae3b094af8d87a130 Mon Sep 17 00:00:00 2001 From: maki Date: Tue, 6 Feb 2024 16:50:26 -0300 Subject: [PATCH 062/472] =?UTF-8?q?feat:=20apartado=20de=20cuentas=20dentr?= =?UTF-8?q?o=20de=20actividades=20de=20moderaci=C3=B3n=20#15091?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/moderation_queue_controller.rb | 10 +++------- app/views/moderation_queue/_account.haml | 2 ++ app/views/moderation_queue/_accounts.haml | 5 ++--- config/locales/es.yml | 2 +- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index 4a65f136..eec0c70f 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -4,21 +4,17 @@ class ModerationQueueController < ApplicationController # Cola de moderación viendo todo el sitio def index - @moderation_queue = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'moderation_queue.yaml'))) - @remote_profile = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'remote_profile.yaml'))) - @moderation_queue.each do |activity| - activity['attributedTo'] = @remote_profile - end + dummy_data end # Perfil remoto de usuarie def remote_profile - @remote_profile = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'remote_profile.yaml'))) + dummy_data end # todon.nl está usando /api/v2/instance # mauve.moe usa /api/v1/instance def instances - @instances = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'instances.yaml'))) + dummy_data end end diff --git a/app/views/moderation_queue/_account.haml b/app/views/moderation_queue/_account.haml index e69de29b..751d0c0e 100644 --- a/app/views/moderation_queue/_account.haml +++ b/app/views/moderation_queue/_account.haml @@ -0,0 +1,2 @@ +%a{href: profile['id']}= profile['preferredUsername'] +%p= sanitize profile['summary'] \ No newline at end of file diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index 26485119..fcdfdce6 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -1,6 +1,3 @@ -- @moderation_queue.each do |comment| - = render 'account', comment: comment, profile: @remote_profile -- filtros_moderation_queue - botoneras_moderation_queue .d-flex.py-2.justify-content-center @@ -12,4 +9,6 @@ = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_allow'), path: '/' = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' +- @moderation_queue.map{|c| c['attributedTo']}.uniq.each do |remote_profile| + = render 'account', profile: remote_profile = render 'moderation_queue/button_box', btn_params: @profile_btn_params diff --git a/config/locales/es.yml b/config/locales/es.yml index 96f068f3..8828ee9f 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -14,7 +14,7 @@ es: profile_published: Publicada profile_summary: Resumen profile_button_box: - text_approve: Aprovar siempre + text_approve: Aprobar siempre text_check: Revisar siempre text_deny: Bloquear text_report: Reportar From ab1186d08a12c4adc10c3cb3f1b548b70b6030b1 Mon Sep 17 00:00:00 2001 From: maki Date: Tue, 6 Feb 2024 17:22:44 -0300 Subject: [PATCH 063/472] =?UTF-8?q?feat:=20apartado=20de=20instancias=20de?= =?UTF-8?q?ntro=20de=20actividades=20de=20moderaci=C3=B3n=20#15091?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_instance.haml | 11 +++++++++++ app/views/moderation_queue/_instances.haml | 4 +++- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 app/views/moderation_queue/_instance.haml diff --git a/app/views/moderation_queue/_instance.haml b/app/views/moderation_queue/_instance.haml new file mode 100644 index 00000000..d3b56a03 --- /dev/null +++ b/app/views/moderation_queue/_instance.haml @@ -0,0 +1,11 @@ +- host = instance['domain'] +- host ||= instance['uri'] +- host = "https://#{host}" + + +%a{href: host}= instance['title'] +%p= instance['description'] +%span Users: +%span + = instance.dig('usage', 'users', 'active_month') + = instance.dig('stats', 'user_count') diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index 811aeaec..88a1e11c 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -9,7 +9,9 @@ = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_allow'), path: '/' = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' -= render 'moderation_queue/button_box', btn_params: @instances_btn_params +- @instances.each do |instance| + = render 'moderation_queue/instance', instance: instance + = render 'moderation_queue/button_box', btn_params: @instances_btn_params %h3.cyan.mt-5= t('moderation_queue.instances.title') %p.pb-2= t('moderation_queue.instances.description') From f9a7d8d21ac031720d41fe0f6fce28475fc95304 Mon Sep 17 00:00:00 2001 From: maki Date: Tue, 6 Feb 2024 17:27:07 -0300 Subject: [PATCH 064/472] =?UTF-8?q?feat:=20t=C3=ADtulo=20para=20actividade?= =?UTF-8?q?s=20de=20moderaci=C3=B3n=20#15091?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/index.haml | 2 ++ config/locales/en.yml | 1 + config/locales/es.yml | 1 + 3 files changed, 4 insertions(+) diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml index 1a9838de..43b83b83 100644 --- a/app/views/moderation_queue/index.haml +++ b/app/views/moderation_queue/index.haml @@ -1,3 +1,5 @@ +.row.justify-content-center.mb-5 + %h1= t('moderation_queue.index.title') .row.justify-content-center .col-md-8 - @summary = t('moderation_queue.index.instances') diff --git a/config/locales/en.yml b/config/locales/en.yml index 9b8bb92b..9b06a78d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,6 +1,7 @@ en: moderation_queue: index: + title: Moderation instances: Instances accounts: Accounts comments: Comments diff --git a/config/locales/es.yml b/config/locales/es.yml index 8828ee9f..f1b5f2e5 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1,6 +1,7 @@ es: moderation_queue: index: + title: Actividades de moderación instances: Instancias accounts: Cuentas comments: Comentarios From dbdce703c3e40065e7b9588e44ec38420e990bfd Mon Sep 17 00:00:00 2001 From: jazzari Date: Wed, 7 Feb 2024 14:42:25 -0300 Subject: [PATCH 065/472] fix: corregidos botones en comentarios, instancias y cuentas #15028 --- app/helpers/moderation_queue_helper.rb | 63 ------------------- app/views/moderation_queue/_accounts.haml | 15 ++++- app/views/moderation_queue/_btn_base.haml | 2 +- app/views/moderation_queue/_button_box.haml | 6 -- app/views/moderation_queue/_comments.haml | 16 ++++- app/views/moderation_queue/_instances.haml | 14 ++++- .../moderation_queue/_remote_profile.haml | 15 ++++- app/views/posts/_moderation_queue.haml | 17 ++++- 8 files changed, 64 insertions(+), 84 deletions(-) delete mode 100644 app/helpers/moderation_queue_helper.rb delete mode 100644 app/views/moderation_queue/_button_box.haml diff --git a/app/helpers/moderation_queue_helper.rb b/app/helpers/moderation_queue_helper.rb deleted file mode 100644 index 16be2a51..00000000 --- a/app/helpers/moderation_queue_helper.rb +++ /dev/null @@ -1,63 +0,0 @@ -module ModerationQueueHelper - - # parámetros de botones: - # text: [texto del botón] - # class: [clases css] - # href: [href del botón] - def botoneras_moderation_queue - # botones de comentarios - @btn_params = [[t('moderation_queue.button_box.text_pause'), 'btn-secondary', ''], - [t('moderation_queue.button_box.text_reject'), 'btn-primary', ''], - [t('moderation_queue.button_box.text_accept'), 'bg-blue white', ''], - [t('moderation_queue.button_box.text_reply'), 'btn-outline-primary', ''], - [t('moderation_queue.button_box.text_report'), 'btn-danger', '']] - - #botones de remote_profile (cuentas) - @profile_btn_params = [[t('moderation_queue.profile_button_box.text_approve'), 'btn-success', ''], - [t('moderation_queue.profile_button_box.text_check'), 'btn-outline-success', ''], - [t('moderation_queue.profile_button_box.text_deny'), 'bg-blue white', ''], - [t('moderation_queue.profile_button_box.text_report'), 'btn-danger', '']] - - #botones de instances (instancias) - @instances_btn_params = [[t('moderation_queue.instances_button_box.text_check'), 'btn-outline-success', ''], - [t('moderation_queue.instances_button_box.text_allow'), 'btn-success', ''], - [t('moderation_queue.instances_button_box.text_deny'), 'btn-danger', '']] - end - - # parámetros de filtros: - # text: [texto del botón] - # href: [href del botón] - def filtros_moderation_queue - #filtros de comentarios - @comment_filter_params = { - t('moderation_queue.filter_box.text_checked') => - [ - [t('moderation_queue.filter_box.submenu_pause'), '/sutty.nl'], - [t('moderation_queue.filter_box.submenu_reject'), '#reject'], - [t('moderation_queue.filter_box.submenu_accept'),'#accept'] - ], - t('moderation_queue.filter_box.text_show') => - [ - [t('moderation_queue.filter_box.submenu_pause'), '#pause'], - [t('moderation_queue.filter_box.submenu_reject'), '#reject'], - [t('moderation_queue.filter_box.submenu_accept'),'#accept'], - [t('moderation_queue.filter_box.submenu_report'), '#report'] - ] - } - - #filtros de instancias - @instances_filter_params = { - t('moderation_queue.filter_box.text_checked') => - [ - [t('moderation_queue.filter_box.submenu_case'), '#case_by_case'], - [t('moderation_queue.filter_box.submenu_allow'), '#allow'], - [t('moderation_queue.filter_box.submenu_reject'),'#reject'] - ], - t('moderation_queue.filter_box.text_show') => - [ - [t('moderation_queue.filter_box.submenu_allow'), '#allow'], - [t('moderation_queue.filter_box.submenu_reject'), '#reject'] - ] - } - end -end \ No newline at end of file diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index fcdfdce6..825b77c2 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -1,5 +1,4 @@ -- botoneras_moderation_queue - +-# Filtros .d-flex.py-2.justify-content-center = render 'components/dropdown', text: t('moderation_queue.filter_box.text_checked') do = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_case'), path: '/' @@ -11,4 +10,14 @@ - @moderation_queue.map{|c| c['attributedTo']}.uniq.each do |remote_profile| = render 'account', profile: remote_profile -= render 'moderation_queue/button_box', btn_params: @profile_btn_params + +-# Botones de Moderación +.d-flex.py-4.justify-content-center + - @class = 'btn-success' + = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_approve'), class: @class, href: '' + - @class = 'btn-outline-success' + = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_check'), class: @class, href: '' + - @class = 'bg-blue white' + = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_deny'), class: @class, href: '' + - @class = 'btn-danger' + = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_report'), class: @class, href: '' diff --git a/app/views/moderation_queue/_btn_base.haml b/app/views/moderation_queue/_btn_base.haml index 0f9d7c08..41349ec5 100644 --- a/app/views/moderation_queue/_btn_base.haml +++ b/app/views/moderation_queue/_btn_base.haml @@ -1,3 +1,3 @@ -# Componente Botón general Moderación -%a.btn.btn-lg.rounded.mx-2{role: 'button', href: href, class: @class} #{text} +%button.btn.btn-lg.rounded.mx-2{ href: href, class: @class } #{text} diff --git a/app/views/moderation_queue/_button_box.haml b/app/views/moderation_queue/_button_box.haml deleted file mode 100644 index 8971a780..00000000 --- a/app/views/moderation_queue/_button_box.haml +++ /dev/null @@ -1,6 +0,0 @@ --# Componente Botonera de Moderación - -.d-flex.py-4.justify-content-center - - btn_params.each do |btn| - - @class = btn[1] - = render 'moderation_queue/btn_base', href: btn[2], class: @class, text: btn[0] diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index 39c8cfae..8bb11eec 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -1,4 +1,4 @@ -- botoneras_moderation_queue +-# Filtros .d-flex.py-2.justify-content-center = render 'components/dropdown', text: t('moderation_queue.filter_box.text_checked') do = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_pause'), path: '/' @@ -13,4 +13,16 @@ - moderation_queue.each do |comment| = render 'comment', comment: comment, profile: @remote_profile - = render 'moderation_queue/button_box', btn_params: @btn_params \ No newline at end of file + + -# Botones moderación + .d-flex.py-4.justify-content-center + - @class = 'btn-secondary' + = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_pause'), class: @class, href: '' + - @class = 'btn-primary' + = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_reject'), class: @class, href: '' + - @class = 'bg-blue white' + = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_accept'), class: @class, href: '' + - @class = 'btn-outline-primary' + = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_reply'), class: @class, href: '' + - @class = 'btn-danger' + = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_report'), class: @class, href: '' \ No newline at end of file diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index 88a1e11c..7af106ee 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -1,5 +1,4 @@ -- botoneras_moderation_queue - +-# Filtros .d-flex.py-2.justify-content-center = render 'components/dropdown', text: t('moderation_queue.filter_box.text_checked') do = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_case'), path: '/' @@ -11,7 +10,16 @@ - @instances.each do |instance| = render 'moderation_queue/instance', instance: instance - = render 'moderation_queue/button_box', btn_params: @instances_btn_params + + + -# Botones moderación + .d-flex.py-4.justify-content-center + - @class = 'btn-outline-success' + = render 'moderation_queue/btn_base', text: t('moderation_queue.instances_button_box.text_check'), class: @class, href: '' + - @class = 'btn-success' + = render 'moderation_queue/btn_base', text: t('moderation_queue.instances_button_box.text_check'), class: @class, href: '' + - @class = 'btn-danger' + = render 'moderation_queue/btn_base', text: t('moderation_queue.instances_button_box.text_check'), class: @class, href: '' %h3.cyan.mt-5= t('moderation_queue.instances.title') %p.pb-2= t('moderation_queue.instances.description') diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml index b50d63e6..a972b051 100644 --- a/app/views/moderation_queue/_remote_profile.haml +++ b/app/views/moderation_queue/_remote_profile.haml @@ -1,8 +1,7 @@ -# Componente Remote_Profile .flex.py-2.mx-2.text-center - - botoneras_moderation_queue - + -# Filtros .d-flex.py-2.justify-content-center = render 'components/dropdown', text: t('moderation_queue.filter_box.text_checked') do = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_pause'), path: '/' @@ -19,4 +18,14 @@ %h5= t('.profile_published') + ': ' + remote_profile['published'].to_datetime.strftime('%m/%d/%Y') %h5= t('.profile_summary') + ':' %p= sanitize remote_profile['summary'] - = render 'moderation_queue/button_box', btn_params: @profile_btn_params + +-# Botones de Moderación +.d-flex.py-4.justify-content-center + - @class = 'btn-success' + = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_approve'), class: @class, href: '' + - @class = 'btn-outline-success' + = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_check'), class: @class, href: '' + - @class = 'bg-blue white' + = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_deny'), class: @class, href: '' + - @class = 'btn-danger' + = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_report'), class: @class, href: '' diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index 34e30538..e7bbfd22 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -1,6 +1,6 @@ .flex %h3.text-center.py-2 Comentarios - - botoneras_moderation_queue + -# Filtros .d-flex.py-2.justify-content-center = render 'components/dropdown', text: t('moderation_queue.filter_box.text_checked') do = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_pause'), path: '/' @@ -14,5 +14,16 @@ - moderation_queue.each do |comment| = render 'moderation_queue/comment', comment: comment, profile: @remote_profile - .row.d-flex.justify-content-center - = render 'moderation_queue/button_box', btn_params: @btn_params + + -# Botones moderación + .d-flex.py-4.justify-content-center + - @class = 'btn-secondary' + = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_pause'), class: @class, href: '' + - @class = 'btn-primary' + = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_reject'), class: @class, href: '' + - @class = 'bg-blue white' + = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_accept'), class: @class, href: '' + - @class = 'btn-outline-primary' + = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_reply'), class: @class, href: '' + - @class = 'btn-danger' + = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_report'), class: @class, href: '' From 9ffd49aae2d116e6077341e20409b4f6a082590f Mon Sep 17 00:00:00 2001 From: jazzari Date: Wed, 7 Feb 2024 15:03:48 -0300 Subject: [PATCH 066/472] fix: corregida vista remote_profile --- app/views/moderation_queue/_remote_profile.haml | 4 ++++ config/locales/es.yml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml index a972b051..4a5e806f 100644 --- a/app/views/moderation_queue/_remote_profile.haml +++ b/app/views/moderation_queue/_remote_profile.haml @@ -19,6 +19,10 @@ %h5= t('.profile_summary') + ':' %p= sanitize remote_profile['summary'] + = render 'moderation_queue/comments', moderation_queue: @moderation_queue + +%h3.text-center.pt-4= t('.profile') +%h4.my-2.text-center= t('.profile_name') + ': ' + remote_profile['name'] -# Botones de Moderación .d-flex.py-4.justify-content-center - @class = 'btn-success' diff --git a/config/locales/es.yml b/config/locales/es.yml index f1b5f2e5..1127f357 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -9,7 +9,7 @@ es: source_profile: Cuenta de Origen reply_to: En respuesta a remote_profile: - profile: Cuentas + profile: Cuenta de Origen profile_name: Nombre de la Cuenta profile_id: ID profile_published: Publicada From 60950400086691f7cb38d3356baa25a773dfef2f Mon Sep 17 00:00:00 2001 From: jazzari Date: Wed, 7 Feb 2024 15:06:04 -0300 Subject: [PATCH 067/472] fix: corregidos filtros vista remote_profile --- app/views/moderation_queue/_remote_profile.haml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml index 4a5e806f..6afa2ed0 100644 --- a/app/views/moderation_queue/_remote_profile.haml +++ b/app/views/moderation_queue/_remote_profile.haml @@ -1,17 +1,6 @@ -# Componente Remote_Profile .flex.py-2.mx-2.text-center - -# Filtros - .d-flex.py-2.justify-content-center - = render 'components/dropdown', text: t('moderation_queue.filter_box.text_checked') do - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_pause'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_accept'), path: '/' - = render 'components/dropdown', text: t('moderation_queue.filter_box.text_show') do - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_pause'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_accept'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_report'), path: '/' %h4.my-2= t('.profile_name') + ': ' + remote_profile['name'] %h5= t('.profile_id') + ': ' + remote_profile['id'] From 471b82969078e24db1b1243349f57fe6438bc5f2 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 7 Feb 2024 16:24:52 -0300 Subject: [PATCH 068/472] feat: actualizar cliente de DP --- Gemfile | 2 +- Gemfile.lock | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 466ec079..80051e93 100644 --- a/Gemfile +++ b/Gemfile @@ -37,7 +37,7 @@ gem 'commonmarker' gem 'devise' gem 'devise-i18n' gem 'devise_invitable' -gem 'distributed-press-api-client', '~> 0.3.0rc0' +gem 'distributed-press-api-client', '~> 0.4.0rc0' gem 'email_address', git: 'https://github.com/fauno/email_address', branch: 'i18n' gem 'exception_notification' gem 'fast_blank' diff --git a/Gemfile.lock b/Gemfile.lock index 78563c84..90bf6d98 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -157,11 +157,12 @@ GEM devise_invitable (2.0.8) actionmailer (>= 5.0) devise (>= 4.6) - distributed-press-api-client (0.3.0rc0) + distributed-press-api-client (0.4.0rc0) addressable (~> 2.3, >= 2.3.0) climate_control dry-schema httparty (~> 0.18) + httparty-cache json (~> 2.1, >= 2.1.0) jwt (~> 2.6.0) dotenv (2.8.1) @@ -259,6 +260,8 @@ GEM httparty (0.21.0) mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) + httparty-cache (0.0.1) + httparty (~> 0.18) i18n (1.14.1) concurrent-ruby (~> 1.0) icalendar (2.8.0) @@ -600,7 +603,7 @@ DEPENDENCIES devise devise-i18n devise_invitable - distributed-press-api-client (~> 0.3.0rc0) + distributed-press-api-client (~> 0.4.0rc0) dotenv-rails down ed25519 From d5bfbc578f9751d778695eb4c0c99b55fe6a4ba9 Mon Sep 17 00:00:00 2001 From: jazzari Date: Wed, 7 Feb 2024 17:12:00 -0300 Subject: [PATCH 069/472] fix: correcciones varias de CI --- app/views/moderation_queue/_accounts.haml | 3 ++- app/views/moderation_queue/_block_lists.haml | 6 +++--- app/views/moderation_queue/_instance.haml | 7 +++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index 825b77c2..5c58f88b 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -8,7 +8,7 @@ = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_allow'), path: '/' = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' -- @moderation_queue.map{|c| c['attributedTo']}.uniq.each do |remote_profile| +- @moderation_queue.map{ |c| c['attributedTo'] }.uniq.each do |remote_profile| = render 'account', profile: remote_profile -# Botones de Moderación @@ -21,3 +21,4 @@ = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_deny'), class: @class, href: '' - @class = 'btn-danger' = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_report'), class: @class, href: '' + \ No newline at end of file diff --git a/app/views/moderation_queue/_block_lists.haml b/app/views/moderation_queue/_block_lists.haml index 669d451a..fdb3f044 100644 --- a/app/views/moderation_queue/_block_lists.haml +++ b/app/views/moderation_queue/_block_lists.haml @@ -1,5 +1,5 @@ -.flex - .card +.flex + .card .card-body %input{ type: 'checkbox', value: '', class: 'ml-5' } - %h4.d-inline.red.ml-5= t('moderation_queue.instances.block_lists') \ No newline at end of file + %h4.d-inline.red.ml-5= t('moderation_queue.instances.block_lists') diff --git a/app/views/moderation_queue/_instance.haml b/app/views/moderation_queue/_instance.haml index d3b56a03..80114985 100644 --- a/app/views/moderation_queue/_instance.haml +++ b/app/views/moderation_queue/_instance.haml @@ -2,10 +2,9 @@ - host ||= instance['uri'] - host = "https://#{host}" - -%a{href: host}= instance['title'] +%a{ href: host }= instance['title'] %p= instance['description'] %span Users: %span - = instance.dig('usage', 'users', 'active_month') - = instance.dig('stats', 'user_count') + = instance.dig('usage', 'users', 'active_month') + = instance.dig('stats', 'user_count') From a32a3ce7db29636ba854eecea3d5bc18d22d41cc Mon Sep 17 00:00:00 2001 From: jazzari Date: Wed, 7 Feb 2024 17:59:57 -0300 Subject: [PATCH 070/472] fix: corregidos colores de botones y details --- app/assets/stylesheets/application.scss | 19 +++---------------- app/views/moderation_queue/_accounts.haml | 8 ++++---- .../_block_instances_textarea.haml | 2 +- app/views/moderation_queue/_comments.haml | 8 ++++---- app/views/moderation_queue/_instances.haml | 10 +++++----- .../moderation_queue/_remote_profile.haml | 8 ++++---- app/views/posts/_moderation_queue.haml | 8 ++++---- 7 files changed, 25 insertions(+), 38 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index c0a666ab..836d647f 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -3,7 +3,6 @@ $white: white; $grey: grey; $cyan: #13fefe; $magenta: #f206f9; -$blue: blue; $colors: ( "black": $black, @@ -15,7 +14,6 @@ $colors: ( // Redefinir variables de Bootstrap $primary: $magenta; $secondary: $black; -$info: $blue; $jumbotron-bg: transparent; $enable-rounded: false; $form-feedback-valid-color: $black; @@ -569,26 +567,15 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); &::after { content: '▶'; - font-size: 2rem; + font-size: 1.7rem; position: absolute; left: 97%; - bottom: 2%; - transform: rotate(55deg); - color: $magenta - } - - &:focus { - background-color: #13FEFE; - color: black + bottom: 3%; + transform: rotate(58deg); } } .details[open] > summary::after { transform: rotate(90deg) translatey(-0.1em); - color: $magenta } -.bg-blue { - background-color: $azul; -} - diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index 5c58f88b..540d13a2 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -13,12 +13,12 @@ -# Botones de Moderación .d-flex.py-4.justify-content-center - - @class = 'btn-success' + - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_approve'), class: @class, href: '' - - @class = 'btn-outline-success' + - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_check'), class: @class, href: '' - - @class = 'bg-blue white' + - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_deny'), class: @class, href: '' - - @class = 'btn-danger' + - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_report'), class: @class, href: '' \ No newline at end of file diff --git a/app/views/moderation_queue/_block_instances_textarea.haml b/app/views/moderation_queue/_block_instances_textarea.haml index 22a63c39..4f294f0b 100644 --- a/app/views/moderation_queue/_block_instances_textarea.haml +++ b/app/views/moderation_queue/_block_instances_textarea.haml @@ -1,5 +1,5 @@ .form-group .d-flex.flex-column.mt-5 %textarea.red.mb-3{ name: '', id: '', placeholder: t('moderation_queue.instances.custom_block') } - %button.col-4.offset-md-8.rounded{ type: 'submit', class: 'btn btn-primary' }= t('moderation_queue.instances.submit') + %button.col-4.offset-md-8.rounded{ type: 'submit', class: 'btn btn-secondary' }= t('moderation_queue.instances.submit') diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index 8bb11eec..d7d300b7 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -18,11 +18,11 @@ .d-flex.py-4.justify-content-center - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_pause'), class: @class, href: '' - - @class = 'btn-primary' + - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_reject'), class: @class, href: '' - - @class = 'bg-blue white' + - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_accept'), class: @class, href: '' - - @class = 'btn-outline-primary' + - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_reply'), class: @class, href: '' - - @class = 'btn-danger' + - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_report'), class: @class, href: '' \ No newline at end of file diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index 7af106ee..ed5d2404 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -14,12 +14,12 @@ -# Botones moderación .d-flex.py-4.justify-content-center - - @class = 'btn-outline-success' - = render 'moderation_queue/btn_base', text: t('moderation_queue.instances_button_box.text_check'), class: @class, href: '' - - @class = 'btn-success' - = render 'moderation_queue/btn_base', text: t('moderation_queue.instances_button_box.text_check'), class: @class, href: '' - - @class = 'btn-danger' + - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.instances_button_box.text_check'), class: @class, href: '' + - @class = 'btn-secondary' + = render 'moderation_queue/btn_base', text: t('moderation_queue.instances_button_box.text_allow'), class: @class, href: '' + - @class = 'btn-secondary' + = render 'moderation_queue/btn_base', text: t('moderation_queue.instances_button_box.text_deny'), class: @class, href: '' %h3.cyan.mt-5= t('moderation_queue.instances.title') %p.pb-2= t('moderation_queue.instances.description') diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml index 6afa2ed0..755e96fd 100644 --- a/app/views/moderation_queue/_remote_profile.haml +++ b/app/views/moderation_queue/_remote_profile.haml @@ -14,11 +14,11 @@ %h4.my-2.text-center= t('.profile_name') + ': ' + remote_profile['name'] -# Botones de Moderación .d-flex.py-4.justify-content-center - - @class = 'btn-success' + - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_approve'), class: @class, href: '' - - @class = 'btn-outline-success' + - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_check'), class: @class, href: '' - - @class = 'bg-blue white' + - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_deny'), class: @class, href: '' - - @class = 'btn-danger' + - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_report'), class: @class, href: '' diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index e7bbfd22..f2acb818 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -19,11 +19,11 @@ .d-flex.py-4.justify-content-center - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_pause'), class: @class, href: '' - - @class = 'btn-primary' + - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_reject'), class: @class, href: '' - - @class = 'bg-blue white' + - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_accept'), class: @class, href: '' - - @class = 'btn-outline-primary' + - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_reply'), class: @class, href: '' - - @class = 'btn-danger' + - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_report'), class: @class, href: '' From 33cf101b5953fa18c82047a30d1f8593ff6ff26a Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 8 Feb 2024 14:41:50 -0300 Subject: [PATCH 071/472] =?UTF-8?q?fix:=20quitada=20alineaci=C3=B3n=20cent?= =?UTF-8?q?rada=20varios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/assets/stylesheets/application.scss | 4 ++-- app/controllers/posts_controller.rb | 2 +- app/views/layouts/_details.haml | 2 +- app/views/moderation_queue/_accounts.haml | 7 ++----- .../moderation_queue/_block_instances_textarea.haml | 5 +++-- app/views/moderation_queue/_block_lists.haml | 2 +- app/views/moderation_queue/_btn_base.haml | 2 +- app/views/moderation_queue/_comments.haml | 8 ++------ app/views/moderation_queue/_instances.haml | 12 +++++------- app/views/moderation_queue/_remote_profile.haml | 12 +++++------- app/views/moderation_queue/remote_profile.haml | 2 +- app/views/posts/_moderation_queue.haml | 6 +++--- 12 files changed, 27 insertions(+), 37 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 836d647f..5419bcdd 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -567,11 +567,11 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); &::after { content: '▶'; - font-size: 1.7rem; + font-size: 1.8rem; position: absolute; left: 97%; bottom: 3%; - transform: rotate(58deg); + transform: rotate(64deg); } } diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 5be56acc..99dc6f7d 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -38,7 +38,7 @@ class PostsController < ApplicationController @usuarie = site.usuarie? current_usuarie @site_stat = SiteStat.new(site) - @moderation_queue = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'moderation_queue.yaml'))) + dummy_data end def show diff --git a/app/views/layouts/_details.haml b/app/views/layouts/_details.haml index 1fe8d2ec..ac1d7c82 100644 --- a/app/views/layouts/_details.haml +++ b/app/views/layouts/_details.haml @@ -2,5 +2,5 @@ %details.details.py-2 %summary - %h3.py-2.text-center= @summary + %h3.py-2= @summary = yield diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index 540d13a2..1885059e 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -1,5 +1,5 @@ -# Filtros -.d-flex.py-2.justify-content-center +.d-flex.py-2 = render 'components/dropdown', text: t('moderation_queue.filter_box.text_checked') do = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_case'), path: '/' = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_allow'), path: '/' @@ -12,13 +12,10 @@ = render 'account', profile: remote_profile -# Botones de Moderación -.d-flex.py-4.justify-content-center +.d-flex.py-4 - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_approve'), class: @class, href: '' - - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_check'), class: @class, href: '' - - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_deny'), class: @class, href: '' - - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_report'), class: @class, href: '' \ No newline at end of file diff --git a/app/views/moderation_queue/_block_instances_textarea.haml b/app/views/moderation_queue/_block_instances_textarea.haml index 4f294f0b..34eb1e5d 100644 --- a/app/views/moderation_queue/_block_instances_textarea.haml +++ b/app/views/moderation_queue/_block_instances_textarea.haml @@ -1,5 +1,6 @@ .form-group .d-flex.flex-column.mt-5 - %textarea.red.mb-3{ name: '', id: '', placeholder: t('moderation_queue.instances.custom_block') } - %button.col-4.offset-md-8.rounded{ type: 'submit', class: 'btn btn-secondary' }= t('moderation_queue.instances.submit') + %textarea.mb-3{ name: '', id: '', placeholder: t('moderation_queue.instances.custom_block') } + .d-flex.justify-content-end + %button.col{ type: 'submit', class: 'btn btn-secondary' }= t('moderation_queue.instances.submit') diff --git a/app/views/moderation_queue/_block_lists.haml b/app/views/moderation_queue/_block_lists.haml index fdb3f044..577af12e 100644 --- a/app/views/moderation_queue/_block_lists.haml +++ b/app/views/moderation_queue/_block_lists.haml @@ -2,4 +2,4 @@ .card .card-body %input{ type: 'checkbox', value: '', class: 'ml-5' } - %h4.d-inline.red.ml-5= t('moderation_queue.instances.block_lists') + %h4.d-inline.ml-5= t('moderation_queue.instances.block_lists') diff --git a/app/views/moderation_queue/_btn_base.haml b/app/views/moderation_queue/_btn_base.haml index 41349ec5..7f6233cd 100644 --- a/app/views/moderation_queue/_btn_base.haml +++ b/app/views/moderation_queue/_btn_base.haml @@ -1,3 +1,3 @@ -# Componente Botón general Moderación -%button.btn.btn-lg.rounded.mx-2{ href: href, class: @class } #{text} +%button.btn.btn-lg.mx-2{ href: href, class: @class }= text diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index d7d300b7..9a9c9454 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -1,5 +1,5 @@ -# Filtros -.d-flex.py-2.justify-content-center +.d-flex.py-2 = render 'components/dropdown', text: t('moderation_queue.filter_box.text_checked') do = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_pause'), path: '/' = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' @@ -15,14 +15,10 @@ = render 'comment', comment: comment, profile: @remote_profile -# Botones moderación - .d-flex.py-4.justify-content-center + .d-flex.py-4 - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_pause'), class: @class, href: '' - - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_reject'), class: @class, href: '' - - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_accept'), class: @class, href: '' - - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_reply'), class: @class, href: '' - - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_report'), class: @class, href: '' \ No newline at end of file diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index ed5d2404..38f4ad51 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -1,5 +1,5 @@ -# Filtros -.d-flex.py-2.justify-content-center +.d-flex.py-2 = render 'components/dropdown', text: t('moderation_queue.filter_box.text_checked') do = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_case'), path: '/' = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_allow'), path: '/' @@ -13,15 +13,13 @@ -# Botones moderación - .d-flex.py-4.justify-content-center - - @class = 'btn-secondary' + .d-flex.py-4 + - @class = 'btn btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.instances_button_box.text_check'), class: @class, href: '' - - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.instances_button_box.text_allow'), class: @class, href: '' - - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.instances_button_box.text_deny'), class: @class, href: '' -%h3.cyan.mt-5= t('moderation_queue.instances.title') -%p.pb-2= t('moderation_queue.instances.description') +%h3.mt-5= t('moderation_queue.instances.title') +%p= t('moderation_queue.instances.description') = render 'moderation_queue/block_lists' = render 'moderation_queue/block_instances_textarea' diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml index 755e96fd..965f8854 100644 --- a/app/views/moderation_queue/_remote_profile.haml +++ b/app/views/moderation_queue/_remote_profile.haml @@ -1,6 +1,6 @@ -# Componente Remote_Profile -.flex.py-2.mx-2.text-center +.flex.py-2.mx-2 %h4.my-2= t('.profile_name') + ': ' + remote_profile['name'] %h5= t('.profile_id') + ': ' + remote_profile['id'] @@ -10,15 +10,13 @@ = render 'moderation_queue/comments', moderation_queue: @moderation_queue -%h3.text-center.pt-4= t('.profile') -%h4.my-2.text-center= t('.profile_name') + ': ' + remote_profile['name'] +%h3.pt-4= t('.profile') +%h4.my-2= t('.profile_name') + ': ' + remote_profile['name'] + -# Botones de Moderación -.d-flex.py-4.justify-content-center +.d-flex.py-4 - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_approve'), class: @class, href: '' - - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_check'), class: @class, href: '' - - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_deny'), class: @class, href: '' - - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_report'), class: @class, href: '' diff --git a/app/views/moderation_queue/remote_profile.haml b/app/views/moderation_queue/remote_profile.haml index 3eab5e35..ed66a394 100644 --- a/app/views/moderation_queue/remote_profile.haml +++ b/app/views/moderation_queue/remote_profile.haml @@ -1,3 +1,3 @@ .flex - %h1.text-center= t('.profile') + %h1= t('.profile') = render 'moderation_queue/remote_profile', remote_profile: @remote_profile diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index f2acb818..6db885bb 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -1,7 +1,7 @@ .flex - %h3.text-center.py-2 Comentarios + %h3.py-2 Comentarios -# Filtros - .d-flex.py-2.justify-content-center + .d-flex.py-2 = render 'components/dropdown', text: t('moderation_queue.filter_box.text_checked') do = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_pause'), path: '/' = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' @@ -16,7 +16,7 @@ = render 'moderation_queue/comment', comment: comment, profile: @remote_profile -# Botones moderación - .d-flex.py-4.justify-content-center + .d-flex.py-4 - @class = 'btn-secondary' = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_pause'), class: @class, href: '' - @class = 'btn-secondary' From ffc3f4a72aa9514e061799d6b33971eba87de8ae Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 8 Feb 2024 15:02:09 -0300 Subject: [PATCH 072/472] fix: corregido texto de comentarios en componente moderation_queue --- app/views/posts/_moderation_queue.haml | 1 - config/locales/es.yml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index 6db885bb..fa6adfef 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -1,5 +1,4 @@ .flex - %h3.py-2 Comentarios -# Filtros .d-flex.py-2 = render 'components/dropdown', text: t('moderation_queue.filter_box.text_checked') do diff --git a/config/locales/es.yml b/config/locales/es.yml index 1127f357..fd1626e3 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -566,7 +566,7 @@ es: ar: 'árabe' posts: edit: - moderation_queue: Cola de Moderación + moderation_queue: Comentarios post: Contenido prev: Página anterior next: Página siguiente From 47de966f69a4558980080a1c5c97d6b8857aa0df Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 8 Feb 2024 17:59:10 -0300 Subject: [PATCH 073/472] fix: cambiadas variables globales por locales --- app/views/layouts/_details.haml | 2 +- app/views/moderation_queue/_comments.haml | 11 +---------- app/views/moderation_queue/index.haml | 14 +++++++------- app/views/posts/edit.haml | 8 ++++---- 4 files changed, 13 insertions(+), 22 deletions(-) diff --git a/app/views/layouts/_details.haml b/app/views/layouts/_details.haml index ac1d7c82..306986bf 100644 --- a/app/views/layouts/_details.haml +++ b/app/views/layouts/_details.haml @@ -2,5 +2,5 @@ %details.details.py-2 %summary - %h3.py-2= @summary + %h3.py-2= summary = yield diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index 9a9c9454..e4285326 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -1,14 +1,5 @@ -# Filtros -.d-flex.py-2 - = render 'components/dropdown', text: t('moderation_queue.filter_box.text_checked') do - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_pause'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_accept'), path: '/' - = render 'components/dropdown', text: t('moderation_queue.filter_box.text_show') do - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_pause'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_accept'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_report'), path: '/' += render 'moderation_queue/filter_box' - moderation_queue.each do |comment| diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml index 43b83b83..b361c085 100644 --- a/app/views/moderation_queue/index.haml +++ b/app/views/moderation_queue/index.haml @@ -1,13 +1,13 @@ .row.justify-content-center.mb-5 - %h1= t('moderation_queue.index.title') + %h1= t('.title') .row.justify-content-center .col-md-8 - - @summary = t('moderation_queue.index.instances') - = render 'layouts/details', summary: @summary do + - summary = t('.instances') + = render 'layouts/details', summary: summary do = render 'moderation_queue/instances', site: @site, post: @post, moderation_queue: @moderation_queue - - @summary = t('moderation_queue.index.accounts') - = render 'layouts/details', summary: @summary do + - summary = t('.accounts') + = render 'layouts/details', summary: summary do = render 'moderation_queue/accounts', site: @site, post: @post, moderation_queue: @moderation_queue - - @summary = t('moderation_queue.index.comments') - = render 'layouts/details', summary: @summary do + - summary = t('.comments') + = render 'layouts/details', summary: summary do = render 'moderation_queue/comments', site: @site, post: @post, moderation_queue: @moderation_queue diff --git a/app/views/posts/edit.haml b/app/views/posts/edit.haml index 5234f257..2e46590e 100644 --- a/app/views/posts/edit.haml +++ b/app/views/posts/edit.haml @@ -1,8 +1,8 @@ .row.justify-content-center .col-md-8 - - @summary = t('posts.edit.post') - = render 'layouts/details', summary: @summary do + - summary = t('posts.edit.post') + = render 'layouts/details', summary: summary do = render 'posts/form', site: @site, post: @post - - @summary = t('posts.edit.moderation_queue') - = render 'layouts/details', summary: @summary do + - summary = t('posts.edit.moderation_queue') + = render 'layouts/details', summary: summary do = render 'posts/moderation_queue', site: @site, post: @post, moderation_queue: @moderation_queue From 111f2d65030bae4ce010e26b09eac2bfdfe60c86 Mon Sep 17 00:00:00 2001 From: jazzari Date: Fri, 9 Feb 2024 12:01:04 -0300 Subject: [PATCH 074/472] fix: creados componentes de filtros para comentarios, cuentas e instancias --- .../components/_comments_checked_submenu.haml | 3 ++ app/views/components/_comments_filters.haml | 6 +++ .../components/_comments_show_submenu.haml | 4 ++ .../_instances_checked_submenu.haml | 3 ++ app/views/components/_instances_filters.haml | 6 +++ .../components/_instances_show_submenu.haml | 2 + .../components/_profiles_checked_submenu.haml | 4 ++ app/views/components/_profiles_filters.haml | 6 +++ .../components/_profiles_show_submenu.haml | 3 ++ app/views/moderation_queue/_accounts.haml | 9 +--- app/views/moderation_queue/_comments.haml | 2 +- app/views/moderation_queue/_instances.haml | 10 +--- app/views/posts/_moderation_queue.haml | 11 +---- config/locales/es.yml | 47 +++++++++++++++---- 14 files changed, 79 insertions(+), 37 deletions(-) create mode 100644 app/views/components/_comments_checked_submenu.haml create mode 100644 app/views/components/_comments_filters.haml create mode 100644 app/views/components/_comments_show_submenu.haml create mode 100644 app/views/components/_instances_checked_submenu.haml create mode 100644 app/views/components/_instances_filters.haml create mode 100644 app/views/components/_instances_show_submenu.haml create mode 100644 app/views/components/_profiles_checked_submenu.haml create mode 100644 app/views/components/_profiles_filters.haml create mode 100644 app/views/components/_profiles_show_submenu.haml diff --git a/app/views/components/_comments_checked_submenu.haml b/app/views/components/_comments_checked_submenu.haml new file mode 100644 index 00000000..4998e5c7 --- /dev/null +++ b/app/views/components/_comments_checked_submenu.haml @@ -0,0 +1,3 @@ += render 'components/dropdown_item', text: t('.submenu_pause'), path: '/' += render 'components/dropdown_item', text: t('.submenu_accept'), path: '/' += render 'components/dropdown_item', text: t('.submenu_reject'), path: '/' \ No newline at end of file diff --git a/app/views/components/_comments_filters.haml b/app/views/components/_comments_filters.haml new file mode 100644 index 00000000..7c453088 --- /dev/null +++ b/app/views/components/_comments_filters.haml @@ -0,0 +1,6 @@ +.d-flex.py-2 + = render 'components/dropdown', text: t('.text_checked') do + = render 'components/comments_checked_submenu' + + = render 'components/dropdown', text: t('.text_show') do + = render 'components/comments_show_submenu' \ No newline at end of file diff --git a/app/views/components/_comments_show_submenu.haml b/app/views/components/_comments_show_submenu.haml new file mode 100644 index 00000000..0308b926 --- /dev/null +++ b/app/views/components/_comments_show_submenu.haml @@ -0,0 +1,4 @@ += render 'components/dropdown_item', text: t('.submenu_pause'), path: '/' += render 'components/dropdown_item', text: t('.submenu_accept'), path: '/' += render 'components/dropdown_item', text: t('.submenu_report'), path: '/' += render 'components/dropdown_item', text: t('.submenu_reject'), path: '/' \ No newline at end of file diff --git a/app/views/components/_instances_checked_submenu.haml b/app/views/components/_instances_checked_submenu.haml new file mode 100644 index 00000000..f0b76185 --- /dev/null +++ b/app/views/components/_instances_checked_submenu.haml @@ -0,0 +1,3 @@ += render 'components/dropdown_item', text: t('.submenu_case'), path: '/' += render 'components/dropdown_item', text: t('.submenu_allow'), path: '/' += render 'components/dropdown_item', text: t('.submenu_reject'), path: '/' \ No newline at end of file diff --git a/app/views/components/_instances_filters.haml b/app/views/components/_instances_filters.haml new file mode 100644 index 00000000..213bb7c0 --- /dev/null +++ b/app/views/components/_instances_filters.haml @@ -0,0 +1,6 @@ +.d-flex.py-2 + = render 'components/dropdown', text: t('.text_checked') do + = render 'components/instances_checked_submenu' + + = render 'components/dropdown', text: t('.text_show') do + = render 'components/comments_show_submenu' diff --git a/app/views/components/_instances_show_submenu.haml b/app/views/components/_instances_show_submenu.haml new file mode 100644 index 00000000..1074cc3f --- /dev/null +++ b/app/views/components/_instances_show_submenu.haml @@ -0,0 +1,2 @@ += render 'components/dropdown_item', text: t('.submenu_allow'), path: '/' += render 'components/dropdown_item', text: t('.submenu_reject'), path: '/' \ No newline at end of file diff --git a/app/views/components/_profiles_checked_submenu.haml b/app/views/components/_profiles_checked_submenu.haml new file mode 100644 index 00000000..8d8f8940 --- /dev/null +++ b/app/views/components/_profiles_checked_submenu.haml @@ -0,0 +1,4 @@ += render 'components/dropdown_item', text: t('.submenu_pause'), path: '/' += render 'components/dropdown_item', text: t('.submenu_accept'), path: '/' += render 'components/dropdown_item', text: t('.submenu_reject'), path: '/' += render 'components/dropdown_item', text: t('.submenu_block'), path: '/' diff --git a/app/views/components/_profiles_filters.haml b/app/views/components/_profiles_filters.haml new file mode 100644 index 00000000..0088afef --- /dev/null +++ b/app/views/components/_profiles_filters.haml @@ -0,0 +1,6 @@ +.d-flex.py-2 + = render 'components/dropdown', text: t('.text_checked') do + = render 'components/profiles_checked_submenu' + + = render 'components/dropdown', text: t('.text_show') do + = render 'components/profiles_show_submenu' \ No newline at end of file diff --git a/app/views/components/_profiles_show_submenu.haml b/app/views/components/_profiles_show_submenu.haml new file mode 100644 index 00000000..2ba949b1 --- /dev/null +++ b/app/views/components/_profiles_show_submenu.haml @@ -0,0 +1,3 @@ += render 'components/dropdown_item', text: t('.submenu_accept'), path: '/' += render 'components/dropdown_item', text: t('.submenu_reject'), path: '/' += render 'components/dropdown_item', text: t('.submenu_block'), path: '/' \ No newline at end of file diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index 1885059e..e954d2f3 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -1,12 +1,5 @@ -# Filtros -.d-flex.py-2 - = render 'components/dropdown', text: t('moderation_queue.filter_box.text_checked') do - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_case'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_allow'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' - = render 'components/dropdown', text: t('moderation_queue.filter_box.text_show') do - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_allow'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' += render 'components/profiles_filters' - @moderation_queue.map{ |c| c['attributedTo'] }.uniq.each do |remote_profile| = render 'account', profile: remote_profile diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index e4285326..c5f7ae5d 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -1,5 +1,5 @@ -# Filtros -= render 'moderation_queue/filter_box' += render 'components/comments_filters' - moderation_queue.each do |comment| diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index 38f4ad51..e50a6e02 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -1,17 +1,9 @@ -# Filtros -.d-flex.py-2 - = render 'components/dropdown', text: t('moderation_queue.filter_box.text_checked') do - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_case'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_allow'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' - = render 'components/dropdown', text: t('moderation_queue.filter_box.text_show') do - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_allow'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' += render 'components/instances_filters' - @instances.each do |instance| = render 'moderation_queue/instance', instance: instance - -# Botones moderación .d-flex.py-4 - @class = 'btn btn-secondary' diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index fa6adfef..df17b1ff 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -1,15 +1,6 @@ .flex -# Filtros - .d-flex.py-2 - = render 'components/dropdown', text: t('moderation_queue.filter_box.text_checked') do - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_pause'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_accept'), path: '/' - = render 'components/dropdown', text: t('moderation_queue.filter_box.text_show') do - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_pause'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_reject'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_accept'), path: '/' - = render 'components/dropdown_item', text: t('moderation_queue.filter_box.submenu_report'), path: '/' + = render 'components/comments_filters' - moderation_queue.each do |comment| = render 'moderation_queue/comment', comment: comment, profile: @remote_profile diff --git a/config/locales/es.yml b/config/locales/es.yml index fd1626e3..7cd59cbf 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1,4 +1,39 @@ es: + components: + instances_filters: + text_show: Ver + text_checked: Con los marcados + instances_checked_submenu: + submenu_case: Moderar caso por caso + submenu_allow: Permitir todo + submenu_reject: Rechazado + instances_show_submenu: + submenu_allow: Permitido + submenu_reject: Rechazado + comments_filters: + text_show: Ver + text_checked: Con los marcados + comments_checked_submenu: + submenu_pause: Pausado + submenu_accept: Aceptado + submenu_reject: Rechazado + comments_show_submenu: + submenu_pause: Pausado + submenu_accept: Aceptado + submenu_report: Reportado + submenu_reject: Rechazado + profiles_filters: + text_show: Ver + text_checked: Con los marcados + profiles_checked_submenu: + submenu_pause: Pausado + submenu_accept: Aceptado + submenu_reject: Rechazado + submenu_block: Bloqueado + profiles_show_submenu: + submenu_accept: Aceptado + submenu_block: Bloqueado + submenu_reject: Rechazado moderation_queue: index: title: Actividades de moderación @@ -25,15 +60,6 @@ es: text_accept: Aceptar Publicación text_reply: Responder text_report: Reportar - filter_box: - text_show: Ver - text_checked: Con los marcados - submenu_pause: Pausado - submenu_reject: Rechazado - submenu_accept: Aceptado - submenu_report: Reportado - submenu_case: Moderar caso por caso - submenu_allow: Permitir todo instances_button_box: text_check: Moderar caso por caso text_allow: Permitir todo @@ -44,6 +70,9 @@ es: block_lists: Listas de bloqueo custom_block: Lista personalizada de bloqueo submit: Guardar lista de bloqueo + comments_filter_box: + text_show: Ver + text_checked: Con los marcados dark: Oscuro es: Castellano en: English From 754538024efdde09cceaab35ea1680d3fe6d57c3 Mon Sep 17 00:00:00 2001 From: jazzari Date: Fri, 9 Feb 2024 13:17:00 -0300 Subject: [PATCH 075/472] feat: agregado componente checkbox --- app/views/components/_checkbox.haml | 2 ++ app/views/moderation_queue/_block_lists.haml | 2 +- app/views/moderation_queue/_comment.haml | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 app/views/components/_checkbox.haml diff --git a/app/views/components/_checkbox.haml b/app/views/components/_checkbox.haml new file mode 100644 index 00000000..ccf22e84 --- /dev/null +++ b/app/views/components/_checkbox.haml @@ -0,0 +1,2 @@ +.custom-control.custom-checkbox + %input{ type: 'checkbox', id: '', class: '' } \ No newline at end of file diff --git a/app/views/moderation_queue/_block_lists.haml b/app/views/moderation_queue/_block_lists.haml index 577af12e..14dd770e 100644 --- a/app/views/moderation_queue/_block_lists.haml +++ b/app/views/moderation_queue/_block_lists.haml @@ -1,5 +1,5 @@ .flex .card .card-body - %input{ type: 'checkbox', value: '', class: 'ml-5' } + = render 'components/checkbox' %h4.d-inline.ml-5= t('moderation_queue.instances.block_lists') diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index d3532734..463f47c7 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -2,7 +2,7 @@ .flex.mx-4.my-5 .row.no-gutters .col-1 - %input{ type: 'checkbox', id: '' } + = render 'components/checkbox' .col-10 .row.border.border-white .col.col-1.border.border-white.mr-5 From 31294ccbc7f3bba6e61d99b23fc762bdbd9bd333 Mon Sep 17 00:00:00 2001 From: jazzari Date: Fri, 9 Feb 2024 14:15:11 -0300 Subject: [PATCH 076/472] fix: movido componente block_lists a app/views/components y corregido es.yml --- app/views/components/_block_lists.haml | 7 +++++++ app/views/moderation_queue/_block_lists.haml | 5 ----- app/views/moderation_queue/_instances.haml | 10 +++++----- config/locales/es.yml | 3 ++- 4 files changed, 14 insertions(+), 11 deletions(-) create mode 100644 app/views/components/_block_lists.haml delete mode 100644 app/views/moderation_queue/_block_lists.haml diff --git a/app/views/components/_block_lists.haml b/app/views/components/_block_lists.haml new file mode 100644 index 00000000..7764dfa5 --- /dev/null +++ b/app/views/components/_block_lists.haml @@ -0,0 +1,7 @@ +-# Componente Listas de bloqueo de Instancias +.flex + .card + .card-body + .d-flex.flex-row + = render 'components/checkbox' + %h4.ml-5= t('.title') diff --git a/app/views/moderation_queue/_block_lists.haml b/app/views/moderation_queue/_block_lists.haml deleted file mode 100644 index 14dd770e..00000000 --- a/app/views/moderation_queue/_block_lists.haml +++ /dev/null @@ -1,5 +0,0 @@ -.flex - .card - .card-body - = render 'components/checkbox' - %h4.d-inline.ml-5= t('moderation_queue.instances.block_lists') diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index e50a6e02..fc249e46 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -6,12 +6,12 @@ -# Botones moderación .d-flex.py-4 - - @class = 'btn btn-secondary' - = render 'moderation_queue/btn_base', text: t('moderation_queue.instances_button_box.text_check'), class: @class, href: '' - = render 'moderation_queue/btn_base', text: t('moderation_queue.instances_button_box.text_allow'), class: @class, href: '' - = render 'moderation_queue/btn_base', text: t('moderation_queue.instances_button_box.text_deny'), class: @class, href: '' + - btn_class = 'btn btn-secondary' + = render 'moderation_queue/btn_base', text: t('moderation_queue.instances_button_box.text_check'), class: btn_class, href: '' + = render 'moderation_queue/btn_base', text: t('moderation_queue.instances_button_box.text_allow'), class: btn_class, href: '' + = render 'moderation_queue/btn_base', text: t('moderation_queue.instances_button_box.text_deny'), class: btn_class, href: '' %h3.mt-5= t('moderation_queue.instances.title') %p= t('moderation_queue.instances.description') -= render 'moderation_queue/block_lists' += render 'components/block_lists' = render 'moderation_queue/block_instances_textarea' diff --git a/config/locales/es.yml b/config/locales/es.yml index 7cd59cbf..4aad1cc7 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -34,6 +34,8 @@ es: submenu_accept: Aceptado submenu_block: Bloqueado submenu_reject: Rechazado + block_lists: + title: Listas de bloqueo moderation_queue: index: title: Actividades de moderación @@ -67,7 +69,6 @@ es: instances: title: Mis listas de bloqueo description: Descripción de listas de bloqueo - block_lists: Listas de bloqueo custom_block: Lista personalizada de bloqueo submit: Guardar lista de bloqueo comments_filter_box: From 3f288ab6e4a7806c29d472dd71f34d8d8265dd2f Mon Sep 17 00:00:00 2001 From: jazzari Date: Fri, 9 Feb 2024 14:45:12 -0300 Subject: [PATCH 077/472] fix: creados componentes botoneras de comentarios, instancias y cuentas, y movidos a app/views/components --- app/views/components/_btn_base.haml | 3 ++ app/views/components/_checkbox.haml | 3 +- app/views/components/_comments_btn_box.haml | 9 ++++++ app/views/components/_instances_btn_box.haml | 6 ++++ app/views/components/_profiles_btn_box.haml | 7 +++++ app/views/moderation_queue/_accounts.haml | 6 +--- app/views/moderation_queue/_btn_base.haml | 3 -- app/views/moderation_queue/_comments.haml | 8 +---- app/views/moderation_queue/_instances.haml | 7 ++--- .../moderation_queue/_remote_profile.haml | 7 +---- app/views/moderation_queue/index.haml | 6 ++-- app/views/posts/_moderation_queue.haml | 11 +------ app/views/posts/edit.haml | 4 +-- config/locales/es.yml | 30 +++++++++---------- 14 files changed, 53 insertions(+), 57 deletions(-) create mode 100644 app/views/components/_btn_base.haml create mode 100644 app/views/components/_comments_btn_box.haml create mode 100644 app/views/components/_instances_btn_box.haml create mode 100644 app/views/components/_profiles_btn_box.haml delete mode 100644 app/views/moderation_queue/_btn_base.haml diff --git a/app/views/components/_btn_base.haml b/app/views/components/_btn_base.haml new file mode 100644 index 00000000..2985d646 --- /dev/null +++ b/app/views/components/_btn_base.haml @@ -0,0 +1,3 @@ +-# Componente Botón general Moderación + +%button.btn.btn-lg.mx-2{ href: href, class: local_assigns[:class] }= text diff --git a/app/views/components/_checkbox.haml b/app/views/components/_checkbox.haml index ccf22e84..33630780 100644 --- a/app/views/components/_checkbox.haml +++ b/app/views/components/_checkbox.haml @@ -1,2 +1,3 @@ +-# Componente Checkbox .custom-control.custom-checkbox - %input{ type: 'checkbox', id: '', class: '' } \ No newline at end of file + %input{ type: 'checkbox', id: '', class: '' } diff --git a/app/views/components/_comments_btn_box.haml b/app/views/components/_comments_btn_box.haml new file mode 100644 index 00000000..aa755dcc --- /dev/null +++ b/app/views/components/_comments_btn_box.haml @@ -0,0 +1,9 @@ +-# Componente Botonera de Comentarios + +.d-flex.py-4 +- btn_class = 'btn-secondary' += render 'components/btn_base', text: t('.text_pause'), class: btn_class, href: '' += render 'components/btn_base', text: t('.text_reject'), class: btn_class, href: '' += render 'components/btn_base', text: t('.text_accept'), class: btn_class, href: '' += render 'components/btn_base', text: t('.text_reply'), class: btn_class, href: '' += render 'components/btn_base', text: t('.text_report'), class: btn_class, href: '' \ No newline at end of file diff --git a/app/views/components/_instances_btn_box.haml b/app/views/components/_instances_btn_box.haml new file mode 100644 index 00000000..854262c0 --- /dev/null +++ b/app/views/components/_instances_btn_box.haml @@ -0,0 +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: '' \ No newline at end of file diff --git a/app/views/components/_profiles_btn_box.haml b/app/views/components/_profiles_btn_box.haml new file mode 100644 index 00000000..2c63ce3a --- /dev/null +++ b/app/views/components/_profiles_btn_box.haml @@ -0,0 +1,7 @@ +-# Componente Botonera de Moderación de Cuentas (Remote_profile) + +- @class = 'btn-secondary' += render 'components/btn_base', text: t('.text_approve'), class: @class, href: '' += render 'components/btn_base', text: t('.text_check'), class: @class, href: '' += render 'components/btn_base', text: t('.text_deny'), class: @class, href: '' += render 'components/btn_base', text: t('.text_report'), class: @class, href: '' \ No newline at end of file diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index e954d2f3..e92c3a20 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -6,9 +6,5 @@ -# Botones de Moderación .d-flex.py-4 - - @class = 'btn-secondary' - = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_approve'), class: @class, href: '' - = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_check'), class: @class, href: '' - = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_deny'), class: @class, href: '' - = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_report'), class: @class, href: '' + = render 'components/profiles_btn_box' \ No newline at end of file diff --git a/app/views/moderation_queue/_btn_base.haml b/app/views/moderation_queue/_btn_base.haml deleted file mode 100644 index 7f6233cd..00000000 --- a/app/views/moderation_queue/_btn_base.haml +++ /dev/null @@ -1,3 +0,0 @@ --# Componente Botón general Moderación - -%button.btn.btn-lg.mx-2{ href: href, class: @class }= text diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index c5f7ae5d..d5f2b3bd 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -6,10 +6,4 @@ = render 'comment', comment: comment, profile: @remote_profile -# Botones moderación - .d-flex.py-4 - - @class = 'btn-secondary' - = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_pause'), class: @class, href: '' - = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_reject'), class: @class, href: '' - = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_accept'), class: @class, href: '' - = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_reply'), class: @class, href: '' - = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_report'), class: @class, href: '' \ No newline at end of file + = render 'components/comments_btn_box' \ No newline at end of file diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index fc249e46..26caaeca 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -5,11 +5,8 @@ = render 'moderation_queue/instance', instance: instance -# Botones moderación - .d-flex.py-4 - - btn_class = 'btn btn-secondary' - = render 'moderation_queue/btn_base', text: t('moderation_queue.instances_button_box.text_check'), class: btn_class, href: '' - = render 'moderation_queue/btn_base', text: t('moderation_queue.instances_button_box.text_allow'), class: btn_class, href: '' - = render 'moderation_queue/btn_base', text: t('moderation_queue.instances_button_box.text_deny'), class: btn_class, href: '' + .d-flex.py-5 + = render 'components/instances_btn_box' %h3.mt-5= t('moderation_queue.instances.title') %p= t('moderation_queue.instances.description') diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml index 965f8854..ab29ae4d 100644 --- a/app/views/moderation_queue/_remote_profile.haml +++ b/app/views/moderation_queue/_remote_profile.haml @@ -14,9 +14,4 @@ %h4.my-2= t('.profile_name') + ': ' + remote_profile['name'] -# Botones de Moderación -.d-flex.py-4 - - @class = 'btn-secondary' - = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_approve'), class: @class, href: '' - = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_check'), class: @class, href: '' - = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_deny'), class: @class, href: '' - = render 'moderation_queue/btn_base', text: t('moderation_queue.profile_button_box.text_report'), class: @class, href: '' += render 'components/comments_btn_box' diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml index b361c085..eae3b5a5 100644 --- a/app/views/moderation_queue/index.haml +++ b/app/views/moderation_queue/index.haml @@ -1,7 +1,7 @@ -.row.justify-content-center.mb-5 +.row.mb-5 %h1= t('.title') -.row.justify-content-center - .col-md-8 +.row + .col-md-10 - summary = t('.instances') = render 'layouts/details', summary: summary do = render 'moderation_queue/instances', site: @site, post: @post, moderation_queue: @moderation_queue diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index df17b1ff..e4a9683c 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -7,13 +7,4 @@ -# Botones moderación .d-flex.py-4 - - @class = 'btn-secondary' - = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_pause'), class: @class, href: '' - - @class = 'btn-secondary' - = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_reject'), class: @class, href: '' - - @class = 'btn-secondary' - = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_accept'), class: @class, href: '' - - @class = 'btn-secondary' - = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_reply'), class: @class, href: '' - - @class = 'btn-secondary' - = render 'moderation_queue/btn_base', text: t('moderation_queue.button_box.text_report'), class: @class, href: '' + = render 'components/comments_btn_box' diff --git a/app/views/posts/edit.haml b/app/views/posts/edit.haml index 2e46590e..a83c72af 100644 --- a/app/views/posts/edit.haml +++ b/app/views/posts/edit.haml @@ -1,5 +1,5 @@ -.row.justify-content-center - .col-md-8 +.row + .col-md-10 - summary = t('posts.edit.post') = render 'layouts/details', summary: summary do = render 'posts/form', site: @site, post: @post diff --git a/config/locales/es.yml b/config/locales/es.yml index 4aad1cc7..868f8fc6 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -36,6 +36,21 @@ es: submenu_reject: Rechazado block_lists: title: Listas de bloqueo + comments_btn_box: + text_pause: Pausa + text_reject: Rechazar + text_accept: Aceptar Publicación + text_reply: Responder + text_report: Reportar + instances_btn_box: + text_check: Moderar caso por caso + text_allow: Permitir todo + text_deny: Bloquear instancia + profiles_btn_box: + text_approve: Aprobar siempre + text_check: Revisar siempre + text_deny: Bloquear + text_report: Reportar moderation_queue: index: title: Actividades de moderación @@ -51,21 +66,6 @@ es: profile_id: ID profile_published: Publicada profile_summary: Resumen - profile_button_box: - text_approve: Aprobar siempre - text_check: Revisar siempre - text_deny: Bloquear - text_report: Reportar - button_box: - text_pause: Pausa - text_reject: Rechazar - text_accept: Aceptar Publicación - text_reply: Responder - text_report: Reportar - instances_button_box: - text_check: Moderar caso por caso - text_allow: Permitir todo - text_deny: Bloquear instancia instances: title: Mis listas de bloqueo description: Descripción de listas de bloqueo From ba26b505e499f0c2e139c5778c53c0c10607978f Mon Sep 17 00:00:00 2001 From: jazzari Date: Fri, 9 Feb 2024 15:03:47 -0300 Subject: [PATCH 078/472] =?UTF-8?q?fix:=20corregidos=20m=C3=A1rgenes=20en?= =?UTF-8?q?=20vistas=20de=20moderaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/index.haml | 27 ++++++++++--------- .../moderation_queue/remote_profile.haml | 7 ++--- app/views/posts/edit.haml | 4 +-- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml index eae3b5a5..982a41c8 100644 --- a/app/views/moderation_queue/index.haml +++ b/app/views/moderation_queue/index.haml @@ -1,13 +1,14 @@ -.row.mb-5 - %h1= t('.title') -.row - .col-md-10 - - summary = t('.instances') - = render 'layouts/details', summary: summary do - = render 'moderation_queue/instances', site: @site, post: @post, moderation_queue: @moderation_queue - - summary = t('.accounts') - = render 'layouts/details', summary: summary do - = render 'moderation_queue/accounts', site: @site, post: @post, moderation_queue: @moderation_queue - - summary = t('.comments') - = render 'layouts/details', summary: summary do - = render 'moderation_queue/comments', site: @site, post: @post, moderation_queue: @moderation_queue +.row.justify-content-center + .col-md-8 + %h1= t('.title') + .row + .col + - summary = t('.instances') + = render 'layouts/details', summary: summary do + = render 'moderation_queue/instances', site: @site, post: @post, moderation_queue: @moderation_queue + - summary = t('.accounts') + = render 'layouts/details', summary: summary do + = render 'moderation_queue/accounts', site: @site, post: @post, moderation_queue: @moderation_queue + - summary = t('.comments') + = render 'layouts/details', summary: summary do + = render 'moderation_queue/comments', site: @site, post: @post, moderation_queue: @moderation_queue diff --git a/app/views/moderation_queue/remote_profile.haml b/app/views/moderation_queue/remote_profile.haml index ed66a394..ba0fc257 100644 --- a/app/views/moderation_queue/remote_profile.haml +++ b/app/views/moderation_queue/remote_profile.haml @@ -1,3 +1,4 @@ -.flex - %h1= t('.profile') - = render 'moderation_queue/remote_profile', remote_profile: @remote_profile +.row.justify-content-center + .col-md-8 + %h1= t('.profile') + = render 'moderation_queue/remote_profile', remote_profile: @remote_profile diff --git a/app/views/posts/edit.haml b/app/views/posts/edit.haml index a83c72af..2e46590e 100644 --- a/app/views/posts/edit.haml +++ b/app/views/posts/edit.haml @@ -1,5 +1,5 @@ -.row - .col-md-10 +.row.justify-content-center + .col-md-8 - summary = t('posts.edit.post') = render 'layouts/details', summary: summary do = render 'posts/form', site: @site, post: @post From 529711c47dbb823665a0f2685d0b7681792f3d9e Mon Sep 17 00:00:00 2001 From: jazzari Date: Fri, 9 Feb 2024 16:54:16 -0300 Subject: [PATCH 079/472] fix: corregido compo _remote_profile para hacerlo semantico con dl --- app/views/moderation_queue/_remote_profile.haml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml index ab29ae4d..fae38dec 100644 --- a/app/views/moderation_queue/_remote_profile.haml +++ b/app/views/moderation_queue/_remote_profile.haml @@ -1,12 +1,18 @@ -# Componente Remote_Profile .flex.py-2.mx-2 + %dl + %dt= t('.profile_name') + %dd= remote_profile['name'] - %h4.my-2= t('.profile_name') + ': ' + remote_profile['name'] - %h5= t('.profile_id') + ': ' + remote_profile['id'] - %h5= t('.profile_published') + ': ' + remote_profile['published'].to_datetime.strftime('%m/%d/%Y') - %h5= t('.profile_summary') + ':' - %p= sanitize remote_profile['summary'] + %dt= t('.profile_id') + %dd= remote_profile['id'] + + %dt= t('.profile_published') + %dd= remote_profile['published'].to_datetime.strftime('%m/%d/%Y') + + %dt= t('.profile_summary') + %dd= remote_profile['summary'] = render 'moderation_queue/comments', moderation_queue: @moderation_queue From faf3bf3fcf6e590c0984ef0819febc01119b2592 Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 12 Feb 2024 11:27:24 -0300 Subject: [PATCH 080/472] fix: corregido codigo de details en application.scss --- app/assets/stylesheets/application.scss | 27 ++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 5419bcdd..c05c49fe 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -559,7 +559,7 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); } } // details styles - +/* .details summary { list-style: none; cursor: default; @@ -578,4 +578,29 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); .details[open] > summary::after { transform: rotate(90deg) translatey(-0.1em); } +*/ + +.details { + summary { + list-style: none; + cursor: default; + position: relative; + } + summary::after { + content: '▶'; + font-size: 1.8rem; + position: absolute; + left: 97%; + bottom: 3%; + transform: rotate(64deg); + } +} + .details[open] { + & > summary { + &::after { + transform: rotate(90deg) translatey(-0.1em); + } + } + } + From 8bfdf3ed0a81fa5b332b2e53c0d7647325851a6a Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 12 Feb 2024 11:29:00 -0300 Subject: [PATCH 081/472] fix: corregido cursor de apertura de details --- app/assets/stylesheets/application.scss | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index c05c49fe..a411c124 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -559,26 +559,6 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); } } // details styles -/* -.details summary { - list-style: none; - cursor: default; - position: relative; - - &::after { - content: '▶'; - font-size: 1.8rem; - position: absolute; - left: 97%; - bottom: 3%; - transform: rotate(64deg); - } - } - -.details[open] > summary::after { - transform: rotate(90deg) translatey(-0.1em); - } -*/ .details { summary { @@ -592,7 +572,7 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); position: absolute; left: 97%; bottom: 3%; - transform: rotate(64deg); + transform: rotate(60deg); } } .details[open] { From d829b5b4ae8b5a7d6fd6ecd9f9b1f7bb675b40b1 Mon Sep 17 00:00:00 2001 From: jazzari Date: Mon, 12 Feb 2024 12:02:06 -0300 Subject: [PATCH 082/472] feat: agregada traducciones en en.yml --- config/locales/en.yml | 71 +++++++++++++++++++++++++++++++++++++++---- config/locales/es.yml | 4 +-- 2 files changed, 66 insertions(+), 9 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 9b06a78d..b1243091 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,18 +1,77 @@ en: + components: + instances_filters: + text_show: Show + text_checked: With the checked + instances_checked_submenu: + submenu_case: Check case by case + submenu_allow: Allow everything + submenu_reject: Reject + instances_show_submenu: + submenu_allow: Allow + submenu_reject: Reject + comments_filters: + text_show: Sho + text_checked: With the checked + comments_checked_submenu: + submenu_pause: Pause + submenu_accept: Accept + submenu_reject: Reject + comments_show_submenu: + submenu_pause: Pause + submenu_accept: Accept + submenu_report: Report + submenu_reject: Reject + profiles_filters: + text_show: Show + text_checked: With the checked + profiles_checked_submenu: + submenu_pause: Pause + submenu_accept: Accept + submenu_reject: Reject + submenu_block: Block + profiles_show_submenu: + submenu_accept: Accept + submenu_block: Block + submenu_reject: Reject + block_lists: + title: Block lists + comments_btn_box: + text_pause: Pause + text_reject: Reject + text_accept: Accept + text_reply: Reply + text_report: Report + instances_btn_box: + text_check: Check case by case + text_allow: Allow everything + text_deny: Block instance + profiles_btn_box: + text_approve: Always approve + text_check: Always check + text_deny: Block + text_report: Report moderation_queue: index: title: Moderation instances: Instances accounts: Accounts comments: Comments + comment: + source_profile: Source Profile + reply_to: Reply to remote_profile: user: Username - button_box: - text_pause: Pause - text_reject: Reject - text_accept: Accept Publication - text_reply: Reply - text_report: Report + profile: Profile + profile_name: Profile name + profile_id: ID + profile_published: Published + profile_summary: Summary + instances: + title: My block lists + description: Description + custom_block: Custom block lists + submit: Save block lists dark: Dark dir: ltr en: English diff --git a/config/locales/es.yml b/config/locales/es.yml index 868f8fc6..4b68f968 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -61,6 +61,7 @@ es: source_profile: Cuenta de Origen reply_to: En respuesta a remote_profile: + user: Nombre de usuario profile: Cuenta de Origen profile_name: Nombre de la Cuenta profile_id: ID @@ -71,9 +72,6 @@ es: description: Descripción de listas de bloqueo custom_block: Lista personalizada de bloqueo submit: Guardar lista de bloqueo - comments_filter_box: - text_show: Ver - text_checked: Con los marcados dark: Oscuro es: Castellano en: English From fb19938361ca88216f7f94e74cb18e30213e08bf Mon Sep 17 00:00:00 2001 From: maki Date: Wed, 14 Feb 2024 14:38:34 -0300 Subject: [PATCH 083/472] fix: quitar bordes blancos de _comment.haml --- app/views/moderation_queue/_comment.haml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 463f47c7..26cfbe29 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -4,15 +4,15 @@ .col-1 = render 'components/checkbox' .col-10 - .row.border.border-white - .col.col-1.border.border-white.mr-5 + .row + .col.col-1.mr-5 %p= comment['published'].to_datetime.strftime('%m/%d/%Y') - .col.border.border-white + .col %span.mr-2= t('.source_profile') %a{ href: comment['attributedTo'] }= profile['preferredUsername'] - .row.border.border-white + .row %p.mr-3= t('.reply_to') %span %a{ href: comment['inReplyTo'] }= comment['inReplyTo'] - .row.border.border-white + .row %p= sanitize comment['content'] From 58012f662e84fd2e7b67498e22a23ebc91496cae Mon Sep 17 00:00:00 2001 From: maki Date: Wed, 14 Feb 2024 14:44:33 -0300 Subject: [PATCH 084/472] fix: row sin col --- app/views/moderation_queue/_comment.haml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 26cfbe29..5f50c996 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -11,8 +11,10 @@ %span.mr-2= t('.source_profile') %a{ href: comment['attributedTo'] }= profile['preferredUsername'] .row - %p.mr-3= t('.reply_to') - %span - %a{ href: comment['inReplyTo'] }= comment['inReplyTo'] + .col.p-0 + %span.mr-3= t('.reply_to') + %span + %a{ href: comment['inReplyTo'] }= comment['inReplyTo'] .row - %p= sanitize comment['content'] + .col.p-0 + %p= sanitize comment['content'] From fdc6ad95b82975ae59ca7f2ab6fa61142e22af58 Mon Sep 17 00:00:00 2001 From: maki Date: Wed, 14 Feb 2024 14:51:27 -0300 Subject: [PATCH 085/472] fix: span sin p en _comment.haml --- app/views/moderation_queue/_comment.haml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 5f50c996..ed77d40f 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -8,13 +8,15 @@ .col.col-1.mr-5 %p= comment['published'].to_datetime.strftime('%m/%d/%Y') .col - %span.mr-2= t('.source_profile') - %a{ href: comment['attributedTo'] }= profile['preferredUsername'] + %p + %span.mr-2= t('.source_profile') + %a{ href: comment['attributedTo'] }= profile['preferredUsername'] .row .col.p-0 - %span.mr-3= t('.reply_to') - %span - %a{ href: comment['inReplyTo'] }= comment['inReplyTo'] + %p + %span.mr-3= t('.reply_to') + %span + %a{ href: comment['inReplyTo'] }= comment['inReplyTo'] .row .col.p-0 %p= sanitize comment['content'] From 8dfa3860a5a6fcaae872bd627e16fe363dd88cc5 Mon Sep 17 00:00:00 2001 From: maki Date: Wed, 14 Feb 2024 14:58:10 -0300 Subject: [PATCH 086/472] fix: span sin p y texto hardcodeado en _instance.haml --- app/views/moderation_queue/_instance.haml | 9 +++++---- config/locales/en.yml | 1 + config/locales/es.yml | 1 + 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/app/views/moderation_queue/_instance.haml b/app/views/moderation_queue/_instance.haml index 80114985..6f0df926 100644 --- a/app/views/moderation_queue/_instance.haml +++ b/app/views/moderation_queue/_instance.haml @@ -4,7 +4,8 @@ %a{ href: host }= instance['title'] %p= instance['description'] -%span Users: -%span - = instance.dig('usage', 'users', 'active_month') - = instance.dig('stats', 'user_count') +%p + %span= t('.users') + %span + = instance.dig('usage', 'users', 'active_month') + = instance.dig('stats', 'user_count') diff --git a/config/locales/en.yml b/config/locales/en.yml index b1243091..5a8877fd 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -72,6 +72,7 @@ en: description: Description custom_block: Custom block lists submit: Save block lists + users: "Users:" dark: Dark dir: ltr en: English diff --git a/config/locales/es.yml b/config/locales/es.yml index 4b68f968..bd20d3f0 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -72,6 +72,7 @@ es: description: Descripción de listas de bloqueo custom_block: Lista personalizada de bloqueo submit: Guardar lista de bloqueo + users: "Usuaries:" dark: Oscuro es: Castellano en: English From 1deb4053a70142afc00b9c76a24561b15e84bb72 Mon Sep 17 00:00:00 2001 From: maki Date: Wed, 14 Feb 2024 15:10:18 -0300 Subject: [PATCH 087/472] fix: condicional en En Respuesta A en _comment.haml --- app/views/moderation_queue/_comment.haml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index ed77d40f..2666d005 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -13,10 +13,11 @@ %a{ href: comment['attributedTo'] }= profile['preferredUsername'] .row .col.p-0 - %p - %span.mr-3= t('.reply_to') - %span - %a{ href: comment['inReplyTo'] }= comment['inReplyTo'] + - if comment['inReplyTo'] + %p + %span.mr-3= t('.reply_to') + %span + %a{ href: comment['inReplyTo'] }= comment['inReplyTo'] .row .col.p-0 %p= sanitize comment['content'] From 2de756867685455218763a1fdbc09b65d72d51d3 Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 15 Feb 2024 15:05:27 -0300 Subject: [PATCH 088/472] fix: corregido cuenta de origen de comentarios --- app/views/moderation_queue/_comments.haml | 3 +-- app/views/moderation_queue/_remote_profile.haml | 7 ++++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index d5f2b3bd..76e08559 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -2,8 +2,7 @@ = render 'components/comments_filters' - moderation_queue.each do |comment| - - = render 'comment', comment: comment, profile: @remote_profile + = render 'comment', comment: comment, profile: comment['attributedTo'] -# Botones moderación = render 'components/comments_btn_box' \ No newline at end of file diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml index fae38dec..744d6445 100644 --- a/app/views/moderation_queue/_remote_profile.haml +++ b/app/views/moderation_queue/_remote_profile.haml @@ -12,12 +12,13 @@ %dd= remote_profile['published'].to_datetime.strftime('%m/%d/%Y') %dt= t('.profile_summary') - %dd= remote_profile['summary'] + %dd= sanitize remote_profile['summary'] = render 'moderation_queue/comments', moderation_queue: @moderation_queue -%h3.pt-4= t('.profile') -%h4.my-2= t('.profile_name') + ': ' + remote_profile['name'] +%dl.mt-5 + %dt= t('.profile_name') + %dd= remote_profile['name'] -# Botones de Moderación = render 'components/comments_btn_box' From d0e1d87c98fbc63eaa64272be1c26e6e59b15f8d Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 15 Feb 2024 15:14:11 -0300 Subject: [PATCH 089/472] fix: quitada sanitizacion en comentarios y remote_profile --- app/views/moderation_queue/_comment.haml | 2 +- app/views/moderation_queue/_remote_profile.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 2666d005..213aa220 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -20,4 +20,4 @@ %a{ href: comment['inReplyTo'] }= comment['inReplyTo'] .row .col.p-0 - %p= sanitize comment['content'] + %p= comment['content'] diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml index 744d6445..e8635cc6 100644 --- a/app/views/moderation_queue/_remote_profile.haml +++ b/app/views/moderation_queue/_remote_profile.haml @@ -12,7 +12,7 @@ %dd= remote_profile['published'].to_datetime.strftime('%m/%d/%Y') %dt= t('.profile_summary') - %dd= sanitize remote_profile['summary'] + %dd= remote_profile['summary'] = render 'moderation_queue/comments', moderation_queue: @moderation_queue From 68b8aee1f22cf80707b67bb506ce78fae5411d2a Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 15 Feb 2024 16:06:49 -0300 Subject: [PATCH 090/472] fix: quitada sanitizacion y quitado row extra --- app/views/moderation_queue/_account.haml | 2 +- app/views/moderation_queue/_block_instances_textarea.haml | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/views/moderation_queue/_account.haml b/app/views/moderation_queue/_account.haml index 751d0c0e..01c1fbf9 100644 --- a/app/views/moderation_queue/_account.haml +++ b/app/views/moderation_queue/_account.haml @@ -1,2 +1,2 @@ %a{href: profile['id']}= profile['preferredUsername'] -%p= sanitize profile['summary'] \ No newline at end of file +%p= profile['summary'] \ No newline at end of file diff --git a/app/views/moderation_queue/_block_instances_textarea.haml b/app/views/moderation_queue/_block_instances_textarea.haml index 34eb1e5d..339bd25c 100644 --- a/app/views/moderation_queue/_block_instances_textarea.haml +++ b/app/views/moderation_queue/_block_instances_textarea.haml @@ -1,6 +1,4 @@ .form-group .d-flex.flex-column.mt-5 %textarea.mb-3{ name: '', id: '', placeholder: t('moderation_queue.instances.custom_block') } - .d-flex.justify-content-end - %button.col{ type: 'submit', class: 'btn btn-secondary' }= t('moderation_queue.instances.submit') - + %button.col{ type: 'submit', class: 'btn btn-secondary' }= t('moderation_queue.instances.submit') From 700e71ff97c5886283c6012366eb9318f44767d1 Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 15 Feb 2024 16:15:57 -0300 Subject: [PATCH 091/472] fix: corregido details en application.scss --- app/assets/stylesheets/application.scss | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index a411c124..ef36c3be 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -574,13 +574,14 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); bottom: 3%; transform: rotate(60deg); } -} - .details[open] { + &[open] { & > summary { &::after { - transform: rotate(90deg) translatey(-0.1em); + transform: rotate(90deg); } } } +} + From f2724c27fb3e24616d376dd920d78dbec0048add Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 15 Feb 2024 16:20:46 -0300 Subject: [PATCH 092/472] =?UTF-8?q?fix:=20corregidos=20par=C3=A1metros=20d?= =?UTF-8?q?e=20compo=20checkbox?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/components/_checkbox.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/components/_checkbox.haml b/app/views/components/_checkbox.haml index 33630780..cbc5cb2d 100644 --- a/app/views/components/_checkbox.haml +++ b/app/views/components/_checkbox.haml @@ -1,3 +1,3 @@ -# Componente Checkbox .custom-control.custom-checkbox - %input{ type: 'checkbox', id: '', class: '' } + %input{ type: 'checkbox', id: local_assigns[:id], class: local_assigns[:class] } From 643139aaffb0bec5c833bd49649cd1b52cadaa86 Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 15 Feb 2024 16:24:06 -0300 Subject: [PATCH 093/472] fix: corregida indentacion en botones de comentarios --- app/views/components/_comments_btn_box.haml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/views/components/_comments_btn_box.haml b/app/views/components/_comments_btn_box.haml index aa755dcc..0487c3db 100644 --- a/app/views/components/_comments_btn_box.haml +++ b/app/views/components/_comments_btn_box.haml @@ -1,9 +1,9 @@ -# Componente Botonera de Comentarios .d-flex.py-4 -- btn_class = 'btn-secondary' -= render 'components/btn_base', text: t('.text_pause'), class: btn_class, href: '' -= render 'components/btn_base', text: t('.text_reject'), class: btn_class, href: '' -= render 'components/btn_base', text: t('.text_accept'), class: btn_class, href: '' -= render 'components/btn_base', text: t('.text_reply'), class: btn_class, href: '' -= render 'components/btn_base', text: t('.text_report'), class: btn_class, href: '' \ No newline at end of file + - btn_class = 'btn-secondary' + = render 'components/btn_base', text: t('.text_pause'), class: btn_class, href: '' + = render 'components/btn_base', text: t('.text_reject'), class: btn_class, href: '' + = render 'components/btn_base', text: t('.text_accept'), class: btn_class, href: '' + = render 'components/btn_base', text: t('.text_reply'), class: btn_class, href: '' + = render 'components/btn_base', text: t('.text_report'), class: btn_class, href: '' \ No newline at end of file From e11de6c835091610513aec479c4d6771386bae8d Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 15 Feb 2024 16:27:05 -0300 Subject: [PATCH 094/472] fix: cambiada variable global por local en botonera de profiles --- app/views/components/_profiles_btn_box.haml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/views/components/_profiles_btn_box.haml b/app/views/components/_profiles_btn_box.haml index 2c63ce3a..06faa8a1 100644 --- a/app/views/components/_profiles_btn_box.haml +++ b/app/views/components/_profiles_btn_box.haml @@ -1,7 +1,7 @@ -# Componente Botonera de Moderación de Cuentas (Remote_profile) -- @class = 'btn-secondary' -= render 'components/btn_base', text: t('.text_approve'), class: @class, href: '' -= render 'components/btn_base', text: t('.text_check'), class: @class, href: '' -= render 'components/btn_base', text: t('.text_deny'), class: @class, href: '' -= render 'components/btn_base', text: t('.text_report'), class: @class, href: '' \ No newline at end of file +- btn_class = 'btn-secondary' += render 'components/btn_base', text: t('.text_approve'), class: btn_class, href: '' += render 'components/btn_base', text: t('.text_check'), class: btn_class, href: '' += render 'components/btn_base', text: t('.text_deny'), class: btn_class, href: '' += render 'components/btn_base', text: t('.text_report'), class: btn_class, href: '' \ No newline at end of file From 243a998451f793d1438aea514b9666ef78e26c7e Mon Sep 17 00:00:00 2001 From: maki Date: Thu, 15 Feb 2024 16:46:04 -0300 Subject: [PATCH 095/472] =?UTF-8?q?fix:=20row=20va=20dentro=20del=20if=20p?= =?UTF-8?q?ara=20no=20quedar=20vac=C3=ADa=20si=20false?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_comment.haml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 2666d005..b92b3b11 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -11,9 +11,10 @@ %p %span.mr-2= t('.source_profile') %a{ href: comment['attributedTo'] }= profile['preferredUsername'] - .row - .col.p-0 - - if comment['inReplyTo'] + + - if comment['inReplyTo'] + .row + .col.p-0 %p %span.mr-3= t('.reply_to') %span From 90b14ce2b2589fe80b1329bac314ac626f78ba37 Mon Sep 17 00:00:00 2001 From: maki Date: Thu, 15 Feb 2024 17:07:36 -0300 Subject: [PATCH 096/472] fix: cambio de p por lead --- app/views/moderation_queue/_instances.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index 26caaeca..c34bc022 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -9,6 +9,6 @@ = render 'components/instances_btn_box' %h3.mt-5= t('moderation_queue.instances.title') -%p= t('moderation_queue.instances.description') +%lead= t('moderation_queue.instances.description') = render 'components/block_lists' = render 'moderation_queue/block_instances_textarea' From e3cdafe2a6f7c68dae8813127ee4381ed3464ab9 Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 15 Feb 2024 17:17:06 -0300 Subject: [PATCH 097/472] fix: corregida clase en compo textarea --- app/views/moderation_queue/_block_instances_textarea.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/moderation_queue/_block_instances_textarea.haml b/app/views/moderation_queue/_block_instances_textarea.haml index 339bd25c..0c0f55ca 100644 --- a/app/views/moderation_queue/_block_instances_textarea.haml +++ b/app/views/moderation_queue/_block_instances_textarea.haml @@ -1,4 +1,4 @@ .form-group .d-flex.flex-column.mt-5 %textarea.mb-3{ name: '', id: '', placeholder: t('moderation_queue.instances.custom_block') } - %button.col{ type: 'submit', class: 'btn btn-secondary' }= t('moderation_queue.instances.submit') + %button.col.btn.btn-secondary{ type: 'submit' }= t('moderation_queue.instances.submit') From 78e478c00453c7e75ac7a321f4a7ec8fbc459100 Mon Sep 17 00:00:00 2001 From: maki Date: Thu, 15 Feb 2024 17:18:38 -0300 Subject: [PATCH 098/472] =?UTF-8?q?fix:=20fecha=20con=20formato=20seg?= =?UTF-8?q?=C3=BAn=20idioma?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_comment.haml | 2 +- config/locales/en.yml | 49 ++++++++++++++++++++++++ config/locales/es.yml | 49 ++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 1 deletion(-) diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index e525de8f..daf68290 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -6,7 +6,7 @@ .col-10 .row .col.col-1.mr-5 - %p= comment['published'].to_datetime.strftime('%m/%d/%Y') + %p= comment['published'].to_datetime.strftime(t('date.format')) .col %p %span.mr-2= t('.source_profile') diff --git a/config/locales/en.yml b/config/locales/en.yml index 5a8877fd..d6a15d4b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,4 +1,53 @@ en: + date: + format: '%m/%d/%Y' + published_at: "Published at" + last_modified_at: "Last modification" + abbr_day_names: + - Mon + - Tue + - Wed + - Thu + - Fri + - Sat + - Sun + day_names: + - Monday + - Tuesday + - Wednesday + - Thursday + - Friday + - Saturday + - Sunday + abbr_month_names: + - Jan + - Feb + - Mar + - Apr + - May + - Jun + - Jul + - Aug + - Sep + - Oct + - Nov + - Dec + month_names: + - January + - February + - March + - April + - May + - June + - July + - August + - September + - October + - November + - December + time: + am: am + pm: pm components: instances_filters: text_show: Show diff --git a/config/locales/es.yml b/config/locales/es.yml index bd20d3f0..65df27bf 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1,4 +1,53 @@ es: + date: + format: '%d/%m/%Y' + published_at: "Publicado en" + last_modified_at: "Última modificación" + abbr_day_names: + - Lun + - Mar + - Mié + - Jue + - Vie + - Sáb + - Dom + day_names: + - Lunes + - Martes + - Miércoles + - Jueves + - Viernes + - Sábado + - Domingo + abbr_month_names: + - Ene + - Feb + - Mar + - Abr + - May + - Jun + - Jul + - Ago + - Sep + - Oct + - Nov + - Dic + month_names: + - Enero + - Febrero + - Marzo + - Abril + - Mayo + - Junio + - Julio + - Agosto + - Septiembre + - Octubre + - Noviembre + - Diciembre + time: + am: am + pm: pm components: instances_filters: text_show: Ver From 564dc060f0d2ee1f53c33be215bc9fcf72d1a3bf Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 15 Feb 2024 17:24:25 -0300 Subject: [PATCH 099/472] fix: quitado flex de compo block_lists --- app/views/components/_block_lists.haml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/views/components/_block_lists.haml b/app/views/components/_block_lists.haml index 7764dfa5..7d9d741d 100644 --- a/app/views/components/_block_lists.haml +++ b/app/views/components/_block_lists.haml @@ -1,7 +1,6 @@ -# Componente Listas de bloqueo de Instancias -.flex - .card - .card-body - .d-flex.flex-row - = render 'components/checkbox' - %h4.ml-5= t('.title') +.card.mt-3 + .card-body + .d-flex.flex-row + = render 'components/checkbox' + %h4.ml-5= t('.title') From 476f0c005fc10224163442df3d369732676f5ab2 Mon Sep 17 00:00:00 2001 From: maki Date: Thu, 15 Feb 2024 17:47:04 -0300 Subject: [PATCH 100/472] fix: remote profile asociado al comentario dentro de posts/_moderation_queue.haml --- app/views/posts/_moderation_queue.haml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index e4a9683c..6921acbb 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -1,10 +1,9 @@ -.flex - -# Filtros - = render 'components/comments_filters' +-# Filtros += render 'components/comments_filters' - - moderation_queue.each do |comment| - = render 'moderation_queue/comment', comment: comment, profile: @remote_profile +- moderation_queue.each do |comment| + = render 'moderation_queue/comment', comment: comment, profile: comment['attributedTo'] - -# Botones moderación - .d-flex.py-4 - = render 'components/comments_btn_box' + -# Botones moderación + .d-flex.py-4 + = render 'components/comments_btn_box' From 9634f758704887550b45980bd967e3fe9a8a6361 Mon Sep 17 00:00:00 2001 From: maki Date: Thu, 15 Feb 2024 17:56:12 -0300 Subject: [PATCH 101/472] fix: html_safe en comentarios y descripciones --- app/views/moderation_queue/_account.haml | 2 +- app/views/moderation_queue/_comment.haml | 2 +- app/views/moderation_queue/_instance.haml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/moderation_queue/_account.haml b/app/views/moderation_queue/_account.haml index 01c1fbf9..28bba0e9 100644 --- a/app/views/moderation_queue/_account.haml +++ b/app/views/moderation_queue/_account.haml @@ -1,2 +1,2 @@ %a{href: profile['id']}= profile['preferredUsername'] -%p= profile['summary'] \ No newline at end of file +%p= profile['summary'].html_safe \ No newline at end of file diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index daf68290..98679a9f 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -21,4 +21,4 @@ %a{ href: comment['inReplyTo'] }= comment['inReplyTo'] .row .col.p-0 - %p= comment['content'] + %p= comment['content'].html_safe diff --git a/app/views/moderation_queue/_instance.haml b/app/views/moderation_queue/_instance.haml index 6f0df926..eb5d6581 100644 --- a/app/views/moderation_queue/_instance.haml +++ b/app/views/moderation_queue/_instance.haml @@ -3,7 +3,7 @@ - host = "https://#{host}" %a{ href: host }= instance['title'] -%p= instance['description'] +%p= instance['description'].html_safe %p %span= t('.users') %span From e769c6ed5c36c4499989b8877d57a7126c005972 Mon Sep 17 00:00:00 2001 From: maki Date: Thu, 15 Feb 2024 18:14:37 -0300 Subject: [PATCH 102/472] fix: responsive de moderation_queue/_comment.haml --- app/views/components/_checkbox.haml | 2 +- app/views/moderation_queue/_comment.haml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/components/_checkbox.haml b/app/views/components/_checkbox.haml index cbc5cb2d..3444720e 100644 --- a/app/views/components/_checkbox.haml +++ b/app/views/components/_checkbox.haml @@ -1,3 +1,3 @@ -# Componente Checkbox -.custom-control.custom-checkbox +.custom-control.custom-checkbox.p-0 %input{ type: 'checkbox', id: local_assigns[:id], class: local_assigns[:class] } diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 98679a9f..aa8d777d 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -4,10 +4,10 @@ .col-1 = render 'components/checkbox' .col-10 - .row - .col.col-1.mr-5 + .row.no-gutters + .col.col-4 %p= comment['published'].to_datetime.strftime(t('date.format')) - .col + .col.col-8 %p %span.mr-2= t('.source_profile') %a{ href: comment['attributedTo'] }= profile['preferredUsername'] From 6841945b398cd04a38b859715fcaedb26e51bf81 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 16 Feb 2024 14:52:37 -0300 Subject: [PATCH 103/472] feat: dependencias --- Gemfile | 5 ++++- Gemfile.lock | 18 ++++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index 80051e93..3cf01934 100644 --- a/Gemfile +++ b/Gemfile @@ -37,7 +37,9 @@ gem 'commonmarker' gem 'devise' gem 'devise-i18n' gem 'devise_invitable' -gem 'distributed-press-api-client', '~> 0.4.0rc0' +gem 'redis-client' +gem 'hiredis-client' +gem 'distributed-press-api-client', '~> 0.4.0rc2' gem 'email_address', git: 'https://github.com/fauno/email_address', branch: 'i18n' gem 'exception_notification' gem 'fast_blank' @@ -65,6 +67,7 @@ gem 'redis', '~> 4.0', require: %w[redis redis/connection/hiredis] gem 'redis-rails' gem 'rollups', git: 'https://github.com/fauno/rollup.git', branch: 'update' gem 'rubyzip' +gem 'ruby-brs' gem 'rugged', '1.5.0.1' gem 'git_clone_url' gem 'concurrent-ruby-ext' diff --git a/Gemfile.lock b/Gemfile.lock index 90bf6d98..5b8ca619 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -88,6 +88,7 @@ GEM zeitwerk (~> 2.3) addressable (2.8.4) public_suffix (>= 2.0.2, < 6.0) + adsp (1.0.10) ast (2.4.2) autoprefixer-rails (10.4.13.0) execjs (~> 2) @@ -157,12 +158,12 @@ GEM devise_invitable (2.0.8) actionmailer (>= 5.0) devise (>= 4.6) - distributed-press-api-client (0.4.0rc0) + distributed-press-api-client (0.4.0rc2) addressable (~> 2.3, >= 2.3.0) climate_control dry-schema httparty (~> 0.18) - httparty-cache + httparty-cache (~> 0.0.4) json (~> 2.1, >= 2.1.0) jwt (~> 2.6.0) dotenv (2.8.1) @@ -256,11 +257,13 @@ GEM heapy (0.2.0) thor hiredis (0.6.3-x86_64-linux-musl) + hiredis-client (0.14.1-x86_64-linux-musl) + redis-client (= 0.14.1) http_parser.rb (0.8.0-x86_64-linux-musl) httparty (0.21.0) mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) - httparty-cache (0.0.1) + httparty-cache (0.0.4) httparty (~> 0.18) i18n (1.14.1) concurrent-ruby (~> 1.0) @@ -450,6 +453,8 @@ GEM redis-activesupport (5.3.0) activesupport (>= 3, < 8) redis-store (>= 1.3, < 2) + redis-client (0.14.1) + connection_pool redis-rack (2.1.4) rack (>= 2.0.8, < 3) redis-store (>= 1.2, < 2) @@ -487,6 +492,8 @@ GEM activesupport (>= 4.2.0) rack (>= 1.1) rubocop (>= 1.33.0, < 2.0) + ruby-brs (1.3.3-x86_64-linux-musl) + adsp (~> 1.0) ruby-filemagic (0.7.3-x86_64-linux-musl) ruby-progressbar (1.13.0) ruby-statistics (3.0.2) @@ -603,7 +610,7 @@ DEPENDENCIES devise devise-i18n devise_invitable - distributed-press-api-client (~> 0.4.0rc0) + distributed-press-api-client (~> 0.4.0rc2) dotenv-rails down ed25519 @@ -619,6 +626,7 @@ DEPENDENCIES haml-lint hamlit-rails hiredis + hiredis-client httparty icalendar image_processing @@ -652,10 +660,12 @@ DEPENDENCIES rails-i18n rails_warden redis (~> 4.0) + redis-client redis-rails rgl rollups! rubocop-rails + ruby-brs rubyzip rugged (= 1.5.0.1) safe_yaml From cdf0685c67721e0f4686e205379a00883506800f Mon Sep 17 00:00:00 2001 From: f Date: Fri, 16 Feb 2024 14:53:05 -0300 Subject: [PATCH 104/472] feat: asociar rol con deploy nos permite acceder al token --- app/models/deploy.rb | 2 ++ app/models/rol.rb | 1 + .../20240216170202_add_rol_to_deploys.rb | 18 ++++++++++++++++++ db/structure.sql | 6 ++++-- 4 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20240216170202_add_rol_to_deploys.rb diff --git a/app/models/deploy.rb b/app/models/deploy.rb index 1f087eb3..8f28f214 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -10,6 +10,8 @@ require 'open3' # :attributes`. class Deploy < ApplicationRecord belongs_to :site + belongs_to :rol + has_many :build_stats, dependent: :destroy DEPENDENCIES = [] diff --git a/app/models/rol.rb b/app/models/rol.rb index 37332400..c9a92515 100644 --- a/app/models/rol.rb +++ b/app/models/rol.rb @@ -11,6 +11,7 @@ class Rol < ApplicationRecord belongs_to :usuarie belongs_to :site + has_many :deploys validates_inclusion_of :rol, in: ROLES diff --git a/db/migrate/20240216170202_add_rol_to_deploys.rb b/db/migrate/20240216170202_add_rol_to_deploys.rb new file mode 100644 index 00000000..5f629432 --- /dev/null +++ b/db/migrate/20240216170202_add_rol_to_deploys.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# Establece una relación entre roles y deploys +class AddRolToDeploys < ActiveRecord::Migration[6.1] + def up + add_column :deploys, :rol_id, :integer, index: true + + Deploy.find_each do |deploy| + rol_id = deploy.site.roles.find_by(rol: 'usuarie', temporal: false).id + + deploy.update_column(:rol_id, rol_id) if rol_id + end + end + + def down + remove_column :deploys, :rol_id + end +end diff --git a/db/structure.sql b/db/structure.sql index cb085f63..dede286d 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -759,7 +759,8 @@ CREATE TABLE public.deploys ( updated_at timestamp without time zone NOT NULL, site_id integer, type character varying, - "values" text + "values" text, + rol_id integer ); @@ -2318,6 +2319,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20230731195050'), ('20230829204127'), ('20230921155401'), -('20230927153926'); +('20230927153926'), +('20240216170202'); From 6d0ea6fa5d864ae9969d43fa2fef5caf54888548 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 16 Feb 2024 14:54:50 -0300 Subject: [PATCH 105/472] feat: acceder a la social inbox desde el sitio --- app/models/site/social_distributed_press.rb | 11 ++++- app/models/social_inbox.rb | 52 +++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 app/models/social_inbox.rb diff --git a/app/models/site/social_distributed_press.rb b/app/models/site/social_distributed_press.rb index 3be6404e..1193ca76 100644 --- a/app/models/site/social_distributed_press.rb +++ b/app/models/site/social_distributed_press.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'distributed_press/v1/social/client' + class Site # Agrega soporte para Social Distributed Press en los sitios module SocialDistributedPress @@ -10,13 +12,20 @@ class Site before_save :generate_private_key_pem!, unless: :private_key_pem? + # @return [SocialInbox] + def social_inbox + @social_inbox ||= SocialInbox.new(site: self) + end + private # Genera la llave privada y la almacena # # @return [nil] def generate_private_key_pem! - self.private_key_pem ||= ::DistributedPress::V1::Social::Client.new(public_key_url: nil, key_size: 2048).private_key.export + self.private_key_pem ||= DistributedPress::V1::Social::Client.new( + public_key_url: nil, + key_size: 2048).private_key.export end end end diff --git a/app/models/social_inbox.rb b/app/models/social_inbox.rb new file mode 100644 index 00000000..47c3457c --- /dev/null +++ b/app/models/social_inbox.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require 'distributed_press/v1/social/client' + +# Gestiona la Social Inbox de un sitio +class SocialInbox + # @return [Site] + attr_reader :site + + # @param :site [Site] + def initialize(site:) + @site = site + end + + # @return [String] + def actor + @actor ||= + begin + user = site.config.dig('activity_pub', 'username') + user ||= hostname.split('.', 2).first + + "@#{user}@#{hostname}" + end + end + + # @return [DistributedPress::V1::Social::Client] + def client + @client ||= DistributedPress::V1::Social::Client.new( + url: site.config.dig('activity_pub', 'url'), + public_key_url: public_key_url, + private_key_pem: site.private_key_pem, + logger: Rails.logger, + cache_store: :redis + ) + end + + # @return [String] + def public_key_url + @public_key_url ||= URI("https://#{hostname}").tap do |uri| + uri.path = '/about.jsonld' + uri.fragment = 'main-key' + end.to_s + end + + def hostname + @hostname ||= + begin + host = site.config.dig('activity_pub', 'hostname') + host ||= site.hostname + end + end +end From e7595b86887764080dd60503b005dd1ea33534a7 Mon Sep 17 00:00:00 2001 From: maki Date: Fri, 16 Feb 2024 15:33:28 -0300 Subject: [PATCH 106/472] =?UTF-8?q?fix:=20la=20descripci=C3=B3n=20ya=20tra?= =?UTF-8?q?=C3=ADa=20etiqueta=20p,=20redundancia=20borrada?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_account.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/moderation_queue/_account.haml b/app/views/moderation_queue/_account.haml index 28bba0e9..85fe96d5 100644 --- a/app/views/moderation_queue/_account.haml +++ b/app/views/moderation_queue/_account.haml @@ -1,2 +1,2 @@ %a{href: profile['id']}= profile['preferredUsername'] -%p= profile['summary'].html_safe \ No newline at end of file +=profile['summary'].html_safe \ No newline at end of file From 4114c1abe6cd4f4fa33c84f2f6d758ec338f6381 Mon Sep 17 00:00:00 2001 From: maki Date: Fri, 16 Feb 2024 15:35:26 -0300 Subject: [PATCH 107/472] fix: p reemplazado por dl --- app/views/moderation_queue/_comment.haml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index aa8d777d..5b0f01a6 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -8,9 +8,10 @@ .col.col-4 %p= comment['published'].to_datetime.strftime(t('date.format')) .col.col-8 - %p - %span.mr-2= t('.source_profile') - %a{ href: comment['attributedTo'] }= profile['preferredUsername'] + %dl + %dt.d-inline.mr-2= t('.source_profile') + %dd.d-inline + %a{ href: comment['attributedTo'] }= profile['preferredUsername'] - if comment['inReplyTo'] .row From 2c61f3baa2e2466179d7089a1a8abd2747049159 Mon Sep 17 00:00:00 2001 From: maki Date: Fri, 16 Feb 2024 15:38:26 -0300 Subject: [PATCH 108/472] =?UTF-8?q?fix:=20comments=5Fbtn=5Fbox=20recibe=20?= =?UTF-8?q?comment=20como=20par=C3=A1metro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_comments.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index 76e08559..d51909a3 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -5,4 +5,4 @@ = render 'comment', comment: comment, profile: comment['attributedTo'] -# Botones moderación - = render 'components/comments_btn_box' \ No newline at end of file + = render 'components/comments_btn_box', comment: comment \ No newline at end of file From b792cb2d43a6ac145bb8a3afea6f0ccb1841eab5 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 16 Feb 2024 15:59:37 -0300 Subject: [PATCH 109/472] feat: poder reutilizar webhooks --- .../api/v1/concerns/webhook_concern.rb | 71 +++++++++++++++++++ app/controllers/api/v1/webhooks_controller.rb | 56 +-------------- config/routes.rb | 4 +- 3 files changed, 75 insertions(+), 56 deletions(-) create mode 100644 app/controllers/api/v1/concerns/webhook_concern.rb diff --git a/app/controllers/api/v1/concerns/webhook_concern.rb b/app/controllers/api/v1/concerns/webhook_concern.rb new file mode 100644 index 00000000..59d48b28 --- /dev/null +++ b/app/controllers/api/v1/concerns/webhook_concern.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +module Api + module V1 + # Helpers para webhooks + module WebhookConcern + extend ActiveSupport::Concern + + included do + # Responde con forbidden si falla la validación del token + rescue_from ActiveRecord::RecordNotFound, with: :platforms_answer + + private + + # Valida el token que envía la plataforma en el webhook + # + # @return [String] + def token + @token ||= + begin + _headers = request.headers + _token ||= _headers['X-Gitlab-Token'].presence + _token ||= token_from_signature(_headers['X-Gitea-Signature'].presence) + _token ||= token_from_signature(_headers['X-Hub-Signature-256'].presence, 'sha256=') + _token + ensure + raise ActiveRecord::RecordNotFound, 'Proveedor no soportado' if _token.blank? + end + end + + # Valida token a partir de firma + # + # @param signature [String,nil] + # @param prepend [String] + # @return [String, nil] + def token_from_signature(signature, prepend = '') + return if signature.nil? + + payload = request.raw_post + + site.roles.where(temporal: false, rol: 'usuarie').pluck(:token).find do |token| + new_signature = prepend + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), token, payload) + + ActiveSupport::SecurityUtils.secure_compare(new_signature, signature.to_s) + end + end + + # Encuentra el sitio a partir de la URL + # + # @return [Site] + def site + @site ||= Site.find_by_name!(params[:site_id]) + end + + # Encuentra le usuarie + # + # @return [Site] + def usuarie + @usuarie ||= site.roles.find_by!(temporal: false, rol: 'usuarie', token: token).usuarie + end + + # Respuesta de error a plataformas + def platforms_answer(exception) + ExceptionNotifier.notify_exception(exception, data: { headers: request.headers.to_h }) + + head :forbidden + end + end + end + end +end diff --git a/app/controllers/api/v1/webhooks_controller.rb b/app/controllers/api/v1/webhooks_controller.rb index 6e7b7022..f64fa93c 100644 --- a/app/controllers/api/v1/webhooks_controller.rb +++ b/app/controllers/api/v1/webhooks_controller.rb @@ -4,8 +4,7 @@ module Api module V1 # Recibe webhooks y lanza un PullJob class WebhooksController < BaseController - # responde con forbidden si falla la validación del token - rescue_from ActiveRecord::RecordNotFound, with: :platforms_answer + include WebhookConcern # Trae los cambios a partir de un post de Webhooks: # (Gitlab, Github, Gitea, etc) @@ -19,59 +18,6 @@ module Api GitPullJob.perform_later(site, usuarie, message) head :ok end - - private - - # encuentra el sitio a partir de la url - def site - @site ||= Site.find_by_name!(params[:site_id]) - end - - # valida el token que envía la plataforma del webhook - # - # @return [String] - def token - @token ||= - begin - # Gitlab - if request.headers['X-Gitlab-Token'].present? - request.headers['X-Gitlab-Token'] - # Github - elsif request.headers['X-Hub-Signature-256'].present? - token_from_signature(request.headers['X-Hub-Signature-256'], 'sha256=') - # Gitea - elsif request.headers['X-Gitea-Signature'].present? - token_from_signature(request.headers['X-Gitea-Signature']) - else - raise ActiveRecord::RecordNotFound, 'proveedor no soportado' - end - end - end - - # valida token a partir de firma de webhook - # - # @return [String, Boolean] - def token_from_signature(signature, prepend = '') - payload = request.body.read - site.roles.where(temporal: false, rol: 'usuarie').pluck(:token).find do |token| - new_signature = prepend + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), token, payload) - ActiveSupport::SecurityUtils.secure_compare(new_signature, signature.to_s) - end.tap do |t| - raise ActiveRecord::RecordNotFound, 'token no encontrado' if t.nil? - end - end - - # encuentra le usuarie - def usuarie - @usuarie ||= site.roles.find_by!(temporal: false, rol: 'usuarie', token: token).usuarie - end - - # respuesta de error a plataformas - def platforms_answer(exception) - ExceptionNotifier.notify_exception(exception, data: { headers: request.headers.to_h }) - - head :forbidden - end end end end diff --git a/config/routes.rb b/config/routes.rb index 635be07a..8186b64e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -18,7 +18,9 @@ Rails.application.routes.draw do get :'contact/cookie', to: 'invitades#contact_cookie' post :'contact/:form', to: 'contact#receive', as: :contact - post :'webhooks/pull', to: 'webhooks#pull' + namespace :webhooks do + post :pull, to: 'webhooks#pull' + end end end end From b24f49fe2611791eb377a56d4f7e9cdbeafafbd4 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 16 Feb 2024 16:01:17 -0300 Subject: [PATCH 110/472] feat: crear webhooks en la social inbox #15109 --- .../api/v1/social_inbox_controller.rb | 22 +++++++++++ app/models/deploy_social_distributed_press.rb | 39 +++++++++++++++++++ app/models/social_inbox.rb | 6 +++ config/application.rb | 3 ++ config/routes.rb | 6 +++ 5 files changed, 76 insertions(+) create mode 100644 app/controllers/api/v1/social_inbox_controller.rb diff --git a/app/controllers/api/v1/social_inbox_controller.rb b/app/controllers/api/v1/social_inbox_controller.rb new file mode 100644 index 00000000..3881b6bc --- /dev/null +++ b/app/controllers/api/v1/social_inbox_controller.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Api + module V1 + # Recibe webhooks de la Social Inbox + class SocialInboxController < BaseController + include WebhookConcern + + def moderationqueued + head :accepted + end + + def onapproved + head :accepted + end + + def onrejected + head :accepted + end + end + end +end diff --git a/app/models/deploy_social_distributed_press.rb b/app/models/deploy_social_distributed_press.rb index db555ab7..f5c38a22 100644 --- a/app/models/deploy_social_distributed_press.rb +++ b/app/models/deploy_social_distributed_press.rb @@ -7,6 +7,8 @@ class DeploySocialDistributedPress < Deploy # Solo luego de publicar remotamente DEPENDENCIES = %i[deploy_distributed_press deploy_rsync deploy_full_rsync] + after_save :create_hooks! + # Envía las notificaciones def deploy(output: false) with_tempfile(site.private_key_pem) do |file| @@ -52,4 +54,41 @@ class DeploySocialDistributedPress < Deploy def flags_for_build(**args) "--key #{Shellwords.escape args[:private_key].path}" end + + private + + # Obtiene el hostname de la API de Sutty + # + # @return [String] + def api_hostname + Rails.application.routes.default_url_options[:host].sub('panel', 'api') + end + + # Crea los hooks en la Social Inbox para que nos avise de actividades + # nuevas + # + # @return [nil] + def create_hooks! + hook_client = site.social_inbox.hook + + hook_client.class::EVENTS.each do |event| + event_url = :"v1_site_webhooks_social_inbox_#{event}_url" + + webhook = DistributedPress::V1::Social::Schemas::Webhook.new.call({ + method: 'POST', + url: Rails.application.routes.url_helpers.public_send(event_url, site_id: site.name, host: api_hostname), + headers: { + 'X-Social-Inbox': rol.token + } + }) + + raise ArgumentError, webhook.errors.messages if webhook.failure? + + response = hook_client.put(event: event, hook: webhook) + + raise ArgumentError, response.parsed_body unless response.ok? + rescue ArgumentError => e + ExceptionNotifier.notify_exception(e, data: { site_id: site.name, usuarie_id: rol.usuarie_id }) + end + end end diff --git a/app/models/social_inbox.rb b/app/models/social_inbox.rb index 47c3457c..8aa5b504 100644 --- a/app/models/social_inbox.rb +++ b/app/models/social_inbox.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'distributed_press/v1/social/client' +require 'distributed_press/v1/social/hook' # Gestiona la Social Inbox de un sitio class SocialInbox @@ -34,6 +35,11 @@ class SocialInbox ) end + # @return [DistributedPress::V1::Social::Hook] + def hook + @hook ||= DistributedPress::V1::Social::Hook.new(client: client, actor: actor) + end + # @return [String] def public_key_url @public_key_url ||= URI("https://#{hostname}").tap do |uri| diff --git a/config/application.rb b/config/application.rb index 529e341a..73a7a884 100644 --- a/config/application.rb +++ b/config/application.rb @@ -2,6 +2,9 @@ require_relative 'boot' +require 'redis-client' +require 'hiredis-client' +require 'brs' require 'rails' # Pick the frameworks you want: require 'active_model/railtie' diff --git a/config/routes.rb b/config/routes.rb index 8186b64e..f6f081f7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -20,6 +20,12 @@ Rails.application.routes.draw do namespace :webhooks do post :pull, to: 'webhooks#pull' + + namespace :social_inbox do + post :moderationqueued, to: 'social_inbox#moderationqueued' + post :onapproved, to: 'social_inbox#onapproved' + post :onrejected, to: 'social_inbox#onrejected' + end end end end From b4117d7c348b63b0af2efa86bbb3b79d582ec1ad Mon Sep 17 00:00:00 2001 From: f Date: Sat, 17 Feb 2024 14:11:17 -0300 Subject: [PATCH 111/472] chore: rubocop --- .../api/v1/concerns/webhook_concern.rb | 13 ++++++------ app/models/deploy.rb | 8 ++++---- app/models/deploy_social_distributed_press.rb | 20 +++++++++++-------- app/models/site/social_distributed_press.rb | 3 ++- app/models/social_inbox.rb | 5 +---- 5 files changed, 26 insertions(+), 23 deletions(-) diff --git a/app/controllers/api/v1/concerns/webhook_concern.rb b/app/controllers/api/v1/concerns/webhook_concern.rb index 59d48b28..9960e550 100644 --- a/app/controllers/api/v1/concerns/webhook_concern.rb +++ b/app/controllers/api/v1/concerns/webhook_concern.rb @@ -18,13 +18,14 @@ module Api def token @token ||= begin - _headers = request.headers - _token ||= _headers['X-Gitlab-Token'].presence - _token ||= token_from_signature(_headers['X-Gitea-Signature'].presence) - _token ||= token_from_signature(_headers['X-Hub-Signature-256'].presence, 'sha256=') - _token + header = request.headers + token = header['X-Social-Inbox'].presence + token ||= header['X-Gitlab-Token'].presence + token ||= token_from_signature(header['X-Gitea-Signature'].presence) + token ||= token_from_signature(header['X-Hub-Signature-256'].presence, 'sha256=') + token ensure - raise ActiveRecord::RecordNotFound, 'Proveedor no soportado' if _token.blank? + raise ActiveRecord::RecordNotFound, 'Proveedor no soportado' if token.blank? end end diff --git a/app/models/deploy.rb b/app/models/deploy.rb index 8f28f214..77646034 100644 --- a/app/models/deploy.rb +++ b/app/models/deploy.rb @@ -14,8 +14,8 @@ class Deploy < ApplicationRecord has_many :build_stats, dependent: :destroy - DEPENDENCIES = [] - SOFT_DEPENDENCIES = [] + DEPENDENCIES = [].freeze + SOFT_DEPENDENCIES = [].freeze def deploy(**) raise NotImplementedError @@ -74,7 +74,7 @@ class Deploy < ApplicationRecord 'HOME' => home_dir, 'PATH' => paths.join(':'), 'JEKYLL_ENV' => Rails.env, - 'LANG' => ENV['LANG'], + 'LANG' => ENV.fetch('LANG', nil) }) end @@ -139,7 +139,7 @@ class Deploy < ApplicationRecord # provisto con el archivo como parámetro # # @param :content [String] - def with_tempfile(content, &block) + def with_tempfile(content) Tempfile.create(SecureRandom.hex) do |file| file.write content.to_s file.rewind diff --git a/app/models/deploy_social_distributed_press.rb b/app/models/deploy_social_distributed_press.rb index f5c38a22..fc0e01d5 100644 --- a/app/models/deploy_social_distributed_press.rb +++ b/app/models/deploy_social_distributed_press.rb @@ -5,7 +5,7 @@ require 'distributed_press/v1/social/client' # Publicar novedades al Fediverso class DeploySocialDistributedPress < Deploy # Solo luego de publicar remotamente - DEPENDENCIES = %i[deploy_distributed_press deploy_rsync deploy_full_rsync] + DEPENDENCIES = %i[deploy_distributed_press deploy_rsync deploy_full_rsync].freeze after_save :create_hooks! @@ -70,17 +70,21 @@ class DeploySocialDistributedPress < Deploy # @return [nil] def create_hooks! hook_client = site.social_inbox.hook + webhook_class = DistributedPress::V1::Social::Schemas::Webhook hook_client.class::EVENTS.each do |event| event_url = :"v1_site_webhooks_social_inbox_#{event}_url" - webhook = DistributedPress::V1::Social::Schemas::Webhook.new.call({ - method: 'POST', - url: Rails.application.routes.url_helpers.public_send(event_url, site_id: site.name, host: api_hostname), - headers: { - 'X-Social-Inbox': rol.token - } - }) + webhook = + webhook_class.new.call({ + method: 'POST', + url: Rails.application.routes.url_helpers.public_send( + event_url, site_id: site.name, host: api_hostname + ), + headers: { + 'X-Social-Inbox': rol.token + } + }) raise ArgumentError, webhook.errors.messages if webhook.failure? diff --git a/app/models/site/social_distributed_press.rb b/app/models/site/social_distributed_press.rb index 1193ca76..d3ebf579 100644 --- a/app/models/site/social_distributed_press.rb +++ b/app/models/site/social_distributed_press.rb @@ -25,7 +25,8 @@ class Site def generate_private_key_pem! self.private_key_pem ||= DistributedPress::V1::Social::Client.new( public_key_url: nil, - key_size: 2048).private_key.export + key_size: 2048 + ).private_key.export end end end diff --git a/app/models/social_inbox.rb b/app/models/social_inbox.rb index 8aa5b504..24f749be 100644 --- a/app/models/social_inbox.rb +++ b/app/models/social_inbox.rb @@ -50,9 +50,6 @@ class SocialInbox def hostname @hostname ||= - begin - host = site.config.dig('activity_pub', 'hostname') - host ||= site.hostname - end + site.config.dig('activity_pub', 'hostname') || site.hostname end end From 9554ad1627b1167c140799202ac5c9081e5df885 Mon Sep 17 00:00:00 2001 From: maki Date: Mon, 19 Feb 2024 13:57:39 -0300 Subject: [PATCH 112/472] fix: sintaxis --- app/views/moderation_queue/_comment.haml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 5b0f01a6..fea4570f 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -3,23 +3,23 @@ .row.no-gutters .col-1 = render 'components/checkbox' - .col-10 + .col-11 .row.no-gutters - .col.col-4 + .col-4 %p= comment['published'].to_datetime.strftime(t('date.format')) - .col.col-8 + .col-8 %dl %dt.d-inline.mr-2= t('.source_profile') %dd.d-inline %a{ href: comment['attributedTo'] }= profile['preferredUsername'] - if comment['inReplyTo'] - .row + .row.no-gutters .col.p-0 %p %span.mr-3= t('.reply_to') %span %a{ href: comment['inReplyTo'] }= comment['inReplyTo'] - .row + .row.no-gutters .col.p-0 %p= comment['content'].html_safe From ecab598595130d8cd498161572902dd2cb1a57ca Mon Sep 17 00:00:00 2001 From: maki Date: Mon, 19 Feb 2024 14:21:32 -0300 Subject: [PATCH 113/472] =?UTF-8?q?fix:=20no=20se=20ve=C3=ADan=20los=20bot?= =?UTF-8?q?ones=20en=20modo=20oscuro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/assets/stylesheets/dark.scss | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/assets/stylesheets/dark.scss b/app/assets/stylesheets/dark.scss index 59e15180..f7f3a09d 100644 --- a/app/assets/stylesheets/dark.scss +++ b/app/assets/stylesheets/dark.scss @@ -8,6 +8,10 @@ $cyan: #13fefe; --color: #{$cyan}; } +.btn { + background-color: $white; +} + .btn-secondary { background-color: $white; color: $black; @@ -26,3 +30,5 @@ $cyan: #13fefe; box-shadow: 0 0 0 0.2rem $cyan; } } + + From 5ee9c49529c479625f3c1eee606d3ba3053a6421 Mon Sep 17 00:00:00 2001 From: jazzari Date: Tue, 20 Feb 2024 14:23:16 -0300 Subject: [PATCH 114/472] fix: corregidos botones y espacios en details de instancias --- app/views/components/_btn_base.haml | 2 +- app/views/components/_comments_btn_box.haml | 13 ++++++------- app/views/moderation_queue/_instance.haml | 19 ++++++++++++------- app/views/moderation_queue/_instances.haml | 3 ++- app/views/posts/_moderation_queue.haml | 2 +- 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/app/views/components/_btn_base.haml b/app/views/components/_btn_base.haml index 2985d646..ccc7ce35 100644 --- a/app/views/components/_btn_base.haml +++ b/app/views/components/_btn_base.haml @@ -1,3 +1,3 @@ -# Componente Botón general Moderación -%button.btn.btn-lg.mx-2{ href: href, class: local_assigns[:class] }= text +%button.btn.mx-2{ href: href, class: local_assigns[:class] }= text diff --git a/app/views/components/_comments_btn_box.haml b/app/views/components/_comments_btn_box.haml index 0487c3db..7932068f 100644 --- a/app/views/components/_comments_btn_box.haml +++ b/app/views/components/_comments_btn_box.haml @@ -1,9 +1,8 @@ -# Componente Botonera de Comentarios -.d-flex.py-4 - - btn_class = 'btn-secondary' - = render 'components/btn_base', text: t('.text_pause'), class: btn_class, href: '' - = render 'components/btn_base', text: t('.text_reject'), class: btn_class, href: '' - = render 'components/btn_base', text: t('.text_accept'), class: btn_class, href: '' - = render 'components/btn_base', text: t('.text_reply'), class: btn_class, href: '' - = render 'components/btn_base', text: t('.text_report'), class: btn_class, href: '' \ No newline at end of file +- btn_class = 'btn-secondary' += render 'components/btn_base', text: t('.text_pause'), class: btn_class, href: '' += render 'components/btn_base', text: t('.text_reject'), class: btn_class, href: '' += render 'components/btn_base', text: t('.text_accept'), class: btn_class, href: '' += render 'components/btn_base', text: t('.text_reply'), class: btn_class, href: '' += render 'components/btn_base', text: t('.text_report'), class: btn_class, href: '' \ No newline at end of file diff --git a/app/views/moderation_queue/_instance.haml b/app/views/moderation_queue/_instance.haml index eb5d6581..74bda75b 100644 --- a/app/views/moderation_queue/_instance.haml +++ b/app/views/moderation_queue/_instance.haml @@ -2,10 +2,15 @@ - host ||= instance['uri'] - host = "https://#{host}" -%a{ href: host }= instance['title'] -%p= instance['description'].html_safe -%p - %span= t('.users') - %span - = instance.dig('usage', 'users', 'active_month') - = instance.dig('stats', 'user_count') +.row.no-gutters.pt-2 + .col-1 + = render 'components/checkbox' + .col-11 + %h4 + %a{ href: host }= instance['title'] + %p= instance['description'].html_safe + %p + %span= t('.users') + %span + = instance.dig('usage', 'users', 'active_month') + = instance.dig('stats', 'user_count') diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index c34bc022..d19ef8ed 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -5,8 +5,9 @@ = render 'moderation_queue/instance', instance: instance -# Botones moderación - .d-flex.py-5 + .d-flex.pb-4 = render 'components/instances_btn_box' + %hr %h3.mt-5= t('moderation_queue.instances.title') %lead= t('moderation_queue.instances.description') diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index 6921acbb..2be35f7f 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -5,5 +5,5 @@ = render 'moderation_queue/comment', comment: comment, profile: comment['attributedTo'] -# Botones moderación - .d-flex.py-4 + .d-flex = render 'components/comments_btn_box' From 9064325f7f8d52b98932a88afb14cd2cb7e8e2a3 Mon Sep 17 00:00:00 2001 From: maki Date: Tue, 20 Feb 2024 14:26:55 -0300 Subject: [PATCH 115/472] fix: flecha del details apunta donde tiene que apuntar --- app/assets/stylesheets/application.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index ef36c3be..f40af493 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -572,7 +572,7 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); position: absolute; left: 97%; bottom: 3%; - transform: rotate(60deg); + transform: rotate(0deg); } &[open] { & > summary { From f968c60bdf554acf69c95d4791fd68c9636932c3 Mon Sep 17 00:00:00 2001 From: maki Date: Tue, 20 Feb 2024 14:29:48 -0300 Subject: [PATCH 116/472] =?UTF-8?q?fix:=20l=C3=ADneas=20de=20separaci?= =?UTF-8?q?=C3=B3n=20entre=20secciones=20de=20Actividades=20de=20moderaci?= =?UTF-8?q?=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/index.haml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml index 982a41c8..ab98ee30 100644 --- a/app/views/moderation_queue/index.haml +++ b/app/views/moderation_queue/index.haml @@ -6,9 +6,11 @@ - summary = t('.instances') = render 'layouts/details', summary: summary do = render 'moderation_queue/instances', site: @site, post: @post, moderation_queue: @moderation_queue + %hr - summary = t('.accounts') = render 'layouts/details', summary: summary do = render 'moderation_queue/accounts', site: @site, post: @post, moderation_queue: @moderation_queue + %hr - summary = t('.comments') = render 'layouts/details', summary: summary do = render 'moderation_queue/comments', site: @site, post: @post, moderation_queue: @moderation_queue From 195fdb56723fd1805deb97ac7962e8549b9cf42d Mon Sep 17 00:00:00 2001 From: maki Date: Tue, 20 Feb 2024 14:52:23 -0300 Subject: [PATCH 117/472] =?UTF-8?q?fix:=20que=20el=20separador=20entre=20d?= =?UTF-8?q?etails=20se=20vea=20en=20modo=20oscuro=20tambi=C3=A9n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/assets/stylesheets/application.scss | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index f40af493..054faee9 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -584,4 +584,6 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); } - +hr { + border-bottom: 1px solid #dee2e6; +} \ No newline at end of file From 3d543a22fdf5d302c534388cdb49adcb1be50576 Mon Sep 17 00:00:00 2001 From: maki Date: Tue, 20 Feb 2024 14:58:59 -0300 Subject: [PATCH 118/472] =?UTF-8?q?fix:=20la=20flecha=20del=20details=20te?= =?UTF-8?q?n=C3=ADa=20que=20apuntar=20para=20la=20izq=20ups?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/assets/stylesheets/application.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 054faee9..240e61a5 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -572,7 +572,7 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); position: absolute; left: 97%; bottom: 3%; - transform: rotate(0deg); + transform: rotate(180deg); } &[open] { & > summary { From 5c2f2b9c614eacfc5b9cdaacdb96216d2be412cb Mon Sep 17 00:00:00 2001 From: jazzari Date: Tue, 20 Feb 2024 15:12:42 -0300 Subject: [PATCH 119/472] =?UTF-8?q?fix:=20agregada=20l=C3=ADnea=20de=20sep?= =?UTF-8?q?araci=C3=B3n=20de=20tarjetas=20en=20compo=20accounts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_account.haml | 9 +++++++-- app/views/moderation_queue/_accounts.haml | 5 +++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/views/moderation_queue/_account.haml b/app/views/moderation_queue/_account.haml index 85fe96d5..ab4fc4c7 100644 --- a/app/views/moderation_queue/_account.haml +++ b/app/views/moderation_queue/_account.haml @@ -1,2 +1,7 @@ -%a{href: profile['id']}= profile['preferredUsername'] -=profile['summary'].html_safe \ No newline at end of file +.row.no-gutters.pt-2 + .col-1 + = render 'components/checkbox' + .col-11 + %h4 + %a{href: profile['id']}= profile['preferredUsername'] + =profile['summary'].html_safe diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index e92c3a20..9a6738bd 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -2,9 +2,10 @@ = render 'components/profiles_filters' - @moderation_queue.map{ |c| c['attributedTo'] }.uniq.each do |remote_profile| + %hr = render 'account', profile: remote_profile -# Botones de Moderación -.d-flex.py-4 +.d-flex.pb-4 = render 'components/profiles_btn_box' - \ No newline at end of file + From 71d0985a39dc9b5dc126b57f560f3c580864d7d3 Mon Sep 17 00:00:00 2001 From: maki Date: Tue, 20 Feb 2024 15:13:54 -0300 Subject: [PATCH 120/472] =?UTF-8?q?fix:=20bot=C3=B3n=20no=20deber=C3=ADa?= =?UTF-8?q?=20ocupar=20todo=20el=20ancho=20del=20div?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_block_instances_textarea.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/moderation_queue/_block_instances_textarea.haml b/app/views/moderation_queue/_block_instances_textarea.haml index 0c0f55ca..ff8f9286 100644 --- a/app/views/moderation_queue/_block_instances_textarea.haml +++ b/app/views/moderation_queue/_block_instances_textarea.haml @@ -1,4 +1,4 @@ .form-group .d-flex.flex-column.mt-5 %textarea.mb-3{ name: '', id: '', placeholder: t('moderation_queue.instances.custom_block') } - %button.col.btn.btn-secondary{ type: 'submit' }= t('moderation_queue.instances.submit') + %button.btn.btn-secondary{ type: 'submit' }= t('moderation_queue.instances.submit') From bd41144ecf5939fa5a11e5607f8ca2317744051e Mon Sep 17 00:00:00 2001 From: maki Date: Tue, 20 Feb 2024 15:41:49 -0300 Subject: [PATCH 121/472] fix: textarea --- app/views/components/_block_lists.haml | 2 +- app/views/moderation_queue/_block_instances_textarea.haml | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/views/components/_block_lists.haml b/app/views/components/_block_lists.haml index 7d9d741d..8cdcd43b 100644 --- a/app/views/components/_block_lists.haml +++ b/app/views/components/_block_lists.haml @@ -1,5 +1,5 @@ -# Componente Listas de bloqueo de Instancias -.card.mt-3 +.card.mt-3.mb-3 .card-body .d-flex.flex-row = render 'components/checkbox' diff --git a/app/views/moderation_queue/_block_instances_textarea.haml b/app/views/moderation_queue/_block_instances_textarea.haml index ff8f9286..9b388a0d 100644 --- a/app/views/moderation_queue/_block_instances_textarea.haml +++ b/app/views/moderation_queue/_block_instances_textarea.haml @@ -1,4 +1,5 @@ .form-group - .d-flex.flex-column.mt-5 - %textarea.mb-3{ name: '', id: '', placeholder: t('moderation_queue.instances.custom_block') } - %button.btn.btn-secondary{ type: 'submit' }= t('moderation_queue.instances.submit') + = label_tag "custom_blocklist", t('moderation_queue.instances.custom_block') + = text_area_tag "custom_blocklist", nil, class: 'form-control' + %button.btn.btn-secondary.mt-3{ type: 'submit' }= t('moderation_queue.instances.submit') + From 27c0ca655eef45d61523f577dc9cc34cee0d0afe Mon Sep 17 00:00:00 2001 From: f Date: Tue, 20 Feb 2024 14:44:52 -0300 Subject: [PATCH 122/472] feat: modelo de datos de activitypub #15109 --- app/models/activity_pub.rb | 33 ++++ app/models/activity_pub/activity.rb | 24 +++ app/models/activity_pub/activity/create.rb | 3 + app/models/activity_pub/activity/delete.rb | 3 + app/models/activity_pub/activity/flag.rb | 3 + app/models/activity_pub/activity/follow.rb | 7 + app/models/activity_pub/activity/generic.rb | 3 + app/models/activity_pub/activity/undo.rb | 8 + app/models/activity_pub/activity/update.rb | 3 + app/models/activity_pub/actor.rb | 14 ++ .../activity_pub/concerns/json_ld_concern.rb | 32 ++++ app/models/activity_pub/instance.rb | 21 +++ app/models/activity_pub/object.rb | 11 ++ app/models/activity_pub/object/application.rb | 6 + app/models/activity_pub/object/article.rb | 6 + app/models/activity_pub/object/generic.rb | 4 + app/models/activity_pub/object/note.rb | 6 + .../activity_pub/object/organization.rb | 6 + app/models/activity_pub/object/person.rb | 6 + ...19153919_create_activity_pub_activities.rb | 16 ++ ...240219175839_create_activity_pub_actors.rb | 12 ++ .../20240219204011_create_activity_pubs.rb | 18 ++ ...40219204224_create_activity_pub_objects.rb | 17 ++ ...220161414_create_activity_pub_instances.rb | 13 ++ db/structure.sql | 161 +++++++++++++++++- 25 files changed, 435 insertions(+), 1 deletion(-) create mode 100644 app/models/activity_pub.rb create mode 100644 app/models/activity_pub/activity.rb create mode 100644 app/models/activity_pub/activity/create.rb create mode 100644 app/models/activity_pub/activity/delete.rb create mode 100644 app/models/activity_pub/activity/flag.rb create mode 100644 app/models/activity_pub/activity/follow.rb create mode 100644 app/models/activity_pub/activity/generic.rb create mode 100644 app/models/activity_pub/activity/undo.rb create mode 100644 app/models/activity_pub/activity/update.rb create mode 100644 app/models/activity_pub/actor.rb create mode 100644 app/models/activity_pub/concerns/json_ld_concern.rb create mode 100644 app/models/activity_pub/instance.rb create mode 100644 app/models/activity_pub/object.rb create mode 100644 app/models/activity_pub/object/application.rb create mode 100644 app/models/activity_pub/object/article.rb create mode 100644 app/models/activity_pub/object/generic.rb create mode 100644 app/models/activity_pub/object/note.rb create mode 100644 app/models/activity_pub/object/organization.rb create mode 100644 app/models/activity_pub/object/person.rb create mode 100644 db/migrate/20240219153919_create_activity_pub_activities.rb create mode 100644 db/migrate/20240219175839_create_activity_pub_actors.rb create mode 100644 db/migrate/20240219204011_create_activity_pubs.rb create mode 100644 db/migrate/20240219204224_create_activity_pub_objects.rb create mode 100644 db/migrate/20240220161414_create_activity_pub_instances.rb diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb new file mode 100644 index 00000000..c0474b89 --- /dev/null +++ b/app/models/activity_pub.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +# = ActivityPub = +# +# El registro de actividades recibidas y su estado. Cuando recibimos +# una actividad, puede estar destinada a varies actores dentro de Sutty, +# con lo que generamos una cola para cada une. +# +# @see {https://www.w3.org/TR/activitypub/#client-to-server-interactions} +class ActivityPub < ApplicationRecord + include AASM + + belongs_to :site + belongs_to :object, polymorphic: true + has_many :activities + + validates :site_id, presence: true + validates :object_id, presence: true + validates :aasm_state, presence: true, inclusion: { in: %w[paused approved rejected reported deleted] } + + aasm do + # Todavía no hay una decisión sobre el objeto + state :paused, initial: true + # Le usuarie aprobó el objeto + state :approved + # Le usuarie rechazó el objeto + state :rejected + # Le usuarie reportó el objeto + state :reported + # Le actore eliminó el objeto + state :deleted + end +end diff --git a/app/models/activity_pub/activity.rb b/app/models/activity_pub/activity.rb new file mode 100644 index 00000000..4a88c1f3 --- /dev/null +++ b/app/models/activity_pub/activity.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +# = Activity = +# +# Lleva un registro de las actividades que nos piden hacer remotamente. +# +# Las actividades pueden tener distintos destinataries (sitios/actores). +# +# @todo Obtener el contenido del objeto dinámicamente si no existe +# localmente, por ejemplo cuando la actividad crea un objeto pero lo +# envía como referencia en lugar de anidarlo. +# +# @see {https://www.w3.org/TR/activitypub/#client-to-server-interactions} +class ActivityPub::Activity < ApplicationRecord + include ActivityPub::Concerns::JsonLdConcern + + belongs_to :activity_pub + has_one :object, through: :activity_pub + + validates :activity_pub_id, presence: true + + # Siempre en orden descendiente para saber el último estado + default_scope -> { order(created_at: :desc) } +end diff --git a/app/models/activity_pub/activity/create.rb b/app/models/activity_pub/activity/create.rb new file mode 100644 index 00000000..3dcba5c2 --- /dev/null +++ b/app/models/activity_pub/activity/create.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +class ActivityPub::Activity::Create < ActivityPub::Activity; end diff --git a/app/models/activity_pub/activity/delete.rb b/app/models/activity_pub/activity/delete.rb new file mode 100644 index 00000000..f3684a0f --- /dev/null +++ b/app/models/activity_pub/activity/delete.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +class ActivityPub::Activity::Delete < ActivityPub::Activity; end diff --git a/app/models/activity_pub/activity/flag.rb b/app/models/activity_pub/activity/flag.rb new file mode 100644 index 00000000..2911911e --- /dev/null +++ b/app/models/activity_pub/activity/flag.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +class ActivityPub::Activity::Flag < ActivityPub::Activity; end diff --git a/app/models/activity_pub/activity/follow.rb b/app/models/activity_pub/activity/follow.rb new file mode 100644 index 00000000..c22dfd51 --- /dev/null +++ b/app/models/activity_pub/activity/follow.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +# = Follow = +# +# Una actividad de seguimiento se refiere siempre a une actore (el +# sitio) y proviene de otre actore. +class ActivityPub::Activity::Follow < ActivityPub::Activity; end diff --git a/app/models/activity_pub/activity/generic.rb b/app/models/activity_pub/activity/generic.rb new file mode 100644 index 00000000..8bf76471 --- /dev/null +++ b/app/models/activity_pub/activity/generic.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +class ActivityPub::Activity::Generic < ActivityPub::Activity; end diff --git a/app/models/activity_pub/activity/undo.rb b/app/models/activity_pub/activity/undo.rb new file mode 100644 index 00000000..a4915394 --- /dev/null +++ b/app/models/activity_pub/activity/undo.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# = Undo = +# +# Deshace una actividad, dependiendo de la actividad a la que se +# refiere. +class ActivityPub::Activity::Undo < ActivityPub::Activity +end diff --git a/app/models/activity_pub/activity/update.rb b/app/models/activity_pub/activity/update.rb new file mode 100644 index 00000000..8089cdcf --- /dev/null +++ b/app/models/activity_pub/activity/update.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +class ActivityPub::Activity::Update < ActivityPub::Activity; end diff --git a/app/models/activity_pub/actor.rb b/app/models/activity_pub/actor.rb new file mode 100644 index 00000000..f29c382a --- /dev/null +++ b/app/models/activity_pub/actor.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# = Actor = +# +# Actor es la entidad que realiza acciones en ActivityPub +# +# @todo Obtener el perfil dinámicamente +class ActivityPub::Actor < ApplicationRecord + include ActivityPub::Concerns::JsonLdConcern + + belongs_to :instance + has_many :activity_pubs, as: :object + has_many :objects +end diff --git a/app/models/activity_pub/concerns/json_ld_concern.rb b/app/models/activity_pub/concerns/json_ld_concern.rb new file mode 100644 index 00000000..b0899606 --- /dev/null +++ b/app/models/activity_pub/concerns/json_ld_concern.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +class ActivityPub + module Concerns + module JsonLdConcern + extend ActiveSupport::Concern + + included do + validates :uri, presence: true, uniqueness: true + + # Cuando asignamos contenido, obtener la URI si no lo hicimos ya + before_save :uri_from_content!, unless: :uri? + + # Obtiene un tipo de actividad a partir del tipo informado + # + # @param object [Hash] + # @return [Activity] + def self.type_from(object) + "#{self.class.name}::#{object[:type].presence || 'Generic'}".constantize + rescue NameError + self.class::Generic + end + + private + + def uri_from_content! + self.uri = content[:id] + end + end + end + end +end diff --git a/app/models/activity_pub/instance.rb b/app/models/activity_pub/instance.rb new file mode 100644 index 00000000..fe4a777b --- /dev/null +++ b/app/models/activity_pub/instance.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +# = Instance = +# +# Representa cada instancia del fediverso que interactúa con la Social +# Inbox. +class ActivityPub::Instance < ApplicationRecord + include AASM + + validates :aasm_state, presence: true, inclusion: { in: %w[paused allowed blocked] } + validates :hostname, uniqueness: true, hostname: true + + has_many :activity_pubs + has_many :actors + + aasm do + state :paused, initial: true + state :allowed + state :blocked + end +end diff --git a/app/models/activity_pub/object.rb b/app/models/activity_pub/object.rb new file mode 100644 index 00000000..519749ef --- /dev/null +++ b/app/models/activity_pub/object.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +# Almacena objetos de ActivityPub, como Note, Article, etc. +class ActivityPub::Object < ApplicationRecord + include ActivityPub::Concerns::JsonLdConcern + + belongs_to :actor + has_many :activity_pubs, as: :object + + validates :actor_id, presence: true +end diff --git a/app/models/activity_pub/object/application.rb b/app/models/activity_pub/object/application.rb new file mode 100644 index 00000000..e8a6f97c --- /dev/null +++ b/app/models/activity_pub/object/application.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +# = Application = +# +# Una aplicación o instancia +class ActivityPub::Object::Application < ActivityPub::Object; end diff --git a/app/models/activity_pub/object/article.rb b/app/models/activity_pub/object/article.rb new file mode 100644 index 00000000..ad1a6131 --- /dev/null +++ b/app/models/activity_pub/object/article.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +# = Article = +# +# Representa artículos +class ActivityPub::Object::Article < ActivityPub::Object; end diff --git a/app/models/activity_pub/object/generic.rb b/app/models/activity_pub/object/generic.rb new file mode 100644 index 00000000..f345e7a9 --- /dev/null +++ b/app/models/activity_pub/object/generic.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +# = Generic = +class ActivityPub::Object::Generic < ActivityPub::Object; end diff --git a/app/models/activity_pub/object/note.rb b/app/models/activity_pub/object/note.rb new file mode 100644 index 00000000..0f84c747 --- /dev/null +++ b/app/models/activity_pub/object/note.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +# = Note = +# +# Representa notas, el tipo más común de objeto del Fediverso. +class ActivityPub::Object::Note < ActivityPub::Object; end diff --git a/app/models/activity_pub/object/organization.rb b/app/models/activity_pub/object/organization.rb new file mode 100644 index 00000000..a5327d10 --- /dev/null +++ b/app/models/activity_pub/object/organization.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +# = Organization = +# +# Una organización +class ActivityPub::Object::Organization < ActivityPub::Object; end diff --git a/app/models/activity_pub/object/person.rb b/app/models/activity_pub/object/person.rb new file mode 100644 index 00000000..98a1568d --- /dev/null +++ b/app/models/activity_pub/object/person.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +# = Person = +# +# Una persona, el perfil de une actore +class ActivityPub::Object::Person < ActivityPub::Object; end diff --git a/db/migrate/20240219153919_create_activity_pub_activities.rb b/db/migrate/20240219153919_create_activity_pub_activities.rb new file mode 100644 index 00000000..555656ad --- /dev/null +++ b/db/migrate/20240219153919_create_activity_pub_activities.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# Actividades. Se asocian a un objeto y a una cola de moderación +class CreateActivityPubActivities < ActiveRecord::Migration[6.1] + def change + create_table :activity_pub_activities, id: :uuid do |t| + t.timestamps + + t.uuid :activity_pub_id, index: true, null: false + + t.string :type, null: false + t.string :uri, null: false + t.jsonb :content, default: {} + end + end +end diff --git a/db/migrate/20240219175839_create_activity_pub_actors.rb b/db/migrate/20240219175839_create_activity_pub_actors.rb new file mode 100644 index 00000000..656b3f63 --- /dev/null +++ b/db/migrate/20240219175839_create_activity_pub_actors.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +# Almacena actores de ActivityPub y los relaciona con actividades +class CreateActivityPubActors < ActiveRecord::Migration[6.1] + def change + create_table :activity_pub_actors, id: :uuid do |t| + t.timestamps + t.uuid :instance_id, index: true, null: false + t.string :uri, index: true, unique: true, null: false + end + end +end diff --git a/db/migrate/20240219204011_create_activity_pubs.rb b/db/migrate/20240219204011_create_activity_pubs.rb new file mode 100644 index 00000000..cf797fc8 --- /dev/null +++ b/db/migrate/20240219204011_create_activity_pubs.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# Registro de actividades. +class CreateActivityPubs < ActiveRecord::Migration[6.1] + def change + create_table :activity_pubs, id: :uuid do |t| + t.timestamps + + t.bigint :site_id, null: false + t.uuid :object_id, null: false + t.string :object_type, null: false + + t.string :aasm_state, null: false + + t.index %i[site_id object_id object_type], unique: true + end + end +end diff --git a/db/migrate/20240219204224_create_activity_pub_objects.rb b/db/migrate/20240219204224_create_activity_pub_objects.rb new file mode 100644 index 00000000..865589ab --- /dev/null +++ b/db/migrate/20240219204224_create_activity_pub_objects.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +# Almacena objetos de ActivityPub. Los objetos pueden estar compartidos +# por toda la instancia. +class CreateActivityPubObjects < ActiveRecord::Migration[6.1] + def change + create_table :activity_pub_objects, id: :uuid do |t| + t.timestamps + + t.uuid :actor_id, index: true, null: false + + t.string :type, null: false + t.string :uri, null: false, unique: true + t.jsonb :content, default: {} + end + end +end diff --git a/db/migrate/20240220161414_create_activity_pub_instances.rb b/db/migrate/20240220161414_create_activity_pub_instances.rb new file mode 100644 index 00000000..feb9351d --- /dev/null +++ b/db/migrate/20240220161414_create_activity_pub_instances.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +# Almacena las instancias +class CreateActivityPubInstances < ActiveRecord::Migration[6.1] + def change + create_table :activity_pub_instances, id: :uuid do |t| + t.timestamps + t.string :hostname, index: true, unique: true, null: false + t.string :aasm_state, null: false + t.jsonb :content, default: {} + end + end +end diff --git a/db/structure.sql b/db/structure.sql index dede286d..723c9e99 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -473,6 +473,78 @@ CREATE SEQUENCE public.active_storage_variant_records_id_seq ALTER SEQUENCE public.active_storage_variant_records_id_seq OWNED BY public.active_storage_variant_records.id; +-- +-- Name: activity_pub_activities; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.activity_pub_activities ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, + activity_pub_id uuid NOT NULL, + type character varying NOT NULL, + uri character varying NOT NULL, + content jsonb DEFAULT '{}'::jsonb +); + + +-- +-- Name: activity_pub_actors; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.activity_pub_actors ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, + instance_id uuid NOT NULL, + uri character varying NOT NULL +); + + +-- +-- Name: activity_pub_instances; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.activity_pub_instances ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, + hostname character varying NOT NULL, + aasm_state character varying NOT NULL, + content jsonb DEFAULT '{}'::jsonb +); + + +-- +-- Name: activity_pub_objects; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.activity_pub_objects ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, + actor_id uuid NOT NULL, + type character varying NOT NULL, + uri character varying NOT NULL, + content jsonb DEFAULT '{}'::jsonb +); + + +-- +-- Name: activity_pubs; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.activity_pubs ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, + site_id bigint NOT NULL, + object_id uuid NOT NULL, + object_type character varying NOT NULL, + aasm_state character varying NOT NULL +); + + -- -- Name: ar_internal_metadata; Type: TABLE; Schema: public; Owner: - -- @@ -1565,6 +1637,46 @@ ALTER TABLE ONLY public.active_storage_variant_records ADD CONSTRAINT active_storage_variant_records_pkey PRIMARY KEY (id); +-- +-- Name: activity_pub_activities activity_pub_activities_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.activity_pub_activities + ADD CONSTRAINT activity_pub_activities_pkey PRIMARY KEY (id); + + +-- +-- Name: activity_pub_actors activity_pub_actors_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.activity_pub_actors + ADD CONSTRAINT activity_pub_actors_pkey PRIMARY KEY (id); + + +-- +-- Name: activity_pub_instances activity_pub_instances_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.activity_pub_instances + ADD CONSTRAINT activity_pub_instances_pkey PRIMARY KEY (id); + + +-- +-- Name: activity_pub_objects activity_pub_objects_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.activity_pub_objects + ADD CONSTRAINT activity_pub_objects_pkey PRIMARY KEY (id); + + +-- +-- Name: activity_pubs activity_pubs_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.activity_pubs + ADD CONSTRAINT activity_pubs_pkey PRIMARY KEY (id); + + -- -- Name: blazer_audits blazer_audits_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -1865,6 +1977,48 @@ CREATE UNIQUE INDEX index_active_storage_blobs_on_key_and_service_name ON public CREATE UNIQUE INDEX index_active_storage_variant_records_uniqueness ON public.active_storage_variant_records USING btree (blob_id, variation_digest); +-- +-- Name: index_activity_pub_activities_on_activity_pub_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_activity_pub_activities_on_activity_pub_id ON public.activity_pub_activities USING btree (activity_pub_id); + + +-- +-- Name: index_activity_pub_actors_on_instance_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_activity_pub_actors_on_instance_id ON public.activity_pub_actors USING btree (instance_id); + + +-- +-- Name: index_activity_pub_actors_on_uri; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_activity_pub_actors_on_uri ON public.activity_pub_actors USING btree (uri); + + +-- +-- Name: index_activity_pub_instances_on_hostname; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_activity_pub_instances_on_hostname ON public.activity_pub_instances USING btree (hostname); + + +-- +-- Name: index_activity_pub_objects_on_actor_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_activity_pub_objects_on_actor_id ON public.activity_pub_objects USING btree (actor_id); + + +-- +-- Name: index_activity_pubs_on_site_id_and_object_id_and_object_type; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_activity_pubs_on_site_id_and_object_id_and_object_type ON public.activity_pubs USING btree (site_id, object_id, object_type); + + -- -- Name: index_blazer_audits_on_query_id; Type: INDEX; Schema: public; Owner: - -- @@ -2320,6 +2474,11 @@ INSERT INTO "schema_migrations" (version) VALUES ('20230829204127'), ('20230921155401'), ('20230927153926'), -('20240216170202'); +('20240216170202'), +('20240219153919'), +('20240219175839'), +('20240219204011'), +('20240219204224'), +('20240220161414'); From 8921de81aef45c3d822144fc1f2e4bbb38fe0f3e Mon Sep 17 00:00:00 2001 From: f Date: Tue, 20 Feb 2024 17:13:42 -0300 Subject: [PATCH 123/472] feat: rutas --- .../api/v1/concerns/webhook_concern.rb | 72 ------------------ .../api/v1/social_inbox_controller.rb | 22 ------ .../v1/webhooks/concerns/webhook_concern.rb | 76 +++++++++++++++++++ .../api/v1/webhooks/pull_controller.rb | 25 ++++++ .../v1/webhooks/social_inbox_controller.rb | 39 ++++++++++ app/controllers/api/v1/webhooks_controller.rb | 23 ------ config/routes.rb | 4 +- 7 files changed, 142 insertions(+), 119 deletions(-) delete mode 100644 app/controllers/api/v1/concerns/webhook_concern.rb delete mode 100644 app/controllers/api/v1/social_inbox_controller.rb create mode 100644 app/controllers/api/v1/webhooks/concerns/webhook_concern.rb create mode 100644 app/controllers/api/v1/webhooks/pull_controller.rb create mode 100644 app/controllers/api/v1/webhooks/social_inbox_controller.rb delete mode 100644 app/controllers/api/v1/webhooks_controller.rb diff --git a/app/controllers/api/v1/concerns/webhook_concern.rb b/app/controllers/api/v1/concerns/webhook_concern.rb deleted file mode 100644 index 9960e550..00000000 --- a/app/controllers/api/v1/concerns/webhook_concern.rb +++ /dev/null @@ -1,72 +0,0 @@ -# frozen_string_literal: true - -module Api - module V1 - # Helpers para webhooks - module WebhookConcern - extend ActiveSupport::Concern - - included do - # Responde con forbidden si falla la validación del token - rescue_from ActiveRecord::RecordNotFound, with: :platforms_answer - - private - - # Valida el token que envía la plataforma en el webhook - # - # @return [String] - def token - @token ||= - begin - header = request.headers - token = header['X-Social-Inbox'].presence - token ||= header['X-Gitlab-Token'].presence - token ||= token_from_signature(header['X-Gitea-Signature'].presence) - token ||= token_from_signature(header['X-Hub-Signature-256'].presence, 'sha256=') - token - ensure - raise ActiveRecord::RecordNotFound, 'Proveedor no soportado' if token.blank? - end - end - - # Valida token a partir de firma - # - # @param signature [String,nil] - # @param prepend [String] - # @return [String, nil] - def token_from_signature(signature, prepend = '') - return if signature.nil? - - payload = request.raw_post - - site.roles.where(temporal: false, rol: 'usuarie').pluck(:token).find do |token| - new_signature = prepend + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), token, payload) - - ActiveSupport::SecurityUtils.secure_compare(new_signature, signature.to_s) - end - end - - # Encuentra el sitio a partir de la URL - # - # @return [Site] - def site - @site ||= Site.find_by_name!(params[:site_id]) - end - - # Encuentra le usuarie - # - # @return [Site] - def usuarie - @usuarie ||= site.roles.find_by!(temporal: false, rol: 'usuarie', token: token).usuarie - end - - # Respuesta de error a plataformas - def platforms_answer(exception) - ExceptionNotifier.notify_exception(exception, data: { headers: request.headers.to_h }) - - head :forbidden - end - end - end - end -end diff --git a/app/controllers/api/v1/social_inbox_controller.rb b/app/controllers/api/v1/social_inbox_controller.rb deleted file mode 100644 index 3881b6bc..00000000 --- a/app/controllers/api/v1/social_inbox_controller.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -module Api - module V1 - # Recibe webhooks de la Social Inbox - class SocialInboxController < BaseController - include WebhookConcern - - def moderationqueued - head :accepted - end - - def onapproved - head :accepted - end - - def onrejected - head :accepted - end - end - end -end diff --git a/app/controllers/api/v1/webhooks/concerns/webhook_concern.rb b/app/controllers/api/v1/webhooks/concerns/webhook_concern.rb new file mode 100644 index 00000000..a546a55c --- /dev/null +++ b/app/controllers/api/v1/webhooks/concerns/webhook_concern.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +module Api + module V1 + module Webhooks + module Concerns + # Helpers para webhooks + module WebhookConcern + extend ActiveSupport::Concern + + included do + # Responde con forbidden si falla la validación del token + rescue_from ActiveRecord::RecordNotFound, with: :platforms_answer + + private + + # Valida el token que envía la plataforma en el webhook + # + # @return [String] + def token + @token ||= + begin + header = request.headers + token = header['X-Social-Inbox'].presence + token ||= header['X-Gitlab-Token'].presence + token ||= token_from_signature(header['X-Gitea-Signature'].presence) + token ||= token_from_signature(header['X-Hub-Signature-256'].presence, 'sha256=') + token + ensure + raise ActiveRecord::RecordNotFound, 'Proveedor no soportado' if token.blank? + end + end + + # Valida token a partir de firma + # + # @param signature [String,nil] + # @param prepend [String] + # @return [String, nil] + def token_from_signature(signature, prepend = '') + return if signature.nil? + + payload = request.raw_post + + site.roles.where(temporal: false, rol: 'usuarie').pluck(:token).find do |token| + new_signature = prepend + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), token, payload) + + ActiveSupport::SecurityUtils.secure_compare(new_signature, signature.to_s) + end + end + + # Encuentra el sitio a partir de la URL + # + # @return [Site] + def site + @site ||= Site.find_by_name!(params[:site_id]) + end + + # Encuentra le usuarie + # + # @return [Site] + def usuarie + @usuarie ||= site.roles.find_by!(temporal: false, rol: 'usuarie', token: token).usuarie + end + + # Respuesta de error a plataformas + def platforms_answer(exception) + ExceptionNotifier.notify_exception(exception, data: { headers: request.headers.to_h }) + + head :forbidden + end + end + end + end + end + end +end diff --git a/app/controllers/api/v1/webhooks/pull_controller.rb b/app/controllers/api/v1/webhooks/pull_controller.rb new file mode 100644 index 00000000..5f0b703b --- /dev/null +++ b/app/controllers/api/v1/webhooks/pull_controller.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Api + module V1 + module Webhooks + # Recibe webhooks y lanza un PullJob + class PullController < BaseController + include WebhookConcern + + # Trae los cambios a partir de un post de Webhooks: + # (Gitlab, Github, Gitea, etc) + # + # @return [nil] + def pull + message = I18n.with_locale(site.default_locale) do + I18n.t('webhooks.pull.message') + end + + GitPullJob.perform_later(site, usuarie, message) + head :ok + end + end + end + end +end diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb new file mode 100644 index 00000000..bc604156 --- /dev/null +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module Api + module V1 + module Webhooks + # Recibe webhooks de la Social Inbox + # + # @see {https://www.w3.org/TR/activitypub/} + class SocialInboxController < BaseController + include Api::V1::Webhooks::Concerns::WebhookConcern + + # Cuando una actividad ingresa en la cola de moderación, la + # recibimos por acá + # + # Vamos a recibir Create, Update, Delete, Follow, Undo y obtener + # el objeto dentro de cada una para guardar un estado asociado + # al sitio. + # + # El objeto del estado puede ser un objeto o une actore, + # dependiendo de la actividad. + def moderationqueued + head :accepted + end + + # Cuando aprobamos una actividad, recibimos la confirmación y + # cambiamos el estado + def onapproved + head :accepted + end + + # Cuando rechazamos una actividad, recibimos la confirmación y + # cambiamos el estado + def onrejected + head :accepted + end + end + end + end +end diff --git a/app/controllers/api/v1/webhooks_controller.rb b/app/controllers/api/v1/webhooks_controller.rb deleted file mode 100644 index f64fa93c..00000000 --- a/app/controllers/api/v1/webhooks_controller.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -module Api - module V1 - # Recibe webhooks y lanza un PullJob - class WebhooksController < BaseController - include WebhookConcern - - # Trae los cambios a partir de un post de Webhooks: - # (Gitlab, Github, Gitea, etc) - # - # @return [nil] - def pull - message = I18n.with_locale(site.default_locale) do - I18n.t('webhooks.pull.message') - end - - GitPullJob.perform_later(site, usuarie, message) - head :ok - end - end - end -end diff --git a/config/routes.rb b/config/routes.rb index f6f081f7..88376dde 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -19,9 +19,9 @@ Rails.application.routes.draw do post :'contact/:form', to: 'contact#receive', as: :contact namespace :webhooks do - post :pull, to: 'webhooks#pull' + post :pull, to: 'pull#pull' - namespace :social_inbox do + scope :social_inbox do post :moderationqueued, to: 'social_inbox#moderationqueued' post :onapproved, to: 'social_inbox#onapproved' post :onrejected, to: 'social_inbox#onrejected' From 9fa43353144d01154dca75cf88bd27a4c879dc03 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 20 Feb 2024 17:15:43 -0300 Subject: [PATCH 124/472] feat: recibir y almacenar actividades --- Gemfile | 3 + Gemfile.lock | 237 ++++++++++-------- .../v1/webhooks/social_inbox_controller.rb | 105 ++++++++ app/models/activity_pub/activity.rb | 5 + .../activity_pub/concerns/json_ld_concern.rb | 6 +- app/models/site/social_distributed_press.rb | 2 + app/models/social_inbox.rb | 19 +- 7 files changed, 262 insertions(+), 115 deletions(-) diff --git a/Gemfile b/Gemfile index 3cf01934..8e955e8f 100644 --- a/Gemfile +++ b/Gemfile @@ -80,6 +80,9 @@ gem 'yaml_db', git: 'https://0xacab.org/sutty/yaml_db.git' gem 'kaminari' gem 'device_detector' +gem 'after_commit_everywhere' +gem 'aasm' + # database gem 'hairtrigger' gem 'pg' diff --git a/Gemfile.lock b/Gemfile.lock index 5b8ca619..50745140 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -27,74 +27,80 @@ GIT GEM remote: https://17.3.alpine.gems.sutty.nl/ specs: - actioncable (6.1.7.3) - actionpack (= 6.1.7.3) - activesupport (= 6.1.7.3) + aasm (5.5.0) + concurrent-ruby (~> 1.0) + actioncable (6.1.7.4) + actionpack (= 6.1.7.4) + activesupport (= 6.1.7.4) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.1.7.3) - actionpack (= 6.1.7.3) - activejob (= 6.1.7.3) - activerecord (= 6.1.7.3) - activestorage (= 6.1.7.3) - activesupport (= 6.1.7.3) + actionmailbox (6.1.7.4) + actionpack (= 6.1.7.4) + activejob (= 6.1.7.4) + activerecord (= 6.1.7.4) + activestorage (= 6.1.7.4) + activesupport (= 6.1.7.4) mail (>= 2.7.1) - actionmailer (6.1.7.3) - actionpack (= 6.1.7.3) - actionview (= 6.1.7.3) - activejob (= 6.1.7.3) - activesupport (= 6.1.7.3) + actionmailer (6.1.7.4) + actionpack (= 6.1.7.4) + actionview (= 6.1.7.4) + activejob (= 6.1.7.4) + activesupport (= 6.1.7.4) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.1.7.3) - actionview (= 6.1.7.3) - activesupport (= 6.1.7.3) + actionpack (6.1.7.4) + actionview (= 6.1.7.4) + activesupport (= 6.1.7.4) rack (~> 2.0, >= 2.0.9) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.1.7.3) - actionpack (= 6.1.7.3) - activerecord (= 6.1.7.3) - activestorage (= 6.1.7.3) - activesupport (= 6.1.7.3) + actiontext (6.1.7.4) + actionpack (= 6.1.7.4) + activerecord (= 6.1.7.4) + activestorage (= 6.1.7.4) + activesupport (= 6.1.7.4) nokogiri (>= 1.8.5) - actionview (6.1.7.3) - activesupport (= 6.1.7.3) + actionview (6.1.7.4) + activesupport (= 6.1.7.4) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.1.7.3) - activesupport (= 6.1.7.3) + activejob (6.1.7.4) + activesupport (= 6.1.7.4) globalid (>= 0.3.6) - activemodel (6.1.7.3) - activesupport (= 6.1.7.3) - activerecord (6.1.7.3) - activemodel (= 6.1.7.3) - activesupport (= 6.1.7.3) - activestorage (6.1.7.3) - actionpack (= 6.1.7.3) - activejob (= 6.1.7.3) - activerecord (= 6.1.7.3) - activesupport (= 6.1.7.3) + activemodel (6.1.7.4) + activesupport (= 6.1.7.4) + activerecord (6.1.7.4) + activemodel (= 6.1.7.4) + activesupport (= 6.1.7.4) + activestorage (6.1.7.4) + actionpack (= 6.1.7.4) + activejob (= 6.1.7.4) + activerecord (= 6.1.7.4) + activesupport (= 6.1.7.4) marcel (~> 1.0) mini_mime (>= 1.1.0) - activesupport (6.1.7.3) + activesupport (6.1.7.4) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) zeitwerk (~> 2.3) - addressable (2.8.4) + addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) adsp (1.0.10) + after_commit_everywhere (1.4.0) + activerecord (>= 4.2) + activesupport ast (2.4.2) autoprefixer-rails (10.4.13.0) execjs (~> 2) - bcrypt (3.1.19-x86_64-linux-musl) + bcrypt (3.1.20-x86_64-linux-musl) bcrypt_pbkdf (1.1.0-x86_64-linux-musl) benchmark-ips (2.12.0) + bigdecimal (3.1.1) bindex (0.8.1-x86_64-linux-musl) blazer (2.6.5) activerecord (>= 5) @@ -105,7 +111,8 @@ GEM autoprefixer-rails (>= 9.1.0) popper_js (>= 1.16.1, < 2) sassc-rails (>= 2.0.0) - brakeman (5.4.1) + brakeman (6.1.1) + racc builder (3.2.4) bundler-audit (0.9.1) bundler (>= 1.2.0, < 3) @@ -125,6 +132,7 @@ GEM concurrent-ruby (1.2.2) concurrent-ruby-ext (1.2.2-x86_64-linux-musl) concurrent-ruby (= 1.2.2) + connection_pool (2.4.1) crass (1.0.6) database_cleaner (2.0.2) database_cleaner-active_record (>= 2, < 3) @@ -132,7 +140,7 @@ GEM activerecord (>= 5.a) database_cleaner-core (~> 2.0.0) database_cleaner-core (2.0.1) - date (3.3.3-x86_64-linux-musl) + date (3.3.4-x86_64-linux-musl) dead_end (4.0.0) derailed_benchmarks (2.1.2) benchmark-ips (~> 2) @@ -146,8 +154,8 @@ GEM rake (> 10, < 14) ruby-statistics (>= 2.1) thor (>= 0.19, < 2) - device_detector (1.1.1) - devise (4.9.2) + device_detector (1.1.2) + devise (4.9.3) bcrypt (~> 3.0) orm_adapter (~> 0.1) railties (>= 4.1.0) @@ -155,7 +163,7 @@ GEM warden (~> 1.2.3) devise-i18n (1.11.0) devise (>= 4.9.0) - devise_invitable (2.0.8) + devise_invitable (2.0.9) actionmailer (>= 5.0) devise (>= 4.6) distributed-press-api-client (0.4.0rc2) @@ -172,10 +180,10 @@ GEM railties (>= 3.2) down (5.4.1) addressable (~> 2.8) - dry-configurable (1.0.1) + dry-configurable (1.1.0) dry-core (~> 1.0, < 2) zeitwerk (~> 2.6) - dry-core (1.0.0) + dry-core (1.0.1) concurrent-ruby (~> 1.0) zeitwerk (~> 2.6) dry-inflector (1.0.0) @@ -184,7 +192,7 @@ GEM concurrent-ruby (~> 1.0) dry-core (~> 1.0, < 2) zeitwerk (~> 2.6) - dry-schema (1.13.1) + dry-schema (1.13.3) concurrent-ruby (~> 1.0) dry-configurable (~> 1.0, >= 1.0.1) dry-core (~> 1.0, < 2) @@ -192,7 +200,8 @@ GEM dry-logic (>= 1.4, < 2) dry-types (>= 1.7, < 2) zeitwerk (~> 2.6) - dry-types (1.7.1) + dry-types (1.7.2) + bigdecimal (~> 3.0) concurrent-ruby (~> 1.0) dry-core (~> 1.0) dry-inflector (~> 1.0) @@ -225,25 +234,25 @@ GEM ffi (~> 1.0) git_clone_url (2.0.0) uri-ssh_git (>= 2.0) - globalid (1.1.0) - activesupport (>= 5.0) + globalid (1.2.1) + activesupport (>= 6.1) groupdate (6.2.1) activesupport (>= 5.2) hairtrigger (1.0.0) activerecord (>= 6.0, < 8) ruby2ruby (~> 2.4) ruby_parser (~> 3.10) - haml (6.1.2-x86_64-linux-musl) + haml (6.3.0) temple (>= 0.8.2) thor tilt haml-lint (0.999.999) haml_lint - haml_lint (0.45.0) - haml (>= 4.0, < 6.2) + haml_lint (0.53.0) + haml (>= 5.0) parallel (~> 1.10) rainbow - rubocop (>= 0.50.0) + rubocop (>= 1.0) sysexits (~> 1.1) hamlit (3.0.3-x86_64-linux-musl) temple (>= 0.8.2) @@ -296,7 +305,7 @@ GEM terminal-table (~> 2.0) jekyll-commonmark (1.4.0) commonmarker (~> 0.22) - jekyll-images (0.4.1) + jekyll-images (0.4.4) jekyll (~> 4) ruby-filemagic (~> 0.7) ruby-vips (~> 2) @@ -306,7 +315,7 @@ GEM sassc (> 2.0.1, < 3.0) jekyll-watch (2.2.1) listen (~> 3.0) - json (2.6.3-x86_64-linux-musl) + json (2.7.1-x86_64-linux-musl) jwt (2.6.0) kaminari (1.2.2) activesupport (>= 4.1.0) @@ -335,12 +344,12 @@ GEM loaf (0.10.0) railties (>= 3.2) lockbox (1.2.0) - lograge (0.12.0) + lograge (0.14.0) actionpack (>= 4) activesupport (>= 4) railties (>= 4) request_store (~> 1.0) - loofah (2.21.3) + loofah (2.22.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) mail (2.8.1) @@ -354,36 +363,37 @@ GEM method_source (1.0.0) mini_histogram (0.3.1) mini_magick (4.12.0) - mini_mime (1.1.2) - mini_portile2 (2.8.2) - minitest (5.18.0) + mini_mime (1.1.5) + mini_portile2 (2.8.5) + minitest (5.21.1) mobility (1.2.9) i18n (>= 0.6.10, < 2) request_store (~> 1.0) multi_xml (0.6.0) - net-imap (0.3.4) + net-imap (0.4.9) date net-protocol net-pop (0.1.2) net-protocol - net-protocol (0.2.1) + net-protocol (0.2.2) timeout - net-smtp (0.3.3) + net-smtp (0.4.0) net-protocol - net-ssh (7.1.0) + net-ssh (7.2.1) netaddr (2.0.6) - nio4r (2.5.9-x86_64-linux-musl) - nokogiri (1.15.4-x86_64-linux-musl) + nio4r (2.7.0-x86_64-linux-musl) + nokogiri (1.16.0-x86_64-linux-musl) mini_portile2 (~> 2.8.2) racc (~> 1.4) orm_adapter (0.5.0) pairing_heap (3.0.1) - parallel (1.23.0) - parser (3.2.2.1) + parallel (1.24.0) + parser (3.2.2.3) ast (~> 2.4.1) + racc pathutil (0.16.2) forwardable-extended (~> 2.6) - pg (1.5.3-x86_64-linux-musl) + pg (1.5.4-x86_64-linux-musl) pg_search (2.3.6) activerecord (>= 5.2) activesupport (>= 5.2) @@ -393,55 +403,57 @@ GEM pry (0.14.2) coderay (~> 1.1) method_source (~> 1.0) - public_suffix (5.0.3) - puma (6.3.1-x86_64-linux-musl) + public_suffix (5.0.4) + puma (6.4.2-x86_64-linux-musl) nio4r (~> 2.0) - pundit (2.3.0) + pundit (2.3.1) activesupport (>= 3.0.0) que (2.2.1) - racc (1.7.1-x86_64-linux-musl) - rack (2.2.7) + racc (1.7.3-x86_64-linux-musl) + rack (2.2.8) rack-cors (2.0.1) rack (>= 2.0.0) rack-mini-profiler (3.1.0) rack (>= 1.2.0) - rack-proxy (0.7.6) + rack-proxy (0.7.7) rack rack-test (2.1.0) rack (>= 1.3) - rails (6.1.7.3) - actioncable (= 6.1.7.3) - actionmailbox (= 6.1.7.3) - actionmailer (= 6.1.7.3) - actionpack (= 6.1.7.3) - actiontext (= 6.1.7.3) - actionview (= 6.1.7.3) - activejob (= 6.1.7.3) - activemodel (= 6.1.7.3) - activerecord (= 6.1.7.3) - activestorage (= 6.1.7.3) - activesupport (= 6.1.7.3) + rails (6.1.7.4) + actioncable (= 6.1.7.4) + actionmailbox (= 6.1.7.4) + actionmailer (= 6.1.7.4) + actionpack (= 6.1.7.4) + actiontext (= 6.1.7.4) + actionview (= 6.1.7.4) + activejob (= 6.1.7.4) + activemodel (= 6.1.7.4) + activerecord (= 6.1.7.4) + activestorage (= 6.1.7.4) + activesupport (= 6.1.7.4) bundler (>= 1.15.0) - railties (= 6.1.7.3) + railties (= 6.1.7.4) sprockets-rails (>= 2.0.0) - rails-dom-testing (2.0.3) - activesupport (>= 4.2.0) + rails-dom-testing (2.2.0) + activesupport (>= 5.0.0) + minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.5.0) - loofah (~> 2.19, >= 2.19.1) - rails-i18n (7.0.7) + rails-html-sanitizer (1.6.0) + loofah (~> 2.21) + nokogiri (~> 1.14) + rails-i18n (7.0.8) i18n (>= 0.7, < 2) railties (>= 6.0.0, < 8) rails_warden (0.6.0) warden (>= 1.2.0) - railties (6.1.7.3) - actionpack (= 6.1.7.3) - activesupport (= 6.1.7.3) + railties (6.1.7.4) + actionpack (= 6.1.7.4) + activesupport (= 6.1.7.4) method_source rake (>= 12.2) thor (~> 1.0) rainbow (3.1.1) - rake (13.0.6) + rake (13.1.0) rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) @@ -464,13 +476,13 @@ GEM redis-store (>= 1.2, < 2) redis-store (1.9.2) redis (>= 4, < 6) - regexp_parser (2.8.0) + regexp_parser (2.9.0) request_store (1.5.1) rack (>= 1.4) - responders (3.1.0) + responders (3.1.1) actionpack (>= 5.2) railties (>= 5.2) - rexml (3.2.5) + rexml (3.2.6) rgl (0.6.3) pairing_heap (>= 0.3.0) rexml (~> 3.2, >= 3.2.4) @@ -486,18 +498,19 @@ GEM rubocop-ast (>= 1.24.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.28.1) + rubocop-ast (1.30.0) parser (>= 3.2.1.0) - rubocop-rails (2.19.1) + rubocop-rails (2.23.1) activesupport (>= 4.2.0) rack (>= 1.1) rubocop (>= 1.33.0, < 2.0) + rubocop-ast (>= 1.30.0, < 2.0) ruby-brs (1.3.3-x86_64-linux-musl) adsp (~> 1.0) ruby-filemagic (0.7.3-x86_64-linux-musl) ruby-progressbar (1.13.0) ruby-statistics (3.0.2) - ruby-vips (2.1.4) + ruby-vips (2.2.0) ffi (~> 1.12) ruby2ruby (2.5.0) ruby_parser (~> 3.1) @@ -530,14 +543,14 @@ GEM spring-watcher-listen (2.1.0) listen (>= 2.7, < 4.0) spring (>= 4) - sprockets (4.2.0) + sprockets (4.2.1) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) sprockets-rails (3.4.2) actionpack (>= 5.2) activesupport (>= 5.2) sprockets (>= 3.0.0) - sqlite3 (1.6.3-x86_64-linux-musl) + sqlite3 (1.7.0-x86_64-linux-musl) mini_portile2 (~> 2.8.0) stackprof (0.2.25-x86_64-linux-musl) stream (0.5.5) @@ -546,13 +559,13 @@ GEM jekyll (~> 4) symbol-fstring (1.0.2-x86_64-linux-musl) sysexits (1.2.0) - temple (0.10.1) + temple (0.10.3) terminal-table (2.0.0) unicode-display_width (~> 1.1, >= 1.1.1) thor (1.3.0) - tilt (2.1.0) + tilt (2.3.0) timecop (0.9.6) - timeout (0.3.2) + timeout (0.4.1) turbolinks (5.2.1) turbolinks-source (~> 5.2) turbolinks-source (5.2.0) @@ -562,7 +575,7 @@ GEM execjs (>= 0.3.0, < 3) unf (0.1.4) unf_ext - unf_ext (0.0.8.2-x86_64-linux-musl) + unf_ext (0.0.9-x86_64-linux-musl) unicode-display_width (1.8.0) uri-ssh_git (2.0.0) validates_hostname (1.0.13) @@ -588,12 +601,14 @@ GEM xpath (3.2.0) nokogiri (~> 1.8) yard (0.9.34) - zeitwerk (2.6.8) + zeitwerk (2.6.12) PLATFORMS x86_64-linux-musl DEPENDENCIES + aasm + after_commit_everywhere bcrypt (~> 3.1.7) bcrypt_pbkdf blazer diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index bc604156..c8c695c1 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -19,6 +19,16 @@ module Api # El objeto del estado puede ser un objeto o une actore, # dependiendo de la actividad. def moderationqueued + # Devuelve un error si el token no es válido + usuarie.present? + + ActivityPub.transaction do + # Crea todos los registros necesarios y actualiza el estado + activity.update_activity_pub_state! + end + rescue ActiveRecord::RecordInvalid => e + ExceptionNotifier.notify_exception(e, data: { site: site.name, usuarie: usuarie.email, activity: original_activity }) + ensure head :accepted end @@ -33,6 +43,101 @@ module Api def onrejected head :accepted end + + private + + # Si el objeto ya viene incorporado en la actividad o lo tenemos + # que traer remotamente. + # + # @return [Bool] + def object_embedded? + @object_embedded ||= original_activity[:object].is_a?(Hash) + end + + # Encuentra la URI del objeto o falla si no la encuentra. + # + # @return [String] + def object_uri + @object_uri ||= + begin + case original_activity[:object] + when String then original_activity[:object] + when Hash then original_activity.dig(:object, :id) + end + end + ensure + raise ActiveRecord::RecordNotFound, 'object id missing' unless @object_uri + end + + # Atajo a la instancia + # + # @return [ActivityPub::Instance] + def instance + actor.instance + end + + # Genera un objeto a partir de la actividad. Si el objeto ya + # existe, actualiza su contenido. + # + # @return [ActivityPub::Object] + def object + @object ||= ActivityPub::Object.type_from(original_object).find_or_initialize_by(actor: actor, uri: object_uri).tap do |o| + o.content = original_object if object_embedded? + o.save! + end + end + + # Genera el seguimiento del estado del objeto con respecto al + # sitio. + # + # @return [ActivityPub] + def activity_pub + @activity_pub ||= site.activity_pubs.find_or_create_by!(site: site, object: object) + end + + # Crea la actividad y la vincula con el estado + # + # @return [ActivityPub::Activity] + def activity + @activity ||= ActivityPub::Activity.type_from(original_activity).new(uri: original_activity[:id], activity_pub: activity_pub).tap do |a| + a.content = original_activity.dup + a.content[:object] = object.uri + a.save! + end + end + + # Actor, si no hay instancia, la crea en el momento + # + # @return [Actor] + def actor + @actor ||= ActivityPub::Actor.find_or_initialize_by(uri: original_activity[:actor]).tap do |a| + next if a.instance + + a.instance = ActivityPub::Instance.find_or_create_by(hostname: URI.parse(a.uri).hostname) + a.save! + end + end + + # Descubre la actividad recibida, generando un error si la + # actividad no está dirigida a nosotres. + # + # @todo Validar formato + # @return [Hash] + def original_activity + @original_activity ||= FastJsonparser.parse(request.raw_post).tap do |activity| + raise '@context missing' unless activity[:@context].presence + raise 'id missing' unless activity[:id].presence + raise 'object missing' unless activity[:object].presence + raise 'not for us' unless [activity[:to]].flatten.include?(site.social_inbox.actor_id) + rescue RuntimeError => e + raise ActiveRecord::RecordNotFound, e.message + end + end + + # @return [Hash,String] + def original_object + @original_object ||= original_activity[:object].dup + end end end end diff --git a/app/models/activity_pub/activity.rb b/app/models/activity_pub/activity.rb index 4a88c1f3..a1f734e0 100644 --- a/app/models/activity_pub/activity.rb +++ b/app/models/activity_pub/activity.rb @@ -21,4 +21,9 @@ class ActivityPub::Activity < ApplicationRecord # Siempre en orden descendiente para saber el último estado default_scope -> { order(created_at: :desc) } + + # Cambia la máquina de estados según el tipo de actividad + def update_activity_pub_state! + nil + end end diff --git a/app/models/activity_pub/concerns/json_ld_concern.rb b/app/models/activity_pub/concerns/json_ld_concern.rb index b0899606..bc30330c 100644 --- a/app/models/activity_pub/concerns/json_ld_concern.rb +++ b/app/models/activity_pub/concerns/json_ld_concern.rb @@ -16,9 +16,11 @@ class ActivityPub # @param object [Hash] # @return [Activity] def self.type_from(object) - "#{self.class.name}::#{object[:type].presence || 'Generic'}".constantize + raise NameError unless object.is_a?(Hash) + + "#{model_name.name}::#{object[:type].presence || 'Generic'}".constantize rescue NameError - self.class::Generic + model_name.name.constantize::Generic end private diff --git a/app/models/site/social_distributed_press.rb b/app/models/site/social_distributed_press.rb index d3ebf579..c3abe06e 100644 --- a/app/models/site/social_distributed_press.rb +++ b/app/models/site/social_distributed_press.rb @@ -10,6 +10,8 @@ class Site included do encrypts :private_key_pem + has_many :activity_pubs + before_save :generate_private_key_pem!, unless: :private_key_pem? # @return [SocialInbox] diff --git a/app/models/social_inbox.rb b/app/models/social_inbox.rb index 24f749be..78362a10 100644 --- a/app/models/social_inbox.rb +++ b/app/models/social_inbox.rb @@ -24,6 +24,12 @@ class SocialInbox end end + def actor_id + @actor_id ||= generate_uri do |uri| + uri.path = '/about.jsonld' + end + end + # @return [DistributedPress::V1::Social::Client] def client @client ||= DistributedPress::V1::Social::Client.new( @@ -42,14 +48,23 @@ class SocialInbox # @return [String] def public_key_url - @public_key_url ||= URI("https://#{hostname}").tap do |uri| + @public_key_url ||= generate_uri do |uri| uri.path = '/about.jsonld' uri.fragment = 'main-key' - end.to_s + end end def hostname @hostname ||= site.config.dig('activity_pub', 'hostname') || site.hostname end + + # Genera una URI dentro de este sitio + # + # @return [String] + def generate_uri(&block) + @public_key_url ||= URI("https://#{hostname}").tap do |uri| + yield uri + end.to_s + end end From 88e93e3b5bab7c8fff75062bfc4788f4b33e2453 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 20 Feb 2024 17:15:57 -0300 Subject: [PATCH 125/472] feat: al eliminar una actividad, vaciar su objeto --- app/models/activity_pub.rb | 11 +++++++++++ app/models/activity_pub/activity/delete.rb | 8 +++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index c0474b89..c15998ea 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -29,5 +29,16 @@ class ActivityPub < ApplicationRecord state :reported # Le actore eliminó el objeto state :deleted + + # Recibir una acción de eliminación, eliminar el contenido de la + # base de datos. Esto elimina el contenido para todos los sitios + # porque estamos respetando lo que pidió le actore. + event :delete do + transitions to: :deleted + + after do + object.update(object: {}) + end + end end end diff --git a/app/models/activity_pub/activity/delete.rb b/app/models/activity_pub/activity/delete.rb index f3684a0f..1730d49d 100644 --- a/app/models/activity_pub/activity/delete.rb +++ b/app/models/activity_pub/activity/delete.rb @@ -1,3 +1,9 @@ # frozen_string_literal: true -class ActivityPub::Activity::Delete < ActivityPub::Activity; end +class ActivityPub::Activity::Delete < ActivityPub::Activity + # Si estamos eliminando el objeto, tenemos que vaciar su contenido y + # cambiar el estado a borrado + def update_activity_pub_state! + activity_pub.deleted! + end +end From 8ff556c9ed5f4f585c1148488bed5930d2db6d91 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 20 Feb 2024 17:16:08 -0300 Subject: [PATCH 126/472] fix: al actualizar un objeto, pausar la actividad --- app/models/activity_pub/activity/update.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/models/activity_pub/activity/update.rb b/app/models/activity_pub/activity/update.rb index 8089cdcf..34703938 100644 --- a/app/models/activity_pub/activity/update.rb +++ b/app/models/activity_pub/activity/update.rb @@ -1,3 +1,9 @@ # frozen_string_literal: true -class ActivityPub::Activity::Update < ActivityPub::Activity; end +class ActivityPub::Activity::Update < ActivityPub::Activity + # Si estamos actualizando el objeto, tenemos que devolverlo a estado + # de moderación + def update_activity_pub_state! + activity_pub.paused! + end +end From 9a479a157b6d865cf4233c9737bf26d750934e99 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 20 Feb 2024 17:18:15 -0300 Subject: [PATCH 127/472] feat: volver a pausar un objeto aprobado cuando se lo actualiza --- app/models/activity_pub.rb | 6 ++++++ app/models/activity_pub/activity/update.rb | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index c15998ea..2a127433 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -40,5 +40,11 @@ class ActivityPub < ApplicationRecord object.update(object: {}) end end + + # Si un objeto previamente aprobado fue actualizado, volvemos a + # pausarlo. + event :pause do + transitions from: :approved, to: :paused + end end end diff --git a/app/models/activity_pub/activity/update.rb b/app/models/activity_pub/activity/update.rb index 34703938..e9203ba5 100644 --- a/app/models/activity_pub/activity/update.rb +++ b/app/models/activity_pub/activity/update.rb @@ -4,6 +4,6 @@ class ActivityPub::Activity::Update < ActivityPub::Activity # Si estamos actualizando el objeto, tenemos que devolverlo a estado # de moderación def update_activity_pub_state! - activity_pub.paused! + activity_pub.pause! if activity_pub.approved? end end From fc7a524a85189bd1cdfe2c86cffa938faa5962aa Mon Sep 17 00:00:00 2001 From: f Date: Tue, 20 Feb 2024 17:18:39 -0300 Subject: [PATCH 128/472] fix: aasm --- config/application.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/config/application.rb b/config/application.rb index 73a7a884..27a21cc6 100644 --- a/config/application.rb +++ b/config/application.rb @@ -2,6 +2,7 @@ require_relative 'boot' +require 'aasm' require 'redis-client' require 'hiredis-client' require 'brs' From 051d8c6d5624486fb85f9f625eec6bf8ec854789 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 12:30:01 -0300 Subject: [PATCH 129/472] =?UTF-8?q?feat:=20obtener=20el=20contenido=20del?= =?UTF-8?q?=20objeto=20m=C3=A1s=20adelante?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/v1/webhooks/social_inbox_controller.rb | 9 +++++++-- app/jobs/activity_pub/fetch_job.rb | 18 ++++++++++++++++++ app/models/social_inbox.rb | 6 ++++++ 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 app/jobs/activity_pub/fetch_job.rb diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index c8c695c1..e51b89dd 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -77,12 +77,17 @@ module Api end # Genera un objeto a partir de la actividad. Si el objeto ya - # existe, actualiza su contenido. + # existe, actualiza su contenido. Si el objeto no viene + # incorporado, obtenemos el contenido más tarde. # # @return [ActivityPub::Object] def object @object ||= ActivityPub::Object.type_from(original_object).find_or_initialize_by(actor: actor, uri: object_uri).tap do |o| - o.content = original_object if object_embedded? + if object_embedded? + o.content = original_object + else + ActivityPub::FetchJob.perform_later(site: site, object: object) + end o.save! end end diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb new file mode 100644 index 00000000..526cdafb --- /dev/null +++ b/app/jobs/activity_pub/fetch_job.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# Obtiene o actualiza el contenido de un objeto, usando las credenciales +# del sitio. +# +# XXX: Esto usa las credenciales del sitio para volver el objeto +# disponible para todo el CMS. Asumimos que el objeto devuelto es el +# mismo para todo el mundo y las credenciales solo son para +# autenticación. +class ActivityPub::FetchJob < ApplicationJob + def perform(site:, object:) + ActivityPub::Object.transaction do + response = site.social_inbox.dereferencer.get(uri: object.uri) + + object.update(content: FastJsonparser.parse(response.body)) if response.ok? + end + end +end diff --git a/app/models/social_inbox.rb b/app/models/social_inbox.rb index 78362a10..624ee571 100644 --- a/app/models/social_inbox.rb +++ b/app/models/social_inbox.rb @@ -2,6 +2,7 @@ require 'distributed_press/v1/social/client' require 'distributed_press/v1/social/hook' +require 'distributed_press/v1/social/dereferencer' # Gestiona la Social Inbox de un sitio class SocialInbox @@ -41,6 +42,11 @@ class SocialInbox ) end + # @return [DistributedPress::V1::Social::Dereferencer] + def dereferencer + @dereferencer ||= DistributedPress::V1::Social::Dereferencer.new(client: client) + end + # @return [DistributedPress::V1::Social::Hook] def hook @hook ||= DistributedPress::V1::Social::Hook.new(client: client, actor: actor) From fb4401fd537cf0071ce41963334ec919a70ada63 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 12:32:39 -0300 Subject: [PATCH 130/472] feat: no actualizar si no es necesario MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cuando la respuesta viene desde la caché, no es es necesario modificar el objeto. --- app/jobs/activity_pub/fetch_job.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index 526cdafb..097a8d32 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -12,7 +12,11 @@ class ActivityPub::FetchJob < ApplicationJob ActivityPub::Object.transaction do response = site.social_inbox.dereferencer.get(uri: object.uri) - object.update(content: FastJsonparser.parse(response.body)) if response.ok? + # @todo Fallar cuando la respuesta no funcione? + return unless response.ok? + return unless response.miss? + + object.update(content: FastJsonparser.parse(response.body)) end end end From 091d5ac41d5a0bfc1ff30ae4e28a6b61c74a963c Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 12:46:38 -0300 Subject: [PATCH 131/472] chore: rubocop --- .../v1/webhooks/social_inbox_controller.rb | 18 ++++++++------- app/jobs/activity_pub/fetch_job.rb | 18 ++++++++------- app/models/activity_pub/activity.rb | 22 ++++++++++--------- app/models/activity_pub/activity/create.rb | 6 ++++- app/models/activity_pub/activity/delete.rb | 14 +++++++----- app/models/activity_pub/activity/flag.rb | 6 ++++- app/models/activity_pub/activity/follow.rb | 6 ++++- app/models/activity_pub/activity/generic.rb | 6 ++++- app/models/activity_pub/activity/undo.rb | 6 ++++- app/models/activity_pub/activity/update.rb | 14 +++++++----- app/models/activity_pub/actor.rb | 12 +++++----- app/models/activity_pub/instance.rb | 22 ++++++++++--------- app/models/activity_pub/object.rb | 12 +++++----- app/models/activity_pub/object/application.rb | 6 ++++- app/models/activity_pub/object/article.rb | 6 ++++- app/models/activity_pub/object/generic.rb | 6 ++++- app/models/activity_pub/object/note.rb | 6 ++++- .../activity_pub/object/organization.rb | 6 ++++- app/models/activity_pub/object/person.rb | 6 ++++- app/models/social_inbox.rb | 4 +--- 20 files changed, 132 insertions(+), 70 deletions(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index e51b89dd..3341b33d 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -27,7 +27,9 @@ module Api activity.update_activity_pub_state! end rescue ActiveRecord::RecordInvalid => e - ExceptionNotifier.notify_exception(e, data: { site: site.name, usuarie: usuarie.email, activity: original_activity }) + ExceptionNotifier.notify_exception(e, + data: { site: site.name, usuarie: usuarie.email, + activity: original_activity }) ensure head :accepted end @@ -59,11 +61,9 @@ module Api # @return [String] def object_uri @object_uri ||= - begin - case original_activity[:object] - when String then original_activity[:object] - when Hash then original_activity.dig(:object, :id) - end + case original_activity[:object] + when String then original_activity[:object] + when Hash then original_activity.dig(:object, :id) end ensure raise ActiveRecord::RecordNotFound, 'object id missing' unless @object_uri @@ -82,7 +82,8 @@ module Api # # @return [ActivityPub::Object] def object - @object ||= ActivityPub::Object.type_from(original_object).find_or_initialize_by(actor: actor, uri: object_uri).tap do |o| + @object ||= ActivityPub::Object.type_from(original_object).find_or_initialize_by(actor: actor, + uri: object_uri).tap do |o| if object_embedded? o.content = original_object else @@ -104,7 +105,8 @@ module Api # # @return [ActivityPub::Activity] def activity - @activity ||= ActivityPub::Activity.type_from(original_activity).new(uri: original_activity[:id], activity_pub: activity_pub).tap do |a| + @activity ||= ActivityPub::Activity.type_from(original_activity).new(uri: original_activity[:id], + activity_pub: activity_pub).tap do |a| a.content = original_activity.dup a.content[:object] = object.uri a.save! diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index 097a8d32..ff14c795 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -7,16 +7,18 @@ # disponible para todo el CMS. Asumimos que el objeto devuelto es el # mismo para todo el mundo y las credenciales solo son para # autenticación. -class ActivityPub::FetchJob < ApplicationJob - def perform(site:, object:) - ActivityPub::Object.transaction do - response = site.social_inbox.dereferencer.get(uri: object.uri) +class ActivityPub + class FetchJob < ApplicationJob + def perform(site:, object:) + ActivityPub::Object.transaction do + response = site.social_inbox.dereferencer.get(uri: object.uri) - # @todo Fallar cuando la respuesta no funcione? - return unless response.ok? - return unless response.miss? + # @todo Fallar cuando la respuesta no funcione? + return unless response.ok? + return unless response.miss? - object.update(content: FastJsonparser.parse(response.body)) + object.update(content: FastJsonparser.parse(response.body)) + end end end end diff --git a/app/models/activity_pub/activity.rb b/app/models/activity_pub/activity.rb index a1f734e0..5ee3d2d1 100644 --- a/app/models/activity_pub/activity.rb +++ b/app/models/activity_pub/activity.rb @@ -11,19 +11,21 @@ # envía como referencia en lugar de anidarlo. # # @see {https://www.w3.org/TR/activitypub/#client-to-server-interactions} -class ActivityPub::Activity < ApplicationRecord - include ActivityPub::Concerns::JsonLdConcern +class ActivityPub + class Activity < ApplicationRecord + include ActivityPub::Concerns::JsonLdConcern - belongs_to :activity_pub - has_one :object, through: :activity_pub + belongs_to :activity_pub + has_one :object, through: :activity_pub - validates :activity_pub_id, presence: true + validates :activity_pub_id, presence: true - # Siempre en orden descendiente para saber el último estado - default_scope -> { order(created_at: :desc) } + # Siempre en orden descendiente para saber el último estado + default_scope -> { order(created_at: :desc) } - # Cambia la máquina de estados según el tipo de actividad - def update_activity_pub_state! - nil + # Cambia la máquina de estados según el tipo de actividad + def update_activity_pub_state! + nil + end end end diff --git a/app/models/activity_pub/activity/create.rb b/app/models/activity_pub/activity/create.rb index 3dcba5c2..4acafaf2 100644 --- a/app/models/activity_pub/activity/create.rb +++ b/app/models/activity_pub/activity/create.rb @@ -1,3 +1,7 @@ # frozen_string_literal: true -class ActivityPub::Activity::Create < ActivityPub::Activity; end +class ActivityPub + module Activity + class Create < ActivityPub::Activity; end + end +end diff --git a/app/models/activity_pub/activity/delete.rb b/app/models/activity_pub/activity/delete.rb index 1730d49d..2973f730 100644 --- a/app/models/activity_pub/activity/delete.rb +++ b/app/models/activity_pub/activity/delete.rb @@ -1,9 +1,13 @@ # frozen_string_literal: true -class ActivityPub::Activity::Delete < ActivityPub::Activity - # Si estamos eliminando el objeto, tenemos que vaciar su contenido y - # cambiar el estado a borrado - def update_activity_pub_state! - activity_pub.deleted! +class ActivityPub + module Activity + class Delete < ActivityPub::Activity + # Si estamos eliminando el objeto, tenemos que vaciar su contenido y + # cambiar el estado a borrado + def update_activity_pub_state! + activity_pub.deleted! + end + end end end diff --git a/app/models/activity_pub/activity/flag.rb b/app/models/activity_pub/activity/flag.rb index 2911911e..27bbe266 100644 --- a/app/models/activity_pub/activity/flag.rb +++ b/app/models/activity_pub/activity/flag.rb @@ -1,3 +1,7 @@ # frozen_string_literal: true -class ActivityPub::Activity::Flag < ActivityPub::Activity; end +class ActivityPub + module Activity + class Flag < ActivityPub::Activity; end + end +end diff --git a/app/models/activity_pub/activity/follow.rb b/app/models/activity_pub/activity/follow.rb index c22dfd51..9e32b67d 100644 --- a/app/models/activity_pub/activity/follow.rb +++ b/app/models/activity_pub/activity/follow.rb @@ -4,4 +4,8 @@ # # Una actividad de seguimiento se refiere siempre a une actore (el # sitio) y proviene de otre actore. -class ActivityPub::Activity::Follow < ActivityPub::Activity; end +class ActivityPub + module Activity + class Follow < ActivityPub::Activity; end + end +end diff --git a/app/models/activity_pub/activity/generic.rb b/app/models/activity_pub/activity/generic.rb index 8bf76471..89c26247 100644 --- a/app/models/activity_pub/activity/generic.rb +++ b/app/models/activity_pub/activity/generic.rb @@ -1,3 +1,7 @@ # frozen_string_literal: true -class ActivityPub::Activity::Generic < ActivityPub::Activity; end +class ActivityPub + module Activity + class Generic < ActivityPub::Activity; end + end +end diff --git a/app/models/activity_pub/activity/undo.rb b/app/models/activity_pub/activity/undo.rb index a4915394..98233af9 100644 --- a/app/models/activity_pub/activity/undo.rb +++ b/app/models/activity_pub/activity/undo.rb @@ -4,5 +4,9 @@ # # Deshace una actividad, dependiendo de la actividad a la que se # refiere. -class ActivityPub::Activity::Undo < ActivityPub::Activity +class ActivityPub + module Activity + class Undo < ActivityPub::Activity + end + end end diff --git a/app/models/activity_pub/activity/update.rb b/app/models/activity_pub/activity/update.rb index e9203ba5..50622b93 100644 --- a/app/models/activity_pub/activity/update.rb +++ b/app/models/activity_pub/activity/update.rb @@ -1,9 +1,13 @@ # frozen_string_literal: true -class ActivityPub::Activity::Update < ActivityPub::Activity - # Si estamos actualizando el objeto, tenemos que devolverlo a estado - # de moderación - def update_activity_pub_state! - activity_pub.pause! if activity_pub.approved? +class ActivityPub + module Activity + class Update < ActivityPub::Activity + # Si estamos actualizando el objeto, tenemos que devolverlo a estado + # de moderación + def update_activity_pub_state! + activity_pub.pause! if activity_pub.approved? + end + end end end diff --git a/app/models/activity_pub/actor.rb b/app/models/activity_pub/actor.rb index f29c382a..7be69602 100644 --- a/app/models/activity_pub/actor.rb +++ b/app/models/activity_pub/actor.rb @@ -5,10 +5,12 @@ # Actor es la entidad que realiza acciones en ActivityPub # # @todo Obtener el perfil dinámicamente -class ActivityPub::Actor < ApplicationRecord - include ActivityPub::Concerns::JsonLdConcern +class ActivityPub + class Actor < ApplicationRecord + include ActivityPub::Concerns::JsonLdConcern - belongs_to :instance - has_many :activity_pubs, as: :object - has_many :objects + belongs_to :instance + has_many :activity_pubs, as: :object + has_many :objects + end end diff --git a/app/models/activity_pub/instance.rb b/app/models/activity_pub/instance.rb index fe4a777b..b13b8676 100644 --- a/app/models/activity_pub/instance.rb +++ b/app/models/activity_pub/instance.rb @@ -4,18 +4,20 @@ # # Representa cada instancia del fediverso que interactúa con la Social # Inbox. -class ActivityPub::Instance < ApplicationRecord - include AASM +class ActivityPub + class Instance < ApplicationRecord + include AASM - validates :aasm_state, presence: true, inclusion: { in: %w[paused allowed blocked] } - validates :hostname, uniqueness: true, hostname: true + validates :aasm_state, presence: true, inclusion: { in: %w[paused allowed blocked] } + validates :hostname, uniqueness: true, hostname: true - has_many :activity_pubs - has_many :actors + has_many :activity_pubs + has_many :actors - aasm do - state :paused, initial: true - state :allowed - state :blocked + aasm do + state :paused, initial: true + state :allowed + state :blocked + end end end diff --git a/app/models/activity_pub/object.rb b/app/models/activity_pub/object.rb index 519749ef..49a06772 100644 --- a/app/models/activity_pub/object.rb +++ b/app/models/activity_pub/object.rb @@ -1,11 +1,13 @@ # frozen_string_literal: true # Almacena objetos de ActivityPub, como Note, Article, etc. -class ActivityPub::Object < ApplicationRecord - include ActivityPub::Concerns::JsonLdConcern +class ActivityPub + class Object < ApplicationRecord + include ActivityPub::Concerns::JsonLdConcern - belongs_to :actor - has_many :activity_pubs, as: :object + belongs_to :actor + has_many :activity_pubs, as: :object - validates :actor_id, presence: true + validates :actor_id, presence: true + end end diff --git a/app/models/activity_pub/object/application.rb b/app/models/activity_pub/object/application.rb index e8a6f97c..e8d8fa0e 100644 --- a/app/models/activity_pub/object/application.rb +++ b/app/models/activity_pub/object/application.rb @@ -3,4 +3,8 @@ # = Application = # # Una aplicación o instancia -class ActivityPub::Object::Application < ActivityPub::Object; end +class ActivityPub + module Object + class Application < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/article.rb b/app/models/activity_pub/object/article.rb index ad1a6131..69fe371c 100644 --- a/app/models/activity_pub/object/article.rb +++ b/app/models/activity_pub/object/article.rb @@ -3,4 +3,8 @@ # = Article = # # Representa artículos -class ActivityPub::Object::Article < ActivityPub::Object; end +class ActivityPub + module Object + class Article < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/generic.rb b/app/models/activity_pub/object/generic.rb index f345e7a9..c16b25c6 100644 --- a/app/models/activity_pub/object/generic.rb +++ b/app/models/activity_pub/object/generic.rb @@ -1,4 +1,8 @@ # frozen_string_literal: true # = Generic = -class ActivityPub::Object::Generic < ActivityPub::Object; end +class ActivityPub + module Object + class Generic < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/note.rb b/app/models/activity_pub/object/note.rb index 0f84c747..06b969ab 100644 --- a/app/models/activity_pub/object/note.rb +++ b/app/models/activity_pub/object/note.rb @@ -3,4 +3,8 @@ # = Note = # # Representa notas, el tipo más común de objeto del Fediverso. -class ActivityPub::Object::Note < ActivityPub::Object; end +class ActivityPub + module Object + class Note < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/organization.rb b/app/models/activity_pub/object/organization.rb index a5327d10..31e5887d 100644 --- a/app/models/activity_pub/object/organization.rb +++ b/app/models/activity_pub/object/organization.rb @@ -3,4 +3,8 @@ # = Organization = # # Una organización -class ActivityPub::Object::Organization < ActivityPub::Object; end +class ActivityPub + module Object + class Organization < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/person.rb b/app/models/activity_pub/object/person.rb index 98a1568d..fd01e515 100644 --- a/app/models/activity_pub/object/person.rb +++ b/app/models/activity_pub/object/person.rb @@ -3,4 +3,8 @@ # = Person = # # Una persona, el perfil de une actore -class ActivityPub::Object::Person < ActivityPub::Object; end +class ActivityPub + module Object + class Person < ActivityPub::Object; end + end +end diff --git a/app/models/social_inbox.rb b/app/models/social_inbox.rb index 624ee571..45b8afd8 100644 --- a/app/models/social_inbox.rb +++ b/app/models/social_inbox.rb @@ -69,8 +69,6 @@ class SocialInbox # # @return [String] def generate_uri(&block) - @public_key_url ||= URI("https://#{hostname}").tap do |uri| - yield uri - end.to_s + @public_key_url ||= URI("https://#{hostname}").tap(&block).to_s end end From 7b8730c34c2ca41e5f3f25bd77c15cd3cf1e572a Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 13:04:15 -0300 Subject: [PATCH 132/472] feat: las actividades se aprueban cuando las confirma la SI --- .../api/v1/webhooks/social_inbox_controller.rb | 6 +++++- app/models/activity_pub.rb | 9 ++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index 3341b33d..76c7ec40 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -35,8 +35,12 @@ module Api end # Cuando aprobamos una actividad, recibimos la confirmación y - # cambiamos el estado + # cambiamos el estado. def onapproved + ActivityPub.transaction do + activity_pub.approve! if activity_pub.waiting? + end + head :accepted end diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 2a127433..71d67722 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -21,6 +21,8 @@ class ActivityPub < ApplicationRecord aasm do # Todavía no hay una decisión sobre el objeto state :paused, initial: true + # Estamos esperando respuesta desde la Social Inbox + state :waiting # Le usuarie aprobó el objeto state :approved # Le usuarie rechazó el objeto @@ -44,7 +46,12 @@ class ActivityPub < ApplicationRecord # Si un objeto previamente aprobado fue actualizado, volvemos a # pausarlo. event :pause do - transitions from: :approved, to: :paused + transitions from: %i[waiting approved], to: :paused + end + + # La actividad se aprueba + event :approve do + transitions from: :waiting, to: :approved end end end From e733c45b63cfd901e82dd9565585b2cb2bcbea3b Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 13:06:06 -0300 Subject: [PATCH 133/472] fix: las actividades se pueden rechazar --- app/controllers/api/v1/webhooks/social_inbox_controller.rb | 4 ++++ app/models/activity_pub.rb | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index 76c7ec40..20028708 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -47,6 +47,10 @@ module Api # Cuando rechazamos una actividad, recibimos la confirmación y # cambiamos el estado def onrejected + ActivityPub.transaction do + activity_pub.reject! if activity_pub.waiting? + end + head :accepted end diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 71d67722..b8e8eded 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -53,5 +53,10 @@ class ActivityPub < ApplicationRecord event :approve do transitions from: :waiting, to: :approved end + + # La actividad fue rechazada + event :reject do + transitions from: :waiting, to: :rejected + end end end From a9bdabf409076494b97d237631d47e1bbe64e592 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 13:07:27 -0300 Subject: [PATCH 134/472] =?UTF-8?q?fix:=20se=20puede=20volver=20a=20pausar?= =?UTF-8?q?=20despu=C3=A9s=20de=20rechazarla?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/activity_pub.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index b8e8eded..1c225226 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -46,7 +46,7 @@ class ActivityPub < ApplicationRecord # Si un objeto previamente aprobado fue actualizado, volvemos a # pausarlo. event :pause do - transitions from: %i[waiting approved], to: :paused + transitions from: %i[waiting approved rejected], to: :paused end # La actividad se aprueba From b477487b659e01e522d621584cb9b94fba676eb7 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 13:13:24 -0300 Subject: [PATCH 135/472] =?UTF-8?q?fixup!=20feat:=20obtener=20el=20conteni?= =?UTF-8?q?do=20del=20objeto=20m=C3=A1s=20adelante?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/api/v1/webhooks/social_inbox_controller.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index 20028708..532cca5e 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -95,8 +95,9 @@ module Api if object_embedded? o.content = original_object else - ActivityPub::FetchJob.perform_later(site: site, object: object) + ActivityPub::FetchJob.perform_later(site: site, object: o) end + o.save! end end From 732012e14b8d54db01e274db2d9f53a223523898 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 13:13:34 -0300 Subject: [PATCH 136/472] docs: orden en que se crean los registros --- app/controllers/api/v1/webhooks/social_inbox_controller.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index 532cca5e..51322990 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -24,6 +24,12 @@ module Api ActivityPub.transaction do # Crea todos los registros necesarios y actualiza el estado + # + # 1. Actor + # 2. Instance + # 3. Object + # 4. ActivityPub + # 5. Activity activity.update_activity_pub_state! end rescue ActiveRecord::RecordInvalid => e From 1fba54d80b3ae3e021c69e5a62f01174da63db33 Mon Sep 17 00:00:00 2001 From: maki Date: Wed, 21 Feb 2024 13:50:29 -0300 Subject: [PATCH 137/472] fix: checkboxes --- app/controllers/application_controller.rb | 1 + app/views/components/_block_list.haml | 6 ++++++ app/views/components/_block_lists.haml | 8 ++------ app/views/components/_checkbox.haml | 5 +++-- app/views/moderation_queue/_account.haml | 2 +- app/views/moderation_queue/_comment.haml | 2 +- app/views/moderation_queue/_instance.haml | 6 +++--- app/views/moderation_queue/_instances.haml | 2 +- db/seeds/blocklists.yml | 5 +++++ 9 files changed, 23 insertions(+), 14 deletions(-) create mode 100644 app/views/components/_block_list.haml create mode 100644 db/seeds/blocklists.yml diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index f673ee83..eca479fe 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -32,6 +32,7 @@ class ApplicationController < ActionController::Base @moderation_queue = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'moderation_queue.yaml'))) @remote_profile = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'remote_profile.yaml'))) @instances = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'instances.yaml'))) + @blocklists= YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'blocklists.yml'))) @moderation_queue.each do |activity| activity['attributedTo'] = @remote_profile end diff --git a/app/views/components/_block_list.haml b/app/views/components/_block_list.haml new file mode 100644 index 00000000..c2af3262 --- /dev/null +++ b/app/views/components/_block_list.haml @@ -0,0 +1,6 @@ +-# Componente Listas de bloqueo de Instancias +.card.mt-3.mb-3 + .card-body + .d-flex.flex-row + = render 'components/checkbox', id: blocklist["id"] do + %span.h4= blocklist["title"] diff --git a/app/views/components/_block_lists.haml b/app/views/components/_block_lists.haml index 8cdcd43b..1e9cd76f 100644 --- a/app/views/components/_block_lists.haml +++ b/app/views/components/_block_lists.haml @@ -1,6 +1,2 @@ --# Componente Listas de bloqueo de Instancias -.card.mt-3.mb-3 - .card-body - .d-flex.flex-row - = render 'components/checkbox' - %h4.ml-5= t('.title') +- @blocklists.each do |blocklist| + = render 'components/block_list', blocklist: blocklist diff --git a/app/views/components/_checkbox.haml b/app/views/components/_checkbox.haml index 3444720e..27f9a776 100644 --- a/app/views/components/_checkbox.haml +++ b/app/views/components/_checkbox.haml @@ -1,3 +1,4 @@ -# Componente Checkbox -.custom-control.custom-checkbox.p-0 - %input{ type: 'checkbox', id: local_assigns[:id], class: local_assigns[:class] } +.custom-control.custom-checkbox + %input.custom-control-input{ type: 'checkbox', id: id, name: id, class: local_assigns[:class] } + %label.custom-control-label{ for: id }= yield diff --git a/app/views/moderation_queue/_account.haml b/app/views/moderation_queue/_account.haml index ab4fc4c7..412f0aa7 100644 --- a/app/views/moderation_queue/_account.haml +++ b/app/views/moderation_queue/_account.haml @@ -1,6 +1,6 @@ .row.no-gutters.pt-2 .col-1 - = render 'components/checkbox' + = render 'components/checkbox', id: profile['id'] .col-11 %h4 %a{href: profile['id']}= profile['preferredUsername'] diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index fea4570f..99059133 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -2,7 +2,7 @@ .flex.mx-4.my-5 .row.no-gutters .col-1 - = render 'components/checkbox' + = render 'components/checkbox', id: comment['id'] .col-11 .row.no-gutters .col-4 diff --git a/app/views/moderation_queue/_instance.haml b/app/views/moderation_queue/_instance.haml index 74bda75b..cff8a957 100644 --- a/app/views/moderation_queue/_instance.haml +++ b/app/views/moderation_queue/_instance.haml @@ -1,13 +1,13 @@ - host = instance['domain'] - host ||= instance['uri'] -- host = "https://#{host}" +- hosthttps = "https://#{host}" .row.no-gutters.pt-2 .col-1 - = render 'components/checkbox' + = render 'components/checkbox', id: host .col-11 %h4 - %a{ href: host }= instance['title'] + %a{ href: hosthttps }= instance['title'] %p= instance['description'].html_safe %p %span= t('.users') diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index d19ef8ed..c51ba74f 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -11,5 +11,5 @@ %h3.mt-5= t('moderation_queue.instances.title') %lead= t('moderation_queue.instances.description') -= render 'components/block_lists' += render 'components/block_lists', blocklists: @blocklists = render 'moderation_queue/block_instances_textarea' diff --git a/db/seeds/blocklists.yml b/db/seeds/blocklists.yml new file mode 100644 index 00000000..d9f9dd6f --- /dev/null +++ b/db/seeds/blocklists.yml @@ -0,0 +1,5 @@ +--- +- id: gardenfence + title: Gardenfence +- id: lista + title: Lista From 34e63ff2dca083306ada0023098a7937b373f19f Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 14:07:11 -0300 Subject: [PATCH 138/472] =?UTF-8?q?feat:=20actualizar=20el=20tipo=20tambi?= =?UTF-8?q?=C3=A9n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/activity_pub/fetch_job.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index ff14c795..e5950c86 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -17,7 +17,9 @@ class ActivityPub return unless response.ok? return unless response.miss? - object.update(content: FastJsonparser.parse(response.body)) + content = FastJsonparser.parse(response.body) + + object.update(content: content, type: ActivityPub::Object.type_from(content).name) end end end From 03c0b71b5f36f14af1f8a9dbab1f9a97fb706d2f Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 15:42:56 -0300 Subject: [PATCH 139/472] fix: no es necesario vincular actores con objetos --- .../api/v1/webhooks/social_inbox_controller.rb | 3 +-- app/models/activity_pub/actor.rb | 1 - app/models/activity_pub/object.rb | 2 -- .../20240221184007_remove_actor_from_objects.rb | 12 ++++++++++++ 4 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 db/migrate/20240221184007_remove_actor_from_objects.rb diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index 51322990..c15a757d 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -96,8 +96,7 @@ module Api # # @return [ActivityPub::Object] def object - @object ||= ActivityPub::Object.type_from(original_object).find_or_initialize_by(actor: actor, - uri: object_uri).tap do |o| + @object ||= ActivityPub::Object.type_from(original_object).find_or_initialize_by(uri: object_uri).tap do |o| if object_embedded? o.content = original_object else diff --git a/app/models/activity_pub/actor.rb b/app/models/activity_pub/actor.rb index 7be69602..e79a596a 100644 --- a/app/models/activity_pub/actor.rb +++ b/app/models/activity_pub/actor.rb @@ -11,6 +11,5 @@ class ActivityPub belongs_to :instance has_many :activity_pubs, as: :object - has_many :objects end end diff --git a/app/models/activity_pub/object.rb b/app/models/activity_pub/object.rb index 49a06772..ec759e3e 100644 --- a/app/models/activity_pub/object.rb +++ b/app/models/activity_pub/object.rb @@ -7,7 +7,5 @@ class ActivityPub belongs_to :actor has_many :activity_pubs, as: :object - - validates :actor_id, presence: true end end diff --git a/db/migrate/20240221184007_remove_actor_from_objects.rb b/db/migrate/20240221184007_remove_actor_from_objects.rb new file mode 100644 index 00000000..6ee5822c --- /dev/null +++ b/db/migrate/20240221184007_remove_actor_from_objects.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +# No es necesario vincular actores con objetos, porque la forma en que +# lo estábamos haciendo no se refiere a le actore del objeto, sino de +# acciones distintas sobre el mismo objeto, generado por une actore. +# +# Y ese valor ya lo podemos obtener desde attributedTo +class RemoveActorFromObjects < ActiveRecord::Migration[6.1] + def change + remove_column :activity_pub_objects, :actor_id, :uuid, index: true + end +end From 0443cb0fc3cce6d7e6eff11b97b9f5b5914939c1 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 15:43:10 -0300 Subject: [PATCH 140/472] fix: responder con forbidden cuando los registros no sean validos --- app/controllers/api/v1/webhooks/concerns/webhook_concern.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/api/v1/webhooks/concerns/webhook_concern.rb b/app/controllers/api/v1/webhooks/concerns/webhook_concern.rb index a546a55c..b94c91f6 100644 --- a/app/controllers/api/v1/webhooks/concerns/webhook_concern.rb +++ b/app/controllers/api/v1/webhooks/concerns/webhook_concern.rb @@ -11,6 +11,7 @@ module Api included do # Responde con forbidden si falla la validación del token rescue_from ActiveRecord::RecordNotFound, with: :platforms_answer + rescue_from ActiveRecord::RecordInvalid, with: :platforms_answer private From 5dbff20e2bf43df6833106c1f5f790a2399b38bc Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 15:44:04 -0300 Subject: [PATCH 141/472] fixup! chore: rubocop --- app/models/activity_pub/activity/create.rb | 2 +- app/models/activity_pub/activity/delete.rb | 2 +- app/models/activity_pub/activity/flag.rb | 2 +- app/models/activity_pub/activity/follow.rb | 2 +- app/models/activity_pub/activity/generic.rb | 2 +- app/models/activity_pub/activity/undo.rb | 2 +- app/models/activity_pub/activity/update.rb | 2 +- app/models/activity_pub/object/application.rb | 2 +- app/models/activity_pub/object/article.rb | 2 +- app/models/activity_pub/object/generic.rb | 2 +- app/models/activity_pub/object/note.rb | 2 +- app/models/activity_pub/object/organization.rb | 2 +- app/models/activity_pub/object/person.rb | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/models/activity_pub/activity/create.rb b/app/models/activity_pub/activity/create.rb index 4acafaf2..9cd32559 100644 --- a/app/models/activity_pub/activity/create.rb +++ b/app/models/activity_pub/activity/create.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class ActivityPub - module Activity + class Activity class Create < ActivityPub::Activity; end end end diff --git a/app/models/activity_pub/activity/delete.rb b/app/models/activity_pub/activity/delete.rb index 2973f730..7080375e 100644 --- a/app/models/activity_pub/activity/delete.rb +++ b/app/models/activity_pub/activity/delete.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class ActivityPub - module Activity + class Activity class Delete < ActivityPub::Activity # Si estamos eliminando el objeto, tenemos que vaciar su contenido y # cambiar el estado a borrado diff --git a/app/models/activity_pub/activity/flag.rb b/app/models/activity_pub/activity/flag.rb index 27bbe266..ffbc374b 100644 --- a/app/models/activity_pub/activity/flag.rb +++ b/app/models/activity_pub/activity/flag.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class ActivityPub - module Activity + class Activity class Flag < ActivityPub::Activity; end end end diff --git a/app/models/activity_pub/activity/follow.rb b/app/models/activity_pub/activity/follow.rb index 9e32b67d..e383490a 100644 --- a/app/models/activity_pub/activity/follow.rb +++ b/app/models/activity_pub/activity/follow.rb @@ -5,7 +5,7 @@ # Una actividad de seguimiento se refiere siempre a une actore (el # sitio) y proviene de otre actore. class ActivityPub - module Activity + class Activity class Follow < ActivityPub::Activity; end end end diff --git a/app/models/activity_pub/activity/generic.rb b/app/models/activity_pub/activity/generic.rb index 89c26247..95fff3eb 100644 --- a/app/models/activity_pub/activity/generic.rb +++ b/app/models/activity_pub/activity/generic.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class ActivityPub - module Activity + class Activity class Generic < ActivityPub::Activity; end end end diff --git a/app/models/activity_pub/activity/undo.rb b/app/models/activity_pub/activity/undo.rb index 98233af9..41fb5e51 100644 --- a/app/models/activity_pub/activity/undo.rb +++ b/app/models/activity_pub/activity/undo.rb @@ -5,7 +5,7 @@ # Deshace una actividad, dependiendo de la actividad a la que se # refiere. class ActivityPub - module Activity + class Activity class Undo < ActivityPub::Activity end end diff --git a/app/models/activity_pub/activity/update.rb b/app/models/activity_pub/activity/update.rb index 50622b93..19c95b68 100644 --- a/app/models/activity_pub/activity/update.rb +++ b/app/models/activity_pub/activity/update.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class ActivityPub - module Activity + class Activity class Update < ActivityPub::Activity # Si estamos actualizando el objeto, tenemos que devolverlo a estado # de moderación diff --git a/app/models/activity_pub/object/application.rb b/app/models/activity_pub/object/application.rb index e8d8fa0e..99ac935c 100644 --- a/app/models/activity_pub/object/application.rb +++ b/app/models/activity_pub/object/application.rb @@ -4,7 +4,7 @@ # # Una aplicación o instancia class ActivityPub - module Object + class Object class Application < ActivityPub::Object; end end end diff --git a/app/models/activity_pub/object/article.rb b/app/models/activity_pub/object/article.rb index 69fe371c..126ba3f1 100644 --- a/app/models/activity_pub/object/article.rb +++ b/app/models/activity_pub/object/article.rb @@ -4,7 +4,7 @@ # # Representa artículos class ActivityPub - module Object + class Object class Article < ActivityPub::Object; end end end diff --git a/app/models/activity_pub/object/generic.rb b/app/models/activity_pub/object/generic.rb index c16b25c6..3e5ff719 100644 --- a/app/models/activity_pub/object/generic.rb +++ b/app/models/activity_pub/object/generic.rb @@ -2,7 +2,7 @@ # = Generic = class ActivityPub - module Object + class Object class Generic < ActivityPub::Object; end end end diff --git a/app/models/activity_pub/object/note.rb b/app/models/activity_pub/object/note.rb index 06b969ab..ca113c15 100644 --- a/app/models/activity_pub/object/note.rb +++ b/app/models/activity_pub/object/note.rb @@ -4,7 +4,7 @@ # # Representa notas, el tipo más común de objeto del Fediverso. class ActivityPub - module Object + class Object class Note < ActivityPub::Object; end end end diff --git a/app/models/activity_pub/object/organization.rb b/app/models/activity_pub/object/organization.rb index 31e5887d..e3385232 100644 --- a/app/models/activity_pub/object/organization.rb +++ b/app/models/activity_pub/object/organization.rb @@ -4,7 +4,7 @@ # # Una organización class ActivityPub - module Object + class Object class Organization < ActivityPub::Object; end end end diff --git a/app/models/activity_pub/object/person.rb b/app/models/activity_pub/object/person.rb index fd01e515..a6a85d43 100644 --- a/app/models/activity_pub/object/person.rb +++ b/app/models/activity_pub/object/person.rb @@ -4,7 +4,7 @@ # # Una persona, el perfil de une actore class ActivityPub - module Object + class Object class Person < ActivityPub::Object; end end end From ddaee30da715981c9871728706450050ecbfd091 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 15:44:16 -0300 Subject: [PATCH 142/472] fix: primero guardar el objeto antes de obtener su contenido --- .../api/v1/webhooks/social_inbox_controller.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index c15a757d..24865c92 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -97,13 +97,13 @@ module Api # @return [ActivityPub::Object] def object @object ||= ActivityPub::Object.type_from(original_object).find_or_initialize_by(uri: object_uri).tap do |o| - if object_embedded? - o.content = original_object - else - ActivityPub::FetchJob.perform_later(site: site, object: o) - end + o.content = original_object if object_embedded? o.save! + + # XXX: el objeto necesita ser guardado antes de poder + # procesarlo + ActivityPub::FetchJob.perform_later(site: site, object: o) unless object_embedded? end end From d98f893a7153d5fe546c6db5632356733e2ec4eb Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 15:44:29 -0300 Subject: [PATCH 143/472] fix: algunas actividades no tienen destinatarie --- app/controllers/api/v1/webhooks/social_inbox_controller.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index 24865c92..fb7ede50 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -149,7 +149,6 @@ module Api raise '@context missing' unless activity[:@context].presence raise 'id missing' unless activity[:id].presence raise 'object missing' unless activity[:object].presence - raise 'not for us' unless [activity[:to]].flatten.include?(site.social_inbox.actor_id) rescue RuntimeError => e raise ActiveRecord::RecordNotFound, e.message end From 39bbc3a2bd26c7240a933e4769e5c642cea7fff7 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 15:44:41 -0300 Subject: [PATCH 144/472] =?UTF-8?q?fix:=20deleted=20es=20un=20m=C3=A9todo?= =?UTF-8?q?=20reservado?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/activity_pub.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 1c225226..42ed3f61 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -30,13 +30,13 @@ class ActivityPub < ApplicationRecord # Le usuarie reportó el objeto state :reported # Le actore eliminó el objeto - state :deleted + state :removed # Recibir una acción de eliminación, eliminar el contenido de la # base de datos. Esto elimina el contenido para todos los sitios # porque estamos respetando lo que pidió le actore. - event :delete do - transitions to: :deleted + event :remove do + transitions to: :removed after do object.update(object: {}) From f517889992e9f72fb517ab9c79afed20c80e2769 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 15:45:15 -0300 Subject: [PATCH 145/472] fixup! fix: no es necesario vincular actores con objetos --- db/structure.sql | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/db/structure.sql b/db/structure.sql index 723c9e99..ee99e791 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -523,7 +523,6 @@ CREATE TABLE public.activity_pub_objects ( id uuid DEFAULT gen_random_uuid() NOT NULL, created_at timestamp(6) without time zone NOT NULL, updated_at timestamp(6) without time zone NOT NULL, - actor_id uuid NOT NULL, type character varying NOT NULL, uri character varying NOT NULL, content jsonb DEFAULT '{}'::jsonb @@ -2005,13 +2004,6 @@ CREATE INDEX index_activity_pub_actors_on_uri ON public.activity_pub_actors USIN CREATE INDEX index_activity_pub_instances_on_hostname ON public.activity_pub_instances USING btree (hostname); --- --- Name: index_activity_pub_objects_on_actor_id; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX index_activity_pub_objects_on_actor_id ON public.activity_pub_objects USING btree (actor_id); - - -- -- Name: index_activity_pubs_on_site_id_and_object_id_and_object_type; Type: INDEX; Schema: public; Owner: - -- @@ -2479,6 +2471,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20240219175839'), ('20240219204011'), ('20240219204224'), -('20240220161414'); +('20240220161414'), +('20240221184007'); From f8f0eb9d3c341467ec25b9b48d242d29c36b3401 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 16:42:02 -0300 Subject: [PATCH 146/472] fix: no buscar csrf --- app/controllers/api/v1/webhooks/concerns/webhook_concern.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/controllers/api/v1/webhooks/concerns/webhook_concern.rb b/app/controllers/api/v1/webhooks/concerns/webhook_concern.rb index b94c91f6..aef2dd83 100644 --- a/app/controllers/api/v1/webhooks/concerns/webhook_concern.rb +++ b/app/controllers/api/v1/webhooks/concerns/webhook_concern.rb @@ -9,6 +9,8 @@ module Api extend ActiveSupport::Concern included do + skip_before_action :verify_authenticity_token + # Responde con forbidden si falla la validación del token rescue_from ActiveRecord::RecordNotFound, with: :platforms_answer rescue_from ActiveRecord::RecordInvalid, with: :platforms_answer From a4133c60018772af78b5bb5813050b4d1fbf5b34 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 16:42:14 -0300 Subject: [PATCH 147/472] fix: asegurarse que todos los registros existan --- .../api/v1/webhooks/social_inbox_controller.rb | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index fb7ede50..e6b80c4b 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -24,12 +24,10 @@ module Api ActivityPub.transaction do # Crea todos los registros necesarios y actualiza el estado - # - # 1. Actor - # 2. Instance - # 3. Object - # 4. ActivityPub - # 5. Activity + actor.present? + instance.present? + object.present? + activity_pub.present? activity.update_activity_pub_state! end rescue ActiveRecord::RecordInvalid => e From 3292d7ebe3fc8f82fe817bc9ccd5d0be0074a171 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 16:42:28 -0300 Subject: [PATCH 148/472] fix: vaciar el contenido antes de cambiar de estado --- app/models/activity_pub.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 42ed3f61..9445717f 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -38,8 +38,8 @@ class ActivityPub < ApplicationRecord event :remove do transitions to: :removed - after do - object.update(object: {}) + before do + object.update(content: {}) end end From a13f42c22f39f00835a6a5862e750a00a61be62f Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 16:43:31 -0300 Subject: [PATCH 149/472] fixup! fixup! fix: no es necesario vincular actores con objetos --- app/models/activity_pub/object.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/activity_pub/object.rb b/app/models/activity_pub/object.rb index ec759e3e..898d5375 100644 --- a/app/models/activity_pub/object.rb +++ b/app/models/activity_pub/object.rb @@ -5,7 +5,6 @@ class ActivityPub class Object < ApplicationRecord include ActivityPub::Concerns::JsonLdConcern - belongs_to :actor has_many :activity_pubs, as: :object end end From b562b006bc716200898524a027ac67efb24d9080 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 17:03:59 -0300 Subject: [PATCH 150/472] =?UTF-8?q?fix:=20versi=C3=B3n=20requerida=20por?= =?UTF-8?q?=20aasm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Gemfile | 2 +- Gemfile.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index 8e955e8f..676b3673 100644 --- a/Gemfile +++ b/Gemfile @@ -80,7 +80,7 @@ gem 'yaml_db', git: 'https://0xacab.org/sutty/yaml_db.git' gem 'kaminari' gem 'device_detector' -gem 'after_commit_everywhere' +gem 'after_commit_everywhere', '~> 1.0' gem 'aasm' # database diff --git a/Gemfile.lock b/Gemfile.lock index 50745140..7aac4c12 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -608,7 +608,7 @@ PLATFORMS DEPENDENCIES aasm - after_commit_everywhere + after_commit_everywhere (~> 1.0) bcrypt (~> 3.1.7) bcrypt_pbkdf blazer From e53f31f359617b90cd77921c4e67f2521daed337 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 17:04:39 -0300 Subject: [PATCH 151/472] =?UTF-8?q?fixup!=20fix:=20deleted=20es=20un=20m?= =?UTF-8?q?=C3=A9todo=20reservado?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/activity_pub.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 9445717f..902924b6 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -16,7 +16,7 @@ class ActivityPub < ApplicationRecord validates :site_id, presence: true validates :object_id, presence: true - validates :aasm_state, presence: true, inclusion: { in: %w[paused approved rejected reported deleted] } + validates :aasm_state, presence: true, inclusion: { in: %w[paused approved rejected reported removed] } aasm do # Todavía no hay una decisión sobre el objeto From fc7c2e5b7455b8e91d526a366ac0f57bce8c6c2e Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 17:05:17 -0300 Subject: [PATCH 152/472] fix: undo auto-cancela la actividad --- app/models/activity_pub.rb | 4 +++- app/models/activity_pub/activity/undo.rb | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 902924b6..7e5bcabe 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -38,8 +38,10 @@ class ActivityPub < ApplicationRecord event :remove do transitions to: :removed + # @todo Es posible que haya un ActivityPub::FetchJob pendiente + # cuando estamos haciendo esto, que rellene el objeto después. before do - object.update(content: {}) + object.update(content: {}) unless object.content.empty? end end diff --git a/app/models/activity_pub/activity/undo.rb b/app/models/activity_pub/activity/undo.rb index 41fb5e51..4b6a5a4c 100644 --- a/app/models/activity_pub/activity/undo.rb +++ b/app/models/activity_pub/activity/undo.rb @@ -7,6 +7,18 @@ class ActivityPub class Activity class Undo < ActivityPub::Activity + # Una actividad de deshacer tiene anidada como objeto la actividad + # a deshacer. Para respetar la voluntad de le actore remote, + # tendríamos que eliminar cualquier actividad pendiente sobre el + # objeto. + # + # Sin embargo, estas acciones nunca deberían llegar a nuestra + # Inbox. + # + # @see {https://github.com/hyphacoop/social.distributed.press/issues/43} + def update_activity_pub_state! + activity_pub.remove! + end end end end From dca266714d520cfb0fbd36460c7a898573fac33a Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 17:08:11 -0300 Subject: [PATCH 153/472] fix: no completar el contenido si el objeto tiene actividades canceladas --- app/jobs/activity_pub/fetch_job.rb | 2 ++ app/models/activity_pub.rb | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index e5950c86..ec8c29f7 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -11,6 +11,8 @@ class ActivityPub class FetchJob < ApplicationJob def perform(site:, object:) ActivityPub::Object.transaction do + return if object.activity_pubs.where(aasm_state: 'removed').count.positive? + response = site.social_inbox.dereferencer.get(uri: object.uri) # @todo Fallar cuando la respuesta no funcione? diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 7e5bcabe..df8e5c5c 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -38,8 +38,6 @@ class ActivityPub < ApplicationRecord event :remove do transitions to: :removed - # @todo Es posible que haya un ActivityPub::FetchJob pendiente - # cuando estamos haciendo esto, que rellene el objeto después. before do object.update(content: {}) unless object.content.empty? end From 2ae2b8e9e87b254cc041bda6c060a7b93d171592 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 17:09:15 -0300 Subject: [PATCH 154/472] =?UTF-8?q?fix:=20las=20actividades=20de=20borrado?= =?UTF-8?q?=20eliminan=20el=20contenido=20tambi=C3=A9n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/activity_pub/activity/delete.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/activity_pub/activity/delete.rb b/app/models/activity_pub/activity/delete.rb index 7080375e..351dd3cb 100644 --- a/app/models/activity_pub/activity/delete.rb +++ b/app/models/activity_pub/activity/delete.rb @@ -4,9 +4,9 @@ class ActivityPub class Activity class Delete < ActivityPub::Activity # Si estamos eliminando el objeto, tenemos que vaciar su contenido y - # cambiar el estado a borrado + # cambiar el estado a borrado. def update_activity_pub_state! - activity_pub.deleted! + activity_pub.remove! end end end From 7a936c114314ae4fbcc5827cc1aa019dad02bd2e Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 17:22:31 -0300 Subject: [PATCH 155/472] =?UTF-8?q?fix:=20no=20actualizar=20si=20ya=20esta?= =?UTF-8?q?ba=20cacheado=20y=20el=20contenido=20exist=C3=ADa?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/activity_pub/fetch_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index ec8c29f7..b6c45026 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -17,7 +17,7 @@ class ActivityPub # @todo Fallar cuando la respuesta no funcione? return unless response.ok? - return unless response.miss? + return if response.miss? && object.content.present? content = FastJsonparser.parse(response.body) From a7bd712a7c5725125ccbadcf0c075e71bd4f36fe Mon Sep 17 00:00:00 2001 From: maki Date: Wed, 21 Feb 2024 17:33:58 -0300 Subject: [PATCH 156/472] =?UTF-8?q?fix:=20tama=C3=B1o=20botones=20de=20mod?= =?UTF-8?q?eraci=C3=B3n=20de=20comentarios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/components/_btn_base.haml | 2 +- app/views/components/_comments_btn_box.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/components/_btn_base.haml b/app/views/components/_btn_base.haml index ccc7ce35..7fa507ca 100644 --- a/app/views/components/_btn_base.haml +++ b/app/views/components/_btn_base.haml @@ -1,3 +1,3 @@ -# Componente Botón general Moderación -%button.btn.mx-2{ href: href, class: local_assigns[:class] }= text +%button.btn{ href: href, class: local_assigns[:class] }= text diff --git a/app/views/components/_comments_btn_box.haml b/app/views/components/_comments_btn_box.haml index 7932068f..8b8d7268 100644 --- a/app/views/components/_comments_btn_box.haml +++ b/app/views/components/_comments_btn_box.haml @@ -1,6 +1,6 @@ -# Componente Botonera de Comentarios -- btn_class = 'btn-secondary' +- btn_class = 'btn-secondary py-1 px-2' = render 'components/btn_base', text: t('.text_pause'), class: btn_class, href: '' = render 'components/btn_base', text: t('.text_reject'), class: btn_class, href: '' = render 'components/btn_base', text: t('.text_accept'), class: btn_class, href: '' From e4e604f56d866b6d06e5479328330edf4e640894 Mon Sep 17 00:00:00 2001 From: maki Date: Wed, 21 Feb 2024 17:34:46 -0300 Subject: [PATCH 157/472] =?UTF-8?q?fix:=20separadores=20en=20actividades?= =?UTF-8?q?=20de=20moderaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_comment.haml | 8 ++++---- app/views/moderation_queue/_comments.haml | 4 +++- app/views/moderation_queue/_instances.haml | 3 ++- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 99059133..7c77545a 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -1,13 +1,13 @@ -# Componente Comentario -.flex.mx-4.my-5 +.flex.mx-4.my-4 .row.no-gutters .col-1 = render 'components/checkbox', id: comment['id'] .col-11 .row.no-gutters - .col-4 + .col-3 %p= comment['published'].to_datetime.strftime(t('date.format')) - .col-8 + .col-9 %dl %dt.d-inline.mr-2= t('.source_profile') %dd.d-inline @@ -17,7 +17,7 @@ .row.no-gutters .col.p-0 %p - %span.mr-3= t('.reply_to') + %span= t('.reply_to') %span %a{ href: comment['inReplyTo'] }= comment['inReplyTo'] .row.no-gutters diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index d51909a3..b67fc71f 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -2,7 +2,9 @@ = render 'components/comments_filters' - moderation_queue.each do |comment| + %hr = render 'comment', comment: comment, profile: comment['attributedTo'] -# Botones moderación - = render 'components/comments_btn_box', comment: comment \ No newline at end of file + .d-flex.justify-content-between + = render 'components/comments_btn_box', comment: comment \ No newline at end of file diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index c51ba74f..1accf60d 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -2,13 +2,14 @@ = render 'components/instances_filters' - @instances.each do |instance| + %hr = render 'moderation_queue/instance', instance: instance -# Botones moderación .d-flex.pb-4 = render 'components/instances_btn_box' - %hr +%hr %h3.mt-5= t('moderation_queue.instances.title') %lead= t('moderation_queue.instances.description') = render 'components/block_lists', blocklists: @blocklists From b489b713ac64df577ced3b937172c076be44c0f5 Mon Sep 17 00:00:00 2001 From: maki Date: Wed, 21 Feb 2024 17:52:53 -0300 Subject: [PATCH 158/472] fix: faltaba poner la hora de los comentarios --- app/views/moderation_queue/_comment.haml | 8 +++++--- config/locales/en.yml | 1 + config/locales/es.yml | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 7c77545a..80446587 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -5,9 +5,11 @@ = render 'components/checkbox', id: comment['id'] .col-11 .row.no-gutters - .col-3 - %p= comment['published'].to_datetime.strftime(t('date.format')) - .col-9 + .col-5.col-sm-3.col-lg-4 + %p + %span= comment['published'].to_datetime.strftime(t('date.format')) + %span= comment['published'].to_datetime.strftime(t('time.format')) + .col-7.col-sm-9.col-lg-8 %dl %dt.d-inline.mr-2= t('.source_profile') %dd.d-inline diff --git a/config/locales/en.yml b/config/locales/en.yml index d6a15d4b..0d10b3db 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -48,6 +48,7 @@ en: time: am: am pm: pm + format: '%-I:%M %p' components: instances_filters: text_show: Show diff --git a/config/locales/es.yml b/config/locales/es.yml index 65df27bf..e277f76b 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -48,6 +48,7 @@ es: time: am: am pm: pm + format: '%-H:%M' components: instances_filters: text_show: Ver From e62d6c6c1d5e03d3b4b6c9c47feefc5d2b186833 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 17:50:06 -0300 Subject: [PATCH 159/472] fix: asignar un tipo por defecto para el objeto --- app/controllers/api/v1/webhooks/social_inbox_controller.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index e6b80c4b..c71c4922 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -94,7 +94,10 @@ module Api # # @return [ActivityPub::Object] def object - @object ||= ActivityPub::Object.type_from(original_object).find_or_initialize_by(uri: object_uri).tap do |o| + @object ||= ActivityPub::Object.find_or_initialize_by(uri: object_uri).tap do |o| + # XXX: Si el objeto es una actividad, esto siempre va a ser + # Generic + o.type ||= 'ActivityPub::Object::Generic' o.content = original_object if object_embedded? o.save! From 6b12e5141cd1f4004b53573d39d934f2c205d24b Mon Sep 17 00:00:00 2001 From: f Date: Wed, 21 Feb 2024 17:54:18 -0300 Subject: [PATCH 160/472] feat: al deshacer una actividad resolvemos la pendiente --- app/models/activity_pub/activity/undo.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/models/activity_pub/activity/undo.rb b/app/models/activity_pub/activity/undo.rb index 4b6a5a4c..18fbff5e 100644 --- a/app/models/activity_pub/activity/undo.rb +++ b/app/models/activity_pub/activity/undo.rb @@ -17,7 +17,10 @@ class ActivityPub # # @see {https://github.com/hyphacoop/social.distributed.press/issues/43} def update_activity_pub_state! - activity_pub.remove! + ActivityPub.transaction do + ActivityPub::Activity.find_by(uri: content['object'])&.activity_pub&.remove! + activity_pub.remove! + end end end end From 1b8685b7ca978f4a1f45d40161d6080678eaa51a Mon Sep 17 00:00:00 2001 From: maki Date: Wed, 21 Feb 2024 18:01:10 -0300 Subject: [PATCH 161/472] fix: yaml roto --- app/views/moderation_queue/_comments.haml | 2 +- config/locales/en.yml | 102 +++++++++++----------- 2 files changed, 52 insertions(+), 52 deletions(-) diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index b67fc71f..0e6ce334 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -6,5 +6,5 @@ = render 'comment', comment: comment, profile: comment['attributedTo'] -# Botones moderación - .d-flex.justify-content-between + .d-flex.justify-content-center = render 'components/comments_btn_box', comment: comment \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index 0d10b3db..1b4f2d86 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -50,57 +50,57 @@ en: pm: pm format: '%-I:%M %p' components: - instances_filters: - text_show: Show - text_checked: With the checked - instances_checked_submenu: - submenu_case: Check case by case - submenu_allow: Allow everything - submenu_reject: Reject - instances_show_submenu: - submenu_allow: Allow - submenu_reject: Reject - comments_filters: - text_show: Sho - text_checked: With the checked - comments_checked_submenu: - submenu_pause: Pause - submenu_accept: Accept - submenu_reject: Reject - comments_show_submenu: - submenu_pause: Pause - submenu_accept: Accept - submenu_report: Report - submenu_reject: Reject - profiles_filters: - text_show: Show - text_checked: With the checked - profiles_checked_submenu: - submenu_pause: Pause - submenu_accept: Accept - submenu_reject: Reject - submenu_block: Block - profiles_show_submenu: - submenu_accept: Accept - submenu_block: Block - submenu_reject: Reject - block_lists: - title: Block lists - comments_btn_box: - text_pause: Pause - text_reject: Reject - text_accept: Accept - text_reply: Reply - text_report: Report - instances_btn_box: - text_check: Check case by case - text_allow: Allow everything - text_deny: Block instance - profiles_btn_box: - text_approve: Always approve - text_check: Always check - text_deny: Block - text_report: Report + instances_filters: + text_show: Show + text_checked: With selected + instances_checked_submenu: + submenu_case: Check case by case + submenu_allow: Allow everything + submenu_reject: Reject + instances_show_submenu: + submenu_allow: Allow + submenu_reject: Reject + comments_filters: + text_show: Show + text_checked: With selected + comments_checked_submenu: + submenu_pause: Pause + submenu_accept: Accept + submenu_reject: Reject + comments_show_submenu: + submenu_pause: Pause + submenu_accept: Accept + submenu_report: Report + submenu_reject: Reject + profiles_filters: + text_show: Show + text_checked: With selected + profiles_checked_submenu: + submenu_pause: Pause + submenu_accept: Accept + submenu_reject: Reject + submenu_block: Block + profiles_show_submenu: + submenu_accept: Accept + submenu_block: Block + submenu_reject: Reject + block_lists: + title: Block lists + comments_btn_box: + text_pause: Pause + text_reject: Reject + text_accept: Accept + text_reply: Reply + text_report: Report + instances_btn_box: + text_check: Check case by case + text_allow: Allow everything + text_deny: Block instance + profiles_btn_box: + text_approve: Always approve + text_check: Always check + text_deny: Block + text_report: Report moderation_queue: index: title: Moderation From df88f80b300bd401547fb8f2a76203ff1736c20f Mon Sep 17 00:00:00 2001 From: maki Date: Wed, 21 Feb 2024 18:08:54 -0300 Subject: [PATCH 162/472] fix: comentario en un details si tiene summary --- app/views/moderation_queue/_comment.haml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 80446587..a066f845 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -24,4 +24,9 @@ %a{ href: comment['inReplyTo'] }= comment['inReplyTo'] .row.no-gutters .col.p-0 - %p= comment['content'].html_safe + - if comment['summary'] + - summary = comment['summary'] + = render 'layouts/details', summary: summary do + %p= comment['content'].html_safe + - else + %p= comment['content'].html_safe From 476ab951bbd4f8d0f560ffdcb3ba709e1b5ba258 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 22 Feb 2024 13:31:31 -0300 Subject: [PATCH 163/472] fixup! feat: rutas --- app/controllers/api/v1/webhooks/pull_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/v1/webhooks/pull_controller.rb b/app/controllers/api/v1/webhooks/pull_controller.rb index 5f0b703b..93256fc7 100644 --- a/app/controllers/api/v1/webhooks/pull_controller.rb +++ b/app/controllers/api/v1/webhooks/pull_controller.rb @@ -5,7 +5,7 @@ module Api module Webhooks # Recibe webhooks y lanza un PullJob class PullController < BaseController - include WebhookConcern + include Api::V1::Webhooks::Concerns::WebhookConcern # Trae los cambios a partir de un post de Webhooks: # (Gitlab, Github, Gitea, etc) From 1404d2006d4566508c9eaa242de0940c4af61836 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 22 Feb 2024 13:32:30 -0300 Subject: [PATCH 164/472] fixup! feat: asociar rol con deploy nos permite acceder al token --- db/migrate/20240216170202_add_rol_to_deploys.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20240216170202_add_rol_to_deploys.rb b/db/migrate/20240216170202_add_rol_to_deploys.rb index 5f629432..93c4553d 100644 --- a/db/migrate/20240216170202_add_rol_to_deploys.rb +++ b/db/migrate/20240216170202_add_rol_to_deploys.rb @@ -6,7 +6,7 @@ class AddRolToDeploys < ActiveRecord::Migration[6.1] add_column :deploys, :rol_id, :integer, index: true Deploy.find_each do |deploy| - rol_id = deploy.site.roles.find_by(rol: 'usuarie', temporal: false).id + rol_id = deploy.site.roles.find_by(rol: 'usuarie', temporal: false)&.id deploy.update_column(:rol_id, rol_id) if rol_id end From e62e26c87c17152979c244b771ce7a02dda7fcb9 Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 22 Feb 2024 15:36:42 -0300 Subject: [PATCH 165/472] fix: agregado checkbox general a comentarios --- app/views/moderation_queue/_comments.haml | 8 ++++++-- app/views/posts/_moderation_queue.haml | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index 0e6ce334..41193ce1 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -1,5 +1,9 @@ --# Filtros -= render 'components/comments_filters' +.row.no-gutters.pt-2 + .col-1 + = render 'components/checkbox', id: moderation_queue.first['id'] + .col-11 + -# Filtros + = render 'components/comments_filters' - moderation_queue.each do |comment| %hr diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index 2be35f7f..2ec6a07d 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -1,5 +1,9 @@ --# Filtros -= render 'components/comments_filters' +.row.no-gutters.pt-2 + .col-1 + = render 'components/checkbox', id: moderation_queue.first['id'] + .col-11 + -# Filtros + = render 'components/comments_filters' - moderation_queue.each do |comment| = render 'moderation_queue/comment', comment: comment, profile: comment['attributedTo'] From af1afe8f50c6e288474e4e1137179e3a682e5a8e Mon Sep 17 00:00:00 2001 From: jazzari Date: Thu, 22 Feb 2024 15:50:57 -0300 Subject: [PATCH 166/472] fix: agregado html_safe a summary en remote_profile --- app/views/moderation_queue/_remote_profile.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml index e8635cc6..43474b80 100644 --- a/app/views/moderation_queue/_remote_profile.haml +++ b/app/views/moderation_queue/_remote_profile.haml @@ -12,7 +12,7 @@ %dd= remote_profile['published'].to_datetime.strftime('%m/%d/%Y') %dt= t('.profile_summary') - %dd= remote_profile['summary'] + %dd= remote_profile['summary'].html_safe = render 'moderation_queue/comments', moderation_queue: @moderation_queue @@ -21,4 +21,4 @@ %dd= remote_profile['name'] -# Botones de Moderación -= render 'components/comments_btn_box' += render 'components/profiles_btn_box' From c415c79c5c91eaca7ebf615a46fc33df88efa8df Mon Sep 17 00:00:00 2001 From: f Date: Thu, 22 Feb 2024 17:46:58 -0300 Subject: [PATCH 167/472] =?UTF-8?q?fix:=20por=20alguna=20raz=C3=B3n=20usam?= =?UTF-8?q?os=20REDIS=5FSERVER?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/social_inbox.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/social_inbox.rb b/app/models/social_inbox.rb index 45b8afd8..b0fde523 100644 --- a/app/models/social_inbox.rb +++ b/app/models/social_inbox.rb @@ -38,7 +38,7 @@ class SocialInbox public_key_url: public_key_url, private_key_pem: site.private_key_pem, logger: Rails.logger, - cache_store: :redis + cache_store: HTTParty::Cache::Store::Redis.new(redis_url: ENV['REDIS_SERVER']) ) end From b0e07d5d023baeddd7d63ef21cc690b9c140c31e Mon Sep 17 00:00:00 2001 From: f Date: Thu, 22 Feb 2024 17:56:12 -0300 Subject: [PATCH 168/472] fix: require --- app/models/social_inbox.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/social_inbox.rb b/app/models/social_inbox.rb index b0fde523..036aa02b 100644 --- a/app/models/social_inbox.rb +++ b/app/models/social_inbox.rb @@ -3,6 +3,7 @@ require 'distributed_press/v1/social/client' require 'distributed_press/v1/social/hook' require 'distributed_press/v1/social/dereferencer' +require 'httparty/cache/store/redis' # Gestiona la Social Inbox de un sitio class SocialInbox From 1022d57fd3e2ee56de3c56353d26ef6a5627346e Mon Sep 17 00:00:00 2001 From: f Date: Thu, 22 Feb 2024 17:58:51 -0300 Subject: [PATCH 169/472] fix: los scopes en las rutas son raros --- app/models/deploy_social_distributed_press.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/deploy_social_distributed_press.rb b/app/models/deploy_social_distributed_press.rb index fc0e01d5..29670d3b 100644 --- a/app/models/deploy_social_distributed_press.rb +++ b/app/models/deploy_social_distributed_press.rb @@ -73,7 +73,7 @@ class DeploySocialDistributedPress < Deploy webhook_class = DistributedPress::V1::Social::Schemas::Webhook hook_client.class::EVENTS.each do |event| - event_url = :"v1_site_webhooks_social_inbox_#{event}_url" + event_url = :"v1_site_webhooks_#{event}_url" webhook = webhook_class.new.call({ From f50e2d430d4ca57eb743ec5fe226a064e8d34495 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 22 Feb 2024 18:01:09 -0300 Subject: [PATCH 170/472] fix: dump --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 7aac4c12..8ece3064 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -272,7 +272,7 @@ GEM httparty (0.21.0) mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) - httparty-cache (0.0.4) + httparty-cache (0.0.5) httparty (~> 0.18) i18n (1.14.1) concurrent-ruby (~> 1.0) From c23d931dd43e1ca248a71df495b39c6830a8a718 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 22 Feb 2024 18:04:56 -0300 Subject: [PATCH 171/472] =?UTF-8?q?fix:=20usar=20el=20m=C3=A9todo=20correc?= =?UTF-8?q?to?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy_social_distributed_press.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/deploy_social_distributed_press.rb b/app/models/deploy_social_distributed_press.rb index 29670d3b..7f761e46 100644 --- a/app/models/deploy_social_distributed_press.rb +++ b/app/models/deploy_social_distributed_press.rb @@ -90,7 +90,7 @@ class DeploySocialDistributedPress < Deploy response = hook_client.put(event: event, hook: webhook) - raise ArgumentError, response.parsed_body unless response.ok? + raise ArgumentError, response.body unless response.ok? rescue ArgumentError => e ExceptionNotifier.notify_exception(e, data: { site_id: site.name, usuarie_id: rol.usuarie_id }) end From c02a9762068284586f5c636dc98694613774b21e Mon Sep 17 00:00:00 2001 From: f Date: Thu, 22 Feb 2024 18:08:48 -0300 Subject: [PATCH 172/472] feat: poder acceder a la inbox --- app/models/social_inbox.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/models/social_inbox.rb b/app/models/social_inbox.rb index 036aa02b..21b0ca45 100644 --- a/app/models/social_inbox.rb +++ b/app/models/social_inbox.rb @@ -2,6 +2,7 @@ require 'distributed_press/v1/social/client' require 'distributed_press/v1/social/hook' +require 'distributed_press/v1/social/inbox' require 'distributed_press/v1/social/dereferencer' require 'httparty/cache/store/redis' @@ -43,6 +44,11 @@ class SocialInbox ) end + # @return [DistributedPress::V1::Social::Inbox] + def inbox + @inbox ||= DistributedPress::V1::Social::Inbox.new(client: client, actor: actor) + end + # @return [DistributedPress::V1::Social::Dereferencer] def dereferencer @dereferencer ||= DistributedPress::V1::Social::Dereferencer.new(client: client) From 9b401f8c120f9cf074779c8c2bea724d21fec854 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 22 Feb 2024 18:13:53 -0300 Subject: [PATCH 173/472] fix: el hostname puede estar en varios lados --- app/models/social_inbox.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/models/social_inbox.rb b/app/models/social_inbox.rb index 21b0ca45..2f5e7eca 100644 --- a/app/models/social_inbox.rb +++ b/app/models/social_inbox.rb @@ -67,9 +67,12 @@ class SocialInbox end end + # El hostname puede estar en varios lados... + # + # @return [String] def hostname @hostname ||= - site.config.dig('activity_pub', 'hostname') || site.hostname + site.config.dig('activity_pub', 'hostname') || site.config['hostname'] || site.hostname end # Genera una URI dentro de este sitio From 3a382390b1e82f78df79b6910cfd6d4ecdee8c1c Mon Sep 17 00:00:00 2001 From: f Date: Thu, 22 Feb 2024 18:42:20 -0300 Subject: [PATCH 174/472] fix: la social inbox no confirma acciones! --- .../v1/webhooks/social_inbox_controller.rb | 24 ++++++++++++++----- app/models/activity_pub.rb | 8 +++---- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index c71c4922..1ffc1596 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -38,21 +38,33 @@ module Api head :accepted end - # Cuando aprobamos una actividad, recibimos la confirmación y - # cambiamos el estado. + # Cuando la Social Inbox acepta una actividad, la recibimos + # igual y la guardamos por si cambiamos de idea. + # + # @todo DRY def onapproved ActivityPub.transaction do - activity_pub.approve! if activity_pub.waiting? + actor.present? + instance.present? + object.present? + activity.present? + activity_pub.approve! end head :accepted end - # Cuando rechazamos una actividad, recibimos la confirmación y - # cambiamos el estado + # Cuando la Social Inbox rechaza una actividad, la recibimos + # igual y la guardamos por si cambiamos de idea. + # + # @todo DRY def onrejected ActivityPub.transaction do - activity_pub.reject! if activity_pub.waiting? + actor.present? + instance.present? + object.present? + activity.present? + activity_pub.reject! end head :accepted diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index df8e5c5c..07754b87 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -21,8 +21,6 @@ class ActivityPub < ApplicationRecord aasm do # Todavía no hay una decisión sobre el objeto state :paused, initial: true - # Estamos esperando respuesta desde la Social Inbox - state :waiting # Le usuarie aprobó el objeto state :approved # Le usuarie rechazó el objeto @@ -46,17 +44,17 @@ class ActivityPub < ApplicationRecord # Si un objeto previamente aprobado fue actualizado, volvemos a # pausarlo. event :pause do - transitions from: %i[waiting approved rejected], to: :paused + transitions from: %i[approved rejected], to: :paused end # La actividad se aprueba event :approve do - transitions from: :waiting, to: :approved + transitions from: %i[paused rejected], to: :approved end # La actividad fue rechazada event :reject do - transitions from: :waiting, to: :rejected + transitions from: %i[paused approved], to: :rejected end end end From fd1d2382fa481ec45888bb036bc8aac27e3d50b4 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 22 Feb 2024 18:42:36 -0300 Subject: [PATCH 175/472] feat: luego de rechazar podemos reportar --- app/models/activity_pub.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 07754b87..217c15a1 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -56,5 +56,10 @@ class ActivityPub < ApplicationRecord event :reject do transitions from: %i[paused approved], to: :rejected end + + # Solo podemos reportarla luego de rechazarla + event :report do + transitions from: :rejected, to: :reported + end end end From 836e5d5935e675d46adf507353a4a6de4332f4bf Mon Sep 17 00:00:00 2001 From: f Date: Fri, 23 Feb 2024 12:26:33 -0300 Subject: [PATCH 176/472] fix: las actividades pueden existir previamente --- .../api/v1/webhooks/social_inbox_controller.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index 1ffc1596..8b8ba35f 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -132,12 +132,14 @@ module Api # # @return [ActivityPub::Activity] def activity - @activity ||= ActivityPub::Activity.type_from(original_activity).new(uri: original_activity[:id], - activity_pub: activity_pub).tap do |a| - a.content = original_activity.dup - a.content[:object] = object.uri - a.save! - end + @activity ||= + ActivityPub::Activity + .type_from(original_activity) + .find_or_initialize_by(uri: original_activity[:id], activity_pub: activity_pub).tap do |a| + a.content = original_activity.dup + a.content[:object] = object.uri + a.save! + end end # Actor, si no hay instancia, la crea en el momento From a51cb4dbddb0a984e2546edc807c4a7e897321e2 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 23 Feb 2024 12:36:03 -0300 Subject: [PATCH 177/472] =?UTF-8?q?fix:=20copiar=20el=20contexto=20desde?= =?UTF-8?q?=20la=20acci=C3=B3n=20al=20objeto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/api/v1/webhooks/social_inbox_controller.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index 8b8ba35f..02c91813 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -171,7 +171,9 @@ module Api # @return [Hash,String] def original_object - @original_object ||= original_activity[:object].dup + @original_object ||= original_activity[:object].dup.tap do |o| + o[:@context] = original_activity[:@context].dup + end end end end From a4062c5f545a7f2bac4c5b909d83eaca037ea3ec Mon Sep 17 00:00:00 2001 From: f Date: Fri, 23 Feb 2024 12:52:01 -0300 Subject: [PATCH 178/472] feat: eliminar un objeto elimina todas las actividades pendientes --- app/models/activity_pub/activity/delete.rb | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/app/models/activity_pub/activity/delete.rb b/app/models/activity_pub/activity/delete.rb index 351dd3cb..9e7daa16 100644 --- a/app/models/activity_pub/activity/delete.rb +++ b/app/models/activity_pub/activity/delete.rb @@ -3,10 +3,19 @@ class ActivityPub class Activity class Delete < ActivityPub::Activity - # Si estamos eliminando el objeto, tenemos que vaciar su contenido y - # cambiar el estado a borrado. + # Los Delete se refieren a objetos. Al eliminar un objeto, + # cancelamos todas las actividades que tienen relacionadas. + # + # XXX: La actividad tiene una firma, pero la implementación no + # está recomendada + # + # @see {https://docs.joinmastodon.org/spec/security/#ld} def update_activity_pub_state! - activity_pub.remove! + ActivityPub.transaction do + ActivityPub::Object.find_by(uri: ActivityPub.uri_from_object(content['object']))&.activity_pubs&.find_each(&:remove!) + + activity_pub.remove! + end end end end From 2c8dbc885c38d25037df28b1a99a1ce0991ff5fd Mon Sep 17 00:00:00 2001 From: f Date: Fri, 23 Feb 2024 12:53:56 -0300 Subject: [PATCH 179/472] fix: evitar advertencias --- app/controllers/application_controller.rb | 2 +- app/models/concerns/tienda.rb | 2 +- app/models/site.rb | 2 +- app/models/site/api.rb | 2 +- app/models/site/social_distributed_press.rb | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 2746ab10..3201b909 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -3,7 +3,7 @@ # Forma de ingreso a Sutty class ApplicationController < ActionController::Base include ExceptionHandler - include Pundit + include Pundit::Authorization protect_from_forgery with: :null_session, prepend: true diff --git a/app/models/concerns/tienda.rb b/app/models/concerns/tienda.rb index cd09358e..86174c9a 100644 --- a/app/models/concerns/tienda.rb +++ b/app/models/concerns/tienda.rb @@ -5,7 +5,7 @@ module Tienda extend ActiveSupport::Concern included do - encrypts :tienda_api_key + has_encrypted :tienda_api_key def tienda? tienda_api_key.present? && tienda_url.present? diff --git a/app/models/site.rb b/app/models/site.rb index dd250e3d..a9cb3652 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -17,7 +17,7 @@ class Site < ApplicationRecord # tiene acceso pero los datos se guardan cifrados en el sitio. Esto # protege información privada en repositorios públicos, pero no la # protege de acceso al panel de Sutty! - encrypts :private_key + has_encrypted :private_key validates :name, uniqueness: true, hostname: { allow_root_label: true diff --git a/app/models/site/api.rb b/app/models/site/api.rb index 73f8e710..6c6f0ece 100644 --- a/app/models/site/api.rb +++ b/app/models/site/api.rb @@ -5,7 +5,7 @@ class Site extend ActiveSupport::Concern included do - encrypts :api_key + has_encrypted :api_key before_save :add_api_key_if_missing! # Genera mensajes secretos que podemos usar para la API de cada diff --git a/app/models/site/social_distributed_press.rb b/app/models/site/social_distributed_press.rb index c3abe06e..7ebdcb36 100644 --- a/app/models/site/social_distributed_press.rb +++ b/app/models/site/social_distributed_press.rb @@ -8,7 +8,7 @@ class Site extend ActiveSupport::Concern included do - encrypts :private_key_pem + has_encrypted :private_key_pem has_many :activity_pubs From e3aabf4b91e485ddfa90293fc71d1e41145fea7f Mon Sep 17 00:00:00 2001 From: f Date: Fri, 23 Feb 2024 12:54:31 -0300 Subject: [PATCH 180/472] feat: poder obtener el id desde un objeto --- app/models/activity_pub.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 217c15a1..e99fa1f4 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -18,6 +18,16 @@ class ActivityPub < ApplicationRecord validates :object_id, presence: true validates :aasm_state, presence: true, inclusion: { in: %w[paused approved rejected reported removed] } + # Encuentra la URI de un objeto + # + # @return [String, nil] + def self.uri_from_object(object) + case object + when String then object + when Hash then object['id'] + end + end + aasm do # Todavía no hay una decisión sobre el objeto state :paused, initial: true From 77137f311cba52a54b0a028f18d7f009f011c9cb Mon Sep 17 00:00:00 2001 From: f Date: Fri, 23 Feb 2024 12:56:39 -0300 Subject: [PATCH 181/472] docs: recordar que tenemos que validar mejor --- app/models/activity_pub/activity/delete.rb | 2 ++ app/models/activity_pub/activity/undo.rb | 2 ++ 2 files changed, 4 insertions(+) diff --git a/app/models/activity_pub/activity/delete.rb b/app/models/activity_pub/activity/delete.rb index 9e7daa16..f6ff6536 100644 --- a/app/models/activity_pub/activity/delete.rb +++ b/app/models/activity_pub/activity/delete.rb @@ -9,6 +9,8 @@ class ActivityPub # XXX: La actividad tiene una firma, pero la implementación no # está recomendada # + # @todo Validar que le Actor corresponda con los objetos. Esto ya + # lo haría la Social Inbox por nosotres. # @see {https://docs.joinmastodon.org/spec/security/#ld} def update_activity_pub_state! ActivityPub.transaction do diff --git a/app/models/activity_pub/activity/undo.rb b/app/models/activity_pub/activity/undo.rb index 18fbff5e..ae78a0d3 100644 --- a/app/models/activity_pub/activity/undo.rb +++ b/app/models/activity_pub/activity/undo.rb @@ -15,6 +15,8 @@ class ActivityPub # Sin embargo, estas acciones nunca deberían llegar a nuestra # Inbox. # + # @todo Validar que le Actor corresponda con los objetos. Esto ya + # lo haría la Social Inbox por nosotres. # @see {https://github.com/hyphacoop/social.distributed.press/issues/43} def update_activity_pub_state! ActivityPub.transaction do From 2f19aae793b91447c3cc633456b19d8d0a35fa99 Mon Sep 17 00:00:00 2001 From: jazzari Date: Fri, 23 Feb 2024 13:52:31 -0300 Subject: [PATCH 182/472] feat: agregado enlace a listas de bloquedo y quitado estilo en css --- app/assets/stylesheets/application.scss | 5 ----- app/views/components/_block_list.haml | 6 ++++-- db/seeds/blocklists.yml | 2 ++ 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 240e61a5..a24af4c8 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -582,8 +582,3 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); } } } - - -hr { - border-bottom: 1px solid #dee2e6; -} \ No newline at end of file diff --git a/app/views/components/_block_list.haml b/app/views/components/_block_list.haml index c2af3262..36ca8144 100644 --- a/app/views/components/_block_list.haml +++ b/app/views/components/_block_list.haml @@ -2,5 +2,7 @@ .card.mt-3.mb-3 .card-body .d-flex.flex-row - = render 'components/checkbox', id: blocklist["id"] do - %span.h4= blocklist["title"] + = render 'components/checkbox', id: blocklist['id'] do + -#%span.h4= blocklist["title"] + %h4 + %a{ href: blocklist['link'] }= blocklist['title'] diff --git a/db/seeds/blocklists.yml b/db/seeds/blocklists.yml index d9f9dd6f..54dfe6c9 100644 --- a/db/seeds/blocklists.yml +++ b/db/seeds/blocklists.yml @@ -1,5 +1,7 @@ --- - id: gardenfence title: Gardenfence + link: 'https://gardenfence.github.io/' - id: lista title: Lista + link: '#' From e632bd249b16b6e888f65a9e90c517dbbe424a39 Mon Sep 17 00:00:00 2001 From: jazzari Date: Fri, 23 Feb 2024 14:47:24 -0300 Subject: [PATCH 183/472] fix: corregido compo comentario en cuenta de origen y fecha --- app/views/moderation_queue/_comment.haml | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index a066f845..4836f03d 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -5,16 +5,10 @@ = render 'components/checkbox', id: comment['id'] .col-11 .row.no-gutters - .col-5.col-sm-3.col-lg-4 - %p - %span= comment['published'].to_datetime.strftime(t('date.format')) - %span= comment['published'].to_datetime.strftime(t('time.format')) - .col-7.col-sm-9.col-lg-8 - %dl - %dt.d-inline.mr-2= t('.source_profile') - %dd.d-inline - %a{ href: comment['attributedTo'] }= profile['preferredUsername'] - + .col.col-lg-10.d-inline-flex.justify-content-between + %h4 + %a{ href: comment['attributedTo'] }= profile['preferredUsername'] + = render 'layouts/time', time: comment['published'] - if comment['inReplyTo'] .row.no-gutters .col.p-0 @@ -30,3 +24,4 @@ %p= comment['content'].html_safe - else %p= comment['content'].html_safe + From ea6d794b572b48d3198275967927b74efbccb2be Mon Sep 17 00:00:00 2001 From: jazzari Date: Fri, 23 Feb 2024 14:57:07 -0300 Subject: [PATCH 184/472] fix: corregido checkbox general en comentarios, cuentas e instancias --- app/views/moderation_queue/_accounts.haml | 8 ++++++-- app/views/moderation_queue/_comments.haml | 2 +- app/views/moderation_queue/_instances.haml | 8 ++++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index 9a6738bd..5fa8638c 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -1,5 +1,9 @@ --# Filtros -= render 'components/profiles_filters' +.row.no-gutters.pt-2 + .col-1.d-flex.align-items-center + = render 'components/checkbox', id: moderation_queue.first['id'] + .col-11 + -# Filtros + = render 'components/profiles_filters' - @moderation_queue.map{ |c| c['attributedTo'] }.uniq.each do |remote_profile| %hr diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index 41193ce1..6fa8c0f4 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -1,5 +1,5 @@ .row.no-gutters.pt-2 - .col-1 + .col-1.d-flex.align-items-center = render 'components/checkbox', id: moderation_queue.first['id'] .col-11 -# Filtros diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index 1accf60d..cf67a473 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -1,5 +1,9 @@ --# Filtros -= render 'components/instances_filters' +.row.no-gutters.pt-2 + .col-1.d-flex.align-items-center + = render 'components/checkbox', id: moderation_queue.first['id'] + .col-11 + -# Filtros + = render 'components/instances_filters' - @instances.each do |instance| %hr From f83642797922b32f316398e276533095180b2e35 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 24 Feb 2024 11:09:57 -0300 Subject: [PATCH 185/472] =?UTF-8?q?feat:=20obtener=20informaci=C3=B3n=20so?= =?UTF-8?q?bre=20la=20instancia?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../v1/webhooks/social_inbox_controller.rb | 3 +++ app/jobs/activity_pub/instance_fetch_job.rb | 22 +++++++++++++++++++ app/models/social_inbox.rb | 8 +++---- 3 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 app/jobs/activity_pub/instance_fetch_job.rb diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index 02c91813..97ca58b5 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -150,6 +150,9 @@ module Api next if a.instance a.instance = ActivityPub::Instance.find_or_create_by(hostname: URI.parse(a.uri).hostname) + + ActivityPub::InstanceFetchJob.perform_later(site: site, instance: a.instance) + a.save! end end diff --git a/app/jobs/activity_pub/instance_fetch_job.rb b/app/jobs/activity_pub/instance_fetch_job.rb new file mode 100644 index 00000000..a5c07162 --- /dev/null +++ b/app/jobs/activity_pub/instance_fetch_job.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class ActivityPub + # Obtiene o actualiza los datos de una instancia. + class InstanceFetchJob < ApplicationJob + def perform(site:, instance:) + %w[/api/v2/instance /api/v1/instance].each do |api| + uri = SocialInbox.generate_uri(instance.hostname) do |u| + u.path = api + end + + response = site.social_inbox.dereferencer.get(uri: uri) + + next unless response.ok? + + instance.update(content: response.parsed_response) + + break + end + end + end +end diff --git a/app/models/social_inbox.rb b/app/models/social_inbox.rb index 2f5e7eca..03612779 100644 --- a/app/models/social_inbox.rb +++ b/app/models/social_inbox.rb @@ -28,7 +28,7 @@ class SocialInbox end def actor_id - @actor_id ||= generate_uri do |uri| + @actor_id ||= SocialInbox.generate_uri(hostname) do |uri| uri.path = '/about.jsonld' end end @@ -61,7 +61,7 @@ class SocialInbox # @return [String] def public_key_url - @public_key_url ||= generate_uri do |uri| + @public_key_url ||= SocialInbox.generate_uri(hostname) do |uri| uri.path = '/about.jsonld' uri.fragment = 'main-key' end @@ -78,7 +78,7 @@ class SocialInbox # Genera una URI dentro de este sitio # # @return [String] - def generate_uri(&block) - @public_key_url ||= URI("https://#{hostname}").tap(&block).to_s + def self.generate_uri(hostname, &block) + URI("https://#{hostname}").tap(&block).to_s end end From 9e54d6311c0fbd9a7dfc34ab5b37460cf97b1021 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 24 Feb 2024 12:46:55 -0300 Subject: [PATCH 186/472] =?UTF-8?q?feat:=20obtener=20informaci=C3=B3n=20de?= =?UTF-8?q?=20le=20actore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../v1/webhooks/social_inbox_controller.rb | 2 ++ app/jobs/activity_pub/actor_fetch_job.rb | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 app/jobs/activity_pub/actor_fetch_job.rb diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index 97ca58b5..a5951716 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -154,6 +154,8 @@ module Api ActivityPub::InstanceFetchJob.perform_later(site: site, instance: a.instance) a.save! + + ActivityPub::ActorFetchJob.perform_later(site: site, actor: a) end end diff --git a/app/jobs/activity_pub/actor_fetch_job.rb b/app/jobs/activity_pub/actor_fetch_job.rb new file mode 100644 index 00000000..1c6f1735 --- /dev/null +++ b/app/jobs/activity_pub/actor_fetch_job.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +# Obtiene o actualiza el contenido de un objeto, usando las credenciales +# del sitio. +# +# XXX: Esto usa las credenciales del sitio para volver el objeto +# disponible para todo el CMS. Asumimos que el objeto devuelto es el +# mismo para todo el mundo y las credenciales solo son para +# autenticación. +class ActivityPub + class ActorFetchJob < ApplicationJob + def perform(site:, actor:) + ActivityPub::Actor.transaction do + response = site.social_inbox.dereferencer.get(uri: actor.uri) + + # @todo Fallar cuando la respuesta no funcione? + return unless response.ok? + return if response.miss? && actor.content.present? + + actor.update(content: FastJsonparser.parse(response.body)) + end + end + end +end From a76c652f98e217a451a8b489586c3dc7500b8ef0 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 24 Feb 2024 12:47:11 -0300 Subject: [PATCH 187/472] =?UTF-8?q?fix:=20permitir=20guardar=20le=20actore?= =?UTF-8?q?=20si=20la=20instancia=20ya=20exist=C3=ADa?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/v1/webhooks/social_inbox_controller.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index a5951716..a1ff9677 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -147,11 +147,11 @@ module Api # @return [Actor] def actor @actor ||= ActivityPub::Actor.find_or_initialize_by(uri: original_activity[:actor]).tap do |a| - next if a.instance + unless a.instance + a.instance = ActivityPub::Instance.find_or_create_by(hostname: URI.parse(a.uri).hostname) - a.instance = ActivityPub::Instance.find_or_create_by(hostname: URI.parse(a.uri).hostname) - - ActivityPub::InstanceFetchJob.perform_later(site: site, instance: a.instance) + ActivityPub::InstanceFetchJob.perform_later(site: site, instance: a.instance) + end a.save! From 380d484c00aa2b53d171c0c85bc21160482679d0 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 24 Feb 2024 13:04:52 -0300 Subject: [PATCH 188/472] feat: poder encontrar instancias a partir de actividades --- app/controllers/moderation_queue_controller.rb | 6 ++++++ app/models/activity_pub/activity.rb | 1 + app/models/activity_pub/actor.rb | 1 + app/models/activity_pub/instance.rb | 4 ++++ app/models/activity_pub/object.rb | 7 +++++++ app/views/moderation_queue/_instance.haml | 18 +++++++----------- app/views/moderation_queue/_instances.haml | 2 +- .../20240223170317_add_actor_to_activities.rb | 18 ++++++++++++++++++ db/structure.sql | 6 ++++-- 9 files changed, 49 insertions(+), 14 deletions(-) create mode 100644 db/migrate/20240223170317_add_actor_to_activities.rb diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index eec0c70f..5f94e1f7 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -5,6 +5,12 @@ class ModerationQueueController < ApplicationController # Cola de moderación viendo todo el sitio def index dummy_data + + # @todo cambiar el estado por query + @activity_pubs = site.activity_pubs.where(aasm_state: 'paused') + @activities = ActivityPub::Activity.where(activity_pub_id: @activity_pubs.pluck(:id)) + @actors = ActivityPub::Actor.where(id: @activities.unscoped.distinct.pluck(:actor_id)) + @instances = ActivityPub::Instance.where(id: @actors.distinct.pluck(:instance_id)) end # Perfil remoto de usuarie diff --git a/app/models/activity_pub/activity.rb b/app/models/activity_pub/activity.rb index 5ee3d2d1..a220b831 100644 --- a/app/models/activity_pub/activity.rb +++ b/app/models/activity_pub/activity.rb @@ -16,6 +16,7 @@ class ActivityPub include ActivityPub::Concerns::JsonLdConcern belongs_to :activity_pub + belongs_to :actor has_one :object, through: :activity_pub validates :activity_pub_id, presence: true diff --git a/app/models/activity_pub/actor.rb b/app/models/activity_pub/actor.rb index e79a596a..7a858a7e 100644 --- a/app/models/activity_pub/actor.rb +++ b/app/models/activity_pub/actor.rb @@ -11,5 +11,6 @@ class ActivityPub belongs_to :instance has_many :activity_pubs, as: :object + has_many :activities end end diff --git a/app/models/activity_pub/instance.rb b/app/models/activity_pub/instance.rb index b13b8676..17bf183d 100644 --- a/app/models/activity_pub/instance.rb +++ b/app/models/activity_pub/instance.rb @@ -19,5 +19,9 @@ class ActivityPub state :allowed state :blocked end + + def uri + @uri ||= "https://#{hostname}/" + end end end diff --git a/app/models/activity_pub/object.rb b/app/models/activity_pub/object.rb index 898d5375..c196160f 100644 --- a/app/models/activity_pub/object.rb +++ b/app/models/activity_pub/object.rb @@ -6,5 +6,12 @@ class ActivityPub include ActivityPub::Concerns::JsonLdConcern has_many :activity_pubs, as: :object + + # Encontrar le Actor por su relación con el objeto + # + # @return [ActivityPub::Actor,nil] + def actor + ActivityPub::Actor.find_by(uri: content['actor']) + end end end diff --git a/app/views/moderation_queue/_instance.haml b/app/views/moderation_queue/_instance.haml index cff8a957..958a0199 100644 --- a/app/views/moderation_queue/_instance.haml +++ b/app/views/moderation_queue/_instance.haml @@ -1,16 +1,12 @@ -- host = instance['domain'] -- host ||= instance['uri'] -- hosthttps = "https://#{host}" - .row.no-gutters.pt-2 .col-1 - = render 'components/checkbox', id: host + = render 'components/checkbox', id: instance.hostname .col-11 - %h4 - %a{ href: hosthttps }= instance['title'] - %p= instance['description'].html_safe - %p + %h4 + %a{ href: instance.uri }= instance.content['title'] + %p= instance.content['description'].html_safe + %p %span= t('.users') %span - = instance.dig('usage', 'users', 'active_month') - = instance.dig('stats', 'user_count') + = instance.content.dig('usage', 'users', 'active_month') + = instance.content.dig('stats', 'user_count') diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index 1accf60d..e836d7e0 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -7,7 +7,7 @@ -# Botones moderación .d-flex.pb-4 - = render 'components/instances_btn_box' + = render 'components/instances_btn_box', instance: instance %hr %h3.mt-5= t('moderation_queue.instances.title') diff --git a/db/migrate/20240223170317_add_actor_to_activities.rb b/db/migrate/20240223170317_add_actor_to_activities.rb new file mode 100644 index 00000000..a546cd94 --- /dev/null +++ b/db/migrate/20240223170317_add_actor_to_activities.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# Relaciona Actor con Activity +class AddActorToActivities < ActiveRecord::Migration[6.1] + def up + add_column :activity_pub_activities, :actor_id, :uuid, index: true + + ActivityPub::Activity.find_each do |activity| + actor = ActivityPub::Actor.find_by(uri: activity.content['actor']) + + activity.update(actor: actor) if actor.present? + end + end + + def down + remove_column :activity_pub_activities, :actor_id, :uuid, index: true + end +end diff --git a/db/structure.sql b/db/structure.sql index ee99e791..97e9ba36 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -484,7 +484,8 @@ CREATE TABLE public.activity_pub_activities ( activity_pub_id uuid NOT NULL, type character varying NOT NULL, uri character varying NOT NULL, - content jsonb DEFAULT '{}'::jsonb + content jsonb DEFAULT '{}'::jsonb, + actor_id uuid ); @@ -2472,6 +2473,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20240219204011'), ('20240219204224'), ('20240220161414'), -('20240221184007'); +('20240221184007'), +('20240223170317'); From 64cef8a13e5532ad670378dd8dffd04ef9135dbf Mon Sep 17 00:00:00 2001 From: f Date: Mon, 26 Feb 2024 10:39:00 -0300 Subject: [PATCH 189/472] feat: relacionar actividades con instancias de origen --- app/controllers/moderation_queue_controller.rb | 6 ++---- app/models/activity_pub.rb | 1 + ...226133022_add_instance_id_to_activity_pubs.rb | 16 ++++++++++++++++ db/structure.sql | 6 ++++-- 4 files changed, 23 insertions(+), 6 deletions(-) create mode 100644 db/migrate/20240226133022_add_instance_id_to_activity_pubs.rb diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index 5f94e1f7..8920c717 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -7,10 +7,8 @@ class ModerationQueueController < ApplicationController dummy_data # @todo cambiar el estado por query - @activity_pubs = site.activity_pubs.where(aasm_state: 'paused') - @activities = ActivityPub::Activity.where(activity_pub_id: @activity_pubs.pluck(:id)) - @actors = ActivityPub::Actor.where(id: @activities.unscoped.distinct.pluck(:actor_id)) - @instances = ActivityPub::Instance.where(id: @actors.distinct.pluck(:instance_id)) + @activity_pubs = site.activity_pubs + @instances = ActivityPub::Instance.where(id: @activity_pubs.distinct.pluck(:instance_id)) end # Perfil remoto de usuarie diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index e99fa1f4..1afeee96 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -10,6 +10,7 @@ class ActivityPub < ApplicationRecord include AASM + belongs_to :instance belongs_to :site belongs_to :object, polymorphic: true has_many :activities diff --git a/db/migrate/20240226133022_add_instance_id_to_activity_pubs.rb b/db/migrate/20240226133022_add_instance_id_to_activity_pubs.rb new file mode 100644 index 00000000..710aacef --- /dev/null +++ b/db/migrate/20240226133022_add_instance_id_to_activity_pubs.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# Relaciona instancias con sus actividades +class AddInstanceIdToActivityPubs < ActiveRecord::Migration[6.1] + def up + add_column :activity_pubs, :instance_id, :uuid, index: true + + ActivityPub.all.find_each do |activity_pub| + activity_pub.update(instance: activity_pub&.object&.actor&.instance) + end + end + + def down + remove_column :activity_pubs, :instance_id, :uuid, index: true + end +end diff --git a/db/structure.sql b/db/structure.sql index 97e9ba36..4fb11e5a 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -541,7 +541,8 @@ CREATE TABLE public.activity_pubs ( site_id bigint NOT NULL, object_id uuid NOT NULL, object_type character varying NOT NULL, - aasm_state character varying NOT NULL + aasm_state character varying NOT NULL, + instance_id uuid ); @@ -2474,6 +2475,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20240219204224'), ('20240220161414'), ('20240221184007'), -('20240223170317'); +('20240223170317'), +('20240226133022'); From dc11e6efc76a72a6d934f8eee13718b206531206 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 26 Feb 2024 12:27:56 -0300 Subject: [PATCH 190/472] =?UTF-8?q?feat:=20cada=20sitio=20tiene=20un=20est?= =?UTF-8?q?ado=20de=20moderaci=C3=B3n=20para=20la=20instancia?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../v1/webhooks/social_inbox_controller.rb | 5 +- .../instance_moderations_controller.rb | 35 +++++++++ .../moderation_queue_controller.rb | 2 +- app/models/activity_pub/instance.rb | 1 + app/models/instance_moderation.rb | 27 +++++++ app/models/site/social_distributed_press.rb | 1 + app/policies/instance_moderation_policy.rb | 16 +++++ app/views/components/_btn_base.haml | 6 +- app/views/components/_instances_btn_box.haml | 6 +- app/views/moderation_queue/_instances.haml | 6 +- app/views/moderation_queue/index.haml | 2 +- config/routes.rb | 6 ++ ...240226134335_create_instance_moderation.rb | 26 +++++++ db/structure.sql | 72 ++++++++++++++++++- 14 files changed, 200 insertions(+), 11 deletions(-) create mode 100644 app/controllers/instance_moderations_controller.rb create mode 100644 app/models/instance_moderation.rb create mode 100644 app/policies/instance_moderation_policy.rb create mode 100644 db/migrate/20240226134335_create_instance_moderation.rb diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index a1ff9677..12545915 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -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 diff --git a/app/controllers/instance_moderations_controller.rb b/app/controllers/instance_moderations_controller.rb new file mode 100644 index 00000000..55f3c51b --- /dev/null +++ b/app/controllers/instance_moderations_controller.rb @@ -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 diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index 8920c717..d2123234 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -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 diff --git a/app/models/activity_pub/instance.rb b/app/models/activity_pub/instance.rb index 17bf183d..627ccb10 100644 --- a/app/models/activity_pub/instance.rb +++ b/app/models/activity_pub/instance.rb @@ -13,6 +13,7 @@ class ActivityPub has_many :activity_pubs has_many :actors + has_many :instance_moderations aasm do state :paused, initial: true diff --git a/app/models/instance_moderation.rb b/app/models/instance_moderation.rb new file mode 100644 index 00000000..3c092958 --- /dev/null +++ b/app/models/instance_moderation.rb @@ -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 diff --git a/app/models/site/social_distributed_press.rb b/app/models/site/social_distributed_press.rb index 7ebdcb36..73b284bf 100644 --- a/app/models/site/social_distributed_press.rb +++ b/app/models/site/social_distributed_press.rb @@ -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? diff --git a/app/policies/instance_moderation_policy.rb b/app/policies/instance_moderation_policy.rb new file mode 100644 index 00000000..6b3157e8 --- /dev/null +++ b/app/policies/instance_moderation_policy.rb @@ -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 diff --git a/app/views/components/_btn_base.haml b/app/views/components/_btn_base.haml index 7fa507ca..677b88f1 100644 --- a/app/views/components/_btn_base.haml +++ b/app/views/components/_btn_base.haml @@ -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 diff --git a/app/views/components/_instances_btn_box.haml b/app/views/components/_instances_btn_box.haml index 854262c0..74cad4a4 100644 --- a/app/views/components/_instances_btn_box.haml +++ b/app/views/components/_instances_btn_box.haml @@ -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: '' \ No newline at end of file += 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? diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index e836d7e0..318cddef 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -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') diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml index ab98ee30..0c937758 100644 --- a/app/views/moderation_queue/index.haml +++ b/app/views/moderation_queue/index.haml @@ -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 diff --git a/config/routes.rb b/config/routes.rb index ddc29994..b6250902 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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 diff --git a/db/migrate/20240226134335_create_instance_moderation.rb b/db/migrate/20240226134335_create_instance_moderation.rb new file mode 100644 index 00000000..8b08e14e --- /dev/null +++ b/db/migrate/20240226134335_create_instance_moderation.rb @@ -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 diff --git a/db/structure.sql b/db/structure.sql index 4fb11e5a..c3896060 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -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'); From ffdcb5fae8b37187963182323076ddf048e149c9 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 26 Feb 2024 16:12:56 -0300 Subject: [PATCH 191/472] =?UTF-8?q?feat:=20poder=20cambiar=20el=20estado?= =?UTF-8?q?=20de=20moderaci=C3=B3n=20a=20instancias?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/activity_pub/instance.rb | 6 ++++++ app/models/instance_moderation.rb | 30 ++++++++++++++++++++++++++--- app/models/social_inbox.rb | 12 ++++++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/app/models/activity_pub/instance.rb b/app/models/activity_pub/instance.rb index 627ccb10..42cd2695 100644 --- a/app/models/activity_pub/instance.rb +++ b/app/models/activity_pub/instance.rb @@ -15,12 +15,18 @@ class ActivityPub has_many :actors has_many :instance_moderations + # XXX: Mantenemos esto por si queremos bloquear una instancia a + # nivel general aasm do state :paused, initial: true state :allowed state :blocked end + def list_name + "@*@#{hostname}" + end + def uri @uri ||= "https://#{hostname}/" end diff --git a/app/models/instance_moderation.rb b/app/models/instance_moderation.rb index 3c092958..17b38fb7 100644 --- a/app/models/instance_moderation.rb +++ b/app/models/instance_moderation.rb @@ -13,15 +13,39 @@ class InstanceModeration < ApplicationRecord state :blocked event :pause do - transitions from: %i[allowed blocked], to: :paused + transitions from: %i[allowed blocked], to: :paused, guard: :pause_remotely! end event :allow do - transitions from: %i[paused blocked], to: :allowed + transitions from: %i[paused blocked], to: :allowed, guard: :allow_remotely! end event :block do - transitions from: %i[paused allowed], to: :blocked + transitions from: %i[paused allowed], to: :blocked, guard: :block_remotely! end end + + # Elimina la instancia de todas las listas + # + # @return [Boolean] + def pause_remotely! + 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! + 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! + site.social_inbox.blocklist.delete(list: [instance.list_name]).ok? && + site.social_inbox.allowlist.post(list: [instance.list_name]).ok? + end end diff --git a/app/models/social_inbox.rb b/app/models/social_inbox.rb index 03612779..6677a320 100644 --- a/app/models/social_inbox.rb +++ b/app/models/social_inbox.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true require 'distributed_press/v1/social/client' +require 'distributed_press/v1/social/allowlist' +require 'distributed_press/v1/social/blocklist' require 'distributed_press/v1/social/hook' require 'distributed_press/v1/social/inbox' require 'distributed_press/v1/social/dereferencer' @@ -59,6 +61,16 @@ class SocialInbox @hook ||= DistributedPress::V1::Social::Hook.new(client: client, actor: actor) end + # @return [DistributedPress::V1::Social::Allowlist] + def allowlist + @allowlist ||= DistributedPress::V1::Social::Allowlist.new(client: client, actor: actor) + end + + # @return [DistributedPress::V1::Social::Blocklist] + def blocklist + @blocklist ||= DistributedPress::V1::Social::Blocklist.new(client: client, actor: actor) + end + # @return [String] def public_key_url @public_key_url ||= SocialInbox.generate_uri(hostname) do |uri| From a1b5e385b0ff97a079d60fb689fa05757002269e Mon Sep 17 00:00:00 2001 From: f Date: Mon, 26 Feb 2024 16:50:03 -0300 Subject: [PATCH 192/472] fix: los guards se ejecutan todo el tiempo --- app/models/instance_moderation.rb | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/app/models/instance_moderation.rb b/app/models/instance_moderation.rb index 17b38fb7..735ec387 100644 --- a/app/models/instance_moderation.rb +++ b/app/models/instance_moderation.rb @@ -13,15 +13,27 @@ class InstanceModeration < ApplicationRecord state :blocked event :pause do - transitions from: %i[allowed blocked], to: :paused, guard: :pause_remotely! + transitions from: %i[allowed blocked], to: :paused + + before do + pause_remotely! + end end event :allow do - transitions from: %i[paused blocked], to: :allowed, guard: :allow_remotely! + transitions from: %i[paused blocked], to: :allowed + + before do + allow_remotely! + end end event :block do - transitions from: %i[paused allowed], to: :blocked, guard: :block_remotely! + transitions from: %i[paused allowed], to: :blocked + + before do + block_remotely! + end end end @@ -29,7 +41,8 @@ class InstanceModeration < ApplicationRecord # # @return [Boolean] def pause_remotely! - site.social_inbox.blocklist.delete(list: [instance.list_name]).ok? && + raise AASM::InvalidTransition unless + site.social_inbox.blocklist.delete(list: [instance.list_name]).ok? && site.social_inbox.allowlist.delete(list: [instance.list_name]).ok? end @@ -37,7 +50,8 @@ class InstanceModeration < ApplicationRecord # # @return [Boolean] def block_remotely! - site.social_inbox.allowlist.delete(list: [instance.list_name]).ok? && + raise AASM::InvalidTransition unless + site.social_inbox.allowlist.delete(list: [instance.list_name]).ok? && site.social_inbox.blocklist.post(list: [instance.list_name]).ok? end @@ -45,7 +59,8 @@ class InstanceModeration < ApplicationRecord # # @return [Boolean] def allow_remotely! - site.social_inbox.blocklist.delete(list: [instance.list_name]).ok? && + raise AASM::InvalidTransition unless + site.social_inbox.blocklist.delete(list: [instance.list_name]).ok? && site.social_inbox.allowlist.post(list: [instance.list_name]).ok? end end From cc7175ab997f2febd906022b9af6a69df7d7e057 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 26 Feb 2024 16:51:33 -0300 Subject: [PATCH 193/472] feat: poder filtrar por estado de la instancia --- app/controllers/moderation_queue_controller.rb | 2 +- app/views/components/_instances_filters.haml | 2 +- app/views/components/_instances_show_submenu.haml | 5 +++-- app/views/moderation_queue/_instances.haml | 3 +++ config/locales/en.yml | 5 +++++ config/locales/es.yml | 6 ++++-- 6 files changed, 17 insertions(+), 6 deletions(-) diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index d2123234..8c030460 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -8,7 +8,7 @@ class ModerationQueueController < ApplicationController # @todo cambiar el estado por query @activity_pubs = site.activity_pubs - @instance_moderations = site.instance_moderations + @instance_moderations = rubanok_process(site.instance_moderations, with: InstanceModerationProcessor) end # Perfil remoto de usuarie diff --git a/app/views/components/_instances_filters.haml b/app/views/components/_instances_filters.haml index 213bb7c0..eac20d38 100644 --- a/app/views/components/_instances_filters.haml +++ b/app/views/components/_instances_filters.haml @@ -3,4 +3,4 @@ = render 'components/instances_checked_submenu' = render 'components/dropdown', text: t('.text_show') do - = render 'components/comments_show_submenu' + = render 'components/instances_show_submenu' diff --git a/app/views/components/_instances_show_submenu.haml b/app/views/components/_instances_show_submenu.haml index 1074cc3f..56206735 100644 --- a/app/views/components/_instances_show_submenu.haml +++ b/app/views/components/_instances_show_submenu.haml @@ -1,2 +1,3 @@ -= render 'components/dropdown_item', text: t('.submenu_allow'), path: '/' -= render 'components/dropdown_item', text: t('.submenu_reject'), path: '/' \ No newline at end of file += render 'components/dropdown_item', text: t('.submenu_paused'), path: site_moderation_queue_path(state: 'paused') += render 'components/dropdown_item', text: t('.submenu_allowed'), path: site_moderation_queue_path(state: 'allowed') += render 'components/dropdown_item', text: t('.submenu_blocked'), path: site_moderation_queue_path(state: 'blocked') diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index 2303a061..4c55c439 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -5,6 +5,9 @@ -# Filtros = render 'components/instances_filters' +- if instance_moderations.count.zero? + %h3= t('moderation_queue.nothing') + - instance_moderations.each do |instance_moderation| %hr = render 'moderation_queue/instance', instance: instance_moderation.instance diff --git a/config/locales/en.yml b/config/locales/en.yml index 1b4f2d86..188b85c4 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -60,6 +60,10 @@ en: instances_show_submenu: submenu_allow: Allow submenu_reject: Reject + instances_show_submenu: + submenu_paused: Moderated + submenu_allowed: Allowed + submenu_blocked: Blocked comments_filters: text_show: Show text_checked: With selected @@ -102,6 +106,7 @@ en: text_deny: Block text_report: Report moderation_queue: + nothing: "There's nothing for this filter" index: title: Moderation instances: Instances diff --git a/config/locales/es.yml b/config/locales/es.yml index e277f76b..d3651cb7 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -58,8 +58,9 @@ es: submenu_allow: Permitir todo submenu_reject: Rechazado instances_show_submenu: - submenu_allow: Permitido - submenu_reject: Rechazado + submenu_paused: Pausadas + submenu_allowed: Permitidas + submenu_blocked: Bloqueadas comments_filters: text_show: Ver text_checked: Con los marcados @@ -102,6 +103,7 @@ es: text_deny: Bloquear text_report: Reportar moderation_queue: + nothing: 'No hay nada para este filtro' index: title: Actividades de moderación instances: Instancias From e78f71f25a5d6c1190b5efc4a8ede116e4b12800 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 26 Feb 2024 16:52:02 -0300 Subject: [PATCH 194/472] fix: acciones --- app/views/components/_instances_checked_submenu.haml | 4 ++-- app/views/moderation_queue/_instances.haml | 5 +++-- config/locales/en.yml | 8 +++----- config/locales/es.yml | 5 +++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/views/components/_instances_checked_submenu.haml b/app/views/components/_instances_checked_submenu.haml index f0b76185..9da642a7 100644 --- a/app/views/components/_instances_checked_submenu.haml +++ b/app/views/components/_instances_checked_submenu.haml @@ -1,3 +1,3 @@ -= render 'components/dropdown_item', text: t('.submenu_case'), path: '/' += render 'components/dropdown_item', text: t('.submenu_pause'), path: '/' = render 'components/dropdown_item', text: t('.submenu_allow'), path: '/' -= render 'components/dropdown_item', text: t('.submenu_reject'), path: '/' \ No newline at end of file += render 'components/dropdown_item', text: t('.submenu_block'), path: '/' diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index 4c55c439..20501370 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -1,6 +1,7 @@ -.row.no-gutters.pt-2 +.row.no-gutters.pt-2 .col-1.d-flex.align-items-center - = render 'components/checkbox', id: moderation_queue.first['id'] + = render 'components/checkbox', id: 'all' do + %span.sr-only= t('moderation_queue.everything') .col-11 -# Filtros = render 'components/instances_filters' diff --git a/config/locales/en.yml b/config/locales/en.yml index 188b85c4..9e40c433 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -54,12 +54,9 @@ en: text_show: Show text_checked: With selected instances_checked_submenu: - submenu_case: Check case by case - submenu_allow: Allow everything - submenu_reject: Reject - instances_show_submenu: + submenu_pause: Moderate submenu_allow: Allow - submenu_reject: Reject + submenu_block: Block instances_show_submenu: submenu_paused: Moderated submenu_allowed: Allowed @@ -106,6 +103,7 @@ en: text_deny: Block text_report: Report moderation_queue: + everything: 'Select all' nothing: "There's nothing for this filter" index: title: Moderation diff --git a/config/locales/es.yml b/config/locales/es.yml index d3651cb7..af75105b 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -54,9 +54,9 @@ es: text_show: Ver text_checked: Con los marcados instances_checked_submenu: - submenu_case: Moderar caso por caso + submenu_pause: Moderar caso por caso submenu_allow: Permitir todo - submenu_reject: Rechazado + submenu_block: Rechazar todo instances_show_submenu: submenu_paused: Pausadas submenu_allowed: Permitidas @@ -103,6 +103,7 @@ es: text_deny: Bloquear text_report: Reportar moderation_queue: + everything: 'Seleccionar todo' nothing: 'No hay nada para este filtro' index: title: Actividades de moderación From 761d68604b9bbb1ce2a597d0717bd4121762f4e2 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 26 Feb 2024 17:03:18 -0300 Subject: [PATCH 195/472] feat: poder seleccionar todas las instancias --- .../controllers/select_all_controller.js | 11 +++++++ app/views/components/_checkbox.haml | 2 +- app/views/components/_select_all.haml | 4 +++ app/views/moderation_queue/_instance.haml | 2 +- app/views/moderation_queue/_instances.haml | 33 ++++++++++--------- 5 files changed, 34 insertions(+), 18 deletions(-) create mode 100644 app/javascript/controllers/select_all_controller.js create mode 100644 app/views/components/_select_all.haml diff --git a/app/javascript/controllers/select_all_controller.js b/app/javascript/controllers/select_all_controller.js new file mode 100644 index 00000000..7aca0f59 --- /dev/null +++ b/app/javascript/controllers/select_all_controller.js @@ -0,0 +1,11 @@ +import { Controller } from "stimulus"; + +export default class extends Controller { + static targets = ["toggle", "input"]; + + toggle(event = undefined) { + this.inputTargets.forEach(input => { + input.checked = this.toggleTarget.checked; + }); + } +} diff --git a/app/views/components/_checkbox.haml b/app/views/components/_checkbox.haml index 27f9a776..1932df90 100644 --- a/app/views/components/_checkbox.haml +++ b/app/views/components/_checkbox.haml @@ -1,4 +1,4 @@ -# Componente Checkbox .custom-control.custom-checkbox - %input.custom-control-input{ type: 'checkbox', id: id, name: id, class: local_assigns[:class] } + %input.custom-control-input{ type: 'checkbox', id: id, name: id, **local_assigns } %label.custom-control-label{ for: id }= yield diff --git a/app/views/components/_select_all.haml b/app/views/components/_select_all.haml new file mode 100644 index 00000000..2603dfd3 --- /dev/null +++ b/app/views/components/_select_all.haml @@ -0,0 +1,4 @@ +-# + @param id [String] += render 'components/checkbox', id: id, data: { action: 'select-all#toggle', target: 'select-all.toggle' } do + %span.sr-only= t('.label') diff --git a/app/views/moderation_queue/_instance.haml b/app/views/moderation_queue/_instance.haml index 958a0199..327ea892 100644 --- a/app/views/moderation_queue/_instance.haml +++ b/app/views/moderation_queue/_instance.haml @@ -1,6 +1,6 @@ .row.no-gutters.pt-2 .col-1 - = render 'components/checkbox', id: instance.hostname + = render 'components/checkbox', id: instance.hostname, data: { target: 'select-all.input' } .col-11 %h4 %a{ href: instance.uri }= instance.content['title'] diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index 20501370..1540ae53 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -1,24 +1,25 @@ -.row.no-gutters.pt-2 +.row.no-gutters.pt-2{ data: { controller: 'select-all' } } .col-1.d-flex.align-items-center - = render 'components/checkbox', id: 'all' do - %span.sr-only= t('moderation_queue.everything') + = render 'components/select_all', id: 'instances' .col-11 -# Filtros = render 'components/instances_filters' -- if instance_moderations.count.zero? - %h3= t('moderation_queue.nothing') + .col-12 + - if instance_moderations.count.zero? + %h3= t('moderation_queue.nothing') -- instance_moderations.each do |instance_moderation| - %hr - = render 'moderation_queue/instance', instance: instance_moderation.instance + - instance_moderations.each do |instance_moderation| + %hr + = render 'moderation_queue/instance', instance: instance_moderation.instance - -# Botones moderación - .d-flex.pb-4 - = render 'components/instances_btn_box', site: site, instance_moderation: instance_moderation + -# Botones moderación + .d-flex.pb-4 + = render 'components/instances_btn_box', site: site, instance_moderation: instance_moderation -%hr -%h3.mt-5= t('moderation_queue.instances.title') -%lead= t('moderation_queue.instances.description') -= render 'components/block_lists', blocklists: @blocklists -= render 'moderation_queue/block_instances_textarea' + %hr + .col-12 + %h3.mt-5= t('moderation_queue.instances.title') + %lead= t('moderation_queue.instances.description') + = render 'components/block_lists', blocklists: @blocklists + = render 'moderation_queue/block_instances_textarea' From 9b2efaafac38cf7a52dacb63a15f5265d38c1990 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 26 Feb 2024 17:37:34 -0300 Subject: [PATCH 196/472] =?UTF-8?q?feat:=20hacer=20una=20acci=C3=B3n=20con?= =?UTF-8?q?=20las=20seleccionadas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../instance_moderations_controller.rb | 23 ++++++++++- app/policies/instance_moderation_policy.rb | 6 +++ app/views/components/_checkbox.haml | 3 +- app/views/components/_dropdown_button.haml | 4 ++ .../_instances_checked_submenu.haml | 6 +-- app/views/moderation_queue/_instance.haml | 2 +- app/views/moderation_queue/_instances.haml | 38 ++++++++++--------- config/routes.rb | 2 + 8 files changed, 60 insertions(+), 24 deletions(-) create mode 100644 app/views/components/_dropdown_button.haml diff --git a/app/controllers/instance_moderations_controller.rb b/app/controllers/instance_moderations_controller.rb index 55f3c51b..67a6be1d 100644 --- a/app/controllers/instance_moderations_controller.rb +++ b/app/controllers/instance_moderations_controller.rb @@ -2,7 +2,7 @@ # Actualiza la relación entre un sitio y una instancia class InstanceModerationsController < ApplicationController - before_action :authorize_policy + before_action :authorize_policy, except: %i[action_on_several] def pause instance_moderation.pause! @@ -22,6 +22,27 @@ class InstanceModerationsController < ApplicationController redirect_to site_moderation_queue_path end + def action_on_several + instance_moderations = site.instance_moderations.where(id: params[:instance_moderation]) + + authorize instance_moderations + + action = params[:instance_moderation_action].to_sym + method = :"#{action}!" + + InstanceModeration.transaction do + instance_moderations.find_each do |instance_moderation| + events = instance_moderation.aasm.events.map(&:name) + + next unless events.include? action + + instance_moderation.public_send(method) + end + end + + redirect_to site_moderation_queue_path + end + private # @return [InstanceModeration] diff --git a/app/policies/instance_moderation_policy.rb b/app/policies/instance_moderation_policy.rb index 6b3157e8..c07455b3 100644 --- a/app/policies/instance_moderation_policy.rb +++ b/app/policies/instance_moderation_policy.rb @@ -13,4 +13,10 @@ InstanceModerationPolicy = Struct.new(:usuarie, :instance_moderation) do def block? pause? end + + # En este paso tenemos varias instancias por moderar pero todas son + # del mismo sitio. + def action_on_several? + instance_moderation.first.site.usuarie? usuarie + end end diff --git a/app/views/components/_checkbox.haml b/app/views/components/_checkbox.haml index 1932df90..596ff074 100644 --- a/app/views/components/_checkbox.haml +++ b/app/views/components/_checkbox.haml @@ -1,4 +1,5 @@ -# Componente Checkbox +- local_assigns[:name] ||= id .custom-control.custom-checkbox - %input.custom-control-input{ type: 'checkbox', id: id, name: id, **local_assigns } + %input.custom-control-input{ type: 'checkbox', id: id, **local_assigns } %label.custom-control-label{ for: id }= yield diff --git a/app/views/components/_dropdown_button.haml b/app/views/components/_dropdown_button.haml new file mode 100644 index 00000000..8b0c4684 --- /dev/null +++ b/app/views/components/_dropdown_button.haml @@ -0,0 +1,4 @@ +-# + @param name [String] + @param value [String] +%button.dropdown-item{type: 'submit', data: { target: 'dropdown.item' }, name: name, value: value }= text diff --git a/app/views/components/_instances_checked_submenu.haml b/app/views/components/_instances_checked_submenu.haml index 9da642a7..c3573ead 100644 --- a/app/views/components/_instances_checked_submenu.haml +++ b/app/views/components/_instances_checked_submenu.haml @@ -1,3 +1,3 @@ -= render 'components/dropdown_item', text: t('.submenu_pause'), path: '/' -= render 'components/dropdown_item', text: t('.submenu_allow'), path: '/' -= render 'components/dropdown_item', text: t('.submenu_block'), path: '/' += render 'components/dropdown_button', text: t('.submenu_pause'), name: 'instance_moderation_action', value: 'pause' += render 'components/dropdown_button', text: t('.submenu_allow'), name: 'instance_moderation_action', value: 'allow' += render 'components/dropdown_button', text: t('.submenu_block'), name: 'instance_moderation_action', value: 'block' diff --git a/app/views/moderation_queue/_instance.haml b/app/views/moderation_queue/_instance.haml index 327ea892..e7f74b7e 100644 --- a/app/views/moderation_queue/_instance.haml +++ b/app/views/moderation_queue/_instance.haml @@ -1,6 +1,6 @@ .row.no-gutters.pt-2 .col-1 - = render 'components/checkbox', id: instance.hostname, data: { target: 'select-all.input' } + = render 'components/checkbox', id: instance.hostname, name: 'instance_moderation[]', value: instance_moderation.id, data: { target: 'select-all.input' } .col-11 %h4 %a{ href: instance.uri }= instance.content['title'] diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index 1540ae53..129e1d41 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -1,24 +1,26 @@ -.row.no-gutters.pt-2{ data: { controller: 'select-all' } } - .col-1.d-flex.align-items-center - = render 'components/select_all', id: 'instances' - .col-11 - -# Filtros - = render 'components/instances_filters' +%section + %form{ action: site_instance_moderations_action_on_several_path, method: :post } + .row.no-gutters.pt-2{ data: { controller: 'select-all' } } + .col-1.d-flex.align-items-center + = render 'components/select_all', id: 'instances' + .col-11 + -# Filtros + = render 'components/instances_filters' - .col-12 - - if instance_moderations.count.zero? - %h3= t('moderation_queue.nothing') + .col-12 + - if instance_moderations.count.zero? + %h3= t('moderation_queue.nothing') + + - instance_moderations.each do |instance_moderation| + %hr + = render 'moderation_queue/instance', instance_moderation: instance_moderation, instance: instance_moderation.instance + + -# Botones moderación + .d-flex.pb-4 + = render 'components/instances_btn_box', site: site, instance_moderation: instance_moderation - - instance_moderations.each do |instance_moderation| %hr - = render 'moderation_queue/instance', instance: instance_moderation.instance - - -# Botones moderación - .d-flex.pb-4 - = render 'components/instances_btn_box', site: site, instance_moderation: instance_moderation - - %hr - .col-12 + %div %h3.mt-5= t('moderation_queue.instances.title') %lead= t('moderation_queue.instances.description') = render 'components/block_lists', blocklists: @blocklists diff --git a/config/routes.rb b/config/routes.rb index b6250902..d9e2aca7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -68,6 +68,8 @@ Rails.application.routes.draw do patch :block, to: 'instance_moderations#block' end + patch :instance_moderations_action_on_several, to: 'instance_moderations#action_on_several' + # Gestionar artículos según idioma nested do scope '/(:locale)', constraint: /[a-z]{2}(-[A-Z]{2})?/ do From ca4b3360cde74d1f325861e98d5d056980b11800 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 26 Feb 2024 17:38:00 -0300 Subject: [PATCH 197/472] fixup! feat: poder seleccionar todas las instancias --- app/processors/instance_moderation_processor.rb | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 app/processors/instance_moderation_processor.rb diff --git a/app/processors/instance_moderation_processor.rb b/app/processors/instance_moderation_processor.rb new file mode 100644 index 00000000..414901d6 --- /dev/null +++ b/app/processors/instance_moderation_processor.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# Gestiona los filtros de InstanceModeration +class InstanceModerationProcessor < Rubanok::Processor + map :state, activate_always: true do |state: 'paused'| + raw.where(aasm_state: state) + end +end From 85cfed59fc8fa58fcfc3ba68c73bc03c727215b8 Mon Sep 17 00:00:00 2001 From: jazzari Date: Tue, 27 Feb 2024 12:14:44 -0300 Subject: [PATCH 198/472] =?UTF-8?q?fix:=20corregido=20posici=C3=B3n=20de?= =?UTF-8?q?=20sumary=20en=20details=20y=20boton=20de=20bloqueo=20de=20inst?= =?UTF-8?q?ancias?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/layouts/_details.haml | 3 ++- app/views/moderation_queue/_block_instances_textarea.haml | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/views/layouts/_details.haml b/app/views/layouts/_details.haml index 306986bf..dd6ac5cf 100644 --- a/app/views/layouts/_details.haml +++ b/app/views/layouts/_details.haml @@ -2,5 +2,6 @@ %details.details.py-2 %summary - %h3.py-2= summary + .col-11 + %h3.py-2= summary = yield diff --git a/app/views/moderation_queue/_block_instances_textarea.haml b/app/views/moderation_queue/_block_instances_textarea.haml index 9b388a0d..a90704cc 100644 --- a/app/views/moderation_queue/_block_instances_textarea.haml +++ b/app/views/moderation_queue/_block_instances_textarea.haml @@ -1,5 +1,5 @@ .form-group = label_tag "custom_blocklist", t('moderation_queue.instances.custom_block') = text_area_tag "custom_blocklist", nil, class: 'form-control' - %button.btn.btn-secondary.mt-3{ type: 'submit' }= t('moderation_queue.instances.submit') - + %p + %a.mt-3{ role: 'button', href: '', class: 'btn btn-secondary' }= t('moderation_queue.instances.submit') From 7837e2e85f1a15b546ba6121b2db57e41d460f1a Mon Sep 17 00:00:00 2001 From: jazzari Date: Tue, 27 Feb 2024 12:18:18 -0300 Subject: [PATCH 199/472] fix: corregido espacio en componente block_list --- app/views/components/_block_list.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/components/_block_list.haml b/app/views/components/_block_list.haml index 36ca8144..0d07a340 100644 --- a/app/views/components/_block_list.haml +++ b/app/views/components/_block_list.haml @@ -4,5 +4,5 @@ .d-flex.flex-row = render 'components/checkbox', id: blocklist['id'] do -#%span.h4= blocklist["title"] - %h4 + %h4.m-0 %a{ href: blocklist['link'] }= blocklist['title'] From 570459fef3c6f424f46483c718320f529e728da5 Mon Sep 17 00:00:00 2001 From: jazzari Date: Tue, 27 Feb 2024 12:25:09 -0300 Subject: [PATCH 200/472] =?UTF-8?q?fix:=20corregido=20posici=C3=B3n=20de?= =?UTF-8?q?=20botones=20de=20moderaci=C3=B3n=20en=20details=20de=20Instanc?= =?UTF-8?q?ias=20y=20Cuentas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_account.haml | 4 ++++ app/views/moderation_queue/_accounts.haml | 3 --- app/views/moderation_queue/_instance.haml | 4 ++++ app/views/moderation_queue/_instances.haml | 4 ---- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/views/moderation_queue/_account.haml b/app/views/moderation_queue/_account.haml index 412f0aa7..2c929402 100644 --- a/app/views/moderation_queue/_account.haml +++ b/app/views/moderation_queue/_account.haml @@ -5,3 +5,7 @@ %h4 %a{href: profile['id']}= profile['preferredUsername'] =profile['summary'].html_safe + + -# Botones de Moderación + .d-flex.pb-4 + = render 'components/profiles_btn_box' \ No newline at end of file diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index 5fa8638c..2d8e1420 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -9,7 +9,4 @@ %hr = render 'account', profile: remote_profile --# Botones de Moderación -.d-flex.pb-4 - = render 'components/profiles_btn_box' diff --git a/app/views/moderation_queue/_instance.haml b/app/views/moderation_queue/_instance.haml index cff8a957..889b6095 100644 --- a/app/views/moderation_queue/_instance.haml +++ b/app/views/moderation_queue/_instance.haml @@ -14,3 +14,7 @@ %span = instance.dig('usage', 'users', 'active_month') = instance.dig('stats', 'user_count') + + -# Botones moderación + .d-flex.pb-4 + = render 'components/instances_btn_box' diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index cf67a473..72be522f 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -9,10 +9,6 @@ %hr = render 'moderation_queue/instance', instance: instance - -# Botones moderación - .d-flex.pb-4 - = render 'components/instances_btn_box' - %hr %h3.mt-5= t('moderation_queue.instances.title') %lead= t('moderation_queue.instances.description') From f53ab113396b3e06544b39adf19b9012a865502a Mon Sep 17 00:00:00 2001 From: f Date: Tue, 27 Feb 2024 12:29:42 -0300 Subject: [PATCH 201/472] fixup! feat: poder seleccionar todas las instancias --- Gemfile | 1 + Gemfile.lock | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Gemfile b/Gemfile index 676b3673..d720a2d6 100644 --- a/Gemfile +++ b/Gemfile @@ -79,6 +79,7 @@ gem 'webpacker' gem 'yaml_db', git: 'https://0xacab.org/sutty/yaml_db.git' gem 'kaminari' gem 'device_detector' +gem 'rubanok' gem 'after_commit_everywhere', '~> 1.0' gem 'aasm' diff --git a/Gemfile.lock b/Gemfile.lock index 8ece3064..72a30af1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -488,6 +488,7 @@ GEM rexml (~> 3.2, >= 3.2.4) stream (~> 0.5.3) rouge (3.30.0) + rubanok (0.5.0) rubocop (1.42.0) json (~> 2.3) parallel (~> 1.10) @@ -679,6 +680,7 @@ DEPENDENCIES redis-rails rgl rollups! + rubanok rubocop-rails ruby-brs rubyzip From df6c04888244afd876a786834892b671baa1bb54 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 27 Feb 2024 12:32:09 -0300 Subject: [PATCH 202/472] feat: fediblock --- app/models/activity_pub/fediblock.rb | 77 +++++++++++++++++++ app/models/activity_pub/instance.rb | 6 ++ .../20240227134845_create_fediblocks.rb | 26 +++++++ db/seeds.rb | 6 ++ db/seeds/activity_pub/fediblocks.yml | 16 ++++ db/structure.sql | 27 ++++++- 6 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 app/models/activity_pub/fediblock.rb create mode 100644 db/migrate/20240227134845_create_fediblocks.rb create mode 100644 db/seeds/activity_pub/fediblocks.yml diff --git a/app/models/activity_pub/fediblock.rb b/app/models/activity_pub/fediblock.rb new file mode 100644 index 00000000..8d024f56 --- /dev/null +++ b/app/models/activity_pub/fediblock.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +require 'httparty' + +# Listas de bloqueo y sus URLs de descarga +class ActivityPub + class Fediblock < ApplicationRecord + class Client + include ::HTTParty + + # @param url [String] + # @return [HTTParty::Response] + def get(url) + self.class.get(url, parser: csv_parser) + end + + # Procesa el CSV + # + # @return [Proc] + def csv_parser + @csv_parser ||= + begin + require 'csv' + + proc do |body, _| + CSV.parse(body, headers: true) + end + end + end + end + + class FediblockDownloadError < ::StandardError; end + + validates_presence_of :title, :url, :download_url, :format + validates_inclusion_of :format, in: %w[mastodon fediblock] + + HOSTNAME_HEADERS = { + 'mastodon' => '#domain', + 'fediblock' => 'domain' + } + + def client + @client ||= Client.new + end + + # Descarga la lista y crea las instancias con el estado necesario + def process! + response = client.get(download_url) + + raise FediblockDownloadError unless response.ok? + + Fediblock.transaction do + csv = response.parsed_response + process_csv! csv + + update(instances: csv.map { |r| r[hostname_header] }) + end + end + + private + + def hostname_header + HOSTNAME_HEADERS[format] + end + + # Crea o encuentra instancias que ya existían y las bloquea + # + # @param csv [CSV::Table] + def process_csv!(csv) + csv.each do |row| + ActivityPub::Instance.find_or_create_by(hostname: row[hostname_header]).tap do |i| + i.block! if i.may_block? + end + end + end + end +end diff --git a/app/models/activity_pub/instance.rb b/app/models/activity_pub/instance.rb index 42cd2695..749d98ac 100644 --- a/app/models/activity_pub/instance.rb +++ b/app/models/activity_pub/instance.rb @@ -21,6 +21,12 @@ class ActivityPub state :paused, initial: true state :allowed state :blocked + + # Al pasar una instancia a bloqueo, quiere decir que todos los + # sitios adoptan esta lista + event :block do + transitions from: %i[paused allowed], to: :blocked + end end def list_name diff --git a/db/migrate/20240227134845_create_fediblocks.rb b/db/migrate/20240227134845_create_fediblocks.rb new file mode 100644 index 00000000..03f65f7c --- /dev/null +++ b/db/migrate/20240227134845_create_fediblocks.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +# Las fediblocks son listas descargables de instancias bloqueadas. El +# formato hace una recomendación sobre suspensión o desfederación, pero +# nosotres bloqueamos todo. +class CreateFediblocks < ActiveRecord::Migration[6.1] + def up + create_table :activity_pub_fediblocks, id: :uuid do |t| + t.timestamps + + t.string :title, null: false + t.string :url, null: false + t.string :download_url, null: false + t.string :format, null: false + t.jsonb :instances, default: [] + end + + YAML.safe_load(File.read('db/seeds/activity_pub/fediblocks.yml')).each do |fediblock| + ActivityPub::Fediblock.create(**fediblock).process! + end + end + + def down + drop_table :activity_pub_fediblocks + end +end diff --git a/db/seeds.rb b/db/seeds.rb index b9ef96a1..8e8c291f 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -27,3 +27,9 @@ if PrivacyPolicy.count.zero? PrivacyPolicy.new(**pp).save! end end + +YAML.safe_load(File.read('db/seeds/activity_pub/fediblocks.yml')).each do |fediblock| + ActivityPub::Fediblock.find_or_create_by(id: fediblock['id']).tap do |f| + f.update(**fediblock) + end +end diff --git a/db/seeds/activity_pub/fediblocks.yml b/db/seeds/activity_pub/fediblocks.yml new file mode 100644 index 00000000..c977f9bf --- /dev/null +++ b/db/seeds/activity_pub/fediblocks.yml @@ -0,0 +1,16 @@ +--- +- title: "Gardenfence" + url: "https://gardenfence.github.io/" + download_url: "https://github.com/gardenfence/blocklist/raw/main/gardenfence-fediblocksync.csv" + format: "fediblock" + id: "9046789a-5de8-4b16-beed-796060f8f3cc" +- title: "Oliphant Tier 0" + url: "https://writer.oliphant.social/oliphant/the-oliphant-social-blocklist" + download_url: "https://codeberg.org/oliphant/blocklists/raw/branch/main/blocklists/mastodon/tier0.csv" + format: "mastodon" + id: "fc1efcb8-7e68-4a76-ae9e-0c447752b12b" +- title: "The Bad Space (90%)" + url: "https://tweaking.thebad.space/exports" + download_url: "https://tweaking.thebad.space/exports/mastodon/90" + format: "fediblock" + id: "5dd6705a-c28f-4912-9456-07b0d4983108" diff --git a/db/structure.sql b/db/structure.sql index c3896060..241039d1 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -502,6 +502,22 @@ CREATE TABLE public.activity_pub_actors ( ); +-- +-- Name: activity_pub_fediblocks; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.activity_pub_fediblocks ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, + title character varying NOT NULL, + url character varying NOT NULL, + download_url character varying NOT NULL, + format character varying NOT NULL, + instances jsonb DEFAULT '[]'::jsonb +); + + -- -- Name: activity_pub_instances; Type: TABLE; Schema: public; Owner: - -- @@ -1694,6 +1710,14 @@ ALTER TABLE ONLY public.activity_pub_actors ADD CONSTRAINT activity_pub_actors_pkey PRIMARY KEY (id); +-- +-- Name: activity_pub_fediblocks activity_pub_fediblocks_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.activity_pub_fediblocks + ADD CONSTRAINT activity_pub_fediblocks_pkey PRIMARY KEY (id); + + -- -- Name: activity_pub_instances activity_pub_instances_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -2546,6 +2570,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20240221184007'), ('20240223170317'), ('20240226133022'), -('20240226134335'); +('20240226134335'), +('20240227134845'); From e728c09cc244b7a7a528d57b543fead8b74da312 Mon Sep 17 00:00:00 2001 From: jazzari Date: Tue, 27 Feb 2024 12:35:25 -0300 Subject: [PATCH 203/472] =?UTF-8?q?fix:=20corregida=20traducci=C3=B3n=20de?= =?UTF-8?q?=20usuarios=20de=20instancia?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_instance.haml | 6 +++--- config/locales/en.yml | 1 + config/locales/es.yml | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/views/moderation_queue/_instance.haml b/app/views/moderation_queue/_instance.haml index 889b6095..3bfbde44 100644 --- a/app/views/moderation_queue/_instance.haml +++ b/app/views/moderation_queue/_instance.haml @@ -9,9 +9,9 @@ %h4 %a{ href: hosthttps }= instance['title'] %p= instance['description'].html_safe - %p - %span= t('.users') - %span + %dl + %dt= t('.users') + %dd = instance.dig('usage', 'users', 'active_month') = instance.dig('stats', 'user_count') diff --git a/config/locales/en.yml b/config/locales/en.yml index 1b4f2d86..51b1df4d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -122,6 +122,7 @@ en: description: Description custom_block: Custom block lists submit: Save block lists + instance: users: "Users:" dark: Dark dir: ltr diff --git a/config/locales/es.yml b/config/locales/es.yml index e277f76b..f4751c7a 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -122,6 +122,7 @@ es: description: Descripción de listas de bloqueo custom_block: Lista personalizada de bloqueo submit: Guardar lista de bloqueo + instance: users: "Usuaries:" dark: Oscuro es: Castellano From ae0ca386c3102171e44fb9b0173350208ba7740e Mon Sep 17 00:00:00 2001 From: jazzari Date: Tue, 27 Feb 2024 13:07:51 -0300 Subject: [PATCH 204/472] fix: correciones varias en componente remote_profile --- app/views/moderation_queue/_remote_profile.haml | 10 +++++++--- config/locales/en.yml | 1 + config/locales/es.yml | 3 ++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml index 43474b80..263f9c6b 100644 --- a/app/views/moderation_queue/_remote_profile.haml +++ b/app/views/moderation_queue/_remote_profile.haml @@ -5,12 +5,16 @@ %dt= t('.profile_name') %dd= remote_profile['name'] + %dt= t('.preferred_name') + %dd= remote_profile['preferredUsername'] + %dt= t('.profile_id') - %dd= remote_profile['id'] + %dd + %a{ href: 'https://mastodon.mauve.moe/users/mauve' }= remote_profile['id'] %dt= t('.profile_published') - %dd= remote_profile['published'].to_datetime.strftime('%m/%d/%Y') - + %dd + = render 'layouts/time', time: remote_profile['published'] %dt= t('.profile_summary') %dd= remote_profile['summary'].html_safe diff --git a/config/locales/en.yml b/config/locales/en.yml index 51b1df4d..9aa2c801 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -114,6 +114,7 @@ en: user: Username profile: Profile profile_name: Profile name + preferred_name: Name in Fediverse profile_id: ID profile_published: Published profile_summary: Summary diff --git a/config/locales/es.yml b/config/locales/es.yml index f4751c7a..e39b13c2 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -114,9 +114,10 @@ es: user: Nombre de usuario profile: Cuenta de Origen profile_name: Nombre de la Cuenta + preferred_name: Nombre en el Fediverso profile_id: ID profile_published: Publicada - profile_summary: Resumen + profile_summary: Presentación instances: title: Mis listas de bloqueo description: Descripción de listas de bloqueo From 5a30da4232282d8fdb7483109b9c420d9dfbc674 Mon Sep 17 00:00:00 2001 From: jazzari Date: Tue, 27 Feb 2024 13:14:25 -0300 Subject: [PATCH 205/472] =?UTF-8?q?fix:=20corregido=20parrafo=20en=20Prese?= =?UTF-8?q?ntaci=C3=B3n=20de=20componente=20Remote=5Fprofile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_remote_profile.haml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml index 263f9c6b..92cf8e96 100644 --- a/app/views/moderation_queue/_remote_profile.haml +++ b/app/views/moderation_queue/_remote_profile.haml @@ -16,7 +16,8 @@ %dd = render 'layouts/time', time: remote_profile['published'] %dt= t('.profile_summary') - %dd= remote_profile['summary'].html_safe + %dd + %p= remote_profile['summary'].html_safe = render 'moderation_queue/comments', moderation_queue: @moderation_queue From 8654228edcd3d7b24562f0f62565662b99100373 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 27 Feb 2024 13:25:40 -0300 Subject: [PATCH 206/472] =?UTF-8?q?feat:=20actualizar=20los=20fediblocks?= =?UTF-8?q?=20todos=20los=20d=C3=ADas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Procfile | 1 + app/jobs/activity_pub/fediblock_fetch_job.rb | 14 ++++++++++++++ lib/tasks/activity_pub.rake | 8 ++++++++ monit.conf | 5 +++++ 4 files changed, 28 insertions(+) create mode 100644 app/jobs/activity_pub/fediblock_fetch_job.rb create mode 100644 lib/tasks/activity_pub.rake diff --git a/Procfile b/Procfile index eab8a502..a74f613b 100644 --- a/Procfile +++ b/Procfile @@ -10,3 +10,4 @@ cleanup: bundle exec rake cleanup:everything emergency_cleanup: bundle exec rake cleanup:everything BEFORE=7 stats: bundle exec rake stats:process_all que: daemonize -c /srv/ -p /srv/tmp/que.pid -u rails /usr/local/bin/syslogize bundle exec que +fediblock: bundle exec rails activity_pub:fediblocks diff --git a/app/jobs/activity_pub/fediblock_fetch_job.rb b/app/jobs/activity_pub/fediblock_fetch_job.rb new file mode 100644 index 00000000..d6cb4b83 --- /dev/null +++ b/app/jobs/activity_pub/fediblock_fetch_job.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class ActivityPub + # Se encarga de mantener las listas de bloqueo actualizadas + class FediblockFetchJob < ApplicationJob + def perform + ActivityPub::Fediblock.find_each do |fediblock| + fediblock.process! + rescue ActivityPub::Fediblock::FediblockDownloadError => e + ExceptionNotifier.notify_exception(e, data: { fediblock: fediblock.title }) + end + end + end +end diff --git a/lib/tasks/activity_pub.rake b/lib/tasks/activity_pub.rake new file mode 100644 index 00000000..08c0f980 --- /dev/null +++ b/lib/tasks/activity_pub.rake @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +namespace :activity_pub do + desc 'Update Fediblocks' + task fediblocks: :environment do |_, args| + ActivityPub::FediblockFetchJob.perform_later + end +end diff --git a/monit.conf b/monit.conf index accd0e28..2b7e50a8 100644 --- a/monit.conf +++ b/monit.conf @@ -9,6 +9,11 @@ check program distributed_press_tokens_renew every "0 3 * * *" if status != 0 then alert +check program fediblocks + with path "/usr/bin/foreman run -f /srv/Procfile -d /srv fediblocks" as uid "rails" gid "www-data" + every "0 7 * * *" + if status != 0 then alert + check program access_logs with path "/srv/http/bin/access_logs" as uid "app" and gid "www-data" every "0 0 * * *" From ebdd95151e61bc90d646a7564c289ed67d326981 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 27 Feb 2024 13:43:46 -0300 Subject: [PATCH 207/472] feat: relacionar sitios con fediblocks --- app/models/fediblock_state.rb | 72 +++++++++++++++++++ app/models/site/social_distributed_press.rb | 1 + .../20240227142019_create_fediblock_states.rb | 29 ++++++++ db/structure.sql | 46 +++++++++++- 4 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 app/models/fediblock_state.rb create mode 100644 db/migrate/20240227142019_create_fediblock_states.rb diff --git a/app/models/fediblock_state.rb b/app/models/fediblock_state.rb new file mode 100644 index 00000000..8045e23e --- /dev/null +++ b/app/models/fediblock_state.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +# Relación entre Fediblocks y Sites +class FediblockState < ApplicationRecord + include AASM + + belongs_to :site + belongs_to :fediblock, class_name: 'ActivityPub::Fediblock' + + # El efecto secundario de esta máquina de estados es modificar el + # estado de moderación de cada instancia en el sitio. Nos salteamos + # los hooks de los eventos individuales. + aasm do + # 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 + state :enabled + + event :enable do + transitions from: :disabled, to: :enabled + + before do + enable_remotely! + end + end + + # Al deshabilitar, las listas pasan a modo pausa. + # + # @todo No cambiar el estado si se habían habilitado manualmente, + # pero esto implica que tenemos que encontrar las que sí y quitarlas + # de list_names + event :disable do + transitions from: :enabled, to: :disabled + + before do + disable_remotely! + end + end + end + + private + + # Obtiene todos los IDs de instancias para poder obtener el estado de + # moderación en el sitio. + # + # @return [Array] + def instance_ids + ActivityPub::Instance.where(hostname: fediblock.instances).pluck(:id) + end + + # @return [Array] + def list_names + @list_names ||= fediblock.instances.map do |instance| + "@*@#{instance}" + end + end + + # Al deshabilitar, las instancias pasan a ser analizadas caso por caso + def disable_remotely! + raise AASM::InvalidTransition unless + site.social_inbox.blocklist.delete(list: list_names).ok? && + site.social_inbox.allowlist.delete(list: list_names).ok? + end + + # Al habilitar, se bloquean todas las instancias de la lista + def enable_remotely! + raise AASM::InvalidTransition unless + site.social_inbox.blocklist.post(list: list_names).ok? && + site.social_inbox.allowlist.delete(list: list_names).ok? + end +end diff --git a/app/models/site/social_distributed_press.rb b/app/models/site/social_distributed_press.rb index 73b284bf..e0d2d4f4 100644 --- a/app/models/site/social_distributed_press.rb +++ b/app/models/site/social_distributed_press.rb @@ -12,6 +12,7 @@ class Site has_many :activity_pubs has_many :instance_moderations + has_many :fediblock_states before_save :generate_private_key_pem!, unless: :private_key_pem? diff --git a/db/migrate/20240227142019_create_fediblock_states.rb b/db/migrate/20240227142019_create_fediblock_states.rb new file mode 100644 index 00000000..c99cf63d --- /dev/null +++ b/db/migrate/20240227142019_create_fediblock_states.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +# La relación entre sitios y fediblocks +class CreateFediblockStates < ActiveRecord::Migration[6.1] + def up + create_table :fediblock_states, id: :uuid do |t| + t.timestamps + + t.belongs_to :site + t.uuid :fediblock_id, index: true + t.string :aasm_state + + t.index %i[site_id fediblock_id], unique: true + end + + # Todas las listas están activas por defecto + DeploySocialDistributedPress.find_each do |deploy| + ActivityPub::Fediblock.find_each do |fediblock| + FediblockState.create(site: deploy.site, fediblock: fediblock, aasm_state: 'disabled').tap do |f| + f.enable! + end + end + end + end + + def down + drop_table :fediblock_states + end +end diff --git a/db/structure.sql b/db/structure.sql index 241039d1..ac897695 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -944,6 +944,20 @@ CREATE SEQUENCE public.distributed_press_publishers_id_seq ALTER SEQUENCE public.distributed_press_publishers_id_seq OWNED BY public.distributed_press_publishers.id; +-- +-- Name: fediblock_states; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.fediblock_states ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, + site_id bigint, + fediblock_id uuid, + aasm_state character varying +); + + -- -- Name: indexed_posts; Type: TABLE; Schema: public; Owner: - -- @@ -1830,6 +1844,14 @@ ALTER TABLE ONLY public.distributed_press_publishers ADD CONSTRAINT distributed_press_publishers_pkey PRIMARY KEY (id); +-- +-- Name: fediblock_states fediblock_states_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.fediblock_states + ADD CONSTRAINT fediblock_states_pkey PRIMARY KEY (id); + + -- -- Name: indexed_posts indexed_posts_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -2176,6 +2198,27 @@ CREATE UNIQUE INDEX index_designs_on_gem ON public.designs USING btree (gem); CREATE UNIQUE INDEX index_designs_on_name ON public.designs USING btree (name); +-- +-- Name: index_fediblock_states_on_fediblock_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_fediblock_states_on_fediblock_id ON public.fediblock_states USING btree (fediblock_id); + + +-- +-- Name: index_fediblock_states_on_site_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_fediblock_states_on_site_id ON public.fediblock_states USING btree (site_id); + + +-- +-- Name: index_fediblock_states_on_site_id_and_fediblock_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_fediblock_states_on_site_id_and_fediblock_id ON public.fediblock_states USING btree (site_id, fediblock_id); + + -- -- Name: index_indexed_posts_on_front_matter; Type: INDEX; Schema: public; Owner: - -- @@ -2571,6 +2614,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20240223170317'), ('20240226133022'), ('20240226134335'), -('20240227134845'); +('20240227134845'), +('20240227142019'); From c0b64fc3da31846c2e1e85c900d3b1d5e0323988 Mon Sep 17 00:00:00 2001 From: jazzari Date: Tue, 27 Feb 2024 14:08:48 -0300 Subject: [PATCH 208/472] fix: corregido enlace a listas de bloqueo en compo block_list --- app/views/components/_block_list.haml | 4 ++-- app/views/moderation_queue/_block_instances_textarea.haml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/components/_block_list.haml b/app/views/components/_block_list.haml index 0d07a340..5bc0e130 100644 --- a/app/views/components/_block_list.haml +++ b/app/views/components/_block_list.haml @@ -3,6 +3,6 @@ .card-body .d-flex.flex-row = render 'components/checkbox', id: blocklist['id'] do - -#%span.h4= blocklist["title"] - %h4.m-0 + %span.h4= blocklist["title"] + %p %a{ href: blocklist['link'] }= blocklist['title'] diff --git a/app/views/moderation_queue/_block_instances_textarea.haml b/app/views/moderation_queue/_block_instances_textarea.haml index a90704cc..9b388a0d 100644 --- a/app/views/moderation_queue/_block_instances_textarea.haml +++ b/app/views/moderation_queue/_block_instances_textarea.haml @@ -1,5 +1,5 @@ .form-group = label_tag "custom_blocklist", t('moderation_queue.instances.custom_block') = text_area_tag "custom_blocklist", nil, class: 'form-control' - %p - %a.mt-3{ role: 'button', href: '', class: 'btn btn-secondary' }= t('moderation_queue.instances.submit') + %button.btn.btn-secondary.mt-3{ type: 'submit' }= t('moderation_queue.instances.submit') + From ec328d31b9e988c85d0b2c58c04f76e8dccee0a5 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 27 Feb 2024 14:23:57 -0300 Subject: [PATCH 209/472] feat: cargar las fediblocks en la pantalla --- app/views/components/_block_list.haml | 6 +++--- app/views/components/_block_lists.haml | 4 ++-- app/views/moderation_queue/_instances.haml | 2 +- app/views/moderation_queue/index.haml | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/views/components/_block_list.haml b/app/views/components/_block_list.haml index 5bc0e130..c70b40f8 100644 --- a/app/views/components/_block_list.haml +++ b/app/views/components/_block_list.haml @@ -2,7 +2,7 @@ .card.mt-3.mb-3 .card-body .d-flex.flex-row - = render 'components/checkbox', id: blocklist['id'] do - %span.h4= blocklist["title"] + = render 'components/checkbox', id: state.id, checked: state.enabled? do + %span.h4= blocklist.title %p - %a{ href: blocklist['link'] }= blocklist['title'] + %a{ href: blocklist.url }= t('.more') diff --git a/app/views/components/_block_lists.haml b/app/views/components/_block_lists.haml index 1e9cd76f..b6dc0afa 100644 --- a/app/views/components/_block_lists.haml +++ b/app/views/components/_block_lists.haml @@ -1,2 +1,2 @@ -- @blocklists.each do |blocklist| - = render 'components/block_list', blocklist: blocklist +- blocklists.each do |blocklist| + = render 'components/block_list', blocklist: blocklist.fediblock, state: blocklist diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index 6303d07c..a08c8b10 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -19,5 +19,5 @@ %div %h3.mt-5= t('moderation_queue.instances.title') %lead= t('moderation_queue.instances.description') - = render 'components/block_lists', blocklists: @blocklists + = render 'components/block_lists', blocklists: fediblock_states = render 'moderation_queue/block_instances_textarea' diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml index 0c937758..0fb1c968 100644 --- a/app/views/moderation_queue/index.haml +++ b/app/views/moderation_queue/index.haml @@ -5,7 +5,7 @@ .col - summary = t('.instances') = render 'layouts/details', summary: summary do - = render 'moderation_queue/instances', site: @site, instance_moderations: @instance_moderations + = render 'moderation_queue/instances', site: @site, instance_moderations: @instance_moderations, fediblock_states: @site.fediblock_states %hr - summary = t('.accounts') = render 'layouts/details', summary: summary do From cda5fc1215c1613465047fe73fb3866244fff1d3 Mon Sep 17 00:00:00 2001 From: jazzari Date: Tue, 27 Feb 2024 14:37:07 -0300 Subject: [PATCH 210/472] fix: corregido enlace en block_list y texto en es.yml --- app/views/components/_block_list.haml | 3 ++- config/locales/es.yml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/views/components/_block_list.haml b/app/views/components/_block_list.haml index 5bc0e130..0c7a7b04 100644 --- a/app/views/components/_block_list.haml +++ b/app/views/components/_block_list.haml @@ -4,5 +4,6 @@ .d-flex.flex-row = render 'components/checkbox', id: blocklist['id'] do %span.h4= blocklist["title"] - %p + + %p.mb-0 %a{ href: blocklist['link'] }= blocklist['title'] diff --git a/config/locales/es.yml b/config/locales/es.yml index e39b13c2..7a2bfd85 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -122,7 +122,7 @@ es: title: Mis listas de bloqueo description: Descripción de listas de bloqueo custom_block: Lista personalizada de bloqueo - submit: Guardar lista de bloqueo + submit: Guardar listas de bloqueo instance: users: "Usuaries:" dark: Oscuro From 0dba9e550040f1cfb53778ee9f4f1de5c7aed406 Mon Sep 17 00:00:00 2001 From: jazzari Date: Tue, 27 Feb 2024 15:05:16 -0300 Subject: [PATCH 211/472] =?UTF-8?q?fix:=20corregida=20alineaci=C3=B3n=20de?= =?UTF-8?q?=20checkbox=20general=20en=20details=20comentarios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_comment.haml | 44 +++++++++++------------ app/views/moderation_queue/_comments.haml | 2 +- app/views/posts/_moderation_queue.haml | 1 + 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 4836f03d..afd2a335 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -1,27 +1,27 @@ -# Componente Comentario -.flex.mx-4.my-4 - .row.no-gutters - .col-1 - = render 'components/checkbox', id: comment['id'] - .col-11 - .row.no-gutters - .col.col-lg-10.d-inline-flex.justify-content-between - %h4 - %a{ href: comment['attributedTo'] }= profile['preferredUsername'] - = render 'layouts/time', time: comment['published'] - - if comment['inReplyTo'] - .row.no-gutters - .col.p-0 - %p - %span= t('.reply_to') - %span - %a{ href: comment['inReplyTo'] }= comment['inReplyTo'] + +.row.no-gutters + .col-1 + = render 'components/checkbox', id: comment['id'] + .col-11 + .row.no-gutters + .col.col-lg-10.d-inline-flex.justify-content-between + %h4 + %a{ href: comment['attributedTo'] }= profile['preferredUsername'] + = render 'layouts/time', time: comment['published'] + - if comment['inReplyTo'] .row.no-gutters .col.p-0 - - if comment['summary'] - - summary = comment['summary'] - = render 'layouts/details', summary: summary do - %p= comment['content'].html_safe - - else + %p + %span= t('.reply_to') + %span + %a{ href: comment['inReplyTo'] }= comment['inReplyTo'] + .row.no-gutters + .col.p-0 + - if comment['summary'] + - summary = comment['summary'] + = render 'layouts/details', summary: summary do %p= comment['content'].html_safe + - else + %p= comment['content'].html_safe diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index 6fa8c0f4..eadfd78b 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -1,7 +1,7 @@ .row.no-gutters.pt-2 .col-1.d-flex.align-items-center = render 'components/checkbox', id: moderation_queue.first['id'] - .col-11 + .col-md-9 -# Filtros = render 'components/comments_filters' diff --git a/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml index 2ec6a07d..a72e8abd 100644 --- a/app/views/posts/_moderation_queue.haml +++ b/app/views/posts/_moderation_queue.haml @@ -6,6 +6,7 @@ = render 'components/comments_filters' - moderation_queue.each do |comment| + %hr = render 'moderation_queue/comment', comment: comment, profile: comment['attributedTo'] -# Botones moderación From bbbbad18a073e5931adad4b256599840297977d1 Mon Sep 17 00:00:00 2001 From: jazzari Date: Tue, 27 Feb 2024 15:21:31 -0300 Subject: [PATCH 212/472] fix: corregido margen en summary de compo details --- app/views/layouts/_details.haml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/views/layouts/_details.haml b/app/views/layouts/_details.haml index dd6ac5cf..99ba4894 100644 --- a/app/views/layouts/_details.haml +++ b/app/views/layouts/_details.haml @@ -2,6 +2,7 @@ %details.details.py-2 %summary - .col-11 - %h3.py-2= summary + .row + .col-11.pr-2 + %h3.py-2= summary = yield From e239bd8b85fd6dad2e7fe4fcec72c46beb323b7a Mon Sep 17 00:00:00 2001 From: jazzari Date: Tue, 27 Feb 2024 15:25:25 -0300 Subject: [PATCH 213/472] fix: corregido usuarios en compo instance --- app/views/moderation_queue/_instance.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/moderation_queue/_instance.haml b/app/views/moderation_queue/_instance.haml index 3bfbde44..ec887d2d 100644 --- a/app/views/moderation_queue/_instance.haml +++ b/app/views/moderation_queue/_instance.haml @@ -9,8 +9,8 @@ %h4 %a{ href: hosthttps }= instance['title'] %p= instance['description'].html_safe - %dl - %dt= t('.users') + %dl.d-inline-flex + %dt.pr-2= t('.users') %dd = instance.dig('usage', 'users', 'active_month') = instance.dig('stats', 'user_count') From d4fa056db4d652070a829b16b79cea92f3e5c426 Mon Sep 17 00:00:00 2001 From: jazzari Date: Tue, 27 Feb 2024 16:08:11 -0300 Subject: [PATCH 214/472] fix: corregido summary en compo details --- app/views/layouts/_details.haml | 4 +--- app/views/moderation_queue/_remote_profile.haml | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/views/layouts/_details.haml b/app/views/layouts/_details.haml index 99ba4894..a40d0403 100644 --- a/app/views/layouts/_details.haml +++ b/app/views/layouts/_details.haml @@ -2,7 +2,5 @@ %details.details.py-2 %summary - .row - .col-11.pr-2 - %h3.py-2= summary + %h3.py-2.pr-2= summary = yield diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml index 92cf8e96..263f9c6b 100644 --- a/app/views/moderation_queue/_remote_profile.haml +++ b/app/views/moderation_queue/_remote_profile.haml @@ -16,8 +16,7 @@ %dd = render 'layouts/time', time: remote_profile['published'] %dt= t('.profile_summary') - %dd - %p= remote_profile['summary'].html_safe + %dd= remote_profile['summary'].html_safe = render 'moderation_queue/comments', moderation_queue: @moderation_queue From 4bc11c700755d211967ef1b71e5e6828fc0f9e94 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 27 Feb 2024 16:39:02 -0300 Subject: [PATCH 215/472] feat: gestionar listas de bloqueo desde el panel --- .../fediblock_states_controller.rb | 40 +++++++++++++++++++ .../activity_pub/instance_moderation_job.rb | 29 ++++++++++++++ app/models/site/social_distributed_press.rb | 1 + app/views/components/_block_list.haml | 14 ++++--- .../_block_instances_textarea.haml | 6 +-- app/views/moderation_queue/_instances.haml | 9 ++++- config/locales/en.yml | 2 + config/locales/es.yml | 2 + config/routes.rb | 1 + 9 files changed, 93 insertions(+), 11 deletions(-) create mode 100644 app/controllers/fediblock_states_controller.rb create mode 100644 app/jobs/activity_pub/instance_moderation_job.rb diff --git a/app/controllers/fediblock_states_controller.rb b/app/controllers/fediblock_states_controller.rb new file mode 100644 index 00000000..c116b75a --- /dev/null +++ b/app/controllers/fediblock_states_controller.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +# Estado de las listas de bloqueo en cada sitio +class FediblockStatesController < ApplicationController + # Realiza cambios en las listas de bloqueo + def action_on_several + if fediblock_states_ids.present? + # Encontrar todas y deshabilitar las que no se enviaron + site.fediblock_states.all.find_each do |fediblock_state| + if fediblock_states_ids.include? fediblock_state.id + fediblock_state.enable! if fediblock_state.may_enable? + elsif fediblock_state.may_disable? + fediblock_state.disable! + end + end + end + + # Bloquear otras instancias + if custom_blocklist.present? + ActivityPub::InstanceModerationJob.perform_later(site: site, hostnames: custom_blocklist) + end + + redirect_to site_moderation_queue_path + end + + private + + def fediblock_states_ids + params[:fediblock_states_ids] || [] + end + + # La lista de hostnames + def custom_blocklist + @custom_blocklist ||= fediblocks_states_params[:custom_blocklist].split("\n").map(&:strip).select(&:present?) + end + + def fediblocks_states_params + @fediblocks_states_params ||= params.permit(:custom_blocklist, fediblock_states_ids: []) + end +end diff --git a/app/jobs/activity_pub/instance_moderation_job.rb b/app/jobs/activity_pub/instance_moderation_job.rb new file mode 100644 index 00000000..a9b0bea0 --- /dev/null +++ b/app/jobs/activity_pub/instance_moderation_job.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +class ActivityPub + # Bloquea varias instancias de una sola vez + class InstanceModerationJob < ApplicationJob + # @param :site [Site] + # @param :hostnames [Array] + def perform(site:, hostnames:) + # Crear las instancias que no existan todavía + hostnames.each do |hostname| + ActivityPub::Instance.find_or_create_by(hostname: hostname) + end + + instances = ActivityPub::Instance.where(hostname: hostnames) + + Site.transaction do + # Crea todas las moderaciones de instancia con un estado por + # defecto si no existen + 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? + end + end + end + end + end +end diff --git a/app/models/site/social_distributed_press.rb b/app/models/site/social_distributed_press.rb index e0d2d4f4..fdb37bca 100644 --- a/app/models/site/social_distributed_press.rb +++ b/app/models/site/social_distributed_press.rb @@ -13,6 +13,7 @@ class Site has_many :activity_pubs has_many :instance_moderations has_many :fediblock_states + has_many :instances, through: :instance_moderations before_save :generate_private_key_pem!, unless: :private_key_pem? diff --git a/app/views/components/_block_list.haml b/app/views/components/_block_list.haml index f972642a..79481363 100644 --- a/app/views/components/_block_list.haml +++ b/app/views/components/_block_list.haml @@ -1,8 +1,12 @@ -# Componente Listas de bloqueo de Instancias +- know_more = t('.know_more') .card.mt-3.mb-3 .card-body - .d-flex.flex-row - = render 'components/checkbox', id: state.id, checked: state.enabled? do - %span.h4= blocklist.title - %p.mb-0 - %a{ href: blocklist.url }= t('.more') + = render 'components/checkbox', id: state.id, name: 'fediblock_states_ids[]', value: state.id, checked: state.enabled? do + %span.h4.mb-0= blocklist.title + + %dl.mb-0 + %dt.d-inline= t('.instances_blocked') + %dd.d-inline.font-weight-normal= blocklist.instances.count + %p.mb-0.font-weight-normal + %a{ href: blocklist.url }= know_more diff --git a/app/views/moderation_queue/_block_instances_textarea.haml b/app/views/moderation_queue/_block_instances_textarea.haml index 9b388a0d..9729d4de 100644 --- a/app/views/moderation_queue/_block_instances_textarea.haml +++ b/app/views/moderation_queue/_block_instances_textarea.haml @@ -1,5 +1,3 @@ .form-group - = label_tag "custom_blocklist", t('moderation_queue.instances.custom_block') - = text_area_tag "custom_blocklist", nil, class: 'form-control' - %button.btn.btn-secondary.mt-3{ type: 'submit' }= t('moderation_queue.instances.submit') - + = label_tag 'custom_blocklist', t('moderation_queue.instances.custom_block') + = text_area_tag 'custom_blocklist', nil, class: 'form-control' diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index a08c8b10..d2ebb5a7 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -19,5 +19,10 @@ %div %h3.mt-5= t('moderation_queue.instances.title') %lead= t('moderation_queue.instances.description') - = render 'components/block_lists', blocklists: fediblock_states - = render 'moderation_queue/block_instances_textarea' + + = form_tag site_fediblock_states_action_on_several_path, method: :patch do + = render 'components/block_lists', blocklists: fediblock_states + = render 'moderation_queue/block_instances_textarea' + + .form-group + %button.btn.btn-secondary.mt-3{ type: 'submit' }= t('moderation_queue.instances.submit') diff --git a/config/locales/en.yml b/config/locales/en.yml index 9581285f..717c9ece 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -50,6 +50,8 @@ en: pm: pm format: '%-I:%M %p' components: + block_list: + know_more: Know more instances_filters: text_show: Show text_checked: With selected diff --git a/config/locales/es.yml b/config/locales/es.yml index 9b1f1937..87111523 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -50,6 +50,8 @@ es: pm: pm format: '%-H:%M' components: + block_list: + know_more: Saber más (en inglés) instances_filters: text_show: Ver text_checked: Con los marcados diff --git a/config/routes.rb b/config/routes.rb index d9e2aca7..d70f8339 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -69,6 +69,7 @@ Rails.application.routes.draw do end patch :instance_moderations_action_on_several, to: 'instance_moderations#action_on_several' + patch :fediblock_states_action_on_several, to: 'fediblock_states#action_on_several' # Gestionar artículos según idioma nested do From d5f48c60073e8245e1f1cf1cbd8c558da60cdcfc Mon Sep 17 00:00:00 2001 From: f Date: Tue, 27 Feb 2024 16:40:08 -0300 Subject: [PATCH 216/472] feat: al actualizar las blocklists, bloquear las instancias en los sitios que las tengan habilitadas --- app/jobs/activity_pub/fediblock_fetch_job.rb | 11 ++++++++- .../activity_pub/fediblock_updated_job.rb | 24 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 app/jobs/activity_pub/fediblock_updated_job.rb diff --git a/app/jobs/activity_pub/fediblock_fetch_job.rb b/app/jobs/activity_pub/fediblock_fetch_job.rb index d6cb4b83..6730cbf0 100644 --- a/app/jobs/activity_pub/fediblock_fetch_job.rb +++ b/app/jobs/activity_pub/fediblock_fetch_job.rb @@ -1,11 +1,20 @@ # frozen_string_literal: true class ActivityPub - # Se encarga de mantener las listas de bloqueo actualizadas + # Se encarga de mantener las listas de bloqueo actualizadas. Luego de + # actualizar el listado de instancias, bloquea las instancias en cada + # sitio que tenga el fediblock habilitado. class FediblockFetchJob < ApplicationJob def perform ActivityPub::Fediblock.find_each do |fediblock| fediblock.process! + + instances_added = fediblock.instances - fediblock.instances_was + + # No hacer nada si no cambió con respecto a la versión anterior + next if instances_added.empty? + + ActivityPub::FediblockUpdatedJob.perform_later(fediblock: fediblock, hostnames: instances_added) rescue ActivityPub::Fediblock::FediblockDownloadError => e ExceptionNotifier.notify_exception(e, data: { fediblock: fediblock.title }) end diff --git a/app/jobs/activity_pub/fediblock_updated_job.rb b/app/jobs/activity_pub/fediblock_updated_job.rb new file mode 100644 index 00000000..007fa25e --- /dev/null +++ b/app/jobs/activity_pub/fediblock_updated_job.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +# Se encarga de mantener sincronizadas las listas de instancias +# de los fediblocks con los sitios que las tengan activadas. +class ActivityPub + class FediblockUpdatedJob < ApplicationJob + # @param :fediblock [ActivityPub::Fediblock] + # @param :instances [Array] + def perform(fediblock:, hostnames:) + instances = ActivityPub::Instance.where(hostname: instances) + + # Todos los sitios con la Social Inbox habilitada + Site.where(id: DeploySocialDistributedPress.pluck(:site_id)).find_each do |site| + # Crea el estado si no existía + fediblock_state = site.fediblock_states.find_or_create_by(fediblock: fediblock) + + # No hace nada con los deshabilitados + next unless fediblock_state.enabled? + + ActivityPub::InstanceModerationJob.perform_later(site: site, hostnames: instances) + end + end + end +end From 34ead9ea4a40957e4f6251c691dcc5d53e258488 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 27 Feb 2024 16:53:48 -0300 Subject: [PATCH 217/472] feat: establecer prioridades para las tareas --- app/jobs/activity_pub/actor_fetch_job.rb | 2 ++ app/jobs/activity_pub/fediblock_fetch_job.rb | 2 ++ app/jobs/activity_pub/fediblock_updated_job.rb | 2 ++ app/jobs/activity_pub/fetch_job.rb | 2 ++ app/jobs/activity_pub/instance_fetch_job.rb | 2 ++ app/jobs/activity_pub/instance_moderation_job.rb | 2 ++ 6 files changed, 12 insertions(+) diff --git a/app/jobs/activity_pub/actor_fetch_job.rb b/app/jobs/activity_pub/actor_fetch_job.rb index 1c6f1735..71107151 100644 --- a/app/jobs/activity_pub/actor_fetch_job.rb +++ b/app/jobs/activity_pub/actor_fetch_job.rb @@ -9,6 +9,8 @@ # autenticación. class ActivityPub class ActorFetchJob < ApplicationJob + self.priority = 50 + def perform(site:, actor:) ActivityPub::Actor.transaction do response = site.social_inbox.dereferencer.get(uri: actor.uri) diff --git a/app/jobs/activity_pub/fediblock_fetch_job.rb b/app/jobs/activity_pub/fediblock_fetch_job.rb index 6730cbf0..aa748bc6 100644 --- a/app/jobs/activity_pub/fediblock_fetch_job.rb +++ b/app/jobs/activity_pub/fediblock_fetch_job.rb @@ -5,6 +5,8 @@ class ActivityPub # actualizar el listado de instancias, bloquea las instancias en cada # sitio que tenga el fediblock habilitado. class FediblockFetchJob < ApplicationJob + self.priority = 50 + def perform ActivityPub::Fediblock.find_each do |fediblock| fediblock.process! diff --git a/app/jobs/activity_pub/fediblock_updated_job.rb b/app/jobs/activity_pub/fediblock_updated_job.rb index 007fa25e..b4a56609 100644 --- a/app/jobs/activity_pub/fediblock_updated_job.rb +++ b/app/jobs/activity_pub/fediblock_updated_job.rb @@ -4,6 +4,8 @@ # de los fediblocks con los sitios que las tengan activadas. class ActivityPub class FediblockUpdatedJob < ApplicationJob + self.priority = 50 + # @param :fediblock [ActivityPub::Fediblock] # @param :instances [Array] def perform(fediblock:, hostnames:) diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index b6c45026..e3fef993 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -9,6 +9,8 @@ # autenticación. class ActivityPub class FetchJob < ApplicationJob + self.priority = 50 + def perform(site:, object:) ActivityPub::Object.transaction do return if object.activity_pubs.where(aasm_state: 'removed').count.positive? diff --git a/app/jobs/activity_pub/instance_fetch_job.rb b/app/jobs/activity_pub/instance_fetch_job.rb index a5c07162..0ceb1a8a 100644 --- a/app/jobs/activity_pub/instance_fetch_job.rb +++ b/app/jobs/activity_pub/instance_fetch_job.rb @@ -3,6 +3,8 @@ class ActivityPub # Obtiene o actualiza los datos de una instancia. class InstanceFetchJob < ApplicationJob + self.priority = 100 + def perform(site:, instance:) %w[/api/v2/instance /api/v1/instance].each do |api| uri = SocialInbox.generate_uri(instance.hostname) do |u| diff --git a/app/jobs/activity_pub/instance_moderation_job.rb b/app/jobs/activity_pub/instance_moderation_job.rb index a9b0bea0..b205e68f 100644 --- a/app/jobs/activity_pub/instance_moderation_job.rb +++ b/app/jobs/activity_pub/instance_moderation_job.rb @@ -3,6 +3,8 @@ class ActivityPub # Bloquea varias instancias de una sola vez class InstanceModerationJob < ApplicationJob + self.priority = 50 + # @param :site [Site] # @param :hostnames [Array] def perform(site:, hostnames:) From 342521c897d77243e63fcbb565651eba7ae0f80d Mon Sep 17 00:00:00 2001 From: f Date: Tue, 27 Feb 2024 16:54:09 -0300 Subject: [PATCH 218/472] fix: guardar los datos de la instancia --- app/jobs/activity_pub/instance_fetch_job.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/jobs/activity_pub/instance_fetch_job.rb b/app/jobs/activity_pub/instance_fetch_job.rb index 0ceb1a8a..ce202092 100644 --- a/app/jobs/activity_pub/instance_fetch_job.rb +++ b/app/jobs/activity_pub/instance_fetch_job.rb @@ -1,7 +1,9 @@ # frozen_string_literal: true class ActivityPub - # Obtiene o actualiza los datos de una instancia. + # Obtiene o actualiza los datos de una instancia. Usamos un cliente + # de ActivityPub porque la instancia podría estar en federación + # limitada. class InstanceFetchJob < ApplicationJob self.priority = 100 @@ -14,8 +16,10 @@ class ActivityPub response = site.social_inbox.dereferencer.get(uri: uri) next unless response.ok? + # @todo Validate schema + next unless response.parsed_response.is_a?(DistributedPress::V1::Social::ReferencedObject) - instance.update(content: response.parsed_response) + instance.update(content: response.parsed_response.object) break end From aae04f3739c1cd07a4518922d8ff2cbac66180ac Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 11:54:41 -0300 Subject: [PATCH 219/472] feat: al activar el fediverso, activar las listas de bloqueo --- app/models/deploy_social_distributed_press.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/models/deploy_social_distributed_press.rb b/app/models/deploy_social_distributed_press.rb index 7f761e46..9f968f36 100644 --- a/app/models/deploy_social_distributed_press.rb +++ b/app/models/deploy_social_distributed_press.rb @@ -8,6 +8,7 @@ class DeploySocialDistributedPress < Deploy DEPENDENCIES = %i[deploy_distributed_press deploy_rsync deploy_full_rsync].freeze after_save :create_hooks! + after_create :enable_fediblocks! # Envía las notificaciones def deploy(output: false) @@ -95,4 +96,16 @@ class DeploySocialDistributedPress < Deploy ExceptionNotifier.notify_exception(e, data: { site_id: site.name, usuarie_id: rol.usuarie_id }) end end + + # Habilita todos los fediblocks disponibles. + # + # @todo Hacer que algunos sean opcionales + # @todo Mover a un Job + def enable_fediblocks! + ActivityPub::Fediblock.find_each do |fediblock| + site.fediblock_states.find_or_create_by(fediblock: fediblock).tap do |state| + state.enable! if state.may_enable? + end + end + end end From dc82b8cef2ee014898128a8916b75c5358d9646d Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 12:05:09 -0300 Subject: [PATCH 220/472] feat: asignar rol a deploys al crear o modificar el sitio --- app/services/site_service.rb | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 5c37cfe3..a3649bc5 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -26,6 +26,8 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # que no haya estados intermedios. site.locales = [usuarie.lang] + I18n.available_locales + add_role_to_deploys! + site.save && site.config.write && commit_config(action: :create) && @@ -43,7 +45,10 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # Actualiza el sitio y guarda los cambios en la configuración def update I18n.with_locale(usuarie&.lang&.to_sym || I18n.default_locale) do - site.update(params) && + site.assign_attributes(params) + add_role_to_deploys! + + site.save && site.config.write && commit_config(action: :update) && site.reset.nil? && @@ -224,6 +229,17 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do private + # Asignar un rol a cada deploy si no lo tenía ya + def add_role_to_deploys! + site.deploys.each do |deploy| + deploy.rol ||= current_role + end + end + + def current_role + @current_role ||= usuarie.rol_for_site(site) + end + def with_all_locales(&block) site.locales.map do |locale| next unless I18n.available_locales.include? locale From d5cf0fffe09183cf9aea111bfaff60d6e7d6bfcb Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 12:09:16 -0300 Subject: [PATCH 221/472] feat: no mostrar comentarios a invitades --- app/views/posts/edit.haml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/views/posts/edit.haml b/app/views/posts/edit.haml index 2e46590e..e7e0260d 100644 --- a/app/views/posts/edit.haml +++ b/app/views/posts/edit.haml @@ -1,8 +1,9 @@ .row.justify-content-center .col-md-8 - - summary = t('posts.edit.post') - = render 'layouts/details', summary: summary do + - if policy(@site).edit? + = render 'layouts/details', summary: t('posts.edit.post') do + = render 'posts/form', site: @site, post: @post + = render 'layouts/details', summary: t('posts.edit.moderation_queue') do + = render 'posts/moderation_queue', site: @site, post: @post, moderation_queue: @moderation_queue + - else = render 'posts/form', site: @site, post: @post - - summary = t('posts.edit.moderation_queue') - = render 'layouts/details', summary: summary do - = render 'posts/moderation_queue', site: @site, post: @post, moderation_queue: @moderation_queue From f1de4c80735b106fe4b7951ece4367bb20522bac Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 12:32:59 -0300 Subject: [PATCH 222/472] fix: ignorar instancias que ya no existen --- app/jobs/activity_pub/instance_fetch_job.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/jobs/activity_pub/instance_fetch_job.rb b/app/jobs/activity_pub/instance_fetch_job.rb index ce202092..9c562f7d 100644 --- a/app/jobs/activity_pub/instance_fetch_job.rb +++ b/app/jobs/activity_pub/instance_fetch_job.rb @@ -21,6 +21,16 @@ class ActivityPub instance.update(content: response.parsed_response.object) + break + rescue BRS::BaseError, + Errno::ECONNREFUSED, + HTTParty::Error, + JSON::JSONError, + Net::OpenTimeout, + OpenSSL::OpenSSLError, + SocketError, + Errno::ENETUNREACH => e + ExceptionNotifier.notify_exception(e, data: { instance: uri }) break end end From ee10e170ec6b8c6f939173ee647f874d4770bc3b Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 15:01:36 -0300 Subject: [PATCH 223/472] =?UTF-8?q?fix:=20el=20rol=20todav=C3=ADa=20no=20e?= =?UTF-8?q?st=C3=A1=20guardado?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/services/site_service.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index a3649bc5..6b57fc8b 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -13,7 +13,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do def create self.site = Site.new params - add_role temporal: false, rol: 'usuarie' + role = add_role temporal: false, rol: 'usuarie' site.deploys.build type: 'DeployLocal' # Los sitios de testing no se sincronizan sync_nodes unless site.name.end_with? '.testing' @@ -26,7 +26,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # que no haya estados intermedios. site.locales = [usuarie.lang] + I18n.available_locales - add_role_to_deploys! + add_role_to_deploys! role site.save && site.config.write && @@ -230,9 +230,9 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do private # Asignar un rol a cada deploy si no lo tenía ya - def add_role_to_deploys! + def add_role_to_deploys!(role = current_role) site.deploys.each do |deploy| - deploy.rol ||= current_role + deploy.rol ||= role end end From 670d6063e56922b3a8f8debdbd45fd823c34e38a Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 15:04:52 -0300 Subject: [PATCH 224/472] fix: generar un rol dentro del sitio --- app/services/site_service.rb | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 6b57fc8b..dabce349 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -13,7 +13,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do def create self.site = Site.new params - role = add_role temporal: false, rol: 'usuarie' + role = site.roles.build(usuarie: usuarie, temporal: false, rol: 'usuarie') site.deploys.build type: 'DeployLocal' # Los sitios de testing no se sincronizan sync_nodes unless site.name.end_with? '.testing' @@ -106,11 +106,6 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do GitPushJob.perform_later(site) end - def add_role(temporal: true, rol: 'invitade') - site.roles << Rol.new(site: site, usuarie: usuarie, - temporal: temporal, rol: rol) - end - # Crea la licencia del sitio para cada locale disponible en el sitio # # @return [Boolean] From 7521f598a64df25daac30501029d21171d48f7b1 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 15:45:58 -0300 Subject: [PATCH 225/472] fix: poder deseleccionar todos los fediblocks --- app/controllers/fediblock_states_controller.rb | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/app/controllers/fediblock_states_controller.rb b/app/controllers/fediblock_states_controller.rb index c116b75a..6d9737c3 100644 --- a/app/controllers/fediblock_states_controller.rb +++ b/app/controllers/fediblock_states_controller.rb @@ -4,14 +4,12 @@ class FediblockStatesController < ApplicationController # Realiza cambios en las listas de bloqueo def action_on_several - if fediblock_states_ids.present? - # Encontrar todas y deshabilitar las que no se enviaron - site.fediblock_states.all.find_each do |fediblock_state| - if fediblock_states_ids.include? fediblock_state.id - fediblock_state.enable! if fediblock_state.may_enable? - elsif fediblock_state.may_disable? - fediblock_state.disable! - end + # Encontrar todas y deshabilitar las que no se enviaron + site.fediblock_states.all.find_each do |fediblock_state| + if fediblock_states_ids.include? fediblock_state.id + fediblock_state.enable! if fediblock_state.may_enable? + elsif fediblock_state.may_disable? + fediblock_state.disable! end end From 15800e1096f01707def8a9c845407b38a9e8d545 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 15:47:40 -0300 Subject: [PATCH 226/472] BREAKING CHANGE: renombrar instancias por hostnames --- app/jobs/activity_pub/fediblock_fetch_job.rb | 6 +++--- app/jobs/activity_pub/fediblock_updated_job.rb | 9 ++++++--- app/models/activity_pub/fediblock.rb | 7 ++++++- app/views/components/_block_list.haml | 2 +- ...0228171335_rename_fediblock_instances_to_hostnames.rb | 9 +++++++++ db/structure.sql | 5 +++-- 6 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 db/migrate/20240228171335_rename_fediblock_instances_to_hostnames.rb diff --git a/app/jobs/activity_pub/fediblock_fetch_job.rb b/app/jobs/activity_pub/fediblock_fetch_job.rb index aa748bc6..3d12f4cd 100644 --- a/app/jobs/activity_pub/fediblock_fetch_job.rb +++ b/app/jobs/activity_pub/fediblock_fetch_job.rb @@ -11,12 +11,12 @@ class ActivityPub ActivityPub::Fediblock.find_each do |fediblock| fediblock.process! - instances_added = fediblock.instances - fediblock.instances_was + hostnames_added = fediblock.hostnames - fediblock.hostnames_was # No hacer nada si no cambió con respecto a la versión anterior - next if instances_added.empty? + next if hostnames_added.empty? - ActivityPub::FediblockUpdatedJob.perform_later(fediblock: fediblock, hostnames: instances_added) + ActivityPub::FediblockUpdatedJob.perform_later(fediblock: fediblock, hostnames: hostnames_added) rescue ActivityPub::Fediblock::FediblockDownloadError => e ExceptionNotifier.notify_exception(e, data: { fediblock: fediblock.title }) end diff --git a/app/jobs/activity_pub/fediblock_updated_job.rb b/app/jobs/activity_pub/fediblock_updated_job.rb index b4a56609..1bb47517 100644 --- a/app/jobs/activity_pub/fediblock_updated_job.rb +++ b/app/jobs/activity_pub/fediblock_updated_job.rb @@ -2,14 +2,17 @@ # Se encarga de mantener sincronizadas las listas de instancias # de los fediblocks con los sitios que las tengan activadas. +# +# También va a asociar las listas con todos los sitios que tengan la +# Social Inbox habilitada. class ActivityPub class FediblockUpdatedJob < ApplicationJob self.priority = 50 # @param :fediblock [ActivityPub::Fediblock] - # @param :instances [Array] + # @param :hostnames [Array] def perform(fediblock:, hostnames:) - instances = ActivityPub::Instance.where(hostname: instances) + instances = ActivityPub::Instance.where(hostname: hostnames) # Todos los sitios con la Social Inbox habilitada Site.where(id: DeploySocialDistributedPress.pluck(:site_id)).find_each do |site| @@ -19,7 +22,7 @@ class ActivityPub # No hace nada con los deshabilitados next unless fediblock_state.enabled? - ActivityPub::InstanceModerationJob.perform_later(site: site, hostnames: instances) + ActivityPub::InstanceModerationJob.perform_later(site: site, hostnames: hostnames) end end end diff --git a/app/models/activity_pub/fediblock.rb b/app/models/activity_pub/fediblock.rb index 8d024f56..4abcb80f 100644 --- a/app/models/activity_pub/fediblock.rb +++ b/app/models/activity_pub/fediblock.rb @@ -43,6 +43,11 @@ class ActivityPub @client ||= Client.new end + # Todas las instancias de este fediblock + def instances + ActivityPub::Instance.where(hostname: hostnames) + end + # Descarga la lista y crea las instancias con el estado necesario def process! response = client.get(download_url) @@ -53,7 +58,7 @@ class ActivityPub csv = response.parsed_response process_csv! csv - update(instances: csv.map { |r| r[hostname_header] }) + update(hostnames: csv.map { |r| r[hostname_header] }) end end diff --git a/app/views/components/_block_list.haml b/app/views/components/_block_list.haml index 79481363..75825bb0 100644 --- a/app/views/components/_block_list.haml +++ b/app/views/components/_block_list.haml @@ -7,6 +7,6 @@ %dl.mb-0 %dt.d-inline= t('.instances_blocked') - %dd.d-inline.font-weight-normal= blocklist.instances.count + %dd.d-inline.font-weight-normal= blocklist.hostnames.count %p.mb-0.font-weight-normal %a{ href: blocklist.url }= know_more diff --git a/db/migrate/20240228171335_rename_fediblock_instances_to_hostnames.rb b/db/migrate/20240228171335_rename_fediblock_instances_to_hostnames.rb new file mode 100644 index 00000000..bad343f2 --- /dev/null +++ b/db/migrate/20240228171335_rename_fediblock_instances_to_hostnames.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +# Cambia el nombre de la columna para que podamos obtener todas las +# instancias de un fediblock +class RenameFediblockInstancesToHostnames < ActiveRecord::Migration[6.1] + def change + rename_column :activity_pub_fediblocks, :instances, :hostnames + end +end diff --git a/db/structure.sql b/db/structure.sql index ac897695..740f5d87 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -514,7 +514,7 @@ CREATE TABLE public.activity_pub_fediblocks ( url character varying NOT NULL, download_url character varying NOT NULL, format character varying NOT NULL, - instances jsonb DEFAULT '[]'::jsonb + hostnames jsonb DEFAULT '[]'::jsonb ); @@ -2615,6 +2615,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20240226133022'), ('20240226134335'), ('20240227134845'), -('20240227142019'); +('20240227142019'), +('20240228171335'); From 1ee41f2d5e9de7dc78f79c7afcb574ff2fa79648 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 16:04:37 -0300 Subject: [PATCH 227/472] feat: al activar o desactivar un fediblock, vincular con todas las instancias --- app/models/fediblock_state.rb | 28 +++++++++++++++++++++------- app/models/instance_moderation.rb | 15 +++++++++++++++ 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/app/models/fediblock_state.rb b/app/models/fediblock_state.rb index 8045e23e..13e31cb2 100644 --- a/app/models/fediblock_state.rb +++ b/app/models/fediblock_state.rb @@ -1,6 +1,12 @@ # frozen_string_literal: true -# Relación entre Fediblocks y Sites +# Relación entre Fediblocks y Sites. +# +# Cuando se habilita un Fediblock, tenemos que asociar todas sus +# instancias con el sitio y bloquearlas. Cuando se deshabilita, la +# relación ya está creada y se va actualizando. +# +# @see ActivityPub::FediblockUpdatedJob class FediblockState < ApplicationRecord include AASM @@ -22,6 +28,15 @@ class FediblockState < ApplicationRecord before do enable_remotely! + + # Al actualizar el estado en masa garantizamos que las + # instancias que ya existen queden sincronizadas con el bloqueo + # en masa que acabamos de hacer. + instance_moderations.block_all! + + # Luego esta tarea crea las que falten e ignora las que ya se + # bloquearon. + ActivityPub::InstanceModerationJob.perform_later(site: site, hostnames: fediblock.hostnames) end end @@ -35,18 +50,17 @@ class FediblockState < ApplicationRecord before do disable_remotely! + + instance_moderations.pause_all! end end end private - # Obtiene todos los IDs de instancias para poder obtener el estado de - # moderación en el sitio. - # - # @return [Array] - def instance_ids - ActivityPub::Instance.where(hostname: fediblock.instances).pluck(:id) + # Todas las instancias de moderación de este sitio + def instance_moderations + site.instance_moderations.where(instance_id: fediblock.instances.pluck(:id)) end # @return [Array] diff --git a/app/models/instance_moderation.rb b/app/models/instance_moderation.rb index 735ec387..d9f74527 100644 --- a/app/models/instance_moderation.rb +++ b/app/models/instance_moderation.rb @@ -7,6 +7,21 @@ class InstanceModeration < ApplicationRecord 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 From 43d190ba7426ee8cf85e88a6a88b8fd2cebc94b4 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 16:13:51 -0300 Subject: [PATCH 228/472] feat: mostrar la cantidad de instancias --- app/models/instance_moderation.rb | 3 +++ app/views/components/_instances_filters.haml | 2 +- app/views/components/_instances_show_submenu.haml | 6 +++--- app/views/moderation_queue/_instances.haml | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/models/instance_moderation.rb b/app/models/instance_moderation.rb index d9f74527..10b5e8e0 100644 --- a/app/models/instance_moderation.rb +++ b/app/models/instance_moderation.rb @@ -11,6 +11,9 @@ class InstanceModeration < ApplicationRecord # todas las que no estén bloqueadas ya. scope :may_block, -> { where.not(aasm_state: 'blocked') } scope :may_pause, -> { where.not(aasm_state: 'paused') } + scope :paused, -> { where(aasm_state: 'paused') } + scope :blocked, -> { where(aasm_state: 'blocked') } + scope :allowed, -> { where(aasm_state: 'allowed') } # Bloquear instancias en masa def self.block_all! diff --git a/app/views/components/_instances_filters.haml b/app/views/components/_instances_filters.haml index eac20d38..fe40ced3 100644 --- a/app/views/components/_instances_filters.haml +++ b/app/views/components/_instances_filters.haml @@ -3,4 +3,4 @@ = render 'components/instances_checked_submenu' = render 'components/dropdown', text: t('.text_show') do - = render 'components/instances_show_submenu' + = render 'components/instances_show_submenu', site: site diff --git a/app/views/components/_instances_show_submenu.haml b/app/views/components/_instances_show_submenu.haml index 56206735..811d65c7 100644 --- a/app/views/components/_instances_show_submenu.haml +++ b/app/views/components/_instances_show_submenu.haml @@ -1,3 +1,3 @@ -= render 'components/dropdown_item', text: t('.submenu_paused'), path: site_moderation_queue_path(state: 'paused') -= render 'components/dropdown_item', text: t('.submenu_allowed'), path: site_moderation_queue_path(state: 'allowed') -= render 'components/dropdown_item', text: t('.submenu_blocked'), path: site_moderation_queue_path(state: 'blocked') += render 'components/dropdown_item', text: t('.submenu_paused', count: site.instance_moderations.paused.count), path: site_moderation_queue_path(state: 'paused') += render 'components/dropdown_item', text: t('.submenu_allowed', count: site.instance_moderations.allowed.count), path: site_moderation_queue_path(state: 'allowed') += render 'components/dropdown_item', text: t('.submenu_blocked', count: site.instance_moderations.blocked.count), path: site_moderation_queue_path(state: 'blocked') diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index d2ebb5a7..65f4350a 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -5,7 +5,7 @@ = render 'components/select_all', id: 'instances' .col-11 -# Filtros - = render 'components/instances_filters' + = render 'components/instances_filters', site: site .col-12 - if instance_moderations.count.zero? From 259d1c1e90d86d12c86aedf5aefdeb3bdad1cbbc Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 16:23:18 -0300 Subject: [PATCH 229/472] =?UTF-8?q?feat:=20optimizar=20acceso=20a=20inform?= =?UTF-8?q?aci=C3=B3n=20y=20ordenar=20por=20hostname?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/processors/instance_moderation_processor.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/processors/instance_moderation_processor.rb b/app/processors/instance_moderation_processor.rb index 414901d6..908beaf7 100644 --- a/app/processors/instance_moderation_processor.rb +++ b/app/processors/instance_moderation_processor.rb @@ -2,6 +2,10 @@ # Gestiona los filtros de InstanceModeration class InstanceModerationProcessor < Rubanok::Processor + prepare do + raw.includes(:instance).order('activity_pub_instances.hostname') + end + map :state, activate_always: true do |state: 'paused'| raw.where(aasm_state: state) end From f9d02cc63eeb38d2b4e8c27e69521a463720eec4 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 16:32:03 -0300 Subject: [PATCH 230/472] =?UTF-8?q?feat:=20recordar=20el=20filtro=20que=20?= =?UTF-8?q?est=C3=A1bamos=20usando?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../instance_moderations_controller.rb | 21 +++++++++---------- .../moderation_queue_controller.rb | 2 ++ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/app/controllers/instance_moderations_controller.rb b/app/controllers/instance_moderations_controller.rb index 67a6be1d..d25e1450 100644 --- a/app/controllers/instance_moderations_controller.rb +++ b/app/controllers/instance_moderations_controller.rb @@ -3,23 +3,18 @@ # Actualiza la relación entre un sitio y una instancia class InstanceModerationsController < ApplicationController before_action :authorize_policy, except: %i[action_on_several] + around_action :redirect_to_moderation_queue! def pause - instance_moderation.pause! - - redirect_to site_moderation_queue_path + instance_moderation.pause! if instance_moderation.may_pause? end def allow - instance_moderation.allow! - - redirect_to site_moderation_queue_path + instance_moderation.allow! if instance_moderation.may_allow? end def block - instance_moderation.block! - - redirect_to site_moderation_queue_path + instance_moderation.block! if instance_moderation.may_block? end def action_on_several @@ -39,12 +34,16 @@ class InstanceModerationsController < ApplicationController instance_moderation.public_send(method) end end - - redirect_to site_moderation_queue_path end private + def redirect_to_moderation_queue!(&action) + redirect_back fallback_location: site_moderation_queue_path, state: session[:moderation_queue_filtered_by_state] + + yield + end + # @return [InstanceModeration] def instance_moderation @instance_moderation ||= site.instance_moderations.find(params[:instance_moderation_id]) diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index 8c030460..fd7d2acb 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -6,6 +6,8 @@ class ModerationQueueController < ApplicationController def index dummy_data + session[:moderation_queue_filtered_by_state] = params[:state] + # @todo cambiar el estado por query @activity_pubs = site.activity_pubs @instance_moderations = rubanok_process(site.instance_moderations, with: InstanceModerationProcessor) From 448564aa46739bdb72e4d226775993ee6ea55271 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 16:36:50 -0300 Subject: [PATCH 231/472] =?UTF-8?q?fix:=20hacer=20la=20tarea=20sincr=C3=B3?= =?UTF-8?q?nicamente?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/fediblock_state.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/fediblock_state.rb b/app/models/fediblock_state.rb index 13e31cb2..a160c43a 100644 --- a/app/models/fediblock_state.rb +++ b/app/models/fediblock_state.rb @@ -36,7 +36,7 @@ class FediblockState < ApplicationRecord # Luego esta tarea crea las que falten e ignora las que ya se # bloquearon. - ActivityPub::InstanceModerationJob.perform_later(site: site, hostnames: fediblock.hostnames) + ActivityPub::InstanceModerationJob.perform_now(site: site, hostnames: fediblock.hostnames) end end From 17705f66ad2f0c1a66469393f009e2081ebd50c6 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 16:42:18 -0300 Subject: [PATCH 232/472] feat: tarjeta cacheada de instancia --- app/views/moderation_queue/_instance.haml | 16 +++++++++------- app/views/moderation_queue/_instances.haml | 5 +++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/app/views/moderation_queue/_instance.haml b/app/views/moderation_queue/_instance.haml index ec76c6e6..73655e1b 100644 --- a/app/views/moderation_queue/_instance.haml +++ b/app/views/moderation_queue/_instance.haml @@ -1,15 +1,17 @@ +- usuaries = instance.content.dig('usage', 'users', 'active_month') +- usuaries ||= instance.content.dig('stats', 'user_count') + .row.no-gutters.pt-2 .col-1 = render 'components/checkbox', id: instance.hostname, name: 'instance_moderation[]', value: instance_moderation.id, data: { target: 'select-all.input' } .col-11 %h4 - %a{ href: instance.uri }= instance.content['title'] - %p= instance.content['description'].html_safe - %dl - %dt.d-inline= t('.users') - %dd.d-inline - = instance.content.dig('usage', 'users', 'active_month') - = instance.content.dig('stats', 'user_count') + %a{ href: instance.uri }= sanitize(instance.content['title']) || instance.hostname + %p= sanitize instance.content['description'] + - if usuaries.present? + %dl + %dt.d-inline= t('.users') + %dd.d-inline= sanitize usuaries.to_s -# Botones moderación .d-flex.pb-4 diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index 65f4350a..a45da354 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -12,8 +12,9 @@ %h3= t('moderation_queue.nothing') - instance_moderations.each do |instance_moderation| - %hr - = render 'moderation_queue/instance', instance_moderation: instance_moderation, instance: instance_moderation.instance + - cache [instance_moderation.aasm_state, instance_moderation.instance] do + %hr + = render 'moderation_queue/instance', instance_moderation: instance_moderation, instance: instance_moderation.instance %hr %div From dd20c6ce84881d96704f24a516e9fc2561e535c7 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 16:42:39 -0300 Subject: [PATCH 233/472] fixup! feat: mostrar la cantidad de instancias --- config/locales/en.yml | 6 +++--- config/locales/es.yml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 717c9ece..c6a7d936 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -60,9 +60,9 @@ en: submenu_allow: Allow submenu_block: Block instances_show_submenu: - submenu_paused: Moderated - submenu_allowed: Allowed - submenu_blocked: Blocked + submenu_paused: "Moderated (%{count})" + submenu_allowed: "Allowed (%{count})" + submenu_blocked: "Blocked (%{count})" comments_filters: text_show: Show text_checked: With selected diff --git a/config/locales/es.yml b/config/locales/es.yml index 87111523..b3105220 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -60,9 +60,9 @@ es: submenu_allow: Permitir todo submenu_block: Rechazar todo instances_show_submenu: - submenu_paused: Pausadas - submenu_allowed: Permitidas - submenu_blocked: Bloqueadas + submenu_paused: "Pausadas (%{count})" + submenu_allowed: "Permitidas (%{count})" + submenu_blocked: "Bloqueadas (%{count})" comments_filters: text_show: Ver text_checked: Con los marcados From ef9169c89135259c98d5117b9af4f20179f2b110 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 17:12:33 -0300 Subject: [PATCH 234/472] =?UTF-8?q?fix:=20traducci=C3=B3n=20faltante?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/components/_block_list.haml | 3 ++- config/locales/en.yml | 1 + config/locales/es.yml | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/views/components/_block_list.haml b/app/views/components/_block_list.haml index 75825bb0..27e44cac 100644 --- a/app/views/components/_block_list.haml +++ b/app/views/components/_block_list.haml @@ -1,12 +1,13 @@ -# Componente Listas de bloqueo de Instancias - know_more = t('.know_more') +- instances_blocked = t('.instances_blocked') .card.mt-3.mb-3 .card-body = render 'components/checkbox', id: state.id, name: 'fediblock_states_ids[]', value: state.id, checked: state.enabled? do %span.h4.mb-0= blocklist.title %dl.mb-0 - %dt.d-inline= t('.instances_blocked') + %dt.d-inline= instances_blocked %dd.d-inline.font-weight-normal= blocklist.hostnames.count %p.mb-0.font-weight-normal %a{ href: blocklist.url }= know_more diff --git a/config/locales/en.yml b/config/locales/en.yml index c6a7d936..aaa5a451 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -52,6 +52,7 @@ en: components: block_list: know_more: Know more + instances_blocked: Instances blocked instances_filters: text_show: Show text_checked: With selected diff --git a/config/locales/es.yml b/config/locales/es.yml index b3105220..8fe01b83 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -52,6 +52,7 @@ es: components: block_list: know_more: Saber más (en inglés) + instances_blocked: Instancias bloqueadas instances_filters: text_show: Ver text_checked: Con los marcados From eafe8bcdd577d817a791552ffb774241bfd34422 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 17:26:22 -0300 Subject: [PATCH 235/472] feat: poder seleccionar todas las cuentas --- app/views/moderation_queue/_account.haml | 4 ++-- app/views/moderation_queue/_accounts.haml | 14 ++++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/app/views/moderation_queue/_account.haml b/app/views/moderation_queue/_account.haml index 2c929402..27ea30d1 100644 --- a/app/views/moderation_queue/_account.haml +++ b/app/views/moderation_queue/_account.haml @@ -1,6 +1,6 @@ .row.no-gutters.pt-2 .col-1 - = render 'components/checkbox', id: profile['id'] + = render 'components/checkbox', id: profile['id'], name: 'actor[]', value: profile['id'], data: { target: 'select-all.input' } .col-11 %h4 %a{href: profile['id']}= profile['preferredUsername'] @@ -8,4 +8,4 @@ -# Botones de Moderación .d-flex.pb-4 - = render 'components/profiles_btn_box' \ No newline at end of file + = render 'components/profiles_btn_box' diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index 2d8e1420..c88a2de6 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -1,12 +1,10 @@ -.row.no-gutters.pt-2 +.row.no-gutters.pt-2{ data: { controller: 'select-all' } } .col-1.d-flex.align-items-center - = render 'components/checkbox', id: moderation_queue.first['id'] + = render 'components/select_all', id: 'actors' .col-11 -# Filtros = render 'components/profiles_filters' - -- @moderation_queue.map{ |c| c['attributedTo'] }.uniq.each do |remote_profile| - %hr - = render 'account', profile: remote_profile - - + .col-12 + - @moderation_queue.map{ |c| c['attributedTo'] }.uniq.each do |remote_profile| + %hr + = render 'account', profile: remote_profile From f524724c0ffe37830ef305f3ca6fa66f38b2bfbf Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 17:34:34 -0300 Subject: [PATCH 236/472] feat: moderar actores --- app/models/activity_pub/actor.rb | 1 + app/models/actor_moderation.rb | 32 +++++++++++++++ app/models/site/social_distributed_press.rb | 1 + ...20240228202830_create_actor_moderations.rb | 14 +++++++ db/structure.sql | 39 ++++++++++++++++++- 5 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 app/models/actor_moderation.rb create mode 100644 db/migrate/20240228202830_create_actor_moderations.rb diff --git a/app/models/activity_pub/actor.rb b/app/models/activity_pub/actor.rb index 7a858a7e..92750946 100644 --- a/app/models/activity_pub/actor.rb +++ b/app/models/activity_pub/actor.rb @@ -10,6 +10,7 @@ class ActivityPub include ActivityPub::Concerns::JsonLdConcern belongs_to :instance + has_many :actor_moderation has_many :activity_pubs, as: :object has_many :activities end diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb new file mode 100644 index 00000000..69fbf3bd --- /dev/null +++ b/app/models/actor_moderation.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +# Mantiene la relación entre Site y Actor +class ActorModeration < ApplicationRecord + include AASM + + belongs_to :site + belongs_to :actor, class_name: 'ActivityPub::Actor' + + aasm do + state :paused, initial: true + state :allowed + state :blocked + state :reported + + event :pause do + transitions from: %i[allowed blocked reported], to: :paused + end + + event :allowed do + transitions from: %i[paused blocked reported], to: :allowed + end + + event :blocked do + transitions from: %i[paused allowed], to: :blocked + end + + event :reported do + transitions from: %i[blocked], to: :reported + end + end +end diff --git a/app/models/site/social_distributed_press.rb b/app/models/site/social_distributed_press.rb index fdb37bca..e916bf3e 100644 --- a/app/models/site/social_distributed_press.rb +++ b/app/models/site/social_distributed_press.rb @@ -12,6 +12,7 @@ class Site has_many :activity_pubs has_many :instance_moderations + has_many :actor_moderations has_many :fediblock_states has_many :instances, through: :instance_moderations diff --git a/db/migrate/20240228202830_create_actor_moderations.rb b/db/migrate/20240228202830_create_actor_moderations.rb new file mode 100644 index 00000000..01460eae --- /dev/null +++ b/db/migrate/20240228202830_create_actor_moderations.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Relación entre Actor y Site +class CreateActorModerations < ActiveRecord::Migration[6.1] + def change + create_table :actor_moderations, id: :uuid do |t| + t.timestamps + + t.belongs_to :site + t.uuid :actor_id, index: true + t.string :aasm_state, null: false + end + end +end diff --git a/db/structure.sql b/db/structure.sql index 740f5d87..e4d39ad0 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -562,6 +562,20 @@ CREATE TABLE public.activity_pubs ( ); +-- +-- Name: actor_moderations; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.actor_moderations ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, + site_id bigint, + actor_id uuid, + aasm_state character varying NOT NULL +); + + -- -- Name: ar_internal_metadata; Type: TABLE; Schema: public; Owner: - -- @@ -1756,6 +1770,14 @@ ALTER TABLE ONLY public.activity_pubs ADD CONSTRAINT activity_pubs_pkey PRIMARY KEY (id); +-- +-- Name: actor_moderations actor_moderations_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.actor_moderations + ADD CONSTRAINT actor_moderations_pkey PRIMARY KEY (id); + + -- -- Name: blazer_audits blazer_audits_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -2107,6 +2129,20 @@ CREATE INDEX index_activity_pub_instances_on_hostname ON public.activity_pub_ins CREATE UNIQUE INDEX index_activity_pubs_on_site_id_and_object_id_and_object_type ON public.activity_pubs USING btree (site_id, object_id, object_type); +-- +-- Name: index_actor_moderations_on_actor_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_actor_moderations_on_actor_id ON public.actor_moderations USING btree (actor_id); + + +-- +-- Name: index_actor_moderations_on_site_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_actor_moderations_on_site_id ON public.actor_moderations USING btree (site_id); + + -- -- Name: index_blazer_audits_on_query_id; Type: INDEX; Schema: public; Owner: - -- @@ -2616,6 +2652,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20240226134335'), ('20240227134845'), ('20240227142019'), -('20240228171335'); +('20240228171335'), +('20240228202830'); From aeb8f884935964ec00e2d213042bea33b13fddb2 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 17:44:21 -0300 Subject: [PATCH 237/472] =?UTF-8?q?feat:=20crear=20el=20estado=20de=20mode?= =?UTF-8?q?raci=C3=B3n=20si=20no=20existe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/api/v1/webhooks/social_inbox_controller.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index 12545915..f52525f1 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -158,6 +158,8 @@ module Api a.save! + site.actor_moderations.find_or_create_by(actor: a) + ActivityPub::ActorFetchJob.perform_later(site: site, actor: a) end end From 6eaf00c7ad1597a2bac9b22e1719f10ad8e70b7b Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 17:52:24 -0300 Subject: [PATCH 238/472] fix: recibir actividades correctamente --- .../api/v1/webhooks/social_inbox_controller.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index f52525f1..34ef1d6c 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -5,6 +5,9 @@ module Api module Webhooks # Recibe webhooks de la Social Inbox # + # @todo Mover todo a un Job que obtenga el objeto remoto antes de + # instanciar el objeto localmente en lugar de arreglarlo después y + # poder responder lo más rápido posible el webhook. # @see {https://www.w3.org/TR/activitypub/} class SocialInboxController < BaseController include Api::V1::Webhooks::Concerns::WebhookConcern @@ -28,6 +31,7 @@ module Api instance.present? object.present? activity_pub.present? + activity.update_activity_pub_state! end rescue ActiveRecord::RecordInvalid => e @@ -125,7 +129,7 @@ module Api # # @return [ActivityPub] def activity_pub - @activity_pub ||= site.activity_pubs.find_or_create_by!(site: site, object: object) + @activity_pub ||= site.activity_pubs.find_or_create_by!(site: site, instance: instance, object: object) end # Crea la actividad y la vincula con el estado @@ -135,7 +139,7 @@ module Api @activity ||= ActivityPub::Activity .type_from(original_activity) - .find_or_initialize_by(uri: original_activity[:id], activity_pub: activity_pub).tap do |a| + .find_or_initialize_by(uri: original_activity[:id], activity_pub: activity_pub, actor: actor).tap do |a| a.content = original_activity.dup a.content[:object] = object.uri a.save! From 6d9a64f7283a488b59fd32d325acac1ec6a34af9 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 17:58:00 -0300 Subject: [PATCH 239/472] feat: moderar en la social inbox --- app/models/activity_pub/actor.rb | 11 ++++++++++ app/models/actor_moderation.rb | 37 ++++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/app/models/activity_pub/actor.rb b/app/models/activity_pub/actor.rb index 92750946..a5171815 100644 --- a/app/models/activity_pub/actor.rb +++ b/app/models/activity_pub/actor.rb @@ -13,5 +13,16 @@ class ActivityPub has_many :actor_moderation has_many :activity_pubs, as: :object has_many :activities + + # Obtiene el nombre de la Actor como mención, solo si obtuvimos el + # contenido de antemano. + # + # @return [String, nil] + def mention + return if content['preferredUsername'].blank? + return if instance.blank? + + @mention ||= "@#{content['preferredUsername']}@#{instance.hostname}" + end end end diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index 69fbf3bd..efbde33b 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -15,18 +15,51 @@ class ActorModeration < ApplicationRecord event :pause do transitions from: %i[allowed blocked reported], to: :paused + + before do + pause_remotely! + end end - event :allowed do + event :allow do transitions from: %i[paused blocked reported], to: :allowed + + before do + allow_remotely! + end end - event :blocked do + event :block do transitions from: %i[paused allowed], to: :blocked + + before do + block_remotely! + end end event :reported do transitions from: %i[blocked], to: :reported end end + + def pause_remotely! + raise AASM::InvalidTransition 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 AASM::InvalidTransition 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 AASM::InvalidTransition unless + actor.mention && + site.social_inbox.allowlist.delete(list: [actor.mention]).ok? && + site.social_inbox.blocklist.post(list: [actor.mention]).ok? + end end From e07da7858e02309f0571428dfd754de0bc38687b Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 18:27:15 -0300 Subject: [PATCH 240/472] =?UTF-8?q?feat:=20cambiar=20a=20orden=20descendie?= =?UTF-8?q?nte=20por=20fecha=20de=20modificaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/processors/actor_moderation_processor.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 app/processors/actor_moderation_processor.rb diff --git a/app/processors/actor_moderation_processor.rb b/app/processors/actor_moderation_processor.rb new file mode 100644 index 00000000..efd12666 --- /dev/null +++ b/app/processors/actor_moderation_processor.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +# Gestiona los filtros de ActorModeration +class ActorModerationProcessor < Rubanok::Processor + # En orden descendiente para encontrar le últime Actor + prepare do + raw.order(updated_at: :desc) + end + + map :actor_state, activate_always: true do |state: 'paused'| + raw.where(aasm_state: state) + end +end From 0e2f6276eb501b0787442f096fe916dca0bfd4ba Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 18:31:28 -0300 Subject: [PATCH 241/472] feat: siempre actualizar la fecha de le actore al guardar una actividad --- app/models/activity_pub/activity.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/activity_pub/activity.rb b/app/models/activity_pub/activity.rb index a220b831..1147c5b8 100644 --- a/app/models/activity_pub/activity.rb +++ b/app/models/activity_pub/activity.rb @@ -16,7 +16,7 @@ class ActivityPub include ActivityPub::Concerns::JsonLdConcern belongs_to :activity_pub - belongs_to :actor + belongs_to :actor, touch: true has_one :object, through: :activity_pub validates :activity_pub_id, presence: true From 25c9963284887f581758d2f524e9b81ab9ed4991 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 18:35:34 -0300 Subject: [PATCH 242/472] =?UTF-8?q?feat:=20mostrar=20las=20cuentas=20en=20?= =?UTF-8?q?la=20cola=20de=20moderaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/moderation_queue_controller.rb | 1 + app/processors/actor_moderation_processor.rb | 4 ++-- app/views/moderation_queue/_accounts.haml | 4 ++-- app/views/moderation_queue/index.haml | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index fd7d2acb..a9611a1b 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -11,6 +11,7 @@ class ModerationQueueController < ApplicationController # @todo cambiar el estado por query @activity_pubs = site.activity_pubs @instance_moderations = rubanok_process(site.instance_moderations, with: InstanceModerationProcessor) + @actor_moderations = rubanok_process(site.actor_moderations, with: ActorModerationProcessor) end # Perfil remoto de usuarie diff --git a/app/processors/actor_moderation_processor.rb b/app/processors/actor_moderation_processor.rb index efd12666..a3035654 100644 --- a/app/processors/actor_moderation_processor.rb +++ b/app/processors/actor_moderation_processor.rb @@ -7,7 +7,7 @@ class ActorModerationProcessor < Rubanok::Processor raw.order(updated_at: :desc) end - map :actor_state, activate_always: true do |state: 'paused'| - raw.where(aasm_state: state) + map :actor_state, activate_always: true do |actor_state: 'paused'| + raw.where(aasm_state: actor_state) end end diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index c88a2de6..5630a6d7 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -5,6 +5,6 @@ -# Filtros = render 'components/profiles_filters' .col-12 - - @moderation_queue.map{ |c| c['attributedTo'] }.uniq.each do |remote_profile| + - actor_moderations.find_each do |actor_moderation| %hr - = render 'account', profile: remote_profile + = render 'account', actor_moderation: actor_moderation, profile: actor_moderation.actor.content diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml index 0fb1c968..df2c219d 100644 --- a/app/views/moderation_queue/index.haml +++ b/app/views/moderation_queue/index.haml @@ -9,7 +9,7 @@ %hr - summary = t('.accounts') = render 'layouts/details', summary: summary do - = render 'moderation_queue/accounts', site: @site, post: @post, moderation_queue: @moderation_queue + = render 'moderation_queue/accounts', site: @site, post: @post, actor_moderations: @actor_moderations %hr - summary = t('.comments') = render 'layouts/details', summary: summary do From 2edafc8901a92e81534f3d50ff9c5fea797488ed Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 18:42:48 -0300 Subject: [PATCH 243/472] feat: ver la cuenta de cuentas por moderar --- app/views/components/_profiles_filters.haml | 4 ++-- app/views/components/_profiles_show_submenu.haml | 7 ++++--- app/views/moderation_queue/_accounts.haml | 2 +- config/locales/en.yml | 9 +++++---- config/locales/es.yml | 9 +++++---- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/app/views/components/_profiles_filters.haml b/app/views/components/_profiles_filters.haml index 0088afef..c6397e69 100644 --- a/app/views/components/_profiles_filters.haml +++ b/app/views/components/_profiles_filters.haml @@ -1,6 +1,6 @@ .d-flex.py-2 = render 'components/dropdown', text: t('.text_checked') do - = render 'components/profiles_checked_submenu' + = render 'components/profiles_checked_submenu' = render 'components/dropdown', text: t('.text_show') do - = render 'components/profiles_show_submenu' \ No newline at end of file + = render 'components/profiles_show_submenu', actor_moderations: actor_moderations diff --git a/app/views/components/_profiles_show_submenu.haml b/app/views/components/_profiles_show_submenu.haml index 2ba949b1..703e4a15 100644 --- a/app/views/components/_profiles_show_submenu.haml +++ b/app/views/components/_profiles_show_submenu.haml @@ -1,3 +1,4 @@ -= render 'components/dropdown_item', text: t('.submenu_accept'), path: '/' -= render 'components/dropdown_item', text: t('.submenu_reject'), path: '/' -= render 'components/dropdown_item', text: t('.submenu_block'), path: '/' \ No newline at end of file +- ActorModeration.aasm.states.map(&:name).each do |actor_state| + = render 'components/dropdown_item', + text: t(".submenu_#{actor_state}", count: actor_moderations.unscope(where: :aasm_state).public_send(actor_state).count), + path: site_moderation_queue_path(params.permit(:state, :actor_state).merge(actor_state: actor_state)) diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index 5630a6d7..44c2893e 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -3,7 +3,7 @@ = render 'components/select_all', id: 'actors' .col-11 -# Filtros - = render 'components/profiles_filters' + = render 'components/profiles_filters', actor_moderations: actor_moderations .col-12 - actor_moderations.find_each do |actor_moderation| %hr diff --git a/config/locales/en.yml b/config/locales/en.yml index aaa5a451..c4bff0a9 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -85,10 +85,11 @@ en: submenu_reject: Reject submenu_block: Block profiles_show_submenu: - submenu_accept: Accept - submenu_block: Block - submenu_reject: Reject - block_lists: + submenu_paused: "Paused (%{count})" + submenu_allowed: "Allowed (%{count})" + submenu_blocked: "Blocked (%{count})" + submenu_reported: "Reported (%{count})" + block_lists: title: Block lists comments_btn_box: text_pause: Pause diff --git a/config/locales/es.yml b/config/locales/es.yml index 8fe01b83..9409eddd 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -85,10 +85,11 @@ es: submenu_reject: Rechazado submenu_block: Bloqueado profiles_show_submenu: - submenu_accept: Aceptado - submenu_block: Bloqueado - submenu_reject: Rechazado - block_lists: + submenu_paused: "Pausadas (%{count})" + submenu_allowed: "Permitidas (%{count})" + submenu_blocked: "Bloqueadas (%{count})" + submenu_reported: "Reportadas (%{count})" + block_lists: title: Listas de bloqueo comments_btn_box: text_pause: Pausa From 0539eb8f2245d4c8573aa744352f1ea72b9f74ae Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 18:51:41 -0300 Subject: [PATCH 244/472] =?UTF-8?q?feat:=20avisar=20cuando=20no=20se=20enc?= =?UTF-8?q?ontr=C3=B3=20nada?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_accounts.haml | 2 ++ app/views/moderation_queue/_instances.haml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index 44c2893e..c7dba0a1 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -5,6 +5,8 @@ -# Filtros = render 'components/profiles_filters', actor_moderations: actor_moderations .col-12 + - if actor_moderations.count.zero? + %h4= t('moderation_queue.nothing') - actor_moderations.find_each do |actor_moderation| %hr = render 'account', actor_moderation: actor_moderation, profile: actor_moderation.actor.content diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index a45da354..77b6adea 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -9,7 +9,7 @@ .col-12 - if instance_moderations.count.zero? - %h3= t('moderation_queue.nothing') + %h4= t('moderation_queue.nothing') - instance_moderations.each do |instance_moderation| - cache [instance_moderation.aasm_state, instance_moderation.instance] do From 5370a542ff52be582e927262ed57c8ffce8da42a Mon Sep 17 00:00:00 2001 From: f Date: Wed, 28 Feb 2024 19:10:37 -0300 Subject: [PATCH 245/472] feat: cambiar el estado de les actores desde el panel --- .../actor_moderations_controller.rb | 20 +++++++++++++++++++ .../moderation_queue_controller.rb | 2 +- app/models/actor_moderation.rb | 6 +++++- app/policies/actor_moderation_policy.rb | 16 +++++++++++++++ app/views/components/_profiles_btn_box.haml | 10 ++++++---- app/views/moderation_queue/_account.haml | 7 ++++--- config/locales/en.yml | 6 +++--- config/locales/es.yml | 6 +++--- 8 files changed, 58 insertions(+), 15 deletions(-) create mode 100644 app/controllers/actor_moderations_controller.rb create mode 100644 app/policies/actor_moderation_policy.rb diff --git a/app/controllers/actor_moderations_controller.rb b/app/controllers/actor_moderations_controller.rb new file mode 100644 index 00000000..543ca74d --- /dev/null +++ b/app/controllers/actor_moderations_controller.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +# Gestiona la cola de moderación de actores +class ActorModerationsController < ApplicationController + ActorModeration.aasm.events.map(&:name).each do |actor_event| + define_method(actor_event) do + authorize actor_moderation + + actor_moderation.public_send(:"#{actor_event}!") if actor_moderation.public_send(:"may_#{actor_event}?") + + redirect_back fallback_location: site_moderation_queue_path(**(session[:moderation_queue_filters] || {})) + end + end + + private + + def actor_moderation + @actor_moderation ||= site.actor_moderations.find(params[:actor_moderation_id]) + end +end diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index a9611a1b..df36dfbe 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -6,7 +6,7 @@ class ModerationQueueController < ApplicationController def index dummy_data - session[:moderation_queue_filtered_by_state] = params[:state] + session[:moderation_queue_filters] = params.permit(:state, :actor_state) # @todo cambiar el estado por query @activity_pubs = site.activity_pubs diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index efbde33b..f186dd69 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -7,6 +7,10 @@ class ActorModeration < ApplicationRecord belongs_to :site belongs_to :actor, class_name: 'ActivityPub::Actor' + def self.events + aasm.events.map(&:name) + end + aasm do state :paused, initial: true state :allowed @@ -37,7 +41,7 @@ class ActorModeration < ApplicationRecord end end - event :reported do + event :report do transitions from: %i[blocked], to: :reported end end diff --git a/app/policies/actor_moderation_policy.rb b/app/policies/actor_moderation_policy.rb new file mode 100644 index 00000000..07a9a752 --- /dev/null +++ b/app/policies/actor_moderation_policy.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# Solo les usuaries pueden moderar actores +ActorModerationPolicy = Struct.new(:usuarie, :actor_moderation) do + ActorModeration.events.each do |actor_event| + define_method(:"#{actor_event}?") do + actor_moderation.site.usuarie? usuarie + end + end + + # En este paso tenemos varias cuentas por moderar pero todas son + # del mismo sitio. + def action_on_several? + actor_moderation.first.site.usuarie? usuarie + end +end diff --git a/app/views/components/_profiles_btn_box.haml b/app/views/components/_profiles_btn_box.haml index 06faa8a1..bc1fd7e4 100644 --- a/app/views/components/_profiles_btn_box.haml +++ b/app/views/components/_profiles_btn_box.haml @@ -1,7 +1,9 @@ -# Componente Botonera de Moderación de Cuentas (Remote_profile) - btn_class = 'btn-secondary' -= render 'components/btn_base', text: t('.text_approve'), class: btn_class, href: '' -= render 'components/btn_base', text: t('.text_check'), class: btn_class, href: '' -= render 'components/btn_base', text: t('.text_deny'), class: btn_class, href: '' -= render 'components/btn_base', text: t('.text_report'), class: btn_class, href: '' \ No newline at end of file +- ActorModeration.events.each do |actor_event| + = render 'components/btn_base', + text: t(".text_#{actor_event}"), + path: public_send(:"site_actor_moderation_#{actor_event}_path", actor_moderation_id: actor_moderation), + class: btn_class, + disabled: !actor_moderation.public_send(:"may_#{actor_event}?") diff --git a/app/views/moderation_queue/_account.haml b/app/views/moderation_queue/_account.haml index 27ea30d1..24fbb270 100644 --- a/app/views/moderation_queue/_account.haml +++ b/app/views/moderation_queue/_account.haml @@ -3,9 +3,10 @@ = render 'components/checkbox', id: profile['id'], name: 'actor[]', value: profile['id'], data: { target: 'select-all.input' } .col-11 %h4 - %a{href: profile['id']}= profile['preferredUsername'] - =profile['summary'].html_safe + %a{href: profile['id']}= sanitize profile['name'] + .mb-3 + = sanitize profile['summary'].html_safe -# Botones de Moderación .d-flex.pb-4 - = render 'components/profiles_btn_box' + = render 'components/profiles_btn_box', actor_moderation: actor_moderation diff --git a/config/locales/en.yml b/config/locales/en.yml index c4bff0a9..3c8e8851 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -102,9 +102,9 @@ en: text_allow: Allow everything text_deny: Block instance profiles_btn_box: - text_approve: Always approve - text_check: Always check - text_deny: Block + text_pause: Always check + text_allow: Always approve + text_block: Block text_report: Report moderation_queue: everything: 'Select all' diff --git a/config/locales/es.yml b/config/locales/es.yml index 9409eddd..d2c30ef6 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -102,9 +102,9 @@ es: text_allow: Permitir todo text_deny: Bloquear instancia profiles_btn_box: - text_approve: Aprobar siempre - text_check: Revisar siempre - text_deny: Bloquear + text_pause: Revisar siempre + text_allow: Aprobar siempre + text_block: Bloquear text_report: Reportar moderation_queue: everything: 'Seleccionar todo' From cf46988d9db2aa34bb26ae5dbd521923da28ed23 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 29 Feb 2024 15:53:32 -0300 Subject: [PATCH 246/472] fixup! feat: cambiar el estado de les actores desde el panel --- app/views/actor_moderations/show.haml | 4 ++++ config/routes.rb | 6 ++++++ 2 files changed, 10 insertions(+) create mode 100644 app/views/actor_moderations/show.haml diff --git a/app/views/actor_moderations/show.haml b/app/views/actor_moderations/show.haml new file mode 100644 index 00000000..ba0fc257 --- /dev/null +++ b/app/views/actor_moderations/show.haml @@ -0,0 +1,4 @@ +.row.justify-content-center + .col-md-8 + %h1= t('.profile') + = render 'moderation_queue/remote_profile', remote_profile: @remote_profile diff --git a/config/routes.rb b/config/routes.rb index d70f8339..f6b412e2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -71,6 +71,12 @@ Rails.application.routes.draw do patch :instance_moderations_action_on_several, to: 'instance_moderations#action_on_several' patch :fediblock_states_action_on_several, to: 'fediblock_states#action_on_several' + resources :actor_moderations, only: [] do + ActorModeration.events.each do |actor_event| + patch actor_event, to: "actor_moderations##{actor_event}" + end + end + # Gestionar artículos según idioma nested do scope '/(:locale)', constraint: /[a-z]{2}(-[A-Z]{2})?/ do From 3ba23a8b8c49ae25accd7bbcfaef99f6779d8a05 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 29 Feb 2024 15:54:53 -0300 Subject: [PATCH 247/472] feat: poder ir al perfil desde la lista --- .../actor_moderations_controller.rb | 7 ++++- .../moderation_queue_controller.rb | 5 ---- app/views/actor_moderations/show.haml | 8 +++-- app/views/components/_actor.haml | 21 ++++++++++++++ app/views/components/_profiles_btn_box.haml | 15 +++++----- app/views/moderation_queue/_account.haml | 2 +- .../moderation_queue/_remote_profile.haml | 29 ------------------- .../moderation_queue/remote_profile.haml | 4 --- config/locales/en.yml | 17 ++++++----- config/locales/es.yml | 17 ++++++----- config/routes.rb | 3 +- 11 files changed, 61 insertions(+), 67 deletions(-) create mode 100644 app/views/components/_actor.haml delete mode 100644 app/views/moderation_queue/_remote_profile.haml delete mode 100644 app/views/moderation_queue/remote_profile.haml diff --git a/app/controllers/actor_moderations_controller.rb b/app/controllers/actor_moderations_controller.rb index 543ca74d..f4637d70 100644 --- a/app/controllers/actor_moderations_controller.rb +++ b/app/controllers/actor_moderations_controller.rb @@ -12,9 +12,14 @@ class ActorModerationsController < ApplicationController end end + # Ver el perfil remoto + def show + @remote_profile = actor_moderation.actor.content + end + private def actor_moderation - @actor_moderation ||= site.actor_moderations.find(params[:actor_moderation_id]) + @actor_moderation ||= site.actor_moderations.find(params[:actor_moderation_id] || params[:id]) end end diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index df36dfbe..95639b35 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -14,11 +14,6 @@ class ModerationQueueController < ApplicationController @actor_moderations = rubanok_process(site.actor_moderations, with: ActorModerationProcessor) end - # Perfil remoto de usuarie - def remote_profile - dummy_data - end - # todon.nl está usando /api/v2/instance # mauve.moe usa /api/v1/instance def instances diff --git a/app/views/actor_moderations/show.haml b/app/views/actor_moderations/show.haml index ba0fc257..7b62f672 100644 --- a/app/views/actor_moderations/show.haml +++ b/app/views/actor_moderations/show.haml @@ -1,4 +1,8 @@ .row.justify-content-center - .col-md-8 + .col-12.col-md-8 %h1= t('.profile') - = render 'moderation_queue/remote_profile', remote_profile: @remote_profile + = render 'components/actor', remote_profile: @remote_profile + .col-12.col-md-8 + = render 'components/profiles_btn_box', actor_moderation: @actor_moderation + -# + = render 'moderation_queue/comments', moderation_queue: @moderation_queue diff --git a/app/views/components/_actor.haml b/app/views/components/_actor.haml new file mode 100644 index 00000000..f5d6efae --- /dev/null +++ b/app/views/components/_actor.haml @@ -0,0 +1,21 @@ +-# Componente Remote_Profile + +.py-2 + %dl + %dt= t('.profile_name') + %dd= sanitize remote_profile['name'] + + %dt= t('.preferred_name') + %dd= sanitize remote_profile['preferredUsername'] + + %dt= t('.profile_id') + %dd + = link_to sanitize(remote_profile['id']) + + - if remote_profile['published'].present? + %dt= t('.profile_published') + %dd + = render 'layouts/time', time: sanitize(remote_profile['published']) + %dt= t('.profile_summary') + %dd + = sanitize remote_profile['summary'] diff --git a/app/views/components/_profiles_btn_box.haml b/app/views/components/_profiles_btn_box.haml index bc1fd7e4..bd994f84 100644 --- a/app/views/components/_profiles_btn_box.haml +++ b/app/views/components/_profiles_btn_box.haml @@ -1,9 +1,10 @@ -# Componente Botonera de Moderación de Cuentas (Remote_profile) -- btn_class = 'btn-secondary' -- ActorModeration.events.each do |actor_event| - = render 'components/btn_base', - text: t(".text_#{actor_event}"), - path: public_send(:"site_actor_moderation_#{actor_event}_path", actor_moderation_id: actor_moderation), - class: btn_class, - disabled: !actor_moderation.public_send(:"may_#{actor_event}?") +.d-flex.flex-row + - btn_class = 'btn-secondary' + - ActorModeration.events.each do |actor_event| + = render 'components/btn_base', + text: t(".text_#{actor_event}"), + path: public_send(:"site_actor_moderation_#{actor_event}_path", actor_moderation_id: actor_moderation), + class: btn_class, + disabled: !actor_moderation.public_send(:"may_#{actor_event}?") diff --git a/app/views/moderation_queue/_account.haml b/app/views/moderation_queue/_account.haml index 24fbb270..cdcc0ad4 100644 --- a/app/views/moderation_queue/_account.haml +++ b/app/views/moderation_queue/_account.haml @@ -3,7 +3,7 @@ = render 'components/checkbox', id: profile['id'], name: 'actor[]', value: profile['id'], data: { target: 'select-all.input' } .col-11 %h4 - %a{href: profile['id']}= sanitize profile['name'] + = link_to sanitize(profile['name']), site_actor_moderation_path(id: actor_moderation) .mb-3 = sanitize profile['summary'].html_safe diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml deleted file mode 100644 index 92cf8e96..00000000 --- a/app/views/moderation_queue/_remote_profile.haml +++ /dev/null @@ -1,29 +0,0 @@ --# Componente Remote_Profile - -.flex.py-2.mx-2 - %dl - %dt= t('.profile_name') - %dd= remote_profile['name'] - - %dt= t('.preferred_name') - %dd= remote_profile['preferredUsername'] - - %dt= t('.profile_id') - %dd - %a{ href: 'https://mastodon.mauve.moe/users/mauve' }= remote_profile['id'] - - %dt= t('.profile_published') - %dd - = render 'layouts/time', time: remote_profile['published'] - %dt= t('.profile_summary') - %dd - %p= remote_profile['summary'].html_safe - - = render 'moderation_queue/comments', moderation_queue: @moderation_queue - -%dl.mt-5 - %dt= t('.profile_name') - %dd= remote_profile['name'] - --# Botones de Moderación -= render 'components/profiles_btn_box' diff --git a/app/views/moderation_queue/remote_profile.haml b/app/views/moderation_queue/remote_profile.haml deleted file mode 100644 index ba0fc257..00000000 --- a/app/views/moderation_queue/remote_profile.haml +++ /dev/null @@ -1,4 +0,0 @@ -.row.justify-content-center - .col-md-8 - %h1= t('.profile') - = render 'moderation_queue/remote_profile', remote_profile: @remote_profile diff --git a/config/locales/en.yml b/config/locales/en.yml index 3c8e8851..62e9a1a7 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -106,6 +106,15 @@ en: text_allow: Always approve text_block: Block text_report: Report + actor_moderations: + show: + user: Username + profile: Profile + profile_name: Profile name + preferred_name: Name in Fediverse + profile_id: ID + profile_published: Published + profile_summary: Summary moderation_queue: everything: 'Select all' nothing: "There's nothing for this filter" @@ -117,14 +126,6 @@ en: comment: source_profile: Source Profile reply_to: Reply to - remote_profile: - user: Username - profile: Profile - profile_name: Profile name - preferred_name: Name in Fediverse - profile_id: ID - profile_published: Published - profile_summary: Summary instances: title: My block lists description: Description diff --git a/config/locales/es.yml b/config/locales/es.yml index d2c30ef6..3dc68d98 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -106,6 +106,15 @@ es: text_allow: Aprobar siempre text_block: Bloquear text_report: Reportar + actor_moderations: + show: + user: Nombre de usuarie + profile: Cuenta de Origen + profile_name: Nombre de la cuenta + preferred_name: Nombre en el Fediverso + profile_id: ID + profile_published: Publicada + profile_summary: Presentación moderation_queue: everything: 'Seleccionar todo' nothing: 'No hay nada para este filtro' @@ -117,14 +126,6 @@ es: comment: source_profile: Cuenta de Origen reply_to: En respuesta a - remote_profile: - user: Nombre de usuario - profile: Cuenta de Origen - profile_name: Nombre de la Cuenta - preferred_name: Nombre en el Fediverso - profile_id: ID - profile_published: Publicada - profile_summary: Presentación instances: title: Mis listas de bloqueo description: Descripción de listas de bloqueo diff --git a/config/routes.rb b/config/routes.rb index f6b412e2..ceffcd26 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -59,7 +59,6 @@ Rails.application.routes.draw do post 'collaborate', to: 'collaborations#accept_collaboration' get 'moderation_queue', to: 'moderation_queue#index' - get 'remote_profile', to: 'moderation_queue#remote_profile' get 'instances', to: 'moderation_queue#instances' resources :instance_moderations, only: [] do @@ -71,7 +70,7 @@ Rails.application.routes.draw do patch :instance_moderations_action_on_several, to: 'instance_moderations#action_on_several' patch :fediblock_states_action_on_several, to: 'fediblock_states#action_on_several' - resources :actor_moderations, only: [] do + resources :actor_moderations, only: %i[show] do ActorModeration.events.each do |actor_event| patch actor_event, to: "actor_moderations##{actor_event}" end From cbba822f31b12d5607210aa2dec749915d8184c7 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 29 Feb 2024 16:27:48 -0300 Subject: [PATCH 248/472] feat: recordar el estado del details --- .../controllers/details_controller.js | 17 +++++++++++++++++ app/views/layouts/_details.haml | 9 +++++++-- app/views/moderation_queue/index.haml | 9 +++------ 3 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 app/javascript/controllers/details_controller.js diff --git a/app/javascript/controllers/details_controller.js b/app/javascript/controllers/details_controller.js new file mode 100644 index 00000000..57935e1e --- /dev/null +++ b/app/javascript/controllers/details_controller.js @@ -0,0 +1,17 @@ +import { Controller } from "stimulus"; + +export default class extends Controller { + static targets = []; + + connect() { + const state = window.sessionStorage.getItem(this.element.id); + + if (state === "open") { + this.element.setAttribute("open", true); + } + } + + store(event = undefined) { + window.sessionStorage.setItem(this.element.id, event.newState); + } +} diff --git a/app/views/layouts/_details.haml b/app/views/layouts/_details.haml index 99ba4894..ce38bddd 100644 --- a/app/views/layouts/_details.haml +++ b/app/views/layouts/_details.haml @@ -1,6 +1,11 @@ --# Detail Cola de Moderación +-# + Detail Cola de Moderación -%details.details.py-2 + @param :id [String] El ID opcional sirve para mantener el historial de + cuál estaba abierto y recuperarlo al cargar la página + @param :summary [String] El resumen + +%details.details.py-2{ id: local_assigns[:id], data: { controller: 'details', action: 'toggle->details#store' } } %summary .row .col-11.pr-2 diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml index df2c219d..799fc641 100644 --- a/app/views/moderation_queue/index.haml +++ b/app/views/moderation_queue/index.haml @@ -3,14 +3,11 @@ %h1= t('.title') .row .col - - summary = t('.instances') - = render 'layouts/details', summary: summary do + = render 'layouts/details', id: 'summary', summary: t('.instances') do = render 'moderation_queue/instances', site: @site, instance_moderations: @instance_moderations, fediblock_states: @site.fediblock_states %hr - - summary = t('.accounts') - = render 'layouts/details', summary: summary do + = render 'layouts/details', id: 'accounts', summary: t('.accounts') do = render 'moderation_queue/accounts', site: @site, post: @post, actor_moderations: @actor_moderations %hr - - summary = t('.comments') - = render 'layouts/details', summary: summary do + = render 'layouts/details', id: 'comments', summary: t('.comments') do = render 'moderation_queue/comments', site: @site, post: @post, moderation_queue: @moderation_queue From 6c61aec60e177d522e0dacd7d50152c6ec72b5d0 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 29 Feb 2024 16:45:06 -0300 Subject: [PATCH 249/472] feat: al modificar un fediblock, cambiar el estado a todes les actores --- app/models/actor_moderation.rb | 12 ++++++++++++ app/models/fediblock_state.rb | 19 ++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index f186dd69..1d9bae5d 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -7,6 +7,18 @@ class ActorModeration < ApplicationRecord belongs_to :site belongs_to :actor, class_name: 'ActivityPub::Actor' + # 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 + + # Todos los eventos de la máquina de estados + # + # @return [Array] def self.events aasm.events.map(&:name) end diff --git a/app/models/fediblock_state.rb b/app/models/fediblock_state.rb index a160c43a..180a45b5 100644 --- a/app/models/fediblock_state.rb +++ b/app/models/fediblock_state.rb @@ -37,6 +37,11 @@ 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. + ActorModeration.where(actor_id: actor_ids).paused.block_all! end end @@ -52,15 +57,27 @@ class FediblockState < ApplicationRecord disable_remotely! instance_moderations.pause_all! + + # Volver a pausar todes les actores de esta instancia que fueron + # bloqueades. + ActorModeration.where(actor_id: actor_ids).blocked.pause_all! end end end private + def actor_ids + ActivityPub::Actor.where(instance_id: instance_ids).pluck(:id) + end + + def instance_ids + fediblock.instances.pluck(:id) + end + # Todas las instancias de moderación de este sitio def instance_moderations - site.instance_moderations.where(instance_id: fediblock.instances.pluck(:id)) + site.instance_moderations.where(instance_id: instance_ids) end # @return [Array] From 67d9731b1e37606f6b150704fd9d853b6caf34e3 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 1 Mar 2024 15:04:07 -0300 Subject: [PATCH 250/472] feat: enviar reportes remotos --- .../activity_pub/remote_flags_controller.rb | 27 +++++++++++ app/jobs/activity_pub/remote_flag_job.rb | 25 ++++++++++ app/models/activity_pub/actor.rb | 1 + app/models/deploy_social_distributed_press.rb | 9 +--- app/models/site/social_distributed_press.rb | 8 ++++ app/models/social_inbox.rb | 26 ++++++++--- config/routes.rb | 4 ++ ...201155_create_activity_pub_remote_flags.rb | 16 +++++++ db/structure.sql | 46 ++++++++++++++++++- 9 files changed, 146 insertions(+), 16 deletions(-) create mode 100644 app/controllers/api/v1/activity_pub/remote_flags_controller.rb create mode 100644 app/jobs/activity_pub/remote_flag_job.rb create mode 100644 db/migrate/20240229201155_create_activity_pub_remote_flags.rb diff --git a/app/controllers/api/v1/activity_pub/remote_flags_controller.rb b/app/controllers/api/v1/activity_pub/remote_flags_controller.rb new file mode 100644 index 00000000..23245b8b --- /dev/null +++ b/app/controllers/api/v1/activity_pub/remote_flags_controller.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Api + module V1 + module ActivityPub + # Devuelve los reportes remotos hechos + # + # @todo Verificar la firma. Por ahora no es necesario porque no es + # posible obtener remotamente todos los reportes y se identifican por + # UUIDv4. + class RemoteFlagsController < BaseController + skip_forgery_protection + + def show + render json: (remote_flag&.content || {}), content_type: 'application/activity+json' + end + + private + + # @return [ActivityPub::RemoteFlag,nil] + def remote_flag + @remote_flag ||= ::ActivityPub::RemoteFlag.find(params[:id]) + end + end + end + end +end diff --git a/app/jobs/activity_pub/remote_flag_job.rb b/app/jobs/activity_pub/remote_flag_job.rb new file mode 100644 index 00000000..332d31ac --- /dev/null +++ b/app/jobs/activity_pub/remote_flag_job.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +# Envía un reporte directamente a la instancia remota +# +# @todo El panel debería ser su propia instancia y firmar sus propios +# mensajes. +# @todo Como la Social Inbox no soporta enviar actividades +# a destinataries que no sean seguidores, enviamos el reporte +# directamente a la instancia. +# @see {https://github.com/hyphacoop/social.distributed.press/issues/14} +class ActivityPub + class RemoteFlagJob < ApplicationJob + self.priority = 30 + + def perform(remote_flag:) + client = remote_flag.site.social_inbox.client_for(remote_flag.actor.content['inbox']) + response = client.post(endpoint: '', body: remote_flag.content) + + raise 'No se pudo enviar el reporte' unless response.ok? + rescue Exception => e + ExceptionNotifier.notify_exception(e, data: { remote_flag: remote_flag.id, response: response.parsed_response }) + raise + end + end +end diff --git a/app/models/activity_pub/actor.rb b/app/models/activity_pub/actor.rb index a5171815..fe6052bf 100644 --- a/app/models/activity_pub/actor.rb +++ b/app/models/activity_pub/actor.rb @@ -13,6 +13,7 @@ class ActivityPub has_many :actor_moderation has_many :activity_pubs, as: :object has_many :activities + has_many :remote_flags # Obtiene el nombre de la Actor como mención, solo si obtuvimos el # contenido de antemano. diff --git a/app/models/deploy_social_distributed_press.rb b/app/models/deploy_social_distributed_press.rb index 9f968f36..eec8189b 100644 --- a/app/models/deploy_social_distributed_press.rb +++ b/app/models/deploy_social_distributed_press.rb @@ -58,13 +58,6 @@ class DeploySocialDistributedPress < Deploy private - # Obtiene el hostname de la API de Sutty - # - # @return [String] - def api_hostname - Rails.application.routes.default_url_options[:host].sub('panel', 'api') - end - # Crea los hooks en la Social Inbox para que nos avise de actividades # nuevas # @@ -80,7 +73,7 @@ class DeploySocialDistributedPress < Deploy webhook_class.new.call({ method: 'POST', url: Rails.application.routes.url_helpers.public_send( - event_url, site_id: site.name, host: api_hostname + event_url, site_id: site.name, host: site.social_inbox_hostname ), headers: { 'X-Social-Inbox': rol.token diff --git a/app/models/site/social_distributed_press.rb b/app/models/site/social_distributed_press.rb index e916bf3e..0716a670 100644 --- a/app/models/site/social_distributed_press.rb +++ b/app/models/site/social_distributed_press.rb @@ -15,6 +15,7 @@ class Site has_many :actor_moderations has_many :fediblock_states has_many :instances, through: :instance_moderations + has_many :remote_flags, class_name: 'ActivityPub::RemoteFlag' before_save :generate_private_key_pem!, unless: :private_key_pem? @@ -23,6 +24,13 @@ class Site @social_inbox ||= SocialInbox.new(site: self) end + # Obtiene el hostname de la API de Sutty + # + # @return [String] + def social_inbox_hostname + Rails.application.routes.default_url_options[:host].sub('panel', 'api') + end + private # Genera la llave privada y la almacena diff --git a/app/models/social_inbox.rb b/app/models/social_inbox.rb index 6677a320..183ebfb0 100644 --- a/app/models/social_inbox.rb +++ b/app/models/social_inbox.rb @@ -37,13 +37,25 @@ class SocialInbox # @return [DistributedPress::V1::Social::Client] def client - @client ||= DistributedPress::V1::Social::Client.new( - url: site.config.dig('activity_pub', 'url'), - public_key_url: public_key_url, - private_key_pem: site.private_key_pem, - logger: Rails.logger, - cache_store: HTTParty::Cache::Store::Redis.new(redis_url: ENV['REDIS_SERVER']) - ) + @client ||= client_for site.config.dig('activity_pub', 'url') + end + + # Permite enviar mensajes directo a otro servidor + # + # @param url [String] + # @return [DistributedPress::V1::Social::Client] + def client_for(url) + raise "Falló generar un cliente" if url.blank? + + @client_for ||= {} + @client_for[url] ||= + DistributedPress::V1::Social::Client.new( + url: url, + public_key_url: public_key_url, + private_key_pem: site.private_key_pem, + logger: Rails.logger, + cache_store: HTTParty::Cache::Store::Redis.new(redis_url: ENV['REDIS_SERVER']) + ) end # @return [DistributedPress::V1::Social::Inbox] diff --git a/config/routes.rb b/config/routes.rb index ceffcd26..32936d42 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -11,6 +11,10 @@ Rails.application.routes.draw do namespace :v1 do resources :csp_reports, only: %i[create] + namespace :activity_pub do + resources :remote_flags, only: %i[show] + end + resources :sites, only: %i[index], constraints: { site_id: /[a-z0-9\-.]+/, id: /[a-z0-9\-.]+/ } do get :'invitades/cookie', to: 'invitades#cookie' post :'posts/:layout', to: 'posts#create', as: :posts diff --git a/db/migrate/20240229201155_create_activity_pub_remote_flags.rb b/db/migrate/20240229201155_create_activity_pub_remote_flags.rb new file mode 100644 index 00000000..c60aca22 --- /dev/null +++ b/db/migrate/20240229201155_create_activity_pub_remote_flags.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# Lleva el registro de reportes remotos +class CreateActivityPubRemoteFlags < ActiveRecord::Migration[6.1] + def change + create_table :activity_pub_remote_flags, id: :uuid do |t| + t.timestamps + t.belongs_to :site + t.uuid :actor_id, index: true + + t.text :message + + t.index %i[site_id actor_id], unique: true + end + end +end diff --git a/db/structure.sql b/db/structure.sql index e4d39ad0..6cdb49f1 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -546,6 +546,20 @@ CREATE TABLE public.activity_pub_objects ( ); +-- +-- Name: activity_pub_remote_flags; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.activity_pub_remote_flags ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, + site_id bigint, + actor_id uuid, + message text +); + + -- -- Name: activity_pubs; Type: TABLE; Schema: public; Owner: - -- @@ -1762,6 +1776,14 @@ ALTER TABLE ONLY public.activity_pub_objects ADD CONSTRAINT activity_pub_objects_pkey PRIMARY KEY (id); +-- +-- Name: activity_pub_remote_flags activity_pub_remote_flags_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.activity_pub_remote_flags + ADD CONSTRAINT activity_pub_remote_flags_pkey PRIMARY KEY (id); + + -- -- Name: activity_pubs activity_pubs_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -2122,6 +2144,27 @@ CREATE INDEX index_activity_pub_actors_on_uri ON public.activity_pub_actors USIN CREATE INDEX index_activity_pub_instances_on_hostname ON public.activity_pub_instances USING btree (hostname); +-- +-- Name: index_activity_pub_remote_flags_on_actor_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_activity_pub_remote_flags_on_actor_id ON public.activity_pub_remote_flags USING btree (actor_id); + + +-- +-- Name: index_activity_pub_remote_flags_on_site_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_activity_pub_remote_flags_on_site_id ON public.activity_pub_remote_flags USING btree (site_id); + + +-- +-- Name: index_activity_pub_remote_flags_on_site_id_and_actor_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_activity_pub_remote_flags_on_site_id_and_actor_id ON public.activity_pub_remote_flags USING btree (site_id, actor_id); + + -- -- Name: index_activity_pubs_on_site_id_and_object_id_and_object_type; Type: INDEX; Schema: public; Owner: - -- @@ -2653,6 +2696,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20240227134845'), ('20240227142019'), ('20240228171335'), -('20240228202830'); +('20240228202830'), +('20240229201155'); From 3fa19ee8b042e5e0a35481450ba07f3d734f3392 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 1 Mar 2024 15:51:54 -0300 Subject: [PATCH 251/472] feat: reportar desde el panel --- Gemfile | 2 +- Gemfile.lock | 8 ++++---- .../actor_moderations_controller.rb | 12 ++++++++++- app/models/activity_pub/remote_flag.rb | 20 +++++++++++++++++++ app/models/actor_moderation.rb | 9 +++++++++ app/views/components/_profiles_btn_box.haml | 11 +++++++++- app/views/moderation_queue/_account.haml | 5 +++-- config/locales/en.yml | 1 + config/locales/es.yml | 1 + ...224_add_remote_flag_to_actor_moderation.rb | 18 +++++++++++++++++ db/structure.sql | 6 ++++-- 11 files changed, 82 insertions(+), 11 deletions(-) create mode 100644 app/models/activity_pub/remote_flag.rb create mode 100644 db/migrate/20240301181224_add_remote_flag_to_actor_moderation.rb diff --git a/Gemfile b/Gemfile index d720a2d6..f4125f65 100644 --- a/Gemfile +++ b/Gemfile @@ -39,7 +39,7 @@ gem 'devise-i18n' gem 'devise_invitable' gem 'redis-client' gem 'hiredis-client' -gem 'distributed-press-api-client', '~> 0.4.0rc2' +gem 'distributed-press-api-client', '~> 0.4.0rc3' gem 'email_address', git: 'https://github.com/fauno/email_address', branch: 'i18n' gem 'exception_notification' gem 'fast_blank' diff --git a/Gemfile.lock b/Gemfile.lock index 72a30af1..366b58a5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -166,12 +166,12 @@ GEM devise_invitable (2.0.9) actionmailer (>= 5.0) devise (>= 4.6) - distributed-press-api-client (0.4.0rc2) + distributed-press-api-client (0.4.0rc3) addressable (~> 2.3, >= 2.3.0) climate_control dry-schema httparty (~> 0.18) - httparty-cache (~> 0.0.4) + httparty-cache (~> 0.0.6) json (~> 2.1, >= 2.1.0) jwt (~> 2.6.0) dotenv (2.8.1) @@ -272,7 +272,7 @@ GEM httparty (0.21.0) mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) - httparty-cache (0.0.5) + httparty-cache (0.0.6) httparty (~> 0.18) i18n (1.14.1) concurrent-ruby (~> 1.0) @@ -626,7 +626,7 @@ DEPENDENCIES devise devise-i18n devise_invitable - distributed-press-api-client (~> 0.4.0rc2) + distributed-press-api-client (~> 0.4.0rc3) dotenv-rails down ed25519 diff --git a/app/controllers/actor_moderations_controller.rb b/app/controllers/actor_moderations_controller.rb index f4637d70..7450835b 100644 --- a/app/controllers/actor_moderations_controller.rb +++ b/app/controllers/actor_moderations_controller.rb @@ -2,10 +2,13 @@ # Gestiona la cola de moderación de actores class ActorModerationsController < ApplicationController - ActorModeration.aasm.events.map(&:name).each do |actor_event| + ActorModeration.events.each do |actor_event| define_method(actor_event) do authorize actor_moderation + # Crea una RemoteFlag si se envían los parámetros adecuados + actor_moderation.update(actor_moderation_params) if actor_event == :report + actor_moderation.public_send(:"#{actor_event}!") if actor_moderation.public_send(:"may_#{actor_event}?") redirect_back fallback_location: site_moderation_queue_path(**(session[:moderation_queue_filters] || {})) @@ -22,4 +25,11 @@ class ActorModerationsController < ApplicationController def actor_moderation @actor_moderation ||= site.actor_moderations.find(params[:actor_moderation_id] || params[:id]) end + + def actor_moderation_params + params.require(:actor_moderation).permit(remote_flag_attributes: %i[message]).tap do |p| + p[:remote_flag_attributes][:site_id] = actor_moderation.site_id + p[:remote_flag_attributes][:actor_id] = actor_moderation.actor_id + end + end end diff --git a/app/models/activity_pub/remote_flag.rb b/app/models/activity_pub/remote_flag.rb new file mode 100644 index 00000000..b790c4b1 --- /dev/null +++ b/app/models/activity_pub/remote_flag.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +class ActivityPub + class RemoteFlag < ApplicationRecord + belongs_to :actor + belongs_to :site + + # Genera la actividad a enviar + def content + { + '@context' => 'https://www.w3.org/ns/activitystreams', + 'id' => Rails.application.routes.url_helpers.v1_activity_pub_remote_flag_url(self, host: site.social_inbox_hostname), + 'type' => 'Flag', + 'actor' => ENV.fetch('PANEL_ACTOR_ID') { "https://#{ENV['SUTTY']}/about.jsonld" }, + 'content' => message.to_s, + 'object' => [ actor.uri ] + } + end + end +end diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index 1d9bae5d..c6f8bfc0 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -5,8 +5,11 @@ class ActorModeration < ApplicationRecord include AASM belongs_to :site + belongs_to :remote_flag, 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) @@ -53,8 +56,14 @@ class ActorModeration < ApplicationRecord end end + # Al reportar, necesitamos asociar una RemoteFlag para poder + # enviarla. event :report do transitions from: %i[blocked], to: :reported + + before do + ActivityPub::RemoteFlagJob.perform_later(remote_flag: remote_flag) + end end end diff --git a/app/views/components/_profiles_btn_box.haml b/app/views/components/_profiles_btn_box.haml index bd994f84..3ec95e59 100644 --- a/app/views/components/_profiles_btn_box.haml +++ b/app/views/components/_profiles_btn_box.haml @@ -1,5 +1,13 @@ -# Componente Botonera de Moderación de Cuentas (Remote_profile) +- form_params = {} +- form_params[:report] = { actor_moderation: { remote_flag_attributes: { message: '' } } } +- I18n.available_locales.each do |locale| + - form_params[:report][:actor_moderation][:remote_flag_attributes][:message] += t(locale) + - form_params[:report][:actor_moderation][:remote_flag_attributes][:message] += ': ' + - form_params[:report][:actor_moderation][:remote_flag_attributes][:message] += t('.report_message', locale: locale, panel_actor_mention: ENV.fetch('PANEL_ACTOR_MENTION') { '@sutty@sutty.nl' }) + - form_params[:report][:actor_moderation][:remote_flag_attributes][:message] += '\n\n' + .d-flex.flex-row - btn_class = 'btn-secondary' - ActorModeration.events.each do |actor_event| @@ -7,4 +15,5 @@ text: t(".text_#{actor_event}"), path: public_send(:"site_actor_moderation_#{actor_event}_path", actor_moderation_id: actor_moderation), class: btn_class, - disabled: !actor_moderation.public_send(:"may_#{actor_event}?") + disabled: !actor_moderation.public_send(:"may_#{actor_event}?"), + params: form_params[actor_event] diff --git a/app/views/moderation_queue/_account.haml b/app/views/moderation_queue/_account.haml index cdcc0ad4..5e574c71 100644 --- a/app/views/moderation_queue/_account.haml +++ b/app/views/moderation_queue/_account.haml @@ -8,5 +8,6 @@ = sanitize profile['summary'].html_safe -# Botones de Moderación - .d-flex.pb-4 - = render 'components/profiles_btn_box', actor_moderation: actor_moderation + - cache actor_moderation do + .d-flex.pb-4 + = render 'components/profiles_btn_box', actor_moderation: actor_moderation diff --git a/config/locales/en.yml b/config/locales/en.yml index 62e9a1a7..4aea89f7 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -106,6 +106,7 @@ en: text_allow: Always approve text_block: Block text_report: Report + report_message: "Hi! Someone using Sutty CMS reported this account on your instance. We don't have support for customized report messages yet, but we will soon. You can reach us at %{panel_actor_mention}." actor_moderations: show: user: Username diff --git a/config/locales/es.yml b/config/locales/es.yml index 3dc68d98..7b033859 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -106,6 +106,7 @@ es: text_allow: Aprobar siempre text_block: Bloquear text_report: Reportar + report_message: "¡Hola! Une usuarie de Sutty CMS reportó esta cuenta en tu instancia. Todavía no tenemos soporte para mensajes personalizados. Podés contactarnos en %{panel_actor_mention}." actor_moderations: show: user: Nombre de usuarie diff --git a/db/migrate/20240301181224_add_remote_flag_to_actor_moderation.rb b/db/migrate/20240301181224_add_remote_flag_to_actor_moderation.rb new file mode 100644 index 00000000..63e4ce1b --- /dev/null +++ b/db/migrate/20240301181224_add_remote_flag_to_actor_moderation.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# Las acciones de moderación pueden tener un reporte remoto asociado +class AddRemoteFlagToActorModeration < ActiveRecord::Migration[6.1] + def up + add_column :actor_moderations, :remote_flag_id, :uuid, null: true + + ActivityPub::RemoteFlag.all.find_each do |remote_flag| + actor_moderation = ActorModeration.find_by(actor_id: remote_flag.actor_id) + + actor_moderation&.update_column(:remote_flag_id, remote_flag.id) + end + end + + def down + remove_column :actor_moderations, :remote_flag_id + end +end diff --git a/db/structure.sql b/db/structure.sql index 6cdb49f1..38a56b46 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -586,7 +586,8 @@ CREATE TABLE public.actor_moderations ( updated_at timestamp(6) without time zone NOT NULL, site_id bigint, actor_id uuid, - aasm_state character varying NOT NULL + aasm_state character varying NOT NULL, + remote_flag_id uuid ); @@ -2697,6 +2698,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20240227142019'), ('20240228171335'), ('20240228202830'), -('20240229201155'); +('20240229201155'), +('20240301181224'); From f8b45866336c097267261bc34c80bfb5afd1e4d5 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 1 Mar 2024 16:11:33 -0300 Subject: [PATCH 252/472] feat: poder cambiar el estado a varies actores --- .../actor_moderations_controller.rb | 18 +++++++++++++ .../components/_profiles_checked_submenu.haml | 6 ++--- app/views/moderation_queue/_account.haml | 2 +- app/views/moderation_queue/_accounts.haml | 26 ++++++++++--------- config/locales/en.yml | 4 +-- config/locales/es.yml | 8 +++--- config/routes.rb | 2 ++ 7 files changed, 43 insertions(+), 23 deletions(-) diff --git a/app/controllers/actor_moderations_controller.rb b/app/controllers/actor_moderations_controller.rb index 7450835b..907f21c6 100644 --- a/app/controllers/actor_moderations_controller.rb +++ b/app/controllers/actor_moderations_controller.rb @@ -20,6 +20,24 @@ class ActorModerationsController < ApplicationController @remote_profile = actor_moderation.actor.content end + def action_on_several + actor_moderations = site.actor_moderations.where(id: params[:actor_moderation]) + + authorize actor_moderations + + action = params[:actor_moderation_action].to_sym + method = :"#{action}!" + may = :"may_#{action}?" + + return unless ActorModeration.events.include? action + + ActorModeration.transaction do + actor_moderations.find_each do |actor_moderation| + actor_moderation.public_send(method) if actor_moderation.public_send(may) + end + end + end + private def actor_moderation diff --git a/app/views/components/_profiles_checked_submenu.haml b/app/views/components/_profiles_checked_submenu.haml index 8d8f8940..c0b99aa5 100644 --- a/app/views/components/_profiles_checked_submenu.haml +++ b/app/views/components/_profiles_checked_submenu.haml @@ -1,4 +1,2 @@ -= render 'components/dropdown_item', text: t('.submenu_pause'), path: '/' -= render 'components/dropdown_item', text: t('.submenu_accept'), path: '/' -= render 'components/dropdown_item', text: t('.submenu_reject'), path: '/' -= render 'components/dropdown_item', text: t('.submenu_block'), path: '/' +- ActorModeration.events.each do |actor_event| + = render 'components/dropdown_button', text: t(".submenu_#{actor_event}"), name: 'actor_moderation_action', value: actor_event diff --git a/app/views/moderation_queue/_account.haml b/app/views/moderation_queue/_account.haml index 5e574c71..e891b4ad 100644 --- a/app/views/moderation_queue/_account.haml +++ b/app/views/moderation_queue/_account.haml @@ -1,6 +1,6 @@ .row.no-gutters.pt-2 .col-1 - = render 'components/checkbox', id: profile['id'], name: 'actor[]', value: profile['id'], data: { target: 'select-all.input' } + = render 'components/checkbox', id: actor_moderation.id, name: 'actor_moderation[]', value: actor_moderation.id, data: { target: 'select-all.input' } .col-11 %h4 = link_to sanitize(profile['name']), site_actor_moderation_path(id: actor_moderation) diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index c7dba0a1..35b0b86e 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -1,12 +1,14 @@ -.row.no-gutters.pt-2{ data: { controller: 'select-all' } } - .col-1.d-flex.align-items-center - = render 'components/select_all', id: 'actors' - .col-11 - -# Filtros - = render 'components/profiles_filters', actor_moderations: actor_moderations - .col-12 - - if actor_moderations.count.zero? - %h4= t('moderation_queue.nothing') - - actor_moderations.find_each do |actor_moderation| - %hr - = render 'account', actor_moderation: actor_moderation, profile: actor_moderation.actor.content +%form{ action: site_actor_moderations_action_on_several_path, method: :post } + .row.no-gutters.pt-2{ data: { controller: 'select-all' } } + .col-1.d-flex.align-items-center + = render 'components/select_all', id: 'actors' + .col-11 + -# Filtros + = render 'components/profiles_filters', actor_moderations: actor_moderations + .col-12 + - if actor_moderations.count.zero? + %h4= t('moderation_queue.nothing') + - actor_moderations.find_each do |actor_moderation| + - cache [actor_moderation, actor_moderation.actor] do + %hr + = render 'account', actor_moderation: actor_moderation, profile: actor_moderation.actor.content diff --git a/config/locales/en.yml b/config/locales/en.yml index 4aea89f7..6d5baf5a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -81,9 +81,9 @@ en: text_checked: With selected profiles_checked_submenu: submenu_pause: Pause - submenu_accept: Accept - submenu_reject: Reject + submenu_allow: Allow submenu_block: Block + submenu_report: Report profiles_show_submenu: submenu_paused: "Paused (%{count})" submenu_allowed: "Allowed (%{count})" diff --git a/config/locales/es.yml b/config/locales/es.yml index 7b033859..13534822 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -80,10 +80,10 @@ es: text_show: Ver text_checked: Con los marcados profiles_checked_submenu: - submenu_pause: Pausado - submenu_accept: Aceptado - submenu_reject: Rechazado - submenu_block: Bloqueado + submenu_pause: Pausar + submenu_allow: Aceptar + submenu_block: Bloquear + submenu_report: Reportar profiles_show_submenu: submenu_paused: "Pausadas (%{count})" submenu_allowed: "Permitidas (%{count})" diff --git a/config/routes.rb b/config/routes.rb index 32936d42..9d825a3c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -80,6 +80,8 @@ Rails.application.routes.draw do end end + patch :actor_moderations_action_on_several, to: 'actor_moderations#action_on_several' + # Gestionar artículos según idioma nested do scope '/(:locale)', constraint: /[a-z]{2}(-[A-Z]{2})?/ do From 567f0a10fb9f8427157992352be9ebe8dfd636f5 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 1 Mar 2024 16:12:34 -0300 Subject: [PATCH 253/472] =?UTF-8?q?fix:=20no=20fallar=20si=20no=20se=20pue?= =?UTF-8?q?de=20hacer=20la=20acci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/instance_moderations_controller.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/controllers/instance_moderations_controller.rb b/app/controllers/instance_moderations_controller.rb index d25e1450..dc9e1dfa 100644 --- a/app/controllers/instance_moderations_controller.rb +++ b/app/controllers/instance_moderations_controller.rb @@ -24,14 +24,14 @@ class InstanceModerationsController < ApplicationController action = params[:instance_moderation_action].to_sym method = :"#{action}!" + may = :"may_#{action}?" + events = instance_moderation.aasm.events.map(&:name) + + return unless events.include? action InstanceModeration.transaction do instance_moderations.find_each do |instance_moderation| - events = instance_moderation.aasm.events.map(&:name) - - next unless events.include? action - - instance_moderation.public_send(method) + instance_moderation.public_send(method) if instance_moderation.public_send(may) end end end From 163f3fa7375e624bb7e30a6076f019c2d413eddd Mon Sep 17 00:00:00 2001 From: f Date: Fri, 1 Mar 2024 16:47:00 -0300 Subject: [PATCH 254/472] fix: namespace --- .../v1/webhooks/social_inbox_controller.rb | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index 34ef1d6c..9c1a62ba 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -25,7 +25,8 @@ module Api # Devuelve un error si el token no es válido usuarie.present? - ActivityPub.transaction do + ::ActivityPub.transaction do + # Crea todos los registros necesarios y actualiza el estado actor.present? instance.present? @@ -47,7 +48,7 @@ module Api # # @todo DRY def onapproved - ActivityPub.transaction do + ::ActivityPub.transaction do actor.present? instance.present? object.present? @@ -63,7 +64,7 @@ module Api # # @todo DRY def onrejected - ActivityPub.transaction do + ::ActivityPub.transaction do actor.present? instance.present? object.present? @@ -110,7 +111,7 @@ module Api # # @return [ActivityPub::Object] def object - @object ||= ActivityPub::Object.find_or_initialize_by(uri: object_uri).tap do |o| + @object ||= ::ActivityPub::Object.find_or_initialize_by(uri: object_uri).tap do |o| # XXX: Si el objeto es una actividad, esto siempre va a ser # Generic o.type ||= 'ActivityPub::Object::Generic' @@ -120,7 +121,7 @@ module Api # XXX: el objeto necesita ser guardado antes de poder # procesarlo - ActivityPub::FetchJob.perform_later(site: site, object: o) unless object_embedded? + ::ActivityPub::FetchJob.perform_later(site: site, object: o) unless object_embedded? end end @@ -137,7 +138,7 @@ module Api # @return [ActivityPub::Activity] def activity @activity ||= - ActivityPub::Activity + ::ActivityPub::Activity .type_from(original_activity) .find_or_initialize_by(uri: original_activity[:id], activity_pub: activity_pub, actor: actor).tap do |a| a.content = original_activity.dup @@ -151,20 +152,20 @@ module Api # # @return [Actor] def actor - @actor ||= ActivityPub::Actor.find_or_initialize_by(uri: original_activity[:actor]).tap do |a| + @actor ||= ::ActivityPub::Actor.find_or_initialize_by(uri: original_activity[:actor]).tap do |a| unless a.instance - a.instance = ActivityPub::Instance.find_or_create_by(hostname: URI.parse(a.uri).hostname) + 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) + ::ActivityPub::InstanceFetchJob.perform_later(site: site, instance: a.instance) end a.save! site.actor_moderations.find_or_create_by(actor: a) - ActivityPub::ActorFetchJob.perform_later(site: site, actor: a) + ::ActivityPub::ActorFetchJob.perform_later(site: site, actor: a) end end From 4bef3096210f73b2be57016f21d5e8d2c49a82dc Mon Sep 17 00:00:00 2001 From: f Date: Fri, 1 Mar 2024 16:47:11 -0300 Subject: [PATCH 255/472] fix: soportar flags --- app/controllers/api/v1/webhooks/social_inbox_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index 9c1a62ba..c6aad11f 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -91,6 +91,7 @@ module Api def object_uri @object_uri ||= case original_activity[:object] + when Array then original_activity[:object].first when String then original_activity[:object] when Hash then original_activity.dig(:object, :id) end From 2e1087107af045aa0563c1f0dd5078b27d6bc225 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 1 Mar 2024 16:47:23 -0300 Subject: [PATCH 256/472] fix: indexar por el tipo actual --- app/controllers/api/v1/webhooks/social_inbox_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index c6aad11f..23bd749d 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -131,7 +131,7 @@ module Api # # @return [ActivityPub] def activity_pub - @activity_pub ||= site.activity_pubs.find_or_create_by!(site: site, instance: instance, object: object) + @activity_pub ||= site.activity_pubs.find_or_create_by!(site: site, instance: instance, object_id: object.id, object_type: object.type) end # Crea la actividad y la vincula con el estado From 09e56b88ed5bfa2329b153ef33cf78a534ed5a40 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 1 Mar 2024 16:51:40 -0300 Subject: [PATCH 257/472] =?UTF-8?q?fix:=20detectar=20si=20viene=20vac?= =?UTF-8?q?=C3=ADo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/api/v1/webhooks/social_inbox_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index 23bd749d..3de32104 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -96,7 +96,7 @@ module Api when Hash then original_activity.dig(:object, :id) end ensure - raise ActiveRecord::RecordNotFound, 'object id missing' unless @object_uri + raise ActiveRecord::RecordNotFound, 'object id missing' if @object_uri.blank? end # Atajo a la instancia From 22f730b805dbcfc4daa16bde2147872d07250ceb Mon Sep 17 00:00:00 2001 From: f Date: Fri, 1 Mar 2024 17:14:24 -0300 Subject: [PATCH 258/472] fix: guardar el tipo correcto de objeto si lo soportamos --- .../api/v1/webhooks/social_inbox_controller.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index 3de32104..dec2ee97 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -116,7 +116,15 @@ module Api # XXX: Si el objeto es una actividad, esto siempre va a ser # Generic o.type ||= 'ActivityPub::Object::Generic' - o.content = original_object if object_embedded? + + if object_embedded? + o.content = original_object + begin + type = original_object[:type].presence + o.type = "ActivityPub::Object::#{type}".constantize if type + rescue NameError + end + end o.save! From 85c45d48236f0a7040e2e23545ee08bfc6f2fb9e Mon Sep 17 00:00:00 2001 From: f Date: Fri, 1 Mar 2024 17:29:08 -0300 Subject: [PATCH 259/472] =?UTF-8?q?fix:=20no=20duplicar=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/api/v1/webhooks/social_inbox_controller.rb | 7 +------ app/models/activity_pub.rb | 3 ++- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index dec2ee97..fda51f49 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -89,12 +89,7 @@ module Api # # @return [String] def object_uri - @object_uri ||= - case original_activity[:object] - when Array then original_activity[:object].first - when String then original_activity[:object] - when Hash then original_activity.dig(:object, :id) - end + @object_uri ||= ::ActivityPub.uri_from_object(original_activity[:object]) ensure raise ActiveRecord::RecordNotFound, 'object id missing' if @object_uri.blank? end diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 1afeee96..86c3f240 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -24,8 +24,9 @@ class ActivityPub < ApplicationRecord # @return [String, nil] def self.uri_from_object(object) case object + when Array then uri_from_object(object.first) when String then object - when Hash then object['id'] + when Hash then (object['id'] || object[:id]) end end From b255acf2fd98d2541a8bf6277390a7dc06609843 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 11:59:29 -0300 Subject: [PATCH 260/472] feat: comentarios por actore --- .../v1/webhooks/social_inbox_controller.rb | 2 +- .../moderation_queue_controller.rb | 1 + app/models/activity_pub.rb | 1 + app/processors/activity_pub_processor.rb | 15 ++++++++ app/views/moderation_queue/_comment.haml | 37 +++++++++---------- app/views/moderation_queue/_comments.haml | 10 ++--- app/views/moderation_queue/index.haml | 4 +- ...301202955_add_actor_id_to_activity_pubs.rb | 16 ++++++++ db/structure.sql | 6 ++- 9 files changed, 62 insertions(+), 30 deletions(-) create mode 100644 app/processors/activity_pub_processor.rb create mode 100644 db/migrate/20240301202955_add_actor_id_to_activity_pubs.rb diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index fda51f49..464a0ffe 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -134,7 +134,7 @@ module Api # # @return [ActivityPub] def activity_pub - @activity_pub ||= site.activity_pubs.find_or_create_by!(site: site, instance: instance, object_id: object.id, object_type: object.type) + @activity_pub ||= site.activity_pubs.find_or_create_by!(site: site, actor: actor, instance: instance, object_id: object.id, object_type: object.type) end # Crea la actividad y la vincula con el estado diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index 95639b35..b803ccc9 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -12,6 +12,7 @@ class ModerationQueueController < ApplicationController @activity_pubs = site.activity_pubs @instance_moderations = rubanok_process(site.instance_moderations, with: InstanceModerationProcessor) @actor_moderations = rubanok_process(site.actor_moderations, with: ActorModerationProcessor) + @moderation_queue = rubanok_process(site.activity_pubs, with: ActivityPubProcessor) end # todon.nl está usando /api/v2/instance diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 86c3f240..b52c2a76 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -13,6 +13,7 @@ class ActivityPub < ApplicationRecord belongs_to :instance belongs_to :site belongs_to :object, polymorphic: true + belongs_to :actor has_many :activities validates :site_id, presence: true diff --git a/app/processors/activity_pub_processor.rb b/app/processors/activity_pub_processor.rb new file mode 100644 index 00000000..52cdb6d3 --- /dev/null +++ b/app/processors/activity_pub_processor.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +# Gestiona los filtros de ActivityPub +class ActivityPubProcessor < Rubanok::Processor + # En orden descendiente para encontrar la última actividad + # + # Por ahora solo queremos moderar comentarios. + prepare do + raw.where(object_type: %w[ActivityPub::Object::Note ActivityPub::Object::Article]).order(updated_at: :desc) + end + + map :activity_pub_state, activate_always: true do |activity_pub_state: 'paused'| + raw.where(aasm_state: activity_pub_state) + end +end diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index afd2a335..495aaf55 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -4,24 +4,21 @@ .col-1 = render 'components/checkbox', id: comment['id'] .col-11 - .row.no-gutters - .col.col-lg-10.d-inline-flex.justify-content-between - %h4 - %a{ href: comment['attributedTo'] }= profile['preferredUsername'] + .d-flex.flex-row.align-items-center.justify-content-between + %h4.mb-0 + %a{ href: comment['attributedTo'] }= sanitize profile['preferredUsername'] + %small = render 'layouts/time', time: comment['published'] - - if comment['inReplyTo'] - .row.no-gutters - .col.p-0 - %p - %span= t('.reply_to') - %span - %a{ href: comment['inReplyTo'] }= comment['inReplyTo'] - .row.no-gutters - .col.p-0 - - if comment['summary'] - - summary = comment['summary'] - = render 'layouts/details', summary: summary do - %p= comment['content'].html_safe - - else - %p= comment['content'].html_safe - + - if comment['inReplyTo'].present? + %dl + %dt.d-inline + %small= t('.reply_to') + %dd.d-inline + %small + %a{ href: comment['inReplyTo'] }= sanitize comment['inReplyTo'] + %div + - if comment['summary'].present? + = render 'layouts/details', summary: comment['summary'], summary_class: 'h5' do + = sanitize comment['content'] + - else + = sanitize comment['content'] diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index eadfd78b..4fe84652 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -1,14 +1,14 @@ .row.no-gutters.pt-2 .col-1.d-flex.align-items-center - = render 'components/checkbox', id: moderation_queue.first['id'] + = render 'components/select_all', id: 'select-all-comments' .col-md-9 -# Filtros = render 'components/comments_filters' -- moderation_queue.each do |comment| +- moderation_queue.each do |activity_pub| %hr - = render 'comment', comment: comment, profile: comment['attributedTo'] - + = render 'comment', comment: activity_pub.object.content, profile: activity_pub.actor.content + -# Botones moderación .d-flex.justify-content-center - = render 'components/comments_btn_box', comment: comment \ No newline at end of file + = render 'components/comments_btn_box', comment: activity_pub.object.content diff --git a/app/views/moderation_queue/index.haml b/app/views/moderation_queue/index.haml index 799fc641..80f0bd7c 100644 --- a/app/views/moderation_queue/index.haml +++ b/app/views/moderation_queue/index.haml @@ -7,7 +7,7 @@ = render 'moderation_queue/instances', site: @site, instance_moderations: @instance_moderations, fediblock_states: @site.fediblock_states %hr = render 'layouts/details', id: 'accounts', summary: t('.accounts') do - = render 'moderation_queue/accounts', site: @site, post: @post, actor_moderations: @actor_moderations + = render 'moderation_queue/accounts', site: @site, actor_moderations: @actor_moderations %hr = render 'layouts/details', id: 'comments', summary: t('.comments') do - = render 'moderation_queue/comments', site: @site, post: @post, moderation_queue: @moderation_queue + = render 'moderation_queue/comments', site: @site, moderation_queue: @moderation_queue diff --git a/db/migrate/20240301202955_add_actor_id_to_activity_pubs.rb b/db/migrate/20240301202955_add_actor_id_to_activity_pubs.rb new file mode 100644 index 00000000..37db4bfc --- /dev/null +++ b/db/migrate/20240301202955_add_actor_id_to_activity_pubs.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# Relaciona estados de actividades con les actores que las hicieron +class AddActorIdToActivityPubs < ActiveRecord::Migration[6.1] + def up + add_column :activity_pubs, :actor_id, :uuid + + ActivityPub.all.find_each do |activity_pub| + activity_pub.update_column(:actor_id, activity_pub.activities.last.actor_id) + end + end + + def down + remove_column :activity_pubs, :actor_id + end +end diff --git a/db/structure.sql b/db/structure.sql index 38a56b46..ca3a868b 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -572,7 +572,8 @@ CREATE TABLE public.activity_pubs ( object_id uuid NOT NULL, object_type character varying NOT NULL, aasm_state character varying NOT NULL, - instance_id uuid + instance_id uuid, + actor_id uuid ); @@ -2699,6 +2700,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20240228171335'), ('20240228202830'), ('20240229201155'), -('20240301181224'); +('20240301181224'), +('20240301202955'); From d1a87177a58664da0c420e17764e297fdb74ffa9 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 12:01:32 -0300 Subject: [PATCH 261/472] fix: eliminar indice unico en realidad lo queremos mantener... --- ...240301194154_remove_unique_index_from_activity_pubs.rb | 8 ++++++++ db/structure.sql | 8 +------- 2 files changed, 9 insertions(+), 7 deletions(-) create mode 100644 db/migrate/20240301194154_remove_unique_index_from_activity_pubs.rb diff --git a/db/migrate/20240301194154_remove_unique_index_from_activity_pubs.rb b/db/migrate/20240301194154_remove_unique_index_from_activity_pubs.rb new file mode 100644 index 00000000..0fa80e60 --- /dev/null +++ b/db/migrate/20240301194154_remove_unique_index_from_activity_pubs.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# A veces tenemos varias acciones sobre el mismo objeto +class RemoveUniqueIndexFromActivityPubs < ActiveRecord::Migration[6.1] + def change + remove_index :activity_pubs, %i[site_id object_id object_type], unique: true + end +end diff --git a/db/structure.sql b/db/structure.sql index ca3a868b..ff6cf895 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -2167,13 +2167,6 @@ CREATE INDEX index_activity_pub_remote_flags_on_site_id ON public.activity_pub_r CREATE UNIQUE INDEX index_activity_pub_remote_flags_on_site_id_and_actor_id ON public.activity_pub_remote_flags USING btree (site_id, actor_id); --- --- Name: index_activity_pubs_on_site_id_and_object_id_and_object_type; Type: INDEX; Schema: public; Owner: - --- - -CREATE UNIQUE INDEX index_activity_pubs_on_site_id_and_object_id_and_object_type ON public.activity_pubs USING btree (site_id, object_id, object_type); - - -- -- Name: index_actor_moderations_on_actor_id; Type: INDEX; Schema: public; Owner: - -- @@ -2701,6 +2694,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20240228202830'), ('20240229201155'), ('20240301181224'), +('20240301194154'), ('20240301202955'); From b8e7e53ebd651332cae10f0c23dfb8239a3d1089 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 13:09:36 -0300 Subject: [PATCH 262/472] feat: limpieza de texto --- app/helpers/application_helper.rb | 22 ++++++++++++++++++---- app/models/metadata_template.rb | 14 ++------------ app/views/posts/show.haml | 1 - config/application.rb | 5 +++++ 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 9f7be213..146846f0 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -33,10 +33,24 @@ module ApplicationHelper end end - # Devuelve todas las etiquetas HTML que queremos mantener - def all_html_tags - %w[h1 h2 h3 h4 h5 h6 p a ul ol li table tr td th tbody thead - tfoot em strong sup blockquote cite pre section article] + # Sanitizador que elimina todo + # + # @param html [String] + # @return [String] + def text_plain(html) + sanitize(html, tags: [], attributes: []) + end + + # Sanitizador con etiquetas y atributos por defecto + # + # @param html [String] + # @param options [Hash] + # @return [String] + def sanitize(html, options = {}) + options[:tags] ||= Sutty::ALLOWED_TAGS + options[:attributes] ||= Sutty::ALLOWED_ATTRIBUTES + + super(html, options) end # Genera HTML y limpia etiquetas innecesarias diff --git a/app/models/metadata_template.rb b/app/models/metadata_template.rb index 823443d2..a9765918 100644 --- a/app/models/metadata_template.rb +++ b/app/models/metadata_template.rb @@ -190,8 +190,8 @@ MetadataTemplate = Struct.new(:site, :document, :name, :label, :type, sanitizer .sanitize(string.tr("\r", '').unicode_normalize, - tags: allowed_tags, - attributes: allowed_attributes) + tags: Sutty::ALLOWED_TAGS, + attributes: Sutty::ALLOWED_ATTRIBUTES) .strip .html_safe end @@ -200,16 +200,6 @@ MetadataTemplate = Struct.new(:site, :document, :name, :label, :type, @sanitizer ||= Rails::Html::Sanitizer.safe_list_sanitizer.new end - def allowed_attributes - @allowed_attributes ||= %w[style href src alt controls data-align data-multimedia data-multimedia-inner id - name rel target referrerpolicy class colspan rowspan role data-turbo start type reversed].freeze - end - - def allowed_tags - @allowed_tags ||= %w[strong em del u mark p h1 h2 h3 h4 h5 h6 ul ol li img iframe audio video div figure blockquote - figcaption a sub sup small table thead tbody tfoot tr th td br code].freeze - end - # Decifra el valor # # XXX: Otros tipos de valores necesitan implementar su propio método diff --git a/app/views/posts/show.haml b/app/views/posts/show.haml index ec191d87..10fe64e3 100644 --- a/app/views/posts/show.haml +++ b/app/views/posts/show.haml @@ -20,7 +20,6 @@ post: @post, attribute: attr, metadata: metadata, site: @site, - tags: all_html_tags, locale: @locale, dir: dir) diff --git a/config/application.rb b/config/application.rb index 27a21cc6..ed7e5a78 100644 --- a/config/application.rb +++ b/config/application.rb @@ -37,6 +37,11 @@ if %w[development test].include? ENV['RAILS_ENV'] end module Sutty + ALLOWED_ATTRIBUTES = %w[style href src alt controls data-align data-multimedia data-multimedia-inner id name rel + target referrerpolicy class colspan rowspan role data-turbo start type reversed].freeze + ALLOWED_TAGS = %w[strong em del u mark p h1 h2 h3 h4 h5 h6 ul ol li img iframe audio video div figure blockquote + figcaption a sub sup small table thead tbody tfoot tr th td br code].freeze + # Sutty! class Application < Rails::Application # Initialize configuration defaults for originally generated Rails From 01c042b51265222638d32c8a06d89d66c4f8cf38 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 13:11:17 -0300 Subject: [PATCH 263/472] fix: limpiar html remoto --- app/views/components/_actor.haml | 8 ++++---- app/views/moderation_queue/_account.haml | 4 ++-- app/views/moderation_queue/_comment.haml | 10 ++++++---- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/app/views/components/_actor.haml b/app/views/components/_actor.haml index 68aa3f90..3983d617 100644 --- a/app/views/components/_actor.haml +++ b/app/views/components/_actor.haml @@ -3,18 +3,18 @@ .py-2 %dl %dt= t('.profile_name') - %dd= sanitize remote_profile['name'] + %dd= text_plain remote_profile['name'] %dt= t('.preferred_name') - %dd= sanitize remote_profile['preferredUsername'] + %dd= text_plain remote_profile['preferredUsername'] %dt= t('.profile_id') %dd - = link_to sanitize(remote_profile['id']) + = link_to text_plain(remote_profile['id']) - if remote_profile['published'].present? %dt= t('.profile_published') %dd - = render 'layouts/time', time: sanitize(remote_profile['published']) + = render 'layouts/time', time: text_plain(remote_profile['published']) %dt= t('.profile_summary') %dd= sanitize remote_profile['summary'] diff --git a/app/views/moderation_queue/_account.haml b/app/views/moderation_queue/_account.haml index e891b4ad..fee90316 100644 --- a/app/views/moderation_queue/_account.haml +++ b/app/views/moderation_queue/_account.haml @@ -3,9 +3,9 @@ = render 'components/checkbox', id: actor_moderation.id, name: 'actor_moderation[]', value: actor_moderation.id, data: { target: 'select-all.input' } .col-11 %h4 - = link_to sanitize(profile['name']), site_actor_moderation_path(id: actor_moderation) + = link_to text_plain(profile['name']), site_actor_moderation_path(id: actor_moderation) .mb-3 - = sanitize profile['summary'].html_safe + = sanitize profile['summary'] -# Botones de Moderación - cache actor_moderation do diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 495aaf55..e0e625fd 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -1,24 +1,26 @@ -# Componente Comentario +- in_reply_to = text_plain comment['inReplyTo'] + .row.no-gutters .col-1 = render 'components/checkbox', id: comment['id'] .col-11 .d-flex.flex-row.align-items-center.justify-content-between %h4.mb-0 - %a{ href: comment['attributedTo'] }= sanitize profile['preferredUsername'] + %a{ href: text_plain(comment['attributedTo']) }= text_plain profile['preferredUsername'] %small = render 'layouts/time', time: comment['published'] - - if comment['inReplyTo'].present? + - if in_reply_to.present? %dl %dt.d-inline %small= t('.reply_to') %dd.d-inline %small - %a{ href: comment['inReplyTo'] }= sanitize comment['inReplyTo'] + %a{ href: in_reply_to) }= in_reply_to %div - if comment['summary'].present? - = render 'layouts/details', summary: comment['summary'], summary_class: 'h5' do + = render 'layouts/details', summary: text_plain(comment['summary']), summary_class: 'h5' do = sanitize comment['content'] - else = sanitize comment['content'] From 6110172324f6f267f5d10a1b33e2458f061ea67a Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 13:12:22 -0300 Subject: [PATCH 264/472] feat: poder cambiar el nivel de summary --- app/assets/stylesheets/application.scss | 34 ++++++++++++++----------- app/views/layouts/_details.haml | 9 +++++-- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index a24af4c8..cdf97b5b 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -561,24 +561,28 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); // details styles .details { - summary { + & > summary { list-style: none; - cursor: default; - position: relative; + cursor: pointer; + + .hide-when-open { + display: inline; + } + + .show-when-open { + display: none; + } } - summary::after { - content: '▶'; - font-size: 1.8rem; - position: absolute; - left: 97%; - bottom: 3%; - transform: rotate(180deg); - } + &[open] { & > summary { - &::after { - transform: rotate(90deg); - } + .hide-when-open { + display: none; + } + + .show-when-open { + display: inline; + } } } -} +} diff --git a/app/views/layouts/_details.haml b/app/views/layouts/_details.haml index 3260bfcb..a21f46c1 100644 --- a/app/views/layouts/_details.haml +++ b/app/views/layouts/_details.haml @@ -4,8 +4,13 @@ @param :id [String] El ID opcional sirve para mantener el historial de cuál estaba abierto y recuperarlo al cargar la página @param :summary [String] El resumen + @param :summary_class [String] Clases para el summary + +- local_assigns[:summary_class] ||= 'h3' %details.details.py-2{ id: local_assigns[:id], data: { controller: 'details', action: 'toggle->details#store' } } - %summary - %h3.py-2.pr-2= summary + %summary.d-flex.flex-row.align-items-center.justify-content-between{ class: local_assigns[:summary_class] } + %span= summary + %span.hide-when-open ▶ + %span.show-when-open ▼ = yield From d8487ea7e9b29ef389d8a1c3ebd790bcf52f6ebe Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 13:17:21 -0300 Subject: [PATCH 265/472] fixup! fix: limpiar html remoto --- app/views/moderation_queue/_comment.haml | 11 ++++++----- app/views/moderation_queue/_instance.haml | 5 +++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index e0e625fd..29888ef7 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -1,6 +1,7 @@ -# Componente Comentario - in_reply_to = text_plain comment['inReplyTo'] +- summary = text_plain(comment['summary']) .row.no-gutters .col-1 @@ -10,17 +11,17 @@ %h4.mb-0 %a{ href: text_plain(comment['attributedTo']) }= text_plain profile['preferredUsername'] %small - = render 'layouts/time', time: comment['published'] + = render 'layouts/time', time: text_plain(comment['published']) - if in_reply_to.present? %dl %dt.d-inline %small= t('.reply_to') %dd.d-inline %small - %a{ href: in_reply_to) }= in_reply_to - %div - - if comment['summary'].present? - = render 'layouts/details', summary: text_plain(comment['summary']), summary_class: 'h5' do + %a{ href: in_reply_to }= in_reply_to + .content + - if summary.present? + = render 'layouts/details', summary: summary, summary_class: 'h5' do = sanitize comment['content'] - else = sanitize comment['content'] diff --git a/app/views/moderation_queue/_instance.haml b/app/views/moderation_queue/_instance.haml index 73655e1b..97d23f10 100644 --- a/app/views/moderation_queue/_instance.haml +++ b/app/views/moderation_queue/_instance.haml @@ -7,11 +7,12 @@ .col-11 %h4 %a{ href: instance.uri }= sanitize(instance.content['title']) || instance.hostname - %p= sanitize instance.content['description'] + .content + = sanitize instance.content['description'] - if usuaries.present? %dl %dt.d-inline= t('.users') - %dd.d-inline= sanitize usuaries.to_s + %dd.d-inline= text_plain usuaries.to_s -# Botones moderación .d-flex.pb-4 From 5fabe9cd832753e90b2f27f9e5cab77c7c2c6a0d Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 13:49:07 -0300 Subject: [PATCH 266/472] feat: acciones sobre comentarios --- app/controllers/activity_pubs_controller.rb | 22 +++++++++++++++++ app/models/activity_pub.rb | 3 +++ app/models/actor_moderation.rb | 10 +++----- app/models/concerns/aasm_events_concern.rb | 14 +++++++++++ app/views/components/_btn_base.haml | 1 + app/views/components/_comments_btn_box.haml | 12 +++++----- app/views/moderation_queue/_comment.haml | 12 +++++++--- app/views/moderation_queue/_comments.haml | 26 ++++++++++----------- config/locales/en.yml | 2 +- config/locales/es.yml | 5 ++-- config/routes.rb | 8 +++++++ 11 files changed, 82 insertions(+), 33 deletions(-) create mode 100644 app/controllers/activity_pubs_controller.rb create mode 100644 app/models/concerns/aasm_events_concern.rb diff --git a/app/controllers/activity_pubs_controller.rb b/app/controllers/activity_pubs_controller.rb new file mode 100644 index 00000000..dfe388a4 --- /dev/null +++ b/app/controllers/activity_pubs_controller.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +# Gestiona acciones de moderación +class ActivityPubsController < ApplicationController + ActivityPub.events.each do |event| + define_method(event) do + activity_pub.public_send(:"#{event}!") if activity_pub.public_send(:"may_#{event}?") + + redirect_back fallback_location: site_moderation_queue_path(**(session[:moderation_queue_filters] || {})) + end + end + + def action_on_several + + end + + private + + def activity_pub + @activity_pub ||= site.activity_pubs.find(params[:activity_pub_id]) + end +end diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index b52c2a76..95fa3bf3 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -9,6 +9,9 @@ # @see {https://www.w3.org/TR/activitypub/#client-to-server-interactions} class ActivityPub < ApplicationRecord include AASM + include AasmEventsConcern + + IGNORED_EVENTS = %i[remove] belongs_to :instance belongs_to :site diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index c6f8bfc0..1fc1a42a 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -3,6 +3,9 @@ # Mantiene la relación entre Site y Actor class ActorModeration < ApplicationRecord include AASM + include AasmEventsConcern + + IGNORED_EVENTS = [] belongs_to :site belongs_to :remote_flag, class_name: 'ActivityPub::RemoteFlag' @@ -19,13 +22,6 @@ class ActorModeration < ApplicationRecord self.update_all(aasm_state: 'paused', updated_at: Time.now) end - # Todos los eventos de la máquina de estados - # - # @return [Array] - def self.events - aasm.events.map(&:name) - end - aasm do state :paused, initial: true state :allowed diff --git a/app/models/concerns/aasm_events_concern.rb b/app/models/concerns/aasm_events_concern.rb new file mode 100644 index 00000000..79250ea9 --- /dev/null +++ b/app/models/concerns/aasm_events_concern.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module AasmEventsConcern + extend ActiveSupport::Concern + + included do + # Todos los eventos de la máquina de estados + # + # @return [Array] + def self.events + aasm.events.map(&:name) - self::IGNORED_EVENTS + end + end +end diff --git a/app/views/components/_btn_base.haml b/app/views/components/_btn_base.haml index 677b88f1..a950ad5a 100644 --- a/app/views/components/_btn_base.haml +++ b/app/views/components/_btn_base.haml @@ -1,6 +1,7 @@ -# Componente Botón general Moderación - local_assigns[:method] ||= 'patch' +- local_assigns[:class] ||= 'btn-secondary' - local_assigns[:class] = "btn #{local_assigns[:class]}" -# @todo path es obligatorio diff --git a/app/views/components/_comments_btn_box.haml b/app/views/components/_comments_btn_box.haml index 8b8d7268..285eefdb 100644 --- a/app/views/components/_comments_btn_box.haml +++ b/app/views/components/_comments_btn_box.haml @@ -1,8 +1,8 @@ -# Componente Botonera de Comentarios -- btn_class = 'btn-secondary py-1 px-2' -= render 'components/btn_base', text: t('.text_pause'), class: btn_class, href: '' -= render 'components/btn_base', text: t('.text_reject'), class: btn_class, href: '' -= render 'components/btn_base', text: t('.text_accept'), class: btn_class, href: '' -= render 'components/btn_base', text: t('.text_reply'), class: btn_class, href: '' -= render 'components/btn_base', text: t('.text_report'), class: btn_class, href: '' \ No newline at end of file +.d-flex.flex-row + - ActivityPub.events.each do |event| + = render 'components/btn_base', + text: t(".text_#{event}"), + path: public_send(:"site_activity_pub_#{event}_path", activity_pub_id: activity_pub), + disabled: !activity_pub.public_send(:"may_#{event}?") diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 29888ef7..ffaf76cf 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -1,11 +1,16 @@ --# Componente Comentario +-# + Componente Comentario + + @param profile [Hash] + @param comment [Hash] + @param activity_pub [ActivityPub] - in_reply_to = text_plain comment['inReplyTo'] -- summary = text_plain(comment['summary']) +- summary = text_plain comment['summary'] .row.no-gutters .col-1 - = render 'components/checkbox', id: comment['id'] + = render 'components/checkbox', id: activity_pub.id, name: 'activity_pub[]', value: activity_pub.id, data: { target: 'select-all.input' } .col-11 .d-flex.flex-row.align-items-center.justify-content-between %h4.mb-0 @@ -25,3 +30,4 @@ = sanitize comment['content'] - else = sanitize comment['content'] + = render 'components/comments_btn_box', activity_pub: activity_pub diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index 4fe84652..97f77e3c 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -1,14 +1,14 @@ -.row.no-gutters.pt-2 - .col-1.d-flex.align-items-center - = render 'components/select_all', id: 'select-all-comments' - .col-md-9 - -# Filtros - = render 'components/comments_filters' +%form{ action: site_activity_pubs_action_on_several_path, method: :post, data: { controller: 'select-all' } } + .row.no-gutters.pt-2 + .col-1.d-flex.align-items-center + = render 'components/select_all', id: 'select-all-comments' + .col-md-9 + -# Filtros + = render 'components/comments_filters' -- moderation_queue.each do |activity_pub| - %hr - = render 'comment', comment: activity_pub.object.content, profile: activity_pub.actor.content - - -# Botones moderación - .d-flex.justify-content-center - = render 'components/comments_btn_box', comment: activity_pub.object.content + - if moderation_queue.count.zero? + %h4= t('moderation_queue.nothing') + - moderation_queue.each do |activity_pub| + - cache [activity_pub, activity_pub.object, activity_pub.actor] do + %hr + = render 'comment', comment: activity_pub.object.content, profile: activity_pub.actor.content, activity_pub: activity_pub diff --git a/config/locales/en.yml b/config/locales/en.yml index 6d5baf5a..f69d60b0 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -93,8 +93,8 @@ en: title: Block lists comments_btn_box: text_pause: Pause + text_approve: Approve text_reject: Reject - text_accept: Accept text_reply: Reply text_report: Report instances_btn_box: diff --git a/config/locales/es.yml b/config/locales/es.yml index 13534822..a0aaa4d6 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -92,10 +92,9 @@ es: block_lists: title: Listas de bloqueo comments_btn_box: - text_pause: Pausa + text_pause: Pausar + text_approve: Aceptar text_reject: Rechazar - text_accept: Aceptar Publicación - text_reply: Responder text_report: Reportar instances_btn_box: text_check: Moderar caso por caso diff --git a/config/routes.rb b/config/routes.rb index 9d825a3c..8809767b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -82,6 +82,14 @@ Rails.application.routes.draw do patch :actor_moderations_action_on_several, to: 'actor_moderations#action_on_several' + resources :activity_pub, only: [] do + ActivityPub.events.each do |event| + patch event, to: "activity_pubs##{event}" + end + end + + patch :activity_pubs_action_on_several, to: 'activity_pubs#action_on_several' + # Gestionar artículos según idioma nested do scope '/(:locale)', constraint: /[a-z]{2}(-[A-Z]{2})?/ do From a2204779af2bca3f5b158e59553fa6c8787986b0 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 13:59:01 -0300 Subject: [PATCH 267/472] feat: filtrar por estado del comentario --- app/helpers/moderation_queue_helper.rb | 7 +++++++ app/models/activity_pub.rb | 1 + app/models/actor_moderation.rb | 1 + app/models/concerns/aasm_events_concern.rb | 7 +++++++ app/views/components/_comments_filters.haml | 2 +- app/views/components/_comments_show_submenu.haml | 8 ++++---- app/views/components/_profiles_show_submenu.haml | 4 ++-- app/views/moderation_queue/_comments.haml | 2 +- config/locales/en.yml | 8 ++++---- config/locales/es.yml | 8 ++++---- 10 files changed, 32 insertions(+), 16 deletions(-) create mode 100644 app/helpers/moderation_queue_helper.rb diff --git a/app/helpers/moderation_queue_helper.rb b/app/helpers/moderation_queue_helper.rb new file mode 100644 index 00000000..3681bec3 --- /dev/null +++ b/app/helpers/moderation_queue_helper.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module ModerationQueueHelper + def filter_states(**args) + params.permit(:state, :actor_state, :activity_pub_state).merge(**args) + end +end diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 95fa3bf3..51ee0d71 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -12,6 +12,7 @@ class ActivityPub < ApplicationRecord include AasmEventsConcern IGNORED_EVENTS = %i[remove] + IGNORED_STATES = %i[removed] belongs_to :instance belongs_to :site diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index 1fc1a42a..421d4c6e 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -6,6 +6,7 @@ class ActorModeration < ApplicationRecord include AasmEventsConcern IGNORED_EVENTS = [] + IGNORED_STATES = [] belongs_to :site belongs_to :remote_flag, class_name: 'ActivityPub::RemoteFlag' diff --git a/app/models/concerns/aasm_events_concern.rb b/app/models/concerns/aasm_events_concern.rb index 79250ea9..59ea243f 100644 --- a/app/models/concerns/aasm_events_concern.rb +++ b/app/models/concerns/aasm_events_concern.rb @@ -10,5 +10,12 @@ module AasmEventsConcern def self.events aasm.events.map(&:name) - self::IGNORED_EVENTS end + + # Todos los estados de la máquina de estados + # + # @return [Array] + def self.states + aasm.states.map(&:name) - self::IGNORED_STATES + end end end diff --git a/app/views/components/_comments_filters.haml b/app/views/components/_comments_filters.haml index 7c453088..b4597be5 100644 --- a/app/views/components/_comments_filters.haml +++ b/app/views/components/_comments_filters.haml @@ -3,4 +3,4 @@ = render 'components/comments_checked_submenu' = render 'components/dropdown', text: t('.text_show') do - = render 'components/comments_show_submenu' \ No newline at end of file + = render 'components/comments_show_submenu', activity_pubs: activity_pubs diff --git a/app/views/components/_comments_show_submenu.haml b/app/views/components/_comments_show_submenu.haml index 0308b926..eb037975 100644 --- a/app/views/components/_comments_show_submenu.haml +++ b/app/views/components/_comments_show_submenu.haml @@ -1,4 +1,4 @@ -= render 'components/dropdown_item', text: t('.submenu_pause'), path: '/' -= render 'components/dropdown_item', text: t('.submenu_accept'), path: '/' -= render 'components/dropdown_item', text: t('.submenu_report'), path: '/' -= render 'components/dropdown_item', text: t('.submenu_reject'), path: '/' \ No newline at end of file +- ActivityPub.states.each do |state| + = render 'components/dropdown_item', + text: t(".submenu_#{state}", count: activity_pubs.unscope(where: :aasm_state).public_send(state).count), + path: site_moderation_queue_path(filter_states(activity_pub_state: state)) diff --git a/app/views/components/_profiles_show_submenu.haml b/app/views/components/_profiles_show_submenu.haml index 703e4a15..0209ef2f 100644 --- a/app/views/components/_profiles_show_submenu.haml +++ b/app/views/components/_profiles_show_submenu.haml @@ -1,4 +1,4 @@ -- ActorModeration.aasm.states.map(&:name).each do |actor_state| +- ActorModeration.states.each do |actor_state| = render 'components/dropdown_item', text: t(".submenu_#{actor_state}", count: actor_moderations.unscope(where: :aasm_state).public_send(actor_state).count), - path: site_moderation_queue_path(params.permit(:state, :actor_state).merge(actor_state: actor_state)) + path: site_moderation_queue_path(filter_states(actor_state: actor_state)) diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index 97f77e3c..f243b02a 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -4,7 +4,7 @@ = render 'components/select_all', id: 'select-all-comments' .col-md-9 -# Filtros - = render 'components/comments_filters' + = render 'components/comments_filters', activity_pubs: moderation_queue - if moderation_queue.count.zero? %h4= t('moderation_queue.nothing') diff --git a/config/locales/en.yml b/config/locales/en.yml index f69d60b0..eecd5ebd 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -72,10 +72,10 @@ en: submenu_accept: Accept submenu_reject: Reject comments_show_submenu: - submenu_pause: Pause - submenu_accept: Accept - submenu_report: Report - submenu_reject: Reject + submenu_paused: "Paused (%{count})" + submenu_approved: "Approved (%{count})" + submenu_rejected: "Rejected (%{count})" + submenu_reported: "Reported (%{count})" profiles_filters: text_show: Show text_checked: With selected diff --git a/config/locales/es.yml b/config/locales/es.yml index a0aaa4d6..0f9eb68a 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -72,10 +72,10 @@ es: submenu_accept: Aceptado submenu_reject: Rechazado comments_show_submenu: - submenu_pause: Pausado - submenu_accept: Aceptado - submenu_report: Reportado - submenu_reject: Rechazado + submenu_paused: "Pausados (%{count})" + submenu_approved: "Aprobados (%{count})" + submenu_rejected: "Rechazados (%{count})" + submenu_reported: "Reportados (%{count})" profiles_filters: text_show: Ver text_checked: Con los marcados From 0b3f4e33fb4f32671f11bc6b2593adfe3a60524b Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 14:25:19 -0300 Subject: [PATCH 268/472] =?UTF-8?q?fix:=20siempre=20es=20un=20bot=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://blog.saeloun.com/2021/08/24/rails-7-button-to-rendering/ --- app/views/components/_btn_base.haml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/components/_btn_base.haml b/app/views/components/_btn_base.haml index a950ad5a..4d8566d3 100644 --- a/app/views/components/_btn_base.haml +++ b/app/views/components/_btn_base.haml @@ -5,4 +5,5 @@ - local_assigns[:class] = "btn #{local_assigns[:class]}" -# @todo path es obligatorio -= button_to text, local_assigns[:path], **local_assigns += button_to local_assigns[:path], **local_assigns do + = text From 27d7589f9aab294283df57a14fa3b9a7cb7c7ee9 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 14:26:41 -0300 Subject: [PATCH 269/472] fix: no se pueden anidar formularios MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit usando el atributo form, podemos crear un formulario vacío y colocar inputs por fuera de su contexto. de lo contrario el primer botón de acción individual no funciona --- app/models/instance_moderation.rb | 7 +++-- app/views/components/_checkbox.haml | 2 +- app/views/components/_dropdown_button.haml | 2 +- .../_instances_checked_submenu.haml | 5 ++- app/views/components/_instances_filters.haml | 2 +- app/views/components/_select_all.haml | 2 +- app/views/moderation_queue/_comment.haml | 2 +- app/views/moderation_queue/_instance.haml | 2 +- app/views/moderation_queue/_instances.haml | 31 ++++++++++--------- 9 files changed, 28 insertions(+), 27 deletions(-) diff --git a/app/models/instance_moderation.rb b/app/models/instance_moderation.rb index 10b5e8e0..7447cc89 100644 --- a/app/models/instance_moderation.rb +++ b/app/models/instance_moderation.rb @@ -3,6 +3,10 @@ # Mantiene el registro de relaciones entre sitios e instancias class InstanceModeration < ApplicationRecord include AASM + include AasmEventsConcern + + IGNORED_EVENTS = [] + IGNORED_STATES = [] belongs_to :site belongs_to :instance, class_name: 'ActivityPub::Instance' @@ -11,9 +15,6 @@ class InstanceModeration < ApplicationRecord # todas las que no estén bloqueadas ya. scope :may_block, -> { where.not(aasm_state: 'blocked') } scope :may_pause, -> { where.not(aasm_state: 'paused') } - scope :paused, -> { where(aasm_state: 'paused') } - scope :blocked, -> { where(aasm_state: 'blocked') } - scope :allowed, -> { where(aasm_state: 'allowed') } # Bloquear instancias en masa def self.block_all! diff --git a/app/views/components/_checkbox.haml b/app/views/components/_checkbox.haml index 596ff074..68f1a663 100644 --- a/app/views/components/_checkbox.haml +++ b/app/views/components/_checkbox.haml @@ -1,5 +1,5 @@ -# Componente Checkbox - local_assigns[:name] ||= id .custom-control.custom-checkbox - %input.custom-control-input{ type: 'checkbox', id: id, **local_assigns } + %input.custom-control-input{ form: local_assigns[:form_id], type: 'checkbox', id: id, **local_assigns } %label.custom-control-label{ for: id }= yield diff --git a/app/views/components/_dropdown_button.haml b/app/views/components/_dropdown_button.haml index 8b0c4684..c8c98209 100644 --- a/app/views/components/_dropdown_button.haml +++ b/app/views/components/_dropdown_button.haml @@ -1,4 +1,4 @@ -# @param name [String] @param value [String] -%button.dropdown-item{type: 'submit', data: { target: 'dropdown.item' }, name: name, value: value }= text +%button.dropdown-item{type: 'submit', data: { target: 'dropdown.item' }, name: name, value: value, form: local_assigns[:form_id] }= text diff --git a/app/views/components/_instances_checked_submenu.haml b/app/views/components/_instances_checked_submenu.haml index c3573ead..2d28fb1c 100644 --- a/app/views/components/_instances_checked_submenu.haml +++ b/app/views/components/_instances_checked_submenu.haml @@ -1,3 +1,2 @@ -= render 'components/dropdown_button', text: t('.submenu_pause'), name: 'instance_moderation_action', value: 'pause' -= render 'components/dropdown_button', text: t('.submenu_allow'), name: 'instance_moderation_action', value: 'allow' -= render 'components/dropdown_button', text: t('.submenu_block'), name: 'instance_moderation_action', value: 'block' +- InstanceModeration.events.each do |event| + = render 'components/dropdown_button', text: t(".submenu_#{event}"), name: 'instance_moderation_action', value: event, form_id: form_id diff --git a/app/views/components/_instances_filters.haml b/app/views/components/_instances_filters.haml index fe40ced3..2c05693a 100644 --- a/app/views/components/_instances_filters.haml +++ b/app/views/components/_instances_filters.haml @@ -1,6 +1,6 @@ .d-flex.py-2 = render 'components/dropdown', text: t('.text_checked') do - = render 'components/instances_checked_submenu' + = render 'components/instances_checked_submenu', form_id: form_id = render 'components/dropdown', text: t('.text_show') do = render 'components/instances_show_submenu', site: site diff --git a/app/views/components/_select_all.haml b/app/views/components/_select_all.haml index 2603dfd3..68711c4a 100644 --- a/app/views/components/_select_all.haml +++ b/app/views/components/_select_all.haml @@ -1,4 +1,4 @@ -# @param id [String] -= render 'components/checkbox', id: id, data: { action: 'select-all#toggle', target: 'select-all.toggle' } do += render 'components/checkbox', id: id, form: local_assigns[:form_id], data: { action: 'select-all#toggle', target: 'select-all.toggle' } do %span.sr-only= t('.label') diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index ffaf76cf..33ebc722 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -10,7 +10,7 @@ .row.no-gutters .col-1 - = render 'components/checkbox', id: activity_pub.id, name: 'activity_pub[]', value: activity_pub.id, data: { target: 'select-all.input' } + = render 'components/checkbox', id: activity_pub.id, name: 'activity_pub[]', value: activity_pub.id, data: { target: 'select-all.input' }, form: form_id .col-11 .d-flex.flex-row.align-items-center.justify-content-between %h4.mb-0 diff --git a/app/views/moderation_queue/_instance.haml b/app/views/moderation_queue/_instance.haml index 97d23f10..05510724 100644 --- a/app/views/moderation_queue/_instance.haml +++ b/app/views/moderation_queue/_instance.haml @@ -3,7 +3,7 @@ .row.no-gutters.pt-2 .col-1 - = render 'components/checkbox', id: instance.hostname, name: 'instance_moderation[]', value: instance_moderation.id, data: { target: 'select-all.input' } + = render 'components/checkbox', id: instance.hostname, form_id: form_id, name: 'instance_moderation[]', value: instance_moderation.id, data: { target: 'select-all.input' } .col-11 %h4 %a{ href: instance.uri }= sanitize(instance.content['title']) || instance.hostname diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index 77b6adea..83b0c772 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -1,22 +1,23 @@ +- form_id = 'instance_moderation_action_on_several' %section - %form{ action: site_instance_moderations_action_on_several_path, method: :post } - .row.no-gutters.pt-2{ data: { controller: 'select-all' } } - .col-1.d-flex.align-items-center - = render 'components/select_all', id: 'instances' - .col-11 - -# Filtros - = render 'components/instances_filters', site: site + %form{ id: form_id, action: site_instance_moderations_action_on_several_path, method: :post } + .row.no-gutters.pt-2{ data: { controller: 'select-all' } } + .col-1.d-flex.align-items-center + = render 'components/select_all', id: 'instances', form_id: form_id + .col-11 + -# Filtros + = render 'components/instances_filters', site: site, form_id: form_id - .col-12 - - if instance_moderations.count.zero? - %h4= t('moderation_queue.nothing') + .col-12 + - if instance_moderations.count.zero? + %h4= t('moderation_queue.nothing') - - instance_moderations.each do |instance_moderation| - - cache [instance_moderation.aasm_state, instance_moderation.instance] do - %hr - = render 'moderation_queue/instance', instance_moderation: instance_moderation, instance: instance_moderation.instance + - instance_moderations.each do |instance_moderation| + - cache [instance_moderation.aasm_state, instance_moderation.instance] do + %hr + = render 'moderation_queue/instance', instance_moderation: instance_moderation, instance: instance_moderation.instance, form_id: form_id - %hr + %hr %div %h3.mt-5= t('moderation_queue.instances.title') %lead= t('moderation_queue.instances.description') From 5211c9bd28c089ea6db5b568bf20e2497e5a1597 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 14:39:06 -0300 Subject: [PATCH 270/472] fix: formularios --- .../components/_profiles_checked_submenu.haml | 2 +- app/views/components/_profiles_filters.haml | 2 +- app/views/moderation_queue/_account.haml | 2 +- app/views/moderation_queue/_accounts.haml | 31 ++++++++++--------- 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/app/views/components/_profiles_checked_submenu.haml b/app/views/components/_profiles_checked_submenu.haml index c0b99aa5..13e016ca 100644 --- a/app/views/components/_profiles_checked_submenu.haml +++ b/app/views/components/_profiles_checked_submenu.haml @@ -1,2 +1,2 @@ - ActorModeration.events.each do |actor_event| - = render 'components/dropdown_button', text: t(".submenu_#{actor_event}"), name: 'actor_moderation_action', value: actor_event + = render 'components/dropdown_button', text: t(".submenu_#{actor_event}"), name: 'actor_moderation_action', value: actor_event, form_id: form_id diff --git a/app/views/components/_profiles_filters.haml b/app/views/components/_profiles_filters.haml index c6397e69..a2593f4c 100644 --- a/app/views/components/_profiles_filters.haml +++ b/app/views/components/_profiles_filters.haml @@ -1,6 +1,6 @@ .d-flex.py-2 = render 'components/dropdown', text: t('.text_checked') do - = render 'components/profiles_checked_submenu' + = render 'components/profiles_checked_submenu', form_id: form_id = render 'components/dropdown', text: t('.text_show') do = render 'components/profiles_show_submenu', actor_moderations: actor_moderations diff --git a/app/views/moderation_queue/_account.haml b/app/views/moderation_queue/_account.haml index fee90316..f63b6f6f 100644 --- a/app/views/moderation_queue/_account.haml +++ b/app/views/moderation_queue/_account.haml @@ -1,6 +1,6 @@ .row.no-gutters.pt-2 .col-1 - = render 'components/checkbox', id: actor_moderation.id, name: 'actor_moderation[]', value: actor_moderation.id, data: { target: 'select-all.input' } + = render 'components/checkbox', id: actor_moderation.id, form_id: form_id, name: 'actor_moderation[]', value: actor_moderation.id, data: { target: 'select-all.input' } .col-11 %h4 = link_to text_plain(profile['name']), site_actor_moderation_path(id: actor_moderation) diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index 35b0b86e..53d2f28e 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -1,14 +1,17 @@ -%form{ action: site_actor_moderations_action_on_several_path, method: :post } - .row.no-gutters.pt-2{ data: { controller: 'select-all' } } - .col-1.d-flex.align-items-center - = render 'components/select_all', id: 'actors' - .col-11 - -# Filtros - = render 'components/profiles_filters', actor_moderations: actor_moderations - .col-12 - - if actor_moderations.count.zero? - %h4= t('moderation_queue.nothing') - - actor_moderations.find_each do |actor_moderation| - - cache [actor_moderation, actor_moderation.actor] do - %hr - = render 'account', actor_moderation: actor_moderation, profile: actor_moderation.actor.content +- form_id = 'actor_moderations_action_on_several' + += form_tag site_actor_moderations_action_on_several_path, id: form_id, method: :patch + +.row.no-gutters.pt-2{ data: { controller: 'select-all' } } + .col-1.d-flex.align-items-center + = render 'components/select_all', id: 'actors', form_id: form_id + .col-11 + -# Filtros + = render 'components/profiles_filters', actor_moderations: actor_moderations, form_id: form_id + .col-12 + - if actor_moderations.count.zero? + %h4= t('moderation_queue.nothing') + - actor_moderations.find_each do |actor_moderation| + - cache [actor_moderation, actor_moderation.actor] do + %hr + = render 'account', actor_moderation: actor_moderation, profile: actor_moderation.actor.content, form_id: form_id From 8e681cdba79024e6fb584654025ce730d9c5d90a Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 14:47:20 -0300 Subject: [PATCH 271/472] fix: sincronizar controladores --- app/controllers/activity_pubs_controller.rb | 8 +++-- .../actor_moderations_controller.rb | 6 +++- .../concerns/moderation_concern.rb | 13 ++++++++ .../instance_moderations_controller.rb | 32 ++++++------------- .../moderation_queue_controller.rb | 2 +- app/policies/activity_pub_policy.rb | 16 ++++++++++ app/policies/instance_moderation_policy.rb | 14 +++----- 7 files changed, 55 insertions(+), 36 deletions(-) create mode 100644 app/controllers/concerns/moderation_concern.rb create mode 100644 app/policies/activity_pub_policy.rb diff --git a/app/controllers/activity_pubs_controller.rb b/app/controllers/activity_pubs_controller.rb index dfe388a4..057e65f7 100644 --- a/app/controllers/activity_pubs_controller.rb +++ b/app/controllers/activity_pubs_controller.rb @@ -2,16 +2,20 @@ # Gestiona acciones de moderación class ActivityPubsController < ApplicationController + include ModerationConcern + ActivityPub.events.each do |event| define_method(event) do + authorize activity_pub + activity_pub.public_send(:"#{event}!") if activity_pub.public_send(:"may_#{event}?") - redirect_back fallback_location: site_moderation_queue_path(**(session[:moderation_queue_filters] || {})) + redirect_to_moderation_queue! end end def action_on_several - + redirect_to_moderation_queue! end private diff --git a/app/controllers/actor_moderations_controller.rb b/app/controllers/actor_moderations_controller.rb index 907f21c6..eadc2165 100644 --- a/app/controllers/actor_moderations_controller.rb +++ b/app/controllers/actor_moderations_controller.rb @@ -2,6 +2,8 @@ # Gestiona la cola de moderación de actores class ActorModerationsController < ApplicationController + include ModerationConcern + ActorModeration.events.each do |actor_event| define_method(actor_event) do authorize actor_moderation @@ -11,7 +13,7 @@ class ActorModerationsController < ApplicationController actor_moderation.public_send(:"#{actor_event}!") if actor_moderation.public_send(:"may_#{actor_event}?") - redirect_back fallback_location: site_moderation_queue_path(**(session[:moderation_queue_filters] || {})) + redirect_to_moderation_queue! end end @@ -29,6 +31,8 @@ class ActorModerationsController < ApplicationController method = :"#{action}!" may = :"may_#{action}?" + redirect_to_moderation_queue! + return unless ActorModeration.events.include? action ActorModeration.transaction do diff --git a/app/controllers/concerns/moderation_concern.rb b/app/controllers/concerns/moderation_concern.rb new file mode 100644 index 00000000..9a4f1c16 --- /dev/null +++ b/app/controllers/concerns/moderation_concern.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module ModerationConcern + extend ActiveSupport::Concern + + included do + private + + def redirect_to_moderation_queue! + redirect_back fallback_location: site_moderation_queue_path(**(session[:moderation_queue_filters] || {})) + end + end +end diff --git a/app/controllers/instance_moderations_controller.rb b/app/controllers/instance_moderations_controller.rb index dc9e1dfa..270f0588 100644 --- a/app/controllers/instance_moderations_controller.rb +++ b/app/controllers/instance_moderations_controller.rb @@ -2,19 +2,16 @@ # Actualiza la relación entre un sitio y una instancia class InstanceModerationsController < ApplicationController - before_action :authorize_policy, except: %i[action_on_several] - around_action :redirect_to_moderation_queue! + include ModerationConcern - def pause - instance_moderation.pause! if instance_moderation.may_pause? - end + InstanceModeration.events.each do |event| + define_method(event) do + authorize instance_moderation - def allow - instance_moderation.allow! if instance_moderation.may_allow? - end + instance_moderation.public_send(:"#{event}!") if instance_moderation.public_send(:"may_#{event}?") - def block - instance_moderation.block! if instance_moderation.may_block? + redirect_to_moderation_queue! + end end def action_on_several @@ -25,9 +22,10 @@ class InstanceModerationsController < ApplicationController action = params[:instance_moderation_action].to_sym method = :"#{action}!" may = :"may_#{action}?" - events = instance_moderation.aasm.events.map(&:name) - return unless events.include? action + redirect_to_moderation_queue! + + return unless InstanceModeration.events.include? action InstanceModeration.transaction do instance_moderations.find_each do |instance_moderation| @@ -38,18 +36,8 @@ class InstanceModerationsController < ApplicationController private - def redirect_to_moderation_queue!(&action) - redirect_back fallback_location: site_moderation_queue_path, state: session[:moderation_queue_filtered_by_state] - - yield - end - # @return [InstanceModeration] def instance_moderation @instance_moderation ||= site.instance_moderations.find(params[:instance_moderation_id]) end - - def authorize_policy - authorize instance_moderation - end end diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index b803ccc9..6a628aaa 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -6,7 +6,7 @@ class ModerationQueueController < ApplicationController def index dummy_data - session[:moderation_queue_filters] = params.permit(:state, :actor_state) + session[:moderation_queue_filters] = params.permit(:state, :actor_state, :activity_pub_state) # @todo cambiar el estado por query @activity_pubs = site.activity_pubs diff --git a/app/policies/activity_pub_policy.rb b/app/policies/activity_pub_policy.rb new file mode 100644 index 00000000..f5755840 --- /dev/null +++ b/app/policies/activity_pub_policy.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# Solo les usuaries pueden moderar comentarios +ActivityPubPolicy = Struct.new(:usuarie, :activity_pub) do + ActivityPub.events.each do |event| + define_method(:"#{event}?") do + activity_pub.site.usuarie? usuarie + end + end + + # En este paso tenemos varias instancias por moderar pero todas son + # del mismo sitio. + def action_on_several? + activity_pub.first.site.usuarie? usuarie + end +end diff --git a/app/policies/instance_moderation_policy.rb b/app/policies/instance_moderation_policy.rb index c07455b3..13ebfeca 100644 --- a/app/policies/instance_moderation_policy.rb +++ b/app/policies/instance_moderation_policy.rb @@ -2,16 +2,10 @@ # 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? + InstanceModeration.events.each do |event| + define_method(:"#{event}?") do + instance_moderation.site.usuarie? usuarie + end end # En este paso tenemos varias instancias por moderar pero todas son From a7d33976ec7c5da2d3a7a5257eee7ba66d329ce9 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 14:59:17 -0300 Subject: [PATCH 272/472] fixup! fix: no se pueden anidar formularios --- app/views/moderation_queue/_instances.haml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index 83b0c772..a707d48a 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -1,6 +1,8 @@ - form_id = 'instance_moderation_action_on_several' + %section - %form{ id: form_id, action: site_instance_moderations_action_on_several_path, method: :post } + = form_tag site_instance_moderations_action_on_several_path, id: form_id, method: :patch + .row.no-gutters.pt-2{ data: { controller: 'select-all' } } .col-1.d-flex.align-items-center = render 'components/select_all', id: 'instances', form_id: form_id From 3967a631632c09a1310c4248c7b1a61406284d3e Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 15:10:20 -0300 Subject: [PATCH 273/472] feat: extraer en un componente --- app/views/components/_select_all_container.haml | 13 +++++++++++++ app/views/moderation_queue/_accounts.haml | 2 +- app/views/moderation_queue/_instances.haml | 3 +-- 3 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 app/views/components/_select_all_container.haml diff --git a/app/views/components/_select_all_container.haml b/app/views/components/_select_all_container.haml new file mode 100644 index 00000000..5fa91e2d --- /dev/null +++ b/app/views/components/_select_all_container.haml @@ -0,0 +1,13 @@ +-# + Contenedor para las acciones en masa. + + Es un formulario auto-contenido, que permite colocar los elementos + fuera del formulario para evitar anidarlos. Mientras los elementos + tengan el atributo `form` con el mismo parámetro `form_id`, el + navegador los va a asignar a este formulario. + + @param path [String] + @param form_id [String] + += form_tag path, id: form_id, method: :patch do + -# nada diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index 53d2f28e..65ff953f 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -1,6 +1,6 @@ - form_id = 'actor_moderations_action_on_several' -= form_tag site_actor_moderations_action_on_several_path, id: form_id, method: :patch += render 'components/select_all_container', path: site_actor_moderations_action_on_several_path, form_id: form_id .row.no-gutters.pt-2{ data: { controller: 'select-all' } } .col-1.d-flex.align-items-center diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index a707d48a..d9db967f 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -1,8 +1,7 @@ - form_id = 'instance_moderation_action_on_several' %section - = form_tag site_instance_moderations_action_on_several_path, id: form_id, method: :patch - + = render 'components/select_all_container', path: site_instance_moderations_action_on_several_path, form_id: form_id .row.no-gutters.pt-2{ data: { controller: 'select-all' } } .col-1.d-flex.align-items-center = render 'components/select_all', id: 'instances', form_id: form_id From b201c3de1881c0e20f8b53468ea69f62b8aeb386 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 15:11:29 -0300 Subject: [PATCH 274/472] feat: filtros y acciones para comentarios --- .../components/_comments_checked_submenu.haml | 5 ++-- app/views/components/_comments_filters.haml | 2 +- app/views/moderation_queue/_comments.haml | 27 ++++++++++--------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/app/views/components/_comments_checked_submenu.haml b/app/views/components/_comments_checked_submenu.haml index 4998e5c7..fa3d7612 100644 --- a/app/views/components/_comments_checked_submenu.haml +++ b/app/views/components/_comments_checked_submenu.haml @@ -1,3 +1,2 @@ -= render 'components/dropdown_item', text: t('.submenu_pause'), path: '/' -= render 'components/dropdown_item', text: t('.submenu_accept'), path: '/' -= render 'components/dropdown_item', text: t('.submenu_reject'), path: '/' \ No newline at end of file +- ActivityPub.events.each do |event| + = render 'components/dropdown_button', form_id: form_id, text: t(".submenu_#{event}"), name: 'activity_pub_action', value: event diff --git a/app/views/components/_comments_filters.haml b/app/views/components/_comments_filters.haml index b4597be5..15f5173d 100644 --- a/app/views/components/_comments_filters.haml +++ b/app/views/components/_comments_filters.haml @@ -1,6 +1,6 @@ .d-flex.py-2 = render 'components/dropdown', text: t('.text_checked') do - = render 'components/comments_checked_submenu' + = render 'components/comments_checked_submenu', form_id: form_id = render 'components/dropdown', text: t('.text_show') do = render 'components/comments_show_submenu', activity_pubs: activity_pubs diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index f243b02a..bf1e94a0 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -1,14 +1,17 @@ -%form{ action: site_activity_pubs_action_on_several_path, method: :post, data: { controller: 'select-all' } } - .row.no-gutters.pt-2 - .col-1.d-flex.align-items-center - = render 'components/select_all', id: 'select-all-comments' - .col-md-9 - -# Filtros - = render 'components/comments_filters', activity_pubs: moderation_queue +- form_id = 'activity_pub_action_on_several' - - if moderation_queue.count.zero? - %h4= t('moderation_queue.nothing') - - moderation_queue.each do |activity_pub| - - cache [activity_pub, activity_pub.object, activity_pub.actor] do += render 'components/select_all_container', path: site_activity_pubs_action_on_several_path, form_id: form_id + +.row.no-gutters.pt-2{ data: { controller: 'select-all' } } + .col-1.d-flex.align-items-center + = render 'components/select_all', id: 'select-all-comments', form_id: form_id + .col-md-9 + -# Filtros + = render 'components/comments_filters', activity_pubs: moderation_queue, form_id: form_id + .col-12 + - if moderation_queue.count.zero? + %h4= t('moderation_queue.nothing') + - moderation_queue.each do |activity_pub| + -# cache [activity_pub, activity_pub.object, activity_pub.actor] do %hr - = render 'comment', comment: activity_pub.object.content, profile: activity_pub.actor.content, activity_pub: activity_pub + = render 'comment', comment: activity_pub.object.content, profile: activity_pub.actor.content, activity_pub: activity_pub, form_id: form_id From b7989808655e29cfad5db4d04755b28194108a88 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 15:13:01 -0300 Subject: [PATCH 275/472] feat: acciones masivas para comentarios --- app/controllers/activity_pubs_controller.rb | 16 ++++++++++++++++ config/locales/en.yml | 3 ++- config/locales/es.yml | 7 ++++--- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/app/controllers/activity_pubs_controller.rb b/app/controllers/activity_pubs_controller.rb index 057e65f7..9bbbb9cc 100644 --- a/app/controllers/activity_pubs_controller.rb +++ b/app/controllers/activity_pubs_controller.rb @@ -15,7 +15,23 @@ class ActivityPubsController < ApplicationController end def action_on_several + activity_pubs = site.activity_pubs.where(id: params[:activity_pub]) + + authorize activity_pubs + + action = params[:activity_pub_action].to_sym + method = :"#{action}!" + may = :"may_#{action}?" + redirect_to_moderation_queue! + + return unless ActivityPub.events.include? action + + ActivityPub.transaction do + activity_pubs.find_each do |activity_pub| + activity_pub.public_send(method) if activity_pub.public_send(may) + end + end end private diff --git a/config/locales/en.yml b/config/locales/en.yml index eecd5ebd..a10b9f3a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -69,8 +69,9 @@ en: text_checked: With selected comments_checked_submenu: submenu_pause: Pause - submenu_accept: Accept + submenu_approve: Approve submenu_reject: Reject + submenu_report: Report comments_show_submenu: submenu_paused: "Paused (%{count})" submenu_approved: "Approved (%{count})" diff --git a/config/locales/es.yml b/config/locales/es.yml index 0f9eb68a..f5487e47 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -68,9 +68,10 @@ es: text_show: Ver text_checked: Con los marcados comments_checked_submenu: - submenu_pause: Pausado - submenu_accept: Aceptado - submenu_reject: Rechazado + submenu_pause: Pausar + submenu_approve: Aprobar + submenu_reject: Rechazar + submenu_report: Reportar comments_show_submenu: submenu_paused: "Pausados (%{count})" submenu_approved: "Aprobados (%{count})" From ccd3df2038b893b0ead29682df691dbb81862dfa Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 16:46:43 -0300 Subject: [PATCH 276/472] feat: aprobar o rechazar actividades --- app/models/activity_pub.rb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 51ee0d71..838eea80 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -64,14 +64,26 @@ class ActivityPub < ApplicationRecord transitions from: %i[approved rejected], to: :paused end - # La actividad se aprueba + # La actividad se aprueba, informándole a la Social Inbox que está + # aprobada. También recibimos la aprobación via + # webhook a modo de confirmación. event :approve do transitions from: %i[paused rejected], to: :approved + + before do + raise AASM::InvalidTransition unless + site.social_inbox.inbox.accept(id: object.uri).ok? + end end # La actividad fue rechazada event :reject do transitions from: %i[paused approved], to: :rejected + + before do + raise AASM::InvalidTransition unless + site.social_inbox.inbox.reject(id: object.uri).ok? + end end # Solo podemos reportarla luego de rechazarla From 0e2a4c42882774f56a494e29fb674401b10904e2 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 16:52:28 -0300 Subject: [PATCH 277/472] =?UTF-8?q?fix:=20todav=C3=ADa=20no=20se=20puede?= =?UTF-8?q?=20volver=20de=20una=20actividad=20rechazada?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/activity_pub.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 838eea80..0cd44814 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -61,14 +61,14 @@ class ActivityPub < ApplicationRecord # Si un objeto previamente aprobado fue actualizado, volvemos a # pausarlo. event :pause do - transitions from: %i[approved rejected], to: :paused + transitions from: %i[approved], to: :paused end # La actividad se aprueba, informándole a la Social Inbox que está # aprobada. También recibimos la aprobación via # webhook a modo de confirmación. event :approve do - transitions from: %i[paused rejected], to: :approved + transitions from: %i[paused], to: :approved before do raise AASM::InvalidTransition unless From 1fe6199cea375c319e6eb3423985151337d091e8 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 16:53:23 -0300 Subject: [PATCH 278/472] =?UTF-8?q?fix:=20todav=C3=ADa=20no=20se=20puede?= =?UTF-8?q?=20pausar=20luego=20de=20aprobar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/activity_pub.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 0cd44814..6f0d884c 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -58,12 +58,6 @@ class ActivityPub < ApplicationRecord end end - # Si un objeto previamente aprobado fue actualizado, volvemos a - # pausarlo. - event :pause do - transitions from: %i[approved], to: :paused - end - # La actividad se aprueba, informándole a la Social Inbox que está # aprobada. También recibimos la aprobación via # webhook a modo de confirmación. From c49182e278edd723a29fcad7671a138ee1f1d623 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 17:14:46 -0300 Subject: [PATCH 279/472] feat: poder bloquear en masa --- .../actor_moderations_controller.rb | 27 ++++++++++++++++--- app/views/components/_profiles_btn_box.haml | 12 +-------- config/locales/en.yml | 2 +- config/locales/es.yml | 2 +- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/app/controllers/actor_moderations_controller.rb b/app/controllers/actor_moderations_controller.rb index eadc2165..2d834015 100644 --- a/app/controllers/actor_moderations_controller.rb +++ b/app/controllers/actor_moderations_controller.rb @@ -9,7 +9,7 @@ class ActorModerationsController < ApplicationController authorize actor_moderation # Crea una RemoteFlag si se envían los parámetros adecuados - actor_moderation.update(actor_moderation_params) if actor_event == :report + actor_moderation.update(actor_moderation_params(actor_moderation)) if actor_event == :report actor_moderation.public_send(:"#{actor_event}!") if actor_moderation.public_send(:"may_#{actor_event}?") @@ -37,7 +37,11 @@ class ActorModerationsController < ApplicationController ActorModeration.transaction do actor_moderations.find_each do |actor_moderation| - actor_moderation.public_send(method) if actor_moderation.public_send(may) + next unless actor_moderation.public_send(may) + + actor_moderation.update(actor_moderation_params(actor_moderation)) if action == :report + + actor_moderation.public_send(method) end end end @@ -48,10 +52,25 @@ class ActorModerationsController < ApplicationController @actor_moderation ||= site.actor_moderations.find(params[:actor_moderation_id] || params[:id]) end - def actor_moderation_params - params.require(:actor_moderation).permit(remote_flag_attributes: %i[message]).tap do |p| + # @return [String] + def panel_actor_mention + @panel_actor_mention ||= ENV.fetch('PANEL_ACTOR_MENTION', '@sutty@sutty.nl') + end + + # @return [Hash] + def actor_moderation_params(actor_moderation) + { remote_flag_attributes: { id: actor_moderation.remote_flag_id, message: '' } }.tap do |p| p[:remote_flag_attributes][:site_id] = actor_moderation.site_id p[:remote_flag_attributes][:actor_id] = actor_moderation.actor_id + + I18n.available_locales.each do |locale| + p[:remote_flag_attributes][:message].tap do |m| + m += I18n.t(locale) + m += ': ' + m += I18n.t('actor_moderations.report_message', locale: locale, panel_actor_mention: panel_actor_mention) + m += '\n\n' + end + end end end end diff --git a/app/views/components/_profiles_btn_box.haml b/app/views/components/_profiles_btn_box.haml index 3ec95e59..073c142e 100644 --- a/app/views/components/_profiles_btn_box.haml +++ b/app/views/components/_profiles_btn_box.haml @@ -1,13 +1,4 @@ -# Componente Botonera de Moderación de Cuentas (Remote_profile) - -- form_params = {} -- form_params[:report] = { actor_moderation: { remote_flag_attributes: { message: '' } } } -- I18n.available_locales.each do |locale| - - form_params[:report][:actor_moderation][:remote_flag_attributes][:message] += t(locale) - - form_params[:report][:actor_moderation][:remote_flag_attributes][:message] += ': ' - - form_params[:report][:actor_moderation][:remote_flag_attributes][:message] += t('.report_message', locale: locale, panel_actor_mention: ENV.fetch('PANEL_ACTOR_MENTION') { '@sutty@sutty.nl' }) - - form_params[:report][:actor_moderation][:remote_flag_attributes][:message] += '\n\n' - .d-flex.flex-row - btn_class = 'btn-secondary' - ActorModeration.events.each do |actor_event| @@ -15,5 +6,4 @@ text: t(".text_#{actor_event}"), path: public_send(:"site_actor_moderation_#{actor_event}_path", actor_moderation_id: actor_moderation), class: btn_class, - disabled: !actor_moderation.public_send(:"may_#{actor_event}?"), - params: form_params[actor_event] + disabled: !actor_moderation.public_send(:"may_#{actor_event}?") diff --git a/config/locales/en.yml b/config/locales/en.yml index a10b9f3a..fe8798f4 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -107,7 +107,6 @@ en: text_allow: Always approve text_block: Block text_report: Report - report_message: "Hi! Someone using Sutty CMS reported this account on your instance. We don't have support for customized report messages yet, but we will soon. You can reach us at %{panel_actor_mention}." actor_moderations: show: user: Username @@ -117,6 +116,7 @@ en: profile_id: ID profile_published: Published profile_summary: Summary + report_message: "Hi! Someone using Sutty CMS reported this account on your instance. We don't have support for customized report messages yet, but we will soon. You can reach us at %{panel_actor_mention}." moderation_queue: everything: 'Select all' nothing: "There's nothing for this filter" diff --git a/config/locales/es.yml b/config/locales/es.yml index f5487e47..e22fdf57 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -106,7 +106,6 @@ es: text_allow: Aprobar siempre text_block: Bloquear text_report: Reportar - report_message: "¡Hola! Une usuarie de Sutty CMS reportó esta cuenta en tu instancia. Todavía no tenemos soporte para mensajes personalizados. Podés contactarnos en %{panel_actor_mention}." actor_moderations: show: user: Nombre de usuarie @@ -116,6 +115,7 @@ es: profile_id: ID profile_published: Publicada profile_summary: Presentación + report_message: "¡Hola! Une usuarie de Sutty CMS reportó esta cuenta en tu instancia. Todavía no tenemos soporte para mensajes personalizados. Podés contactarnos en %{panel_actor_mention}." moderation_queue: everything: 'Seleccionar todo' nothing: 'No hay nada para este filtro' From 67a56c540aff22e01c76a42dbb5c71ba6f414ee6 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 4 Mar 2024 17:45:16 -0300 Subject: [PATCH 280/472] feat: no mostrar opciones que no se pueden ejecutar con el filtro actual --- app/models/concerns/aasm_events_concern.rb | 10 ++++++++++ app/views/components/_comments_checked_submenu.haml | 8 ++++++-- app/views/components/_comments_filters.haml | 7 +++++-- app/views/components/_instances_checked_submenu.haml | 2 +- app/views/components/_instances_filters.haml | 7 +++++-- app/views/components/_profiles_checked_submenu.haml | 2 +- app/views/components/_profiles_filters.haml | 7 +++++-- app/views/moderation_queue/_comments.haml | 2 +- 8 files changed, 34 insertions(+), 11 deletions(-) diff --git a/app/models/concerns/aasm_events_concern.rb b/app/models/concerns/aasm_events_concern.rb index 59ea243f..418368d8 100644 --- a/app/models/concerns/aasm_events_concern.rb +++ b/app/models/concerns/aasm_events_concern.rb @@ -11,6 +11,16 @@ module AasmEventsConcern aasm.events.map(&:name) - self::IGNORED_EVENTS end + # Encuentra todos los eventos que se pueden ejecutar con el filtro + # actual. + # + # @return [Array] + def self.transitionable_events(current_state) + self.events.select do |event| + aasm.events.find { |x| x.name == event }.transitions_from_state? current_state + end + end + # Todos los estados de la máquina de estados # # @return [Array] diff --git a/app/views/components/_comments_checked_submenu.haml b/app/views/components/_comments_checked_submenu.haml index fa3d7612..a09da426 100644 --- a/app/views/components/_comments_checked_submenu.haml +++ b/app/views/components/_comments_checked_submenu.haml @@ -1,2 +1,6 @@ -- ActivityPub.events.each do |event| - = render 'components/dropdown_button', form_id: form_id, text: t(".submenu_#{event}"), name: 'activity_pub_action', value: event +- current_state = params[:activity_pub_state]&.to_sym || ActivityPub.states.first + +- ActivityPub.aasm.events.each do |event| + - next if ActivityPub::IGNORED_EVENTS.include? event.name + - next unless event.transitions_from_state?(current_state) + = render 'components/dropdown_button', form_id: form_id, text: t(".submenu_#{event.name}"), name: 'activity_pub_action', value: event.name diff --git a/app/views/components/_comments_filters.haml b/app/views/components/_comments_filters.haml index 15f5173d..35cd5dda 100644 --- a/app/views/components/_comments_filters.haml +++ b/app/views/components/_comments_filters.haml @@ -1,6 +1,9 @@ +- current_state = params[:activity_pub_state]&.to_sym || ActivityPub.states.first + .d-flex.py-2 - = render 'components/dropdown', text: t('.text_checked') do - = render 'components/comments_checked_submenu', form_id: form_id + - if ActivityPub.transitionable_events(current_state).present? + = render 'components/dropdown', text: t('.text_checked') do + = render 'components/comments_checked_submenu', form_id: form_id = render 'components/dropdown', text: t('.text_show') do = render 'components/comments_show_submenu', activity_pubs: activity_pubs diff --git a/app/views/components/_instances_checked_submenu.haml b/app/views/components/_instances_checked_submenu.haml index 2d28fb1c..4c45b7ab 100644 --- a/app/views/components/_instances_checked_submenu.haml +++ b/app/views/components/_instances_checked_submenu.haml @@ -1,2 +1,2 @@ -- InstanceModeration.events.each do |event| +- InstanceModeration.transitionable_events(current_state).each do |event| = render 'components/dropdown_button', text: t(".submenu_#{event}"), name: 'instance_moderation_action', value: event, form_id: form_id diff --git a/app/views/components/_instances_filters.haml b/app/views/components/_instances_filters.haml index 2c05693a..9e8509c4 100644 --- a/app/views/components/_instances_filters.haml +++ b/app/views/components/_instances_filters.haml @@ -1,6 +1,9 @@ +- current_state = params[:state]&.to_sym || InstanceModeration.states.first + .d-flex.py-2 - = render 'components/dropdown', text: t('.text_checked') do - = render 'components/instances_checked_submenu', form_id: form_id + - if InstanceModeration.transitionable_events(current_state).present? + = render 'components/dropdown', text: t('.text_checked') do + = render 'components/instances_checked_submenu', form_id: form_id, current_state: current_state = render 'components/dropdown', text: t('.text_show') do = render 'components/instances_show_submenu', site: site diff --git a/app/views/components/_profiles_checked_submenu.haml b/app/views/components/_profiles_checked_submenu.haml index 13e016ca..66a0fa78 100644 --- a/app/views/components/_profiles_checked_submenu.haml +++ b/app/views/components/_profiles_checked_submenu.haml @@ -1,2 +1,2 @@ -- ActorModeration.events.each do |actor_event| +- ActorModeration.transitionable_events(current_state).each do |actor_event| = render 'components/dropdown_button', text: t(".submenu_#{actor_event}"), name: 'actor_moderation_action', value: actor_event, form_id: form_id diff --git a/app/views/components/_profiles_filters.haml b/app/views/components/_profiles_filters.haml index a2593f4c..bf7fb48a 100644 --- a/app/views/components/_profiles_filters.haml +++ b/app/views/components/_profiles_filters.haml @@ -1,6 +1,9 @@ +- current_state = params[:actor_state]&.to_sym || ActorModeration.states.first + .d-flex.py-2 - = render 'components/dropdown', text: t('.text_checked') do - = render 'components/profiles_checked_submenu', form_id: form_id + - if ActorModeration.transitionable_events(current_state).present? + = render 'components/dropdown', text: t('.text_checked') do + = render 'components/profiles_checked_submenu', form_id: form_id, current_state: current_state = render 'components/dropdown', text: t('.text_show') do = render 'components/profiles_show_submenu', actor_moderations: actor_moderations diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index bf1e94a0..436777db 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -5,7 +5,7 @@ .row.no-gutters.pt-2{ data: { controller: 'select-all' } } .col-1.d-flex.align-items-center = render 'components/select_all', id: 'select-all-comments', form_id: form_id - .col-md-9 + .col-11 -# Filtros = render 'components/comments_filters', activity_pubs: moderation_queue, form_id: form_id .col-12 From ff428c652713c0d412b0660cb5788d274fec71fa Mon Sep 17 00:00:00 2001 From: f Date: Tue, 5 Mar 2024 14:18:06 -0300 Subject: [PATCH 281/472] feat: poder reportar comentarios --- app/controllers/activity_pubs_controller.rb | 5 +++- .../actor_moderations_controller.rb | 24 +------------------ .../concerns/moderation_concern.rb | 21 ++++++++++++++++ app/jobs/activity_pub/remote_flag_job.rb | 2 +- app/models/activity_pub.rb | 7 ++++++ app/models/activity_pub/remote_flag.rb | 7 +++++- config/locales/en.yml | 1 + config/locales/es.yml | 1 + .../20240305164653_change_remote_flags.rb | 12 ++++++++++ db/structure.sql | 6 +++-- 10 files changed, 58 insertions(+), 28 deletions(-) create mode 100644 db/migrate/20240305164653_change_remote_flags.rb diff --git a/app/controllers/activity_pubs_controller.rb b/app/controllers/activity_pubs_controller.rb index 9bbbb9cc..37702d96 100644 --- a/app/controllers/activity_pubs_controller.rb +++ b/app/controllers/activity_pubs_controller.rb @@ -8,6 +8,7 @@ class ActivityPubsController < ApplicationController define_method(event) do authorize activity_pub + activity_pub.update(remote_flag_params(activity_pub)) if event == :report activity_pub.public_send(:"#{event}!") if activity_pub.public_send(:"may_#{event}?") redirect_to_moderation_queue! @@ -29,7 +30,9 @@ class ActivityPubsController < ApplicationController ActivityPub.transaction do activity_pubs.find_each do |activity_pub| - activity_pub.public_send(method) if activity_pub.public_send(may) + next unless activity_pub.public_send(may) + + activity_pub.public_send(method) end end end diff --git a/app/controllers/actor_moderations_controller.rb b/app/controllers/actor_moderations_controller.rb index 2d834015..56adda4a 100644 --- a/app/controllers/actor_moderations_controller.rb +++ b/app/controllers/actor_moderations_controller.rb @@ -9,7 +9,7 @@ class ActorModerationsController < ApplicationController authorize actor_moderation # Crea una RemoteFlag si se envían los parámetros adecuados - actor_moderation.update(actor_moderation_params(actor_moderation)) if actor_event == :report + actor_moderation.update(remote_flag_params(actor_moderation)) if actor_event == :report actor_moderation.public_send(:"#{actor_event}!") if actor_moderation.public_send(:"may_#{actor_event}?") @@ -51,26 +51,4 @@ class ActorModerationsController < ApplicationController def actor_moderation @actor_moderation ||= site.actor_moderations.find(params[:actor_moderation_id] || params[:id]) end - - # @return [String] - def panel_actor_mention - @panel_actor_mention ||= ENV.fetch('PANEL_ACTOR_MENTION', '@sutty@sutty.nl') - end - - # @return [Hash] - def actor_moderation_params(actor_moderation) - { remote_flag_attributes: { id: actor_moderation.remote_flag_id, message: '' } }.tap do |p| - p[:remote_flag_attributes][:site_id] = actor_moderation.site_id - p[:remote_flag_attributes][:actor_id] = actor_moderation.actor_id - - I18n.available_locales.each do |locale| - p[:remote_flag_attributes][:message].tap do |m| - m += I18n.t(locale) - m += ': ' - m += I18n.t('actor_moderations.report_message', locale: locale, panel_actor_mention: panel_actor_mention) - m += '\n\n' - end - end - end - end end diff --git a/app/controllers/concerns/moderation_concern.rb b/app/controllers/concerns/moderation_concern.rb index 9a4f1c16..5b4c276d 100644 --- a/app/controllers/concerns/moderation_concern.rb +++ b/app/controllers/concerns/moderation_concern.rb @@ -9,5 +9,26 @@ module ModerationConcern def redirect_to_moderation_queue! redirect_back fallback_location: site_moderation_queue_path(**(session[:moderation_queue_filters] || {})) end + + # @return [String] + def panel_actor_mention + @panel_actor_mention ||= ENV.fetch('PANEL_ACTOR_MENTION', '@sutty@sutty.nl') + end + + def remote_flag_params(model) + { remote_flag_attributes: { id: model.remote_flag_id, message: '' } }.tap do |p| + p[:remote_flag_attributes][:site_id] = model.site_id + p[:remote_flag_attributes][:actor_id] = model.actor_id + + I18n.available_locales.each do |locale| + p[:remote_flag_attributes][:message].tap do |m| + m << I18n.t(locale) + m << ': ' + m << I18n.t('remote_flags.report_message', locale: locale, panel_actor_mention: panel_actor_mention) + m << '\n\n' + end + end + end + end end end diff --git a/app/jobs/activity_pub/remote_flag_job.rb b/app/jobs/activity_pub/remote_flag_job.rb index 332d31ac..30796923 100644 --- a/app/jobs/activity_pub/remote_flag_job.rb +++ b/app/jobs/activity_pub/remote_flag_job.rb @@ -13,7 +13,7 @@ class ActivityPub self.priority = 30 def perform(remote_flag:) - client = remote_flag.site.social_inbox.client_for(remote_flag.actor.content['inbox']) + client = remote_flag.site.social_inbox.client_for(remote_flag.actor&.content['inbox']) response = client.post(endpoint: '', body: remote_flag.content) raise 'No se pudo enviar el reporte' unless response.ok? diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 6f0d884c..23f4324f 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -18,12 +18,15 @@ class ActivityPub < ApplicationRecord belongs_to :site belongs_to :object, polymorphic: true belongs_to :actor + belongs_to :remote_flag, class_name: 'ActivityPub::RemoteFlag' has_many :activities validates :site_id, presence: true validates :object_id, presence: true validates :aasm_state, presence: true, inclusion: { in: %w[paused approved rejected reported removed] } + accepts_nested_attributes_for :remote_flag + # Encuentra la URI de un objeto # # @return [String, nil] @@ -83,6 +86,10 @@ class ActivityPub < ApplicationRecord # Solo podemos reportarla luego de rechazarla event :report do transitions from: :rejected, to: :reported + + before do + ActivityPub::RemoteFlagJob.perform_later(remote_flag: remote_flag) + end end end end diff --git a/app/models/activity_pub/remote_flag.rb b/app/models/activity_pub/remote_flag.rb index b790c4b1..a302503b 100644 --- a/app/models/activity_pub/remote_flag.rb +++ b/app/models/activity_pub/remote_flag.rb @@ -5,6 +5,11 @@ class ActivityPub belongs_to :actor belongs_to :site + has_one :actor_moderation + has_many :activity_pubs + # XXX: source_type es obligatorio para el `through` + has_many :objects, through: :activity_pubs, source_type: 'ActivityPub::Object::Note' + # Genera la actividad a enviar def content { @@ -13,7 +18,7 @@ class ActivityPub 'type' => 'Flag', 'actor' => ENV.fetch('PANEL_ACTOR_ID') { "https://#{ENV['SUTTY']}/about.jsonld" }, 'content' => message.to_s, - 'object' => [ actor.uri ] + 'object' => [ actor.uri ] + objects.pluck(:uri) } end end diff --git a/config/locales/en.yml b/config/locales/en.yml index fe8798f4..0ca90aa7 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -116,6 +116,7 @@ en: profile_id: ID profile_published: Published profile_summary: Summary + remote_flags: report_message: "Hi! Someone using Sutty CMS reported this account on your instance. We don't have support for customized report messages yet, but we will soon. You can reach us at %{panel_actor_mention}." moderation_queue: everything: 'Select all' diff --git a/config/locales/es.yml b/config/locales/es.yml index e22fdf57..40a1a18c 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -115,6 +115,7 @@ es: profile_id: ID profile_published: Publicada profile_summary: Presentación + remote_flags: report_message: "¡Hola! Une usuarie de Sutty CMS reportó esta cuenta en tu instancia. Todavía no tenemos soporte para mensajes personalizados. Podés contactarnos en %{panel_actor_mention}." moderation_queue: everything: 'Seleccionar todo' diff --git a/db/migrate/20240305164653_change_remote_flags.rb b/db/migrate/20240305164653_change_remote_flags.rb new file mode 100644 index 00000000..258f3335 --- /dev/null +++ b/db/migrate/20240305164653_change_remote_flags.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +# Agrega relaciones en las remote flags +class ChangeRemoteFlags < ActiveRecord::Migration[6.1] + def up + add_column :activity_pubs, :remote_flag_id, :uuid, index: true, null: true + end + + def down + remove_column :activity_pubs, :remote_flag_id + end +end diff --git a/db/structure.sql b/db/structure.sql index ff6cf895..55a5ecb0 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -573,7 +573,8 @@ CREATE TABLE public.activity_pubs ( object_type character varying NOT NULL, aasm_state character varying NOT NULL, instance_id uuid, - actor_id uuid + actor_id uuid, + remote_flag_id uuid ); @@ -2695,6 +2696,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20240229201155'), ('20240301181224'), ('20240301194154'), -('20240301202955'); +('20240301202955'), +('20240305164653'); From 054dbc31e03bb7df899e978b988b46a59e41ad18 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 5 Mar 2024 14:19:33 -0300 Subject: [PATCH 282/472] =?UTF-8?q?fix:=20no=20fallar=20si=20la=20activida?= =?UTF-8?q?d=20ya=20hab=C3=ADa=20cambiado=20de=20estado?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/api/v1/webhooks/social_inbox_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index 464a0ffe..548781fa 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -53,7 +53,7 @@ module Api instance.present? object.present? activity.present? - activity_pub.approve! + activity_pub.approve! if activity_pub.may_approve? end head :accepted @@ -69,7 +69,7 @@ module Api instance.present? object.present? activity.present? - activity_pub.reject! + activity_pub.reject! if activity_pub.may_reject? end head :accepted From 30fd6c28eec100ba8205f468d4fcf5f4f7e2cfea Mon Sep 17 00:00:00 2001 From: f Date: Tue, 5 Mar 2024 15:46:33 -0300 Subject: [PATCH 283/472] feat: enviar un reporte por actore --- app/controllers/activity_pubs_controller.rb | 14 ++++++++++++++ app/controllers/concerns/moderation_concern.rb | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/app/controllers/activity_pubs_controller.rb b/app/controllers/activity_pubs_controller.rb index 37702d96..2b54cacd 100644 --- a/app/controllers/activity_pubs_controller.rb +++ b/app/controllers/activity_pubs_controller.rb @@ -28,6 +28,20 @@ class ActivityPubsController < ApplicationController return unless ActivityPub.events.include? action + # Crear una sola remote flag por autore + if action == :report + message = remote_flag_params(activity_pubs.first).dig(:remote_flag_attributes, :message) + + activity_pubs.distinct.pluck(:actor_id).each do |actor_id| + remote_flag = ActivityPub::RemoteFlag.find_or_initialize_by(actor_id: actor_id, site_id: site.id) + remote_flag.message = message + remote_flag.save + # XXX: Idealmente todas las ActivityPub que enviamos pueden + # cambiar de estado, pero chequeamos de todas formas. + remote_flag.activity_pubs << (activity_pubs.where(actor_id: actor_id).to_a.select { |a| a.public_send(may) }) + end + end + ActivityPub.transaction do activity_pubs.find_each do |activity_pub| next unless activity_pub.public_send(may) diff --git a/app/controllers/concerns/moderation_concern.rb b/app/controllers/concerns/moderation_concern.rb index 5b4c276d..3b9d818f 100644 --- a/app/controllers/concerns/moderation_concern.rb +++ b/app/controllers/concerns/moderation_concern.rb @@ -16,7 +16,7 @@ module ModerationConcern end def remote_flag_params(model) - { remote_flag_attributes: { id: model.remote_flag_id, message: '' } }.tap do |p| + { remote_flag_attributes: { id: model.remote_flag_id, message: ''.dup } }.tap do |p| p[:remote_flag_attributes][:site_id] = model.site_id p[:remote_flag_attributes][:actor_id] = model.actor_id From 5b53a9813f163ecffe592be15f5c146eca1fca61 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 5 Mar 2024 16:00:47 -0300 Subject: [PATCH 284/472] feat: enviar una sola vez el reporte remoto y volver a enviarlo si le agregamos reportes --- app/controllers/activity_pubs_controller.rb | 2 ++ app/jobs/activity_pub/remote_flag_job.rb | 6 ++++++ app/models/activity_pub.rb | 2 +- app/models/activity_pub/remote_flag.rb | 21 +++++++++++++++++++ app/models/actor_moderation.rb | 2 +- ...0240305184854_add_state_to_remote_flags.rb | 8 +++++++ db/structure.sql | 6 ++++-- 7 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20240305184854_add_state_to_remote_flags.rb diff --git a/app/controllers/activity_pubs_controller.rb b/app/controllers/activity_pubs_controller.rb index 2b54cacd..c8f86ef0 100644 --- a/app/controllers/activity_pubs_controller.rb +++ b/app/controllers/activity_pubs_controller.rb @@ -35,6 +35,8 @@ class ActivityPubsController < ApplicationController activity_pubs.distinct.pluck(:actor_id).each do |actor_id| remote_flag = ActivityPub::RemoteFlag.find_or_initialize_by(actor_id: actor_id, site_id: site.id) remote_flag.message = message + # Lo estamos actualizando, con lo que lo vamos a volver a enviar + remote_flag.requeue if remote_flag.persisted? remote_flag.save # XXX: Idealmente todas las ActivityPub que enviamos pueden # cambiar de estado, pero chequeamos de todas formas. diff --git a/app/jobs/activity_pub/remote_flag_job.rb b/app/jobs/activity_pub/remote_flag_job.rb index 30796923..7d8131db 100644 --- a/app/jobs/activity_pub/remote_flag_job.rb +++ b/app/jobs/activity_pub/remote_flag_job.rb @@ -13,10 +13,16 @@ class ActivityPub self.priority = 30 def perform(remote_flag:) + return if remote_flag.can_queue? + + remote_flag.queue! + client = remote_flag.site.social_inbox.client_for(remote_flag.actor&.content['inbox']) response = client.post(endpoint: '', body: remote_flag.content) raise 'No se pudo enviar el reporte' unless response.ok? + + remote_flag.send! rescue Exception => e ExceptionNotifier.notify_exception(e, data: { remote_flag: remote_flag.id, response: response.parsed_response }) raise diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 23f4324f..b07fe790 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -88,7 +88,7 @@ class ActivityPub < ApplicationRecord transitions from: :rejected, to: :reported before do - ActivityPub::RemoteFlagJob.perform_later(remote_flag: remote_flag) + ActivityPub::RemoteFlagJob.perform_later(remote_flag: remote_flag) if remote_flag.waiting? end end end diff --git a/app/models/activity_pub/remote_flag.rb b/app/models/activity_pub/remote_flag.rb index a302503b..25f1b743 100644 --- a/app/models/activity_pub/remote_flag.rb +++ b/app/models/activity_pub/remote_flag.rb @@ -2,6 +2,27 @@ class ActivityPub class RemoteFlag < ApplicationRecord + include AASM + include AasmEventsConcern + + aasm do + state :waiting, initial: true + state :queued + state :sent + + event :queue do + transitions from: :waiting, to: :queued + end + + event :send do + transitions from: :queued, to: :sent + end + + event :resend do + transitions from: :sent, to: :waiting + end + end + belongs_to :actor belongs_to :site diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index 421d4c6e..d7eea709 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -59,7 +59,7 @@ class ActorModeration < ApplicationRecord transitions from: %i[blocked], to: :reported before do - ActivityPub::RemoteFlagJob.perform_later(remote_flag: remote_flag) + ActivityPub::RemoteFlagJob.perform_later(remote_flag: remote_flag) if remote_flag.waiting? end end end diff --git a/db/migrate/20240305184854_add_state_to_remote_flags.rb b/db/migrate/20240305184854_add_state_to_remote_flags.rb new file mode 100644 index 00000000..7ff78dfb --- /dev/null +++ b/db/migrate/20240305184854_add_state_to_remote_flags.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# Estado de los reportes remotos +class AddStateToRemoteFlags < ActiveRecord::Migration[6.1] + def change + add_column :activity_pub_remote_flags, :aasm_state, :string, null: false, default: 'waiting' + end +end diff --git a/db/structure.sql b/db/structure.sql index 55a5ecb0..97bd372e 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -556,7 +556,8 @@ CREATE TABLE public.activity_pub_remote_flags ( updated_at timestamp(6) without time zone NOT NULL, site_id bigint, actor_id uuid, - message text + message text, + aasm_state character varying DEFAULT 'waiting'::character varying NOT NULL ); @@ -2697,6 +2698,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20240301181224'), ('20240301194154'), ('20240301202955'), -('20240305164653'); +('20240305164653'), +('20240305184854'); From b1dee5d5676954610fd54e52ab00c0cfd9bb90e4 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 5 Mar 2024 16:10:06 -0300 Subject: [PATCH 285/472] fix: dejar de cargar datos de prueba --- app/controllers/application_controller.rb | 10 - .../moderation_queue_controller.rb | 8 - config/routes.rb | 1 - db/seeds/blocklists.yml | 7 - db/seeds/instances.yaml | 285 ------------------ db/seeds/moderation_queue.yaml | 153 ---------- db/seeds/remote_profile.yaml | 106 ------- 7 files changed, 570 deletions(-) delete mode 100644 db/seeds/blocklists.yml delete mode 100644 db/seeds/instances.yaml delete mode 100644 db/seeds/moderation_queue.yaml delete mode 100644 db/seeds/remote_profile.yaml diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index b55176ec..05fa98e9 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -27,16 +27,6 @@ class ApplicationController < ActionController::Base end private - # Traer datos de muestra de la cola de moderación - def dummy_data - @moderation_queue = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'moderation_queue.yaml'))) - @remote_profile = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'remote_profile.yaml'))) - @instances = YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'instances.yaml'))) - @blocklists= YAML.safe_load(File.read(Rails.root.join('db', 'seeds', 'blocklists.yml'))) - @moderation_queue.each do |activity| - activity['attributedTo'] = @remote_profile - end - end def notify_unconfirmed_email return unless current_usuarie diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index 6a628aaa..0df62499 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -4,8 +4,6 @@ class ModerationQueueController < ApplicationController # Cola de moderación viendo todo el sitio def index - dummy_data - session[:moderation_queue_filters] = params.permit(:state, :actor_state, :activity_pub_state) # @todo cambiar el estado por query @@ -14,10 +12,4 @@ class ModerationQueueController < ApplicationController @actor_moderations = rubanok_process(site.actor_moderations, with: ActorModerationProcessor) @moderation_queue = rubanok_process(site.activity_pubs, with: ActivityPubProcessor) end - - # todon.nl está usando /api/v2/instance - # mauve.moe usa /api/v1/instance - def instances - dummy_data - end end diff --git a/config/routes.rb b/config/routes.rb index 8809767b..054b7f4d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -63,7 +63,6 @@ Rails.application.routes.draw do post 'collaborate', to: 'collaborations#accept_collaboration' get 'moderation_queue', to: 'moderation_queue#index' - get 'instances', to: 'moderation_queue#instances' resources :instance_moderations, only: [] do patch :pause, to: 'instance_moderations#pause' diff --git a/db/seeds/blocklists.yml b/db/seeds/blocklists.yml deleted file mode 100644 index 54dfe6c9..00000000 --- a/db/seeds/blocklists.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -- id: gardenfence - title: Gardenfence - link: 'https://gardenfence.github.io/' -- id: lista - title: Lista - link: '#' diff --git a/db/seeds/instances.yaml b/db/seeds/instances.yaml deleted file mode 100644 index bf326832..00000000 --- a/db/seeds/instances.yaml +++ /dev/null @@ -1,285 +0,0 @@ ---- -- domain: todon.nl - title: Todon.nl - version: 4.2.3 - source_url: https://github.com/mastodon/mastodon - description: Radicaal linkse anti-autoritaire server. Voor anarchisten, socialisten, - (klimaat)activisten, LHBTQIA+, antiracisten, antifascisten, antikapitalisten, - intersectionelen, veganisten, mensenrechten, enz. - usage: - users: - active_month: 372 - thumbnail: - url: https://todon.nl/system/site_uploads/files/000/000/004/@1x/297e509bc8a81f62.png - blurhash: UXAw3zN4M|xsoga#WBay9DxntQRmITocofWE - versions: - "@1x": https://todon.nl/system/site_uploads/files/000/000/004/@1x/297e509bc8a81f62.png - "@2x": https://todon.nl/system/site_uploads/files/000/000/004/@2x/297e509bc8a81f62.png - languages: - - en - configuration: - urls: - streaming: wss://todon.nl - status: https://status.todon.eu - accounts: - max_featured_tags: 10 - statuses: - max_characters: 1312 - max_media_attachments: 4 - characters_reserved_per_url: 23 - media_attachments: - supported_mime_types: - - image/jpeg - - image/png - - image/gif - - image/heic - - image/heif - - image/webp - - image/avif - - video/webm - - video/mp4 - - video/quicktime - - video/ogg - - audio/wave - - audio/wav - - audio/x-wav - - audio/x-pn-wave - - audio/vnd.wave - - audio/ogg - - audio/vorbis - - audio/mpeg - - audio/mp3 - - audio/webm - - audio/flac - - audio/aac - - audio/m4a - - audio/x-m4a - - audio/mp4 - - audio/3gpp - - video/x-ms-asf - image_size_limit: 16777216 - image_matrix_limit: 33177600 - video_size_limit: 103809024 - video_frame_rate_limit: 120 - video_matrix_limit: 8294400 - polls: - max_options: 4 - max_characters_per_option: 50 - min_expiration: 300 - max_expiration: 2629746 - translation: - enabled: true - registrations: - enabled: false - approval_required: false - message: | -

¡No pasarán!

- -

Je kunt tijdelijk geen nieuw account op Todon.nl aanvragen.

- - - -

Ga naar joinmastodon.org of FediDB Network om een andere server te vinden.

- -

It is temporary not possible to request on account on Todon.nl.

- - - -

Go to joinmastodon.org or FediDB Network to find another server.

- url: - max_toot_chars: 1312 - contact: - email: todon@posteo.eu - account: - id: '1' - username: admin - acct: admin - display_name: "Admin \U0001F913 Todon.nl (mod)" - locked: false - bot: false - discoverable: false - group: false - created_at: '2017-04-28T00:00:00.000Z' - note: "

This account is used for \U0001F399 Todon.nl announcements and ⚖️ - moderation.

\U0001F6AB Don't follow this account when you are not - on Todon.nl.

New? First read our \U0001F469‍\U0001F3EB Todon 101 \U0001F469‍\U0001F393 - at https://wiki.todon.eu/todon/101

⚖️ - For all our moderators go to https://wiki.todon.nl/todon/moderators

\U0001F4DD Public toots from this account - are in English.

\U0001F515 Criticism is fine, but people who do false - accusations are muted.

✉ todon@posteo.eu

#nobot

" - url: https://todon.nl/@admin - uri: https://todon.nl/users/admin - avatar: https://todon.nl/system/accounts/avatars/000/000/001/original/2db61726225ed3e6.png - avatar_static: https://todon.nl/system/accounts/avatars/000/000/001/original/2db61726225ed3e6.png - header: https://todon.nl/system/accounts/headers/000/000/001/original/fb3a846cbc20aa09.png - header_static: https://todon.nl/system/accounts/headers/000/000/001/original/fb3a846cbc20aa09.png - followers_count: 3164 - following_count: 8 - statuses_count: 724 - last_status_at: '2024-01-12' - noindex: true - emojis: [] - roles: - - id: '3' - name: Admin - color: "#595aff" - fields: - - name: "\U0001F4DC Terms of Service" - value: wiki.todon.nl/todon/terms_en - verified_at: '2018-11-01T14:39:45.465+00:00' - - name: ℹ️ Wiki - value: wiki.todon.nl/todon/informatio - verified_at: '2018-11-01T14:40:54.679+00:00' - - name: "\U0001F4CA Status" - value: status.todon.eu - verified_at: '2023-10-26T20:38:30.185+00:00' - - name: "\U0001F4B3️ Donations" - value: wiki.todon.eu/todon/donations - verified_at: '2022-11-02T00:06:31.865+00:00' - rules: - - id: '1' - text: We do not accept racism (in all its forms, incl. hate against Muslims, antisemitism, - apartheid and casteism - see our Terms of Service for our complete definition). - - id: '2' - text: We do not accept hate against lesbians, gays, bisexuals, pansexuals, transgenders, - non-binary people, intersexual people, queer people in general, etc. - - id: '4' - text: Sexism, misogyny and hate against black women (misogynoir). - - id: '6' - text: We do not accept ableism (incl. COVID-19 denial/downplaying and anti-vax) - and body-shaming. - - id: '8' - text: We do not accept harassment and trolling. - - id: '10' - text: We also do not accept other forms of hate speech. - - id: '11' - text: We do not accept (sexual) abuse of minors, adults and animals (also not - virtual). - - id: '13' - text: We do not accept glorification of violence, calls for murder, death threats, - terrorism and militarism. - - id: '15' - text: We do not accept (neo)colonialism (incl. Zionism), imperialism in all forms - and nationalism (above all nationalism of nation states, incl. flags/symbols - of those on Todon.*, see our Terms of Service). - - id: '16' - text: We do not accept fascism, right-wing populism, and right-wing and religious - extremism. - - id: '17' - text: We do not accept evangelisation and other forms of religious propaganda - [local only], and extreme sects and cults. - - id: '19' - text: We do not accept Marxist-Leninists, Stalinists, Maoists or other followers - of extreme authoritarian (so called) communist/socialist ideologies/regimes - (aka tankies). - - id: '20' - text: We do not accept capitalists, including so called 'anarcho-capitalists' - (aka ancaps) and neoliberals. - - id: '21' - text: We do not accept anthropogenic climate change denial, downplaying the climate - crisis, greenwashing and deceptive climate solutions (like nuclear energy). - - id: '27' - text: We do not accept (right-wing) conspiracy 'theories', hoaxes, fake news and - other forms of disinformation. - - id: '28' - text: Another rule in our terms of service at wiki.todon.eu/todon/terms_en. Explain - in the final step. -- uri: mastodon.mauve.moe - title: Mauvestodon - short_description: Escape ship from centralized social media run by Mauve. - description: Chat about random techie and anarchist stuff. - email: contact@mauve.moe - version: 3.5.10 - urls: - streaming_api: wss://mastodon.mauve.moe - stats: - user_count: 12 - status_count: 3287 - domain_count: 11625 - thumbnail: https://mastodon.mauve.moe/system/site_uploads/files/000/000/001/original/mauvesoftwareinc.png - languages: - - en - registrations: false - approval_required: false - invites_enabled: true - configuration: - statuses: - max_characters: 500 - max_media_attachments: 4 - characters_reserved_per_url: 23 - media_attachments: - supported_mime_types: - - image/jpeg - - image/png - - image/gif - - video/webm - - video/mp4 - - video/quicktime - - video/ogg - - audio/wave - - audio/wav - - audio/x-wav - - audio/x-pn-wave - - audio/ogg - - audio/vorbis - - audio/mpeg - - audio/mp3 - - audio/webm - - audio/flac - - audio/aac - - audio/m4a - - audio/x-m4a - - audio/mp4 - - audio/3gpp - - video/x-ms-asf - image_size_limit: 10485760 - image_matrix_limit: 16777216 - video_size_limit: 41943040 - video_frame_rate_limit: 60 - video_matrix_limit: 2304000 - polls: - max_options: 4 - max_characters_per_option: 50 - min_expiration: 300 - max_expiration: 2629746 - contact_account: - id: '1' - username: admin - acct: admin - display_name: '' - locked: false - bot: false - discoverable: true - group: false - created_at: '2022-04-25T00:00:00.000Z' - note: '' - url: https://mastodon.mauve.moe/@admin - avatar: https://mastodon.mauve.moe/system/accounts/avatars/000/000/001/original/8c21e71667b48a95.png - avatar_static: https://mastodon.mauve.moe/system/accounts/avatars/000/000/001/original/8c21e71667b48a95.png - header: https://mastodon.mauve.moe/headers/original/missing.png - header_static: https://mastodon.mauve.moe/headers/original/missing.png - followers_count: 0 - following_count: 0 - statuses_count: 0 - last_status_at: '2023-01-30' - emojis: [] - fields: - - name: Alternatel Contact - value: @mauve - verified_at: - rules: [] diff --git a/db/seeds/moderation_queue.yaml b/db/seeds/moderation_queue.yaml deleted file mode 100644 index c7075c7e..00000000 --- a/db/seeds/moderation_queue.yaml +++ /dev/null @@ -1,153 +0,0 @@ ---- -- "@context": - - https://www.w3.org/ns/activitystreams - - ostatus: http://ostatus.org# - atomUri: ostatus:atomUri - inReplyToAtomUri: ostatus:inReplyToAtomUri - conversation: ostatus:conversation - sensitive: as:sensitive - toot: http://joinmastodon.org/ns# - votersCount: toot:votersCount - Hashtag: as:Hashtag - id: https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041 - type: Note - summary: - inReplyTo: https://mastodon.mauve.moe/users/mauve/statuses/111461923538534886 - published: '2023-11-23T22:50:10Z' - url: https://mastodon.mauve.moe/@mauve/111462305634770041 - attributedTo: https://mastodon.mauve.moe/users/mauve - to: - - https://www.w3.org/ns/activitystreams#Public - cc: - - https://mastodon.mauve.moe/users/mauve/followers - - https://hypha.coop/about.jsonld - sensitive: false - atomUri: https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041 - inReplyToAtomUri: https://mastodon.mauve.moe/users/mauve/statuses/111461923538534886 - conversation: tag:mastodon.mauve.moe,2023-11-23:objectId=551471:objectType=Conversation - content:

Follow @HyphaCoop@hypha.coop for our announcement post on the 5th!

-

- contentMap: - en:

Follow @HyphaCoop@hypha.coop for our announcement post on the 5th!

-

- attachment: [] - tag: - - type: Mention - href: https://hypha.coop/about.jsonld - name: "@dripline@hypha.coop" - - type: Hashtag - href: https://mastodon.mauve.moe/tags/p2p - name: "#p2p" - - type: Hashtag - href: https://mastodon.mauve.moe/tags/activitypub - name: "#activitypub" - - type: Hashtag - href: https://mastodon.mauve.moe/tags/fediverse - name: "#fediverse" - replies: - id: https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies - type: Collection - first: - type: CollectionPage - next: https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies?only_other_accounts=true&page=true - partOf: https://mastodon.mauve.moe/users/mauve/statuses/111462305634770041/replies - items: [] -- "@context": - - https://www.w3.org/ns/activitystreams - - "@language": es - sensitive: as:sensitive - type: Note - id: https://sutty.nl/lanzamiento-de-publicaciones-distribuidas-en-el-fediverso-a-trav%C3%A9s-de-sutty/ - summary: Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty - published: '2023-12-04T21:53:05+00:00' - updated: '2023-12-05T20:41:34+00:00' - attributedTo: https://sutty.nl/about.jsonld - to: - - https://www.w3.org/ns/activitystreams#Public - cc: - - https://social.distributed.press/v1/@sutty@sutty.nl/followers - inReplyTo: https://hypha.coop/dripline/announcing-dp-social-inbox/ - sensitive: true - content: | -

Estamos felices y orgulloses de anunciar el lanzamiento de la funcionalidad que permite la publicación en el Fediverso de los artículos de todos los sitios creados a través de Sutty.

Gracias al trabajo conjunto con Distributed Press, Hypha y apoyado por la Filecoin Foundation for the Distributed Web, Sutty hace posible que la seguridad de tu sitio estático se combine con la rápida difusión de tu contenido a través de las redes sociales libres y descentralizadas que constituyen el Fediverso.

Esto se logró a través del desarollo y la integración de dos componentes, trabajados en forma conjunta y colaborativa:

    -
  1. Social Inbox, desarrollado principalmente Distributed Press. Aporta la funcionalidad de recibir artículos, responder y mencionar otras cuentas en el Fediverso.

  2. -
  3. Jekyll Activity Pub Plugin, desarrollado principalmente por Sutty. Permite integrar Social Inbox en todos los sitios estáticos generados en Jekyll, admitiendo así la publicación automática de contenido del sitio en el Fediverso.

  4. -

Sutty integra la funcionalidad completa en su CMS para sitios estáticos en Jekyll, permitiendo gestionarla desde una interfaz en continua mejora de su usabilidad.

Si todavía no estás familiarizade con estos nombres y conceptos, te invitamos a conocer más a continuación, en la sección “Para tecno-curioses”.

Qué significa

    -
  • Que si creás tu sitio web a través de Sutty, tenés nuevas posibilidades de difundir tus contenidos e interactuar en redes digitales.

  • -
  • Que tus artículos pueden ser publicados en las redes del Fediverso.

  • -
  • Que tu sitio tendrá un perfil o usuarie personalizable desde el panel en una instancia de Sutty propia.

  • -
  • Que les usuaries del Fediverso pueden seguir tus publicaciones.

  • -
  • Que les usuaries del Fediverso que te sigan podrán leer tus publicaciones, mencionarte y responderte.

  • -
  • Que podrás interactuar con les usuaries del Fediverse con las opciones de responderles y mencionarles.

  • -

Qué permite hacer

    -
  • Activar la publicación en el Fediverso para todos los sitios de Sutty.

  • -
  • Activar la publicación de los artículos que quieras en el Fediverso.

  • -
  • Responder comentarios desde los artículos de tu sitio en Sutty.

  • -
  • Personalizar la cuenta que Sutty crea automáticamente de tu sitio en el Fediverso.

  • -
  • Reportar o informar de usuaries o instancias abusivos mediante nuestro formulario de contacto.

  • -

Qué se viene

    -
  • Mejoras en la integración de las respuestas como comentarios en el sitio.

  • -
  • Incorporación de menciones desde el panel de Sutty.

  • -
  • Mejoras en la interfaz general del panel.

  • -
  • Nuevas implementaciones para una mejor moderación.

  • -
  • Mejor compatibilidad con diversas redes en el Fediverso (Mastodon+Glitch, Pleroma, Ktistec).

  • -
  • Mejoras que permitirán diferenciar el contenido a publicar en el Fediverso y en el sitio de Sutty.

  • -
  • La posibilidad de exportar tu cuenta a una instancia del Fediverso desde tu panel.

  • -
  • La posibilidad de que Sutty anuncie tu contenido y/o usuarie del Fediverse en forma automática para atraer seguidorxs. (Ahora, podés hacerlo a través de un formulario).

  • -
  • Acceder a la lista de seguidorxs y seguides desde tu panel.

  • -
  • Seguir, dejar de seguir, bloquear usuaries y/o instancias del Fediverso desde el panel.

  • -

¡Quiero usarlo!

Te invitamos a dar tus primeros pasos de la mano de nuestro tutorial.

Para tecno-curioses

Cómo funciona

Los sitios web y las redes sociales parecen ser especies distintas dentro del Universo de Internet. Al mismo tiempo, las redes sociales corporativas y concentradas como Instagram, Facebook, X (ex Twitter), entre otras, demostraron ser hostiles con algunos grupos o colectivos sociales en particular (censurando contenido, persiguiendo pezones, ocultando publicaciones por color de piel y de pelo, etc.) y con todes sus usuaries en general (vendiendo data en forma masiva, violando acuerdos de privacidad, eligiendo diseños de interfaz y uso que generan ansiedad y adicción, etc.). Pese a esto, siguen funcionando como espacios obligados a la hora de publicitar un emprendimiento o difundir noticias urgentes.

El Fediverso es una red federada, descentralizada y distribuida de redes sociales libres, cada una con sus características, preferencias, grupos de usuaries. Están diseñadas para facilitar el diálogo entre todas ellas. Es decir, para que los contenidos puedan ser visibles y se puedan generar respuestas entre usuaries, fomentando una cultura de participación y pluralidad de voces, basadas en estándares de desarrollo libre y que buscan ser éticos antes que con fines de lucro sin fin.

Los sitios web siguen siendo formatos para medios de comunicación que, debido a sus características, favorecen la difusión de contenidos como artículos multimedia. Permiten adecuar un estilo a una identidad visual del medio, mantener secciones y contenido institucional variado, entre otras cosas.

Las redes sociales se destacan por sus características de inmediatez, favoreciendo un flujo dialógico en tiempo real con otros tiempos de atención y características de navegación que lo hacen más breve, rápido, a veces efímero. Los medios de comunicación (personas o emprendimientos mediáticos) suelen utilizarlos para llamar la atención sobre contenidos publicados en sus sitios, apostando a la divulgación rápida y las discusiones que puedan darse entre usuaries.

La funcionalidad que desarrollamos en Sutty contempla los casos de uso en los que un contenido quiera ser compartido a más personas, en menor tiempo, con la posibilidad de generar diálogos. Las particularidades de nuestros sitios y redes sociales libres generan condiciones favorables para la libertad de expresión, que preferimos llamar Derecho a la Comunicación, evadiendo las variadas y cada vez más sofisticadas formas de censura de las plataformas corporativas tradicionales. Un contenido reproducido en varios lugares al mismo tiempo ayuda a su divulgación y es ideal para aquellas voces y discursos contrahegemónicos en la web y su supervivencia al paso del tiempo, preservando la memoria popular.

Cómo funciona el Fediverso en la moderación

El Fediverso intenta funcionar como comunidades en línea interconectadas que se autogobiernan en las formas de cuidados colectivos. Así, cada instancia podría ser algo así como un municipio que aloja diferentes cuentas/usuaries bajo unas reglas consensuadas y que pueden ser puestas en discusión si fuera necesario. De esta forma, es posible regular la circulación de contenidos fascistas y discursos de odio que puedan dañar no solamente la participación de diverses usuaries sino también su salud.

Para ello, cada instancia elige sus formas de moderación y puede excluir otras instancias con denuncias previas de contenidos antidemocráticos, odiantes o contrarios a los valores y cuidados de sus habitantes.

En Sutty en particular, nos interesan las estrategias y los mecanismos de cuidados colectivos, por lo que seguimos diseñando modelos que permitan sostenerlos en nuestras tecnologías. Podés revisar nuestros términos y condiciones, política de privacidad y acuerdos de convivencia para más información.

¿Te interesa participar?

Si sos parte de una organización social, grupo de activismo o colectivo social que pensás que podría beneficiarse de estas características, te invitamos a contactarnos a través de nuestro formulario. Estamos busando mejorar los usos de las tecnologías para ustedes y valoramos sus experiencias.

Otras posibilidades de integración de Social Inbox en sitios estáticos

Si te interesa incorporar esta funcionalidad para otros gestores de sitios estáticos, no dudes en contactarnos. Además, mantenete al tanto de las novedades que compartimos en https://dweb.sutty.nl y en nuestro blog https://sutty.nl/blog

Recomendado para saber más

- name: Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty - contentMap: - es: | -

Estamos felices y orgulloses de anunciar el lanzamiento de la funcionalidad que permite la publicación en el Fediverso de los artículos de todos los sitios creados a través de Sutty.

Gracias al trabajo conjunto con Distributed Press, Hypha y apoyado por la Filecoin Foundation for the Distributed Web, Sutty hace posible que la seguridad de tu sitio estático se combine con la rápida difusión de tu contenido a través de las redes sociales libres y descentralizadas que constituyen el Fediverso.

Esto se logró a través del desarollo y la integración de dos componentes, trabajados en forma conjunta y colaborativa:

    -
  1. Social Inbox, desarrollado principalmente Distributed Press. Aporta la funcionalidad de recibir artículos, responder y mencionar otras cuentas en el Fediverso.

  2. -
  3. Jekyll Activity Pub Plugin, desarrollado principalmente por Sutty. Permite integrar Social Inbox en todos los sitios estáticos generados en Jekyll, admitiendo así la publicación automática de contenido del sitio en el Fediverso.

  4. -

Sutty integra la funcionalidad completa en su CMS para sitios estáticos en Jekyll, permitiendo gestionarla desde una interfaz en continua mejora de su usabilidad.

Si todavía no estás familiarizade con estos nombres y conceptos, te invitamos a conocer más a continuación, en la sección “Para tecno-curioses”.

Qué significa

    -
  • Que si creás tu sitio web a través de Sutty, tenés nuevas posibilidades de difundir tus contenidos e interactuar en redes digitales.

  • -
  • Que tus artículos pueden ser publicados en las redes del Fediverso.

  • -
  • Que tu sitio tendrá un perfil o usuarie personalizable desde el panel en una instancia de Sutty propia.

  • -
  • Que les usuaries del Fediverso pueden seguir tus publicaciones.

  • -
  • Que les usuaries del Fediverso que te sigan podrán leer tus publicaciones, mencionarte y responderte.

  • -
  • Que podrás interactuar con les usuaries del Fediverse con las opciones de responderles y mencionarles.

  • -

Qué permite hacer

    -
  • Activar la publicación en el Fediverso para todos los sitios de Sutty.

  • -
  • Activar la publicación de los artículos que quieras en el Fediverso.

  • -
  • Responder comentarios desde los artículos de tu sitio en Sutty.

  • -
  • Personalizar la cuenta que Sutty crea automáticamente de tu sitio en el Fediverso.

  • -
  • Reportar o informar de usuaries o instancias abusivos mediante nuestro formulario de contacto.

  • -

Qué se viene

    -
  • Mejoras en la integración de las respuestas como comentarios en el sitio.

  • -
  • Incorporación de menciones desde el panel de Sutty.

  • -
  • Mejoras en la interfaz general del panel.

  • -
  • Nuevas implementaciones para una mejor moderación.

  • -
  • Mejor compatibilidad con diversas redes en el Fediverso (Mastodon+Glitch, Pleroma, Ktistec).

  • -
  • Mejoras que permitirán diferenciar el contenido a publicar en el Fediverso y en el sitio de Sutty.

  • -
  • La posibilidad de exportar tu cuenta a una instancia del Fediverso desde tu panel.

  • -
  • La posibilidad de que Sutty anuncie tu contenido y/o usuarie del Fediverse en forma automática para atraer seguidorxs. (Ahora, podés hacerlo a través de un formulario).

  • -
  • Acceder a la lista de seguidorxs y seguides desde tu panel.

  • -
  • Seguir, dejar de seguir, bloquear usuaries y/o instancias del Fediverso desde el panel.

  • -

¡Quiero usarlo!

Te invitamos a dar tus primeros pasos de la mano de nuestro tutorial.

Para tecno-curioses

Cómo funciona

Los sitios web y las redes sociales parecen ser especies distintas dentro del Universo de Internet. Al mismo tiempo, las redes sociales corporativas y concentradas como Instagram, Facebook, X (ex Twitter), entre otras, demostraron ser hostiles con algunos grupos o colectivos sociales en particular (censurando contenido, persiguiendo pezones, ocultando publicaciones por color de piel y de pelo, etc.) y con todes sus usuaries en general (vendiendo data en forma masiva, violando acuerdos de privacidad, eligiendo diseños de interfaz y uso que generan ansiedad y adicción, etc.). Pese a esto, siguen funcionando como espacios obligados a la hora de publicitar un emprendimiento o difundir noticias urgentes.

El Fediverso es una red federada, descentralizada y distribuida de redes sociales libres, cada una con sus características, preferencias, grupos de usuaries. Están diseñadas para facilitar el diálogo entre todas ellas. Es decir, para que los contenidos puedan ser visibles y se puedan generar respuestas entre usuaries, fomentando una cultura de participación y pluralidad de voces, basadas en estándares de desarrollo libre y que buscan ser éticos antes que con fines de lucro sin fin.

Los sitios web siguen siendo formatos para medios de comunicación que, debido a sus características, favorecen la difusión de contenidos como artículos multimedia. Permiten adecuar un estilo a una identidad visual del medio, mantener secciones y contenido institucional variado, entre otras cosas.

Las redes sociales se destacan por sus características de inmediatez, favoreciendo un flujo dialógico en tiempo real con otros tiempos de atención y características de navegación que lo hacen más breve, rápido, a veces efímero. Los medios de comunicación (personas o emprendimientos mediáticos) suelen utilizarlos para llamar la atención sobre contenidos publicados en sus sitios, apostando a la divulgación rápida y las discusiones que puedan darse entre usuaries.

La funcionalidad que desarrollamos en Sutty contempla los casos de uso en los que un contenido quiera ser compartido a más personas, en menor tiempo, con la posibilidad de generar diálogos. Las particularidades de nuestros sitios y redes sociales libres generan condiciones favorables para la libertad de expresión, que preferimos llamar Derecho a la Comunicación, evadiendo las variadas y cada vez más sofisticadas formas de censura de las plataformas corporativas tradicionales. Un contenido reproducido en varios lugares al mismo tiempo ayuda a su divulgación y es ideal para aquellas voces y discursos contrahegemónicos en la web y su supervivencia al paso del tiempo, preservando la memoria popular.

Cómo funciona el Fediverso en la moderación

El Fediverso intenta funcionar como comunidades en línea interconectadas que se autogobiernan en las formas de cuidados colectivos. Así, cada instancia podría ser algo así como un municipio que aloja diferentes cuentas/usuaries bajo unas reglas consensuadas y que pueden ser puestas en discusión si fuera necesario. De esta forma, es posible regular la circulación de contenidos fascistas y discursos de odio que puedan dañar no solamente la participación de diverses usuaries sino también su salud.

Para ello, cada instancia elige sus formas de moderación y puede excluir otras instancias con denuncias previas de contenidos antidemocráticos, odiantes o contrarios a los valores y cuidados de sus habitantes.

En Sutty en particular, nos interesan las estrategias y los mecanismos de cuidados colectivos, por lo que seguimos diseñando modelos que permitan sostenerlos en nuestras tecnologías. Podés revisar nuestros términos y condiciones, política de privacidad y acuerdos de convivencia para más información.

¿Te interesa participar?

Si sos parte de una organización social, grupo de activismo o colectivo social que pensás que podría beneficiarse de estas características, te invitamos a contactarnos a través de nuestro formulario. Estamos busando mejorar los usos de las tecnologías para ustedes y valoramos sus experiencias.

Otras posibilidades de integración de Social Inbox en sitios estáticos

Si te interesa incorporar esta funcionalidad para otros gestores de sitios estáticos, no dudes en contactarnos. Además, mantenete al tanto de las novedades que compartimos en https://dweb.sutty.nl y en nuestro blog https://sutty.nl/blog

Recomendado para saber más

- attachment: - - type: Document - mediaType: image/png - url: https://sutty.nl/public/8r7b6ohqy6xzgngxbol6337q8jj9/milestone_2_activity_pub_2.png - name: Botones de colores para activar la "Web Disribuida" y el "Fediverso". diff --git a/db/seeds/remote_profile.yaml b/db/seeds/remote_profile.yaml deleted file mode 100644 index 1a670d6b..00000000 --- a/db/seeds/remote_profile.yaml +++ /dev/null @@ -1,106 +0,0 @@ ---- -"@context": -- https://www.w3.org/ns/activitystreams -- https://w3id.org/security/v1 -- manuallyApprovesFollowers: as:manuallyApprovesFollowers - toot: http://joinmastodon.org/ns# - featured: - "@id": toot:featured - "@type": "@id" - featuredTags: - "@id": toot:featuredTags - "@type": "@id" - alsoKnownAs: - "@id": as:alsoKnownAs - "@type": "@id" - movedTo: - "@id": as:movedTo - "@type": "@id" - schema: http://schema.org# - PropertyValue: schema:PropertyValue - value: schema:value - discoverable: toot:discoverable - Device: toot:Device - Ed25519Signature: toot:Ed25519Signature - Ed25519Key: toot:Ed25519Key - Curve25519Key: toot:Curve25519Key - EncryptedMessage: toot:EncryptedMessage - publicKeyBase64: toot:publicKeyBase64 - deviceId: toot:deviceId - claim: - "@type": "@id" - "@id": toot:claim - fingerprintKey: - "@type": "@id" - "@id": toot:fingerprintKey - identityKey: - "@type": "@id" - "@id": toot:identityKey - devices: - "@type": "@id" - "@id": toot:devices - messageFranking: toot:messageFranking - messageType: toot:messageType - cipherText: toot:cipherText - suspended: toot:suspended - focalPoint: - "@container": "@list" - "@id": toot:focalPoint -id: https://mastodon.mauve.moe/users/mauve -type: Person -following: https://mastodon.mauve.moe/users/mauve/following -followers: https://mastodon.mauve.moe/users/mauve/followers -inbox: https://mastodon.mauve.moe/users/mauve/inbox -outbox: https://mastodon.mauve.moe/users/mauve/outbox -featured: https://mastodon.mauve.moe/users/mauve/collections/featured -featuredTags: https://mastodon.mauve.moe/users/mauve/collections/tags -preferredUsername: mauve -name: "Mauve \U0001F441\U0001F49C" -summary: "

Occult Enby that's making local-first software with peer to peer - protocols, mesh networks, and the web.

Also exploring what a local-first - cyberspace might look like in my spare time.

" -url: https://mastodon.mauve.moe/@mauve -manuallyApprovesFollowers: false -discoverable: true -published: '2022-04-25T00:00:00Z' -devices: https://mastodon.mauve.moe/users/mauve/collections/devices -alsoKnownAs: -- https://infosec.exchange/users/RangerMauve -publicKey: - id: https://mastodon.mauve.moe/users/mauve#main-key - owner: https://mastodon.mauve.moe/users/mauve - publicKeyPem: | - -----BEGIN PUBLIC KEY----- - MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxjxu6bRQOjH4caQu7JgZ - umIWFeX0ZdbVnofElev2d9JByqcDoWhmaks3RYdW71RDPNrr0JxqZvUbIw9kQBng - 7iQ9YTcXTdJ/N9CQoB22msffYkEIw4ilehCDXdchNs4aoVAUwI8IhkM0p/itz6gK - 75C3CQv74Y7rHUJC8ob2p4KUwRUyhgzyhp8QWwCAn/RZ28wP8EbjWF9IskMRo9vq - WUX+Io6hpADRkSwZGoOSW2zxCEBVco6tRmABTte8I0WcAucLyMEyfGMlUvxRew4D - zAWoEBS8SyqM68vUabbZYLns6kya34tvsf1NkvajDGrfgU3D0LlGX++tOa6N9Pkf - XwIDAQAB - -----END PUBLIC KEY----- -tag: [] -attachment: -- type: PropertyValue - name: Pronouns - value: they/them/it -- type: PropertyValue - name: Email - value: mauve@mauve.moe -- type: PropertyValue - name: Matrix - value: @mauve:mauve.moe -- type: PropertyValue - name: Github/Twitter - value: "@RangerMauve" -endpoints: - sharedInbox: https://mastodon.mauve.moe/inbox -icon: - type: Image - mediaType: image/png - url: https://mastodon.mauve.moe/system/accounts/avatars/000/000/002/original/e4b910cee121b1b8.png -image: - type: Image - mediaType: image/png - url: https://mastodon.mauve.moe/system/accounts/headers/000/000/002/original/a96f990025091662.png From 2df9f721cd4b9f6831f8f891aad1f4c08785f295 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 5 Mar 2024 16:10:53 -0300 Subject: [PATCH 286/472] =?UTF-8?q?feat:=20ver=20los=20art=C3=ADculos=20de?= =?UTF-8?q?=20le=20actore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/actor_moderations_controller.rb | 1 + app/views/actor_moderations/show.haml | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/controllers/actor_moderations_controller.rb b/app/controllers/actor_moderations_controller.rb index 56adda4a..00874321 100644 --- a/app/controllers/actor_moderations_controller.rb +++ b/app/controllers/actor_moderations_controller.rb @@ -20,6 +20,7 @@ class ActorModerationsController < ApplicationController # Ver el perfil remoto def show @remote_profile = actor_moderation.actor.content + @moderation_queue = site.activity_pubs.where(actor_id: actor_moderation.actor_id) end def action_on_several diff --git a/app/views/actor_moderations/show.haml b/app/views/actor_moderations/show.haml index 7b62f672..633c1be5 100644 --- a/app/views/actor_moderations/show.haml +++ b/app/views/actor_moderations/show.haml @@ -4,5 +4,5 @@ = render 'components/actor', remote_profile: @remote_profile .col-12.col-md-8 = render 'components/profiles_btn_box', actor_moderation: @actor_moderation - -# - = render 'moderation_queue/comments', moderation_queue: @moderation_queue + .col-12.col-md-8 + = render 'moderation_queue/comments', moderation_queue: @moderation_queue From 0da69de6a73543d90c032b09bd04b74be5c8cbef Mon Sep 17 00:00:00 2001 From: f Date: Tue, 5 Mar 2024 16:24:16 -0300 Subject: [PATCH 287/472] feat: filtros comunes --- app/controllers/actor_moderations_controller.rb | 3 ++- .../concerns/moderation_filters_concern.rb | 15 +++++++++++++++ app/controllers/moderation_queue_controller.rb | 4 ++-- app/processors/instance_moderation_processor.rb | 4 ++-- app/views/components/_comments_show_submenu.haml | 2 +- app/views/components/_dropdown_item.haml | 2 +- app/views/components/_instances_filters.haml | 2 +- app/views/components/_instances_show_submenu.haml | 7 ++++--- app/views/components/_profiles_show_submenu.haml | 2 +- app/views/moderation_queue/_instances.haml | 2 +- 10 files changed, 30 insertions(+), 13 deletions(-) create mode 100644 app/controllers/concerns/moderation_filters_concern.rb diff --git a/app/controllers/actor_moderations_controller.rb b/app/controllers/actor_moderations_controller.rb index 00874321..6b924677 100644 --- a/app/controllers/actor_moderations_controller.rb +++ b/app/controllers/actor_moderations_controller.rb @@ -3,6 +3,7 @@ # Gestiona la cola de moderación de actores class ActorModerationsController < ApplicationController include ModerationConcern + include ModerationFiltersConcern ActorModeration.events.each do |actor_event| define_method(actor_event) do @@ -20,7 +21,7 @@ class ActorModerationsController < ApplicationController # Ver el perfil remoto def show @remote_profile = actor_moderation.actor.content - @moderation_queue = site.activity_pubs.where(actor_id: actor_moderation.actor_id) + @moderation_queue = rubanok_process(site.activity_pubs.where(actor_id: actor_moderation.actor_id), with: ActivityPubProcessor) end def action_on_several diff --git a/app/controllers/concerns/moderation_filters_concern.rb b/app/controllers/concerns/moderation_filters_concern.rb new file mode 100644 index 00000000..25293a4f --- /dev/null +++ b/app/controllers/concerns/moderation_filters_concern.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module ModerationFiltersConcern + extend ActiveSupport::Concern + + included do + before_action :store_filters_in_session!, only: %i[index show] + + private + + def store_filters_in_session! + session[:moderation_queue_filters] = params.permit(:instance_state, :actor_state, :activity_pub_state) + end + end +end diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index 0df62499..eebd9eae 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -2,10 +2,10 @@ # Cola de moderación de ActivityPub class ModerationQueueController < ApplicationController + include ModerationFiltersConcern + # Cola de moderación viendo todo el sitio def index - session[:moderation_queue_filters] = params.permit(:state, :actor_state, :activity_pub_state) - # @todo cambiar el estado por query @activity_pubs = site.activity_pubs @instance_moderations = rubanok_process(site.instance_moderations, with: InstanceModerationProcessor) diff --git a/app/processors/instance_moderation_processor.rb b/app/processors/instance_moderation_processor.rb index 908beaf7..eb9a7c8b 100644 --- a/app/processors/instance_moderation_processor.rb +++ b/app/processors/instance_moderation_processor.rb @@ -6,7 +6,7 @@ class InstanceModerationProcessor < Rubanok::Processor raw.includes(:instance).order('activity_pub_instances.hostname') end - map :state, activate_always: true do |state: 'paused'| - raw.where(aasm_state: state) + map :instance_state, activate_always: true do |instance_state: 'paused'| + raw.where(aasm_state: instance_state) end end diff --git a/app/views/components/_comments_show_submenu.haml b/app/views/components/_comments_show_submenu.haml index eb037975..60c02501 100644 --- a/app/views/components/_comments_show_submenu.haml +++ b/app/views/components/_comments_show_submenu.haml @@ -1,4 +1,4 @@ - ActivityPub.states.each do |state| = render 'components/dropdown_item', text: t(".submenu_#{state}", count: activity_pubs.unscope(where: :aasm_state).public_send(state).count), - path: site_moderation_queue_path(filter_states(activity_pub_state: state)) + path: filter_states(activity_pub_state: state) diff --git a/app/views/components/_dropdown_item.haml b/app/views/components/_dropdown_item.haml index 3f79403d..e5b16950 100644 --- a/app/views/components/_dropdown_item.haml +++ b/app/views/components/_dropdown_item.haml @@ -1,4 +1,4 @@ -# @param :text [String] Contenido del link - @param :path [String] Link + @param :path [String,Hash] Link = link_to text, path, class: 'dropdown-item', data: { target: 'dropdown.item' } diff --git a/app/views/components/_instances_filters.haml b/app/views/components/_instances_filters.haml index 9e8509c4..2c23fd72 100644 --- a/app/views/components/_instances_filters.haml +++ b/app/views/components/_instances_filters.haml @@ -6,4 +6,4 @@ = render 'components/instances_checked_submenu', form_id: form_id, current_state: current_state = render 'components/dropdown', text: t('.text_show') do - = render 'components/instances_show_submenu', site: site + = render 'components/instances_show_submenu', instance_moderations: instance_moderations diff --git a/app/views/components/_instances_show_submenu.haml b/app/views/components/_instances_show_submenu.haml index 811d65c7..c56df547 100644 --- a/app/views/components/_instances_show_submenu.haml +++ b/app/views/components/_instances_show_submenu.haml @@ -1,3 +1,4 @@ -= render 'components/dropdown_item', text: t('.submenu_paused', count: site.instance_moderations.paused.count), path: site_moderation_queue_path(state: 'paused') -= render 'components/dropdown_item', text: t('.submenu_allowed', count: site.instance_moderations.allowed.count), path: site_moderation_queue_path(state: 'allowed') -= render 'components/dropdown_item', text: t('.submenu_blocked', count: site.instance_moderations.blocked.count), path: site_moderation_queue_path(state: 'blocked') +- InstanceModeration.states.each do |state| + = render 'components/dropdown_item', + text: t(".submenu_#{state}", count: instance_moderations.unscope(where: :aasm_state).public_send(state).count), + path: filter_states(instance_state: state) diff --git a/app/views/components/_profiles_show_submenu.haml b/app/views/components/_profiles_show_submenu.haml index 0209ef2f..99694698 100644 --- a/app/views/components/_profiles_show_submenu.haml +++ b/app/views/components/_profiles_show_submenu.haml @@ -1,4 +1,4 @@ - ActorModeration.states.each do |actor_state| = render 'components/dropdown_item', text: t(".submenu_#{actor_state}", count: actor_moderations.unscope(where: :aasm_state).public_send(actor_state).count), - path: site_moderation_queue_path(filter_states(actor_state: actor_state)) + path: filter_states(actor_state: actor_state) diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index d9db967f..3954ce65 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -7,7 +7,7 @@ = render 'components/select_all', id: 'instances', form_id: form_id .col-11 -# Filtros - = render 'components/instances_filters', site: site, form_id: form_id + = render 'components/instances_filters', instance_moderations: instance_moderations, form_id: form_id .col-12 - if instance_moderations.count.zero? From 44ef583a23dcc2ac29b728ef7990c605bf1c1355 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 6 Mar 2024 14:12:04 -0300 Subject: [PATCH 288/472] fix: send es un nombre reservado --- app/jobs/activity_pub/remote_flag_job.rb | 2 +- app/models/activity_pub/remote_flag.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/jobs/activity_pub/remote_flag_job.rb b/app/jobs/activity_pub/remote_flag_job.rb index 7d8131db..26db937a 100644 --- a/app/jobs/activity_pub/remote_flag_job.rb +++ b/app/jobs/activity_pub/remote_flag_job.rb @@ -22,7 +22,7 @@ class ActivityPub raise 'No se pudo enviar el reporte' unless response.ok? - remote_flag.send! + remote_flag.report! rescue Exception => e ExceptionNotifier.notify_exception(e, data: { remote_flag: remote_flag.id, response: response.parsed_response }) raise diff --git a/app/models/activity_pub/remote_flag.rb b/app/models/activity_pub/remote_flag.rb index 25f1b743..76143414 100644 --- a/app/models/activity_pub/remote_flag.rb +++ b/app/models/activity_pub/remote_flag.rb @@ -14,7 +14,7 @@ class ActivityPub transitions from: :waiting, to: :queued end - event :send do + event :report do transitions from: :queued, to: :sent end From 19d998086c0f7e1d2813b68f3f8d4c31c16d75d3 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 6 Mar 2024 14:31:32 -0300 Subject: [PATCH 289/472] fix: raise --- app/models/activity_pub.rb | 6 ++---- app/models/actor_moderation.rb | 6 +++--- app/models/fediblock_state.rb | 4 ++-- app/models/instance_moderation.rb | 6 +++--- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index b07fe790..3887d512 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -68,8 +68,7 @@ class ActivityPub < ApplicationRecord transitions from: %i[paused], to: :approved before do - raise AASM::InvalidTransition unless - site.social_inbox.inbox.accept(id: object.uri).ok? + raise unless site.social_inbox.inbox.accept(id: object.uri).ok? end end @@ -78,8 +77,7 @@ class ActivityPub < ApplicationRecord transitions from: %i[paused approved], to: :rejected before do - raise AASM::InvalidTransition unless - site.social_inbox.inbox.reject(id: object.uri).ok? + raise unless site.social_inbox.inbox.reject(id: object.uri).ok? end end diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index d7eea709..5d44a021 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -65,21 +65,21 @@ class ActorModeration < ApplicationRecord end def pause_remotely! - raise AASM::InvalidTransition unless + 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 AASM::InvalidTransition unless + 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 AASM::InvalidTransition unless + raise unless actor.mention && site.social_inbox.allowlist.delete(list: [actor.mention]).ok? && site.social_inbox.blocklist.post(list: [actor.mention]).ok? diff --git a/app/models/fediblock_state.rb b/app/models/fediblock_state.rb index 180a45b5..214e2f5e 100644 --- a/app/models/fediblock_state.rb +++ b/app/models/fediblock_state.rb @@ -89,14 +89,14 @@ class FediblockState < ApplicationRecord # Al deshabilitar, las instancias pasan a ser analizadas caso por caso def disable_remotely! - raise AASM::InvalidTransition unless + raise unless site.social_inbox.blocklist.delete(list: list_names).ok? && site.social_inbox.allowlist.delete(list: list_names).ok? end # Al habilitar, se bloquean todas las instancias de la lista def enable_remotely! - raise AASM::InvalidTransition unless + raise unless site.social_inbox.blocklist.post(list: list_names).ok? && site.social_inbox.allowlist.delete(list: list_names).ok? end diff --git a/app/models/instance_moderation.rb b/app/models/instance_moderation.rb index 7447cc89..ef04b7ff 100644 --- a/app/models/instance_moderation.rb +++ b/app/models/instance_moderation.rb @@ -60,7 +60,7 @@ class InstanceModeration < ApplicationRecord # # @return [Boolean] def pause_remotely! - raise AASM::InvalidTransition unless + raise unless site.social_inbox.blocklist.delete(list: [instance.list_name]).ok? && site.social_inbox.allowlist.delete(list: [instance.list_name]).ok? end @@ -69,7 +69,7 @@ class InstanceModeration < ApplicationRecord # # @return [Boolean] def block_remotely! - raise AASM::InvalidTransition unless + raise unless site.social_inbox.allowlist.delete(list: [instance.list_name]).ok? && site.social_inbox.blocklist.post(list: [instance.list_name]).ok? end @@ -78,7 +78,7 @@ class InstanceModeration < ApplicationRecord # # @return [Boolean] def allow_remotely! - raise AASM::InvalidTransition unless + raise unless site.social_inbox.blocklist.delete(list: [instance.list_name]).ok? && site.social_inbox.allowlist.post(list: [instance.list_name]).ok? end From fbd741960bd178b473d194980f16e63f1e190e8f Mon Sep 17 00:00:00 2001 From: f Date: Wed, 6 Mar 2024 14:42:08 -0300 Subject: [PATCH 290/472] =?UTF-8?q?fix:=20crear=20hooks=20y=20blocklists?= =?UTF-8?q?=20despu=C3=A9s=20de=20publicar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/deploy_social_distributed_press.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/models/deploy_social_distributed_press.rb b/app/models/deploy_social_distributed_press.rb index eec8189b..b7525dca 100644 --- a/app/models/deploy_social_distributed_press.rb +++ b/app/models/deploy_social_distributed_press.rb @@ -7,9 +7,6 @@ class DeploySocialDistributedPress < Deploy # Solo luego de publicar remotamente DEPENDENCIES = %i[deploy_distributed_press deploy_rsync deploy_full_rsync].freeze - after_save :create_hooks! - after_create :enable_fediblocks! - # Envía las notificaciones def deploy(output: false) with_tempfile(site.private_key_pem) do |file| @@ -18,6 +15,10 @@ class DeploySocialDistributedPress < Deploy run %(bundle exec jekyll notify --trace --key #{key} --destination "#{dest}"), output: output end + + + create_hooks! + enable_fediblocks! end # Igual que DeployLocal From ea34b2c676e079948cbf51a05a039d9383f2f828 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 6 Mar 2024 15:03:17 -0300 Subject: [PATCH 291/472] fix: hostnames --- app/models/fediblock_state.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/fediblock_state.rb b/app/models/fediblock_state.rb index 214e2f5e..b5258fb6 100644 --- a/app/models/fediblock_state.rb +++ b/app/models/fediblock_state.rb @@ -82,8 +82,8 @@ class FediblockState < ApplicationRecord # @return [Array] def list_names - @list_names ||= fediblock.instances.map do |instance| - "@*@#{instance}" + @list_names ||= fediblock.hostnames.map do |hostname| + "@*@#{hostname}" end end From 38ba8795debf571c1e6173116f56d4c594f2ba7d Mon Sep 17 00:00:00 2001 From: f Date: Wed, 6 Mar 2024 15:36:00 -0300 Subject: [PATCH 292/472] fix: el reporte remoto es opcional --- app/models/activity_pub.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 3887d512..33cd4d45 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -18,7 +18,7 @@ class ActivityPub < ApplicationRecord belongs_to :site belongs_to :object, polymorphic: true belongs_to :actor - belongs_to :remote_flag, class_name: 'ActivityPub::RemoteFlag' + belongs_to :remote_flag, optional: true, class_name: 'ActivityPub::RemoteFlag' has_many :activities validates :site_id, presence: true From b334d49654a295b439de085ef0cd0352c7f47645 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 6 Mar 2024 15:41:46 -0300 Subject: [PATCH 293/472] fix: actualizar al estado remoto --- app/controllers/api/v1/webhooks/social_inbox_controller.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index 548781fa..c40857e0 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -53,7 +53,8 @@ module Api instance.present? object.present? activity.present? - activity_pub.approve! if activity_pub.may_approve? + activity_pub.update(aasm_state: 'approved') + activity.update_activity_pub_state! end head :accepted @@ -69,7 +70,7 @@ module Api instance.present? object.present? activity.present? - activity_pub.reject! if activity_pub.may_reject? + activity_pub.update(aasm_state: 'rejected') end head :accepted From 5c22015fe2d7ca3c418005ba4e8a989560270640 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 6 Mar 2024 15:47:27 -0300 Subject: [PATCH 294/472] fix: el reporte remoto es opcional --- app/models/actor_moderation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index 5d44a021..e06ffbb1 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -9,7 +9,7 @@ class ActorModeration < ApplicationRecord IGNORED_STATES = [] belongs_to :site - belongs_to :remote_flag, class_name: 'ActivityPub::RemoteFlag' + belongs_to :remote_flag, optional: true, class_name: 'ActivityPub::RemoteFlag' belongs_to :actor, class_name: 'ActivityPub::Actor' accepts_nested_attributes_for :remote_flag From 019101ba1e07448eceec8e390070f632420d72bc Mon Sep 17 00:00:00 2001 From: f Date: Wed, 6 Mar 2024 15:54:47 -0300 Subject: [PATCH 295/472] feat: almacenar el perfil de le actore en la base de datos --- app/jobs/activity_pub/actor_fetch_job.rb | 2 +- app/models/activity_pub/actor.rb | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/jobs/activity_pub/actor_fetch_job.rb b/app/jobs/activity_pub/actor_fetch_job.rb index 71107151..1190e936 100644 --- a/app/jobs/activity_pub/actor_fetch_job.rb +++ b/app/jobs/activity_pub/actor_fetch_job.rb @@ -19,7 +19,7 @@ class ActivityPub return unless response.ok? return if response.miss? && actor.content.present? - actor.update(content: FastJsonparser.parse(response.body)) + actor.object.update(content: FastJsonparser.parse(response.body)) end end end diff --git a/app/models/activity_pub/actor.rb b/app/models/activity_pub/actor.rb index fe6052bf..0a39dcde 100644 --- a/app/models/activity_pub/actor.rb +++ b/app/models/activity_pub/actor.rb @@ -25,5 +25,13 @@ class ActivityPub @mention ||= "@#{content['preferredUsername']}@#{instance.hostname}" end + + def object + @object ||= ActivityPub::Object::Person.find_or_initialize_by(uri: uri) + end + + def content + object.content + end end end From 5f5b929aa89098726ddb55098756d01e060fd9dc Mon Sep 17 00:00:00 2001 From: f Date: Wed, 6 Mar 2024 15:59:48 -0300 Subject: [PATCH 296/472] fix: traducciones --- config/locales/en.yml | 17 ++++++++--------- config/locales/es.yml | 17 ++++++++--------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 0ca90aa7..0f010c89 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -50,6 +50,14 @@ en: pm: pm format: '%-I:%M %p' components: + actor: + user: Username + profile: Profile + profile_name: Profile name + preferred_name: Name in Fediverse + profile_id: ID + profile_published: Published + profile_summary: Summary block_list: know_more: Know more instances_blocked: Instances blocked @@ -107,15 +115,6 @@ en: text_allow: Always approve text_block: Block text_report: Report - actor_moderations: - show: - user: Username - profile: Profile - profile_name: Profile name - preferred_name: Name in Fediverse - profile_id: ID - profile_published: Published - profile_summary: Summary remote_flags: report_message: "Hi! Someone using Sutty CMS reported this account on your instance. We don't have support for customized report messages yet, but we will soon. You can reach us at %{panel_actor_mention}." moderation_queue: diff --git a/config/locales/es.yml b/config/locales/es.yml index 40a1a18c..0a2538a7 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -50,6 +50,14 @@ es: pm: pm format: '%-H:%M' components: + actor: + user: Nombre de usuarie + profile: Cuenta de Origen + profile_name: Nombre de la cuenta + preferred_name: Nombre en el Fediverso + profile_id: ID + profile_published: Publicada + profile_summary: Presentación block_list: know_more: Saber más (en inglés) instances_blocked: Instancias bloqueadas @@ -106,15 +114,6 @@ es: text_allow: Aprobar siempre text_block: Bloquear text_report: Reportar - actor_moderations: - show: - user: Nombre de usuarie - profile: Cuenta de Origen - profile_name: Nombre de la cuenta - preferred_name: Nombre en el Fediverso - profile_id: ID - profile_published: Publicada - profile_summary: Presentación remote_flags: report_message: "¡Hola! Une usuarie de Sutty CMS reportó esta cuenta en tu instancia. Todavía no tenemos soporte para mensajes personalizados. Podés contactarnos en %{panel_actor_mention}." moderation_queue: From 2e04bc8eac09bcfc4929ca9670971fcf5da35056 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 6 Mar 2024 17:15:21 -0300 Subject: [PATCH 297/472] =?UTF-8?q?fix:=20las=20actividades=20est=C3=A1n?= =?UTF-8?q?=20duplicadas=20con=20respecto=20a=20su=20estado?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit por ejemplo, el borrado de une actore puede estar dirigido a todos los sitios, con lo que se crea varias veces (aunque se ejecuta solo una) --- app/models/activity_pub/activity.rb | 2 ++ app/models/activity_pub/actor.rb | 3 +++ app/models/activity_pub/concerns/json_ld_concern.rb | 2 -- app/models/activity_pub/object.rb | 3 +++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/models/activity_pub/activity.rb b/app/models/activity_pub/activity.rb index 1147c5b8..ee555474 100644 --- a/app/models/activity_pub/activity.rb +++ b/app/models/activity_pub/activity.rb @@ -20,6 +20,8 @@ class ActivityPub has_one :object, through: :activity_pub validates :activity_pub_id, presence: true + # Las actividades son únicas con respecto a su estado + validates :uri, presence: true, uniqueness: { scope: :activity_pub_id, message: 'estado duplicado' } # Siempre en orden descendiente para saber el último estado default_scope -> { order(created_at: :desc) } diff --git a/app/models/activity_pub/actor.rb b/app/models/activity_pub/actor.rb index 0a39dcde..919bc5e0 100644 --- a/app/models/activity_pub/actor.rb +++ b/app/models/activity_pub/actor.rb @@ -15,6 +15,9 @@ class ActivityPub has_many :activities has_many :remote_flags + # Les actores son únicxs a toda la base de datos + validates :uri, presence: true, uniqueness: true + # Obtiene el nombre de la Actor como mención, solo si obtuvimos el # contenido de antemano. # diff --git a/app/models/activity_pub/concerns/json_ld_concern.rb b/app/models/activity_pub/concerns/json_ld_concern.rb index bc30330c..282027df 100644 --- a/app/models/activity_pub/concerns/json_ld_concern.rb +++ b/app/models/activity_pub/concerns/json_ld_concern.rb @@ -6,8 +6,6 @@ class ActivityPub extend ActiveSupport::Concern included do - validates :uri, presence: true, uniqueness: true - # Cuando asignamos contenido, obtener la URI si no lo hicimos ya before_save :uri_from_content!, unless: :uri? diff --git a/app/models/activity_pub/object.rb b/app/models/activity_pub/object.rb index c196160f..15b07bee 100644 --- a/app/models/activity_pub/object.rb +++ b/app/models/activity_pub/object.rb @@ -5,6 +5,9 @@ class ActivityPub class Object < ApplicationRecord include ActivityPub::Concerns::JsonLdConcern + # Los objetos son únicos a toda la base de datos + validates :uri, presence: true, uniqueness: true + has_many :activity_pubs, as: :object # Encontrar le Actor por su relación con el objeto From 00f865f31542a15496355ea878954656323941f4 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 6 Mar 2024 17:22:01 -0300 Subject: [PATCH 298/472] fix: comentario en perfil de actore --- app/models/activity_pub/activity/delete.rb | 10 ++++++++-- app/views/moderation_queue/_comments.haml | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/models/activity_pub/activity/delete.rb b/app/models/activity_pub/activity/delete.rb index f6ff6536..5de20478 100644 --- a/app/models/activity_pub/activity/delete.rb +++ b/app/models/activity_pub/activity/delete.rb @@ -14,9 +14,15 @@ class ActivityPub # @see {https://docs.joinmastodon.org/spec/security/#ld} def update_activity_pub_state! ActivityPub.transaction do - ActivityPub::Object.find_by(uri: ActivityPub.uri_from_object(content['object']))&.activity_pubs&.find_each(&:remove!) + object = ActivityPub::Object.find_by(uri: ActivityPub.uri_from_object(content['object'])) - activity_pub.remove! + if object + object.activity_pubs.find_each do |activity_pub| + activity_pub.remove! if activity_pub.may_remove? + end + end + + activity_pub.remove! if activity_pub.may_remove? end end end diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index 436777db..316b097f 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -14,4 +14,4 @@ - moderation_queue.each do |activity_pub| -# cache [activity_pub, activity_pub.object, activity_pub.actor] do %hr - = render 'comment', comment: activity_pub.object.content, profile: activity_pub.actor.content, activity_pub: activity_pub, form_id: form_id + = render 'moderation_queue/comment', comment: activity_pub.object.content, profile: activity_pub.actor.content, activity_pub: activity_pub, form_id: form_id From 7aa14bd292bafbee9fd0a4dea874ae639e0a9737 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 6 Mar 2024 17:36:13 -0300 Subject: [PATCH 299/472] fix: poder ir al perfil --- app/views/components/_actor.haml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/views/components/_actor.haml b/app/views/components/_actor.haml index 3983d617..c58beae0 100644 --- a/app/views/components/_actor.haml +++ b/app/views/components/_actor.haml @@ -1,5 +1,7 @@ -# Componente Remote_Profile +- uri = text_plain(remote_profile['id']) + .py-2 %dl %dt= t('.profile_name') @@ -10,7 +12,7 @@ %dt= t('.profile_id') %dd - = link_to text_plain(remote_profile['id']) + = link_to uri, uri - if remote_profile['published'].present? %dt= t('.profile_published') From a8f184ecbf80b91336a7ee6a2ce5d4177f4e044e Mon Sep 17 00:00:00 2001 From: f Date: Wed, 6 Mar 2024 17:45:21 -0300 Subject: [PATCH 300/472] feat: validar que las uris sean uris --- app/models/activity_pub/activity.rb | 2 +- app/models/activity_pub/actor.rb | 2 +- app/models/activity_pub/object.rb | 2 +- app/validators/url_validator.rb | 21 +++++++++++++++++++++ 4 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 app/validators/url_validator.rb diff --git a/app/models/activity_pub/activity.rb b/app/models/activity_pub/activity.rb index ee555474..af005ff3 100644 --- a/app/models/activity_pub/activity.rb +++ b/app/models/activity_pub/activity.rb @@ -21,7 +21,7 @@ class ActivityPub validates :activity_pub_id, presence: true # Las actividades son únicas con respecto a su estado - validates :uri, presence: true, uniqueness: { scope: :activity_pub_id, message: 'estado duplicado' } + validates :uri, presence: true, url: true, uniqueness: { scope: :activity_pub_id, message: 'estado duplicado' } # Siempre en orden descendiente para saber el último estado default_scope -> { order(created_at: :desc) } diff --git a/app/models/activity_pub/actor.rb b/app/models/activity_pub/actor.rb index 919bc5e0..b03145e7 100644 --- a/app/models/activity_pub/actor.rb +++ b/app/models/activity_pub/actor.rb @@ -16,7 +16,7 @@ class ActivityPub has_many :remote_flags # Les actores son únicxs a toda la base de datos - validates :uri, presence: true, uniqueness: true + validates :uri, presence: true, url: true, uniqueness: true # Obtiene el nombre de la Actor como mención, solo si obtuvimos el # contenido de antemano. diff --git a/app/models/activity_pub/object.rb b/app/models/activity_pub/object.rb index 15b07bee..3fde326b 100644 --- a/app/models/activity_pub/object.rb +++ b/app/models/activity_pub/object.rb @@ -6,7 +6,7 @@ class ActivityPub include ActivityPub::Concerns::JsonLdConcern # Los objetos son únicos a toda la base de datos - validates :uri, presence: true, uniqueness: true + validates :uri, presence: true, url: true, uniqueness: true has_many :activity_pubs, as: :object diff --git a/app/validators/url_validator.rb b/app/validators/url_validator.rb new file mode 100644 index 00000000..291f9288 --- /dev/null +++ b/app/validators/url_validator.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +# Valida URLs +# +# @see {https://storck.io/posts/better-http-url-validation-in-ruby-on-rails/} +class UrlValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + if value.blank? + record.errors.add(attribute, :url_missing) + return + end + + uri = URI.parse(value) + + record.errors.add(attribute, :scheme_missing) if uri.scheme.blank? + record.errors.add(attribute, :host_missing) if uri.host.blank? + record.errors.add(attribute, :path_missing) if uri.path.blank? + rescue URI::Error + record.errors.add(attribute, :invalid) + end +end From 66e59ee5ad8143630b07965560c3951d5cb2cac2 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 7 Mar 2024 16:54:09 -0300 Subject: [PATCH 301/472] feat: algunos tipos son actores --- app/models/activity_pub/object.rb | 8 ++++++ app/models/activity_pub/object/application.rb | 4 ++- app/models/activity_pub/object/audio.rb | 10 +++++++ .../object/concerns/actor_type_concern.rb | 27 +++++++++++++++++++ app/models/activity_pub/object/document.rb | 10 +++++++ app/models/activity_pub/object/event.rb | 10 +++++++ app/models/activity_pub/object/group.rb | 10 +++++++ app/models/activity_pub/object/image.rb | 10 +++++++ .../activity_pub/object/organization.rb | 4 ++- app/models/activity_pub/object/page.rb | 10 +++++++ app/models/activity_pub/object/person.rb | 4 ++- app/models/activity_pub/object/place.rb | 10 +++++++ app/models/activity_pub/object/profile.rb | 10 +++++++ .../activity_pub/object/relationship.rb | 10 +++++++ app/models/activity_pub/object/service.rb | 10 +++++++ app/models/activity_pub/object/tombstone.rb | 10 +++++++ app/models/activity_pub/object/video.rb | 10 +++++++ 17 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 app/models/activity_pub/object/audio.rb create mode 100644 app/models/activity_pub/object/concerns/actor_type_concern.rb create mode 100644 app/models/activity_pub/object/document.rb create mode 100644 app/models/activity_pub/object/event.rb create mode 100644 app/models/activity_pub/object/group.rb create mode 100644 app/models/activity_pub/object/image.rb create mode 100644 app/models/activity_pub/object/page.rb create mode 100644 app/models/activity_pub/object/place.rb create mode 100644 app/models/activity_pub/object/profile.rb create mode 100644 app/models/activity_pub/object/relationship.rb create mode 100644 app/models/activity_pub/object/service.rb create mode 100644 app/models/activity_pub/object/tombstone.rb create mode 100644 app/models/activity_pub/object/video.rb diff --git a/app/models/activity_pub/object.rb b/app/models/activity_pub/object.rb index 3fde326b..b33c1957 100644 --- a/app/models/activity_pub/object.rb +++ b/app/models/activity_pub/object.rb @@ -16,5 +16,13 @@ class ActivityPub def actor ActivityPub::Actor.find_by(uri: content['actor']) end + + def actor_type? + false + end + + def object_type? + true + end end end diff --git a/app/models/activity_pub/object/application.rb b/app/models/activity_pub/object/application.rb index 99ac935c..d26a7757 100644 --- a/app/models/activity_pub/object/application.rb +++ b/app/models/activity_pub/object/application.rb @@ -5,6 +5,8 @@ # Una aplicación o instancia class ActivityPub class Object - class Application < ActivityPub::Object; end + class Application < ActivityPub::Object + include Concerns::ActorTypeConcern + end end end diff --git a/app/models/activity_pub/object/audio.rb b/app/models/activity_pub/object/audio.rb new file mode 100644 index 00000000..48caea44 --- /dev/null +++ b/app/models/activity_pub/object/audio.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Audio = +# +# Representa artículos +class ActivityPub + class Object + class Audio < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/concerns/actor_type_concern.rb b/app/models/activity_pub/object/concerns/actor_type_concern.rb new file mode 100644 index 00000000..bb840601 --- /dev/null +++ b/app/models/activity_pub/object/concerns/actor_type_concern.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +class ActivityPub + class Object + module Concerns + module ActorTypeConcern + extend ActiveSupport::Concern + + included do + # El objeto referencia a une Actor + # + # @see {https://www.w3.org/TR/activitystreams-vocabulary/#actor-types} + def actor_type? + true + end + + # El objeto es un objeto + # + # @see {https://www.w3.org/TR/activitystreams-vocabulary/#object-types} + def object_type? + false + end + end + end + end + end +end diff --git a/app/models/activity_pub/object/document.rb b/app/models/activity_pub/object/document.rb new file mode 100644 index 00000000..d7444514 --- /dev/null +++ b/app/models/activity_pub/object/document.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Document = +# +# Representa artículos +class ActivityPub + class Object + class Document < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/event.rb b/app/models/activity_pub/object/event.rb new file mode 100644 index 00000000..9fa1f6fc --- /dev/null +++ b/app/models/activity_pub/object/event.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Event = +# +# Representa artículos +class ActivityPub + class Object + class Event < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/group.rb b/app/models/activity_pub/object/group.rb new file mode 100644 index 00000000..08d11d0d --- /dev/null +++ b/app/models/activity_pub/object/group.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Group = +class ActivityPub + class Object + class Group < ActivityPub::Object + include Concerns::ActorTypeConcern + end + end +end diff --git a/app/models/activity_pub/object/image.rb b/app/models/activity_pub/object/image.rb new file mode 100644 index 00000000..9939a14b --- /dev/null +++ b/app/models/activity_pub/object/image.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Image = +# +# Representa artículos +class ActivityPub + class Object + class Image < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/organization.rb b/app/models/activity_pub/object/organization.rb index e3385232..e820c305 100644 --- a/app/models/activity_pub/object/organization.rb +++ b/app/models/activity_pub/object/organization.rb @@ -5,6 +5,8 @@ # Una organización class ActivityPub class Object - class Organization < ActivityPub::Object; end + class Organization < ActivityPub::Object + include Concerns::ActorTypeConcern + end end end diff --git a/app/models/activity_pub/object/page.rb b/app/models/activity_pub/object/page.rb new file mode 100644 index 00000000..f05503e2 --- /dev/null +++ b/app/models/activity_pub/object/page.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Page = +# +# Representa artículos +class ActivityPub + class Object + class Page < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/person.rb b/app/models/activity_pub/object/person.rb index a6a85d43..5bcab596 100644 --- a/app/models/activity_pub/object/person.rb +++ b/app/models/activity_pub/object/person.rb @@ -5,6 +5,8 @@ # Una persona, el perfil de une actore class ActivityPub class Object - class Person < ActivityPub::Object; end + class Person < ActivityPub::Object + include Concerns::ActorTypeConcern + end end end diff --git a/app/models/activity_pub/object/place.rb b/app/models/activity_pub/object/place.rb new file mode 100644 index 00000000..f04032ed --- /dev/null +++ b/app/models/activity_pub/object/place.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Place = +# +# Representa artículos +class ActivityPub + class Object + class Place < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/profile.rb b/app/models/activity_pub/object/profile.rb new file mode 100644 index 00000000..8f7183a2 --- /dev/null +++ b/app/models/activity_pub/object/profile.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Profile = +# +# Representa artículos +class ActivityPub + class Object + class Profile < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/relationship.rb b/app/models/activity_pub/object/relationship.rb new file mode 100644 index 00000000..ece995b4 --- /dev/null +++ b/app/models/activity_pub/object/relationship.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Relationship = +# +# Representa artículos +class ActivityPub + class Object + class Relationship < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/service.rb b/app/models/activity_pub/object/service.rb new file mode 100644 index 00000000..a276ea5b --- /dev/null +++ b/app/models/activity_pub/object/service.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Service = +class ActivityPub + class Object + class Service < ActivityPub::Object + include Concerns::ActorTypeConcern + end + end +end diff --git a/app/models/activity_pub/object/tombstone.rb b/app/models/activity_pub/object/tombstone.rb new file mode 100644 index 00000000..88f136b9 --- /dev/null +++ b/app/models/activity_pub/object/tombstone.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Tombstone = +# +# Representa artículos +class ActivityPub + class Object + class Tombstone < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/video.rb b/app/models/activity_pub/object/video.rb new file mode 100644 index 00000000..fa4bbffb --- /dev/null +++ b/app/models/activity_pub/object/video.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Video = +# +# Representa artículos +class ActivityPub + class Object + class Video < ActivityPub::Object; end + end +end From 5a7331e00e44074bd9639d9023f707721665655b Mon Sep 17 00:00:00 2001 From: f Date: Thu, 7 Mar 2024 17:17:58 -0300 Subject: [PATCH 302/472] =?UTF-8?q?feat:=20cuando=20une=20actore=20es=20el?= =?UTF-8?q?iminade,=20hay=20que=20eliminar=20sus=20estados=20de=20moderaci?= =?UTF-8?q?=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/activity_pub/activity/delete.rb | 8 +++++++- app/models/activity_pub/object.rb | 7 ++++++- .../object/concerns/actor_type_concern.rb | 7 +++++++ app/models/actor_moderation.rb | 15 +++++++++++++-- .../20240307201510_remove_actor_moderations.rb | 13 +++++++++++++ 5 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20240307201510_remove_actor_moderations.rb diff --git a/app/models/activity_pub/activity/delete.rb b/app/models/activity_pub/activity/delete.rb index 5de20478..6a23a8b5 100644 --- a/app/models/activity_pub/activity/delete.rb +++ b/app/models/activity_pub/activity/delete.rb @@ -16,10 +16,16 @@ class ActivityPub ActivityPub.transaction do object = ActivityPub::Object.find_by(uri: ActivityPub.uri_from_object(content['object'])) - if object + if object.present? object.activity_pubs.find_each do |activity_pub| activity_pub.remove! if activity_pub.may_remove? end + + # Encontrar todas las acciones de moderación de le actore + # eliminade y moverlas a eliminar. + if object.actor_type? && object.actor.present? + ActorModeration.where(actor_id: object.actor.id).remove_all! + end end activity_pub.remove! if activity_pub.may_remove? diff --git a/app/models/activity_pub/object.rb b/app/models/activity_pub/object.rb index b33c1957..9061c4c5 100644 --- a/app/models/activity_pub/object.rb +++ b/app/models/activity_pub/object.rb @@ -14,7 +14,12 @@ class ActivityPub # # @return [ActivityPub::Actor,nil] def actor - ActivityPub::Actor.find_by(uri: content['actor']) + ActivityPub::Actor.find_by(uri: actor_uri) + end + + # @return [String] + def actor_uri + content['attributedTo'] end def actor_type? diff --git a/app/models/activity_pub/object/concerns/actor_type_concern.rb b/app/models/activity_pub/object/concerns/actor_type_concern.rb index bb840601..b2a643c7 100644 --- a/app/models/activity_pub/object/concerns/actor_type_concern.rb +++ b/app/models/activity_pub/object/concerns/actor_type_concern.rb @@ -7,6 +7,13 @@ class ActivityPub extend ActiveSupport::Concern included do + # La URI de le Actor en este caso es la misma id + # + # @return [String] + def actor_uri + uri + end + # El objeto referencia a une Actor # # @see {https://www.w3.org/TR/activitystreams-vocabulary/#actor-types} diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index e06ffbb1..01613f72 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -5,8 +5,8 @@ class ActorModeration < ApplicationRecord include AASM include AasmEventsConcern - IGNORED_EVENTS = [] - IGNORED_STATES = [] + IGNORED_EVENTS = %i[remove] + IGNORED_STATES = %i[removed] belongs_to :site belongs_to :remote_flag, optional: true, class_name: 'ActivityPub::RemoteFlag' @@ -23,11 +23,16 @@ class ActorModeration < ApplicationRecord 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 state :blocked state :reported + state :removed event :pause do transitions from: %i[allowed blocked reported], to: :paused @@ -62,6 +67,12 @@ class ActorModeration < ApplicationRecord ActivityPub::RemoteFlagJob.perform_later(remote_flag: remote_flag) if remote_flag.waiting? end end + + # Si un perfil es eliminado remotamente, tenemos que dejar de + # mostrarlo y todas sus actividades. + event :remove do + transitions to: :removed + end end def pause_remotely! diff --git a/db/migrate/20240307201510_remove_actor_moderations.rb b/db/migrate/20240307201510_remove_actor_moderations.rb new file mode 100644 index 00000000..92c6d23a --- /dev/null +++ b/db/migrate/20240307201510_remove_actor_moderations.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +# Mover todes les actores eliminades +class RemoveActorModerations < ActiveRecord::Migration[6.1] + def up + actor_ids = + ActivityPub.where(aasm_state: 'removed', object_type: 'ActivityPub::Object::Person').distinct.pluck(:actor_id) + + ActorModeration.where(id: actor_ids).remove_all! + end + + def down; end +end From b0b8e6877efee116e707efea7ea05145387a7c00 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 7 Mar 2024 17:21:03 -0300 Subject: [PATCH 303/472] =?UTF-8?q?fixup!=20feat:=20cuando=20une=20actore?= =?UTF-8?q?=20es=20eliminade,=20hay=20que=20eliminar=20sus=20estados=20de?= =?UTF-8?q?=20moderaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/migrate/20240307201510_remove_actor_moderations.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20240307201510_remove_actor_moderations.rb b/db/migrate/20240307201510_remove_actor_moderations.rb index 92c6d23a..b451c589 100644 --- a/db/migrate/20240307201510_remove_actor_moderations.rb +++ b/db/migrate/20240307201510_remove_actor_moderations.rb @@ -6,7 +6,7 @@ class RemoveActorModerations < ActiveRecord::Migration[6.1] actor_ids = ActivityPub.where(aasm_state: 'removed', object_type: 'ActivityPub::Object::Person').distinct.pluck(:actor_id) - ActorModeration.where(id: actor_ids).remove_all! + ActorModeration.where(actor_id: actor_ids).remove_all! end def down; end From 2370cf73108b315c833f370f876209896efe7067 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 7 Mar 2024 17:44:40 -0300 Subject: [PATCH 304/472] =?UTF-8?q?feat:=20eliminar=20m=C3=A1s=20actores?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../20240307203039_remove_actor_moderations2.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 db/migrate/20240307203039_remove_actor_moderations2.rb diff --git a/db/migrate/20240307203039_remove_actor_moderations2.rb b/db/migrate/20240307203039_remove_actor_moderations2.rb new file mode 100644 index 00000000..dabc7ed7 --- /dev/null +++ b/db/migrate/20240307203039_remove_actor_moderations2.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +# Algunes quedaron como genéricxs +class RemoveActorModerations2 < ActiveRecord::Migration[6.1] + def up + actor_uris = ActivityPub::Activity.where(type: 'ActivityPub::Activity::Delete').distinct.pluck(Arel.sql("content->>'object'")) + actor_ids = ActivityPub::Actor.where(uri: actor_uris).ids + + ActorModeration.where(actor_id: actor_ids).remove_all! + end + + def down; end +end From 21401d93b6c79a34a55e8d3d8c97cd029c96428a Mon Sep 17 00:00:00 2001 From: f Date: Thu, 7 Mar 2024 17:46:32 -0300 Subject: [PATCH 305/472] =?UTF-8?q?fixup!=20feat:=20eliminar=20m=C3=A1s=20?= =?UTF-8?q?actores?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/migrate/20240307203039_remove_actor_moderations2.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20240307203039_remove_actor_moderations2.rb b/db/migrate/20240307203039_remove_actor_moderations2.rb index dabc7ed7..555a4ffe 100644 --- a/db/migrate/20240307203039_remove_actor_moderations2.rb +++ b/db/migrate/20240307203039_remove_actor_moderations2.rb @@ -3,7 +3,7 @@ # Algunes quedaron como genéricxs class RemoveActorModerations2 < ActiveRecord::Migration[6.1] def up - actor_uris = ActivityPub::Activity.where(type: 'ActivityPub::Activity::Delete').distinct.pluck(Arel.sql("content->>'object'")) + actor_uris = ActivityPub::Activity.unscope(:order).where(type: 'ActivityPub::Activity::Delete').distinct.pluck(Arel.sql("content->>'object'")) actor_ids = ActivityPub::Actor.where(uri: actor_uris).ids ActorModeration.where(actor_id: actor_ids).remove_all! From 550dba08c5cafc9ce9aeee120177fdb0b904be62 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 8 Mar 2024 11:24:57 -0300 Subject: [PATCH 306/472] fix: migraciones --- db/structure.sql | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/db/structure.sql b/db/structure.sql index 97bd372e..ed58ebec 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -2699,6 +2699,8 @@ INSERT INTO "schema_migrations" (version) VALUES ('20240301194154'), ('20240301202955'), ('20240305164653'), -('20240305184854'); +('20240305184854'), +('20240307201510'), +('20240307203039'); From fc77f8e9f406c854155f966e2f7b8fc869e6218c Mon Sep 17 00:00:00 2001 From: f Date: Fri, 8 Mar 2024 13:08:24 -0300 Subject: [PATCH 307/472] fix: form es opcional #15329 --- app/views/components/_checkbox.haml | 3 ++- app/views/components/_comments_checked_submenu.haml | 5 ++++- app/views/components/_comments_filters.haml | 5 ++++- app/views/components/_dropdown_button.haml | 2 +- app/views/components/_instances_checked_submenu.haml | 5 ++++- app/views/components/_instances_filters.haml | 5 ++++- app/views/components/_profiles_checked_submenu.haml | 5 ++++- app/views/components/_profiles_filters.haml | 5 ++++- app/views/components/_select_all.haml | 2 +- app/views/components/_select_all_container.haml | 4 ++-- app/views/moderation_queue/_account.haml | 5 ++++- app/views/moderation_queue/_accounts.haml | 8 ++++---- app/views/moderation_queue/_comment.haml | 3 ++- app/views/moderation_queue/_comments.haml | 8 ++++---- app/views/moderation_queue/_instance.haml | 2 +- app/views/moderation_queue/_instances.haml | 8 ++++---- 16 files changed, 49 insertions(+), 26 deletions(-) diff --git a/app/views/components/_checkbox.haml b/app/views/components/_checkbox.haml index 68f1a663..a58c85b7 100644 --- a/app/views/components/_checkbox.haml +++ b/app/views/components/_checkbox.haml @@ -1,5 +1,6 @@ -# Componente Checkbox - local_assigns[:name] ||= id + .custom-control.custom-checkbox - %input.custom-control-input{ form: local_assigns[:form_id], type: 'checkbox', id: id, **local_assigns } + %input.custom-control-input{ type: 'checkbox', id: id, **local_assigns.compact } %label.custom-control-label{ for: id }= yield diff --git a/app/views/components/_comments_checked_submenu.haml b/app/views/components/_comments_checked_submenu.haml index a09da426..d94e12a9 100644 --- a/app/views/components/_comments_checked_submenu.haml +++ b/app/views/components/_comments_checked_submenu.haml @@ -1,6 +1,9 @@ +-# + @param form [String] + - current_state = params[:activity_pub_state]&.to_sym || ActivityPub.states.first - ActivityPub.aasm.events.each do |event| - next if ActivityPub::IGNORED_EVENTS.include? event.name - next unless event.transitions_from_state?(current_state) - = render 'components/dropdown_button', form_id: form_id, text: t(".submenu_#{event.name}"), name: 'activity_pub_action', value: event.name + = render 'components/dropdown_button', form: form, text: t(".submenu_#{event.name}"), name: 'activity_pub_action', value: event.name diff --git a/app/views/components/_comments_filters.haml b/app/views/components/_comments_filters.haml index 35cd5dda..cf8c1aa2 100644 --- a/app/views/components/_comments_filters.haml +++ b/app/views/components/_comments_filters.haml @@ -1,9 +1,12 @@ +-# + @params form [String] + - current_state = params[:activity_pub_state]&.to_sym || ActivityPub.states.first .d-flex.py-2 - if ActivityPub.transitionable_events(current_state).present? = render 'components/dropdown', text: t('.text_checked') do - = render 'components/comments_checked_submenu', form_id: form_id + = render 'components/comments_checked_submenu', form: form = render 'components/dropdown', text: t('.text_show') do = render 'components/comments_show_submenu', activity_pubs: activity_pubs diff --git a/app/views/components/_dropdown_button.haml b/app/views/components/_dropdown_button.haml index c8c98209..c0f12754 100644 --- a/app/views/components/_dropdown_button.haml +++ b/app/views/components/_dropdown_button.haml @@ -1,4 +1,4 @@ -# @param name [String] @param value [String] -%button.dropdown-item{type: 'submit', data: { target: 'dropdown.item' }, name: name, value: value, form: local_assigns[:form_id] }= text +%button.dropdown-item{type: 'submit', data: { target: 'dropdown.item' }, name: name, value: value, **local_assigns.compact } diff --git a/app/views/components/_instances_checked_submenu.haml b/app/views/components/_instances_checked_submenu.haml index 4c45b7ab..7c9dbd87 100644 --- a/app/views/components/_instances_checked_submenu.haml +++ b/app/views/components/_instances_checked_submenu.haml @@ -1,2 +1,5 @@ +-# + @params form [String] + - InstanceModeration.transitionable_events(current_state).each do |event| - = render 'components/dropdown_button', text: t(".submenu_#{event}"), name: 'instance_moderation_action', value: event, form_id: form_id + = render 'components/dropdown_button', text: t(".submenu_#{event}"), name: 'instance_moderation_action', value: event, form: form diff --git a/app/views/components/_instances_filters.haml b/app/views/components/_instances_filters.haml index 2c23fd72..730184bd 100644 --- a/app/views/components/_instances_filters.haml +++ b/app/views/components/_instances_filters.haml @@ -1,9 +1,12 @@ +-# + @params form [String] + - current_state = params[:state]&.to_sym || InstanceModeration.states.first .d-flex.py-2 - if InstanceModeration.transitionable_events(current_state).present? = render 'components/dropdown', text: t('.text_checked') do - = render 'components/instances_checked_submenu', form_id: form_id, current_state: current_state + = render 'components/instances_checked_submenu', form: form, current_state: current_state = render 'components/dropdown', text: t('.text_show') do = render 'components/instances_show_submenu', instance_moderations: instance_moderations diff --git a/app/views/components/_profiles_checked_submenu.haml b/app/views/components/_profiles_checked_submenu.haml index 66a0fa78..04c86fd4 100644 --- a/app/views/components/_profiles_checked_submenu.haml +++ b/app/views/components/_profiles_checked_submenu.haml @@ -1,2 +1,5 @@ +-# + @params form [String] + - ActorModeration.transitionable_events(current_state).each do |actor_event| - = render 'components/dropdown_button', text: t(".submenu_#{actor_event}"), name: 'actor_moderation_action', value: actor_event, form_id: form_id + = render 'components/dropdown_button', text: t(".submenu_#{actor_event}"), name: 'actor_moderation_action', value: actor_event, form: form diff --git a/app/views/components/_profiles_filters.haml b/app/views/components/_profiles_filters.haml index bf7fb48a..3f830ec8 100644 --- a/app/views/components/_profiles_filters.haml +++ b/app/views/components/_profiles_filters.haml @@ -1,9 +1,12 @@ +-# + @params form [String] + - current_state = params[:actor_state]&.to_sym || ActorModeration.states.first .d-flex.py-2 - if ActorModeration.transitionable_events(current_state).present? = render 'components/dropdown', text: t('.text_checked') do - = render 'components/profiles_checked_submenu', form_id: form_id, current_state: current_state + = render 'components/profiles_checked_submenu', form: form, current_state: current_state = render 'components/dropdown', text: t('.text_show') do = render 'components/profiles_show_submenu', actor_moderations: actor_moderations diff --git a/app/views/components/_select_all.haml b/app/views/components/_select_all.haml index 68711c4a..9778cd13 100644 --- a/app/views/components/_select_all.haml +++ b/app/views/components/_select_all.haml @@ -1,4 +1,4 @@ -# @param id [String] -= render 'components/checkbox', id: id, form: local_assigns[:form_id], data: { action: 'select-all#toggle', target: 'select-all.toggle' } do += render 'components/checkbox', id: id, data: { action: 'select-all#toggle', target: 'select-all.toggle', **local_assigns.compact } do %span.sr-only= t('.label') diff --git a/app/views/components/_select_all_container.haml b/app/views/components/_select_all_container.haml index 5fa91e2d..8c8d9426 100644 --- a/app/views/components/_select_all_container.haml +++ b/app/views/components/_select_all_container.haml @@ -7,7 +7,7 @@ navegador los va a asignar a este formulario. @param path [String] - @param form_id [String] + @param form [String] -= form_tag path, id: form_id, method: :patch do += form_tag path, id: form, method: :patch do -# nada diff --git a/app/views/moderation_queue/_account.haml b/app/views/moderation_queue/_account.haml index f63b6f6f..6b4c67fc 100644 --- a/app/views/moderation_queue/_account.haml +++ b/app/views/moderation_queue/_account.haml @@ -1,6 +1,9 @@ +-# + @params form [String] + .row.no-gutters.pt-2 .col-1 - = render 'components/checkbox', id: actor_moderation.id, form_id: form_id, name: 'actor_moderation[]', value: actor_moderation.id, data: { target: 'select-all.input' } + = render 'components/checkbox', id: actor_moderation.id, form: form, name: 'actor_moderation[]', value: actor_moderation.id, data: { target: 'select-all.input' } .col-11 %h4 = link_to text_plain(profile['name']), site_actor_moderation_path(id: actor_moderation) diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index 65ff953f..abc02b31 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -1,17 +1,17 @@ - form_id = 'actor_moderations_action_on_several' -= render 'components/select_all_container', path: site_actor_moderations_action_on_several_path, form_id: form_id += render 'components/select_all_container', path: site_actor_moderations_action_on_several_path, form: form_id .row.no-gutters.pt-2{ data: { controller: 'select-all' } } .col-1.d-flex.align-items-center - = render 'components/select_all', id: 'actors', form_id: form_id + = render 'components/select_all', id: 'actors', form: form_id .col-11 -# Filtros - = render 'components/profiles_filters', actor_moderations: actor_moderations, form_id: form_id + = render 'components/profiles_filters', actor_moderations: actor_moderations, form: form_id .col-12 - if actor_moderations.count.zero? %h4= t('moderation_queue.nothing') - actor_moderations.find_each do |actor_moderation| - cache [actor_moderation, actor_moderation.actor] do %hr - = render 'account', actor_moderation: actor_moderation, profile: actor_moderation.actor.content, form_id: form_id + = render 'account', actor_moderation: actor_moderation, profile: actor_moderation.actor.content, form: form_id diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 33ebc722..90579a9c 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -1,6 +1,7 @@ -# Componente Comentario + @param form [String] @param profile [Hash] @param comment [Hash] @param activity_pub [ActivityPub] @@ -10,7 +11,7 @@ .row.no-gutters .col-1 - = render 'components/checkbox', id: activity_pub.id, name: 'activity_pub[]', value: activity_pub.id, data: { target: 'select-all.input' }, form: form_id + = render 'components/checkbox', id: activity_pub.id, name: 'activity_pub[]', value: activity_pub.id, data: { target: 'select-all.input' }, form: form .col-11 .d-flex.flex-row.align-items-center.justify-content-between %h4.mb-0 diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index 316b097f..72240287 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -1,17 +1,17 @@ - form_id = 'activity_pub_action_on_several' -= render 'components/select_all_container', path: site_activity_pubs_action_on_several_path, form_id: form_id += render 'components/select_all_container', path: site_activity_pubs_action_on_several_path, form: form_id .row.no-gutters.pt-2{ data: { controller: 'select-all' } } .col-1.d-flex.align-items-center - = render 'components/select_all', id: 'select-all-comments', form_id: form_id + = render 'components/select_all', id: 'select-all-comments', form: form_id .col-11 -# Filtros - = render 'components/comments_filters', activity_pubs: moderation_queue, form_id: form_id + = render 'components/comments_filters', activity_pubs: moderation_queue, form: form_id .col-12 - if moderation_queue.count.zero? %h4= t('moderation_queue.nothing') - moderation_queue.each do |activity_pub| -# cache [activity_pub, activity_pub.object, activity_pub.actor] do %hr - = render 'moderation_queue/comment', comment: activity_pub.object.content, profile: activity_pub.actor.content, activity_pub: activity_pub, form_id: form_id + = render 'moderation_queue/comment', comment: activity_pub.object.content, profile: activity_pub.actor.content, activity_pub: activity_pub, form: form_id diff --git a/app/views/moderation_queue/_instance.haml b/app/views/moderation_queue/_instance.haml index 05510724..7cf3b085 100644 --- a/app/views/moderation_queue/_instance.haml +++ b/app/views/moderation_queue/_instance.haml @@ -3,7 +3,7 @@ .row.no-gutters.pt-2 .col-1 - = render 'components/checkbox', id: instance.hostname, form_id: form_id, name: 'instance_moderation[]', value: instance_moderation.id, data: { target: 'select-all.input' } + = render 'components/checkbox', id: instance.hostname, form: form, name: 'instance_moderation[]', value: instance_moderation.id, data: { target: 'select-all.input' } .col-11 %h4 %a{ href: instance.uri }= sanitize(instance.content['title']) || instance.hostname diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index 3954ce65..9a5349ba 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -1,13 +1,13 @@ - form_id = 'instance_moderation_action_on_several' %section - = render 'components/select_all_container', path: site_instance_moderations_action_on_several_path, form_id: form_id + = render 'components/select_all_container', path: site_instance_moderations_action_on_several_path, form: form_id .row.no-gutters.pt-2{ data: { controller: 'select-all' } } .col-1.d-flex.align-items-center - = render 'components/select_all', id: 'instances', form_id: form_id + = render 'components/select_all', id: 'instances', form: form_id .col-11 -# Filtros - = render 'components/instances_filters', instance_moderations: instance_moderations, form_id: form_id + = render 'components/instances_filters', instance_moderations: instance_moderations, form: form_id .col-12 - if instance_moderations.count.zero? @@ -16,7 +16,7 @@ - instance_moderations.each do |instance_moderation| - cache [instance_moderation.aasm_state, instance_moderation.instance] do %hr - = render 'moderation_queue/instance', instance_moderation: instance_moderation, instance: instance_moderation.instance, form_id: form_id + = render 'moderation_queue/instance', instance_moderation: instance_moderation, instance: instance_moderation.instance, form: form_id %hr %div From 4dff3180306ee4014e58aee69452b53bb0d9fc47 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 8 Mar 2024 14:10:21 -0300 Subject: [PATCH 308/472] feat: al desactivar un fediblock, ignorar otros fediblocks --- app/models/fediblock_state.rb | 76 ++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 27 deletions(-) diff --git a/app/models/fediblock_state.rb b/app/models/fediblock_state.rb index b5258fb6..e50abaef 100644 --- a/app/models/fediblock_state.rb +++ b/app/models/fediblock_state.rb @@ -27,12 +27,14 @@ class FediblockState < ApplicationRecord transitions from: :disabled, to: :enabled before do - enable_remotely! + # Bloquear todos las instancias de este Fediblock + enable_remotely! list_names(fediblock.hostnames) # Al actualizar el estado en masa garantizamos que las # instancias que ya existen queden sincronizadas con el bloqueo # en masa que acabamos de hacer. - instance_moderations.block_all! + instance_ids = fediblock.instances.ids + site.instance_moderations.where(instance_id: instance_ids).block_all! # Luego esta tarea crea las que falten e ignora las que ya se # bloquearon. @@ -41,11 +43,13 @@ class FediblockState < ApplicationRecord # 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 - # Al deshabilitar, las listas pasan a modo pausa. + # Al deshabilitar, las listas pasan a modo pausa, a menos que estén + # activas en otros listados. # # @todo No cambiar el estado si se habían habilitado manualmente, # pero esto implica que tenemos que encontrar las que sí y quitarlas @@ -54,12 +58,19 @@ class FediblockState < ApplicationRecord transitions from: :enabled, to: :disabled before do - disable_remotely! + # Deshabilitar todas las instancias que no estén habilitadas por + # otros fediblocks + disable_remotely! list_names(unique_hostnames) - instance_moderations.pause_all! + # Pausar todas las moderaciones de las instancias que no estén + # 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. + # 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 @@ -67,37 +78,48 @@ class FediblockState < ApplicationRecord private - def actor_ids - ActivityPub::Actor.where(instance_id: instance_ids).pluck(:id) - end - - def instance_ids - fediblock.instances.pluck(:id) - end - - # Todas las instancias de moderación de este sitio - def instance_moderations - site.instance_moderations.where(instance_id: instance_ids) - end - + # Devuelve los hostnames únicos a esta instancia. + # # @return [Array] - def list_names - @list_names ||= fediblock.hostnames.map do |hostname| + def unique_hostnames + @unique_hostnames ||= + begin + other_enabled_fediblock_ids = + site.fediblock_states.enabled.where.not(id: id).pluck(:fediblock_id) + other_enabled_hostnames = + ActivityPub::Fediblock + .where(id: other_enabled_fediblock_ids) + .pluck(:hostnames) + .flatten + .uniq + + fediblock.hostnames - other_enabled_hostnames + end + end + + # @param hostnames [Array] + # @return [Array] + def list_names(hostnames) + hostnames.map do |hostname| "@*@#{hostname}" end end # Al deshabilitar, las instancias pasan a ser analizadas caso por caso - def disable_remotely! + # + # @param list [Array] + def disable_remotely!(list) raise unless - site.social_inbox.blocklist.delete(list: list_names).ok? && - site.social_inbox.allowlist.delete(list: list_names).ok? + 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 - def enable_remotely! + # + # @param list [Array] + def enable_remotely!(list) raise unless - site.social_inbox.blocklist.post(list: list_names).ok? && - site.social_inbox.allowlist.delete(list: list_names).ok? + site.social_inbox.blocklist.post(list: list).ok? && + site.social_inbox.allowlist.delete(list: list).ok? end end From 995c80fed1d3eb837122e1656a41261c544aaae3 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 8 Mar 2024 14:42:27 -0300 Subject: [PATCH 309/472] fix: no colgar toda la cola si algo falla en la api --- app/controllers/fediblock_states_controller.rb | 13 ++++++++++++- app/jobs/activity_pub/instance_moderation_job.rb | 7 +++++++ config/locales/en.yml | 6 ++++++ config/locales/es.yml | 7 +++++++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/app/controllers/fediblock_states_controller.rb b/app/controllers/fediblock_states_controller.rb index 6d9737c3..4d9cc968 100644 --- a/app/controllers/fediblock_states_controller.rb +++ b/app/controllers/fediblock_states_controller.rb @@ -11,11 +11,22 @@ class FediblockStatesController < ApplicationController elsif fediblock_state.may_disable? fediblock_state.disable! end + + flash[:success] = I18n.t('fediblock_states.action_on_several.success') + rescue Exception => e + ExceptionNotifier.notify_exception(e, data: { site: site.name }) + + flash.delete(:success) + flash[:error] = I18n.t('fediblock_states.action_on_several.error') end # Bloquear otras instancias if custom_blocklist.present? - ActivityPub::InstanceModerationJob.perform_later(site: site, hostnames: custom_blocklist) + if ActivityPub::InstanceModerationJob.perform_now(site: site, hostnames: custom_blocklist) + flash[:success] = I18n.t('fediblock_states.action_on_several.custom_blocklist_success') + else + flash[:error] = I18n.t('fediblock_states.action_on_several.custom_blocklist_error') + end end redirect_to site_moderation_queue_path diff --git a/app/jobs/activity_pub/instance_moderation_job.rb b/app/jobs/activity_pub/instance_moderation_job.rb index b205e68f..17def46e 100644 --- a/app/jobs/activity_pub/instance_moderation_job.rb +++ b/app/jobs/activity_pub/instance_moderation_job.rb @@ -14,6 +14,7 @@ class ActivityPub end instances = ActivityPub::Instance.where(hostname: hostnames) + success = true Site.transaction do # Crea todas las moderaciones de instancia con un estado por @@ -23,9 +24,15 @@ class ActivityPub # 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 end + + success end end end diff --git a/config/locales/en.yml b/config/locales/en.yml index 0f010c89..565f0218 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -117,6 +117,12 @@ en: text_report: Report remote_flags: report_message: "Hi! Someone using Sutty CMS reported this account on your instance. We don't have support for customized report messages yet, but we will soon. You can reach us at %{panel_actor_mention}." + 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." + error: "There was an error while enabling or disabling blocklists. We received a report and will be acting on it soon." + custom_blocklist_success: "Custom blocklist has been added, you can find the instances by filtering by Blocked. Any pending account from these instances has also been blocked. You can approve them individually on the Accounts section." + custom_blocklist_error: "There was an error while adding a custom blocklist. We received a report and will be acting on it soon." moderation_queue: everything: 'Select all' nothing: "There's nothing for this filter" diff --git a/config/locales/es.yml b/config/locales/es.yml index 0a2538a7..175ca661 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -116,6 +116,13 @@ es: text_report: Reportar remote_flags: report_message: "¡Hola! Une usuarie de Sutty CMS reportó esta cuenta en tu instancia. Todavía no tenemos soporte para mensajes personalizados. Podés contactarnos en %{panel_actor_mention}." + 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." + error: "Hubo un error al activar o desactivar listas de bloqueo, ya recibimos el reporte y lo estaremos verificando." + custom_blocklist_success: "Se agregaron las instancias personalizadas a la lista de bloqueo, podés encontrarlas filtrando por Bloqueadas. Todas las cuentas de estas instancias pendientes de moderación han sido bloqueadas. Podés aprobarlas individualmente en la sección Cuentas." + custom_blocklist_error: "Hubo un error al agregar instancias personalizadas a la lista de bloqueo, ya recibimos el reporte y lo estaremos verificando." + actor_moderations: moderation_queue: everything: 'Seleccionar todo' nothing: 'No hay nada para este filtro' From cb30a3d02c8b9f6e90faff000683951dd9e5c0ab Mon Sep 17 00:00:00 2001 From: f Date: Fri, 8 Mar 2024 15:07:32 -0300 Subject: [PATCH 310/472] fix: ser informatives --- app/controllers/actor_moderations_controller.rb | 16 +++++++++++++++- config/locales/en.yml | 16 ++++++++++++++++ config/locales/es.yml | 17 ++++++++++++++++- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/app/controllers/actor_moderations_controller.rb b/app/controllers/actor_moderations_controller.rb index 6b924677..7c2c3d82 100644 --- a/app/controllers/actor_moderations_controller.rb +++ b/app/controllers/actor_moderations_controller.rb @@ -14,6 +14,12 @@ class ActorModerationsController < ApplicationController actor_moderation.public_send(:"#{actor_event}!") if actor_moderation.public_send(:"may_#{actor_event}?") + flash[:success] = I18n.t("actor_moderations.#{actor_event}.success") + rescue Exception => e + ExceptionNotifier.notify_exception(e, data: { site: site.name, params: params.permit!.to_h }) + + flash[:error] = I18n.t("actor_moderations.#{actor_event}.error") + ensure redirect_to_moderation_queue! end end @@ -21,7 +27,8 @@ class ActorModerationsController < ApplicationController # Ver el perfil remoto def show @remote_profile = actor_moderation.actor.content - @moderation_queue = rubanok_process(site.activity_pubs.where(actor_id: actor_moderation.actor_id), with: ActivityPubProcessor) + @moderation_queue = rubanok_process(site.activity_pubs.where(actor_id: actor_moderation.actor_id), + with: ActivityPubProcessor) end def action_on_several @@ -44,6 +51,13 @@ class ActorModerationsController < ApplicationController 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') end end end diff --git a/config/locales/en.yml b/config/locales/en.yml index 565f0218..2ae8484b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -117,6 +117,22 @@ en: text_report: Report remote_flags: report_message: "Hi! Someone using Sutty CMS reported this account on your instance. We don't have support for customized report messages yet, but we will soon. You can reach us at %{panel_actor_mention}." + actor_moderations: + action_on_several: + success: "Several accounts have changed moderation state. You can find them using the filters on the Accounts section." + error: "There was an error while changing moderation state. We received a report and will be acting on it soon." + pause: + 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." + 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 anonymously 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." 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." diff --git a/config/locales/es.yml b/config/locales/es.yml index 175ca661..29815a61 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -116,13 +116,28 @@ es: text_report: Reportar remote_flags: report_message: "¡Hola! Une usuarie de Sutty CMS reportó esta cuenta en tu instancia. Todavía no tenemos soporte para mensajes personalizados. Podés contactarnos en %{panel_actor_mention}." + actor_moderations: + action_on_several: + success: "Se han modificado el estado de moderación de varias cuentas. Podés encontrarlas usando los filtros en la sección Cuentas." + error: "Hubo un error al modificar el estado de moderación de varias cuentas. Hemos recibido el reporte y lo estaremos verificando." + pause: + 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." + 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 anónimamente 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." 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." error: "Hubo un error al activar o desactivar listas de bloqueo, ya recibimos el reporte y lo estaremos verificando." custom_blocklist_success: "Se agregaron las instancias personalizadas a la lista de bloqueo, podés encontrarlas filtrando por Bloqueadas. Todas las cuentas de estas instancias pendientes de moderación han sido bloqueadas. Podés aprobarlas individualmente en la sección Cuentas." custom_blocklist_error: "Hubo un error al agregar instancias personalizadas a la lista de bloqueo, ya recibimos el reporte y lo estaremos verificando." - actor_moderations: moderation_queue: everything: 'Seleccionar todo' nothing: 'No hay nada para este filtro' From 8faa6d8ea8c7128f4b77987be117ddfde51d5d7e Mon Sep 17 00:00:00 2001 From: f Date: Fri, 8 Mar 2024 15:18:19 -0300 Subject: [PATCH 311/472] =?UTF-8?q?feat:=20ser=20m=C3=A1s=20informative=20?= =?UTF-8?q?con=20los=20comentarios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/activity_pubs_controller.rb | 15 +++++++++++++++ config/locales/en.yml | 13 +++++++++++++ config/locales/es.yml | 13 +++++++++++++ 3 files changed, 41 insertions(+) diff --git a/app/controllers/activity_pubs_controller.rb b/app/controllers/activity_pubs_controller.rb index c8f86ef0..1efe2b89 100644 --- a/app/controllers/activity_pubs_controller.rb +++ b/app/controllers/activity_pubs_controller.rb @@ -11,6 +11,12 @@ class ActivityPubsController < ApplicationController activity_pub.update(remote_flag_params(activity_pub)) if event == :report activity_pub.public_send(:"#{event}!") if activity_pub.public_send(:"may_#{event}?") + flash[:success] = I18n.t("activity_pubs.#{event}.success") + rescue Exception => e + ExceptionNotifier.notify_exception(e, data: { site: site.name, params: params.permit!.to_h }) + + flash[:error] = I18n.t("activity_pubs.#{event}.error") + ensure redirect_to_moderation_queue! end end @@ -49,6 +55,15 @@ class ActivityPubsController < ApplicationController next unless activity_pub.public_send(may) 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 end end diff --git a/config/locales/en.yml b/config/locales/en.yml index 2ae8484b..23df9e3c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -117,6 +117,19 @@ en: text_report: Report remote_flags: report_message: "Hi! Someone using Sutty CMS reported this account on your instance. We don't have support for customized report messages yet, but we will soon. You can reach us at %{panel_actor_mention}." + activity_pubs: + action_on_several: + success: "Several comments have changed moderation state. You can find them using the filters on the Comments section." + error: "There was an error while changing moderation state. We received a report and will be acting on it soon." + approve: + success: "Comment approved." + error: "There was an error while approving the comment. We received a report and will be acting on it soon." + reject: + success: "Comment rejected. You can report it using the Report button." + error: "There was an error while rejecting the comment. We received a report and will be acting on it soon." + report: + success: "Comment reported." + error: "There was an error while reporting the comment. We received a report and will be acting on it soon." actor_moderations: action_on_several: success: "Several accounts have changed moderation state. You can find them using the filters on the Accounts section." diff --git a/config/locales/es.yml b/config/locales/es.yml index 29815a61..1773a0c6 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -116,6 +116,19 @@ es: text_report: Reportar remote_flags: report_message: "¡Hola! Une usuarie de Sutty CMS reportó esta cuenta en tu instancia. Todavía no tenemos soporte para mensajes personalizados. Podés contactarnos en %{panel_actor_mention}." + activity_pubs: + action_on_several: + success: "Se ha modificado el estado de moderación de varios comentarios. Podés encontrarlos usando los filtros en la sección Comentarios." + error: "Hubo un error al modificar el estado de moderación de varios comentarios. Hemos recibido el reporte y lo estaremos verificando." + approve: + success: "Comentario aprobado." + error: "No se puedo aprobar el comentario. Hemos recibido el reporte y lo estaremos verificando." + reject: + success: "Comentario rechazado. Podés reportarlo usando el botón Reportar." + error: "No se puedo rechazar el comentario. Hemos recibido el reporte y lo estaremos verificando." + report: + success: "Comentario reportado." + error: "No se puedo reportar el comentario. Hemos recibido el reporte y lo estaremos verificando." actor_moderations: action_on_several: success: "Se han modificado el estado de moderación de varias cuentas. Podés encontrarlas usando los filtros en la sección Cuentas." From 42be495465a0fddd2c97db8e5df263f979a48957 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 8 Mar 2024 15:19:21 -0300 Subject: [PATCH 312/472] =?UTF-8?q?fix:=20no=20prometer=20que=20el=20repor?= =?UTF-8?q?te=20es=20an=C3=B3nimo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit le admin de la instancia remota siempre puede d0xear --- config/locales/en.yml | 2 +- config/locales/es.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 23df9e3c..73920b57 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -141,7 +141,7 @@ en: success: "Account allowed. All of their comments will be approved automatically." 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 anonymously to their instance, please use the Report button." + 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." error: "There was an error while blocking the account. We received a report and will be acting on it soon." report: success: "Account reported." diff --git a/config/locales/es.yml b/config/locales/es.yml index 1773a0c6..467f15e8 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -131,7 +131,7 @@ es: error: "No se puedo reportar el comentario. Hemos recibido el reporte y lo estaremos verificando." actor_moderations: action_on_several: - success: "Se han modificado el estado de moderación de varias cuentas. Podés encontrarlas usando los filtros en la sección Cuentas." + success: "Se ha modificado el estado de moderación de varias cuentas. Podés encontrarlas usando los filtros en la sección Cuentas." error: "Hubo un error al modificar el estado de moderación de varias cuentas. Hemos recibido el reporte y lo estaremos verificando." pause: success: "Cuenta pausada. Todos los comentarios que haga necesitan ser aprobados manualmente en la sección Comentarios." @@ -140,7 +140,7 @@ es: success: "Cuenta permitida. Todos los comentarios que haga serán aprobados inmediatamente." 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 anónimamente a su instancia, podés usar el botón Reportar." + 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." error: "No se pudo bloquear la cuenta. Hemos recibido el reporte y lo estaremos verificando." report: success: "Cuenta reportada a su instancia." From 6b74bc454da0a307c32c145af683297d2bc202eb Mon Sep 17 00:00:00 2001 From: f Date: Fri, 8 Mar 2024 15:20:08 -0300 Subject: [PATCH 313/472] fix: sin dummy data en posts --- app/controllers/posts_controller.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 99dc6f7d..057c3068 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -38,7 +38,6 @@ class PostsController < ApplicationController @usuarie = site.usuarie? current_usuarie @site_stat = SiteStat.new(site) - dummy_data end def show @@ -82,7 +81,6 @@ class PostsController < ApplicationController authorize post breadcrumb post.title.value, site_post_path(site, post, locale: locale), match: :exact breadcrumb 'posts.edit', '' - dummy_data end def update From 071102fa3b82247fd7601f4548c3947106b6fd63 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 8 Mar 2024 15:31:41 -0300 Subject: [PATCH 314/472] =?UTF-8?q?feat:=20al=20moderar=20una=20cuenta,=20?= =?UTF-8?q?tambi=C3=A9n=20moderar=20sus=20comentarios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/actor_moderation.rb | 16 ++++++++++++++++ config/locales/en.yml | 4 ++-- config/locales/es.yml | 4 ++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index 01613f72..4b220a58 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -42,19 +42,35 @@ 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).find_each do |activity_pub| + activity_pub.allow! if activity_pub.may_allow? + rescue Exception => e + ExceptionNotifier.notify_exception(e, data: { site: site.name, activity_pub: activity_pub_id }) + end 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).find_each do |activity_pub| + activity_pub.reject! if activity_pub.may_reject? + rescue Exception => e + ExceptionNotifier.notify_exception(e, data: { site: site.name, activity_pub: activity_pub_id }) + end end end diff --git a/config/locales/en.yml b/config/locales/en.yml index 73920b57..48d9ca61 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -138,10 +138,10 @@ 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." diff --git a/config/locales/es.yml b/config/locales/es.yml index 467f15e8..3df608f5 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -137,10 +137,10 @@ 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." From 522cef8c9ae99ce5cc3c2d0ae911e5611064a7d3 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 8 Mar 2024 15:55:01 -0300 Subject: [PATCH 315/472] feat: acciones en masa para actividades --- app/models/activity_pub.rb | 34 ++++++++++++++++++++-- app/models/actor_moderation.rb | 12 ++------ app/models/concerns/aasm_events_concern.rb | 8 +++++ 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 33cd4d45..fce340db 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -38,6 +38,28 @@ class ActivityPub < ApplicationRecord end end + # Permite todos los comentarios. No podemos hacer acciones en masa + # sobre comentarios en la Social Inbox, con lo que tenemos que + # comunicarnos individualmente. + def self.allow_all! + self.find_each do |activity_pub| + activity_pub.allow! if activity_pub.may_allow? + rescue Exception => e + notify_exception!(e, activity_pub) + end + end + + # Rechaza todos los comentarios. No podemos hacer acciones en masa + # sobre comentarios en la Social Inbox, con lo que tenemos que + # comunicarnos individualmente. + def self.reject_all! + self.find_each do |activity_pub| + activity_pub.reject! if activity_pub.may_reject? + rescue Exception => e + notify_exception!(e, activity_pub) + end + end + aasm do # Todavía no hay una decisión sobre el objeto state :paused, initial: true @@ -68,7 +90,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 +99,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 +112,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 diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index 4b220a58..a510f1eb 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -50,11 +50,7 @@ class ActorModeration < ApplicationRecord before do allow_remotely! - site.activity_pubs.paused.where(actor_id: self.actor_id).find_each do |activity_pub| - activity_pub.allow! if activity_pub.may_allow? - rescue Exception => e - ExceptionNotifier.notify_exception(e, data: { site: site.name, activity_pub: activity_pub_id }) - end + site.activity_pubs.paused.where(actor_id: self.actor_id).allow_all! end end @@ -66,11 +62,7 @@ class ActorModeration < ApplicationRecord before do block_remotely! - site.activity_pubs.paused.where(actor_id: self.actor_id).find_each do |activity_pub| - activity_pub.reject! if activity_pub.may_reject? - rescue Exception => e - ExceptionNotifier.notify_exception(e, data: { site: site.name, activity_pub: activity_pub_id }) - end + site.activity_pubs.paused.where(actor_id: self.actor_id).reject_all! end end diff --git a/app/models/concerns/aasm_events_concern.rb b/app/models/concerns/aasm_events_concern.rb index 418368d8..b189dbe4 100644 --- a/app/models/concerns/aasm_events_concern.rb +++ b/app/models/concerns/aasm_events_concern.rb @@ -27,5 +27,13 @@ module AasmEventsConcern def self.states aasm.states.map(&:name) - self::IGNORED_STATES 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 From bf75d50cc35d578c410a117c42b32952a1fbab69 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 12 Mar 2024 13:57:31 -0300 Subject: [PATCH 316/472] =?UTF-8?q?feat:=20modificar=20el=20estado=20de=20?= =?UTF-8?q?moderaci=C3=B3n=20en=20masa=20#15328=20#15327?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/activity_pubs_controller.rb | 45 +++++++------------ .../actor_moderations_controller.rb | 23 +++++----- .../instance_moderations_controller.rb | 15 ++++--- .../activity_pub/instance_moderation_job.rb | 13 ++---- app/models/activity_pub.rb | 22 --------- app/models/actor_moderation.rb | 13 ------ app/models/concerns/aasm_events_concern.rb | 20 +++++++++ app/models/fediblock_state.rb | 12 ----- app/models/instance_moderation.rb | 30 ++++++------- config/locales/es.yml | 13 ++++++ 10 files changed, 88 insertions(+), 118 deletions(-) diff --git a/app/controllers/activity_pubs_controller.rb b/app/controllers/activity_pubs_controller.rb index 1efe2b89..edece8f8 100644 --- a/app/controllers/activity_pubs_controller.rb +++ b/app/controllers/activity_pubs_controller.rb @@ -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,36 +35,25 @@ class ActivityPubsController < ApplicationController return unless ActivityPub.events.include? action # Crear una sola remote flag por autore - if action == :report - message = remote_flag_params(activity_pubs.first).dig(:remote_flag_attributes, :message) - - activity_pubs.distinct.pluck(:actor_id).each do |actor_id| - remote_flag = ActivityPub::RemoteFlag.find_or_initialize_by(actor_id: actor_id, site_id: site.id) - remote_flag.message = message - # Lo estamos actualizando, con lo que lo vamos a volver a enviar - remote_flag.requeue if remote_flag.persisted? - remote_flag.save - # XXX: Idealmente todas las ActivityPub que enviamos pueden - # cambiar de estado, pero chequeamos de todas formas. - remote_flag.activity_pubs << (activity_pubs.where(actor_id: actor_id).to_a.select { |a| a.public_send(may) }) - end - end - ActivityPub.transaction do - activity_pubs.find_each do |activity_pub| - next unless activity_pub.public_send(may) + if action == :report + message = remote_flag_params(activity_pubs.first).dig(:remote_flag_attributes, :message) - 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') + activity_pubs.distinct.pluck(:actor_id).each do |actor_id| + remote_flag = ActivityPub::RemoteFlag.find_or_initialize_by(actor_id: actor_id, site_id: site.id) + remote_flag.message = message + # Lo estamos actualizando, con lo que lo vamos a volver a enviar + remote_flag.requeue if remote_flag.persisted? + remote_flag.save + # XXX: Idealmente todas las ActivityPub que enviamos pueden + # cambiar de estado, pero chequeamos de todas formas. + remote_flag.activity_pubs << (activity_pubs.where(actor_id: actor_id).to_a.select { |a| a.public_send(may) }) + end end + + message = activity_pubs.public_send(method) ? :success : :error + + flash[message] = I18n.t("activity_pubs.action_on_several.#{message}") end end diff --git a/app/controllers/actor_moderations_controller.rb b/app/controllers/actor_moderations_controller.rb index 7c2c3d82..bc4a059b 100644 --- a/app/controllers/actor_moderations_controller.rb +++ b/app/controllers/actor_moderations_controller.rb @@ -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,20 +45,17 @@ class ActorModerationsController < ApplicationController return unless ActorModeration.events.include? action ActorModeration.transaction do - actor_moderations.find_each do |actor_moderation| - next unless actor_moderation.public_send(may) + 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 diff --git a/app/controllers/instance_moderations_controller.rb b/app/controllers/instance_moderations_controller.rb index 270f0588..06f5cfc1 100644 --- a/app/controllers/instance_moderations_controller.rb +++ b/app/controllers/instance_moderations_controller.rb @@ -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 diff --git a/app/jobs/activity_pub/instance_moderation_job.rb b/app/jobs/activity_pub/instance_moderation_job.rb index 17def46e..e28be84e 100644 --- a/app/jobs/activity_pub/instance_moderation_job.rb +++ b/app/jobs/activity_pub/instance_moderation_job.rb @@ -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 + site.instance_moderations.find_or_create_by(instance: instance) end - end - success + site.instance_moderations.where(instance_id: instances.ids).block_all! + end end end end diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index fce340db..38bf3b3a 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -38,28 +38,6 @@ class ActivityPub < ApplicationRecord end end - # Permite todos los comentarios. No podemos hacer acciones en masa - # sobre comentarios en la Social Inbox, con lo que tenemos que - # comunicarnos individualmente. - def self.allow_all! - self.find_each do |activity_pub| - activity_pub.allow! if activity_pub.may_allow? - rescue Exception => e - notify_exception!(e, activity_pub) - end - end - - # Rechaza todos los comentarios. No podemos hacer acciones en masa - # sobre comentarios en la Social Inbox, con lo que tenemos que - # comunicarnos individualmente. - def self.reject_all! - self.find_each do |activity_pub| - activity_pub.reject! if activity_pub.may_reject? - rescue Exception => e - notify_exception!(e, activity_pub) - end - end - aasm do # Todavía no hay una decisión sobre el objeto state :paused, initial: true diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index a510f1eb..7cb8827d 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -14,19 +14,6 @@ class ActorModeration < ApplicationRecord 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 diff --git a/app/models/concerns/aasm_events_concern.rb b/app/models/concerns/aasm_events_concern.rb index b189dbe4..967a61b3 100644 --- a/app/models/concerns/aasm_events_concern.rb +++ b/app/models/concerns/aasm_events_concern.rb @@ -28,6 +28,26 @@ module AasmEventsConcern 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] diff --git a/app/models/fediblock_state.rb b/app/models/fediblock_state.rb index e50abaef..dfdc4e34 100644 --- a/app/models/fediblock_state.rb +++ b/app/models/fediblock_state.rb @@ -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 diff --git a/app/models/instance_moderation.rb b/app/models/instance_moderation.rb index ef04b7ff..918c6ad0 100644 --- a/app/models/instance_moderation.rb +++ b/app/models/instance_moderation.rb @@ -11,26 +11,13 @@ class InstanceModeration < ApplicationRecord 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] + def actor_ids + ActivityPub::Actor.where(instance_id: self.instance_id).ids + end + # Elimina la instancia de todas las listas # # @return [Boolean] diff --git a/config/locales/es.yml b/config/locales/es.yml index 3df608f5..3cc6c49a 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -145,6 +145,19 @@ es: 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." From d2d327dc848b6b5e4abd318d71575effe125c89e Mon Sep 17 00:00:00 2001 From: f Date: Tue, 12 Mar 2024 14:24:38 -0300 Subject: [PATCH 317/472] =?UTF-8?q?fixup!=20feat:=20modificar=20el=20estad?= =?UTF-8?q?o=20de=20moderaci=C3=B3n=20en=20masa=20#15328=20#15327?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/activity_pub.rb | 6 +++--- app/models/actor_moderation.rb | 6 +++--- app/models/instance_moderation.rb | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 38bf3b3a..61120a58 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -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 diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index 7cb8827d..04c96ac0 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -2,12 +2,12 @@ # 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' diff --git a/app/models/instance_moderation.rb b/app/models/instance_moderation.rb index 918c6ad0..1ed7d2c0 100644 --- a/app/models/instance_moderation.rb +++ b/app/models/instance_moderation.rb @@ -2,12 +2,12 @@ # 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' From e783390747f2ab054f4765b353ca575ea3d7b802 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 12 Mar 2024 14:28:26 -0300 Subject: [PATCH 318/472] =?UTF-8?q?fixup!=20fixup!=20feat:=20modificar=20e?= =?UTF-8?q?l=20estado=20de=20moderaci=C3=B3n=20en=20masa=20#15328=20#15327?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/locales/en.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/config/locales/en.yml b/config/locales/en.yml index 48d9ca61..bc6b1285 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -146,6 +146,19 @@ en: 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." From 20c6d6af5042360736d8ebd212da2b99e118ec41 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 12 Mar 2024 14:30:43 -0300 Subject: [PATCH 319/472] feat: eliminar todos los comentarios de une actore eliminade --- app/models/actor_moderation.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index 04c96ac0..783160c7 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -67,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 From 12f77e46581cc539fc6655f8f282c2d72147e71e Mon Sep 17 00:00:00 2001 From: f Date: Tue, 12 Mar 2024 15:57:04 -0300 Subject: [PATCH 320/472] fix: actualizar cliente --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 366b58a5..7b19ba75 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -166,7 +166,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 @@ -626,7 +626,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 From 3c07ddf12c946303fddb5403b166faa6905b4ea1 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 12 Mar 2024 15:59:42 -0300 Subject: [PATCH 321/472] =?UTF-8?q?fixup!=20fixup!=20fixup!=20feat:=20modi?= =?UTF-8?q?ficar=20el=20estado=20de=20moderaci=C3=B3n=20en=20masa=20#15328?= =?UTF-8?q?=20#15327?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/activity_pub/remote_flag.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/models/activity_pub/remote_flag.rb b/app/models/activity_pub/remote_flag.rb index 76143414..1b6f5c5f 100644 --- a/app/models/activity_pub/remote_flag.rb +++ b/app/models/activity_pub/remote_flag.rb @@ -2,6 +2,9 @@ class ActivityPub class RemoteFlag < ApplicationRecord + IGNORED_EVENTS = [] + IGNORED_STATES = [] + include AASM include AasmEventsConcern From 4fde9793d733426a50ccf86104841cbdfe3140f8 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 12 Mar 2024 17:09:21 -0300 Subject: [PATCH 322/472] fix: permitir que la tarea se reporte como hecha --- app/models/deploy_social_distributed_press.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app/models/deploy_social_distributed_press.rb b/app/models/deploy_social_distributed_press.rb index b7525dca..c7a103a4 100644 --- a/app/models/deploy_social_distributed_press.rb +++ b/app/models/deploy_social_distributed_press.rb @@ -13,12 +13,11 @@ class DeploySocialDistributedPress < Deploy key = Shellwords.escape file.path dest = Shellwords.escape destination - run %(bundle exec jekyll notify --trace --key #{key} --destination "#{dest}"), output: output + run(%(bundle exec jekyll notify --trace --key #{key} --destination "#{dest}"), output: output).tap do |_| + create_hooks! + enable_fediblocks! + end end - - - create_hooks! - enable_fediblocks! end # Igual que DeployLocal From d44bcc4098d0959d78c89ac564ee78ec2d01248b Mon Sep 17 00:00:00 2001 From: f Date: Tue, 12 Mar 2024 17:30:47 -0300 Subject: [PATCH 323/472] fix: typo --- app/jobs/activity_pub/remote_flag_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/activity_pub/remote_flag_job.rb b/app/jobs/activity_pub/remote_flag_job.rb index 26db937a..f5650d53 100644 --- a/app/jobs/activity_pub/remote_flag_job.rb +++ b/app/jobs/activity_pub/remote_flag_job.rb @@ -13,7 +13,7 @@ class ActivityPub self.priority = 30 def perform(remote_flag:) - return if remote_flag.can_queue? + return if remote_flag.may_queue? remote_flag.queue! From 45d56502c11bb9c65f5538e08173052699f845ce Mon Sep 17 00:00:00 2001 From: f Date: Tue, 12 Mar 2024 17:44:40 -0300 Subject: [PATCH 324/472] fix: aprobar --- app/models/actor_moderation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index 783160c7..ad29739f 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -37,7 +37,7 @@ class ActorModeration < ApplicationRecord before do allow_remotely! - site.activity_pubs.paused.where(actor_id: self.actor_id).allow_all! + site.activity_pubs.paused.where(actor_id: self.actor_id).approve_all! end end From 32042f32e23d95bb8dcde1976eb4d7203d411753 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Mar 2024 11:05:28 -0300 Subject: [PATCH 325/472] =?UTF-8?q?fix:=20no=20ignorar=20ning=C3=BAn=20eve?= =?UTF-8?q?nto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #15366 closes #15367 closes #15368 closes #15369 closes #15370 closes #15371 closes #15372 closes #15373 closes #15374 closes #15375 closes #15376 closes #15377 closes #15378 closes #15379 closes #15380 closes #15381 closes #15382 closes #15383 closes #15384 closes #15385 closes #15386 closes #15387 closes #15388 closes #15389 closes #15390 closes #15391 closes #15392 closes #15393 closes #15394 closes #15395 closes #15396 closes #15397 closes #15398 closes #15399 closes #15400 closes #15401 closes #15402 closes #15403 closes #15404 closes #15405 closes #15406 closes #15407 closes #15408 closes #15409 closes #15410 closes #15411 closes #15412 closes #15413 closes #15414 closes #15415 closes #15416 closes #15417 closes #15418 closes #15419 closes #15420 closes #15421 closes #15422 closes #15423 closes #15424 closes #15425 closes #15426 closes #15427 closes #15428 closes #15429 closes #15430 closes #15431 closes #15432 closes #15433 closes #15434 closes #15435 closes #15436 closes #15437 closes #15438 closes #15439 closes #15440 closes #15441 closes #15442 closes #15443 closes #15444 closes #15445 closes #15446 closes #15447 closes #15448 closes #15449 closes #15450 closes #15451 closes #15452 closes #15453 closes #15454 closes #15455 closes #15456 closes #15457 closes #15458 closes #15459 closes #15460 closes #15461 closes #15462 closes #15463 closes #15464 closes #15465 closes #15466 closes #15467 closes #15468 closes #15469 closes #15470 closes #15471 closes #15472 closes #15473 closes #15477 closes #15478 closes #15479 closes #15480 closes #15481 closes #15482 closes #15483 closes #15484 closes #15485 closes #15486 closes #15487 closes #15488 closes #15489 closes #15490 closes #15491 closes #15492 closes #15493 closes #15494 closes #15495 closes #15496 closes #15497 closes #15498 closes #15499 closes #15500 closes #15501 closes #15502 closes #15503 closes #15504 closes #15505 closes #15506 closes #15507 closes #15508 closes #15509 closes #15510 closes #15511 closes #15512 closes #15513 closes #15514 closes #15515 closes #15516 closes #15517 closes #15518 closes #15519 closes #15520 closes #15521 closes #15522 closes #15523 closes #15524 closes #15525 closes #15526 closes #15527 closes #15528 closes #15529 closes #15530 closes #15531 closes #15532 closes #15533 closes #15534 closes #15535 closes #15536 closes #15537 closes #15538 closes #15539 closes #15540 closes #15541 closes #15542 closes #15543 closes #15544 closes #15545 closes #15546 closes #15547 closes #15548 closes #15549 --- app/models/concerns/aasm_events_concern.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/concerns/aasm_events_concern.rb b/app/models/concerns/aasm_events_concern.rb index 967a61b3..08b4edd7 100644 --- a/app/models/concerns/aasm_events_concern.rb +++ b/app/models/concerns/aasm_events_concern.rb @@ -32,7 +32,7 @@ module AasmEventsConcern # scope actual. # # @return [Bool] Si hubo al menos un error, devuelve false. - self.events.each do |event| + self.aasm.events.map(&:name).each do |event| define_singleton_method(:"#{event}_all!") do success = true From 40edccf8bbbe9c272245a11674d9a0209ec57955 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Mar 2024 11:15:31 -0300 Subject: [PATCH 326/472] =?UTF-8?q?fixup!=20fix:=20no=20ignorar=20ning?= =?UTF-8?q?=C3=BAn=20evento?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/activity_pub.rb | 4 +++- app/models/activity_pub/remote_flag.rb | 4 +++- app/models/actor_moderation.rb | 4 +++- app/models/instance_moderation.rb | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 61120a58..a6b1401b 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -12,7 +12,6 @@ class ActivityPub < ApplicationRecord IGNORED_STATES = %i[removed] include AASM - include AasmEventsConcern belongs_to :instance belongs_to :site @@ -91,6 +90,9 @@ class ActivityPub < ApplicationRecord end end + # Definir eventos en masa + include AasmEventsConcern + def reject_remotely! raise unless site.social_inbox.inbox.reject(id: object.uri).ok? end diff --git a/app/models/activity_pub/remote_flag.rb b/app/models/activity_pub/remote_flag.rb index 1b6f5c5f..70f09dcc 100644 --- a/app/models/activity_pub/remote_flag.rb +++ b/app/models/activity_pub/remote_flag.rb @@ -6,7 +6,6 @@ class ActivityPub IGNORED_STATES = [] include AASM - include AasmEventsConcern aasm do state :waiting, initial: true @@ -26,6 +25,9 @@ class ActivityPub end end + # Definir eventos en masa + include AasmEventsConcern + belongs_to :actor belongs_to :site diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index ad29739f..7e68f60b 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -6,7 +6,6 @@ class ActorModeration < ApplicationRecord IGNORED_STATES = %i[removed] include AASM - include AasmEventsConcern belongs_to :site belongs_to :remote_flag, optional: true, class_name: 'ActivityPub::RemoteFlag' @@ -74,6 +73,9 @@ class ActorModeration < ApplicationRecord end end + # Definir eventos en masa + include AasmEventsConcern + def pause_remotely! raise unless actor.mention && diff --git a/app/models/instance_moderation.rb b/app/models/instance_moderation.rb index 1ed7d2c0..5b246cee 100644 --- a/app/models/instance_moderation.rb +++ b/app/models/instance_moderation.rb @@ -6,7 +6,6 @@ class InstanceModeration < ApplicationRecord IGNORED_STATES = [] include AASM - include AasmEventsConcern belongs_to :site belongs_to :instance, class_name: 'ActivityPub::Instance' @@ -51,6 +50,9 @@ class InstanceModeration < ApplicationRecord end end + # Definir eventos en masa + include AasmEventsConcern + # @return [Array] def actor_ids ActivityPub::Actor.where(instance_id: self.instance_id).ids From ef482aaedf2d8696408a4d40e642df8730b70447 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Mar 2024 11:41:04 -0300 Subject: [PATCH 327/472] =?UTF-8?q?fix:=20el=20m=C3=A9todo=20es=20de=20cla?= =?UTF-8?q?se?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #15553 --- app/models/concerns/aasm_events_concern.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/concerns/aasm_events_concern.rb b/app/models/concerns/aasm_events_concern.rb index 08b4edd7..70fb5ed2 100644 --- a/app/models/concerns/aasm_events_concern.rb +++ b/app/models/concerns/aasm_events_concern.rb @@ -52,8 +52,8 @@ module AasmEventsConcern # # @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 }) + def self.notify_exception!(exception, record) + ExceptionNotifier.notify_exception(exception, data: { record_type: record.class.name, record_id: record.id }) end end end From f794e8057b3248dfafd1b259a0100a95db847c87 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Mar 2024 15:29:34 -0300 Subject: [PATCH 328/472] feat: no hacer acciones en cascada #15327 #15328 --- .../activity_pub/instance_moderation_job.rb | 13 ++++++++---- app/models/actor_moderation.rb | 8 ++------ app/models/concerns/aasm_events_concern.rb | 13 ++++++++++++ app/models/fediblock_state.rb | 16 +++++---------- app/models/instance_moderation.rb | 12 ++++------- config/locales/en.yml | 20 +++++++++---------- config/locales/es.yml | 20 +++++++++---------- 7 files changed, 53 insertions(+), 49 deletions(-) diff --git a/app/jobs/activity_pub/instance_moderation_job.rb b/app/jobs/activity_pub/instance_moderation_job.rb index e28be84e..214f8dd4 100644 --- a/app/jobs/activity_pub/instance_moderation_job.rb +++ b/app/jobs/activity_pub/instance_moderation_job.rb @@ -3,11 +3,10 @@ class ActivityPub # Bloquea varias instancias de una sola vez class InstanceModerationJob < ApplicationJob - self.priority = 50 - # @param :site [Site] # @param :hostnames [Array] - def perform(site:, hostnames:) + # @param :perform_remotely [Bool] + def perform(site:, hostnames:, perform_remotely: true) # Crear las instancias que no existan todavía hostnames.each do |hostname| ActivityPub::Instance.find_or_create_by(hostname: hostname) @@ -24,7 +23,13 @@ class ActivityPub site.instance_moderations.find_or_create_by(instance: instance) end - site.instance_moderations.where(instance_id: instances.ids).block_all! + scope = site.instance_moderations.where(instance_id: instances.ids) + + if perform_remotely + scope.block_all! + else + scope.block_all_without_callbacks! + end end end end diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index 7e68f60b..3b183a4f 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -28,27 +28,23 @@ class ActorModeration < ApplicationRecord end end - # Al permitir una cuenta se permiten todos los comentarios + # 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 before do allow_remotely! - - site.activity_pubs.paused.where(actor_id: self.actor_id).approve_all! end end - # Al bloquear una cuenta se bloquean todos los comentarios + # 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 before do block_remotely! - - site.activity_pubs.paused.where(actor_id: self.actor_id).reject_all! end end diff --git a/app/models/concerns/aasm_events_concern.rb b/app/models/concerns/aasm_events_concern.rb index 70fb5ed2..4de5f748 100644 --- a/app/models/concerns/aasm_events_concern.rb +++ b/app/models/concerns/aasm_events_concern.rb @@ -46,6 +46,19 @@ module AasmEventsConcern success end + + # Ejecuta la transición del evento en la base de datos sin + # ejecutar los callbacks, sin modificar los items del scope que no + # pueden transicionar. + # + # @return [Integer] Registros modificados + define_singleton_method(:"#{event}_all_without_callbacks!") do + aasm_event = self.aasm.events.find { |e| e.name == event } + to_state = aasm_event.transitions.map(&:to).first + from_states = aasm_event.transitions.map(&:from) + + self.unscope(where: :aasm_state).where(aasm_state: from_states).update_all(aasm_state: to_state, updated_at: Time.now) + end end # Envía notificación de errores diff --git a/app/models/fediblock_state.rb b/app/models/fediblock_state.rb index dfdc4e34..9dde1db3 100644 --- a/app/models/fediblock_state.rb +++ b/app/models/fediblock_state.rb @@ -30,15 +30,9 @@ class FediblockState < ApplicationRecord # Bloquear todos las instancias de este Fediblock enable_remotely! list_names(fediblock.hostnames) - # Al actualizar el estado en masa garantizamos que las - # instancias que ya existen queden sincronizadas con el bloqueo - # en masa que acabamos de hacer. - instance_ids = fediblock.instances.ids - site.instance_moderations.where(instance_id: instance_ids).block_all! - # Luego esta tarea crea las que falten e ignora las que ya se # bloquearon. - ActivityPub::InstanceModerationJob.perform_now(site: site, hostnames: fediblock.hostnames) + ActivityPub::InstanceModerationJob.perform_now(site: site, hostnames: fediblock.hostnames, perform_remotely: false) end end @@ -56,10 +50,10 @@ class FediblockState < ApplicationRecord # otros fediblocks disable_remotely! list_names(unique_hostnames) - # Pausar todas las moderaciones de las instancias que no estén - # bloqueadas por otros fediblocks. - instance_ids = ActivityPub::Instance.where(hostname: unique_hostnames).ids - site.instance_moderations.where(instance_id: instance_ids).pause_all! + # Pausar todas las moderaciones de las instancias que no estén + # bloqueadas por otros fediblocks. + instance_ids = ActivityPub::Instance.where(hostname: unique_hostnames).ids + site.instance_moderations.where(instance_id: instance_ids).pause_all_without_callbacks! end end end diff --git a/app/models/instance_moderation.rb b/app/models/instance_moderation.rb index 5b246cee..9cb6ffdc 100644 --- a/app/models/instance_moderation.rb +++ b/app/models/instance_moderation.rb @@ -25,27 +25,23 @@ class InstanceModeration < ApplicationRecord end end - # Al permitir, también permitimos todes les actores que no hayan - # tenido acciones de moderación. + # Al permitir, solo bloqueamos la instancia, sin modificar el estado + # de les actores y comentarios retroactivamente. 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. + # Al bloquear, solo bloqueamos la instancia, sin modificar el estado + # de les actores y comentarios retroactivamente. 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 diff --git a/config/locales/en.yml b/config/locales/en.yml index bc6b1285..d745e2d5 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -132,38 +132,38 @@ en: error: "There was an error while reporting the comment. We received a report and will be acting on it soon." actor_moderations: action_on_several: - success: "Several accounts have changed moderation state. You can find them using the filters on the Accounts section." + success: "Several accounts have changed moderation state. You can find them using the filters on the Accounts section. No action was performed over existing Comments." error: "There was an error while changing moderation state. We received a report and will be acting on it soon." pause: - success: "Account paused. All of their comments will need to be moderated individually on the Comments section." + success: "Account paused. No action was performed on existing Comments." 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. Any pending comments have been approved." + success: "Account allowed. All of their comments from now on will be approved automatically. No action was performed over existing Comments." 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. Any pending comments have been rejected. If you want to report it to their instance, please use the Report button." + success: "Account blocked. All of their comments from now on will be rejected automatically. No action was performed over existing Comments. 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." + success: "Several instances have changed moderation state. You can find them using the filters on the Instances section. No action was performed over existing Accounts and Comments." 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." + success: "Instance paused. All of their comments and accounts from now on will need to be moderated individually. No action was performed over existing Accounts and Comments." 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." + success: "Instance allowed. All of their comments and accounts from now on will be approved automatically. No action was performed over existing Accounts and Comments." 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." + success: "Instance blocked. All of their comments and accounts from now on will be rejected automatically. No action was performed over existing Accounts and Comments." 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." + success: "Blocklists have been enabled, you can find their instances by filtering by Blocked. You can approve them individually on the Accounts section. No action was performed over existing Accounts and Comments." error: "There was an error while enabling or disabling blocklists. We received a report and will be acting on it soon." - custom_blocklist_success: "Custom blocklist has been added, you can find the instances by filtering by Blocked. Any pending account from these instances has also been blocked. You can approve them individually on the Accounts section." + custom_blocklist_success: "Custom blocklist has been added, you can find the instances by filtering by Blocked. No action was performed over existing Accounts and Comments." custom_blocklist_error: "There was an error while adding a custom blocklist. We received a report and will be acting on it soon." moderation_queue: everything: 'Select all' diff --git a/config/locales/es.yml b/config/locales/es.yml index 3cc6c49a..a7b8d452 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -131,38 +131,38 @@ es: error: "No se puedo reportar el comentario. Hemos recibido el reporte y lo estaremos verificando." actor_moderations: action_on_several: - success: "Se ha modificado el estado de moderación de varias cuentas. Podés encontrarlas usando los filtros en la sección Cuentas." + success: "Se ha modificado el estado de moderación de varias cuentas. Podés encontrarlas usando los filtros en la sección Cuentas. No se modificaron comentarios pre-existentes." error: "Hubo un error al modificar el estado de moderación de varias cuentas. Hemos recibido el reporte y lo estaremos verificando." pause: - success: "Cuenta pausada. Todos los comentarios que haga necesitan ser aprobados manualmente en la sección Comentarios." + success: "Cuenta pausada. Todos los comentarios que haga necesitan ser aprobados manualmente en la sección Comentarios. No se modificaron comentarios pre-existentes." 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. Todos los comentarios pendientes de moderación fueron aprobados." + success: "Cuenta permitida. Todos los comentarios que haga serán aprobados inmediatamente. No se modificaron comentarios pre-existentes." 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. Todos los comentarios pendientes de moderación fueron rechazados. 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. Si querés reportarla a su instancia, podés usar el botón Reportar. No se modificaron comentarios pre-existentes." 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." + success: "Se ha modificado el estado de moderación de varias instancias. Podés encontrarlas usando los filtros en la sección Instancias. No se modificaron cuentas y comentarios pre-existentes." 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." + success: "Instancia pausada. A partir de ahora, todos los comentarios y cuentas de esta instancia necesitan ser aprobados manualmente. No se ha modificado el estado de moderación de cuentas ni 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." + success: "Instancia permitida. A partir de ahora, todos los comentarios y cuentas pendientes serán aprobados inmediatamente. No se modificaron cuentas ni comentarios pre-existentes." 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." + success: "Instancia bloqueada. A partir de ahora, todos los comentarios y cuentas serán rechazados inmediatamente. No se modificaron cuentas ni comentarios pre-existentes." 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." + success: "Se habilitaron las listas de bloqueo, podés encontrar las instancias filtrando por Bloqueadas. Podés activarlas individualmente en la sección Cuentas. No se modificaron cuentas ni comentarios pre-existentes." error: "Hubo un error al activar o desactivar listas de bloqueo, ya recibimos el reporte y lo estaremos verificando." - custom_blocklist_success: "Se agregaron las instancias personalizadas a la lista de bloqueo, podés encontrarlas filtrando por Bloqueadas. Todas las cuentas de estas instancias pendientes de moderación han sido bloqueadas. Podés aprobarlas individualmente en la sección Cuentas." + custom_blocklist_success: "Se agregaron las instancias personalizadas a la lista de bloqueo, podés encontrarlas filtrando por Bloqueadas. Podés aprobarlas individualmente en la sección Cuentas. No se modificaron cuentas ni comentarios pre-existentes." custom_blocklist_error: "Hubo un error al agregar instancias personalizadas a la lista de bloqueo, ya recibimos el reporte y lo estaremos verificando." moderation_queue: everything: 'Seleccionar todo' From 882ab1679c0467929e5cfc18bbf75402143b4752 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Mar 2024 15:52:33 -0300 Subject: [PATCH 329/472] fix: a veces el objeto no existe (?) closes #15554 --- app/models/activity_pub.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index a6b1401b..53bb3de0 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -56,6 +56,8 @@ class ActivityPub < ApplicationRecord transitions to: :removed before do + next if object.blank? + object.update(content: {}) unless object.content.empty? end end From 56c583e0f43efab5d4ea37a725fb8cb2801c30b8 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Mar 2024 16:11:40 -0300 Subject: [PATCH 330/472] fix: serializar correctamente closes #15363 --- app/controllers/api/v1/webhooks/social_inbox_controller.rb | 5 +++-- app/jobs/activity_pub/fetch_job.rb | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index c40857e0..bdf359d2 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -125,8 +125,9 @@ module Api o.save! # XXX: el objeto necesita ser guardado antes de poder - # procesarlo - ::ActivityPub::FetchJob.perform_later(site: site, object: o) unless object_embedded? + # procesarlo. No usamos GlobalID porque el tipo de objeto + # cambia y produce un error de deserialización. + ::ActivityPub::FetchJob.perform_later(site: site, object_id: o.id) unless object_embedded? end end diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index e3fef993..6a4d163b 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -11,8 +11,11 @@ class ActivityPub class FetchJob < ApplicationJob self.priority = 50 - def perform(site:, object:) + def perform(site:, object_id:) ActivityPub::Object.transaction do + object = ::ActivityPub::Object.find(object_id) + + return if object.blank? return if object.activity_pubs.where(aasm_state: 'removed').count.positive? response = site.social_inbox.dereferencer.get(uri: object.uri) From ad9f9c3d618eb7cba2834e350a03dd7c7804bd0c Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Mar 2024 16:27:33 -0300 Subject: [PATCH 331/472] fixup! fix: serializar correctamente --- app/models/que_job.rb | 5 +++++ db/migrate/20240313192134_fix_fetch_jobs.rb | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 app/models/que_job.rb create mode 100644 db/migrate/20240313192134_fix_fetch_jobs.rb diff --git a/app/models/que_job.rb b/app/models/que_job.rb new file mode 100644 index 00000000..0bfffc92 --- /dev/null +++ b/app/models/que_job.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +require 'que/active_record/model' + +class QueJob < Que::ActiveRecord::Model; end diff --git a/db/migrate/20240313192134_fix_fetch_jobs.rb b/db/migrate/20240313192134_fix_fetch_jobs.rb new file mode 100644 index 00000000..3b9d4ad8 --- /dev/null +++ b/db/migrate/20240313192134_fix_fetch_jobs.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +class FixFetchJobs < ActiveRecord::Migration[6.1] + def up + QueJob.where("last_error_message like '%ActiveJob::DeserializationError%'").find_each do |job| + job.error_count = 0 + job.run_at = time.now + + job.args.first['arguments'].first['_aj_ruby2_keywords'].delete('object') + job.args.first['arguments'].first['_aj_ruby2_keywords'] << 'object_id' + + object = job.args.first['arguments'].first.delete('object')['_aj_globalid'] + job.args.first['arguments'].first['object_id'] = object.split('/').last + + job.save + end + end + + def down; end +end From 630f6b31fc93021d5e3ee93447f3b980f3dd1510 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Mar 2024 16:28:59 -0300 Subject: [PATCH 332/472] fixup! fixup! fix: serializar correctamente --- db/migrate/20240313192134_fix_fetch_jobs.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20240313192134_fix_fetch_jobs.rb b/db/migrate/20240313192134_fix_fetch_jobs.rb index 3b9d4ad8..54ffa7e6 100644 --- a/db/migrate/20240313192134_fix_fetch_jobs.rb +++ b/db/migrate/20240313192134_fix_fetch_jobs.rb @@ -4,7 +4,7 @@ class FixFetchJobs < ActiveRecord::Migration[6.1] def up QueJob.where("last_error_message like '%ActiveJob::DeserializationError%'").find_each do |job| job.error_count = 0 - job.run_at = time.now + job.run_at = Time.now job.args.first['arguments'].first['_aj_ruby2_keywords'].delete('object') job.args.first['arguments'].first['_aj_ruby2_keywords'] << 'object_id' From 4dd75eedad7b8023a05bfb848697f71a8e575831 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Mar 2024 16:39:58 -0300 Subject: [PATCH 333/472] =?UTF-8?q?fix:=20prevenir=20doble=20renderizaci?= =?UTF-8?q?=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #15564 --- app/controllers/application_controller.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 05fa98e9..cfa37067 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -77,6 +77,11 @@ class ApplicationController < ActionController::Base # Muestra una página 404 def page_not_found + self.response_body = nil + @_response_body = nil + + headers.delete('Location') + render 'application/page_not_found', status: :not_found end From 061fc81cb058221cd237baa6646b8f67d0fc1843 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Mar 2024 16:44:24 -0300 Subject: [PATCH 334/472] =?UTF-8?q?fixup!=20fix:=20prevenir=20doble=20rend?= =?UTF-8?q?erizaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/application_controller.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index cfa37067..b15157f7 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -76,6 +76,8 @@ class ApplicationController < ActionController::Base end # Muestra una página 404 + # + # @see {https://github.com/rails/rails/issues/25106} def page_not_found self.response_body = nil @_response_body = nil From 93140f37aa6ca1436cb42523ad1cd4865abba097 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Mar 2024 16:46:04 -0300 Subject: [PATCH 335/472] fix: cachear correctamente closes #15567 --- app/views/moderation_queue/_comments.haml | 6 +++--- app/views/moderation_queue/_instances.haml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index 72240287..a4bfd9bd 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -12,6 +12,6 @@ - if moderation_queue.count.zero? %h4= t('moderation_queue.nothing') - moderation_queue.each do |activity_pub| - -# cache [activity_pub, activity_pub.object, activity_pub.actor] do - %hr - = render 'moderation_queue/comment', comment: activity_pub.object.content, profile: activity_pub.actor.content, activity_pub: activity_pub, form: form_id + - cache [activity_pub, activity_pub.object, activity_pub.actor] do + %hr + = render 'moderation_queue/comment', comment: activity_pub.object.content, profile: activity_pub.actor.content, activity_pub: activity_pub, form: form_id diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index 9a5349ba..dec7e6f3 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -14,7 +14,7 @@ %h4= t('moderation_queue.nothing') - instance_moderations.each do |instance_moderation| - - cache [instance_moderation.aasm_state, instance_moderation.instance] do + - cache [instance_moderation, instance_moderation.instance] do %hr = render 'moderation_queue/instance', instance_moderation: instance_moderation, instance: instance_moderation.instance, form: form_id From ac38343a219953038540e3ecea460516f998fb54 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Mar 2024 16:55:34 -0300 Subject: [PATCH 336/472] =?UTF-8?q?fix:=20facilitar=20la=20b=C3=BAsqueda?= =?UTF-8?q?=20de=20instancias=20en=20la=20lista=20#15563?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_instance.haml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/views/moderation_queue/_instance.haml b/app/views/moderation_queue/_instance.haml index 7cf3b085..e5121dad 100644 --- a/app/views/moderation_queue/_instance.haml +++ b/app/views/moderation_queue/_instance.haml @@ -1,12 +1,17 @@ - usuaries = instance.content.dig('usage', 'users', 'active_month') - usuaries ||= instance.content.dig('stats', 'user_count') +- title = sanitize(instance.content['title']) +- title ||= instance.hostname .row.no-gutters.pt-2 .col-1 = render 'components/checkbox', id: instance.hostname, form: form, name: 'instance_moderation[]', value: instance_moderation.id, data: { target: 'select-all.input' } .col-11 %h4 - %a{ href: instance.uri }= sanitize(instance.content['title']) || instance.hostname + %a{ href: instance.uri } + = title + - if title.present? + = " (#{instance.hostname})".html_safe .content = sanitize instance.content['description'] - if usuaries.present? From 79e6ce787274aa928b2c726f94342597a74812bc Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Mar 2024 16:56:51 -0300 Subject: [PATCH 337/472] =?UTF-8?q?fixup!=20fix:=20facilitar=20la=20b?= =?UTF-8?q?=C3=BAsqueda=20de=20instancias=20en=20la=20lista=20#15563?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/moderation_queue/_instance.haml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/views/moderation_queue/_instance.haml b/app/views/moderation_queue/_instance.haml index e5121dad..d66acd83 100644 --- a/app/views/moderation_queue/_instance.haml +++ b/app/views/moderation_queue/_instance.haml @@ -1,15 +1,13 @@ - usuaries = instance.content.dig('usage', 'users', 'active_month') - usuaries ||= instance.content.dig('stats', 'user_count') -- title = sanitize(instance.content['title']) -- title ||= instance.hostname +- title = sanitize(instance.content['title']) .row.no-gutters.pt-2 .col-1 = render 'components/checkbox', id: instance.hostname, form: form, name: 'instance_moderation[]', value: instance_moderation.id, data: { target: 'select-all.input' } .col-11 %h4 - %a{ href: instance.uri } - = title + %a{ href: instance.uri }= title || instance.hostname - if title.present? = " (#{instance.hostname})".html_safe .content From 97653d98b6d3f0d2d667eb153f5e70e8b9b272d1 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Mar 2024 17:02:01 -0300 Subject: [PATCH 338/472] fix: prevenir deadlocks closes #15555 closes #15556 closes #15557 closes #15558 closes #15559 closes #15560 --- app/models/activity_pub/activity/delete.rb | 26 ++++++++++++---------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/app/models/activity_pub/activity/delete.rb b/app/models/activity_pub/activity/delete.rb index 6a23a8b5..1fbe5691 100644 --- a/app/models/activity_pub/activity/delete.rb +++ b/app/models/activity_pub/activity/delete.rb @@ -13,22 +13,24 @@ class ActivityPub # lo haría la Social Inbox por nosotres. # @see {https://docs.joinmastodon.org/spec/security/#ld} def update_activity_pub_state! - ActivityPub.transaction do - object = ActivityPub::Object.find_by(uri: ActivityPub.uri_from_object(content['object'])) + ActiveRecord::Base.connection_pool.with_connection do + ActivityPub.transaction do + object = ActivityPub::Object.find_by(uri: ActivityPub.uri_from_object(content['object'])) - if object.present? - object.activity_pubs.find_each do |activity_pub| - activity_pub.remove! if activity_pub.may_remove? + if object.present? + object.activity_pubs.find_each do |activity_pub| + activity_pub.remove! if activity_pub.may_remove? + end + + # Encontrar todas las acciones de moderación de le actore + # eliminade y moverlas a eliminar. + if object.actor_type? && object.actor.present? + ActorModeration.where(actor_id: object.actor.id).remove_all! + end end - # Encontrar todas las acciones de moderación de le actore - # eliminade y moverlas a eliminar. - if object.actor_type? && object.actor.present? - ActorModeration.where(actor_id: object.actor.id).remove_all! - end + activity_pub.remove! if activity_pub.may_remove? end - - activity_pub.remove! if activity_pub.may_remove? end end end From 1b9e039fda52d2b1ee5779823b2ec7cb00873980 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Mar 2024 17:42:36 -0300 Subject: [PATCH 339/472] =?UTF-8?q?fix:=20errores=20de=20decompresi=C3=B3n?= =?UTF-8?q?=20#15332?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Gemfile | 2 +- Gemfile.lock | 2 +- ...04105_brs_decompressor_corrupted_source_error.rb | 13 +++++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20240313204105_brs_decompressor_corrupted_source_error.rb diff --git a/Gemfile b/Gemfile index f4125f65..e314c172 100644 --- a/Gemfile +++ b/Gemfile @@ -39,7 +39,7 @@ gem 'devise-i18n' gem 'devise_invitable' gem 'redis-client' gem 'hiredis-client' -gem 'distributed-press-api-client', '~> 0.4.0rc3' +gem 'distributed-press-api-client', '~> 0.4.1' gem 'email_address', git: 'https://github.com/fauno/email_address', branch: 'i18n' gem 'exception_notification' gem 'fast_blank' diff --git a/Gemfile.lock b/Gemfile.lock index 7b19ba75..751fc73e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -166,7 +166,7 @@ GEM devise_invitable (2.0.9) actionmailer (>= 5.0) devise (>= 4.6) - distributed-press-api-client (0.4.0) + distributed-press-api-client (0.4.1) addressable (~> 2.3, >= 2.3.0) climate_control dry-schema diff --git a/db/migrate/20240313204105_brs_decompressor_corrupted_source_error.rb b/db/migrate/20240313204105_brs_decompressor_corrupted_source_error.rb new file mode 100644 index 00000000..a0c29311 --- /dev/null +++ b/db/migrate/20240313204105_brs_decompressor_corrupted_source_error.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +# Comprueba que se pueden volver a correr las tareas que dieron error de +# decompresión +class BrsDecompressorCorruptedSourceError < ActiveRecord::Migration[6.1] + def up + raise unless HTTParty.get("https://mas.to/api/v2/instance", headers: { "Accept-Encoding": "br;q=1.0,gzip;q=1.0,deflate;q=0.6,identity;q=0.3" }).ok? + + QueJob.where("last_error_message like '%BRS::DecompressorCorruptedSourceError%'").update_all(error_count: 0, run_at: Time.now) + end + + def down; end +end From b6ed91df11eb238d55f6aedb95e164512046bfa7 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 13 Mar 2024 17:52:45 -0300 Subject: [PATCH 340/472] fix: siempre relacionar la instancia con el sitio #15563 --- app/controllers/api/v1/webhooks/social_inbox_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index bdf359d2..7b17c47b 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -162,11 +162,11 @@ 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 + site.instance_moderations.find_or_create_by(instance: a.instance) + a.save! site.actor_moderations.find_or_create_by(actor: a) From 9d71c5fa0cb4de8725a1b6728cbb71a0edc087e2 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 14 Mar 2024 11:20:04 -0300 Subject: [PATCH 341/472] fix: eliminar actores cuando no se pudo completar el objeto #15576 --- app/models/activity_pub/activity/delete.rb | 4 ++-- ...emove_actor_moderations_for_generic_objects.rb | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20240314141536_remove_actor_moderations_for_generic_objects.rb diff --git a/app/models/activity_pub/activity/delete.rb b/app/models/activity_pub/activity/delete.rb index 1fbe5691..997b96ca 100644 --- a/app/models/activity_pub/activity/delete.rb +++ b/app/models/activity_pub/activity/delete.rb @@ -24,8 +24,8 @@ class ActivityPub # Encontrar todas las acciones de moderación de le actore # eliminade y moverlas a eliminar. - if object.actor_type? && object.actor.present? - ActorModeration.where(actor_id: object.actor.id).remove_all! + if (actor = ActivityPub::Actor.find_by(uri: o.uri)).present? + ActorModeration.where(actor_id: actor.id).remove_all! end end diff --git a/db/migrate/20240314141536_remove_actor_moderations_for_generic_objects.rb b/db/migrate/20240314141536_remove_actor_moderations_for_generic_objects.rb new file mode 100644 index 00000000..a60e755a --- /dev/null +++ b/db/migrate/20240314141536_remove_actor_moderations_for_generic_objects.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +# Elimina actores que no pudieron ser eliminades porque su perfil ya no +# existe. +class RemoveActorModerationsForGenericObjects < ActiveRecord::Migration[6.1] + def up + object_ids = ActivityPub.removed.where(object_type: 'ActivityPub::Object::Generic').distinct.pluck(:object_id) + uris = ActivityPub::Object.where(id: object_ids).pluck(:uri) + actor_ids = ActivityPub::Actor.where(uri: uris).ids + + ActorModeration.where(actor_id: actor_ids).remove_all! + end + + def down; end +end From 30f2f0a4423e623ba79ef385d3cba23e17a12edf Mon Sep 17 00:00:00 2001 From: f Date: Thu, 14 Mar 2024 11:45:33 -0300 Subject: [PATCH 342/472] fix: gestionar las excepciones desde un solo lugar #15564 --- app/controllers/application_controller.rb | 16 --------------- app/controllers/concerns/exception_handler.rb | 20 ++++++++++++++++++- config/locales/en.yml | 1 + config/locales/es.yml | 1 + 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index b15157f7..bd7b8c4b 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -12,10 +12,6 @@ class ApplicationController < ActionController::Base before_action :notify_unconfirmed_email, unless: :devise_controller? around_action :set_locale - rescue_from Pundit::NilPolicyError, with: :page_not_found - rescue_from ActionController::RoutingError, with: :page_not_found - rescue_from ActionController::ParameterMissing, with: :page_not_found - before_action do Rack::MiniProfiler.authorize_request if current_usuarie&.email&.ends_with?('@' + ENV.fetch('SUTTY', 'sutty.nl')) end @@ -75,18 +71,6 @@ class ApplicationController < ActionController::Base I18n.with_locale(current_locale, &action) end - # Muestra una página 404 - # - # @see {https://github.com/rails/rails/issues/25106} - def page_not_found - self.response_body = nil - @_response_body = nil - - headers.delete('Location') - - render 'application/page_not_found', status: :not_found - end - # Necesario para poder acceder a Blazer. Solo les usuaries de este # sitio pueden acceder al panel. def require_usuarie diff --git a/app/controllers/concerns/exception_handler.rb b/app/controllers/concerns/exception_handler.rb index 8c4f54c8..7c1cd540 100644 --- a/app/controllers/concerns/exception_handler.rb +++ b/app/controllers/concerns/exception_handler.rb @@ -12,13 +12,31 @@ module ExceptionHandler rescue_from PageNotFound, with: :page_not_found rescue_from ActionController::RoutingError, with: :page_not_found rescue_from Pundit::NilPolicyError, with: :page_not_found + rescue_from Pundit::NilPolicyError, with: :page_not_found + rescue_from ActionController::RoutingError, with: :page_not_found + rescue_from ActionController::ParameterMissing, with: :page_not_found end def site_not_found + reset_response! + + flash[:error] = I18n.t('errors.site_not_found') + redirect_to sites_path end def page_not_found - send_file Rails.root.join('public', '404.html') + reset_response! + + render 'application/page_not_found', status: :not_found + end + + private + + def reset_response! + self.response_body = nil + @_response_body = nil + + headers.delete('Location') end end diff --git a/config/locales/en.yml b/config/locales/en.yml index d745e2d5..d67fe7d3 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -390,6 +390,7 @@ en: lang: not_available: "This language is not yet available, would you help us by translating Sutty into it?" errors: + site_not_found: "Site not found, or maybe you don't have access to it." argument_error: 'Argument `%{argument}` must be an instance of %{class}' unknown_locale: 'Unknown %{locale} locale' posts: diff --git a/config/locales/es.yml b/config/locales/es.yml index a7b8d452..192b3298 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -389,6 +389,7 @@ es: lang: not_available: "Este idioma todavía no está disponible, ¿nos ayudas a agregarlo y mantenerlo?" errors: + site_not_found: "No encontramos ese sitio o quizás no tengas acceso." argument_error: 'El argumento `%{argument}` debe ser una instancia de %{class}' unknown_locale: 'El idioma %{locale} es desconocido' posts: From cfe70e3a899f136a2a2e004c5ae7ef91681fd4a2 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 14 Mar 2024 11:57:06 -0300 Subject: [PATCH 343/472] fix: no cachear formularios #15570 --- app/views/moderation_queue/_account.haml | 14 ++++----- app/views/moderation_queue/_accounts.haml | 5 ++-- app/views/moderation_queue/_comment.haml | 35 +++++++++++----------- app/views/moderation_queue/_comments.haml | 5 ++-- app/views/moderation_queue/_instance.haml | 21 ++++++------- app/views/moderation_queue/_instances.haml | 5 ++-- 6 files changed, 42 insertions(+), 43 deletions(-) diff --git a/app/views/moderation_queue/_account.haml b/app/views/moderation_queue/_account.haml index 6b4c67fc..498d78f4 100644 --- a/app/views/moderation_queue/_account.haml +++ b/app/views/moderation_queue/_account.haml @@ -5,12 +5,12 @@ .col-1 = render 'components/checkbox', id: actor_moderation.id, form: form, name: 'actor_moderation[]', value: actor_moderation.id, data: { target: 'select-all.input' } .col-11 - %h4 - = link_to text_plain(profile['name']), site_actor_moderation_path(id: actor_moderation) - .mb-3 - = sanitize profile['summary'] + - cache [actor_moderation, profile] do + %h4 + = link_to text_plain(profile['name']), site_actor_moderation_path(id: actor_moderation) + .mb-3 + = sanitize profile['summary'] -# Botones de Moderación - - cache actor_moderation do - .d-flex.pb-4 - = render 'components/profiles_btn_box', actor_moderation: actor_moderation + .d-flex.pb-4 + = render 'components/profiles_btn_box', actor_moderation: actor_moderation diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index abc02b31..d8d76f0d 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -12,6 +12,5 @@ - if actor_moderations.count.zero? %h4= t('moderation_queue.nothing') - actor_moderations.find_each do |actor_moderation| - - cache [actor_moderation, actor_moderation.actor] do - %hr - = render 'account', actor_moderation: actor_moderation, profile: actor_moderation.actor.content, form: form_id + %hr + = render 'account', actor_moderation: actor_moderation, profile: actor_moderation.actor.content, form: form_id diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 90579a9c..c6f6fd5c 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -13,22 +13,23 @@ .col-1 = render 'components/checkbox', id: activity_pub.id, name: 'activity_pub[]', value: activity_pub.id, data: { target: 'select-all.input' }, form: form .col-11 - .d-flex.flex-row.align-items-center.justify-content-between - %h4.mb-0 - %a{ href: text_plain(comment['attributedTo']) }= text_plain profile['preferredUsername'] - %small - = render 'layouts/time', time: text_plain(comment['published']) - - if in_reply_to.present? - %dl - %dt.d-inline - %small= t('.reply_to') - %dd.d-inline - %small - %a{ href: in_reply_to }= in_reply_to - .content - - if summary.present? - = render 'layouts/details', summary: summary, summary_class: 'h5' do + - cache [activity_pub, comment] do + .d-flex.flex-row.align-items-center.justify-content-between + %h4.mb-0 + %a{ href: text_plain(comment['attributedTo']) }= text_plain profile['preferredUsername'] + %small + = render 'layouts/time', time: text_plain(comment['published']) + - if in_reply_to.present? + %dl + %dt.d-inline + %small= t('.reply_to') + %dd.d-inline + %small + %a{ href: in_reply_to }= in_reply_to + .content + - if summary.present? + = render 'layouts/details', summary: summary, summary_class: 'h5' do + = sanitize comment['content'] + - else = sanitize comment['content'] - - else - = sanitize comment['content'] = render 'components/comments_btn_box', activity_pub: activity_pub diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index a4bfd9bd..68671f9e 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -12,6 +12,5 @@ - if moderation_queue.count.zero? %h4= t('moderation_queue.nothing') - moderation_queue.each do |activity_pub| - - cache [activity_pub, activity_pub.object, activity_pub.actor] do - %hr - = render 'moderation_queue/comment', comment: activity_pub.object.content, profile: activity_pub.actor.content, activity_pub: activity_pub, form: form_id + %hr + = render 'moderation_queue/comment', comment: activity_pub.object.content, profile: activity_pub.actor.content, activity_pub: activity_pub, form: form_id diff --git a/app/views/moderation_queue/_instance.haml b/app/views/moderation_queue/_instance.haml index d66acd83..c380089a 100644 --- a/app/views/moderation_queue/_instance.haml +++ b/app/views/moderation_queue/_instance.haml @@ -6,16 +6,17 @@ .col-1 = render 'components/checkbox', id: instance.hostname, form: form, name: 'instance_moderation[]', value: instance_moderation.id, data: { target: 'select-all.input' } .col-11 - %h4 - %a{ href: instance.uri }= title || instance.hostname - - if title.present? - = " (#{instance.hostname})".html_safe - .content - = sanitize instance.content['description'] - - if usuaries.present? - %dl - %dt.d-inline= t('.users') - %dd.d-inline= text_plain usuaries.to_s + - cache [instance_moderation, instance] do + %h4 + %a{ href: instance.uri }= title || instance.hostname + - if title.present? + = " (#{instance.hostname})".html_safe + .content + = sanitize instance.content['description'] + - if usuaries.present? + %dl + %dt.d-inline= t('.users') + %dd.d-inline= text_plain usuaries.to_s -# Botones moderación .d-flex.pb-4 diff --git a/app/views/moderation_queue/_instances.haml b/app/views/moderation_queue/_instances.haml index dec7e6f3..6bc08b95 100644 --- a/app/views/moderation_queue/_instances.haml +++ b/app/views/moderation_queue/_instances.haml @@ -14,9 +14,8 @@ %h4= t('moderation_queue.nothing') - instance_moderations.each do |instance_moderation| - - cache [instance_moderation, instance_moderation.instance] do - %hr - = render 'moderation_queue/instance', instance_moderation: instance_moderation, instance: instance_moderation.instance, form: form_id + %hr + = render 'moderation_queue/instance', instance_moderation: instance_moderation, instance: instance_moderation.instance, form: form_id %hr %div From c57794b54e92cb6eed8dd42944b320aa9c513d7f Mon Sep 17 00:00:00 2001 From: f Date: Thu, 14 Mar 2024 11:58:13 -0300 Subject: [PATCH 344/472] fixup! fix: eliminar actores cuando no se pudo completar el objeto #15576 --- app/models/activity_pub/activity/delete.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/activity_pub/activity/delete.rb b/app/models/activity_pub/activity/delete.rb index 997b96ca..640c7ce9 100644 --- a/app/models/activity_pub/activity/delete.rb +++ b/app/models/activity_pub/activity/delete.rb @@ -24,7 +24,7 @@ class ActivityPub # Encontrar todas las acciones de moderación de le actore # eliminade y moverlas a eliminar. - if (actor = ActivityPub::Actor.find_by(uri: o.uri)).present? + if (actor = ActivityPub::Actor.find_by(uri: object.uri)).present? ActorModeration.where(actor_id: actor.id).remove_all! end end From 1de9d1a12695d97679c64b403c32256a4abf6ec1 Mon Sep 17 00:00:00 2001 From: maki Date: Thu, 14 Mar 2024 12:02:37 -0300 Subject: [PATCH 345/472] =?UTF-8?q?feat:=20breadcrumbs=20en=20Actividades?= =?UTF-8?q?=20de=20Moderaci=C3=B3n=20#15578?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/moderation_queue_controller.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index eec0c70f..ca99d95b 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -2,6 +2,11 @@ # Cola de moderación de ActivityPub class ModerationQueueController < ApplicationController + before_action :authenticate_usuarie! + + breadcrumb -> { current_usuarie.email }, :edit_usuarie_registration_path + breadcrumb 'sites.index', :sites_path, match: :exact + # Cola de moderación viendo todo el sitio def index dummy_data From 33cfdd199513221c8b4bf30f64fbe0b454c4be7a Mon Sep 17 00:00:00 2001 From: maki Date: Thu, 14 Mar 2024 12:21:50 -0300 Subject: [PATCH 346/472] fix: breadcrumbs en todas las acciones --- app/controllers/moderation_queue_controller.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index ca99d95b..cbf2cec5 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -6,7 +6,7 @@ class ModerationQueueController < ApplicationController breadcrumb -> { current_usuarie.email }, :edit_usuarie_registration_path breadcrumb 'sites.index', :sites_path, match: :exact - + # Cola de moderación viendo todo el sitio def index dummy_data @@ -15,11 +15,13 @@ class ModerationQueueController < ApplicationController # Perfil remoto de usuarie def remote_profile dummy_data + breadcrumb post.title.value, '' end # todon.nl está usando /api/v2/instance # mauve.moe usa /api/v1/instance def instances dummy_data + breadcrumb post.title.value, '' end end From 5bf26a7fb2f7b7fb73efd11f110ea8ec6bb44383 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 14 Mar 2024 12:27:59 -0300 Subject: [PATCH 347/472] fix: arreglar las relaciones entre actividades y objetos --- app/jobs/activity_pub/fetch_job.rb | 4 ++++ ...0240314153017_fix_object_type_on_activity_pubs.rb | 12 ++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 db/migrate/20240314153017_fix_object_type_on_activity_pubs.rb diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index 6a4d163b..d7003c11 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -24,9 +24,13 @@ class ActivityPub return unless response.ok? return if response.miss? && object.content.present? + current_type = object.type content = FastJsonparser.parse(response.body) object.update(content: content, type: ActivityPub::Object.type_from(content).name) + + # Arreglar las relaciones con actividades también + ActivityPub.where(object_id: object.id).update_all(object_type: object.type) unless current_type == object.type end end end diff --git a/db/migrate/20240314153017_fix_object_type_on_activity_pubs.rb b/db/migrate/20240314153017_fix_object_type_on_activity_pubs.rb new file mode 100644 index 00000000..81149ad4 --- /dev/null +++ b/db/migrate/20240314153017_fix_object_type_on_activity_pubs.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +# Arregla la relación rota entre ActivityPub y Objects +class FixObjectTypeOnActivityPubs < ActiveRecord::Migration[6.1] + def up + ActivityPub::Object.where.not(type: 'ActivityPub::Object::Generic').find_each do |object| + ActivityPub.where(object_id: object.id).update_all(type: object.type, updated_at: Time.now) + end + end + + def down; end +end From 5969662a7d679836c1936a178ee097641fdfeec6 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 14 Mar 2024 15:42:44 -0300 Subject: [PATCH 348/472] fixup! fix: arreglar las relaciones entre actividades y objetos --- db/migrate/20240314153017_fix_object_type_on_activity_pubs.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20240314153017_fix_object_type_on_activity_pubs.rb b/db/migrate/20240314153017_fix_object_type_on_activity_pubs.rb index 81149ad4..d5475f71 100644 --- a/db/migrate/20240314153017_fix_object_type_on_activity_pubs.rb +++ b/db/migrate/20240314153017_fix_object_type_on_activity_pubs.rb @@ -4,7 +4,7 @@ class FixObjectTypeOnActivityPubs < ActiveRecord::Migration[6.1] def up ActivityPub::Object.where.not(type: 'ActivityPub::Object::Generic').find_each do |object| - ActivityPub.where(object_id: object.id).update_all(type: object.type, updated_at: Time.now) + ActivityPub.where(object_id: object.id).update_all(object_type: object.type, updated_at: Time.now) end end From 96d70100e46ad536d5e017b215f559a7a0615380 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 14 Mar 2024 17:07:58 -0300 Subject: [PATCH 349/472] feat: auto-aprobar solicitudes de seguimiento --- app/models/activity_pub/activity/follow.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/models/activity_pub/activity/follow.rb b/app/models/activity_pub/activity/follow.rb index e383490a..393eb3b4 100644 --- a/app/models/activity_pub/activity/follow.rb +++ b/app/models/activity_pub/activity/follow.rb @@ -4,8 +4,17 @@ # # Una actividad de seguimiento se refiere siempre a une actore (el # sitio) y proviene de otre actore. +# +# Por ahora las solicitudes de seguimiento se auto-aprueban. class ActivityPub class Activity - class Follow < ActivityPub::Activity; end + class Follow < ActivityPub::Activity + # Auto-aprobar la solicitud de seguimiento + def update_activity_pub_state! + activity_pub.approve! + rescue Exception => e + ExceptionNotifier.notify_exception(e, { site: activity_pub.site.name, activity: self.id }) + end + end end end From d92953e5fa3acb9bc1e065dcd5f25d31b326e781 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 14 Mar 2024 17:08:38 -0300 Subject: [PATCH 350/472] fix: poder volver a pausa si se edita el comentario --- app/models/activity_pub.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 53bb3de0..7453a8c3 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -49,6 +49,12 @@ class ActivityPub < ApplicationRecord # Le actore eliminó el objeto state :removed + # Se puede volver a pausa en caso de actualización remota, para + # revisar los cambios. + event :pause do + transitions to: :paused + end + # Recibir una acción de eliminación, eliminar el contenido de la # base de datos. Esto elimina el contenido para todos los sitios # porque estamos respetando lo que pidió le actore. From 1e44fba4b3b70a033bf7026d12ea2da9c3329be8 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 14 Mar 2024 17:08:55 -0300 Subject: [PATCH 351/472] fix: aprobar la actividad, no el objeto --- app/models/activity_pub.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 7453a8c3..bd6c816e 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -101,11 +101,14 @@ 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: object.uri).ok? + raise unless site.social_inbox.inbox.reject(id: activities.first.uri).ok? end def allow_remotely! - raise unless site.social_inbox.inbox.accept(id: object.uri).ok? + raise unless site.social_inbox.inbox.accept(id: activities.first.uri).ok? end end From f4379b45c27583c757dd9b1683e705fdbaf382d8 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 14 Mar 2024 17:58:41 -0300 Subject: [PATCH 352/472] feat: announce y like --- app/models/activity_pub/activity/announce.rb | 8 ++++++++ app/models/activity_pub/activity/like.rb | 8 ++++++++ db/migrate/20240314205923_fix_activity_type.rb | 12 ++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 app/models/activity_pub/activity/announce.rb create mode 100644 app/models/activity_pub/activity/like.rb create mode 100644 db/migrate/20240314205923_fix_activity_type.rb diff --git a/app/models/activity_pub/activity/announce.rb b/app/models/activity_pub/activity/announce.rb new file mode 100644 index 00000000..8ca58906 --- /dev/null +++ b/app/models/activity_pub/activity/announce.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class ActivityPub + class Activity + # Boost + class Announce < ActivityPub::Activity; end + end +end diff --git a/app/models/activity_pub/activity/like.rb b/app/models/activity_pub/activity/like.rb new file mode 100644 index 00000000..531cc32c --- /dev/null +++ b/app/models/activity_pub/activity/like.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class ActivityPub + class Activity + # Like + class Like < ActivityPub::Activity; end + end +end diff --git a/db/migrate/20240314205923_fix_activity_type.rb b/db/migrate/20240314205923_fix_activity_type.rb new file mode 100644 index 00000000..042de8eb --- /dev/null +++ b/db/migrate/20240314205923_fix_activity_type.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +# Soportar nuevos tipos +class FixActivityType < ActiveRecord::Migration[6.1] + def up + %w[Like Announce].each do |type| + ActivityPub::Activity.where(Arel.sql("content->>'type' = '#{type}'")).update_all(type: "ActivityPub::Activity::#{type}", updated_at: Time.now) + end + end + + def down; end +end From 8473927ceed6ea7dc8d01c30856499fcd200e998 Mon Sep 17 00:00:00 2001 From: maki Date: Fri, 15 Mar 2024 12:23:04 -0300 Subject: [PATCH 353/472] fix: breadcrumbs --- app/controllers/moderation_queue_controller.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index cbf2cec5..5e501329 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -10,18 +10,17 @@ class ModerationQueueController < ApplicationController # Cola de moderación viendo todo el sitio def index dummy_data + breadcrumb I18n.t('moderation_queue.index.title'), '' end # Perfil remoto de usuarie def remote_profile dummy_data - breadcrumb post.title.value, '' end # todon.nl está usando /api/v2/instance # mauve.moe usa /api/v1/instance def instances dummy_data - breadcrumb post.title.value, '' end end From 30d32a6e3be6e3fd27ddfe81fa3eeda935f29211 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 15 Mar 2024 13:43:00 -0300 Subject: [PATCH 354/472] feat: confirmar el reporte remoto #15604 --- app/views/components/_btn_base.haml | 2 +- app/views/components/_comments_btn_box.haml | 5 ++++- app/views/components/_instances_btn_box.haml | 12 ++++++++---- app/views/components/_profiles_btn_box.haml | 7 ++++--- config/locales/en.yml | 6 ++++-- config/locales/es.yml | 4 +++- 6 files changed, 24 insertions(+), 12 deletions(-) diff --git a/app/views/components/_btn_base.haml b/app/views/components/_btn_base.haml index 4d8566d3..f9227482 100644 --- a/app/views/components/_btn_base.haml +++ b/app/views/components/_btn_base.haml @@ -5,5 +5,5 @@ - local_assigns[:class] = "btn #{local_assigns[:class]}" -# @todo path es obligatorio -= button_to local_assigns[:path], **local_assigns do += button_to local_assigns[:path], **local_assigns.compact do = text diff --git a/app/views/components/_comments_btn_box.haml b/app/views/components/_comments_btn_box.haml index 285eefdb..1993e5cb 100644 --- a/app/views/components/_comments_btn_box.haml +++ b/app/views/components/_comments_btn_box.haml @@ -1,8 +1,11 @@ -# Componente Botonera de Comentarios +- local_data = { report: { confirm: t('.confirm_report') } } + .d-flex.flex-row - ActivityPub.events.each do |event| = render 'components/btn_base', text: t(".text_#{event}"), path: public_send(:"site_activity_pub_#{event}_path", activity_pub_id: activity_pub), - disabled: !activity_pub.public_send(:"may_#{event}?") + disabled: !activity_pub.public_send(:"may_#{event}?"), + data: local_data[event] diff --git a/app/views/components/_instances_btn_box.haml b/app/views/components/_instances_btn_box.haml index 74cad4a4..15c6c040 100644 --- a/app/views/components/_instances_btn_box.haml +++ b/app/views/components/_instances_btn_box.haml @@ -1,6 +1,10 @@ -# Componente botonera de moderación de Instancias -- btn_class = 'btn btn-secondary' -= 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? +- local_data = {} +- InstanceModeration.events.each do |event| + = render 'components/btn_base', + path: public_send(:"site_instance_moderation_#{event}_path", instance_moderation_id: instance_moderation), + text: t(".text_#{event}"), + class: 'btn btn-secondary', + disabled: !instance_moderation.public_send(:"may_#{event}?"), + data: local_data[event] diff --git a/app/views/components/_profiles_btn_box.haml b/app/views/components/_profiles_btn_box.haml index 073c142e..488373b9 100644 --- a/app/views/components/_profiles_btn_box.haml +++ b/app/views/components/_profiles_btn_box.haml @@ -1,9 +1,10 @@ -# Componente Botonera de Moderación de Cuentas (Remote_profile) .d-flex.flex-row - - btn_class = 'btn-secondary' + - local_data = { report: { confirm: t('.confirm_report') } } - ActorModeration.events.each do |actor_event| = render 'components/btn_base', text: t(".text_#{actor_event}"), path: public_send(:"site_actor_moderation_#{actor_event}_path", actor_moderation_id: actor_moderation), - class: btn_class, - disabled: !actor_moderation.public_send(:"may_#{actor_event}?") + class: 'btn-secondary', + disabled: !actor_moderation.public_send(:"may_#{actor_event}?"), + data: local_data[actor_event] diff --git a/config/locales/en.yml b/config/locales/en.yml index d67fe7d3..6f76fe57 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -106,15 +106,17 @@ en: text_reject: Reject text_reply: Reply text_report: Report + confirm_report: "Send report to the remote instance?" instances_btn_box: - text_check: Check case by case + text_pause: Check case by case text_allow: Allow everything - text_deny: Block instance + text_block: Block instance profiles_btn_box: text_pause: Always check text_allow: Always approve text_block: Block text_report: Report + confirm_report: "Send report to the remote instance?" remote_flags: report_message: "Hi! Someone using Sutty CMS reported this account on your instance. We don't have support for customized report messages yet, but we will soon. You can reach us at %{panel_actor_mention}." activity_pubs: diff --git a/config/locales/es.yml b/config/locales/es.yml index 192b3298..7f71781c 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -105,8 +105,9 @@ es: text_approve: Aceptar text_reject: Rechazar text_report: Reportar + confirm_report: "¿Enviar el reporte a la instancia remota?" instances_btn_box: - text_check: Moderar caso por caso + text_pause: Moderar caso por caso text_allow: Permitir todo text_deny: Bloquear instancia profiles_btn_box: @@ -114,6 +115,7 @@ es: text_allow: Aprobar siempre text_block: Bloquear text_report: Reportar + confirm_report: "¿Enviar el reporte a la instancia remota?" remote_flags: report_message: "¡Hola! Une usuarie de Sutty CMS reportó esta cuenta en tu instancia. Todavía no tenemos soporte para mensajes personalizados. Podés contactarnos en %{panel_actor_mention}." activity_pubs: From 86ba17328db4823140766bdf0dc82d7b5f6f01ed Mon Sep 17 00:00:00 2001 From: f Date: Fri, 15 Mar 2024 14:01:00 -0300 Subject: [PATCH 355/472] feat: migas de pan para actores --- app/controllers/actor_moderations_controller.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/controllers/actor_moderations_controller.rb b/app/controllers/actor_moderations_controller.rb index bc4a059b..769be1fa 100644 --- a/app/controllers/actor_moderations_controller.rb +++ b/app/controllers/actor_moderations_controller.rb @@ -5,6 +5,11 @@ class ActorModerationsController < ApplicationController include ModerationConcern include ModerationFiltersConcern + before_action :authenticate_usuarie! + + breadcrumb -> { current_usuarie.email }, :edit_usuarie_registration_path + breadcrumb 'sites.index', :sites_path, match: :exact + ActorModeration.events.each do |actor_event| define_method(actor_event) do authorize actor_moderation @@ -26,9 +31,13 @@ class ActorModerationsController < ApplicationController # Ver el perfil remoto def show + breadcrumb I18n.t('moderation_queue.index.title'), site_moderation_queue_path(site) + @remote_profile = actor_moderation.actor.content @moderation_queue = rubanok_process(site.activity_pubs.where(actor_id: actor_moderation.actor_id), with: ActivityPubProcessor) + + breadcrumb @remote_profile['name'], '' end def action_on_several From 0fe043dd791dd30342f2f2197da4882e0aacfffb Mon Sep 17 00:00:00 2001 From: f Date: Fri, 15 Mar 2024 14:14:27 -0300 Subject: [PATCH 356/472] fix: informar errores de json closes #15593 --- app/jobs/activity_pub/fetch_job.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index d7003c11..129908d3 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -31,6 +31,8 @@ class ActivityPub # Arreglar las relaciones con actividades también ActivityPub.where(object_id: object.id).update_all(object_type: object.type) unless current_type == object.type + rescue FastJsonparser::ParseError => e + ExceptionNotifier.notify_exception(e, data: { site: site.name, body: response.body }) end end end From 5db750675217ab5226a5955745e0736d805695eb Mon Sep 17 00:00:00 2001 From: f Date: Fri, 15 Mar 2024 14:26:12 -0300 Subject: [PATCH 357/472] =?UTF-8?q?fix:=20no=20se=20puede=20pausar=20todav?= =?UTF-8?q?=C3=ADa=20#15600?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/activity_pub.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index bd6c816e..840cf3b1 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -8,8 +8,8 @@ # # @see {https://www.w3.org/TR/activitypub/#client-to-server-interactions} class ActivityPub < ApplicationRecord - IGNORED_EVENTS = %i[remove] - IGNORED_STATES = %i[removed] + IGNORED_EVENTS = %i[pause remove].freeze + IGNORED_STATES = %i[removed].freeze include AASM From 6412fc108efd2279582f88997f79fc19790f727d Mon Sep 17 00:00:00 2001 From: f Date: Fri, 15 Mar 2024 14:31:54 -0300 Subject: [PATCH 358/472] =?UTF-8?q?fix:=20no=20se=20puede=20rechazar=20lue?= =?UTF-8?q?go=20de=20aprobar=20todav=C3=ADa?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/activity_pub.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 840cf3b1..73006d1d 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -81,7 +81,7 @@ class ActivityPub < ApplicationRecord # La actividad fue rechazada event :reject do - transitions from: %i[paused approved], to: :rejected + transitions from: %i[paused], to: :rejected before do reject_remotely! From fcbff3e1c13a5b8500fd898e9bd2753ca070c853 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 15 Mar 2024 16:52:42 -0300 Subject: [PATCH 359/472] fix: enviar el reporte firmado por el sitio #15605 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pasaban dos cosas: 1. para firmar correctamente, el cliente necesita recibir el path completo por su parámetro `endpoint` 2. la petición tiene que ser hecha por le misme actore que hace el reporte, como estábamos firmando con el sitio, mastodon creía que era un relay y esperaba que se envíen firmas ld --- .env | 2 ++ app/jobs/activity_pub/remote_flag_job.rb | 9 +++++++-- app/models/activity_pub/remote_flag.rb | 16 ++++++++++++---- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/.env b/.env index 480175f8..fe503b11 100644 --- a/.env +++ b/.env @@ -39,3 +39,5 @@ GITLAB_PROJECT= GITLAB_TOKEN= PGVER=15 PGPID=/run/postgresql.pid +PANEL_ACTOR_MENTION=@sutty@sutty.nl +PANEL_ACTOR_SITE_ID=1 diff --git a/app/jobs/activity_pub/remote_flag_job.rb b/app/jobs/activity_pub/remote_flag_job.rb index f5650d53..20833bd4 100644 --- a/app/jobs/activity_pub/remote_flag_job.rb +++ b/app/jobs/activity_pub/remote_flag_job.rb @@ -15,10 +15,15 @@ class ActivityPub def perform(remote_flag:) return if remote_flag.may_queue? + inbox = remote_flag.actor&.content&.[]('inbox') + + raise 'Inbox is missing for actor' if inbox.blank? + remote_flag.queue! - client = remote_flag.site.social_inbox.client_for(remote_flag.actor&.content['inbox']) - response = client.post(endpoint: '', body: remote_flag.content) + uri = URI.parse(inbox) + client = remote_flag.main_site.social_inbox.client_for(uri.origin) + response = client.post(endpoint: uri.path, body: remote_flag.content) raise 'No se pudo enviar el reporte' unless response.ok? diff --git a/app/models/activity_pub/remote_flag.rb b/app/models/activity_pub/remote_flag.rb index 70f09dcc..c3cc0fb0 100644 --- a/app/models/activity_pub/remote_flag.rb +++ b/app/models/activity_pub/remote_flag.rb @@ -2,8 +2,8 @@ class ActivityPub class RemoteFlag < ApplicationRecord - IGNORED_EVENTS = [] - IGNORED_STATES = [] + IGNORED_EVENTS = [].freeze + IGNORED_STATES = [].freeze include AASM @@ -42,10 +42,18 @@ class ActivityPub '@context' => 'https://www.w3.org/ns/activitystreams', 'id' => Rails.application.routes.url_helpers.v1_activity_pub_remote_flag_url(self, host: site.social_inbox_hostname), 'type' => 'Flag', - 'actor' => ENV.fetch('PANEL_ACTOR_ID') { "https://#{ENV['SUTTY']}/about.jsonld" }, + 'actor' => main_site.social_inbox.actor_id, 'content' => message.to_s, - 'object' => [ actor.uri ] + objects.pluck(:uri) + 'object' => [actor.uri] + objects.pluck(:uri) } end + + # Este es el sitio principal que actúa como origen del reporte. + # Tiene que tener la Social Inbox habilitada al mismo tiempo. + # + # @return [Site] + def main_site + @main_site ||= Site.find(ENV.fetch('PANEL_ACTOR_SITE_ID') { 1 }) + end end end From 364b63a075b141a01e429d30b0030e149d86d67f Mon Sep 17 00:00:00 2001 From: f Date: Fri, 15 Mar 2024 17:57:21 -0300 Subject: [PATCH 360/472] =?UTF-8?q?fix:=20notificar=20correctamente=20la?= =?UTF-8?q?=20excepci=C3=B3n=20#15608?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/activity_pub/activity/follow.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/activity_pub/activity/follow.rb b/app/models/activity_pub/activity/follow.rb index 393eb3b4..37dc9d26 100644 --- a/app/models/activity_pub/activity/follow.rb +++ b/app/models/activity_pub/activity/follow.rb @@ -13,7 +13,7 @@ class ActivityPub def update_activity_pub_state! activity_pub.approve! rescue Exception => e - ExceptionNotifier.notify_exception(e, { site: activity_pub.site.name, activity: self.id }) + ExceptionNotifier.notify_exception(e, data: { site: activity_pub.site.name, activity: self.id }) end end end From 00270b7829266120fa2e3beaa87ffde118cae38a Mon Sep 17 00:00:00 2001 From: f Date: Fri, 15 Mar 2024 18:05:05 -0300 Subject: [PATCH 361/472] fix: no mostrar likes #15596 --- app/models/activity_pub.rb | 16 ++++++++++++++-- app/processors/activity_pub_processor.rb | 9 ++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 73006d1d..3671000c 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -6,6 +6,12 @@ # una actividad, puede estar destinada a varies actores dentro de Sutty, # con lo que generamos una cola para cada une. # +# +# @todo Ya que une actore puede hacer varias actividades sobre el mismo +# objeto, lo correcto sería que la actividad a moderar sea una sola en +# lugar de una lista acumulativa. Es decir cada ActivityPub representa +# el estado del conjunto (Actor, Object, Activity) +# # @see {https://www.w3.org/TR/activitypub/#client-to-server-interactions} class ActivityPub < ApplicationRecord IGNORED_EVENTS = %i[pause remove].freeze @@ -105,10 +111,16 @@ class ActivityPub < ApplicationRecord # 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? + fail! 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? + with_failure_handling(activity: activities.first.uri) do + fail! unless site.social_inbox.inbox.accept(id: activities.first.uri).ok? + end + end + + def fail_message + activities.first&.uri || 'Activity missing' end end diff --git a/app/processors/activity_pub_processor.rb b/app/processors/activity_pub_processor.rb index 52cdb6d3..501b73a5 100644 --- a/app/processors/activity_pub_processor.rb +++ b/app/processors/activity_pub_processor.rb @@ -6,7 +6,14 @@ class ActivityPubProcessor < Rubanok::Processor # # Por ahora solo queremos moderar comentarios. prepare do - raw.where(object_type: %w[ActivityPub::Object::Note ActivityPub::Object::Article]).order(updated_at: :desc) + raw + .joins(:activities) + .where( + activity_pub_activities: { + type: %w[ActivityPub::Activity::Create ActivityPub::Activity::Update] + }, + object_type: %w[ActivityPub::Object::Note ActivityPub::Object::Article] + ).order(updated_at: :desc) end map :activity_pub_state, activate_always: true do |activity_pub_state: 'paused'| From 26e865661638e9af84acaf6dd0f331433603e89c Mon Sep 17 00:00:00 2001 From: f Date: Fri, 15 Mar 2024 18:08:34 -0300 Subject: [PATCH 362/472] fixup! fix: no mostrar likes #15596 --- app/models/activity_pub.rb | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 3671000c..cae054cd 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -111,16 +111,10 @@ class ActivityPub < ApplicationRecord # disponible, que según el scope por defecto, va a ser la primera de # la lista. def reject_remotely! - fail! unless site.social_inbox.inbox.reject(id: activities.first.uri).ok? + raise unless site.social_inbox.inbox.reject(id: activities.first.uri).ok? end def allow_remotely! - with_failure_handling(activity: activities.first.uri) do - fail! unless site.social_inbox.inbox.accept(id: activities.first.uri).ok? - end - end - - def fail_message - activities.first&.uri || 'Activity missing' + raise unless site.social_inbox.inbox.accept(id: activities.first.uri).ok? end end From 3a0f1584c1d292997bc850e8bbd7810810bfc6b6 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 16 Mar 2024 11:32:16 -0300 Subject: [PATCH 363/472] fix: poder volver al sitio --- app/controllers/actor_moderations_controller.rb | 1 + app/controllers/moderation_queue_controller.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/app/controllers/actor_moderations_controller.rb b/app/controllers/actor_moderations_controller.rb index 769be1fa..6316a4cf 100644 --- a/app/controllers/actor_moderations_controller.rb +++ b/app/controllers/actor_moderations_controller.rb @@ -31,6 +31,7 @@ class ActorModerationsController < ApplicationController # Ver el perfil remoto def show + breadcrumb site.title, site_posts_path(site) breadcrumb I18n.t('moderation_queue.index.title'), site_moderation_queue_path(site) @remote_profile = actor_moderation.actor.content diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index 3536dc95..4bd61e38 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -11,6 +11,7 @@ class ModerationQueueController < ApplicationController # Cola de moderación viendo todo el sitio def index + breadcrumb site.title, site_posts_path(site) breadcrumb I18n.t('moderation_queue.index.title'), '' # @todo cambiar el estado por query From adfd6c78bbb583ea0dc8936358152d771771fded Mon Sep 17 00:00:00 2001 From: f Date: Sat, 16 Mar 2024 14:15:32 -0300 Subject: [PATCH 364/472] feat: procesar actividades en segundo plano MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit en lugar de hacerlo en el momento, respondemos lo más rápido posible a la social inbox, ya que un webhook fallado genera un error en la social inbox, que genera un error en la instancia remota, que va a volver a intentar muchas veces. ahora recibimos una vez, si falla el procesamiento, lo detenemos para que alguien humane actúe al respecto. --- .../v1/webhooks/social_inbox_controller.rb | 171 ++---------------- app/jobs/activity_pub/process_job.rb | 154 ++++++++++++++++ 2 files changed, 167 insertions(+), 158 deletions(-) create mode 100644 app/jobs/activity_pub/process_job.rb diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index 7b17c47b..6ac91a51 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -5,196 +5,51 @@ module Api module Webhooks # Recibe webhooks de la Social Inbox # - # @todo Mover todo a un Job que obtenga el objeto remoto antes de - # instanciar el objeto localmente en lugar de arreglarlo después y - # poder responder lo más rápido posible el webhook. # @see {https://www.w3.org/TR/activitypub/} class SocialInboxController < BaseController include Api::V1::Webhooks::Concerns::WebhookConcern + # Validar que el token sea correcto + before_action :usuarie + # Cuando una actividad ingresa en la cola de moderación, la # recibimos por acá # - # Vamos a recibir Create, Update, Delete, Follow, Undo y obtener - # el objeto dentro de cada una para guardar un estado asociado - # al sitio. + # Vamos a recibir Create, Update, Delete, Follow, Undo, + # Announce, Like y obtener el objeto dentro de cada una para + # guardar un estado asociado al sitio. # # El objeto del estado puede ser un objeto o une actore, # dependiendo de la actividad. def moderationqueued - # Devuelve un error si el token no es válido - usuarie.present? + process! :paused - ::ActivityPub.transaction do - - # Crea todos los registros necesarios y actualiza el estado - actor.present? - instance.present? - object.present? - activity_pub.present? - - activity.update_activity_pub_state! - end - rescue ActiveRecord::RecordInvalid => e - ExceptionNotifier.notify_exception(e, - data: { site: site.name, usuarie: usuarie.email, - activity: original_activity }) - ensure head :accepted end # Cuando la Social Inbox acepta una actividad, la recibimos # igual y la guardamos por si cambiamos de idea. - # - # @todo DRY def onapproved - ::ActivityPub.transaction do - actor.present? - instance.present? - object.present? - activity.present? - activity_pub.update(aasm_state: 'approved') - activity.update_activity_pub_state! - end + process! :approved head :accepted end # Cuando la Social Inbox rechaza una actividad, la recibimos # igual y la guardamos por si cambiamos de idea. - # - # @todo DRY def onrejected - ::ActivityPub.transaction do - actor.present? - instance.present? - object.present? - activity.present? - activity_pub.update(aasm_state: 'rejected') - end + process! :rejected head :accepted end private - # Si el objeto ya viene incorporado en la actividad o lo tenemos - # que traer remotamente. + # Envía la actividad para procesamiento por separado. # - # @return [Bool] - def object_embedded? - @object_embedded ||= original_activity[:object].is_a?(Hash) - end - - # Encuentra la URI del objeto o falla si no la encuentra. - # - # @return [String] - def object_uri - @object_uri ||= ::ActivityPub.uri_from_object(original_activity[:object]) - ensure - raise ActiveRecord::RecordNotFound, 'object id missing' if @object_uri.blank? - end - - # Atajo a la instancia - # - # @return [ActivityPub::Instance] - def instance - actor.instance - end - - # Genera un objeto a partir de la actividad. Si el objeto ya - # existe, actualiza su contenido. Si el objeto no viene - # incorporado, obtenemos el contenido más tarde. - # - # @return [ActivityPub::Object] - def object - @object ||= ::ActivityPub::Object.find_or_initialize_by(uri: object_uri).tap do |o| - # XXX: Si el objeto es una actividad, esto siempre va a ser - # Generic - o.type ||= 'ActivityPub::Object::Generic' - - if object_embedded? - o.content = original_object - begin - type = original_object[:type].presence - o.type = "ActivityPub::Object::#{type}".constantize if type - rescue NameError - end - end - - o.save! - - # XXX: el objeto necesita ser guardado antes de poder - # procesarlo. No usamos GlobalID porque el tipo de objeto - # cambia y produce un error de deserialización. - ::ActivityPub::FetchJob.perform_later(site: site, object_id: o.id) unless object_embedded? - end - end - - # Genera el seguimiento del estado del objeto con respecto al - # sitio. - # - # @return [ActivityPub] - def activity_pub - @activity_pub ||= site.activity_pubs.find_or_create_by!(site: site, actor: actor, instance: instance, object_id: object.id, object_type: object.type) - end - - # Crea la actividad y la vincula con el estado - # - # @return [ActivityPub::Activity] - def activity - @activity ||= - ::ActivityPub::Activity - .type_from(original_activity) - .find_or_initialize_by(uri: original_activity[:id], activity_pub: activity_pub, actor: actor).tap do |a| - a.content = original_activity.dup - a.content[:object] = object.uri - a.save! - end - end - - # Actor, si no hay instancia, la crea en el momento, junto con - # su estado de moderación. - # - # @return [Actor] - def actor - @actor ||= ::ActivityPub::Actor.find_or_initialize_by(uri: original_activity[:actor]).tap do |a| - unless a.instance - a.instance = ::ActivityPub::Instance.find_or_create_by(hostname: URI.parse(a.uri).hostname) - - ::ActivityPub::InstanceFetchJob.perform_later(site: site, instance: a.instance) - end - - site.instance_moderations.find_or_create_by(instance: a.instance) - - a.save! - - site.actor_moderations.find_or_create_by(actor: a) - - ::ActivityPub::ActorFetchJob.perform_later(site: site, actor: a) - end - end - - # Descubre la actividad recibida, generando un error si la - # actividad no está dirigida a nosotres. - # - # @todo Validar formato - # @return [Hash] - def original_activity - @original_activity ||= FastJsonparser.parse(request.raw_post).tap do |activity| - raise '@context missing' unless activity[:@context].presence - raise 'id missing' unless activity[:id].presence - raise 'object missing' unless activity[:object].presence - rescue RuntimeError => e - raise ActiveRecord::RecordNotFound, e.message - end - end - - # @return [Hash,String] - def original_object - @original_object ||= original_activity[:object].dup.tap do |o| - o[:@context] = original_activity[:@context].dup - end + # @param initial_state [Symbol] + def process!(initial_state) + ::ActivityPub::ProcessJob.perform_later(site: site, body: request.raw_post, initial_state: initial_state) end end end diff --git a/app/jobs/activity_pub/process_job.rb b/app/jobs/activity_pub/process_job.rb new file mode 100644 index 00000000..6554b44d --- /dev/null +++ b/app/jobs/activity_pub/process_job.rb @@ -0,0 +1,154 @@ +# frozen_string_literal: true + +class ActivityPub + # Procesar las actividades a medida que llegan + class ProcessJob < ApplicationJob + attr_reader :body + + # Procesa la actividad en segundo plano + # + # @param :body [String] + # @param :initial_state [Symbol,String] + def perform(site:, body:, initial_state: :paused) + @body = body + @site = site + + ActiveRecord::Base.connection_pool.with_connection do + ::ActivityPub.transaction do + # Crea todos los registros necesarios y actualiza el estado + actor.present? + instance.present? + object.present? + activity_pub.present? + activity_pub.update(aasm_state: initial_state) + + activity.update_activity_pub_state! + end + end + # Al generar una excepción, en lugar de seguir intentando, enviamos + # el reporte. + rescue Exception => e + ExceptionNotifier.notify_exception(e, data: { site: site.name, activity: original_activity }) + end + + private + + # Si el objeto ya viene incorporado en la actividad o lo tenemos + # que traer remotamente. + # + # @return [Bool] + def object_embedded? + @object_embedded ||= original_activity[:object].is_a?(Hash) + end + + # Encuentra la URI del objeto o falla si no la encuentra. + # + # @return [String] + def object_uri + @object_uri ||= ::ActivityPub.uri_from_object(original_activity[:object]) + ensure + raise ActiveRecord::RecordNotFound, 'object id missing' if @object_uri.blank? + end + + # Atajo a la instancia + # + # @return [ActivityPub::Instance] + def instance + actor.instance + end + + # Genera un objeto a partir de la actividad. Si el objeto ya + # existe, actualiza su contenido. Si el objeto no viene + # incorporado, obtenemos el contenido más tarde. + # + # @return [ActivityPub::Object] + def object + @object ||= ::ActivityPub::Object.find_or_initialize_by(uri: object_uri).tap do |o| + # XXX: Si el objeto es una actividad, esto siempre va a ser + # Generic + o.type ||= 'ActivityPub::Object::Generic' + + if object_embedded? + o.content = original_object + begin + type = original_object[:type].presence + o.type = "ActivityPub::Object::#{type}".constantize if type + rescue NameError + end + end + + o.save! + + # XXX: el objeto necesita ser guardado antes de poder + # procesarlo. No usamos GlobalID porque el tipo de objeto + # cambia y produce un error de deserialización. + ::ActivityPub::FetchJob.perform_later(site: site, object_id: o.id) unless object_embedded? + end + end + + # Genera el seguimiento del estado del objeto con respecto al + # sitio. + # + # @return [ActivityPub] + def activity_pub + @activity_pub ||= site.activity_pubs.find_or_create_by!(site: site, actor: actor, instance: instance, + object_id: object.id, object_type: object.type) + end + + # Crea la actividad y la vincula con el estado + # + # @return [ActivityPub::Activity] + def activity + @activity ||= + ::ActivityPub::Activity + .type_from(original_activity) + .find_or_initialize_by(uri: original_activity[:id], activity_pub: activity_pub, actor: actor).tap do |a| + a.content = original_activity.dup + a.content[:object] = object.uri + a.save! + end + end + + # Actor, si no hay instancia, la crea en el momento, junto con + # su estado de moderación. + # + # @return [Actor] + def actor + @actor ||= ::ActivityPub::Actor.find_or_initialize_by(uri: original_activity[:actor]).tap do |a| + unless a.instance + a.instance = ::ActivityPub::Instance.find_or_create_by(hostname: URI.parse(a.uri).hostname) + + ::ActivityPub::InstanceFetchJob.perform_later(site: site, instance: a.instance) + end + + site.instance_moderations.find_or_create_by(instance: a.instance) + + a.save! + + site.actor_moderations.find_or_create_by(actor: a) + + ::ActivityPub::ActorFetchJob.perform_later(site: site, actor: a) + end + end + + # @return [Hash,String] + def original_object + @original_object ||= original_activity[:object].dup.tap do |o| + o[:@context] = original_activity[:@context].dup + end + end + + # Descubre la actividad recibida, generando un error si la + # actividad no está dirigida a nosotres. + # + # @todo Validar formato con Dry::Schema + # @return [Hash] + def original_activity + @original_activity ||= FastJsonparser.parse(body).tap do |activity| + raise '@context missing' unless activity[:@context].present? + raise 'id missing' unless activity[:id].present? + raise 'object missing' unless activity[:object].present? + end + end + end +end From 1dae918a179ecca3f18edfe286e16d58b7546398 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 16 Mar 2024 14:17:28 -0300 Subject: [PATCH 365/472] feat: poder gestionar la cola de tareas --- Gemfile | 1 + Gemfile.lock | 18 +++++++++++++++++- config/initializers/que_web.rb | 5 +++++ config/routes.rb | 3 +++ 4 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 config/initializers/que_web.rb diff --git a/Gemfile b/Gemfile index e314c172..e5e6ed10 100644 --- a/Gemfile +++ b/Gemfile @@ -83,6 +83,7 @@ gem 'rubanok' gem 'after_commit_everywhere', '~> 1.0' gem 'aasm' +gem 'que-web' # database gem 'hairtrigger' diff --git a/Gemfile.lock b/Gemfile.lock index 751fc73e..7087e013 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -97,6 +97,7 @@ GEM ast (2.4.2) autoprefixer-rails (10.4.13.0) execjs (~> 2) + base64 (0.2.0) bcrypt (3.1.20-x86_64-linux-musl) bcrypt_pbkdf (1.1.0-x86_64-linux-musl) benchmark-ips (2.12.0) @@ -370,6 +371,8 @@ GEM i18n (>= 0.6.10, < 2) request_store (~> 1.0) multi_xml (0.6.0) + mustermann (3.0.0) + ruby2_keywords (~> 0.0.1) net-imap (0.4.9) date net-protocol @@ -409,12 +412,18 @@ GEM pundit (2.3.1) activesupport (>= 3.0.0) que (2.2.1) + que-web (0.10.0) + que (>= 1) + sinatra racc (1.7.3-x86_64-linux-musl) rack (2.2.8) rack-cors (2.0.1) rack (>= 2.0.0) rack-mini-profiler (3.1.0) rack (>= 1.2.0) + rack-protection (3.2.0) + base64 (>= 0.1.0) + rack (~> 2.2, >= 2.2.4) rack-proxy (0.7.7) rack rack-test (2.1.0) @@ -513,6 +522,7 @@ GEM ruby-statistics (3.0.2) ruby-vips (2.2.0) ffi (~> 1.12) + ruby2_keywords (0.0.5) ruby2ruby (2.5.0) ruby_parser (~> 3.1) sexp_processor (~> 4.6) @@ -539,6 +549,11 @@ GEM sexp_processor (4.17.0) simpleidn (0.2.1) unf (~> 0.1.4) + sinatra (3.2.0) + mustermann (~> 3.0) + rack (~> 2.2, >= 2.2.4) + rack-protection (= 3.2.0) + tilt (~> 2.0) sourcemap (0.1.1) spring (4.1.1) spring-watcher-listen (2.1.0) @@ -626,7 +641,7 @@ DEPENDENCIES devise devise-i18n devise_invitable - distributed-press-api-client (~> 0.4.0) + distributed-press-api-client (~> 0.4.1) dotenv-rails down ed25519 @@ -670,6 +685,7 @@ DEPENDENCIES puma pundit que + que-web rack-cors rack-mini-profiler rails (~> 6.1.0) diff --git a/config/initializers/que_web.rb b/config/initializers/que_web.rb new file mode 100644 index 00000000..192256db --- /dev/null +++ b/config/initializers/que_web.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +Que::Web.use(Rack::Auth::Basic) do |user, password| + [user, password] == [ENV['HTTP_BASIC_USER'], ENV['HTTP_BASIC_PASSWORD']] +end diff --git a/config/routes.rb b/config/routes.rb index 054b7f4d..4d43d66a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -4,6 +4,9 @@ Rails.application.routes.draw do devise_for :usuaries get '/.well-known/change-password', to: redirect('/usuaries/edit') + require 'que/web' + mount Que::Web => '/que' + root 'application#index' constraints(Constraints::ApiSubdomain.new) do From 8f91b748ff6ed9536d13093efd72e228bb66de3f Mon Sep 17 00:00:00 2001 From: f Date: Sat, 16 Mar 2024 14:27:28 -0300 Subject: [PATCH 366/472] =?UTF-8?q?fix:=20mostrar=20botones=20de=20acci?= =?UTF-8?q?=C3=B3n=20en=20masa?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/components/_btn_base.haml | 4 ++-- app/views/components/_dropdown_button.haml | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/views/components/_btn_base.haml b/app/views/components/_btn_base.haml index f9227482..faa5c85f 100644 --- a/app/views/components/_btn_base.haml +++ b/app/views/components/_btn_base.haml @@ -3,7 +3,7 @@ - local_assigns[:method] ||= 'patch' - local_assigns[:class] ||= 'btn-secondary' - local_assigns[:class] = "btn #{local_assigns[:class]}" +- local_assigns.delete(:text) --# @todo path es obligatorio -= button_to local_assigns[:path], **local_assigns.compact do += button_to(path, **local_assigns.compact) do = text diff --git a/app/views/components/_dropdown_button.haml b/app/views/components/_dropdown_button.haml index c0f12754..d6de6c8e 100644 --- a/app/views/components/_dropdown_button.haml +++ b/app/views/components/_dropdown_button.haml @@ -1,4 +1,6 @@ -# @param name [String] @param value [String] -%button.dropdown-item{type: 'submit', data: { target: 'dropdown.item' }, name: name, value: value, **local_assigns.compact } + @param text [String] +- local_assigns.delete(:text) +%button.dropdown-item{type: 'submit', data: { target: 'dropdown.item' }, name: name, value: value, **local_assigns.compact }= text From 8ff5626e9968407d5b12f5e9a77fd3cb739ff77d Mon Sep 17 00:00:00 2001 From: f Date: Sat, 16 Mar 2024 15:12:55 -0300 Subject: [PATCH 367/472] feat: no permitir entrar al evento si falla la request --- app/controllers/activity_pubs_controller.rb | 14 +++--- .../actor_moderations_controller.rb | 13 ++--- .../instance_moderations_controller.rb | 13 ++--- app/models/activity_pub.rb | 21 ++++---- app/models/actor_moderation.rb | 32 +++++-------- app/models/concerns/aasm_events_concern.rb | 29 ++++------- app/models/fediblock_state.rb | 48 ++++++++++--------- app/models/instance_moderation.rb | 28 ++++------- 8 files changed, 88 insertions(+), 110 deletions(-) diff --git a/app/controllers/activity_pubs_controller.rb b/app/controllers/activity_pubs_controller.rb index edece8f8..225311c2 100644 --- a/app/controllers/activity_pubs_controller.rb +++ b/app/controllers/activity_pubs_controller.rb @@ -9,14 +9,16 @@ class ActivityPubsController < ApplicationController authorize activity_pub activity_pub.update(remote_flag_params(activity_pub)) if event == :report - activity_pub.public_send(:"#{event}!") if activity_pub.public_send(:"may_#{event}?") - flash[:success] = I18n.t("activity_pubs.#{event}.success") - rescue Exception => e - ExceptionNotifier.notify_exception(e, data: { site: site.name, params: params.permit!.to_h }) + message = + if activity_pub.public_send(:"may_#{event}?") && activity_pub.public_send(:"#{event}!") + :success + else + :error + end + + flash[message] = I18n.t("activity_pubs.#{event}.#{message}") - flash[:error] = I18n.t("activity_pubs.#{event}.error") - ensure redirect_to_moderation_queue! end end diff --git a/app/controllers/actor_moderations_controller.rb b/app/controllers/actor_moderations_controller.rb index 6316a4cf..cb7a63a9 100644 --- a/app/controllers/actor_moderations_controller.rb +++ b/app/controllers/actor_moderations_controller.rb @@ -17,14 +17,15 @@ class ActorModerationsController < ApplicationController # Crea una RemoteFlag si se envían los parámetros adecuados actor_moderation.update(remote_flag_params(actor_moderation)) if actor_event == :report - actor_moderation.public_send(:"#{actor_event}!") if actor_moderation.public_send(:"may_#{actor_event}?") + message = + if actor_moderation.public_send(:"may_#{actor_event}?") && actor_moderation.public_send(:"#{actor_event}!") + :success + else + :error + end - flash[:success] = I18n.t("actor_moderations.#{actor_event}.success") - rescue Exception => e - ExceptionNotifier.notify_exception(e, data: { site: site.name, params: params.permit!.to_h }) + flash[message] = I18n.t("actor_moderations.#{actor_event}.#{message}") - flash[:error] = I18n.t("actor_moderations.#{actor_event}.error") - ensure redirect_to_moderation_queue! end end diff --git a/app/controllers/instance_moderations_controller.rb b/app/controllers/instance_moderations_controller.rb index 06f5cfc1..13d7f428 100644 --- a/app/controllers/instance_moderations_controller.rb +++ b/app/controllers/instance_moderations_controller.rb @@ -8,14 +8,15 @@ class InstanceModerationsController < ApplicationController define_method(event) do authorize instance_moderation - instance_moderation.public_send(:"#{event}!") if instance_moderation.public_send(:"may_#{event}?") + message = + if instance_moderation.public_send(:"may_#{event}?") && instance_moderation.public_send(:"#{event}!") + :success + else + :error + end - 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[message] = I18n.t("instance_moderations.#{event}.#{message}") - flash[:error] = I18n.t("instance_moderations.#{event}.error") - ensure redirect_to_moderation_queue! end end diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index cae054cd..8142ecfb 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -47,14 +47,19 @@ class ActivityPub < ApplicationRecord # Todavía no hay una decisión sobre el objeto state :paused, initial: true # Le usuarie aprobó el objeto - state :approved + state :approved, before_enter: :allow_remotely! # Le usuarie rechazó el objeto - state :rejected + state :rejected, before_enter: :reject_remotely! # Le usuarie reportó el objeto state :reported # Le actore eliminó el objeto state :removed + # Gestionar todos los errores + error_on_all_events do |e| + ExceptionNotifier.notify_exception(e, data: { site: site.name, activity_pub: self.id, activity: activities.first.uri }) + end + # Se puede volver a pausa en caso de actualización remota, para # revisar los cambios. event :pause do @@ -67,7 +72,7 @@ class ActivityPub < ApplicationRecord event :remove do transitions to: :removed - before do + after do next if object.blank? object.update(content: {}) unless object.content.empty? @@ -79,26 +84,18 @@ class ActivityPub < ApplicationRecord # webhook a modo de confirmación. event :approve do transitions from: %i[paused], to: :approved - - before do - allow_remotely! - end end # La actividad fue rechazada event :reject do transitions from: %i[paused], to: :rejected - - before do - reject_remotely! - end end # Solo podemos reportarla luego de rechazarla event :report do transitions from: :rejected, to: :reported - before do + after do ActivityPub::RemoteFlagJob.perform_later(remote_flag: remote_flag) if remote_flag.waiting? end end diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index 3b183a4f..c566b844 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -2,8 +2,8 @@ # Mantiene la relación entre Site y Actor class ActorModeration < ApplicationRecord - IGNORED_EVENTS = %i[remove] - IGNORED_STATES = %i[removed] + IGNORED_EVENTS = %i[remove].freeze + IGNORED_STATES = %i[removed].freeze include AASM @@ -14,38 +14,30 @@ class ActorModeration < ApplicationRecord accepts_nested_attributes_for :remote_flag aasm do - state :paused, initial: true - state :allowed - state :blocked + state :paused, initial: true, before_enter: :pause_remotely! + state :allowed, before_enter: :allow_remotely! + state :blocked, before_enter: :block_remotely! state :reported state :removed + error_on_all_events do |e| + ExceptionNotifier.notify_exception(e, data: { site: site.name, actor: actor.uri, actor_moderation: id }) + end + event :pause do transitions from: %i[allowed blocked reported], to: :paused - - before do - pause_remotely! - end 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 - - before do - allow_remotely! - end 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 - - before do - block_remotely! - end end # Al reportar, necesitamos asociar una RemoteFlag para poder @@ -53,7 +45,7 @@ class ActorModeration < ApplicationRecord event :report do transitions from: %i[blocked], to: :reported - before do + after do ActivityPub::RemoteFlagJob.perform_later(remote_flag: remote_flag) if remote_flag.waiting? end end @@ -63,8 +55,8 @@ class ActorModeration < ApplicationRecord event :remove do transitions to: :removed - before do - site.activity_pubs.where(actor_id: self.actor_id).remove_all! + after do + site.activity_pubs.where(actor_id: actor_id).remove_all! end end end diff --git a/app/models/concerns/aasm_events_concern.rb b/app/models/concerns/aasm_events_concern.rb index 4de5f748..788e9e1a 100644 --- a/app/models/concerns/aasm_events_concern.rb +++ b/app/models/concerns/aasm_events_concern.rb @@ -16,7 +16,7 @@ module AasmEventsConcern # # @return [Array] def self.transitionable_events(current_state) - self.events.select do |event| + events.select do |event| aasm.events.find { |x| x.name == event }.transitions_from_state? current_state end end @@ -32,19 +32,15 @@ module AasmEventsConcern # scope actual. # # @return [Bool] Si hubo al menos un error, devuelve false. - self.aasm.events.map(&:name).each do |event| + aasm.events.map(&:name).each do |event| define_singleton_method(:"#{event}_all!") do - success = true + successes = [] - self.find_each do |object| - object.public_send(:"#{event}!") if object.public_send(:"may_#{event}?") - rescue Exception => e - success = false - - notify_exception! e, object + find_each do |object| + successes << (object.public_send(:"may_#{event}?") && object.public_send(:"#{event}!")) end - success + successes.all? end # Ejecuta la transición del evento en la base de datos sin @@ -53,20 +49,13 @@ module AasmEventsConcern # # @return [Integer] Registros modificados define_singleton_method(:"#{event}_all_without_callbacks!") do - aasm_event = self.aasm.events.find { |e| e.name == event } + aasm_event = aasm.events.find { |e| e.name == event } to_state = aasm_event.transitions.map(&:to).first from_states = aasm_event.transitions.map(&:from) - self.unscope(where: :aasm_state).where(aasm_state: from_states).update_all(aasm_state: to_state, updated_at: Time.now) + unscope(where: :aasm_state).where(aasm_state: from_states).update_all(aasm_state: to_state, + updated_at: Time.now) end end - - # Envía notificación de errores - # - # @param exception [Exception] - # @param record [ApplicationRecord] - def self.notify_exception!(exception, record) - ExceptionNotifier.notify_exception(exception, data: { record_type: record.class.name, record_id: record.id }) - end end end diff --git a/app/models/fediblock_state.rb b/app/models/fediblock_state.rb index 9dde1db3..a6faa14f 100644 --- a/app/models/fediblock_state.rb +++ b/app/models/fediblock_state.rb @@ -20,20 +20,15 @@ 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 - state :enabled + state :disabled, initial: true, before_enter: :disable_remotely_and_pause_instances! + state :enabled, before_enter: :enable_remotely_and_block_instances! + + error_on_all_events do |e| + ExceptionNotifier.notify_exception(e, data: { site: site.name, fediblock: id }) + end event :enable do transitions from: :disabled, to: :enabled - - before do - # 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) - end end # Al deshabilitar, las listas pasan a modo pausa, a menos que estén @@ -44,22 +39,31 @@ class FediblockState < ApplicationRecord # de list_names event :disable do transitions from: :enabled, to: :disabled - - before do - # 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. - instance_ids = ActivityPub::Instance.where(hostname: unique_hostnames).ids - site.instance_moderations.where(instance_id: instance_ids).pause_all_without_callbacks! - end 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) + 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. + instance_ids = ActivityPub::Instance.where(hostname: unique_hostnames).ids + site.instance_moderations.where(instance_id: instance_ids).pause_all_without_callbacks! + end + # Devuelve los hostnames únicos a esta instancia. # # @return [Array] diff --git a/app/models/instance_moderation.rb b/app/models/instance_moderation.rb index 9cb6ffdc..7c76262e 100644 --- a/app/models/instance_moderation.rb +++ b/app/models/instance_moderation.rb @@ -2,8 +2,8 @@ # Mantiene el registro de relaciones entre sitios e instancias class InstanceModeration < ApplicationRecord - IGNORED_EVENTS = [] - IGNORED_STATES = [] + IGNORED_EVENTS = [].freeze + IGNORED_STATES = [].freeze include AASM @@ -11,38 +11,30 @@ class InstanceModeration < ApplicationRecord belongs_to :instance, class_name: 'ActivityPub::Instance' aasm do - state :paused, initial: true - state :allowed - state :blocked + state :paused, initial: true, before_enter: :pause_remotely! + state :allowed, before_enter: :allow_remotely! + state :blocked, before_enter: :block_remotely! + + error_on_all_events do |e| + ExceptionNotifier.notify_exception(e, data: { site: site.name, instance: instance.hostname, instance_moderation: id }) + end # 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 - - before do - pause_remotely! - end end # Al permitir, solo bloqueamos la instancia, sin modificar el estado # de les actores y comentarios retroactivamente. event :allow do transitions from: %i[paused blocked], to: :allowed - - before do - allow_remotely! - end end # Al bloquear, solo bloqueamos la instancia, sin modificar el estado # de les actores y comentarios retroactivamente. event :block do transitions from: %i[paused allowed], to: :blocked - - before do - block_remotely! - end end end @@ -51,7 +43,7 @@ class InstanceModeration < ApplicationRecord # @return [Array] def actor_ids - ActivityPub::Actor.where(instance_id: self.instance_id).ids + ActivityPub::Actor.where(instance_id: instance_id).ids end # Elimina la instancia de todas las listas From f6b2895b58a0f9bf2cd8cc19e52f112afe01e9d4 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 16 Mar 2024 16:36:00 -0300 Subject: [PATCH 368/472] =?UTF-8?q?fix:=20aprobar=20las=20peticiones=20de?= =?UTF-8?q?=20seguimiento=20autom=C3=A1ticamente?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/activity_pub/activity/follow.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/models/activity_pub/activity/follow.rb b/app/models/activity_pub/activity/follow.rb index 37dc9d26..b4c34d7a 100644 --- a/app/models/activity_pub/activity/follow.rb +++ b/app/models/activity_pub/activity/follow.rb @@ -11,9 +11,7 @@ class ActivityPub class Follow < ActivityPub::Activity # Auto-aprobar la solicitud de seguimiento def update_activity_pub_state! - activity_pub.approve! - rescue Exception => e - ExceptionNotifier.notify_exception(e, data: { site: activity_pub.site.name, activity: self.id }) + activity_pub.approve! if activity_pub.may_approve? end end end From b972e53e4821c563eaebabb5e1cbcb899ea063f8 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 16 Mar 2024 17:53:29 -0300 Subject: [PATCH 369/472] =?UTF-8?q?feat:=20guardar=20la=20menci=C3=B3n=20d?= =?UTF-8?q?e=20le=20autore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/activity_pub/fetch_job.rb | 7 +++++- app/models/activity_pub/actor.rb | 9 ++++--- .../20240316203721_add_mention_to_actors.rb | 24 +++++++++++++++++++ 3 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20240316203721_add_mention_to_actors.rb diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index 129908d3..e9220bfc 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -29,8 +29,13 @@ class ActivityPub object.update(content: content, type: ActivityPub::Object.type_from(content).name) + return if current_type == object.type + + object = ::ActivityPub::Object.find(object_id) + object.actor.save if object.actor_type? + # Arreglar las relaciones con actividades también - ActivityPub.where(object_id: object.id).update_all(object_type: object.type) unless current_type == object.type + ActivityPub.where(object_id: object.id).update_all(object_type: object.type) rescue FastJsonparser::ParseError => e ExceptionNotifier.notify_exception(e, data: { site: site.name, body: response.body }) end diff --git a/app/models/activity_pub/actor.rb b/app/models/activity_pub/actor.rb index b03145e7..a8cc0d5d 100644 --- a/app/models/activity_pub/actor.rb +++ b/app/models/activity_pub/actor.rb @@ -18,19 +18,22 @@ class ActivityPub # Les actores son únicxs a toda la base de datos validates :uri, presence: true, url: true, uniqueness: true + before_save :mentionize! + # Obtiene el nombre de la Actor como mención, solo si obtuvimos el # contenido de antemano. # # @return [String, nil] - def mention + def mentionize! + return if mention.present? return if content['preferredUsername'].blank? return if instance.blank? - @mention ||= "@#{content['preferredUsername']}@#{instance.hostname}" + self.mention ||= "@#{content['preferredUsername']}@#{instance.hostname}" end def object - @object ||= ActivityPub::Object::Person.find_or_initialize_by(uri: uri) + @object ||= ActivityPub::Object.find_or_initialize_by(uri: uri) end def content diff --git a/db/migrate/20240316203721_add_mention_to_actors.rb b/db/migrate/20240316203721_add_mention_to_actors.rb new file mode 100644 index 00000000..caa4f526 --- /dev/null +++ b/db/migrate/20240316203721_add_mention_to_actors.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +# Guarda la mención en la tabla de actores +class AddMentionToActors < ActiveRecord::Migration[6.1] + def up + add_column :activity_pub_actors, :mention, :string, null: true + + actor_types = %w[ + ActivityPub::Object::Application + ActivityPub::Object::Group + ActivityPub::Object::Organization + ActivityPub::Object::Person + ActivityPub::Object::Service + ] + + ActivityPub::Object.where(type: actor_types).where.not(content: {}).find_each do |object| + ActivityPub::Actor.find_by_uri(object.uri)&.save + end + end + + def down + remove_column :activity_pub_actors, :mention + end +end From 769eae61574e859c0bfc6078785f7fb28ef6aadf Mon Sep 17 00:00:00 2001 From: f Date: Sat, 16 Mar 2024 19:05:12 -0300 Subject: [PATCH 370/472] feat: sincronizar en segundo plano --- .../actor_moderations_controller.rb | 2 +- .../activity_pub/instance_moderation_job.rb | 2 + app/jobs/activity_pub/sync_lists_job.rb | 70 +++++++++++++++++++ app/models/actor_moderation.rb | 33 +++------ app/models/fediblock_state.rb | 55 ++++----------- app/models/instance_moderation.rb | 42 ++--------- 6 files changed, 100 insertions(+), 104 deletions(-) create mode 100644 app/jobs/activity_pub/sync_lists_job.rb diff --git a/app/controllers/actor_moderations_controller.rb b/app/controllers/actor_moderations_controller.rb index cb7a63a9..cd81e441 100644 --- a/app/controllers/actor_moderations_controller.rb +++ b/app/controllers/actor_moderations_controller.rb @@ -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 diff --git a/app/jobs/activity_pub/instance_moderation_job.rb b/app/jobs/activity_pub/instance_moderation_job.rb index 214f8dd4..00100abf 100644 --- a/app/jobs/activity_pub/instance_moderation_job.rb +++ b/app/jobs/activity_pub/instance_moderation_job.rb @@ -30,6 +30,8 @@ class ActivityPub else scope.block_all_without_callbacks! end + + ActivityPub::SyncListsJob.perform_later(site: site) end end end diff --git a/app/jobs/activity_pub/sync_lists_job.rb b/app/jobs/activity_pub/sync_lists_job.rb new file mode 100644 index 00000000..39f6bdc9 --- /dev/null +++ b/app/jobs/activity_pub/sync_lists_job.rb @@ -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] + # @return [Array] + def wildcardize(hostnames) + hostnames.map do |hostname| + "@*@#{hostname}" + end + end + end +end diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index c566b844..18149be4 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -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 diff --git a/app/models/fediblock_state.rb b/app/models/fediblock_state.rb index a6faa14f..82912f76 100644 --- a/app/models/fediblock_state.rb +++ b/app/models/fediblock_state.rb @@ -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] @@ -82,30 +77,4 @@ class FediblockState < ApplicationRecord fediblock.hostnames - other_enabled_hostnames end end - - # @param hostnames [Array] - # @return [Array] - 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] - 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] - def enable_remotely!(list) - raise unless - site.social_inbox.blocklist.post(list: list).ok? && - site.social_inbox.allowlist.delete(list: list).ok? - end end diff --git a/app/models/instance_moderation.rb b/app/models/instance_moderation.rb index 7c76262e..5a1a5ed6 100644 --- a/app/models/instance_moderation.rb +++ b/app/models/instance_moderation.rb @@ -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] - 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 From a65a9f2f504969755529bd51efc03934c4c51a81 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 16 Mar 2024 19:16:30 -0300 Subject: [PATCH 371/472] feat: aprobar o rechazar en segundo plano --- app/jobs/activity_pub/inbox_job.rb | 16 ++++++++++++++++ app/models/activity_pub.rb | 23 ++++++++++------------- 2 files changed, 26 insertions(+), 13 deletions(-) create mode 100644 app/jobs/activity_pub/inbox_job.rb diff --git a/app/jobs/activity_pub/inbox_job.rb b/app/jobs/activity_pub/inbox_job.rb new file mode 100644 index 00000000..93216d44 --- /dev/null +++ b/app/jobs/activity_pub/inbox_job.rb @@ -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 diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 8142ecfb..55b48cd7 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -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 From e8ce721af02e4aade19dc92a2047def267fcb4fe Mon Sep 17 00:00:00 2001 From: f Date: Sat, 16 Mar 2024 19:20:32 -0300 Subject: [PATCH 372/472] =?UTF-8?q?fix:=20traducci=C3=B3n=20faltante?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/locales/es.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/es.yml b/config/locales/es.yml index 7f71781c..39d35afe 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -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 From 883da8d881fc1480cc40370ffdcedf9e6556bdf4 Mon Sep 17 00:00:00 2001 From: f Date: Sun, 17 Mar 2024 12:06:55 -0300 Subject: [PATCH 373/472] =?UTF-8?q?fix:=20quiz=C3=A1s=20no=20hay=20actor?= =?UTF-8?q?=20aun=20(=3F)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/activity_pub/fetch_job.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index e9220bfc..42b2cb27 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -9,6 +9,8 @@ # autenticación. class ActivityPub class FetchJob < ApplicationJob + include Que::Unique + self.priority = 50 def perform(site:, object_id:) @@ -32,7 +34,7 @@ class ActivityPub return if current_type == object.type object = ::ActivityPub::Object.find(object_id) - object.actor.save if object.actor_type? + object.actor&.save if object.actor_type? # Arreglar las relaciones con actividades también ActivityPub.where(object_id: object.id).update_all(object_type: object.type) From bdb5175fcd96c02816bee1be498ccdd80d733486 Mon Sep 17 00:00:00 2001 From: f Date: Sun, 17 Mar 2024 12:10:07 -0300 Subject: [PATCH 374/472] =?UTF-8?q?fixup!=20fix:=20quiz=C3=A1s=20no=20hay?= =?UTF-8?q?=20actor=20aun=20(=3F)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/activity_pub/fetch_job.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index 42b2cb27..bdb98e66 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -9,8 +9,6 @@ # autenticación. class ActivityPub class FetchJob < ApplicationJob - include Que::Unique - self.priority = 50 def perform(site:, object_id:) From 1623d618ee8743ada8d91d6c2ba2a670d20a5b53 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 18 Mar 2024 11:21:13 -0300 Subject: [PATCH 375/472] fix: mostrar link externo al comentario #15638 --- app/models/activity_pub.rb | 36 ++++++++++++++++++++++++ app/views/moderation_queue/_comment.haml | 7 +++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 55b48cd7..913ac67d 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -43,6 +43,42 @@ class ActivityPub < ApplicationRecord end end + # Obtiene el campo `url` de diversas formas. Si es una String, asumir + # que es una URL, si es un Hash, asumir que es un Link, si es un + # Array de Strings, obtener la primera, si es de Hash, obtener el + # primer link con rel=canonical y mediaType=text/html + # + # De lo contrario devolver el ID. + # + # @todo Refactorizar + # @param object [Hash] + # @return [String] + def self.url_from_object(object) + raise unless object.respond_to?(:[]) + + url = + case object['url'] + when String then object['url'] + when Hash then object['href'] + # Esto es un lío porque queremos saber si es un Array o + # Array o mezcla y obtener el que más nos convenga o + # adivinar uno. + when Array + links = object['url'].map.with_index do |link, i| + case link + when Hash then link + else { 'href' => link.to_s } + end + end + + links.find do |link| + link['rel'] == 'canonical' && link['mediaType'] == 'text/html' + end&.[]('href') || links.first&.[]('href') + end + + url || object['id'] + end + aasm do # Todavía no hay una decisión sobre el objeto state :paused, initial: true diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index c6f6fd5c..787ae7c2 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -8,6 +8,8 @@ - in_reply_to = text_plain comment['inReplyTo'] - summary = text_plain comment['summary'] +-# @todo Generar un desplegable con todas las opciones +- url = text_plain ActivityPub.url_from_object(comment) .row.no-gutters .col-1 @@ -17,8 +19,9 @@ .d-flex.flex-row.align-items-center.justify-content-between %h4.mb-0 %a{ href: text_plain(comment['attributedTo']) }= text_plain profile['preferredUsername'] - %small - = render 'layouts/time', time: text_plain(comment['published']) + %a{ href: url } + %small + = render 'layouts/time', time: text_plain(comment['published']) - if in_reply_to.present? %dl %dt.d-inline From 7b87aaa93daf1d58a0b97ab89573043d239c4035 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 18 Mar 2024 11:55:38 -0300 Subject: [PATCH 376/472] feat: referenciar objetos #15642 --- app/models/activity_pub/object.rb | 9 +++++++++ app/views/moderation_queue/_comment.haml | 9 +++++++++ app/views/moderation_queue/_comments.haml | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/app/models/activity_pub/object.rb b/app/models/activity_pub/object.rb index 9061c4c5..1d5d4478 100644 --- a/app/models/activity_pub/object.rb +++ b/app/models/activity_pub/object.rb @@ -29,5 +29,14 @@ class ActivityPub def object_type? true end + + # Poder explorar propiedades remotas + # + # @return [DistributedPress::V1::Social::ReferencedObject] + def referenced(site) + require 'distributed_press/v1/social/referenced_object' + + @referenced ||= DistributedPress::V1::Social::ReferencedObject.new(object: content, dereferencer: site.social_inbox.dereferencer) + end end end diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 787ae7c2..10f09106 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -1,12 +1,21 @@ -# Componente Comentario + @param site [Site] @param form [String] @param profile [Hash] @param comment [Hash] @param activity_pub [ActivityPub] - in_reply_to = text_plain comment['inReplyTo'] +:ruby + begin + if in_reply_to && (remote_object = object.referenced(site)['inReplyTo']) + in_reply_to = ActivityPub.url_from_object(remote_object) + end + rescue Exception => e + ExceptionNotifier.notify_exception(e, data: { site: site.name, object: comment }) + end - summary = text_plain comment['summary'] -# @todo Generar un desplegable con todas las opciones - url = text_plain ActivityPub.url_from_object(comment) diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index 68671f9e..583ef511 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -13,4 +13,4 @@ %h4= t('moderation_queue.nothing') - moderation_queue.each do |activity_pub| %hr - = render 'moderation_queue/comment', comment: activity_pub.object.content, profile: activity_pub.actor.content, activity_pub: activity_pub, form: form_id + = render 'moderation_queue/comment', comment: activity_pub.object.content, profile: activity_pub.actor.content, activity_pub: activity_pub, form: form_id, site: site, object: activity_pub.object From 9dc0ed7684ac56c456283baaabc678358abcda67 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 18 Mar 2024 12:48:09 -0300 Subject: [PATCH 377/472] fix: reusar el reporto remoto #15648 --- app/controllers/concerns/moderation_concern.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/controllers/concerns/moderation_concern.rb b/app/controllers/concerns/moderation_concern.rb index 3b9d818f..8340ec2a 100644 --- a/app/controllers/concerns/moderation_concern.rb +++ b/app/controllers/concerns/moderation_concern.rb @@ -16,7 +16,9 @@ module ModerationConcern end def remote_flag_params(model) - { remote_flag_attributes: { id: model.remote_flag_id, message: ''.dup } }.tap do |p| + remote_flag = ActivityPub::RemoteFlag.find_by(actor_id: model.actor_id) + + { remote_flag_attributes: { id: remote_flag&.id, message: ''.dup } }.tap do |p| p[:remote_flag_attributes][:site_id] = model.site_id p[:remote_flag_attributes][:actor_id] = model.actor_id From bcfb7a5a7ffb3deec681767c54923244c47da0f9 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 18 Mar 2024 12:55:27 -0300 Subject: [PATCH 378/472] fix: asignar la remote flag #15648 --- app/controllers/activity_pubs_controller.rb | 7 ++++++- app/controllers/actor_moderations_controller.rb | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/controllers/activity_pubs_controller.rb b/app/controllers/activity_pubs_controller.rb index 225311c2..d5041a84 100644 --- a/app/controllers/activity_pubs_controller.rb +++ b/app/controllers/activity_pubs_controller.rb @@ -8,7 +8,12 @@ class ActivityPubsController < ApplicationController define_method(event) do authorize activity_pub - activity_pub.update(remote_flag_params(activity_pub)) if event == :report + if event == :report + remote_flag_params(activity_pub).tap do |p| + activity_pub.remote_flag_id = p[:remote_flag_attributes][:id] + activity_pub.update(p) + end + end message = if activity_pub.public_send(:"may_#{event}?") && activity_pub.public_send(:"#{event}!") diff --git a/app/controllers/actor_moderations_controller.rb b/app/controllers/actor_moderations_controller.rb index cd81e441..70aaf992 100644 --- a/app/controllers/actor_moderations_controller.rb +++ b/app/controllers/actor_moderations_controller.rb @@ -15,7 +15,12 @@ class ActorModerationsController < ApplicationController authorize actor_moderation # Crea una RemoteFlag si se envían los parámetros adecuados - actor_moderation.update(remote_flag_params(actor_moderation)) if actor_event == :report + if actor_event == :report + remote_flag_params(actor_moderation).tap do |p| + actor_moderation.remote_flag_id = p[:remote_flag_attributes][:id] + actor_moderation.update(p) + end + end message = if actor_moderation.public_send(:"may_#{actor_event}?") && actor_moderation.public_send(:"#{actor_event}!") From ceeb0009ef2fcd1faa01d5e59f2f77c2a0f124cb Mon Sep 17 00:00:00 2001 From: f Date: Mon, 18 Mar 2024 14:40:11 -0300 Subject: [PATCH 379/472] fix: descubrir el tipo de objeto siempre closes #15656 closes #15657 closes #15658 closes #15660 closes #15661 closes #15662 closes #15663 closes #15664 closes #15665 closes #15666 closes #15667 closes #15668 closes #15669 closes #15670 closes #15671 closes #15672 closes #15673 closes #15674 closes #15675 closes #15676 closes #15677 closes #15678 closes #15679 closes #15680 closes #15681 closes #15682 closes #15683 closes #15684 closes #15685 closes #15686 closes #15687 closes #15688 closes #15689 closes #15690 closes #15691 closes #15692 closes #15693 closes #15694 closes #15695 closes #15696 closes #15697 closes #15698 closes #15699 closes #15700 closes #15701 closes #15702 closes #15704 closes #15705 closes #15706 closes #15707 closes #15708 --- app/jobs/activity_pub/process_job.rb | 13 +------------ app/models/activity_pub/object.rb | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/app/jobs/activity_pub/process_job.rb b/app/jobs/activity_pub/process_job.rb index 6554b44d..9b72be43 100644 --- a/app/jobs/activity_pub/process_job.rb +++ b/app/jobs/activity_pub/process_job.rb @@ -64,18 +64,7 @@ class ActivityPub # @return [ActivityPub::Object] def object @object ||= ::ActivityPub::Object.find_or_initialize_by(uri: object_uri).tap do |o| - # XXX: Si el objeto es una actividad, esto siempre va a ser - # Generic - o.type ||= 'ActivityPub::Object::Generic' - - if object_embedded? - o.content = original_object - begin - type = original_object[:type].presence - o.type = "ActivityPub::Object::#{type}".constantize if type - rescue NameError - end - end + o.content = original_object if object_embedded? o.save! diff --git a/app/models/activity_pub/object.rb b/app/models/activity_pub/object.rb index 1d5d4478..16cd6b01 100644 --- a/app/models/activity_pub/object.rb +++ b/app/models/activity_pub/object.rb @@ -5,6 +5,8 @@ class ActivityPub class Object < ApplicationRecord include ActivityPub::Concerns::JsonLdConcern + before_validation :type_from_content!, unless: :type? + # Los objetos son únicos a toda la base de datos validates :uri, presence: true, url: true, uniqueness: true @@ -38,5 +40,20 @@ class ActivityPub @referenced ||= DistributedPress::V1::Social::ReferencedObject.new(object: content, dereferencer: site.social_inbox.dereferencer) end + + private + + # Encuentra el tipo a partir del contenido, si existe. + # + # XXX: Si el objeto es una actividad, esto siempre va a ser + # Generic + def type_from_content! + self.type = + begin + "ActivityPub::Object::#{content['type'].presence || 'Generic'}".constantize + rescue NameError + ActivityPub::Object::Generic + end + end end end From e50ae70ebb7c254cc87769419a31b46582823c1e Mon Sep 17 00:00:00 2001 From: f Date: Mon, 18 Mar 2024 15:06:41 -0300 Subject: [PATCH 380/472] fix: no actualizar si el contenido estaba cacheado --- app/jobs/activity_pub/fetch_job.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index bdb98e66..78a6dbee 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -22,7 +22,9 @@ class ActivityPub # @todo Fallar cuando la respuesta no funcione? return unless response.ok? - return if response.miss? && object.content.present? + # Ignorar si ya la caché fue revalidada y ya teníamos el + # contenido + return if response.hit? && object.content.present? current_type = object.type content = FastJsonparser.parse(response.body) From e6d4b4d3f16ff9f114e04530c1104d28df0fc0e6 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 18 Mar 2024 15:10:16 -0300 Subject: [PATCH 381/472] fix: validar que el contenido del objeto sea el que queremos --- app/models/activity_pub/object.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/models/activity_pub/object.rb b/app/models/activity_pub/object.rb index 16cd6b01..d37c9b88 100644 --- a/app/models/activity_pub/object.rb +++ b/app/models/activity_pub/object.rb @@ -9,6 +9,7 @@ class ActivityPub # Los objetos son únicos a toda la base de datos validates :uri, presence: true, url: true, uniqueness: true + validate :uri_is_content_id?, if: :content? has_many :activity_pubs, as: :object @@ -43,6 +44,12 @@ class ActivityPub private + def uri_is_content_id? + return if self.uri == content['id'] + + errors.add(:activity_pub_objects, 'El ID del objeto no coincide con su URI') + end + # Encuentra el tipo a partir del contenido, si existe. # # XXX: Si el objeto es una actividad, esto siempre va a ser From 75b6314e1dfc70cf53e716914b211664ee3dd768 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 18 Mar 2024 15:46:03 -0300 Subject: [PATCH 382/472] =?UTF-8?q?fix:=20qu=C3=A9=20pasa=20con=20los=20ob?= =?UTF-8?q?jetos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/activity_pub/fetch_job.rb | 7 ++++--- .../20240318183846_fix_duplicate_objects.rb | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 db/migrate/20240318183846_fix_duplicate_objects.rb diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index 78a6dbee..f1a51e96 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -29,15 +29,16 @@ class ActivityPub current_type = object.type content = FastJsonparser.parse(response.body) - object.update(content: content, type: ActivityPub::Object.type_from(content).name) + object.update!(content: content, type: ActivityPub::Object.type_from(content).name) return if current_type == object.type object = ::ActivityPub::Object.find(object_id) - object.actor&.save if object.actor_type? + # Actualiza la mención + object.actor&.save! if object.actor_type? # Arreglar las relaciones con actividades también - ActivityPub.where(object_id: object.id).update_all(object_type: object.type) + ActivityPub.where(object_id: object.id).update_all(object_type: object.type, updated_at: Time.now) rescue FastJsonparser::ParseError => e ExceptionNotifier.notify_exception(e, data: { site: site.name, body: response.body }) end diff --git a/db/migrate/20240318183846_fix_duplicate_objects.rb b/db/migrate/20240318183846_fix_duplicate_objects.rb new file mode 100644 index 00000000..f863ba3e --- /dev/null +++ b/db/migrate/20240318183846_fix_duplicate_objects.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +# De alguna forma se guardaron objetos duplicados! +class FixDuplicateObjects < ActiveRecord::Migration[6.1] + def up + ActivityPub::Object.group(:uri).count.select { |_, v| v > 1 }.keys.each do |uri| + objects = ActivityPub::Object.where(uri: uri) + deleted_ids = objects[1..].map(&:delete).map(&:id) + + ActivityPub.where(object_id: deleted_ids).update_all(object_id: object.first.id, updated_at: Time.now) + end + end + + def down; end +end From bd0df0a53a5a0c18cd9bcfcd0e89c8ecf569d0a0 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 18 Mar 2024 15:47:38 -0300 Subject: [PATCH 383/472] =?UTF-8?q?fixup!=20fix:=20qu=C3=A9=20pasa=20con?= =?UTF-8?q?=20los=20objetos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/migrate/20240318183846_fix_duplicate_objects.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20240318183846_fix_duplicate_objects.rb b/db/migrate/20240318183846_fix_duplicate_objects.rb index f863ba3e..88d23c6f 100644 --- a/db/migrate/20240318183846_fix_duplicate_objects.rb +++ b/db/migrate/20240318183846_fix_duplicate_objects.rb @@ -7,7 +7,7 @@ class FixDuplicateObjects < ActiveRecord::Migration[6.1] objects = ActivityPub::Object.where(uri: uri) deleted_ids = objects[1..].map(&:delete).map(&:id) - ActivityPub.where(object_id: deleted_ids).update_all(object_id: object.first.id, updated_at: Time.now) + ActivityPub.where(object_id: deleted_ids).update_all(object_id: objects.first.id, updated_at: Time.now) end end From 376339aee50cd7e7353a2212c9aa8f4f68965581 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 18 Mar 2024 16:45:00 -0300 Subject: [PATCH 384/472] fix: correr las consultas de todas formas --- app/jobs/activity_pub/fetch_job.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index f1a51e96..4d4d4483 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -21,6 +21,7 @@ class ActivityPub response = site.social_inbox.dereferencer.get(uri: object.uri) # @todo Fallar cuando la respuesta no funcione? + # @todo Eliminar en 410 Gone return unless response.ok? # Ignorar si ya la caché fue revalidada y ya teníamos el # contenido @@ -31,8 +32,6 @@ class ActivityPub object.update!(content: content, type: ActivityPub::Object.type_from(content).name) - return if current_type == object.type - object = ::ActivityPub::Object.find(object_id) # Actualiza la mención object.actor&.save! if object.actor_type? From 8034d206121c6ef7e1aecca48f2174e075af6426 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 18 Mar 2024 16:55:20 -0300 Subject: [PATCH 385/472] fix: ignorar comentarios y cuentas sin contenido aun --- app/views/moderation_queue/_accounts.haml | 1 + app/views/moderation_queue/_comments.haml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/app/views/moderation_queue/_accounts.haml b/app/views/moderation_queue/_accounts.haml index d8d76f0d..257b0fbf 100644 --- a/app/views/moderation_queue/_accounts.haml +++ b/app/views/moderation_queue/_accounts.haml @@ -12,5 +12,6 @@ - if actor_moderations.count.zero? %h4= t('moderation_queue.nothing') - actor_moderations.find_each do |actor_moderation| + - next if actor_moderation.actor.content.empty? %hr = render 'account', actor_moderation: actor_moderation, profile: actor_moderation.actor.content, form: form_id diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml index 583ef511..a7523517 100644 --- a/app/views/moderation_queue/_comments.haml +++ b/app/views/moderation_queue/_comments.haml @@ -12,5 +12,7 @@ - if moderation_queue.count.zero? %h4= t('moderation_queue.nothing') - moderation_queue.each do |activity_pub| + - next if activity_pub.object.content.empty? + - next if activity_pub.actor.content.empty? %hr = render 'moderation_queue/comment', comment: activity_pub.object.content, profile: activity_pub.actor.content, activity_pub: activity_pub, form: form_id, site: site, object: activity_pub.object From ab43c84ab1b0287a49150b9ab5011f61b76fc151 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 18 Mar 2024 17:13:32 -0300 Subject: [PATCH 386/472] fix: indicar el filtro activo #15652 --- app/helpers/moderation_queue_helper.rb | 10 +++++++++- app/views/components/_comments_show_submenu.haml | 3 ++- app/views/components/_dropdown_item.haml | 3 ++- app/views/components/_instances_show_submenu.haml | 3 ++- app/views/components/_profiles_show_submenu.haml | 3 ++- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/app/helpers/moderation_queue_helper.rb b/app/helpers/moderation_queue_helper.rb index 3681bec3..c69364ae 100644 --- a/app/helpers/moderation_queue_helper.rb +++ b/app/helpers/moderation_queue_helper.rb @@ -2,6 +2,14 @@ module ModerationQueueHelper def filter_states(**args) - params.permit(:state, :actor_state, :activity_pub_state).merge(**args) + params.permit(:instance_state, :actor_state, :activity_pub_state).merge(**args) + end + + def active?(states, state_name, state) + if params[state_name].present? + params[state_name] == state.to_s + else + states.first == state + end end end diff --git a/app/views/components/_comments_show_submenu.haml b/app/views/components/_comments_show_submenu.haml index 60c02501..9964a62a 100644 --- a/app/views/components/_comments_show_submenu.haml +++ b/app/views/components/_comments_show_submenu.haml @@ -1,4 +1,5 @@ - ActivityPub.states.each do |state| = render 'components/dropdown_item', text: t(".submenu_#{state}", count: activity_pubs.unscope(where: :aasm_state).public_send(state).count), - path: filter_states(activity_pub_state: state) + path: filter_states(activity_pub_state: state), + class: ('active' if active?(ActivityPub.states, :activity_pub_state, state)) diff --git a/app/views/components/_dropdown_item.haml b/app/views/components/_dropdown_item.haml index e5b16950..a4d363a8 100644 --- a/app/views/components/_dropdown_item.haml +++ b/app/views/components/_dropdown_item.haml @@ -1,4 +1,5 @@ -# @param :text [String] Contenido del link @param :path [String,Hash] Link -= link_to text, path, class: 'dropdown-item', data: { target: 'dropdown.item' } +- local_assigns[:class] = "dropdown-item #{local_assigns[:class]}" += link_to text, path, class: local_assigns[:class], data: { target: 'dropdown.item' } diff --git a/app/views/components/_instances_show_submenu.haml b/app/views/components/_instances_show_submenu.haml index c56df547..6b9b747e 100644 --- a/app/views/components/_instances_show_submenu.haml +++ b/app/views/components/_instances_show_submenu.haml @@ -1,4 +1,5 @@ - InstanceModeration.states.each do |state| = render 'components/dropdown_item', text: t(".submenu_#{state}", count: instance_moderations.unscope(where: :aasm_state).public_send(state).count), - path: filter_states(instance_state: state) + path: filter_states(instance_state: state), + class: ('active' if active?(InstanceModeration.states, :instance_state, state)) diff --git a/app/views/components/_profiles_show_submenu.haml b/app/views/components/_profiles_show_submenu.haml index 99694698..bebfbe20 100644 --- a/app/views/components/_profiles_show_submenu.haml +++ b/app/views/components/_profiles_show_submenu.haml @@ -1,4 +1,5 @@ - ActorModeration.states.each do |actor_state| = render 'components/dropdown_item', text: t(".submenu_#{actor_state}", count: actor_moderations.unscope(where: :aasm_state).public_send(actor_state).count), - path: filter_states(actor_state: actor_state) + path: filter_states(actor_state: actor_state), + class: ('active' if active?(ActorModeration.states, :actor_state, actor_state)) From dae0346f0ddc3d15825f7d4232b16e9fe86f2c15 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 18 Mar 2024 17:28:49 -0300 Subject: [PATCH 387/472] fix: pasar el sitio como argumento --- app/views/actor_moderations/show.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/actor_moderations/show.haml b/app/views/actor_moderations/show.haml index 633c1be5..ca5764f4 100644 --- a/app/views/actor_moderations/show.haml +++ b/app/views/actor_moderations/show.haml @@ -5,4 +5,4 @@ .col-12.col-md-8 = render 'components/profiles_btn_box', actor_moderation: @actor_moderation .col-12.col-md-8 - = render 'moderation_queue/comments', moderation_queue: @moderation_queue + = render 'moderation_queue/comments', site: @site, moderation_queue: @moderation_queue From 7c9e9758c5fecd4deb09a08f337e95439e0469da Mon Sep 17 00:00:00 2001 From: f Date: Mon, 18 Mar 2024 17:51:29 -0300 Subject: [PATCH 388/472] =?UTF-8?q?fix:=20informar=20la=20uri=20que=20fall?= =?UTF-8?q?=C3=B3=20#15712?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/activity_pub/fetch_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index 4d4d4483..9d14307a 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -39,7 +39,7 @@ class ActivityPub # Arreglar las relaciones con actividades también ActivityPub.where(object_id: object.id).update_all(object_type: object.type, updated_at: Time.now) rescue FastJsonparser::ParseError => e - ExceptionNotifier.notify_exception(e, data: { site: site.name, body: response.body }) + ExceptionNotifier.notify_exception(e, data: { site: site.name, object: object.uri, body: response.body }) end end end From e2abe224d40f7572244f4969cedf3af1bd1a65df Mon Sep 17 00:00:00 2001 From: f Date: Mon, 18 Mar 2024 17:54:07 -0300 Subject: [PATCH 389/472] fix: fallbacks #15659 --- app/controllers/actor_moderations_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/actor_moderations_controller.rb b/app/controllers/actor_moderations_controller.rb index 70aaf992..739b1f46 100644 --- a/app/controllers/actor_moderations_controller.rb +++ b/app/controllers/actor_moderations_controller.rb @@ -44,7 +44,7 @@ class ActorModerationsController < ApplicationController @moderation_queue = rubanok_process(site.activity_pubs.where(actor_id: actor_moderation.actor_id), with: ActivityPubProcessor) - breadcrumb @remote_profile['name'], '' + breadcrumb @remote_profile['name'] || actor_moderation.actor.mention || actor_moderation.actor.uri, '' end def action_on_several From d13e56e692e65344b436d5585289b9268fe43669 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 18 Mar 2024 18:09:32 -0300 Subject: [PATCH 390/472] =?UTF-8?q?fix:=20descripci=C3=B3n=20para=20las=20?= =?UTF-8?q?listas=20de=20bloqueo=20#15643?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/locales/en.yml | 2 +- config/locales/es.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 6f76fe57..075b62ec 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -180,7 +180,7 @@ en: reply_to: Reply to instances: title: My block lists - description: Description + description: "Blocklists contain instances known for hosting hate speech, promote fascism, violence, sexual/gendered abuse and/or misinformation." custom_block: Custom block lists submit: Save block lists instance: diff --git a/config/locales/es.yml b/config/locales/es.yml index 39d35afe..2d4974b1 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -179,7 +179,7 @@ es: reply_to: En respuesta a instances: title: Mis listas de bloqueo - description: Descripción de listas de bloqueo + description: "Las listas de bloqueo contienen instancias conocidas por alojar discurso de odio, promover el fascismo, la violencia, abuso sexual y/o desinformación." custom_block: Lista personalizada de bloqueo submit: Guardar listas de bloqueo instance: From 979f3c1b3ac214856840a7bfa248603229dbdbfe Mon Sep 17 00:00:00 2001 From: f Date: Mon, 18 Mar 2024 18:12:02 -0300 Subject: [PATCH 391/472] fix: ayuda para la lista customizada #15643 --- app/views/moderation_queue/_block_instances_textarea.haml | 2 +- config/locales/en.yml | 3 +++ config/locales/es.yml | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/views/moderation_queue/_block_instances_textarea.haml b/app/views/moderation_queue/_block_instances_textarea.haml index 9729d4de..7daf0410 100644 --- a/app/views/moderation_queue/_block_instances_textarea.haml +++ b/app/views/moderation_queue/_block_instances_textarea.haml @@ -1,3 +1,3 @@ .form-group = label_tag 'custom_blocklist', t('moderation_queue.instances.custom_block') - = text_area_tag 'custom_blocklist', nil, class: 'form-control' + = text_area_tag 'custom_blocklist', nil, class: 'form-control', placeholder: t('moderation_queue.instances.custom_block_placeholder') diff --git a/config/locales/en.yml b/config/locales/en.yml index 075b62ec..35b857e6 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -182,6 +182,9 @@ en: title: My block lists description: "Blocklists contain instances known for hosting hate speech, promote fascism, violence, sexual/gendered abuse and/or misinformation." custom_block: Custom block lists + custom_block_placeholder: | + a.doma.in + per.li.ne submit: Save block lists instance: users: "Users:" diff --git a/config/locales/es.yml b/config/locales/es.yml index 2d4974b1..77e611ed 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -181,6 +181,9 @@ es: title: Mis listas de bloqueo description: "Las listas de bloqueo contienen instancias conocidas por alojar discurso de odio, promover el fascismo, la violencia, abuso sexual y/o desinformación." custom_block: Lista personalizada de bloqueo + custom_block_placeholder: | + un.domin.io + por.lin.ea submit: Guardar listas de bloqueo instance: users: "Usuaries:" From b90f8864461e3b2d8a5f725a0a81cd9f4cc858e7 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 19 Mar 2024 09:47:24 -0300 Subject: [PATCH 392/472] feat: fedipact --- app/models/activity_pub/fediblock.rb | 4 +-- ...240319124212_add_fedipact_to_fediblocks.rb | 25 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20240319124212_add_fedipact_to_fediblocks.rb diff --git a/app/models/activity_pub/fediblock.rb b/app/models/activity_pub/fediblock.rb index 4abcb80f..ec66c032 100644 --- a/app/models/activity_pub/fediblock.rb +++ b/app/models/activity_pub/fediblock.rb @@ -31,8 +31,8 @@ class ActivityPub class FediblockDownloadError < ::StandardError; end - validates_presence_of :title, :url, :download_url, :format - validates_inclusion_of :format, in: %w[mastodon fediblock] + validates_presence_of :title, :url, :format + validates_inclusion_of :format, in: %w[mastodon fediblock none] HOSTNAME_HEADERS = { 'mastodon' => '#domain', diff --git a/db/migrate/20240319124212_add_fedipact_to_fediblocks.rb b/db/migrate/20240319124212_add_fedipact_to_fediblocks.rb new file mode 100644 index 00000000..648f2ee7 --- /dev/null +++ b/db/migrate/20240319124212_add_fedipact_to_fediblocks.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +# Agrega threads.net a las listas de bloqueo +class AddFedipactToFediblocks < ActiveRecord::Migration[6.1] + def up + fedipact = + ActivityPub::Fediblock.create( + hostnames: %w[threads.net], + title: 'Fedipact', + url: 'https://fedipact.online/', + format: 'none' + ) + + DeploySocialDistributedPress.find_each do |deploy| + FediblockState.create(site: deploy.site, fediblock: fedipact, aasm_state: 'disabled').tap do |f| + f.enable! + end + end + end + + def down + fedipact = ActivityPub::Fediblock.find_by(url: 'https://fedipact.online/').delete + FediblockState.where(fediblock_id: fedipact.id).delete_all + end +end From c047858a6f418a7bbf42eb5d3730a5ed114916c1 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 19 Mar 2024 09:49:34 -0300 Subject: [PATCH 393/472] fixup! feat: fedipact --- db/migrate/20240319124212_add_fedipact_to_fediblocks.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/db/migrate/20240319124212_add_fedipact_to_fediblocks.rb b/db/migrate/20240319124212_add_fedipact_to_fediblocks.rb index 648f2ee7..d78439b2 100644 --- a/db/migrate/20240319124212_add_fedipact_to_fediblocks.rb +++ b/db/migrate/20240319124212_add_fedipact_to_fediblocks.rb @@ -3,6 +3,8 @@ # Agrega threads.net a las listas de bloqueo class AddFedipactToFediblocks < ActiveRecord::Migration[6.1] def up + change_column :activity_pub_fediblocks, :download_url, :string, null: true + fedipact = ActivityPub::Fediblock.create( hostnames: %w[threads.net], @@ -21,5 +23,6 @@ class AddFedipactToFediblocks < ActiveRecord::Migration[6.1] def down fedipact = ActivityPub::Fediblock.find_by(url: 'https://fedipact.online/').delete FediblockState.where(fediblock_id: fedipact.id).delete_all + change_column :activity_pub_fediblocks, :download_url, :string, null: false end end From 48d8d2d8d802b46318f6a36c6beb9a1955683fa5 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 19 Mar 2024 10:59:10 -0300 Subject: [PATCH 394/472] =?UTF-8?q?fix:=20la=20l=C3=B3gica=20estaba=20al?= =?UTF-8?q?=20rev=C3=A9s=20#15647?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/activity_pub/remote_flag_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/activity_pub/remote_flag_job.rb b/app/jobs/activity_pub/remote_flag_job.rb index 20833bd4..71751d39 100644 --- a/app/jobs/activity_pub/remote_flag_job.rb +++ b/app/jobs/activity_pub/remote_flag_job.rb @@ -13,7 +13,7 @@ class ActivityPub self.priority = 30 def perform(remote_flag:) - return if remote_flag.may_queue? + return unless remote_flag.may_queue? inbox = remote_flag.actor&.content&.[]('inbox') From 93ebb6431a211d75f462c86163ec9fbc5e9ea73d Mon Sep 17 00:00:00 2001 From: f Date: Tue, 19 Mar 2024 11:20:49 -0300 Subject: [PATCH 395/472] =?UTF-8?q?fix:=20buscar=20un=20c=C3=B3digo=20de?= =?UTF-8?q?=20respuesta=20general?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/activity_pub/actor_fetch_job.rb | 2 +- app/jobs/activity_pub/fetch_job.rb | 2 +- app/jobs/activity_pub/inbox_job.rb | 2 +- app/jobs/activity_pub/instance_fetch_job.rb | 2 +- app/jobs/activity_pub/remote_flag_job.rb | 2 +- app/jobs/activity_pub/sync_lists_job.rb | 2 +- app/models/activity_pub/fediblock.rb | 2 +- app/models/deploy_social_distributed_press.rb | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/jobs/activity_pub/actor_fetch_job.rb b/app/jobs/activity_pub/actor_fetch_job.rb index 1190e936..598ecd83 100644 --- a/app/jobs/activity_pub/actor_fetch_job.rb +++ b/app/jobs/activity_pub/actor_fetch_job.rb @@ -16,7 +16,7 @@ class ActivityPub response = site.social_inbox.dereferencer.get(uri: actor.uri) # @todo Fallar cuando la respuesta no funcione? - return unless response.ok? + return unless response.success? return if response.miss? && actor.content.present? actor.object.update(content: FastJsonparser.parse(response.body)) diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index 9d14307a..beb585ff 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -22,7 +22,7 @@ class ActivityPub # @todo Fallar cuando la respuesta no funcione? # @todo Eliminar en 410 Gone - return unless response.ok? + return unless response.success? # Ignorar si ya la caché fue revalidada y ya teníamos el # contenido return if response.hit? && object.content.present? diff --git a/app/jobs/activity_pub/inbox_job.rb b/app/jobs/activity_pub/inbox_job.rb index 93216d44..cb807704 100644 --- a/app/jobs/activity_pub/inbox_job.rb +++ b/app/jobs/activity_pub/inbox_job.rb @@ -10,7 +10,7 @@ class ActivityPub def perform(site:, activity:, action:) response = site.social_inbox.inbox.public_send(action, id: activity) - raise response.body unless response.ok? + raise response.body unless response.success? end end end diff --git a/app/jobs/activity_pub/instance_fetch_job.rb b/app/jobs/activity_pub/instance_fetch_job.rb index 9c562f7d..dc84caf2 100644 --- a/app/jobs/activity_pub/instance_fetch_job.rb +++ b/app/jobs/activity_pub/instance_fetch_job.rb @@ -15,7 +15,7 @@ class ActivityPub response = site.social_inbox.dereferencer.get(uri: uri) - next unless response.ok? + next unless response.success? # @todo Validate schema next unless response.parsed_response.is_a?(DistributedPress::V1::Social::ReferencedObject) diff --git a/app/jobs/activity_pub/remote_flag_job.rb b/app/jobs/activity_pub/remote_flag_job.rb index 71751d39..f586a92e 100644 --- a/app/jobs/activity_pub/remote_flag_job.rb +++ b/app/jobs/activity_pub/remote_flag_job.rb @@ -25,7 +25,7 @@ class ActivityPub client = remote_flag.main_site.social_inbox.client_for(uri.origin) response = client.post(endpoint: uri.path, body: remote_flag.content) - raise 'No se pudo enviar el reporte' unless response.ok? + raise 'No se pudo enviar el reporte' unless response.success? remote_flag.report! rescue Exception => e diff --git a/app/jobs/activity_pub/sync_lists_job.rb b/app/jobs/activity_pub/sync_lists_job.rb index 39f6bdc9..cc500bee 100644 --- a/app/jobs/activity_pub/sync_lists_job.rb +++ b/app/jobs/activity_pub/sync_lists_job.rb @@ -53,7 +53,7 @@ class ActivityPub def process(stage) response = yield - return if response.ok? + return if response.success? logs[stage] ||= [] logs[stage] << { body: response.body, code: response.code } diff --git a/app/models/activity_pub/fediblock.rb b/app/models/activity_pub/fediblock.rb index ec66c032..17897d79 100644 --- a/app/models/activity_pub/fediblock.rb +++ b/app/models/activity_pub/fediblock.rb @@ -52,7 +52,7 @@ class ActivityPub def process! response = client.get(download_url) - raise FediblockDownloadError unless response.ok? + raise FediblockDownloadError unless response.success? Fediblock.transaction do csv = response.parsed_response diff --git a/app/models/deploy_social_distributed_press.rb b/app/models/deploy_social_distributed_press.rb index c7a103a4..e7f97406 100644 --- a/app/models/deploy_social_distributed_press.rb +++ b/app/models/deploy_social_distributed_press.rb @@ -84,7 +84,7 @@ class DeploySocialDistributedPress < Deploy response = hook_client.put(event: event, hook: webhook) - raise ArgumentError, response.body unless response.ok? + raise ArgumentError, response.body unless response.success? rescue ArgumentError => e ExceptionNotifier.notify_exception(e, data: { site_id: site.name, usuarie_id: rol.usuarie_id }) end From 8d6d215e1af43cd2bc80f24f4aea5a5687f9d286 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 19 Mar 2024 11:21:03 -0300 Subject: [PATCH 396/472] =?UTF-8?q?fix:=20si=20falla=20el=20reporte=20marc?= =?UTF-8?q?arlo=20para=20reenv=C3=ADo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/activity_pub/remote_flag_job.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/jobs/activity_pub/remote_flag_job.rb b/app/jobs/activity_pub/remote_flag_job.rb index f586a92e..211f46fc 100644 --- a/app/jobs/activity_pub/remote_flag_job.rb +++ b/app/jobs/activity_pub/remote_flag_job.rb @@ -30,6 +30,7 @@ class ActivityPub remote_flag.report! rescue Exception => e ExceptionNotifier.notify_exception(e, data: { remote_flag: remote_flag.id, response: response.parsed_response }) + remote_flag.resend! raise end end From 0ed702992b509cbd6d435474db050228cb88354f Mon Sep 17 00:00:00 2001 From: f Date: Tue, 19 Mar 2024 12:39:41 -0300 Subject: [PATCH 397/472] fix: prevenir objetos multiplicados! parece que la forma en que estabamos creando indices unicos ya no funciona (??) asi que a veces estabamos creando objetos duplicados en threads. de paso actorfetchjob ya no es necesario. closes #15621 closes #15622 closes #15623 closes #15729 closes #15730 closes #15731 --- app/jobs/activity_pub/actor_fetch_job.rb | 26 ---------- app/jobs/activity_pub/fetch_job.rb | 2 +- app/jobs/activity_pub/process_job.rb | 17 +++---- app/models/activity_pub/actor.rb | 2 +- ...240319144735_add_missing_unique_indexes.rb | 48 +++++++++++++++++++ db/structure.sql | 28 +++++++++-- 6 files changed, 82 insertions(+), 41 deletions(-) delete mode 100644 app/jobs/activity_pub/actor_fetch_job.rb create mode 100644 db/migrate/20240319144735_add_missing_unique_indexes.rb diff --git a/app/jobs/activity_pub/actor_fetch_job.rb b/app/jobs/activity_pub/actor_fetch_job.rb deleted file mode 100644 index 598ecd83..00000000 --- a/app/jobs/activity_pub/actor_fetch_job.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -# Obtiene o actualiza el contenido de un objeto, usando las credenciales -# del sitio. -# -# XXX: Esto usa las credenciales del sitio para volver el objeto -# disponible para todo el CMS. Asumimos que el objeto devuelto es el -# mismo para todo el mundo y las credenciales solo son para -# autenticación. -class ActivityPub - class ActorFetchJob < ApplicationJob - self.priority = 50 - - def perform(site:, actor:) - ActivityPub::Actor.transaction do - response = site.social_inbox.dereferencer.get(uri: actor.uri) - - # @todo Fallar cuando la respuesta no funcione? - return unless response.success? - return if response.miss? && actor.content.present? - - actor.object.update(content: FastJsonparser.parse(response.body)) - end - end - end -end diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index beb585ff..e0033439 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -30,7 +30,7 @@ class ActivityPub current_type = object.type content = FastJsonparser.parse(response.body) - object.update!(content: content, type: ActivityPub::Object.type_from(content).name) + object.lock.update!(content: content, type: ActivityPub::Object.type_from(content).name) object = ::ActivityPub::Object.find(object_id) # Actualiza la mención diff --git a/app/jobs/activity_pub/process_job.rb b/app/jobs/activity_pub/process_job.rb index 9b72be43..4e278797 100644 --- a/app/jobs/activity_pub/process_job.rb +++ b/app/jobs/activity_pub/process_job.rb @@ -63,7 +63,7 @@ class ActivityPub # # @return [ActivityPub::Object] def object - @object ||= ::ActivityPub::Object.find_or_initialize_by(uri: object_uri).tap do |o| + @object ||= ::ActivityPub::Object.lock.find_or_initialize_by(uri: object_uri).tap do |o| o.content = original_object if object_embedded? o.save! @@ -80,8 +80,8 @@ class ActivityPub # # @return [ActivityPub] def activity_pub - @activity_pub ||= site.activity_pubs.find_or_create_by!(site: site, actor: actor, instance: instance, - object_id: object.id, object_type: object.type) + @activity_pub ||= site.activity_pubs.lock.find_or_create_by!(site: site, actor: actor, instance: instance, + object_id: object.id, object_type: object.type) end # Crea la actividad y la vincula con el estado @@ -91,6 +91,7 @@ class ActivityPub @activity ||= ::ActivityPub::Activity .type_from(original_activity) + .lock .find_or_initialize_by(uri: original_activity[:id], activity_pub: activity_pub, actor: actor).tap do |a| a.content = original_activity.dup a.content[:object] = object.uri @@ -103,20 +104,20 @@ class ActivityPub # # @return [Actor] def actor - @actor ||= ::ActivityPub::Actor.find_or_initialize_by(uri: original_activity[:actor]).tap do |a| + @actor ||= ::ActivityPub::Actor.lock.find_or_initialize_by(uri: original_activity[:actor]).tap do |a| unless a.instance - a.instance = ::ActivityPub::Instance.find_or_create_by(hostname: URI.parse(a.uri).hostname) + a.instance = ::ActivityPub::Instance.lock.find_or_create_by(hostname: URI.parse(a.uri).hostname) ::ActivityPub::InstanceFetchJob.perform_later(site: site, instance: a.instance) end - site.instance_moderations.find_or_create_by(instance: a.instance) + site.instance_moderations.lock.find_or_create_by(instance: a.instance) a.save! - site.actor_moderations.find_or_create_by(actor: a) + site.actor_moderations.lock.find_or_create_by(actor: a) - ::ActivityPub::ActorFetchJob.perform_later(site: site, actor: a) + ::ActivityPub::FetchJob.perform_later(site: site, actor: a.object) end end diff --git a/app/models/activity_pub/actor.rb b/app/models/activity_pub/actor.rb index a8cc0d5d..6a284025 100644 --- a/app/models/activity_pub/actor.rb +++ b/app/models/activity_pub/actor.rb @@ -33,7 +33,7 @@ class ActivityPub end def object - @object ||= ActivityPub::Object.find_or_initialize_by(uri: uri) + @object ||= ActivityPub::Object.lock.find_or_create_by(uri: uri) end def content diff --git a/db/migrate/20240319144735_add_missing_unique_indexes.rb b/db/migrate/20240319144735_add_missing_unique_indexes.rb new file mode 100644 index 00000000..7d18c8e8 --- /dev/null +++ b/db/migrate/20240319144735_add_missing_unique_indexes.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +# Parece que la sintaxis que veníamos usando para los índices únicos ya +# no es válida y por eso teníamos objetos duplicados. +class AddMissingUniqueIndexes < ActiveRecord::Migration[6.1] + def up + ActivityPub::Object.group(:uri).count.select { |_, v| v > 1 }.keys.each do |uri| + objects = ActivityPub::Object.where(uri: uri) + deleted_ids = objects[1..].map(&:delete).map(&:id) + + ActivityPub.where(object_id: deleted_ids).update_all(object_id: objects.first.id, updated_at: Time.now) + end + + ActivityPub::Actor.group(:uri).count.select { |_, v| v > 1 }.keys.each do |uri| + objects = ActivityPub::Actor.where(uri: uri) + deleted_ids = objects[1..].map(&:delete).map(&:id) + + ActivityPub.where(actor_id: deleted_ids).update_all(actor_id: objects.first.id, updated_at: Time.now) + ActorModeration.where(actor_id: deleted_ids).update_all(actor_id: objects.first.id, updated_at: Time.now) + ActivityPub::Activity.where(actor_id: deleted_ids).update_all(actor_id: objects.first.id, updated_at: Time.now) + ActivityPub::RemoteFlag.where(actor_id: deleted_ids).update_all(actor_id: objects.first.id, updated_at: Time.now) + end + + ActivityPub::Instance.group(:hostname).count.select { |_, v| v > 1 }.keys.each do |hostname| + objects = ActivityPub::Instance.where(hostname: hostname) + deleted_ids = objects[1..].map(&:delete).map(&:id) + + ActivityPub.where(instance_id: deleted_ids).update_all(instance_id: objects.first.id, updated_at: Time.now) + InstanceModeration.where(instance_id: deleted_ids).update_all(instance_id: objects.first.id, updated_at: Time.now) + ActivityPub::Actor.where(instance_id: deleted_ids).update_all(instance_id: objects.first.id, updated_at: Time.now) + end + + remove_index :activity_pub_instances, :hostname + remove_index :activity_pub_actors, :uri + add_index :activity_pub_instances, :hostname, unique: true + add_index :activity_pub_objects, :uri, unique: true + add_index :activity_pub_actors, :uri, unique: true + end + + def down + remove_index :activity_pub_instances, :hostname, unique: true + remove_index :activity_pub_objects, :uri, unique: true + remove_index :activity_pub_actors, :uri, unique: true + add_index :activity_pub_instances, :hostname + add_index :activity_pub_objects, :uri + add_index :activity_pub_actors, :uri + end +end diff --git a/db/structure.sql b/db/structure.sql index ed58ebec..21cf04d0 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -498,7 +498,8 @@ CREATE TABLE public.activity_pub_actors ( created_at timestamp(6) without time zone NOT NULL, updated_at timestamp(6) without time zone NOT NULL, instance_id uuid NOT NULL, - uri character varying NOT NULL + uri character varying NOT NULL, + mention character varying ); @@ -512,7 +513,7 @@ CREATE TABLE public.activity_pub_fediblocks ( updated_at timestamp(6) without time zone NOT NULL, title character varying NOT NULL, url character varying NOT NULL, - download_url character varying NOT NULL, + download_url character varying, format character varying NOT NULL, hostnames jsonb DEFAULT '[]'::jsonb ); @@ -557,6 +558,7 @@ CREATE TABLE public.activity_pub_remote_flags ( site_id bigint, actor_id uuid, message text, + content jsonb, aasm_state character varying DEFAULT 'waiting'::character varying NOT NULL ); @@ -2138,14 +2140,21 @@ CREATE INDEX index_activity_pub_actors_on_instance_id ON public.activity_pub_act -- Name: index_activity_pub_actors_on_uri; Type: INDEX; Schema: public; Owner: - -- -CREATE INDEX index_activity_pub_actors_on_uri ON public.activity_pub_actors USING btree (uri); +CREATE UNIQUE INDEX index_activity_pub_actors_on_uri ON public.activity_pub_actors USING btree (uri); -- -- Name: index_activity_pub_instances_on_hostname; Type: INDEX; Schema: public; Owner: - -- -CREATE INDEX index_activity_pub_instances_on_hostname ON public.activity_pub_instances USING btree (hostname); +CREATE UNIQUE INDEX index_activity_pub_instances_on_hostname ON public.activity_pub_instances USING btree (hostname); + + +-- +-- Name: index_activity_pub_objects_on_uri; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_activity_pub_objects_on_uri ON public.activity_pub_objects USING btree (uri); -- @@ -2701,6 +2710,15 @@ INSERT INTO "schema_migrations" (version) VALUES ('20240305164653'), ('20240305184854'), ('20240307201510'), -('20240307203039'); +('20240307203039'), +('20240313192134'), +('20240313204105'), +('20240314141536'), +('20240314153017'), +('20240314205923'), +('20240316203721'), +('20240318183846'), +('20240319124212'), +('20240319144735'); From 029d4e7c974914e9b17b871362be599440d1bc0b Mon Sep 17 00:00:00 2001 From: f Date: Tue, 19 Mar 2024 13:01:26 -0300 Subject: [PATCH 398/472] fix: object_id closes #15739 closes #15738 closes #15737 --- app/jobs/activity_pub/process_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/activity_pub/process_job.rb b/app/jobs/activity_pub/process_job.rb index 4e278797..f3aeebb4 100644 --- a/app/jobs/activity_pub/process_job.rb +++ b/app/jobs/activity_pub/process_job.rb @@ -117,7 +117,7 @@ class ActivityPub site.actor_moderations.lock.find_or_create_by(actor: a) - ::ActivityPub::FetchJob.perform_later(site: site, actor: a.object) + ::ActivityPub::FetchJob.perform_later(site: site, object_id: a.object.id) end end From d33e7b37a14c4636a2dab745d40831ffc091448a Mon Sep 17 00:00:00 2001 From: f Date: Tue, 19 Mar 2024 13:16:28 -0300 Subject: [PATCH 399/472] fix: lock closes #15740 closes #15741 closes #15742 closes #15743 closes #15744 closes #15745 closes #15746 closes #15747 closes #15748 closes #15749 closes #15750 closes #15751 closes #15752 closes #15753 closes #15754 closes #15755 closes #15756 closes #15757 closes #15758 closes #15759 --- app/jobs/activity_pub/fetch_job.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index e0033439..73fc1c9f 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -30,7 +30,9 @@ class ActivityPub current_type = object.type content = FastJsonparser.parse(response.body) - object.lock.update!(content: content, type: ActivityPub::Object.type_from(content).name) + object.with_lock do + object.update!(content: content, type: ActivityPub::Object.type_from(content).name) + end object = ::ActivityPub::Object.find(object_id) # Actualiza la mención From 1ef7996ce90eacea7448293e7f0a29192ee1f1b6 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 19 Mar 2024 13:21:41 -0300 Subject: [PATCH 400/472] fix: agrupar errores para que no nos inunden --- config/environments/production.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/environments/production.rb b/config/environments/production.rb index 5e089ff9..bc7cecd7 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -142,7 +142,7 @@ Rails.application.configure do } config.action_mailer.default_options = { from: ENV.fetch('DEFAULT_FROM', "noreply@sutty.nl") } - config.middleware.use ExceptionNotification::Rack, gitlab: {}, ignore_exceptions: ['DeployJob::DeployAlreadyRunningException'] + config.middleware.use ExceptionNotification::Rack, gitlab: {}, error_grouping: true, ignore_exceptions: ['DeployJob::DeployAlreadyRunningException'] Rails.application.routes.default_url_options[:host] = "panel.#{ENV.fetch('SUTTY', 'sutty.nl')}" Rails.application.routes.default_url_options[:protocol] = 'https' From eafa6fad37cdb15a973f8fc0f3751044c2bab9cc Mon Sep 17 00:00:00 2001 From: f Date: Tue, 19 Mar 2024 17:02:19 -0300 Subject: [PATCH 401/472] fix: cargar el objeto por id y modificarlo closes #15775 closes #15773 closes #15772 closes #15771 closes #15770 closes #15767 closes #15766 closes #15765 closes #15764 --- app/jobs/activity_pub/fetch_job.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index 73fc1c9f..b19d5e41 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -30,9 +30,8 @@ class ActivityPub current_type = object.type content = FastJsonparser.parse(response.body) - object.with_lock do - object.update!(content: content, type: ActivityPub::Object.type_from(content).name) - end + # Modificar atómicamente + ::ActivityPub::Object.lock.find(object_id).update!(content: content, type: ActivityPub::Object.type_from(content).name) object = ::ActivityPub::Object.find(object_id) # Actualiza la mención From 28053b2a5676427deed9097717b69ed7bbd7f682 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 20 Mar 2024 16:18:01 -0300 Subject: [PATCH 402/472] =?UTF-8?q?fix:=20las=20cuentas=20reportadas=20tam?= =?UTF-8?q?bi=C3=A9n=20est=C3=A1n=20bloqueadas=20#15649?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/activity_pub/sync_lists_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/activity_pub/sync_lists_job.rb b/app/jobs/activity_pub/sync_lists_job.rb index cc500bee..de71fe64 100644 --- a/app/jobs/activity_pub/sync_lists_job.rb +++ b/app/jobs/activity_pub/sync_lists_job.rb @@ -18,7 +18,7 @@ class ActivityPub 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 + blocklist = wildcardize(instance_scope.blocked.pluck(:hostname)) + actor_scope.blocked.distinct.pluck(:mention).compact + actor_scope.reported.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 From 0a1b86c11195af3a5ecaa2002173caa95bd0954e Mon Sep 17 00:00:00 2001 From: f Date: Wed, 20 Mar 2024 17:49:09 -0300 Subject: [PATCH 403/472] fix: se pueden rechazar comentarios luego de aprobarlos #15600 --- app/models/activity_pub.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 913ac67d..335121d2 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -128,7 +128,7 @@ class ActivityPub < ApplicationRecord # La actividad fue rechazada event :reject do - transitions from: %i[paused], to: :rejected + transitions from: %i[paused approved], to: :rejected after do ActivityPub::InboxJob.perform_later(site: site, activity: activities.first.uri, action: :reject) From 0578b03ee76f8094c1b7a9fa6ee4fbb491b2503c Mon Sep 17 00:00:00 2001 From: f Date: Wed, 20 Mar 2024 17:50:39 -0300 Subject: [PATCH 404/472] fix: reportar implicar bloquear #15600 --- app/models/activity_pub.rb | 5 +++-- app/models/actor_moderation.rb | 2 +- config/locales/en.yml | 4 ++-- config/locales/es.yml | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index 335121d2..cd893406 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -135,11 +135,12 @@ class ActivityPub < ApplicationRecord end end - # Solo podemos reportarla luego de rechazarla + # Reportarla implica rechazarla event :report do - transitions from: :rejected, to: :reported + transitions from: %i[paused approved rejected], to: :reported after do + ActivityPub::InboxJob.perform_later(site: site, activity: activities.first.uri, action: :reject) ActivityPub::RemoteFlagJob.perform_later(remote_flag: remote_flag) if remote_flag.waiting? end end diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index 18149be4..1c3cf83a 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -43,7 +43,7 @@ class ActorModeration < ApplicationRecord # Al reportar, necesitamos asociar una RemoteFlag para poder # enviarla. event :report do - transitions from: %i[blocked], to: :reported + transitions from: %i[pause allowed blocked], to: :reported, after: :synchronize! after do ActivityPub::RemoteFlagJob.perform_later(remote_flag: remote_flag) if remote_flag.waiting? diff --git a/config/locales/en.yml b/config/locales/en.yml index 35b857e6..643effaf 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -106,7 +106,7 @@ en: text_reject: Reject text_reply: Reply text_report: Report - confirm_report: "Send report to the remote instance?" + confirm_report: "Send report to the remote instance? This action will also reject the comment." instances_btn_box: text_pause: Check case by case text_allow: Allow everything @@ -116,7 +116,7 @@ en: text_allow: Always approve text_block: Block text_report: Report - confirm_report: "Send report to the remote instance?" + confirm_report: "Send report to the remote instance? This action will also block the account." remote_flags: report_message: "Hi! Someone using Sutty CMS reported this account on your instance. We don't have support for customized report messages yet, but we will soon. You can reach us at %{panel_actor_mention}." activity_pubs: diff --git a/config/locales/es.yml b/config/locales/es.yml index 77e611ed..b8bfc524 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -105,7 +105,7 @@ es: text_approve: Aceptar text_reject: Rechazar text_report: Reportar - confirm_report: "¿Enviar el reporte a la instancia remota?" + confirm_report: "¿Enviar el reporte a la instancia remota? Esta acción también rechazará el comentario." instances_btn_box: text_pause: Moderar caso por caso text_allow: Permitir todo @@ -115,7 +115,7 @@ es: text_allow: Aprobar siempre text_block: Bloquear text_report: Reportar - confirm_report: "¿Enviar el reporte a la instancia remota?" + confirm_report: "¿Enviar el reporte a la instancia remota? Esta acción también bloqueará la cuenta." remote_flags: report_message: "¡Hola! Une usuarie de Sutty CMS reportó esta cuenta en tu instancia. Todavía no tenemos soporte para mensajes personalizados. Podés contactarnos en %{panel_actor_mention}." activity_pubs: From e2fdce91f3b2cbfa110559ac2e0b01ef0333ab21 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 20 Mar 2024 17:51:23 -0300 Subject: [PATCH 405/472] fix: agrupar espacialmente acciones #15600 --- app/views/components/_comments_filters.haml | 2 +- app/views/components/_instances_filters.haml | 2 +- app/views/components/_profiles_filters.haml | 2 +- app/views/moderation_queue/_comment.haml | 2 +- config/locales/en.yml | 6 +++--- config/locales/es.yml | 6 +++--- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/views/components/_comments_filters.haml b/app/views/components/_comments_filters.haml index cf8c1aa2..b2870c5a 100644 --- a/app/views/components/_comments_filters.haml +++ b/app/views/components/_comments_filters.haml @@ -3,7 +3,7 @@ - current_state = params[:activity_pub_state]&.to_sym || ActivityPub.states.first -.d-flex.py-2 +.d-flex.flex-row.justify-content-between.py-2 - if ActivityPub.transitionable_events(current_state).present? = render 'components/dropdown', text: t('.text_checked') do = render 'components/comments_checked_submenu', form: form diff --git a/app/views/components/_instances_filters.haml b/app/views/components/_instances_filters.haml index 730184bd..f2296c7b 100644 --- a/app/views/components/_instances_filters.haml +++ b/app/views/components/_instances_filters.haml @@ -3,7 +3,7 @@ - current_state = params[:state]&.to_sym || InstanceModeration.states.first -.d-flex.py-2 +.d-flex.flex-row.justify-content-between.py-2 - if InstanceModeration.transitionable_events(current_state).present? = render 'components/dropdown', text: t('.text_checked') do = render 'components/instances_checked_submenu', form: form, current_state: current_state diff --git a/app/views/components/_profiles_filters.haml b/app/views/components/_profiles_filters.haml index 3f830ec8..c2670944 100644 --- a/app/views/components/_profiles_filters.haml +++ b/app/views/components/_profiles_filters.haml @@ -3,7 +3,7 @@ - current_state = params[:actor_state]&.to_sym || ActorModeration.states.first -.d-flex.py-2 +.d-flex.flex-row.justify-content-between.py-2 - if ActorModeration.transitionable_events(current_state).present? = render 'components/dropdown', text: t('.text_checked') do = render 'components/profiles_checked_submenu', form: form, current_state: current_state diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml index 10f09106..a80bd27c 100644 --- a/app/views/moderation_queue/_comment.haml +++ b/app/views/moderation_queue/_comment.haml @@ -38,7 +38,7 @@ %dd.d-inline %small %a{ href: in_reply_to }= in_reply_to - .content + .content.mb-3 - if summary.present? = render 'layouts/details', summary: summary, summary_class: 'h5' do = sanitize comment['content'] diff --git a/config/locales/en.yml b/config/locales/en.yml index 643effaf..8059b6db 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -63,7 +63,7 @@ en: instances_blocked: Instances blocked instances_filters: text_show: Show - text_checked: With selected + text_checked: With selected... instances_checked_submenu: submenu_pause: Moderate submenu_allow: Allow @@ -74,7 +74,7 @@ en: submenu_blocked: "Blocked (%{count})" comments_filters: text_show: Show - text_checked: With selected + text_checked: With selected... comments_checked_submenu: submenu_pause: Pause submenu_approve: Approve @@ -87,7 +87,7 @@ en: submenu_reported: "Reported (%{count})" profiles_filters: text_show: Show - text_checked: With selected + text_checked: With selected... profiles_checked_submenu: submenu_pause: Pause submenu_allow: Allow diff --git a/config/locales/es.yml b/config/locales/es.yml index b8bfc524..06b933bc 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -63,7 +63,7 @@ es: instances_blocked: Instancias bloqueadas instances_filters: text_show: Ver - text_checked: Con los marcados + text_checked: Con los marcados... instances_checked_submenu: submenu_pause: Moderar caso por caso submenu_allow: Permitir todo @@ -74,7 +74,7 @@ es: submenu_blocked: "Bloqueadas (%{count})" comments_filters: text_show: Ver - text_checked: Con los marcados + text_checked: Con los marcados... comments_checked_submenu: submenu_pause: Pausar submenu_approve: Aprobar @@ -87,7 +87,7 @@ es: submenu_reported: "Reportados (%{count})" profiles_filters: text_show: Ver - text_checked: Con los marcados + text_checked: Con los marcados... profiles_checked_submenu: submenu_pause: Pausar submenu_allow: Aceptar From eda075fd4b889707328c2c62bcc6ac47984944ee Mon Sep 17 00:00:00 2001 From: f Date: Wed, 20 Mar 2024 17:52:31 -0300 Subject: [PATCH 406/472] =?UTF-8?q?fix:=20la=20acci=C3=B3n=20no=20se=20pue?= =?UTF-8?q?de=20hacer=20porque=20es=20el=20estado=20actual=20#15600?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/components/_btn_base.haml | 1 - app/views/components/_comments_btn_box.haml | 4 +++- app/views/components/_instances_btn_box.haml | 5 +++-- app/views/components/_profiles_btn_box.haml | 5 +++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/app/views/components/_btn_base.haml b/app/views/components/_btn_base.haml index faa5c85f..fed3254c 100644 --- a/app/views/components/_btn_base.haml +++ b/app/views/components/_btn_base.haml @@ -1,7 +1,6 @@ -# Componente Botón general Moderación - local_assigns[:method] ||= 'patch' -- local_assigns[:class] ||= 'btn-secondary' - local_assigns[:class] = "btn #{local_assigns[:class]}" - local_assigns.delete(:text) diff --git a/app/views/components/_comments_btn_box.haml b/app/views/components/_comments_btn_box.haml index 1993e5cb..ffc773a7 100644 --- a/app/views/components/_comments_btn_box.haml +++ b/app/views/components/_comments_btn_box.haml @@ -4,8 +4,10 @@ .d-flex.flex-row - ActivityPub.events.each do |event| + - possible = activity_pub.public_send(:"may_#{event}?") = render 'components/btn_base', text: t(".text_#{event}"), path: public_send(:"site_activity_pub_#{event}_path", activity_pub_id: activity_pub), - disabled: !activity_pub.public_send(:"may_#{event}?"), + class: ('btn-secondary' if possible), + disabled: !possible, data: local_data[event] diff --git a/app/views/components/_instances_btn_box.haml b/app/views/components/_instances_btn_box.haml index 15c6c040..8c3a5f88 100644 --- a/app/views/components/_instances_btn_box.haml +++ b/app/views/components/_instances_btn_box.haml @@ -2,9 +2,10 @@ - local_data = {} - InstanceModeration.events.each do |event| + - possible = instance_moderation.public_send(:"may_#{event}?") = render 'components/btn_base', path: public_send(:"site_instance_moderation_#{event}_path", instance_moderation_id: instance_moderation), text: t(".text_#{event}"), - class: 'btn btn-secondary', - disabled: !instance_moderation.public_send(:"may_#{event}?"), + class: ('btn-secondary' if possible), + disabled: !possible, data: local_data[event] diff --git a/app/views/components/_profiles_btn_box.haml b/app/views/components/_profiles_btn_box.haml index 488373b9..9414c178 100644 --- a/app/views/components/_profiles_btn_box.haml +++ b/app/views/components/_profiles_btn_box.haml @@ -2,9 +2,10 @@ .d-flex.flex-row - local_data = { report: { confirm: t('.confirm_report') } } - ActorModeration.events.each do |actor_event| + - possible = !actor_moderation.public_send(:"may_#{actor_event}?") = render 'components/btn_base', text: t(".text_#{actor_event}"), path: public_send(:"site_actor_moderation_#{actor_event}_path", actor_moderation_id: actor_moderation), - class: 'btn-secondary', - disabled: !actor_moderation.public_send(:"may_#{actor_event}?"), + class: ('btn-secondary' if possible), + disabled: !possible, data: local_data[actor_event] From 8dae40cb0ebef8c9851b03467962d2bb6bffb724 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 20 Mar 2024 17:53:00 -0300 Subject: [PATCH 407/472] fix: confirmar al rechazar #15600 --- app/views/components/_comments_btn_box.haml | 2 +- config/locales/en.yml | 1 + config/locales/es.yml | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/views/components/_comments_btn_box.haml b/app/views/components/_comments_btn_box.haml index ffc773a7..19ea169c 100644 --- a/app/views/components/_comments_btn_box.haml +++ b/app/views/components/_comments_btn_box.haml @@ -1,6 +1,6 @@ -# Componente Botonera de Comentarios -- local_data = { report: { confirm: t('.confirm_report') } } +- local_data = { reject: { confirm: t('.confirm_reject') }, report: { confirm: t('.confirm_report') } } .d-flex.flex-row - ActivityPub.events.each do |event| diff --git a/config/locales/en.yml b/config/locales/en.yml index 8059b6db..c88f7b26 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -107,6 +107,7 @@ en: text_reply: Reply text_report: Report confirm_report: "Send report to the remote instance? This action will also reject the comment." + confirm_reject: "Reject this comment? Please notice we can't undo this action at this moment." instances_btn_box: text_pause: Check case by case text_allow: Allow everything diff --git a/config/locales/es.yml b/config/locales/es.yml index 06b933bc..695b4e60 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -106,6 +106,7 @@ es: text_reject: Rechazar text_report: Reportar confirm_report: "¿Enviar el reporte a la instancia remota? Esta acción también rechazará el comentario." + confirm_reject: "¿Rechazar este comentario? Tené en cuenta que por el momento no es posible deshacer esta acción." instances_btn_box: text_pause: Moderar caso por caso text_allow: Permitir todo From e05a8aafda806adadea1af6b95c5ed13b8d0565b Mon Sep 17 00:00:00 2001 From: f Date: Thu, 21 Mar 2024 11:14:36 -0300 Subject: [PATCH 408/472] fix: enviar los botones de reporte a la derecha #15600 --- app/views/components/_comments_btn_box.haml | 15 ++++++++------- app/views/components/_profiles_btn_box.haml | 17 +++++++++-------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/app/views/components/_comments_btn_box.haml b/app/views/components/_comments_btn_box.haml index 19ea169c..578f6662 100644 --- a/app/views/components/_comments_btn_box.haml +++ b/app/views/components/_comments_btn_box.haml @@ -1,13 +1,14 @@ -# Componente Botonera de Comentarios -- local_data = { reject: { confirm: t('.confirm_reject') }, report: { confirm: t('.confirm_report') } } +- local = { reject: { data: { confirm: t('.confirm_reject') } }, report: { class: 'ml-auto', data: { confirm: t('.confirm_report') } } } .d-flex.flex-row - ActivityPub.events.each do |event| - possible = activity_pub.public_send(:"may_#{event}?") - = render 'components/btn_base', - text: t(".text_#{event}"), - path: public_send(:"site_activity_pub_#{event}_path", activity_pub_id: activity_pub), - class: ('btn-secondary' if possible), - disabled: !possible, - data: local_data[event] + %div{ class: local.dig(event, :class) } + = render 'components/btn_base', + text: t(".text_#{event}"), + path: public_send(:"site_activity_pub_#{event}_path", activity_pub_id: activity_pub), + class: ('btn-secondary' if possible), + disabled: !possible, + data: local.dig(event, :data) diff --git a/app/views/components/_profiles_btn_box.haml b/app/views/components/_profiles_btn_box.haml index 9414c178..8fc8dd39 100644 --- a/app/views/components/_profiles_btn_box.haml +++ b/app/views/components/_profiles_btn_box.haml @@ -1,11 +1,12 @@ -# Componente Botonera de Moderación de Cuentas (Remote_profile) -.d-flex.flex-row - - local_data = { report: { confirm: t('.confirm_report') } } +.d-flex.flex-row.w-100 + - local = { report: { class: 'ml-auto', data: { confirm: t('.confirm_report') } } } - ActorModeration.events.each do |actor_event| - possible = !actor_moderation.public_send(:"may_#{actor_event}?") - = render 'components/btn_base', - text: t(".text_#{actor_event}"), - path: public_send(:"site_actor_moderation_#{actor_event}_path", actor_moderation_id: actor_moderation), - class: ('btn-secondary' if possible), - disabled: !possible, - data: local_data[actor_event] + %div{ class: local.dig(actor_event, :class) } + = render 'components/btn_base', + text: t(".text_#{actor_event}"), + path: public_send(:"site_actor_moderation_#{actor_event}_path", actor_moderation_id: actor_moderation), + class: ('btn-secondary' if possible), + disabled: !possible, + data: local.dig(actor_event, :data) From 2aa2b9f3bb5e0aecd5f7b256a3248adadbd25087 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 21 Mar 2024 18:12:12 -0300 Subject: [PATCH 409/472] =?UTF-8?q?fix:=20poder=20ir=20a=20la=20cola=20de?= =?UTF-8?q?=20moderaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/assets/stylesheets/application.scss | 16 ++++ .../moderation_queue_controller.rb | 3 + app/models/moderation_queue.rb | 3 + app/models/site/social_distributed_press.rb | 23 ++++++ app/policies/moderation_queue_policy.rb | 9 +++ app/views/posts/index.haml | 10 +-- app/views/sites/_moderation_queue.haml | 9 +++ app/views/sites/index.haml | 74 +++++++++---------- 8 files changed, 103 insertions(+), 44 deletions(-) create mode 100644 app/models/moderation_queue.rb create mode 100644 app/policies/moderation_queue_policy.rb create mode 100644 app/views/sites/_moderation_queue.haml diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index cdf97b5b..11c44d90 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -32,6 +32,22 @@ $sizes: ( @import "bootstrap"; @import "editor"; +@each $color, $rgb in $theme-colors { + .#{$color} { + color: var(--#{$color}); + + &:focus { + color: var(--#{$color}); + } + + ::-moz-selection, + ::selection { + background: var(--#{$color}); + color: white; + } + } +} + .editor { .editor-content { figure { diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb index 4bd61e38..ef830c41 100644 --- a/app/controllers/moderation_queue_controller.rb +++ b/app/controllers/moderation_queue_controller.rb @@ -11,9 +11,12 @@ class ModerationQueueController < ApplicationController # Cola de moderación viendo todo el sitio def index + authorize ModerationQueue.new(site) breadcrumb site.title, site_posts_path(site) breadcrumb I18n.t('moderation_queue.index.title'), '' + site.moderation_checked! + # @todo cambiar el estado por query @activity_pubs = site.activity_pubs @instance_moderations = rubanok_process(site.instance_moderations, with: InstanceModerationProcessor) diff --git a/app/models/moderation_queue.rb b/app/models/moderation_queue.rb new file mode 100644 index 00000000..31ca3c9b --- /dev/null +++ b/app/models/moderation_queue.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +ModerationQueue = Struct.new(:site) diff --git a/app/models/site/social_distributed_press.rb b/app/models/site/social_distributed_press.rb index 0716a670..8d8d60d4 100644 --- a/app/models/site/social_distributed_press.rb +++ b/app/models/site/social_distributed_press.rb @@ -19,6 +19,29 @@ class Site before_save :generate_private_key_pem!, unless: :private_key_pem? + def moderation_enabled? + deploy_social_inbox.present? + end + + def deploy_social_inbox + @deploy_social_inbox ||= deploys.find_by(type: 'DeploySocialDistributedPress') + end + + def moderation_checked! + deploy_social_inbox.touch + end + + # @return [Bool] + def moderation_needed? + return false unless moderation_enabled? + + last_activity_pub = activity_pubs.order(updated_at: :desc).first&.updated_at + + return false if last_activity_pub.blank? + + last_activity_pub > deploy_social_inbox.updated_at + end + # @return [SocialInbox] def social_inbox @social_inbox ||= SocialInbox.new(site: self) diff --git a/app/policies/moderation_queue_policy.rb b/app/policies/moderation_queue_policy.rb new file mode 100644 index 00000000..75a4c45a --- /dev/null +++ b/app/policies/moderation_queue_policy.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +# Si la cola de moderación está activada y le usuarie tiene permisos de +# usuarie. +ModerationQueuePolicy = Struct.new(:usuarie, :moderation_queue) do + def index? + moderation_queue.site.moderation_enabled? && moderation_queue.site.usuarie?(usuarie) + end +end diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index 69fb2d8f..6d77b75d 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -1,10 +1,10 @@ %main.row %aside.menu.col-md-3 - = render 'sites/header', site: @site - - = render 'sites/status', site: @site - - = render 'sites/build', site: @site, class: 'btn-block' + .mb-3 + = render 'sites/header', site: @site + = render 'sites/status', site: @site + = render 'sites/build', site: @site, class: 'btn-block' + = render 'sites/moderation_queue', site: @site, class: 'btn-block' %h3= t('posts.new') %table.table.table-sm.mb-3 diff --git a/app/views/sites/_moderation_queue.haml b/app/views/sites/_moderation_queue.haml new file mode 100644 index 00000000..6b39d797 --- /dev/null +++ b/app/views/sites/_moderation_queue.haml @@ -0,0 +1,9 @@ +- if policy(ModerationQueue.new(site)).index? + - moderation_needed = site.moderation_needed? + + - local_assigns[:class] = "btn btn-secondary #{local_assigns[:class]}" + = link_to site_moderation_queue_path(site), class: local_assigns[:class], title: (t('.moderation_needed') if moderation_needed) do + = t('moderation_queue.index.title') + - if moderation_needed + %span.primary ⏺ + %span.sr-only= t('.moderation_needed') diff --git a/app/views/sites/index.haml b/app/views/sites/index.haml index ed87180a..fc8184e1 100644 --- a/app/views/sites/index.haml +++ b/app/views/sites/index.haml @@ -15,43 +15,39 @@ %tbody - @sites.each do |site| - next unless site.jekyll? - - rol = current_usuarie.rol_for_site(site) - -# - TODO: Solo les usuaries cachean porque tenemos que separar - les botones por permisos. - - cache_if (rol.usuarie? && !rol.temporal), [site, I18n.locale] do - %tr - %td - %h2 - - if policy(site).show? - = link_to site.title, site_posts_path(site, locale: site.default_locale) - - else - = site.title - %p.lead= site.description - %br - = link_to t('.visit'), site.url, class: 'btn btn-secondary' - - if rol.temporal - = button_to t('sites.invitations.accept'), - site_usuaries_accept_invitation_path(site), - method: :patch, - title: t('help.sites.invitations.accept'), - class: 'btn btn-secondary' - = button_to t('sites.invitations.reject'), - site_usuaries_reject_invitation_path(site), - method: :patch, - title: t('help.sites.invitations.reject'), - class: 'btn btn-secondary' + %tr + %td + %h2 + - if policy(site).show? + = link_to site.title, site_posts_path(site, locale: site.default_locale) - else - - if policy(site).show? - = render 'layouts/btn_with_tooltip', - tooltip: t('help.sites.edit_posts'), - type: 'success', - link: site_path(site), - text: t('sites.posts') - - if policy(SiteUsuarie.new(site, current_usuarie)).index? - = render 'layouts/btn_with_tooltip', - tooltip: t('usuaries.index.help.self'), - text: t('usuaries.index.title'), - type: 'info', - link: site_usuaries_path(site) - = render 'sites/build', site: site + = site.title + %p.lead= site.description + %br + = link_to t('.visit'), site.url, class: 'btn btn-secondary' + - if current_usuarie.rol_for_site(site).temporal? + = render 'components/btn_base', + text: t('sites.invitations.accept'), + path: site_usuaries_accept_invitation_path(site), + title: t('help.sites.invitations.accept'), + class: 'btn-secondary' + = render 'components/btn_base', + text: t('sites.invitations.reject'), + path: site_usuaries_reject_invitation_path(site), + title: t('help.sites.invitations.reject'), + class: 'btn-secondary' + - else + - if policy(site).show? + = render 'layouts/btn_with_tooltip', + tooltip: t('help.sites.edit_posts'), + type: 'success', + link: site_path(site), + text: t('sites.posts') + = render 'sites/build', site: site + = render 'sites/moderation_queue', site: site + - if policy(SiteUsuarie.new(site, current_usuarie)).index? + = render 'layouts/btn_with_tooltip', + tooltip: t('usuaries.index.help.self'), + text: t('usuaries.index.title'), + type: 'info', + link: site_usuaries_path(site) From ad637189b542a386ba6c09908b0cb59d20a2b91f Mon Sep 17 00:00:00 2001 From: f Date: Thu, 21 Mar 2024 18:25:36 -0300 Subject: [PATCH 410/472] =?UTF-8?q?fixup!=20fix:=20poder=20ir=20a=20la=20c?= =?UTF-8?q?ola=20de=20moderaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/locales/en.yml | 2 ++ config/locales/es.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/config/locales/en.yml b/config/locales/en.yml index c88f7b26..f024fa98 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -573,6 +573,8 @@ en: column: "Country" empty: "(couldn't detect country)" sites: + moderation_queue: + moderation_needed: "There are new activities pending revision since the last time you moderated." donations: url: 'https://donaciones.sutty.nl/en/' text: 'Support us' diff --git a/config/locales/es.yml b/config/locales/es.yml index 695b4e60..204a3587 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -577,6 +577,8 @@ es: column: "País" empty: "(no se pudo detectar el país)" sites: + moderation_queue: + moderation_needed: "Hay actividades pendientes de revisión desde la última vez que moderaste." donations: url: 'https://donaciones.sutty.nl/' text: 'Apoyá nuestro trabajo' From 48532633740028bf406d2bd7ca97ab85f9c076bd Mon Sep 17 00:00:00 2001 From: f Date: Fri, 22 Mar 2024 11:53:23 -0300 Subject: [PATCH 411/472] fix: pedir locks antes de guardar closes #15621 closes #15622 closes #15623 closes #15729 closes #15730 closes #15731 closes #15735 closes #15736 --- app/jobs/activity_pub/process_job.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/jobs/activity_pub/process_job.rb b/app/jobs/activity_pub/process_job.rb index f3aeebb4..bd010613 100644 --- a/app/jobs/activity_pub/process_job.rb +++ b/app/jobs/activity_pub/process_job.rb @@ -66,6 +66,7 @@ class ActivityPub @object ||= ::ActivityPub::Object.lock.find_or_initialize_by(uri: object_uri).tap do |o| o.content = original_object if object_embedded? + o.lock! o.save! # XXX: el objeto necesita ser guardado antes de poder @@ -95,6 +96,7 @@ class ActivityPub .find_or_initialize_by(uri: original_activity[:id], activity_pub: activity_pub, actor: actor).tap do |a| a.content = original_activity.dup a.content[:object] = object.uri + a.lock! a.save! end end @@ -113,6 +115,7 @@ class ActivityPub site.instance_moderations.lock.find_or_create_by(instance: a.instance) + a.lock! a.save! site.actor_moderations.lock.find_or_create_by(actor: a) From 0561b022de3eb01d747c4379590904087385f8c2 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 22 Mar 2024 11:57:22 -0300 Subject: [PATCH 412/472] fix: no fallar si no hay registros sobre los que actuar #15725 --- app/controllers/activity_pubs_controller.rb | 6 ++++-- app/controllers/actor_moderations_controller.rb | 6 ++++-- app/controllers/instance_moderations_controller.rb | 6 ++++-- app/policies/instance_moderation_policy.rb | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/app/controllers/activity_pubs_controller.rb b/app/controllers/activity_pubs_controller.rb index d5041a84..428d5cb1 100644 --- a/app/controllers/activity_pubs_controller.rb +++ b/app/controllers/activity_pubs_controller.rb @@ -29,16 +29,18 @@ class ActivityPubsController < ApplicationController end def action_on_several + redirect_to_moderation_queue! + activity_pubs = site.activity_pubs.where(id: params[:activity_pub]) + return if activity_pubs.count.zero? + authorize activity_pubs action = params[:activity_pub_action].to_sym method = :"#{action}_all!" may = :"may_#{action}?" - redirect_to_moderation_queue! - return unless ActivityPub.events.include? action # Crear una sola remote flag por autore diff --git a/app/controllers/actor_moderations_controller.rb b/app/controllers/actor_moderations_controller.rb index 739b1f46..04d2603b 100644 --- a/app/controllers/actor_moderations_controller.rb +++ b/app/controllers/actor_moderations_controller.rb @@ -48,16 +48,18 @@ class ActorModerationsController < ApplicationController end def action_on_several + redirect_to_moderation_queue! + actor_moderations = site.actor_moderations.where(id: params[:actor_moderation]) + return if actor_moderations.count.zero? + authorize actor_moderations action = params[:actor_moderation_action].to_sym method = :"#{action}_all!" may = :"may_#{action}?" - redirect_to_moderation_queue! - return unless ActorModeration.events.include? action ActorModeration.transaction do diff --git a/app/controllers/instance_moderations_controller.rb b/app/controllers/instance_moderations_controller.rb index 13d7f428..de990eb1 100644 --- a/app/controllers/instance_moderations_controller.rb +++ b/app/controllers/instance_moderations_controller.rb @@ -22,15 +22,17 @@ class InstanceModerationsController < ApplicationController end def action_on_several + redirect_to_moderation_queue! + instance_moderations = site.instance_moderations.where(id: params[:instance_moderation]) + return if instance_moderations.count.zero? + authorize instance_moderations action = params[:instance_moderation_action].to_sym method = :"#{action}_all!" - redirect_to_moderation_queue! - return unless InstanceModeration.events.include? action InstanceModeration.transaction do diff --git a/app/policies/instance_moderation_policy.rb b/app/policies/instance_moderation_policy.rb index 13ebfeca..c54eb4b8 100644 --- a/app/policies/instance_moderation_policy.rb +++ b/app/policies/instance_moderation_policy.rb @@ -11,6 +11,6 @@ InstanceModerationPolicy = Struct.new(:usuarie, :instance_moderation) do # En este paso tenemos varias instancias por moderar pero todas son # del mismo sitio. def action_on_several? - instance_moderation.first.site.usuarie? usuarie + instance_moderation.first.presence && instance_moderation.first.site.usuarie? usuarie end end From cc654be121986126642308d68c0b9fdbb6cdb4a3 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 22 Mar 2024 12:01:08 -0300 Subject: [PATCH 413/472] fixup! fix: no fallar si no hay registros sobre los que actuar #15725 --- app/policies/instance_moderation_policy.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/policies/instance_moderation_policy.rb b/app/policies/instance_moderation_policy.rb index c54eb4b8..c6a229d3 100644 --- a/app/policies/instance_moderation_policy.rb +++ b/app/policies/instance_moderation_policy.rb @@ -11,6 +11,6 @@ InstanceModerationPolicy = Struct.new(:usuarie, :instance_moderation) do # En este paso tenemos varias instancias por moderar pero todas son # del mismo sitio. def action_on_several? - instance_moderation.first.presence && instance_moderation.first.site.usuarie? usuarie + instance_moderation.first.presence && instance_moderation.first.site.usuarie?(usuarie) end end From b6fdc8a5801ebacee50eb0b522a374ca4ac3aa52 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 22 Mar 2024 12:38:54 -0300 Subject: [PATCH 414/472] =?UTF-8?q?fix:=20permitir=20hostnames=20num=C3=A9?= =?UTF-8?q?ricos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #15789 --- app/models/activity_pub/instance.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/activity_pub/instance.rb b/app/models/activity_pub/instance.rb index 749d98ac..cd14ef23 100644 --- a/app/models/activity_pub/instance.rb +++ b/app/models/activity_pub/instance.rb @@ -9,7 +9,7 @@ class ActivityPub include AASM validates :aasm_state, presence: true, inclusion: { in: %w[paused allowed blocked] } - validates :hostname, uniqueness: true, hostname: true + validates :hostname, uniqueness: true, hostname: { allow_numeric_hostname: true } has_many :activity_pubs has_many :actors From 5db263ef6c65450ae997e26a9ba9951f7ea859aa Mon Sep 17 00:00:00 2001 From: f Date: Fri, 22 Mar 2024 12:54:27 -0300 Subject: [PATCH 415/472] fix: recordar que hay que volver a correr la tarea manualmente #15789 --- app/jobs/activity_pub/process_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/activity_pub/process_job.rb b/app/jobs/activity_pub/process_job.rb index bd010613..94799735 100644 --- a/app/jobs/activity_pub/process_job.rb +++ b/app/jobs/activity_pub/process_job.rb @@ -28,7 +28,7 @@ class ActivityPub # Al generar una excepción, en lugar de seguir intentando, enviamos # el reporte. rescue Exception => e - ExceptionNotifier.notify_exception(e, data: { site: site.name, activity: original_activity }) + ExceptionNotifier.notify_exception(e, data: { site: site.name, body: body, initial_state: initial_state, activity: original_activity, message: 'Esta acción se canceló automáticamente, para regenerarla, volver a correr el proceso con los mismos parámetros.' }) end private From dad5f5f00ce99d9b724853b6eaaa1ea0a0be70b8 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 22 Mar 2024 13:06:58 -0300 Subject: [PATCH 416/472] =?UTF-8?q?fix:=20solo=20bloquear=20cuando=20ya=20?= =?UTF-8?q?est=C3=A1=20en=20la=20base=20de=20datos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #15791 --- app/jobs/activity_pub/process_job.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/jobs/activity_pub/process_job.rb b/app/jobs/activity_pub/process_job.rb index 94799735..9b7c30fc 100644 --- a/app/jobs/activity_pub/process_job.rb +++ b/app/jobs/activity_pub/process_job.rb @@ -66,7 +66,7 @@ class ActivityPub @object ||= ::ActivityPub::Object.lock.find_or_initialize_by(uri: object_uri).tap do |o| o.content = original_object if object_embedded? - o.lock! + o.lock! if o.persisted? o.save! # XXX: el objeto necesita ser guardado antes de poder @@ -96,7 +96,7 @@ class ActivityPub .find_or_initialize_by(uri: original_activity[:id], activity_pub: activity_pub, actor: actor).tap do |a| a.content = original_activity.dup a.content[:object] = object.uri - a.lock! + a.lock! if o.persisted? a.save! end end @@ -115,7 +115,7 @@ class ActivityPub site.instance_moderations.lock.find_or_create_by(instance: a.instance) - a.lock! + a.lock! if o.persisted? a.save! site.actor_moderations.lock.find_or_create_by(actor: a) From 071f20762c3ed2d435ed5351d5b9b5cd937865e5 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 22 Mar 2024 13:09:13 -0300 Subject: [PATCH 417/472] fix: bloquear antes de empezar a modificar closes #15791 --- app/jobs/activity_pub/process_job.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/jobs/activity_pub/process_job.rb b/app/jobs/activity_pub/process_job.rb index 9b7c30fc..a79abf5d 100644 --- a/app/jobs/activity_pub/process_job.rb +++ b/app/jobs/activity_pub/process_job.rb @@ -64,9 +64,9 @@ class ActivityPub # @return [ActivityPub::Object] def object @object ||= ::ActivityPub::Object.lock.find_or_initialize_by(uri: object_uri).tap do |o| + o.lock! if o.persisted? o.content = original_object if object_embedded? - o.lock! if o.persisted? o.save! # XXX: el objeto necesita ser guardado antes de poder @@ -94,9 +94,9 @@ class ActivityPub .type_from(original_activity) .lock .find_or_initialize_by(uri: original_activity[:id], activity_pub: activity_pub, actor: actor).tap do |a| + a.lock! if o.persisted? a.content = original_activity.dup a.content[:object] = object.uri - a.lock! if o.persisted? a.save! end end @@ -107,6 +107,8 @@ class ActivityPub # @return [Actor] def actor @actor ||= ::ActivityPub::Actor.lock.find_or_initialize_by(uri: original_activity[:actor]).tap do |a| + a.lock! if o.persisted? + unless a.instance a.instance = ::ActivityPub::Instance.lock.find_or_create_by(hostname: URI.parse(a.uri).hostname) @@ -114,8 +116,6 @@ class ActivityPub end site.instance_moderations.lock.find_or_create_by(instance: a.instance) - - a.lock! if o.persisted? a.save! site.actor_moderations.lock.find_or_create_by(actor: a) From dbf15397e53de6ce46f148a1be61ef98ab6fefb8 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 22 Mar 2024 15:44:28 -0300 Subject: [PATCH 418/472] fix: mostrar los desplegables como accionables #15600 --- app/views/components/_dropdown.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/components/_dropdown.haml b/app/views/components/_dropdown.haml index 54ddcffb..6f34950b 100644 --- a/app/views/components/_dropdown.haml +++ b/app/views/components/_dropdown.haml @@ -11,7 +11,7 @@ controller: 'dropdown' } } - %button.btn.dropdown-toggle{ + %button.btn.btn-outline-secondary.dropdown-toggle{ type: 'button', class: button_classes, data: { From 07fd2cff930d26e33e8e3ac3fb3307554a3166b0 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 22 Mar 2024 17:31:53 -0300 Subject: [PATCH 419/472] fix: usar locks en moderaciones de instancia closes #15788 --- app/jobs/activity_pub/instance_moderation_job.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/jobs/activity_pub/instance_moderation_job.rb b/app/jobs/activity_pub/instance_moderation_job.rb index 00100abf..9da0627f 100644 --- a/app/jobs/activity_pub/instance_moderation_job.rb +++ b/app/jobs/activity_pub/instance_moderation_job.rb @@ -9,7 +9,7 @@ class ActivityPub def perform(site:, hostnames:, perform_remotely: true) # Crear las instancias que no existan todavía hostnames.each do |hostname| - ActivityPub::Instance.find_or_create_by(hostname: hostname) + ActivityPub::Instance.lock.find_or_create_by(hostname: hostname) end instances = ActivityPub::Instance.where(hostname: hostnames) @@ -20,7 +20,7 @@ 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) + site.instance_moderations.lock.find_or_create_by(instance: instance) end scope = site.instance_moderations.where(instance_id: instances.ids) From 366494b61535358b6fecaa13482ff3dde10358af Mon Sep 17 00:00:00 2001 From: f Date: Fri, 22 Mar 2024 18:28:34 -0300 Subject: [PATCH 420/472] fix: typo closes #15792 closes #15793 closes #15794 closes #15795 closes #15796 closes #15797 closes #15798 closes #15799 closes #15800 closes #15801 closes #15802 closes #15803 closes #15804 closes #15805 closes #15806 closes #15807 closes #15808 closes #15809 closes #15810 closes #15811 closes #15812 closes #15813 closes #15814 closes #15815 closes #15816 closes #15817 closes #15818 --- app/jobs/activity_pub/process_job.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/jobs/activity_pub/process_job.rb b/app/jobs/activity_pub/process_job.rb index a79abf5d..af686dbd 100644 --- a/app/jobs/activity_pub/process_job.rb +++ b/app/jobs/activity_pub/process_job.rb @@ -94,7 +94,7 @@ class ActivityPub .type_from(original_activity) .lock .find_or_initialize_by(uri: original_activity[:id], activity_pub: activity_pub, actor: actor).tap do |a| - a.lock! if o.persisted? + a.lock! if a.persisted? a.content = original_activity.dup a.content[:object] = object.uri a.save! @@ -107,7 +107,7 @@ class ActivityPub # @return [Actor] def actor @actor ||= ::ActivityPub::Actor.lock.find_or_initialize_by(uri: original_activity[:actor]).tap do |a| - a.lock! if o.persisted? + a.lock! if a.persisted? unless a.instance a.instance = ::ActivityPub::Instance.lock.find_or_create_by(hostname: URI.parse(a.uri).hostname) From fb38600884faffea66a9ff832d854fec3eb5dc03 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 22 Mar 2024 18:34:24 -0300 Subject: [PATCH 421/472] =?UTF-8?q?feat:=20recargar=20autom=C3=A1ticamente?= =?UTF-8?q?=20el=20estado=20de=20publicaci=C3=B3n=20#13611?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/sites_controller.rb | 7 +++++ app/javascript/packs/application.js | 2 ++ app/views/sites/_status.haml | 41 ++++++++++++++++------------- app/views/sites/status.haml | 1 + config/locales/en.yml | 2 +- config/locales/es.yml | 2 +- config/routes.rb | 2 ++ package.json | 3 ++- yarn.lock | 5 ++++ 9 files changed, 43 insertions(+), 22 deletions(-) create mode 100644 app/views/sites/status.haml diff --git a/app/controllers/sites_controller.rb b/app/controllers/sites_controller.rb index bec42b39..49527cf7 100644 --- a/app/controllers/sites_controller.rb +++ b/app/controllers/sites_controller.rb @@ -15,6 +15,13 @@ class SitesController < ApplicationController fresh_when @sites end + # Genera la caja del estado para HTMX + def status + authorize site + + render('sites/status', layout: false) if stale? site + end + # No tenemos propiedades de un sitio aún, así que vamos al listado de # artículos def show diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index 9cbc30bf..9ddc9753 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -33,3 +33,5 @@ import 'chartkick/chart.js' Rails.start() Turbolinks.start() ActiveStorage.start() + +window.htmx = require('htmx.org/dist/htmx') diff --git a/app/views/sites/_status.haml b/app/views/sites/_status.haml index 6a610e73..47bed657 100644 --- a/app/views/sites/_status.haml +++ b/app/views/sites/_status.haml @@ -1,21 +1,24 @@ -- link = nil -- if site.not_published_yet? - - message = t('.not_published_yet') -- elsif site.awaiting_publication? - - message = t('.awaiting_publication') -- elsif site.building? - - if site.average_publication_time_calculable? - - average_building_time = site.average_publication_time - - elsif !site.similar_sites? - - average_building_time = 60 +- cache site do + - link = nil + - if site.not_published_yet? + - message = t('.not_published_yet') + - elsif site.awaiting_publication? + - message = t('.awaiting_publication') + - elsif site.building? + - if site.average_publication_time_calculable? + - average_building_time = site.average_publication_time + - elsif !site.similar_sites? + - average_building_time = 60 + - else + - average_building_time = site.average_publication_time_for_similar_sites + + - average_publication_time_human = distance_of_time_in_words average_building_time + - message = t('.building', average_time: average_publication_time_human, seconds: average_building_time) - else - - average_building_time = site.average_publication_time_for_similar_sites + - message = t('.available') + - link = true - - average_publication_time_human = distance_of_time_in_words average_building_time - - message = t('.building', average_time: average_publication_time_human, seconds: average_building_time) -- else - - message = t('.available') - - link = true - -= render 'bootstrap/alert' do - = link_to_if link, message.html_safe, site_build_stats_path(site), class: 'alert-link' + -# TODO: Calcular cada cuanto sería óptimo recargar + %div{ 'hx-get': site_status_path(site), 'hx-trigger': 'every 10s', 'hx-swap': 'outerHTML' } + = render 'bootstrap/alert' do + = link_to_if link, message.html_safe, site_build_stats_path(site), class: 'alert-link' diff --git a/app/views/sites/status.haml b/app/views/sites/status.haml new file mode 100644 index 00000000..3d9793a5 --- /dev/null +++ b/app/views/sites/status.haml @@ -0,0 +1 @@ += render 'sites/status', site: @site diff --git a/config/locales/en.yml b/config/locales/en.yml index fc9d4894..720f784a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -389,7 +389,7 @@ en: static_file_migration: 'File migration' find_and_replace: 'Search and replace' status: - building: "Your site is building, refresh this page in ." + building: "Your site is building, it will be ready in ." not_published_yet: "Your site is being published for the first time, please wait up to 1 minute..." available: "Your site is available! Click here to find all the different ways to visit it." awaiting_publication: "There are unpublished changes. Click the button below and wait a moment to find them on your site." diff --git a/config/locales/es.yml b/config/locales/es.yml index 4bda4982..e7ff0864 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -394,7 +394,7 @@ es: static_file_migration: 'Migración de archivos' find_and_replace: 'Búsqueda y reemplazo' status: - building: "Tu sitio se está publicando, recargá esta página en ." + building: "Tu sitio se está publicando, estará listo en ." not_published_yet: "Tu sitio se está publicando por primera vez, por favor espera hasta un minuto..." available: "¡Tu sitio está disponible! Cliqueá aquí para encontrar todas las formas en que podés visitarlo." awaiting_publication: "Hay cambios sin publicar, cliqueá el botón debajo y espera un momento para encontrarlos en tu sitio." diff --git a/config/routes.rb b/config/routes.rb index 635be07a..557439e9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -37,6 +37,8 @@ Rails.application.routes.draw do get 'pull', to: 'sites#fetch' post 'pull', to: 'sites#merge' + get 'status', to: 'sites#status' + # Gestionar usuaries get 'usuaries/invite', to: 'usuaries#invite' post 'usuaries/invite', to: 'usuaries#send_invitations' diff --git a/package.json b/package.json index 7901ad41..871c9d9b 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "zepto": "^1.2.0" }, "devDependencies": { - "@types/rails__activestorage": "^6.0.0" + "@types/rails__activestorage": "^6.0.0", + "htmx.org": "^1.9.11" } } diff --git a/yarn.lock b/yarn.lock index 0c52b9d3..4619169e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4548,6 +4548,11 @@ html-entities@^1.3.1: resolved "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz" integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA== +htmx.org@^1.9.11: + version "1.9.11" + resolved "https://registry.yarnpkg.com/htmx.org/-/htmx.org-1.9.11.tgz#00192041ee682d6ca7146d0fbd901169ffe72d87" + integrity sha512-WlVuICn8dfNOOgYmdYzYG8zSnP3++AdHkMHooQAzGZObWpVXYathpz/I37ycF4zikR6YduzfCvEcxk20JkIUsw== + http-deceiver@^1.2.7: version "1.2.7" resolved "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz" From 736f0552f73e9a88a81552da1725b87dfeea33e4 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 22 Mar 2024 18:46:21 -0300 Subject: [PATCH 422/472] =?UTF-8?q?fix:=20poder=20importar=20htmx=20en=20p?= =?UTF-8?q?roducci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/javascript/packs/application.js | 2 +- package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index 9ddc9753..d8ff0dd1 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -34,4 +34,4 @@ Rails.start() Turbolinks.start() ActiveStorage.start() -window.htmx = require('htmx.org/dist/htmx') +window.htmx = require('htmx.org/dist/htmx.js') diff --git a/package.json b/package.json index 871c9d9b..870b8e9b 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "commonmark": "^0.29.0", "fork-awesome": "^1.1.7", "fork-ts-checker-webpack-plugin": "^6.1.0", + "htmx.org": "^1.9.11", "input-map": "git+https://0xacab.org/sutty/input-map.git", "input-tag": "git+https://0xacab.org/sutty/input-tag.git", "leaflet": "^1.7.1", @@ -34,7 +35,6 @@ "zepto": "^1.2.0" }, "devDependencies": { - "@types/rails__activestorage": "^6.0.0", - "htmx.org": "^1.9.11" + "@types/rails__activestorage": "^6.0.0" } } From 95231511b78243dede6c4cab52ab6116fb145a54 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 22 Mar 2024 18:54:18 -0300 Subject: [PATCH 423/472] fix: poder ver el estado --- app/policies/site_policy.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/policies/site_policy.rb b/app/policies/site_policy.rb index 2ca96256..d5465d6b 100644 --- a/app/policies/site_policy.rb +++ b/app/policies/site_policy.rb @@ -14,6 +14,10 @@ class SitePolicy true end + def status? + true + end + # Puede ver la versión privada del sitio? def private? edit? && site.deploys.find_by_type('DeployPrivate') From d7de351e1af36ab1383d2cf0c4e8f040fef6a686 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 25 Mar 2024 13:32:08 -0300 Subject: [PATCH 424/472] fix: espaciar el procesamiento de tareas closes #15621 closes #15622 closes #15623 closes #15729 closes #15730 closes #15731 closes #15735 closes #15736 closes #15824 --- .../api/v1/webhooks/social_inbox_controller.rb | 4 +++- app/jobs/application_job.rb | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v1/webhooks/social_inbox_controller.rb b/app/controllers/api/v1/webhooks/social_inbox_controller.rb index 6ac91a51..9d215812 100644 --- a/app/controllers/api/v1/webhooks/social_inbox_controller.rb +++ b/app/controllers/api/v1/webhooks/social_inbox_controller.rb @@ -49,7 +49,9 @@ module Api # # @param initial_state [Symbol] def process!(initial_state) - ::ActivityPub::ProcessJob.perform_later(site: site, body: request.raw_post, initial_state: initial_state) + ::ActivityPub::ProcessJob + .set(wait: ApplicationJob.random_wait) + .perform_later(site: site, body: request.raw_post, initial_state: initial_state) end end end diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb index 06690c53..1bf20345 100644 --- a/app/jobs/application_job.rb +++ b/app/jobs/application_job.rb @@ -4,6 +4,17 @@ class ApplicationJob < ActiveJob::Base include Que::ActiveJob::JobExtensions + # Esperar una cantidad random de segundos primos, para que no se + # superpongan tareas + # + # @return [Array] + RANDOM_WAIT = [3, 5, 7, 11, 13].seconds + + # @return [ActiveSupport::Duration] + def self.random_wait + RANDOM_WAIT.sample + end + private def site From 718b8643562f2f1d3202ed3c0a7ded93a115ceb5 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 25 Mar 2024 13:33:52 -0300 Subject: [PATCH 425/472] fixup! fix: espaciar el procesamiento de tareas --- app/jobs/application_job.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb index 1bf20345..dc6d0478 100644 --- a/app/jobs/application_job.rb +++ b/app/jobs/application_job.rb @@ -7,12 +7,12 @@ class ApplicationJob < ActiveJob::Base # Esperar una cantidad random de segundos primos, para que no se # superpongan tareas # - # @return [Array] - RANDOM_WAIT = [3, 5, 7, 11, 13].seconds + # @return [Array] + RANDOM_WAIT = [3, 5, 7, 11, 13] # @return [ActiveSupport::Duration] def self.random_wait - RANDOM_WAIT.sample + RANDOM_WAIT.sample.seconds end private From 88cc5f9cb0adee2eca01b5b905d69dd6f160fd37 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 25 Mar 2024 14:17:26 -0300 Subject: [PATCH 426/472] fix: reintentar antes de reportar el error #15824 --- app/jobs/activity_pub/process_job.rb | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/app/jobs/activity_pub/process_job.rb b/app/jobs/activity_pub/process_job.rb index af686dbd..d94c31e2 100644 --- a/app/jobs/activity_pub/process_job.rb +++ b/app/jobs/activity_pub/process_job.rb @@ -3,15 +3,16 @@ class ActivityPub # Procesar las actividades a medida que llegan class ProcessJob < ApplicationJob - attr_reader :body + attr_reader :body, :initial_state # Procesa la actividad en segundo plano # # @param :body [String] # @param :initial_state [Symbol,String] def perform(site:, body:, initial_state: :paused) - @body = body @site = site + @body = body + @initial_state = initial_state ActiveRecord::Base.connection_pool.with_connection do ::ActivityPub.transaction do @@ -25,10 +26,24 @@ class ActivityPub activity.update_activity_pub_state! end end + end + # Al generar una excepción, en lugar de seguir intentando, enviamos # el reporte. - rescue Exception => e - ExceptionNotifier.notify_exception(e, data: { site: site.name, body: body, initial_state: initial_state, activity: original_activity, message: 'Esta acción se canceló automáticamente, para regenerarla, volver a correr el proceso con los mismos parámetros.' }) + def handle_error(error) + case error + when ActiveRecord::RecordInvalid then retry_in(ApplicationJob.random_wait) + else + ExceptionNotifier.notify_exception( + error, + data: { + site: site.name, + body: body, + initial_state: initial_state, + activity: original_activity, + message: 'Esta acción se canceló automáticamente, para regenerarla, volver a correr el proceso con los mismos parámetros.' + }) + end end private From 3f9714f6d06ed33baef92f8d8b3d3f0b31433349 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 25 Mar 2024 15:30:44 -0300 Subject: [PATCH 427/472] =?UTF-8?q?fix:=20permitir=20cargar=20blobs=20en?= =?UTF-8?q?=20previsualizaci=C3=B3n=20de=20videos=20y=20audios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/initializers/content_security_policy.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index 91d287e0..c07c7751 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -7,7 +7,7 @@ # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy Rails.application.config.content_security_policy do |policy| - policy.default_src :self + policy.default_src :self, :blob # XXX: Varios scripts generan estilos en línea policy.style_src :self, :unsafe_inline, :https # Repetimos la default para poder saber cuál es la política en falta From d577075615067d70eca20ce7d46896f1185622f7 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 25 Mar 2024 15:33:10 -0300 Subject: [PATCH 428/472] feat: informar que se va a modificar el archivo #4101 --- .../controllers/file_preview_controller.js | 19 +++++++++++++++++++ app/javascript/etc/image_preview.js | 11 ----------- app/javascript/etc/index.js | 1 - app/views/posts/attributes/_file.haml | 10 ++++++---- app/views/posts/attributes/_image.haml | 9 +++++---- package.json | 1 + yarn.lock | 5 +++++ 7 files changed, 36 insertions(+), 20 deletions(-) create mode 100644 app/javascript/controllers/file_preview_controller.js delete mode 100644 app/javascript/etc/image_preview.js diff --git a/app/javascript/controllers/file_preview_controller.js b/app/javascript/controllers/file_preview_controller.js new file mode 100644 index 00000000..9eaaab2d --- /dev/null +++ b/app/javascript/controllers/file_preview_controller.js @@ -0,0 +1,19 @@ +import { Controller } from 'stimulus' +import bsCustomFileInput from "bs-custom-file-input"; + +document.addEventListener("turbolinks:load", () => { + bsCustomFileInput.init(); +}); + +export default class extends Controller { + static targets = ["preview", "input"]; + + connect() { + } + + update(event = undefined) { + if (!this.hasPreviewTarget) return; + + this.previewTarget.src = window.URL.createObjectURL(this.inputTarget.files[0]) + } +} diff --git a/app/javascript/etc/image_preview.js b/app/javascript/etc/image_preview.js deleted file mode 100644 index fcdeec85..00000000 --- a/app/javascript/etc/image_preview.js +++ /dev/null @@ -1,11 +0,0 @@ -document.addEventListener('turbolinks:load', () => { - document.querySelectorAll('input[type=file]').forEach(file => { - if (!file.dataset.preview) return - - file.addEventListener('change', event => { - if (file.files.length === 0) return - - document.querySelector('#' + file.dataset.preview).src = window.URL.createObjectURL(file.files[0]) - }) - }) -}) diff --git a/app/javascript/etc/index.js b/app/javascript/etc/index.js index d4b9f7a3..e19246af 100644 --- a/app/javascript/etc/index.js +++ b/app/javascript/etc/index.js @@ -1,5 +1,4 @@ import './external_links' -import './image_preview' import './input-date' import './input-tag' import './prosemirror' diff --git a/app/views/posts/attributes/_file.haml b/app/views/posts/attributes/_file.haml index 54f9f81a..20c27399 100644 --- a/app/views/posts/attributes/_file.haml +++ b/app/views/posts/attributes/_file.haml @@ -1,12 +1,14 @@ -.form-group +.form-group{ data: { controller: 'file-preview' } } - if metadata.static_file - case metadata.static_file.blob.content_type - when %r{\Avideo/} = video_tag url_for(metadata.static_file), - controls: true, class: 'img-fluid' + controls: true, class: 'img-fluid', + data: { target: 'file-preview.preview' } - when %r{\Aaudio/} = audio_tag url_for(metadata.static_file), - controls: true, class: 'img-fluid' + controls: true, class: 'img-fluid', + data: { target: 'file-preview.preview' } - when 'application/pdf' %iframe{ src: url_for(metadata.static_file) } - else @@ -24,7 +26,7 @@ = file_field(*field_name_for(base, attribute, :path), **field_options(attribute, metadata, required: (metadata.required && !metadata.path?)), class: "custom-file-input #{invalid(post, attribute)}", - data: { preview: "#{attribute}-preview" }) + data: { target: 'file-preview.input', action: 'file-preview#update' }) = label_tag "#{base}_#{attribute}_path", post_label_t(attribute, :path, post: post), class: 'custom-file-label' = render 'posts/attribute_feedback', diff --git a/app/views/posts/attributes/_image.haml b/app/views/posts/attributes/_image.haml index 84fe56fd..241a78e8 100644 --- a/app/views/posts/attributes/_image.haml +++ b/app/views/posts/attributes/_image.haml @@ -1,9 +1,9 @@ -.form-group +.form-group{ data: { controller: 'file-preview' } } - if metadata.static_file = image_tag url_for(metadata.static_file), alt: metadata.value['description'], class: 'img-fluid', - id: "#{attribute}-preview" + data: { target: 'file-preview.preview' } -# Mantener el valor si no enviamos ninguna imagen = hidden_field_tag "#{base}[#{attribute}][path]", metadata.value['path'] @@ -16,13 +16,14 @@ = image_tag '', alt: metadata.value['description'], class: 'img-fluid', - id: "#{attribute}-preview" + data: { target: 'file-preview.preview' } .custom-file = file_field(*field_name_for(base, attribute, :path), **field_options(attribute, metadata, required: (metadata.required && !metadata.path?)), class: "custom-file-input #{invalid(post, attribute)}", - accept: ActiveStorage.web_image_content_types.join(','), data: { preview: "#{attribute}-preview" }) + accept: ActiveStorage.web_image_content_types.join(','), + data: { target: 'file-preview.input', action: 'file-preview#update' }) = label_tag "#{base}_#{attribute}_path", post_label_t(attribute, :path, post: post), class: 'custom-file-label' = render 'posts/attribute_feedback', diff --git a/package.json b/package.json index 7901ad41..4f5bb05c 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@rails/webpacker": "5.4.4", "@suttyweb/editor": "^0.1.25", "babel-loader": "^8.2.2", + "bs-custom-file-input": "^1.3.4", "chart.js": "^3.5.1", "chartkick": "^4.0.5", "circular-dependency-plugin": "^5.2.2", diff --git a/yarn.lock b/yarn.lock index 0c52b9d3..28155abf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2677,6 +2677,11 @@ browserslist@^4.22.2: node-releases "^2.0.14" update-browserslist-db "^1.0.13" +bs-custom-file-input@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/bs-custom-file-input/-/bs-custom-file-input-1.3.4.tgz#c275cb8d4f1c02ba026324292509fa9a747dbda8" + integrity sha512-NBsQzTnef3OW1MvdKBbMHAYHssCd613MSeJV7z2McXznWtVMnJCy7Ckyc+PwxV6Pk16cu6YBcYWh/ZE0XWNKCA== + buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz" From 0d28748b8b65192f59af90869e02cef44fd0a50c Mon Sep 17 00:00:00 2001 From: f Date: Tue, 26 Mar 2024 11:42:29 -0300 Subject: [PATCH 429/472] fix: i18n --- config/locales/en.yml | 5 +---- config/locales/es.yml | 4 +--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index f024fa98..1c9f4576 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -771,10 +771,7 @@ en: categories: 'Everything' index: search: 'Search' - edit_post: 'Edit' - edit: - moderation_queue: Moderation Queue - post: Post + edit: Edit preview: btn: 'Preliminary version' alert: 'Not every article type has a preliminary version' diff --git a/config/locales/es.yml b/config/locales/es.yml index 204a3587..a96d5e60 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -712,9 +712,7 @@ es: en: 'inglés' ar: 'árabe' posts: - edit: - moderation_queue: Comentarios - post: Contenido + edit: Editar prev: Página anterior next: Página siguiente empty: No hay artículos con estos parámetros de búsqueda. From a27d68cf544d1d9d5459e32c4b2059ef0f6dbeb5 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 26 Mar 2024 12:28:19 -0300 Subject: [PATCH 430/472] fix: las llaves estaban mal nombradas!! #13578 --- app/views/env/index.js.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/env/index.js.haml b/app/views/env/index.js.haml index 597ba53f..8627fa4f 100644 --- a/app/views/env/index.js.haml +++ b/app/views/env/index.js.haml @@ -2,7 +2,7 @@ = cache @site do :plain window.env = { - AIRBRAKE_SITE_ID: #{@site.id}, - AIRBRAKE_API_KEY: "#{@site.airbrake_api_key}", + AIRBRAKE_PROJECT_ID: #{@site.id}, + AIRBRAKE_PROJECT_KEY: "#{@site.airbrake_api_key}", PANEL_URL: "#{ENV['PANEL_URL']}" } From 2fdfbb2eaa0d56fcad9c0040c54ada83e0acccbe Mon Sep 17 00:00:00 2001 From: f Date: Tue, 26 Mar 2024 12:28:40 -0300 Subject: [PATCH 431/472] fix: si no hay sitio para el panel usar el primer sitio --- app/controllers/env_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/env_controller.rb b/app/controllers/env_controller.rb index de61c704..500cdee4 100644 --- a/app/controllers/env_controller.rb +++ b/app/controllers/env_controller.rb @@ -4,7 +4,7 @@ class EnvController < ActionController::Base skip_before_action :verify_authenticity_token def index - @site = Site.find_by_name('panel') + @site = Site.find_by_name('panel') || Site.first stale? @site if @site end From a79354ceb1223d0a952ec0a1c0dc45b1d5cc1997 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 26 Mar 2024 12:28:53 -0300 Subject: [PATCH 432/472] fix: atrasar la carga de js --- app/views/layouts/application.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 16765965..eaa15eb4 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -15,7 +15,7 @@ = csrf_meta_tags = stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' = stylesheet_link_tag 'dark', rel: 'alternate stylesheet', media: 'all', 'data-turbolinks-track': 'reload', title: t('dark') - = javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' + = javascript_pack_tag 'application', 'data-turbolinks-track': 'reload', defer: true = stylesheet_pack_tag 'application', 'data-turbolinks-track': 'reload' = favicon_link_tag 'sutty_cuadrada.png', rel: 'apple-touch-icon', type: 'image/png' = render 'layouts/link_rel_alternate' From b10eef7644a23e8104b9a97019f0f0ec793976bb Mon Sep 17 00:00:00 2001 From: f Date: Tue, 26 Mar 2024 13:03:46 -0300 Subject: [PATCH 433/472] =?UTF-8?q?fix:=20botones=20en=20una=20sola=20l?= =?UTF-8?q?=C3=ADnea?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/posts/index.haml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index 6d77b75d..9def84b0 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -125,10 +125,11 @@ %br/ = post.order %td.text-nowrap - - if @usuarie || policy(post).edit? - = link_to t('posts.edit_post'), edit_site_post_path(@site, post.path), class: 'btn btn-secondary btn-block' - - if @usuarie || policy(post).destroy? - = link_to t('posts.destroy'), site_post_path(@site, post.path), class: 'btn btn-secondary btn-block', method: :delete, data: { confirm: t('posts.confirm_destroy') } + .d-flex.flex-row.align-items-start + - if @usuarie || policy(post).edit? + = link_to t('posts.edit_post'), edit_site_post_path(@site, post.path), class: 'btn btn-secondary' + - if @usuarie || policy(post).destroy? + = link_to t('posts.destroy'), site_post_path(@site, post.path), class: 'btn btn-secondary', method: :delete, data: { confirm: t('posts.confirm_destroy') } #footnotes{ hidden: true } - @filter_params.each do |param, value| From 34a858f26a20fa0095bfb3efb02ef7252944918b Mon Sep 17 00:00:00 2001 From: f Date: Tue, 26 Mar 2024 13:08:11 -0300 Subject: [PATCH 434/472] fix: botones apaisados --- app/views/layouts/_breadcrumb.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/layouts/_breadcrumb.haml b/app/views/layouts/_breadcrumb.haml index 137f086e..a946243a 100644 --- a/app/views/layouts/_breadcrumb.haml +++ b/app/views/layouts/_breadcrumb.haml @@ -13,7 +13,7 @@ %span.line-clamp-1= link_to crumb.name, crumb.url - if @current_usuarie || current_usuarie - %ul.navbar-nav + %ul.navbar-nav.flex-row - if @site&.tienda? %li.nav-item = link_to t('.tienda'), @site.tienda_url, From 263dce14358b2a71037f15f7a85e0f859c997bc0 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 26 Mar 2024 15:29:58 -0300 Subject: [PATCH 435/472] =?UTF-8?q?feat:=20poder=20traer=20algunas=20opcio?= =?UTF-8?q?nes=20de=20configuraci=C3=B3n=20desde=20la=20plantilla=20#174?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Gemfile | 1 + Gemfile.lock | 1 + app/models/site.rb | 1 + app/models/site/default_options.rb | 44 ++++++++++++++++++++++++++++++ app/services/site_service.rb | 1 + 5 files changed, 48 insertions(+) create mode 100644 app/models/site/default_options.rb diff --git a/Gemfile b/Gemfile index 466ec079..c9f735a3 100644 --- a/Gemfile +++ b/Gemfile @@ -76,6 +76,7 @@ gem 'webpacker' gem 'yaml_db', git: 'https://0xacab.org/sutty/yaml_db.git' gem 'kaminari' gem 'device_detector' +gem 'dry-schema' # database gem 'hairtrigger' diff --git a/Gemfile.lock b/Gemfile.lock index 78563c84..7b4ac1ba 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -603,6 +603,7 @@ DEPENDENCIES distributed-press-api-client (~> 0.3.0rc0) dotenv-rails down + dry-schema ed25519 email_address! exception_notification diff --git a/app/models/site.rb b/app/models/site.rb index 7b93184f..14e05e5d 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -11,6 +11,7 @@ class Site < ApplicationRecord include Site::BuildStats include Site::LayoutOrdering include Site::SocialDistributedPress + include Site::DefaultOptions include Tienda # Cifrar la llave privada que cifra y decifra campos ocultos. Sutty diff --git a/app/models/site/default_options.rb b/app/models/site/default_options.rb new file mode 100644 index 00000000..3e392782 --- /dev/null +++ b/app/models/site/default_options.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require 'dry-schema' + +class Site + # Las opciones por defecto se aplican durante la creación del sitio y + # luego se permite a les usuaries modificarlas según quieran. Por el + # momento las opciones nuevas que aparezcan no modifican un sitio que + # ya existe. + module DefaultOptions + extend ActiveSupport::Concern + + Schema = Dry::Schema.Params do + optional(:colaboracion_anonima).value(:bool) + optional(:contact).value(:bool) + optional(:acepta_invitades).value(:bool) + optional(:slugify_mode).value(included_in?: Jekyll::Utils::SLUGIFY_MODES) + optional(:pagination).value(:bool) + end + + included do + validate :validate_options_from_theme!, if: :persisted? + + # @return [Dry::Schema::Result] + def options_from_theme + @options_from_theme ||= Schema.call(data['sutty']) + end + + def update_options_from_theme + return true if options_from_theme.to_h.blank? + + update(**options_from_theme.to_h) + end + + private + + def validate_options_from_theme! + options_from_theme.errors.each do |error| + errors.add(:default_options, "#{error.path.map(&:to_s).join('/')} #{error} (#{error.input})") + end + end + end + end +end diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 5c37cfe3..8c3ea6b6 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -27,6 +27,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do site.locales = [usuarie.lang] + I18n.available_locales site.save && + site.update_options_from_theme && site.config.write && commit_config(action: :create) && site.reset.nil? && From 0975d8d5cf90c0af5265116d38be2051b37bd169 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 26 Mar 2024 15:48:30 -0300 Subject: [PATCH 436/472] fix: no fallar si no hay ninguno --- ...20231101200026_add_default_to_distributed_press_publisher.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20231101200026_add_default_to_distributed_press_publisher.rb b/db/migrate/20231101200026_add_default_to_distributed_press_publisher.rb index ada9392f..fd833acb 100644 --- a/db/migrate/20231101200026_add_default_to_distributed_press_publisher.rb +++ b/db/migrate/20231101200026_add_default_to_distributed_press_publisher.rb @@ -5,7 +5,7 @@ class AddDefaultToDistributedPressPublisher < ActiveRecord::Migration[6.1] def up add_column :distributed_press_publishers, :default, :boolean, default: false - DistributedPressPublisher.last.update(default: true) + DistributedPressPublisher.last&.update(default: true) end def down From c501107856ff21909196a024889cfae0237d047d Mon Sep 17 00:00:00 2001 From: f Date: Wed, 27 Mar 2024 12:56:54 -0300 Subject: [PATCH 437/472] fix: indicar que no hay que reportar el error closes #15621 closes #15622 closes #15623 closes #15729 closes #15730 closes #15731 closes #15735 closes #15736 closes #15824 closes #15838 closes #15839 --- app/jobs/activity_pub/process_job.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/jobs/activity_pub/process_job.rb b/app/jobs/activity_pub/process_job.rb index d94c31e2..4d9c6869 100644 --- a/app/jobs/activity_pub/process_job.rb +++ b/app/jobs/activity_pub/process_job.rb @@ -30,6 +30,9 @@ class ActivityPub # Al generar una excepción, en lugar de seguir intentando, enviamos # el reporte. + # + # @param error [Exception] + # @return [Bool] def handle_error(error) case error when ActiveRecord::RecordInvalid then retry_in(ApplicationJob.random_wait) @@ -44,6 +47,8 @@ class ActivityPub message: 'Esta acción se canceló automáticamente, para regenerarla, volver a correr el proceso con los mismos parámetros.' }) end + + false end private From c9ef1171382e41512ef77c61fd277c9f63014ca7 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 27 Mar 2024 13:36:56 -0300 Subject: [PATCH 438/472] fix: reportar errores de ssh una sola vez closes #14339 closes #14561 closes #14662 closes #15845 closes #15846 closes #15847 closes #15848 closes #15849 closes #15855 closes #15856 closes #15857 closes #15858 closes #15859 closes #15860 closes #15861 closes #15862 closes #15863 closes #15864 closes #15865 closes #15866 closes #15867 closes #15868 closes #15869 closes #15870 closes #15871 --- app/jobs/git_push_job.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/jobs/git_push_job.rb b/app/jobs/git_push_job.rb index 3c62bee2..91589189 100644 --- a/app/jobs/git_push_job.rb +++ b/app/jobs/git_push_job.rb @@ -6,6 +6,14 @@ class GitPushJob < ApplicationJob # @param :site [Site] # @return [nil] def perform(site) - site.repository.push if site.repository.origin + site.repository.push if site.repository.origin end -end \ No newline at end of file + + # Reportar una sola vez para que podamos resolver el problema, pero + # reportarlo igual. + # + # @return [Bool] + def handle_error(error) + expire + end +end From ba3cc9cad99db093c7583e5f5d29964e2c6897a0 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 27 Mar 2024 13:42:27 -0300 Subject: [PATCH 439/472] chore: rubocop --- app/jobs/git_push_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/git_push_job.rb b/app/jobs/git_push_job.rb index 91589189..7c3eb236 100644 --- a/app/jobs/git_push_job.rb +++ b/app/jobs/git_push_job.rb @@ -13,7 +13,7 @@ class GitPushJob < ApplicationJob # reportarlo igual. # # @return [Bool] - def handle_error(error) + def handle_error(_) expire end end From 142962160a9f4a9f25fcc6f3dc5c842c9fe2f177 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 27 Mar 2024 14:06:23 -0300 Subject: [PATCH 440/472] fix: reintentar en algunos errores closes #15351 closes #15352 closes #15612 closes #15618 closes #15621 closes #15622 closes #15623 closes #15729 closes #15730 closes #15731 closes #15735 closes #15736 closes #15776 closes #15824 closes #15827 closes #15828 closes #15829 closes #15830 closes #15831 closes #15832 closes #15838 closes #15839 closes #15882 --- app/jobs/activity_pub/fetch_job.rb | 34 ++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index b19d5e41..54641dbf 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -11,14 +11,42 @@ class ActivityPub class FetchJob < ApplicationJob self.priority = 50 + attr_reader :site, :object, :response + + # Notificar errores de JSON con el contenido, tomar los errores de + # validación y conexión como errores temporales y notificar todo lo + # demás sin reintentar. + # + # @param error [Exception] + # @return [Bool] + def handle_error(error) + case error + when FastJsonparser::ParseError + expire + + ExceptionNotifier.notify_exception(error, data: { site: site.name, object: object.uri, body: response.body }) + + false + when ActiveRecord::RecordInvalid, SocketError, SystemCallError, Net::OpenTimeout, OpenSSL::OpenSSLError + retry_in(ApplicationJob.random_wait) + + false + else + expire + + true + end + end + def perform(site:, object_id:) ActivityPub::Object.transaction do - object = ::ActivityPub::Object.find(object_id) + @site = site + @object = ::ActivityPub::Object.find(object_id) return if object.blank? return if object.activity_pubs.where(aasm_state: 'removed').count.positive? - response = site.social_inbox.dereferencer.get(uri: object.uri) + @response = site.social_inbox.dereferencer.get(uri: object.uri) # @todo Fallar cuando la respuesta no funcione? # @todo Eliminar en 410 Gone @@ -39,8 +67,6 @@ class ActivityPub # Arreglar las relaciones con actividades también ActivityPub.where(object_id: object.id).update_all(object_type: object.type, updated_at: Time.now) - rescue FastJsonparser::ParseError => e - ExceptionNotifier.notify_exception(e, data: { site: site.name, object: object.uri, body: response.body }) end end end From ca4017dbd0ff732b3ca6374103f04a5c178f506c Mon Sep 17 00:00:00 2001 From: f Date: Thu, 28 Mar 2024 10:09:20 -0300 Subject: [PATCH 441/472] =?UTF-8?q?fix:=20activejob=20usa=20su=20propio=20?= =?UTF-8?q?m=C3=A9todo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #15621 closes #15622 closes #15623 closes #15729 closes #15730 closes #15731 closes #15735 closes #15736 closes #15824 closes #15838 closes #15839 closes #15882 --- app/jobs/activity_pub/process_job.rb | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/app/jobs/activity_pub/process_job.rb b/app/jobs/activity_pub/process_job.rb index 4d9c6869..dd76a928 100644 --- a/app/jobs/activity_pub/process_job.rb +++ b/app/jobs/activity_pub/process_job.rb @@ -3,7 +3,9 @@ class ActivityPub # Procesar las actividades a medida que llegan class ProcessJob < ApplicationJob - attr_reader :body, :initial_state + attr_reader :body + + retry_on ActivityPub::RecordInvalid # Procesa la actividad en segundo plano # @@ -12,7 +14,6 @@ class ActivityPub def perform(site:, body:, initial_state: :paused) @site = site @body = body - @initial_state = initial_state ActiveRecord::Base.connection_pool.with_connection do ::ActivityPub.transaction do @@ -28,29 +29,6 @@ class ActivityPub end end - # Al generar una excepción, en lugar de seguir intentando, enviamos - # el reporte. - # - # @param error [Exception] - # @return [Bool] - def handle_error(error) - case error - when ActiveRecord::RecordInvalid then retry_in(ApplicationJob.random_wait) - else - ExceptionNotifier.notify_exception( - error, - data: { - site: site.name, - body: body, - initial_state: initial_state, - activity: original_activity, - message: 'Esta acción se canceló automáticamente, para regenerarla, volver a correr el proceso con los mismos parámetros.' - }) - end - - false - end - private # Si el objeto ya viene incorporado en la actividad o lo tenemos From 3f7f8878417bb034f97738de38d5e094bad0e65e Mon Sep 17 00:00:00 2001 From: f Date: Thu, 28 Mar 2024 10:13:13 -0300 Subject: [PATCH 442/472] fix: activejob gestiona errores por su cuenta closes #15351 closes #15352 closes #15612 closes #15618 closes #15621 closes #15622 closes #15623 closes #15729 closes #15730 closes #15731 closes #15735 closes #15736 closes #15776 closes #15824 closes #15827 closes #15828 closes #15829 closes #15830 closes #15831 closes #15832 closes #15838 closes #15839 closes #15882 --- app/jobs/activity_pub/fetch_job.rb | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index 54641dbf..0a3ebf03 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -19,25 +19,16 @@ class ActivityPub # # @param error [Exception] # @return [Bool] - def handle_error(error) - case error - when FastJsonparser::ParseError - expire - - ExceptionNotifier.notify_exception(error, data: { site: site.name, object: object.uri, body: response.body }) - - false - when ActiveRecord::RecordInvalid, SocketError, SystemCallError, Net::OpenTimeout, OpenSSL::OpenSSLError - retry_in(ApplicationJob.random_wait) - - false - else - expire - - true - end + discard_on(FastJsonparser::ParseError) do |error| + ExceptionNotifier.notify_exception(error, data: { site: site.name, object: object.uri, body: response.body }) end + retry_on ActiveRecord::RecordInvalid + retry_on SocketError, wait: ApplicationJob.random_wait + retry_on SystemCallError, wait: ApplicationJob.random_wait + retry_on Net::OpenTimeout, wait: ApplicationJob.random_wait + retry_on OpenSSL::OpenSSLError, wait: ApplicationJob.random_wait + def perform(site:, object_id:) ActivityPub::Object.transaction do @site = site From fe51ef2193ef18e1cfcbc25bb4faef7a1a70643a Mon Sep 17 00:00:00 2001 From: f Date: Thu, 28 Mar 2024 10:15:21 -0300 Subject: [PATCH 443/472] =?UTF-8?q?fixup!=20fix:=20activejob=20usa=20su=20?= =?UTF-8?q?propio=20m=C3=A9todo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/activity_pub/process_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/activity_pub/process_job.rb b/app/jobs/activity_pub/process_job.rb index dd76a928..69c83e33 100644 --- a/app/jobs/activity_pub/process_job.rb +++ b/app/jobs/activity_pub/process_job.rb @@ -5,7 +5,7 @@ class ActivityPub class ProcessJob < ApplicationJob attr_reader :body - retry_on ActivityPub::RecordInvalid + retry_on ActiveRecord::RecordInvalid # Procesa la actividad en segundo plano # From 94d7b32ce6fc4e4b2fbcb89717655310876086ba Mon Sep 17 00:00:00 2001 From: f Date: Tue, 9 Apr 2024 14:16:01 -0300 Subject: [PATCH 444/472] fix: handle_error no es compatible con activejob --- app/jobs/application_job.rb | 5 +++++ app/jobs/git_push_job.rb | 12 ++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb index 06690c53..8b85358c 100644 --- a/app/jobs/application_job.rb +++ b/app/jobs/application_job.rb @@ -4,6 +4,11 @@ class ApplicationJob < ActiveJob::Base include Que::ActiveJob::JobExtensions + # Si falla por cualquier cosa informar y descartar + discard_on(Exception) do |error| + ExceptionNotifier.notify_exception(error, data: { site: site.name }) + end + private def site diff --git a/app/jobs/git_push_job.rb b/app/jobs/git_push_job.rb index 7c3eb236..260e3476 100644 --- a/app/jobs/git_push_job.rb +++ b/app/jobs/git_push_job.rb @@ -3,17 +3,13 @@ # Permite pushear los cambios cada vez que se # hacen commits en un sitio class GitPushJob < ApplicationJob + attr_reader :site + # @param :site [Site] # @return [nil] def perform(site) + @site = site + site.repository.push if site.repository.origin end - - # Reportar una sola vez para que podamos resolver el problema, pero - # reportarlo igual. - # - # @return [Bool] - def handle_error(_) - expire - end end From 6dbc8fa0c12bbfcec92b16ffaa72549dd83c5c2f Mon Sep 17 00:00:00 2001 From: f Date: Tue, 9 Apr 2024 14:16:27 -0300 Subject: [PATCH 445/472] fix: reintentar compilaciones --- app/jobs/deploy_job.rb | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 3044b59f..6765bb89 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -11,13 +11,8 @@ class DeployJob < ApplicationJob # Lanzar lo antes posible self.priority = 10 - def handle_error(error) - case error - when DeployAlreadyRunningException then retry_in 1.minute - when DeployTimedOutException then expire - else super - end - end + retry_on DeployAlreadyRunningException, wait: 1.minute + discard_on DeployTimedOutException # rubocop:disable Metrics/MethodLength def perform(site, notify: true, time: Time.now, output: false) From b0bf0c0c535b8c52ce6d4fafc5a3167c95322a4e Mon Sep 17 00:00:00 2001 From: f Date: Wed, 10 Apr 2024 11:00:18 -0300 Subject: [PATCH 446/472] BREAKING CHANGE: usar global ids en los jobs --- app/controllers/api/v1/contact_controller.rb | 2 +- app/controllers/api/v1/notices_controller.rb | 2 +- app/jobs/application_job.rb | 8 ++--- app/jobs/backtrace_job.rb | 9 ++---- app/jobs/contact_job.rb | 8 ++--- app/jobs/deploy_job.rb | 32 ++++++++++---------- app/jobs/git_push_job.rb | 4 --- app/jobs/maintenance_job.rb | 3 +- app/jobs/periodic_job.rb | 3 -- app/jobs/stat_collection_job.rb | 6 ++-- app/jobs/uri_collection_job.rb | 4 +-- app/mailers/application_mailer.rb | 2 +- app/mailers/deploy_mailer.rb | 3 +- app/mailers/invitadx_mailer.rb | 9 ------ app/models/log_entry.rb | 2 +- app/services/site_service.rb | 2 +- lib/tasks/stats.rake | 6 ++-- 17 files changed, 37 insertions(+), 68 deletions(-) delete mode 100644 app/mailers/invitadx_mailer.rb diff --git a/app/controllers/api/v1/contact_controller.rb b/app/controllers/api/v1/contact_controller.rb index d949dc30..c340097f 100644 --- a/app/controllers/api/v1/contact_controller.rb +++ b/app/controllers/api/v1/contact_controller.rb @@ -18,7 +18,7 @@ module Api # Si todo salió bien, enviar los correos y redirigir al sitio. # El sitio nos dice a dónde tenemos que ir. - ContactJob.perform_later site.id, + ContactJob.perform_later site, params[:form], contact_params.to_h.symbolize_keys, params[:redirect] diff --git a/app/controllers/api/v1/notices_controller.rb b/app/controllers/api/v1/notices_controller.rb index 8f384f1a..01bec517 100644 --- a/app/controllers/api/v1/notices_controller.rb +++ b/app/controllers/api/v1/notices_controller.rb @@ -11,7 +11,7 @@ module Api # respondemos con lo mismo. def create if (site&.airbrake_valid? airbrake_token) && !detected_device.bot? - BacktraceJob.perform_later site_id: params[:site_id], + BacktraceJob.perform_later site: site, params: airbrake_params.to_h end diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb index 8b85358c..66345949 100644 --- a/app/jobs/application_job.rb +++ b/app/jobs/application_job.rb @@ -4,14 +4,10 @@ class ApplicationJob < ActiveJob::Base include Que::ActiveJob::JobExtensions + attr_reader :site + # Si falla por cualquier cosa informar y descartar discard_on(Exception) do |error| ExceptionNotifier.notify_exception(error, data: { site: site.name }) end - - private - - def site - @site ||= Site.find @params[:site_id] - end end diff --git a/app/jobs/backtrace_job.rb b/app/jobs/backtrace_job.rb index 97e6007b..830dc9b3 100644 --- a/app/jobs/backtrace_job.rb +++ b/app/jobs/backtrace_job.rb @@ -6,10 +6,9 @@ class BacktraceJob < ApplicationJob EMPTY_SOURCEMAP = { 'mappings' => '' }.freeze - attr_reader :params, :site_id + attr_reader :params - def perform(site_id:, params:) - @site_id = site_id + def perform(site:, params:) @params = params unless sources.empty? @@ -44,10 +43,6 @@ class BacktraceJob < ApplicationJob private - def site - @site ||= Site.find_by_id(site_id) - end - # Obtiene todos los archivos del backtrace solo si los puede descargar # desde fuentes seguras. # diff --git a/app/jobs/contact_job.rb b/app/jobs/contact_job.rb index c15d7eee..2ac80ce3 100644 --- a/app/jobs/contact_job.rb +++ b/app/jobs/contact_job.rb @@ -5,11 +5,7 @@ class ContactJob < ApplicationJob # @param [Integer] # @param [String] # @param [Hash] - def perform(site_id, form_name, form, origin = nil) - # Retrocompabilidad al actualizar a 2.7.1 - # @see ApplicationJob#site - @params = { site_id: site_id } - + def perform(site, form_name, form, origin = nil) # Sanitizar los valores form.each_key do |key| form[key] = ActionController::Base.helpers.sanitize form[key] @@ -23,7 +19,7 @@ class ContactJob < ApplicationJob usuaries.each_slice(10) do |u| ContactMailer.with(form_name: form_name, form: form, - site_id: site_id, + site: site, usuaries_emails: u, origin: origin) .notify_usuaries.deliver_now diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 6765bb89..103656f4 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -16,34 +16,32 @@ class DeployJob < ApplicationJob # rubocop:disable Metrics/MethodLength def perform(site, notify: true, time: Time.now, output: false) - @output = output + @site = site ActiveRecord::Base.connection_pool.with_connection do - @site = Site.find(site) - # Si ya hay una tarea corriendo, aplazar esta. Si estuvo # esperando más de 10 minutos, recuperar el estado anterior. # # Como el trabajo actual se aplaza al siguiente, arrastrar la # hora original para poder ir haciendo timeouts. - if @site.building? + if site.building? notify = false if 10.minutes.ago >= time raise DeployTimedOutException, - "#{@site.name} la tarea estuvo más de 10 minutos esperando, volviendo al estado original" + "#{site.name} la tarea estuvo más de 10 minutos esperando, volviendo al estado original" else raise DeployAlreadyRunningException end end @deployed = {} - @site.update status: 'building' - @site.deployment_list.each do |d| + site.update status: 'building' + site.deployment_list.each do |d| begin raise DeployException, 'Una dependencia falló' if failed_dependencies? d - status = d.deploy(output: @output) + status = d.deploy(output: output) seconds = d.build_stats.last.try(:seconds) || 0 size = d.size urls = d.urls.map do |url| @@ -52,7 +50,7 @@ class DeployJob < ApplicationJob nil end.compact - if d == @site.deployment_list.last && !status + if d == site.deployment_list.last && !status raise DeployException, 'Falló la compilación' end rescue StandardError => e @@ -73,7 +71,7 @@ class DeployJob < ApplicationJob } end - return unless @output + return unless output puts (Terminal::Table.new do |t| t << (%w[type] + @deployed.values.first.keys) @@ -83,12 +81,12 @@ class DeployJob < ApplicationJob end end) ensure - if @site.present? - @site.update status: 'waiting' + if site.present? + site.update status: 'waiting' notify_usuaries if notify - puts "\a" if @output + puts "\a" if output end end end @@ -118,7 +116,7 @@ class DeployJob < ApplicationJob # @param :deploy [Deploy] def notify_exception(exception, deploy = nil) data = { - site: @site.id, + site: site.name, deploy: deploy&.type, log: deploy&.build_stats&.last&.log, failed_dependencies: (failed_dependencies(deploy) if deploy) @@ -128,8 +126,10 @@ class DeployJob < ApplicationJob end def notify_usuaries - @site.roles.where(rol: 'usuarie', temporal: false).pluck(:usuarie_id).each do |usuarie| - DeployMailer.with(usuarie: usuarie, site: @site.id) + usuarie_ids = site.roles.where(rol: 'usuarie', temporal: false).pluck(:usuarie_id) + + Usuarie.where(id: usuarie_ids).find_each do |usuarie| + DeployMailer.with(usuarie_id: usuarie, site: site) .deployed(@deployed) .deliver_now end diff --git a/app/jobs/git_push_job.rb b/app/jobs/git_push_job.rb index 260e3476..d8c811ba 100644 --- a/app/jobs/git_push_job.rb +++ b/app/jobs/git_push_job.rb @@ -3,13 +3,9 @@ # Permite pushear los cambios cada vez que se # hacen commits en un sitio class GitPushJob < ApplicationJob - attr_reader :site - # @param :site [Site] # @return [nil] def perform(site) - @site = site - site.repository.push if site.repository.origin end end diff --git a/app/jobs/maintenance_job.rb b/app/jobs/maintenance_job.rb index c7a962f9..02f29a77 100644 --- a/app/jobs/maintenance_job.rb +++ b/app/jobs/maintenance_job.rb @@ -15,8 +15,7 @@ # Lo mismo para salir de mantenimiento, agregando el atributo # are_we_back: true al crear el Maintenance. class MaintenanceJob < ApplicationJob - def perform(maintenance_id:) - maintenance = Maintenance.find(maintenance_id) + def perform(maintenance:) # Decidir cuál vamos a enviar según el estado de Maintenance mailer = maintenance.are_we_back ? :were_back : :notice diff --git a/app/jobs/periodic_job.rb b/app/jobs/periodic_job.rb index 2f60a2b3..f66434c9 100644 --- a/app/jobs/periodic_job.rb +++ b/app/jobs/periodic_job.rb @@ -6,9 +6,6 @@ class PeriodicJob < ApplicationJob STARTING_INTERVAL = Stat::INTERVALS.first - # Tener el sitio a mano - attr_reader :site - # Descartar y notificar si pasó algo más. # # XXX: En realidad deberíamos seguir reintentando? diff --git a/app/jobs/stat_collection_job.rb b/app/jobs/stat_collection_job.rb index e402e3b5..02752901 100644 --- a/app/jobs/stat_collection_job.rb +++ b/app/jobs/stat_collection_job.rb @@ -7,8 +7,8 @@ class StatCollectionJob < PeriodicJob STAT_NAME = 'stat_collection_job' - def perform(site_id:, once: true) - @site = Site.find site_id + def perform(site:, once: true) + @site = site beginning = beginning_of_interval stat = site.stats.create! name: STAT_NAME @@ -22,7 +22,7 @@ class StatCollectionJob < PeriodicJob rollup.average(:seconds) end - dimensions = { site_id: site_id } + dimensions = { site_id: site.id } reduce_rollup(name: 'builds', operation: :sum, dimensions: dimensions) reduce_rollup(name: 'space_used', operation: :average, dimensions: dimensions) diff --git a/app/jobs/uri_collection_job.rb b/app/jobs/uri_collection_job.rb index 4cbbf593..92d788bc 100644 --- a/app/jobs/uri_collection_job.rb +++ b/app/jobs/uri_collection_job.rb @@ -16,8 +16,8 @@ class UriCollectionJob < PeriodicJob IMAGES = %w[.png .jpg .jpeg .gif .webp .jfif].freeze STAT_NAME = 'uri_collection_job' - def perform(site_id:, once: true) - @site = Site.find site_id + def perform(site:, once: true) + @site = site # Obtener el principio del intervalo anterior beginning_of_interval diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index 8369550d..1f1d453e 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -10,7 +10,7 @@ class ApplicationMailer < ActionMailer::Base private def site - @site ||= Site.find @params[:site_id] + @site ||= @params[:site] end def inline_logo! diff --git a/app/mailers/deploy_mailer.rb b/app/mailers/deploy_mailer.rb index 37748b42..abf6932c 100644 --- a/app/mailers/deploy_mailer.rb +++ b/app/mailers/deploy_mailer.rb @@ -13,8 +13,7 @@ class DeployMailer < ApplicationMailer # rubocop:disable Metrics/AbcSize def deployed(deploys = {}) - usuarie = Usuarie.find(params[:usuarie]) - site = usuarie.sites.find(params[:site]) + usuarie = params[:usuarie] hostname = site.hostname deploys ||= {} diff --git a/app/mailers/invitadx_mailer.rb b/app/mailers/invitadx_mailer.rb deleted file mode 100644 index cfb80a55..00000000 --- a/app/mailers/invitadx_mailer.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -class InvitadxMailer < ApplicationMailer - def confirmation_required - @invitadx = params[:invitadx] - @site = params[:site] - mail from: "#{@site.config.dig('title')} <#{ENV.fetch('DEFAULT_FROM', 'sutty@kefir.red')}>", to: @invitadx.email, subject: t('.subject') - end -end diff --git a/app/models/log_entry.rb b/app/models/log_entry.rb index 9685e0d0..7525177a 100644 --- a/app/models/log_entry.rb +++ b/app/models/log_entry.rb @@ -11,7 +11,7 @@ class LogEntry < ApplicationRecord def resend return if sent - ContactJob.perform_later site_id, params[:form], params + ContactJob.perform_later site, params[:form], params end def params diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 5c37cfe3..3a6b36f7 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -5,7 +5,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do def deploy site.enqueue! - DeployJob.perform_later site.id + DeployJob.perform_later site end # Crea un sitio, agrega un rol nuevo y guarda los cambios a la diff --git a/lib/tasks/stats.rake b/lib/tasks/stats.rake index 9461782a..fbcb5fa4 100644 --- a/lib/tasks/stats.rake +++ b/lib/tasks/stats.rake @@ -3,9 +3,9 @@ namespace :stats do desc 'Process stats' task process_all: :environment do - Site.all.pluck(:id).each do |site_id| - UriCollectionJob.perform_now site_id: site_id, once: true - StatCollectionJob.perform_now site_id: site_id, once: true + Site.all.find_each do |site| + UriCollectionJob.perform_now site: site, once: true + StatCollectionJob.perform_now site: site, once: true end end end From 629549c916d45ee79be189dbcfab536ed1396ba4 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 10 Apr 2024 11:49:30 -0300 Subject: [PATCH 447/472] =?UTF-8?q?fix:=20rehabilitar=20el=20bot=C3=B3n=20?= =?UTF-8?q?tambi=C3=A9n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/posts/index.haml | 2 -- app/views/sites/_status.haml | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index 374f06ee..29f6471f 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -4,8 +4,6 @@ = render 'sites/status', site: @site - = render 'sites/build', site: @site, class: 'btn-block' - %h3= t('posts.new') %table.table.table-sm.mb-3 %tbody diff --git a/app/views/sites/_status.haml b/app/views/sites/_status.haml index 47bed657..d3da5c73 100644 --- a/app/views/sites/_status.haml +++ b/app/views/sites/_status.haml @@ -22,3 +22,5 @@ %div{ 'hx-get': site_status_path(site), 'hx-trigger': 'every 10s', 'hx-swap': 'outerHTML' } = render 'bootstrap/alert' do = link_to_if link, message.html_safe, site_build_stats_path(site), class: 'alert-link' + + = render 'sites/build', site: site, class: 'btn-block' From 7cca88b4f3ce0845cdbdfb55885b406b89199d1d Mon Sep 17 00:00:00 2001 From: f Date: Wed, 10 Apr 2024 12:15:30 -0300 Subject: [PATCH 448/472] =?UTF-8?q?fix:=20al=20salir=20de=20la=20p=C3=A1gi?= =?UTF-8?q?na,=20cancelar=20todas=20las=20peticiones=20de=20htmx?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #15880 closes #15881 closes #15883 closes #15884 closes #15893 closes #15894 closes #15973 closes #15974 closes #15975 closes #16003 closes #16004 --- app/javascript/etc/htmx_abort.js | 7 +++++++ app/javascript/etc/index.js | 1 + 2 files changed, 8 insertions(+) create mode 100644 app/javascript/etc/htmx_abort.js diff --git a/app/javascript/etc/htmx_abort.js b/app/javascript/etc/htmx_abort.js new file mode 100644 index 00000000..308d0315 --- /dev/null +++ b/app/javascript/etc/htmx_abort.js @@ -0,0 +1,7 @@ +// Cancela las peticiones pendientes de htmx para todos los elementos al +// cambiar de página. +document.addEventListener("turbolinks:click", () => { + for (const hx of document.querySelectorAll("[hx-get]")) { + window.htmx.trigger(hx, "htmx:abort"); + } +}); diff --git a/app/javascript/etc/index.js b/app/javascript/etc/index.js index d4b9f7a3..9ee6a95a 100644 --- a/app/javascript/etc/index.js +++ b/app/javascript/etc/index.js @@ -7,3 +7,4 @@ import './timezone' import './turbolinks-anchors' import './validation' import './new_editor' +import './htmx_abort' From 53fe2847a1ca5adb96776bb2b74730ec51de1b81 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 10 Apr 2024 13:22:17 -0300 Subject: [PATCH 449/472] fixup! BREAKING CHANGE: usar global ids en los jobs --- app/jobs/deploy_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 103656f4..f84dc55c 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -129,7 +129,7 @@ class DeployJob < ApplicationJob usuarie_ids = site.roles.where(rol: 'usuarie', temporal: false).pluck(:usuarie_id) Usuarie.where(id: usuarie_ids).find_each do |usuarie| - DeployMailer.with(usuarie_id: usuarie, site: site) + DeployMailer.with(usuarie: usuarie, site: site) .deployed(@deployed) .deliver_now end From 847af3374ce02fa352b7ce163ddebbb5d19da247 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 10 Apr 2024 13:26:22 -0300 Subject: [PATCH 450/472] =?UTF-8?q?fix:=20no=20multiplicar=20el=20bot?= =?UTF-8?q?=C3=B3n!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/sites/_status.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/sites/_status.haml b/app/views/sites/_status.haml index d3da5c73..9ac27c15 100644 --- a/app/views/sites/_status.haml +++ b/app/views/sites/_status.haml @@ -23,4 +23,4 @@ = render 'bootstrap/alert' do = link_to_if link, message.html_safe, site_build_stats_path(site), class: 'alert-link' - = render 'sites/build', site: site, class: 'btn-block' + = render 'sites/build', site: site, class: 'btn-block' From 5e1def1028cb1946e2b2f232cc4aaa3bad9c189c Mon Sep 17 00:00:00 2001 From: f Date: Wed, 10 Apr 2024 13:32:37 -0300 Subject: [PATCH 451/472] =?UTF-8?q?feat:=20deshabilitar=20el=20bot=C3=B3n?= =?UTF-8?q?=20mientras=20est=C3=A1=20compilando=20tambi=C3=A9n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit para no lanzar más de una compilación por vez --- app/views/sites/_build.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/sites/_build.haml b/app/views/sites/_build.haml index b0961e31..c723a3ac 100644 --- a/app/views/sites/_build.haml +++ b/app/views/sites/_build.haml @@ -6,4 +6,4 @@ class: "btn btn-secondary #{local_assigns[:class]}", title: site.enqueued? ? t('help.sites.enqueued') : t('help.sites.enqueue'), data: { disable_with: t('sites.enqueued') }, - disabled: site.enqueued? + disabled: !site.waiting? From c80984888c7eb8d726c37882750c58e0ab454a0a Mon Sep 17 00:00:00 2001 From: f Date: Wed, 10 Apr 2024 15:16:09 -0300 Subject: [PATCH 452/472] =?UTF-8?q?feat:=20recordar=20la=20ubicaci=C3=B3n?= =?UTF-8?q?=20#15188?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/application_controller.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 2746ab10..617ce665 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -11,6 +11,7 @@ class ApplicationController < ActionController::Base before_action :configure_permitted_parameters, if: :devise_controller? before_action :notify_unconfirmed_email, unless: :devise_controller? around_action :set_locale + after_action :store_location! rescue_from Pundit::NilPolicyError, with: :page_not_found rescue_from ActionController::RoutingError, with: :page_not_found @@ -115,6 +116,16 @@ class ApplicationController < ActionController::Base def after_sign_in_path_for(resource) session[:locale] = nil - sites_path + super + end + + # Guardar la ubicación para que devise redirija a donde íbamos, a + # menos que estemos recibiendo información o intentando ingresar. + def store_location! + return if request.xhr? + return unless request.request_method_symbol == :GET + return if devise_controller? && !is_a?(Devise::RegistrationsController) && params[:action] != 'edit' + + session[:usuarie_return_to] = request.fullpath end end From 11660bc68829157b4c28235f3ad728d8001c879e Mon Sep 17 00:00:00 2001 From: f Date: Fri, 12 Apr 2024 10:01:53 -0300 Subject: [PATCH 453/472] fix: editor --- package.json | 2 +- yarn.lock | 35 +++++++++++++++++++++++++++++++---- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 7901ad41..480f3d0b 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "@rails/activestorage": "^6.1.3-1", "@rails/ujs": "^6.1.3-1", "@rails/webpacker": "5.4.4", - "@suttyweb/editor": "^0.1.25", + "@suttyweb/editor": "^0.1.26", "babel-loader": "^8.2.2", "chart.js": "^3.5.1", "chartkick": "^4.0.5", diff --git a/yarn.lock b/yarn.lock index 0c52b9d3..69cf4edf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1821,6 +1821,26 @@ resolved "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz" integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw== +"@floating-ui/core@^1.0.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.0.tgz#fa41b87812a16bf123122bf945946bae3fdf7fc1" + integrity sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g== + dependencies: + "@floating-ui/utils" "^0.2.1" + +"@floating-ui/dom@^1.5.1": + version "1.6.3" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.3.tgz#954e46c1dd3ad48e49db9ada7218b0985cee75ef" + integrity sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw== + dependencies: + "@floating-ui/core" "^1.0.0" + "@floating-ui/utils" "^0.2.0" + +"@floating-ui/utils@^0.2.0", "@floating-ui/utils@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.1.tgz#16308cea045f0fc777b6ff20a9f25474dd8293d2" + integrity sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q== + "@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": version "0.3.3" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" @@ -1955,11 +1975,13 @@ resolved "https://registry.npmjs.org/@stimulus/webpack-helpers/-/webpack-helpers-1.1.1.tgz" integrity sha512-XOkqSw53N9072FLHvpLM25PIwy+ndkSSbnTtjKuyzsv8K5yfkFB2rv68jU1pzqYa9FZLcvZWP4yazC0V38dx9A== -"@suttyweb/editor@^0.1.25": - version "0.1.25" - resolved "https://registry.yarnpkg.com/@suttyweb/editor/-/editor-0.1.25.tgz#37b38560642a49b24383473543c28be943695f9f" - integrity sha512-fxOO9LpdntWzgNZch4cZB6QL0u+jEw0NqsNahKcGBbiJaS0GNGLRrT2LUd/Djc6O8HWkQguPLcquVT5eHq2h9g== +"@suttyweb/editor@^0.1.26": + version "0.1.26" + resolved "https://registry.yarnpkg.com/@suttyweb/editor/-/editor-0.1.26.tgz#ba59db20bd6faa7b43d44b764c0bc7b25f461e06" + integrity sha512-nT1DaQjaPBwVG4FofSF0AoiPzIZfAdW6oRX9KOegM99MicvyoBZyItmuGyxl6lv9hpDKa8DwR4W8Cd5ZAD6S7w== dependencies: + "@floating-ui/dom" "^1.5.1" + linkifyjs "^4.1.1" prosemirror-svelte-nodeview "^1.0.2" "@types/caseless@*": @@ -5190,6 +5212,11 @@ linkify-it@^2.0.0: dependencies: uc.micro "^1.0.1" +linkifyjs@^4.1.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-4.1.3.tgz#0edbc346428a7390a23ea2e5939f76112c9ae07f" + integrity sha512-auMesunaJ8yfkHvK4gfg1K0SaKX/6Wn9g2Aac/NwX+l5VdmFZzo/hdPGxEOETj+ryRa4/fiOPjeeKURSAJx1sg== + loader-runner@^2.4.0: version "2.4.0" resolved "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz" From 7a71e1de8856f241e271d14ff3cf04c28544ed8a Mon Sep 17 00:00:00 2001 From: f Date: Fri, 12 Apr 2024 15:31:47 -0300 Subject: [PATCH 454/472] fix: no fallar si no hay sitio #16007 --- app/jobs/application_job.rb | 2 +- app/jobs/backtrace_job.rb | 1 + app/jobs/contact_job.rb | 2 ++ app/jobs/git_pull_job.rb | 2 ++ app/jobs/git_push_job.rb | 2 ++ 5 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb index 66345949..37ec0f76 100644 --- a/app/jobs/application_job.rb +++ b/app/jobs/application_job.rb @@ -8,6 +8,6 @@ class ApplicationJob < ActiveJob::Base # Si falla por cualquier cosa informar y descartar discard_on(Exception) do |error| - ExceptionNotifier.notify_exception(error, data: { site: site.name }) + ExceptionNotifier.notify_exception(error, data: { site: @site&.name }) end end diff --git a/app/jobs/backtrace_job.rb b/app/jobs/backtrace_job.rb index 830dc9b3..5e9a05cf 100644 --- a/app/jobs/backtrace_job.rb +++ b/app/jobs/backtrace_job.rb @@ -9,6 +9,7 @@ class BacktraceJob < ApplicationJob attr_reader :params def perform(site:, params:) + @site = site @params = params unless sources.empty? diff --git a/app/jobs/contact_job.rb b/app/jobs/contact_job.rb index 2ac80ce3..d4c2677f 100644 --- a/app/jobs/contact_job.rb +++ b/app/jobs/contact_job.rb @@ -6,6 +6,8 @@ class ContactJob < ApplicationJob # @param [String] # @param [Hash] def perform(site, form_name, form, origin = nil) + @site = site + # Sanitizar los valores form.each_key do |key| form[key] = ActionController::Base.helpers.sanitize form[key] diff --git a/app/jobs/git_pull_job.rb b/app/jobs/git_pull_job.rb index 58a4e6b1..72e20be0 100644 --- a/app/jobs/git_pull_job.rb +++ b/app/jobs/git_pull_job.rb @@ -7,6 +7,8 @@ class GitPullJob < ApplicationJob # @param :usuarie [Usuarie] # @return [nil] def perform(site, usuarie) + @site = site + return unless site.repository.origin return unless site.repository.fetch.positive? diff --git a/app/jobs/git_push_job.rb b/app/jobs/git_push_job.rb index d8c811ba..4df9f5aa 100644 --- a/app/jobs/git_push_job.rb +++ b/app/jobs/git_push_job.rb @@ -6,6 +6,8 @@ class GitPushJob < ApplicationJob # @param :site [Site] # @return [nil] def perform(site) + @site = site + site.repository.push if site.repository.origin end end From 4ccf37c370cdb3eac19b1ae8b1d222e3a8b7d52c Mon Sep 17 00:00:00 2001 From: f Date: Mon, 15 Apr 2024 11:54:28 -0300 Subject: [PATCH 455/472] =?UTF-8?q?fix:=20informar=20la=20tarea=20que=20fa?= =?UTF-8?q?ll=C3=B3=20de=20forma=20gen=C3=A9rica?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #16052 closes #16058 closes #16059 --- app/jobs/application_job.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb index 37ec0f76..d527c9b9 100644 --- a/app/jobs/application_job.rb +++ b/app/jobs/application_job.rb @@ -7,7 +7,7 @@ class ApplicationJob < ActiveJob::Base attr_reader :site # Si falla por cualquier cosa informar y descartar - discard_on(Exception) do |error| - ExceptionNotifier.notify_exception(error, data: { site: @site&.name }) + discard_on(Exception) do |job, error| + ExceptionNotifier.notify_exception(error, data: { job: job }) end end From fb4228b873e5e1873b82c38498c18f992df73fdb Mon Sep 17 00:00:00 2001 From: f Date: Mon, 15 Apr 2024 16:58:55 -0300 Subject: [PATCH 456/472] =?UTF-8?q?fix:=20no=20filtrar=20informaci=C3=B3n?= =?UTF-8?q?=20privada!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/application_record.rb | 7 +++++++ config/initializers/filter_parameter_logging.rb | 1 + 2 files changed, 8 insertions(+) diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 71fbba5b..27ed3d56 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -2,4 +2,11 @@ class ApplicationRecord < ActiveRecord::Base self.abstract_class = true + + # Obtener una lista filtrada de atributos al momento de serializar + # + # @return [Hash] + def to_yaml(options = {}) + self.class.inspection_filter.filter attributes + end end diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb index 2fc446ff..8ef6ca49 100644 --- a/config/initializers/filter_parameter_logging.rb +++ b/config/initializers/filter_parameter_logging.rb @@ -5,4 +5,5 @@ # Configure sensitive parameters which will be filtered from the log file. Rails.application.config.filter_parameters += %i[ password passw secret token _key crypt salt certificate otp ssn key + _pem _ciphertext ] From 7f437f9e0659ae648c9d90e4c3ebf1d8ac760a3f Mon Sep 17 00:00:00 2001 From: f Date: Mon, 15 Apr 2024 17:00:58 -0300 Subject: [PATCH 457/472] =?UTF-8?q?fix:=20filtrar=20informaci=C3=B3n=20per?= =?UTF-8?q?sonal=20tambi=C3=A9n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/initializers/filter_parameter_logging.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb index 8ef6ca49..b1d9f2b0 100644 --- a/config/initializers/filter_parameter_logging.rb +++ b/config/initializers/filter_parameter_logging.rb @@ -5,5 +5,5 @@ # Configure sensitive parameters which will be filtered from the log file. Rails.application.config.filter_parameters += %i[ password passw secret token _key crypt salt certificate otp ssn key - _pem _ciphertext + _pem _ciphertext email ] From e8cf50b9d22154294b7ca03782d9ffa001273467 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 15 Apr 2024 17:10:19 -0300 Subject: [PATCH 458/472] fix: convertir a yaml --- app/models/application_record.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 27ed3d56..985df966 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -5,8 +5,8 @@ class ApplicationRecord < ActiveRecord::Base # Obtener una lista filtrada de atributos al momento de serializar # - # @return [Hash] + # @return [String] def to_yaml(options = {}) - self.class.inspection_filter.filter attributes + self.class.inspection_filter.filter(attributes).to_yaml(options) end end From 83add8dd7def7b58dfb741d5c51106576f3a0882 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 15 Apr 2024 17:26:40 -0300 Subject: [PATCH 459/472] =?UTF-8?q?fix:=20usar=20una=20versi=C3=B3n=20m?= =?UTF-8?q?=C3=A1s=20corta=20del=20hash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/application_record.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 985df966..f09c4dd4 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -7,6 +7,6 @@ class ApplicationRecord < ActiveRecord::Base # # @return [String] def to_yaml(options = {}) - self.class.inspection_filter.filter(attributes).to_yaml(options) + self.class.inspection_filter.filter(serializable_hash).to_yaml(options) end end From 2eb3145e1cf20581216b1ddcecebe6ee57f41e45 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 15 Apr 2024 17:28:30 -0300 Subject: [PATCH 460/472] fix: los atributos filtrados son por modelo --- app/models/site.rb | 2 ++ app/models/usuarie.rb | 2 ++ 2 files changed, 4 insertions(+) diff --git a/app/models/site.rb b/app/models/site.rb index 7b93184f..c47a14a2 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -13,6 +13,8 @@ class Site < ApplicationRecord include Site::SocialDistributedPress include Tienda + self.filter_attributes += [/_key/, /_ciphertext\z/] + # Cifrar la llave privada que cifra y decifra campos ocultos. Sutty # tiene acceso pero los datos se guardan cifrados en el sitio. Esto # protege información privada en repositorios públicos, pero no la diff --git a/app/models/usuarie.rb b/app/models/usuarie.rb index 42f20c0b..4eba314a 100644 --- a/app/models/usuarie.rb +++ b/app/models/usuarie.rb @@ -21,6 +21,8 @@ class Usuarie < ApplicationRecord has_many :blazer_audits, foreign_key: 'user_id', class_name: 'Blazer::Audit' has_many :blazer_queries, foreign_key: 'creator_id', class_name: 'Blazer::Query' + self.filter_attributes += [/\Aemail\z/, /\Aencrypted_password\z/] + def name email.split('@', 2).first end From 452ca435081af9d29af1b1a03e2d99a221588942 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 19 Apr 2024 13:07:49 -0300 Subject: [PATCH 461/472] =?UTF-8?q?fix:=20doble=20negaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/components/_profiles_btn_box.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/components/_profiles_btn_box.haml b/app/views/components/_profiles_btn_box.haml index 8fc8dd39..2023de96 100644 --- a/app/views/components/_profiles_btn_box.haml +++ b/app/views/components/_profiles_btn_box.haml @@ -2,7 +2,7 @@ .d-flex.flex-row.w-100 - local = { report: { class: 'ml-auto', data: { confirm: t('.confirm_report') } } } - ActorModeration.events.each do |actor_event| - - possible = !actor_moderation.public_send(:"may_#{actor_event}?") + - possible = actor_moderation.public_send(:"may_#{actor_event}?") %div{ class: local.dig(actor_event, :class) } = render 'components/btn_base', text: t(".text_#{actor_event}"), From 14c5530b501edd114828d0ec0b8b0541da0b9ff1 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 22 Apr 2024 11:06:25 -0300 Subject: [PATCH 462/472] feat: editor 0.1.27 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 480f3d0b..2bff3159 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "@rails/activestorage": "^6.1.3-1", "@rails/ujs": "^6.1.3-1", "@rails/webpacker": "5.4.4", - "@suttyweb/editor": "^0.1.26", + "@suttyweb/editor": "^0.1.27", "babel-loader": "^8.2.2", "chart.js": "^3.5.1", "chartkick": "^4.0.5", From 044b14c355c3d50a11dfdd935b31894dce1b7713 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 22 Apr 2024 11:15:09 -0300 Subject: [PATCH 463/472] fixup! feat: editor 0.1.27 --- yarn.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index 69cf4edf..7e1d597c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1975,10 +1975,10 @@ resolved "https://registry.npmjs.org/@stimulus/webpack-helpers/-/webpack-helpers-1.1.1.tgz" integrity sha512-XOkqSw53N9072FLHvpLM25PIwy+ndkSSbnTtjKuyzsv8K5yfkFB2rv68jU1pzqYa9FZLcvZWP4yazC0V38dx9A== -"@suttyweb/editor@^0.1.26": - version "0.1.26" - resolved "https://registry.yarnpkg.com/@suttyweb/editor/-/editor-0.1.26.tgz#ba59db20bd6faa7b43d44b764c0bc7b25f461e06" - integrity sha512-nT1DaQjaPBwVG4FofSF0AoiPzIZfAdW6oRX9KOegM99MicvyoBZyItmuGyxl6lv9hpDKa8DwR4W8Cd5ZAD6S7w== +"@suttyweb/editor@^0.1.27": + version "0.1.27" + resolved "https://registry.yarnpkg.com/@suttyweb/editor/-/editor-0.1.27.tgz#9415a0b767e72dbe4fbf42ce87e62fb8f5125c31" + integrity sha512-Ts9TZtGiRIaHm+ffVBRl+/nuVcANWZNtFsrGacoajgEsagaIyA1cq8qjiNpPoM5ne9vTba3cAaLP04V/uEIhBw== dependencies: "@floating-ui/dom" "^1.5.1" linkifyjs "^4.1.1" From 8de05ccce6d2d7e9cfc8e509350bc0d6d1675311 Mon Sep 17 00:00:00 2001 From: f Date: Mon, 22 Apr 2024 14:54:40 -0300 Subject: [PATCH 464/472] fix: solo permitir los mismos tipos de archivo que jekyll closes #16117 --- app/lib/jekyll/readers/data_reader_decorator.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/lib/jekyll/readers/data_reader_decorator.rb b/app/lib/jekyll/readers/data_reader_decorator.rb index 9fed7ac7..2a2a8fc2 100644 --- a/app/lib/jekyll/readers/data_reader_decorator.rb +++ b/app/lib/jekyll/readers/data_reader_decorator.rb @@ -14,6 +14,8 @@ module Jekyll extend ActiveSupport::Concern included do + DATA_EXTENSIONS = %w[.yaml .yml .json .csv .tsv].freeze + def read_data_to(dir, data) return unless File.directory?(dir) && !@entry_filter.symlink?(dir) @@ -24,7 +26,7 @@ module Jekyll if File.directory?(path) read_data_to(path, data[sanitize_filename(entry)] = {}) - else + elsif DATA_EXTENSIONS.include?(File.extname(entry)) key = sanitize_filename(File.basename(entry, ".*")) data[key] = read_data_file(path) end From 5f0672bcaebd1d68d81738c9d74f4275eb6866b9 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 30 Apr 2024 17:44:33 -0300 Subject: [PATCH 465/472] =?UTF-8?q?feat:=20recargar=20el=20bot=C3=B3n=20de?= =?UTF-8?q?=20publicar=20por=20separado=20#16180?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/sites_controller.rb | 6 ++++++ app/policies/site_policy.rb | 4 ++++ app/views/posts/index.haml | 1 + app/views/sites/_build.haml | 17 +++++++++-------- app/views/sites/_status.haml | 4 +--- app/views/sites/build.haml | 1 + config/routes.rb | 1 + 7 files changed, 23 insertions(+), 11 deletions(-) create mode 100644 app/views/sites/build.haml diff --git a/app/controllers/sites_controller.rb b/app/controllers/sites_controller.rb index 49527cf7..e911daac 100644 --- a/app/controllers/sites_controller.rb +++ b/app/controllers/sites_controller.rb @@ -22,6 +22,12 @@ class SitesController < ApplicationController render('sites/status', layout: false) if stale? site end + def button + authorize site + + render('sites/build', layout: false) + end + # No tenemos propiedades de un sitio aún, así que vamos al listado de # artículos def show diff --git a/app/policies/site_policy.rb b/app/policies/site_policy.rb index d5465d6b..ce56a2e7 100644 --- a/app/policies/site_policy.rb +++ b/app/policies/site_policy.rb @@ -61,6 +61,10 @@ class SitePolicy show? && usuarie? end + def button? + show? + end + def enqueue? build? end diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml index 29f6471f..3ea82309 100644 --- a/app/views/posts/index.haml +++ b/app/views/posts/index.haml @@ -3,6 +3,7 @@ = render 'sites/header', site: @site = render 'sites/status', site: @site + = render 'sites/build', site: @site, class: 'btn-block' %h3= t('posts.new') %table.table.table-sm.mb-3 diff --git a/app/views/sites/_build.haml b/app/views/sites/_build.haml index c723a3ac..8db4d370 100644 --- a/app/views/sites/_build.haml +++ b/app/views/sites/_build.haml @@ -1,9 +1,10 @@ - if policy(site).build? - = form_tag site_enqueue_path(site), - method: :post, - class: 'form-inline inline' do - = submit_tag site.enqueued? ? t('sites.enqueued') : t('sites.enqueue'), - class: "btn btn-secondary #{local_assigns[:class]}", - title: site.enqueued? ? t('help.sites.enqueued') : t('help.sites.enqueue'), - data: { disable_with: t('sites.enqueued') }, - disabled: !site.waiting? + %div{ 'hx-get': site_button_path(site, class: local_assigns[:class]), 'hx-trigger': 'every 10s', 'hx-swap': 'outerHTML' } + = form_tag site_enqueue_path(site), + method: :post, + class: 'form-inline inline' do + = submit_tag site.enqueued? ? t('sites.enqueued') : t('sites.enqueue'), + class: "btn btn-secondary #{local_assigns[:class]}", + title: site.enqueued? ? t('help.sites.enqueued') : t('help.sites.enqueue'), + data: { disable_with: t('sites.enqueued') }, + disabled: !site.waiting? diff --git a/app/views/sites/_status.haml b/app/views/sites/_status.haml index 9ac27c15..a3dfd4ad 100644 --- a/app/views/sites/_status.haml +++ b/app/views/sites/_status.haml @@ -18,9 +18,7 @@ - message = t('.available') - link = true - -# TODO: Calcular cada cuanto sería óptimo recargar + -# TODO: Calcular cada cuánto sería óptimo recargar %div{ 'hx-get': site_status_path(site), 'hx-trigger': 'every 10s', 'hx-swap': 'outerHTML' } = render 'bootstrap/alert' do = link_to_if link, message.html_safe, site_build_stats_path(site), class: 'alert-link' - - = render 'sites/build', site: site, class: 'btn-block' diff --git a/app/views/sites/build.haml b/app/views/sites/build.haml new file mode 100644 index 00000000..c2becec0 --- /dev/null +++ b/app/views/sites/build.haml @@ -0,0 +1 @@ += render 'sites/build', site: @site, class: params.permit(:class)[:class] diff --git a/config/routes.rb b/config/routes.rb index 557439e9..d97611fd 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -38,6 +38,7 @@ Rails.application.routes.draw do post 'pull', to: 'sites#merge' get 'status', to: 'sites#status' + get 'button', to: 'sites#button' # Gestionar usuaries get 'usuaries/invite', to: 'usuaries#invite' From 79be9538bb8ccf9350e5e4cb71150e92440fdcb6 Mon Sep 17 00:00:00 2001 From: f Date: Tue, 30 Apr 2024 17:45:33 -0300 Subject: [PATCH 466/472] fix: ignorar los errores de abort de htmx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit el problema es que cuando se envía un abort a htmx, se loguea un mensaje de todas formas. closes #15880 closes #15881 closes #15883 closes #15884 closes #15893 closes #15894 closes #15973 closes #15974 closes #15975 closes #16003 closes #16004 closes #16015 closes #16016 closes #16023 closes #16024 closes #16050 closes #16051 closes #16063 closes #16064 closes #16073 closes #16074 closes #16116 closes #16125 closes #16126 --- app/javascript/packs/application.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index d8ff0dd1..e10e2b5d 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -9,9 +9,16 @@ try { host: window.env.PANEL_URL }); + const ignoredErrors = ["htmx:afterRequest", "htmx:sendAbort"]; + console.originalError = console.error; console.error = (...e) => { - window.airbrake.notify(e.join(" ")); + const msg = e.join(" "); + + if (!ignoredErrors.some(x => msg.includes(x))) { + window.airbrake.notify(e.join(" ")); + } + return console.originalError(...e); }; } catch(e) { From 4f12d1211824ca2cd6652001aadf5592f5396a48 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 2 May 2024 15:49:20 -0300 Subject: [PATCH 467/472] ci: usar los locks para identificar la cache [skip ci] --- .gitlab-ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bb674844..dceb1a42 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,9 +6,15 @@ - paths: - "vendor/ruby" - ".bundle" + key: + files: + - "Gemfile.lock" .cache-node: &cache-node - paths: - "node_modules" + key: + files: + - "yarn.lock" .cache-task: &cache-task - paths: - ".task" From 9c0ea76c219fc5db9d2972e3118418bcd7f01d31 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 2 May 2024 15:54:54 -0300 Subject: [PATCH 468/472] ci: instalar gemas [skip ci] --- Taskfile.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Taskfile.yaml b/Taskfile.yaml index 57fb0238..796ab721 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -185,9 +185,13 @@ tasks: - "test -f ../hain/usr/bin/bundler-audit" rubocop: desc: "Ruby linting" + deps: + - "gems" cmds: - "./bin/modified_files | ./bin/with_extension rb | xargs -r {{.HAINISH}} bundle exec rubocop {{.CLI_ARGS}}" haml-lint: desc: "HAML linting" + deps: + - "gems" cmds: - "./bin/modified_files | ./bin/with_extension haml | xargs -r {{.HAINISH}} bundle exec haml-lint {{.CLI_ARGS}}" From 8fba98f9fd0da1a1e5949e5a729d4de8d74059f8 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 2 May 2024 15:57:49 -0300 Subject: [PATCH 469/472] chore: rubocop --- app/jobs/backtrace_job.rb | 4 +--- app/jobs/deploy_job.rb | 17 +++++++---------- app/models/site.rb | 18 +++++++++--------- app/models/usuarie.rb | 10 +++++----- app/services/site_service.rb | 4 +--- 5 files changed, 23 insertions(+), 30 deletions(-) diff --git a/app/jobs/backtrace_job.rb b/app/jobs/backtrace_job.rb index 5e9a05cf..4ef5287c 100644 --- a/app/jobs/backtrace_job.rb +++ b/app/jobs/backtrace_job.rb @@ -55,9 +55,7 @@ class BacktraceJob < ApplicationJob x['backtrace'] end.flatten.map do |x| x['file'].split('@').last - end.uniq.select do |x| - %r{\Ahttps://} =~ x - end + end.uniq.grep(%r{\Ahttps://}) end # Descarga y devuelve los datos de un archivo diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index f84dc55c..66cccd1b 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -27,12 +27,11 @@ class DeployJob < ApplicationJob if site.building? notify = false - if 10.minutes.ago >= time - raise DeployTimedOutException, - "#{site.name} la tarea estuvo más de 10 minutos esperando, volviendo al estado original" - else - raise DeployAlreadyRunningException - end + raise DeployAlreadyRunningException unless 10.minutes.ago >= time + + raise DeployTimedOutException, + "#{site.name} la tarea estuvo más de 10 minutos esperando, volviendo al estado original" + end @deployed = {} @@ -50,9 +49,7 @@ class DeployJob < ApplicationJob nil end.compact - if d == site.deployment_list.last && !status - raise DeployException, 'Falló la compilación' - end + raise DeployException, 'Falló la compilación' if d == site.deployment_list.last && !status rescue StandardError => e status = false seconds ||= 0 @@ -73,7 +70,7 @@ class DeployJob < ApplicationJob return unless output - puts (Terminal::Table.new do |t| + puts(Terminal::Table.new do |t| t << (%w[type] + @deployed.values.first.keys) t.add_separator @deployed.each do |type, row| diff --git a/app/models/site.rb b/app/models/site.rb index e3068734..f51d2c6f 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -292,11 +292,11 @@ class Site < ApplicationRecord # layouts. Si pasamos un layout que no existe, obtenemos un # NoMethodError @layouts_struct ||= Struct.new(*layout_keys, keyword_init: true) - @layouts ||= @layouts_struct.new(**data['layouts'].map do |name, metadata| + @layouts ||= @layouts_struct.new(**data['layouts'].to_h do |name, metadata| [name.to_sym, Layout.new(site: self, name: name.to_sym, meta: metadata.delete('meta')&.with_indifferent_access, metadata: metadata.with_indifferent_access)] - end.to_h) + end) end # TODO: Si la estructura de datos no existe, vamos a producir una @@ -389,7 +389,7 @@ class Site < ApplicationRecord end def reload - super.tap do |s| + super.tap do |_s| reload_jekyll! end self @@ -479,7 +479,7 @@ class Site < ApplicationRecord def clone_skel! return if jekyll? - Rugged::Repository.clone_at(ENV['SKEL_SUTTY'], path, checkout_branch: design.gem) + Rugged::Repository.clone_at(ENV.fetch('SKEL_SUTTY', nil), path, checkout_branch: design.gem) # Necesita un bloque repository.rugged.remotes.rename('origin', 'upstream') {} @@ -579,11 +579,11 @@ class Site < ApplicationRecord deploy_local = deploys.find_by_type('DeployLocal') deploy_local.git_lfs - if !gems_installed? || gemfile_updated? || gemfile_lock_updated? - deploy_local.bundle - touch - FileUtils.touch(gemfile_path) - end + return unless !gems_installed? || gemfile_updated? || gemfile_lock_updated? + + deploy_local.bundle + touch + FileUtils.touch(gemfile_path) end def gem_path diff --git a/app/models/usuarie.rb b/app/models/usuarie.rb index 4eba314a..4856f17f 100644 --- a/app/models/usuarie.rb +++ b/app/models/usuarie.rb @@ -76,10 +76,10 @@ class Usuarie < ApplicationRecord # Si le usuarie (re)confirma su cuenta con una invitación pendiente, # considerarla aceptada también. def accept_invitation_after_confirmation! - if confirmed? - self.invitation_token = nil - self.invitation_accepted_at ||= Time.now.utc - end + return unless confirmed? + + self.invitation_token = nil + self.invitation_accepted_at ||= Time.now.utc end # Muestra un error si el idioma no está disponible al cambiar el @@ -87,7 +87,7 @@ class Usuarie < ApplicationRecord # # @return [nil] def locale_available! - return if I18n.locale_available? self.lang + return if I18n.locale_available? lang errors.add(:lang, I18n.t('activerecord.errors.models.usuarie.attributes.lang.not_available')) nil diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 3a6b36f7..a28e5ee8 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -222,9 +222,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do end end - private - - def with_all_locales(&block) + def with_all_locales site.locales.map do |locale| next unless I18n.available_locales.include? locale From b11282997b8574c093e0742b6409b4378e966df3 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 2 May 2024 16:02:34 -0300 Subject: [PATCH 470/472] fix: redundante --- app/jobs/activity_pub/fetch_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index 0a3ebf03..5d9e02de 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -11,7 +11,7 @@ class ActivityPub class FetchJob < ApplicationJob self.priority = 50 - attr_reader :site, :object, :response + attr_reader :object, :response # Notificar errores de JSON con el contenido, tomar los errores de # validación y conexión como errores temporales y notificar todo lo From c2cc08007e6d3018a929e61d7727f226380c074c Mon Sep 17 00:00:00 2001 From: f Date: Thu, 2 May 2024 16:05:35 -0300 Subject: [PATCH 471/472] chore: rubocop --- app/controllers/application_controller.rb | 9 +++------ app/helpers/application_helper.rb | 4 ++-- app/jobs/activity_pub/fetch_job.rb | 3 ++- app/jobs/activity_pub/sync_lists_job.rb | 4 +++- app/jobs/application_job.rb | 4 +--- app/models/activity_pub.rb | 5 +++-- app/models/activity_pub/fediblock.rb | 4 ++-- app/models/activity_pub/object.rb | 5 +++-- app/models/activity_pub/remote_flag.rb | 5 +++-- app/models/concerns/tienda.rb | 2 +- app/models/fediblock_state.rb | 3 ++- app/models/instance_moderation.rb | 4 +++- app/models/metadata_template.rb | 2 +- app/models/social_inbox.rb | 4 ++-- app/services/site_service.rb | 2 -- config/environments/production.rb | 9 +++++---- config/initializers/que_web.rb | 2 +- db/migrate/20240227142019_create_fediblock_states.rb | 4 +--- ...0313204105_brs_decompressor_corrupted_source_error.rb | 6 ++++-- db/migrate/20240314205923_fix_activity_type.rb | 4 +++- db/migrate/20240318183846_fix_duplicate_objects.rb | 2 +- db/migrate/20240319124212_add_fedipact_to_fediblocks.rb | 4 +--- db/migrate/20240319144735_add_missing_unique_indexes.rb | 6 +++--- db/seeds.rb | 4 ++-- 24 files changed, 52 insertions(+), 49 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index b76238a0..117be995 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -14,7 +14,7 @@ class ApplicationController < ActionController::Base after_action :store_location! before_action do - Rack::MiniProfiler.authorize_request if current_usuarie&.email&.ends_with?('@' + ENV.fetch('SUTTY', 'sutty.nl')) + Rack::MiniProfiler.authorize_request if current_usuarie&.email&.ends_with?("@#{ENV.fetch('SUTTY', 'sutty.nl')}") end # No tenemos índice de sutty, vamos directamente a ver el listado de @@ -24,7 +24,7 @@ class ApplicationController < ActionController::Base end private - + def notify_unconfirmed_email return unless current_usuarie return if current_usuarie.confirmed? @@ -58,9 +58,7 @@ class ApplicationController < ActionController::Base def current_locale locale = params[:change_locale_to] - if locale.present? && I18n.locale_available?(locale) - session[:locale] = params[:change_locale_to] - end + session[:locale] = params[:change_locale_to] if locale.present? && I18n.locale_available?(locale) session[:locale] || current_usuarie&.lang || I18n.locale end @@ -119,5 +117,4 @@ class ApplicationController < ActionController::Base session[:usuarie_return_to] = request.fullpath end - end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 146846f0..fcbd4074 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -13,7 +13,7 @@ module ApplicationHelper root = names.shift names.each do |n| - root += '[' + n.to_s + ']' + root += "[#{n}]" end [root, name] @@ -22,7 +22,7 @@ module ApplicationHelper def plain_field_name_for(*names) root, name = field_name_for(*names) - root + '[' + name.to_s + ']' + "#{root}[#{name}]" end def distance_of_time_in_words_if_more_than_a_minute(seconds) diff --git a/app/jobs/activity_pub/fetch_job.rb b/app/jobs/activity_pub/fetch_job.rb index 5d9e02de..07190c35 100644 --- a/app/jobs/activity_pub/fetch_job.rb +++ b/app/jobs/activity_pub/fetch_job.rb @@ -50,7 +50,8 @@ class ActivityPub content = FastJsonparser.parse(response.body) # Modificar atómicamente - ::ActivityPub::Object.lock.find(object_id).update!(content: content, type: ActivityPub::Object.type_from(content).name) + ::ActivityPub::Object.lock.find(object_id).update!(content: content, + type: ActivityPub::Object.type_from(content).name) object = ::ActivityPub::Object.find(object_id) # Actualiza la mención diff --git a/app/jobs/activity_pub/sync_lists_job.rb b/app/jobs/activity_pub/sync_lists_job.rb index de71fe64..e37e15be 100644 --- a/app/jobs/activity_pub/sync_lists_job.rb +++ b/app/jobs/activity_pub/sync_lists_job.rb @@ -43,7 +43,9 @@ class ActivityPub # 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 }) + ExceptionNotifier.notify_exception(e, + data: { site: site.name, logs: logs, blocklist: blocklist, + allowlist: allowlist, pauselist: pauselist }) raise end diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb index 4bb68359..ee4e3b2c 100644 --- a/app/jobs/application_job.rb +++ b/app/jobs/application_job.rb @@ -8,7 +8,7 @@ class ApplicationJob < ActiveJob::Base # superpongan tareas # # @return [Array] - RANDOM_WAIT = [3, 5, 7, 11, 13] + RANDOM_WAIT = [3, 5, 7, 11, 13].freeze # @return [ActiveSupport::Duration] def self.random_wait @@ -17,8 +17,6 @@ class ApplicationJob < ActiveJob::Base attr_reader :site - private - # Si falla por cualquier cosa informar y descartar discard_on(Exception) do |job, error| ExceptionNotifier.notify_exception(error, data: { job: job }) diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb index cd893406..7f8155cd 100644 --- a/app/models/activity_pub.rb +++ b/app/models/activity_pub.rb @@ -64,7 +64,7 @@ class ActivityPub < ApplicationRecord # Array o mezcla y obtener el que más nos convenga o # adivinar uno. when Array - links = object['url'].map.with_index do |link, i| + links = object['url'].map.with_index do |link, _i| case link when Hash then link else { 'href' => link.to_s } @@ -93,7 +93,8 @@ class ActivityPub < ApplicationRecord # Gestionar todos los errores error_on_all_events do |e| - ExceptionNotifier.notify_exception(e, data: { site: site.name, activity_pub: self.id, activity: activities.first.uri }) + ExceptionNotifier.notify_exception(e, + data: { site: site.name, activity_pub: id, activity: activities.first.uri }) end # Se puede volver a pausa en caso de actualización remota, para diff --git a/app/models/activity_pub/fediblock.rb b/app/models/activity_pub/fediblock.rb index 17897d79..e66e6e60 100644 --- a/app/models/activity_pub/fediblock.rb +++ b/app/models/activity_pub/fediblock.rb @@ -35,9 +35,9 @@ class ActivityPub validates_inclusion_of :format, in: %w[mastodon fediblock none] HOSTNAME_HEADERS = { - 'mastodon' => '#domain', + 'mastodon' => '#domain', 'fediblock' => 'domain' - } + }.freeze def client @client ||= Client.new diff --git a/app/models/activity_pub/object.rb b/app/models/activity_pub/object.rb index d37c9b88..b10b4431 100644 --- a/app/models/activity_pub/object.rb +++ b/app/models/activity_pub/object.rb @@ -39,13 +39,14 @@ class ActivityPub def referenced(site) require 'distributed_press/v1/social/referenced_object' - @referenced ||= DistributedPress::V1::Social::ReferencedObject.new(object: content, dereferencer: site.social_inbox.dereferencer) + @referenced ||= DistributedPress::V1::Social::ReferencedObject.new(object: content, + dereferencer: site.social_inbox.dereferencer) end private def uri_is_content_id? - return if self.uri == content['id'] + return if uri == content['id'] errors.add(:activity_pub_objects, 'El ID del objeto no coincide con su URI') end diff --git a/app/models/activity_pub/remote_flag.rb b/app/models/activity_pub/remote_flag.rb index c3cc0fb0..d6348650 100644 --- a/app/models/activity_pub/remote_flag.rb +++ b/app/models/activity_pub/remote_flag.rb @@ -40,7 +40,8 @@ class ActivityPub def content { '@context' => 'https://www.w3.org/ns/activitystreams', - 'id' => Rails.application.routes.url_helpers.v1_activity_pub_remote_flag_url(self, host: site.social_inbox_hostname), + 'id' => Rails.application.routes.url_helpers.v1_activity_pub_remote_flag_url(self, + host: site.social_inbox_hostname), 'type' => 'Flag', 'actor' => main_site.social_inbox.actor_id, 'content' => message.to_s, @@ -53,7 +54,7 @@ class ActivityPub # # @return [Site] def main_site - @main_site ||= Site.find(ENV.fetch('PANEL_ACTOR_SITE_ID') { 1 }) + @main_site ||= Site.find(ENV.fetch('PANEL_ACTOR_SITE_ID', 1)) end end end diff --git a/app/models/concerns/tienda.rb b/app/models/concerns/tienda.rb index 86174c9a..a3e6007a 100644 --- a/app/models/concerns/tienda.rb +++ b/app/models/concerns/tienda.rb @@ -17,7 +17,7 @@ module Tienda return t if new_record? - t.blank? ? 'https://' + name + '.' + ENV.fetch('TIENDA', 'tienda.sutty.nl') : t + t.blank? ? "https://#{name}.#{ENV.fetch('TIENDA', 'tienda.sutty.nl')}" : t end end end diff --git a/app/models/fediblock_state.rb b/app/models/fediblock_state.rb index 82912f76..02dee2d8 100644 --- a/app/models/fediblock_state.rb +++ b/app/models/fediblock_state.rb @@ -45,7 +45,8 @@ class FediblockState < ApplicationRecord private def block_instances! - ActivityPub::InstanceModerationJob.perform_later(site: site, hostnames: fediblock.hostnames, perform_remotely: false) + ActivityPub::InstanceModerationJob.perform_later(site: site, hostnames: fediblock.hostnames, + perform_remotely: false) end # Pausar todas las moderaciones de las instancias que no estén diff --git a/app/models/instance_moderation.rb b/app/models/instance_moderation.rb index 5a1a5ed6..c1192615 100644 --- a/app/models/instance_moderation.rb +++ b/app/models/instance_moderation.rb @@ -16,7 +16,9 @@ class InstanceModeration < ApplicationRecord state :blocked error_on_all_events do |e| - ExceptionNotifier.notify_exception(e, data: { site: site.name, instance: instance.hostname, instance_moderation: id }) + ExceptionNotifier.notify_exception(e, + data: { site: site.name, instance: instance.hostname, + instance_moderation: id }) end after_all_events do diff --git a/app/models/metadata_template.rb b/app/models/metadata_template.rb index a9765918..78989e15 100644 --- a/app/models/metadata_template.rb +++ b/app/models/metadata_template.rb @@ -134,7 +134,7 @@ MetadataTemplate = Struct.new(:site, :document, :name, :label, :type, # En caso de que algún campo necesite realizar acciones antes de ser # guardado def save - if !changed? + unless changed? self[:value] = document_value if private? return true diff --git a/app/models/social_inbox.rb b/app/models/social_inbox.rb index 183ebfb0..adeedffc 100644 --- a/app/models/social_inbox.rb +++ b/app/models/social_inbox.rb @@ -45,7 +45,7 @@ class SocialInbox # @param url [String] # @return [DistributedPress::V1::Social::Client] def client_for(url) - raise "Falló generar un cliente" if url.blank? + raise 'Falló generar un cliente' if url.blank? @client_for ||= {} @client_for[url] ||= @@ -54,7 +54,7 @@ class SocialInbox public_key_url: public_key_url, private_key_pem: site.private_key_pem, logger: Rails.logger, - cache_store: HTTParty::Cache::Store::Redis.new(redis_url: ENV['REDIS_SERVER']) + cache_store: HTTParty::Cache::Store::Redis.new(redis_url: ENV.fetch('REDIS_SERVER', nil)) ) end diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 53e953f3..1a85d401 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -222,8 +222,6 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do end end - private - # Asignar un rol a cada deploy si no lo tenía ya def add_role_to_deploys!(role = current_role) site.deploys.each do |deploy| diff --git a/config/environments/production.rb b/config/environments/production.rb index bc7cecd7..5b0667a5 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -62,7 +62,7 @@ Rails.application.configure do config.log_tags = %i[request_id] # Use a different cache store in production. - config.cache_store = :redis_cache_store, { url: ENV['REDIS_SERVER'] } + config.cache_store = :redis_cache_store, { url: ENV.fetch('REDIS_SERVER', nil) } config.action_mailer.perform_caching = false @@ -87,7 +87,7 @@ Rails.application.configure do config.lograge.enabled = true # Use default logging formatter so that PID and timestamp are not # suppressed. - config.log_formatter = ::Logger::Formatter.new + config.log_formatter = Logger::Formatter.new # Use a different logger for distributed setups. require 'syslog/logger' @@ -140,9 +140,10 @@ Rails.application.configure do domain: ENV.fetch('SUTTY', 'sutty.nl'), enable_starttls_auto: false } - config.action_mailer.default_options = { from: ENV.fetch('DEFAULT_FROM', "noreply@sutty.nl") } + config.action_mailer.default_options = { from: ENV.fetch('DEFAULT_FROM', 'noreply@sutty.nl') } - config.middleware.use ExceptionNotification::Rack, gitlab: {}, error_grouping: true, ignore_exceptions: ['DeployJob::DeployAlreadyRunningException'] + config.middleware.use ExceptionNotification::Rack, gitlab: {}, error_grouping: true, + ignore_exceptions: ['DeployJob::DeployAlreadyRunningException'] Rails.application.routes.default_url_options[:host] = "panel.#{ENV.fetch('SUTTY', 'sutty.nl')}" Rails.application.routes.default_url_options[:protocol] = 'https' diff --git a/config/initializers/que_web.rb b/config/initializers/que_web.rb index 192256db..a6b87cf8 100644 --- a/config/initializers/que_web.rb +++ b/config/initializers/que_web.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true Que::Web.use(Rack::Auth::Basic) do |user, password| - [user, password] == [ENV['HTTP_BASIC_USER'], ENV['HTTP_BASIC_PASSWORD']] + [user, password] == [ENV.fetch('HTTP_BASIC_USER', nil), ENV.fetch('HTTP_BASIC_PASSWORD', nil)] end diff --git a/db/migrate/20240227142019_create_fediblock_states.rb b/db/migrate/20240227142019_create_fediblock_states.rb index c99cf63d..1e718343 100644 --- a/db/migrate/20240227142019_create_fediblock_states.rb +++ b/db/migrate/20240227142019_create_fediblock_states.rb @@ -16,9 +16,7 @@ class CreateFediblockStates < ActiveRecord::Migration[6.1] # Todas las listas están activas por defecto DeploySocialDistributedPress.find_each do |deploy| ActivityPub::Fediblock.find_each do |fediblock| - FediblockState.create(site: deploy.site, fediblock: fediblock, aasm_state: 'disabled').tap do |f| - f.enable! - end + FediblockState.create(site: deploy.site, fediblock: fediblock, aasm_state: 'disabled').tap(&:enable!) end end end diff --git a/db/migrate/20240313204105_brs_decompressor_corrupted_source_error.rb b/db/migrate/20240313204105_brs_decompressor_corrupted_source_error.rb index a0c29311..e22d759b 100644 --- a/db/migrate/20240313204105_brs_decompressor_corrupted_source_error.rb +++ b/db/migrate/20240313204105_brs_decompressor_corrupted_source_error.rb @@ -4,9 +4,11 @@ # decompresión class BrsDecompressorCorruptedSourceError < ActiveRecord::Migration[6.1] def up - raise unless HTTParty.get("https://mas.to/api/v2/instance", headers: { "Accept-Encoding": "br;q=1.0,gzip;q=1.0,deflate;q=0.6,identity;q=0.3" }).ok? + raise unless HTTParty.get('https://mas.to/api/v2/instance', + headers: { 'Accept-Encoding': 'br;q=1.0,gzip;q=1.0,deflate;q=0.6,identity;q=0.3' }).ok? - QueJob.where("last_error_message like '%BRS::DecompressorCorruptedSourceError%'").update_all(error_count: 0, run_at: Time.now) + QueJob.where("last_error_message like '%BRS::DecompressorCorruptedSourceError%'").update_all(error_count: 0, + run_at: Time.now) end def down; end diff --git a/db/migrate/20240314205923_fix_activity_type.rb b/db/migrate/20240314205923_fix_activity_type.rb index 042de8eb..e6640ff8 100644 --- a/db/migrate/20240314205923_fix_activity_type.rb +++ b/db/migrate/20240314205923_fix_activity_type.rb @@ -4,7 +4,9 @@ class FixActivityType < ActiveRecord::Migration[6.1] def up %w[Like Announce].each do |type| - ActivityPub::Activity.where(Arel.sql("content->>'type' = '#{type}'")).update_all(type: "ActivityPub::Activity::#{type}", updated_at: Time.now) + ActivityPub::Activity.where(Arel.sql("content->>'type' = '#{type}'")).update_all( + type: "ActivityPub::Activity::#{type}", updated_at: Time.now + ) end end diff --git a/db/migrate/20240318183846_fix_duplicate_objects.rb b/db/migrate/20240318183846_fix_duplicate_objects.rb index 88d23c6f..9f02c3db 100644 --- a/db/migrate/20240318183846_fix_duplicate_objects.rb +++ b/db/migrate/20240318183846_fix_duplicate_objects.rb @@ -3,7 +3,7 @@ # De alguna forma se guardaron objetos duplicados! class FixDuplicateObjects < ActiveRecord::Migration[6.1] def up - ActivityPub::Object.group(:uri).count.select { |_, v| v > 1 }.keys.each do |uri| + ActivityPub::Object.group(:uri).count.select { |_, v| v > 1 }.each_key do |uri| objects = ActivityPub::Object.where(uri: uri) deleted_ids = objects[1..].map(&:delete).map(&:id) diff --git a/db/migrate/20240319124212_add_fedipact_to_fediblocks.rb b/db/migrate/20240319124212_add_fedipact_to_fediblocks.rb index d78439b2..f751123a 100644 --- a/db/migrate/20240319124212_add_fedipact_to_fediblocks.rb +++ b/db/migrate/20240319124212_add_fedipact_to_fediblocks.rb @@ -14,9 +14,7 @@ class AddFedipactToFediblocks < ActiveRecord::Migration[6.1] ) DeploySocialDistributedPress.find_each do |deploy| - FediblockState.create(site: deploy.site, fediblock: fedipact, aasm_state: 'disabled').tap do |f| - f.enable! - end + FediblockState.create(site: deploy.site, fediblock: fedipact, aasm_state: 'disabled').tap(&:enable!) end end diff --git a/db/migrate/20240319144735_add_missing_unique_indexes.rb b/db/migrate/20240319144735_add_missing_unique_indexes.rb index 7d18c8e8..2f6ef1aa 100644 --- a/db/migrate/20240319144735_add_missing_unique_indexes.rb +++ b/db/migrate/20240319144735_add_missing_unique_indexes.rb @@ -4,14 +4,14 @@ # no es válida y por eso teníamos objetos duplicados. class AddMissingUniqueIndexes < ActiveRecord::Migration[6.1] def up - ActivityPub::Object.group(:uri).count.select { |_, v| v > 1 }.keys.each do |uri| + ActivityPub::Object.group(:uri).count.select { |_, v| v > 1 }.each_key do |uri| objects = ActivityPub::Object.where(uri: uri) deleted_ids = objects[1..].map(&:delete).map(&:id) ActivityPub.where(object_id: deleted_ids).update_all(object_id: objects.first.id, updated_at: Time.now) end - ActivityPub::Actor.group(:uri).count.select { |_, v| v > 1 }.keys.each do |uri| + ActivityPub::Actor.group(:uri).count.select { |_, v| v > 1 }.each_key do |uri| objects = ActivityPub::Actor.where(uri: uri) deleted_ids = objects[1..].map(&:delete).map(&:id) @@ -21,7 +21,7 @@ class AddMissingUniqueIndexes < ActiveRecord::Migration[6.1] ActivityPub::RemoteFlag.where(actor_id: deleted_ids).update_all(actor_id: objects.first.id, updated_at: Time.now) end - ActivityPub::Instance.group(:hostname).count.select { |_, v| v > 1 }.keys.each do |hostname| + ActivityPub::Instance.group(:hostname).count.select { |_, v| v > 1 }.each_key do |hostname| objects = ActivityPub::Instance.where(hostname: hostname) deleted_ids = objects[1..].map(&:delete).map(&:id) diff --git a/db/seeds.rb b/db/seeds.rb index 8e8c291f..41474883 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -20,13 +20,13 @@ if CodeOfConduct.count.zero? YAML.safe_load(File.read('db/seeds/codes_of_conduct.yml')).each do |coc| CodeOfConduct.new(**coc).save! end -end +end if PrivacyPolicy.count.zero? YAML.safe_load(File.read('db/seeds/privacy_policies.yml')).each do |pp| PrivacyPolicy.new(**pp).save! end -end +end YAML.safe_load(File.read('db/seeds/activity_pub/fediblocks.yml')).each do |fediblock| ActivityPub::Fediblock.find_or_create_by(id: fediblock['id']).tap do |f| From fe78c354a77e55668d235e6a68df66c72b4aa86b Mon Sep 17 00:00:00 2001 From: f Date: Thu, 2 May 2024 16:18:34 -0300 Subject: [PATCH 472/472] ci: instalar dependencias antes de usarlas --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dceb1a42..2830cd86 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -36,6 +36,7 @@ assets: - *cache-node - *cache-task before_script: + - *apk-add - "gitlab_ci_log_section --name git --header=\"Configuring git\"" - "git config --global user.email \"${GIT_USER_EMAIL:-$GITLAB_USER_EMAIL}\"" - "git config --global user.name \"${GIT_USER_NAME:-$GITLAB_USER_NAME}\"" @@ -43,7 +44,6 @@ assets: - "gitlab_ci_log_section --name git --end" - "gitlab_ci_log_section --name apk --header=\"Installing dependencies\"" - "apk add brotli" - - *apk-add - *disable-hainish - "gitlab_ci_log_section --name apk --end" script: