From 66acf8203b87bc88402edd7eec9ec00f48bbc42c Mon Sep 17 00:00:00 2001 From: Daigo 3 Dango Date: Thu, 16 Jul 2020 10:01:34 -1000 Subject: [PATCH 01/19] Stop using heroku-buildpack-nodejs (#14341) heroku-buildpack-ruby started to install Node 12 by default. This makes it possible to run Mastodon without heroku-buildpack-nodejs. --- app.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/app.json b/app.json index 211f17d812e..e4f7cf403ec 100644 --- a/app.json +++ b/app.json @@ -88,9 +88,6 @@ { "url": "https://github.com/heroku/heroku-buildpack-apt" }, - { - "url": "heroku/nodejs" - }, { "url": "heroku/ruby" } From d668fd8b83fdbb38291927762722d47306788ab1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2020 07:06:45 +0200 Subject: [PATCH 02/19] Bump lodash from 4.17.15 to 4.17.19 (#14321) Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 178c18d0ed2..37c6d97d3c7 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "intl-relativeformat": "^6.4.3", "is-nan": "^1.3.0", "js-yaml": "^3.13.1", - "lodash": "^4.17.14", + "lodash": "^4.17.19", "mark-loader": "^0.1.6", "marky": "^1.2.1", "mini-css-extract-plugin": "^0.9.0", diff --git a/yarn.lock b/yarn.lock index 5b71b6b79b4..5449ae10ff5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6969,10 +6969,10 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.3.0, lodash@~4.17.12: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== +lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.3.0, lodash@~4.17.12: + version "4.17.19" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" + integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== loglevel@^1.6.8: version "1.6.8" From 85bc0f9639c9c1ecccfa6963929b6c405fb8452c Mon Sep 17 00:00:00 2001 From: ThibG Date: Fri, 17 Jul 2020 07:07:18 +0200 Subject: [PATCH 03/19] Fix audio player controls color in mastodon-light theme (#14338) Fixes #14337 The new audio player sets the background and foreground colors automatically based on the thumbnail of the audio file, but the mastodon-light theme overrides the controls' colors with a hardcoded color, which sometimes make them unreadable. --- app/javascript/styles/mastodon-light/diff.scss | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/javascript/styles/mastodon-light/diff.scss b/app/javascript/styles/mastodon-light/diff.scss index 7a846bcc678..8c8d69fc47e 100644 --- a/app/javascript/styles/mastodon-light/diff.scss +++ b/app/javascript/styles/mastodon-light/diff.scss @@ -767,10 +767,3 @@ html { .compose-form .compose-form__warning { box-shadow: none; } - -.audio-player .video-player__controls button, -.audio-player .video-player__time-sep, -.audio-player .video-player__time-current, -.audio-player .video-player__time-total { - color: $primary-text-color; -} From 322d74fc2aa9db2d05e5bad944661c6edf1660e1 Mon Sep 17 00:00:00 2001 From: ThibG Date: Fri, 17 Jul 2020 07:07:54 +0200 Subject: [PATCH 04/19] Fix boosted toots from blocked account not being retroactively removed from TL (#14339) * Fix boosted toots from blocked account not being retroactively removed from TL Fixes #14301 * Add test for clear_from_timeline --- app/lib/feed_manager.rb | 8 +++++++- spec/lib/feed_manager_spec.rb | 25 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index 53ff31f5ecb..96fa6cfc06e 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -124,9 +124,15 @@ class FeedManager end def clear_from_timeline(account, target_account) + # Clear from timeline all statuses from or mentionning target_account timeline_key = key(:home, account.id) timeline_status_ids = redis.zrange(timeline_key, 0, -1) - target_statuses = Status.where(id: timeline_status_ids, account: target_account) + statuses = Status.where(id: timeline_status_ids).select(:id, :reblog_of_id, :account_id).to_a + reblogged_ids = Status.where(id: statuses.map(&:reblog_of_id).compact, account: target_account).pluck(:id) + with_mentions_ids = Mention.active.where(status_id: statuses.flat_map { |s| [s.id, s.reblog_of_id] }.compact, account: target_account).pluck(:status_id) + target_statuses = statuses.filter do |status| + status.account_id == target_account.id || reblogged_ids.include?(status.reblog_of_id) || with_mentions_ids.include?(status.id) || with_mentions_ids.include?(status.reblog_of_id) + end target_statuses.each do |status| unpush_from_home(account, status) diff --git a/spec/lib/feed_manager_spec.rb b/spec/lib/feed_manager_spec.rb index b996997b136..22eddd2ab6e 100644 --- a/spec/lib/feed_manager_spec.rb +++ b/spec/lib/feed_manager_spec.rb @@ -429,4 +429,29 @@ RSpec.describe FeedManager do expect(Redis.current).to have_received(:publish).with("timeline:#{receiver.id}", deletion) end end + + describe '#clear_from_timeline' do + let(:account) { Fabricate(:account) } + let(:followed_account) { Fabricate(:account) } + let(:target_account) { Fabricate(:account) } + let(:status_1) { Fabricate(:status, account: followed_account) } + let(:status_2) { Fabricate(:status, account: target_account) } + let(:status_3) { Fabricate(:status, account: followed_account, mentions: [Fabricate(:mention, account: target_account)]) } + let(:status_4) { Fabricate(:status, mentions: [Fabricate(:mention, account: target_account)]) } + let(:status_5) { Fabricate(:status, account: followed_account, reblog: status_4) } + let(:status_6) { Fabricate(:status, account: followed_account, reblog: status_2) } + let(:status_7) { Fabricate(:status, account: followed_account) } + + before do + [status_1, status_3, status_5, status_6, status_7].each do |status| + Redis.current.zadd("feed:home:#{account.id}", status.id, status.id) + end + end + + it 'correctly cleans the timeline' do + FeedManager.instance.clear_from_timeline(account, target_account) + + expect(Redis.current.zrange("feed:home:#{account.id}", 0, -1)).to eq [status_1.id.to_s, status_7.id.to_s] + end + end end From 17b1d71536609c6deabcf3b13ec9be0ec9fd793f Mon Sep 17 00:00:00 2001 From: Sasha Sorokin Date: Fri, 17 Jul 2020 12:08:23 +0700 Subject: [PATCH 05/19] Fix following_counter plural to include "one" (#14342) That should've worked just fine, but unfortunately, Crowdin wasn't able to pick up on our non-existent "one" category, thus appending empty translation block to people's translations. Empty block WILL BE used by any ICU FormatMessage library, thus resulting in an empty translation for "one" category, and that requires immediate fix. This commit duplicates contents of the "other" plural category. --- app/javascript/mastodon/components/common_counter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/components/common_counter.js b/app/javascript/mastodon/components/common_counter.js index 4fdf3babfda..e10cd9b7652 100644 --- a/app/javascript/mastodon/components/common_counter.js +++ b/app/javascript/mastodon/components/common_counter.js @@ -37,7 +37,7 @@ export function counterRenderer(counterType, isBold = true) { return (displayNumber, pluralReady) => ( Date: Sat, 18 Jul 2020 18:55:36 +0200 Subject: [PATCH 06/19] Fix keyboard navigation in scrollable lists (#14348) Fixes #14347 --- app/javascript/mastodon/components/scrollable_list.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/components/scrollable_list.js b/app/javascript/mastodon/components/scrollable_list.js index 35740f226a4..2689b18ef3d 100644 --- a/app/javascript/mastodon/components/scrollable_list.js +++ b/app/javascript/mastodon/components/scrollable_list.js @@ -20,7 +20,7 @@ const mapStateToProps = (state, { scrollKey }) => { }; }; -export default @connect(mapStateToProps) +export default @connect(mapStateToProps, null, null, { forwardRef: true }) class ScrollableList extends PureComponent { static contextTypes = { From f2d977914efe0707ac6258c23ebfc68d5bba24e6 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 18 Jul 2020 12:00:59 -0500 Subject: [PATCH 07/19] Set bundle config in local file, and set path (#14351) --- .circleci/config.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9f43a057356..862fa126b7f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -72,11 +72,12 @@ aliases: - run: name: Set bundler settings command: | - bundle config clean 'true' - bundle config deployment 'true' - bundle config with 'pam_authentication' - bundle config without 'development production' - bundle config frozen 'true' + bundle config --local clean 'true' + bundle config --local deployment 'true' + bundle config --local with 'pam_authentication' + bundle config --local without 'development production' + bundle config --local frozen 'true' + bundle config --local path $BUNDLE_PATH - run: name: Install bundler dependencies command: bundle check || (bundle install && bundle clean) From d87958e1775e6aa99b52d21bd8976cd3c76067d6 Mon Sep 17 00:00:00 2001 From: mayaeh Date: Sun, 19 Jul 2020 02:01:16 +0900 Subject: [PATCH 08/19] ran `yarn manage:translations` (#14344) --- app/javascript/mastodon/locales/ar.json | 2 +- app/javascript/mastodon/locales/ast.json | 2 +- app/javascript/mastodon/locales/bg.json | 2 +- app/javascript/mastodon/locales/bn.json | 2 +- app/javascript/mastodon/locales/cs.json | 2 +- app/javascript/mastodon/locales/cy.json | 2 +- app/javascript/mastodon/locales/da.json | 2 +- .../mastodon/locales/defaultMessages.json | 18 +++++++++++++++++- app/javascript/mastodon/locales/en.json | 2 +- app/javascript/mastodon/locales/et.json | 2 +- app/javascript/mastodon/locales/eu.json | 2 +- app/javascript/mastodon/locales/fi.json | 2 +- app/javascript/mastodon/locales/ga.json | 2 +- app/javascript/mastodon/locales/he.json | 2 +- app/javascript/mastodon/locales/hi.json | 2 +- app/javascript/mastodon/locales/hr.json | 2 +- app/javascript/mastodon/locales/id.json | 2 +- app/javascript/mastodon/locales/io.json | 2 +- app/javascript/mastodon/locales/is.json | 2 +- app/javascript/mastodon/locales/ka.json | 2 +- app/javascript/mastodon/locales/kab.json | 2 +- app/javascript/mastodon/locales/kk.json | 2 +- app/javascript/mastodon/locales/kn.json | 2 +- app/javascript/mastodon/locales/ku.json | 2 +- app/javascript/mastodon/locales/lt.json | 2 +- app/javascript/mastodon/locales/lv.json | 2 +- app/javascript/mastodon/locales/mk.json | 2 +- app/javascript/mastodon/locales/ml.json | 2 +- app/javascript/mastodon/locales/mr.json | 2 +- app/javascript/mastodon/locales/ms.json | 2 +- app/javascript/mastodon/locales/nl.json | 2 +- app/javascript/mastodon/locales/nn.json | 2 +- app/javascript/mastodon/locales/no.json | 2 +- app/javascript/mastodon/locales/oc.json | 2 +- app/javascript/mastodon/locales/pl.json | 2 +- app/javascript/mastodon/locales/ro.json | 2 +- app/javascript/mastodon/locales/sc.json | 2 +- app/javascript/mastodon/locales/sk.json | 2 +- app/javascript/mastodon/locales/sl.json | 2 +- app/javascript/mastodon/locales/sr-Latn.json | 2 +- app/javascript/mastodon/locales/sr.json | 2 +- app/javascript/mastodon/locales/sv.json | 2 +- app/javascript/mastodon/locales/szl.json | 2 +- app/javascript/mastodon/locales/ta.json | 2 +- app/javascript/mastodon/locales/tai.json | 2 +- app/javascript/mastodon/locales/te.json | 2 +- app/javascript/mastodon/locales/th.json | 2 +- app/javascript/mastodon/locales/tr.json | 2 +- app/javascript/mastodon/locales/ug.json | 2 +- app/javascript/mastodon/locales/uk.json | 2 +- app/javascript/mastodon/locales/ur.json | 2 +- app/javascript/mastodon/locales/zh-HK.json | 2 +- app/javascript/mastodon/locales/zh-TW.json | 2 +- 53 files changed, 69 insertions(+), 53 deletions(-) diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json index a0b540432e8..548471edfd8 100644 --- a/app/javascript/mastodon/locales/ar.json +++ b/app/javascript/mastodon/locales/ar.json @@ -16,7 +16,7 @@ "account.followers": "مُتابِعون", "account.followers.empty": "لا أحد يتبع هذا الحساب بعد.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "هذا الحساب لا يتبع أحدًا بعد.", "account.follows_you": "يتابعك", "account.hide_reblogs": "إخفاء ترقيات @{name}", diff --git a/app/javascript/mastodon/locales/ast.json b/app/javascript/mastodon/locales/ast.json index 491faa0570d..6c6232262ef 100644 --- a/app/javascript/mastodon/locales/ast.json +++ b/app/javascript/mastodon/locales/ast.json @@ -16,7 +16,7 @@ "account.followers": "Siguidores", "account.followers.empty": "Naide sigue a esti usuariu entá.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Esti usuariu entá nun sigue a naide.", "account.follows_you": "Síguete", "account.hide_reblogs": "Anubrir les comparticiones de @{name}", diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index 472c88afc74..16520dbad52 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -16,7 +16,7 @@ "account.followers": "Последователи", "account.followers.empty": "Все още никой не следва този потребител.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Този потребител все още не следва никого.", "account.follows_you": "Твой последовател", "account.hide_reblogs": "Hide boosts from @{name}", diff --git a/app/javascript/mastodon/locales/bn.json b/app/javascript/mastodon/locales/bn.json index b41cdf16d17..7de1a10221b 100644 --- a/app/javascript/mastodon/locales/bn.json +++ b/app/javascript/mastodon/locales/bn.json @@ -16,7 +16,7 @@ "account.followers": "অনুসরণকারী", "account.followers.empty": "এই সদস্যকে এখনো কেউ অনুসরণ করে না।.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "এই সদস্য কাওকে এখনো অনুসরণ করেন না.", "account.follows_you": "আপনাকে অনুসরণ করে", "account.hide_reblogs": "@{name}'র সমর্থনগুলি লুকিয়ে ফেলুন", diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json index f991b7a25c5..0ddd18de898 100644 --- a/app/javascript/mastodon/locales/cs.json +++ b/app/javascript/mastodon/locales/cs.json @@ -16,7 +16,7 @@ "account.followers": "Sledující", "account.followers.empty": "Tohoto uživatele ještě nikdo nesleduje.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Tento uživatel ještě nikoho nesleduje.", "account.follows_you": "Sleduje vás", "account.hide_reblogs": "Skrýt boosty od uživatele @{name}", diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index 984237a3291..312a0f97a27 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -16,7 +16,7 @@ "account.followers": "Dilynwyr", "account.followers.empty": "Nid oes neb yn dilyn y defnyddiwr hwn eto.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Nid yw'r defnyddiwr hwn yn dilyn unrhyw un eto.", "account.follows_you": "Yn eich dilyn chi", "account.hide_reblogs": "Cuddio bwstiau o @{name}", diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index e59f5283c20..a0fb354e669 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -16,7 +16,7 @@ "account.followers": "Følgere", "account.followers.empty": "Der er endnu ingen der følger denne bruger.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Denne bruger følger endnu ikke nogen.", "account.follows_you": "Følger dig", "account.hide_reblogs": "Skjul fremhævelserne fra @{name}", diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json index 179cfd6bc7d..bd9ebbc0de9 100644 --- a/app/javascript/mastodon/locales/defaultMessages.json +++ b/app/javascript/mastodon/locales/defaultMessages.json @@ -146,7 +146,7 @@ "id": "account.statuses_counter" }, { - "defaultMessage": "{count, plural, other {{counter} Following}}", + "defaultMessage": "{count, plural, one {{counter} Following} other {{counter} Following}}", "id": "account.following_counter" }, { @@ -2659,6 +2659,22 @@ "defaultMessage": "Boost", "id": "status.reblog" }, + { + "defaultMessage": "Public", + "id": "privacy.public.short" + }, + { + "defaultMessage": "Unlisted", + "id": "privacy.unlisted.short" + }, + { + "defaultMessage": "Followers-only", + "id": "privacy.private.short" + }, + { + "defaultMessage": "Direct", + "id": "privacy.direct.short" + }, { "defaultMessage": "You can press {combo} to skip this next time", "id": "boost_modal.combo" diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 529c2339718..381ff028bba 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -16,7 +16,7 @@ "account.followers": "Followers", "account.followers.empty": "No one follows this user yet.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Follows you", "account.hide_reblogs": "Hide boosts from @{name}", diff --git a/app/javascript/mastodon/locales/et.json b/app/javascript/mastodon/locales/et.json index fc00a627065..558fe38de25 100644 --- a/app/javascript/mastodon/locales/et.json +++ b/app/javascript/mastodon/locales/et.json @@ -16,7 +16,7 @@ "account.followers": "Jälgijad", "account.followers.empty": "Keegi ei jälgi seda kasutajat veel.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "See kasutaja ei jälgi veel kedagi.", "account.follows_you": "Jälgib Teid", "account.hide_reblogs": "Peida upitused kasutajalt @{name}", diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json index 0a8043d4d39..09471ff2ab4 100644 --- a/app/javascript/mastodon/locales/eu.json +++ b/app/javascript/mastodon/locales/eu.json @@ -16,7 +16,7 @@ "account.followers": "Jarraitzaileak", "account.followers.empty": "Ez du inork erabiltzaile hau jarraitzen oraindik.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Erabiltzaile honek ez du inor jarraitzen oraindik.", "account.follows_you": "Jarraitzen dizu", "account.hide_reblogs": "Ezkutatu @{name}(r)en bultzadak", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 364427e6537..44589aa4afb 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -16,7 +16,7 @@ "account.followers": "Seuraajaa", "account.followers.empty": "Tällä käyttäjällä ei ole vielä seuraajia.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Tämä käyttäjä ei vielä seuraa ketään.", "account.follows_you": "Seuraa sinua", "account.hide_reblogs": "Piilota buustaukset käyttäjältä @{name}", diff --git a/app/javascript/mastodon/locales/ga.json b/app/javascript/mastodon/locales/ga.json index 5a27ed96c4f..5de7b27a50b 100644 --- a/app/javascript/mastodon/locales/ga.json +++ b/app/javascript/mastodon/locales/ga.json @@ -16,7 +16,7 @@ "account.followers": "Followers", "account.followers.empty": "No one follows this user yet.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Follows you", "account.hide_reblogs": "Hide boosts from @{name}", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index 81e713dc3cd..91fce039f5b 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -16,7 +16,7 @@ "account.followers": "עוקבים", "account.followers.empty": "אף אחד לא עוקב אחר המשתמש הזה עדיין.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "משתמש זה לא עוקב אחר אף אחד עדיין.", "account.follows_you": "במעקב אחריך", "account.hide_reblogs": "להסתיר הידהודים מאת @{name}", diff --git a/app/javascript/mastodon/locales/hi.json b/app/javascript/mastodon/locales/hi.json index 4cc12830fd3..ff207d6406f 100644 --- a/app/javascript/mastodon/locales/hi.json +++ b/app/javascript/mastodon/locales/hi.json @@ -16,7 +16,7 @@ "account.followers": "फॉलोवर", "account.followers.empty": "कोई भी इस यूज़र् को फ़ॉलो नहीं करता है", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "यह यूज़र् अभी तक किसी को फॉलो नहीं करता है।", "account.follows_you": "आपको फॉलो करता है", "account.hide_reblogs": "@{name} के बूस्ट छुपाएं", diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json index a7e13b2eb10..7179bc53640 100644 --- a/app/javascript/mastodon/locales/hr.json +++ b/app/javascript/mastodon/locales/hr.json @@ -16,7 +16,7 @@ "account.followers": "Sljedbenici", "account.followers.empty": "No one follows this user yet.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "te slijedi", "account.hide_reblogs": "Hide boosts from @{name}", diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json index 5b0f345af9d..91ad76e0394 100644 --- a/app/javascript/mastodon/locales/id.json +++ b/app/javascript/mastodon/locales/id.json @@ -16,7 +16,7 @@ "account.followers": "Pengikut", "account.followers.empty": "Tidak ada satupun yang mengkuti pengguna ini saat ini.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Pengguna ini belum mengikuti siapapun.", "account.follows_you": "Mengikuti anda", "account.hide_reblogs": "Sembunyikan boosts dari @{name}", diff --git a/app/javascript/mastodon/locales/io.json b/app/javascript/mastodon/locales/io.json index 45e74b67517..e79bee21da7 100644 --- a/app/javascript/mastodon/locales/io.json +++ b/app/javascript/mastodon/locales/io.json @@ -16,7 +16,7 @@ "account.followers": "Sequanti", "account.followers.empty": "No one follows this user yet.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Sequas tu", "account.hide_reblogs": "Hide boosts from @{name}", diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json index 4a281cf805b..72d8fefaf61 100644 --- a/app/javascript/mastodon/locales/is.json +++ b/app/javascript/mastodon/locales/is.json @@ -16,7 +16,7 @@ "account.followers": "Fylgjendur", "account.followers.empty": "Ennþá fylgist enginn með þessum notanda.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Þessi notandi fylgist ennþá ekki með neinum.", "account.follows_you": "Fylgir þér", "account.hide_reblogs": "Fela endurbirtingar fyrir @{name}", diff --git a/app/javascript/mastodon/locales/ka.json b/app/javascript/mastodon/locales/ka.json index 36f27e69d91..0051fee1fed 100644 --- a/app/javascript/mastodon/locales/ka.json +++ b/app/javascript/mastodon/locales/ka.json @@ -16,7 +16,7 @@ "account.followers": "მიმდევრები", "account.followers.empty": "No one follows this user yet.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "მოგყვებათ", "account.hide_reblogs": "დაიმალოს ბუსტები @{name}-სგან", diff --git a/app/javascript/mastodon/locales/kab.json b/app/javascript/mastodon/locales/kab.json index dceb434d3fe..05f72596b53 100644 --- a/app/javascript/mastodon/locales/kab.json +++ b/app/javascript/mastodon/locales/kab.json @@ -16,7 +16,7 @@ "account.followers": "Imeḍfaren", "account.followers.empty": "Ar tura, ulac yiwen i yeṭṭafaṛen amseqdac-agi.", "account.followers_counter": "{count, plural, one {{count} n umeḍfar} other {{count} n imeḍfaren}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Ar tura, amseqdac-agi ur yeṭṭafaṛ yiwen.", "account.follows_you": "Yeṭṭafaṛ-ik", "account.hide_reblogs": "Ffer ayen i ibeṭṭu @{name}", diff --git a/app/javascript/mastodon/locales/kk.json b/app/javascript/mastodon/locales/kk.json index d7adf58362a..322c15fff69 100644 --- a/app/javascript/mastodon/locales/kk.json +++ b/app/javascript/mastodon/locales/kk.json @@ -16,7 +16,7 @@ "account.followers": "Оқырмандар", "account.followers.empty": "Әлі ешкім жазылмаған.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Ешкімге жазылмапты.", "account.follows_you": "Сізге жазылыпты", "account.hide_reblogs": "@{name} атты қолданушының әрекеттерін жасыру", diff --git a/app/javascript/mastodon/locales/kn.json b/app/javascript/mastodon/locales/kn.json index 43738ba70e9..e9618e0f2e9 100644 --- a/app/javascript/mastodon/locales/kn.json +++ b/app/javascript/mastodon/locales/kn.json @@ -16,7 +16,7 @@ "account.followers": "Followers", "account.followers.empty": "No one follows this user yet.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Follows you", "account.hide_reblogs": "Hide boosts from @{name}", diff --git a/app/javascript/mastodon/locales/ku.json b/app/javascript/mastodon/locales/ku.json index 36f55e80025..e5d833fe874 100644 --- a/app/javascript/mastodon/locales/ku.json +++ b/app/javascript/mastodon/locales/ku.json @@ -16,7 +16,7 @@ "account.followers": "Followers", "account.followers.empty": "No one follows this user yet.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Follows you", "account.hide_reblogs": "Hide boosts from @{name}", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index 43738ba70e9..e9618e0f2e9 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -16,7 +16,7 @@ "account.followers": "Followers", "account.followers.empty": "No one follows this user yet.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Follows you", "account.hide_reblogs": "Hide boosts from @{name}", diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json index 01fe7a07c3c..2812760a658 100644 --- a/app/javascript/mastodon/locales/lv.json +++ b/app/javascript/mastodon/locales/lv.json @@ -16,7 +16,7 @@ "account.followers": "Sekotāji", "account.followers.empty": "Šim lietotājam nav sekotāju.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Šis lietotājs pagaidām nevienam neseko.", "account.follows_you": "Seko tev", "account.hide_reblogs": "Paslēpt paceltos ierakstus no lietotāja @{name}", diff --git a/app/javascript/mastodon/locales/mk.json b/app/javascript/mastodon/locales/mk.json index 7e9c0dc4269..2bb9a2e2ac7 100644 --- a/app/javascript/mastodon/locales/mk.json +++ b/app/javascript/mastodon/locales/mk.json @@ -16,7 +16,7 @@ "account.followers": "Следбеници", "account.followers.empty": "Никој не го следи овој корисник сеуште.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Корисникот не следи никој сеуште.", "account.follows_you": "Те следи тебе", "account.hide_reblogs": "Сокриј буст од @{name}", diff --git a/app/javascript/mastodon/locales/ml.json b/app/javascript/mastodon/locales/ml.json index 78dced5320e..4a390ad70fb 100644 --- a/app/javascript/mastodon/locales/ml.json +++ b/app/javascript/mastodon/locales/ml.json @@ -16,7 +16,7 @@ "account.followers": "പിന്തുടരുന്നവർ", "account.followers.empty": "ഈ ഉപയോക്താവിനെ ആരും ഇതുവരെ പിന്തുടരുന്നില്ല.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "ഈ ഉപയോക്താവ് ആരേയും ഇതുവരെ പിന്തുടരുന്നില്ല.", "account.follows_you": "നിങ്ങളെ പിന്തുടരുന്നു", "account.hide_reblogs": "@{name} ബൂസ്റ്റ് ചെയ്തവ മറയ്കുക", diff --git a/app/javascript/mastodon/locales/mr.json b/app/javascript/mastodon/locales/mr.json index a56d2544a7b..5a93ae851be 100644 --- a/app/javascript/mastodon/locales/mr.json +++ b/app/javascript/mastodon/locales/mr.json @@ -16,7 +16,7 @@ "account.followers": "अनुयायी", "account.followers.empty": "ह्या वापरकर्त्याचा आतापर्यंत कोणी अनुयायी नाही.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "हा वापरकर्ता अजूनपर्यंत कोणाचा अनुयायी नाही.", "account.follows_you": "तुमचा अनुयायी आहे", "account.hide_reblogs": "@{name} पासून सर्व बूस्ट लपवा", diff --git a/app/javascript/mastodon/locales/ms.json b/app/javascript/mastodon/locales/ms.json index a1948301418..5fc77788793 100644 --- a/app/javascript/mastodon/locales/ms.json +++ b/app/javascript/mastodon/locales/ms.json @@ -16,7 +16,7 @@ "account.followers": "Followers", "account.followers.empty": "No one follows this user yet.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Follows you", "account.hide_reblogs": "Hide boosts from @{name}", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index ad10bb63ce2..73e2b9a1369 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -16,7 +16,7 @@ "account.followers": "Volgers", "account.followers.empty": "Niemand volgt nog deze gebruiker.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Deze gebruiker volgt nog niemand.", "account.follows_you": "Volgt jou", "account.hide_reblogs": "Verberg boosts van @{name}", diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json index ed151565d99..b567a35330d 100644 --- a/app/javascript/mastodon/locales/nn.json +++ b/app/javascript/mastodon/locales/nn.json @@ -16,7 +16,7 @@ "account.followers": "Fylgjarar", "account.followers.empty": "Ingen fylgjer denne brukaren enno.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Denne brukaren fylgjer ikkje nokon enno.", "account.follows_you": "Fylgjer deg", "account.hide_reblogs": "Gøym fremhevingar frå @{name}", diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json index 7ddfea5bc0a..a15e96fdc2d 100644 --- a/app/javascript/mastodon/locales/no.json +++ b/app/javascript/mastodon/locales/no.json @@ -16,7 +16,7 @@ "account.followers": "Følgere", "account.followers.empty": "Ingen følger denne brukeren ennå.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Denne brukeren følger ikke noen enda.", "account.follows_you": "Følger deg", "account.hide_reblogs": "Skjul fremhevinger fra @{name}", diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json index dfee6f15771..1aa0193a527 100644 --- a/app/javascript/mastodon/locales/oc.json +++ b/app/javascript/mastodon/locales/oc.json @@ -16,7 +16,7 @@ "account.followers": "Seguidors", "account.followers.empty": "Degun sèc pas aqueste utilizaire pel moment.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Aqueste utilizaire sèc pas degun pel moment.", "account.follows_you": "Vos sèc", "account.hide_reblogs": "Rescondre los partatges de @{name}", diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index 3755b762c5b..4e0230b7581 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -16,7 +16,7 @@ "account.followers": "Śledzący", "account.followers.empty": "Nikt jeszcze nie śledzi tego użytkownika.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Ten użytkownik nie śledzi jeszcze nikogo.", "account.follows_you": "Śledzi Cię", "account.hide_reblogs": "Ukryj podbicia od @{name}", diff --git a/app/javascript/mastodon/locales/ro.json b/app/javascript/mastodon/locales/ro.json index c00eca2974e..544d6810215 100644 --- a/app/javascript/mastodon/locales/ro.json +++ b/app/javascript/mastodon/locales/ro.json @@ -16,7 +16,7 @@ "account.followers": "Urmăritori", "account.followers.empty": "Acest utilizator nu are încă urmăritori.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Acest utilizator nu urmărește pe nimeni încă.", "account.follows_you": "Te urmărește", "account.hide_reblogs": "Ascunde impulsurile de la @{name}", diff --git a/app/javascript/mastodon/locales/sc.json b/app/javascript/mastodon/locales/sc.json index 916576656b2..30a3e33745b 100644 --- a/app/javascript/mastodon/locales/sc.json +++ b/app/javascript/mastodon/locales/sc.json @@ -16,7 +16,7 @@ "account.followers": "Sighiduras", "account.followers.empty": "Nemos sighit ancora custa persone.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Custa persone non sighit ancora a nemos.", "account.follows_you": "Ti sighit", "account.hide_reblogs": "Cua is cumpartziduras de @{name}", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index 569a8cd125c..4e48d53c84f 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -16,7 +16,7 @@ "account.followers": "Sledujúci", "account.followers.empty": "Tohto používateľa ešte nikto nenásleduje.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Tento používateľ ešte nikoho nenasleduje.", "account.follows_you": "Nasleduje ťa", "account.hide_reblogs": "Skry vyzdvihnutia od @{name}", diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json index d13bf5e36da..71ba0d1b622 100644 --- a/app/javascript/mastodon/locales/sl.json +++ b/app/javascript/mastodon/locales/sl.json @@ -16,7 +16,7 @@ "account.followers": "Sledilci", "account.followers.empty": "Nihče ne sledi temu uporabniku.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Ta uporabnik še ne sledi nikomur.", "account.follows_you": "Sledi tebi", "account.hide_reblogs": "Skrij spodbude od @{name}", diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json index 7a17e9134a5..d7be7380f5d 100644 --- a/app/javascript/mastodon/locales/sr-Latn.json +++ b/app/javascript/mastodon/locales/sr-Latn.json @@ -16,7 +16,7 @@ "account.followers": "Pratioca", "account.followers.empty": "No one follows this user yet.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Prati Vas", "account.hide_reblogs": "Sakrij podrške koje daje korisnika @{name}", diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json index bcaa45ed084..7c42f0e8a01 100644 --- a/app/javascript/mastodon/locales/sr.json +++ b/app/javascript/mastodon/locales/sr.json @@ -16,7 +16,7 @@ "account.followers": "Пратиоци", "account.followers.empty": "Тренутно нико не прати овог корисника.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Корисник тренутно не прати никога.", "account.follows_you": "Прати Вас", "account.hide_reblogs": "Сакриј подршке које даје корисника @{name}", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index a0d0807abb7..c9251d73c53 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -16,7 +16,7 @@ "account.followers": "Följare", "account.followers.empty": "Ingen följer denna användare än.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Denna användare följer inte någon än.", "account.follows_you": "Följer dig", "account.hide_reblogs": "Dölj knuffar från @{name}", diff --git a/app/javascript/mastodon/locales/szl.json b/app/javascript/mastodon/locales/szl.json index 36f55e80025..e5d833fe874 100644 --- a/app/javascript/mastodon/locales/szl.json +++ b/app/javascript/mastodon/locales/szl.json @@ -16,7 +16,7 @@ "account.followers": "Followers", "account.followers.empty": "No one follows this user yet.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Follows you", "account.hide_reblogs": "Hide boosts from @{name}", diff --git a/app/javascript/mastodon/locales/ta.json b/app/javascript/mastodon/locales/ta.json index 9caef05825d..28f03f78113 100644 --- a/app/javascript/mastodon/locales/ta.json +++ b/app/javascript/mastodon/locales/ta.json @@ -16,7 +16,7 @@ "account.followers": "பின்தொடர்பவர்கள்", "account.followers.empty": "இதுவரை யாரும் இந்த பயனரைப் பின்தொடரவில்லை.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "இந்த பயனர் இதுவரை யாரையும் பின்தொடரவில்லை.", "account.follows_you": "உங்களைப் பின்தொடர்கிறார்", "account.hide_reblogs": "இருந்து ஊக்கியாக மறை @{name}", diff --git a/app/javascript/mastodon/locales/tai.json b/app/javascript/mastodon/locales/tai.json index 36f55e80025..e5d833fe874 100644 --- a/app/javascript/mastodon/locales/tai.json +++ b/app/javascript/mastodon/locales/tai.json @@ -16,7 +16,7 @@ "account.followers": "Followers", "account.followers.empty": "No one follows this user yet.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Follows you", "account.hide_reblogs": "Hide boosts from @{name}", diff --git a/app/javascript/mastodon/locales/te.json b/app/javascript/mastodon/locales/te.json index a57efd7c614..4763dcbd309 100644 --- a/app/javascript/mastodon/locales/te.json +++ b/app/javascript/mastodon/locales/te.json @@ -16,7 +16,7 @@ "account.followers": "అనుచరులు", "account.followers.empty": "ఈ వినియోగదారుడిని ఇంకా ఎవరూ అనుసరించడంలేదు.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "ఈ వినియోగదారి ఇంకా ఎవరినీ అనుసరించడంలేదు.", "account.follows_you": "మిమ్మల్ని అనుసరిస్తున్నారు", "account.hide_reblogs": "@{name} నుంచి బూస్ట్ లను దాచిపెట్టు", diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index 5852ec5caa2..a5c6b07cde6 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -16,7 +16,7 @@ "account.followers": "ผู้ติดตาม", "account.followers.empty": "ยังไม่มีใครติดตามผู้ใช้นี้", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "ผู้ใช้นี้ยังไม่ได้ติดตามใคร", "account.follows_you": "ติดตามคุณ", "account.hide_reblogs": "ซ่อนการดันจาก @{name}", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index a5bbbfcd933..351e80f8119 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -16,7 +16,7 @@ "account.followers": "Takipçi", "account.followers.empty": "Henüz kimse bu kullanıcıyı takip etmiyor.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Bu kullanıcı henüz kimseyi takip etmiyor.", "account.follows_you": "Seni takip ediyor", "account.hide_reblogs": "@{name} kişisinin yinelemelerini gizle", diff --git a/app/javascript/mastodon/locales/ug.json b/app/javascript/mastodon/locales/ug.json index 36f55e80025..e5d833fe874 100644 --- a/app/javascript/mastodon/locales/ug.json +++ b/app/javascript/mastodon/locales/ug.json @@ -16,7 +16,7 @@ "account.followers": "Followers", "account.followers.empty": "No one follows this user yet.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "This user doesn't follow anyone yet.", "account.follows_you": "Follows you", "account.hide_reblogs": "Hide boosts from @{name}", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index 18e15126325..244f04a9e87 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -16,7 +16,7 @@ "account.followers": "Підписники", "account.followers.empty": "Ніхто ще не підписався на цього користувача.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "Цей користувач ще ні на кого не підписався.", "account.follows_you": "Підписаний(-а) на вас", "account.hide_reblogs": "Сховати передмухи від @{name}", diff --git a/app/javascript/mastodon/locales/ur.json b/app/javascript/mastodon/locales/ur.json index 5924d148705..b94b7c16200 100644 --- a/app/javascript/mastodon/locales/ur.json +++ b/app/javascript/mastodon/locales/ur.json @@ -16,7 +16,7 @@ "account.followers": "پیروکار", "account.followers.empty": "\"ہنوز اس صارف کی کوئی پیروی نہیں کرتا\".", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "\"یہ صارف ہنوز کسی کی پیروی نہیں کرتا ہے\".", "account.follows_you": "آپ کا پیروکار ہے", "account.hide_reblogs": "@{name} سے فروغ چھپائیں", diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json index b537ca4f3d9..24a63ab6b38 100644 --- a/app/javascript/mastodon/locales/zh-HK.json +++ b/app/javascript/mastodon/locales/zh-HK.json @@ -16,7 +16,7 @@ "account.followers": "關注的人", "account.followers.empty": "尚沒有人關注這位使用者。", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "這位使用者尚未關注任何使用者。", "account.follows_you": "關注你", "account.hide_reblogs": "隱藏 @{name} 的轉推", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index d674734c118..e964ccd4961 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -16,7 +16,7 @@ "account.followers": "關注者", "account.followers.empty": "尚沒有人關注這位使用者。", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", - "account.following_counter": "{count, plural, other {{counter} Following}}", + "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "這位使用者尚未關注任何使用者。", "account.follows_you": "關注了你", "account.hide_reblogs": "隱藏來自 @{name} 的轉推", From a29080256ecb39c7c719a7717fa15d3bc6d9776b Mon Sep 17 00:00:00 2001 From: Alex Dunn Date: Sat, 18 Jul 2020 10:30:46 -0700 Subject: [PATCH 09/19] helm: add examples of annotation for NGINX upload limits (#14350) --- chart/values.yaml.template | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/chart/values.yaml.template b/chart/values.yaml.template index 4a8286d0014..694bc4d4224 100644 --- a/chart/values.yaml.template +++ b/chart/values.yaml.template @@ -16,6 +16,12 @@ ingress: kubernetes.io/ingress.class: nginx kubernetes.io/tls-acme: "true" # cert-manager.io/cluster-issuer: "letsencrypt" + # + # ensure that NGINX's upload size matches Mastodon's + # for the K8s ingress controller: + # nginx.ingress.kubernetes.io/proxy-body-size: 40m + # for the NGINX ingress controller: + # nginx.org/client-max-body-size: 40m # this value is used for LOCAL_DOMAIN hostname: mastodon.local tls: From 101485a41fb2ea326496142d9ccb368522cbe0f0 Mon Sep 17 00:00:00 2001 From: Takeshi Umeda Date: Sun, 19 Jul 2020 20:09:47 +0900 Subject: [PATCH 10/19] Fix mimetype returning nil (#14356) --- lib/paperclip/media_type_spoof_detector_extensions.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/paperclip/media_type_spoof_detector_extensions.rb b/lib/paperclip/media_type_spoof_detector_extensions.rb index 363934d8d13..43337cc6884 100644 --- a/lib/paperclip/media_type_spoof_detector_extensions.rb +++ b/lib/paperclip/media_type_spoof_detector_extensions.rb @@ -18,7 +18,7 @@ module Paperclip @type_from_mime_magic ||= begin begin File.open(@file.path) do |file| - MimeMagic.by_magic(file)&.type + MimeMagic.by_magic(file)&.type || '' end rescue Errno::ENOENT '' From 2ada2ae18af3429f9666fd35c70675dc62a0b99f Mon Sep 17 00:00:00 2001 From: Ariel Date: Sun, 19 Jul 2020 12:04:02 -0300 Subject: [PATCH 11/19] Fix/14021 behaviour on add or remove toots (#14212) * Add toot send by current user at local state after send a new toot Related to #14021 * Decrement toot counter at profile when remove a toot Related to #14021 * Remove semicolon at end of line --- app/controllers/api/v1/statuses_controller.rb | 1 + app/javascript/mastodon/actions/compose.js | 2 +- app/javascript/mastodon/actions/statuses.js | 3 ++- app/javascript/mastodon/actions/streaming.js | 13 +++++++------ .../mastodon/features/account_timeline/index.js | 15 +++++++++++++++ 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb index 8d6cb84b667..106fc8224e2 100644 --- a/app/controllers/api/v1/statuses_controller.rb +++ b/app/controllers/api/v1/statuses_controller.rb @@ -57,6 +57,7 @@ class Api::V1::StatusesController < Api::BaseController @status.discard RemovalWorker.perform_async(@status.id, redraft: true) + @status.account.statuses_count = @status.account.statuses_count - 1 render json: @status, serializer: REST::StatusSerializer, source_requested: true end diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js index 20341f9ec0e..03092252026 100644 --- a/app/javascript/mastodon/actions/compose.js +++ b/app/javascript/mastodon/actions/compose.js @@ -163,7 +163,6 @@ export function submitCompose(routerHistory) { // To make the app more responsive, immediately push the status // into the columns - const insertIfOnline = timelineId => { const timeline = getState().getIn(['timelines', timelineId]); @@ -179,6 +178,7 @@ export function submitCompose(routerHistory) { if (response.data.in_reply_to_id === null && response.data.visibility === 'public') { insertIfOnline('community'); insertIfOnline('public'); + insertIfOnline(`account:${response.data.account.id}`); } }).catch(function (error) { dispatch(submitComposeFail(error)); diff --git a/app/javascript/mastodon/actions/statuses.js b/app/javascript/mastodon/actions/statuses.js index 5640201c621..e565e0b0ab5 100644 --- a/app/javascript/mastodon/actions/statuses.js +++ b/app/javascript/mastodon/actions/statuses.js @@ -3,7 +3,7 @@ import openDB from '../storage/db'; import { evictStatus } from '../storage/modifier'; import { deleteFromTimelines } from './timelines'; -import { importFetchedStatus, importFetchedStatuses, importAccount, importStatus } from './importer'; +import { importFetchedStatus, importFetchedStatuses, importAccount, importStatus, importFetchedAccount } from './importer'; import { ensureComposeIsVisible } from './compose'; export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST'; @@ -155,6 +155,7 @@ export function deleteStatus(id, routerHistory, withRedraft = false) { evictStatus(id); dispatch(deleteStatusSuccess(id)); dispatch(deleteFromTimelines(id)); + dispatch(importFetchedAccount(response.data.account)); if (withRedraft) { dispatch(redraft(status, response.data.text)); diff --git a/app/javascript/mastodon/actions/streaming.js b/app/javascript/mastodon/actions/streaming.js index d998fcac480..7cecff66e1b 100644 --- a/app/javascript/mastodon/actions/streaming.js +++ b/app/javascript/mastodon/actions/streaming.js @@ -71,9 +71,10 @@ const refreshHomeTimelineAndNotification = (dispatch, done) => { dispatch(fetchAnnouncements(done)))))); }; -export const connectUserStream = () => connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification); -export const connectCommunityStream = ({ onlyMedia } = {}) => connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`); -export const connectPublicStream = ({ onlyMedia, onlyRemote } = {}) => connectTimelineStream(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, `public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`); -export const connectHashtagStream = (id, tag, local, accept) => connectTimelineStream(`hashtag:${id}${local ? ':local' : ''}`, `hashtag${local ? ':local' : ''}&tag=${tag}`, null, accept); -export const connectDirectStream = () => connectTimelineStream('direct', 'direct'); -export const connectListStream = id => connectTimelineStream(`list:${id}`, `list&list=${id}`); +export const connectUserStream = () => connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification); +export const connectUserTimelineStream = (accountId) => connectTimelineStream(`account:${accountId}`, 'user'); +export const connectCommunityStream = ({ onlyMedia } = {}) => connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`); +export const connectPublicStream = ({ onlyMedia, onlyRemote } = {}) => connectTimelineStream(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, `public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`); +export const connectHashtagStream = (id, tag, local, accept) => connectTimelineStream(`hashtag:${id}${local ? ':local' : ''}`, `hashtag${local ? ':local' : ''}&tag=${tag}`, null, accept); +export const connectDirectStream = () => connectTimelineStream('direct', 'direct'); +export const connectListStream = id => connectTimelineStream(`list:${id}`, `list&list=${id}`); diff --git a/app/javascript/mastodon/features/account_timeline/index.js b/app/javascript/mastodon/features/account_timeline/index.js index 5ea907a1f11..3846cc6377f 100644 --- a/app/javascript/mastodon/features/account_timeline/index.js +++ b/app/javascript/mastodon/features/account_timeline/index.js @@ -15,6 +15,8 @@ import { FormattedMessage } from 'react-intl'; import { fetchAccountIdentityProofs } from '../../actions/identity_proofs'; import MissingIndicator from 'mastodon/components/missing_indicator'; import TimelineHint from 'mastodon/components/timeline_hint'; +import { me } from 'mastodon/initial_state'; +import { connectUserTimelineStream } from '../../actions/streaming'; const emptyList = ImmutableList(); @@ -73,6 +75,12 @@ class AccountTimeline extends ImmutablePureComponent { this.props.dispatch(expandAccountTimeline(accountId, { withReplies })); } + componentDidMount () { + if (this.props.params.accountId === me) { + this.disconnect = this.props.dispatch(connectUserTimelineStream(me)); + } + } + componentWillReceiveProps (nextProps) { if ((nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) || nextProps.withReplies !== this.props.withReplies) { this.props.dispatch(fetchAccount(nextProps.params.accountId)); @@ -86,6 +94,13 @@ class AccountTimeline extends ImmutablePureComponent { } } + componentWillUnmount () { + if (this.disconnect) { + this.disconnect(); + this.disconnect = null; + } + } + handleLoadMore = maxId => { this.props.dispatch(expandAccountTimeline(this.props.params.accountId, { maxId, withReplies: this.props.withReplies })); } From 47931db1f50db3b6773fbb3cc4645fdb4a4692eb Mon Sep 17 00:00:00 2001 From: Takeshi Umeda Date: Mon, 20 Jul 2020 02:53:31 +0900 Subject: [PATCH 12/19] Add thumbnail_remote_url in MediaAttachment REST response (#14358) * Add thumbnail_remote_url in MediaAttachment REST response * Change thumbnail_remote_url to preview_remote_url --- app/serializers/rest/media_attachment_serializer.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/serializers/rest/media_attachment_serializer.rb b/app/serializers/rest/media_attachment_serializer.rb index e65f7acf1a9..a24f953152f 100644 --- a/app/serializers/rest/media_attachment_serializer.rb +++ b/app/serializers/rest/media_attachment_serializer.rb @@ -4,7 +4,7 @@ class REST::MediaAttachmentSerializer < ActiveModel::Serializer include RoutingHelper attributes :id, :type, :url, :preview_url, - :remote_url, :text_url, :meta, + :remote_url, :preview_remote_url, :text_url, :meta, :description, :blurhash def id @@ -35,6 +35,10 @@ class REST::MediaAttachmentSerializer < ActiveModel::Serializer end end + def preview_remote_url + object.thumbnail_remote_url.presence + end + def text_url object.local? ? medium_url(object) : nil end From 7540e235a2b387ca08cf57f8942d1b190d242808 Mon Sep 17 00:00:00 2001 From: Takeshi Umeda Date: Mon, 20 Jul 2020 05:28:27 +0900 Subject: [PATCH 13/19] Fix movie width and frame_rate returning nil (#14357) * Fix movie width and frame_rate returning nil * Add StreamValidationError and raise * Fix code style --- app/lib/exceptions.rb | 1 + app/models/concerns/remotable.rb | 2 +- app/models/media_attachment.rb | 1 + app/services/update_account_service.rb | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/lib/exceptions.rb b/app/lib/exceptions.rb index 3362576b0bc..7c8e778713a 100644 --- a/app/lib/exceptions.rb +++ b/app/lib/exceptions.rb @@ -7,6 +7,7 @@ module Mastodon class HostValidationError < ValidationError; end class LengthValidationError < ValidationError; end class DimensionsValidationError < ValidationError; end + class StreamValidationError < ValidationError; end class RaceConditionError < Error; end class RateLimitExceededError < Error; end diff --git a/app/models/concerns/remotable.rb b/app/models/concerns/remotable.rb index c6d0c7f1f44..56b9c016422 100644 --- a/app/models/concerns/remotable.rb +++ b/app/models/concerns/remotable.rb @@ -29,7 +29,7 @@ module Remotable rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError => e Rails.logger.debug "Error fetching remote #{attachment_name}: #{e}" raise e unless suppress_errors - rescue Paperclip::Errors::NotIdentifiedByImageMagickError, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError, Paperclip::Error, Mastodon::DimensionsValidationError => e + rescue Paperclip::Errors::NotIdentifiedByImageMagickError, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError, Paperclip::Error, Mastodon::DimensionsValidationError, Mastodon::StreamValidationError => e Rails.logger.debug "Error fetching remote #{attachment_name}: #{e}" end diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index 3f2e0ceb1b8..3d93ec75ba8 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -336,6 +336,7 @@ class MediaAttachment < ApplicationRecord return unless movie.valid? + raise Mastodon::StreamValidationError, 'Video has no video stream' if movie.width.nil? || movie.frame_rate.nil? raise Mastodon::DimensionsValidationError, "#{movie.width}x#{movie.height} videos are not supported" if movie.width * movie.height > MAX_VIDEO_MATRIX_LIMIT raise Mastodon::DimensionsValidationError, "#{movie.frame_rate.to_i}fps videos are not supported" if movie.frame_rate > MAX_VIDEO_FRAME_RATE end diff --git a/app/services/update_account_service.rb b/app/services/update_account_service.rb index 4172d577408..666db5c7113 100644 --- a/app/services/update_account_service.rb +++ b/app/services/update_account_service.rb @@ -12,7 +12,7 @@ class UpdateAccountService < BaseService check_links(account) process_hashtags(account) end - rescue Mastodon::DimensionsValidationError => de + rescue Mastodon::DimensionsValidationError, Mastodon::StreamValidationError => de account.errors.add(:avatar, de.message) false end From 0ab97107c76732d3af2ff415d8d9d9d89da25d93 Mon Sep 17 00:00:00 2001 From: Jeong Arm Date: Mon, 20 Jul 2020 16:48:10 +0900 Subject: [PATCH 14/19] Remove nodejs buildpack from buildpacks (#14364) --- .buildpacks | 1 - 1 file changed, 1 deletion(-) diff --git a/.buildpacks b/.buildpacks index 3450683ce84..5e73304a5d7 100644 --- a/.buildpacks +++ b/.buildpacks @@ -1,4 +1,3 @@ https://github.com/heroku/heroku-buildpack-apt https://github.com/Scalingo/ffmpeg-buildpack -https://github.com/Scalingo/nodejs-buildpack https://github.com/Scalingo/ruby-buildpack From fcb3f259e5a36dc4ac5300aa715d583f3a577c2b Mon Sep 17 00:00:00 2001 From: Takeshi Umeda Date: Mon, 20 Jul 2020 18:25:26 +0900 Subject: [PATCH 15/19] Fix to add RedisLock to handle Announce activity (#14365) --- app/lib/activitypub/activity/announce.rb | 39 +++++++++++++++--------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/app/lib/activitypub/activity/announce.rb b/app/lib/activitypub/activity/announce.rb index 34c646668b1..9e108985a3e 100644 --- a/app/lib/activitypub/activity/announce.rb +++ b/app/lib/activitypub/activity/announce.rb @@ -4,25 +4,32 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity def perform return reject_payload! if delete_arrived_first?(@json['id']) || !related_to_local_activity? - original_status = status_from_object + RedisLock.acquire(lock_options) do |lock| + if lock.acquired? + original_status = status_from_object - return reject_payload! if original_status.nil? || !announceable?(original_status) + return reject_payload! if original_status.nil? || !announceable?(original_status) - status = Status.find_by(account: @account, reblog: original_status) + @status = Status.find_by(account: @account, reblog: original_status) - return status unless status.nil? + return @status unless @status.nil? - status = Status.create!( - account: @account, - reblog: original_status, - uri: @json['id'], - created_at: @json['published'], - override_timestamps: @options[:override_timestamps], - visibility: visibility_from_audience - ) + @status = Status.create!( + account: @account, + reblog: original_status, + uri: @json['id'], + created_at: @json['published'], + override_timestamps: @options[:override_timestamps], + visibility: visibility_from_audience + ) - distribute(status) - status + distribute(@status) + else + raise Mastodon::RaceConditionError + end + end + + @status end private @@ -54,4 +61,8 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity def reblog_of_local_status? status_from_uri(object_uri)&.account&.local? end + + def lock_options + { redis: Redis.current, key: "announce:#{@object['id']}" } + end end From a8b6524b43235a3ce477b7594c918eaa957f27a2 Mon Sep 17 00:00:00 2001 From: Takeshi Umeda Date: Mon, 20 Jul 2020 18:26:12 +0900 Subject: [PATCH 16/19] Changed retries and rescued in ActivityPub::ProcessingWorker (#14355) * Changed the number of retries and rescued exceptions in ActivityPub::ProcessingWorker * Remove RecordNotUnique from rescue --- app/workers/activitypub/processing_worker.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/workers/activitypub/processing_worker.rb b/app/workers/activitypub/processing_worker.rb index 05139f616db..cef59531949 100644 --- a/app/workers/activitypub/processing_worker.rb +++ b/app/workers/activitypub/processing_worker.rb @@ -3,7 +3,7 @@ class ActivityPub::ProcessingWorker include Sidekiq::Worker - sidekiq_options backtrace: true + sidekiq_options backtrace: true, retry: 8 def perform(account_id, body, delivered_to_account_id = nil) ActivityPub::ProcessCollectionService.new.call(body, Account.find(account_id), override_timestamps: true, delivered_to_account_id: delivered_to_account_id, delivery: true) From bcf85b5208c936486550da0ce978098840218073 Mon Sep 17 00:00:00 2001 From: ThibG Date: Wed, 22 Jul 2020 11:43:17 +0200 Subject: [PATCH 17/19] Dereference object URIs in Create and Update messages (#14359) * Dereference object URIs in Create and Update messages Fixes #14353 Signed-off-by: Thibaut Girka * Refactor, and perform origin check *before* attempting to fetch object Co-authored-by: Fire Demon --- app/lib/activitypub/activity.rb | 28 ++++++++++++++++++++++++++ app/lib/activitypub/activity/create.rb | 2 ++ app/lib/activitypub/activity/update.rb | 2 ++ 3 files changed, 32 insertions(+) diff --git a/app/lib/activitypub/activity.rb b/app/lib/activitypub/activity.rb index 0ce279d2873..ab946470b9f 100644 --- a/app/lib/activitypub/activity.rb +++ b/app/lib/activitypub/activity.rb @@ -157,6 +157,34 @@ class ActivityPub::Activity fetch_remote_original_status end + def dereference_object! + return unless @object.is_a?(String) + return if invalid_origin?(@object) + + object = fetch_resource(@object, true, signed_fetch_account) + return unless object.present? && object.is_a?(Hash) && supported_context?(object) + + @object = object + end + + def signed_fetch_account + first_mentioned_local_account || first_local_follower + end + + def first_mentioned_local_account + audience = (as_array(@json['to']) + as_array(@json['cc'])).uniq + local_usernames = audience.select { |uri| ActivityPub::TagManager.instance.local_uri?(uri) } + .map { |uri| ActivityPub::TagManager.instance.uri_to_local_id(uri, :username) } + + return if local_usernames.empty? + + Account.local.where(username: local_usernames).first + end + + def first_local_follower + @account.followers.local.first + end + def follow_request_from_object @follow_request ||= FollowRequest.find_by(target_account: @account, uri: object_uri) unless object_uri.nil? end diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index e81452e3cae..08dd98e942d 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -2,6 +2,8 @@ class ActivityPub::Activity::Create < ActivityPub::Activity def perform + dereference_object! + case @object['type'] when 'EncryptedMessage' create_encrypted_message diff --git a/app/lib/activitypub/activity/update.rb b/app/lib/activitypub/activity/update.rb index 70035325b65..018e2df5492 100644 --- a/app/lib/activitypub/activity/update.rb +++ b/app/lib/activitypub/activity/update.rb @@ -4,6 +4,8 @@ class ActivityPub::Activity::Update < ActivityPub::Activity SUPPORTED_TYPES = %w(Application Group Organization Person Service).freeze def perform + dereference_object! + if equals_or_includes_any?(@object['type'], SUPPORTED_TYPES) update_account elsif equals_or_includes_any?(@object['type'], %w(Question)) From f55dd193f9a62623054dba1537d01bd7f5cd32f3 Mon Sep 17 00:00:00 2001 From: ThibG Date: Wed, 22 Jul 2020 11:44:02 +0200 Subject: [PATCH 18/19] Fix RSS feeds not being cachable (#14368) * Add tests for some cachable responses This only covers responses that we should have managed to make cachable so far. It's not the case of all responses that should be cachable in the end. * Fix RSS feeds not being cachable --- app/controllers/application_controller.rb | 2 +- spec/controllers/accounts_controller_spec.rb | 31 ++++++++++++------- .../collections_controller_spec.rb | 23 ++++++++++---- .../activitypub/outboxes_controller_spec.rb | 23 ++++++++++---- .../activitypub/replies_controller_spec.rb | 23 ++++++++++---- spec/controllers/statuses_controller_spec.rb | 23 ++++++++++---- 6 files changed, 88 insertions(+), 37 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 973db6aca97..2201e463e68 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -55,7 +55,7 @@ class ApplicationController < ActionController::Base end def store_current_location - store_location_for(:user, request.url) unless request.format == :json + store_location_for(:user, request.url) unless [:json, :rss].include?(request.format&.to_sym) end def require_admin! diff --git a/spec/controllers/accounts_controller_spec.rb b/spec/controllers/accounts_controller_spec.rb index bd36f549407..93bf2c83f40 100644 --- a/spec/controllers/accounts_controller_spec.rb +++ b/spec/controllers/accounts_controller_spec.rb @@ -5,6 +5,21 @@ RSpec.describe AccountsController, type: :controller do let(:account) { Fabricate(:user).account } + shared_examples 'cachable response' do + it 'does not set cookies' do + expect(response.cookies).to be_empty + expect(response.headers['Set-Cookies']).to be nil + end + + it 'does not set sessions' do + expect(session).to be_empty + end + + it 'returns public Cache-Control header' do + expect(response.headers['Cache-Control']).to include 'public' + end + end + describe 'GET #show' do let(:format) { 'html' } @@ -323,9 +338,7 @@ RSpec.describe AccountsController, type: :controller do expect(response.content_type).to eq 'application/activity+json' end - it 'returns public Cache-Control header' do - expect(response.headers['Cache-Control']).to include 'public' - end + it_behaves_like 'cachable response' it 'renders account' do json = body_as_json @@ -343,9 +356,7 @@ RSpec.describe AccountsController, type: :controller do expect(response.content_type).to eq 'application/activity+json' end - it 'returns public Cache-Control header' do - expect(response.headers['Cache-Control']).to include 'public' - end + it_behaves_like 'cachable response' it 'returns Vary header with Signature' do expect(response.headers['Vary']).to include 'Signature' @@ -401,9 +412,7 @@ RSpec.describe AccountsController, type: :controller do expect(response.content_type).to eq 'application/activity+json' end - it 'returns public Cache-Control header' do - expect(response.headers['Cache-Control']).to include 'public' - end + it_behaves_like 'cachable response' it 'renders account' do json = body_as_json @@ -447,9 +456,7 @@ RSpec.describe AccountsController, type: :controller do expect(response).to have_http_status(200) end - it 'returns public Cache-Control header' do - expect(response.headers['Cache-Control']).to include 'public' - end + it_behaves_like 'cachable response' end context do diff --git a/spec/controllers/activitypub/collections_controller_spec.rb b/spec/controllers/activitypub/collections_controller_spec.rb index 56be49be3d7..89939d1d258 100644 --- a/spec/controllers/activitypub/collections_controller_spec.rb +++ b/spec/controllers/activitypub/collections_controller_spec.rb @@ -6,6 +6,21 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do let!(:account) { Fabricate(:account) } let(:remote_account) { nil } + shared_examples 'cachable response' do + it 'does not set cookies' do + expect(response.cookies).to be_empty + expect(response.headers['Set-Cookies']).to be nil + end + + it 'does not set sessions' do + expect(session).to be_empty + end + + it 'returns public Cache-Control header' do + expect(response.headers['Cache-Control']).to include 'public' + end + end + before do allow(controller).to receive(:signed_request_account).and_return(remote_account) @@ -31,9 +46,7 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do expect(response.content_type).to eq 'application/activity+json' end - it 'returns public Cache-Control header' do - expect(response.headers['Cache-Control']).to include 'public' - end + it_behaves_like 'cachable response' it 'returns orderedItems with pinned statuses' do json = body_as_json @@ -58,9 +71,7 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do expect(response.content_type).to eq 'application/activity+json' end - it 'returns public Cache-Control header' do - expect(response.headers['Cache-Control']).to include 'public' - end + it_behaves_like 'cachable response' it 'returns orderedItems with pinned statuses' do json = body_as_json diff --git a/spec/controllers/activitypub/outboxes_controller_spec.rb b/spec/controllers/activitypub/outboxes_controller_spec.rb index 03490533dd5..1baf5a62300 100644 --- a/spec/controllers/activitypub/outboxes_controller_spec.rb +++ b/spec/controllers/activitypub/outboxes_controller_spec.rb @@ -3,6 +3,21 @@ require 'rails_helper' RSpec.describe ActivityPub::OutboxesController, type: :controller do let!(:account) { Fabricate(:account) } + shared_examples 'cachable response' do + it 'does not set cookies' do + expect(response.cookies).to be_empty + expect(response.headers['Set-Cookies']).to be nil + end + + it 'does not set sessions' do + expect(session).to be_empty + end + + it 'returns public Cache-Control header' do + expect(response.headers['Cache-Control']).to include 'public' + end + end + before do Fabricate(:status, account: account, visibility: :public) Fabricate(:status, account: account, visibility: :unlisted) @@ -39,9 +54,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do expect(json[:totalItems]).to eq 4 end - it 'returns public Cache-Control header' do - expect(response.headers['Cache-Control']).to include 'public' - end + it_behaves_like 'cachable response' end context 'with page requested' do @@ -62,9 +75,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do expect(json[:orderedItems].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) }).to be true end - it 'returns public Cache-Control header' do - expect(response.headers['Cache-Control']).to include 'public' - end + it_behaves_like 'cachable response' end end diff --git a/spec/controllers/activitypub/replies_controller_spec.rb b/spec/controllers/activitypub/replies_controller_spec.rb index d956e1b35f0..ed383864dd1 100644 --- a/spec/controllers/activitypub/replies_controller_spec.rb +++ b/spec/controllers/activitypub/replies_controller_spec.rb @@ -7,6 +7,21 @@ RSpec.describe ActivityPub::RepliesController, type: :controller do let(:remote_reply_id) { nil } let(:remote_account) { nil } + shared_examples 'cachable response' do + it 'does not set cookies' do + expect(response.cookies).to be_empty + expect(response.headers['Set-Cookies']).to be nil + end + + it 'does not set sessions' do + expect(session).to be_empty + end + + it 'returns public Cache-Control header' do + expect(response.headers['Cache-Control']).to include 'public' + end + end + before do allow(controller).to receive(:signed_request_account).and_return(remote_account) @@ -36,9 +51,7 @@ RSpec.describe ActivityPub::RepliesController, type: :controller do expect(response.content_type).to eq 'application/activity+json' end - it 'returns public Cache-Control header' do - expect(response.headers['Cache-Control']).to include 'public' - end + it_behaves_like 'cachable response' it 'returns items with account\'s own replies' do json = body_as_json @@ -87,9 +100,7 @@ RSpec.describe ActivityPub::RepliesController, type: :controller do expect(response.content_type).to eq 'application/activity+json' end - it 'returns public Cache-Control header' do - expect(response.headers['Cache-Control']).to include 'public' - end + it_behaves_like 'cachable response' context 'without only_other_accounts' do it 'returns items with account\'s own replies' do diff --git a/spec/controllers/statuses_controller_spec.rb b/spec/controllers/statuses_controller_spec.rb index ba1f1370a63..cd6e1e6074b 100644 --- a/spec/controllers/statuses_controller_spec.rb +++ b/spec/controllers/statuses_controller_spec.rb @@ -5,6 +5,21 @@ require 'rails_helper' describe StatusesController do render_views + shared_examples 'cachable response' do + it 'does not set cookies' do + expect(response.cookies).to be_empty + expect(response.headers['Set-Cookies']).to be nil + end + + it 'does not set sessions' do + expect(session).to be_empty + end + + it 'returns public Cache-Control header' do + expect(response.headers['Cache-Control']).to include 'public' + end + end + describe 'GET #show' do let(:account) { Fabricate(:account) } let(:status) { Fabricate(:status, account: account) } @@ -80,9 +95,7 @@ describe StatusesController do expect(response.headers['Vary']).to eq 'Accept' end - it 'returns public Cache-Control header' do - expect(response.headers['Cache-Control']).to include 'public' - end + it_behaves_like 'cachable response' it 'returns Content-Type header' do expect(response.headers['Content-Type']).to include 'application/activity+json' @@ -470,9 +483,7 @@ describe StatusesController do expect(response.headers['Vary']).to eq 'Accept' end - it 'returns public Cache-Control header' do - expect(response.headers['Cache-Control']).to include 'public' - end + it_behaves_like 'cachable response' it 'returns Content-Type header' do expect(response.headers['Content-Type']).to include 'application/activity+json' From 5d9acc0ce41aa0274fef2dd321a8fad1fb0665ea Mon Sep 17 00:00:00 2001 From: ThibG Date: Wed, 22 Jul 2020 11:45:35 +0200 Subject: [PATCH 19/19] Fix not handling Undo on some activity types when they aren't inlined (#14346) * Fix not handling Undo on some activity types when they aren't inlined When receiving an Undo for a non-inlined activity, try looking it up in database using the URI. The queries are ad-hoc because we don't have a global index of object URIs, and not all activity types are stored in database with an index on their URI. Announces are just statuses, and have an index on URIs, so this check can be done efficiently. Accepts cannot be handled at all because we don't record their URI at any point. Follows don't have an index on URI, but they have an index on the issuing account, which should make such queries largely manageable. Likes don't have an index on URI, they have an index on the issuing account, but the number of favs per account may be very high, so I decided not to handle that. Blocks don't have an index on URI, but they have an index on the issuing account, which should make such queries largely manageable. In all cases, if an Undo could not be handled properly, we call `delete_later!` because that does not require us to know more than the URI of the undone property. * Add tests * Make newer blocks overwrite older ones Allows re-synchronizing block info by re-blocking and un-blocking again when the original Undo Block has been lost. --- app/lib/activitypub/activity/block.rb | 7 ++- app/lib/activitypub/activity/undo.rb | 51 +++++++++++++++++++++ spec/lib/activitypub/activity/block_spec.rb | 22 +++++++++ spec/lib/activitypub/activity/undo_spec.rb | 35 +++++++++++++- 4 files changed, 112 insertions(+), 3 deletions(-) diff --git a/app/lib/activitypub/activity/block.rb b/app/lib/activitypub/activity/block.rb index a17a2d50a6a..90477bf3369 100644 --- a/app/lib/activitypub/activity/block.rb +++ b/app/lib/activitypub/activity/block.rb @@ -4,7 +4,12 @@ class ActivityPub::Activity::Block < ActivityPub::Activity def perform target_account = account_from_uri(object_uri) - return if target_account.nil? || !target_account.local? || @account.blocking?(target_account) + return if target_account.nil? || !target_account.local? + + if @account.blocking?(target_account) + @account.block_relationships.find_by(target_account: target_account).update(uri: @json['id']) if @json['id'].present? + return + end UnfollowService.new.call(target_account, @account) if target_account.following?(@account) diff --git a/app/lib/activitypub/activity/undo.rb b/app/lib/activitypub/activity/undo.rb index 599823c6e25..9eff1b71c9d 100644 --- a/app/lib/activitypub/activity/undo.rb +++ b/app/lib/activitypub/activity/undo.rb @@ -13,11 +13,62 @@ class ActivityPub::Activity::Undo < ActivityPub::Activity undo_like when 'Block' undo_block + when nil + handle_reference end end private + def handle_reference + # Some implementations do not inline the object, and as we don't have a + # global index, we have to guess what object it is. + return if object_uri.nil? + + try_undo_announce || try_undo_accept || try_undo_follow || try_undo_like || try_undo_block || delete_later!(object_uri) + end + + def try_undo_announce + status = Status.where.not(reblog_of_id: nil).find_by(uri: object_uri, account: @account) + if status.present? + RemoveStatusService.new.call(status) + true + else + false + end + end + + def try_undo_accept + # We can't currently handle `Undo Accept` as we don't record `Accept`'s uri + false + end + + def try_undo_follow + follow = @account.follow_requests.find_by(uri: object_uri) || @account.active_relationships.find_by(uri: object_uri) + + if follow.present? + follow.destroy + true + else + false + end + end + + def try_undo_like + # There is an index on accounts, but an account may have *many* favs, so this may be too costly + false + end + + def try_undo_block + block = @account.block_relationships.find_by(uri: object_uri) + if block.present? + UnblockService.new.call(@account, block.target_account) + true + else + false + end + end + def undo_announce return if object_uri.nil? diff --git a/spec/lib/activitypub/activity/block_spec.rb b/spec/lib/activitypub/activity/block_spec.rb index 94d37356dd1..42bdfdc810e 100644 --- a/spec/lib/activitypub/activity/block_spec.rb +++ b/spec/lib/activitypub/activity/block_spec.rb @@ -28,6 +28,28 @@ RSpec.describe ActivityPub::Activity::Block do end end + context 'when the recipient is already blocked' do + before do + sender.block!(recipient, uri: 'old') + end + + describe '#perform' do + subject { described_class.new(json, sender) } + + before do + subject.perform + end + + it 'creates a block from sender to recipient' do + expect(sender.blocking?(recipient)).to be true + end + + it 'sets the uri to that of last received block activity' do + expect(sender.block_relationships.find_by(target_account: recipient).uri).to eq 'foo' + end + end + end + context 'when the recipient follows the sender' do before do recipient.follow!(sender) diff --git a/spec/lib/activitypub/activity/undo_spec.rb b/spec/lib/activitypub/activity/undo_spec.rb index 9545e1f46af..c0309e49daf 100644 --- a/spec/lib/activitypub/activity/undo_spec.rb +++ b/spec/lib/activitypub/activity/undo_spec.rb @@ -50,6 +50,19 @@ RSpec.describe ActivityPub::Activity::Undo do expect(sender.reblogged?(status)).to be false end end + + context 'with only object uri' do + let(:object_json) { 'bar' } + + before do + Fabricate(:status, reblog: status, account: sender, uri: 'bar') + end + + it 'deletes the reblog by uri' do + subject.perform + expect(sender.reblogged?(status)).to be false + end + end end context 'with Accept' do @@ -91,13 +104,22 @@ RSpec.describe ActivityPub::Activity::Undo do end before do - sender.block!(recipient) + sender.block!(recipient, uri: 'bar') end it 'deletes block from sender to recipient' do subject.perform expect(sender.blocking?(recipient)).to be false end + + context 'with only object uri' do + let(:object_json) { 'bar' } + + it 'deletes block from sender to recipient' do + subject.perform + expect(sender.blocking?(recipient)).to be false + end + end end context 'with Follow' do @@ -113,13 +135,22 @@ RSpec.describe ActivityPub::Activity::Undo do end before do - sender.follow!(recipient) + sender.follow!(recipient, uri: 'bar') end it 'deletes follow from sender to recipient' do subject.perform expect(sender.following?(recipient)).to be false end + + context 'with only object uri' do + let(:object_json) { 'bar' } + + it 'deletes follow from sender to recipient' do + subject.perform + expect(sender.following?(recipient)).to be false + end + end end context 'with Like' do