From a187dcefa1e0604e55eaff97a3c6403157528cdf Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 3 Sep 2017 01:11:23 +0200 Subject: [PATCH 01/31] Instantly upgrade account to ActivityPub if we receive ActivityPub payload (#4766) --- app/controllers/activitypub/inboxes_controller.rb | 8 ++++++-- app/workers/resolve_remote_account_worker.rb | 11 +++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 app/workers/resolve_remote_account_worker.rb diff --git a/app/controllers/activitypub/inboxes_controller.rb b/app/controllers/activitypub/inboxes_controller.rb index 5fce505fd2..b37910b364 100644 --- a/app/controllers/activitypub/inboxes_controller.rb +++ b/app/controllers/activitypub/inboxes_controller.rb @@ -26,8 +26,12 @@ class ActivityPub::InboxesController < Api::BaseController end def upgrade_account - return unless signed_request_account.subscribed? - Pubsubhubbub::UnsubscribeWorker.perform_async(signed_request_account.id) + if signed_request_account.ostatus? + signed_request_account.update(last_webfingered_at: nil) + ResolveRemoteAccountWorker.perform_async(signed_request_account.acct) + end + + Pubsubhubbub::UnsubscribeWorker.perform_async(signed_request_account.id) if signed_request_account.subscribed? end def process_payload diff --git a/app/workers/resolve_remote_account_worker.rb b/app/workers/resolve_remote_account_worker.rb new file mode 100644 index 0000000000..5dd84ccb6b --- /dev/null +++ b/app/workers/resolve_remote_account_worker.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class ResolveRemoteAccountWorker + include Sidekiq::Worker + + sidekiq_options queue: 'pull', unique: :until_executed + + def perform(uri) + ResolveRemoteAccountService.new.call(uri) + end +end From 9dd8dff683a148bdd00d715e85b7af40c3d4be21 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 3 Sep 2017 01:12:05 +0200 Subject: [PATCH 02/31] Bump version to 1.6.0rc1 (#4768) --- lib/mastodon/version.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index fcca875d9b..b5fa476dc2 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -9,11 +9,11 @@ module Mastodon end def minor - 5 + 6 end def patch - 1 + 0 end def pre @@ -21,7 +21,7 @@ module Mastodon end def flags - '' + 'rc1' end def to_a From 249bdc169cd52ad9adc7bda1c47c74c22bb01369 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Sun, 3 Sep 2017 14:58:58 +0900 Subject: [PATCH 03/31] Explicitly define attached file of DeprecatedPreviewCard (#4786) The path template of the attached files must explicitly be defined because it is contradicting to the name of the class. --- lib/tasks/mastodon.rake | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/tasks/mastodon.rake b/lib/tasks/mastodon.rake index f04201a3cd..f4f6e4d237 100644 --- a/lib/tasks/mastodon.rake +++ b/lib/tasks/mastodon.rake @@ -275,8 +275,15 @@ namespace :mastodon do task remove_deprecated_preview_cards: :environment do return unless ActiveRecord::Base.connection.table_exists? 'deprecated_preview_cards' - class DeprecatedPreviewCard < PreviewCard - self.table_name = 'deprecated_preview_cards' + class DeprecatedPreviewCard < ActiveRecord::Base + self.inheritance_column = false + + path = '/preview_cards/:attachment/:id_partition/:style/:filename' + if ENV['S3_ENABLED'] != 'true' + path = (ENV['PAPERCLIP_ROOT_PATH'] || ':rails_root/public/system') + path + end + + has_attached_file :image, styles: { original: '280x120>' }, convert_options: { all: '-quality 80 -strip' }, path: path end puts 'Delete records and associated files from deprecated preview cards? [y/N]: ' From 8538170c2d5c13e1ebc0e54afc8ebb8158128604 Mon Sep 17 00:00:00 2001 From: Quent-in Date: Sun, 3 Sep 2017 11:08:37 +0200 Subject: [PATCH 04/31] l10n Occitan update for Embed, cancel follow request, ... (#4788) * Update: some missing strings * Updates missing strings * New string * Update oc.json * Update oc.yml * Update oc.json --- app/javascript/mastodon/locales/oc.json | 8 ++++---- config/locales/doorkeeper.oc.yml | 6 ++++++ config/locales/oc.yml | 14 +++++++++++++- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json index 141bff0421..a86033e6f6 100644 --- a/app/javascript/mastodon/locales/oc.json +++ b/app/javascript/mastodon/locales/oc.json @@ -12,7 +12,7 @@ "account.mute": "Rescondre @{name}", "account.posts": "Estatuts", "account.report": "Senhalar @{name}", - "account.requested": "Invitacion mandada", + "account.requested": "Invitacion mandada. Clicatz per anullar.", "account.share": "Partejar lo perfil a @{name}", "account.unblock": "Desblocar @{name}", "account.unblock_domain": "Desblocar {domain}", @@ -63,8 +63,8 @@ "confirmations.mute.message": "Sètz segur de voler metre en silenci {name} ?", "confirmations.unfollow.confirm": "Quitar de sègre", "confirmations.unfollow.message": "Volètz vertadièrament quitar de sègre {name} ?", - "embed.instructions": "Embed this status on your website by copying the code below.", - "embed.preview": "Here is what it will look like:", + "embed.instructions": "Embarcar aqueste estatut per o far veire sus un site Internet en copiar lo còdi çai-jos.", + "embed.preview": "Semblarà aquò : ", "emoji_button.activity": "Activitats", "emoji_button.flags": "Drapèus", "emoji_button.food": "Beure e manjar", @@ -164,7 +164,7 @@ "standalone.public_title": "Una ulhada dedins…", "status.cannot_reblog": "Aqueste estatut pòt pas èsser partejat", "status.delete": "Escafar", - "status.embed": "Embed", + "status.embed": "Embarcar", "status.favourite": "Apondre als favorits", "status.load_more": "Cargar mai", "status.media_hidden": "Mèdia rescondut", diff --git a/config/locales/doorkeeper.oc.yml b/config/locales/doorkeeper.oc.yml index 3d12c95881..b6aebea487 100644 --- a/config/locales/doorkeeper.oc.yml +++ b/config/locales/doorkeeper.oc.yml @@ -5,6 +5,8 @@ oc: doorkeeper/application: name: Nom redirect_uri: URL de redireccion + scopes: Encastres + website: Aplicacion web errors: models: doorkeeper/application: @@ -33,9 +35,13 @@ oc: redirect_uri: Utilizatz una linha per URI scopes: Separatz los encastres amb d’espacis. Daissatz void per utilizar l’encastre per defaut. index: + application: Aplicacion callback_url: URL de rapèl + delete: Suprimir name: Nom new: Nòva aplicacion + scopes: Encastres + show: Veire title: Vòstras aplicacions new: title: Nòva aplicacion diff --git a/config/locales/oc.yml b/config/locales/oc.yml index 019d3b196e..d077175ae8 100644 --- a/config/locales/oc.yml +++ b/config/locales/oc.yml @@ -103,6 +103,7 @@ oc: title: Comptes undo_silenced: Levar lo silenci undo_suspension: Levar la suspension + unsubscribe: Se desabonar username: Nom d’utilizaire web: Web domain_blocks: @@ -430,6 +431,17 @@ oc: reblog: body: "%{name} a tornat partejar vòstre estatut :" subject: "%{name} a tornat partejar vòstre estatut" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: Seguent prev: Precedent @@ -447,7 +459,7 @@ oc: action_favourite: Ajustar als favorits title: "%{name} vos a mencionat" reblog: - title: "%{name} a partejat vòstre estatut" + title: "%{name} a partejat vòstre estatut" remote_follow: acct: Picatz vòstre utilizaire@instància que cal utilizar per sègre aqueste utilizaire missing_resource: URL de redireccion pas trobada From 579c7a88e03fe4299e9b3fabac345031b8b64a8b Mon Sep 17 00:00:00 2001 From: May Kittens Devour Your Soul Date: Sun, 3 Sep 2017 11:10:53 +0200 Subject: [PATCH 05/31] Croatian translation - updated (#4183) * Update hr.json * Update hr.json --- app/javascript/mastodon/locales/hr.json | 55 +++++++++++++------------ 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json index 27e943bdd9..f301723cf2 100644 --- a/app/javascript/mastodon/locales/hr.json +++ b/app/javascript/mastodon/locales/hr.json @@ -1,7 +1,7 @@ { "account.block": "Blokiraj @{name}", "account.block_domain": "Sakrij sve sa {domain}", - "account.disclaimer_full": "Information below may reflect the user's profile incompletely.", + "account.disclaimer_full": "Ovaj korisnik je sa druge instance. Ovaj broj bi mogao biti veći.", "account.edit_profile": "Uredi profil", "account.follow": "Slijedi", "account.followers": "Sljedbenici", @@ -15,7 +15,7 @@ "account.requested": "Čeka pristanak", "account.share": "Share @{name}'s profile", "account.unblock": "Deblokiraj @{name}", - "account.unblock_domain": "Otkrij {domain}", + "account.unblock_domain": "Poništi sakrivanje {domain}", "account.unfollow": "Prestani slijediti", "account.unmute": "Poništi utišavanje @{name}", "account.view_full_profile": "View full profile", @@ -43,7 +43,7 @@ "column_header.unpin": "Unpin", "column_subheading.navigation": "Navigacija", "column_subheading.settings": "Postavke", - "compose_form.lock_disclaimer": "Tvoj račun nije {locked}. Svatko te može slijediti i vidjeti tvoje postove namijenjene samo sljedbenicima.", + "compose_form.lock_disclaimer": "Tvoj račun nije {locked}. Svatko te može slijediti kako bi vidio postove namijenjene samo tvojim sljedbenicima.", "compose_form.lock_disclaimer.lock": "zaključan", "compose_form.placeholder": "Što ti je na umu?", "compose_form.privacy_disclaimer": "Tvoj privatni status će biti dostavljen spomenutim korisnicima na {domains}. Vjeruješ li {domainsCount, plural, one {that server} drugim {those servers}}? Privatnost postova radi samo na Mastodon instancama. Ako {domains} {domainsCount, plural, one {is not a Mastodon instance} other {are not Mastodon instances}}, neće biti indikacije da je tvoj post privatan, i mogao bi biti podignut ili biti učinjen vidljivim na drugi način neželjenim primateljima.", @@ -54,13 +54,14 @@ "compose_form.spoiler_placeholder": "Upozorenje o sadržaju", "confirmation_modal.cancel": "Otkaži", "confirmations.block.confirm": "Blokiraj", - "confirmations.block.message": "Jesi li siguran da želiš blokirati {name}?", + "confirmations.block.message": "Želiš li sigurno blokirati {name}?", "confirmations.delete.confirm": "Obriši", - "confirmations.delete.message": "Jesi li siguran da želiš obrisati ovaj status?", + "confirmations.delete.message": "Želiš li stvarno obrisati ovaj status?", "confirmations.domain_block.confirm": "Sakrij cijelu domenu", - "confirmations.domain_block.message": "Jesi li zaista, zaista siguran da želiš blokirati sve sa {domain}? U većini slučajeva nekoliko ciljanih blokiranja ili utišavanja je dostatno i poželjnije.", + "confirmations.domain_block.message": "Jesi li zaista, zaista siguran da želiš potpuno blokirati {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", "confirmations.mute.confirm": "Utišaj", "confirmations.mute.message": "Jesi li siguran da želiš utišati {name}?", + "confirmations.mute.message": "Jesi li siguran da želiš utišati {name}?", "confirmations.unfollow.confirm": "Unfollow", "confirmations.unfollow.message": "Are you sure you want to unfollow {name}?", "embed.instructions": "Embed this status on your website by copying the code below.", @@ -69,16 +70,16 @@ "emoji_button.flags": "Zastave", "emoji_button.food": "Hrana & Piće", "emoji_button.label": "Umetni smajlije", - "emoji_button.nature": "Nature", + "emoji_button.nature": "Priroda", "emoji_button.objects": "Objekti", "emoji_button.people": "Ljudi", "emoji_button.search": "Traži...", "emoji_button.symbols": "Simboli", - "emoji_button.travel": "Putovanja i Mjesta", + "emoji_button.travel": "Putovanja & Mjesta", "empty_column.community": "Lokalni timeline je prazan. Napiši nešto javno kako bi pokrenuo stvari!", "empty_column.hashtag": "Još ne postoji ništa s ovim hashtagom.", "empty_column.home": "Još ne slijediš nikoga. Posjeti {public} ili koristi tražilicu kako bi počeo i upoznao druge korisnike.", - "empty_column.home.inactivity": "Tvoj home feed je prazan. Ako si neko vrijeme bio neaktivan, regenerirat će se uskoro.", + "empty_column.home.inactivity": "Tvoj home feed je prazan. Ako si neko vrijeme bio neaktivan, uskoro ćese regenerirati.", "empty_column.home.public_timeline": "javni timeline", "empty_column.notifications": "Još nemaš notifikacija. Komuniciraj sa drugima kako bi započeo razgovor.", "empty_column.public": "Ovdje nema ništa! Napiši nešto javno, ili ručno slijedi korisnike sa drugih instanci kako bi popunio", @@ -88,11 +89,11 @@ "getting_started.faq": "FAQ", "getting_started.heading": "Počnimo", "getting_started.open_source_notice": "Mastodon je softver otvorenog koda. Možeš pridonijeti ili prijaviti probleme na GitHubu {github}.", - "getting_started.userguide": "Vodič za korisnike", + "getting_started.userguide": "Upute za korištenje", "home.column_settings.advanced": "Napredno", "home.column_settings.basic": "Osnovno", "home.column_settings.filter_regex": "Filtriraj s regularnim izrazima", - "home.column_settings.show_reblogs": "Pokaži boosts", + "home.column_settings.show_reblogs": "Pokaži boostove", "home.column_settings.show_replies": "Pokaži odgovore", "home.settings": "Postavke Stupca", "lightbox.close": "Zatvori", @@ -113,7 +114,7 @@ "navigation_bar.public_timeline": "Federalni timeline", "notification.favourite": "{name} je lajkao tvoj status", "notification.follow": "{name} te sada slijedi", - "notification.mention": "{name} mentioned you", + "notification.mention": "{name} te je spomenuo", "notification.reblog": "{name} je podigao tvoj status", "notifications.clear": "Očisti notifikacije", "notifications.clear_confirmation": "Želiš li zaista obrisati sve svoje notifikacije?", @@ -123,28 +124,28 @@ "notifications.column_settings.mention": "Spominjanja:", "notifications.column_settings.push": "Push notifications", "notifications.column_settings.push_meta": "This device", - "notifications.column_settings.reblog": "Boosts:", + "notifications.column_settings.reblog": "Boostovi:", "notifications.column_settings.show": "Prikaži u stupcu", "notifications.column_settings.sound": "Sviraj zvuk", "onboarding.done": "Učinjeno", - "onboarding.next": "Sljedeća", - "onboarding.page_five.public_timelines": "The local timeline prikazuje javne postove svih na {domain}. Federalni timeline pokazuje javne postove svih sa {domain} domena koje slijediš. To je sjajan način da otkriješ nove ljude.", - "onboarding.page_four.home": "The home timeline prikazuje samo postove ljudi koje slijediš.", - "onboarding.page_four.notifications": "Stupac notifikacija pokazuje kada je netko u interakciji s tobom.", - "onboarding.page_one.federation": "Mastodon je mreža nezavisnih servera udruženih kako bi stvorili veću socijalnu mrežu. Te servere zovemo instance.", - "onboarding.page_one.handle": "Ti si na {domain}, tako da je tvoj potpuni opis {handle}", - "onboarding.page_one.welcome": "Dobro došli u Mastodon!", + "onboarding.next": "Sljedeće", + "onboarding.page_five.public_timelines": "Lokalni timeline prikazuje javne postove sviju od svakog na {domain}. Federalni timeline prikazuje javne postove svakog koga ljudi na {domain} slijede. To su Javni Timelineovi, sjajan način za otkriti nove ljude.", + "onboarding.page_four.home": "The home timeline prikazuje postove ljudi koje slijediš.", + "onboarding.page_four.notifications": "Stupac za notifikacije pokazuje poruke drugih upućene tebi.", + "onboarding.page_one.federation": "Mastodon čini mreža neovisnih servera udruženih u jednu veću socialnu mrežu. Te servere nazivamo instancama.", + "onboarding.page_one.handle": "Ti si na {domain}, i tvoja puna handle je {handle}", + "onboarding.page_one.welcome": "Dobro došli na Mastodon!", "onboarding.page_six.admin": "Administrator tvoje instance je {admin}.", "onboarding.page_six.almost_done": "Još malo pa gotovo...", "onboarding.page_six.appetoot": "Živjeli!", "onboarding.page_six.apps_available": "Postoje {apps} dostupne za iOS, Android i druge platforme.", - "onboarding.page_six.github": "Mastodon je besplatan softver otvorenog koda. Možeš prijaviti greške, zahtijevati mogućnosti, ili pridonijeti kodu na {github}.", + "onboarding.page_six.github": "Mastodon je besplatan softver otvorenog koda. You can report bugs, request features, or contribute to the code on {github}.", "onboarding.page_six.guidelines": "smjernice zajednice", - "onboarding.page_six.read_guidelines": "Molimo, pročitaj {domain}'s {guidelines}!", + "onboarding.page_six.read_guidelines": "Molimo pročitaj {domain}'s {guidelines}!", "onboarding.page_six.various_app": "mobilne aplikacije", - "onboarding.page_three.profile": "Uredi svoj profil mijenjanjem avatara, biografije i imena koje će biti prikazano. Naći ćeš i druge korisne postavke.", - "onboarding.page_three.search": "Koristi tražilicu kako bi pronašao ljude i sadržaj sa određenim hashtagovima, kao što su {illustration} i {introductions}. Da bi našao osobu koja nije na ovoj instanci, upotrijebi njihov puni opis.", - "onboarding.page_two.compose": "Piši postove u stupcu za njihovo sastavljanje. Možeš uploadati slike, promijeniti postavke privatnosti, i dodati upozorenja o sadržaju s ikonama ispod.", + "onboarding.page_three.profile": "Uredi svoj profil promjenom svog avatara, biografije, i imena. Ovdje ćeš isto tako pronaći i druge postavke.", + "onboarding.page_three.search": "Koristi tražilicu kako bi pronašao ljude i tražio hashtags, kao što su {illustration} i {introductions}. Kako bi pronašao osobu koja nije na ovoj instanci, upotrijebi njen pun handle.", + "onboarding.page_two.compose": "Piši postove u stupcu za sastavljanje. Možeš uploadati slike, promijeniti postavke privatnosti, i dodati upozorenja o sadržaju s ikonama ispod.", "onboarding.skip": "Preskoči", "privacy.change": "Podesi status privatnosti", "privacy.direct.long": "Prikaži samo spomenutim korisnicima", @@ -162,7 +163,7 @@ "search.placeholder": "Traži", "search_results.total": "{count, number} {count, plural, one {result} other {results}}", "standalone.public_title": "A look inside...", - "status.cannot_reblog": "Ovaj post ne može biti podignut", + "status.cannot_reblog": "Ovaj post ne može biti boostan", "status.delete": "Obriši", "status.embed": "Embed", "status.favourite": "Označi omiljenim", @@ -196,5 +197,5 @@ "video_player.expand": "Proširi video", "video_player.toggle_sound": "Toggle zvuk", "video_player.toggle_visible": "Preklopi vidljivost", - "video_player.video_error": "Video nije mogao biti prikazan" + "video_player.video_error": "Video ne može biti reproduciran" } From a7893153618566ee250d27e4f47f47818cd90150 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Sun, 3 Sep 2017 19:39:39 +0900 Subject: [PATCH 06/31] Use next instead of return in task (#4787) --- lib/tasks/mastodon.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tasks/mastodon.rake b/lib/tasks/mastodon.rake index f4f6e4d237..307bc240db 100644 --- a/lib/tasks/mastodon.rake +++ b/lib/tasks/mastodon.rake @@ -273,7 +273,7 @@ namespace :mastodon do desc 'Remove deprecated preview cards' task remove_deprecated_preview_cards: :environment do - return unless ActiveRecord::Base.connection.table_exists? 'deprecated_preview_cards' + next unless ActiveRecord::Base.connection.table_exists? 'deprecated_preview_cards' class DeprecatedPreviewCard < ActiveRecord::Base self.inheritance_column = false From d3f46a77c34d45cc5ce90c906a53558844785bc2 Mon Sep 17 00:00:00 2001 From: Andreas Drop Date: Sun, 3 Sep 2017 15:17:24 +0200 Subject: [PATCH 07/31] Make german translation more gender neutral #4755 (#4789) --- app/javascript/mastodon/locales/de.json | 22 +++++++++++----------- config/locales/de.yml | 14 +++++++------- config/locales/doorkeeper.de.yml | 4 ++-- config/locales/simple_form.de.yml | 6 +++--- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 38324e156f..3133238cd8 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -26,12 +26,12 @@ "bundle_modal_error.close": "Schließen", "bundle_modal_error.message": "Etwas ist beim Laden schiefgelaufen.", "bundle_modal_error.retry": "Erneut versuchen", - "column.blocks": "Blockierte Benutzer", + "column.blocks": "Blockierte Profile", "column.community": "Lokale Zeitleiste", "column.favourites": "Favoriten", "column.follow_requests": "Folgeanfragen", "column.home": "Startseite", - "column.mutes": "Stummgeschaltete Benutzer", + "column.mutes": "Stummgeschaltete Profile", "column.notifications": "Mitteilungen", "column.public": "Gesamtes bekanntes Netz", "column_back_button.label": "Zurück", @@ -46,7 +46,7 @@ "compose_form.lock_disclaimer": "Dein Profil ist nicht {locked}. Jeder kann dir jederzeit folgen, um deine privaten Beiträge einzusehen.", "compose_form.lock_disclaimer.lock": "gesperrt", "compose_form.placeholder": "Worüber möchtest du schreiben?", - "compose_form.privacy_disclaimer": "Dein privater Status wird an die genannten Benutzer auf den Domains {domains} zugestellt. Vertraust du {domainsCount, plural, one {diesem Server} other {diesen Servern}}? Private Beiträge funktionieren nur auf Mastodon-Instanzen. Wenn {domains} {domainsCount, plural, one {keine Mastodon-Instanz ist} other {keine Mastodon-Instanzen sind}}, wird es dort kein Anzeichen geben, dass dein Beitrag privat ist und er könnte geteilt oder anderweitig für unerwünschte Empfänger sichtbar gemacht werden.", + "compose_form.privacy_disclaimer": "Dein privater Status wird an die genannten Profile auf den Domains {domains} zugestellt. Vertraust du {domainsCount, plural, one {diesem Server} other {diesen Servern}}? Private Beiträge funktionieren nur auf Mastodon-Instanzen. Wenn {domains} {domainsCount, plural, one {keine Mastodon-Instanz ist} other {keine Mastodon-Instanzen sind}}, wird es dort kein Anzeichen geben, dass dein Beitrag privat ist und er könnte geteilt oder anderweitig für unerwünschte Empfänger sichtbar gemacht werden.", "compose_form.publish": "Tröt", "compose_form.publish_loud": "{publish}!", "compose_form.sensitive": "Medien als heikel markieren", @@ -77,18 +77,18 @@ "emoji_button.travel": "Reise und Orte", "empty_column.community": "Die lokale Zeitleiste ist leer. Schreibe etwas öffentlich, um den Ball ins Rollen zu bringen!", "empty_column.hashtag": "Es gibt noch nichts unter diesem Hashtag.", - "empty_column.home": "Du folgst noch niemandem. Besuche {public} oder benutze die Suche, um zu starten oder andere Benutzer anzutreffen.", + "empty_column.home": "Du folgst noch niemandem. Besuche {public} oder benutze die Suche, um zu starten oder andere Profile zu finden.", "empty_column.home.inactivity": "Deine Zeitleiste ist leer. Falls du eine längere Zeit inaktiv gewesen bist, wird sie für dich so schnell wie möglich wiedererstellt.", "empty_column.home.public_timeline": "die öffentliche Zeitleiste", "empty_column.notifications": "Du hast noch keine Mitteilungen. Interagiere mit anderen, um die Konversation zu starten.", - "empty_column.public": "Hier ist nichts zu sehen! Schreibe etwas öffentlich oder folge Benutzern von anderen Instanzen, um es aufzufüllen.", + "empty_column.public": "Hier ist nichts zu sehen! Schreibe etwas öffentlich oder folge Profilen von anderen Instanzen, um es aufzufüllen.", "follow_request.authorize": "Erlauben", "follow_request.reject": "Ablehnen", "getting_started.appsshort": "Anwendungen", "getting_started.faq": "Häufig gestellte Fragen", "getting_started.heading": "Erste Schritte", "getting_started.open_source_notice": "Mastodon ist quelloffene Software. Du kannst auf {github} dazu beitragen oder Probleme melden.", - "getting_started.userguide": "Nutzeranleitung", + "getting_started.userguide": "Bedienungsanleitung", "home.column_settings.advanced": "Fortgeschritten", "home.column_settings.basic": "Einfach", "home.column_settings.filter_regex": "Filter durch reguläre Ausdrücke", @@ -101,14 +101,14 @@ "loading_indicator.label": "Lade…", "media_gallery.toggle_visible": "Sichtbarkeit einstellen", "missing_indicator.label": "Nicht gefunden", - "navigation_bar.blocks": "Blockierte Benutzer", + "navigation_bar.blocks": "Blockierte Profile", "navigation_bar.community_timeline": "Lokale Zeitleiste", "navigation_bar.edit_profile": "Profil bearbeiten", "navigation_bar.favourites": "Favoriten", "navigation_bar.follow_requests": "Folgeanfragen", "navigation_bar.info": "Erweiterte Informationen", "navigation_bar.logout": "Abmelden", - "navigation_bar.mutes": "Stummgeschaltete Benutzer", + "navigation_bar.mutes": "Stummgeschaltete Profile", "navigation_bar.preferences": "Einstellungen", "navigation_bar.public_timeline": "Föderierte Zeitleiste", "notification.favourite": "{name} favorisierte deinen Status", @@ -132,7 +132,7 @@ "onboarding.page_four.home": "Die Startseite zeigt dir Beiträge von Leuten, denen du folgst.", "onboarding.page_four.notifications": "Wenn jemand mir dir interagiert, bekommst du eine Mitteilung.", "onboarding.page_one.federation": "Mastodon ist ein soziales Netzwerk, das aus unabhängigen Servern besteht. Diese Server nennen wir auch Instanzen.", - "onboarding.page_one.handle": "Du bist auf der Instanz {domain}, also ist dein vollständiger Nutzername im Netzwerk {handle}", + "onboarding.page_one.handle": "Du bist auf der Instanz {domain}, also ist dein vollständiger Profilname im Netzwerk {handle}", "onboarding.page_one.welcome": "Willkommen bei Mastodon!", "onboarding.page_six.admin": "Für deine Instanz ist {admin} zuständig.", "onboarding.page_six.almost_done": "Fast fertig…", @@ -143,11 +143,11 @@ "onboarding.page_six.read_guidelines": "Bitte mach dich mit den {guidelines} von {domain} vertraut!", "onboarding.page_six.various_app": "mobile Anwendungen", "onboarding.page_three.profile": "Bearbeite dein Profil, um dein Bild, deinen Namen oder deine Beschreibung anzupassen. Dort findest du auch andere Einstellungen.", - "onboarding.page_three.search": "Benutze die Suchfunktion, um Leute oder Themen zu finden. Zum Beispiel, die Hashtags {illustration} oder {introductions}. Um eine Person zu finden, die auf einer anderen Instanz ist, benutze den vollständigen Nutzernamen.", + "onboarding.page_three.search": "Benutze die Suchfunktion, um Leute oder Themen zu finden. Zum Beispiel, die Hashtags {illustration} oder {introductions}. Um eine Person zu finden, die auf einer anderen Instanz ist, benutze den vollständigen Profilnamen.", "onboarding.page_two.compose": "Schreibe Beiträge aus der Schreiben-Spalte. Du kannst Bilder und kurze Videos hochladen, Sichtbarkeitseinstellungen ändern und Inhaltswarnungen hinzufügen.", "onboarding.skip": "Überspringen", "privacy.change": "Privatsphäre des Status anpassen", - "privacy.direct.long": "Beitrag nur an erwähnte Benutzer", + "privacy.direct.long": "Beitrag nur an erwähnte Profile", "privacy.direct.short": "Direkt", "privacy.private.long": "Beitrag nur an Folgende", "privacy.private.short": "Privat", diff --git a/config/locales/de.yml b/config/locales/de.yml index 1f3675f477..379eb8e429 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -12,15 +12,15 @@ de: source_code: Quellcode status_count_after: Beiträge verfassten status_count_before: die - user_count_after: Benutzer + user_count_after: Profile user_count_before: Heimat für accounts: follow: Folgen followers: Folgende following: Folgt nothing_here: Hier gibt es nichts! - people_followed_by: Nutzer, denen %{name} folgt - people_who_follow: Nutzer, die %{name} folgen + people_followed_by: Profile, denen %{name} folgt + people_who_follow: Profile, die %{name} folgen posts: Beiträge remote_follow: Folgen unfollow: Entfolgen @@ -67,7 +67,7 @@ de: title: Konten undo_silenced: Stummschaltung zurücknehmen undo_suspension: Sperre zurücknehmen - username: Benutzername + username: Profilname web: Web domain_blocks: add_new: Neu hinzufügen @@ -124,7 +124,7 @@ de: settings: contact_information: email: Eine öffentliche E-Mail-Adresse angeben - username: Einen Benutzernamen angeben + username: Einen Profilnamen angeben registrations: closed_message: desc_html: Wird auf der Frontseite angezeigt, wenn die Registrierung geschlossen ist
Du kannst HTML-Tags benutzen @@ -208,7 +208,7 @@ de: following: Folgeliste muting: Stummschaltungsliste upload: Hochladen - landing_strip_html: "%{name} ist ein Benutzer auf %{link_to_root_path}. Du kannst ihm folgen oder mit ihm interagieren, sofern du ein Konto irgendwo in der Fediverse hast." + landing_strip_html: "%{name} hat ein Profil auf %{link_to_root_path}. Du kannst folgen oder interagieren, sofern du ein Konto irgendwo im Fediversum hast." landing_strip_signup_html: Wenn nicht, kannst du dich hier anmelden. media_attachments: validations: @@ -244,7 +244,7 @@ de: prev: Zurück truncate: "…" remote_follow: - acct: Dein Nutzername@Domain, von dem aus du dieser Person folgen möchtest. + acct: Dein Profilname@Domain, von dem aus du dieser Person folgen möchtest. missing_resource: Die erforderliche Weiterleitungs-URL konnte leider in deinem Profil nicht gefunden werden. proceed: Weiter prompt: 'Du wirst dieser Person folgen:' diff --git a/config/locales/doorkeeper.de.yml b/config/locales/doorkeeper.de.yml index b37ba1dbeb..b0ba2fb98b 100644 --- a/config/locales/doorkeeper.de.yml +++ b/config/locales/doorkeeper.de.yml @@ -77,7 +77,7 @@ de: invalid_grant: Die bereitgestellte Autorisierung ist inkorrekt, abgelaufen, widerrufen, ist mit einem anderen Client verknüpft oder der Redirection URI stimmt nicht mit der Autorisierungs-Anfrage überein. invalid_redirect_uri: Der Redirect-URI in der Anfrage ist ungültig. invalid_request: Die Anfrage enthält einen nicht-unterstützten Parameter, ein Parameter fehlt oder sie ist anderweitig fehlerhaft. - invalid_resource_owner: Die angegebenen Zugangsdaten für den "Resource Owner" sind inkorrekt oder dieser Benutzer existiert nicht. + invalid_resource_owner: Die angegebenen Zugangsdaten für den "Resource Owner" sind inkorrekt oder dieses Profil existiert nicht. invalid_scope: Der angeforderte Scope ist inkorrekt, unbekannt oder fehlerhaft. invalid_token: expired: Der Zugriffstoken ist abgelaufen @@ -108,6 +108,6 @@ de: application: title: OAuth-Autorisierung nötig scopes: - follow: Nutzer folgen, blocken, entblocken und entfolgen + follow: Profil folgen, blocken, entblocken und entfolgen read: deine Daten lesen write: Beiträge von deinem Konto aus veröffentlichen diff --git a/config/locales/simple_form.de.yml b/config/locales/simple_form.de.yml index 85ec0e4fc7..c07dc28464 100644 --- a/config/locales/simple_form.de.yml +++ b/config/locales/simple_form.de.yml @@ -6,7 +6,7 @@ de: avatar: PNG, GIF oder JPG. Maximal 2MB. Wird auf 120x120px herunterskaliert display_name: '%{count} Zeichen verbleiben' header: PNG, GIF oder JPG. Maximal 2MB. Wird auf 700x335px herunterskaliert - locked: Erlaubt dir, Nutzer zu überprüfen, bevor sie dir folgen können + locked: Erlaubt dir, Profile zu überprüfen, bevor sie dir folgen können note: '%{count} Zeichen verbleiben' imports: data: CSV-Datei, die von einer anderen Mastodon-Instanz exportiert wurde @@ -33,10 +33,10 @@ de: setting_default_privacy: Beitragsprivatspäre severity: Gewichtung type: Importtyp - username: Nutzername + username: Profilname interactions: must_be_follower: Benachrichtigungen von Nicht-Folgern blockieren - must_be_following: Benachrichtigungen von Nutzern blockieren, denen ich nicht folge + must_be_following: Benachrichtigungen von Profilen blockieren, denen ich nicht folge notification_emails: digest: Schicke Übersichts-E-Mails favourite: E-Mail senden, wenn jemand meinen Beitrag favorisiert From 8b12e3cc7f3d0876b7cfd57999e70fd001c6c45c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 3 Sep 2017 15:17:34 +0200 Subject: [PATCH 08/31] Fix short number locales (#4790) Overwrite values from rails-i18n by manually overwriting in every locale. We want numbers like 1.5K in every language --- config/locales/ar.yml | 11 +++++++++++ config/locales/bg.yml | 11 +++++++++++ config/locales/ca.yml | 11 +++++++++++ config/locales/de.yml | 11 +++++++++++ config/locales/eo.yml | 11 +++++++++++ config/locales/es.yml | 11 +++++++++++ config/locales/fa.yml | 11 +++++++++++ config/locales/fi.yml | 11 +++++++++++ config/locales/fr.yml | 11 +++++++++++ config/locales/he.yml | 11 +++++++++++ config/locales/hr.yml | 11 +++++++++++ config/locales/hu.yml | 11 +++++++++++ config/locales/id.yml | 11 +++++++++++ config/locales/io.yml | 11 +++++++++++ config/locales/it.yml | 11 +++++++++++ config/locales/ko.yml | 11 +++++++++++ config/locales/nl.yml | 11 +++++++++++ config/locales/no.yml | 11 +++++++++++ config/locales/oc.yml | 2 +- config/locales/pl.yml | 11 +++++++++++ config/locales/pt-BR.yml | 11 +++++++++++ config/locales/pt.yml | 11 +++++++++++ config/locales/ru.yml | 11 +++++++++++ config/locales/th.yml | 11 +++++++++++ config/locales/tr.yml | 11 +++++++++++ config/locales/uk.yml | 11 +++++++++++ config/locales/zh-CN.yml | 11 +++++++++++ config/locales/zh-HK.yml | 11 +++++++++++ config/locales/zh-TW.yml | 11 +++++++++++ 29 files changed, 309 insertions(+), 1 deletion(-) diff --git a/config/locales/ar.yml b/config/locales/ar.yml index 575c5114c2..cda9a2fda8 100644 --- a/config/locales/ar.yml +++ b/config/locales/ar.yml @@ -108,6 +108,17 @@ ar: reblog: body: 'Your status was boosted by %{name}:' subject: "%{name} boosted your status" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: التالي prev: السابق diff --git a/config/locales/bg.yml b/config/locales/bg.yml index e7c3e1ef64..13d0394a38 100644 --- a/config/locales/bg.yml +++ b/config/locales/bg.yml @@ -108,6 +108,17 @@ bg: reblog: body: 'Твоята публикация беше споделена от %{name}:' subject: "%{name} сподели публикацията ти" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: Напред prev: Назад diff --git a/config/locales/ca.yml b/config/locales/ca.yml index b6bff82880..6a92b7f1b4 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -340,6 +340,17 @@ ca: reblog: body: "%{name} ha retootejat el teu estat" subject: "%{name} ha retootejat el teu estat" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: Pròxim prev: Anterior diff --git a/config/locales/de.yml b/config/locales/de.yml index 379eb8e429..de6c86737b 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -239,6 +239,17 @@ de: reblog: body: 'Dein Beitrag wurde von %{name} geteilt:' subject: "%{name} teilte deinen Beitrag." + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: Vorwärts prev: Zurück diff --git a/config/locales/eo.yml b/config/locales/eo.yml index f8b5ec0acf..21def0c5f4 100644 --- a/config/locales/eo.yml +++ b/config/locales/eo.yml @@ -103,6 +103,17 @@ eo: reblog: body: "%{name} diskonigis vian mesaĝon:" subject: "%{name} diskonigis vian mesaĝon" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: Sekva prev: Malsekva diff --git a/config/locales/es.yml b/config/locales/es.yml index d2d1de14f8..a02330521b 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -108,6 +108,17 @@ es: reblog: body: "%{name} ha retooteado tu estado" subject: "%{name} ha retooteado tu estado" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: Próximo prev: Anterior diff --git a/config/locales/fa.yml b/config/locales/fa.yml index 08ffb44849..ba726fc75a 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -339,6 +339,17 @@ fa: reblog: body: "%{name} نوشتهٔ شما را بازبوقید:" subject: "%{name} نوشتهٔ شما را بازبوقید" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: بعدی prev: قبلی diff --git a/config/locales/fi.yml b/config/locales/fi.yml index b748f71846..08ae904471 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -103,6 +103,17 @@ fi: reblog: body: 'Sinun statustasi boostasi %{name}:' subject: "%{name} boostasi statustasi" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: Seuraava prev: Edellinen diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 8029d8bd59..6198a54545 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -358,6 +358,17 @@ fr: reblog: body: "%{name} a partagé votre statut :" subject: "%{name} a partagé votre statut" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: Suivant prev: Précédent diff --git a/config/locales/he.yml b/config/locales/he.yml index f04e8ad621..84d6d8468e 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -264,6 +264,17 @@ he: reblog: body: 'חצרוצך הודהד על ידי %{name}:' subject: חצרוצך הודהד על ידי%{name} + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: הבא prev: הקודם diff --git a/config/locales/hr.yml b/config/locales/hr.yml index 52a8bd35f8..581912420d 100644 --- a/config/locales/hr.yml +++ b/config/locales/hr.yml @@ -105,6 +105,17 @@ hr: reblog: body: 'Tvoj status je potaknut od %{name}:' subject: "%{name} je potakao tvoj status" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: Sljedeći prev: Prošli diff --git a/config/locales/hu.yml b/config/locales/hu.yml index 53319a673e..77551223f3 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -45,6 +45,17 @@ hu: reblog: body: 'Az állapotod reblogolta %{name}:' subject: "%{name} reblogolta az állapotod" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: Következő prev: Előző diff --git a/config/locales/id.yml b/config/locales/id.yml index c76b3d6bbe..f3a6649d1c 100644 --- a/config/locales/id.yml +++ b/config/locales/id.yml @@ -254,6 +254,17 @@ id: reblog: body: 'Status anda di-boost oleh %{name}:' subject: "%{name} mem-boost status anda" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: Selanjutnya prev: Sebelumnya diff --git a/config/locales/io.yml b/config/locales/io.yml index 112771ee4f..4114e52312 100644 --- a/config/locales/io.yml +++ b/config/locales/io.yml @@ -239,6 +239,17 @@ io: reblog: body: "%{name} diskonocigis tua mesajo:" subject: "%{name} diskonocigis tua mesajo" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: Sequanta prev: Preiranta diff --git a/config/locales/it.yml b/config/locales/it.yml index 75d56362a6..ec0209bc19 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -108,6 +108,17 @@ it: reblog: body: 'Il tuo status è stato condiviso da %{name}:' subject: "%{name} ha condiviso il tuo status" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: Avanti prev: Indietro diff --git a/config/locales/ko.yml b/config/locales/ko.yml index f980595269..d6f4b15656 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -285,6 +285,17 @@ ko: reblog: body: "%{name} 님이 내 Toot을 부스트 했습니다:" subject: "%{name} 님이 내 Toot을 부스트 했습니다" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: 다음 prev: 이전 diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 50ae5508b7..2b7a1a5115 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -337,6 +337,17 @@ nl: reblog: body: 'Jouw toot werd door %{name} geboost:' subject: "%{name} boostte jouw toot" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: Volgende prev: Vorige diff --git a/config/locales/no.yml b/config/locales/no.yml index 996ea1d97f..207f86afcd 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -257,6 +257,17 @@ reblog: body: 'Din status ble fremhevd av %{name}:' subject: "%{name} fremhevde din status" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: Neste prev: Forrige diff --git a/config/locales/oc.yml b/config/locales/oc.yml index d077175ae8..c3807428b1 100644 --- a/config/locales/oc.yml +++ b/config/locales/oc.yml @@ -459,7 +459,7 @@ oc: action_favourite: Ajustar als favorits title: "%{name} vos a mencionat" reblog: - title: "%{name} a partejat vòstre estatut" + title: "%{name} a partejat vòstre estatut" remote_follow: acct: Picatz vòstre utilizaire@instància que cal utilizar per sègre aqueste utilizaire missing_resource: URL de redireccion pas trobada diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 246028f9b8..842baef451 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -355,6 +355,17 @@ pl: reblog: body: 'Twój wpis został podbity przez %{name}:' subject: Twój wpis został podbity przez %{name} + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: Następna prev: Poprzednia diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 6dec2b50a6..7501202995 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -255,6 +255,17 @@ pt-BR: reblog: body: 'O seu post foi reblogado por %{name}:' subject: "%{name} reblogou o seu post" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: Next prev: Prev diff --git a/config/locales/pt.yml b/config/locales/pt.yml index f6dd322005..140f6b71bb 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -182,6 +182,17 @@ pt: reblog: body: 'O teu post foi partilhado por %{name}:' subject: "%{name} partilhou o teu post" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: Seguinte prev: Anterior diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 52cb71c60f..9ca08831e0 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -262,6 +262,17 @@ ru: reblog: body: 'Ваш статус был продвинут %{name}:' subject: "%{name} продвинул(а) Ваш статус" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: След prev: Пред diff --git a/config/locales/th.yml b/config/locales/th.yml index 9d08879282..2db3aee8a4 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -257,6 +257,17 @@ th: reblog: body: 'Your status was boosted by %{name}:' subject: "%{name} boosted your status" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: ต่อไป prev: ย้อนกลับ diff --git a/config/locales/tr.yml b/config/locales/tr.yml index 91ef9544cf..6aff78fa16 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -255,6 +255,17 @@ tr: reblog: body: "%{name} durumunuzu boost etti:" subject: "%{name} durumunuzu boost etti" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: Sonraki prev: Önceki diff --git a/config/locales/uk.yml b/config/locales/uk.yml index 4d12ddf4e8..995a682a7c 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -250,6 +250,17 @@ uk: reblog: body: 'Ваш статус було передмухнуто %{name}:' subject: "%{name} передмухнув ваш статус" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: Далі prev: Назад diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index 0672202a21..95c24d0bc6 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -261,6 +261,17 @@ zh-CN: reblog: body: 你的嘟文得到 %{name} 的转嘟 subject: "%{name} 转嘟(嘟嘟滴)了你的嘟文" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: 下一页 prev: 上一页 diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml index 9d6c74008a..aa6b1ea6af 100644 --- a/config/locales/zh-HK.yml +++ b/config/locales/zh-HK.yml @@ -256,6 +256,17 @@ zh-HK: reblog: body: 你的文章得到 %{name} 的轉推 subject: "%{name} 轉推了你的文章" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: 下一頁 prev: 上一頁 diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index 7065acf9ab..299a92da7b 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -211,6 +211,17 @@ zh-TW: reblog: body: 您的文章被 %{name} 轉推 subject: "%{name} 轉推了您的文章" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' pagination: next: 下一頁 prev: 上一頁 From 334a633c2a7980dfce30b49c377d8ff8f85a9386 Mon Sep 17 00:00:00 2001 From: abcang Date: Mon, 4 Sep 2017 03:31:51 +0900 Subject: [PATCH 09/31] Fix a problem that notification column goes to top (#4792) --- app/javascript/mastodon/features/notifications/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/javascript/mastodon/features/notifications/index.js b/app/javascript/mastodon/features/notifications/index.js index c23560a434..b74473b9f5 100644 --- a/app/javascript/mastodon/features/notifications/index.js +++ b/app/javascript/mastodon/features/notifications/index.js @@ -106,6 +106,7 @@ export default class Notifications extends React.PureComponent { const scrollContainer = ( Date: Mon, 4 Sep 2017 02:14:12 +0200 Subject: [PATCH 10/31] Fix #4551 - Use correct syntax for content preloading (#4798) --- app/views/layouts/application.html.haml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index e21fb1ce14..88eff7d178 100755 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -21,13 +21,13 @@ = stylesheet_pack_tag 'common', media: 'all' = javascript_pack_tag 'common', integrity: true, crossorigin: 'anonymous' - = javascript_pack_tag 'features/getting_started', integrity: true, crossorigin: 'anonymous', rel: 'preload', as: 'script' - = javascript_pack_tag 'features/compose', integrity: true, crossorigin: 'anonymous', rel: 'preload', as: 'script' - = javascript_pack_tag 'features/home_timeline', integrity: true, crossorigin: 'anonymous', rel: 'preload', as: 'script' - = javascript_pack_tag 'features/notifications', integrity: true, crossorigin: 'anonymous', rel: 'preload', as: 'script' - = javascript_pack_tag 'features/community_timeline', integrity: true, crossorigin: 'anonymous', rel: 'preload', as: 'script' - = javascript_pack_tag 'features/public_timeline', integrity: true, crossorigin: 'anonymous', rel: 'preload', as: 'script' - = javascript_pack_tag 'emojione_picker', integrity: true, crossorigin: 'anonymous', rel: 'preload', as: 'script' + %link{ href: asset_pack_path('features/getting_started.js'), crossorigin: 'anonymous', rel: 'preload', as: 'script' }/ + %link{ href: asset_pack_path('features/compose.js'), crossorigin: 'anonymous', rel: 'preload', as: 'script' }/ + %link{ href: asset_pack_path('features/home_timeline.js'), crossorigin: 'anonymous', rel: 'preload', as: 'script' }/ + %link{ href: asset_pack_path('features/notifications.js'), crossorigin: 'anonymous', rel: 'preload', as: 'script' }/ + %link{ href: asset_pack_path('features/community_timeline.js'), crossorigin: 'anonymous', rel: 'preload', as: 'script' }/ + %link{ href: asset_pack_path('features/public_timeline.js'), crossorigin: 'anonymous', rel: 'preload', as: 'script' }/ + %link{ href: asset_pack_path('emojione_picker.js'), crossorigin: 'anonymous', rel: 'preload', as: 'script' }/ = javascript_pack_tag "locale_#{I18n.locale}", integrity: true, crossorigin: 'anonymous' = csrf_meta_tags From b6f3869f8d600d319b3747b145b1d779869f8cc2 Mon Sep 17 00:00:00 2001 From: voidSatisfaction Date: Mon, 4 Sep 2017 19:52:06 +0900 Subject: [PATCH 11/31] Fix streaming url to lowercase (#4804) --- streaming/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/streaming/index.js b/streaming/index.js index c7e0de96c2..3e80c8b308 100644 --- a/streaming/index.js +++ b/streaming/index.js @@ -403,11 +403,11 @@ const startWorker = (workerId) => { }); app.get('/api/v1/streaming/hashtag', (req, res) => { - streamFrom(`timeline:hashtag:${req.query.tag}`, req, streamToHttp(req, res), streamHttpEnd(req), true); + streamFrom(`timeline:hashtag:${req.query.tag.toLowerCase()}`, req, streamToHttp(req, res), streamHttpEnd(req), true); }); app.get('/api/v1/streaming/hashtag/local', (req, res) => { - streamFrom(`timeline:hashtag:${req.query.tag}:local`, req, streamToHttp(req, res), streamHttpEnd(req), true); + streamFrom(`timeline:hashtag:${req.query.tag.toLowerCase()}:local`, req, streamToHttp(req, res), streamHttpEnd(req), true); }); const wss = new WebSocket.Server({ server, verifyClient: wsVerifyClient }); @@ -438,10 +438,10 @@ const startWorker = (workerId) => { streamFrom('timeline:public:local', req, streamToWs(req, ws), streamWsEnd(req, ws), true); break; case 'hashtag': - streamFrom(`timeline:hashtag:${location.query.tag}`, req, streamToWs(req, ws), streamWsEnd(req, ws), true); + streamFrom(`timeline:hashtag:${location.query.tag.toLowerCase()}`, req, streamToWs(req, ws), streamWsEnd(req, ws), true); break; case 'hashtag:local': - streamFrom(`timeline:hashtag:${location.query.tag}:local`, req, streamToWs(req, ws), streamWsEnd(req, ws), true); + streamFrom(`timeline:hashtag:${location.query.tag.toLowerCase()}:local`, req, streamToWs(req, ws), streamWsEnd(req, ws), true); break; default: ws.close(); From 2293466edd0972c2069628c55baec9b0cb861445 Mon Sep 17 00:00:00 2001 From: nullkal Date: Mon, 4 Sep 2017 19:53:18 +0900 Subject: [PATCH 12/31] Show pinned statuses only in the top of the profile page (#4803) * Show pinned statuses only in the top of the profile page * Refactor AccountsController#show_pinned_statuses? --- app/controllers/accounts_controller.rb | 6 +++- spec/controllers/accounts_controller_spec.rb | 31 ++++++++++++++++---- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 8dad12f115..afa0417fa3 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -14,7 +14,7 @@ class AccountsController < ApplicationController return end - @pinned_statuses = cache_collection(@account.pinned_statuses, Status) unless media_requested? + @pinned_statuses = cache_collection(@account.pinned_statuses, Status) if show_pinned_statuses? @statuses = filtered_statuses.paginate_by_max_id(20, params[:max_id], params[:since_id]) @statuses = cache_collection(@statuses, Status) @next_url = next_url unless @statuses.empty? @@ -33,6 +33,10 @@ class AccountsController < ApplicationController private + def show_pinned_statuses? + [replies_requested?, media_requested?, params[:max_id].present?, params[:since_id].present?].none? + end + def filtered_statuses default_statuses.tap do |statuses| statuses.merge!(only_media_scope) if media_requested? diff --git a/spec/controllers/accounts_controller_spec.rb b/spec/controllers/accounts_controller_spec.rb index 4e37b1b5fc..92f8885907 100644 --- a/spec/controllers/accounts_controller_spec.rb +++ b/spec/controllers/accounts_controller_spec.rb @@ -61,7 +61,29 @@ RSpec.describe AccountsController, type: :controller do end end - context 'html' do + context 'html without since_id nor max_id' do + before do + get :show, params: { username: alice.username } + end + + it 'assigns @account' do + expect(assigns(:account)).to eq alice + end + + it 'assigns @pinned_statuses' do + pinned_statuses = assigns(:pinned_statuses).to_a + expect(pinned_statuses.size).to eq 3 + expect(pinned_statuses[0]).to eq status7 + expect(pinned_statuses[1]).to eq status5 + expect(pinned_statuses[2]).to eq status6 + end + + it 'returns http success' do + expect(response).to have_http_status(:success) + end + end + + context 'html with since_id and max_id' do before do get :show, params: { username: alice.username, max_id: status4.id, since_id: status1.id } end @@ -77,12 +99,9 @@ RSpec.describe AccountsController, type: :controller do expect(statuses[1]).to eq status2 end - it 'assigns @pinned_statuses' do + it 'assigns an empty array to @pinned_statuses' do pinned_statuses = assigns(:pinned_statuses).to_a - expect(pinned_statuses.size).to eq 3 - expect(pinned_statuses[0]).to eq status7 - expect(pinned_statuses[1]).to eq status5 - expect(pinned_statuses[2]).to eq status6 + expect(pinned_statuses.size).to eq 0 end it 'returns http success' do From 9b50a9dd835c3a08effc86a6ef3e29e3a16e3d27 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 4 Sep 2017 18:26:33 +0200 Subject: [PATCH 13/31] Fix some ActivityPub JSON bugs (#4796) - Fix assumption that `url` is always a string. Handle it if it's an array of strings, array of objects, object, or string, both for accounts and for objects - `sharedInbox` is actually supposed to be under `endpoints`, handle both cases and adjust the serializer --- app/lib/activitypub/activity/create.rb | 12 +++++++++++- .../activitypub/actor_serializer.rb | 18 +++++++++++++++--- .../activitypub/process_account_service.rb | 18 ++++++++++++++---- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index 081e805703..9a34484f5e 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -33,7 +33,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity def status_params { uri: @object['id'], - url: @object['url'] || @object['id'], + url: object_url || @object['id'], account: @account, text: text_from_content || '', language: language_from_content, @@ -147,6 +147,16 @@ class ActivityPub::Activity::Create < ActivityPub::Activity @object['contentMap'].keys.first end + def object_url + return if @object['url'].blank? + + value = first_of_value(@object['url']) + + return value if value.is_a?(String) + + value['href'] + end + def language_map? @object['contentMap'].is_a?(Hash) && !@object['contentMap'].empty? end diff --git a/app/serializers/activitypub/actor_serializer.rb b/app/serializers/activitypub/actor_serializer.rb index 25521eca94..a11178f5ba 100644 --- a/app/serializers/activitypub/actor_serializer.rb +++ b/app/serializers/activitypub/actor_serializer.rb @@ -4,7 +4,7 @@ class ActivityPub::ActorSerializer < ActiveModel::Serializer include RoutingHelper attributes :id, :type, :following, :followers, - :inbox, :outbox, :shared_inbox, + :inbox, :outbox, :preferred_username, :name, :summary, :url, :manually_approves_followers @@ -24,6 +24,18 @@ class ActivityPub::ActorSerializer < ActiveModel::Serializer end end + class EndpointsSerializer < ActiveModel::Serializer + include RoutingHelper + + attributes :shared_inbox + + def shared_inbox + inbox_url + end + end + + has_one :endpoints, serializer: EndpointsSerializer + has_one :icon, serializer: ImageSerializer, if: :avatar_exists? has_one :image, serializer: ImageSerializer, if: :header_exists? @@ -51,8 +63,8 @@ class ActivityPub::ActorSerializer < ActiveModel::Serializer account_outbox_url(object) end - def shared_inbox - inbox_url + def endpoints + object end def preferred_username diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb index a26b39cb52..29eb1c2e10 100644 --- a/app/services/activitypub/process_account_service.rb +++ b/app/services/activitypub/process_account_service.rb @@ -6,7 +6,7 @@ class ActivityPub::ProcessAccountService < BaseService # Should be called with confirmed valid JSON # and WebFinger-resolved username and domain def call(username, domain, json) - return unless json['inbox'].present? + return if json['inbox'].blank? @json = json @uri = @json['id'] @@ -42,9 +42,9 @@ class ActivityPub::ProcessAccountService < BaseService @account.protocol = :activitypub @account.inbox_url = @json['inbox'] || '' @account.outbox_url = @json['outbox'] || '' - @account.shared_inbox_url = @json['sharedInbox'] || '' + @account.shared_inbox_url = (@json['endpoints'].is_a?(Hash) ? @json['endpoints']['sharedInbox'] : @json['sharedInbox']) || '' @account.followers_url = @json['followers'] || '' - @account.url = @json['url'] || @uri + @account.url = url || @uri @account.display_name = @json['name'] || '' @account.note = @json['summary'] || '' @account.avatar_remote_url = image_url('icon') @@ -62,7 +62,7 @@ class ActivityPub::ProcessAccountService < BaseService value = first_of_value(@json[key]) return if value.nil? - return @json[key]['url'] if @json[key].is_a?(Hash) + return value['url'] if value.is_a?(Hash) image = fetch_resource(value) image['url'] if image @@ -78,6 +78,16 @@ class ActivityPub::ProcessAccountService < BaseService key['publicKeyPem'] if key end + def url + return if @json['url'].blank? + + value = first_of_value(@json['url']) + + return value if value.is_a?(String) + + value['href'] + end + def auto_suspend? domain_block && domain_block.suspend? end From f09a250a7c0058e9e71098fa51481f786bfd4b73 Mon Sep 17 00:00:00 2001 From: ButterflyOfFire Date: Mon, 4 Sep 2017 18:54:12 +0100 Subject: [PATCH 14/31] Update ar.yml (#4810) Some little changes to "ar" locale --- config/locales/ar.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/config/locales/ar.yml b/config/locales/ar.yml index cda9a2fda8..604b096000 100644 --- a/config/locales/ar.yml +++ b/config/locales/ar.yml @@ -47,16 +47,16 @@ ar: datetime: distance_in_words: about_x_hours: "%{count}سا" - about_x_months: "%{count}شهر" - about_x_years: "%{count}سنة" - almost_x_years: "%{count}سنوات" - half_a_minute: Just now - less_than_x_minutes: "%{count}د" + about_x_months: "%{count} شهر" + about_x_years: "%{count} سنة" + almost_x_years: "%{count} سنوات" + half_a_minute: الآن + less_than_x_minutes: "%{count} د" less_than_x_seconds: الآن - over_x_years: "%{count}سنين" - x_days: "%{count}أيام" + over_x_years: "%{count} سنين" + x_days: "%{count} أيام" x_minutes: "%{count}د" - x_months: "%{count}شه" + x_months: "%{count} شه" x_seconds: "%{count}ث" exports: blocks: قمت بحظر @@ -94,7 +94,7 @@ ar: one: "إشعار واحد منذ زيارتك الأخيرة \U0001F418" other: "%{count} إشعارات جديدة منذ زيارتك الأخيرة \U0001F418" favourite: - body: 'Your status was favourited by %{name}:' + body: 'أُعجب %{name} بمنشورك' subject: "%{name} favourited your status" follow: body: "%{name} من متتبعيك الآن !" @@ -159,7 +159,7 @@ ar: enabled_success: تم تفعيل إثبات الهوية المزدوج بنجاح instructions_html: "Scan this QR code into Google Authenticator or a similiar TOTP app on your phone. From now on, that app will generate tokens that you will have to enter when logging in." manual_instructions: 'If you can''t scan the QR code and need to enter it manually, here is the plain-text secret:' - setup: Set up + setup: تنشيط wrong_code: الرمز الذي أدخلته غير صالح. تحقق من صحة الوقت على الخادم و الجهاز. users: invalid_email: عنوان البريد الإلكتروني غير صالح From 4d67bf18feefa9562a999fd47e93c816e6be3ba2 Mon Sep 17 00:00:00 2001 From: voidSatisfaction Date: Tue, 5 Sep 2017 03:40:02 +0900 Subject: [PATCH 15/31] Translation korean added (#4802) --- config/locales/ko.yml | 107 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 100 insertions(+), 7 deletions(-) diff --git a/config/locales/ko.yml b/config/locales/ko.yml index d6f4b15656..6fdc3b9855 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -1,29 +1,52 @@ --- ko: about: - about_mastodon_html: Mastodon 은자유로운 오픈 소스소셜 네트워크입니다. 상용 플랫폼의 대체로써 분산형 구조를 채택해, 여러분의 대화가 한 회사에 독점되는 것을 방지합니다. 신뢰할 수 있는 인스턴스를 선택하세요 — 어떤 인스턴스를 고르더라도, 누구와도 대화할 수 있습니다. 누구나 자신만의 Mastodon 인스턴스를 만들 수 있으며, Seamless하게 소셜 네트워크에 참가할 수 있습니다. + about_mastodon_html: Mastodon은 오픈 소스 기반의 소셜 네트워크 서비스 입니다. 상용 플랫폼의 대체로서 분산형 구조를 채택해, 여러분의 대화가 한 회사에 독점되는 것을 방지합니다. 신뢰할 수 있는 인스턴스를 선택하세요 — 어떤 인스턴스를 고르더라도, 누구와도 대화할 수 있습니다. 누구나 자신만의 Mastodon 인스턴스를 만들 수 있으며, Seamless하게 소셜 네트워크에 참가할 수 있습니다. about_this: 이 인스턴스에 대해서 closed_registrations: 현재 이 인스턴스에서는 신규 등록을 받고 있지 않습니다. contact: 연락처 - description_headline: "%{domain} 는 무엇인가요?" + contact_missing: 미설정 + contact_unavailable: N/A + description_headline: "%{domain} (은)는 무엇인가요?" domain_count_after: 개의 인스턴스 - domain_count_before: 연결됨 + domain_count_before: 연결된 + extended_description_html: | +

룰을 작성하는 장소

+

아직 설명이 작성되지 않았습니다.

+ features: + humane_approach_body: 다른 SNS의 실패를 교훈삼아, Mastodon은 소셜미디어가 잘못 사용되는 것을 막기 위하여 윤리적인 설계를 추구합니다. + humane_approach_title: 보다 배려를 의식한 설계를 추구 + not_a_product_body: Mastodon은 이익을 추구하는 SNS가 아닙니다. 그러므로 광고와 데이터의 수집 및 분석이 존재하지 않고, 유저를 구속하지도 않습니다. + not_a_product_title: 여러분은 사람이며, 상품이 아닙니다. + real_conversation_body: 자유롭게 사용할 수 있는 500문자의 메세지와 미디어 경고 내용을 바탕으로, 자기자신을 자유롭게 표현할 수 있습니다. + real_conversation_title: 진정한 커뮤니케이션을 위하여 + within_reach_body: 개발자 친화적인 API에 의해서 실현된 iOS나 Android, 그 외의 여러 Platform들 덕분에 어디서든 친구들과 자유롭게 메세지를 주고 받을 수 있습니다. + within_reach_title: 언제나 유저의 곁에서 + find_another_instance: 다른 인스턴스 찾기 + generic_description: "%{domain} 은 Mastodon의 인스턴스 입니다." + hosted_on: Mastodon hosted on %{domain} + learn_more: 자세히 other_instances: 다른 인스턴스 source_code: 소스 코드 status_count_after: Toot status_count_before: Toot 수 user_count_after: 명 user_count_before: 사용자 수 + what_is_mastodon: Mastodon이란? accounts: follow: 팔로우 followers: 팔로워 following: 팔로잉 + media: 미디어 nothing_here: 아무 것도 없습니다. people_followed_by: "%{name} 님이 팔로우 중인 계정" people_who_follow: "%{name} 님을 팔로우 중인 계정" - posts: 포스트 + posts: Toot + posts_with_replies: Toot와 답장 remote_follow: 리모트 팔로우 reserved_username: 이 아이디는 예약되어 있습니다. + roles: + admin: Admin unfollow: 팔로우 해제 admin: accounts: @@ -38,6 +61,7 @@ ko: feed_url: 피드 URL followers: 팔로워 수 follows: 팔로잉 수 + inbox_url: Inbox URL ip: IP location: all: 전체 @@ -57,8 +81,10 @@ ko: alphabetic: 알파벳 순 most_recent: 최근 활동 순 title: 순서 + outbox_url: Outbox URL perform_full_suspension: 완전히 정지시키기 profile_url: 프로필 URL + protocol: Protocol public: 전체 공개 push_subscription_expires: PuSH 구독 기간 만료 redownload: 아바타 업데이트 @@ -90,12 +116,14 @@ ko: hint: 도메인 차단은 내부 데이터베이스에 계정이 생성되는 것까지는 막을 수 없지만, 그 도메인에서 생성된 계정에 자동적으로 특정한 모더레이션을 적용하게 할 수 있습니다. severity: desc_html: "침묵은 계정을 팔로우 하지 않고 있는 사람들에겐 계정의 Toot을 보이지 않게 합니다. 정지는 계정의 컨텐츠, 미디어, 프로필 데이터를 삭제합니다." + noop: 없음 silence: 침묵 suspend: 정지 title: 새로운 도메인 차단 reject_media: 미디어 파일 거부하기 reject_media_hint: 로컬에 저장된 미디어 파일을 삭제하고, 이후로도 다운로드를 거부합니다. 정지하고는 관계 없습니다. severities: + noop: 없음 silence: 침묵 suspend: 정지 severity: 심각도 @@ -146,16 +174,41 @@ ko: closed_message: desc_html: 신규 등록을 받지 않을 때 프론트 페이지에 표시됩니다.
HTML 태그를 사용할 수 있습니다. title: 신규 등록 정지 시 메시지 + deletion: + desc_html: 유저가 자신의 계정을 삭제할 수 있도록 설정합니다. + title: 계정 삭제를 허가함 open: - title: 신규 등록을 받음 + desc_html: 유저가 자신의 계정을 생성할 수 있도록 설정합니다. + title: 신규 계정 등록을 받음 site_description: desc_html: 탑 페이지와 meta 태그에 사용됩니다.
HTML 태그, 예를 들어<a> 태그와 <em> 태그를 사용할 수 있습니다. title: 사이트 설명 site_description_extended: desc_html: 인스턴스 정보 페이지에 표시됩니다.
HTML 태그를 사용할 수 있습니다. title: 사이트 상세 설명 + site_terms: + desc_html: 당신은 독자적인 개인정보 취급 방침이나 이용약관, 그 외의 법적 근거를 작성할 수 있습니다. 또한 HTML태그를 사용할 수 있습니다. + title: 커스텀 서비스 이용 약관 site_title: 사이트 이름 + timeline_preview: + desc_html: Landing page에 공개 타임라인을 표시합니다. + title: 타임라인 프리뷰 title: 사이트 설정 + statuses: + back_to_account: 계정으로 돌아가기 + batch: + delete: 삭제 + nsfw_off: NSFW 끄기 + nsfw_on: NSFW 켜기 + execute: 실행 + failed_to_execute: 실행이 실패하였습니다. + media: + hide: 미디어 숨기기 + show: 미디어 보여주기 + title: 미디어 + no_media: 미디어 없음 + title: 계정 Toot + with_media: 미디어 있음 subscriptions: callback_url: 콜백 URL confirmed: 확인됨 @@ -173,13 +226,21 @@ ko: signature: Mastodon %{instance} 인스턴스로에서 알림 view: 'View:' applications: + created: 어플리케이션이 작성되었습니다. + destroyed: 어플리케이션이 삭제되었습니다. invalid_url: 올바르지 않은 URL입니다 + regenerate_token: 토큰 재생성 + token_regenerated: 액세스 토큰이 재생성되었습니다. + warning: 이 데이터는 다른 사람들과 절대로 공유하지 마세요. + your_token: 액세스 토큰 auth: + agreement_html: 이 등록으로 이용규약개인정보 취급 방침에 동의하는 것으로 간주됩니다. change_password: 보안 delete_account: 계정 삭제 delete_account_html: 계정을 삭제하고 싶은 경우, 여기서 삭제할 수 있습니다. 삭제 전 확인 화면이 표시됩니다. didnt_get_confirmation: 확인 메일을 받지 못하셨습니까? forgot_password: 비밀번호를 잊어버리셨습니까? + invalid_reset_password_token: 비밀번호 리셋 토큰이 올바르지 못하거나 기간이 만료되었습니다. 다시 요청해주세요. login: 로그인 logout: 로그아웃 register: 등록하기 @@ -189,6 +250,12 @@ ko: authorize_follow: error: 리모트 팔로우 도중 오류가 발생했습니다. follow: 팔로우 + follow_request: '당신은 다음 계정에 팔로우 신청을 했습니다:' + following: '성공! 당신은 다음 계정을 팔로우 하고 있습니다:' + post_follow: + close: 혹은, 당신은 이 윈도우를 닫을 수 있습니다 + return: 유저 프로필로 돌아가기 + web: 웹으로 가기 title: "%{acct} 를 팔로우" datetime: distance_in_words: @@ -271,8 +338,8 @@ ko: one: "1건의 새로운 알림 \U0001F418" other: "%{count}건의 새로운 알림 \U0001F418" favourite: - body: "%{name} 님이 내 Toot을 즐겨찾기에 등록했습니다." - subject: "%{name} 님이 내 Toot을 즐겨찾기에 등록했습니다" + body: "%{name} 님이 내 Toot를 즐겨찾기에 등록했습니다." + subject: "%{name} 님이 내 Toot를 즐겨찾기에 등록했습니다" follow: body: "%{name} 님이 나를 팔로우 했습니다" subject: "%{name} 님이 나를 팔로우 했습니다" @@ -300,6 +367,20 @@ ko: next: 다음 prev: 이전 truncate: "…" + push_notifications: + favourite: + title: "%{name} 님이 당신의 Toot를 즐겨찾기에 등록했습니다." + follow: + title: "%{name} 님이 나를 팔로우 하고 있습니다." + group: + title: "%{count} 건의 알림" + mention: + action_boost: 부스트 + action_expand: 더보기 + action_favourite: 즐겨찾기 + title: "%{name} 님이 답장을 보냈습니다" + reblog: + title: "%{name} 님이 당신의 Toot를 부스트 했습니다." remote_follow: acct: 아이디@도메인을 입력해 주십시오 missing_resource: 리디렉션 대상을 찾을 수 없습니다 @@ -341,11 +422,14 @@ ko: windows: Windows windows_mobile: Windows Mobile windows_phone: Windows Phone + revoke: 삭제 + revoke_success: 세션이 삭제되었습니다. title: 세션 settings: authorized_apps: 인증된 어플리케이션 back: 돌아가기 delete: 계정 삭제 + development: 개발 edit_profile: 프로필 편집 export: 데이터 내보내기 followers: 신뢰 중인 인스턴스 @@ -353,9 +437,14 @@ ko: preferences: 사용자 설정 settings: 설정 two_factor_authentication: 2단계 인증 + your_apps: 애플리케이션 statuses: open_in_web: Web으로 열기 over_character_limit: 최대 %{max}자까지 입력할 수 있습니다 + pin_errors: + ownership: 다른 사람의 Toot는 고정될 수 없습니다. + private: 비공개 Toot는 고정될 수 없습니다. + reblog: 부스트는 고정될 수 없습니다. show_more: 더 보기 visibilities: private: 비공개 @@ -366,8 +455,11 @@ ko: unlisted_long: 누구나 볼 수 있지만, 공개 타임라인에는 표시되지 않습니다 stream_entries: click_to_show: 클릭해서 표시 + pinned: 고정된 Toot reblogged: 님이 부스트 했습니다 sensitive_content: 민감한 컨텐츠 + terms: + title: "%{instance} 이용약관과 개인정보 취급 방침" time: formats: default: "%Y년 %m월 %d일 %H:%M" @@ -390,3 +482,4 @@ ko: users: invalid_email: 메일 주소가 올바르지 않습니다 invalid_otp_token: 2단계 인증 코드가 올바르지 않습니다 + signed_in_as: '다음과 같이 로그인 중:' From aefb4719bcab6d9a17b3f2fd063f4c2ad455223d Mon Sep 17 00:00:00 2001 From: Treyssat-Vincent Nino Date: Tue, 5 Sep 2017 12:13:25 +0200 Subject: [PATCH 16/31] comment correction (#4812) --- .env.production.sample | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.production.sample b/.env.production.sample index 1d8a177aa2..07c8876923 100644 --- a/.env.production.sample +++ b/.env.production.sample @@ -26,7 +26,7 @@ LOCAL_HTTPS=true # ALTERNATE_DOMAINS=example1.com,example2.com # Application secrets -# Generate each with the `rake secret` task (`docker-compose run --rm web rake secret` if you use docker compose) +# Generate each with the `RAILS_ENV=production bundle exec rake secret` task (`docker-compose run --rm web rake secret` if you use docker compose) PAPERCLIP_SECRET= SECRET_KEY_BASE= OTP_SECRET= @@ -36,7 +36,7 @@ OTP_SECRET= # You should only generate this once per instance. If you later decide to change it, all push subscription will # be invalidated, requiring the users to access the website again to resubscribe. # -# Generate with `rake mastodon:webpush:generate_vapid_key` task (`docker-compose run --rm web rake mastodon:webpush:generate_vapid_key` if you use docker compose) +# Generate with `RAILS_ENV=production bundle exec rake mastodon:webpush:generate_vapid_key` task (`docker-compose run --rm web rake mastodon:webpush:generate_vapid_key` if you use docker compose) # # For more information visit https://rossta.net/blog/using-the-web-push-api-with-vapid.html VAPID_PRIVATE_KEY= From 672df4ecc0d0563c58877a878264b9807102ecf0 Mon Sep 17 00:00:00 2001 From: takayamaki Date: Tue, 5 Sep 2017 19:30:01 +0900 Subject: [PATCH 17/31] add index_notifications_on_id_and_account_id_and_activity_type on notifications table (#4750) --- ...add_index_id_account_id_activity_type_on_notifications.rb | 5 +++++ db/schema.rb | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20170905044538_add_index_id_account_id_activity_type_on_notifications.rb diff --git a/db/migrate/20170905044538_add_index_id_account_id_activity_type_on_notifications.rb b/db/migrate/20170905044538_add_index_id_account_id_activity_type_on_notifications.rb new file mode 100644 index 0000000000..c47cea9e26 --- /dev/null +++ b/db/migrate/20170905044538_add_index_id_account_id_activity_type_on_notifications.rb @@ -0,0 +1,5 @@ +class AddIndexIdAccountIdActivityTypeOnNotifications < ActiveRecord::Migration[5.1] + def change + add_index :notifications, [:id, :account_id, :activity_type], order: { id: :desc } + end +end diff --git a/db/schema.rb b/db/schema.rb index c3a2581e3d..ea7edc2f9c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170901142658) do +ActiveRecord::Schema.define(version: 20170905044538) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -180,6 +180,7 @@ ActiveRecord::Schema.define(version: 20170901142658) do t.integer "from_account_id" t.index ["account_id", "activity_id", "activity_type"], name: "account_activity", unique: true t.index ["activity_id", "activity_type"], name: "index_notifications_on_activity_id_and_activity_type" + t.index ["id", "account_id", "activity_type"], name: "index_notifications_on_id_and_account_id_and_activity_type", order: { id: :desc } end create_table "oauth_access_grants", id: :serial, force: :cascade do |t| From 4c3dd0b25472b4d291f607979d255dd406856bef Mon Sep 17 00:00:00 2001 From: Lynx Kotoura Date: Tue, 5 Sep 2017 19:31:24 +0900 Subject: [PATCH 18/31] Adjust status embeds (#4808) * Adjust status embeds Adjust styles of embed code. Adjust styles of embed pages. Fix overflow of embed-modal. * Remove trailing whitespace * Using width from the variable --- app/javascript/styles/components.scss | 97 ++++++++++--------- app/javascript/styles/stream_entries.scss | 79 +++++++-------- app/serializers/oembed_serializer.rb | 3 +- .../stream_entries/_detailed_status.html.haml | 10 +- 4 files changed, 97 insertions(+), 92 deletions(-) diff --git a/app/javascript/styles/components.scss b/app/javascript/styles/components.scss index 0fbaeeea0a..1b9763e90a 100644 --- a/app/javascript/styles/components.scss +++ b/app/javascript/styles/components.scss @@ -3966,41 +3966,10 @@ noscript { } } -.embed-modal__html { - color: $ui-secondary-color; - outline: 0; - box-sizing: border-box; - display: block; - width: 100%; - border: none; - padding: 10px; - font-family: 'mastodon-font-monospace', monospace; - background: $ui-base-color; - color: $ui-primary-color; - font-size: 14px; - margin: 0; - margin-bottom: 15px; - - &::-moz-focus-inner { - border: 0; - } - - &::-moz-focus-inner, - &:focus, - &:active { - outline: 0 !important; - } - - &:focus { - background: lighten($ui-base-color, 4%); - } - - @media screen and (max-width: 600px) { - font-size: 16px; - } -} - .embed-modal { + max-width: 80vw; + max-height: 80vh; + h4 { padding: 30px; font-weight: 500; @@ -4008,18 +3977,52 @@ noscript { text-align: center; } - .hint { - margin-bottom: 15px; + .embed-modal__container { + padding: 10px; + + .hint { + margin-bottom: 15px; + } + + .embed-modal__html { + color: $ui-secondary-color; + outline: 0; + box-sizing: border-box; + display: block; + width: 100%; + border: none; + padding: 10px; + font-family: 'mastodon-font-monospace', monospace; + background: $ui-base-color; + color: $ui-primary-color; + font-size: 14px; + margin: 0; + margin-bottom: 15px; + + &::-moz-focus-inner { + border: 0; + } + + &::-moz-focus-inner, + &:focus, + &:active { + outline: 0 !important; + } + + &:focus { + background: lighten($ui-base-color, 4%); + } + + @media screen and (max-width: 600px) { + font-size: 16px; + } + } + + .embed-modal__iframe { + width: 400px; + max-width: 100%; + overflow: hidden; + border: 0; + } } } - -.embed-modal__container { - padding: 10px; -} - -.embed-modal__iframe { - width: 100%; - min-width: 400px; - overflow: hidden; - border: 0; -} diff --git a/app/javascript/styles/stream_entries.scss b/app/javascript/styles/stream_entries.scss index 7048ab110c..8ed4c0b25f 100644 --- a/app/javascript/styles/stream_entries.scss +++ b/app/javascript/styles/stream_entries.scss @@ -403,51 +403,54 @@ .embed { .activity-stream { - border-radius: 4px; box-shadow: none; .entry { - &:last-child { - border-radius: 0 0 4px 4px; - } - &:first-child { - border-radius: 4px 4px 0 0; + .detailed-status.light { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: flex-start; - &:last-child { - border-radius: 4px; + .detailed-status__display-name { + flex: 1; + margin: 0 5px 15px 0; + } + + .button.button-secondary.logo-button { + flex: 0 auto; + font-size: 14px; + + svg { + width: 20px; + height: auto; + vertical-align: middle; + margin-right: 5px; + + path:first-child { + fill: $ui-primary-color; + } + + path:last-child { + fill: $simple-background-color; + } + } + + &:active, + &:focus, + &:hover { + svg path:first-child { + fill: lighten($ui-primary-color, 4%); + } + } + } + + .status__content, + .detailed-status__meta { + flex: 100%; } } } } } - -.button.button-secondary.logo-button { - position: absolute; - right: 14px; - top: 14px; - font-size: 14px; - - svg { - width: 20px; - height: auto; - vertical-align: middle; - margin-right: 5px; - - path:first-child { - fill: $ui-primary-color; - } - - path:last-child { - fill: $simple-background-color; - } - } - - &:active, - &:focus, - &:hover { - svg path:first-child { - fill: lighten($ui-primary-color, 4%); - } - } -} diff --git a/app/serializers/oembed_serializer.rb b/app/serializers/oembed_serializer.rb index 4f92930433..bd05da585a 100644 --- a/app/serializers/oembed_serializer.rb +++ b/app/serializers/oembed_serializer.rb @@ -40,8 +40,7 @@ class OEmbedSerializer < ActiveModel::Serializer attributes = { src: embed_short_account_status_url(object.account, object), class: 'mastodon-embed', - frameborder: '0', - scrolling: 'no', + style: 'max-width: 100%; border: none;', width: width, height: height, } diff --git a/app/views/stream_entries/_detailed_status.html.haml b/app/views/stream_entries/_detailed_status.html.haml index 107202b759..466087b6a0 100644 --- a/app/views/stream_entries/_detailed_status.html.haml +++ b/app/views/stream_entries/_detailed_status.html.haml @@ -1,9 +1,4 @@ .detailed-status.light - - if embedded_view? - = link_to "web+mastodon://follow?uri=#{status.account.local_username_and_domain}", class: 'button button-secondary logo-button', target: '_new' do - = render file: Rails.root.join('app', 'javascript', 'images', 'logo.svg') - = t('accounts.follow') - = link_to TagManager.instance.url_for(status.account), class: 'detailed-status__display-name p-author h-card', target: stream_link_target, rel: 'noopener' do %div .avatar @@ -12,6 +7,11 @@ %strong.p-name.emojify= display_name(status.account) %span= acct(status.account) + - if embedded_view? + = link_to "web+mastodon://follow?uri=#{status.account.local_username_and_domain}", class: 'button button-secondary logo-button', target: '_new' do + = render file: Rails.root.join('app', 'javascript', 'images', 'logo.svg') + = t('accounts.follow') + .status__content.p-name.emojify< - if status.spoiler_text? %p{ style: 'margin-bottom: 0' }< From 9b994c4aee379f7998d2ddb562a08ccff92e0b0b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 5 Sep 2017 17:48:13 +0200 Subject: [PATCH 19/31] Fix #4794 - Fake instant follow in API response when account is believed unlocked (#4799) --- app/controllers/api/v1/accounts_controller.rb | 10 ++++++++++ app/presenters/account_relationships_presenter.rb | 14 +++++++------- .../controllers/api/v1/accounts_controller_spec.rb | 7 +++++++ 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb index f621aa245d..656cacd8ab 100644 --- a/app/controllers/api/v1/accounts_controller.rb +++ b/app/controllers/api/v1/accounts_controller.rb @@ -14,6 +14,16 @@ class Api::V1::AccountsController < Api::BaseController def follow FollowService.new.call(current_user.account, @account.acct) + + unless @account.locked? + relationships = AccountRelationshipsPresenter.new( + [@account.id], + current_user.account_id, + following_map: { @account.id => true }, + requested_map: { @account.id => false } + ) + end + render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships end diff --git a/app/presenters/account_relationships_presenter.rb b/app/presenters/account_relationships_presenter.rb index 6578078639..a30558bace 100644 --- a/app/presenters/account_relationships_presenter.rb +++ b/app/presenters/account_relationships_presenter.rb @@ -4,12 +4,12 @@ class AccountRelationshipsPresenter attr_reader :following, :followed_by, :blocking, :muting, :requested, :domain_blocking - def initialize(account_ids, current_account_id) - @following = Account.following_map(account_ids, current_account_id) - @followed_by = Account.followed_by_map(account_ids, current_account_id) - @blocking = Account.blocking_map(account_ids, current_account_id) - @muting = Account.muting_map(account_ids, current_account_id) - @requested = Account.requested_map(account_ids, current_account_id) - @domain_blocking = Account.domain_blocking_map(account_ids, current_account_id) + def initialize(account_ids, current_account_id, options = {}) + @following = Account.following_map(account_ids, current_account_id).merge(options[:following_map] || {}) + @followed_by = Account.followed_by_map(account_ids, current_account_id).merge(options[:followed_by_map] || {}) + @blocking = Account.blocking_map(account_ids, current_account_id).merge(options[:blocking_map] || {}) + @muting = Account.muting_map(account_ids, current_account_id).merge(options[:muting_map] || {}) + @requested = Account.requested_map(account_ids, current_account_id).merge(options[:requested_map] || {}) + @domain_blocking = Account.domain_blocking_map(account_ids, current_account_id).merge(options[:domain_blocking_map] || {}) end end diff --git a/spec/controllers/api/v1/accounts_controller_spec.rb b/spec/controllers/api/v1/accounts_controller_spec.rb index c13509e7bb..05df2f8444 100644 --- a/spec/controllers/api/v1/accounts_controller_spec.rb +++ b/spec/controllers/api/v1/accounts_controller_spec.rb @@ -28,6 +28,13 @@ RSpec.describe Api::V1::AccountsController, type: :controller do expect(response).to have_http_status(:success) end + it 'returns JSON with following=true and requested=false' do + json = body_as_json + + expect(json[:following]).to be true + expect(json[:requested]).to be false + end + it 'creates a following relation between user and target user' do expect(user.account.following?(other_account)).to be true end From e821c00e743160474072e78483f568dc4fdc6887 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 5 Sep 2017 20:55:25 +0200 Subject: [PATCH 20/31] Fix mentions in direct statuses not being delivered via AP (#4806) --- app/services/process_mentions_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/process_mentions_service.rb b/app/services/process_mentions_service.rb index dc386c9e72..f123bf8697 100644 --- a/app/services/process_mentions_service.rb +++ b/app/services/process_mentions_service.rb @@ -41,7 +41,7 @@ class ProcessMentionsService < BaseService NotifyService.new.call(mentioned_account, mention) elsif mentioned_account.ostatus? && (Rails.configuration.x.use_ostatus_privacy || !status.stream_entry.hidden?) NotificationWorker.perform_async(stream_entry_to_xml(status.stream_entry), status.account_id, mentioned_account.id) - elsif mentioned_account.activitypub? && !mentioned_account.following?(status.account) + elsif mentioned_account.activitypub? ActivityPub::DeliveryWorker.perform_async(build_json(mention.status), mention.status.account_id, mentioned_account.inbox_url) end end From be7ffa2d7539d5a1946a3933cb9d242b9fac0ddc Mon Sep 17 00:00:00 2001 From: abcang Date: Wed, 6 Sep 2017 03:56:20 +0900 Subject: [PATCH 21/31] Do not execute the job with the same arguments as the retry job (#4814) --- app/workers/pubsubhubbub/subscribe_worker.rb | 2 +- config/application.rb | 1 + config/initializers/sidekiq.rb | 3 +++ lib/mastodon/unique_retry_job_middleware.rb | 20 ++++++++++++++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 lib/mastodon/unique_retry_job_middleware.rb diff --git a/app/workers/pubsubhubbub/subscribe_worker.rb b/app/workers/pubsubhubbub/subscribe_worker.rb index 7560c2671f..130c967e02 100644 --- a/app/workers/pubsubhubbub/subscribe_worker.rb +++ b/app/workers/pubsubhubbub/subscribe_worker.rb @@ -3,7 +3,7 @@ class Pubsubhubbub::SubscribeWorker include Sidekiq::Worker - sidekiq_options queue: 'push', retry: 10, unique: :until_executed, dead: false + sidekiq_options queue: 'push', retry: 10, unique: :until_executed, dead: false, unique_retry: true sidekiq_retry_in do |count| case count diff --git a/config/application.rb b/config/application.rb index b6ce741477..f98f7af167 100644 --- a/config/application.rb +++ b/config/application.rb @@ -10,6 +10,7 @@ require_relative '../app/lib/exceptions' require_relative '../lib/paperclip/gif_transcoder' require_relative '../lib/paperclip/video_transcoder' require_relative '../lib/mastodon/version' +require_relative '../lib/mastodon/unique_retry_job_middleware' Dotenv::Railtie.load diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb index b70784d79a..61e1313364 100644 --- a/config/initializers/sidekiq.rb +++ b/config/initializers/sidekiq.rb @@ -13,4 +13,7 @@ end Sidekiq.configure_client do |config| config.redis = redis_params + config.client_middleware do |chain| + chain.add Mastodon::UniqueRetryJobMiddleware + end end diff --git a/lib/mastodon/unique_retry_job_middleware.rb b/lib/mastodon/unique_retry_job_middleware.rb new file mode 100644 index 0000000000..75da8a0c94 --- /dev/null +++ b/lib/mastodon/unique_retry_job_middleware.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +class Mastodon::UniqueRetryJobMiddleware + def call(_worker_class, item, _queue, _redis_pool) + return if item['unique_retry'] && retried?(item) + yield + end + + private + + def retried?(item) + # Use unique digest key of SidekiqUniqueJobs + unique_key = SidekiqUniqueJobs::UNIQUE_DIGEST_KEY + unique_digest = item[unique_key] + class_name = item['class'] + retries = Sidekiq::RetrySet.new + + retries.any? { |job| job.item['class'] == class_name && job.item[unique_key] == unique_digest } + end +end From 6994664a1391d6a027caec3d5ca9e022f41a0711 Mon Sep 17 00:00:00 2001 From: Adam Thurlow Date: Tue, 5 Sep 2017 18:17:06 -0300 Subject: [PATCH 22/31] swift-enable the paperclip! :paperclip: (#2322) --- Gemfile | 1 + Gemfile.lock | 15 +++++++++++++++ app/helpers/routing_helper.rb | 8 +++++++- config/initializers/ostatus.rb | 1 + config/initializers/paperclip.rb | 15 +++++++++++++++ 5 files changed, 39 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index ae90697f1d..486e72cc4a 100644 --- a/Gemfile +++ b/Gemfile @@ -15,6 +15,7 @@ gem 'pghero', '~> 1.7' gem 'dotenv-rails', '~> 2.2' gem 'aws-sdk', '~> 2.9' +gem 'fog-openstack', '~> 0.1' gem 'paperclip', '~> 5.1' gem 'paperclip-av-transcoder', '~> 0.6' diff --git a/Gemfile.lock b/Gemfile.lock index 4a3f20e09d..ef99e0d7b3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -154,12 +154,25 @@ GEM erubis (2.7.0) et-orbi (1.0.5) tzinfo + excon (0.58.0) execjs (2.7.0) fabrication (2.16.2) faker (1.7.3) i18n (~> 0.5) fast_blank (1.0.0) ffi (1.9.18) + fog-core (1.45.0) + builder + excon (~> 0.58) + formatador (~> 0.2) + fog-json (1.0.2) + fog-core (~> 1.0) + multi_json (~> 1.10) + fog-openstack (0.1.21) + fog-core (>= 1.40) + fog-json (>= 1.0) + ipaddress (>= 0.8) + formatador (0.2.5) fuubar (2.2.0) rspec-core (~> 3.0) ruby-progressbar (~> 1.4) @@ -211,6 +224,7 @@ GEM rainbow (~> 2.2) terminal-table (>= 1.5.1) idn-ruby (0.1.0) + ipaddress (0.8.3) jmespath (1.3.1) json (2.1.0) json-ld (2.1.5) @@ -535,6 +549,7 @@ DEPENDENCIES fabrication (~> 2.16) faker (~> 1.7) fast_blank (~> 1.0) + fog-openstack (~> 0.1) fuubar (~> 2.2) goldfinger (~> 2.0) hamlit-rails (~> 0.2) diff --git a/app/helpers/routing_helper.rb b/app/helpers/routing_helper.rb index 1fbf77ec31..f4693358c7 100644 --- a/app/helpers/routing_helper.rb +++ b/app/helpers/routing_helper.rb @@ -12,8 +12,14 @@ module RoutingHelper end def full_asset_url(source, options = {}) - source = ActionController::Base.helpers.asset_url(source, options) unless Rails.configuration.x.use_s3 + source = ActionController::Base.helpers.asset_url(source, options) unless use_storage? URI.join(root_url, source).to_s end + + private + + def use_storage? + Rails.configuration.x.use_s3 || Rails.configuration.x.use_swift + end end diff --git a/config/initializers/ostatus.rb b/config/initializers/ostatus.rb index a885545f86..c00aba0ded 100644 --- a/config/initializers/ostatus.rb +++ b/config/initializers/ostatus.rb @@ -12,6 +12,7 @@ Rails.application.configure do config.x.web_domain = web_host config.x.use_https = https config.x.use_s3 = ENV['S3_ENABLED'] == 'true' + config.x.use_swift = ENV['SWIFT_ENABLED'] == 'true' config.x.alternate_domains = alternate_domains.split(/\s*,\s*/) diff --git a/config/initializers/paperclip.rb b/config/initializers/paperclip.rb index 740c1a953e..e9f455251b 100644 --- a/config/initializers/paperclip.rb +++ b/config/initializers/paperclip.rb @@ -40,6 +40,21 @@ if ENV['S3_ENABLED'] == 'true' Paperclip::Attachment.default_options[:url] = ':s3_alias_url' Paperclip::Attachment.default_options[:s3_host_alias] = ENV['S3_CLOUDFRONT_HOST'] end +elsif ENV['SWIFT_ENABLED'] == 'true' + Paperclip::Attachment.default_options.merge!( + path: ':class/:attachment/:id_partition/:style/:filename', + storage: :fog, + fog_credentials: { + provider: 'OpenStack', + openstack_username: ENV.fetch('SWIFT_USERNAME'), + openstack_tenant: ENV.fetch('SWIFT_TENANT'), + openstack_api_key: ENV.fetch('SWIFT_PASSWORD'), + openstack_auth_url: ENV.fetch('SWIFT_AUTH_URL'), + }, + fog_directory: ENV.fetch('SWIFT_CONTAINER'), + fog_host: ENV.fetch('SWIFT_OBJECT_URL'), + fog_public: true + ) else Paperclip::Attachment.default_options[:path] = (ENV['PAPERCLIP_ROOT_PATH'] || ':rails_root/public/system') + '/:class/:attachment/:id_partition/:style/:filename' Paperclip::Attachment.default_options[:url] = (ENV['PAPERCLIP_ROOT_URL'] || '/system') + '/:class/:attachment/:id_partition/:style/:filename' From fa21d004c7d8ea1c76d1106700f4e18a703e39fd Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Wed, 6 Sep 2017 19:13:00 +0900 Subject: [PATCH 23/31] Add environment sample for OpenStack Swift (#4816) --- .env.production.sample | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.env.production.sample b/.env.production.sample index 07c8876923..3e054db844 100644 --- a/.env.production.sample +++ b/.env.production.sample @@ -98,6 +98,15 @@ SMTP_FROM_ADDRESS=notifications@example.com # S3_ENDPOINT= # S3_SIGNATURE_VERSION= +# Swift (optional) +# SWIFT_ENABLED=true +# SWIFT_USERNAME= +# SWIFT_TENANT= +# SWIFT_PASSWORD= +# SWIFT_AUTH_URL= +# SWIFT_CONTAINER= +# SWIFT_OBJECT_URL= + # Optional alias for S3 if you want to use Cloudfront or Cloudflare in front # S3_CLOUDFRONT_HOST= From d8d2a5474148c38ddc5754fc5d7cbf8083bab3bf Mon Sep 17 00:00:00 2001 From: PFM Date: Wed, 6 Sep 2017 20:55:47 +0900 Subject: [PATCH 24/31] fix text position of NSFW for video file (#4819) --- .../mastodon/components/video_player.js | 4 ++-- app/javascript/styles/components.scss | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/app/javascript/mastodon/components/video_player.js b/app/javascript/mastodon/components/video_player.js index 999cf42d9e..2c834fb665 100644 --- a/app/javascript/mastodon/components/video_player.js +++ b/app/javascript/mastodon/components/video_player.js @@ -146,7 +146,7 @@ export default class VideoPlayer extends React.PureComponent { if (!this.state.visible) { if (sensitive) { return ( -
+
{spoilerButton} @@ -154,7 +154,7 @@ export default class VideoPlayer extends React.PureComponent { ); } else { return ( -
+
{spoilerButton} diff --git a/app/javascript/styles/components.scss b/app/javascript/styles/components.scss index 1b9763e90a..bd7d0c3d48 100644 --- a/app/javascript/styles/components.scss +++ b/app/javascript/styles/components.scss @@ -2343,6 +2343,22 @@ button.icon-button.active i.fa-retweet { height: 100%; } +.media-spoiler__video { + align-items: center; + background: $base-overlay-background; + color: $primary-text-color; + cursor: pointer; + display: flex; + flex-direction: column; + border: 0; + width: 100%; + height: 100%; + justify-content: center; + position: relative; + text-align: center; + z-index: 100; +} + .media-spoiler__warning { display: block; font-size: 14px; From e0cda4a851e03e671aaaa81117c615ca6a5be3a8 Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Wed, 6 Sep 2017 23:25:19 +0900 Subject: [PATCH 25/31] Update react-intl to version 2.4.0 (#4820) --- package.json | 2 +- yarn.lock | 24 +++++++++--------------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index 5fdd491ee7..228dd1f257 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "react-dom": "^15.6.1", "react-immutable-proptypes": "^2.1.0", "react-immutable-pure-component": "^1.0.0", - "react-intl": "^2.3.0", + "react-intl": "^2.4.0", "react-motion": "^0.5.0", "react-notification": "^6.7.1", "react-redux": "^5.0.4", diff --git a/yarn.lock b/yarn.lock index cfb0f51752..c1c27a615c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3130,23 +3130,17 @@ intl-messageformat-parser@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-1.3.0.tgz#c5d26ffb894c7d9c2b9fa444c67f417ab2594268" -intl-messageformat@1.3.0, intl-messageformat@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-1.3.0.tgz#f7d926aded7a3ab19b2dc601efd54e99a4bd4eae" - dependencies: - intl-messageformat-parser "1.2.0" - intl-messageformat@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-2.0.0.tgz#3d56982583425aee23b76c8b985fb9b0aae5be3c" dependencies: intl-messageformat-parser "1.2.0" -intl-relativeformat@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/intl-relativeformat/-/intl-relativeformat-1.3.0.tgz#893dc7076fccd380cf091a2300c380fa57ace45b" +intl-messageformat@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-2.1.0.tgz#1c51da76f02a3f7b360654cdc51bbc4d3fa6c72c" dependencies: - intl-messageformat "1.3.0" + intl-messageformat-parser "1.2.0" intl-relativeformat@^2.0.0: version "2.0.0" @@ -5312,13 +5306,13 @@ react-intl-translations-manager@^5.0.0: json-stable-stringify "^1.0.1" mkdirp "^0.5.1" -react-intl@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-2.3.0.tgz#e1df6af5667fdf01cbe4aab20e137251e2ae5142" +react-intl@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-2.4.0.tgz#66c14dc9df9a73b2fbbfbd6021726e80a613eb15" dependencies: intl-format-cache "^2.0.5" - intl-messageformat "^1.3.0" - intl-relativeformat "^1.3.0" + intl-messageformat "^2.1.0" + intl-relativeformat "^2.0.0" invariant "^2.1.1" react-motion@^0.5.0: From 1646f622a53f0308738c7927ebaaf8d216b69f3e Mon Sep 17 00:00:00 2001 From: Clworld Date: Thu, 7 Sep 2017 00:29:56 +0900 Subject: [PATCH 26/31] fix scroll position (#4821) --- app/javascript/mastodon/components/scrollable_list.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/javascript/mastodon/components/scrollable_list.js b/app/javascript/mastodon/components/scrollable_list.js index 1a122dbe58..e47b1e9aa5 100644 --- a/app/javascript/mastodon/components/scrollable_list.js +++ b/app/javascript/mastodon/components/scrollable_list.js @@ -5,6 +5,7 @@ import IntersectionObserverArticle from './intersection_observer_article'; import LoadMore from './load_more'; import IntersectionObserverWrapper from '../features/ui/util/intersection_observer_wrapper'; import { throttle } from 'lodash'; +import { List as ImmutableList } from 'immutable'; export default class ScrollableList extends PureComponent { @@ -95,7 +96,12 @@ export default class ScrollableList extends PureComponent { getFirstChildKey (props) { const { children } = props; - const firstChild = Array.isArray(children) ? children[0] : children; + let firstChild = children; + if (children instanceof ImmutableList) { + firstChild = children.get(0); + } else if (Array.isArray(children)) { + firstChild = children[0]; + } return firstChild && firstChild.key; } From aec5097d44212455e3662c77f6b3f1f76e2570d6 Mon Sep 17 00:00:00 2001 From: Masoud Abkenar Date: Wed, 6 Sep 2017 17:31:54 +0200 Subject: [PATCH 27/31] i18n: update Persian translation (#4822) --- app/javascript/mastodon/locales/fa.json | 10 +++++----- config/locales/doorkeeper.fa.yml | 18 ++++++++++++------ 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json index b51340fa74..d05b26eb9f 100644 --- a/app/javascript/mastodon/locales/fa.json +++ b/app/javascript/mastodon/locales/fa.json @@ -63,8 +63,8 @@ "confirmations.mute.message": "آیا واقعاً می‌خواهید {name} را بی‌صدا کنید؟", "confirmations.unfollow.confirm": "لغو پیگیری", "confirmations.unfollow.message": "آیا واقعاً می‌خواهید به پیگیری از {name} پایان دهید؟", - "embed.instructions": "Embed this status on your website by copying the code below.", - "embed.preview": "Here is what it will look like:", + "embed.instructions": "برای جاگذاری این نوشته در سایت خودتان، کد زیر را کپی کنید.", + "embed.preview": "نوشتهٔ جاگذاری‌شده این گونه به نظر خواهد رسید:", "emoji_button.activity": "فعالیت", "emoji_button.flags": "پرچم‌ها", "emoji_button.food": "غذا و نوشیدنی", @@ -164,14 +164,14 @@ "standalone.public_title": "نگاهی به کاربران این سرور...", "status.cannot_reblog": "این نوشته را نمی‌شود بازبوقید", "status.delete": "پاک‌کردن", - "status.embed": "Embed", + "status.embed": "جاگذاری", "status.favourite": "پسندیدن", "status.load_more": "بیشتر نشان بده", "status.media_hidden": "تصویر پنهان شده", "status.mention": "نام‌بردن از @{name}", "status.mute_conversation": "بی‌صداکردن گفتگو", "status.open": "این نوشته را باز کن", - "status.pin": "Pin on profile", + "status.pin": "نوشتهٔ ثابت نمایه", "status.reblog": "بازبوقیدن", "status.reblogged_by": "‫{name}‬ بازبوقید", "status.reply": "پاسخ", @@ -183,7 +183,7 @@ "status.show_less": "نهفتن", "status.show_more": "نمایش", "status.unmute_conversation": "باصداکردن گفتگو", - "status.unpin": "Unpin from profile", + "status.unpin": "برداشتن نوشتهٔ ثابت نمایه", "tabs_bar.compose": "بنویسید", "tabs_bar.federated_timeline": "همگانی", "tabs_bar.home": "خانه", diff --git a/config/locales/doorkeeper.fa.yml b/config/locales/doorkeeper.fa.yml index 33f453a3f0..3435805307 100644 --- a/config/locales/doorkeeper.fa.yml +++ b/config/locales/doorkeeper.fa.yml @@ -3,8 +3,10 @@ fa: activerecord: attributes: doorkeeper/application: - name: Name + name: Application name redirect_uri: Redirect URI + scopes: Scopes + website: Application website errors: models: doorkeeper/application: @@ -33,18 +35,22 @@ fa: redirect_uri: Use one line per URI scopes: Separate scopes with spaces. Leave blank to use the default scopes. index: + application: Application callback_url: Callback URL + delete: Delete name: Name - new: New Application + new: New application + scopes: Scopes + show: Show title: Your applications new: - title: New Application + title: New application show: actions: Actions - application_id: Application Id - callback_urls: Callback urls + application_id: Client key + callback_urls: Callback URLs scopes: Scopes - secret: Secret + secret: Client secret title: 'Application: %{name}' authorizations: buttons: From 13ffa3c59e1a2727b287b2e6cde47f39c14ae815 Mon Sep 17 00:00:00 2001 From: voidSatisfaction Date: Thu, 7 Sep 2017 00:32:15 +0900 Subject: [PATCH 28/31] Add Smartphone screen favourite back button and adjust styles (#4813) * Feat add get-back button on favourite columnHeader * Style adjust nice looking get-back button * Fix delete media query and add padding right * fix: restore padding and add lastchild style for back-button --- app/javascript/mastodon/features/favourited_statuses/index.js | 1 + app/javascript/styles/components.scss | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/app/javascript/mastodon/features/favourited_statuses/index.js b/app/javascript/mastodon/features/favourited_statuses/index.js index 82b16b3698..1e1f5873c2 100644 --- a/app/javascript/mastodon/features/favourited_statuses/index.js +++ b/app/javascript/mastodon/features/favourited_statuses/index.js @@ -77,6 +77,7 @@ export default class Favourites extends ImmutablePureComponent { onClick={this.handleHeaderClick} pinned={pinned} multiColumn={multiColumn} + showBackButton /> Date: Wed, 6 Sep 2017 19:01:28 +0200 Subject: [PATCH 29/31] Switch to static URIs, new URI format in both protocols for new statuses (#4815) * Decouple Status#local? from uri being nil * Replace on-the-fly URI generation with stored URIs - Generate URI in after_save hook for local statuses - Use static value in TagManager when available, fallback to tag format - Make TagManager use ActivityPub::TagManager to understand new format - Adjust tests * Use other heuristic for locality of old statuses, do not perform long query * Exclude tombstone stream entries from Atom feed * Prevent nil statuses from landing in Pubsubhubbub::DistributionWorker * Fix URI not being saved (#4818) * Add more specs for Status * Save generated uri immediately and also fix method order to minimize diff. * Fix alternate HTML URL in Atom * Fix tests * Remove not-null constraint from statuses migration to speed it up --- app/controllers/accounts_controller.rb | 2 +- app/lib/ostatus/atom_serializer.rb | 4 +-- app/lib/tag_manager.rb | 13 +++++--- app/models/status.rb | 14 ++++++++- .../pubsubhubbub/distribution_worker.rb | 2 +- .../20170905165803_add_local_to_statuses.rb | 5 +++ db/schema.rb | 3 +- spec/fabricators/status_fabricator.rb | 4 +++ spec/lib/activitypub/activity/delete_spec.rb | 2 +- spec/lib/activitypub/activity/undo_spec.rb | 2 +- spec/lib/formatter_spec.rb | 4 +-- spec/lib/ostatus/atom_serializer_spec.rb | 31 +++++++++---------- spec/lib/tag_manager_spec.rb | 15 ++------- spec/models/status_spec.rb | 27 ++++++++++++++-- spec/services/fetch_link_card_service_spec.rb | 2 +- 15 files changed, 84 insertions(+), 46 deletions(-) create mode 100644 db/migrate/20170905165803_add_local_to_statuses.rb diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index afa0417fa3..26ab6636b5 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -22,7 +22,7 @@ class AccountsController < ApplicationController format.atom do @entries = @account.stream_entries.where(hidden: false).with_includes.paginate_by_max_id(20, params[:max_id], params[:since_id]) - render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.feed(@account, @entries.to_a)) + render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.feed(@account, @entries.reject { |entry| entry.status.nil? })) end format.json do diff --git a/app/lib/ostatus/atom_serializer.rb b/app/lib/ostatus/atom_serializer.rb index 81fae4140e..b8e22a3813 100644 --- a/app/lib/ostatus/atom_serializer.rb +++ b/app/lib/ostatus/atom_serializer.rb @@ -65,7 +65,7 @@ class OStatus::AtomSerializer add_namespaces(entry) if root - append_element(entry, 'id', TagManager.instance.unique_tag(stream_entry.created_at, stream_entry.activity_id, stream_entry.activity_type)) + append_element(entry, 'id', TagManager.instance.uri_for(stream_entry.status)) append_element(entry, 'published', stream_entry.created_at.iso8601) append_element(entry, 'updated', stream_entry.updated_at.iso8601) append_element(entry, 'title', stream_entry&.status&.title || "#{stream_entry.account.acct} deleted status") @@ -86,7 +86,7 @@ class OStatus::AtomSerializer serialize_status_attributes(entry, stream_entry.status) end - append_element(entry, 'link', nil, rel: :alternate, type: 'text/html', href: account_stream_entry_url(stream_entry.account, stream_entry)) + append_element(entry, 'link', nil, rel: :alternate, type: 'text/html', href: TagManager.instance.url_for(stream_entry.status)) append_element(entry, 'link', nil, rel: :self, type: 'application/atom+xml', href: account_stream_entry_url(stream_entry.account, stream_entry, format: 'atom')) append_element(entry, 'thr:in-reply-to', nil, ref: TagManager.instance.uri_for(stream_entry.thread), href: TagManager.instance.url_for(stream_entry.thread)) if stream_entry.threaded? append_element(entry, 'ostatus:conversation', nil, ref: conversation_uri(stream_entry.status.conversation)) unless stream_entry&.status&.conversation_id.nil? diff --git a/app/lib/tag_manager.rb b/app/lib/tag_manager.rb index 5f87a2a48d..f33a20c6f7 100644 --- a/app/lib/tag_manager.rb +++ b/app/lib/tag_manager.rb @@ -49,12 +49,17 @@ class TagManager def unique_tag_to_local_id(tag, expected_type) return nil unless local_id?(tag) - matches = Regexp.new("objectId=([\\d]+):objectType=#{expected_type}").match(tag) - return matches[1] unless matches.nil? + + if ActivityPub::TagManager.instance.local_uri?(tag) + ActivityPub::TagManager.instance.uri_to_local_id(tag) + else + matches = Regexp.new("objectId=([\\d]+):objectType=#{expected_type}").match(tag) + return matches[1] unless matches.nil? + end end def local_id?(id) - id.start_with?("tag:#{Rails.configuration.x.local_domain}") + id.start_with?("tag:#{Rails.configuration.x.local_domain}") || ActivityPub::TagManager.instance.local_uri?(id) end def web_domain?(domain) @@ -92,7 +97,7 @@ class TagManager when :person account_url(target) when :note, :comment, :activity - unique_tag(target.created_at, target.id, 'Status') + target.uri || unique_tag(target.created_at, target.id, 'Status') end end diff --git a/app/models/status.rb b/app/models/status.rb index f44f79aafd..53eff0377e 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -22,6 +22,7 @@ # reblogs_count :integer default(0), not null # language :string # conversation_id :integer +# local :boolean default(FALSE) # class Status < ApplicationRecord @@ -84,7 +85,7 @@ class Status < ApplicationRecord end def local? - uri.nil? + attributes['local'] || uri.nil? end def reblog? @@ -131,11 +132,14 @@ class Status < ApplicationRecord !sensitive? && media_attachments.any? end + after_create :store_uri, if: :local? + before_validation :prepare_contents, if: :local? before_validation :set_reblog before_validation :set_visibility before_validation :set_conversation before_validation :set_sensitivity + before_validation :set_local class << self def not_in_filtered_languages(account) @@ -253,6 +257,10 @@ class Status < ApplicationRecord private + def store_uri + update_attribute(:uri, ActivityPub::TagManager.instance.uri_for(self)) if uri.nil? + end + def prepare_contents text&.strip! spoiler_text&.strip! @@ -292,4 +300,8 @@ class Status < ApplicationRecord thread.account_id end end + + def set_local + self.local = account.local? + end end diff --git a/app/workers/pubsubhubbub/distribution_worker.rb b/app/workers/pubsubhubbub/distribution_worker.rb index 2a5e60fa0e..524f6849fc 100644 --- a/app/workers/pubsubhubbub/distribution_worker.rb +++ b/app/workers/pubsubhubbub/distribution_worker.rb @@ -6,7 +6,7 @@ class Pubsubhubbub::DistributionWorker sidekiq_options queue: 'push' def perform(stream_entry_ids) - stream_entries = StreamEntry.where(id: stream_entry_ids).includes(:status).reject { |e| e.status&.direct_visibility? } + stream_entries = StreamEntry.where(id: stream_entry_ids).includes(:status).reject { |e| e.status.nil? || e.status.direct_visibility? } return if stream_entries.empty? diff --git a/db/migrate/20170905165803_add_local_to_statuses.rb b/db/migrate/20170905165803_add_local_to_statuses.rb new file mode 100644 index 0000000000..e89a0469de --- /dev/null +++ b/db/migrate/20170905165803_add_local_to_statuses.rb @@ -0,0 +1,5 @@ +class AddLocalToStatuses < ActiveRecord::Migration[5.1] + def change + add_column :statuses, :local, :boolean, null: true, default: false + end +end diff --git a/db/schema.rb b/db/schema.rb index ea7edc2f9c..21bde2086b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170905044538) do +ActiveRecord::Schema.define(version: 20170905165803) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -315,6 +315,7 @@ ActiveRecord::Schema.define(version: 20170905044538) do t.integer "reblogs_count", default: 0, null: false t.string "language" t.bigint "conversation_id" + t.boolean "local", default: false t.index ["account_id", "id"], name: "index_statuses_on_account_id_id" t.index ["conversation_id"], name: "index_statuses_on_conversation_id" t.index ["in_reply_to_id"], name: "index_statuses_on_in_reply_to_id" diff --git a/spec/fabricators/status_fabricator.rb b/spec/fabricators/status_fabricator.rb index 8ec5f4ba79..04bbbcf4b0 100644 --- a/spec/fabricators/status_fabricator.rb +++ b/spec/fabricators/status_fabricator.rb @@ -1,4 +1,8 @@ Fabricator(:status) do account text "Lorem ipsum dolor sit amet" + + after_build do |status| + status.uri = Faker::Internet.device_token if !status.account.local? && status.uri.nil? + end end diff --git a/spec/lib/activitypub/activity/delete_spec.rb b/spec/lib/activitypub/activity/delete_spec.rb index 65e743abb2..38254e31c3 100644 --- a/spec/lib/activitypub/activity/delete_spec.rb +++ b/spec/lib/activitypub/activity/delete_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' RSpec.describe ActivityPub::Activity::Delete do - let(:sender) { Fabricate(:account) } + let(:sender) { Fabricate(:account, domain: 'example.com') } let(:status) { Fabricate(:status, account: sender, uri: 'foobar') } let(:json) do diff --git a/spec/lib/activitypub/activity/undo_spec.rb b/spec/lib/activitypub/activity/undo_spec.rb index 4629a033f2..14c68efe5f 100644 --- a/spec/lib/activitypub/activity/undo_spec.rb +++ b/spec/lib/activitypub/activity/undo_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' RSpec.describe ActivityPub::Activity::Undo do - let(:sender) { Fabricate(:account) } + let(:sender) { Fabricate(:account, domain: 'example.com') } let(:json) do { diff --git a/spec/lib/formatter_spec.rb b/spec/lib/formatter_spec.rb index dfe1d8b8fe..ab04ccbabb 100644 --- a/spec/lib/formatter_spec.rb +++ b/spec/lib/formatter_spec.rb @@ -178,7 +178,7 @@ RSpec.describe Formatter do end context 'with remote status' do - let(:status) { Fabricate(:status, text: 'Beep boop', uri: 'beepboop') } + let(:status) { Fabricate(:status, account: remote_account, text: 'Beep boop') } it 'reformats' do is_expected.to eq 'Beep boop' @@ -226,7 +226,7 @@ RSpec.describe Formatter do end context 'with remote status' do - let(:status) { Fabricate(:status, text: '', uri: 'beep boop') } + let(:status) { Fabricate(:status, account: remote_account, text: '') } it 'returns tag-stripped text' do is_expected.to eq '' diff --git a/spec/lib/ostatus/atom_serializer_spec.rb b/spec/lib/ostatus/atom_serializer_spec.rb index 301a0ce30d..0451eceeb4 100644 --- a/spec/lib/ostatus/atom_serializer_spec.rb +++ b/spec/lib/ostatus/atom_serializer_spec.rb @@ -403,8 +403,7 @@ RSpec.describe OStatus::AtomSerializer do it 'returns element whose rendered view triggers creation when processed' do remote_account = Account.create!(username: 'username') - remote_status = Fabricate(:status, account: remote_account) - remote_status.stream_entry.update!(created_at: '2000-01-01T00:00:00Z') + remote_status = Fabricate(:status, account: remote_account, created_at: '2000-01-01T00:00:00Z') entry = OStatus::AtomSerializer.new.entry(remote_status.stream_entry, true) entry.nodes.delete_if { |node| node[:type] == 'application/activity+json' } # Remove ActivityPub link to simplify test @@ -421,7 +420,7 @@ RSpec.describe OStatus::AtomSerializer do ProcessFeedService.new.call(xml, account) - expect(Status.find_by(uri: "tag:remote,2000-01-01:objectId=#{remote_status.id}:objectType=Status")).to be_instance_of Status + expect(Status.find_by(uri: "https://remote/users/#{remote_status.account.to_param}/statuses/#{remote_status.id}")).to be_instance_of Status end end @@ -465,12 +464,11 @@ RSpec.describe OStatus::AtomSerializer do end it 'appends id element with unique tag' do - status = Fabricate(:status, reblog_of_id: nil) - status.stream_entry.update!(created_at: '2000-01-01T00:00:00Z') + status = Fabricate(:status, reblog_of_id: nil, created_at: '2000-01-01T00:00:00Z') entry = OStatus::AtomSerializer.new.entry(status.stream_entry) - expect(entry.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.id}:objectType=Status" + expect(entry.id.text).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}" end it 'appends published element with created date' do @@ -515,7 +513,7 @@ RSpec.describe OStatus::AtomSerializer do entry = OStatus::AtomSerializer.new.entry(reblog.stream_entry) object = entry.nodes.find { |node| node.name == 'activity:object' } - expect(object.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{reblogged.id}:objectType=Status" + expect(object.id.text).to eq "https://cb6e6126.ngrok.io/users/#{reblogged.account.to_param}/statuses/#{reblogged.id}" end it 'does not append activity:object element if target is not present' do @@ -532,7 +530,7 @@ RSpec.describe OStatus::AtomSerializer do link = entry.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' && node[:type] == 'text/html' } expect(link[:type]).to eq 'text/html' - expect(link[:href]).to eq "https://cb6e6126.ngrok.io/users/username/updates/#{status.stream_entry.id}" + expect(link[:href]).to eq "https://cb6e6126.ngrok.io/@username/#{status.id}" end it 'appends link element for itself' do @@ -553,7 +551,7 @@ RSpec.describe OStatus::AtomSerializer do entry = OStatus::AtomSerializer.new.entry(reply_status.stream_entry) in_reply_to = entry.nodes.find { |node| node.name == 'thr:in-reply-to' } - expect(in_reply_to[:ref]).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{in_reply_to_status.id}:objectType=Status" + expect(in_reply_to[:ref]).to eq "https://cb6e6126.ngrok.io/users/#{in_reply_to_status.account.to_param}/statuses/#{in_reply_to_status.id}" end it 'does not append thr:in-reply-to element if not threaded' do @@ -934,7 +932,7 @@ RSpec.describe OStatus::AtomSerializer do favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite) object = favourite_salmon.nodes.find { |node| node.name == 'activity:object' } - expect(object.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.id}:objectType=Status" + expect(object.id.text).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}" end it 'appends thr:in-reply-to element for status' do @@ -945,7 +943,7 @@ RSpec.describe OStatus::AtomSerializer do favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite) in_reply_to = favourite_salmon.nodes.find { |node| node.name == 'thr:in-reply-to' } - expect(in_reply_to.ref).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.id}:objectType=Status" + expect(in_reply_to.ref).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}" expect(in_reply_to.href).to eq "https://cb6e6126.ngrok.io/@username/#{status.id}" end @@ -1034,7 +1032,7 @@ RSpec.describe OStatus::AtomSerializer do unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite) object = unfavourite_salmon.nodes.find { |node| node.name == 'activity:object' } - expect(object.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.id}:objectType=Status" + expect(object.id.text).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}" end it 'appends thr:in-reply-to element for status' do @@ -1045,7 +1043,7 @@ RSpec.describe OStatus::AtomSerializer do unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite) in_reply_to = unfavourite_salmon.nodes.find { |node| node.name == 'thr:in-reply-to' } - expect(in_reply_to.ref).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.id}:objectType=Status" + expect(in_reply_to.ref).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}" expect(in_reply_to.href).to eq "https://cb6e6126.ngrok.io/@username/#{status.id}" end @@ -1453,7 +1451,7 @@ RSpec.describe OStatus::AtomSerializer do it 'appends id element with URL for status' do status = Fabricate(:status, created_at: '2000-01-01T00:00:00Z') object = OStatus::AtomSerializer.new.object(status) - expect(object.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.id}:objectType=Status" + expect(object.id.text).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}" end it 'appends published element with created date' do @@ -1463,7 +1461,8 @@ RSpec.describe OStatus::AtomSerializer do end it 'appends updated element with updated date' do - status = Fabricate(:status, updated_at: '2000-01-01T00:00:00Z') + status = Fabricate(:status) + status.updated_at = '2000-01-01T00:00:00Z' object = OStatus::AtomSerializer.new.object(status) expect(object.updated.text).to eq '2000-01-01T00:00:00Z' end @@ -1523,7 +1522,7 @@ RSpec.describe OStatus::AtomSerializer do entry = OStatus::AtomSerializer.new.object(reply) in_reply_to = entry.nodes.find { |node| node.name == 'thr:in-reply-to' } - expect(in_reply_to.ref).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{thread.id}:objectType=Status" + expect(in_reply_to.ref).to eq "https://cb6e6126.ngrok.io/users/#{thread.account.to_param}/statuses/#{thread.id}" expect(in_reply_to.href).to eq "https://cb6e6126.ngrok.io/@username/#{thread.id}" end diff --git a/spec/lib/tag_manager_spec.rb b/spec/lib/tag_manager_spec.rb index 1fae6bec45..1cd6e0a6fe 100644 --- a/spec/lib/tag_manager_spec.rb +++ b/spec/lib/tag_manager_spec.rb @@ -157,23 +157,12 @@ RSpec.describe TagManager do describe '#uri_for' do subject { TagManager.instance.uri_for(target) } - context 'activity object' do - let(:target) { Fabricate(:status, reblog: Fabricate(:status)).stream_entry } - - before { target.update!(created_at: '2000-01-01T00:00:00Z') } - - it 'returns the unique tag for status' do - expect(target.object_type).to eq :activity - is_expected.to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{target.id}:objectType=Status" - end - end - context 'comment object' do let(:target) { Fabricate(:status, created_at: '2000-01-01T00:00:00Z', reply: true) } it 'returns the unique tag for status' do expect(target.object_type).to eq :comment - is_expected.to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{target.id}:objectType=Status" + is_expected.to eq target.uri end end @@ -182,7 +171,7 @@ RSpec.describe TagManager do it 'returns the unique tag for status' do expect(target.object_type).to eq :note - is_expected.to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{target.id}:objectType=Status" + is_expected.to eq target.uri end end diff --git a/spec/models/status_spec.rb b/spec/models/status_spec.rb index 626fc3f985..484effd5e1 100644 --- a/spec/models/status_spec.rb +++ b/spec/models/status_spec.rb @@ -13,9 +13,15 @@ RSpec.describe Status, type: :model do end it 'returns false if a remote URI is set' do - subject.uri = 'a' + alice.update(domain: 'example.com') + subject.save expect(subject.local?).to be false end + + it 'returns true if a URI is set and `local` is true' do + subject.update(uri: 'example.com', local: true) + expect(subject.local?).to be true + end end describe '#reblog?' do @@ -495,7 +501,7 @@ RSpec.describe Status, type: :model do end end - describe 'before_create' do + describe 'before_validation' do it 'sets account being replied to correctly over intermediary nodes' do first_status = Fabricate(:status, account: bob) intermediary = Fabricate(:status, thread: first_status, account: alice) @@ -512,5 +518,22 @@ RSpec.describe Status, type: :model do parent = Fabricate(:status, text: 'First') expect(Status.create(account: alice, thread: parent, text: 'Response').conversation_id).to eq parent.conversation_id end + + it 'sets `local` to true for status by local account' do + expect(Status.create(account: alice, text: 'foo').local).to be true + end + + it 'sets `local` to false for status by remote account' do + alice.update(domain: 'example.com') + expect(Status.create(account: alice, text: 'foo').local).to be false + end + end + + describe 'after_create' do + it 'saves ActivityPub uri as uri for local status' do + status = Status.create(account: alice, text: 'foo') + status.reload + expect(status.uri).to start_with('https://') + end end end diff --git a/spec/services/fetch_link_card_service_spec.rb b/spec/services/fetch_link_card_service_spec.rb index 3a0786d03c..b0aa740ac9 100644 --- a/spec/services/fetch_link_card_service_spec.rb +++ b/spec/services/fetch_link_card_service_spec.rb @@ -55,7 +55,7 @@ RSpec.describe FetchLinkCardService do end context 'in a remote status' do - let(:status) { Fabricate(:status, uri: 'abc', text: 'Habt ihr ein paar gute Links zu #Wannacry herumfliegen? Ich will mal unter
https://github.com/qbi/WannaCry was sammeln. !security ') } + let(:status) { Fabricate(:status, account: Fabricate(:account, domain: 'example.com'), text: 'Habt ihr ein paar gute Links zu #Wannacry herumfliegen? Ich will mal unter
https://github.com/qbi/WannaCry was sammeln. !security ') } it 'parses out URLs' do expect(a_request(:head, 'https://github.com/qbi/WannaCry')).to have_been_made.at_least_once From dd5cb5085c35516163c7cce1289c4bd81c936a28 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 6 Sep 2017 19:02:03 +0200 Subject: [PATCH 30/31] Bump version to 1.6.0rc2 --- lib/mastodon/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index b5fa476dc2..de2516d6c2 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -21,7 +21,7 @@ module Mastodon end def flags - 'rc1' + 'rc2' end def to_a From 11bddd31ce33b654ef72b00221715e6026486e7c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 6 Sep 2017 20:57:52 +0200 Subject: [PATCH 31/31] Fix locking migration on statuses table. Nullable column and NO default value (#4825) --- app/models/status.rb | 2 +- db/migrate/20170905165803_add_local_to_statuses.rb | 2 +- db/schema.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/status.rb b/app/models/status.rb index 53eff0377e..fdc230d8f6 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -22,7 +22,7 @@ # reblogs_count :integer default(0), not null # language :string # conversation_id :integer -# local :boolean default(FALSE) +# local :boolean # class Status < ApplicationRecord diff --git a/db/migrate/20170905165803_add_local_to_statuses.rb b/db/migrate/20170905165803_add_local_to_statuses.rb index e89a0469de..fb4e7019df 100644 --- a/db/migrate/20170905165803_add_local_to_statuses.rb +++ b/db/migrate/20170905165803_add_local_to_statuses.rb @@ -1,5 +1,5 @@ class AddLocalToStatuses < ActiveRecord::Migration[5.1] def change - add_column :statuses, :local, :boolean, null: true, default: false + add_column :statuses, :local, :boolean, null: true, default: nil end end diff --git a/db/schema.rb b/db/schema.rb index 21bde2086b..d8af0a1f8e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -315,7 +315,7 @@ ActiveRecord::Schema.define(version: 20170905165803) do t.integer "reblogs_count", default: 0, null: false t.string "language" t.bigint "conversation_id" - t.boolean "local", default: false + t.boolean "local" t.index ["account_id", "id"], name: "index_statuses_on_account_id_id" t.index ["conversation_id"], name: "index_statuses_on_conversation_id" t.index ["in_reply_to_id"], name: "index_statuses_on_in_reply_to_id"