From 14530a232383282e9d45e4832a6935592d541620 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Jan 2021 23:32:42 +0900 Subject: [PATCH 01/24] Bump bullet from 6.1.2 to 6.1.3 (#15629) Bumps [bullet](https://github.com/flyerhzm/bullet) from 6.1.2 to 6.1.3. - [Release notes](https://github.com/flyerhzm/bullet/releases) - [Changelog](https://github.com/flyerhzm/bullet/blob/master/CHANGELOG.md) - [Commits](https://github.com/flyerhzm/bullet/compare/6.1.2...6.1.3) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 516db5a3219..b400c4c80c8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -109,7 +109,7 @@ GEM brakeman (4.10.1) browser (4.2.0) builder (3.2.4) - bullet (6.1.2) + bullet (6.1.3) activesupport (>= 3.0.0) uniform_notifier (~> 1.11) bundler-audit (0.7.0.1) @@ -647,7 +647,7 @@ GEM unf_ext unf_ext (0.0.7.7) unicode-display_width (1.7.0) - uniform_notifier (1.13.0) + uniform_notifier (1.13.2) warden (1.2.9) rack (>= 2.0.9) webauthn (3.0.0.alpha1) From 3a3990a81dc56e344cf81af14f0bb0ee1658ca58 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Jan 2021 23:33:06 +0900 Subject: [PATCH 02/24] Bump rack-attack from 6.3.1 to 6.4.0 (#15628) Bumps [rack-attack](https://github.com/rack/rack-attack) from 6.3.1 to 6.4.0. - [Release notes](https://github.com/rack/rack-attack/releases) - [Changelog](https://github.com/rack/rack-attack/blob/master/CHANGELOG.md) - [Commits](https://github.com/rack/rack-attack/compare/v6.3.1...v6.4.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index aeb6d73ee74..e1e3cc8f569 100644 --- a/Gemfile +++ b/Gemfile @@ -73,7 +73,7 @@ gem 'parallel', '~> 1.20' gem 'posix-spawn' gem 'pundit', '~> 2.1' gem 'premailer-rails' -gem 'rack-attack', '~> 6.3' +gem 'rack-attack', '~> 6.4' gem 'rack-cors', '~> 1.1', require: 'rack/cors' gem 'rails-i18n', '~> 5.1' gem 'rails-settings-cached', '~> 0.6' diff --git a/Gemfile.lock b/Gemfile.lock index b400c4c80c8..9c5706fa0ec 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -436,7 +436,7 @@ GEM raabro (1.3.3) racc (1.5.2) rack (2.2.3) - rack-attack (6.3.1) + rack-attack (6.4.0) rack (>= 1.0, < 3) rack-cors (1.1.1) rack (>= 2.0.0) @@ -772,7 +772,7 @@ DEPENDENCIES puma (~> 5.1) pundit (~> 2.1) rack (~> 2.2.3) - rack-attack (~> 6.3) + rack-attack (~> 6.4) rack-cors (~> 1.1) rails (~> 5.2.4.4) rails-controller-testing (~> 1.0) From 97e075f197e30b8e55fbe169c8073cef08d4daef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Jan 2021 23:33:46 +0900 Subject: [PATCH 03/24] Bump oj from 3.11.0 to 3.11.1 (#15626) Bumps [oj](https://github.com/ohler55/oj) from 3.11.0 to 3.11.1. - [Release notes](https://github.com/ohler55/oj/releases) - [Changelog](https://github.com/ohler55/oj/blob/develop/CHANGELOG.md) - [Commits](https://github.com/ohler55/oj/compare/v3.11.0...v3.11.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9c5706fa0ec..dbca7343bac 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -369,7 +369,7 @@ GEM concurrent-ruby (~> 1.0, >= 1.0.2) sidekiq (>= 3.5) statsd-ruby (~> 1.4, >= 1.4.0) - oj (3.11.0) + oj (3.11.1) omniauth (1.9.1) hashie (>= 3.4.6) rack (>= 1.6.2, < 3) From 4d16f25119e4934f396b858298b91f239f9aeb70 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Jan 2021 23:34:05 +0900 Subject: [PATCH 04/24] Bump webpack-bundle-analyzer from 4.3.0 to 4.4.0 (#15625) Bumps [webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer) from 4.3.0 to 4.4.0. - [Release notes](https://github.com/webpack-contrib/webpack-bundle-analyzer/releases) - [Changelog](https://github.com/webpack-contrib/webpack-bundle-analyzer/blob/master/CHANGELOG.md) - [Commits](https://github.com/webpack-contrib/webpack-bundle-analyzer/compare/v4.3.0...v4.4.0) 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 cc88ee2c613..755b52b3786 100644 --- a/package.json +++ b/package.json @@ -165,7 +165,7 @@ "uuid": "^8.3.1", "webpack": "^4.46.0", "webpack-assets-manifest": "^4.0.1", - "webpack-bundle-analyzer": "^4.3.0", + "webpack-bundle-analyzer": "^4.4.0", "webpack-cli": "^3.3.12", "webpack-merge": "^5.7.3", "wicg-inert": "^3.1.0" diff --git a/yarn.lock b/yarn.lock index 1110d9dfc7e..75dc36d3812 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11069,10 +11069,10 @@ webpack-assets-manifest@^4.0.1: tapable "^1.0" webpack-sources "^1.0" -webpack-bundle-analyzer@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.3.0.tgz#2f3c0ca9041d5ee47fa418693cf56b4a518b578b" - integrity sha512-J3TPm54bPARx6QG8z4cKBszahnUglcv70+N+8gUqv2I5KOFHJbzBiLx+pAp606so0X004fxM7hqRu10MLjJifA== +webpack-bundle-analyzer@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.4.0.tgz#74013106e7e2b07cbd64f3a5ae847f7e814802c7" + integrity sha512-9DhNa+aXpqdHk8LkLPTBU/dMfl84Y+WE2+KnfI6rSpNRNVKa0VGLjPd2pjFubDeqnWmulFggxmWBxhfJXZnR0g== dependencies: acorn "^8.0.4" acorn-walk "^8.0.0" From 70128820dc06501cb791a88559fb4b82244a08c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Jan 2021 23:34:48 +0900 Subject: [PATCH 05/24] Bump tzinfo-data from 1.2020.6 to 1.2021.1 (#15623) Bumps [tzinfo-data](https://github.com/tzinfo/tzinfo-data) from 1.2020.6 to 1.2021.1. - [Release notes](https://github.com/tzinfo/tzinfo-data/releases) - [Commits](https://github.com/tzinfo/tzinfo-data/compare/v1.2020.6...v1.2021.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index e1e3cc8f569..bbad0a84164 100644 --- a/Gemfile +++ b/Gemfile @@ -94,7 +94,7 @@ gem 'stoplight', '~> 2.2.1' gem 'strong_migrations', '~> 0.7' gem 'tty-prompt', '~> 0.23', require: false gem 'twitter-text', '~> 1.14' -gem 'tzinfo-data', '~> 1.2020' +gem 'tzinfo-data', '~> 1.2021' gem 'webpacker', '~> 5.2' gem 'webpush' gem 'webauthn', '~> 3.0.0.alpha1' diff --git a/Gemfile.lock b/Gemfile.lock index dbca7343bac..50ca2feb1c4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -641,7 +641,7 @@ GEM unf (~> 0.1.0) tzinfo (1.2.9) thread_safe (~> 0.1) - tzinfo-data (1.2020.6) + tzinfo-data (1.2021.1) tzinfo (>= 1.0.0) unf (0.1.4) unf_ext @@ -807,7 +807,7 @@ DEPENDENCIES thor (~> 1.0) tty-prompt (~> 0.23) twitter-text (~> 1.14) - tzinfo-data (~> 1.2020) + tzinfo-data (~> 1.2021) webauthn (~> 3.0.0.alpha1) webmock (~> 3.11) webpacker (~> 5.2) From e9ac2632299e9df7ee120d5936648ed96b9fd4a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Jan 2021 23:35:03 +0900 Subject: [PATCH 06/24] Bump thor from 1.0.1 to 1.1.0 (#15622) Bumps [thor](https://github.com/erikhuda/thor) from 1.0.1 to 1.1.0. - [Release notes](https://github.com/erikhuda/thor/releases) - [Changelog](https://github.com/erikhuda/thor/blob/master/CHANGELOG.md) - [Commits](https://github.com/erikhuda/thor/compare/v1.0.1...v1.1.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index bbad0a84164..971c3967f7b 100644 --- a/Gemfile +++ b/Gemfile @@ -8,7 +8,7 @@ gem 'pkg-config', '~> 1.4' gem 'puma', '~> 5.1' gem 'rails', '~> 5.2.4.4' gem 'sprockets', '~> 3.7.2' -gem 'thor', '~> 1.0' +gem 'thor', '~> 1.1' gem 'rack', '~> 2.2.3' gem 'hamlit-rails', '~> 0.2' diff --git a/Gemfile.lock b/Gemfile.lock index 50ca2feb1c4..003f426095a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -619,7 +619,7 @@ GEM unicode-display_width (~> 1.1, >= 1.1.1) terrapin (0.6.0) climate_control (>= 0.0.3, < 1.0) - thor (1.0.1) + thor (1.1.0) thread_safe (0.3.6) thwait (0.2.0) e2mmap @@ -804,7 +804,7 @@ DEPENDENCIES stoplight (~> 2.2.1) streamio-ffmpeg (~> 3.0) strong_migrations (~> 0.7) - thor (~> 1.0) + thor (~> 1.1) tty-prompt (~> 0.23) twitter-text (~> 1.14) tzinfo-data (~> 1.2021) From 38f56315883f8bb45a1fbcff371016246cd1b3f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 Jan 2021 08:58:29 +0900 Subject: [PATCH 07/24] Bump sidekiq from 6.1.2 to 6.1.3 (#15621) Bumps [sidekiq](https://github.com/mperham/sidekiq) from 6.1.2 to 6.1.3. - [Release notes](https://github.com/mperham/sidekiq/releases) - [Changelog](https://github.com/mperham/sidekiq/blob/master/Changes.md) - [Commits](https://github.com/mperham/sidekiq/compare/v6.1.2...v6.1.3) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 003f426095a..113d5638d41 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -569,7 +569,7 @@ GEM railties (>= 4.0.0) securecompare (1.0.0) semantic_range (2.3.0) - sidekiq (6.1.2) + sidekiq (6.1.3) connection_pool (>= 2.2.2) rack (~> 2.0) redis (>= 4.2.0) From 2319e85a8a681b135b80e12a2f32a5cdbcec1b6a Mon Sep 17 00:00:00 2001 From: abcang Date: Fri, 29 Jan 2021 02:24:22 +0900 Subject: [PATCH 08/24] Fix react/jsx-no-duplicate-props (#15636) --- app/javascript/mastodon/features/account/components/header.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/features/account/components/header.js b/app/javascript/mastodon/features/account/components/header.js index 4647b98b21a..2087fc3b80d 100644 --- a/app/javascript/mastodon/features/account/components/header.js +++ b/app/javascript/mastodon/features/account/components/header.js @@ -330,7 +330,7 @@ class Header extends ImmutablePureComponent {
-
+
{pair.get('verified_at') && }
From b4281f5a51c8c54891b7a74e9573faec6871a460 Mon Sep 17 00:00:00 2001 From: Daniel Jakots Date: Thu, 28 Jan 2021 16:53:56 -0500 Subject: [PATCH 09/24] Update to Node.js-12.20.1 (#15558) This is a security release. You can read the announce at https://nodejs.org/en/blog/vulnerability/january-2021-security-releases/ --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 136b2a35ae6..84e6435f3ee 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ FROM ubuntu:20.04 as build-dep SHELL ["/usr/bin/bash", "-c"] # Install Node v12 (LTS) -ENV NODE_VER="12.20.0" +ENV NODE_VER="12.20.1" RUN ARCH= && \ dpkgArch="$(dpkg --print-architecture)" && \ case "${dpkgArch##*-}" in \ From 13d5b8157904b2eb6b7f43e3fb834fca2f38f0dd Mon Sep 17 00:00:00 2001 From: ThibG Date: Fri, 29 Jan 2021 18:38:56 +0100 Subject: [PATCH 10/24] =?UTF-8?q?Fix=20=E2=80=9Ctootctl=20accounts=20unfol?= =?UTF-8?q?low=E2=80=9D=20(#15639)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #15635 Co-authored-by: Claire --- lib/mastodon/accounts_cli.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mastodon/accounts_cli.rb b/lib/mastodon/accounts_cli.rb index 653bfca3010..74162256ff7 100644 --- a/lib/mastodon/accounts_cli.rb +++ b/lib/mastodon/accounts_cli.rb @@ -402,7 +402,7 @@ module Mastodon exit(1) end - parallelize_with_progress(target_account.followers.local) do |account| + processed, = parallelize_with_progress(target_account.followers.local) do |account| UnfollowService.new.call(account, target_account) end From eb0f9e315939a66ebad0b174beeb1edde7ba7e8d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Feb 2021 03:48:29 +0900 Subject: [PATCH 11/24] Bump rubocop from 1.7.0 to 1.8.1 (#15573) * Bump rubocop from 1.7.0 to 1.8.1 Bumps [rubocop](https://github.com/rubocop-hq/rubocop) from 1.7.0 to 1.8.1. - [Release notes](https://github.com/rubocop-hq/rubocop/releases) - [Changelog](https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md) - [Commits](https://github.com/rubocop-hq/rubocop/compare/v1.7.0...v1.8.1) Signed-off-by: dependabot[bot] * Fix .codeclimate.yml Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Yamagishi Kazutoshi --- .codeclimate.yml | 2 +- Gemfile | 2 +- Gemfile.lock | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.codeclimate.yml b/.codeclimate.yml index 2d1de877cea..62dc2334caa 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -30,7 +30,7 @@ plugins: channel: eslint-7 rubocop: enabled: true - channel: rubocop-1-70 + channel: rubocop-1-8-1 sass-lint: enabled: true exclude_patterns: diff --git a/Gemfile b/Gemfile index 971c3967f7b..8ac92cdf95e 100644 --- a/Gemfile +++ b/Gemfile @@ -138,7 +138,7 @@ group :development do gem 'letter_opener', '~> 1.7' gem 'letter_opener_web', '~> 1.4' gem 'memory_profiler' - gem 'rubocop', '~> 1.7', require: false + gem 'rubocop', '~> 1.8', require: false gem 'rubocop-rails', '~> 2.9', require: false gem 'brakeman', '~> 4.10', require: false gem 'bundler-audit', '~> 0.7', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 113d5638d41..ba6fd64ac74 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -538,16 +538,16 @@ GEM rspec-support (3.10.1) rspec_junit_formatter (0.4.1) rspec-core (>= 2, < 4, != 2.12.0) - rubocop (1.7.0) + rubocop (1.8.1) parallel (~> 1.10) - parser (>= 2.7.1.5) + parser (>= 3.0.0.0) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) rexml rubocop-ast (>= 1.2.0, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 2.0) - rubocop-ast (1.3.0) + unicode-display_width (>= 1.4.0, < 3.0) + rubocop-ast (1.4.0) parser (>= 2.7.1.5) rubocop-rails (2.9.1) activesupport (>= 4.2.0) @@ -786,7 +786,7 @@ DEPENDENCIES rspec-rails (~> 4.0) rspec-sidekiq (~> 3.1) rspec_junit_formatter (~> 0.4) - rubocop (~> 1.7) + rubocop (~> 1.8) rubocop-rails (~> 2.9) ruby-progressbar (~> 1.11) sanitize (~> 5.2) From c8c764dd8b168ec876918d16b3f25280893d20dc Mon Sep 17 00:00:00 2001 From: abcang Date: Mon, 1 Feb 2021 05:24:17 +0900 Subject: [PATCH 12/24] Fix N+1 query when rendering with StatusSerializer (#15641) --- app/models/status.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/status.rb b/app/models/status.rb index fcc7a026d5c..74e81f6127c 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -114,7 +114,7 @@ class Status < ApplicationRecord :tags, :preview_cards, :preloadable_poll, - account: :account_stat, + account: [:account_stat, :user], active_mentions: { account: :account_stat }, reblog: [ :application, @@ -124,7 +124,7 @@ class Status < ApplicationRecord :conversation, :status_stat, :preloadable_poll, - account: :account_stat, + account: [:account_stat, :user], active_mentions: { account: :account_stat }, ], thread: { account: :account_stat } @@ -301,7 +301,7 @@ class Status < ApplicationRecord return if account_ids.empty? - accounts = Account.where(id: account_ids).includes(:account_stat).index_by(&:id) + accounts = Account.where(id: account_ids).includes(:account_stat, :user).index_by(&:id) cached_items.each do |item| item.account = accounts[item.account_id] From 7ab53f221a3d66a0bbc94b36d847b7bcf62fbd16 Mon Sep 17 00:00:00 2001 From: abcang Date: Mon, 1 Feb 2021 05:24:57 +0900 Subject: [PATCH 13/24] Improved performance of notification preloading (#15640) * Improved performance of notification preloading * Remove Cacheable from Notification * Fix test --- .../api/v1/notifications_controller.rb | 7 +- app/models/notification.rb | 56 ++++++--- .../application_controller_spec.rb | 4 - spec/models/notification_spec.rb | 119 ++++++++++++++---- 4 files changed, 136 insertions(+), 50 deletions(-) diff --git a/app/controllers/api/v1/notifications_controller.rb b/app/controllers/api/v1/notifications_controller.rb index 522c35ba548..f9d78083984 100644 --- a/app/controllers/api/v1/notifications_controller.rb +++ b/app/controllers/api/v1/notifications_controller.rb @@ -31,12 +31,13 @@ class Api::V1::NotificationsController < Api::BaseController private def load_notifications - cache_collection_paginated_by_id( - browserable_account_notifications, - Notification, + notifications = browserable_account_notifications.includes(from_account: :account_stat).to_a_paginated_by_id( limit_param(DEFAULT_NOTIFICATIONS_LIMIT), params_slice(:max_id, :since_id, :min_id) ) + Notification.preload_cache_collection_target_statuses(notifications) do |target_statuses| + cache_collection(target_statuses, Status) + end end def browserable_account_notifications diff --git a/app/models/notification.rb b/app/models/notification.rb index 5e9ea62a0d5..98a6a618f5f 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -17,7 +17,6 @@ class Notification < ApplicationRecord self.inheritance_column = nil include Paginable - include Cacheable LEGACY_TYPE_CLASS_MAP = { 'Mention' => :mention, @@ -38,7 +37,13 @@ class Notification < ApplicationRecord poll ).freeze - STATUS_INCLUDES = [:account, :application, :preloadable_poll, :media_attachments, :tags, active_mentions: :account, reblog: [:account, :application, :preloadable_poll, :media_attachments, :tags, active_mentions: :account]].freeze + TARGET_STATUS_INCLUDES_BY_TYPE = { + status: :status, + reblog: [status: :reblog], + mention: [mention: :status], + favourite: [favourite: :status], + poll: [poll: :status], + }.freeze belongs_to :account, optional: true belongs_to :from_account, class_name: 'Account', optional: true @@ -65,8 +70,6 @@ class Notification < ApplicationRecord end } - cache_associated :from_account, status: STATUS_INCLUDES, mention: [status: STATUS_INCLUDES], favourite: [:account, status: STATUS_INCLUDES], follow: :account, follow_request: :account, poll: [status: STATUS_INCLUDES] - def type @type ||= (super || LEGACY_TYPE_CLASS_MAP[activity_type]).to_sym end @@ -87,21 +90,40 @@ class Notification < ApplicationRecord end class << self - def cache_ids - select(:id, :updated_at, :activity_type, :activity_id) - end + def preload_cache_collection_target_statuses(notifications, &_block) + notifications.group_by(&:type).each do |type, grouped_notifications| + associations = TARGET_STATUS_INCLUDES_BY_TYPE[type] + next unless associations - def reload_stale_associations!(cached_items) - account_ids = (cached_items.map(&:from_account_id) + cached_items.filter_map { |item| item.target_status&.account_id }).uniq - - return if account_ids.empty? - - accounts = Account.where(id: account_ids).includes(:account_stat).index_by(&:id) - - cached_items.each do |item| - item.from_account = accounts[item.from_account_id] - item.target_status.account = accounts[item.target_status.account_id] if item.target_status + # Instead of using the usual `includes`, manually preload each type. + # If polymorphic associations are loaded with the usual `includes`, other types of associations will be loaded more. + ActiveRecord::Associations::Preloader.new.preload(grouped_notifications, associations) end + + unique_target_statuses = notifications.map(&:target_status).compact.uniq + # Call cache_collection in block + cached_statuses_by_id = yield(unique_target_statuses).index_by(&:id) + + notifications.each do |notification| + next if notification.target_status.nil? + + cached_status = cached_statuses_by_id[notification.target_status.id] + + case notification.type + when :status + notification.status = cached_status + when :reblog + notification.status.reblog = cached_status + when :favourite + notification.favourite.status = cached_status + when :mention + notification.mention.status = cached_status + when :poll + notification.poll.status = cached_status + end + end + + notifications end end diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 63ae27a924e..e73a08a0e99 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -349,10 +349,6 @@ describe ApplicationController, type: :controller do expect(C.new.cache_collection(raw, Object)).to eq raw end - context 'Notification' do - include_examples 'cacheable', :notification, Notification - end - context 'Status' do include_examples 'cacheable', :status, Status end diff --git a/spec/models/notification_spec.rb b/spec/models/notification_spec.rb index 0a045904bb2..1e9e45d8d6d 100644 --- a/spec/models/notification_spec.rb +++ b/spec/models/notification_spec.rb @@ -56,47 +56,114 @@ RSpec.describe Notification, type: :model do end end - describe '.reload_stale_associations!' do - context 'account_ids are empty' do - let(:cached_items) { [] } - - subject { described_class.reload_stale_associations!(cached_items) } - - it 'returns nil' do - is_expected.to be nil + describe '.preload_cache_collection_target_statuses' do + subject do + described_class.preload_cache_collection_target_statuses(notifications) do |target_statuses| + # preload account for testing instead of using cache_collection + Status.preload(:account).where(id: target_statuses.map(&:id)) end end - context 'account_ids are present' do + context 'notifications are empty' do + let(:notifications) { [] } + + it 'returns []' do + is_expected.to eq [] + end + end + + context 'notifications are present' do before do - allow(accounts_with_ids).to receive(:[]).with(stale_account1.id).and_return(account1) - allow(accounts_with_ids).to receive(:[]).with(stale_account2.id).and_return(account2) - allow(Account).to receive_message_chain(:where, :includes, :index_by).and_return(accounts_with_ids) + notifications.each(&:reload) end - let(:cached_items) do + let(:mention) { Fabricate(:mention) } + let(:status) { Fabricate(:status) } + let(:reblog) { Fabricate(:status, reblog: Fabricate(:status)) } + let(:follow) { Fabricate(:follow) } + let(:follow_request) { Fabricate(:follow_request) } + let(:favourite) { Fabricate(:favourite) } + let(:poll) { Fabricate(:poll) } + + let(:notifications) do [ - Fabricate(:notification, activity: Fabricate(:status)), - Fabricate(:notification, activity: Fabricate(:follow)), + Fabricate(:notification, type: :mention, activity: mention), + Fabricate(:notification, type: :status, activity: status), + Fabricate(:notification, type: :reblog, activity: reblog), + Fabricate(:notification, type: :follow, activity: follow), + Fabricate(:notification, type: :follow_request, activity: follow_request), + Fabricate(:notification, type: :favourite, activity: favourite), + Fabricate(:notification, type: :poll, activity: poll), ] end - let(:stale_account1) { cached_items[0].from_account } - let(:stale_account2) { cached_items[1].from_account } + it 'preloads target status' do + # mention + expect(subject[0].type).to eq :mention + expect(subject[0].association(:mention)).to be_loaded + expect(subject[0].mention.association(:status)).to be_loaded - let(:account1) { Fabricate(:account) } - let(:account2) { Fabricate(:account) } + # status + expect(subject[1].type).to eq :status + expect(subject[1].association(:status)).to be_loaded - let(:accounts_with_ids) { { account1.id => account1, account2.id => account2 } } + # reblog + expect(subject[2].type).to eq :reblog + expect(subject[2].association(:status)).to be_loaded + expect(subject[2].status.association(:reblog)).to be_loaded - it 'reloads associations' do - expect(cached_items[0].from_account).to be stale_account1 - expect(cached_items[1].from_account).to be stale_account2 + # follow: nothing + expect(subject[3].type).to eq :follow + expect(subject[3].target_status).to be_nil - described_class.reload_stale_associations!(cached_items) + # follow_request: nothing + expect(subject[4].type).to eq :follow_request + expect(subject[4].target_status).to be_nil - expect(cached_items[0].from_account).to be account1 - expect(cached_items[1].from_account).to be account2 + # favourite + expect(subject[5].type).to eq :favourite + expect(subject[5].association(:favourite)).to be_loaded + expect(subject[5].favourite.association(:status)).to be_loaded + + # poll + expect(subject[6].type).to eq :poll + expect(subject[6].association(:poll)).to be_loaded + expect(subject[6].poll.association(:status)).to be_loaded + end + + it 'replaces to cached status' do + # mention + expect(subject[0].type).to eq :mention + expect(subject[0].target_status.association(:account)).to be_loaded + expect(subject[0].target_status).to eq mention.status + + # status + expect(subject[1].type).to eq :status + expect(subject[1].target_status.association(:account)).to be_loaded + expect(subject[1].target_status).to eq status + + # reblog + expect(subject[2].type).to eq :reblog + expect(subject[2].target_status.association(:account)).to be_loaded + expect(subject[2].target_status).to eq reblog.reblog + + # follow: nothing + expect(subject[3].type).to eq :follow + expect(subject[3].target_status).to be_nil + + # follow_request: nothing + expect(subject[4].type).to eq :follow_request + expect(subject[4].target_status).to be_nil + + # favourite + expect(subject[5].type).to eq :favourite + expect(subject[5].target_status.association(:account)).to be_loaded + expect(subject[5].target_status).to eq favourite.status + + # poll + expect(subject[6].type).to eq :poll + expect(subject[6].target_status.association(:account)).to be_loaded + expect(subject[6].target_status).to eq poll.status end end end From 3efa0c54b6656fba189baab0857e60c0bc4f3c7d Mon Sep 17 00:00:00 2001 From: ThibG Date: Sun, 31 Jan 2021 21:25:31 +0100 Subject: [PATCH 14/24] Change custom emoji to be animated when hovering container (#15637) Co-authored-by: Claire --- .../__snapshots__/display_name-test.js.snap | 2 + .../mastodon/components/display_name.js | 43 +++++---------- .../mastodon/components/status_content.js | 43 +++++++-------- .../features/account/components/header.js | 43 +++++---------- .../components/conversation.js | 43 +++++---------- .../directory/components/account_card.js | 47 ++++++---------- .../components/announcements.js | 53 +++++++++---------- 7 files changed, 103 insertions(+), 171 deletions(-) diff --git a/app/javascript/mastodon/components/__tests__/__snapshots__/display_name-test.js.snap b/app/javascript/mastodon/components/__tests__/__snapshots__/display_name-test.js.snap index 29fdc2412db..0f27473af4e 100644 --- a/app/javascript/mastodon/components/__tests__/__snapshots__/display_name-test.js.snap +++ b/app/javascript/mastodon/components/__tests__/__snapshots__/display_name-test.js.snap @@ -3,6 +3,8 @@ exports[` renders display name + account name 1`] = ` { + if (autoPlayGif) { return; } - const emojis = node.querySelectorAll('.custom-emoji'); + const emojis = currentTarget.querySelectorAll('.custom-emoji'); for (var i = 0; i < emojis.length; i++) { let emoji = emojis[i]; - if (emoji.classList.contains('status-emoji')) { - continue; - } - emoji.classList.add('status-emoji'); - - emoji.addEventListener('mouseenter', this.handleEmojiMouseEnter, false); - emoji.addEventListener('mouseleave', this.handleEmojiMouseLeave, false); + emoji.src = emoji.getAttribute('data-original'); } } - componentDidMount () { - this._updateEmojis(); - } + handleMouseLeave = ({ currentTarget }) => { + if (autoPlayGif) { + return; + } - componentDidUpdate () { - this._updateEmojis(); - } + const emojis = currentTarget.querySelectorAll('.custom-emoji'); - handleEmojiMouseEnter = ({ target }) => { - target.src = target.getAttribute('data-original'); - } - - handleEmojiMouseLeave = ({ target }) => { - target.src = target.getAttribute('data-static'); - } - - setRef = (c) => { - this.node = c; + for (var i = 0; i < emojis.length; i++) { + let emoji = emojis[i]; + emoji.src = emoji.getAttribute('data-static'); + } } render () { @@ -81,7 +66,7 @@ export default class DisplayName extends React.PureComponent { } return ( - + {displayName} {suffix} ); diff --git a/app/javascript/mastodon/components/status_content.js b/app/javascript/mastodon/components/status_content.js index 190ced1a807..35bd505142e 100644 --- a/app/javascript/mastodon/components/status_content.js +++ b/app/javascript/mastodon/components/status_content.js @@ -75,35 +75,38 @@ export default class StatusContent extends React.PureComponent { } } - _updateStatusEmojis () { - const node = this.node; - - if (!node || autoPlayGif) { + handleMouseEnter = ({ currentTarget }) => { + if (autoPlayGif) { return; } - const emojis = node.querySelectorAll('.custom-emoji'); + const emojis = currentTarget.querySelectorAll('.custom-emoji'); for (var i = 0; i < emojis.length; i++) { let emoji = emojis[i]; - if (emoji.classList.contains('status-emoji')) { - continue; - } - emoji.classList.add('status-emoji'); + emoji.src = emoji.getAttribute('data-original'); + } + } - emoji.addEventListener('mouseenter', this.handleEmojiMouseEnter, false); - emoji.addEventListener('mouseleave', this.handleEmojiMouseLeave, false); + handleMouseLeave = ({ currentTarget }) => { + if (autoPlayGif) { + return; + } + + const emojis = currentTarget.querySelectorAll('.custom-emoji'); + + for (var i = 0; i < emojis.length; i++) { + let emoji = emojis[i]; + emoji.src = emoji.getAttribute('data-static'); } } componentDidMount () { this._updateStatusLinks(); - this._updateStatusEmojis(); } componentDidUpdate () { this._updateStatusLinks(); - this._updateStatusEmojis(); } onMentionClick = (mention, e) => { @@ -122,14 +125,6 @@ export default class StatusContent extends React.PureComponent { } } - handleEmojiMouseEnter = ({ target }) => { - target.src = target.getAttribute('data-original'); - } - - handleEmojiMouseLeave = ({ target }) => { - target.src = target.getAttribute('data-static'); - } - handleMouseDown = (e) => { this.startXY = [e.clientX, e.clientY]; } @@ -219,7 +214,7 @@ export default class StatusContent extends React.PureComponent { } return ( -
+
+
{!!status.get('poll') && } @@ -253,7 +248,7 @@ export default class StatusContent extends React.PureComponent { return output; } else { return ( -
+
{!!status.get('poll') && } diff --git a/app/javascript/mastodon/features/account/components/header.js b/app/javascript/mastodon/features/account/components/header.js index 2087fc3b80d..8e49486bdaa 100644 --- a/app/javascript/mastodon/features/account/components/header.js +++ b/app/javascript/mastodon/features/account/components/header.js @@ -96,45 +96,30 @@ class Header extends ImmutablePureComponent { return !location.pathname.match(/\/(followers|following)\/?$/); } - _updateEmojis () { - const node = this.node; - - if (!node || autoPlayGif) { + handleMouseEnter = ({ currentTarget }) => { + if (autoPlayGif) { return; } - const emojis = node.querySelectorAll('.custom-emoji'); + const emojis = currentTarget.querySelectorAll('.custom-emoji'); for (var i = 0; i < emojis.length; i++) { let emoji = emojis[i]; - if (emoji.classList.contains('status-emoji')) { - continue; - } - emoji.classList.add('status-emoji'); - - emoji.addEventListener('mouseenter', this.handleEmojiMouseEnter, false); - emoji.addEventListener('mouseleave', this.handleEmojiMouseLeave, false); + emoji.src = emoji.getAttribute('data-original'); } } - componentDidMount () { - this._updateEmojis(); - } + handleMouseLeave = ({ currentTarget }) => { + if (autoPlayGif) { + return; + } - componentDidUpdate () { - this._updateEmojis(); - } + const emojis = currentTarget.querySelectorAll('.custom-emoji'); - handleEmojiMouseEnter = ({ target }) => { - target.src = target.getAttribute('data-original'); - } - - handleEmojiMouseLeave = ({ target }) => { - target.src = target.getAttribute('data-static'); - } - - setRef = (c) => { - this.node = c; + for (var i = 0; i < emojis.length; i++) { + let emoji = emojis[i]; + emoji.src = emoji.getAttribute('data-static'); + } } render () { @@ -276,7 +261,7 @@ class Header extends ImmutablePureComponent { } return ( -
+
{!suspended && info} diff --git a/app/javascript/mastodon/features/direct_timeline/components/conversation.js b/app/javascript/mastodon/features/direct_timeline/components/conversation.js index 6ecc27facd1..43e1d77b946 100644 --- a/app/javascript/mastodon/features/direct_timeline/components/conversation.js +++ b/app/javascript/mastodon/features/direct_timeline/components/conversation.js @@ -44,41 +44,30 @@ class Conversation extends ImmutablePureComponent { intl: PropTypes.object.isRequired, }; - _updateEmojis () { - const node = this.namesNode; - - if (!node || autoPlayGif) { + handleMouseEnter = ({ currentTarget }) => { + if (autoPlayGif) { return; } - const emojis = node.querySelectorAll('.custom-emoji'); + const emojis = currentTarget.querySelectorAll('.custom-emoji'); for (var i = 0; i < emojis.length; i++) { let emoji = emojis[i]; - if (emoji.classList.contains('status-emoji')) { - continue; - } - emoji.classList.add('status-emoji'); - - emoji.addEventListener('mouseenter', this.handleEmojiMouseEnter, false); - emoji.addEventListener('mouseleave', this.handleEmojiMouseLeave, false); + emoji.src = emoji.getAttribute('data-original'); } } - componentDidMount () { - this._updateEmojis(); - } + handleMouseLeave = ({ currentTarget }) => { + if (autoPlayGif) { + return; + } - componentDidUpdate () { - this._updateEmojis(); - } + const emojis = currentTarget.querySelectorAll('.custom-emoji'); - handleEmojiMouseEnter = ({ target }) => { - target.src = target.getAttribute('data-original'); - } - - handleEmojiMouseLeave = ({ target }) => { - target.src = target.getAttribute('data-static'); + for (var i = 0; i < emojis.length; i++) { + let emoji = emojis[i]; + emoji.src = emoji.getAttribute('data-static'); + } } handleClick = () => { @@ -123,10 +112,6 @@ class Conversation extends ImmutablePureComponent { this.props.onToggleHidden(this.props.lastStatus); } - setNamesRef = (c) => { - this.namesNode = c; - } - render () { const { accounts, lastStatus, unread, scrollKey, intl } = this.props; @@ -171,7 +156,7 @@ class Conversation extends ImmutablePureComponent { {unread && }
-
+
{names} }} />
diff --git a/app/javascript/mastodon/features/directory/components/account_card.js b/app/javascript/mastodon/features/directory/components/account_card.js index e3773382803..8f0e8db4b41 100644 --- a/app/javascript/mastodon/features/directory/components/account_card.js +++ b/app/javascript/mastodon/features/directory/components/account_card.js @@ -102,43 +102,32 @@ class AccountCard extends ImmutablePureComponent { onMute: PropTypes.func.isRequired, }; - _updateEmojis() { - const node = this.node; - - if (!node || autoPlayGif) { + handleMouseEnter = ({ currentTarget }) => { + if (autoPlayGif) { return; } - const emojis = node.querySelectorAll('.custom-emoji'); + const emojis = currentTarget.querySelectorAll('.custom-emoji'); for (var i = 0; i < emojis.length; i++) { let emoji = emojis[i]; - if (emoji.classList.contains('status-emoji')) { - continue; - } - emoji.classList.add('status-emoji'); - - emoji.addEventListener('mouseenter', this.handleEmojiMouseEnter, false); - emoji.addEventListener('mouseleave', this.handleEmojiMouseLeave, false); + emoji.src = emoji.getAttribute('data-original'); } } - componentDidMount() { - this._updateEmojis(); + handleMouseLeave = ({ currentTarget }) => { + if (autoPlayGif) { + return; + } + + const emojis = currentTarget.querySelectorAll('.custom-emoji'); + + for (var i = 0; i < emojis.length; i++) { + let emoji = emojis[i]; + emoji.src = emoji.getAttribute('data-static'); + } } - componentDidUpdate() { - this._updateEmojis(); - } - - handleEmojiMouseEnter = ({ target }) => { - target.src = target.getAttribute('data-original'); - }; - - handleEmojiMouseLeave = ({ target }) => { - target.src = target.getAttribute('data-static'); - }; - handleFollow = () => { this.props.onFollow(this.props.account); }; @@ -151,10 +140,6 @@ class AccountCard extends ImmutablePureComponent { this.props.onMute(this.props.account); }; - setRef = (c) => { - this.node = c; - }; - render() { const { account, intl } = this.props; @@ -239,7 +224,7 @@ class AccountCard extends ImmutablePureComponent {
-
+
{ - target.src = target.getAttribute('data-original'); + handleMouseEnter = ({ currentTarget }) => { + if (autoPlayGif) { + return; + } + + const emojis = currentTarget.querySelectorAll('.custom-emoji'); + + for (var i = 0; i < emojis.length; i++) { + let emoji = emojis[i]; + emoji.src = emoji.getAttribute('data-original'); + } } - handleEmojiMouseLeave = ({ target }) => { - target.src = target.getAttribute('data-static'); + handleMouseLeave = ({ currentTarget }) => { + if (autoPlayGif) { + return; + } + + const emojis = currentTarget.querySelectorAll('.custom-emoji'); + + for (var i = 0; i < emojis.length; i++) { + let emoji = emojis[i]; + emoji.src = emoji.getAttribute('data-static'); + } } render () { @@ -148,6 +141,8 @@ class Content extends ImmutablePureComponent { className='announcements__item__content translate' ref={this.setRef} dangerouslySetInnerHTML={{ __html: announcement.get('contentHtml') }} + onMouseEnter={this.handleMouseEnter} + onMouseLeave={this.handleMouseLeave} /> ); } From c8d11b8bdb97a1a2f8aaf5deca5f1c6c7c0d2688 Mon Sep 17 00:00:00 2001 From: Shubhendra Singh Chauhan Date: Mon, 1 Feb 2021 01:56:09 +0530 Subject: [PATCH 15/24] Fixed code quality issues (#15541) * Added .deepsource.toml * Removed bad use of `alias` * Fixed operand order in the binary expression * Prefixed unused method arguments with an underscore * Replaced the old OpenSSL algorithmic constants with the newer strings initializers. * Removed unnecessary UTF-8 encoding comment --- .deepsource.toml | 18 ++++++++++++++++++ config/initializers/fast_blank.rb | 2 +- config/initializers/simple_form.rb | 4 ++-- config/initializers/twitter_regex.rb | 2 +- lib/json_ld/identity.rb | 1 - lib/json_ld/security.rb | 1 - lib/mastodon/email_domain_blocks_cli.rb | 2 +- lib/paperclip/color_extractor.rb | 4 ++-- .../activitypub/linked_data_signature_spec.rb | 2 +- 9 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 .deepsource.toml diff --git a/.deepsource.toml b/.deepsource.toml new file mode 100644 index 00000000000..73d38901caa --- /dev/null +++ b/.deepsource.toml @@ -0,0 +1,18 @@ +version = 1 + +test_patterns = ["/app/javascript/mastodon/**/__tests__/**"] + +[[analyzers]] +name = "ruby" +enabled = true + +[[analyzers]] +name = "javascript" +enabled = true + + [analyzers.meta] + environment = [ + "nodejs", + "browser", + "jest" + ] diff --git a/config/initializers/fast_blank.rb b/config/initializers/fast_blank.rb index 174ea766477..f0b7cac78bf 100644 --- a/config/initializers/fast_blank.rb +++ b/config/initializers/fast_blank.rb @@ -1,5 +1,5 @@ if String.method_defined?(:blank_as?) class String - alias_method :blank?, :blank_as? + alias blank? blank_as? end end diff --git a/config/initializers/simple_form.rb b/config/initializers/simple_form.rb index 3dc48ef08f9..3a2097d2fb9 100644 --- a/config/initializers/simple_form.rb +++ b/config/initializers/simple_form.rb @@ -1,7 +1,7 @@ # Use this setup block to configure all options available in SimpleForm. module AppendComponent - def append(wrapper_options = nil) + def append(_wrapper_options = nil) @append ||= begin options[:append].to_s.html_safe if options[:append].present? end @@ -9,7 +9,7 @@ module AppendComponent end module RecommendedComponent - def recommended(wrapper_options = nil) + def recommended(_wrapper_options = nil) return unless options[:recommended] options[:label_text] = ->(raw_label_text, _required_label_text, _label_present) { safe_join([raw_label_text, ' ', content_tag(:span, I18n.t('simple_form.recommended'), class: 'recommended')]) } nil diff --git a/config/initializers/twitter_regex.rb b/config/initializers/twitter_regex.rb index 7f99a000564..aca85dd43a5 100644 --- a/config/initializers/twitter_regex.rb +++ b/config/initializers/twitter_regex.rb @@ -75,7 +75,7 @@ module Twitter # XMPP or magnet URIs an empty array will be returned. # # If a block is given then it will be called for each XMPP URI. - def extract_extra_uris_with_indices(text, options = {}) # :yields: uri, start, end + def extract_extra_uris_with_indices(text, _options = {}) # :yields: uri, start, end return [] unless text && text.index(":") urls = [] diff --git a/lib/json_ld/identity.rb b/lib/json_ld/identity.rb index 4fb3f8e9d9c..f41899150de 100644 --- a/lib/json_ld/identity.rb +++ b/lib/json_ld/identity.rb @@ -1,4 +1,3 @@ -# -*- encoding: utf-8 -*- # frozen_string_literal: true # This file generated automatically from http://w3id.org/identity/v1 require 'json/ld' diff --git a/lib/json_ld/security.rb b/lib/json_ld/security.rb index a6fbce95f58..ef539134010 100644 --- a/lib/json_ld/security.rb +++ b/lib/json_ld/security.rb @@ -1,4 +1,3 @@ -# -*- encoding: utf-8 -*- # frozen_string_literal: true # This file generated automatically from http://w3id.org/security/v1 require 'json/ld' diff --git a/lib/mastodon/email_domain_blocks_cli.rb b/lib/mastodon/email_domain_blocks_cli.rb index 55a637d6828..f79df302a24 100644 --- a/lib/mastodon/email_domain_blocks_cli.rb +++ b/lib/mastodon/email_domain_blocks_cli.rb @@ -113,7 +113,7 @@ module Mastodon result = entry.destroy if result - processed += 1 + children_count + processed += children_count + 1 else say("#{domain} could not be unblocked.", :red) failed += 1 diff --git a/lib/paperclip/color_extractor.rb b/lib/paperclip/color_extractor.rb index a70a3d21f21..d3b8e102295 100644 --- a/lib/paperclip/color_extractor.rb +++ b/lib/paperclip/color_extractor.rb @@ -55,7 +55,7 @@ module Paperclip # If we don't have enough colors for accent and foreground, generate # new ones by manipulating the background color (2 - foreground_colors.size).times do |i| - foreground_colors << lighten_or_darken(background_color, 35 + (15 * i)) + foreground_colors << lighten_or_darken(background_color, 35 + (i * 15)) end # We want the color with the highest contrast to background to be the foreground one, @@ -147,7 +147,7 @@ module Paperclip g = l.to_f b = l.to_f # achromatic else - q = l < 0.5 ? l * (1 + s) : l + s - l * s + q = l < 0.5 ? l * (s + 1) : l + s - l * s p = 2 * l - q r = hue_to_rgb(p, q, h + 1 / 3.0) g = hue_to_rgb(p, q, h) diff --git a/spec/lib/activitypub/linked_data_signature_spec.rb b/spec/lib/activitypub/linked_data_signature_spec.rb index 1f413eec991..2222c46fb55 100644 --- a/spec/lib/activitypub/linked_data_signature_spec.rb +++ b/spec/lib/activitypub/linked_data_signature_spec.rb @@ -81,6 +81,6 @@ RSpec.describe ActivityPub::LinkedDataSignature do options_hash = Digest::SHA256.hexdigest(canonicalize(options.merge('@context' => ActivityPub::LinkedDataSignature::CONTEXT))) document_hash = Digest::SHA256.hexdigest(canonicalize(document)) to_be_verified = options_hash + document_hash - Base64.strict_encode64(from_account.keypair.sign(OpenSSL::Digest::SHA256.new, to_be_verified)) + Base64.strict_encode64(from_account.keypair.sign(OpenSSL::Digest.new('SHA256'), to_be_verified)) end end From a044ddac5b3c0e2012c0e91bfbc07aa256a0684f Mon Sep 17 00:00:00 2001 From: ThibG Date: Tue, 2 Feb 2021 14:49:57 +0100 Subject: [PATCH 16/24] Fix race conditions on account migration creation (#15597) * Atomically check for processing lock in Move handler * Prevent race condition when creating account migrations Fixes #15595 * Add tests Co-authored-by: Claire --- app/lib/activitypub/activity/move.rb | 11 +-- app/models/account_migration.rb | 14 ++- .../settings/migrations_controller_spec.rb | 37 ++++++- spec/lib/activitypub/activity/move_spec.rb | 99 ++++++++++++++----- 4 files changed, 127 insertions(+), 34 deletions(-) diff --git a/app/lib/activitypub/activity/move.rb b/app/lib/activitypub/activity/move.rb index 7e073f64d23..8576ceccdf2 100644 --- a/app/lib/activitypub/activity/move.rb +++ b/app/lib/activitypub/activity/move.rb @@ -4,9 +4,8 @@ class ActivityPub::Activity::Move < ActivityPub::Activity PROCESSING_COOLDOWN = 7.days.seconds def perform - return if origin_account.uri != object_uri || processed? - - mark_as_processing! + return if origin_account.uri != object_uri + return unless mark_as_processing! target_account = ActivityPub::FetchRemoteAccountService.new.call(target_uri) @@ -35,12 +34,8 @@ class ActivityPub::Activity::Move < ActivityPub::Activity value_or_id(@json['target']) end - def processed? - redis.exists?("move_in_progress:#{@account.id}") - end - def mark_as_processing! - redis.setex("move_in_progress:#{@account.id}", PROCESSING_COOLDOWN, true) + redis.set("move_in_progress:#{@account.id}", true, nx: true, ex: PROCESSING_COOLDOWN) end def unmark_as_processing! diff --git a/app/models/account_migration.rb b/app/models/account_migration.rb index 4fae98ed726..ded32c9c600 100644 --- a/app/models/account_migration.rb +++ b/app/models/account_migration.rb @@ -14,6 +14,8 @@ # class AccountMigration < ApplicationRecord + include Redisable + COOLDOWN_PERIOD = 30.days.freeze belongs_to :account @@ -39,7 +41,13 @@ class AccountMigration < ApplicationRecord return false unless errors.empty? - save + RedisLock.acquire(lock_options) do |lock| + if lock.acquired? + save + else + raise Mastodon::RaceConditionError + end + end end def cooldown_at @@ -75,4 +83,8 @@ class AccountMigration < ApplicationRecord def validate_migration_cooldown errors.add(:base, I18n.t('migrations.errors.on_cooldown')) if account.migrations.within_cooldown.exists? end + + def lock_options + { redis: redis, key: "account_migration:#{account.id}" } + end end diff --git a/spec/controllers/settings/migrations_controller_spec.rb b/spec/controllers/settings/migrations_controller_spec.rb index 36e4ba86e46..048d9de8d2e 100644 --- a/spec/controllers/settings/migrations_controller_spec.rb +++ b/spec/controllers/settings/migrations_controller_spec.rb @@ -51,7 +51,7 @@ describe Settings::MigrationsController do it_behaves_like 'authenticate user' end - context 'when user is sign in' do + context 'when user is signed in' do subject { post :create, params: { account_migration: { acct: acct, current_password: '12345678' } } } let(:user) { Fabricate(:user, password: '12345678') } @@ -67,12 +67,45 @@ describe Settings::MigrationsController do end end - context 'when acct is a current account' do + context 'when acct is the current account' do let(:acct) { user.account } it 'renders show' do is_expected.to render_template :show end + + it 'does not update the moved account' do + expect(user.account.reload.moved_to_account_id).to be_nil + end + end + + context 'when target account does not reference the account being moved from' do + let(:acct) { Fabricate(:account, also_known_as: []) } + + it 'renders show' do + is_expected.to render_template :show + end + + it 'does not update the moved account' do + expect(user.account.reload.moved_to_account_id).to be_nil + end + end + + context 'when a recent migration already exists ' do + let(:acct) { Fabricate(:account, also_known_as: [ActivityPub::TagManager.instance.uri_for(user.account)]) } + + before do + moved_to = Fabricate(:account, also_known_as: [ActivityPub::TagManager.instance.uri_for(user.account)]) + user.account.migrations.create!(acct: moved_to.acct) + end + + it 'renders show' do + is_expected.to render_template :show + end + + it 'does not update the moved account' do + expect(user.account.reload.moved_to_account_id).to be_nil + end end end end diff --git a/spec/lib/activitypub/activity/move_spec.rb b/spec/lib/activitypub/activity/move_spec.rb index 3574f273a90..2d1d276c57a 100644 --- a/spec/lib/activitypub/activity/move_spec.rb +++ b/spec/lib/activitypub/activity/move_spec.rb @@ -1,23 +1,11 @@ require 'rails_helper' RSpec.describe ActivityPub::Activity::Move do - let(:follower) { Fabricate(:account) } - let(:old_account) { Fabricate(:account) } - let(:new_account) { Fabricate(:account) } - - before do - follower.follow!(old_account) - - old_account.update!(uri: 'https://example.org/alice', domain: 'example.org', protocol: :activitypub, inbox_url: 'https://example.org/inbox') - new_account.update!(uri: 'https://example.com/alice', domain: 'example.com', protocol: :activitypub, inbox_url: 'https://example.com/inbox', also_known_as: [old_account.uri]) - - stub_request(:post, 'https://example.org/inbox').to_return(status: 200) - stub_request(:post, 'https://example.com/inbox').to_return(status: 200) - - service_stub = double - allow(ActivityPub::FetchRemoteAccountService).to receive(:new).and_return(service_stub) - allow(service_stub).to receive(:call).and_return(new_account) - end + let(:follower) { Fabricate(:account) } + let(:old_account) { Fabricate(:account, uri: 'https://example.org/alice', domain: 'example.org', protocol: :activitypub, inbox_url: 'https://example.org/inbox') } + let(:new_account) { Fabricate(:account, uri: 'https://example.com/alice', domain: 'example.com', protocol: :activitypub, inbox_url: 'https://example.com/inbox', also_known_as: also_known_as) } + let(:also_known_as) { [old_account.uri] } + let(:returned_account) { new_account } let(:json) do { @@ -30,6 +18,17 @@ RSpec.describe ActivityPub::Activity::Move do }.with_indifferent_access end + before do + follower.follow!(old_account) + + stub_request(:post, old_account.inbox_url).to_return(status: 200) + stub_request(:post, new_account.inbox_url).to_return(status: 200) + + service_stub = double + allow(ActivityPub::FetchRemoteAccountService).to receive(:new).and_return(service_stub) + allow(service_stub).to receive(:call).and_return(returned_account) + end + describe '#perform' do subject { described_class.new(json, old_account) } @@ -37,16 +36,70 @@ RSpec.describe ActivityPub::Activity::Move do subject.perform end - it 'sets moved account on old account' do - expect(old_account.reload.moved_to_account_id).to eq new_account.id + context 'when all conditions are met' do + it 'sets moved account on old account' do + expect(old_account.reload.moved_to_account_id).to eq new_account.id + end + + it 'makes followers unfollow old account' do + expect(follower.following?(old_account)).to be false + end + + it 'makes followers follow-request the new account' do + expect(follower.requested?(new_account)).to be true + end end - it 'makes followers unfollow old account' do - expect(follower.following?(old_account)).to be false + context "when the new account can't be resolved" do + let(:returned_account) { nil } + + it 'does not set moved account on old account' do + expect(old_account.reload.moved_to_account_id).to be_nil + end + + it 'does not make followers unfollow old account' do + expect(follower.following?(old_account)).to be true + end + + it 'does not make followers follow-request the new account' do + expect(follower.requested?(new_account)).to be false + end end - it 'makes followers follow-request the new account' do - expect(follower.requested?(new_account)).to be true + context 'when the new account does not references the old account' do + let(:also_known_as) { [] } + + it 'does not set moved account on old account' do + expect(old_account.reload.moved_to_account_id).to be_nil + end + + it 'does not make followers unfollow old account' do + expect(follower.following?(old_account)).to be true + end + + it 'does not make followers follow-request the new account' do + expect(follower.requested?(new_account)).to be false + end + end + + context 'when a Move has been recently processed' do + around do |example| + Redis.current.set("move_in_progress:#{old_account.id}", true, nx: true, ex: 7.days.seconds) + example.run + Redis.current.del("move_in_progress:#{old_account.id}") + end + + it 'does not set moved account on old account' do + expect(old_account.reload.moved_to_account_id).to be_nil + end + + it 'does not make followers unfollow old account' do + expect(follower.following?(old_account)).to be true + end + + it 'does not make followers follow-request the new account' do + expect(follower.requested?(new_account)).to be false + end end end end From ab39d5fda55de468c9f5689065e3c328c7a9bd71 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Feb 2021 23:47:12 +0900 Subject: [PATCH 17/24] Bump chewy from 5.1.0 to 5.2.0 (#15648) Bumps [chewy](https://github.com/toptal/chewy) from 5.1.0 to 5.2.0. - [Release notes](https://github.com/toptal/chewy/releases) - [Changelog](https://github.com/toptal/chewy/blob/master/CHANGELOG.md) - [Commits](https://github.com/toptal/chewy/compare/v5.1.0...v5.2.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 22 +++++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Gemfile b/Gemfile index 8ac92cdf95e..8dc1c43889c 100644 --- a/Gemfile +++ b/Gemfile @@ -31,7 +31,7 @@ gem 'bootsnap', '~> 1.5', require: false gem 'browser' gem 'charlock_holmes', '~> 0.7.7' gem 'iso-639' -gem 'chewy', '~> 5.1' +gem 'chewy', '~> 5.2' gem 'cld3', '~> 3.4.1' gem 'devise', '~> 4.7' gem 'devise-two-factor', '~> 3.1' diff --git a/Gemfile.lock b/Gemfile.lock index ba6fd64ac74..a96d4ee9bca 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -143,8 +143,8 @@ GEM activesupport cbor (0.5.9.6) charlock_holmes (0.7.7) - chewy (5.1.0) - activesupport (>= 4.0) + chewy (5.2.0) + activesupport (>= 5.2) elasticsearch (>= 2.0.0) elasticsearch-dsl chunky_png (1.3.15) @@ -195,13 +195,13 @@ GEM railties (>= 3.2) e2mmap (0.1.0) ed25519 (1.2.4) - elasticsearch (7.9.0) - elasticsearch-api (= 7.9.0) - elasticsearch-transport (= 7.9.0) - elasticsearch-api (7.9.0) + elasticsearch (7.10.1) + elasticsearch-api (= 7.10.1) + elasticsearch-transport (= 7.10.1) + elasticsearch-api (7.10.1) multi_json elasticsearch-dsl (0.1.9) - elasticsearch-transport (7.9.0) + elasticsearch-transport (7.10.1) faraday (~> 1) multi_json encryptor (3.0.0) @@ -212,8 +212,11 @@ GEM fabrication (2.21.1) faker (2.15.1) i18n (>= 1.6, < 2) - faraday (1.0.1) + faraday (1.3.0) + faraday-net_http (~> 1.0) multipart-post (>= 1.2, < 3) + ruby2_keywords + faraday-net_http (1.0.1) fast_blank (1.0.0) fastimage (2.2.1) ffi (1.10.0) @@ -556,6 +559,7 @@ GEM ruby-progressbar (1.11.0) ruby-saml (1.11.0) nokogiri (>= 1.5.10) + ruby2_keywords (0.0.4) rufus-scheduler (3.6.0) fugit (~> 1.1, >= 1.1.6) safety_net_attestation (0.4.0) @@ -703,7 +707,7 @@ DEPENDENCIES capistrano-yarn (~> 2.0) capybara (~> 3.34) charlock_holmes (~> 0.7.7) - chewy (~> 5.1) + chewy (~> 5.2) cld3 (~> 3.4.1) climate_control (~> 0.2) color_diff (~> 0.1) From b109df0e2cda737bc8e69dc3c92e725ebc08d07e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Feb 2021 23:47:35 +0900 Subject: [PATCH 18/24] Bump capybara from 3.34.0 to 3.35.3 (#15649) Bumps [capybara](https://github.com/teamcapybara/capybara) from 3.34.0 to 3.35.3. - [Release notes](https://github.com/teamcapybara/capybara/releases) - [Changelog](https://github.com/teamcapybara/capybara/blob/master/History.md) - [Commits](https://github.com/teamcapybara/capybara/compare/3.34.0...3.35.3) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index 8dc1c43889c..9443725ee82 100644 --- a/Gemfile +++ b/Gemfile @@ -117,7 +117,7 @@ group :production, :test do end group :test do - gem 'capybara', '~> 3.34' + gem 'capybara', '~> 3.35' gem 'climate_control', '~> 0.2' gem 'faker', '~> 2.15' gem 'microformats', '~> 4.2' diff --git a/Gemfile.lock b/Gemfile.lock index a96d4ee9bca..2d25252f5d3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -131,13 +131,13 @@ GEM sshkit (~> 1.3) capistrano-yarn (2.0.2) capistrano (~> 3.0) - capybara (3.34.0) + capybara (3.35.3) addressable mini_mime (>= 0.1.3) nokogiri (~> 1.8) rack (>= 1.6.0) rack-test (>= 0.6.3) - regexp_parser (~> 1.5) + regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) case_transform (0.2) activesupport @@ -506,7 +506,7 @@ GEM redis-store (>= 1.2, < 2) redis-store (1.9.0) redis (>= 4, < 5) - regexp_parser (1.8.2) + regexp_parser (2.0.3) request_store (1.5.0) rack (>= 1.4) responders (3.0.1) @@ -705,7 +705,7 @@ DEPENDENCIES capistrano-rails (~> 1.6) capistrano-rbenv (~> 2.2) capistrano-yarn (~> 2.0) - capybara (~> 3.34) + capybara (~> 3.35) charlock_holmes (~> 0.7.7) chewy (~> 5.2) cld3 (~> 3.4.1) From 2620e2cfa33c60984cf5de1525e4545fd46e4cd2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Feb 2021 23:56:17 +0900 Subject: [PATCH 19/24] Bump webmock from 3.11.1 to 3.11.2 (#15650) Bumps [webmock](https://github.com/bblimke/webmock) from 3.11.1 to 3.11.2. - [Release notes](https://github.com/bblimke/webmock/releases) - [Changelog](https://github.com/bblimke/webmock/blob/master/CHANGELOG.md) - [Commits](https://github.com/bblimke/webmock/compare/v3.11.1...v3.11.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2d25252f5d3..a0a72a9f1ab 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -664,7 +664,7 @@ GEM safety_net_attestation (~> 0.4.0) securecompare (~> 1.0) tpm-key_attestation (~> 0.9.0) - webmock (3.11.1) + webmock (3.11.2) addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) From fd7f4056af927868ccf623f49abba356aa2a830e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Feb 2021 23:56:54 +0900 Subject: [PATCH 20/24] Bump mini-css-extract-plugin from 1.3.4 to 1.3.5 (#15654) Bumps [mini-css-extract-plugin](https://github.com/webpack-contrib/mini-css-extract-plugin) from 1.3.4 to 1.3.5. - [Release notes](https://github.com/webpack-contrib/mini-css-extract-plugin/releases) - [Changelog](https://github.com/webpack-contrib/mini-css-extract-plugin/blob/master/CHANGELOG.md) - [Commits](https://github.com/webpack-contrib/mini-css-extract-plugin/compare/v1.3.4...v1.3.5) 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 755b52b3786..c7542d8f441 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "lodash": "^4.17.19", "mark-loader": "^0.1.6", "marky": "^1.2.1", - "mini-css-extract-plugin": "^1.3.4", + "mini-css-extract-plugin": "^1.3.5", "mkdirp": "^1.0.4", "npmlog": "^4.1.2", "object-assign": "^4.1.1", diff --git a/yarn.lock b/yarn.lock index 75dc36d3812..f4eb6a9ab67 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7105,10 +7105,10 @@ min-indent@^1.0.0: resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== -mini-css-extract-plugin@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-1.3.4.tgz#706e69632cdcdb8b15bf8e638442a0dba304a9c8" - integrity sha512-dNjqyeogUd8ucUgw5sxm1ahvSfSUgef7smbmATRSbDm4EmNx5kQA6VdUEhEeCKSjX6CTYjb5vxgMUvRjqP3uHg== +mini-css-extract-plugin@^1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-1.3.5.tgz#252166e78879c106e0130f229d44e0cbdfcebed3" + integrity sha512-tvmzcwqJJXau4OQE5vT72pRT18o2zF+tQJp8CWchqvfQnTlflkzS+dANYcRdyPRWUWRkfmeNTKltx0NZI/b5dQ== dependencies: loader-utils "^2.0.0" schema-utils "^3.0.0" From b8aed2d25541b767d9dfb1ee2ad8d5cd2db16695 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Feb 2021 04:27:19 +0900 Subject: [PATCH 21/24] Bump fastimage from 2.2.1 to 2.2.2 (#15651) Bumps [fastimage](https://github.com/sdsykes/fastimage) from 2.2.1 to 2.2.2. - [Release notes](https://github.com/sdsykes/fastimage/releases) - [Commits](https://github.com/sdsykes/fastimage/compare/v2.2.1...v2.2.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index a0a72a9f1ab..65512d711f8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -218,7 +218,7 @@ GEM ruby2_keywords faraday-net_http (1.0.1) fast_blank (1.0.0) - fastimage (2.2.1) + fastimage (2.2.2) ffi (1.10.0) ffi-compiler (1.0.1) ffi (>= 1.0.0) From 1d96bf9f43529745148b15a4cbb39a852ebb5280 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Feb 2021 04:27:57 +0900 Subject: [PATCH 22/24] Bump oj from 3.11.1 to 3.11.2 (#15657) Bumps [oj](https://github.com/ohler55/oj) from 3.11.1 to 3.11.2. - [Release notes](https://github.com/ohler55/oj/releases) - [Changelog](https://github.com/ohler55/oj/blob/develop/CHANGELOG.md) - [Commits](https://github.com/ohler55/oj/compare/v3.11.1...v3.11.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 65512d711f8..1a8c012ffbf 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -372,7 +372,7 @@ GEM concurrent-ruby (~> 1.0, >= 1.0.2) sidekiq (>= 3.5) statsd-ruby (~> 1.4, >= 1.4.0) - oj (3.11.1) + oj (3.11.2) omniauth (1.9.1) hashie (>= 3.4.6) rack (>= 1.6.2, < 3) From 4e933924bdea3392ebeaeaa7c341593eb200512c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczak?= Date: Wed, 3 Feb 2021 00:38:48 +0100 Subject: [PATCH 23/24] Update Doorkeeper strings for `doorkeeper.errors.messages.invalid_request` (#15659) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update Doorkeeper strings for doorkeeper.errors.messages.invalid_request Signed-off-by: marcin mikołajczak * Update config/locales/doorkeeper.en.yml Co-authored-by: Yamagishi Kazutoshi Co-authored-by: Yamagishi Kazutoshi --- config/locales/doorkeeper.en.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/config/locales/doorkeeper.en.yml b/config/locales/doorkeeper.en.yml index 2be2ef0364d..ec322f07186 100644 --- a/config/locales/doorkeeper.en.yml +++ b/config/locales/doorkeeper.en.yml @@ -83,7 +83,10 @@ en: invalid_client: Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method. invalid_grant: The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client. invalid_redirect_uri: The redirect uri included is not valid. - invalid_request: The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed. + invalid_request: + missing_param: 'Missing required parameter: %{value}.' + request_not_authorized: Request need to be authorized. Required parameter for authorizing request is missing or invalid. + unknown: The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed. invalid_resource_owner: The provided resource owner credentials are not valid, or resource owner cannot be found invalid_scope: The requested scope is invalid, unknown, or malformed. invalid_token: From e1fa06c459a28a575d0da540432c61b702e99cdd Mon Sep 17 00:00:00 2001 From: ThibG Date: Sun, 31 Jan 2021 21:25:31 +0100 Subject: [PATCH 24/24] [Glitch] Change custom emoji to be animated when hovering container Port 3efa0c54b6656fba189baab0857e60c0bc4f3c7d to glitch-soc Co-authored-by: Claire Signed-off-by: Claire --- .../glitch/components/display_name.js | 43 +++++--------- .../glitch/components/status_content.js | 59 ++++++++++--------- .../features/account/components/header.js | 43 +++++--------- .../components/conversation.js | 43 +++++--------- .../directory/components/account_card.js | 47 +++++---------- .../components/announcements.js | 53 ++++++++--------- 6 files changed, 112 insertions(+), 176 deletions(-) diff --git a/app/javascript/flavours/glitch/components/display_name.js b/app/javascript/flavours/glitch/components/display_name.js index 44662a8b873..ad978a2c610 100644 --- a/app/javascript/flavours/glitch/components/display_name.js +++ b/app/javascript/flavours/glitch/components/display_name.js @@ -15,45 +15,30 @@ export default class DisplayName extends React.PureComponent { handleClick: PropTypes.func, }; - _updateEmojis () { - const node = this.node; - - if (!node || autoPlayGif) { + handleMouseEnter = ({ currentTarget }) => { + if (autoPlayGif) { return; } - const emojis = node.querySelectorAll('.custom-emoji'); + const emojis = currentTarget.querySelectorAll('.custom-emoji'); for (var i = 0; i < emojis.length; i++) { let emoji = emojis[i]; - if (emoji.classList.contains('status-emoji')) { - continue; - } - emoji.classList.add('status-emoji'); - - emoji.addEventListener('mouseenter', this.handleEmojiMouseEnter, false); - emoji.addEventListener('mouseleave', this.handleEmojiMouseLeave, false); + emoji.src = emoji.getAttribute('data-original'); } } - componentDidMount () { - this._updateEmojis(); - } + handleMouseLeave = ({ currentTarget }) => { + if (autoPlayGif) { + return; + } - componentDidUpdate () { - this._updateEmojis(); - } + const emojis = currentTarget.querySelectorAll('.custom-emoji'); - handleEmojiMouseEnter = ({ target }) => { - target.src = target.getAttribute('data-original'); - } - - handleEmojiMouseLeave = ({ target }) => { - target.src = target.getAttribute('data-static'); - } - - setRef = (c) => { - this.node = c; + for (var i = 0; i < emojis.length; i++) { + let emoji = emojis[i]; + emoji.src = emoji.getAttribute('data-static'); + } } render() { @@ -101,7 +86,7 @@ export default class DisplayName extends React.PureComponent { } return ( - + {displayName} {inline ? ' ' : null} {suffix} diff --git a/app/javascript/flavours/glitch/components/status_content.js b/app/javascript/flavours/glitch/components/status_content.js index 61a28e9a765..34ff9730595 100644 --- a/app/javascript/flavours/glitch/components/status_content.js +++ b/app/javascript/flavours/glitch/components/status_content.js @@ -154,35 +154,38 @@ export default class StatusContent extends React.PureComponent { } } - _updateStatusEmojis () { - const node = this.node; - - if (!node || autoPlayGif) { + handleMouseEnter = ({ currentTarget }) => { + if (autoPlayGif) { return; } - const emojis = node.querySelectorAll('.custom-emoji'); + const emojis = currentTarget.querySelectorAll('.custom-emoji'); for (var i = 0; i < emojis.length; i++) { let emoji = emojis[i]; - if (emoji.classList.contains('status-emoji')) { - continue; - } - emoji.classList.add('status-emoji'); + emoji.src = emoji.getAttribute('data-original'); + } + } - emoji.addEventListener('mouseenter', this.handleEmojiMouseEnter, false); - emoji.addEventListener('mouseleave', this.handleEmojiMouseLeave, false); + handleMouseLeave = ({ currentTarget }) => { + if (autoPlayGif) { + return; + } + + const emojis = currentTarget.querySelectorAll('.custom-emoji'); + + for (var i = 0; i < emojis.length; i++) { + let emoji = emojis[i]; + emoji.src = emoji.getAttribute('data-static'); } } componentDidMount () { this._updateStatusLinks(); - this._updateStatusEmojis(); } componentDidUpdate () { this._updateStatusLinks(); - this._updateStatusEmojis(); if (this.props.onUpdate) this.props.onUpdate(); } @@ -206,14 +209,6 @@ export default class StatusContent extends React.PureComponent { } } - handleEmojiMouseEnter = ({ target }) => { - target.src = target.getAttribute('data-original'); - } - - handleEmojiMouseLeave = ({ target }) => { - target.src = target.getAttribute('data-static'); - } - handleMouseDown = (e) => { this.startXY = [e.clientX, e.clientY]; } @@ -253,10 +248,6 @@ export default class StatusContent extends React.PureComponent { } } - setRef = (c) => { - this.node = c; - } - setContentsRef = (c) => { this.contentsNode = c; } @@ -323,7 +314,7 @@ export default class StatusContent extends React.PureComponent { } return ( -
+
@@ -356,7 +349,6 @@ export default class StatusContent extends React.PureComponent { onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp} tabIndex='0' - ref={this.setRef} >
{media}
@@ -373,9 +367,16 @@ export default class StatusContent extends React.PureComponent {
-
+
{media}
); diff --git a/app/javascript/flavours/glitch/features/account/components/header.js b/app/javascript/flavours/glitch/features/account/components/header.js index 6a572862d35..c18520c00af 100644 --- a/app/javascript/flavours/glitch/features/account/components/header.js +++ b/app/javascript/flavours/glitch/features/account/components/header.js @@ -88,45 +88,30 @@ class Header extends ImmutablePureComponent { window.open(profileLink, '_blank'); } - _updateEmojis () { - const node = this.node; - - if (!node || autoPlayGif) { + handleMouseEnter = ({ currentTarget }) => { + if (autoPlayGif) { return; } - const emojis = node.querySelectorAll('.custom-emoji'); + const emojis = currentTarget.querySelectorAll('.custom-emoji'); for (var i = 0; i < emojis.length; i++) { let emoji = emojis[i]; - if (emoji.classList.contains('status-emoji')) { - continue; - } - emoji.classList.add('status-emoji'); - - emoji.addEventListener('mouseenter', this.handleEmojiMouseEnter, false); - emoji.addEventListener('mouseleave', this.handleEmojiMouseLeave, false); + emoji.src = emoji.getAttribute('data-original'); } } - componentDidMount () { - this._updateEmojis(); - } + handleMouseLeave = ({ currentTarget }) => { + if (autoPlayGif) { + return; + } - componentDidUpdate () { - this._updateEmojis(); - } + const emojis = currentTarget.querySelectorAll('.custom-emoji'); - handleEmojiMouseEnter = ({ target }) => { - target.src = target.getAttribute('data-original'); - } - - handleEmojiMouseLeave = ({ target }) => { - target.src = target.getAttribute('data-static'); - } - - setRef = (c) => { - this.node = c; + for (var i = 0; i < emojis.length; i++) { + let emoji = emojis[i]; + emoji.src = emoji.getAttribute('data-static'); + } } render () { @@ -279,7 +264,7 @@ class Header extends ImmutablePureComponent { } return ( -
+
{info} diff --git a/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js b/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js index 0af8b348f23..98b48cd90e1 100644 --- a/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js +++ b/app/javascript/flavours/glitch/features/direct_timeline/components/conversation.js @@ -67,41 +67,30 @@ class Conversation extends ImmutablePureComponent { } } - _updateEmojis () { - const node = this.namesNode; - - if (!node || autoPlayGif) { + handleMouseEnter = ({ currentTarget }) => { + if (autoPlayGif) { return; } - const emojis = node.querySelectorAll('.custom-emoji'); + const emojis = currentTarget.querySelectorAll('.custom-emoji'); for (var i = 0; i < emojis.length; i++) { let emoji = emojis[i]; - if (emoji.classList.contains('status-emoji')) { - continue; - } - emoji.classList.add('status-emoji'); - - emoji.addEventListener('mouseenter', this.handleEmojiMouseEnter, false); - emoji.addEventListener('mouseleave', this.handleEmojiMouseLeave, false); + emoji.src = emoji.getAttribute('data-original'); } } - componentDidMount () { - this._updateEmojis(); - } + handleMouseLeave = ({ currentTarget }) => { + if (autoPlayGif) { + return; + } - componentDidUpdate () { - this._updateEmojis(); - } + const emojis = currentTarget.querySelectorAll('.custom-emoji'); - handleEmojiMouseEnter = ({ target }) => { - target.src = target.getAttribute('data-original'); - } - - handleEmojiMouseLeave = ({ target }) => { - target.src = target.getAttribute('data-static'); + for (var i = 0; i < emojis.length; i++) { + let emoji = emojis[i]; + emoji.src = emoji.getAttribute('data-static'); + } } handleClick = () => { @@ -152,10 +141,6 @@ class Conversation extends ImmutablePureComponent { this.setState({ isExpanded: value }); } - setNamesRef = (c) => { - this.namesNode = c; - } - render () { const { accounts, lastStatus, unread, scrollKey, intl } = this.props; const { isExpanded } = this.state; @@ -206,7 +191,7 @@ class Conversation extends ImmutablePureComponent { {unread && }
-
+
{names} }} />
diff --git a/app/javascript/flavours/glitch/features/directory/components/account_card.js b/app/javascript/flavours/glitch/features/directory/components/account_card.js index 5f952b38251..9fe84c10b18 100644 --- a/app/javascript/flavours/glitch/features/directory/components/account_card.js +++ b/app/javascript/flavours/glitch/features/directory/components/account_card.js @@ -102,43 +102,32 @@ class AccountCard extends ImmutablePureComponent { onMute: PropTypes.func.isRequired, }; - _updateEmojis() { - const node = this.node; - - if (!node || autoPlayGif) { + handleMouseEnter = ({ currentTarget }) => { + if (autoPlayGif) { return; } - const emojis = node.querySelectorAll('.custom-emoji'); + const emojis = currentTarget.querySelectorAll('.custom-emoji'); for (var i = 0; i < emojis.length; i++) { let emoji = emojis[i]; - if (emoji.classList.contains('status-emoji')) { - continue; - } - emoji.classList.add('status-emoji'); - - emoji.addEventListener('mouseenter', this.handleEmojiMouseEnter, false); - emoji.addEventListener('mouseleave', this.handleEmojiMouseLeave, false); + emoji.src = emoji.getAttribute('data-original'); } } - componentDidMount() { - this._updateEmojis(); + handleMouseLeave = ({ currentTarget }) => { + if (autoPlayGif) { + return; + } + + const emojis = currentTarget.querySelectorAll('.custom-emoji'); + + for (var i = 0; i < emojis.length; i++) { + let emoji = emojis[i]; + emoji.src = emoji.getAttribute('data-static'); + } } - componentDidUpdate() { - this._updateEmojis(); - } - - handleEmojiMouseEnter = ({ target }) => { - target.src = target.getAttribute('data-original'); - }; - - handleEmojiMouseLeave = ({ target }) => { - target.src = target.getAttribute('data-static'); - }; - handleFollow = () => { this.props.onFollow(this.props.account); }; @@ -151,10 +140,6 @@ class AccountCard extends ImmutablePureComponent { this.props.onMute(this.props.account); }; - setRef = (c) => { - this.node = c; - }; - render() { const { account, intl } = this.props; @@ -239,7 +224,7 @@ class AccountCard extends ImmutablePureComponent {
-
+
{ - target.src = target.getAttribute('data-original'); + handleMouseEnter = ({ currentTarget }) => { + if (autoPlayGif) { + return; + } + + const emojis = currentTarget.querySelectorAll('.custom-emoji'); + + for (var i = 0; i < emojis.length; i++) { + let emoji = emojis[i]; + emoji.src = emoji.getAttribute('data-original'); + } } - handleEmojiMouseLeave = ({ target }) => { - target.src = target.getAttribute('data-static'); + handleMouseLeave = ({ currentTarget }) => { + if (autoPlayGif) { + return; + } + + const emojis = currentTarget.querySelectorAll('.custom-emoji'); + + for (var i = 0; i < emojis.length; i++) { + let emoji = emojis[i]; + emoji.src = emoji.getAttribute('data-static'); + } } render () { @@ -148,6 +141,8 @@ class Content extends ImmutablePureComponent { className='announcements__item__content translate' ref={this.setRef} dangerouslySetInnerHTML={{ __html: announcement.get('contentHtml') }} + onMouseEnter={this.handleMouseEnter} + onMouseLeave={this.handleMouseLeave} /> ); }