mirror of
https://github.com/glitch-soc/mastodon.git
synced 2026-03-29 03:00:33 +02:00
Merge commit 'f652c54c3334890176331f62150559a96eeb41ae' into glitch-soc/merge-upstream
Conflicts: - `app/services/backup_service.rb`: Upstream refactored activity serialization while glitch-soc passed an extra argument. Followed upstream's refactor, keeping our extra argument.
This commit is contained in:
2
Gemfile
2
Gemfile
@@ -28,7 +28,7 @@ gem 'bootsnap', require: false
|
||||
gem 'browser'
|
||||
gem 'charlock_holmes', '~> 0.7.7'
|
||||
gem 'chewy', '~> 7.3'
|
||||
gem 'devise', '~> 4.9'
|
||||
gem 'devise'
|
||||
gem 'devise-two-factor'
|
||||
|
||||
group :pam_authentication, optional: true do
|
||||
|
||||
14
Gemfile.lock
14
Gemfile.lock
@@ -131,7 +131,7 @@ GEM
|
||||
blurhash (0.1.8)
|
||||
bootsnap (1.20.1)
|
||||
msgpack (~> 1.2)
|
||||
brakeman (8.0.1)
|
||||
brakeman (8.0.2)
|
||||
racc
|
||||
browser (6.2.0)
|
||||
builder (3.3.0)
|
||||
@@ -187,10 +187,10 @@ GEM
|
||||
irb (~> 1.10)
|
||||
reline (>= 0.3.8)
|
||||
debug_inspector (1.2.0)
|
||||
devise (4.9.4)
|
||||
devise (5.0.0)
|
||||
bcrypt (~> 3.0)
|
||||
orm_adapter (~> 0.1)
|
||||
railties (>= 4.1.0)
|
||||
railties (>= 7.0)
|
||||
responders
|
||||
warden (~> 1.2.3)
|
||||
devise-two-factor (6.4.0)
|
||||
@@ -390,7 +390,7 @@ GEM
|
||||
activerecord
|
||||
kaminari-core (= 1.2.2)
|
||||
kaminari-core (1.2.2)
|
||||
kt-paperclip (7.2.2)
|
||||
kt-paperclip (7.3.0)
|
||||
activemodel (>= 4.2.0)
|
||||
activesupport (>= 4.2.0)
|
||||
marcel (~> 1.0.1)
|
||||
@@ -446,7 +446,7 @@ GEM
|
||||
mime-types (3.7.0)
|
||||
logger
|
||||
mime-types-data (~> 3.2025, >= 3.2025.0507)
|
||||
mime-types-data (3.2025.0924)
|
||||
mime-types-data (3.2026.0127)
|
||||
mini_mime (1.1.5)
|
||||
mini_portile2 (2.8.9)
|
||||
minitest (6.0.1)
|
||||
@@ -862,7 +862,7 @@ GEM
|
||||
unicode-display_width (>= 1.1.1, < 4)
|
||||
terrapin (1.1.1)
|
||||
climate_control
|
||||
test-prof (1.5.1)
|
||||
test-prof (1.5.2)
|
||||
thor (1.5.0)
|
||||
tilt (2.7.0)
|
||||
timeout (0.6.0)
|
||||
@@ -965,7 +965,7 @@ DEPENDENCIES
|
||||
csv (~> 3.2)
|
||||
database_cleaner-active_record
|
||||
debug (~> 1.8)
|
||||
devise (~> 4.9)
|
||||
devise
|
||||
devise-two-factor
|
||||
devise_pam_authenticatable2 (~> 9.2)
|
||||
discard (~> 1.2)
|
||||
|
||||
@@ -26,7 +26,7 @@ class Api::V1::Statuses::PinsController < Api::V1::Statuses::BaseController
|
||||
def distribute_add_activity!
|
||||
json = ActiveModelSerializers::SerializableResource.new(
|
||||
@status,
|
||||
serializer: ActivityPub::AddSerializer,
|
||||
serializer: ActivityPub::AddNoteSerializer,
|
||||
adapter: ActivityPub::Adapter
|
||||
).as_json
|
||||
|
||||
@@ -36,7 +36,7 @@ class Api::V1::Statuses::PinsController < Api::V1::Statuses::BaseController
|
||||
def distribute_remove_activity!
|
||||
json = ActiveModelSerializers::SerializableResource.new(
|
||||
@status,
|
||||
serializer: ActivityPub::RemoveSerializer,
|
||||
serializer: ActivityPub::RemoveNoteSerializer,
|
||||
adapter: ActivityPub::Adapter
|
||||
).as_json
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ class Api::V1Alpha::CollectionsController < Api::BaseController
|
||||
def destroy
|
||||
authorize @collection, :destroy?
|
||||
|
||||
@collection.destroy
|
||||
DeleteCollectionService.new.call(@collection)
|
||||
|
||||
head 200
|
||||
end
|
||||
|
||||
@@ -197,14 +197,14 @@ class Auth::SessionsController < Devise::SessionsController
|
||||
"2fa_auth_attempts:#{user.id}:#{Time.now.utc.hour}"
|
||||
end
|
||||
|
||||
def respond_to_on_destroy
|
||||
def respond_to_on_destroy(**)
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
render json: {
|
||||
redirect_to: after_sign_out_path_for(resource_name),
|
||||
}, status: 200
|
||||
end
|
||||
format.all { super }
|
||||
format.all { super(**) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -37,7 +37,7 @@ class StatusesController < ApplicationController
|
||||
|
||||
def activity
|
||||
expires_in 3.minutes, public: @status.distributable? && public_fetch_mode?
|
||||
render_with_cache json: ActivityPub::ActivityPresenter.from_status(@status), content_type: 'application/activity+json', serializer: ActivityPub::ActivitySerializer, adapter: ActivityPub::Adapter
|
||||
render_with_cache json: @status, content_type: 'application/activity+json', serializer: activity_serializer, adapter: ActivityPub::Adapter
|
||||
end
|
||||
|
||||
def embed
|
||||
@@ -69,4 +69,8 @@ class StatusesController < ApplicationController
|
||||
def redirect_to_original
|
||||
redirect_to(ActivityPub::TagManager.instance.url_for(@status.reblog), allow_other_host: true) if @status.reblog?
|
||||
end
|
||||
|
||||
def activity_serializer
|
||||
@status.reblog? ? ActivityPub::AnnounceNoteSerializer : ActivityPub::CreateNoteSerializer
|
||||
end
|
||||
end
|
||||
|
||||
@@ -233,12 +233,10 @@
|
||||
"column.bookmarks": "Закладкі",
|
||||
"column.collections": "Мае калекцыі",
|
||||
"column.community": "Лакальная стужка",
|
||||
"column.create_collection": "Стварыць калекцыю",
|
||||
"column.create_list": "Стварыць спіс",
|
||||
"column.direct": "Прыватныя згадванні",
|
||||
"column.directory": "Праглядзець профілі",
|
||||
"column.domain_blocks": "Заблакіраваныя дамены",
|
||||
"column.edit_collection": "Змяніць калекцыю",
|
||||
"column.edit_list": "Рэдагаваць спіс",
|
||||
"column.favourites": "Упадабанае",
|
||||
"column.firehose": "Стужкі",
|
||||
|
||||
@@ -227,12 +227,10 @@
|
||||
"column.bookmarks": "Marcadors",
|
||||
"column.collections": "Les meves coŀleccions",
|
||||
"column.community": "Línia de temps local",
|
||||
"column.create_collection": "Crear una coŀlecció",
|
||||
"column.create_list": "Crea una llista",
|
||||
"column.direct": "Mencions privades",
|
||||
"column.directory": "Navega pels perfils",
|
||||
"column.domain_blocks": "Dominis blocats",
|
||||
"column.edit_collection": "Editar la col·lecció",
|
||||
"column.edit_list": "Edita la llista",
|
||||
"column.favourites": "Favorits",
|
||||
"column.firehose": "Tuts en directe",
|
||||
|
||||
@@ -252,12 +252,10 @@
|
||||
"column.bookmarks": "Llyfrnodau",
|
||||
"column.collections": "Fy nghasgliadau",
|
||||
"column.community": "Ffrwd lleol",
|
||||
"column.create_collection": "Creu casgliad",
|
||||
"column.create_list": "Creu rhestr",
|
||||
"column.direct": "Crybwylliadau preifat",
|
||||
"column.directory": "Pori proffiliau",
|
||||
"column.domain_blocks": "Parthau wedi'u rhwystro",
|
||||
"column.edit_collection": "Golygu casgliad",
|
||||
"column.edit_list": "Golygu rhestr",
|
||||
"column.favourites": "Ffefrynnau",
|
||||
"column.firehose": "Ffrydiau byw",
|
||||
|
||||
@@ -236,28 +236,43 @@
|
||||
"collections.collection_description": "Beskrivelse",
|
||||
"collections.collection_name": "Navn",
|
||||
"collections.collection_topic": "Emne",
|
||||
"collections.content_warning": "Indholdsadvarsel",
|
||||
"collections.continue": "Fortsæt",
|
||||
"collections.create.accounts_subtitle": "Kun konti, du følger, og som har tilmeldt sig opdagelse, kan tilføjes.",
|
||||
"collections.create.accounts_title": "Hvem vil du fremhæve i denne samling?",
|
||||
"collections.create.basic_details_title": "Grundlæggende oplysninger",
|
||||
"collections.create.settings_title": "Indstillinger",
|
||||
"collections.create.steps": "Trin {step}/{total}",
|
||||
"collections.create_a_collection_hint": "Opret en samling for at anbefale eller dele dine yndlingskonti med andre.",
|
||||
"collections.create_collection": "Opret samling",
|
||||
"collections.delete_collection": "Slet samling",
|
||||
"collections.description_length_hint": "Begrænset til 100 tegn",
|
||||
"collections.edit_details": "Rediger grundlæggende oplysninger",
|
||||
"collections.edit_settings": "Rediger indstillinger",
|
||||
"collections.error_loading_collections": "Der opstod en fejl under indlæsning af dine samlinger.",
|
||||
"collections.manage_accounts": "Administrer konti",
|
||||
"collections.manage_accounts_in_collection": "Administrer konti i denne samling",
|
||||
"collections.mark_as_sensitive": "Markér som sensitiv",
|
||||
"collections.mark_as_sensitive_hint": "Skjuler samlingens beskrivelse og konti bag en indholdsadvarsel. Samlingens navn vil stadig være synligt.",
|
||||
"collections.name_length_hint": "Begrænset til 100 tegn",
|
||||
"collections.new_collection": "Ny samling",
|
||||
"collections.no_collections_yet": "Ingen samlinger endnu.",
|
||||
"collections.topic_hint": "Tilføj et hashtag, der hjælper andre med at forstå det overordnede emne for denne samling.",
|
||||
"collections.view_collection": "Vis samling",
|
||||
"collections.visibility_public": "Offentlig",
|
||||
"collections.visibility_public_hint": "Kan opdages i søgeresultater og andre områder, hvor anbefalinger vises.",
|
||||
"collections.visibility_title": "Synlighed",
|
||||
"collections.visibility_unlisted": "Skjul offentligt",
|
||||
"collections.visibility_unlisted_hint": "Synlig for alle, der har et link. Skjult i søgeresultater og anbefalinger.",
|
||||
"column.about": "Om",
|
||||
"column.blocks": "Blokerede brugere",
|
||||
"column.bookmarks": "Bogmærker",
|
||||
"column.collections": "Mine samlinger",
|
||||
"column.community": "Lokal tidslinje",
|
||||
"column.create_collection": "Opret samling",
|
||||
"column.create_list": "Opret liste",
|
||||
"column.direct": "Private omtaler",
|
||||
"column.directory": "Gennemse profiler",
|
||||
"column.domain_blocks": "Blokerede domæner",
|
||||
"column.edit_collection": "Rediger samling",
|
||||
"column.edit_list": "Redigér liste",
|
||||
"column.favourites": "Favoritter",
|
||||
"column.firehose": "Live feeds",
|
||||
|
||||
@@ -236,28 +236,43 @@
|
||||
"collections.collection_description": "Beschreibung",
|
||||
"collections.collection_name": "Titel",
|
||||
"collections.collection_topic": "Thema",
|
||||
"collections.content_warning": "Inhaltswarnung",
|
||||
"collections.continue": "Fortfahren",
|
||||
"collections.create.accounts_subtitle": "Du kannst nur Profile hinzufügen, denen du folgst und das Hinzufügen gestatten.",
|
||||
"collections.create.accounts_title": "Wen möchtest du in dieser Sammlung präsentieren?",
|
||||
"collections.create.basic_details_title": "Allgemeine Informationen",
|
||||
"collections.create.settings_title": "Einstellungen",
|
||||
"collections.create.steps": "Schritt {step}/{total}",
|
||||
"collections.create_a_collection_hint": "Erstelle eine Sammlung, um deine Lieblingsprofile anderen zu empfehlen oder sie zu teilen.",
|
||||
"collections.create_collection": "Sammlung erstellen",
|
||||
"collections.delete_collection": "Sammlung löschen",
|
||||
"collections.description_length_hint": "Maximal 100 Zeichen",
|
||||
"collections.edit_details": "Allgemeine Informationen bearbeiten",
|
||||
"collections.edit_settings": "Einstellungen bearbeiten",
|
||||
"collections.error_loading_collections": "Beim Laden deiner Sammlungen ist ein Fehler aufgetreten.",
|
||||
"collections.manage_accounts": "Profile verwalten",
|
||||
"collections.manage_accounts_in_collection": "Profile in dieser Sammlung verwalten",
|
||||
"collections.mark_as_sensitive": "Mit Inhaltswarnung versehen",
|
||||
"collections.mark_as_sensitive_hint": "Die Beschreibung sowie enthaltenen Profile werden durch eine Inhaltswarnung ausgeblendet. Der Titel bleibt weiterhin sichtbar.",
|
||||
"collections.name_length_hint": "Maximal 100 Zeichen",
|
||||
"collections.new_collection": "Neue Sammlung",
|
||||
"collections.no_collections_yet": "Bisher keine Sammlungen vorhanden.",
|
||||
"collections.topic_hint": "Ein Hashtag hilft anderen dabei, das zentrale Thema dieser Sammlung besser zu verstehen.",
|
||||
"collections.view_collection": "Sammlungen anzeigen",
|
||||
"collections.visibility_public": "Öffentlich",
|
||||
"collections.visibility_public_hint": "Wird in den Suchergebnissen und anderen Bereichen mit Empfehlungen angezeigt.",
|
||||
"collections.visibility_title": "Sichtbarkeit",
|
||||
"collections.visibility_unlisted": "Nicht gelistet",
|
||||
"collections.visibility_unlisted_hint": "Für alle mit einem Link sichtbar. Wird vor Suchergebnissen und Empfehlungen verborgen.",
|
||||
"column.about": "Über",
|
||||
"column.blocks": "Blockierte Profile",
|
||||
"column.bookmarks": "Lesezeichen",
|
||||
"column.collections": "Meine Sammlungen",
|
||||
"column.community": "Lokale Timeline",
|
||||
"column.create_collection": "Sammlung erstellen",
|
||||
"column.create_list": "Liste erstellen",
|
||||
"column.direct": "Private Erwähnungen",
|
||||
"column.directory": "Profile durchstöbern",
|
||||
"column.domain_blocks": "Blockierte Domains",
|
||||
"column.edit_collection": "Sammlung bearbeiten",
|
||||
"column.edit_list": "Liste bearbeiten",
|
||||
"column.favourites": "Favoriten",
|
||||
"column.firehose": "Live-Feeds",
|
||||
|
||||
@@ -236,28 +236,43 @@
|
||||
"collections.collection_description": "Περιγραφή",
|
||||
"collections.collection_name": "Όνομα",
|
||||
"collections.collection_topic": "Θέμα",
|
||||
"collections.content_warning": "Προειδοποίηση περιεχομένου",
|
||||
"collections.continue": "Συνέχεια",
|
||||
"collections.create.accounts_subtitle": "Μόνο οι λογαριασμοί που ακολουθείτε που έχουν επιλέξει ανακάλυψη μπορούν να προστεθούν.",
|
||||
"collections.create.accounts_title": "Ποιον θα αναδείξετε σε αυτήν τη συλλογή;",
|
||||
"collections.create.basic_details_title": "Βασικά στοιχεία",
|
||||
"collections.create.settings_title": "Ρυθμίσεις",
|
||||
"collections.create.steps": "Βήμα {step}/{total}",
|
||||
"collections.create_a_collection_hint": "Δημιουργήστε μια συλλογή για να προτείνετε ή να μοιραστείτε τους αγαπημένους σας λογαριασμούς με άλλους.",
|
||||
"collections.create_collection": "Δημιουργία συλλογής",
|
||||
"collections.delete_collection": "Διαγραφή συλλογής",
|
||||
"collections.description_length_hint": "Όριο 100 χαρακτήρων",
|
||||
"collections.edit_details": "Επεξεργασία βασικών στοιχείων",
|
||||
"collections.edit_settings": "Επεξεργασία ρυθμίσεων",
|
||||
"collections.error_loading_collections": "Παρουσιάστηκε σφάλμα κατά την προσπάθεια φόρτωσης των συλλογών σας.",
|
||||
"collections.manage_accounts": "Διαχείριση λογαριασμών",
|
||||
"collections.manage_accounts_in_collection": "Διαχείριση λογαριασμών σε αυτήν τη συλλογή",
|
||||
"collections.mark_as_sensitive": "Σήμανση ως ευαίσθητο",
|
||||
"collections.mark_as_sensitive_hint": "Κρύβει την περιγραφή και τους λογαριασμούς της συλλογής πίσω από μια προειδοποίηση περιεχομένου. Το όνομα της συλλογής θα είναι ακόμη ορατό.",
|
||||
"collections.name_length_hint": "Όριο 100 χαρακτήρων",
|
||||
"collections.new_collection": "Νέα συλλογή",
|
||||
"collections.no_collections_yet": "Καμία συλλογή ακόμη.",
|
||||
"collections.topic_hint": "Προσθέστε μια ετικέτα που βοηθά άλλους να κατανοήσουν το κύριο θέμα αυτής της συλλογής.",
|
||||
"collections.view_collection": "Προβολή συλλογής",
|
||||
"collections.visibility_public": "Δημόσια",
|
||||
"collections.visibility_public_hint": "Ανιχνεύσιμη στα αποτελέσματα αναζήτησης και σε άλλα σημεία όπου εμφανίζονται προτάσεις.",
|
||||
"collections.visibility_title": "Ορατότητα",
|
||||
"collections.visibility_unlisted": "Μη καταχωρημένη",
|
||||
"collections.visibility_unlisted_hint": "Ορατή σε οποιονδήποτε με σύνδεσμο. Κρυμμένη από τα αποτελέσματα αναζήτησης και τις προτάσεις.",
|
||||
"column.about": "Σχετικά με",
|
||||
"column.blocks": "Αποκλεισμένοι χρήστες",
|
||||
"column.bookmarks": "Σελιδοδείκτες",
|
||||
"column.collections": "Οι συλλογές μου",
|
||||
"column.community": "Τοπική ροή",
|
||||
"column.create_collection": "Δημιουργία συλλογής",
|
||||
"column.create_list": "Δημιουργία λίστας",
|
||||
"column.direct": "Ιδιωτικές επισημάνσεις",
|
||||
"column.directory": "Περιήγηση στα προφίλ",
|
||||
"column.domain_blocks": "Αποκλεισμένοι τομείς",
|
||||
"column.edit_collection": "Επεξεργασία συλλογής",
|
||||
"column.edit_list": "Επεξεργασία λίστας",
|
||||
"column.favourites": "Αγαπημένα",
|
||||
"column.firehose": "Ζωντανές ροές",
|
||||
|
||||
@@ -252,12 +252,10 @@
|
||||
"column.bookmarks": "Bookmarks",
|
||||
"column.collections": "My collections",
|
||||
"column.community": "Local timeline",
|
||||
"column.create_collection": "Create collection",
|
||||
"column.create_list": "Create list",
|
||||
"column.direct": "Private mentions",
|
||||
"column.directory": "Browse profiles",
|
||||
"column.domain_blocks": "Blocked domains",
|
||||
"column.edit_collection": "Edit collection",
|
||||
"column.edit_list": "Edit list",
|
||||
"column.favourites": "Favourites",
|
||||
"column.firehose": "Live feeds",
|
||||
|
||||
@@ -236,28 +236,43 @@
|
||||
"collections.collection_description": "Descripción",
|
||||
"collections.collection_name": "Nombre",
|
||||
"collections.collection_topic": "Tema",
|
||||
"collections.content_warning": "Advertencia de contenido",
|
||||
"collections.continue": "Continuar",
|
||||
"collections.create.accounts_subtitle": "Solo las cuentas que seguís —las cuales optaron por ser descubiertas— pueden ser agregadas.",
|
||||
"collections.create.accounts_title": "¿A quién vas a destacar en esta colección?",
|
||||
"collections.create.basic_details_title": "Detalles básicos",
|
||||
"collections.create.settings_title": "Configuración",
|
||||
"collections.create.steps": "Paso {step}/{total}",
|
||||
"collections.create_a_collection_hint": "Creá una colección para recomendar o compartir tus cuentas favoritas con otras personas.",
|
||||
"collections.create_collection": "Crear colección",
|
||||
"collections.delete_collection": "Eliminar colección",
|
||||
"collections.description_length_hint": "Límite de 100 caracteres",
|
||||
"collections.edit_details": "Editar detalles básicos",
|
||||
"collections.edit_settings": "Editar configuración",
|
||||
"collections.error_loading_collections": "Hubo un error al intentar cargar tus colecciones.",
|
||||
"collections.manage_accounts": "Administrar cuentas",
|
||||
"collections.manage_accounts_in_collection": "Administrar cuentas en esta colección",
|
||||
"collections.mark_as_sensitive": "Marcar como sensible",
|
||||
"collections.mark_as_sensitive_hint": "Oculta la descripción de la colección y las cuentas detrás de una advertencia de contenido. El nombre de la colección seguirá siendo visible.",
|
||||
"collections.name_length_hint": "Límite de 100 caracteres",
|
||||
"collections.new_collection": "Nueva colección",
|
||||
"collections.no_collections_yet": "No hay colecciones aún.",
|
||||
"collections.topic_hint": "Agregá una etiqueta que ayude a otros usuarios a entender el tema principal de esta colección.",
|
||||
"collections.view_collection": "Abrir colección",
|
||||
"collections.visibility_public": "Pública",
|
||||
"collections.visibility_public_hint": "Puede ser descubierta en los resultados de búsqueda y en otras áreas donde aparezcan recomendaciones.",
|
||||
"collections.visibility_title": "Visibilidad",
|
||||
"collections.visibility_unlisted": "No listada",
|
||||
"collections.visibility_unlisted_hint": "Visible para quien tenga el enlace. Oculta de los resultados de búsqueda y recomendaciones.",
|
||||
"column.about": "Información",
|
||||
"column.blocks": "Usuarios bloqueados",
|
||||
"column.bookmarks": "Marcadores",
|
||||
"column.collections": "Mis colecciones",
|
||||
"column.community": "Línea temporal local",
|
||||
"column.create_collection": "Crear colección",
|
||||
"column.create_list": "Crear lista",
|
||||
"column.direct": "Menciones privadas",
|
||||
"column.directory": "Explorar perfiles",
|
||||
"column.domain_blocks": "Dominios bloqueados",
|
||||
"column.edit_collection": "Editar colección",
|
||||
"column.edit_list": "Editar lista",
|
||||
"column.favourites": "Favoritos",
|
||||
"column.firehose": "Líneas temporales en vivo",
|
||||
|
||||
@@ -236,28 +236,43 @@
|
||||
"collections.collection_description": "Descripción",
|
||||
"collections.collection_name": "Nombre",
|
||||
"collections.collection_topic": "Tema",
|
||||
"collections.content_warning": "Advertencia de contenido",
|
||||
"collections.continue": "Continuar",
|
||||
"collections.create.accounts_subtitle": "Solo se pueden agregar cuentas que sigas y que hayan optado por aparecer en los resultados de búsqueda.",
|
||||
"collections.create.accounts_title": "¿A quién incluirás en esta colección?",
|
||||
"collections.create.basic_details_title": "Detalles básicos",
|
||||
"collections.create.settings_title": "Configuración",
|
||||
"collections.create.steps": "Paso {step}/{total}",
|
||||
"collections.create_a_collection_hint": "Crea una colección para recomendar o compartir tus cuentas favoritas con otras personas.",
|
||||
"collections.create_collection": "Crear colección",
|
||||
"collections.delete_collection": "Eliminar colección",
|
||||
"collections.description_length_hint": "Limitado a 100 caracteres",
|
||||
"collections.edit_details": "Editar detalles básicos",
|
||||
"collections.edit_settings": "Editar configuración",
|
||||
"collections.error_loading_collections": "Se produjo un error al intentar cargar tus colecciones.",
|
||||
"collections.manage_accounts": "Administrar cuentas",
|
||||
"collections.manage_accounts_in_collection": "Administrar cuentas en esta colección",
|
||||
"collections.mark_as_sensitive": "Marcar como sensible",
|
||||
"collections.mark_as_sensitive_hint": "Oculta la descripción y las cuentas de la colección detrás de una advertencia de contenido. El nombre de la colección seguirá siendo visible.",
|
||||
"collections.name_length_hint": "Limitado a 100 caracteres",
|
||||
"collections.new_collection": "Nueva colección",
|
||||
"collections.no_collections_yet": "No hay colecciones todavía.",
|
||||
"collections.topic_hint": "Agrega una etiqueta que ayude a los demás a comprender el tema principal de esta colección.",
|
||||
"collections.view_collection": "Ver colección",
|
||||
"collections.visibility_public": "Pública",
|
||||
"collections.visibility_public_hint": "Visible en los resultados de búsqueda y otras áreas donde aparecen recomendaciones.",
|
||||
"collections.visibility_title": "Visibilidad",
|
||||
"collections.visibility_unlisted": "No listado",
|
||||
"collections.visibility_unlisted_hint": "Visible para cualquier persona que tenga el enlace. Oculto en los resultados de búsqueda y las recomendaciones.",
|
||||
"column.about": "Acerca de",
|
||||
"column.blocks": "Usuarios bloqueados",
|
||||
"column.bookmarks": "Marcadores",
|
||||
"column.collections": "Mis colecciones",
|
||||
"column.community": "Cronología local",
|
||||
"column.create_collection": "Crear colección",
|
||||
"column.create_list": "Crear lista",
|
||||
"column.direct": "Menciones privadas",
|
||||
"column.directory": "Buscar perfiles",
|
||||
"column.domain_blocks": "Dominios ocultados",
|
||||
"column.edit_collection": "Editar colección",
|
||||
"column.edit_list": "Editar lista",
|
||||
"column.favourites": "Favoritos",
|
||||
"column.firehose": "Feeds en vivo",
|
||||
|
||||
@@ -17,8 +17,12 @@
|
||||
"account.activity": "Actividad",
|
||||
"account.add_note": "Añadir una nota personal",
|
||||
"account.add_or_remove_from_list": "Agregar o eliminar de listas",
|
||||
"account.badges.admin": "Administrador",
|
||||
"account.badges.blocked": "Bloqueado",
|
||||
"account.badges.bot": "Automatizada",
|
||||
"account.badges.domain_blocked": "Dominio bloqueado",
|
||||
"account.badges.group": "Grupo",
|
||||
"account.badges.muted": "Silenciado",
|
||||
"account.block": "Bloquear a @{name}",
|
||||
"account.block_domain": "Bloquear dominio {domain}",
|
||||
"account.block_short": "Bloquear",
|
||||
@@ -229,12 +233,10 @@
|
||||
"column.bookmarks": "Marcadores",
|
||||
"column.collections": "Mis colecciones",
|
||||
"column.community": "Cronología local",
|
||||
"column.create_collection": "Crear colección",
|
||||
"column.create_list": "Crear lista",
|
||||
"column.direct": "Menciones privadas",
|
||||
"column.directory": "Buscar perfiles",
|
||||
"column.domain_blocks": "Dominios bloqueados",
|
||||
"column.edit_collection": "Editar colección",
|
||||
"column.edit_list": "Editar lista",
|
||||
"column.favourites": "Favoritos",
|
||||
"column.firehose": "Cronologías",
|
||||
|
||||
@@ -236,6 +236,10 @@
|
||||
"collections.collection_description": "Kirjeldus",
|
||||
"collections.collection_name": "Nimi",
|
||||
"collections.collection_topic": "Teema",
|
||||
"collections.content_warning": "Sisuhoiatus",
|
||||
"collections.continue": "Jätka",
|
||||
"collections.create.settings_title": "Seadistused",
|
||||
"collections.create.steps": "Samm {step}/{total}",
|
||||
"collections.create_a_collection_hint": "Soovitamaks oma lemmikuid teistele kasutajatele lisa asjakohane kogumik.",
|
||||
"collections.create_collection": "Loo kogumik",
|
||||
"collections.delete_collection": "Kustuta kogumik",
|
||||
@@ -244,20 +248,20 @@
|
||||
"collections.mark_as_sensitive": "Märgi delikaatseks",
|
||||
"collections.mark_as_sensitive_hint": "Peidab kogumiku kirjelduse ja kontod sisuhoiatuse taha. Kogumiku nimi ise on sellele vaatamata nähtav.",
|
||||
"collections.name_length_hint": "Kuni 100 tähemärki",
|
||||
"collections.new_collection": "Uus kogumik",
|
||||
"collections.no_collections_yet": "Kogumikke veel pole.",
|
||||
"collections.topic_hint": "Lisa teemaviide, mis aitab teistel kasutajatel mõista selle kogumiku põhisisu.",
|
||||
"collections.view_collection": "Vaata kogumikku",
|
||||
"collections.visibility_public": "Avalik",
|
||||
"column.about": "Teave",
|
||||
"column.blocks": "Blokeeritud kasutajad",
|
||||
"column.bookmarks": "Järjehoidjad",
|
||||
"column.collections": "Minu kogumikud",
|
||||
"column.community": "Kohalik ajajoon",
|
||||
"column.create_collection": "Loo kogumik",
|
||||
"column.create_list": "Loo loend",
|
||||
"column.direct": "Privaatsed mainimised",
|
||||
"column.directory": "Sirvi profiile",
|
||||
"column.domain_blocks": "Peidetud domeenid",
|
||||
"column.edit_collection": "Muuda kogumikku",
|
||||
"column.edit_list": "Muuda loendit",
|
||||
"column.favourites": "Lemmikud",
|
||||
"column.firehose": "Postitused reaalajas",
|
||||
|
||||
@@ -236,28 +236,43 @@
|
||||
"collections.collection_description": "Kuvaus",
|
||||
"collections.collection_name": "Nimi",
|
||||
"collections.collection_topic": "Aihe",
|
||||
"collections.content_warning": "Sisältövaroitus",
|
||||
"collections.continue": "Jatka",
|
||||
"collections.create.accounts_subtitle": "Lisätä voi vain tilejä, joita seuraat ja jotka ovat valinneet tulla löydetyiksi.",
|
||||
"collections.create.accounts_title": "Keitä esittelet tässä kokoelmassa?",
|
||||
"collections.create.basic_details_title": "Perustiedot",
|
||||
"collections.create.settings_title": "Asetukset",
|
||||
"collections.create.steps": "Vaihe {step}/{total}",
|
||||
"collections.create_a_collection_hint": "Luomalla kokoelman voit suositella tai jakaa suosikkitilejäsi muiden kanssa.",
|
||||
"collections.create_collection": "Luo kokoelma",
|
||||
"collections.delete_collection": "Poista kokoelma",
|
||||
"collections.description_length_hint": "100 merkin rajoitus",
|
||||
"collections.edit_details": "Muokkaa perustietoja",
|
||||
"collections.edit_settings": "Muokkaa asetuksia",
|
||||
"collections.error_loading_collections": "Kokoelmien latauksessa tapahtui virhe.",
|
||||
"collections.manage_accounts": "Hallitse tilejä",
|
||||
"collections.manage_accounts_in_collection": "Hallitse tässä kokoelmassa olevia tilejä",
|
||||
"collections.mark_as_sensitive": "Merkitse arkaluonteiseksi",
|
||||
"collections.mark_as_sensitive_hint": "Piilottaa kokoelman kuvauksen ja tilit sisältövaroituksen taakse. Kokoelman nimi jää esiin.",
|
||||
"collections.name_length_hint": "100 merkin rajoitus",
|
||||
"collections.new_collection": "Uusi kokoelma",
|
||||
"collections.no_collections_yet": "Ei vielä kokoelmia.",
|
||||
"collections.topic_hint": "Lisää aihetunniste, joka auttaa muita ymmärtämään tämän kokoelman pääaiheen.",
|
||||
"collections.view_collection": "Näytä kokoelma",
|
||||
"collections.visibility_public": "Julkinen",
|
||||
"collections.visibility_public_hint": "Löydettävissä hakutuloksista ja muualta, jossa ilmenee suosituksia.",
|
||||
"collections.visibility_title": "Näkyvyys",
|
||||
"collections.visibility_unlisted": "Listaamaton",
|
||||
"collections.visibility_unlisted_hint": "Näkyy kaikille, joilla on linkki. Piilotetaan hakutuloksista ja suosituksista.",
|
||||
"column.about": "Tietoja",
|
||||
"column.blocks": "Estetyt käyttäjät",
|
||||
"column.bookmarks": "Kirjanmerkit",
|
||||
"column.collections": "Omat kokoelmat",
|
||||
"column.community": "Paikallinen aikajana",
|
||||
"column.create_collection": "Luo kokoelma",
|
||||
"column.create_list": "Luo lista",
|
||||
"column.direct": "Yksityismaininnat",
|
||||
"column.directory": "Selaa profiileja",
|
||||
"column.domain_blocks": "Estetyt verkkotunnukset",
|
||||
"column.edit_collection": "Muokkaa kokoelmaa",
|
||||
"column.edit_list": "Muokkaa listaa",
|
||||
"column.favourites": "Suosikit",
|
||||
"column.firehose": "Livesyötteet",
|
||||
|
||||
@@ -252,12 +252,10 @@
|
||||
"column.bookmarks": "Bókamerki",
|
||||
"column.collections": "Míni søvn",
|
||||
"column.community": "Lokal tíðarlinja",
|
||||
"column.create_collection": "Ger savn",
|
||||
"column.create_list": "Ger lista",
|
||||
"column.direct": "Privatar umrøður",
|
||||
"column.directory": "Blaða gjøgnum vangar",
|
||||
"column.domain_blocks": "Bannað økisnøvn",
|
||||
"column.edit_collection": "Rætta savn",
|
||||
"column.edit_list": "Broyt lista",
|
||||
"column.favourites": "Dámdir postar",
|
||||
"column.firehose": "Beinleiðis rásir",
|
||||
|
||||
@@ -252,12 +252,10 @@
|
||||
"column.bookmarks": "Signets",
|
||||
"column.collections": "Mes collections",
|
||||
"column.community": "Fil local",
|
||||
"column.create_collection": "Créer une collection",
|
||||
"column.create_list": "Créer une liste",
|
||||
"column.direct": "Mention privée",
|
||||
"column.directory": "Parcourir les profils",
|
||||
"column.domain_blocks": "Domaines bloqués",
|
||||
"column.edit_collection": "Modifier la collection",
|
||||
"column.edit_list": "Modifier la liste",
|
||||
"column.favourites": "Favoris",
|
||||
"column.firehose": "Flux en direct",
|
||||
|
||||
@@ -252,12 +252,10 @@
|
||||
"column.bookmarks": "Marque-pages",
|
||||
"column.collections": "Mes collections",
|
||||
"column.community": "Fil public local",
|
||||
"column.create_collection": "Créer une collection",
|
||||
"column.create_list": "Créer une liste",
|
||||
"column.direct": "Mentions privées",
|
||||
"column.directory": "Parcourir les profils",
|
||||
"column.domain_blocks": "Domaines bloqués",
|
||||
"column.edit_collection": "Modifier la collection",
|
||||
"column.edit_list": "Modifier la liste",
|
||||
"column.favourites": "Favoris",
|
||||
"column.firehose": "Flux en direct",
|
||||
|
||||
@@ -252,12 +252,10 @@
|
||||
"column.bookmarks": "Leabharmharcanna",
|
||||
"column.collections": "Mo bhailiúcháin",
|
||||
"column.community": "Amlíne áitiúil",
|
||||
"column.create_collection": "Cruthaigh bailiúchán",
|
||||
"column.create_list": "Cruthaigh liosta",
|
||||
"column.direct": "Luann príobháideach",
|
||||
"column.directory": "Brabhsáil próifílí",
|
||||
"column.domain_blocks": "Fearainn bhactha",
|
||||
"column.edit_collection": "Cuir bailiúchán in eagar",
|
||||
"column.edit_list": "Cuir liosta in eagar",
|
||||
"column.favourites": "Ceanáin",
|
||||
"column.firehose": "Fothaí beo",
|
||||
|
||||
@@ -236,28 +236,43 @@
|
||||
"collections.collection_description": "Descrición",
|
||||
"collections.collection_name": "Nome",
|
||||
"collections.collection_topic": "Temática",
|
||||
"collections.content_warning": "Aviso sobre o contido",
|
||||
"collections.continue": "Continuar",
|
||||
"collections.create.accounts_subtitle": "Só se poden engadir contas que segues e que optaron por ser incluídas en descubrir.",
|
||||
"collections.create.accounts_title": "A quen queres incluír nesta colección?",
|
||||
"collections.create.basic_details_title": "Detalles básicos",
|
||||
"collections.create.settings_title": "Axustes",
|
||||
"collections.create.steps": "Paso {step}/{total}",
|
||||
"collections.create_a_collection_hint": "Crear unha colección para recomendar ou compartir as túas contas favoritas.",
|
||||
"collections.create_collection": "Crear colección",
|
||||
"collections.delete_collection": "Eliminar colección",
|
||||
"collections.description_length_hint": "Límite de 100 caracteres",
|
||||
"collections.edit_details": "Editar detalles básicos",
|
||||
"collections.edit_settings": "Editar axustes",
|
||||
"collections.error_loading_collections": "Houbo un erro ao intentar cargar as túas coleccións.",
|
||||
"collections.manage_accounts": "Xestionar contas",
|
||||
"collections.manage_accounts_in_collection": "Xestionar as contas nesta colección",
|
||||
"collections.mark_as_sensitive": "Marcar como sensible",
|
||||
"collections.mark_as_sensitive_hint": "Oculta a descrición e contas da colección detrás dun aviso sobre o contido. O nome da colección permanece visible.",
|
||||
"collections.name_length_hint": "Límite de 100 caracteres",
|
||||
"collections.new_collection": "Nova colección",
|
||||
"collections.no_collections_yet": "Aínda non tes coleccións.",
|
||||
"collections.topic_hint": "Engadir un cancelo para que axudar a que outras persoas coñezan a temática desta colección.",
|
||||
"collections.view_collection": "Ver colección",
|
||||
"collections.visibility_public": "Pública",
|
||||
"collections.visibility_public_hint": "Pódese atopar nos resultados das buscas e noutras áreas onde se mostran recomendacións.",
|
||||
"collections.visibility_title": "Visibilidade",
|
||||
"collections.visibility_unlisted": "Fóra das listas",
|
||||
"collections.visibility_unlisted_hint": "Visible para calquera que teña a ligazón. Oculta nos resultados e recomendacións.",
|
||||
"column.about": "Sobre",
|
||||
"column.blocks": "Usuarias bloqueadas",
|
||||
"column.bookmarks": "Marcadores",
|
||||
"column.collections": "As miñas coleccións",
|
||||
"column.community": "Cronoloxía local",
|
||||
"column.create_collection": "Crear colección",
|
||||
"column.create_list": "Crear lista",
|
||||
"column.direct": "Mencións privadas",
|
||||
"column.directory": "Procurar perfís",
|
||||
"column.domain_blocks": "Dominios agochados",
|
||||
"column.edit_collection": "Editar colección",
|
||||
"column.edit_list": "Editar lista",
|
||||
"column.favourites": "Favoritas",
|
||||
"column.firehose": "O que acontece",
|
||||
|
||||
@@ -236,28 +236,43 @@
|
||||
"collections.collection_description": "תיאור",
|
||||
"collections.collection_name": "כינוי",
|
||||
"collections.collection_topic": "נושא",
|
||||
"collections.content_warning": "אזהרת תוכן",
|
||||
"collections.continue": "המשך",
|
||||
"collections.create.accounts_subtitle": "רק חשבונות נעקבים שבחרו להופיע ב\"תגליות\" ניתנים להוספה.",
|
||||
"collections.create.accounts_title": "את מי תבליטו באוסף זה?",
|
||||
"collections.create.basic_details_title": "פרטים בסיסיים",
|
||||
"collections.create.settings_title": "הגדרות",
|
||||
"collections.create.steps": "צעד {step} מתוך {total}",
|
||||
"collections.create_a_collection_hint": "יצירת אוסף כדי להמליץ או לשתף את החשבונות החביבים עליך עם אחרים.",
|
||||
"collections.create_collection": "יצירת אוסף",
|
||||
"collections.delete_collection": "מחיקת האוסף",
|
||||
"collections.description_length_hint": "מגבלה של 100 תווים",
|
||||
"collections.edit_details": "עריכת פרטים בסיסיים",
|
||||
"collections.edit_settings": "עריכת הגדרות",
|
||||
"collections.error_loading_collections": "חלה שגיאה בנסיון לטעון את אוספיך.",
|
||||
"collections.manage_accounts": "ניהול חשבונות",
|
||||
"collections.manage_accounts_in_collection": "ניהול החשבונות שבאוסף זה",
|
||||
"collections.mark_as_sensitive": "מסומנים כרגישים",
|
||||
"collections.mark_as_sensitive_hint": "הסתרת תיאור וחשבונות האוסף מאחורי אזהרת תוכן. שם האוסף עדיין ישאר גלוי.",
|
||||
"collections.name_length_hint": "מגבלה של 100 תווים",
|
||||
"collections.new_collection": "אוסף חדש",
|
||||
"collections.no_collections_yet": "עוד אין אוספים.",
|
||||
"collections.topic_hint": "הוספת תגית שמסייעת לאחרים להבין את הנושא הראשי של האוסף.",
|
||||
"collections.view_collection": "צפיה באוסף",
|
||||
"collections.visibility_public": "פומבי",
|
||||
"collections.visibility_public_hint": "זמין לגילוי בתוצאות חיפוש ושאר אזורים בהם מופיעות המלצות.",
|
||||
"collections.visibility_title": "ניראות",
|
||||
"collections.visibility_unlisted": "מוסתר",
|
||||
"collections.visibility_unlisted_hint": "זמין לכל מי שקיבל קישור. נסתר מתוצאות חיפוש והמלצות.",
|
||||
"column.about": "אודות",
|
||||
"column.blocks": "משתמשים חסומים",
|
||||
"column.bookmarks": "סימניות",
|
||||
"column.collections": "האוספים שלי",
|
||||
"column.community": "פיד שרת מקומי",
|
||||
"column.create_collection": "יצירת אוסף",
|
||||
"column.create_list": "יצירת רשימה",
|
||||
"column.direct": "הודעות פרטיות",
|
||||
"column.directory": "עיין בפרופילים",
|
||||
"column.domain_blocks": "קהילות (שמות מתחם) מוסתרות",
|
||||
"column.edit_collection": "עריכת אוסף",
|
||||
"column.edit_list": "עריכת רשימה",
|
||||
"column.favourites": "חיבובים",
|
||||
"column.firehose": "פידים עדכניים",
|
||||
|
||||
@@ -252,12 +252,10 @@
|
||||
"column.bookmarks": "Könyvjelzők",
|
||||
"column.collections": "Saját gyűjtemények",
|
||||
"column.community": "Helyi idővonal",
|
||||
"column.create_collection": "Gyűjtemény létrehozása",
|
||||
"column.create_list": "Lista létrehozása",
|
||||
"column.direct": "Személyes említések",
|
||||
"column.directory": "Profilok böngészése",
|
||||
"column.domain_blocks": "Letiltott domainek",
|
||||
"column.edit_collection": "Gyűjtemény szerkesztése",
|
||||
"column.edit_list": "Lista módosítása",
|
||||
"column.favourites": "Kedvencek",
|
||||
"column.firehose": "Hírfolyamok",
|
||||
|
||||
@@ -236,28 +236,36 @@
|
||||
"collections.collection_description": "Lýsing",
|
||||
"collections.collection_name": "Nafn",
|
||||
"collections.collection_topic": "Umfjöllunarefni",
|
||||
"collections.content_warning": "Viðvörun vegna efnis",
|
||||
"collections.continue": "Halda áfram",
|
||||
"collections.create.settings_title": "Stillingar",
|
||||
"collections.create.steps": "Skref {step}/{total}",
|
||||
"collections.create_a_collection_hint": "Búðu til safn með eftirlætisnotendunum þínum til að deila eða mæla með við aðra.",
|
||||
"collections.create_collection": "Búa til safn",
|
||||
"collections.delete_collection": "Eyða safni",
|
||||
"collections.description_length_hint": "100 stafa takmörk",
|
||||
"collections.edit_settings": "Breyta stillingum",
|
||||
"collections.error_loading_collections": "Villa kom upp þegar reynt var að hlaða inn söfnunum þínum.",
|
||||
"collections.manage_accounts": "Sýsla með notandaaðganga",
|
||||
"collections.mark_as_sensitive": "Merkja sem viðkvæmt",
|
||||
"collections.mark_as_sensitive_hint": "Felur lýsingu safnsins og notendur á bakvið aðvörun vegna efnis. Nafn safnsins verður áfram sýnilegt.",
|
||||
"collections.name_length_hint": "100 stafa takmörk",
|
||||
"collections.new_collection": "Nýtt safn",
|
||||
"collections.no_collections_yet": "Engin söfn ennþá.",
|
||||
"collections.topic_hint": "Bættu við myllumerki sem hjálpar öðrum að skilja aðalefni þessa safns.",
|
||||
"collections.view_collection": "Skoða safn",
|
||||
"collections.visibility_public": "Opinbert",
|
||||
"collections.visibility_title": "Sýnileiki",
|
||||
"collections.visibility_unlisted": "Óskráð",
|
||||
"column.about": "Um hugbúnaðinn",
|
||||
"column.blocks": "Útilokaðir notendur",
|
||||
"column.bookmarks": "Bókamerki",
|
||||
"column.collections": "Söfnin mín",
|
||||
"column.community": "Staðvær tímalína",
|
||||
"column.create_collection": "Búa til safn",
|
||||
"column.create_list": "Búa til lista",
|
||||
"column.direct": "Einkaspjall",
|
||||
"column.directory": "Skoða notendasnið",
|
||||
"column.domain_blocks": "Útilokuð lén",
|
||||
"column.edit_collection": "Breyta safni",
|
||||
"column.edit_list": "Breyta lista",
|
||||
"column.favourites": "Eftirlæti",
|
||||
"column.firehose": "Bein streymi",
|
||||
|
||||
@@ -252,12 +252,10 @@
|
||||
"column.bookmarks": "Segnalibri",
|
||||
"column.collections": "Le mie collezioni",
|
||||
"column.community": "Cronologia locale",
|
||||
"column.create_collection": "Crea la collezione",
|
||||
"column.create_list": "Crea lista",
|
||||
"column.direct": "Menzioni private",
|
||||
"column.directory": "Sfoglia profili",
|
||||
"column.domain_blocks": "Domini bloccati",
|
||||
"column.edit_collection": "Modifica la collezione",
|
||||
"column.edit_list": "Modifica lista",
|
||||
"column.favourites": "Preferiti",
|
||||
"column.firehose": "Feed in diretta",
|
||||
|
||||
@@ -229,12 +229,10 @@
|
||||
"column.bookmarks": "冊籤",
|
||||
"column.collections": "我ê收藏",
|
||||
"column.community": "本地ê時間線",
|
||||
"column.create_collection": "建立收藏",
|
||||
"column.create_list": "建立列單",
|
||||
"column.direct": "私人ê提起",
|
||||
"column.directory": "瀏覽個人資料",
|
||||
"column.domain_blocks": "封鎖ê域名",
|
||||
"column.edit_collection": "編輯收藏",
|
||||
"column.edit_list": "編輯列單",
|
||||
"column.favourites": "Siōng kah意",
|
||||
"column.firehose": "Tsit-má ê動態",
|
||||
|
||||
@@ -229,12 +229,10 @@
|
||||
"column.bookmarks": "Bladwijzers",
|
||||
"column.collections": "Mijn verzamelingen",
|
||||
"column.community": "Lokale tijdlijn",
|
||||
"column.create_collection": "Verzameling aanmaken",
|
||||
"column.create_list": "Lijst aanmaken",
|
||||
"column.direct": "Privéberichten",
|
||||
"column.directory": "Gebruikersgids",
|
||||
"column.domain_blocks": "Geblokkeerde servers",
|
||||
"column.edit_collection": "Verzameling bewerken",
|
||||
"column.edit_list": "Lijst bewerken",
|
||||
"column.favourites": "Favorieten",
|
||||
"column.firehose": "Openbare tijdlijnen",
|
||||
|
||||
@@ -228,12 +228,10 @@
|
||||
"column.bookmarks": "Salvos",
|
||||
"column.collections": "Minhas coleções",
|
||||
"column.community": "Linha local",
|
||||
"column.create_collection": "Criar coleção",
|
||||
"column.create_list": "Criar lista",
|
||||
"column.direct": "Menções privadas",
|
||||
"column.directory": "Explorar perfis",
|
||||
"column.domain_blocks": "Domínios bloqueados",
|
||||
"column.edit_collection": "Editar coleção",
|
||||
"column.edit_list": "Editar lista",
|
||||
"column.favourites": "Favoritos",
|
||||
"column.firehose": "Feeds ao vivo",
|
||||
|
||||
@@ -252,12 +252,10 @@
|
||||
"column.bookmarks": "Marcadores",
|
||||
"column.collections": "As minhas coleções",
|
||||
"column.community": "Cronologia local",
|
||||
"column.create_collection": "Criar coleção",
|
||||
"column.create_list": "Criar lista",
|
||||
"column.direct": "Menções privadas",
|
||||
"column.directory": "Explorar perfis",
|
||||
"column.domain_blocks": "Domínios bloqueados",
|
||||
"column.edit_collection": "Editar coleção",
|
||||
"column.edit_list": "Editar lista",
|
||||
"column.favourites": "Favoritos",
|
||||
"column.firehose": "Cronologias em tempo real",
|
||||
|
||||
@@ -234,28 +234,43 @@
|
||||
"collections.collection_description": "Përshkrim",
|
||||
"collections.collection_name": "Emër",
|
||||
"collections.collection_topic": "Temë",
|
||||
"collections.content_warning": "Sinjalizim lënde",
|
||||
"collections.continue": "Vazhdo",
|
||||
"collections.create.accounts_subtitle": "Mund të shtohen vetëm llogari që ju ndiqni të cilat kanë zgjedhur të jenë të zbulueshme.",
|
||||
"collections.create.accounts_title": "Kë do të shfaqni në këtë koleksion?",
|
||||
"collections.create.basic_details_title": "Hollësi bazë",
|
||||
"collections.create.settings_title": "Rregullime",
|
||||
"collections.create.steps": "Hapi {step}/{total}",
|
||||
"collections.create_a_collection_hint": "Krijoni një koleksion për ta rekomanduar, ose për të ndarë me të tjerët llogaritë tuaja të parapëlqyera.",
|
||||
"collections.create_collection": "Krijoni koleksion",
|
||||
"collections.delete_collection": "Fshije koleksionin",
|
||||
"collections.description_length_hint": "Kufi prej 100 shenjash",
|
||||
"collections.edit_details": "Përpunoni hollësi bazë",
|
||||
"collections.edit_settings": "Përpunoni rregullime",
|
||||
"collections.error_loading_collections": "Pati një gabim teksa provohej të ngarkoheshin koleksionet tuaj.",
|
||||
"collections.manage_accounts": "Administroni llogari",
|
||||
"collections.manage_accounts_in_collection": "Administroni llogari në këtë koleksion",
|
||||
"collections.mark_as_sensitive": "Vëri shenjë si rezervat",
|
||||
"collections.mark_as_sensitive_hint": "Bën fshehjen e përshkrimit të koleksionit dhe llogarive prapa një sinjalizimi lënde. Emri i koleksionit do të jetë ende i dukshëm.",
|
||||
"collections.name_length_hint": "Kufi prej 100 shenjash",
|
||||
"collections.new_collection": "Koleksion i ri",
|
||||
"collections.no_collections_yet": "Ende pa koleksione.",
|
||||
"collections.topic_hint": "Shtoni një hashtag që ndihmon të tjerët të kuptojnë temën kryesore të këtij koleksion.",
|
||||
"collections.view_collection": "Shiheni koleksionin",
|
||||
"collections.visibility_public": "Publik",
|
||||
"collections.visibility_public_hint": "I zbulueshëm në përfundime kërkimi dhe fusha të tjera ku shfaqen rekomandime.",
|
||||
"collections.visibility_title": "Dukshmëri",
|
||||
"collections.visibility_unlisted": "Jo në listë",
|
||||
"collections.visibility_unlisted_hint": "I dukshëm për këdo me një lidhje. I fshehur nga përfundime kërkimi dhe rekomandime.",
|
||||
"column.about": "Mbi",
|
||||
"column.blocks": "Përdorues të bllokuar",
|
||||
"column.bookmarks": "Faqerojtës",
|
||||
"column.collections": "Koleksionet e mi",
|
||||
"column.community": "Rrjedhë kohore vendore",
|
||||
"column.create_collection": "Krijoni koleksion",
|
||||
"column.create_list": "Krijo listë",
|
||||
"column.direct": "Përmendje private",
|
||||
"column.directory": "Shfletoni profile",
|
||||
"column.domain_blocks": "Përkatësi të bllokuara",
|
||||
"column.edit_collection": "Përpunoni koleksion",
|
||||
"column.edit_list": "Përpunoni listën",
|
||||
"column.favourites": "Të parapëlqyer",
|
||||
"column.firehose": "Prurje “live”",
|
||||
|
||||
@@ -252,12 +252,10 @@
|
||||
"column.bookmarks": "Yer İşaretleri",
|
||||
"column.collections": "Koleksiyonlarım",
|
||||
"column.community": "Yerel ağ akışı",
|
||||
"column.create_collection": "Koleksiyon oluştur",
|
||||
"column.create_list": "Liste oluştur",
|
||||
"column.direct": "Özel bahsetmeler",
|
||||
"column.directory": "Profillere göz at",
|
||||
"column.domain_blocks": "Engellenen alan adları",
|
||||
"column.edit_collection": "Koleksiyonu düzenle",
|
||||
"column.edit_list": "Listeyi düzenle",
|
||||
"column.favourites": "Gözdelerin",
|
||||
"column.firehose": "Anlık Akışlar",
|
||||
|
||||
@@ -236,28 +236,43 @@
|
||||
"collections.collection_description": "Mô tả",
|
||||
"collections.collection_name": "Tên",
|
||||
"collections.collection_topic": "Chủ đề",
|
||||
"collections.content_warning": "Nội dung ẩn",
|
||||
"collections.continue": "Tiếp tục",
|
||||
"collections.create.accounts_subtitle": "Chỉ những tài khoản bạn theo dõi và đã chọn tham gia chương trình khám phá mới có thể được thêm vào.",
|
||||
"collections.create.accounts_title": "Bạn sẽ chọn ai để giới thiệu trong bộ sưu tập này?",
|
||||
"collections.create.basic_details_title": "Thông tin cơ bản",
|
||||
"collections.create.settings_title": "Cài đặt",
|
||||
"collections.create.steps": "Bước {step}/{total}",
|
||||
"collections.create_a_collection_hint": "Tạo một collection để giới thiệu hoặc chia sẻ những trạm tút yêu thích của bạn với người khác.",
|
||||
"collections.create_collection": "Tạo collection",
|
||||
"collections.delete_collection": "Xóa collection",
|
||||
"collections.description_length_hint": "Giới hạn 100 ký tự",
|
||||
"collections.edit_details": "Sửa thông tin cơ bản",
|
||||
"collections.edit_settings": "Sửa cài đặt",
|
||||
"collections.error_loading_collections": "Đã xảy ra lỗi khi tải những collection của bạn.",
|
||||
"collections.manage_accounts": "Quản lý tài khoản",
|
||||
"collections.manage_accounts_in_collection": "Quản lý tài khoản trong collection này",
|
||||
"collections.mark_as_sensitive": "Đánh dấu nhạy cảm",
|
||||
"collections.mark_as_sensitive_hint": "Ẩn phần mô tả và thông tin tài khoản của collection phía sau cảnh báo nội dung. Tên bộ sưu tập vẫn hiển thị.",
|
||||
"collections.name_length_hint": "Giới hạn 100 ký tự",
|
||||
"collections.new_collection": "Collection mới",
|
||||
"collections.no_collections_yet": "Chưa có collection.",
|
||||
"collections.topic_hint": "Thêm hashtag giúp người khác hiểu chủ đề chính của collection này.",
|
||||
"collections.view_collection": "Xem collection",
|
||||
"collections.visibility_public": "Công khai",
|
||||
"collections.visibility_public_hint": "Có thể tìm thấy trong kết quả tìm kiếm và các khu vực khác nơi xuất hiện đề xuất.",
|
||||
"collections.visibility_title": "Hiển thị",
|
||||
"collections.visibility_unlisted": "Hạn chế",
|
||||
"collections.visibility_unlisted_hint": "Hiển thị cho bất kỳ ai có liên kết. Ẩn khỏi kết quả tìm kiếm và đề xuất.",
|
||||
"column.about": "Giới thiệu",
|
||||
"column.blocks": "Trạm tút đã chặn",
|
||||
"column.bookmarks": "Những tút đã lưu",
|
||||
"column.collections": "Collection của tôi",
|
||||
"column.community": "Máy chủ này",
|
||||
"column.create_collection": "Tạo collection",
|
||||
"column.create_list": "Tạo danh sách",
|
||||
"column.direct": "Nhắn riêng",
|
||||
"column.directory": "Tìm trạm tút",
|
||||
"column.domain_blocks": "Máy chủ đã chặn",
|
||||
"column.edit_collection": "Sửa collection",
|
||||
"column.edit_list": "Sửa danh sách",
|
||||
"column.favourites": "Những tút đã thích",
|
||||
"column.firehose": "Bảng tin",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"about.blocks": "被限制的服务器",
|
||||
"about.contact": "联系方式:",
|
||||
"about.default_locale": "默认默认",
|
||||
"about.default_locale": "默认",
|
||||
"about.disclaimer": "Mastodon 是自由的开源软件,商标由 Mastodon gGmbH 持有。",
|
||||
"about.domain_blocks.no_reason_available": "原因不可用",
|
||||
"about.domain_blocks.preamble": "通常来说,在 Mastodon 上,你可以浏览联邦宇宙中任何一台服务器上的内容,并且和上面的用户互动。但其中一些在本服务器上被设置为例外。",
|
||||
@@ -22,7 +22,7 @@
|
||||
"account.badges.bot": "机器人",
|
||||
"account.badges.domain_blocked": "已屏蔽域名",
|
||||
"account.badges.group": "群组",
|
||||
"account.badges.muted": "已隐藏",
|
||||
"account.badges.muted": "已停止提醒",
|
||||
"account.block": "屏蔽 @{name}",
|
||||
"account.block_domain": "屏蔽 {domain} 实例",
|
||||
"account.block_short": "屏蔽",
|
||||
@@ -46,6 +46,8 @@
|
||||
"account.featured.hashtags": "话题",
|
||||
"account.featured_tags.last_status_at": "上次发言于 {date}",
|
||||
"account.featured_tags.last_status_never": "暂无嘟文",
|
||||
"account.fields.scroll_next": "显示下一个",
|
||||
"account.fields.scroll_prev": "显示上一个",
|
||||
"account.filters.all": "所有活动",
|
||||
"account.filters.boosts_toggle": "显示转嘟",
|
||||
"account.filters.posts_boosts": "嘟文与转嘟",
|
||||
@@ -77,6 +79,23 @@
|
||||
"account.locked_info": "此账号已锁嘟。账号所有人会手动审核新关注者。",
|
||||
"account.media": "媒体",
|
||||
"account.mention": "提及 @{name}",
|
||||
"account.menu.add_to_list": "添加到列表…",
|
||||
"account.menu.block": "屏蔽账户",
|
||||
"account.menu.block_domain": "屏蔽 {domain}",
|
||||
"account.menu.copied": "已复制账户链接到剪贴板",
|
||||
"account.menu.copy": "复制链接",
|
||||
"account.menu.direct": "私下提及",
|
||||
"account.menu.hide_reblogs": "在时间线中隐藏转嘟",
|
||||
"account.menu.mention": "提及",
|
||||
"account.menu.mute": "停止提醒账户",
|
||||
"account.menu.open_original_page": "在 {domain} 上查看",
|
||||
"account.menu.remove_follower": "移除关注者",
|
||||
"account.menu.report": "举报账户",
|
||||
"account.menu.share": "分享…",
|
||||
"account.menu.show_reblogs": "在时间线中显示转嘟",
|
||||
"account.menu.unblock": "取消屏蔽账户",
|
||||
"account.menu.unblock_domain": "取消屏蔽 {domain}",
|
||||
"account.menu.unmute": "恢复提醒账户",
|
||||
"account.moved_to": "{name} 的新账号是:",
|
||||
"account.mute": "隐藏 @{name}",
|
||||
"account.mute_notifications_short": "关闭通知",
|
||||
@@ -85,14 +104,14 @@
|
||||
"account.muting": "正在静音",
|
||||
"account.mutual": "你们互相关注",
|
||||
"account.no_bio": "未提供描述。",
|
||||
"account.node_modal.callout": "个人备注仅对您个人可见。",
|
||||
"account.node_modal.callout": "个人备注仅对你个人可见。",
|
||||
"account.node_modal.edit_title": "编辑个人备注",
|
||||
"account.node_modal.error_unknown": "无法保存备注",
|
||||
"account.node_modal.field_label": "个人备注",
|
||||
"account.node_modal.save": "保存",
|
||||
"account.node_modal.title": "添加个人备注",
|
||||
"account.note.edit_button": "编辑",
|
||||
"account.note.title": "个人备注(仅对您可见)",
|
||||
"account.note.title": "个人备注(仅对你可见)",
|
||||
"account.open_original_page": "打开原始页面",
|
||||
"account.posts": "嘟文",
|
||||
"account.posts_with_replies": "嘟文和回复",
|
||||
@@ -138,7 +157,7 @@
|
||||
"annual_report.announcement.action_build": "构建我的 Wrapstodon 年度回顾",
|
||||
"annual_report.announcement.action_dismiss": "不了,谢谢",
|
||||
"annual_report.announcement.action_view": "查看我的 Wrapstodon 年度回顾",
|
||||
"annual_report.announcement.description": "探索更多关于您过去一年在 Mastodon 上的互动情况。",
|
||||
"annual_report.announcement.description": "探索更多关于你过去一年在 Mastodon 上的互动情况。",
|
||||
"annual_report.announcement.title": "Wrapstodon {year} 年度回顾来啦",
|
||||
"annual_report.nav_item.badge": "新",
|
||||
"annual_report.shared_page.donate": "捐助",
|
||||
@@ -217,28 +236,43 @@
|
||||
"collections.collection_description": "说明",
|
||||
"collections.collection_name": "名称",
|
||||
"collections.collection_topic": "话题",
|
||||
"collections.content_warning": "内容警告",
|
||||
"collections.continue": "继续",
|
||||
"collections.create.accounts_subtitle": "只有你关注的且已经主动加入发现功能的账号可以添加。",
|
||||
"collections.create.accounts_title": "你想在收藏列表中添加哪些人?",
|
||||
"collections.create.basic_details_title": "基本信息",
|
||||
"collections.create.settings_title": "设置",
|
||||
"collections.create.steps": "第 {step} 步(共 {total} 步)",
|
||||
"collections.create_a_collection_hint": "创建用于向其他人推荐或分享你最喜欢账号的收藏列表。",
|
||||
"collections.create_collection": "创建收藏列表",
|
||||
"collections.delete_collection": "删除收藏列表",
|
||||
"collections.description_length_hint": "100字限制",
|
||||
"collections.error_loading_collections": "加载您的收藏列表时发生错误。",
|
||||
"collections.edit_details": "编辑基本信息",
|
||||
"collections.edit_settings": "编辑设置",
|
||||
"collections.error_loading_collections": "加载你的收藏列表时发生错误。",
|
||||
"collections.manage_accounts": "管理账户",
|
||||
"collections.manage_accounts_in_collection": "管理此收藏列表内的账户",
|
||||
"collections.mark_as_sensitive": "标记为敏感内容",
|
||||
"collections.mark_as_sensitive_hint": "将此收藏列表的说明用内容警告隐藏。此收藏列表的名称仍将可见。",
|
||||
"collections.name_length_hint": "100字限制",
|
||||
"collections.new_collection": "新建收藏列表",
|
||||
"collections.no_collections_yet": "尚无收藏列表。",
|
||||
"collections.topic_hint": "添加话题标签,帮助他人了解此收藏列表的主题。",
|
||||
"collections.view_collection": "查看收藏列表",
|
||||
"collections.visibility_public": "公开",
|
||||
"collections.visibility_public_hint": "可在搜索结果及其他推荐功能可用的区域被发现。",
|
||||
"collections.visibility_title": "可见性",
|
||||
"collections.visibility_unlisted": "悄悄公开",
|
||||
"collections.visibility_unlisted_hint": "对任何知晓链接的人可见。在搜索结果及推荐中隐藏。",
|
||||
"column.about": "关于",
|
||||
"column.blocks": "屏蔽的用户",
|
||||
"column.bookmarks": "书签",
|
||||
"column.collections": "我的收藏列表",
|
||||
"column.community": "本站时间线",
|
||||
"column.create_collection": "创建收藏列表",
|
||||
"column.create_list": "创建列表",
|
||||
"column.direct": "私下提及",
|
||||
"column.directory": "浏览用户资料",
|
||||
"column.domain_blocks": "已屏蔽的域名",
|
||||
"column.edit_collection": "编辑收藏列表",
|
||||
"column.edit_list": "编辑列表",
|
||||
"column.favourites": "喜欢",
|
||||
"column.firehose": "实时动态",
|
||||
@@ -862,7 +896,7 @@
|
||||
"relative_time.today": "今天",
|
||||
"remove_quote_hint.button_label": "明白了",
|
||||
"remove_quote_hint.message": "你可以通过 {icon} 选项菜单进行此操作。",
|
||||
"remove_quote_hint.title": "是否想要删除你的引用嘟文?",
|
||||
"remove_quote_hint.title": "是否想要移除你的引用嘟文?",
|
||||
"reply_indicator.attachments": "{count, plural, other {# 个附件}}",
|
||||
"reply_indicator.cancel": "取消",
|
||||
"reply_indicator.poll": "投票",
|
||||
|
||||
@@ -236,28 +236,43 @@
|
||||
"collections.collection_description": "說明",
|
||||
"collections.collection_name": "名稱",
|
||||
"collections.collection_topic": "主題",
|
||||
"collections.content_warning": "內容警告",
|
||||
"collections.continue": "繼續",
|
||||
"collections.create.accounts_subtitle": "僅能加入您跟隨並選擇加入探索功能之帳號。",
|
||||
"collections.create.accounts_title": "您想於此收藏名單推薦誰?",
|
||||
"collections.create.basic_details_title": "基本資料",
|
||||
"collections.create.settings_title": "設定",
|
||||
"collections.create.steps": "步驟 {step}/{total}",
|
||||
"collections.create_a_collection_hint": "建立用以向其他人推薦或分享您最喜愛帳號之收藏名單。",
|
||||
"collections.create_collection": "建立收藏名單",
|
||||
"collections.delete_collection": "刪除收藏名單",
|
||||
"collections.description_length_hint": "100 字限制",
|
||||
"collections.edit_details": "編輯基本資料",
|
||||
"collections.edit_settings": "編輯設定",
|
||||
"collections.error_loading_collections": "讀取您的收藏名單時發生錯誤。",
|
||||
"collections.manage_accounts": "管理帳號",
|
||||
"collections.manage_accounts_in_collection": "管理此收藏名單之帳號",
|
||||
"collections.mark_as_sensitive": "標記為敏感內容",
|
||||
"collections.mark_as_sensitive_hint": "將此收藏名單之說明隱藏於內容警告之後。此收藏名單名稱仍將可見。",
|
||||
"collections.name_length_hint": "100 字限制",
|
||||
"collections.new_collection": "新增收藏名單",
|
||||
"collections.no_collections_yet": "您沒有任何收藏名單。",
|
||||
"collections.topic_hint": "新增主題標籤以協助其他人瞭解此收藏名單之主題。",
|
||||
"collections.view_collection": "檢視收藏名單",
|
||||
"collections.visibility_public": "公開",
|
||||
"collections.visibility_public_hint": "可於搜尋結果與其他推薦處可見。",
|
||||
"collections.visibility_title": "可見性",
|
||||
"collections.visibility_unlisted": "不公開",
|
||||
"collections.visibility_unlisted_hint": "任何擁有連結的人可見。但隱藏於搜尋結果與推薦中。",
|
||||
"column.about": "關於",
|
||||
"column.blocks": "已封鎖使用者",
|
||||
"column.bookmarks": "書籤",
|
||||
"column.collections": "我的收藏名單",
|
||||
"column.community": "本站時間軸",
|
||||
"column.create_collection": "建立收藏名單",
|
||||
"column.create_list": "建立列表",
|
||||
"column.direct": "私訊",
|
||||
"column.directory": "瀏覽個人檔案",
|
||||
"column.domain_blocks": "已封鎖網域",
|
||||
"column.edit_collection": "編輯收藏名單",
|
||||
"column.edit_list": "編輯列表",
|
||||
"column.favourites": "最愛",
|
||||
"column.firehose": "即時內容",
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub::ActivityPresenter < ActiveModelSerializers::Model
|
||||
attributes :id, :type, :actor, :published, :to, :cc, :virtual_object
|
||||
|
||||
class << self
|
||||
def from_status(status, allow_inlining: true)
|
||||
new.tap do |presenter|
|
||||
presenter.id = ActivityPub::TagManager.instance.activity_uri_for(status)
|
||||
presenter.type = status.reblog? ? 'Announce' : 'Create'
|
||||
presenter.actor = ActivityPub::TagManager.instance.uri_for(status.account)
|
||||
presenter.published = status.created_at
|
||||
presenter.to = ActivityPub::TagManager.instance.to(status)
|
||||
presenter.cc = ActivityPub::TagManager.instance.cc(status)
|
||||
|
||||
presenter.virtual_object = begin
|
||||
if status.reblog?
|
||||
if allow_inlining && status.account == status.proper.account && status.proper.private_visibility? && status.local?
|
||||
status.proper
|
||||
else
|
||||
ActivityPub::TagManager.instance.uri_for(status.proper)
|
||||
end
|
||||
else
|
||||
status.proper
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,20 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub::ActivitySerializer < ActivityPub::Serializer
|
||||
def self.serializer_for(model, options)
|
||||
case model.class.name
|
||||
when 'Status'
|
||||
ActivityPub::NoteSerializer
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
attributes :id, :type, :actor, :published, :to, :cc
|
||||
|
||||
has_one :virtual_object, key: :object
|
||||
|
||||
def published
|
||||
object.published.iso8601
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,20 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub::AddFeaturedCollectionSerializer < ActivityPub::Serializer
|
||||
include RoutingHelper
|
||||
|
||||
attributes :type, :actor, :target
|
||||
has_one :object, serializer: ActivityPub::FeaturedCollectionSerializer
|
||||
|
||||
def type
|
||||
'Add'
|
||||
end
|
||||
|
||||
def actor
|
||||
ActivityPub::TagManager.instance.uri_for(object.account)
|
||||
end
|
||||
|
||||
def target
|
||||
ap_account_featured_collections_url(object.account_id)
|
||||
end
|
||||
end
|
||||
24
app/serializers/activitypub/add_hashtag_serializer.rb
Normal file
24
app/serializers/activitypub/add_hashtag_serializer.rb
Normal file
@@ -0,0 +1,24 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub::AddHashtagSerializer < ActivityPub::Serializer
|
||||
attributes :type, :actor, :target
|
||||
|
||||
has_one :object, serializer: ActivityPub::HashtagSerializer
|
||||
|
||||
def type
|
||||
'Add'
|
||||
end
|
||||
|
||||
def actor
|
||||
ActivityPub::TagManager.instance.uri_for(object.account)
|
||||
end
|
||||
|
||||
def target
|
||||
# Technically this is not correct, as tags have their own collection.
|
||||
# But sadly we do not store the collection URI for tags anywhere so cannot
|
||||
# handle `Add` activities to that properly (yet). The receiving code for
|
||||
# this currently looks at the type of the contained objects to do the
|
||||
# right thing.
|
||||
ActivityPub::TagManager.instance.collection_uri_for(object.account, :featured)
|
||||
end
|
||||
end
|
||||
23
app/serializers/activitypub/add_note_serializer.rb
Normal file
23
app/serializers/activitypub/add_note_serializer.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub::AddNoteSerializer < ActivityPub::Serializer
|
||||
attributes :type, :actor, :target
|
||||
|
||||
has_one :proper_object, key: :object
|
||||
|
||||
def type
|
||||
'Add'
|
||||
end
|
||||
|
||||
def actor
|
||||
ActivityPub::TagManager.instance.uri_for(object.account)
|
||||
end
|
||||
|
||||
def proper_object
|
||||
ActivityPub::TagManager.instance.uri_for(object)
|
||||
end
|
||||
|
||||
def target
|
||||
ActivityPub::TagManager.instance.collection_uri_for(object.account, :featured)
|
||||
end
|
||||
end
|
||||
@@ -1,55 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub::AddSerializer < ActivityPub::Serializer
|
||||
class UriSerializer < ActiveModel::Serializer
|
||||
include RoutingHelper
|
||||
|
||||
def serializable_hash(*_args)
|
||||
ActivityPub::TagManager.instance.uri_for(object)
|
||||
end
|
||||
end
|
||||
|
||||
def self.serializer_for(model, options)
|
||||
case model
|
||||
when Status
|
||||
UriSerializer
|
||||
when FeaturedTag
|
||||
ActivityPub::HashtagSerializer
|
||||
when Collection
|
||||
ActivityPub::FeaturedCollectionSerializer
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
include RoutingHelper
|
||||
|
||||
attributes :type, :actor, :target
|
||||
has_one :proper_object, key: :object
|
||||
|
||||
def type
|
||||
'Add'
|
||||
end
|
||||
|
||||
def actor
|
||||
ActivityPub::TagManager.instance.uri_for(object.account)
|
||||
end
|
||||
|
||||
def proper_object
|
||||
object
|
||||
end
|
||||
|
||||
def target
|
||||
case object
|
||||
when Status, FeaturedTag
|
||||
# Technically this is not correct, as tags have their own collection.
|
||||
# But sadly we do not store the collection URI for tags anywhere so cannot
|
||||
# handle `Add` activities to that properly (yet). The receiving code for
|
||||
# this currently looks at the type of the contained objects to do the
|
||||
# right thing.
|
||||
ActivityPub::TagManager.instance.collection_uri_for(object.account, :featured)
|
||||
when Collection
|
||||
ap_account_featured_collections_url(object.account_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
53
app/serializers/activitypub/announce_note_serializer.rb
Normal file
53
app/serializers/activitypub/announce_note_serializer.rb
Normal file
@@ -0,0 +1,53 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub::AnnounceNoteSerializer < ActivityPub::Serializer
|
||||
def self.serializer_for(model, options)
|
||||
return ActivityPub::NoteSerializer if model.is_a?(Status)
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
attributes :id, :type, :actor, :published, :to, :cc
|
||||
|
||||
has_one :virtual_object, key: :object
|
||||
|
||||
def id
|
||||
ActivityPub::TagManager.instance.activity_uri_for(object)
|
||||
end
|
||||
|
||||
def type
|
||||
'Announce'
|
||||
end
|
||||
|
||||
def actor
|
||||
ActivityPub::TagManager.instance.uri_for(object.account)
|
||||
end
|
||||
|
||||
def to
|
||||
ActivityPub::TagManager.instance.to(object)
|
||||
end
|
||||
|
||||
def cc
|
||||
ActivityPub::TagManager.instance.cc(object)
|
||||
end
|
||||
|
||||
def published
|
||||
object.created_at.iso8601
|
||||
end
|
||||
|
||||
def virtual_object
|
||||
if allow_inlining? && object.account == object.proper.account && object.proper.private_visibility? && object.local?
|
||||
object.proper
|
||||
else
|
||||
ActivityPub::TagManager.instance.uri_for(object.proper)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def allow_inlining?
|
||||
return instance_options[:allow_inlining] if instance_options.key?(:allow_inlining)
|
||||
|
||||
true
|
||||
end
|
||||
end
|
||||
31
app/serializers/activitypub/create_note_serializer.rb
Normal file
31
app/serializers/activitypub/create_note_serializer.rb
Normal file
@@ -0,0 +1,31 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub::CreateNoteSerializer < ActivityPub::Serializer
|
||||
attributes :id, :type, :actor, :published, :to, :cc
|
||||
|
||||
has_one :object, serializer: ActivityPub::NoteSerializer
|
||||
|
||||
def id
|
||||
ActivityPub::TagManager.instance.activity_uri_for(object)
|
||||
end
|
||||
|
||||
def type
|
||||
'Create'
|
||||
end
|
||||
|
||||
def actor
|
||||
ActivityPub::TagManager.instance.uri_for(object.account)
|
||||
end
|
||||
|
||||
def to
|
||||
ActivityPub::TagManager.instance.to(object)
|
||||
end
|
||||
|
||||
def cc
|
||||
ActivityPub::TagManager.instance.cc(object)
|
||||
end
|
||||
|
||||
def published
|
||||
object.created_at.iso8601
|
||||
end
|
||||
end
|
||||
@@ -1,6 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub::DeleteSerializer < ActivityPub::Serializer
|
||||
class ActivityPub::DeleteNoteSerializer < ActivityPub::Serializer
|
||||
class TombstoneSerializer < ActivityPub::Serializer
|
||||
context_extensions :atom_uri
|
||||
|
||||
@@ -2,14 +2,15 @@
|
||||
|
||||
class ActivityPub::OutboxSerializer < ActivityPub::CollectionSerializer
|
||||
def self.serializer_for(model, options)
|
||||
if model.instance_of?(::ActivityPub::ActivityPresenter)
|
||||
ActivityPub::ActivitySerializer
|
||||
case model
|
||||
when Status
|
||||
model.reblog? ? ActivityPub::AnnounceNoteSerializer : ActivityPub::CreateNoteSerializer
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def items
|
||||
object.items.map { |status| ActivityPub::ActivityPresenter.from_status(status) }
|
||||
object.items
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub::RemoveFeaturedCollectionSerializer < ActivityPub::Serializer
|
||||
include RoutingHelper
|
||||
|
||||
attributes :type, :actor, :target
|
||||
has_one :object_uri, key: :object
|
||||
|
||||
def type
|
||||
'Remove'
|
||||
end
|
||||
|
||||
def actor
|
||||
ActivityPub::TagManager.instance.uri_for(object.account)
|
||||
end
|
||||
|
||||
def target
|
||||
ap_account_featured_collections_url(object.account_id)
|
||||
end
|
||||
|
||||
def object_uri
|
||||
ActivityPub::TagManager.instance.uri_for(object)
|
||||
end
|
||||
end
|
||||
18
app/serializers/activitypub/remove_hashtag_serializer.rb
Normal file
18
app/serializers/activitypub/remove_hashtag_serializer.rb
Normal file
@@ -0,0 +1,18 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub::RemoveHashtagSerializer < ActivityPub::Serializer
|
||||
attributes :type, :actor, :target
|
||||
has_one :object, serializer: ActivityPub::HashtagSerializer
|
||||
|
||||
def type
|
||||
'Remove'
|
||||
end
|
||||
|
||||
def actor
|
||||
ActivityPub::TagManager.instance.uri_for(object.account)
|
||||
end
|
||||
|
||||
def target
|
||||
ActivityPub::TagManager.instance.collection_uri_for(object.account, :featured)
|
||||
end
|
||||
end
|
||||
22
app/serializers/activitypub/remove_note_serializer.rb
Normal file
22
app/serializers/activitypub/remove_note_serializer.rb
Normal file
@@ -0,0 +1,22 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub::RemoveNoteSerializer < ActivityPub::Serializer
|
||||
attributes :type, :actor, :target
|
||||
has_one :proper_object, key: :object
|
||||
|
||||
def type
|
||||
'Remove'
|
||||
end
|
||||
|
||||
def actor
|
||||
ActivityPub::TagManager.instance.uri_for(object.account)
|
||||
end
|
||||
|
||||
def proper_object
|
||||
ActivityPub::TagManager.instance.uri_for(object)
|
||||
end
|
||||
|
||||
def target
|
||||
ActivityPub::TagManager.instance.collection_uri_for(object.account, :featured)
|
||||
end
|
||||
end
|
||||
@@ -1,43 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub::RemoveSerializer < ActivityPub::Serializer
|
||||
class UriSerializer < ActiveModel::Serializer
|
||||
include RoutingHelper
|
||||
|
||||
def serializable_hash(*_args)
|
||||
ActivityPub::TagManager.instance.uri_for(object)
|
||||
end
|
||||
end
|
||||
|
||||
def self.serializer_for(model, options)
|
||||
case model.class.name
|
||||
when 'Status'
|
||||
UriSerializer
|
||||
when 'FeaturedTag'
|
||||
ActivityPub::HashtagSerializer
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
include RoutingHelper
|
||||
|
||||
attributes :type, :actor, :target
|
||||
has_one :proper_object, key: :object
|
||||
|
||||
def type
|
||||
'Remove'
|
||||
end
|
||||
|
||||
def actor
|
||||
ActivityPub::TagManager.instance.uri_for(object.account)
|
||||
end
|
||||
|
||||
def proper_object
|
||||
object
|
||||
end
|
||||
|
||||
def target
|
||||
ActivityPub::TagManager.instance.collection_uri_for(object.account, :featured)
|
||||
end
|
||||
end
|
||||
@@ -3,7 +3,11 @@
|
||||
class ActivityPub::UndoAnnounceSerializer < ActivityPub::Serializer
|
||||
attributes :id, :type, :actor, :to
|
||||
|
||||
has_one :virtual_object, key: :object, serializer: ActivityPub::ActivitySerializer
|
||||
has_one :virtual_object, key: :object, serializer: ActivityPub::AnnounceNoteSerializer do |serializer|
|
||||
serializer.send(:instance_options)[:allow_inlining] = false
|
||||
|
||||
object
|
||||
end
|
||||
|
||||
def id
|
||||
[ActivityPub::TagManager.instance.uri_for(object.account), '#announces/', object.id, '/undo'].join
|
||||
@@ -22,6 +26,6 @@ class ActivityPub::UndoAnnounceSerializer < ActivityPub::Serializer
|
||||
end
|
||||
|
||||
def virtual_object
|
||||
ActivityPub::ActivityPresenter.from_status(object, allow_inlining: false)
|
||||
object
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub::UpdateSerializer < ActivityPub::Serializer
|
||||
class ActivityPub::UpdateActorSerializer < ActivityPub::Serializer
|
||||
attributes :id, :type, :actor, :to
|
||||
|
||||
has_one :object, serializer: ActivityPub::ActorSerializer
|
||||
37
app/serializers/activitypub/update_note_serializer.rb
Normal file
37
app/serializers/activitypub/update_note_serializer.rb
Normal file
@@ -0,0 +1,37 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub::UpdateNoteSerializer < ActivityPub::Serializer
|
||||
attributes :id, :type, :actor, :published, :to, :cc
|
||||
|
||||
has_one :object, serializer: ActivityPub::NoteSerializer
|
||||
|
||||
def id
|
||||
[ActivityPub::TagManager.instance.uri_for(object), '#updates/', edited_at.to_i].join
|
||||
end
|
||||
|
||||
def type
|
||||
'Update'
|
||||
end
|
||||
|
||||
def actor
|
||||
ActivityPub::TagManager.instance.uri_for(object.account)
|
||||
end
|
||||
|
||||
def to
|
||||
ActivityPub::TagManager.instance.to(object)
|
||||
end
|
||||
|
||||
def cc
|
||||
ActivityPub::TagManager.instance.cc(object)
|
||||
end
|
||||
|
||||
def published
|
||||
edited_at.iso8601
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def edited_at
|
||||
instance_options[:updated_at]&.to_datetime || object.edited_at
|
||||
end
|
||||
end
|
||||
@@ -34,7 +34,8 @@ class BackupService < BaseService
|
||||
add_comma = true
|
||||
|
||||
file.write(statuses.map do |status|
|
||||
item = serialize_payload(ActivityPub::ActivityPresenter.from_status(status), ActivityPub::ActivitySerializer, allow_local_only: true)
|
||||
serializer = status.reblog? ? ActivityPub::AnnounceNoteSerializer : ActivityPub::CreateNoteSerializer
|
||||
item = serialize_payload(status, serializer, allow_local_only: true)
|
||||
item.delete(:@context)
|
||||
|
||||
unless item[:type] == 'Announce' || item[:object][:attachment].blank?
|
||||
|
||||
@@ -32,6 +32,6 @@ class CreateCollectionService
|
||||
end
|
||||
|
||||
def activity_json
|
||||
ActiveModelSerializers::SerializableResource.new(@collection, serializer: ActivityPub::AddSerializer, adapter: ActivityPub::Adapter).to_json
|
||||
ActiveModelSerializers::SerializableResource.new(@collection, serializer: ActivityPub::AddFeaturedCollectionSerializer, adapter: ActivityPub::Adapter).to_json
|
||||
end
|
||||
end
|
||||
|
||||
@@ -26,6 +26,6 @@ class CreateFeaturedTagService < BaseService
|
||||
private
|
||||
|
||||
def build_json(featured_tag)
|
||||
Oj.dump(serialize_payload(featured_tag, ActivityPub::AddSerializer, signer: @account))
|
||||
Oj.dump(serialize_payload(featured_tag, ActivityPub::AddHashtagSerializer, signer: @account))
|
||||
end
|
||||
end
|
||||
|
||||
20
app/services/delete_collection_service.rb
Normal file
20
app/services/delete_collection_service.rb
Normal file
@@ -0,0 +1,20 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class DeleteCollectionService
|
||||
def call(collection)
|
||||
@collection = collection
|
||||
@collection.destroy!
|
||||
|
||||
distribute_remove_activity if Mastodon::Feature.collections_federation_enabled?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def distribute_remove_activity
|
||||
ActivityPub::AccountRawDistributionWorker.perform_async(activity_json, @collection.account.id)
|
||||
end
|
||||
|
||||
def activity_json
|
||||
ActiveModelSerializers::SerializableResource.new(@collection, serializer: ActivityPub::RemoveFeaturedCollectionSerializer, adapter: ActivityPub::Adapter).to_json
|
||||
end
|
||||
end
|
||||
@@ -49,8 +49,4 @@ class ReblogService < BaseService
|
||||
def increment_statistics
|
||||
ActivityTracker.increment('activity:interactions')
|
||||
end
|
||||
|
||||
def build_json(reblog)
|
||||
Oj.dump(serialize_payload(ActivityPub::ActivityPresenter.from_status(reblog), ActivityPub::ActivitySerializer, signer: reblog.account))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -26,6 +26,6 @@ class RemoveFeaturedTagService < BaseService
|
||||
private
|
||||
|
||||
def build_json(featured_tag)
|
||||
Oj.dump(serialize_payload(featured_tag, ActivityPub::RemoveSerializer, signer: @account))
|
||||
Oj.dump(serialize_payload(featured_tag, ActivityPub::RemoveHashtagSerializer, signer: @account))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -105,7 +105,7 @@ class RemoveStatusService < BaseService
|
||||
end
|
||||
|
||||
def signed_activity_json
|
||||
@signed_activity_json ||= Oj.dump(serialize_payload(@status, @status.reblog? ? ActivityPub::UndoAnnounceSerializer : ActivityPub::DeleteSerializer, signer: @account, always_sign: true))
|
||||
@signed_activity_json ||= Oj.dump(serialize_payload(@status, @status.reblog? ? ActivityPub::UndoAnnounceSerializer : ActivityPub::DeleteNoteSerializer, signer: @account, always_sign: true))
|
||||
end
|
||||
|
||||
def remove_reblogs
|
||||
|
||||
@@ -72,6 +72,6 @@ class SuspendAccountService < BaseService
|
||||
end
|
||||
|
||||
def signed_activity_json
|
||||
@signed_activity_json ||= Oj.dump(serialize_payload(@account, ActivityPub::UpdateSerializer, signer: @account))
|
||||
@signed_activity_json ||= Oj.dump(serialize_payload(@account, ActivityPub::UpdateActorSerializer, signer: @account))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -63,6 +63,6 @@ class UnsuspendAccountService < BaseService
|
||||
end
|
||||
|
||||
def signed_activity_json
|
||||
@signed_activity_json ||= Oj.dump(serialize_payload(@account, ActivityPub::UpdateSerializer, signer: @account))
|
||||
@signed_activity_json ||= Oj.dump(serialize_payload(@account, ActivityPub::UpdateActorSerializer, signer: @account))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -24,11 +24,15 @@ class ActivityPub::DistributionWorker < ActivityPub::RawDistributionWorker
|
||||
end
|
||||
|
||||
def payload
|
||||
@payload ||= Oj.dump(serialize_payload(activity, ActivityPub::ActivitySerializer, signer: @account))
|
||||
@payload ||= Oj.dump(serialize_payload(@status, activity_serializer, serializer_options.merge(signer: @account)))
|
||||
end
|
||||
|
||||
def activity
|
||||
ActivityPub::ActivityPresenter.from_status(@status)
|
||||
def activity_serializer
|
||||
@status.reblog? ? ActivityPub::AnnounceNoteSerializer : ActivityPub::CreateNoteSerializer
|
||||
end
|
||||
|
||||
def serializer_options
|
||||
{}
|
||||
end
|
||||
|
||||
def options
|
||||
|
||||
@@ -15,15 +15,11 @@ class ActivityPub::StatusUpdateDistributionWorker < ActivityPub::DistributionWor
|
||||
|
||||
protected
|
||||
|
||||
def activity
|
||||
ActivityPub::ActivityPresenter.new(
|
||||
id: [ActivityPub::TagManager.instance.uri_for(@status), '#updates/', @options[:updated_at]&.to_datetime&.to_i || @status.edited_at.to_i].join,
|
||||
type: 'Update',
|
||||
actor: ActivityPub::TagManager.instance.uri_for(@status.account),
|
||||
published: @options[:updated_at]&.to_datetime || @status.edited_at,
|
||||
to: ActivityPub::TagManager.instance.to(@status),
|
||||
cc: ActivityPub::TagManager.instance.cc(@status),
|
||||
virtual_object: @status
|
||||
)
|
||||
def activity_serializer
|
||||
ActivityPub::UpdateNoteSerializer
|
||||
end
|
||||
|
||||
def serializer_options
|
||||
super.merge({ updated_at: @options[:updated_at] })
|
||||
end
|
||||
end
|
||||
|
||||
@@ -23,6 +23,6 @@ class ActivityPub::UpdateDistributionWorker < ActivityPub::RawDistributionWorker
|
||||
end
|
||||
|
||||
def payload
|
||||
@payload ||= Oj.dump(serialize_payload(@account, ActivityPub::UpdateSerializer, signer: @account, sign_with: @options[:sign_with]))
|
||||
@payload ||= Oj.dump(serialize_payload(@account, ActivityPub::UpdateActorSerializer, signer: @account, sign_with: @options[:sign_with]))
|
||||
end
|
||||
end
|
||||
|
||||
11
bin/brakeman
11
bin/brakeman
@@ -10,17 +10,6 @@
|
||||
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
||||
|
||||
bundle_binstub = File.expand_path("bundle", __dir__)
|
||||
|
||||
if File.file?(bundle_binstub)
|
||||
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
||||
load(bundle_binstub)
|
||||
else
|
||||
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
||||
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
||||
end
|
||||
end
|
||||
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
|
||||
|
||||
109
bin/bundle
109
bin/bundle
@@ -1,109 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# This file was generated by Bundler.
|
||||
#
|
||||
# The application 'bundle' is installed as part of a gem, and
|
||||
# this file is here to facilitate running it.
|
||||
#
|
||||
|
||||
require "rubygems"
|
||||
|
||||
m = Module.new do
|
||||
module_function
|
||||
|
||||
def invoked_as_script?
|
||||
File.expand_path($0) == File.expand_path(__FILE__)
|
||||
end
|
||||
|
||||
def env_var_version
|
||||
ENV["BUNDLER_VERSION"]
|
||||
end
|
||||
|
||||
def cli_arg_version
|
||||
return unless invoked_as_script? # don't want to hijack other binstubs
|
||||
return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
|
||||
bundler_version = nil
|
||||
update_index = nil
|
||||
ARGV.each_with_index do |a, i|
|
||||
if update_index && update_index.succ == i && a.match?(Gem::Version::ANCHORED_VERSION_PATTERN)
|
||||
bundler_version = a
|
||||
end
|
||||
next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
|
||||
bundler_version = $1
|
||||
update_index = i
|
||||
end
|
||||
bundler_version
|
||||
end
|
||||
|
||||
def gemfile
|
||||
gemfile = ENV["BUNDLE_GEMFILE"]
|
||||
return gemfile if gemfile && !gemfile.empty?
|
||||
|
||||
File.expand_path("../Gemfile", __dir__)
|
||||
end
|
||||
|
||||
def lockfile
|
||||
lockfile =
|
||||
case File.basename(gemfile)
|
||||
when "gems.rb" then gemfile.sub(/\.rb$/, ".locked")
|
||||
else "#{gemfile}.lock"
|
||||
end
|
||||
File.expand_path(lockfile)
|
||||
end
|
||||
|
||||
def lockfile_version
|
||||
return unless File.file?(lockfile)
|
||||
lockfile_contents = File.read(lockfile)
|
||||
return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
|
||||
Regexp.last_match(1)
|
||||
end
|
||||
|
||||
def bundler_requirement
|
||||
@bundler_requirement ||=
|
||||
env_var_version ||
|
||||
cli_arg_version ||
|
||||
bundler_requirement_for(lockfile_version)
|
||||
end
|
||||
|
||||
def bundler_requirement_for(version)
|
||||
return "#{Gem::Requirement.default}.a" unless version
|
||||
|
||||
bundler_gem_version = Gem::Version.new(version)
|
||||
|
||||
bundler_gem_version.approximate_recommendation
|
||||
end
|
||||
|
||||
def load_bundler!
|
||||
ENV["BUNDLE_GEMFILE"] ||= gemfile
|
||||
|
||||
activate_bundler
|
||||
end
|
||||
|
||||
def activate_bundler
|
||||
gem_error = activation_error_handling do
|
||||
gem "bundler", bundler_requirement
|
||||
end
|
||||
return if gem_error.nil?
|
||||
require_error = activation_error_handling do
|
||||
require "bundler/version"
|
||||
end
|
||||
return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
|
||||
warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
|
||||
exit 42
|
||||
end
|
||||
|
||||
def activation_error_handling
|
||||
yield
|
||||
nil
|
||||
rescue StandardError, LoadError => e
|
||||
e
|
||||
end
|
||||
end
|
||||
|
||||
m.load_bundler!
|
||||
|
||||
if m.invoked_as_script?
|
||||
load Gem.bin_path("bundler", "bundle")
|
||||
end
|
||||
@@ -10,17 +10,6 @@
|
||||
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
||||
|
||||
bundle_binstub = File.expand_path("bundle", __dir__)
|
||||
|
||||
if File.file?(bundle_binstub)
|
||||
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
||||
load(bundle_binstub)
|
||||
else
|
||||
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
||||
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
||||
end
|
||||
end
|
||||
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
|
||||
|
||||
11
bin/flatware
11
bin/flatware
@@ -10,17 +10,6 @@
|
||||
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
||||
|
||||
bundle_binstub = File.expand_path("bundle", __dir__)
|
||||
|
||||
if File.file?(bundle_binstub)
|
||||
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
||||
load(bundle_binstub)
|
||||
else
|
||||
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
||||
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
||||
end
|
||||
end
|
||||
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
|
||||
|
||||
@@ -10,17 +10,6 @@
|
||||
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
||||
|
||||
bundle_binstub = File.expand_path("bundle", __dir__)
|
||||
|
||||
if File.file?(bundle_binstub)
|
||||
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
||||
load(bundle_binstub)
|
||||
else
|
||||
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
||||
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
||||
end
|
||||
end
|
||||
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
|
||||
|
||||
@@ -10,17 +10,6 @@
|
||||
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
||||
|
||||
bundle_binstub = File.expand_path("bundle", __dir__)
|
||||
|
||||
if File.file?(bundle_binstub)
|
||||
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
||||
load(bundle_binstub)
|
||||
else
|
||||
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
||||
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
||||
end
|
||||
end
|
||||
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
|
||||
|
||||
@@ -10,17 +10,6 @@
|
||||
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
||||
|
||||
bundle_binstub = File.expand_path("bundle", __dir__)
|
||||
|
||||
if File.file?(bundle_binstub)
|
||||
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
||||
load(bundle_binstub)
|
||||
else
|
||||
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
||||
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
||||
end
|
||||
end
|
||||
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
|
||||
|
||||
11
bin/rspec
11
bin/rspec
@@ -10,17 +10,6 @@
|
||||
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
||||
|
||||
bundle_binstub = File.expand_path("bundle", __dir__)
|
||||
|
||||
if File.file?(bundle_binstub)
|
||||
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
||||
load(bundle_binstub)
|
||||
else
|
||||
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
||||
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
||||
end
|
||||
end
|
||||
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
|
||||
|
||||
11
bin/rubocop
11
bin/rubocop
@@ -10,17 +10,6 @@
|
||||
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
||||
|
||||
bundle_binstub = File.expand_path("bundle", __dir__)
|
||||
|
||||
if File.file?(bundle_binstub)
|
||||
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
||||
load(bundle_binstub)
|
||||
else
|
||||
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
||||
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
||||
end
|
||||
end
|
||||
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
|
||||
|
||||
11
bin/vite
11
bin/vite
@@ -10,17 +10,6 @@
|
||||
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
||||
|
||||
bundle_binstub = File.expand_path("bundle", __dir__)
|
||||
|
||||
if File.file?(bundle_binstub)
|
||||
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
||||
load(bundle_binstub)
|
||||
else
|
||||
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
||||
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
||||
end
|
||||
end
|
||||
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
|
||||
|
||||
@@ -105,11 +105,9 @@ Devise.setup do |config|
|
||||
# The secret key used by Devise. Devise uses this key to generate
|
||||
# random tokens. Changing this key will render invalid all existing
|
||||
# confirmation, reset password and unlock tokens in the database.
|
||||
#
|
||||
# Set explicitly to Rails default to avoid deprecation warnings.
|
||||
# https://github.com/heartcombo/devise/pull/5645#issuecomment-1871849856
|
||||
# Remove when Devise changes `SecretKeyFinder` to not emit deprecations.
|
||||
config.secret_key = Rails.application.secret_key_base
|
||||
# Devise will use the `secret_key_base` as its `secret_key`
|
||||
# by default. You can change it below and use your own secret key.
|
||||
# config.secret_key = '<%= SecureRandom.hex(64) %>'
|
||||
|
||||
# ==> Mailer Configuration
|
||||
# Configure the e-mail address which will be shown in Devise::Mailer,
|
||||
|
||||
@@ -12,6 +12,9 @@ de:
|
||||
followers:
|
||||
one: Follower
|
||||
other: Follower
|
||||
following:
|
||||
one: Folge ich
|
||||
other: Folge ich
|
||||
instance_actor_flash: Dieses Konto ist ein virtueller Akteur, der den Server selbst repräsentiert, und kein persönliches Profil. Es wird für Föderationszwecke verwendet und sollte daher nicht gesperrt werden.
|
||||
last_active: zuletzt aktiv
|
||||
link_verified_on: Das Profil mit dieser E-Mail-Adresse wurde bereits am %{date} bestätigt
|
||||
|
||||
@@ -7,7 +7,7 @@ zh-CN:
|
||||
send_paranoid_instructions: 如果你的邮箱地址存在于我们的数据库中,你将在几分钟内收到一封邮件,内含如何验证邮箱地址的指引。如果你没有收到这封邮件,请检查你的垃圾邮件文件夹。
|
||||
failure:
|
||||
already_authenticated: 你已登录。
|
||||
closed_registrations: 你的注册因为网络政策已被阻止。若您认为这是错误,请联系 %{email}。
|
||||
closed_registrations: 你的注册因为网络政策已被阻止。若你认为这是错误,请联系 %{email}。
|
||||
inactive: 你还没有激活账号。
|
||||
invalid: "%{authentication_keys} 无效或密码错误。"
|
||||
last_attempt: 你只有最后一次尝试机会,若未通过,账号将被锁定。
|
||||
|
||||
@@ -12,6 +12,9 @@ el:
|
||||
followers:
|
||||
one: Ακόλουθος
|
||||
other: Ακόλουθοι
|
||||
following:
|
||||
one: Ακολουθεί
|
||||
other: Ακολουθούν
|
||||
instance_actor_flash: Αυτός ο λογαριασμός είναι εικονικός και χρησιμοποιείται για να αντιπροσωπεύει τον ίδιο τον διακομιστή και όχι κάποιον μεμονωμένο χρήστη. Χρησιμοποιείται για σκοπούς ομοσπονδίας και δεν πρέπει να ανασταλεί.
|
||||
last_active: τελευταία ενεργός/ή
|
||||
link_verified_on: Η ιδιοκτησία αυτού του συνδέσμου ελέγχθηκε στις %{date}
|
||||
|
||||
@@ -12,6 +12,9 @@ es-MX:
|
||||
followers:
|
||||
one: Seguidor
|
||||
other: Seguidores
|
||||
following:
|
||||
one: Siguiendo
|
||||
other: Siguiendo
|
||||
instance_actor_flash: Esta cuenta es un actor virtual utilizado para representar al servidor en sí mismo y no a ningún usuario individual. Se utiliza para propósitos de la federación y no se debe suspender.
|
||||
last_active: última conexión
|
||||
link_verified_on: La propiedad de este vínculo fue verificada el %{date}
|
||||
|
||||
@@ -93,7 +93,7 @@ zh-CN:
|
||||
content_cache_retention_period: 来自其它实例的所有嘟文(包括转嘟与回复)都将在指定天数后被删除,不论本实例用户是否与这些嘟文产生过交互。这包括被本实例用户喜欢和收藏的嘟文。实例间用户的私下提及也将丢失并无法恢复。此设置针对的是特殊用途的实例,用于一般用途时会打破许多用户的期望。
|
||||
custom_css: 你可以为网页版 Mastodon 应用自定义样式。
|
||||
favicon: WEBP、PNG、GIF 或 JPG。使用自定义图标覆盖 Mastodon 的默认图标。
|
||||
landing_page: 选择新访客首次访问您的服务器时看到的页面。 如果选择“热门”,则需要在“发现”设置中启用热门趋势。 如果选择“本站动态”,则在“发现”设置中“展示本站嘟文的实时动态访问权限”一项需要设置为“所有人”。
|
||||
landing_page: 选择新访客首次访问你的服务器时看到的页面。 如果选择“热门”,则需要在“发现”设置中启用热门趋势。 如果选择“本站动态”,则在“发现”设置中“展示本站嘟文的实时动态访问权限”一项需要设置为“所有人”。
|
||||
mascot: 覆盖高级网页界面中的绘图形象。
|
||||
media_cache_retention_period: 来自外站用户嘟文的媒体文件将被缓存到你的实例上。当该值被设为正值时,缓存的媒体文件将在指定天数后被清除。如果媒体文件在被清除后重新被请求,且源站内容仍然可用,它将被重新下载。由于链接预览卡拉取第三方站点的频率受到限制,建议将此值设置为至少 14 天,如果小于该值,链接预览卡将不会按需更新。
|
||||
min_age: 用户注册时必须确认出生日期
|
||||
|
||||
@@ -12,6 +12,9 @@ sq:
|
||||
followers:
|
||||
one: Ndjekës
|
||||
other: Ndjekës
|
||||
following:
|
||||
one: E ndjekur
|
||||
other: Të ndjekura
|
||||
instance_actor_flash: Kjo llogari është një aktor virtual, i përdorur për të përfaqësuar vetë serverin dhe jo ndonjë përdorues. Përdoret për qëllime federimi dhe s’duhet pezulluar.
|
||||
last_active: aktiv së fundi
|
||||
link_verified_on: Pronësia e kësaj lidhjeje qe kontrolluar më %{date}
|
||||
|
||||
@@ -11,6 +11,8 @@ vi:
|
||||
cannot_be_added_to_collections: Tài khoản này không thể thêm vào bộ sưu tập.
|
||||
followers:
|
||||
other: Người theo dõi
|
||||
following:
|
||||
other: Theo dõi
|
||||
instance_actor_flash: Tài khoản này được dùng để đại diện cho máy chủ và không phải là người thật. Đừng bao giờ vô hiệu hóa tài khoản này.
|
||||
last_active: online
|
||||
link_verified_on: Liên kết này đã được xác minh quyền sở hữu vào %{date}
|
||||
|
||||
@@ -11,6 +11,8 @@ zh-CN:
|
||||
cannot_be_added_to_collections: 此账号无法被添加到收藏列表内。
|
||||
followers:
|
||||
other: 关注者
|
||||
following:
|
||||
other: 正在关注
|
||||
instance_actor_flash: 该账号用来代表虚拟角色,并不代表个人用户,仅代表服务器本身。该账号用于联合目的,不应该被停用。
|
||||
last_active: 上次活跃
|
||||
link_verified_on: 此链接的所有权已在 %{date} 验证
|
||||
@@ -1642,7 +1644,7 @@ zh-CN:
|
||||
disabled_account: 此后,你的当前账号将无法使用。但是,你仍然有权导出数据或者重新激活。
|
||||
followers: 这步操作将把全部关注者从当前账号移动到新账号
|
||||
only_redirect_html: 或者,你可以<a href="%{path}">只在你的账号资料上设置一个跳转</a>。
|
||||
other_data: 其他数据不会自动移动(包括您的嘟文及您关注的账号列表)
|
||||
other_data: 其他数据不会自动移动(包括你的嘟文及你关注的账号列表)
|
||||
redirect: 在收到一个跳转通知后,你当前的账号资料将会更新,并被排除在搜索范围外
|
||||
moderation:
|
||||
title: 审核
|
||||
@@ -1691,7 +1693,7 @@ zh-CN:
|
||||
subject: "%{name} 转嘟了你的嘟文"
|
||||
title: 新的转嘟
|
||||
severed_relationships:
|
||||
subject: 由于管理决定,您已失去网络上的关注关系
|
||||
subject: 由于管理决定,你已失去网络上的关注关系
|
||||
status:
|
||||
subject: "%{name} 刚刚发布嘟文"
|
||||
update:
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Admin::ConfirmationsController do
|
||||
render_views
|
||||
|
||||
before do
|
||||
sign_in Fabricate(:admin_user), scope: :user
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
it 'confirms the user' do
|
||||
user = Fabricate(:user, confirmed_at: nil)
|
||||
post :create, params: { account_id: user.account.id }
|
||||
|
||||
expect(response).to redirect_to(admin_accounts_path)
|
||||
expect(user.reload).to be_confirmed
|
||||
end
|
||||
|
||||
it 'raises an error when there is no account' do
|
||||
post :create, params: { account_id: 'fake' }
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
|
||||
it 'raises an error when there is no user' do
|
||||
account = Fabricate(:account, user: nil)
|
||||
post :create, params: { account_id: account.id }
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #resend' do
|
||||
subject { post :resend, params: { account_id: user.account.id } }
|
||||
|
||||
let!(:user) { Fabricate(:user, confirmed_at: confirmed_at) }
|
||||
|
||||
before do
|
||||
allow(UserMailer).to receive(:confirmation_instructions) { instance_double(ActionMailer::MessageDelivery, deliver_later: nil) }
|
||||
end
|
||||
|
||||
context 'when email is not confirmed' do
|
||||
let(:confirmed_at) { nil }
|
||||
|
||||
it 'resends confirmation mail' do
|
||||
expect(subject).to redirect_to admin_accounts_path
|
||||
expect(flash[:notice]).to eq I18n.t('admin.accounts.resend_confirmation.success')
|
||||
expect(UserMailer).to have_received(:confirmation_instructions).once
|
||||
end
|
||||
end
|
||||
|
||||
context 'when email is confirmed' do
|
||||
let(:confirmed_at) { Time.zone.now }
|
||||
|
||||
it 'does not resend confirmation mail' do
|
||||
expect(subject).to redirect_to admin_accounts_path
|
||||
expect(flash[:error]).to eq I18n.t('admin.accounts.resend_confirmation.already_confirmed')
|
||||
expect(UserMailer).to_not have_received(:confirmation_instructions)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -70,7 +70,7 @@ RSpec.describe Auth::SessionsController do
|
||||
end
|
||||
|
||||
it 'shows a login error and does not log the user in' do
|
||||
expect(flash[:alert]).to match I18n.t('devise.failure.invalid', authentication_keys: I18n.t('activerecord.attributes.user.email'))
|
||||
expect(flash[:alert]).to match(/#{failure_message_invalid_email}/i)
|
||||
|
||||
expect(controller.current_user).to be_nil
|
||||
end
|
||||
@@ -163,7 +163,7 @@ RSpec.describe Auth::SessionsController do
|
||||
end
|
||||
|
||||
it 'shows a login error and does not log the user in' do
|
||||
expect(flash[:alert]).to match I18n.t('devise.failure.invalid', authentication_keys: I18n.t('activerecord.attributes.user.email'))
|
||||
expect(flash[:alert]).to match(/#{failure_message_invalid_email}/i)
|
||||
|
||||
expect(controller.current_user).to be_nil
|
||||
end
|
||||
@@ -420,5 +420,9 @@ RSpec.describe Auth::SessionsController do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def failure_message_invalid_email
|
||||
I18n.t('devise.failure.invalid', authentication_keys: I18n.t('activerecord.attributes.user.email'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
56
spec/requests/admin/confirmations_spec.rb
Normal file
56
spec/requests/admin/confirmations_spec.rb
Normal file
@@ -0,0 +1,56 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Admin Confirmations' do
|
||||
before { sign_in Fabricate(:admin_user) }
|
||||
|
||||
describe 'POST /admin/accounts/:account_id/confirmation' do
|
||||
context 'when account does not exist' do
|
||||
let(:account_id) { 'fake' }
|
||||
|
||||
it 'raises an error' do
|
||||
post admin_account_confirmation_path(account_id:)
|
||||
|
||||
expect(response)
|
||||
.to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when account does not have a user' do
|
||||
let(:account) { Fabricate :account, user: nil }
|
||||
|
||||
it 'raises an error' do
|
||||
post admin_account_confirmation_path(account_id: account.id)
|
||||
|
||||
expect(response)
|
||||
.to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /admin/accounts/:account_id/confirmation/resend' do
|
||||
subject { post resend_admin_account_confirmation_path(account_id: user.account.id) }
|
||||
|
||||
let(:user) { Fabricate(:user, confirmed_at: confirmed_at) }
|
||||
|
||||
context 'when email is confirmed' do
|
||||
let(:confirmed_at) { Time.zone.now }
|
||||
|
||||
it 'does not resend confirmation mail' do
|
||||
emails = capture_emails { subject }
|
||||
|
||||
expect(emails)
|
||||
.to be_empty
|
||||
|
||||
expect(response)
|
||||
.to redirect_to admin_accounts_path
|
||||
|
||||
follow_redirect!
|
||||
|
||||
expect(response.body)
|
||||
.to include(I18n.t('admin.accounts.resend_confirmation.already_confirmed'))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,102 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::ActivitySerializer do
|
||||
subject { serialized_record_json(presenter, described_class, adapter: ActivityPub::Adapter) }
|
||||
|
||||
let(:tag_manager) { ActivityPub::TagManager.instance }
|
||||
let(:status) { Fabricate(:status, created_at: Time.utc(2026, 0o1, 27, 15, 29, 31)) }
|
||||
|
||||
context 'with a new status' do
|
||||
let(:presenter) { ActivityPub::ActivityPresenter.from_status(status) }
|
||||
|
||||
it 'serializes to the expected json' do
|
||||
expect(subject).to include({
|
||||
'id' => tag_manager.activity_uri_for(status),
|
||||
'type' => 'Create',
|
||||
'actor' => tag_manager.uri_for(status.account),
|
||||
'published' => '2026-01-27T15:29:31Z',
|
||||
'to' => ['https://www.w3.org/ns/activitystreams#Public'],
|
||||
'cc' => [a_string_matching(/followers$/)],
|
||||
'object' => a_hash_including(
|
||||
'id' => tag_manager.uri_for(status)
|
||||
),
|
||||
})
|
||||
|
||||
expect(subject).to_not have_key('target')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a new reblog' do
|
||||
let(:reblog) { Fabricate(:status, reblog: status, created_at: Time.utc(2026, 0o1, 27, 16, 21, 44)) }
|
||||
let(:presenter) { ActivityPub::ActivityPresenter.from_status(reblog) }
|
||||
|
||||
it 'serializes to the expected json' do
|
||||
expect(subject).to include({
|
||||
'id' => tag_manager.activity_uri_for(reblog),
|
||||
'type' => 'Announce',
|
||||
'actor' => tag_manager.uri_for(reblog.account),
|
||||
'published' => '2026-01-27T16:21:44Z',
|
||||
'to' => ['https://www.w3.org/ns/activitystreams#Public'],
|
||||
'cc' => [tag_manager.uri_for(status.account), a_string_matching(/followers$/)],
|
||||
'object' => tag_manager.uri_for(status),
|
||||
})
|
||||
|
||||
expect(subject).to_not have_key('target')
|
||||
end
|
||||
|
||||
context 'when inlining of private local status is allowed' do
|
||||
let(:status) { Fabricate(:status, visibility: :private, created_at: Time.utc(2026, 0o1, 27, 15, 29, 31)) }
|
||||
let(:reblog) { Fabricate(:status, reblog: status, account: status.account, created_at: Time.utc(2026, 0o1, 27, 16, 21, 44)) }
|
||||
let(:presenter) { ActivityPub::ActivityPresenter.from_status(reblog, allow_inlining: true) }
|
||||
|
||||
it 'serializes to the expected json' do
|
||||
expect(subject).to include({
|
||||
'id' => tag_manager.activity_uri_for(reblog),
|
||||
'type' => 'Announce',
|
||||
'actor' => tag_manager.uri_for(reblog.account),
|
||||
'published' => '2026-01-27T16:21:44Z',
|
||||
'to' => ['https://www.w3.org/ns/activitystreams#Public'],
|
||||
'cc' => [tag_manager.uri_for(status.account), a_string_matching(/followers$/)],
|
||||
'object' => a_hash_including(
|
||||
'id' => tag_manager.uri_for(status)
|
||||
),
|
||||
})
|
||||
|
||||
expect(subject).to_not have_key('target')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a custom presenter for a status `Update`' do
|
||||
let(:status) { Fabricate(:status, edited_at: Time.utc(2026, 0o1, 27, 15, 29, 31)) }
|
||||
let(:presenter) do
|
||||
ActivityPub::ActivityPresenter.new(
|
||||
id: 'https://localhost/status/1#updates/1769527771',
|
||||
type: 'Update',
|
||||
actor: 'https://localhost/actor/1',
|
||||
published: status.edited_at,
|
||||
to: ['https://www.w3.org/ns/activitystreams#Public'],
|
||||
cc: ['https://localhost/actor/1/followers'],
|
||||
virtual_object: status
|
||||
)
|
||||
end
|
||||
|
||||
it 'serializes to the expected json' do
|
||||
expect(subject).to include({
|
||||
'id' => 'https://localhost/status/1#updates/1769527771',
|
||||
'type' => 'Update',
|
||||
'actor' => 'https://localhost/actor/1',
|
||||
'published' => '2026-01-27T15:29:31Z',
|
||||
'to' => ['https://www.w3.org/ns/activitystreams#Public'],
|
||||
'cc' => ['https://localhost/actor/1/followers'],
|
||||
'object' => a_hash_including(
|
||||
'id' => tag_manager.uri_for(status)
|
||||
),
|
||||
})
|
||||
|
||||
expect(subject).to_not have_key('target')
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,26 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::AddFeaturedCollectionSerializer do
|
||||
subject { serialized_record_json(object, described_class, adapter: ActivityPub::Adapter) }
|
||||
|
||||
let(:tag_manager) { ActivityPub::TagManager.instance }
|
||||
let(:object) { Fabricate(:collection) }
|
||||
|
||||
it 'serializes to the expected json' do
|
||||
expect(subject).to include({
|
||||
'type' => 'Add',
|
||||
'actor' => tag_manager.uri_for(object.account),
|
||||
'target' => a_string_matching(%r{/featured_collections$}),
|
||||
'object' => a_hash_including({
|
||||
'type' => 'FeaturedCollection',
|
||||
}),
|
||||
})
|
||||
|
||||
expect(subject).to_not have_key('id')
|
||||
expect(subject).to_not have_key('published')
|
||||
expect(subject).to_not have_key('to')
|
||||
expect(subject).to_not have_key('cc')
|
||||
end
|
||||
end
|
||||
26
spec/serializers/activitypub/add_hashtag_serializer_spec.rb
Normal file
26
spec/serializers/activitypub/add_hashtag_serializer_spec.rb
Normal file
@@ -0,0 +1,26 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::AddHashtagSerializer do
|
||||
subject { serialized_record_json(object, described_class, adapter: ActivityPub::Adapter) }
|
||||
|
||||
let(:tag_manager) { ActivityPub::TagManager.instance }
|
||||
let(:object) { Fabricate(:featured_tag) }
|
||||
|
||||
it 'serializes to the expected json' do
|
||||
expect(subject).to include({
|
||||
'type' => 'Add',
|
||||
'actor' => tag_manager.uri_for(object.account),
|
||||
'target' => a_string_matching(%r{/featured$}),
|
||||
'object' => a_hash_including({
|
||||
'type' => 'Hashtag',
|
||||
}),
|
||||
})
|
||||
|
||||
expect(subject).to_not have_key('id')
|
||||
expect(subject).to_not have_key('published')
|
||||
expect(subject).to_not have_key('to')
|
||||
expect(subject).to_not have_key('cc')
|
||||
end
|
||||
end
|
||||
24
spec/serializers/activitypub/add_note_serializer_spec.rb
Normal file
24
spec/serializers/activitypub/add_note_serializer_spec.rb
Normal file
@@ -0,0 +1,24 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::AddNoteSerializer do
|
||||
subject { serialized_record_json(object, described_class, adapter: ActivityPub::Adapter) }
|
||||
|
||||
let(:tag_manager) { ActivityPub::TagManager.instance }
|
||||
let(:object) { Fabricate(:status) }
|
||||
|
||||
it 'serializes to the expected json' do
|
||||
expect(subject).to include({
|
||||
'type' => 'Add',
|
||||
'actor' => tag_manager.uri_for(object.account),
|
||||
'target' => a_string_matching(%r{/featured$}),
|
||||
'object' => tag_manager.uri_for(object),
|
||||
})
|
||||
|
||||
expect(subject).to_not have_key('id')
|
||||
expect(subject).to_not have_key('published')
|
||||
expect(subject).to_not have_key('to')
|
||||
expect(subject).to_not have_key('cc')
|
||||
end
|
||||
end
|
||||
@@ -1,119 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::AddSerializer do
|
||||
describe '.serializer_for' do
|
||||
subject { described_class.serializer_for(model, {}) }
|
||||
|
||||
context 'with a Status model' do
|
||||
let(:model) { Status.new }
|
||||
|
||||
it { is_expected.to eq(described_class::UriSerializer) }
|
||||
end
|
||||
|
||||
context 'with a FeaturedTag model' do
|
||||
let(:model) { FeaturedTag.new }
|
||||
|
||||
it { is_expected.to eq(ActivityPub::HashtagSerializer) }
|
||||
end
|
||||
|
||||
context 'with a Collection model' do
|
||||
let(:model) { Collection.new }
|
||||
|
||||
it { is_expected.to eq(ActivityPub::FeaturedCollectionSerializer) }
|
||||
end
|
||||
|
||||
context 'with an Array' do
|
||||
let(:model) { [] }
|
||||
|
||||
it { is_expected.to eq(ActiveModel::Serializer::CollectionSerializer) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#target' do
|
||||
subject { described_class.new(object).target }
|
||||
|
||||
context 'when object is a Status' do
|
||||
let(:object) { Fabricate(:status) }
|
||||
|
||||
it { is_expected.to match(%r{/#{object.account_id}/collections/featured$}) }
|
||||
end
|
||||
|
||||
context 'when object is a FeaturedTag' do
|
||||
let(:object) { Fabricate(:featured_tag) }
|
||||
|
||||
it { is_expected.to match(%r{/#{object.account_id}/collections/featured$}) }
|
||||
end
|
||||
|
||||
context 'when object is a Collection' do
|
||||
let(:object) { Fabricate(:collection) }
|
||||
|
||||
it { is_expected.to match(%r{/#{object.account_id}/featured_collections$}) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Serialization' do
|
||||
subject { serialized_record_json(object, described_class, adapter: ActivityPub::Adapter) }
|
||||
|
||||
let(:tag_manager) { ActivityPub::TagManager.instance }
|
||||
|
||||
context 'with a status' do
|
||||
let(:object) { Fabricate(:status) }
|
||||
|
||||
it 'serializes to the expected json' do
|
||||
expect(subject).to include({
|
||||
'type' => 'Add',
|
||||
'actor' => tag_manager.uri_for(object.account),
|
||||
'target' => a_string_matching(%r{/featured$}),
|
||||
'object' => tag_manager.uri_for(object),
|
||||
})
|
||||
|
||||
expect(subject).to_not have_key('id')
|
||||
expect(subject).to_not have_key('published')
|
||||
expect(subject).to_not have_key('to')
|
||||
expect(subject).to_not have_key('cc')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a featured tag' do
|
||||
let(:object) { Fabricate(:featured_tag) }
|
||||
|
||||
it 'serializes to the expected json' do
|
||||
expect(subject).to include({
|
||||
'type' => 'Add',
|
||||
'actor' => tag_manager.uri_for(object.account),
|
||||
'target' => a_string_matching(%r{/featured$}),
|
||||
'object' => a_hash_including({
|
||||
'type' => 'Hashtag',
|
||||
}),
|
||||
})
|
||||
|
||||
expect(subject).to_not have_key('id')
|
||||
expect(subject).to_not have_key('published')
|
||||
expect(subject).to_not have_key('to')
|
||||
expect(subject).to_not have_key('cc')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a collection' do
|
||||
let(:object) { Fabricate(:collection) }
|
||||
|
||||
it 'serializes to the expected json' do
|
||||
expect(subject).to include({
|
||||
'type' => 'Add',
|
||||
'actor' => tag_manager.uri_for(object.account),
|
||||
'target' => a_string_matching(%r{/featured_collections$}),
|
||||
'object' => a_hash_including({
|
||||
'type' => 'FeaturedCollection',
|
||||
}),
|
||||
})
|
||||
|
||||
expect(subject).to_not have_key('id')
|
||||
expect(subject).to_not have_key('published')
|
||||
expect(subject).to_not have_key('to')
|
||||
expect(subject).to_not have_key('cc')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,79 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::AnnounceNoteSerializer do
|
||||
subject { serialized_record_json(reblog, described_class, adapter: ActivityPub::Adapter, options:) }
|
||||
|
||||
let(:tag_manager) { ActivityPub::TagManager.instance }
|
||||
let(:status) { Fabricate(:status, created_at: Time.utc(2026, 1, 27, 15, 29, 31)) }
|
||||
let(:reblog) { Fabricate(:status, reblog: status, created_at: Time.utc(2026, 1, 27, 16, 21, 44)) }
|
||||
let(:options) { {} }
|
||||
|
||||
it 'serializes to the expected json' do
|
||||
expect(subject).to include({
|
||||
'id' => tag_manager.activity_uri_for(reblog),
|
||||
'type' => 'Announce',
|
||||
'actor' => tag_manager.uri_for(reblog.account),
|
||||
'published' => '2026-01-27T16:21:44Z',
|
||||
'to' => ['https://www.w3.org/ns/activitystreams#Public'],
|
||||
'cc' => [tag_manager.uri_for(status.account), a_string_matching(/followers$/)],
|
||||
'object' => tag_manager.uri_for(status),
|
||||
})
|
||||
|
||||
expect(subject).to_not have_key('target')
|
||||
end
|
||||
|
||||
context 'when status is local and private' do
|
||||
let(:status) { Fabricate(:status, visibility: :private, created_at: Time.utc(2026, 1, 27, 15, 29, 31)) }
|
||||
let(:reblog) { Fabricate(:status, reblog: status, account: status.account, created_at: Time.utc(2026, 1, 27, 16, 21, 44)) }
|
||||
|
||||
context 'when inlining of private local status is allowed' do
|
||||
shared_examples 'serialization with inlining' do
|
||||
it 'serializes to the expected json' do
|
||||
expect(subject).to include({
|
||||
'id' => tag_manager.activity_uri_for(reblog),
|
||||
'type' => 'Announce',
|
||||
'actor' => tag_manager.uri_for(reblog.account),
|
||||
'published' => '2026-01-27T16:21:44Z',
|
||||
'to' => ['https://www.w3.org/ns/activitystreams#Public'],
|
||||
'cc' => [tag_manager.uri_for(status.account), a_string_matching(/followers$/)],
|
||||
'object' => a_hash_including(
|
||||
'id' => tag_manager.uri_for(status)
|
||||
),
|
||||
})
|
||||
|
||||
expect(subject).to_not have_key('target')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with `allow_inlining` explicitly set to `true`' do
|
||||
let(:options) { { allow_inlining: true } }
|
||||
|
||||
it_behaves_like 'serialization with inlining'
|
||||
end
|
||||
|
||||
context 'with `allow_inlining` unset' do
|
||||
let(:options) { {} }
|
||||
|
||||
it_behaves_like 'serialization with inlining'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when inlining is not allowed' do
|
||||
let(:options) { { allow_inlining: false } }
|
||||
|
||||
it 'serializes to the expected json' do
|
||||
expect(subject).to include({
|
||||
'id' => tag_manager.activity_uri_for(reblog),
|
||||
'type' => 'Announce',
|
||||
'actor' => tag_manager.uri_for(reblog.account),
|
||||
'published' => '2026-01-27T16:21:44Z',
|
||||
'to' => ['https://www.w3.org/ns/activitystreams#Public'],
|
||||
'cc' => [tag_manager.uri_for(status.account), a_string_matching(/followers$/)],
|
||||
'object' => tag_manager.uri_for(status),
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
26
spec/serializers/activitypub/create_note_serializer_spec.rb
Normal file
26
spec/serializers/activitypub/create_note_serializer_spec.rb
Normal file
@@ -0,0 +1,26 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::CreateNoteSerializer do
|
||||
subject { serialized_record_json(status, described_class, adapter: ActivityPub::Adapter) }
|
||||
|
||||
let(:tag_manager) { ActivityPub::TagManager.instance }
|
||||
let(:status) { Fabricate(:status, created_at: Time.utc(2026, 1, 27, 15, 29, 31)) }
|
||||
|
||||
it 'serializes to the expected json' do
|
||||
expect(subject).to include({
|
||||
'id' => tag_manager.activity_uri_for(status),
|
||||
'type' => 'Create',
|
||||
'actor' => tag_manager.uri_for(status.account),
|
||||
'published' => '2026-01-27T15:29:31Z',
|
||||
'to' => ['https://www.w3.org/ns/activitystreams#Public'],
|
||||
'cc' => [a_string_matching(/followers$/)],
|
||||
'object' => a_hash_including(
|
||||
'id' => tag_manager.uri_for(status)
|
||||
),
|
||||
})
|
||||
|
||||
expect(subject).to_not have_key('target')
|
||||
end
|
||||
end
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::DeleteSerializer do
|
||||
RSpec.describe ActivityPub::DeleteNoteSerializer do
|
||||
subject { serialized_record_json(status, described_class, adapter: ActivityPub::Adapter) }
|
||||
|
||||
let(:tag_manager) { ActivityPub::TagManager.instance }
|
||||
@@ -0,0 +1,24 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::RemoveFeaturedCollectionSerializer do
|
||||
subject { serialized_record_json(object, described_class, adapter: ActivityPub::Adapter) }
|
||||
|
||||
let(:tag_manager) { ActivityPub::TagManager.instance }
|
||||
let(:object) { Fabricate(:collection) }
|
||||
|
||||
it 'serializes to the expected json' do
|
||||
expect(subject).to include({
|
||||
'type' => 'Remove',
|
||||
'actor' => tag_manager.uri_for(object.account),
|
||||
'target' => a_string_matching(%r{/featured_collections$}),
|
||||
'object' => tag_manager.uri_for(object),
|
||||
})
|
||||
|
||||
expect(subject).to_not have_key('id')
|
||||
expect(subject).to_not have_key('published')
|
||||
expect(subject).to_not have_key('to')
|
||||
expect(subject).to_not have_key('cc')
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,26 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::RemoveHashtagSerializer do
|
||||
subject { serialized_record_json(object, described_class, adapter: ActivityPub::Adapter) }
|
||||
|
||||
let(:tag_manager) { ActivityPub::TagManager.instance }
|
||||
let(:object) { Fabricate(:featured_tag) }
|
||||
|
||||
it 'serializes to the expected json' do
|
||||
expect(subject).to include({
|
||||
'type' => 'Remove',
|
||||
'actor' => tag_manager.uri_for(object.account),
|
||||
'target' => a_string_matching(%r{/featured$}),
|
||||
'object' => a_hash_including({
|
||||
'type' => 'Hashtag',
|
||||
}),
|
||||
})
|
||||
|
||||
expect(subject).to_not have_key('id')
|
||||
expect(subject).to_not have_key('published')
|
||||
expect(subject).to_not have_key('to')
|
||||
expect(subject).to_not have_key('cc')
|
||||
end
|
||||
end
|
||||
24
spec/serializers/activitypub/remove_note_serializer_spec.rb
Normal file
24
spec/serializers/activitypub/remove_note_serializer_spec.rb
Normal file
@@ -0,0 +1,24 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::RemoveNoteSerializer do
|
||||
subject { serialized_record_json(object, described_class, adapter: ActivityPub::Adapter) }
|
||||
|
||||
let(:tag_manager) { ActivityPub::TagManager.instance }
|
||||
let(:object) { Fabricate(:status) }
|
||||
|
||||
it 'serializes to the expected json' do
|
||||
expect(subject).to include({
|
||||
'type' => 'Remove',
|
||||
'actor' => tag_manager.uri_for(object.account),
|
||||
'target' => a_string_matching(%r{/featured$}),
|
||||
'object' => tag_manager.uri_for(object),
|
||||
})
|
||||
|
||||
expect(subject).to_not have_key('id')
|
||||
expect(subject).to_not have_key('published')
|
||||
expect(subject).to_not have_key('to')
|
||||
expect(subject).to_not have_key('cc')
|
||||
end
|
||||
end
|
||||
@@ -1,71 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::RemoveSerializer do
|
||||
describe '.serializer_for' do
|
||||
subject { described_class.serializer_for(model, {}) }
|
||||
|
||||
context 'with a Status model' do
|
||||
let(:model) { Status.new }
|
||||
|
||||
it { is_expected.to eq(described_class::UriSerializer) }
|
||||
end
|
||||
|
||||
context 'with a FeaturedTag model' do
|
||||
let(:model) { FeaturedTag.new }
|
||||
|
||||
it { is_expected.to eq(ActivityPub::HashtagSerializer) }
|
||||
end
|
||||
|
||||
context 'with an Array' do
|
||||
let(:model) { [] }
|
||||
|
||||
it { is_expected.to eq(ActiveModel::Serializer::CollectionSerializer) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Serialization' do
|
||||
subject { serialized_record_json(object, described_class, adapter: ActivityPub::Adapter) }
|
||||
|
||||
let(:tag_manager) { ActivityPub::TagManager.instance }
|
||||
|
||||
context 'with a status' do
|
||||
let(:object) { Fabricate(:status) }
|
||||
|
||||
it 'serializes to the expected json' do
|
||||
expect(subject).to include({
|
||||
'type' => 'Remove',
|
||||
'actor' => tag_manager.uri_for(object.account),
|
||||
'target' => a_string_matching(%r{/featured$}),
|
||||
'object' => tag_manager.uri_for(object),
|
||||
})
|
||||
|
||||
expect(subject).to_not have_key('id')
|
||||
expect(subject).to_not have_key('published')
|
||||
expect(subject).to_not have_key('to')
|
||||
expect(subject).to_not have_key('cc')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a featured tag' do
|
||||
let(:object) { Fabricate(:featured_tag) }
|
||||
|
||||
it 'serializes to the expected json' do
|
||||
expect(subject).to include({
|
||||
'type' => 'Remove',
|
||||
'actor' => tag_manager.uri_for(object.account),
|
||||
'target' => a_string_matching(%r{/featured$}),
|
||||
'object' => a_hash_including({
|
||||
'type' => 'Hashtag',
|
||||
}),
|
||||
})
|
||||
|
||||
expect(subject).to_not have_key('id')
|
||||
expect(subject).to_not have_key('published')
|
||||
expect(subject).to_not have_key('to')
|
||||
expect(subject).to_not have_key('cc')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -26,4 +26,17 @@ RSpec.describe ActivityPub::UndoAnnounceSerializer do
|
||||
expect(subject).to_not have_key('cc')
|
||||
expect(subject).to_not have_key('target')
|
||||
end
|
||||
|
||||
context 'when status is local and private' do
|
||||
let(:status) { Fabricate(:status, visibility: :private) }
|
||||
let(:reblog) { Fabricate(:status, reblog: status, account: status.account) }
|
||||
|
||||
it 'does not inline the status' do
|
||||
expect(subject).to include({
|
||||
'object' => a_hash_including({
|
||||
'object' => tag_manager.uri_for(status),
|
||||
}),
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user