From cbc2e6bd4094bf2e9d3bf71d7150b8a46cba171b Mon Sep 17 00:00:00 2001 From: ThibG Date: Sat, 11 Aug 2018 18:00:41 +0200 Subject: [PATCH 01/24] Make some migration script more robust (fixes #8007) (#8170) Include a dummy Account class in the migration script containing only the attributes relevant to the migration in order to not rely as much on the codebase being in sync with the database schema. --- db/migrate/20180528141303_fix_accounts_unique_index.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/db/migrate/20180528141303_fix_accounts_unique_index.rb b/db/migrate/20180528141303_fix_accounts_unique_index.rb index 96cee37f9cb..624ea229e4f 100644 --- a/db/migrate/20180528141303_fix_accounts_unique_index.rb +++ b/db/migrate/20180528141303_fix_accounts_unique_index.rb @@ -1,4 +1,13 @@ class FixAccountsUniqueIndex < ActiveRecord::Migration[5.2] + class Account < ApplicationRecord + # Dummy class, to make migration possible across version changes + has_one :user, inverse_of: :account + + def local? + domain.nil? + end + end + disable_ddl_transaction! def up From 38e39c9366d16ccb6536b4de5164e76684ff500b Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Sun, 12 Aug 2018 04:59:23 +0900 Subject: [PATCH 02/24] Weblate translations (2018-08-12) (#8171) * Translated using Weblate (Japanese) Currently translated at 100.0% (307 of 307 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/ja/ * Translated using Weblate (Japanese) Currently translated at 98.5% (657 of 667 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ja/ * Translated using Weblate (Japanese) Currently translated at 98.5% (657 of 667 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ja/ * Translated using Weblate (Japanese) Currently translated at 99.8% (666 of 667 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ja/ * Translated using Weblate (Czech) Currently translated at 100.0% (307 of 307 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/cs/ * Translated using Weblate (Czech) Currently translated at 98.5% (657 of 667 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/cs/ * Translated using Weblate (Czech) Currently translated at 100.0% (307 of 307 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/cs/ * Translated using Weblate (Czech) Currently translated at 99.8% (666 of 667 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/cs/ * Translated using Weblate (Czech) Currently translated at 100.0% (2 of 2 strings) Translation: Mastodon/Activerecord Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/activerecord/cs/ * Translated using Weblate (Czech) Currently translated at 61.2% (38 of 62 strings) Translation: Mastodon/Devise Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/cs/ * Translated using Weblate (Ukrainian) Currently translated at 51.2% (42 of 82 strings) Translation: Mastodon/Preferences Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/uk/ * Translated using Weblate (Czech) Currently translated at 100.0% (62 of 62 strings) Translation: Mastodon/Devise Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/devise/cs/ * Translated using Weblate (Galician) Currently translated at 99.8% (666 of 667 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/gl/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 99.8% (666 of 667 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/pt_BR/ * Translated using Weblate (Dutch) Currently translated at 100.0% (667 of 667 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/nl/ * Translated using Weblate (Ukrainian) Currently translated at 99.6% (306 of 307 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/uk/ * Translated using Weblate (Czech) Currently translated at 67.0% (55 of 82 strings) Translation: Mastodon/Preferences Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/cs/ * Translated using Weblate (Ukrainian) Currently translated at 97.0% (647 of 667 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/uk/ * Translated using Weblate (Ukrainian) Currently translated at 97.1% (648 of 667 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/uk/ * Translated using Weblate (Czech) Currently translated at 100.0% (82 of 82 strings) Translation: Mastodon/Preferences Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/cs/ * Translated using Weblate (Czech) Currently translated at 18.3% (18 of 98 strings) Translation: Mastodon/Doorkeeper Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/cs/ * Translated using Weblate (Danish) Currently translated at 79.3% (529 of 667 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/da/ * Translated using Weblate (Czech) Currently translated at 61.2% (60 of 98 strings) Translation: Mastodon/Doorkeeper Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/cs/ * Translated using Weblate (Czech) Currently translated at 100.0% (98 of 98 strings) Translation: Mastodon/Doorkeeper Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/cs/ * Translated using Weblate (Occitan) Currently translated at 99.7% (667 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/oc/ * Translated using Weblate (German) Currently translated at 96.5% (646 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/de/ * Translated using Weblate (Japanese) Currently translated at 99.7% (667 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ja/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 99.8% (668 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/pt_BR/ * Translated using Weblate (Czech) Currently translated at 99.8% (668 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/cs/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (307 of 307 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/pt_BR/ * Translated using Weblate (Corsican) Currently translated at 99.3% (305 of 307 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/co/ * Translated using Weblate (Corsican) Currently translated at 92.2% (617 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/co/ * Translated using Weblate (Telugu) Currently translated at 100.0% (307 of 307 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/te/ * Translated using Weblate (Arabic) Currently translated at 91.4% (75 of 82 strings) Translation: Mastodon/Preferences Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/ar/ * Translated using Weblate (Arabic) Currently translated at 100.0% (307 of 307 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/ar/ * Translated using Weblate (Arabic) Currently translated at 92.9% (622 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ar/ * Translated using Weblate (Danish) Currently translated at 92.8% (91 of 98 strings) Translation: Mastodon/Doorkeeper Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/da/ * Translated using Weblate (Greek) Currently translated at 99.8% (668 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/el/ * Translated using Weblate (Danish) Currently translated at 82.0% (549 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/da/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 99.8% (668 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/pt_BR/ * Translated using Weblate (Korean) Currently translated at 98.2% (657 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ko/ * Translated using Weblate (Korean) Currently translated at 100.0% (307 of 307 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/ko/ * Translated using Weblate (German) Currently translated at 97.7% (654 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/de/ * Translated using Weblate (Corsican) Currently translated at 98.5% (659 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/co/ * Translated using Weblate (Corsican) Currently translated at 100.0% (82 of 82 strings) Translation: Mastodon/Preferences Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/co/ * Translated using Weblate (Corsican) Currently translated at 100.0% (307 of 307 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/co/ * Translated using Weblate (Corsican) Currently translated at 100.0% (98 of 98 strings) Translation: Mastodon/Doorkeeper Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/co/ * Translated using Weblate (French) Currently translated at 100.0% (307 of 307 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/fr/ * Translated using Weblate (Basque) Currently translated at 96.2% (644 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/eu/ * Translated using Weblate (Basque) Currently translated at 100.0% (98 of 98 strings) Translation: Mastodon/Doorkeeper Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/eu/ * Translated using Weblate (Basque) Currently translated at 90.2% (74 of 82 strings) Translation: Mastodon/Preferences Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/eu/ * Translated using Weblate (Basque) Currently translated at 100.0% (307 of 307 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/eu/ * Translated using Weblate (Czech) Currently translated at 99.8% (668 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/cs/ * Translated using Weblate (Czech) Currently translated at 100.0% (2 of 2 strings) Translation: Mastodon/Activerecord Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/activerecord/cs/ * Translated using Weblate (Czech) Currently translated at 100.0% (82 of 82 strings) Translation: Mastodon/Preferences Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/cs/ * Translated using Weblate (Czech) Currently translated at 100.0% (307 of 307 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/cs/ * Translated using Weblate (Asturian) Currently translated at 29.8% (200 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ast/ * Translated using Weblate (Greek) Currently translated at 99.8% (668 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/el/ * Translated using Weblate (Greek) Currently translated at 100.0% (307 of 307 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/el/ * Translated using Weblate (Czech) Currently translated at 100.0% (98 of 98 strings) Translation: Mastodon/Doorkeeper Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/cs/ * Translated using Weblate (German) Currently translated at 100.0% (98 of 98 strings) Translation: Mastodon/Doorkeeper Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/de/ * Translated using Weblate (Greek) Currently translated at 100.0% (82 of 82 strings) Translation: Mastodon/Preferences Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/el/ * Translated using Weblate (German) Currently translated at 96.3% (79 of 82 strings) Translation: Mastodon/Preferences Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/de/ * Translated using Weblate (German) Currently translated at 99.7% (667 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/de/ * Translated using Weblate (German) Currently translated at 100.0% (307 of 307 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/de/ * Translated using Weblate (German) Currently translated at 100.0% (98 of 98 strings) Translation: Mastodon/Doorkeeper Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/de/ * Translated using Weblate (French) Currently translated at 100.0% (98 of 98 strings) Translation: Mastodon/Doorkeeper Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/doorkeeper/fr/ * Translated using Weblate (German) Currently translated at 97.5% (80 of 82 strings) Translation: Mastodon/Preferences Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/de/ * Translated using Weblate (French) Currently translated at 100.0% (82 of 82 strings) Translation: Mastodon/Preferences Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/fr/ * Translated using Weblate (French) Currently translated at 100.0% (307 of 307 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/fr/ * Translated using Weblate (German) Currently translated at 98.7% (81 of 82 strings) Translation: Mastodon/Preferences Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/de/ * Translated using Weblate (German) Currently translated at 99.8% (668 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/de/ * Translated using Weblate (German) Currently translated at 98.7% (81 of 82 strings) Translation: Mastodon/Preferences Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/de/ * Translated using Weblate (German) Currently translated at 98.7% (82 of 82 strings) Translation: Mastodon/Preferences Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/simple_form/de/ * Translated using Weblate (French) Currently translated at 97.4% (652 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/fr/ * Translated using Weblate (German) Currently translated at 99.8% (668 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/de/ * Translated using Weblate (Japanese) Currently translated at 99.8% (668 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/ja/ * Translated using Weblate (German) Currently translated at 99.8% (668 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/de/ * Translated using Weblate (Dutch) Currently translated at 100.0% (669 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/nl/ * Translated using Weblate (German) Currently translated at 99.8% (668 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/de/ * Translated using Weblate (Danish) Currently translated at 85.0% (569 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/da/ * Translated using Weblate (Czech) Currently translated at 100.0% (307 of 307 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/cs/ * Translated using Weblate (Dutch) Currently translated at 100.0% (307 of 307 strings) Translation: Mastodon/React Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/frontend/nl/ * Translated using Weblate (Dutch) Currently translated at 100.0% (669 of 669 strings) Translation: Mastodon/Backend Translate-URL: https://weblate.joinmastodon.org/projects/mastodon/backend/nl/ * yarn manage:translations * i18n-tasks normalize && i18n-tasks remove-unused --- app/javascript/mastodon/locales/cs.json | 2 +- app/javascript/mastodon/locales/nl.json | 2 +- config/locales/da.yml | 22 +++++++++++ config/locales/de.yml | 10 ++--- config/locales/fr.yml | 49 ++++++++++++++++++++++++- config/locales/ja.yml | 2 +- config/locales/nl.yml | 5 ++- config/locales/simple_form.ar.yml | 2 + 8 files changed, 84 insertions(+), 10 deletions(-) diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json index 6efb99381c7..e93baf750c7 100644 --- a/app/javascript/mastodon/locales/cs.json +++ b/app/javascript/mastodon/locales/cs.json @@ -252,7 +252,7 @@ "search_results.hashtags": "Hashtagy", "search_results.statuses": "Tooty", "search_results.total": "{count, number} {count, plural, one {výsledek} other {výsledků}}", - "standalone.public_title": "Nahlédnout dovnitř...", + "standalone.public_title": "Nahlédněte dovnitř...", "status.block": "Zablokovat uživatele @{name}", "status.cancel_reblog_private": "Zrušit boost", "status.cannot_reblog": "Tento příspěvek nemůže být boostnutý", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index 5c6d18e1d71..c19598a2198 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -139,7 +139,7 @@ "keyboard_shortcuts.hotkey": "Sneltoets", "keyboard_shortcuts.legend": "om deze legenda te tonen", "keyboard_shortcuts.mention": "om de auteur te vermelden", - "keyboard_shortcuts.profile": "to open author's profile", + "keyboard_shortcuts.profile": "om het gebruikersprofiel te openen", "keyboard_shortcuts.reply": "om te reageren", "keyboard_shortcuts.search": "om het zoekvak te focussen", "keyboard_shortcuts.toggle_hidden": "om tekst achter een waarschuwing (CW) te tonen/verbergen", diff --git a/config/locales/da.yml b/config/locales/da.yml index 54da05aa845..1a27db34f68 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -368,6 +368,7 @@ da: confirmed: Bekræftet expires_in: Udløber om last_delivery: Sidste levering + title: Websub topic: Emne title: Administration admin_mailer: @@ -403,6 +404,7 @@ da: saml: SAML register: Opret dig register_elsewhere: Opret dig på en anden server + resend_confirmation: Gensend bekræftelses instrukser reset_password: Nulstil kodeord security: Sikkerhed set_new_password: Sæt et nyt kodeord @@ -539,6 +541,8 @@ da: body: "%{name} følger dig nu!" subject: "%{name} følger dig nu" title: Ny følger + follow_request: + body: "%{name} har anmodet om at følge dig" mention: action: Svar body: 'Du blev nævnt af %{name} i:' @@ -554,6 +558,10 @@ da: units: billion: mia. million: mio. + quadrillion: Q + thousand: K + trillion: T + unit: "\n" pagination: newer: Nyere next: Næste @@ -578,18 +586,23 @@ da: browsers: blackberry: Blackberry OS chrome: Google Chrome + edge: Microsoft edge firefox: Mozilla Firefox generic: Ukendt browser ie: IE + qq: QQ browser safari: Apple Safari description: "%{browser} på %{platform}" ip: IP platforms: + adobe_air: Adobe air android: Android ios: iOS linux: Linux mac: Mac. other: ukendt platform + windows: Microsoft windows + windows_phone: Windows fon settings: authorized_apps: Godkendte apps back: Tilbage til Mastodon @@ -602,6 +615,7 @@ da: notifications: Notifikationer preferences: Indstillinger settings: Indstillinger + two_factor_authentication: To-faktor godkendelse your_apps: Dine applikationer statuses: attached: @@ -615,10 +629,13 @@ da: boosted_from_html: Fremhævet fra %{acct_link} content_warning: 'Advarsel om indhold: %{warning}' language_detection: Opfang automatisk sprog + open_in_web: Åbn i browser + over_character_limit: grænsen på %{max} tegn er overskredet pin_errors: limit: Du har allerede fastgjort det maksimale antal trut ownership: Dun kan ikke fastgøre en anden persons toot private: Ikke offentlige trut kan ikke blive fastgjort + reblog: Fremhævede trut kan ikke fastgøres show_more: Vis mere title: '%{name}: "%{quote}"' visibilities: @@ -627,15 +644,20 @@ da: public: Offentlig public_long: Alle kan se unlisted: Ikke listet + unlisted_long: Alle kan se, men vil ikke være listet på offentlige tidslinjer stream_entries: pinned: Fastgjort toot + reblogged: fremhævede sensitive_content: Følsomt indhold + terms: + title: Vilkår og privatlivpolitik for %{instance} themes: contrast: Høj kontrast default: Mastodon mastodon-light: Mastodon (lys) time: formats: + default: "%b %d, %Y, %H:%M" month: "%b %Y" two_factor_authentication: code_hint: Indtast koden der er genereret af din app for at bekræfte diff --git a/config/locales/de.yml b/config/locales/de.yml index 8c221e957af..299e7439286 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -27,7 +27,7 @@ de: hosted_on: Mastodon, beherbergt auf %{domain} learn_more: Mehr erfahren other_instances: Andere Instanzen - privacy_policy: Datenschutzbestimmungen + privacy_policy: Datenschutzerklärung source_code: Quellcode status_count_after: Beiträge verfassten status_count_before: die @@ -56,7 +56,7 @@ de: unfollow: Entfolgen admin: account_moderation_notes: - create: Notiz hinterlassen + create: Notiz erstellen created_msg: Moderationsnotiz erfolgreich erstellt! delete: Löschen destroyed_msg: Moderationsnotiz erfolgreich gelöscht! @@ -224,7 +224,7 @@ de: space: Speicherverbrauch title: Übersicht total_users: Benutzer Insgesamt - trends: Tendenz + trends: Trends week_interactions: Interaktionen diese Woche week_users_active: Aktiv diese Woche week_users_new: Benutzer diese Woche @@ -501,7 +501,7 @@ de: archive_takeout: date: Datum download: Dein Archiv herunterladen - hint_html: Du kannst ein Archiv deiner Beiträge und hochgeladenen Medien anfragen. Die exportierten Daten werden im ActivityPub-Format gespeichert, welches mit jeder Software lesbar ist, die das Format unterstützt. Du kannst alle 7 Tage ein neues Archiv anfordern. + hint_html: Du kannst ein Archiv deiner Beiträge und hochgeladenen Medien anfragen. Die exportierten Daten werden im ActivityPub-Format gespeichert, welches mit jeder Software lesbar ist die das Format unterstützt. Du kannst alle 7 Tage ein Archiv anfordern. in_progress: Stelle dein Archiv zusammen... request: Dein Archiv anfragen size: Größe @@ -885,6 +885,6 @@ de: users: invalid_email: Ungültige E-Mail-Adresse invalid_otp_token: Ungültiger Zwei-Faktor-Authentisierungs-Code - otp_lost_help_html: Wenn Sie zu beidem keinen Zugriff mehr haben, kontaktieren sie %{email} + otp_lost_help_html: Wenn Du beides nicht mehr weißt, melde Dich bei uns unter der E-Mailadresse %{email} seamless_external_login: Du bist angemeldet über einen Drittanbieter-Dienst, weswegen Passwort- und E-Maileinstellungen nicht verfügbar sind. signed_in_as: 'Angemeldet als:' diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 2eb1ba0ce16..c6884fd4a93 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -5,10 +5,12 @@ fr: about_mastodon_html: Mastodon est un réseau social utilisant des formats ouverts et des logiciels libres. Comme le courriel, il est décentralisé. about_this: À propos administered_by: 'Administré par :' + api: API closed_registrations: Les inscriptions sont actuellement fermées sur cette instance. Cependant, vous pouvez trouver une autre instance sur laquelle vous créer un compte et à partir de laquelle vous pourrez accéder au même réseau. contact: Contact contact_missing: Manquant contact_unavailable: Non disponible + documentation: Documentation extended_description_html: |

Un bon endroit pour les règles

La description étendue n’a pas été remplie.

@@ -202,6 +204,23 @@ fr: update_failed_msg: N'a pas pu mettre à jour cet emoji updated_msg: Emoji mis à jour avec succès ! upload: Téléverser + dashboard: + config: Configuration + feature_invites: Liens d'invitation + feature_relay: Relais de fédération + features: Fonctionnalités + hidden_service: Fédération avec des services cachés + recent_users: Utilisateurs récents + search: Recherche texte-plein + single_user_mode: Mode utilisateur unique + software: Logiciel + space: Utilisation d'espace + title: Tableau de bord + total_users: utilisateurs au total + trends: Tendances + week_interactions: interactions cette semaine + week_users_active: actif cette semaine + week_users_new: utilisateurs cette semaine domain_blocks: add_new: Ajouter created_msg: Le blocage de domaine est désormais activé @@ -257,6 +276,12 @@ fr: expired: Expiré title: Filtre title: Invitations + relays: + add_new: Ajouter un nouveau relais + inbox_url: URL de relais + setup: Paramétrer une connexion de relais + status: Statut + title: Relais report_notes: created_msg: Note de signalement créée avec succès ! destroyed_msg: Note de signalement effacée avec succès ! @@ -332,11 +357,13 @@ fr: desc_html: Montrer un badge de responsable sur une page utilisateur title: Montrer un badge de responsable site_description: - desc_html: Paragraphe introductif sur la page d'accueil et dans les méta-balises. Vous pouvez utiliser des balises HTML, en particulier <a> et <em>. + desc_html: Paragraphe introductif sur la page d'accueil. Décrivez ce qui rend spécifique ce serveur Mastodon et toute autre chose importante. Vous pouvez utiliser des balises HTML, en particulier <a> et <em>. title: Description du site site_description_extended: desc_html: Affichée sur la page d’informations complémentaires du site
Vous pouvez utiliser des balises HTML title: Description étendue du site + site_short_description: + title: Description courte de l'instance site_terms: desc_html: Affichée sur la page des conditions d’utilisation du site
Vous pouvez utiliser des balises HTML title: Politique de confidentialité @@ -470,6 +497,19 @@ fr: follows: Vous suivez mutes: Vous masquez storage: Médias stockés + filters: + contexts: + home: Ligne de temps personnelle + notifications: Notifications + public: Lignes de temps public + thread: Conversations + edit: + title: Filtre d'édition + index: + delete: Effacer + title: Filtres + new: + title: Ajouter un nouveau filtre followers: domain: Domaine explanation_html: Si vous voulez être sûr⋅e que vos statuts restent privés, vous devez savoir qui vous suit. Vos statuts privés seront diffusés à toutes les instances des utilisateur⋅ice⋅s qui vous suivent. Vous voudrez peut-être les passer en revue et les supprimer si vous n’êtes pas sûr⋅e que votre vie privée sera respectée par l’administration ou le logiciel de ces instances. @@ -482,6 +522,10 @@ fr: true_privacy_html: Soyez conscient⋅e⋅s qu’une vraie confidentialité ne peut être atteinte que par un chiffrement de bout-en-bout. unlocked_warning_html: N’importe qui peut vous suivre et voir vos statuts privés. %{lock_link} afin de pouvoir vérifier et rejeter des abonné⋅e⋅s. unlocked_warning_title: Votre compte n’est pas privé + footer: + developers: Développeurs + more: Davantage… + resources: Ressources generic: changes_saved_msg: Les modifications ont été enregistrées avec succès ! save_changes: Enregistrer les modifications @@ -509,6 +553,7 @@ fr: '86400': 1 jour expires_in_prompt: Jamais generate: Générer + invited_by: 'Vous avez été invité par :' max_uses: one: 1 usage other: "%{count} usages" @@ -667,6 +712,7 @@ fr: disallowed_hashtags: one: 'contient un hashtag désactivé : %{tags}' other: 'contient les hashtag désactivés : %{tags}' + language_detection: Détecter automatiquement la langue open_in_web: Ouvrir sur le web over_character_limit: limite de caractères dépassée de %{max} caractères pin_errors: @@ -696,6 +742,7 @@ fr: time: formats: default: "%d %b %Y, %H:%M" + month: "%b %Y" two_factor_authentication: code_hint: Entrez le code généré par votre application pour confirmer description_html: Si vous activez l’identification à deux facteurs, vous devrez être en possession de votre téléphone afin de générer un code de connexion. diff --git a/config/locales/ja.yml b/config/locales/ja.yml index b0adbbb5de9..5fe784aaea6 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -369,7 +369,7 @@ ja: desc_html: ユーザーページにスタッフのバッジを表示します title: スタッフバッジを表示する site_description: - desc_html: フロントページへの表示と meta タグに使用される紹介文です。HTMLタグ、特に<a><em>が使えます。 + desc_html: フロントページへの表示に使用される紹介文です。このMastodonインスタンスを特徴付けることやその他重要なことを記述してください。HTMLタグ、特に<a><em>が使えます。 title: インスタンスの説明 site_description_extended: desc_html: あなたのインスタンスにおける行動規範やルール、ガイドライン、そのほかの記述をする際に最適な場所です。HTMLタグが使えます diff --git a/config/locales/nl.yml b/config/locales/nl.yml index c3390fe73b4..f1171720885 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -369,11 +369,14 @@ nl: desc_html: Medewerkersbadge op profielpagina tonen title: Medewerkersbadge tonen site_description: - desc_html: Dit wordt als een alinea op de voorpagina getoond en gebruikt als meta-tag in de paginabron.
Je kan HTML gebruiken, zoals <a> en <em>. + desc_html: Dit wordt als een alinea op de voorpagina getoond. Beschrijf wat er speciaal is aan deze server en andere zaken die van belang zijn. Je kan HTML gebruiken, zoals <a> en <em>. title: Omschrijving Mastodonserver site_description_extended: desc_html: Wordt op de uitgebreide informatiepagina weergegeven
Je kan ook hier HTML gebruiken title: Uitgebreide omschrijving Mastodonserver + site_short_description: + desc_html: Dit wordt in de zijbalk getoond als en als metatag in de paginabron. Beschrijf in één alinea wat Mastodon is en wat deze server speciaal maakt. De (langere) omschrijving van de Mastodonserver wordt gebruikt wanneer dit veld wordt leeg gelaten. + title: Korte omschrijving Mastodonserver site_terms: desc_html: Je kan hier jouw eigen privacybeleid, gebruiksvoorwaarden en ander juridisch jargon kwijt. Je kan HTML gebruiken title: Aangepaste gebruiksvoorwaarden diff --git a/config/locales/simple_form.ar.yml b/config/locales/simple_form.ar.yml index c7eb9585772..d7cb88a6f5c 100644 --- a/config/locales/simple_form.ar.yml +++ b/config/locales/simple_form.ar.yml @@ -8,12 +8,14 @@ ar: bot: يُعلِم أنّ هذا الحساب لا يمثل شخصًا context: واحد أو أكثر من السياقات التي يجب أن ينطبق عليها عامل التصفية digest: تُرسَل إليك بعد مُضيّ مدة مِن خمول نشاطك و فقط إذا ما تلقيت رسائل شخصية مباشِرة أثناء فترة غيابك مِن الشبكة + display_name: %{count} حرف باق fields: يُمكنك عرض 4 عناصر على شكل جدول في ملفك الشخصي header: ملف PNG أو GIF أو JPG. حجمه على أقصى تصدير %{size}. سيتم تصغيره إلى %{dimensions}px inbox_url: نسخ العنوان الذي تريد استخدامه مِن صفحة الإستقبال للمُرحَّل irreversible: التبويقات التي تم تصفيتها ستختفي لا محالة حتى و إن تمت إزالة عامِل التصفية لاحقًا locale: لغة واجهة المستخدم و الرسائل الإلكترونية و الإشعارات locked: يتطلب منك الموافقة يدويا على طلبات المتابعة + note: %{count} حرف باق scopes: ما هي المجالات المسموح بها في التطبيق ؟ إن قمت باختيار أعلى المجالات فيمكنك الإستغناء عن الخَيار اليدوي. setting_default_language: يمكن الكشف التلقائي للّغة اللتي استخدمتها في تحرير تبويقاتك ، غيرَ أنّ العملية ليست دائما دقيقة setting_hide_network: الحسابات التي تُتابعها و التي تُتابِعك على حد سواء لن تُعرَض على صفحتك الشخصية From 110b3f63352e85c6ac138918b285d963382ce623 Mon Sep 17 00:00:00 2001 From: ThibG Date: Sat, 11 Aug 2018 22:02:55 +0200 Subject: [PATCH 03/24] Add some feedback to maintenance rake tasks (#8173) --- lib/tasks/mastodon.rake | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/tasks/mastodon.rake b/lib/tasks/mastodon.rake index de8c0bb8687..f693c8b5abe 100644 --- a/lib/tasks/mastodon.rake +++ b/lib/tasks/mastodon.rake @@ -502,18 +502,24 @@ namespace :mastodon do desc 'Remove media attachments attributed to silenced accounts' task remove_silenced: :environment do + nb_media_attachments = 0 MediaAttachment.where(account: Account.silenced).select(:id).find_in_batches do |media_attachments| + nb_media_attachments += media_attachments.length Maintenance::DestroyMediaWorker.push_bulk(media_attachments.map(&:id)) end + puts "Scheduled the deletion of #{nb_media_attachments} media attachments" end desc 'Remove cached remote media attachments that are older than NUM_DAYS. By default 7 (week)' task remove_remote: :environment do time_ago = ENV.fetch('NUM_DAYS') { 7 }.to_i.days.ago + nb_media_attachments = 0 MediaAttachment.where.not(remote_url: '').where.not(file_file_name: nil).where('created_at < ?', time_ago).select(:id).find_in_batches do |media_attachments| + nb_media_attachments += media_attachments.length Maintenance::UncacheMediaWorker.push_bulk(media_attachments.map(&:id)) end + puts "Scheduled the deletion of #{nb_media_attachments} media attachments" end desc 'Set unknown attachment type for remote-only attachments' @@ -527,10 +533,13 @@ namespace :mastodon do task redownload_avatars: :environment do accounts = Account.remote accounts = accounts.where(domain: ENV['DOMAIN']) if ENV['DOMAIN'].present? + nb_accounts = 0 accounts.select(:id).find_in_batches do |accounts_batch| + nb_accounts += accounts_batch.length Maintenance::RedownloadAccountMediaWorker.push_bulk(accounts_batch.map(&:id)) end + puts "Scheduled the download of avatars/headers for #{nb_accounts} remote users" end end From 2aeeffc3ec421111f751cab61a15642cbddd9f0d Mon Sep 17 00:00:00 2001 From: "S.H" Date: Sun, 12 Aug 2018 19:25:23 +0900 Subject: [PATCH 04/24] Update Rails (#8141) * Update Rails * fix Update Rails --- Gemfile | 2 +- Gemfile.lock | 88 +++++++++---------- .../controllers/api/salmon_controller_spec.rb | 9 +- .../api/subscriptions_controller_spec.rb | 3 +- .../concerns/signature_verification_spec.rb | 2 +- 5 files changed, 50 insertions(+), 54 deletions(-) diff --git a/Gemfile b/Gemfile index 7a6e1568d28..8c2970c41bf 100644 --- a/Gemfile +++ b/Gemfile @@ -6,7 +6,7 @@ ruby '>= 2.3.0', '< 2.6.0' gem 'pkg-config', '~> 1.3' gem 'puma', '~> 3.11' -gem 'rails', '~> 5.2.0' +gem 'rails', '~> 5.2.1' gem 'hamlit-rails', '~> 0.2' gem 'pg', '~> 1.0' diff --git a/Gemfile.lock b/Gemfile.lock index e1929a05c83..f9cf3d3458b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -15,25 +15,25 @@ GIT GEM remote: https://rubygems.org/ specs: - actioncable (5.2.0) - actionpack (= 5.2.0) + actioncable (5.2.1) + actionpack (= 5.2.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailer (5.2.0) - actionpack (= 5.2.0) - actionview (= 5.2.0) - activejob (= 5.2.0) + actionmailer (5.2.1) + actionpack (= 5.2.1) + actionview (= 5.2.1) + activejob (= 5.2.1) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.2.0) - actionview (= 5.2.0) - activesupport (= 5.2.0) + actionpack (5.2.1) + actionview (= 5.2.1) + activesupport (= 5.2.1) rack (~> 2.0) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.2.0) - activesupport (= 5.2.0) + actionview (5.2.1) + activesupport (= 5.2.1) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) @@ -44,20 +44,20 @@ GEM case_transform (>= 0.2) jsonapi-renderer (>= 0.1.1.beta1, < 0.3) active_record_query_trace (1.5.4) - activejob (5.2.0) - activesupport (= 5.2.0) + activejob (5.2.1) + activesupport (= 5.2.1) globalid (>= 0.3.6) - activemodel (5.2.0) - activesupport (= 5.2.0) - activerecord (5.2.0) - activemodel (= 5.2.0) - activesupport (= 5.2.0) + activemodel (5.2.1) + activesupport (= 5.2.1) + activerecord (5.2.1) + activemodel (= 5.2.1) + activesupport (= 5.2.1) arel (>= 9.0) - activestorage (5.2.0) - actionpack (= 5.2.0) - activerecord (= 5.2.0) + activestorage (5.2.1) + actionpack (= 5.2.1) + activerecord (= 5.2.1) marcel (~> 0.3.1) - activesupport (5.2.0) + activesupport (5.2.1) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -269,7 +269,7 @@ GEM httplog (1.0.2) colorize (~> 0.8) rack (>= 1.0) - i18n (1.0.1) + i18n (1.1.0) concurrent-ruby (~> 1.0) i18n-tasks (0.9.21) activesupport (>= 4.0.2) @@ -346,8 +346,8 @@ GEM net-scp (1.2.1) net-ssh (>= 2.6.5) net-ssh (4.2.0) - nio4r (2.3.0) - nokogiri (1.8.2) + nio4r (2.3.1) + nokogiri (1.8.4) mini_portile2 (~> 2.3.0) nokogumbo (1.5.0) nokogiri @@ -415,7 +415,7 @@ GEM puma (3.11.4) pundit (1.1.0) activesupport (>= 3.0.0) - rack (2.0.4) + rack (2.0.5) rack-attack (5.2.0) rack rack-cors (1.0.2) @@ -423,20 +423,20 @@ GEM rack rack-proxy (0.6.4) rack - rack-test (1.0.0) + rack-test (1.1.0) rack (>= 1.0, < 3) - rails (5.2.0) - actioncable (= 5.2.0) - actionmailer (= 5.2.0) - actionpack (= 5.2.0) - actionview (= 5.2.0) - activejob (= 5.2.0) - activemodel (= 5.2.0) - activerecord (= 5.2.0) - activestorage (= 5.2.0) - activesupport (= 5.2.0) + rails (5.2.1) + actioncable (= 5.2.1) + actionmailer (= 5.2.1) + actionpack (= 5.2.1) + actionview (= 5.2.1) + activejob (= 5.2.1) + activemodel (= 5.2.1) + activerecord (= 5.2.1) + activestorage (= 5.2.1) + activesupport (= 5.2.1) bundler (>= 1.3.0) - railties (= 5.2.0) + railties (= 5.2.1) sprockets-rails (>= 2.0.0) rails-controller-testing (1.0.2) actionpack (~> 5.x, >= 5.0.1) @@ -452,12 +452,12 @@ GEM railties (>= 5.0, < 6) rails-settings-cached (0.6.6) rails (>= 4.2.0) - railties (5.2.0) - actionpack (= 5.2.0) - activesupport (= 5.2.0) + railties (5.2.1) + actionpack (= 5.2.1) + activesupport (= 5.2.1) method_source rake (>= 0.8.7) - thor (>= 0.18.1, < 2.0) + thor (>= 0.19.0, < 2.0) rainbow (3.0.0) rake (12.3.1) rb-fsevent (0.10.3) @@ -725,7 +725,7 @@ DEPENDENCIES pundit (~> 1.1) rack-attack (~> 5.2) rack-cors (~> 1.0) - rails (~> 5.2.0) + rails (~> 5.2.1) rails-controller-testing (~> 1.0) rails-i18n (~> 5.1) rails-settings-cached (~> 0.6) @@ -764,4 +764,4 @@ RUBY VERSION ruby 2.5.0p0 BUNDLED WITH - 1.16.2 + 1.16.3 diff --git a/spec/controllers/api/salmon_controller_spec.rb b/spec/controllers/api/salmon_controller_spec.rb index 5f01f807352..8ce4913a52d 100644 --- a/spec/controllers/api/salmon_controller_spec.rb +++ b/spec/controllers/api/salmon_controller_spec.rb @@ -15,8 +15,7 @@ RSpec.describe Api::SalmonController, type: :controller do describe 'POST #update' do context 'with valid post data' do before do - request.env['RAW_POST_DATA'] = File.read(File.join(Rails.root, 'spec', 'fixtures', 'salmon', 'mention.xml')) - post :update, params: { id: account.id } + post :update, params: { id: account.id }, body: File.read(File.join(Rails.root, 'spec', 'fixtures', 'salmon', 'mention.xml')) end it 'contains XML in the request body' do @@ -42,8 +41,7 @@ RSpec.describe Api::SalmonController, type: :controller do context 'with empty post data' do before do - request.env['RAW_POST_DATA'] = '' - post :update, params: { id: account.id } + post :update, params: { id: account.id }, body: '' end it 'returns http client error' do @@ -56,8 +54,7 @@ RSpec.describe Api::SalmonController, type: :controller do service = double(call: false) allow(VerifySalmonService).to receive(:new).and_return(service) - request.env['RAW_POST_DATA'] = File.read(File.join(Rails.root, 'spec', 'fixtures', 'salmon', 'mention.xml')) - post :update, params: { id: account.id } + post :update, params: { id: account.id }, body: File.read(File.join(Rails.root, 'spec', 'fixtures', 'salmon', 'mention.xml')) end it 'returns http client error' do diff --git a/spec/controllers/api/subscriptions_controller_spec.rb b/spec/controllers/api/subscriptions_controller_spec.rb index 48eb1fc64c9..b46971a5478 100644 --- a/spec/controllers/api/subscriptions_controller_spec.rb +++ b/spec/controllers/api/subscriptions_controller_spec.rb @@ -53,9 +53,8 @@ RSpec.describe Api::SubscriptionsController, type: :controller do stub_request(:any, "https://mastodon.social/users/Gargron").to_return(status: 404) request.env['HTTP_X_HUB_SIGNATURE'] = "sha1=#{OpenSSL::HMAC.hexdigest('sha1', 'abc', feed)}" - request.env['RAW_POST_DATA'] = feed - post :update, params: { id: account.id } + post :update, params: { id: account.id }, body: feed end it 'returns http success' do diff --git a/spec/controllers/concerns/signature_verification_spec.rb b/spec/controllers/concerns/signature_verification_spec.rb index 64648621e04..3daf1fc4e8c 100644 --- a/spec/controllers/concerns/signature_verification_spec.rb +++ b/spec/controllers/concerns/signature_verification_spec.rb @@ -105,7 +105,7 @@ describe ApplicationController, type: :controller do end it 'returns nil when body has been tampered' do - request.headers['RAW_POST_DATA'] = 'doo doo doo' + post :success, body: 'doo doo doo' expect(controller.signed_request_account).to be_nil end end From 39e361a56d849a027ed12df69122a369bc6ff39d Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 12 Aug 2018 18:16:26 +0200 Subject: [PATCH 05/24] Expect relays to answer with accept/reject (#8179) --- app/lib/activitypub/activity/accept.rb | 14 ++++++++++++++ app/lib/activitypub/activity/reject.rb | 14 ++++++++++++++ app/models/relay.rb | 12 ++++++++---- .../20180812123222_change_relays_enabled.rb | 19 +++++++++++++++++++ db/schema.rb | 5 ++--- 5 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 db/migrate/20180812123222_change_relays_enabled.rb diff --git a/app/lib/activitypub/activity/accept.rb b/app/lib/activitypub/activity/accept.rb index bd90c901944..7e60b2c00eb 100644 --- a/app/lib/activitypub/activity/accept.rb +++ b/app/lib/activitypub/activity/accept.rb @@ -11,6 +11,8 @@ class ActivityPub::Activity::Accept < ActivityPub::Activity private def accept_follow + return accept_follow_for_relay if relay_follow? + target_account = account_from_uri(target_uri) return if target_account.nil? || !target_account.local? @@ -19,6 +21,18 @@ class ActivityPub::Activity::Accept < ActivityPub::Activity follow_request&.authorize! end + def accept_follow_for_relay + relay.update!(state: :accepted) + end + + def relay + @relay ||= Relay.find_by(follow_activity_id: object_uri) + end + + def relay_follow? + relay.present? + end + def target_uri @target_uri ||= value_or_id(@object['actor']) end diff --git a/app/lib/activitypub/activity/reject.rb b/app/lib/activitypub/activity/reject.rb index 28d472883f2..d81b157de8a 100644 --- a/app/lib/activitypub/activity/reject.rb +++ b/app/lib/activitypub/activity/reject.rb @@ -11,6 +11,8 @@ class ActivityPub::Activity::Reject < ActivityPub::Activity private def reject_follow + return reject_follow_for_relay if relay_follow? + target_account = account_from_uri(target_uri) return if target_account.nil? || !target_account.local? @@ -21,6 +23,18 @@ class ActivityPub::Activity::Reject < ActivityPub::Activity UnfollowService.new.call(target_account, @account) if target_account.following?(@account) end + def reject_follow_for_relay + relay.update!(state: :rejected) + end + + def relay + @relay ||= Relay.find_by(follow_activity_id: object_uri) + end + + def relay_follow? + relay.present? + end + def target_uri @target_uri ||= value_or_id(@object['actor']) end diff --git a/app/models/relay.rb b/app/models/relay.rb index 76143bb27a2..75cb060b26f 100644 --- a/app/models/relay.rb +++ b/app/models/relay.rb @@ -5,10 +5,10 @@ # # id :bigint(8) not null, primary key # inbox_url :string default(""), not null -# enabled :boolean default(FALSE), not null # follow_activity_id :string # created_at :datetime not null # updated_at :datetime not null +# state :integer default("idle"), not null # class Relay < ApplicationRecord @@ -16,24 +16,28 @@ class Relay < ApplicationRecord validates :inbox_url, presence: true, uniqueness: true, url: true, if: :will_save_change_to_inbox_url? - scope :enabled, -> { where(enabled: true) } + enum state: [:idle, :pending, :accepted, :rejected] + + scope :enabled, -> { accepted } before_destroy :ensure_disabled + alias enabled? accepted? + def enable! activity_id = ActivityPub::TagManager.instance.generate_uri_for(nil) payload = Oj.dump(follow_activity(activity_id)) + update!(state: :pending, follow_activity_id: activity_id) ActivityPub::DeliveryWorker.perform_async(payload, some_local_account.id, inbox_url) - update(enabled: true, follow_activity_id: activity_id) end def disable! activity_id = ActivityPub::TagManager.instance.generate_uri_for(nil) payload = Oj.dump(unfollow_activity(activity_id)) + update!(state: :idle, follow_activity_id: nil) ActivityPub::DeliveryWorker.perform_async(payload, some_local_account.id, inbox_url) - update(enabled: false, follow_activity_id: nil) end private diff --git a/db/migrate/20180812123222_change_relays_enabled.rb b/db/migrate/20180812123222_change_relays_enabled.rb new file mode 100644 index 00000000000..c4fd8179be6 --- /dev/null +++ b/db/migrate/20180812123222_change_relays_enabled.rb @@ -0,0 +1,19 @@ +class ChangeRelaysEnabled < ActiveRecord::Migration[5.2] + def up + # The relays table is supposed to be very small, + # single-digit number of rows, so this should be fine + safety_assured do + add_column :relays, :state, :integer, default: 0, null: false + + # At the time of this migration, no relays reject anyone, so if + # there are enabled ones, they are accepted + execute 'UPDATE relays SET state = 2 WHERE enabled = true' + remove_column :relays, :enabled + end + end + + def down + remove_column :relays, :state + add_column :relays, :enabled, :boolean, default: false, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 46ee42714c3..edb5a023c7e 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: 2018_08_08_175627) do +ActiveRecord::Schema.define(version: 2018_08_12_123222) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -383,11 +383,10 @@ ActiveRecord::Schema.define(version: 2018_08_08_175627) do create_table "relays", force: :cascade do |t| t.string "inbox_url", default: "", null: false - t.boolean "enabled", default: false, null: false t.string "follow_activity_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.index ["enabled"], name: "index_relays_on_enabled" + t.integer "state", default: 0, null: false end create_table "report_notes", force: :cascade do |t| From b7091c6c0fe057f7469a97f138c3e2451d95a28f Mon Sep 17 00:00:00 2001 From: Evgeny Petrov Date: Mon, 13 Aug 2018 00:11:40 +0300 Subject: [PATCH 06/24] Added endorse strings, fixed footer 'developers' string (#8183) --- app/javascript/mastodon/locales/ru.json | 4 ++-- config/locales/ru.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json index 0f2a26e7678..0e8586903fe 100644 --- a/app/javascript/mastodon/locales/ru.json +++ b/app/javascript/mastodon/locales/ru.json @@ -7,7 +7,7 @@ "account.disclaimer_full": "Нижеуказанная информация может не полностью отражать профиль пользователя.", "account.domain_blocked": "Домен скрыт", "account.edit_profile": "Изменить профиль", - "account.endorse": "Feature on profile", + "account.endorse": "Рекомендовать в профиле", "account.follow": "Подписаться", "account.followers": "Подписаны", "account.follows": "Подписки", @@ -27,7 +27,7 @@ "account.show_reblogs": "Показывать продвижения от @{name}", "account.unblock": "Разблокировать", "account.unblock_domain": "Разблокировать {domain}", - "account.unendorse": "Don't feature on profile", + "account.unendorse": "Не рекомендовать в профиле", "account.unfollow": "Отписаться", "account.unmute": "Снять глушение", "account.unmute_notifications": "Показывать уведомления от @{name}", diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 9d5c3184b84..44e41eaf6df 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -544,7 +544,7 @@ ru: unlocked_warning_html: Кто угодно может подписаться на Вас и получить доступ к просмотру Ваших приватных статусов. %{lock_link}, чтобы получить возможность рассматривать и вручную подтверждать запросы о подписке. unlocked_warning_title: Ваш аккаунт не закрыт для подписки footer: - developers: Разработчики + developers: Разработчикам more: Ещё… resources: Ссылки generic: From 018a9e4e7fdfac0f2e482f4b5fa66247afbc2ddb Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 13 Aug 2018 13:40:01 +0200 Subject: [PATCH 07/24] Add post-deployment migration system (#8182) Adopted from GitLab CE. Generate new migration with: rails g post_deployment_migration name_of_migration_here By default they are run together with db:migrate. To not run them, the env variable SKIP_POST_DEPLOYMENT_MIGRATIONS must be set Code by Yorick Peterse , see also: https://gitlab.com/gitlab-org/gitlab-ce/commit/83c8241160ed48ab066e2c5bd58d0914a745197c --- .rubocop.yml | 1 + .../0_post_deployment_migrations.rb | 15 +++++++++++++++ db/post_migrate/.gitkeep | 0 .../post_deployment_migration_generator.rb | 17 +++++++++++++++++ .../post_deployment_migration/migration.rb | 8 ++++++++ 5 files changed, 41 insertions(+) create mode 100644 config/initializers/0_post_deployment_migrations.rb create mode 100644 db/post_migrate/.gitkeep create mode 100644 lib/generators/post_deployment_migration_generator.rb create mode 100644 lib/templates/rails/post_deployment_migration/migration.rb diff --git a/.rubocop.yml b/.rubocop.yml index 6faeaca6f20..4f9e09b4384 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -11,6 +11,7 @@ AllCops: - 'Vagrantfile' - 'vendor/**/*' - 'lib/json_ld/*' + - 'lib/templates/**/*' Bundler/OrderedGems: Enabled: false diff --git a/config/initializers/0_post_deployment_migrations.rb b/config/initializers/0_post_deployment_migrations.rb new file mode 100644 index 00000000000..61121ccd70a --- /dev/null +++ b/config/initializers/0_post_deployment_migrations.rb @@ -0,0 +1,15 @@ +# Post deployment migrations are included by default. This file must be loaded +# before other initializers as Rails may otherwise memoize a list of migrations +# excluding the post deployment migrations. + +unless ENV['SKIP_POST_DEPLOYMENT_MIGRATIONS'] + Rails.application.config.paths['db'].each do |db_path| + path = Rails.root.join(db_path, 'post_migrate').to_s + + Rails.application.config.paths['db/migrate'] << path + + # Rails memoizes migrations at certain points where it won't read the above + # path just yet. As such we must also update the following list of paths. + ActiveRecord::Migrator.migrations_paths << path + end +end diff --git a/db/post_migrate/.gitkeep b/db/post_migrate/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/generators/post_deployment_migration_generator.rb b/lib/generators/post_deployment_migration_generator.rb new file mode 100644 index 00000000000..798c01b883a --- /dev/null +++ b/lib/generators/post_deployment_migration_generator.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'rails/generators' + +module Rails + class PostDeploymentMigrationGenerator < Rails::Generators::NamedBase + def create_migration_file + timestamp = Time.zone.now.strftime('%Y%m%d%H%M%S') + + template 'migration.rb', "db/post_migrate/#{timestamp}_#{file_name}.rb" + end + + def migration_class_name + file_name.camelize + end + end +end diff --git a/lib/templates/rails/post_deployment_migration/migration.rb b/lib/templates/rails/post_deployment_migration/migration.rb new file mode 100644 index 00000000000..503205b8415 --- /dev/null +++ b/lib/templates/rails/post_deployment_migration/migration.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class <%= migration_class_name %> < ActiveRecord::Migration[5.2] + disable_ddl_transaction! + + def change + end +end From 8e111b753a3411b258cdb008c9a53bad696f4df1 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 14 Aug 2018 19:19:32 +0200 Subject: [PATCH 08/24] Move status counters to separate table, count replies (#8104) * Move status counters to separate table, count replies * Migration to remove old counter columns from statuses table * Fix schema file --- app/models/favourite.rb | 13 +--- app/models/status.rb | 72 ++++++++++++++----- app/models/status_stat.rb | 17 +++++ app/serializers/rest/status_serializer.rb | 3 +- .../20180812162710_create_status_stats.rb | 12 ++++ .../20180812173710_copy_status_stats.rb | 19 +++++ ...0180813113448_copy_status_stats_cleanup.rb | 12 ++++ db/schema.rb | 15 +++- spec/fabricators/status_stat_fabricator.rb | 6 ++ spec/models/status_stat_spec.rb | 5 ++ 10 files changed, 142 insertions(+), 32 deletions(-) create mode 100644 app/models/status_stat.rb create mode 100644 db/migrate/20180812162710_create_status_stats.rb create mode 100644 db/migrate/20180812173710_copy_status_stats.rb create mode 100644 db/post_migrate/20180813113448_copy_status_stats_cleanup.rb create mode 100644 spec/fabricators/status_stat_fabricator.rb create mode 100644 spec/models/status_stat_spec.rb diff --git a/app/models/favourite.rb b/app/models/favourite.rb index 0fce82f6f92..ce7a6a33615 100644 --- a/app/models/favourite.rb +++ b/app/models/favourite.rb @@ -32,20 +32,11 @@ class Favourite < ApplicationRecord private def increment_cache_counters - if association(:status).loaded? - status.update_attribute(:favourites_count, status.favourites_count + 1) - else - Status.where(id: status_id).update_all('favourites_count = COALESCE(favourites_count, 0) + 1') - end + status.increment_count!(:favourites_count) end def decrement_cache_counters return if association(:status).loaded? && (status.marked_for_destruction? || status.marked_for_mass_destruction?) - - if association(:status).loaded? - status.update_attribute(:favourites_count, [status.favourites_count - 1, 0].max) - else - Status.where(id: status_id).update_all('favourites_count = GREATEST(COALESCE(favourites_count, 0) - 1, 0)') - end + status.decrement_count!(:favourites_count) end end diff --git a/app/models/status.rb b/app/models/status.rb index e7dd0df29e0..1c87f2566f8 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -15,8 +15,6 @@ # visibility :integer default("public"), not null # spoiler_text :text default(""), not null # reply :boolean default(FALSE), not null -# favourites_count :integer default(0), not null -# reblogs_count :integer default(0), not null # language :string # conversation_id :bigint(8) # local :boolean @@ -26,6 +24,8 @@ # class Status < ApplicationRecord + self.cache_versioning = false + include Paginable include Streamable include Cacheable @@ -59,6 +59,7 @@ class Status < ApplicationRecord has_one :notification, as: :activity, dependent: :destroy has_one :stream_entry, as: :activity, inverse_of: :status + has_one :status_stat, inverse_of: :status validates :uri, uniqueness: true, presence: true, unless: :local? validates :text, presence: true, unless: -> { with_media? || reblog? } @@ -81,7 +82,25 @@ class Status < ApplicationRecord scope :not_excluded_by_account, ->(account) { where.not(account_id: account.excluded_from_timeline_account_ids) } scope :not_domain_blocked_by_account, ->(account) { account.excluded_from_timeline_domains.blank? ? left_outer_joins(:account) : left_outer_joins(:account).where('accounts.domain IS NULL OR accounts.domain NOT IN (?)', account.excluded_from_timeline_domains) } - cache_associated :account, :application, :media_attachments, :conversation, :tags, :stream_entry, mentions: :account, reblog: [:account, :application, :stream_entry, :tags, :media_attachments, :conversation, mentions: :account], thread: :account + cache_associated :account, + :application, + :media_attachments, + :conversation, + :status_stat, + :tags, + :stream_entry, + mentions: :account, + reblog: [ + :account, + :application, + :stream_entry, + :tags, + :media_attachments, + :conversation, + :status_stat, + mentions: :account, + ], + thread: :account delegate :domain, to: :account, prefix: true @@ -175,6 +194,26 @@ class Status < ApplicationRecord @marked_for_mass_destruction end + def replies_count + status_stat&.replies_count || 0 + end + + def reblogs_count + status_stat&.reblogs_count || 0 + end + + def favourites_count + status_stat&.favourites_count || 0 + end + + def increment_count!(key) + update_status_stat!(key => public_send(key) + 1) + end + + def decrement_count!(key) + update_status_stat!(key => [public_send(key) - 1, 0].max) + end + after_create :increment_counter_caches after_destroy :decrement_counter_caches @@ -190,6 +229,10 @@ class Status < ApplicationRecord before_validation :set_local class << self + def cache_ids + left_outer_joins(:status_stat).select('statuses.id, greatest(statuses.updated_at, status_stats.updated_at) AS updated_at') + end + def in_chosen_languages(account) where(language: nil).or where(language: account.chosen_languages) end @@ -352,6 +395,11 @@ class Status < ApplicationRecord private + def update_status_stat!(attrs) + record = status_stat || build_status_stat + record.update(attrs) + end + def store_uri update_attribute(:uri, ActivityPub::TagManager.instance.uri_for(self)) if uri.nil? end @@ -408,13 +456,8 @@ class Status < ApplicationRecord Account.where(id: account_id).update_all('statuses_count = COALESCE(statuses_count, 0) + 1') end - return unless reblog? - - if association(:reblog).loaded? - reblog.update_attribute(:reblogs_count, reblog.reblogs_count + 1) - else - Status.where(id: reblog_of_id).update_all('reblogs_count = COALESCE(reblogs_count, 0) + 1') - end + thread.increment_count!(:replies_count) if in_reply_to_id.present? + reblog.increment_count!(:reblogs_count) if reblog? end def decrement_counter_caches @@ -426,12 +469,7 @@ class Status < ApplicationRecord Account.where(id: account_id).update_all('statuses_count = GREATEST(COALESCE(statuses_count, 0) - 1, 0)') end - return unless reblog? - - if association(:reblog).loaded? - reblog.update_attribute(:reblogs_count, [reblog.reblogs_count - 1, 0].max) - else - Status.where(id: reblog_of_id).update_all('reblogs_count = GREATEST(COALESCE(reblogs_count, 0) - 1, 0)') - end + thread.decrement_count!(:replies_count) if in_reply_to_id.present? + reblog.decrement_count!(:reblogs_count) if reblog? end end diff --git a/app/models/status_stat.rb b/app/models/status_stat.rb new file mode 100644 index 00000000000..9d358776b4d --- /dev/null +++ b/app/models/status_stat.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# == Schema Information +# +# Table name: status_stats +# +# id :bigint(8) not null, primary key +# status_id :bigint(8) not null +# replies_count :bigint(8) default(0), not null +# reblogs_count :bigint(8) default(0), not null +# favourites_count :bigint(8) default(0), not null +# created_at :datetime not null +# updated_at :datetime not null +# + +class StatusStat < ApplicationRecord + belongs_to :status, inverse_of: :status_stat +end diff --git a/app/serializers/rest/status_serializer.rb b/app/serializers/rest/status_serializer.rb index fe3dc9bfcfb..61423f96151 100644 --- a/app/serializers/rest/status_serializer.rb +++ b/app/serializers/rest/status_serializer.rb @@ -3,7 +3,8 @@ class REST::StatusSerializer < ActiveModel::Serializer attributes :id, :created_at, :in_reply_to_id, :in_reply_to_account_id, :sensitive, :spoiler_text, :visibility, :language, - :uri, :content, :url, :reblogs_count, :favourites_count + :uri, :content, :url, :replies_count, :reblogs_count, + :favourites_count attribute :favourited, if: :current_user? attribute :reblogged, if: :current_user? diff --git a/db/migrate/20180812162710_create_status_stats.rb b/db/migrate/20180812162710_create_status_stats.rb new file mode 100644 index 00000000000..d4da36fe786 --- /dev/null +++ b/db/migrate/20180812162710_create_status_stats.rb @@ -0,0 +1,12 @@ +class CreateStatusStats < ActiveRecord::Migration[5.2] + def change + create_table :status_stats do |t| + t.belongs_to :status, null: false, foreign_key: { on_delete: :cascade }, index: { unique: true } + t.bigint :replies_count, null: false, default: 0 + t.bigint :reblogs_count, null: false, default: 0 + t.bigint :favourites_count, null: false, default: 0 + + t.timestamps + end + end +end diff --git a/db/migrate/20180812173710_copy_status_stats.rb b/db/migrate/20180812173710_copy_status_stats.rb new file mode 100644 index 00000000000..6ecccc0ae65 --- /dev/null +++ b/db/migrate/20180812173710_copy_status_stats.rb @@ -0,0 +1,19 @@ +class CopyStatusStats < ActiveRecord::Migration[5.2] + disable_ddl_transaction! + + def up + safety_assured do + execute <<-SQL.squish + INSERT INTO status_stats (status_id, reblogs_count, favourites_count) + SELECT id, reblogs_count, favourites_count + FROM statuses + ON CONFLICT (status_id) DO UPDATE + SET reblogs_count = EXCLUDED.reblogs_count, favourites_count = EXCLUDED.favourites_count + SQL + end + end + + def down + # Nothing + end +end diff --git a/db/post_migrate/20180813113448_copy_status_stats_cleanup.rb b/db/post_migrate/20180813113448_copy_status_stats_cleanup.rb new file mode 100644 index 00000000000..f3ae772c79e --- /dev/null +++ b/db/post_migrate/20180813113448_copy_status_stats_cleanup.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class CopyStatusStatsCleanup < ActiveRecord::Migration[5.2] + disable_ddl_transaction! + + def change + safety_assured do + remove_column :statuses, :reblogs_count, :integer, default: 0, null: false + remove_column :statuses, :favourites_count, :integer, default: 0, null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb index edb5a023c7e..2cf7b849a90 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: 2018_08_12_123222) do +ActiveRecord::Schema.define(version: 2018_08_13_113448) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -456,6 +456,16 @@ ActiveRecord::Schema.define(version: 2018_08_12_123222) do t.index ["account_id", "status_id"], name: "index_status_pins_on_account_id_and_status_id", unique: true end + create_table "status_stats", force: :cascade do |t| + t.bigint "status_id", null: false + t.bigint "replies_count", default: 0, null: false + t.bigint "reblogs_count", default: 0, null: false + t.bigint "favourites_count", default: 0, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["status_id"], name: "index_status_stats_on_status_id", unique: true + end + create_table "statuses", id: :bigint, default: -> { "timestamp_id('statuses'::text)" }, force: :cascade do |t| t.string "uri" t.text "text", default: "", null: false @@ -468,8 +478,6 @@ ActiveRecord::Schema.define(version: 2018_08_12_123222) do t.integer "visibility", default: 0, null: false t.text "spoiler_text", default: "", null: false t.boolean "reply", default: false, null: false - t.integer "favourites_count", default: 0, null: false - t.integer "reblogs_count", default: 0, null: false t.string "language" t.bigint "conversation_id" t.boolean "local" @@ -630,6 +638,7 @@ ActiveRecord::Schema.define(version: 2018_08_12_123222) do add_foreign_key "session_activations", "users", name: "fk_e5fda67334", on_delete: :cascade add_foreign_key "status_pins", "accounts", name: "fk_d4cb435b62", on_delete: :cascade add_foreign_key "status_pins", "statuses", on_delete: :cascade + add_foreign_key "status_stats", "statuses", on_delete: :cascade add_foreign_key "statuses", "accounts", column: "in_reply_to_account_id", name: "fk_c7fa917661", on_delete: :nullify add_foreign_key "statuses", "accounts", name: "fk_9bda1543f7", on_delete: :cascade add_foreign_key "statuses", "statuses", column: "in_reply_to_id", on_delete: :nullify diff --git a/spec/fabricators/status_stat_fabricator.rb b/spec/fabricators/status_stat_fabricator.rb new file mode 100644 index 00000000000..9c67fd404ae --- /dev/null +++ b/spec/fabricators/status_stat_fabricator.rb @@ -0,0 +1,6 @@ +Fabricator(:status_stat) do + status_id nil + replies_count "" + reblogs_count "" + favourites_count "" +end diff --git a/spec/models/status_stat_spec.rb b/spec/models/status_stat_spec.rb new file mode 100644 index 00000000000..5e9351aff4b --- /dev/null +++ b/spec/models/status_stat_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe StatusStat, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end From be13e95d066bcef058abb88790d5cdff74f57a21 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 14 Aug 2018 20:24:36 +0200 Subject: [PATCH 09/24] Fix null constraint violation in copy status stats migration (#8198) --- db/migrate/20180812173710_copy_status_stats.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/db/migrate/20180812173710_copy_status_stats.rb b/db/migrate/20180812173710_copy_status_stats.rb index 6ecccc0ae65..64a564ca07b 100644 --- a/db/migrate/20180812173710_copy_status_stats.rb +++ b/db/migrate/20180812173710_copy_status_stats.rb @@ -4,8 +4,8 @@ class CopyStatusStats < ActiveRecord::Migration[5.2] def up safety_assured do execute <<-SQL.squish - INSERT INTO status_stats (status_id, reblogs_count, favourites_count) - SELECT id, reblogs_count, favourites_count + INSERT INTO status_stats (status_id, reblogs_count, favourites_count, created_at, updated_at) + SELECT id, reblogs_count, favourites_count, created_at, updated_at FROM statuses ON CONFLICT (status_id) DO UPDATE SET reblogs_count = EXCLUDED.reblogs_count, favourites_count = EXCLUDED.favourites_count From 464daffdf9a37e9a773d224a162fad022890d463 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 14 Aug 2018 20:24:47 +0200 Subject: [PATCH 10/24] Upgrade Doorkeeper to 4.4.1 (#8197) --- Gemfile | 2 +- Gemfile.lock | 4 ++-- ..._change_account_id_nonnullable_in_lists.rb | 2 -- ..._confidential_to_doorkeeper_application.rb | 23 +++++++++++++++++++ db/schema.rb | 3 ++- 5 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 db/migrate/20180814171349_add_confidential_to_doorkeeper_application.rb diff --git a/Gemfile b/Gemfile index 8c2970c41bf..cb34ae2ec15 100644 --- a/Gemfile +++ b/Gemfile @@ -41,7 +41,7 @@ gem 'omniauth-cas', '~> 1.1' gem 'omniauth-saml', '~> 1.10' gem 'omniauth', '~> 1.2' -gem 'doorkeeper', '~> 4.2', '< 4.3' +gem 'doorkeeper', '~> 4.4' gem 'fast_blank', '~> 1.0' gem 'fastimage' gem 'goldfinger', '~> 2.1' diff --git a/Gemfile.lock b/Gemfile.lock index f9cf3d3458b..ba7bdaa7b8f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -181,7 +181,7 @@ GEM docile (1.3.0) domain_name (0.5.20180417) unf (>= 0.0.5, < 1.0.0) - doorkeeper (4.2.6) + doorkeeper (4.4.1) railties (>= 4.2) dotenv (2.2.2) dotenv-rails (2.2.2) @@ -670,7 +670,7 @@ DEPENDENCIES devise (~> 4.4) devise-two-factor (~> 3.0) devise_pam_authenticatable2 (~> 9.1) - doorkeeper (~> 4.2, < 4.3) + doorkeeper (~> 4.4) dotenv-rails (~> 2.2, < 2.3) fabrication (~> 2.20) faker (~> 1.8) diff --git a/db/migrate/20171201000000_change_account_id_nonnullable_in_lists.rb b/db/migrate/20171201000000_change_account_id_nonnullable_in_lists.rb index 120f7440264..3369e3b9e97 100644 --- a/db/migrate/20171201000000_change_account_id_nonnullable_in_lists.rb +++ b/db/migrate/20171201000000_change_account_id_nonnullable_in_lists.rb @@ -1,5 +1,3 @@ -require Rails.root.join('lib', 'mastodon', 'migration_helpers') - class ChangeAccountIdNonnullableInLists < ActiveRecord::Migration[5.1] def change change_column_null :lists, :account_id, false diff --git a/db/migrate/20180814171349_add_confidential_to_doorkeeper_application.rb b/db/migrate/20180814171349_add_confidential_to_doorkeeper_application.rb new file mode 100644 index 00000000000..7077a4e6597 --- /dev/null +++ b/db/migrate/20180814171349_add_confidential_to_doorkeeper_application.rb @@ -0,0 +1,23 @@ +require Rails.root.join('lib', 'mastodon', 'migration_helpers') + +class AddConfidentialToDoorkeeperApplication < ActiveRecord::Migration[5.2] + include Mastodon::MigrationHelpers + + disable_ddl_transaction! + + def up + safety_assured do + add_column_with_default( + :oauth_applications, + :confidential, + :boolean, + allow_null: false, + default: true # maintaining backwards compatibility: require secrets + ) + end + end + + def down + remove_column :oauth_applications, :confidential + end +end diff --git a/db/schema.rb b/db/schema.rb index 2cf7b849a90..8e924297342 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: 2018_08_13_113448) do +ActiveRecord::Schema.define(version: 2018_08_14_171349) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -349,6 +349,7 @@ ActiveRecord::Schema.define(version: 2018_08_13_113448) do t.string "website" t.string "owner_type" t.bigint "owner_id" + t.boolean "confidential", default: true, null: false t.index ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type" t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true end From ec2c516ab865ea63b5e7bc4405d0141d377e3e12 Mon Sep 17 00:00:00 2001 From: ThibG Date: Tue, 14 Aug 2018 21:51:17 +0200 Subject: [PATCH 11/24] Various fixes regarding the video position slider (#8201) * Prevent default event handling when clicking on the video position slider This prevents accidental text selection when clicking on the position slider. * Fix bug when clicking on video position slider before starting the video * Slightly more aggressive video preloading - Preload video metadata if the video is loaded in detailed view, as it is likely to get played, and metadata is useful for seeking in the video. - Preload video data if it's fullscreen as it is extremely likely to get played right after being put in fullscreen (although those are two steps). - Preload video data if the user has clicked the position slider, as the video will play as soon as the mouse button is released, and video metadata is needed to properly seek into the video. --- .../mastodon/features/video/index.js | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/app/javascript/mastodon/features/video/index.js b/app/javascript/mastodon/features/video/index.js index 47a165e1698..55ea32acbe8 100644 --- a/app/javascript/mastodon/features/video/index.js +++ b/app/javascript/mastodon/features/video/index.js @@ -158,6 +158,9 @@ export default class Video extends React.PureComponent { this.setState({ dragging: true }); this.video.pause(); this.handleMouseMove(e); + + e.preventDefault(); + e.stopPropagation(); } handleMouseUp = () => { @@ -174,8 +177,10 @@ export default class Video extends React.PureComponent { const { x } = getPointerPosition(this.seek, e); const currentTime = Math.floor(this.video.duration * x); - this.video.currentTime = currentTime; - this.setState({ currentTime }); + if (!isNaN(currentTime)) { + this.video.currentTime = currentTime; + this.setState({ currentTime }); + } }, 60); togglePlay = () => { @@ -281,6 +286,15 @@ export default class Video extends React.PureComponent { playerStyle.height = height; } + let preload; + if (startTime || fullscreen || dragging) { + preload = 'auto'; + } else if (detailed) { + preload = 'metadata'; + } else { + preload = 'none'; + } + return (
Date: Tue, 14 Aug 2018 21:56:17 +0200 Subject: [PATCH 12/24] Show exact number of followers/statuses on export page/in tooltip (#8199) * Show exact number of followers/statuses on export page/in tooltip * Fix tests --- .../features/account/components/action_bar.js | 6 +++--- app/models/export.rb | 10 +++++++++- app/views/accounts/_header.html.haml | 6 +++--- app/views/settings/exports/show.html.haml | 14 +++++++++++--- app/views/settings/imports/show.html.haml | 11 +++++++---- spec/models/export_spec.rb | 6 +++--- 6 files changed, 36 insertions(+), 17 deletions(-) diff --git a/app/javascript/mastodon/features/account/components/action_bar.js b/app/javascript/mastodon/features/account/components/action_bar.js index 43b4811e103..bc6f86628e0 100644 --- a/app/javascript/mastodon/features/account/components/action_bar.js +++ b/app/javascript/mastodon/features/account/components/action_bar.js @@ -147,17 +147,17 @@ export default class ActionBar extends React.PureComponent {
- + {shortNumberFormat(account.get('statuses_count'))} - + {shortNumberFormat(account.get('following_count'))} - + {shortNumberFormat(account.get('followers_count'))} diff --git a/app/models/export.rb b/app/models/export.rb index f0d5dd2557d..0eeac0dc074 100644 --- a/app/models/export.rb +++ b/app/models/export.rb @@ -24,8 +24,16 @@ class Export account.media_attachments.sum(:file_file_size) end + def total_statuses + account.statuses_count + end + def total_follows - account.following.count + account.following_count + end + + def total_followers + account.followers_count end def total_blocks diff --git a/app/views/accounts/_header.html.haml b/app/views/accounts/_header.html.haml index d3b9893c419..caf03bd7cb9 100644 --- a/app/views/accounts/_header.html.haml +++ b/app/views/accounts/_header.html.haml @@ -14,17 +14,17 @@ .public-account-header__tabs__tabs .details-counters .counter{ class: active_nav_class(short_account_url(account)) } - = link_to short_account_url(account), class: 'u-url u-uid' do + = link_to short_account_url(account), class: 'u-url u-uid', title: number_with_delimiter(account.statuses_count) do %span.counter-number= number_to_human account.statuses_count, strip_insignificant_zeros: true %span.counter-label= t('accounts.posts') .counter{ class: active_nav_class(account_following_index_url(account)) } - = link_to account_following_index_url(account) do + = link_to account_following_index_url(account), title: number_with_delimiter(account.following_count) do %span.counter-number= number_to_human account.following_count, strip_insignificant_zeros: true %span.counter-label= t('accounts.following') .counter{ class: active_nav_class(account_followers_url(account)) } - = link_to account_followers_url(account) do + = link_to account_followers_url(account), title: number_with_delimiter(account.followers_count) do %span.counter-number= number_to_human account.followers_count, strip_insignificant_zeros: true %span.counter-label= t('accounts.followers') .spacer diff --git a/app/views/settings/exports/show.html.haml b/app/views/settings/exports/show.html.haml index 30cd2691407..ef2d2b89418 100644 --- a/app/views/settings/exports/show.html.haml +++ b/app/views/settings/exports/show.html.haml @@ -8,17 +8,25 @@ %th= t('exports.storage') %td= number_to_human_size @export.total_storage %td + %tr + %th= t('accounts.statuses') + %td= number_with_delimiter @export.total_statuses + %td %tr %th= t('exports.follows') - %td= number_to_human @export.total_follows + %td= number_with_delimiter @export.total_follows %td= table_link_to 'download', t('exports.csv'), settings_exports_follows_path(format: :csv) + %tr + %th= t('accounts.followers') + %td= number_with_delimiter @export.total_followers + %td %tr %th= t('exports.blocks') - %td= number_to_human @export.total_blocks + %td= number_with_delimiter @export.total_blocks %td= table_link_to 'download', t('exports.csv'), settings_exports_blocks_path(format: :csv) %tr %th= t('exports.mutes') - %td= number_to_human @export.total_mutes + %td= number_with_delimiter @export.total_mutes %td= table_link_to 'download', t('exports.csv'), settings_exports_mutes_path(format: :csv) %p.muted-hint= t('exports.archive_takeout.hint_html') diff --git a/app/views/settings/imports/show.html.haml b/app/views/settings/imports/show.html.haml index 991dd4e941d..2b43cb13492 100644 --- a/app/views/settings/imports/show.html.haml +++ b/app/views/settings/imports/show.html.haml @@ -1,11 +1,14 @@ - content_for :page_title do = t('settings.import') -%p.hint= t('imports.preface') - = simple_form_for @import, url: settings_import_path do |f| - = f.input :type, collection: Import.types.keys, wrapper: :with_label, include_blank: false, label_method: lambda { |type| I18n.t("imports.types.#{type}") }, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li' - = f.input :data, wrapper: :with_label, hint: t('simple_form.hints.imports.data') + %p.hint= t('imports.preface') + + .field-group + = f.input :type, collection: Import.types.keys, wrapper: :with_label, include_blank: false, label_method: lambda { |type| I18n.t("imports.types.#{type}") }, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li' + + .field-group + = f.input :data, wrapper: :with_block_label, hint: t('simple_form.hints.imports.data') .actions = f.button :button, t('imports.upload'), type: :submit diff --git a/spec/models/export_spec.rb b/spec/models/export_spec.rb index 6daa4614575..277dcc52649 100644 --- a/spec/models/export_spec.rb +++ b/spec/models/export_spec.rb @@ -48,17 +48,17 @@ describe Export do describe 'total_follows' do it 'returns the total number of the followed accounts' do target_accounts.each(&account.method(:follow!)) - expect(Export.new(account).total_follows).to eq 2 + expect(Export.new(account.reload).total_follows).to eq 2 end it 'returns the total number of the blocked accounts' do target_accounts.each(&account.method(:block!)) - expect(Export.new(account).total_blocks).to eq 2 + expect(Export.new(account.reload).total_blocks).to eq 2 end it 'returns the total number of the muted accounts' do target_accounts.each(&account.method(:mute!)) - expect(Export.new(account).total_mutes).to eq 2 + expect(Export.new(account.reload).total_mutes).to eq 2 end end end From b0f4fe456b15bfe74b9feca247d0ac67a8ba21fb Mon Sep 17 00:00:00 2001 From: Immae Date: Wed, 15 Aug 2018 18:12:44 +0200 Subject: [PATCH 13/24] Add ldap search filter (#8151) --- .env.production.sample | 1 + config/initializers/devise.rb | 3 +++ lib/devise/ldap_authenticatable.rb | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.env.production.sample b/.env.production.sample index ebb0788781d..349daedd8f3 100644 --- a/.env.production.sample +++ b/.env.production.sample @@ -162,6 +162,7 @@ STREAMING_CLUSTER_NUM=1 # LDAP_BIND_DN= # LDAP_PASSWORD= # LDAP_UID=cn +# LDAP_SEARCH_FILTER="%{uid}=%{email}" # PAM authentication (optional) # PAM authentication uses for the email generation the "email" pam variable diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 8532c9d9a28..cd9bacf6803 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -59,6 +59,8 @@ module Devise @@ldap_password = nil mattr_accessor :ldap_tls_no_verify @@ldap_tls_no_verify = false + mattr_accessor :ldap_search_filter + @@ldap_search_filter = nil class Strategies::PamAuthenticatable def valid? @@ -362,5 +364,6 @@ Devise.setup do |config| config.ldap_password = ENV.fetch('LDAP_PASSWORD') config.ldap_uid = ENV.fetch('LDAP_UID', 'cn') config.ldap_tls_no_verify = ENV['LDAP_TLS_NO_VERIFY'] == 'true' + config.ldap_search_filter = ENV.fetch('LDAP_SEARCH_FILTER', '%{uid}=%{email}') end end diff --git a/lib/devise/ldap_authenticatable.rb b/lib/devise/ldap_authenticatable.rb index ef786fbb77a..534c7a85175 100644 --- a/lib/devise/ldap_authenticatable.rb +++ b/lib/devise/ldap_authenticatable.rb @@ -24,7 +24,8 @@ module Devise connect_timeout: 10 ) - if (user_info = ldap.bind_as(base: Devise.ldap_base, filter: "(#{Devise.ldap_uid}=#{email})", password: password)) + filter = format(Devise.ldap_search_filter, uid: Devise.ldap_uid, email: email) + if (user_info = ldap.bind_as(base: Devise.ldap_base, filter: filter, password: password)) user = User.ldap_get_user(user_info.first) success!(user) else From 4df9cabb22cbed8f9cd8af45325ecdcc7c72d6cb Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 15 Aug 2018 19:29:52 +0200 Subject: [PATCH 14/24] Display replies count in web UI (#8181) --- .../mastodon/components/status_action_bar.js | 12 ++++++++++- .../styles/mastodon/components.scss | 20 +++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/app/javascript/mastodon/components/status_action_bar.js b/app/javascript/mastodon/components/status_action_bar.js index 0ae21e3f042..c799d4e9860 100644 --- a/app/javascript/mastodon/components/status_action_bar.js +++ b/app/javascript/mastodon/components/status_action_bar.js @@ -32,6 +32,16 @@ const messages = defineMessages({ embed: { id: 'status.embed', defaultMessage: 'Embed' }, }); +const obfuscatedCount = count => { + if (count < 0) { + return 0; + } else if (count <= 1) { + return count; + } else { + return '1+'; + } +}; + @injectIntl export default class StatusActionBar extends ImmutablePureComponent { @@ -194,7 +204,7 @@ export default class StatusActionBar extends ImmutablePureComponent { return (
- +
{obfuscatedCount(status.get('replies_count'))}
{shareButton} diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 708a6868a32..931f1aa0d5f 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -921,15 +921,31 @@ align-items: center; display: flex; margin-top: 8px; + + &__counter { + display: inline-flex; + margin-right: 11px; + align-items: center; + + .status__action-bar-button { + margin-right: 4px; + } + + &__label { + display: inline-block; + width: 14px; + font-size: 12px; + font-weight: 500; + color: $action-button-color; + } + } } .status__action-bar-button { - float: left; margin-right: 18px; } .status__action-bar-dropdown { - float: left; height: 23.15px; width: 23.15px; } From af912fb308cffe98f52e155484c4c6b0a62efceb Mon Sep 17 00:00:00 2001 From: ThibG Date: Wed, 15 Aug 2018 19:33:36 +0200 Subject: [PATCH 15/24] Allow accessing local private/DM messages by URL (#8196) * Allow accessing local private/DM messages by URL (Provided the user pasting the URL is authorized to see the toot, obviously) * Fix SearchServiceSpec tests --- app/services/resolve_url_service.rb | 10 ++++++++-- app/services/search_service.rb | 2 +- spec/services/search_service_spec.rb | 6 +++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/app/services/resolve_url_service.rb b/app/services/resolve_url_service.rb index a068c1ed86a..1db1917e27c 100644 --- a/app/services/resolve_url_service.rb +++ b/app/services/resolve_url_service.rb @@ -2,11 +2,13 @@ class ResolveURLService < BaseService include JsonLdHelper + include Authorization attr_reader :url - def call(url) + def call(url, on_behalf_of: nil) @url = url + @on_behalf_of = on_behalf_of return process_local_url if local_url? @@ -84,6 +86,10 @@ class ResolveURLService < BaseService def check_local_status(status) return if status.nil? - status if status.public_visibility? || status.unlisted_visibility? + authorize_with @on_behalf_of, status, :show? + status + rescue Mastodon::NotPermittedError + # Do not disclose the existence of status the user is not authorized to see + nil end end diff --git a/app/services/search_service.rb b/app/services/search_service.rb index 5bb395942da..cc1fcb52f0a 100644 --- a/app/services/search_service.rb +++ b/app/services/search_service.rb @@ -53,7 +53,7 @@ class SearchService < BaseService end def url_resource - @_url_resource ||= ResolveURLService.new.call(query) + @_url_resource ||= ResolveURLService.new.call(query, on_behalf_of: @account) end def url_resource_symbol diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb index 673de523385..671080f1d98 100644 --- a/spec/services/search_service_spec.rb +++ b/spec/services/search_service_spec.rb @@ -29,7 +29,7 @@ describe SearchService, type: :service do allow(ResolveURLService).to receive(:new).and_return(service) results = subject.call(@query, 10) - expect(service).to have_received(:call).with(@query) + expect(service).to have_received(:call).with(@query, on_behalf_of: nil) expect(results).to eq empty_results end end @@ -41,7 +41,7 @@ describe SearchService, type: :service do allow(ResolveURLService).to receive(:new).and_return(service) results = subject.call(@query, 10) - expect(service).to have_received(:call).with(@query) + expect(service).to have_received(:call).with(@query, on_behalf_of: nil) expect(results).to eq empty_results.merge(accounts: [account]) end end @@ -53,7 +53,7 @@ describe SearchService, type: :service do allow(ResolveURLService).to receive(:new).and_return(service) results = subject.call(@query, 10) - expect(service).to have_received(:call).with(@query) + expect(service).to have_received(:call).with(@query, on_behalf_of: nil) expect(results).to eq empty_results.merge(statuses: [status]) end end From 625b5a567bb94a557572176357cd2381ac17a06d Mon Sep 17 00:00:00 2001 From: ThibG Date: Wed, 15 Aug 2018 19:38:56 +0200 Subject: [PATCH 16/24] Get rid of the Content Warning rainbows (#8129) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Disable the animated rainbow text when the “Reduce motion” setting is set * Get rid of the Content Warning rainbows * Revert to default color for CWs in admin view Since that colorscheme is apparently broken for some colorblind people. * Use HTML5's details and summary for statuses with CWs in admin interface --- app/javascript/styles/mastodon/tables.scss | 16 ++++------------ app/views/admin/reports/_status.html.haml | 12 +++++++----- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/app/javascript/styles/mastodon/tables.scss b/app/javascript/styles/mastodon/tables.scss index e54c55947e6..c2206cf55dd 100644 --- a/app/javascript/styles/mastodon/tables.scss +++ b/app/javascript/styles/mastodon/tables.scss @@ -1,9 +1,3 @@ -@keyframes Swag { - 0% { background-position: 0% 0%; } - 50% { background-position: 100% 0%; } - 100% { background-position: 200% 0%; } -} - .table { width: 100%; max-width: 100%; @@ -191,14 +185,12 @@ a.table-action-link { .status__content { padding-top: 0; + summary { + display: list-item; + } + strong { font-weight: 700; - background: linear-gradient(to right, orange , yellow, green, cyan, blue, violet,orange , yellow, green, cyan, blue, violet); - background-size: 200% 100%; - -webkit-background-clip: text; - background-clip: text; - color: transparent; - animation: Swag 2s linear 0s infinite; } } } diff --git a/app/views/admin/reports/_status.html.haml b/app/views/admin/reports/_status.html.haml index 5e174f312ec..5b410ec84d6 100644 --- a/app/views/admin/reports/_status.html.haml +++ b/app/views/admin/reports/_status.html.haml @@ -3,11 +3,13 @@ = f.check_box :status_ids, { multiple: true, include_hidden: false }, status.id .batch-table__row__content .status__content>< - - unless status.proper.spoiler_text.blank? - %p>< - %strong> Content warning: #{Formatter.instance.format_spoiler(status.proper)} - - = Formatter.instance.format(status.proper, custom_emojify: true) + - if status.proper.spoiler_text.blank? + = Formatter.instance.format(status.proper, custom_emojify: true) + - else + %details< + %summary>< + %strong> Content warning: #{Formatter.instance.format_spoiler(status.proper)} + = Formatter.instance.format(status.proper, custom_emojify: true) - unless status.proper.media_attachments.empty? - if status.proper.media_attachments.first.video? From 4f24dc31dc58cedc3820baf258112e9bed2b3e69 Mon Sep 17 00:00:00 2001 From: ThibG Date: Wed, 15 Aug 2018 20:23:12 +0200 Subject: [PATCH 17/24] Fix FixAccountsUniqueIndex migration (#8212) --- db/migrate/20180528141303_fix_accounts_unique_index.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/db/migrate/20180528141303_fix_accounts_unique_index.rb b/db/migrate/20180528141303_fix_accounts_unique_index.rb index 624ea229e4f..bd4e158b7ec 100644 --- a/db/migrate/20180528141303_fix_accounts_unique_index.rb +++ b/db/migrate/20180528141303_fix_accounts_unique_index.rb @@ -6,6 +6,10 @@ class FixAccountsUniqueIndex < ActiveRecord::Migration[5.2] def local? domain.nil? end + + def acct + local? ? username : "#{username}@#{domain}" + end end disable_ddl_transaction! From be0b372a22347fcad9d4e4e4199e9f59caa5f901 Mon Sep 17 00:00:00 2001 From: ThibG Date: Wed, 15 Aug 2018 23:38:31 +0200 Subject: [PATCH 18/24] Fix admin.js starting rails-ujs twice (fixes #8168) (#8213) --- app/javascript/packs/admin.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/javascript/packs/admin.js b/app/javascript/packs/admin.js index b151b4af087..5dbcc03d394 100644 --- a/app/javascript/packs/admin.js +++ b/app/javascript/packs/admin.js @@ -1,7 +1,4 @@ import { delegate } from 'rails-ujs'; -import { start } from '../mastodon/common'; - -start(); function handleDeleteStatus(event) { const [data] = event.detail; From d78474264da0bd51e021c5f04311515e10ac828e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 16 Aug 2018 14:21:52 +0200 Subject: [PATCH 19/24] Update reply counters only if the reply is public/unlisted (#8211) --- app/models/status.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/status.rb b/app/models/status.rb index 1c87f2566f8..2eed336595a 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -456,8 +456,8 @@ class Status < ApplicationRecord Account.where(id: account_id).update_all('statuses_count = COALESCE(statuses_count, 0) + 1') end - thread.increment_count!(:replies_count) if in_reply_to_id.present? reblog.increment_count!(:reblogs_count) if reblog? + thread.increment_count!(:replies_count) if in_reply_to_id.present? && (public_visibility? || unlisted_visibility?) end def decrement_counter_caches @@ -469,7 +469,7 @@ class Status < ApplicationRecord Account.where(id: account_id).update_all('statuses_count = GREATEST(COALESCE(statuses_count, 0) - 1, 0)') end - thread.decrement_count!(:replies_count) if in_reply_to_id.present? reblog.decrement_count!(:reblogs_count) if reblog? + thread.decrement_count!(:replies_count) if in_reply_to_id.present? && (public_visibility? || unlisted_visibility?) end end From c98681c358c1f32f044992d2fe97f2e7843c83d1 Mon Sep 17 00:00:00 2001 From: ThibG Date: Thu, 16 Aug 2018 20:02:52 +0200 Subject: [PATCH 20/24] Do not error out when performing admin actions on no statuses (#8220) Fixes the other issue with #8168 --- app/controllers/admin/statuses_controller.rb | 4 ++++ config/locales/en.yml | 1 + 2 files changed, 5 insertions(+) diff --git a/app/controllers/admin/statuses_controller.rb b/app/controllers/admin/statuses_controller.rb index 382bfc4a23f..a69f1208454 100644 --- a/app/controllers/admin/statuses_controller.rb +++ b/app/controllers/admin/statuses_controller.rb @@ -28,6 +28,10 @@ module Admin @form = Form::StatusBatch.new(form_status_batch_params.merge(current_account: current_account, action: action_from_button)) flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save + redirect_to admin_account_statuses_path(@account.id, current_params) + rescue ActionController::ParameterMissing + flash[:alert] = I18n.t('admin.statuses.no_status_selected') + redirect_to admin_account_statuses_path(@account.id, current_params) end diff --git a/config/locales/en.yml b/config/locales/en.yml index a5e4ab75d68..9c2800433e5 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -401,6 +401,7 @@ en: media: title: Media no_media: No media + no_status_selected: No statuses were changed as none were selected title: Account statuses with_media: With media subscriptions: From 106fa28a00ae9b336c05a25b800b9897bd61820d Mon Sep 17 00:00:00 2001 From: ThibG Date: Thu, 16 Aug 2018 20:05:26 +0200 Subject: [PATCH 21/24] Prevent actions log from crashing when displaying deleted status (fixes #8133) (#8219) --- app/helpers/admin/action_logs_helper.rb | 6 +++++- config/locales/en.yml | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/helpers/admin/action_logs_helper.rb b/app/helpers/admin/action_logs_helper.rb index 4c663211e71..85bd303046e 100644 --- a/app/helpers/admin/action_logs_helper.rb +++ b/app/helpers/admin/action_logs_helper.rb @@ -34,7 +34,11 @@ module Admin::ActionLogsHelper link_to attributes['domain'], "https://#{attributes['domain']}" when 'Status' tmp_status = Status.new(attributes) - link_to tmp_status.account&.acct || "##{tmp_status.account_id}", TagManager.instance.url_for(tmp_status) + if tmp_status.account + link_to tmp_status.account&.acct || "##{tmp_status.account_id}", admin_account_path(tmp_status.account_id) + else + I18n.t('admin.action_logs.deleted_status') + end end end diff --git a/config/locales/en.yml b/config/locales/en.yml index 9c2800433e5..cc24a02cfe7 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -184,6 +184,7 @@ en: unsuspend_account: "%{name} unsuspended %{target}'s account" update_custom_emoji: "%{name} updated emoji %{target}" update_status: "%{name} updated status by %{target}" + deleted_status: "(deleted status)" title: Audit log custom_emojis: by_domain: Domain From 4601a58ac24f2c97ba4934445da694ca18308b81 Mon Sep 17 00:00:00 2001 From: ThibG Date: Fri, 17 Aug 2018 14:07:38 +0200 Subject: [PATCH 22/24] Defer scrollIntoView after DOM is drawn (fixes #8239) (#8242) --- app/javascript/mastodon/features/status/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/javascript/mastodon/features/status/index.js b/app/javascript/mastodon/features/status/index.js index 89387ca434e..0ffeaa4dc11 100644 --- a/app/javascript/mastodon/features/status/index.js +++ b/app/javascript/mastodon/features/status/index.js @@ -355,7 +355,9 @@ export default class Status extends ImmutablePureComponent { if (status && ancestorsIds && ancestorsIds.size > 0) { const element = this.node.querySelectorAll('.focusable')[ancestorsIds.size - 1]; - element.scrollIntoView(true); + window.requestAnimationFrame(() => { + element.scrollIntoView(true); + }); this._scrolledIntoView = true; } } From 1ee675d68bfd2034183a03408a2377c338dfac41 Mon Sep 17 00:00:00 2001 From: ThibG Date: Fri, 17 Aug 2018 14:08:17 +0200 Subject: [PATCH 23/24] Use correct activity id in Accept when receiving duplicate Follow (fixes #8218) (#8244) --- app/lib/activitypub/activity/follow.rb | 2 +- app/services/authorize_follow_service.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/lib/activitypub/activity/follow.rb b/app/lib/activitypub/activity/follow.rb index 826dcf18ef2..c458326482c 100644 --- a/app/lib/activitypub/activity/follow.rb +++ b/app/lib/activitypub/activity/follow.rb @@ -13,7 +13,7 @@ class ActivityPub::Activity::Follow < ActivityPub::Activity # Fast-forward repeat follow requests if @account.following?(target_account) - AuthorizeFollowService.new.call(@account, target_account, skip_follow_request: true) + AuthorizeFollowService.new.call(@account, target_account, skip_follow_request: true, follow_request_uri: @json['id']) return end diff --git a/app/services/authorize_follow_service.rb b/app/services/authorize_follow_service.rb index f47d488f11c..1674239df73 100644 --- a/app/services/authorize_follow_service.rb +++ b/app/services/authorize_follow_service.rb @@ -3,7 +3,7 @@ class AuthorizeFollowService < BaseService def call(source_account, target_account, **options) if options[:skip_follow_request] - follow_request = FollowRequest.new(account: source_account, target_account: target_account) + follow_request = FollowRequest.new(account: source_account, target_account: target_account, uri: options[:follow_request_uri]) else follow_request = FollowRequest.find_by!(account: source_account, target_account: target_account) follow_request.authorize! From 59f7f4c923494bb8dd6f2881a1610c7b51240d9c Mon Sep 17 00:00:00 2001 From: ThibG Date: Fri, 17 Aug 2018 16:24:56 +0200 Subject: [PATCH 24/24] Implement Undo { Accept { Follow } } (fixes #8234) (#8245) * Add Follow#revoke_request! * Implement Undo { Accept { Follow } } (fixes #8234) --- app/lib/activitypub/activity/undo.rb | 6 +++++ app/models/follow.rb | 5 +++++ spec/lib/activitypub/activity/undo_spec.rb | 26 ++++++++++++++++++++++ spec/models/follow_spec.rb | 16 +++++++++++++ 4 files changed, 53 insertions(+) diff --git a/app/lib/activitypub/activity/undo.rb b/app/lib/activitypub/activity/undo.rb index cbed417c4e8..64c2be7d9c2 100644 --- a/app/lib/activitypub/activity/undo.rb +++ b/app/lib/activitypub/activity/undo.rb @@ -5,6 +5,8 @@ class ActivityPub::Activity::Undo < ActivityPub::Activity case @object['type'] when 'Announce' undo_announce + when 'Accept' + undo_accept when 'Follow' undo_follow when 'Like' @@ -27,6 +29,10 @@ class ActivityPub::Activity::Undo < ActivityPub::Activity end end + def undo_accept + ::Follow.find_by(target_account: @account, uri: target_uri)&.revoke_request! + end + def undo_follow target_account = account_from_uri(target_uri) diff --git a/app/models/follow.rb b/app/models/follow.rb index 3fce14b9ac5..714f4e8981f 100644 --- a/app/models/follow.rb +++ b/app/models/follow.rb @@ -32,6 +32,11 @@ class Follow < ApplicationRecord false # Force uri_for to use uri attribute end + def revoke_request! + FollowRequest.create!(account: account, target_account: target_account, show_reblogs: show_reblogs, uri: uri) + destroy! + end + before_validation :set_uri, only: :create after_destroy :remove_endorsements diff --git a/spec/lib/activitypub/activity/undo_spec.rb b/spec/lib/activitypub/activity/undo_spec.rb index e01c5e03e70..9545e1f46af 100644 --- a/spec/lib/activitypub/activity/undo_spec.rb +++ b/spec/lib/activitypub/activity/undo_spec.rb @@ -52,6 +52,32 @@ RSpec.describe ActivityPub::Activity::Undo do end end + context 'with Accept' do + let(:recipient) { Fabricate(:account) } + let(:object_json) do + { + id: 'bar', + type: 'Accept', + actor: ActivityPub::TagManager.instance.uri_for(sender), + object: 'follow-to-revoke', + } + end + + before do + recipient.follow!(sender, uri: 'follow-to-revoke') + end + + it 'deletes follow from recipient to sender' do + subject.perform + expect(recipient.following?(sender)).to be false + end + + it 'creates a follow request from recipient to sender' do + subject.perform + expect(recipient.requested?(sender)).to be true + end + end + context 'with Block' do let(:recipient) { Fabricate(:account) } diff --git a/spec/models/follow_spec.rb b/spec/models/follow_spec.rb index 43175d8526a..f221973b6d7 100644 --- a/spec/models/follow_spec.rb +++ b/spec/models/follow_spec.rb @@ -37,4 +37,20 @@ RSpec.describe Follow, type: :model do expect(a[1]).to eq follow0 end end + + describe 'revoke_request!' do + let(:follow) { Fabricate(:follow, account: account, target_account: target_account) } + let(:account) { Fabricate(:account) } + let(:target_account) { Fabricate(:account) } + + it 'revokes the follow relation' do + follow.revoke_request! + expect(account.following?(target_account)).to be false + end + + it 'creates a follow request' do + follow.revoke_request! + expect(account.requested?(target_account)).to be true + end + end end