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 c2d72472..57fb0238 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -183,3 +183,11 @@ tasks: - "{{.HAINISH}} gem install bundler-audit" status: - "test -f ../hain/usr/bin/bundler-audit" + rubocop: + desc: "Ruby linting" + cmds: + - "./bin/modified_files | ./bin/with_extension rb | xargs -r {{.HAINISH}} bundle exec rubocop {{.CLI_ARGS}}" + haml-lint: + desc: "HAML linting" + cmds: + - "./bin/modified_files | ./bin/with_extension haml | xargs -r {{.HAINISH}} bundle exec haml-lint {{.CLI_ARGS}}" diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 7f62e658..240e61a5 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -558,3 +558,32 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); } } } +// details styles + +.details { + summary { + list-style: none; + cursor: default; + position: relative; + } + summary::after { + content: '▶'; + font-size: 1.8rem; + position: absolute; + left: 97%; + bottom: 3%; + transform: rotate(180deg); + } + &[open] { + & > summary { + &::after { + transform: rotate(90deg); + } + } + } +} + + +hr { + border-bottom: 1px solid #dee2e6; +} \ No newline at end of file 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; } } + + diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 3201b909..b55176ec 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -27,7 +27,17 @@ 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 return if current_usuarie.confirmed? @@ -117,4 +127,5 @@ class ApplicationController < ActionController::Base sites_path end + end diff --git a/app/controllers/moderation_queue_controller.rb b/app/controllers/moderation_queue_controller.rb new file mode 100644 index 00000000..eec0c70f --- /dev/null +++ b/app/controllers/moderation_queue_controller.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +# Cola de moderación de ActivityPub +class ModerationQueueController < ApplicationController + # Cola de moderación viendo todo el sitio + def index + dummy_data + 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 + dummy_data + end +end diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 057c3068..99dc6f7d 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) + dummy_data end def show @@ -81,6 +82,7 @@ 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 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/_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 new file mode 100644 index 00000000..1e9cd76f --- /dev/null +++ b/app/views/components/_block_lists.haml @@ -0,0 +1,2 @@ +- @blocklists.each do |blocklist| + = render 'components/block_list', blocklist: blocklist diff --git a/app/views/components/_btn_base.haml b/app/views/components/_btn_base.haml new file mode 100644 index 00000000..7fa507ca --- /dev/null +++ b/app/views/components/_btn_base.haml @@ -0,0 +1,3 @@ +-# Componente Botón general Moderación + +%button.btn{ href: href, class: local_assigns[:class] }= text diff --git a/app/views/components/_checkbox.haml b/app/views/components/_checkbox.haml new file mode 100644 index 00000000..27f9a776 --- /dev/null +++ b/app/views/components/_checkbox.haml @@ -0,0 +1,4 @@ +-# Componente Checkbox +.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/components/_comments_btn_box.haml b/app/views/components/_comments_btn_box.haml new file mode 100644 index 00000000..8b8d7268 --- /dev/null +++ b/app/views/components/_comments_btn_box.haml @@ -0,0 +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 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/_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' } 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/_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_btn_box.haml b/app/views/components/_profiles_btn_box.haml new file mode 100644 index 00000000..06faa8a1 --- /dev/null +++ b/app/views/components/_profiles_btn_box.haml @@ -0,0 +1,7 @@ +-# 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 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/layouts/_details.haml b/app/views/layouts/_details.haml new file mode 100644 index 00000000..306986bf --- /dev/null +++ b/app/views/layouts/_details.haml @@ -0,0 +1,6 @@ +-# Detail Cola de Moderación + +%details.details.py-2 + %summary + %h3.py-2= summary + = yield diff --git a/app/views/moderation_queue/_account.haml b/app/views/moderation_queue/_account.haml new file mode 100644 index 00000000..412f0aa7 --- /dev/null +++ b/app/views/moderation_queue/_account.haml @@ -0,0 +1,7 @@ +.row.no-gutters.pt-2 + .col-1 + = render 'components/checkbox', id: profile['id'] + .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 new file mode 100644 index 00000000..9a6738bd --- /dev/null +++ b/app/views/moderation_queue/_accounts.haml @@ -0,0 +1,11 @@ +-# Filtros += 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.pb-4 + = render 'components/profiles_btn_box' + 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..9b388a0d --- /dev/null +++ b/app/views/moderation_queue/_block_instances_textarea.haml @@ -0,0 +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') + diff --git a/app/views/moderation_queue/_comment.haml b/app/views/moderation_queue/_comment.haml new file mode 100644 index 00000000..a066f845 --- /dev/null +++ b/app/views/moderation_queue/_comment.haml @@ -0,0 +1,32 @@ +-# Componente Comentario +.flex.mx-4.my-4 + .row.no-gutters + .col-1 + = 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'] + + - 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 diff --git a/app/views/moderation_queue/_comments.haml b/app/views/moderation_queue/_comments.haml new file mode 100644 index 00000000..41193ce1 --- /dev/null +++ b/app/views/moderation_queue/_comments.haml @@ -0,0 +1,14 @@ +.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 + = render 'comment', comment: comment, profile: comment['attributedTo'] + + -# Botones moderación + .d-flex.justify-content-center + = render 'components/comments_btn_box', comment: comment \ No newline at end of file diff --git a/app/views/moderation_queue/_instance.haml b/app/views/moderation_queue/_instance.haml new file mode 100644 index 00000000..cff8a957 --- /dev/null +++ b/app/views/moderation_queue/_instance.haml @@ -0,0 +1,16 @@ +- host = instance['domain'] +- host ||= instance['uri'] +- hosthttps = "https://#{host}" + +.row.no-gutters.pt-2 + .col-1 + = render 'components/checkbox', id: host + .col-11 + %h4 + %a{ href: hosthttps }= 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 new file mode 100644 index 00000000..1accf60d --- /dev/null +++ b/app/views/moderation_queue/_instances.haml @@ -0,0 +1,16 @@ +-# Filtros += 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 +%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' diff --git a/app/views/moderation_queue/_remote_profile.haml b/app/views/moderation_queue/_remote_profile.haml new file mode 100644 index 00000000..43474b80 --- /dev/null +++ b/app/views/moderation_queue/_remote_profile.haml @@ -0,0 +1,24 @@ +-# Componente Remote_Profile + +.flex.py-2.mx-2 + %dl + %dt= t('.profile_name') + %dd= remote_profile['name'] + + %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'].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/index.haml b/app/views/moderation_queue/index.haml new file mode 100644 index 00000000..ab98ee30 --- /dev/null +++ b/app/views/moderation_queue/index.haml @@ -0,0 +1,16 @@ +.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 + %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 diff --git a/app/views/moderation_queue/remote_profile.haml b/app/views/moderation_queue/remote_profile.haml new file mode 100644 index 00000000..ba0fc257 --- /dev/null +++ b/app/views/moderation_queue/remote_profile.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/app/views/posts/_moderation_queue.haml b/app/views/posts/_moderation_queue.haml new file mode 100644 index 00000000..2ec6a07d --- /dev/null +++ b/app/views/posts/_moderation_queue.haml @@ -0,0 +1,13 @@ +.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'] + + -# Botones moderación + .d-flex + = render 'components/comments_btn_box' diff --git a/app/views/posts/edit.haml b/app/views/posts/edit.haml index c792ac93..2e46590e 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: "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/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' 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" \ diff --git a/config/locales/en.yml b/config/locales/en.yml index fc9d4894..1b4f2d86 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,4 +1,128 @@ 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 + format: '%-I:%M %p' + components: + 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 + instances: Instances + accounts: Accounts + comments: Comments + comment: + source_profile: Source Profile + reply_to: Reply to + remote_profile: + user: Username + 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 + users: "Users:" dark: Dark dir: ltr en: English @@ -578,7 +702,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 4bda4982..e277f76b 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1,4 +1,128 @@ 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 + format: '%-H:%M' + 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 + 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 + instances: Instancias + accounts: Cuentas + comments: Comentarios + 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 + profile_id: ID + profile_published: Publicada + profile_summary: Resumen + instances: + title: Mis listas de bloqueo + 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 @@ -520,6 +644,9 @@ es: en: 'inglés' ar: 'árabe' posts: + edit: + moderation_queue: Comentarios + post: Contenido prev: Página anterior next: Página siguiente empty: No hay artículos con estos parámetros de búsqueda. @@ -586,7 +713,7 @@ es: remove_filter_help: 'Quitar este filtro: %{filter}' index: search: 'Buscar' - edit: 'Editar' + edit_post: 'Editar' preview: btn: 'Versión preliminar' alert: 'No todos los tipos de artículos poseen vista preliminar :)' diff --git a/config/routes.rb b/config/routes.rb index 88376dde..ddc29994 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -58,6 +58,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 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 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

Qué permite hacer

Qué se viene

¡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

Qué permite hacer

Qué se viene

¡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