mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-22 19:56:21 +00:00
Merge branch 'rails' into issue-14339
This commit is contained in:
commit
7a03269aa3
63 changed files with 1434 additions and 51 deletions
|
@ -6,9 +6,15 @@
|
||||||
- paths:
|
- paths:
|
||||||
- "vendor/ruby"
|
- "vendor/ruby"
|
||||||
- ".bundle"
|
- ".bundle"
|
||||||
|
key:
|
||||||
|
files:
|
||||||
|
- "Gemfile.lock"
|
||||||
.cache-node: &cache-node
|
.cache-node: &cache-node
|
||||||
- paths:
|
- paths:
|
||||||
- "node_modules"
|
- "node_modules"
|
||||||
|
key:
|
||||||
|
files:
|
||||||
|
- "yarn.lock"
|
||||||
.cache-task: &cache-task
|
.cache-task: &cache-task
|
||||||
- paths:
|
- paths:
|
||||||
- ".task"
|
- ".task"
|
||||||
|
@ -90,7 +96,7 @@ rubocop:
|
||||||
- *apk-add
|
- *apk-add
|
||||||
- *disable-hainish
|
- *disable-hainish
|
||||||
script:
|
script:
|
||||||
- "./bin/modified_files | ./bin/with_extension rb | xargs -r go-task bundle -- exec rubocop"
|
- "go-task rubocop"
|
||||||
haml:
|
haml:
|
||||||
stage: "test"
|
stage: "test"
|
||||||
cache:
|
cache:
|
||||||
|
@ -101,4 +107,4 @@ haml:
|
||||||
- *apk-add
|
- *apk-add
|
||||||
- *disable-hainish
|
- *disable-hainish
|
||||||
script:
|
script:
|
||||||
- "./bin/modified_files | ./bin/with_extension haml | xargs -r go-task bundle -- exec haml-lint"
|
- "go-task haml-lint"
|
||||||
|
|
|
@ -183,3 +183,15 @@ tasks:
|
||||||
- "{{.HAINISH}} gem install bundler-audit"
|
- "{{.HAINISH}} gem install bundler-audit"
|
||||||
status:
|
status:
|
||||||
- "test -f ../hain/usr/bin/bundler-audit"
|
- "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}}"
|
||||||
|
|
|
@ -577,3 +577,27 @@ $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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,10 @@ $cyan: #13fefe;
|
||||||
--color: #{$cyan};
|
--color: #{$cyan};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
background-color: $white;
|
||||||
|
}
|
||||||
|
|
||||||
.btn-secondary {
|
.btn-secondary {
|
||||||
background-color: $white;
|
background-color: $white;
|
||||||
color: $black;
|
color: $black;
|
||||||
|
@ -26,3 +30,5 @@ $cyan: #13fefe;
|
||||||
box-shadow: 0 0 0 0.2rem $cyan;
|
box-shadow: 0 0 0 0.2rem $cyan;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ class ApplicationController < ActionController::Base
|
||||||
before_action :configure_permitted_parameters, if: :devise_controller?
|
before_action :configure_permitted_parameters, if: :devise_controller?
|
||||||
before_action :notify_unconfirmed_email, unless: :devise_controller?
|
before_action :notify_unconfirmed_email, unless: :devise_controller?
|
||||||
around_action :set_locale
|
around_action :set_locale
|
||||||
|
after_action :store_location!
|
||||||
|
|
||||||
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::RoutingError, with: :page_not_found
|
||||||
|
@ -27,7 +28,17 @@ class ApplicationController < ActionController::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
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
|
def notify_unconfirmed_email
|
||||||
return unless current_usuarie
|
return unless current_usuarie
|
||||||
return if current_usuarie.confirmed?
|
return if current_usuarie.confirmed?
|
||||||
|
@ -115,6 +126,17 @@ class ApplicationController < ActionController::Base
|
||||||
def after_sign_in_path_for(resource)
|
def after_sign_in_path_for(resource)
|
||||||
session[:locale] = nil
|
session[:locale] = nil
|
||||||
|
|
||||||
sites_path
|
super
|
||||||
end
|
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
|
end
|
||||||
|
|
20
app/controllers/moderation_queue_controller.rb
Normal file
20
app/controllers/moderation_queue_controller.rb
Normal file
|
@ -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
|
|
@ -38,6 +38,7 @@ class PostsController < ApplicationController
|
||||||
@usuarie = site.usuarie? current_usuarie
|
@usuarie = site.usuarie? current_usuarie
|
||||||
|
|
||||||
@site_stat = SiteStat.new(site)
|
@site_stat = SiteStat.new(site)
|
||||||
|
dummy_data
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
@ -81,6 +82,7 @@ class PostsController < ApplicationController
|
||||||
authorize post
|
authorize post
|
||||||
breadcrumb post.title.value, site_post_path(site, post, locale: locale), match: :exact
|
breadcrumb post.title.value, site_post_path(site, post, locale: locale), match: :exact
|
||||||
breadcrumb 'posts.edit', ''
|
breadcrumb 'posts.edit', ''
|
||||||
|
dummy_data
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
|
|
|
@ -15,6 +15,19 @@ class SitesController < ApplicationController
|
||||||
fresh_when @sites
|
fresh_when @sites
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Genera la caja del estado para HTMX
|
||||||
|
def status
|
||||||
|
authorize site
|
||||||
|
|
||||||
|
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
|
# No tenemos propiedades de un sitio aún, así que vamos al listado de
|
||||||
# artículos
|
# artículos
|
||||||
def show
|
def show
|
||||||
|
|
106
app/javascript/controllers/dropdown_controller.js
Normal file
106
app/javascript/controllers/dropdown_controller.js
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
app/javascript/etc/htmx_abort.js
Normal file
7
app/javascript/etc/htmx_abort.js
Normal file
|
@ -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");
|
||||||
|
}
|
||||||
|
});
|
|
@ -7,3 +7,4 @@ import './timezone'
|
||||||
import './turbolinks-anchors'
|
import './turbolinks-anchors'
|
||||||
import './validation'
|
import './validation'
|
||||||
import './new_editor'
|
import './new_editor'
|
||||||
|
import './htmx_abort'
|
||||||
|
|
|
@ -9,9 +9,16 @@ try {
|
||||||
host: window.env.PANEL_URL
|
host: window.env.PANEL_URL
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const ignoredErrors = ["htmx:afterRequest", "htmx:sendAbort"];
|
||||||
|
|
||||||
console.originalError = console.error;
|
console.originalError = console.error;
|
||||||
console.error = (...e) => {
|
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);
|
return console.originalError(...e);
|
||||||
};
|
};
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
|
@ -33,3 +40,5 @@ import 'chartkick/chart.js'
|
||||||
Rails.start()
|
Rails.start()
|
||||||
Turbolinks.start()
|
Turbolinks.start()
|
||||||
ActiveStorage.start()
|
ActiveStorage.start()
|
||||||
|
|
||||||
|
window.htmx = require('htmx.org/dist/htmx.js')
|
||||||
|
|
|
@ -14,6 +14,8 @@ module Jekyll
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
included do
|
included do
|
||||||
|
DATA_EXTENSIONS = %w[.yaml .yml .json .csv .tsv].freeze
|
||||||
|
|
||||||
def read_data_to(dir, data)
|
def read_data_to(dir, data)
|
||||||
return unless File.directory?(dir) && !@entry_filter.symlink?(dir)
|
return unless File.directory?(dir) && !@entry_filter.symlink?(dir)
|
||||||
|
|
||||||
|
@ -24,7 +26,7 @@ module Jekyll
|
||||||
|
|
||||||
if File.directory?(path)
|
if File.directory?(path)
|
||||||
read_data_to(path, data[sanitize_filename(entry)] = {})
|
read_data_to(path, data[sanitize_filename(entry)] = {})
|
||||||
else
|
elsif DATA_EXTENSIONS.include?(File.extname(entry))
|
||||||
key = sanitize_filename(File.basename(entry, ".*"))
|
key = sanitize_filename(File.basename(entry, ".*"))
|
||||||
data[key] = read_data_file(path)
|
data[key] = read_data_file(path)
|
||||||
end
|
end
|
||||||
|
|
|
@ -87,7 +87,7 @@ class DeployDistributedPress < Deploy
|
||||||
# @return [Array]
|
# @return [Array]
|
||||||
def gateway_urls
|
def gateway_urls
|
||||||
remote_info.dig(:distributed_press, :links)&.values&.map do |protocol|
|
remote_info.dig(:distributed_press, :links)&.values&.map do |protocol|
|
||||||
[ protocol[:link], protocol[:gateway] ]
|
[protocol[:link]]
|
||||||
end&.flatten&.compact&.select do |link|
|
end&.flatten&.compact&.select do |link|
|
||||||
link.include? '://'
|
link.include? '://'
|
||||||
end || []
|
end || []
|
||||||
|
|
|
@ -389,8 +389,10 @@ class Site < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def reload
|
def reload
|
||||||
super
|
super.tap do |s|
|
||||||
reload_jekyll!
|
reload_jekyll!
|
||||||
|
end
|
||||||
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
def configuration
|
def configuration
|
||||||
|
|
|
@ -14,6 +14,10 @@ class SitePolicy
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def status?
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
# Puede ver la versión privada del sitio?
|
# Puede ver la versión privada del sitio?
|
||||||
def private?
|
def private?
|
||||||
edit? && site.deploys.find_by_type('DeployPrivate')
|
edit? && site.deploys.find_by_type('DeployPrivate')
|
||||||
|
@ -57,6 +61,10 @@ class SitePolicy
|
||||||
show? && usuarie?
|
show? && usuarie?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def button?
|
||||||
|
show?
|
||||||
|
end
|
||||||
|
|
||||||
def enqueue?
|
def enqueue?
|
||||||
build?
|
build?
|
||||||
end
|
end
|
||||||
|
|
9
app/views/components/_block_list.haml
Normal file
9
app/views/components/_block_list.haml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
-# 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"]
|
||||||
|
|
||||||
|
%p.mb-0
|
||||||
|
%a{ href: blocklist['link'] }= blocklist['title']
|
2
app/views/components/_block_lists.haml
Normal file
2
app/views/components/_block_lists.haml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
- @blocklists.each do |blocklist|
|
||||||
|
= render 'components/block_list', blocklist: blocklist
|
3
app/views/components/_btn_base.haml
Normal file
3
app/views/components/_btn_base.haml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
-# Componente Botón general Moderación
|
||||||
|
|
||||||
|
%button.btn{ href: href, class: local_assigns[:class] }= text
|
4
app/views/components/_checkbox.haml
Normal file
4
app/views/components/_checkbox.haml
Normal file
|
@ -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
|
8
app/views/components/_comments_btn_box.haml
Normal file
8
app/views/components/_comments_btn_box.haml
Normal file
|
@ -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: ''
|
3
app/views/components/_comments_checked_submenu.haml
Normal file
3
app/views/components/_comments_checked_submenu.haml
Normal file
|
@ -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: '/'
|
6
app/views/components/_comments_filters.haml
Normal file
6
app/views/components/_comments_filters.haml
Normal file
|
@ -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'
|
4
app/views/components/_comments_show_submenu.haml
Normal file
4
app/views/components/_comments_show_submenu.haml
Normal file
|
@ -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: '/'
|
34
app/views/components/_dropdown.haml
Normal file
34
app/views/components/_dropdown.haml
Normal file
|
@ -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
|
4
app/views/components/_dropdown_item.haml
Normal file
4
app/views/components/_dropdown_item.haml
Normal file
|
@ -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' }
|
6
app/views/components/_instances_btn_box.haml
Normal file
6
app/views/components/_instances_btn_box.haml
Normal file
|
@ -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: ''
|
3
app/views/components/_instances_checked_submenu.haml
Normal file
3
app/views/components/_instances_checked_submenu.haml
Normal file
|
@ -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: '/'
|
6
app/views/components/_instances_filters.haml
Normal file
6
app/views/components/_instances_filters.haml
Normal file
|
@ -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'
|
2
app/views/components/_instances_show_submenu.haml
Normal file
2
app/views/components/_instances_show_submenu.haml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
= render 'components/dropdown_item', text: t('.submenu_allow'), path: '/'
|
||||||
|
= render 'components/dropdown_item', text: t('.submenu_reject'), path: '/'
|
7
app/views/components/_profiles_btn_box.haml
Normal file
7
app/views/components/_profiles_btn_box.haml
Normal file
|
@ -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: ''
|
4
app/views/components/_profiles_checked_submenu.haml
Normal file
4
app/views/components/_profiles_checked_submenu.haml
Normal file
|
@ -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: '/'
|
6
app/views/components/_profiles_filters.haml
Normal file
6
app/views/components/_profiles_filters.haml
Normal file
|
@ -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'
|
3
app/views/components/_profiles_show_submenu.haml
Normal file
3
app/views/components/_profiles_show_submenu.haml
Normal file
|
@ -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: '/'
|
6
app/views/layouts/_details.haml
Normal file
6
app/views/layouts/_details.haml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
-# Detail Cola de Moderación
|
||||||
|
|
||||||
|
%details.details.py-2
|
||||||
|
%summary
|
||||||
|
%h3.py-2.pr-2= summary
|
||||||
|
= yield
|
11
app/views/moderation_queue/_account.haml
Normal file
11
app/views/moderation_queue/_account.haml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
.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
|
||||||
|
|
||||||
|
-# Botones de Moderación
|
||||||
|
.d-flex.pb-4
|
||||||
|
= render 'components/profiles_btn_box'
|
12
app/views/moderation_queue/_accounts.haml
Normal file
12
app/views/moderation_queue/_accounts.haml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
.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
|
||||||
|
= render 'account', profile: remote_profile
|
||||||
|
|
||||||
|
|
|
@ -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')
|
||||||
|
|
27
app/views/moderation_queue/_comment.haml
Normal file
27
app/views/moderation_queue/_comment.haml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
-# Componente Comentario
|
||||||
|
|
||||||
|
.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.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
|
||||||
|
|
14
app/views/moderation_queue/_comments.haml
Normal file
14
app/views/moderation_queue/_comments.haml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
.row.no-gutters.pt-2
|
||||||
|
.col-1.d-flex.align-items-center
|
||||||
|
= render 'components/checkbox', id: moderation_queue.first['id']
|
||||||
|
.col-md-9
|
||||||
|
-# 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
|
20
app/views/moderation_queue/_instance.haml
Normal file
20
app/views/moderation_queue/_instance.haml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
- 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
|
||||||
|
%dl.d-inline-flex
|
||||||
|
%dt.pr-2= t('.users')
|
||||||
|
%dd
|
||||||
|
= instance.dig('usage', 'users', 'active_month')
|
||||||
|
= instance.dig('stats', 'user_count')
|
||||||
|
|
||||||
|
-# Botones moderación
|
||||||
|
.d-flex.pb-4
|
||||||
|
= render 'components/instances_btn_box'
|
16
app/views/moderation_queue/_instances.haml
Normal file
16
app/views/moderation_queue/_instances.haml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
.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
|
||||||
|
= render 'moderation_queue/instance', instance: instance
|
||||||
|
|
||||||
|
%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'
|
28
app/views/moderation_queue/_remote_profile.haml
Normal file
28
app/views/moderation_queue/_remote_profile.haml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
-# 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= 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'
|
16
app/views/moderation_queue/index.haml
Normal file
16
app/views/moderation_queue/index.haml
Normal file
|
@ -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
|
4
app/views/moderation_queue/remote_profile.haml
Normal file
4
app/views/moderation_queue/remote_profile.haml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.row.justify-content-center
|
||||||
|
.col-md-8
|
||||||
|
%h1= t('.profile')
|
||||||
|
= render 'moderation_queue/remote_profile', remote_profile: @remote_profile
|
14
app/views/posts/_moderation_queue.haml
Normal file
14
app/views/posts/_moderation_queue.haml
Normal file
|
@ -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 'moderation_queue/comment', comment: comment, profile: comment['attributedTo']
|
||||||
|
|
||||||
|
-# Botones moderación
|
||||||
|
.d-flex
|
||||||
|
= render 'components/comments_btn_box'
|
|
@ -1,6 +1,8 @@
|
||||||
.row.justify-content-center
|
.row.justify-content-center
|
||||||
.col-md-8
|
.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 '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
|
= render 'posts/moderation_queue', site: @site, post: @post, moderation_queue: @moderation_queue
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
= render 'sites/header', site: @site
|
= render 'sites/header', site: @site
|
||||||
|
|
||||||
= render 'sites/status', site: @site
|
= render 'sites/status', site: @site
|
||||||
|
|
||||||
= render 'sites/build', site: @site, class: 'btn-block'
|
= render 'sites/build', site: @site, class: 'btn-block'
|
||||||
|
|
||||||
%h3= t('posts.new')
|
%h3= t('posts.new')
|
||||||
|
@ -126,7 +125,7 @@
|
||||||
= post.order
|
= post.order
|
||||||
%td.text-nowrap
|
%td.text-nowrap
|
||||||
- if @usuarie || policy(post).edit?
|
- 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?
|
- 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') }
|
= 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') }
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
.row.justify-content-center
|
.row.justify-content-center
|
||||||
.col-md-8
|
.col-md-8
|
||||||
%article.content.table-responsive-md
|
%article.content.table-responsive-md
|
||||||
= link_to t('posts.edit'),
|
= link_to t('posts.edit_post'),
|
||||||
edit_site_post_path(@site, @post.id),
|
edit_site_post_path(@site, @post.id),
|
||||||
class: 'btn btn-secondary btn-block'
|
class: 'btn btn-secondary btn-block'
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
- if policy(site).build?
|
- if policy(site).build?
|
||||||
= form_tag site_enqueue_path(site),
|
%div{ 'hx-get': site_button_path(site, class: local_assigns[:class]), 'hx-trigger': 'every 10s', 'hx-swap': 'outerHTML' }
|
||||||
method: :post,
|
= form_tag site_enqueue_path(site),
|
||||||
class: 'form-inline inline' do
|
method: :post,
|
||||||
= submit_tag site.enqueued? ? t('sites.enqueued') : t('sites.enqueue'),
|
class: 'form-inline inline' do
|
||||||
class: "btn btn-secondary #{local_assigns[:class]}",
|
= submit_tag site.enqueued? ? t('sites.enqueued') : t('sites.enqueue'),
|
||||||
title: site.enqueued? ? t('help.sites.enqueued') : t('help.sites.enqueue'),
|
class: "btn btn-secondary #{local_assigns[:class]}",
|
||||||
data: { disable_with: t('sites.enqueued') },
|
title: site.enqueued? ? t('help.sites.enqueued') : t('help.sites.enqueue'),
|
||||||
disabled: site.enqueued?
|
data: { disable_with: t('sites.enqueued') },
|
||||||
|
disabled: !site.waiting?
|
||||||
|
|
|
@ -1,21 +1,24 @@
|
||||||
- link = nil
|
- cache site do
|
||||||
- if site.not_published_yet?
|
- link = nil
|
||||||
- message = t('.not_published_yet')
|
- if site.not_published_yet?
|
||||||
- elsif site.awaiting_publication?
|
- message = t('.not_published_yet')
|
||||||
- message = t('.awaiting_publication')
|
- elsif site.awaiting_publication?
|
||||||
- elsif site.building?
|
- message = t('.awaiting_publication')
|
||||||
- if site.average_publication_time_calculable?
|
- elsif site.building?
|
||||||
- average_building_time = site.average_publication_time
|
- if site.average_publication_time_calculable?
|
||||||
- elsif !site.similar_sites?
|
- average_building_time = site.average_publication_time
|
||||||
- average_building_time = 60
|
- 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
|
- 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
|
-# TODO: Calcular cada cuánto sería óptimo recargar
|
||||||
- message = t('.building', average_time: average_publication_time_human, seconds: average_building_time)
|
%div{ 'hx-get': site_status_path(site), 'hx-trigger': 'every 10s', 'hx-swap': 'outerHTML' }
|
||||||
- else
|
= render 'bootstrap/alert' do
|
||||||
- message = t('.available')
|
= link_to_if link, message.html_safe, site_build_stats_path(site), class: 'alert-link'
|
||||||
- link = true
|
|
||||||
|
|
||||||
= render 'bootstrap/alert' do
|
|
||||||
= link_to_if link, message.html_safe, site_build_stats_path(site), class: 'alert-link'
|
|
||||||
|
|
1
app/views/sites/build.haml
Normal file
1
app/views/sites/build.haml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
= render 'sites/build', site: @site, class: params.permit(:class)[:class]
|
1
app/views/sites/status.haml
Normal file
1
app/views/sites/status.haml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
= render 'sites/status', site: @site
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -e
|
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} \
|
git diff --name-status ${CI_MERGE_REQUEST_DIFF_BASE_SHA} \
|
||||||
| grep -v "^D" \
|
| grep -v "^D" \
|
||||||
|
|
|
@ -1,4 +1,130 @@
|
||||||
en:
|
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
|
||||||
|
preferred_name: Name in Fediverse
|
||||||
|
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
|
||||||
|
instance:
|
||||||
|
users: "Users:"
|
||||||
dark: Dark
|
dark: Dark
|
||||||
dir: ltr
|
dir: ltr
|
||||||
en: English
|
en: English
|
||||||
|
@ -389,7 +515,7 @@ en:
|
||||||
static_file_migration: 'File migration'
|
static_file_migration: 'File migration'
|
||||||
find_and_replace: 'Search and replace'
|
find_and_replace: 'Search and replace'
|
||||||
status:
|
status:
|
||||||
building: "Your site is building, refresh this page in <time datetime=\"PT%{seconds}S\">%{average_time}</time>."
|
building: "Your site is building, it will be ready in <time datetime=\"PT%{seconds}S\">%{average_time}</time>."
|
||||||
not_published_yet: "Your site is being published for the first time, please wait up to 1 minute..."
|
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."
|
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."
|
awaiting_publication: "There are unpublished changes. Click the button below and wait a moment to find them on your site."
|
||||||
|
@ -578,7 +704,10 @@ en:
|
||||||
categories: 'Everything'
|
categories: 'Everything'
|
||||||
index:
|
index:
|
||||||
search: 'Search'
|
search: 'Search'
|
||||||
edit: 'Edit'
|
edit_post: 'Edit'
|
||||||
|
edit:
|
||||||
|
moderation_queue: Moderation Queue
|
||||||
|
post: Post
|
||||||
preview:
|
preview:
|
||||||
btn: 'Preliminary version'
|
btn: 'Preliminary version'
|
||||||
alert: 'Not every article type has a preliminary version'
|
alert: 'Not every article type has a preliminary version'
|
||||||
|
|
|
@ -1,4 +1,130 @@
|
||||||
es:
|
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
|
||||||
|
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
|
||||||
|
custom_block: Lista personalizada de bloqueo
|
||||||
|
submit: Guardar listas de bloqueo
|
||||||
|
instance:
|
||||||
|
users: "Usuaries:"
|
||||||
dark: Oscuro
|
dark: Oscuro
|
||||||
es: Castellano
|
es: Castellano
|
||||||
en: English
|
en: English
|
||||||
|
@ -394,7 +520,7 @@ es:
|
||||||
static_file_migration: 'Migración de archivos'
|
static_file_migration: 'Migración de archivos'
|
||||||
find_and_replace: 'Búsqueda y reemplazo'
|
find_and_replace: 'Búsqueda y reemplazo'
|
||||||
status:
|
status:
|
||||||
building: "Tu sitio se está publicando, recargá esta página en <time datetime=\"PT%{seconds}S\">%{average_time}</time>."
|
building: "Tu sitio se está publicando, estará listo en <time datetime=\"PT%{seconds}S\">%{average_time}</time>."
|
||||||
not_published_yet: "Tu sitio se está publicando por primera vez, por favor espera hasta un minuto..."
|
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."
|
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."
|
awaiting_publication: "Hay cambios sin publicar, cliqueá el botón debajo y espera un momento para encontrarlos en tu sitio."
|
||||||
|
@ -520,6 +646,9 @@ es:
|
||||||
en: 'inglés'
|
en: 'inglés'
|
||||||
ar: 'árabe'
|
ar: 'árabe'
|
||||||
posts:
|
posts:
|
||||||
|
edit:
|
||||||
|
moderation_queue: Comentarios
|
||||||
|
post: Contenido
|
||||||
prev: Página anterior
|
prev: Página anterior
|
||||||
next: Página siguiente
|
next: Página siguiente
|
||||||
empty: No hay artículos con estos parámetros de búsqueda.
|
empty: No hay artículos con estos parámetros de búsqueda.
|
||||||
|
@ -586,7 +715,7 @@ es:
|
||||||
remove_filter_help: 'Quitar este filtro: %{filter}'
|
remove_filter_help: 'Quitar este filtro: %{filter}'
|
||||||
index:
|
index:
|
||||||
search: 'Buscar'
|
search: 'Buscar'
|
||||||
edit: 'Editar'
|
edit_post: 'Editar'
|
||||||
preview:
|
preview:
|
||||||
btn: 'Versión preliminar'
|
btn: 'Versión preliminar'
|
||||||
alert: 'No todos los tipos de artículos poseen vista preliminar :)'
|
alert: 'No todos los tipos de artículos poseen vista preliminar :)'
|
||||||
|
|
|
@ -37,6 +37,9 @@ Rails.application.routes.draw do
|
||||||
get 'pull', to: 'sites#fetch'
|
get 'pull', to: 'sites#fetch'
|
||||||
post 'pull', to: 'sites#merge'
|
post 'pull', to: 'sites#merge'
|
||||||
|
|
||||||
|
get 'status', to: 'sites#status'
|
||||||
|
get 'button', to: 'sites#button'
|
||||||
|
|
||||||
# Gestionar usuaries
|
# Gestionar usuaries
|
||||||
get 'usuaries/invite', to: 'usuaries#invite'
|
get 'usuaries/invite', to: 'usuaries#invite'
|
||||||
post 'usuaries/invite', to: 'usuaries#send_invitations'
|
post 'usuaries/invite', to: 'usuaries#send_invitations'
|
||||||
|
@ -50,6 +53,10 @@ Rails.application.routes.draw do
|
||||||
get 'collaborate', to: 'collaborations#collaborate'
|
get 'collaborate', to: 'collaborations#collaborate'
|
||||||
post 'collaborate', to: 'collaborations#accept_collaboration'
|
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
|
# Gestionar artículos según idioma
|
||||||
nested do
|
nested do
|
||||||
scope '/(:locale)', constraint: /[a-z]{2}(-[A-Z]{2})?/ do
|
scope '/(:locale)', constraint: /[a-z]{2}(-[A-Z]{2})?/ do
|
||||||
|
|
7
db/seeds/blocklists.yml
Normal file
7
db/seeds/blocklists.yml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
- id: gardenfence
|
||||||
|
title: Gardenfence
|
||||||
|
link: 'https://gardenfence.github.io/'
|
||||||
|
- id: lista
|
||||||
|
title: Lista
|
||||||
|
link: '#'
|
285
db/seeds/instances.yaml
Normal file
285
db/seeds/instances.yaml
Normal file
|
@ -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: |
|
||||||
|
<p style="text-align: center"><strong>¡No pasarán!</strong></p>
|
||||||
|
|
||||||
|
<p>Je kunt tijdelijk geen nieuw account op Todon.nl aanvragen.</p>
|
||||||
|
|
||||||
|
<!--<p>Je kunt tussen 9u00 en 23u00 Midden-Europese tijd (UTC+1) een account op Todon.nl aanvragen. Geef ons ajb voldoende tijd om je accountaanvraag te beoordelen.</p>-->
|
||||||
|
|
||||||
|
<p>Ga naar <a href="https://joinmastodon.org/servers">joinmastodon.org</a> of <a href="https://fedidb.org/network?s=mastodon">FediDB Network</a> om een andere server te vinden.</p>
|
||||||
|
|
||||||
|
<p>It is temporary not possible to request on account on Todon.nl.</p>
|
||||||
|
|
||||||
|
<!--<p>You can request an account on Todon.nl between 9h00 and 23h00 Central European Time (UTC+1). Please give us enough time to review your account request.</p>-->
|
||||||
|
|
||||||
|
<p>Go to <a href="https://joinmastodon.org/servers">joinmastodon.org</a> or <a href="https://fedidb.org/network?s=mastodon">FediDB Network</a> to find another server.</p>
|
||||||
|
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: "<p>This account is used for \U0001F399 Todon.nl announcements and ⚖️
|
||||||
|
moderation.</p><p>\U0001F6AB Don't follow this account when you are not
|
||||||
|
on Todon.nl.</p><p>New? First read our \U0001F469\U0001F3EB Todon 101 \U0001F469\U0001F393
|
||||||
|
at <a href=\"https://wiki.todon.eu/todon/101\" target=\"_blank\" rel=\"nofollow
|
||||||
|
noopener noreferrer\" translate=\"no\"><span class=\"invisible\">https://</span><span
|
||||||
|
class=\"\">wiki.todon.eu/todon/101</span><span class=\"invisible\"></span></a></p><p>⚖️
|
||||||
|
For all our moderators go to <a href=\"https://wiki.todon.nl/todon/moderators\"
|
||||||
|
target=\"_blank\" rel=\"nofollow noopener noreferrer\" translate=\"no\"><span
|
||||||
|
class=\"invisible\">https://</span><span class=\"\">wiki.todon.nl/todon/moderators</span><span
|
||||||
|
class=\"invisible\"></span></a></p><p>\U0001F4DD Public toots from this account
|
||||||
|
are in English.</p><p>\U0001F515 Criticism is fine, but people who do false
|
||||||
|
accusations are muted. </p><p>✉ todon@posteo.eu</p><p><a href=\"https://todon.nl/tags/nobot\"
|
||||||
|
class=\"mention hashtag\" rel=\"tag\">#<span>nobot</span></a></p>"
|
||||||
|
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: <a href="https://wiki.todon.nl/todon/terms_en" target="_blank" rel="nofollow
|
||||||
|
noopener noreferrer me" translate="no"><span class="invisible">https://</span><span
|
||||||
|
class="">wiki.todon.nl/todon/terms_en</span><span class="invisible"></span></a>
|
||||||
|
verified_at: '2018-11-01T14:39:45.465+00:00'
|
||||||
|
- name: ℹ️ Wiki
|
||||||
|
value: <a href="https://wiki.todon.nl/todon/information" target="_blank" rel="nofollow
|
||||||
|
noopener noreferrer me" translate="no"><span class="invisible">https://</span><span
|
||||||
|
class="ellipsis">wiki.todon.nl/todon/informatio</span><span class="invisible">n</span></a>
|
||||||
|
verified_at: '2018-11-01T14:40:54.679+00:00'
|
||||||
|
- name: "\U0001F4CA Status"
|
||||||
|
value: <a href="https://status.todon.eu" target="_blank" rel="nofollow noopener
|
||||||
|
noreferrer me" translate="no"><span class="invisible">https://</span><span
|
||||||
|
class="">status.todon.eu</span><span class="invisible"></span></a>
|
||||||
|
verified_at: '2023-10-26T20:38:30.185+00:00'
|
||||||
|
- name: "\U0001F4B3️ Donations"
|
||||||
|
value: <a href="https://wiki.todon.eu/todon/donations" target="_blank" rel="nofollow
|
||||||
|
noopener noreferrer me" translate="no"><span class="invisible">https://</span><span
|
||||||
|
class="">wiki.todon.eu/todon/donations</span><span class="invisible"></span></a>
|
||||||
|
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: <span class="h-card"><a href="https://mastodon.mauve.moe/@mauve" class="u-url
|
||||||
|
mention">@<span>mauve</span></a></span>
|
||||||
|
verified_at:
|
||||||
|
rules: []
|
153
db/seeds/moderation_queue.yaml
Normal file
153
db/seeds/moderation_queue.yaml
Normal file
File diff suppressed because one or more lines are too long
106
db/seeds/remote_profile.yaml
Normal file
106
db/seeds/remote_profile.yaml
Normal file
|
@ -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: "<p>Occult Enby that's making local-first software with peer to peer
|
||||||
|
protocols, mesh networks, and the web.</p><p>Also exploring what a local-first
|
||||||
|
cyberspace might look like in my spare time.</p>"
|
||||||
|
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: <span class="h-card"><a href="https://mastodon.mauve.moe/@mauve" class="u-url
|
||||||
|
mention">@<span>mauve</span></a></span>: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
|
|
@ -13,7 +13,7 @@
|
||||||
"@rails/activestorage": "^6.1.3-1",
|
"@rails/activestorage": "^6.1.3-1",
|
||||||
"@rails/ujs": "^6.1.3-1",
|
"@rails/ujs": "^6.1.3-1",
|
||||||
"@rails/webpacker": "5.4.4",
|
"@rails/webpacker": "5.4.4",
|
||||||
"@suttyweb/editor": "^0.1.25",
|
"@suttyweb/editor": "^0.1.27",
|
||||||
"babel-loader": "^8.2.2",
|
"babel-loader": "^8.2.2",
|
||||||
"chart.js": "^3.5.1",
|
"chart.js": "^3.5.1",
|
||||||
"chartkick": "^4.0.5",
|
"chartkick": "^4.0.5",
|
||||||
|
@ -21,6 +21,7 @@
|
||||||
"commonmark": "^0.29.0",
|
"commonmark": "^0.29.0",
|
||||||
"fork-awesome": "^1.1.7",
|
"fork-awesome": "^1.1.7",
|
||||||
"fork-ts-checker-webpack-plugin": "^6.1.0",
|
"fork-ts-checker-webpack-plugin": "^6.1.0",
|
||||||
|
"htmx.org": "^1.9.11",
|
||||||
"input-map": "git+https://0xacab.org/sutty/input-map.git",
|
"input-map": "git+https://0xacab.org/sutty/input-map.git",
|
||||||
"input-tag": "git+https://0xacab.org/sutty/input-tag.git",
|
"input-tag": "git+https://0xacab.org/sutty/input-tag.git",
|
||||||
"leaflet": "^1.7.1",
|
"leaflet": "^1.7.1",
|
||||||
|
|
40
yarn.lock
40
yarn.lock
|
@ -1821,6 +1821,26 @@
|
||||||
resolved "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz"
|
resolved "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz"
|
||||||
integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==
|
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":
|
"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2":
|
||||||
version "0.3.3"
|
version "0.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098"
|
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"
|
resolved "https://registry.npmjs.org/@stimulus/webpack-helpers/-/webpack-helpers-1.1.1.tgz"
|
||||||
integrity sha512-XOkqSw53N9072FLHvpLM25PIwy+ndkSSbnTtjKuyzsv8K5yfkFB2rv68jU1pzqYa9FZLcvZWP4yazC0V38dx9A==
|
integrity sha512-XOkqSw53N9072FLHvpLM25PIwy+ndkSSbnTtjKuyzsv8K5yfkFB2rv68jU1pzqYa9FZLcvZWP4yazC0V38dx9A==
|
||||||
|
|
||||||
"@suttyweb/editor@^0.1.25":
|
"@suttyweb/editor@^0.1.27":
|
||||||
version "0.1.25"
|
version "0.1.27"
|
||||||
resolved "https://registry.yarnpkg.com/@suttyweb/editor/-/editor-0.1.25.tgz#37b38560642a49b24383473543c28be943695f9f"
|
resolved "https://registry.yarnpkg.com/@suttyweb/editor/-/editor-0.1.27.tgz#9415a0b767e72dbe4fbf42ce87e62fb8f5125c31"
|
||||||
integrity sha512-fxOO9LpdntWzgNZch4cZB6QL0u+jEw0NqsNahKcGBbiJaS0GNGLRrT2LUd/Djc6O8HWkQguPLcquVT5eHq2h9g==
|
integrity sha512-Ts9TZtGiRIaHm+ffVBRl+/nuVcANWZNtFsrGacoajgEsagaIyA1cq8qjiNpPoM5ne9vTba3cAaLP04V/uEIhBw==
|
||||||
dependencies:
|
dependencies:
|
||||||
|
"@floating-ui/dom" "^1.5.1"
|
||||||
|
linkifyjs "^4.1.1"
|
||||||
prosemirror-svelte-nodeview "^1.0.2"
|
prosemirror-svelte-nodeview "^1.0.2"
|
||||||
|
|
||||||
"@types/caseless@*":
|
"@types/caseless@*":
|
||||||
|
@ -4548,6 +4570,11 @@ html-entities@^1.3.1:
|
||||||
resolved "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz"
|
resolved "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz"
|
||||||
integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==
|
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:
|
http-deceiver@^1.2.7:
|
||||||
version "1.2.7"
|
version "1.2.7"
|
||||||
resolved "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz"
|
resolved "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz"
|
||||||
|
@ -5190,6 +5217,11 @@ linkify-it@^2.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
uc.micro "^1.0.1"
|
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:
|
loader-runner@^2.4.0:
|
||||||
version "2.4.0"
|
version "2.4.0"
|
||||||
resolved "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz"
|
resolved "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz"
|
||||||
|
|
Loading…
Reference in a new issue