From 90097e55a04909d50736d6078ae6488e7a67bd68 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 13 Feb 2022 08:00:26 +0900 Subject: [PATCH 01/35] Bump rspec-rails from 5.0.2 to 5.1.0 (#17406) Bumps [rspec-rails](https://github.com/rspec/rspec-rails) from 5.0.2 to 5.1.0. - [Release notes](https://github.com/rspec/rspec-rails/releases) - [Changelog](https://github.com/rspec/rspec-rails/blob/main/Changelog.md) - [Commits](https://github.com/rspec/rspec-rails/compare/v5.0.2...v5.1.0) --- updated-dependencies: - dependency-name: rspec-rails dependency-type: direct:development update-type: version-update:semver-minor ... 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, 12 insertions(+), 12 deletions(-) diff --git a/Gemfile b/Gemfile index 9b52c0e6c6..1a7193b19f 100644 --- a/Gemfile +++ b/Gemfile @@ -103,7 +103,7 @@ group :development, :test do gem 'i18n-tasks', '~> 0.9', require: false gem 'pry-byebug', '~> 3.9' gem 'pry-rails', '~> 0.3' - gem 'rspec-rails', '~> 5.0' + gem 'rspec-rails', '~> 5.1' end group :production, :test do diff --git a/Gemfile.lock b/Gemfile.lock index eee2890568..f0ba4efdc9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -181,7 +181,7 @@ GEM devise_pam_authenticatable2 (9.2.0) devise (>= 4.0.0) rpam2 (~> 4.0) - diff-lcs (1.4.4) + diff-lcs (1.5.0) discard (1.2.1) activerecord (>= 4.2, < 8) docile (1.3.4) @@ -354,7 +354,7 @@ GEM activesupport (>= 4) railties (>= 4) request_store (~> 1.0) - loofah (2.13.0) + loofah (2.14.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) @@ -510,15 +510,15 @@ GEM chunky_png (~> 1.0) rqrcode_core (~> 1.0) rqrcode_core (1.2.0) - rspec-core (3.10.1) - rspec-support (~> 3.10.0) - rspec-expectations (3.10.1) + rspec-core (3.11.0) + rspec-support (~> 3.11.0) + rspec-expectations (3.11.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.10.0) - rspec-mocks (3.10.2) + rspec-support (~> 3.11.0) + rspec-mocks (3.11.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.10.0) - rspec-rails (5.0.2) + rspec-support (~> 3.11.0) + rspec-rails (5.1.0) actionpack (>= 5.2) activesupport (>= 5.2) railties (>= 5.2) @@ -529,7 +529,7 @@ GEM rspec-sidekiq (3.1.0) rspec-core (~> 3.0, >= 3.0.0) sidekiq (>= 2.4.0) - rspec-support (3.10.3) + rspec-support (3.11.0) rspec_junit_formatter (0.5.1) rspec-core (>= 2, < 4, != 2.12.0) rubocop (1.25.1) @@ -770,7 +770,7 @@ DEPENDENCIES redis-namespace (~> 1.8) rexml (~> 3.2) rqrcode (~> 2.1) - rspec-rails (~> 5.0) + rspec-rails (~> 5.1) rspec-sidekiq (~> 3.1) rspec_junit_formatter (~> 0.5) rubocop (~> 1.25) From bb445a991f77ac99a2b2496fdd876c9d29c0fab6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 13 Feb 2022 08:04:32 +0900 Subject: [PATCH 02/35] Bump annotate from 3.1.1 to 3.2.0 (#17503) Bumps [annotate](https://github.com/ctran/annotate_models) from 3.1.1 to 3.2.0. - [Release notes](https://github.com/ctran/annotate_models/releases) - [Changelog](https://github.com/ctran/annotate_models/blob/develop/CHANGELOG.md) - [Commits](https://github.com/ctran/annotate_models/compare/v3.1.1...v3.2.0) --- updated-dependencies: - dependency-name: annotate dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 1a7193b19f..55ed06bb72 100644 --- a/Gemfile +++ b/Gemfile @@ -124,7 +124,7 @@ end group :development do gem 'active_record_query_trace', '~> 1.8' - gem 'annotate', '~> 3.1' + gem 'annotate', '~> 3.2' gem 'better_errors', '~> 2.9' gem 'binding_of_caller', '~> 1.0' gem 'bullet', '~> 7.0' diff --git a/Gemfile.lock b/Gemfile.lock index f0ba4efdc9..84a28f9040 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -71,8 +71,8 @@ GEM airbrussh (1.4.0) sshkit (>= 1.6.1, != 1.7.0) android_key_attestation (0.3.0) - annotate (3.1.1) - activerecord (>= 3.2, < 7.0) + annotate (3.2.0) + activerecord (>= 3.2, < 8.0) rake (>= 10.4, < 14.0) ast (2.4.2) attr_encrypted (3.1.0) @@ -682,7 +682,7 @@ DEPENDENCIES active_model_serializers (~> 0.10) active_record_query_trace (~> 1.8) addressable (~> 2.8) - annotate (~> 3.1) + annotate (~> 3.2) aws-sdk-s3 (~> 1.112) better_errors (~> 2.9) binding_of_caller (~> 1.0) From 6b996fca0f7c9aa6137d08ffa7a56760c981a923 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 13 Feb 2022 08:05:22 +0900 Subject: [PATCH 03/35] Bump strong_migrations from 0.7.9 to 0.8.0 (#17504) Bumps [strong_migrations](https://github.com/ankane/strong_migrations) from 0.7.9 to 0.8.0. - [Release notes](https://github.com/ankane/strong_migrations/releases) - [Changelog](https://github.com/ankane/strong_migrations/blob/master/CHANGELOG.md) - [Commits](https://github.com/ankane/strong_migrations/compare/v0.7.9...v0.8.0) --- updated-dependencies: - dependency-name: strong_migrations dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 55ed06bb72..47fa180ca7 100644 --- a/Gemfile +++ b/Gemfile @@ -85,7 +85,7 @@ gem 'simple-navigation', '~> 4.3' gem 'simple_form', '~> 5.1' gem 'sprockets-rails', '~> 3.4', require: 'sprockets/railtie' gem 'stoplight', '~> 2.2.1' -gem 'strong_migrations', '~> 0.7' +gem 'strong_migrations', '~> 0.8' gem 'tty-prompt', '~> 0.23', require: false gem 'twitter-text', '~> 3.1.0' gem 'tzinfo-data', '~> 1.2021' diff --git a/Gemfile.lock b/Gemfile.lock index 84a28f9040..0e62f0a097 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -606,8 +606,8 @@ GEM stackprof (0.2.17) statsd-ruby (1.5.0) stoplight (2.2.1) - strong_migrations (0.7.9) - activerecord (>= 5) + strong_migrations (0.8.0) + activerecord (>= 5.2) temple (0.8.2) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) @@ -789,7 +789,7 @@ DEPENDENCIES sprockets-rails (~> 3.4) stackprof stoplight (~> 2.2.1) - strong_migrations (~> 0.7) + strong_migrations (~> 0.8) thor (~> 1.2) tty-prompt (~> 0.23) twitter-text (~> 3.1.0) From 518ac93f00088da0ace4a19562f899c13ad54276 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 13 Feb 2022 01:58:26 +0100 Subject: [PATCH 04/35] Fix duplicate accounts when searching by IP range in admin UI (#17524) --- app/models/account_filter.rb | 2 +- app/models/user.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/account_filter.rb b/app/models/account_filter.rb index dcb1741227..86b7f5f417 100644 --- a/app/models/account_filter.rb +++ b/app/models/account_filter.rb @@ -49,7 +49,7 @@ class AccountFilter when 'email' accounts_with_users.merge(User.matches_email(value)) when 'ip' - valid_ip?(value) ? accounts_with_users.merge(User.matches_ip(value)) : Account.none + valid_ip?(value) ? accounts_with_users.merge(User.matches_ip(value).group('users.id, accounts.id')) : Account.none when 'invited_by' invited_by_scope(value) when 'order' diff --git a/app/models/user.rb b/app/models/user.rb index a11bc38248..fd1d7049a9 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -111,7 +111,7 @@ class User < ApplicationRecord scope :inactive, -> { where(arel_table[:current_sign_in_at].lt(ACTIVE_DURATION.ago)) } scope :active, -> { confirmed.where(arel_table[:current_sign_in_at].gteq(ACTIVE_DURATION.ago)).joins(:account).where(accounts: { suspended_at: nil }) } scope :matches_email, ->(value) { where(arel_table[:email].matches("#{value}%")) } - scope :matches_ip, ->(value) { left_joins(:ips).where('user_ips.ip <<= ?', value) } + scope :matches_ip, ->(value) { left_joins(:ips).where('user_ips.ip <<= ?', value).group('users.id') } scope :emailable, -> { confirmed.enabled.joins(:account).merge(Account.searchable) } before_validation :sanitize_languages From 77529aba869bff29fe386e264f4779495bd8fd37 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 13 Feb 2022 02:52:34 +0100 Subject: [PATCH 05/35] Fix privacy policy link not being visible on small screens (#17533) Fix #17482 --- app/javascript/styles/mastodon/footer.scss | 17 ++++++++++++++++- app/views/layouts/public.html.haml | 4 ++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/app/javascript/styles/mastodon/footer.scss b/app/javascript/styles/mastodon/footer.scss index 00d2908832..073ebda7e4 100644 --- a/app/javascript/styles/mastodon/footer.scss +++ b/app/javascript/styles/mastodon/footer.scss @@ -90,6 +90,20 @@ .column-4 { display: none; } + + .column-2 h4 { + display: none; + } + } + } + + .legal-xs { + display: none; + text-align: center; + padding-top: 20px; + + @media screen and (max-width: $no-gap-breakpoint) { + display: block; } } @@ -105,7 +119,8 @@ } } - ul a { + ul a, + .legal-xs a { text-decoration: none; color: lighten($ui-base-color, 34%); diff --git a/app/views/layouts/public.html.haml b/app/views/layouts/public.html.haml index 069931cfd6..3a9ca7ed7b 100644 --- a/app/views/layouts/public.html.haml +++ b/app/views/layouts/public.html.haml @@ -54,5 +54,9 @@ %ul %li= link_to t('about.source_code'), Mastodon::Version.source_url %li= link_to t('about.apps'), 'https://joinmastodon.org/apps' + .legal-xs + = link_to "v#{Mastodon::Version.to_s}", Mastodon::Version.source_url + · + = link_to t('about.privacy_policy'), terms_path = render template: 'layouts/application' From 64cdb83d94037db6537c5113fc1165e3d0629a94 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 13 Feb 2022 20:21:09 +0900 Subject: [PATCH 06/35] Bump kt-paperclip from 7.0.1 to 7.1.1 (#17502) Bumps [kt-paperclip](https://github.com/kreeti/kt-paperclip) from 7.0.1 to 7.1.1. - [Release notes](https://github.com/kreeti/kt-paperclip/releases) - [Changelog](https://github.com/kreeti/kt-paperclip/blob/master/NEWS) - [Commits](https://github.com/kreeti/kt-paperclip/compare/v7.0.1...v7.1.1) --- updated-dependencies: - dependency-name: kt-paperclip dependency-type: direct:production update-type: version-update:semver-minor ... 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 47fa180ca7..c5bf5c73e0 100644 --- a/Gemfile +++ b/Gemfile @@ -21,7 +21,7 @@ gem 'dotenv-rails', '~> 2.7' gem 'aws-sdk-s3', '~> 1.112', require: false gem 'fog-core', '<= 2.1.0' gem 'fog-openstack', '~> 0.3', require: false -gem 'kt-paperclip', '~> 7.0' +gem 'kt-paperclip', '~> 7.1' gem 'blurhash', '~> 0.1' gem 'active_model_serializers', '~> 0.10' diff --git a/Gemfile.lock b/Gemfile.lock index 0e62f0a097..9314fc27e7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -330,7 +330,7 @@ GEM activerecord kaminari-core (= 1.2.2) kaminari-core (1.2.2) - kt-paperclip (7.0.1) + kt-paperclip (7.1.1) activemodel (>= 4.2.0) activesupport (>= 4.2.0) marcel (~> 1.0.1) @@ -361,7 +361,7 @@ GEM mini_mime (>= 0.1.1) makara (0.5.1) activerecord (>= 5.2.0) - marcel (1.0.1) + marcel (1.0.2) mario-redis-lock (1.2.1) redis (>= 3.0.5) matrix (0.4.2) @@ -372,7 +372,7 @@ GEM nokogiri (~> 1.10) mime-types (3.4.1) mime-types-data (~> 3.2015) - mime-types-data (3.2021.1115) + mime-types-data (3.2022.0105) mini_mime (1.1.2) mini_portile2 (2.7.1) minitest (5.15.0) @@ -728,7 +728,7 @@ DEPENDENCIES json-ld json-ld-preloaded (~> 3.2) kaminari (~> 1.2) - kt-paperclip (~> 7.0) + kt-paperclip (~> 7.1) letter_opener (~> 1.7) letter_opener_web (~> 2.0) link_header (~> 0.0) From cf8fee1379293ef894cb5a1b91fd35b2c4c63a37 Mon Sep 17 00:00:00 2001 From: Jeong Arm Date: Mon, 14 Feb 2022 08:17:09 +0900 Subject: [PATCH 07/35] Add `from:` query operator to search syntax (#16526) * Add 'by:userhandle' parameter to search api * Use search syntax for "by" prefix * Codeclimate * Use 'from' instead of 'by' --- app/lib/search_query_transformer.rb | 37 +++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/app/lib/search_query_transformer.rb b/app/lib/search_query_transformer.rb index e07ebfffed..c685d7b6fd 100644 --- a/app/lib/search_query_transformer.rb +++ b/app/lib/search_query_transformer.rb @@ -2,19 +2,21 @@ class SearchQueryTransformer < Parslet::Transform class Query - attr_reader :should_clauses, :must_not_clauses, :must_clauses + attr_reader :should_clauses, :must_not_clauses, :must_clauses, :filter_clauses def initialize(clauses) grouped = clauses.chunk(&:operator).to_h @should_clauses = grouped.fetch(:should, []) @must_not_clauses = grouped.fetch(:must_not, []) @must_clauses = grouped.fetch(:must, []) + @filter_clauses = grouped.fetch(:filter, []) end def apply(search) should_clauses.each { |clause| search = search.query.should(clause_to_query(clause)) } must_clauses.each { |clause| search = search.query.must(clause_to_query(clause)) } must_not_clauses.each { |clause| search = search.query.must_not(clause_to_query(clause)) } + filter_clauses.each { |clause| search = search.filter(**clause_to_filter(clause)) } search.query.minimum_should_match(1) end @@ -30,6 +32,15 @@ class SearchQueryTransformer < Parslet::Transform raise "Unexpected clause type: #{clause}" end end + + def clause_to_filter(clause) + case clause + when PrefixClause + { term: { clause.filter => clause.term } } + else + raise "Unexpected clause type: #{clause}" + end + end end class Operator @@ -69,11 +80,33 @@ class SearchQueryTransformer < Parslet::Transform end end + class PrefixClause + attr_reader :filter, :operator, :term + + def initialize(prefix, term) + @operator = :filter + case prefix + when 'from' + @filter = :account_id + username, domain = term.split('@') + account = Account.find_remote(username, domain) + + raise "Account not found: #{term}" unless account + + @term = account.id + else + raise "Unknown prefix: #{prefix}" + end + end + end + rule(clause: subtree(:clause)) do prefix = clause[:prefix][:term].to_s if clause[:prefix] operator = clause[:operator]&.to_s - if clause[:term] + if clause[:prefix] + PrefixClause.new(prefix, clause[:term].to_s) + elsif clause[:term] TermClause.new(prefix, operator, clause[:term].to_s) elsif clause[:shortcode] TermClause.new(prefix, operator, ":#{clause[:term]}:") From 0ad6f982afaaeea92d75ffec79eb237224327241 Mon Sep 17 00:00:00 2001 From: Jeong Arm Date: Tue, 15 Feb 2022 00:07:04 +0900 Subject: [PATCH 08/35] Fix admin statuses page order with media (#17538) --- app/models/admin/status_filter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/admin/status_filter.rb b/app/models/admin/status_filter.rb index ce5bb5f461..4fba612a65 100644 --- a/app/models/admin/status_filter.rb +++ b/app/models/admin/status_filter.rb @@ -31,7 +31,7 @@ class Admin::StatusFilter def scope_for(key, value) case key.to_s when 'media' - Status.joins(:media_attachments).merge(@account.media_attachments.reorder(nil)).group(:id) + Status.joins(:media_attachments).merge(@account.media_attachments.reorder(nil)).group(:id).reorder('statuses.id desc') when 'id' Status.where(id: value) else From a40e6f5d97f14e91ac6f9071d163fff056dd6efd Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Tue, 15 Feb 2022 00:08:02 +0900 Subject: [PATCH 09/35] Remove protobuf dependencies (#17539) --- .circleci/config.yml | 2 +- .github/workflows/build-image.yml | 6 +++++- .github/workflows/check-i18n.yml | 2 +- Aptfile | 2 -- Dockerfile | 4 ++-- Vagrantfile | 2 -- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 751ca95b18..a9ad921457 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -32,7 +32,7 @@ commands: name: Install system dependencies command: | sudo apt-get update - sudo apt-get install -y libicu-dev libidn11-dev libprotobuf-dev protobuf-compiler + sudo apt-get install -y libicu-dev libidn11-dev install-ruby-dependencies: parameters: ruby-version: diff --git a/.github/workflows/build-image.yml b/.github/workflows/build-image.yml index 0aaea6b1fe..92a164c40e 100644 --- a/.github/workflows/build-image.yml +++ b/.github/workflows/build-image.yml @@ -6,6 +6,10 @@ on: - "main" tags: - "*" + pull_request: + paths: + - .github/workflows/build-image.yml + - Dockerfile jobs: build-image: runs-on: ubuntu-latest @@ -30,7 +34,7 @@ jobs: with: context: . platforms: linux/amd64,linux/arm64 - push: true + push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} cache-from: type=registry,ref=tootsuite/mastodon:latest cache-to: type=inline diff --git a/.github/workflows/check-i18n.yml b/.github/workflows/check-i18n.yml index 2e8f230f31..9cb98dd125 100644 --- a/.github/workflows/check-i18n.yml +++ b/.github/workflows/check-i18n.yml @@ -18,7 +18,7 @@ jobs: - name: Install system dependencies run: | sudo apt-get update - sudo apt-get install -y libicu-dev libidn11-dev libprotobuf-dev protobuf-compiler + sudo apt-get install -y libicu-dev libidn11-dev - name: Set up Ruby uses: ruby/setup-ruby@v1 with: diff --git a/Aptfile b/Aptfile index b2cbad714d..9235141ad5 100644 --- a/Aptfile +++ b/Aptfile @@ -4,10 +4,8 @@ libicu-dev libidn11 libidn11-dev libpq-dev -libprotobuf-dev libxdamage1 libxfixes3 -protobuf-compiler zlib1g-dev libcairo2 libcroco3 diff --git a/Dockerfile b/Dockerfile index c6287b5a7a..1b3661561e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -51,7 +51,7 @@ RUN npm install -g npm@latest && \ gem install bundler && \ apt-get update && \ apt-get install -y --no-install-recommends git libicu-dev libidn11-dev \ - libpq-dev libprotobuf-dev protobuf-compiler shared-mime-info + libpq-dev shared-mime-info COPY Gemfile* package.json yarn.lock /opt/mastodon/ @@ -88,7 +88,7 @@ RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selectio RUN apt-get update && \ apt-get -y --no-install-recommends install \ libssl1.1 libpq5 imagemagick ffmpeg libjemalloc2 \ - libicu66 libprotobuf17 libidn11 libyaml-0-2 \ + libicu66 libidn11 libyaml-0-2 \ file ca-certificates tzdata libreadline8 gcc tini apt-utils && \ ln -s /opt/mastodon /mastodon && \ gem install bundler && \ diff --git a/Vagrantfile b/Vagrantfile index e086ddd987..3e73d9e470 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -33,11 +33,9 @@ sudo apt-get install \ redis-tools \ postgresql \ postgresql-contrib \ - protobuf-compiler \ yarn \ libicu-dev \ libidn11-dev \ - libprotobuf-dev \ libreadline-dev \ libpam0g-dev \ -y From 47c24cf2ebbd608d4dc5b87b95c3acd77dcf7e3c Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 14 Feb 2022 16:08:23 +0100 Subject: [PATCH 10/35] Revert "Bump strong_migrations from 0.7.9 to 0.8.0 (#17504)" (#17540) This reverts commit 6b996fca0f7c9aa6137d08ffa7a56760c981a923. --- Gemfile | 2 +- Gemfile.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index c5bf5c73e0..ee5395bfcd 100644 --- a/Gemfile +++ b/Gemfile @@ -85,7 +85,7 @@ gem 'simple-navigation', '~> 4.3' gem 'simple_form', '~> 5.1' gem 'sprockets-rails', '~> 3.4', require: 'sprockets/railtie' gem 'stoplight', '~> 2.2.1' -gem 'strong_migrations', '~> 0.8' +gem 'strong_migrations', '~> 0.7' gem 'tty-prompt', '~> 0.23', require: false gem 'twitter-text', '~> 3.1.0' gem 'tzinfo-data', '~> 1.2021' diff --git a/Gemfile.lock b/Gemfile.lock index 9314fc27e7..71e8cf4cd4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -606,8 +606,8 @@ GEM stackprof (0.2.17) statsd-ruby (1.5.0) stoplight (2.2.1) - strong_migrations (0.8.0) - activerecord (>= 5.2) + strong_migrations (0.7.9) + activerecord (>= 5) temple (0.8.2) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) @@ -789,7 +789,7 @@ DEPENDENCIES sprockets-rails (~> 3.4) stackprof stoplight (~> 2.2.1) - strong_migrations (~> 0.8) + strong_migrations (~> 0.7) thor (~> 1.2) tty-prompt (~> 0.23) twitter-text (~> 3.1.0) From 82f8d1942429e5b6a563dcaddbd0cb5f5a908424 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 14 Feb 2022 21:27:53 +0100 Subject: [PATCH 11/35] Add appeals (#17364) * Add appeals * Add ability to reject appeals and ability to browse pending appeals in admin UI * Add strikes to account page in settings * Various fixes and improvements - Add separate notification setting for appeals, separate from reports - Fix style of links in report/strike header - Change approving an appeal to not restore statuses (due to federation complexities) - Change style of successfully appealed strikes on account settings page - Change account settings page to only show unappealed or recently appealed strikes * Change appealed_at to overruled_at * Fix missing method error --- app/controllers/admin/accounts_controller.rb | 4 +- app/controllers/admin/dashboard_controller.rb | 1 + .../admin/disputes/appeals_controller.rb | 40 ++++++ .../auth/registrations_controller.rb | 11 +- .../disputes/appeals_controller.rb | 25 ++++ app/controllers/disputes/base_controller.rb | 18 +++ .../disputes/strikes_controller.rb | 17 +++ .../admin/account_moderation_notes_helper.rb | 4 +- app/helpers/admin/action_logs_helper.rb | 2 + app/helpers/admin/trends/statuses_helper.rb | 20 +++ app/javascript/styles/mastodon/admin.scss | 89 +++++++++++- app/mailers/admin_mailer.rb | 10 ++ app/mailers/user_mailer.rb | 20 +++ app/models/account.rb | 4 + app/models/account_filter.rb | 2 + app/models/account_warning.rb | 8 +- app/models/admin/action_log_filter.rb | 2 + app/models/admin/appeal_filter.rb | 49 +++++++ app/models/appeal.rb | 58 ++++++++ app/models/user.rb | 4 + app/policies/account_warning_policy.rb | 17 +++ app/policies/appeal_policy.rb | 13 ++ app/services/appeal_service.rb | 28 ++++ app/services/approve_appeal_service.rb | 74 ++++++++++ .../_account_moderation_note.html.haml | 7 - .../_account_warning.html.haml | 30 ++++- app/views/admin/accounts/show.html.haml | 21 ++- app/views/admin/dashboard/index.html.haml | 3 + .../admin/disputes/appeals/_appeal.html.haml | 21 +++ .../admin/disputes/appeals/index.html.haml | 22 +++ .../admin/report_notes/_report_note.html.haml | 2 +- app/views/admin/reports/show.html.haml | 2 +- app/views/admin_mailer/new_appeal.text.erb | 9 ++ .../registrations/_account_warning.html.haml | 20 +++ .../auth/registrations/_status.html.haml | 31 ++--- app/views/disputes/strikes/show.html.haml | 127 ++++++++++++++++++ .../preferences/notifications/show.html.haml | 1 + app/views/statuses/_detailed_status.html.haml | 2 +- .../user_mailer/appeal_approved.html.haml | 59 ++++++++ .../user_mailer/appeal_approved.text.erb | 7 + .../user_mailer/appeal_rejected.html.haml | 59 ++++++++ .../user_mailer/appeal_rejected.text.erb | 7 + app/views/user_mailer/warning.html.haml | 6 +- config/brakeman.ignore | 64 +++++---- config/locales/en.yml | 77 ++++++++++- config/locales/simple_form.en.yml | 9 +- config/navigation.rb | 4 +- config/routes.rb | 15 +++ config/settings.yml | 1 + db/migrate/20220124141035_create_appeals.rb | 14 ++ ...19_add_overruled_at_to_account_warnings.rb | 5 + db/schema.rb | 23 +++- .../admin/disputes/appeals_controller_spec.rb | 53 ++++++++ .../disputes/appeals_controller_spec.rb | 27 ++++ .../disputes/strikes_controller_spec.rb | 30 +++++ .../fabricators/account_warning_fabricator.rb | 7 +- spec/fabricators/appeal_fabricator.rb | 5 + spec/mailers/previews/admin_mailer_preview.rb | 5 + spec/mailers/previews/user_mailer_preview.rb | 5 + spec/models/appeal_spec.rb | 5 + 60 files changed, 1212 insertions(+), 93 deletions(-) create mode 100644 app/controllers/admin/disputes/appeals_controller.rb create mode 100644 app/controllers/disputes/appeals_controller.rb create mode 100644 app/controllers/disputes/base_controller.rb create mode 100644 app/controllers/disputes/strikes_controller.rb create mode 100644 app/helpers/admin/trends/statuses_helper.rb create mode 100644 app/models/admin/appeal_filter.rb create mode 100644 app/models/appeal.rb create mode 100644 app/policies/account_warning_policy.rb create mode 100644 app/policies/appeal_policy.rb create mode 100644 app/services/appeal_service.rb create mode 100644 app/services/approve_appeal_service.rb delete mode 100644 app/views/admin/account_moderation_notes/_account_moderation_note.html.haml create mode 100644 app/views/admin/disputes/appeals/_appeal.html.haml create mode 100644 app/views/admin/disputes/appeals/index.html.haml create mode 100644 app/views/admin_mailer/new_appeal.text.erb create mode 100644 app/views/auth/registrations/_account_warning.html.haml create mode 100644 app/views/disputes/strikes/show.html.haml create mode 100644 app/views/user_mailer/appeal_approved.html.haml create mode 100644 app/views/user_mailer/appeal_approved.text.erb create mode 100644 app/views/user_mailer/appeal_rejected.html.haml create mode 100644 app/views/user_mailer/appeal_rejected.text.erb create mode 100644 db/migrate/20220124141035_create_appeals.rb create mode 100644 db/migrate/20220210153119_add_overruled_at_to_account_warnings.rb create mode 100644 spec/controllers/admin/disputes/appeals_controller_spec.rb create mode 100644 spec/controllers/disputes/appeals_controller_spec.rb create mode 100644 spec/controllers/disputes/strikes_controller_spec.rb create mode 100644 spec/fabricators/appeal_fabricator.rb create mode 100644 spec/models/appeal_spec.rb diff --git a/app/controllers/admin/accounts_controller.rb b/app/controllers/admin/accounts_controller.rb index e7f56e243b..e0ae71b9f2 100644 --- a/app/controllers/admin/accounts_controller.rb +++ b/app/controllers/admin/accounts_controller.rb @@ -28,7 +28,7 @@ module Admin @deletion_request = @account.deletion_request @account_moderation_note = current_account.account_moderation_notes.new(target_account: @account) @moderation_notes = @account.targeted_moderation_notes.latest - @warnings = @account.strikes.custom.latest + @warnings = @account.strikes.includes(:target_account, :account, :appeal).latest @domain_block = DomainBlock.rule_for(@account.domain) end @@ -146,7 +146,7 @@ module Admin end def filter_params - params.slice(*AccountFilter::KEYS).permit(*AccountFilter::KEYS) + params.slice(:page, *AccountFilter::KEYS).permit(:page, *AccountFilter::KEYS) end def form_account_batch_params diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb index f0a9354110..e376baab22 100644 --- a/app/controllers/admin/dashboard_controller.rb +++ b/app/controllers/admin/dashboard_controller.rb @@ -8,6 +8,7 @@ module Admin @pending_users_count = User.pending.count @pending_reports_count = Report.unresolved.count @pending_tags_count = Tag.pending_review.count + @pending_appeals_count = Appeal.pending.count end private diff --git a/app/controllers/admin/disputes/appeals_controller.rb b/app/controllers/admin/disputes/appeals_controller.rb new file mode 100644 index 0000000000..32e5e2f6fd --- /dev/null +++ b/app/controllers/admin/disputes/appeals_controller.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +class Admin::Disputes::AppealsController < Admin::BaseController + before_action :set_appeal, except: :index + + def index + authorize :appeal, :index? + + @appeals = filtered_appeals.page(params[:page]) + end + + def approve + authorize @appeal, :approve? + log_action :approve, @appeal + ApproveAppealService.new.call(@appeal, current_account) + redirect_to disputes_strike_path(@appeal.strike) + end + + def reject + authorize @appeal, :approve? + log_action :reject, @appeal + @appeal.reject!(current_account) + UserMailer.appeal_rejected(@appeal.account.user, @appeal) + redirect_to disputes_strike_path(@appeal.strike) + end + + private + + def filtered_appeals + Admin::AppealFilter.new(filter_params.with_defaults(status: 'pending')).results.includes(strike: :account) + end + + def filter_params + params.slice(:page, *Admin::AppealFilter::KEYS).permit(:page, *Admin::AppealFilter::KEYS) + end + + def set_appeal + @appeal = Appeal.find(params[:id]) + end +end diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb index f37e906fde..3b025838b0 100644 --- a/app/controllers/auth/registrations_controller.rb +++ b/app/controllers/auth/registrations_controller.rb @@ -9,6 +9,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController before_action :check_enabled_registrations, only: [:new, :create] before_action :configure_sign_up_params, only: [:create] before_action :set_sessions, only: [:edit, :update] + before_action :set_strikes, only: [:edit, :update] before_action :set_instance_presenter, only: [:new, :create, :update] before_action :set_body_classes, only: [:new, :create, :edit, :update] before_action :require_not_suspended!, only: [:update] @@ -111,8 +112,10 @@ class Auth::RegistrationsController < Devise::RegistrationsController end def set_invite - invite = invite_code.present? ? Invite.find_by(code: invite_code) : nil - @invite = invite&.valid_for_use? ? invite : nil + @invite = begin + invite = Invite.find_by(code: invite_code) if invite_code.present? + invite if invite&.valid_for_use? + end end def determine_layout @@ -123,6 +126,10 @@ class Auth::RegistrationsController < Devise::RegistrationsController @sessions = current_user.session_activations end + def set_strikes + @strikes = current_account.strikes.active.latest + end + def require_not_suspended! forbidden if current_account.suspended? end diff --git a/app/controllers/disputes/appeals_controller.rb b/app/controllers/disputes/appeals_controller.rb new file mode 100644 index 0000000000..15367c8792 --- /dev/null +++ b/app/controllers/disputes/appeals_controller.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +class Disputes::AppealsController < Disputes::BaseController + before_action :set_strike + + def create + authorize @strike, :appeal? + + @appeal = AppealService.new.call(@strike, appeal_params[:text]) + + redirect_to disputes_strike_path(@strike), notice: I18n.t('disputes.strikes.appealed_msg') + rescue ActiveRecord::RecordInvalid + render template: 'disputes/strikes/show' + end + + private + + def set_strike + @strike = current_account.strikes.find(params[:strike_id]) + end + + def appeal_params + params.require(:appeal).permit(:text) + end +end diff --git a/app/controllers/disputes/base_controller.rb b/app/controllers/disputes/base_controller.rb new file mode 100644 index 0000000000..865146b5cc --- /dev/null +++ b/app/controllers/disputes/base_controller.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class Disputes::BaseController < ApplicationController + include Authorization + + layout 'admin' + + skip_before_action :require_functional! + + before_action :set_body_classes + before_action :authenticate_user! + + private + + def set_body_classes + @body_classes = 'admin' + end +end diff --git a/app/controllers/disputes/strikes_controller.rb b/app/controllers/disputes/strikes_controller.rb new file mode 100644 index 0000000000..d41c5c727e --- /dev/null +++ b/app/controllers/disputes/strikes_controller.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class Disputes::StrikesController < Disputes::BaseController + before_action :set_strike + + def show + authorize @strike, :show? + + @appeal = @strike.appeal || @strike.build_appeal + end + + private + + def set_strike + @strike = AccountWarning.find(params[:id]) + end +end diff --git a/app/helpers/admin/account_moderation_notes_helper.rb b/app/helpers/admin/account_moderation_notes_helper.rb index 40b2a52892..2f08538ca6 100644 --- a/app/helpers/admin/account_moderation_notes_helper.rb +++ b/app/helpers/admin/account_moderation_notes_helper.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true module Admin::AccountModerationNotesHelper - def admin_account_link_to(account) + def admin_account_link_to(account, path: nil) return if account.nil? - link_to admin_account_path(account.id), class: name_tag_classes(account), title: account.acct do + link_to path || admin_account_path(account.id), class: name_tag_classes(account), title: account.acct do safe_join([ image_tag(account.avatar.url, width: 15, height: 15, alt: display_name(account), class: 'avatar'), content_tag(:span, account.acct, class: 'username'), diff --git a/app/helpers/admin/action_logs_helper.rb b/app/helpers/admin/action_logs_helper.rb index f3aa4be4f2..47eeeaac3a 100644 --- a/app/helpers/admin/action_logs_helper.rb +++ b/app/helpers/admin/action_logs_helper.rb @@ -33,6 +33,8 @@ module Admin::ActionLogsHelper "#{record.ip}/#{record.ip.prefix} (#{I18n.t("simple_form.labels.ip_block.severities.#{record.severity}")})" when 'Instance' record.domain + when 'Appeal' + link_to record.account.acct, disputes_strike_path(record.strike) end end diff --git a/app/helpers/admin/trends/statuses_helper.rb b/app/helpers/admin/trends/statuses_helper.rb new file mode 100644 index 0000000000..d16e3dd121 --- /dev/null +++ b/app/helpers/admin/trends/statuses_helper.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Admin::Trends::StatusesHelper + def one_line_preview(status) + text = begin + if status.local? + status.text.split("\n").first + else + Nokogiri::HTML(status.text).css('html > body > *').first&.text + end + end + + return '' if text.blank? + + html = Formatter.instance.send(:encode, text) + html = Formatter.instance.send(:encode_custom_emojis, html, status.emojis, prefers_autoplay?) + + html.html_safe # rubocop:disable Rails/OutputSafety + end +end diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss index 546de16400..f5741bd502 100644 --- a/app/javascript/styles/mastodon/admin.scss +++ b/app/javascript/styles/mastodon/admin.scss @@ -578,12 +578,16 @@ body, } .log-entry { + display: block; line-height: 20px; padding: 15px; padding-left: 15px * 2 + 40px; background: $ui-base-color; border-bottom: 1px solid darken($ui-base-color, 8%); position: relative; + text-decoration: none; + color: $darker-text-color; + font-size: 14px; &:first-child { border-top-left-radius: 4px; @@ -596,15 +600,12 @@ body, border-bottom: 0; } - &:hover { + &:hover, + &:focus, + &:active { background: lighten($ui-base-color, 4%); } - &__header { - color: $darker-text-color; - font-size: 14px; - } - &__avatar { position: absolute; left: 15px; @@ -640,6 +641,18 @@ body, text-decoration: underline; } } + + &--inactive { + .log-entry__title { + text-decoration: line-through; + } + + a, + .username, + .target { + color: $darker-text-color; + } + } } a.name-tag, @@ -1175,6 +1188,17 @@ a.sparkline { font-weight: 600; padding: 4px 0; } + + a { + color: $ui-highlight-color; + text-decoration: none; + + &:hover, + &:focus, + &:active { + text-decoration: underline; + } + } } &--horizontal { @@ -1451,3 +1475,56 @@ a.sparkline { } } } + +.strike-card { + padding: 15px; + border-radius: 4px; + background: $ui-base-color; + font-size: 15px; + line-height: 20px; + word-wrap: break-word; + font-weight: 400; + color: $primary-text-color; + + p { + margin-bottom: 20px; + unicode-bidi: plaintext; + + &:last-child { + margin-bottom: 0; + } + } + + &__statuses-list { + border-radius: 4px; + border: 1px solid darken($ui-base-color, 8%); + font-size: 13px; + line-height: 18px; + overflow: hidden; + + &__item { + padding: 16px; + background: lighten($ui-base-color, 2%); + border-bottom: 1px solid darken($ui-base-color, 8%); + + &:last-child { + border-bottom: 0; + } + + &__meta { + color: $darker-text-color; + } + + a { + color: inherit; + text-decoration: none; + + &:hover, + &:focus, + &:active { + text-decoration: underline; + } + } + } + } +} diff --git a/app/mailers/admin_mailer.rb b/app/mailers/admin_mailer.rb index b23bd1296f..a9d00c000d 100644 --- a/app/mailers/admin_mailer.rb +++ b/app/mailers/admin_mailer.rb @@ -15,6 +15,16 @@ class AdminMailer < ApplicationMailer end end + def new_appeal(recipient, appeal) + @appeal = appeal + @me = recipient + @instance = Rails.configuration.x.local_domain + + locale_for_account(@me) do + mail to: @me.user_email, subject: I18n.t('admin_mailer.new_appeal.subject', instance: @instance, username: @appeal.account.username) + end + end + def new_pending_account(recipient, user) @account = user.account @me = recipient diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index 5221a48928..583c948b0e 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -173,6 +173,26 @@ class UserMailer < Devise::Mailer end end + def appeal_approved(user, appeal) + @resource = user + @instance = Rails.configuration.x.local_domain + @appeal = appeal + + I18n.with_locale(@resource.locale || I18n.default_locale) do + mail to: @resource.email, subject: I18n.t('user_mailer.appeal_approved.subject', date: l(@appeal.created_at)) + end + end + + def appeal_rejected(user, appeal) + @resource = user + @instance = Rails.configuration.x.local_domain + @appeal = appeal + + I18n.with_locale(@resource.locale || I18n.default_locale) do + mail to: @resource.email, subject: I18n.t('user_mailer.appeal_rejected.subject', date: l(@appeal.created_at)) + end + end + def sign_in_token(user, remote_ip, user_agent, timestamp) @resource = user @instance = Rails.configuration.x.local_domain diff --git a/app/models/account.rb b/app/models/account.rb index 771cc0b1ba..2ad45feda0 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -270,6 +270,10 @@ class Account < ApplicationRecord true end + def previous_strikes_count + strikes.where(overruled_at: nil).count + end + def keypair @keypair ||= OpenSSL::PKey::RSA.new(private_key || public_key) end diff --git a/app/models/account_filter.rb b/app/models/account_filter.rb index 86b7f5f417..9da1522dd1 100644 --- a/app/models/account_filter.rb +++ b/app/models/account_filter.rb @@ -24,6 +24,8 @@ class AccountFilter scope = Account.includes(:account_stat, user: [:ips, :invite_request]).without_instance_actor.reorder(nil) params.each do |key, value| + next if key.to_s == 'page' + scope.merge!(scope_for(key, value.to_s.strip)) if value.present? end diff --git a/app/models/account_warning.rb b/app/models/account_warning.rb index fc0d988fdc..05d01942df 100644 --- a/app/models/account_warning.rb +++ b/app/models/account_warning.rb @@ -12,6 +12,7 @@ # updated_at :datetime not null # report_id :bigint(8) # status_ids :string is an Array +# overruled_at :datetime # class AccountWarning < ApplicationRecord @@ -28,12 +29,17 @@ class AccountWarning < ApplicationRecord belongs_to :target_account, class_name: 'Account', inverse_of: :strikes belongs_to :report, optional: true - has_one :appeal, dependent: :destroy + has_one :appeal, dependent: :destroy, inverse_of: :strike scope :latest, -> { order(id: :desc) } scope :custom, -> { where.not(text: '') } + scope :active, -> { where(overruled_at: nil).or(where('account_warnings.overruled_at >= ?', 30.days.ago)) } def statuses Status.with_discarded.where(id: status_ids || []) end + + def overruled? + overruled_at.present? + end end diff --git a/app/models/admin/action_log_filter.rb b/app/models/admin/action_log_filter.rb index 12136223be..0f2f712a25 100644 --- a/app/models/admin/action_log_filter.rb +++ b/app/models/admin/action_log_filter.rb @@ -8,6 +8,8 @@ class Admin::ActionLogFilter ).freeze ACTION_TYPE_MAP = { + approve_appeal: { target_type: 'Appeal', action: 'approve' }.freeze, + reject_appeal: { target_type: 'Appeal', action: 'reject' }.freeze, assigned_to_self_report: { target_type: 'Report', action: 'assigned_to_self' }.freeze, change_email_user: { target_type: 'User', action: 'change_email' }.freeze, confirm_user: { target_type: 'User', action: 'confirm' }.freeze, diff --git a/app/models/admin/appeal_filter.rb b/app/models/admin/appeal_filter.rb new file mode 100644 index 0000000000..b163d2e568 --- /dev/null +++ b/app/models/admin/appeal_filter.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +class Admin::AppealFilter + KEYS = %i( + status + ).freeze + + attr_reader :params + + def initialize(params) + @params = params + end + + def results + scope = Appeal.order(id: :desc) + + params.each do |key, value| + next if %w(page).include?(key.to_s) + + scope.merge!(scope_for(key, value.to_s.strip)) if value.present? + end + + scope + end + + private + + def scope_for(key, value) + case key.to_s + when 'status' + status_scope(value) + else + raise "Unknown filter: #{key}" + end + end + + def status_scope(value) + case value + when 'approved' + Appeal.approved + when 'rejected' + Appeal.rejected + when 'pending' + Appeal.pending + else + raise "Unknown status: #{value}" + end + end +end diff --git a/app/models/appeal.rb b/app/models/appeal.rb new file mode 100644 index 0000000000..46f35ae375 --- /dev/null +++ b/app/models/appeal.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: appeals +# +# id :bigint(8) not null, primary key +# account_id :bigint(8) not null +# account_warning_id :bigint(8) not null +# text :text default(""), not null +# approved_at :datetime +# approved_by_account_id :bigint(8) +# rejected_at :datetime +# rejected_by_account_id :bigint(8) +# created_at :datetime not null +# updated_at :datetime not null +# +class Appeal < ApplicationRecord + belongs_to :account + belongs_to :strike, class_name: 'AccountWarning', foreign_key: 'account_warning_id' + belongs_to :approved_by_account, class_name: 'Account', optional: true + belongs_to :rejected_by_account, class_name: 'Account', optional: true + + validates :text, presence: true, length: { maximum: 2_000 } + validates :account_warning_id, uniqueness: true + + validate :validate_time_frame, on: :create + + scope :approved, -> { where.not(approved_at: nil) } + scope :rejected, -> { where.not(rejected_at: nil) } + scope :pending, -> { where(approved_at: nil, rejected_at: nil) } + + def pending? + !approved? && !rejected? + end + + def approved? + approved_at.present? + end + + def rejected? + rejected_at.present? + end + + def approve!(current_account) + update!(approved_at: Time.now.utc, approved_by_account: current_account) + end + + def reject!(current_account) + update!(rejected_at: Time.now.utc, rejected_by_account: current_account) + end + + private + + def validate_time_frame + errors.add(:base, I18n.t('strikes.errors.too_late')) if Time.now.utc > (strike.created_at + 20.days) + end +end diff --git a/app/models/user.rb b/app/models/user.rb index fd1d7049a9..517254a910 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -265,6 +265,10 @@ class User < ApplicationRecord settings.notification_emails['pending_account'] end + def allows_appeal_emails? + settings.notification_emails['appeal'] + end + def allows_trending_tag_emails? settings.notification_emails['trending_tag'] end diff --git a/app/policies/account_warning_policy.rb b/app/policies/account_warning_policy.rb new file mode 100644 index 0000000000..6b92da475b --- /dev/null +++ b/app/policies/account_warning_policy.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AccountWarningPolicy < ApplicationPolicy + def show? + target? || staff? + end + + def appeal? + target? + end + + private + + def target? + record.target_account_id == current_account&.id + end +end diff --git a/app/policies/appeal_policy.rb b/app/policies/appeal_policy.rb new file mode 100644 index 0000000000..a25187172a --- /dev/null +++ b/app/policies/appeal_policy.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class AppealPolicy < ApplicationPolicy + def index? + staff? + end + + def approve? + record.pending? && staff? + end + + alias reject? approve? +end diff --git a/app/services/appeal_service.rb b/app/services/appeal_service.rb new file mode 100644 index 0000000000..1397c50f5f --- /dev/null +++ b/app/services/appeal_service.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +class AppealService < BaseService + def call(strike, text) + @strike = strike + @text = text + + create_appeal! + notify_staff! + + @appeal + end + + private + + def create_appeal! + @appeal = @strike.create_appeal!( + text: @text, + account: @strike.target_account + ) + end + + def notify_staff! + User.staff.includes(:account).each do |u| + AdminMailer.new_appeal(u.account, @appeal).deliver_later if u.allows_appeal_emails? + end + end +end diff --git a/app/services/approve_appeal_service.rb b/app/services/approve_appeal_service.rb new file mode 100644 index 0000000000..f76bf8943e --- /dev/null +++ b/app/services/approve_appeal_service.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +class ApproveAppealService < BaseService + def call(appeal, current_account) + @appeal = appeal + @strike = appeal.strike + @current_account = current_account + + ApplicationRecord.transaction do + undo_strike_action! + mark_strike_as_appealed! + end + + queue_workers! + notify_target_account! + end + + private + + def target_account + @strike.target_account + end + + def undo_strike_action! + case @strike.action + when 'disable' + undo_disable! + when 'delete_statuses' + undo_delete_statuses! + when 'sensitive' + undo_sensitive! + when 'silence' + undo_silence! + when 'suspend' + undo_suspend! + end + end + + def mark_strike_as_appealed! + @appeal.approve!(@current_account) + @strike.touch(:overruled_at) + end + + def undo_disable! + target_account.user.enable! + end + + def undo_delete_statuses! + # Cannot be undone + end + + def undo_sensitive! + target_account.unsensitize! + end + + def undo_silence! + target_account.unsilence! + end + + def undo_suspend! + target_account.unsuspend! + end + + def queue_workers! + case @strike.action + when 'suspend' + Admin::UnsuspensionWorker.perform_async(target_account.id) + end + end + + def notify_target_account! + UserMailer.appeal_approved(target_account.user, @appeal).deliver_later + end +end diff --git a/app/views/admin/account_moderation_notes/_account_moderation_note.html.haml b/app/views/admin/account_moderation_notes/_account_moderation_note.html.haml deleted file mode 100644 index 432fb79a6e..0000000000 --- a/app/views/admin/account_moderation_notes/_account_moderation_note.html.haml +++ /dev/null @@ -1,7 +0,0 @@ -.speech-bubble - .speech-bubble__bubble - = simple_format(h(account_moderation_note.content)) - .speech-bubble__owner - = admin_account_link_to account_moderation_note.account - %time.formatted{ datetime: account_moderation_note.created_at.iso8601 }= l account_moderation_note.created_at - = table_link_to 'trash', t('admin.account_moderation_notes.delete'), admin_account_moderation_note_path(account_moderation_note), method: :delete if can?(:destroy, account_moderation_note) diff --git a/app/views/admin/account_warnings/_account_warning.html.haml b/app/views/admin/account_warnings/_account_warning.html.haml index 8c9c9679ce..ef23c3b776 100644 --- a/app/views/admin/account_warnings/_account_warning.html.haml +++ b/app/views/admin/account_warnings/_account_warning.html.haml @@ -1,6 +1,24 @@ -.speech-bubble.warning - .speech-bubble__bubble - = Formatter.instance.linkify(account_warning.text) - .speech-bubble__owner - = admin_account_link_to account_warning.account - %time.formatted{ datetime: account_warning.created_at.iso8601 }= l account_warning.created_at += link_to disputes_strike_path(account_warning), class: ['log-entry', account_warning.overruled? && 'log-entry--inactive'] do + .log-entry__header + .log-entry__avatar + = image_tag account_warning.target_account.avatar.url(:original), alt: '', width: 40, height: 40, class: 'avatar' + .log-entry__content + .log-entry__title + = t(account_warning.action, scope: 'admin.strikes.actions', name: content_tag(:span, account_warning.account.username, class: 'username'), target: content_tag(:span, account_warning.target_account.acct, class: 'target')).html_safe + .log-entry__timestamp + %time.formatted{ datetime: account_warning.created_at.iso8601 } + = l(account_warning.created_at) + + - if account_warning.report_id.present? + · + = t('admin.reports.title', id: account_warning.report_id) + + - if account_warning.overruled? + · + %span.positive-hint= t('admin.strikes.appeal_approved') + - elsif account_warning.appeal&.pending? + · + %span.warning-hint= t('admin.strikes.appeal_pending') + - elsif account_warning.appeal&.rejected? + · + %span.negative-hint= t('admin.strikes.appeal_rejected') diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml index f3853d629e..9a1f07a066 100644 --- a/app/views/admin/accounts/show.html.haml +++ b/app/views/admin/accounts/show.html.haml @@ -246,18 +246,29 @@ %hr.spacer/ - unless @warnings.empty? - = render @warnings + + %h3= t 'admin.accounts.previous_strikes' + + %p= t('admin.accounts.previous_strikes_description_html', count: @account.previous_strikes_count) + + .account-strikes + = render @warnings %hr.spacer/ - = render @moderation_notes + %h3= t 'admin.reports.notes.title' - = simple_form_for @account_moderation_note, url: admin_account_moderation_notes_path do |f| - = render 'shared/error_messages', object: @account_moderation_note + %p= t 'admin.reports.notes_description_html' - = f.input :content, placeholder: t('admin.reports.notes.placeholder'), rows: 6 + .report-notes + = render partial: 'admin/report_notes/report_note', collection: @moderation_notes + + = simple_form_for @account_moderation_note, url: admin_account_moderation_notes_path do |f| = f.hidden_field :target_account_id + .field-group + = f.input :content, placeholder: t('admin.reports.notes.placeholder'), rows: 6 + .actions = f.button :button, t('admin.account_moderation_notes.create'), type: :submit diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 4b581f5ea6..59b75e0e1d 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -46,6 +46,9 @@ %span= t('admin.dashboard.pending_tags_html', count: @pending_tags_count) = fa_icon 'chevron-right fw' + = link_to admin_disputes_appeals_path(status: 'pending'), class: 'dashboard__quick-access' do + %span= t('admin.dashboard.pending_appeals_html', count: @pending_appeals_count) + = fa_icon 'chevron-right fw' .dashboard__item = react_admin_component :dimension, dimension: 'sources', start_at: @time_period.first, end_at: @time_period.last, limit: 8, label: t('admin.dashboard.sources') diff --git a/app/views/admin/disputes/appeals/_appeal.html.haml b/app/views/admin/disputes/appeals/_appeal.html.haml new file mode 100644 index 0000000000..02b8777e13 --- /dev/null +++ b/app/views/admin/disputes/appeals/_appeal.html.haml @@ -0,0 +1,21 @@ += link_to disputes_strike_path(appeal.strike), class: ['log-entry', appeal.approved? && 'log-entry--inactive'] do + .log-entry__header + .log-entry__avatar + = image_tag appeal.account.avatar.url(:original), alt: '', width: 40, height: 40, class: 'avatar' + .log-entry__content + .log-entry__title + = t(appeal.strike.action, scope: 'admin.strikes.actions', name: content_tag(:span, appeal.strike.account.username, class: 'username'), target: content_tag(:span, appeal.account.acct, class: 'target')).html_safe + .log-entry__timestamp + %time.formatted{ datetime: appeal.strike.created_at.iso8601 } + = l(appeal.strike.created_at) + + - if appeal.strike.report_id.present? + · + = t('admin.reports.title', id: appeal.strike.report_id) + · + - if appeal.approved? + %span.positive-hint= t('admin.strikes.appeal_approved') + - elsif appeal.rejected? + %span.negative-hint= t('admin.strikes.appeal_rejected') + - else + %span.warning-hint= t('admin.strikes.appeal_pending') diff --git a/app/views/admin/disputes/appeals/index.html.haml b/app/views/admin/disputes/appeals/index.html.haml new file mode 100644 index 0000000000..dd6a6f403f --- /dev/null +++ b/app/views/admin/disputes/appeals/index.html.haml @@ -0,0 +1,22 @@ +- content_for :page_title do + = t('admin.disputes.appeals.title') + +- content_for :header_tags do + = javascript_pack_tag 'admin', async: true, crossorigin: 'anonymous' + +.filters + .filter-subset + %strong= t('admin.tags.review') + %ul + %li= filter_link_to safe_join([t('admin.accounts.moderation.pending'), "(#{Appeal.pending.count})"], ' '), status: 'pending' + %li= filter_link_to t('admin.trends.approved'), status: 'approved' + %li= filter_link_to t('admin.trends.rejected'), status: 'rejected' + +- if @appeals.empty? + %div.muted-hint.center-text + = t 'admin.disputes.appeals.empty' +- else + .announcements-list + = render partial: 'appeal', collection: @appeals + += paginate @appeals diff --git a/app/views/admin/report_notes/_report_note.html.haml b/app/views/admin/report_notes/_report_note.html.haml index 428b6cf59c..f9d57c2ae3 100644 --- a/app/views/admin/report_notes/_report_note.html.haml +++ b/app/views/admin/report_notes/_report_note.html.haml @@ -3,7 +3,7 @@ .report-notes__item__header %span.username - = link_to display_name(report_note.account), admin_account_path(report_note.account_id) + = link_to report_note.account.username, admin_account_path(report_note.account_id) %time{ datetime: report_note.created_at.iso8601, title: l(report_note.created_at) } - if report_note.created_at.today? = t('admin.report_notes.today_at', time: l(report_note.created_at, format: :time)) diff --git a/app/views/admin/reports/show.html.haml b/app/views/admin/reports/show.html.haml index 02c46e3840..e53c180e50 100644 --- a/app/views/admin/reports/show.html.haml +++ b/app/views/admin/reports/show.html.haml @@ -57,7 +57,7 @@ .report-header__details__item__header %strong= t('admin.accounts.strikes') .report-header__details__item__content - = @report.target_account.strikes.count + = @report.target_account.previous_strikes_count .report-header__details .report-header__details__item diff --git a/app/views/admin_mailer/new_appeal.text.erb b/app/views/admin_mailer/new_appeal.text.erb new file mode 100644 index 0000000000..db4529eb7d --- /dev/null +++ b/app/views/admin_mailer/new_appeal.text.erb @@ -0,0 +1,9 @@ +<%= raw t('application_mailer.salutation', name: display_name(@me)) %> + +<%= raw t('admin_mailer.new_appeal.body', target: @appeal.account.username, action_taken_by: @appeal.strike.account.username, date: l(@appeal.strike.created_at), type: t(@appeal.strike.action, scope: 'admin_mailer.new_appeal.actions')) %> + +> <%= raw word_wrap(@appeal.text, break_sequence: "\n> ") %> + +<%= raw t('admin_mailer.new_appeal.next_steps') %> + +<%= raw t('application_mailer.view')%> <%= disputes_strike_url(@appeal.strike) %> diff --git a/app/views/auth/registrations/_account_warning.html.haml b/app/views/auth/registrations/_account_warning.html.haml new file mode 100644 index 0000000000..40e7e12968 --- /dev/null +++ b/app/views/auth/registrations/_account_warning.html.haml @@ -0,0 +1,20 @@ += link_to disputes_strike_path(account_warning), class: 'log-entry' do + .log-entry__header + .log-entry__avatar + .indicator-icon{ class: account_warning.overruled? ? 'success' : 'failure' } + = fa_icon 'warning' + .log-entry__content + .log-entry__title + = t('disputes.strikes.title', action: t(account_warning.action, scope: 'disputes.strikes.title_actions'), date: l(account_warning.created_at.to_date)) + .log-entry__timestamp + %time.formatted{ datetime: account_warning.created_at.iso8601 }= l(account_warning.created_at) + + - if account_warning.overruled? + · + %span.positive-hint= t('disputes.strikes.your_appeal_approved') + - elsif account_warning.appeal&.pending? + · + %span.warning-hint= t('disputes.strikes.your_appeal_pending') + - elsif account_warning.appeal&.rejected? + · + %span.negative-hint= t('disputes.strikes.your_appeal_rejected') diff --git a/app/views/auth/registrations/_status.html.haml b/app/views/auth/registrations/_status.html.haml index 47112dae07..3546510b21 100644 --- a/app/views/auth/registrations/_status.html.haml +++ b/app/views/auth/registrations/_status.html.haml @@ -1,22 +1,17 @@ +- if !@user.confirmed? + .flash-message.warning + = t('auth.status.confirming') + = link_to t('auth.didnt_get_confirmation'), new_user_confirmation_path +- elsif !@user.approved? + .flash-message.warning + = t('auth.status.pending') +- elsif @user.account.moved_to_account_id.present? + .flash-message.warning + = t('auth.status.redirecting_to', acct: @user.account.moved_to_account.acct) + = link_to t('migrations.cancel'), settings_migration_path + %h3= t('auth.status.account_status') -.simple_form - %p.hint - - if @user.account.suspended? - %span.negative-hint= t('user_mailer.warning.explanation.suspend') - - elsif @user.disabled? - %span.negative-hint= t('user_mailer.warning.explanation.disable') - - elsif @user.account.silenced? - %span.warning-hint= t('user_mailer.warning.explanation.silence') - - elsif !@user.confirmed? - %span.warning-hint= t('auth.status.confirming') - = link_to t('auth.didnt_get_confirmation'), new_user_confirmation_path - - elsif !@user.approved? - %span.warning-hint= t('auth.status.pending') - - elsif @user.account.moved_to_account_id.present? - %span.positive-hint= t('auth.status.redirecting_to', acct: @user.account.moved_to_account.acct) - = link_to t('migrations.cancel'), settings_migration_path - - else - %span.positive-hint= t('auth.status.functional') += render partial: 'account_warning', collection: @strikes %hr.spacer/ diff --git a/app/views/disputes/strikes/show.html.haml b/app/views/disputes/strikes/show.html.haml new file mode 100644 index 0000000000..3dcb19016e --- /dev/null +++ b/app/views/disputes/strikes/show.html.haml @@ -0,0 +1,127 @@ +- content_for :page_title do + = t('disputes.strikes.title', action: t(@strike.action, scope: 'disputes.strikes.title_actions'), date: l(@strike.created_at.to_date)) + +- content_for :heading_actions do + - if @appeal.persisted? + = link_to t('admin.accounts.approve'), approve_admin_disputes_appeal_path(@appeal), method: :post, class: 'button' if can?(:approve, @appeal) + = link_to t('admin.accounts.reject'), reject_admin_disputes_appeal_path(@appeal), method: :post, class: 'button button--destructive' if can?(:reject, @appeal) + +- if @strike.overruled? + %p.hint + %span.positive-hint + = fa_icon 'check' + = ' ' + = t 'disputes.strikes.appeal_approved' +- elsif @appeal.persisted? && @appeal.rejected? + %p.hint + %span.negative-hint + = fa_icon 'times' + = ' ' + = t 'disputes.strikes.appeal_rejected' + +.report-header + .report-header__card + .strike-card + - unless @strike.none_action? + %p= t "user_mailer.warning.explanation.#{@strike.action}" + + - unless @strike.text.blank? + = Formatter.instance.linkify(@strike.text) + + - if @strike.report && !@strike.report.other? + %p + %strong= t('user_mailer.warning.reason') + = t("user_mailer.warning.categories.#{@strike.report.category}") + + - if @strike.report.violation? && @strike.report.rule_ids.present? + %ul.rules-list + - @strike.report.rules.each do |rule| + %li= rule.text + + - if @strike.status_ids.present? && !@strike.status_ids.empty? + %p + %strong= t('user_mailer.warning.statuses') + + .strike-card__statuses-list + - status_map = @strike.statuses.includes(:application, :media_attachments).index_by(&:id) + + - @strike.status_ids.each do |status_id| + .strike-card__statuses-list__item + - if (status = status_map[status_id.to_i]) + .one-liner + = link_to short_account_status_url(@strike.target_account, status_id), class: 'emojify' do + = one_line_preview(status) + + - status.media_attachments.each do |media_attachment| + %abbr{ title: media_attachment.description } + = fa_icon 'link' + = media_attachment.file_file_name + .strike-card__statuses-list__item__meta + %time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at) + · + = status.application.name + - else + .one-liner= t('disputes.strikes.status', id: status_id) + .strike-card__statuses-list__item__meta + = t('disputes.strikes.status_removed') + + .report-header__details + .report-header__details__item + .report-header__details__item__header + %strong= t('disputes.strikes.created_at') + .report-header__details__item__content + %time.formatted{ datetime: @strike.created_at.iso8601, title: l(@strike.created_at) }= l(@strike.created_at) + .report-header__details__item + .report-header__details__item__header + %strong= t('disputes.strikes.recipient') + .report-header__details__item__content + = admin_account_link_to @strike.target_account, path: can?(:show, @strike.target_account) ? admin_account_path(@strike.target_account_id) : ActivityPub::TagManager.instance.url_for(@strike.target_account) + .report-header__details__item + .report-header__details__item__header + %strong= t('disputes.strikes.action_taken') + .report-header__details__item__content + - if @strike.overruled? + %del= t(@strike.action, scope: 'user_mailer.warning.title') + - else + = t(@strike.action, scope: 'user_mailer.warning.title') + - if @strike.report && can?(:show, @strike.report) + .report-header__details__item + .report-header__details__item__header + %strong= t('disputes.strikes.associated_report') + .report-header__details__item__content + = link_to t('admin.reports.report', id: @strike.report.id), admin_report_path(@strike.report) + - if @appeal.persisted? + .report-header__details__item + .report-header__details__item__header + %strong= t('disputes.strikes.appeal_submitted_at') + .report-header__details__item__content + %time.formatted{ datetime: @appeal.created_at.iso8601, title: l(@appeal.created_at) }= l(@appeal.created_at) +%hr.spacer/ + +- if @appeal.persisted? + %h3= t('disputes.strikes.appeal') + + .report-notes + .report-notes__item + = image_tag @appeal.account.avatar.url, class: 'report-notes__item__avatar' + + .report-notes__item__header + %span.username + = link_to @appeal.account.username, can?(:show, @appeal.account) ? admin_account_path(@appeal.account_id) : short_account_url(@appeal.account) + %time{ datetime: @appeal.created_at.iso8601, title: l(@appeal.created_at) } + - if @appeal.created_at.today? + = t('admin.report_notes.today_at', time: l(@appeal.created_at, format: :time)) + - else + = l @appeal.created_at.to_date + + .report-notes__item__content + = simple_format(h(@appeal.text)) +- elsif can?(:appeal, @strike) + %h3= t('disputes.strikes.appeals.submit') + + = simple_form_for(@appeal, url: disputes_strike_appeal_path(@strike)) do |f| + .fields-group + = f.input :text, wrapper: :with_label, input_html: { maxlength: 500 } + + .actions + = f.button :button, t('disputes.strikes.appeals.submit'), type: :submit diff --git a/app/views/settings/preferences/notifications/show.html.haml b/app/views/settings/preferences/notifications/show.html.haml index d7cc1ed5d1..223e5d7407 100644 --- a/app/views/settings/preferences/notifications/show.html.haml +++ b/app/views/settings/preferences/notifications/show.html.haml @@ -21,6 +21,7 @@ - if current_user.staff? = ff.input :report, as: :boolean, wrapper: :with_label + = ff.input :appeal, as: :boolean, wrapper: :with_label = ff.input :pending_account, as: :boolean, wrapper: :with_label = ff.input :trending_tag, as: :boolean, wrapper: :with_label diff --git a/app/views/statuses/_detailed_status.html.haml b/app/views/statuses/_detailed_status.html.haml index cd5ed52af4..1922f53ce3 100644 --- a/app/views/statuses/_detailed_status.html.haml +++ b/app/views/statuses/_detailed_status.html.haml @@ -49,7 +49,7 @@ %span.detailed-status__visibility-icon = visibility_icon status · - - if status.application && @account.user&.setting_show_application + - if status.application && status.account.user&.setting_show_application - if status.application.website.blank? %strong.detailed-status__application= status.application.name - else diff --git a/app/views/user_mailer/appeal_approved.html.haml b/app/views/user_mailer/appeal_approved.html.haml new file mode 100644 index 0000000000..962cab2e2c --- /dev/null +++ b/app/views/user_mailer/appeal_approved.html.haml @@ -0,0 +1,59 @@ +%table.email-table{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.email-body + .email-container + %table.content-section{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.content-cell.hero + .email-row + .col-6 + %table.column{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.column-cell.text-center.padded + %table.hero-icon{ align: 'center', cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td + = image_tag full_pack_url('media/images/mailer/icon_done.png'), alt: '' + + %h1= t 'user_mailer.appeal_approved.title' + +%table.email-table{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.email-body + .email-container + %table.content-section{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.content-cell.content-start + .email-row + .col-6 + %table.column{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.column-cell.text-center + %p= t 'user_mailer.appeal_approved.explanation', appeal_date: l(@appeal.created_at), strike_date: l(@appeal.strike.created_at) + +%table.email-table{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.email-body + .email-container + %table.content-section{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.content-cell + %table.column{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.column-cell.button-cell + %table.button{ align: 'center', cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.button-primary + = link_to root_url do + %span= t 'user_mailer.appeal_approved.action' diff --git a/app/views/user_mailer/appeal_approved.text.erb b/app/views/user_mailer/appeal_approved.text.erb new file mode 100644 index 0000000000..290fa24c36 --- /dev/null +++ b/app/views/user_mailer/appeal_approved.text.erb @@ -0,0 +1,7 @@ +<%= t 'user_mailer.appeal_approved.title' %> + +=== + +<%= t 'user_mailer.appeal_approved.explanation', appeal_date: l(@appeal.created_at), strike_date: l(@appeal.strike.created_at) %> + +=> <%= root_url %> diff --git a/app/views/user_mailer/appeal_rejected.html.haml b/app/views/user_mailer/appeal_rejected.html.haml new file mode 100644 index 0000000000..75cd9d023b --- /dev/null +++ b/app/views/user_mailer/appeal_rejected.html.haml @@ -0,0 +1,59 @@ +%table.email-table{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.email-body + .email-container + %table.content-section{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.content-cell.hero + .email-row + .col-6 + %table.column{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.column-cell.text-center.padded + %table.hero-icon{ align: 'center', cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td + = image_tag full_pack_url('media/images/mailer/icon_warning.png'), alt: '' + + %h1= t 'user_mailer.appeal_rejected.title' + +%table.email-table{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.email-body + .email-container + %table.content-section{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.content-cell.content-start + .email-row + .col-6 + %table.column{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.column-cell.text-center + %p= t 'user_mailer.appeal_rejected.explanation', appeal_date: l(@appeal.created_at), strike_date: l(@appeal.strike.created_at) + +%table.email-table{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.email-body + .email-container + %table.content-section{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.content-cell + %table.column{ cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.column-cell.button-cell + %table.button{ align: 'center', cellspacing: 0, cellpadding: 0 } + %tbody + %tr + %td.button-primary + = link_to root_url do + %span= t 'user_mailer.appeal_approved.action' diff --git a/app/views/user_mailer/appeal_rejected.text.erb b/app/views/user_mailer/appeal_rejected.text.erb new file mode 100644 index 0000000000..f47a768181 --- /dev/null +++ b/app/views/user_mailer/appeal_rejected.text.erb @@ -0,0 +1,7 @@ +<%= t 'user_mailer.appeal_rejected.title' %> + +=== + +<%= t 'user_mailer.appeal_rejected.explanation', appeal_date: l(@appeal.created_at), strike_date: l(@appeal.strike.created_at) %> + +=> <%= root_url %> diff --git a/app/views/user_mailer/warning.html.haml b/app/views/user_mailer/warning.html.haml index bda1fef6cf..b308e18f7b 100644 --- a/app/views/user_mailer/warning.html.haml +++ b/app/views/user_mailer/warning.html.haml @@ -77,8 +77,8 @@ %tbody %tr %td.button-primary - = link_to about_more_url do - %span= t 'user_mailer.warning.review_server_policies' + = link_to disputes_strike_url(@warning) do + %span= t 'user_mailer.warning.appeal' %table.email-table{ cellspacing: 0, cellpadding: 0 } %tbody @@ -95,4 +95,4 @@ %tbody %tr %td.column-cell.text-center - %p= t 'user_mailer.warning.get_in_touch', instance: @instance + %p= t 'user_mailer.warning.appeal_description', instance: @instance diff --git a/config/brakeman.ignore b/config/brakeman.ignore index 4245b71924..6ffe12ae06 100644 --- a/config/brakeman.ignore +++ b/config/brakeman.ignore @@ -1,25 +1,5 @@ { "ignored_warnings": [ - { - "warning_type": "SQL Injection", - "warning_code": 0, - "fingerprint": "04dbbc249b989db2e0119bbb0f59c9818e12889d2b97c529cdc0b1526002ba4b", - "check_name": "SQL", - "message": "Possible SQL injection", - "file": "app/models/report.rb", - "line": 113, - "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", - "code": "Admin::ActionLog.from(\"(#{[Admin::ActionLog.where(:target_type => \"Report\", :target_id => id, :created_at => ((created_at..updated_at))).unscope(:order), Admin::ActionLog.where(:target_type => \"Account\", :target_id => target_account_id, :created_at => ((created_at..updated_at))).unscope(:order), Admin::ActionLog.where(:target_type => \"Status\", :target_id => status_ids, :created_at => ((created_at..updated_at))).unscope(:order)].map do\n \"(#{query.to_sql})\"\n end.join(\" UNION ALL \")}) AS admin_action_logs\")", - "render_path": null, - "location": { - "type": "method", - "class": "Report", - "method": "history" - }, - "user_input": "Admin::ActionLog.where(:target_type => \"Status\", :target_id => status_ids, :created_at => ((created_at..updated_at))).unscope(:order)", - "confidence": "High", - "note": "" - }, { "warning_type": "SQL Injection", "warning_code": 0, @@ -27,7 +7,7 @@ "check_name": "SQL", "message": "Possible SQL injection", "file": "app/models/status.rb", - "line": 100, + "line": 104, "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", "code": "result.joins(\"INNER JOIN statuses_tags t#{id} ON t#{id}.status_id = statuses.id AND t#{id}.tag_id = #{id}\")", "render_path": null, @@ -107,7 +87,7 @@ "check_name": "PermitAttributes", "message": "Potentially dangerous key allowed for mass assignment", "file": "app/controllers/api/v1/admin/reports_controller.rb", - "line": 78, + "line": 90, "link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/", "code": "params.permit(:resolved, :account_id, :target_account_id)", "render_path": null, @@ -140,6 +120,36 @@ "confidence": "Medium", "note": "" }, + { + "warning_type": "Cross-Site Scripting", + "warning_code": 2, + "fingerprint": "afad51718ae373b2f19d2513029fd2afccf58b9148e475934bc6a162ee33c352", + "check_name": "CrossSiteScripting", + "message": "Unescaped model attribute", + "file": "app/views/admin/disputes/appeals/_appeal.html.haml", + "line": 7, + "link": "https://brakemanscanner.org/docs/warning_types/cross_site_scripting", + "code": "t((Unresolved Model).new.strike.action, :scope => \"admin.strikes.actions\", :name => content_tag(:span, (Unresolved Model).new.strike.account.username, :class => \"username\"), :target => content_tag(:span, (Unresolved Model).new.account.acct, :class => \"target\"))", + "render_path": [ + { + "type": "template", + "name": "admin/disputes/appeals/index", + "line": 16, + "file": "app/views/admin/disputes/appeals/index.html.haml", + "rendered": { + "name": "admin/disputes/appeals/_appeal", + "file": "app/views/admin/disputes/appeals/_appeal.html.haml" + } + } + ], + "location": { + "type": "template", + "template": "admin/disputes/appeals/_appeal" + }, + "user_input": "(Unresolved Model).new.strike", + "confidence": "Weak", + "note": "" + }, { "warning_type": "Redirect", "warning_code": 18, @@ -194,7 +204,7 @@ { "type": "template", "name": "admin/trends/links/index", - "line": 37, + "line": 39, "file": "app/views/admin/trends/links/index.html.haml", "rendered": { "name": "admin/trends/links/_preview_card", @@ -213,13 +223,13 @@ { "warning_type": "Mass Assignment", "warning_code": 105, - "fingerprint": "e867661b2c9812bc8b75a5df12b28e2a53ab97015de0638b4e732fe442561b28", + "fingerprint": "f9de0ca4b04ae4b51b74d98db14dcbb6dae6809e627b58e711019cf9b4a47866", "check_name": "PermitAttributes", "message": "Potentially dangerous key allowed for mass assignment", "file": "app/controllers/api/v1/reports_controller.rb", "line": 36, "link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/", - "code": "params.permit(:account_id, :comment, :forward, :status_ids => ([]))", + "code": "params.permit(:account_id, :comment, :category, :forward, :status_ids => ([]), :rule_ids => ([]))", "render_path": null, "location": { "type": "method", @@ -231,6 +241,6 @@ "note": "" } ], - "updated": "2021-11-14 05:26:09 +0100", - "brakeman_version": "5.1.2" + "updated": "2022-02-13 02:24:12 +0100", + "brakeman_version": "5.2.1" } diff --git a/config/locales/en.yml b/config/locales/en.yml index 1809f123ed..05c64e18a7 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -94,7 +94,6 @@ en: account_moderation_notes: create: Leave note created_msg: Moderation note successfully created! - delete: Delete destroyed_msg: Moderation note successfully destroyed! accounts: add_email_domain_block: Block e-mail domain @@ -163,6 +162,11 @@ en: not_subscribed: Not subscribed pending: Pending review perform_full_suspension: Suspend + previous_strikes: Previous strikes + previous_strikes_description_html: + one: This account has one strike. + other: This account has %{count} strikes. + zero: This account is in good standing. promote: Promote protocol: Protocol public: Public @@ -227,6 +231,7 @@ en: whitelisted: Allowed for federation action_logs: action_types: + approve_appeal: Approve Appeal approve_user: Approve User assigned_to_self_report: Assign Report change_email_user: Change E-mail for User @@ -258,6 +263,7 @@ en: enable_user: Enable User memorialize_account: Memorialize Account promote_user: Promote User + reject_appeal: Reject Appeal reject_user: Reject User remove_avatar_user: Remove Avatar reopen_report: Reopen Report @@ -276,6 +282,7 @@ en: update_domain_block: Update Domain Block update_status: Update Post actions: + approve_appeal_html: "%{name} approved moderation decision appeal from %{target}" approve_user_html: "%{name} approved sign-up from %{target}" assigned_to_self_report_html: "%{name} assigned report %{target} to themselves" change_email_user_html: "%{name} changed the e-mail address of user %{target}" @@ -307,6 +314,7 @@ en: enable_user_html: "%{name} enabled login for user %{target}" memorialize_account_html: "%{name} turned %{target}'s account into a memoriam page" promote_user_html: "%{name} promoted user %{target}" + reject_appeal_html: "%{name} rejected moderation decision appeal from %{target}" reject_user_html: "%{name} rejected sign-up from %{target}" remove_avatar_user_html: "%{name} removed %{target}'s avatar" reopen_report_html: "%{name} reopened report %{target}" @@ -385,6 +393,9 @@ en: media_storage: Media storage new_users: new users opened_reports: reports opened + pending_appeals_html: + one: "1 pending appeal" + other: "%{count} pending appeals" pending_reports_html: one: "1 pending report" other: "%{count} pending reports" @@ -402,6 +413,10 @@ en: top_languages: Top active languages top_servers: Top active servers website: Website + disputes: + appeals: + empty: No appeals found. + title: Appeals domain_allows: add_new: Allow federation with domain created_msg: Domain has been successfully allowed for federation @@ -720,6 +735,16 @@ en: no_status_selected: No posts were changed as none were selected title: Account posts with_media: With media + strikes: + actions: + delete_statuses: "%{name} deleted %{target}'s posts" + disable: "%{name} froze %{target}'s account" + none: "%{name} sent a warning to %{target}" + sensitive: "%{name} marked %{target}'s account as sensitive" + silence: "%{name} limited %{target}'s account" + suspend: "%{name} suspended %{target}'s account" + appeal_approved: Appealed + appeal_pending: Appeal pending system_checks: database_schema_check: message_html: There are pending database migrations. Please run them to ensure the application behaves as expected @@ -781,6 +806,17 @@ en: empty: You haven't defined any warning presets yet. title: Manage warning presets admin_mailer: + new_appeal: + actions: + delete_statuses: to delete their posts + disable: to freeze their account + none: a warning + sensitive: to mark their account as sensitive + silence: to limit their account + suspend: to suspend their account + body: "%{target} is appealing a moderation decision by %{action_taken_by} from %{date}, which was %{type}. They wrote:" + next_steps: You can approve the appeal to undo the moderation decision, or ignore it. + subject: "%{username} is appealing a moderation decision on %{instance}" new_pending_account: body: The details of the new account are below. You can approve or reject this application. subject: New account up for review on %{instance} (%{username}) @@ -871,7 +907,6 @@ en: status: account_status: Account status confirming: Waiting for e-mail confirmation to be completed. - functional: Your account is fully operational. pending: Your application is pending review by our staff. This may take some time. You will receive an e-mail if your application is approved. redirecting_to: Your account is inactive because it is currently redirecting to %{acct}. too_fast: Form submitted too fast, try again. @@ -937,6 +972,32 @@ en: directory: Profile directory explanation: Discover users based on their interests explore_mastodon: Explore %{title} + disputes: + strikes: + action_taken: Action taken + appeal: Appeal + appeal_approved: This strike has been successfully appealed and is no longer valid + appeal_rejected: The appeal has been rejected + appeal_submitted_at: Appeal submitted + appealed_msg: Your appeal has been submitted. If it is approved, you will be notified. + appeals: + submit: Submit appeal + associated_report: Associated report + created_at: Dated + recipient: Addressed to + status: 'Post #%{id}' + status_removed: Post already removed from system + title: "%{action} from %{date}" + title_actions: + delete_statuses: Post removal + disable: Freezing of account + none: Warning + sensitive: Marking as sensitive of account + silence: Limitation of account + suspend: Suspension of account + your_appeal_approved: Your appeal has been approved + your_appeal_pending: You have submitted an appeal + your_appeal_rejected: Your appeal has been rejected domain_validator: invalid_domain: is not a valid domain name errors: @@ -1501,6 +1562,15 @@ en: recovery_instructions_html: If you ever lose access to your phone, you can use one of the recovery codes below to regain access to your account. Keep the recovery codes safe. For example, you may print them and store them with other important documents. webauthn: Security keys user_mailer: + appeal_approved: + action: Go to your account + explanation: The appeal of the strike against your account on %{strike_date} that you submitted on %{appeal_date} has been approved. Your account is once again in good standing. + subject: Your appeal from %{date} has been approved + title: Appeal approved + appeal_rejected: + explanation: The appeal of the strike against your account on %{strike_date} that you submitted on %{appeal_date} has been rejected. + subject: Your appeal from %{date} has been rejected + title: Appeal rejected backup_ready: explanation: You requested a full backup of your Mastodon account. It's now ready for download! subject: Your archive is ready for download @@ -1512,6 +1582,8 @@ en: subject: Please confirm attempted sign in title: Sign in attempt warning: + appeal: Submit an appeal + appeal_description: If you believe this is an error, you can submit an appeal to the staff of %{instance}. categories: spam: Spam violation: Content violates the following community guidelines @@ -1523,7 +1595,6 @@ en: suspend: You can no longer use your account, and your profile and other data are no longer accessible. You can still login to request a backup of your data until the data is fully removed in about 30 days, but we will retain some basic data to prevent you from evading the suspension. get_in_touch: If you believe this is an error, you can reply to this e-mail to get in touch with the staff of %{instance}. reason: 'Reason:' - review_server_policies: Review server policies statuses: 'Posts that have been found in violation:' subject: delete_statuses: Your posts on %{acct} have been removed diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index d6376782d4..03eefd0d5a 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -27,6 +27,8 @@ en: scheduled_at: Leave blank to publish the announcement immediately starts_at: Optional. In case your announcement is bound to a specific time range text: You can use post syntax. Please be mindful of the space the announcement will take up on the user's screen + appeal: + text: You can only appeal a strike once defaults: autofollow: People who sign up through the invite will automatically follow you avatar: PNG, GIF or JPG. At most %{size}. Will be downscaled to %{dimensions}px @@ -119,6 +121,8 @@ en: scheduled_at: Schedule publication starts_at: Start of event text: Announcement + appeal: + text: Explain why this decision should be reversed defaults: autofollow: Invite to follow your account avatar: Avatar @@ -197,6 +201,7 @@ en: sign_up_requires_approval: Limit sign-ups severity: Rule notification_emails: + appeal: Someone appeals a moderator decision digest: Send digest e-mails favourite: Someone favourited your post follow: Someone followed you @@ -204,8 +209,8 @@ en: mention: Someone mentioned you pending_account: New account needs review reblog: Someone boosted your post - report: A new report is submitted - trending_tag: A new trend requires approval + report: New report is submitted + trending_tag: New trend requires review rule: text: Rule tag: diff --git a/config/navigation.rb b/config/navigation.rb index fc03a2a778..3fc3747d59 100644 --- a/config/navigation.rb +++ b/config/navigation.rb @@ -20,7 +20,7 @@ SimpleNavigation::Configuration.run do |navigation| n.item :statuses_cleanup, safe_join([fa_icon('history fw'), t('settings.statuses_cleanup')]), statuses_cleanup_url, if: -> { current_user.functional? } n.item :security, safe_join([fa_icon('lock fw'), t('settings.account')]), edit_user_registration_url do |s| - s.item :password, safe_join([fa_icon('lock fw'), t('settings.account_settings')]), edit_user_registration_url, highlights_on: %r{/auth/edit|/settings/delete|/settings/migration|/settings/aliases|/settings/login_activities} + s.item :password, safe_join([fa_icon('lock fw'), t('settings.account_settings')]), edit_user_registration_url, highlights_on: %r{/auth/edit|/settings/delete|/settings/migration|/settings/aliases|/settings/login_activities|^/disputes} s.item :two_factor_authentication, safe_join([fa_icon('mobile fw'), t('settings.two_factor_authentication')]), settings_two_factor_authentication_methods_url, highlights_on: %r{/settings/two_factor_authentication|/settings/otp_authentication|/settings/security_keys} s.item :authorized_apps, safe_join([fa_icon('list fw'), t('settings.authorized_apps')]), oauth_authorized_applications_url end @@ -41,7 +41,7 @@ SimpleNavigation::Configuration.run do |navigation| n.item :moderation, safe_join([fa_icon('gavel fw'), t('moderation.title')]), admin_reports_url, if: proc { current_user.staff? } do |s| s.item :action_logs, safe_join([fa_icon('bars fw'), t('admin.action_logs.title')]), admin_action_logs_url s.item :reports, safe_join([fa_icon('flag fw'), t('admin.reports.title')]), admin_reports_url, highlights_on: %r{/admin/reports} - s.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_url(origin: 'local'), highlights_on: %r{/admin/accounts|/admin/pending_accounts} + s.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_url(origin: 'local'), highlights_on: %r{/admin/accounts|/admin/pending_accounts|/admin/disputes} s.item :invites, safe_join([fa_icon('user-plus fw'), t('admin.invites.title')]), admin_invites_path s.item :follow_recommendations, safe_join([fa_icon('user-plus fw'), t('admin.follow_recommendations.title')]), admin_follow_recommendations_path, highlights_on: %r{/admin/follow_recommendations} s.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_url(limited: whitelist_mode? ? nil : '1'), highlights_on: %r{/admin/instances|/admin/domain_blocks|/admin/domain_allows}, if: -> { current_user.admin? } diff --git a/config/routes.rb b/config/routes.rb index 5edb36519a..f59f2a5bba 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -164,6 +164,12 @@ Rails.application.routes.draw do resources :login_activities, only: [:index] end + namespace :disputes do + resources :strikes, only: [:show] do + resource :appeal, only: [:create] + end + end + resources :media, only: [:show] do get :player end @@ -324,6 +330,15 @@ Rails.application.routes.draw do end end end + + namespace :disputes do + resources :appeals, only: [:index] do + member do + post :approve + post :reject + end + end + end end get '/admin', to: redirect('/admin/dashboard', status: 302) diff --git a/config/settings.yml b/config/settings.yml index 06cee25324..e63788ba2f 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -48,6 +48,7 @@ defaults: &defaults report: true pending_account: true trending_tag: true + appeal: true interactions: must_be_follower: false must_be_following: false diff --git a/db/migrate/20220124141035_create_appeals.rb b/db/migrate/20220124141035_create_appeals.rb new file mode 100644 index 0000000000..afb3efbd53 --- /dev/null +++ b/db/migrate/20220124141035_create_appeals.rb @@ -0,0 +1,14 @@ +class CreateAppeals < ActiveRecord::Migration[6.1] + def change + create_table :appeals do |t| + t.belongs_to :account, null: false, foreign_key: { on_delete: :cascade } + t.belongs_to :account_warning, null: false, foreign_key: { on_delete: :cascade }, index: { unique: true } + t.text :text, null: false, default: '' + t.datetime :approved_at + t.belongs_to :approved_by_account, foreign_key: { to_table: :accounts, on_delete: :nullify } + t.datetime :rejected_at + t.belongs_to :rejected_by_account, foreign_key: { to_table: :accounts, on_delete: :nullify } + t.timestamps + end + end +end diff --git a/db/migrate/20220210153119_add_overruled_at_to_account_warnings.rb b/db/migrate/20220210153119_add_overruled_at_to_account_warnings.rb new file mode 100644 index 0000000000..a082da774c --- /dev/null +++ b/db/migrate/20220210153119_add_overruled_at_to_account_warnings.rb @@ -0,0 +1,5 @@ +class AddOverruledAtToAccountWarnings < ActiveRecord::Migration[6.1] + def change + add_column :account_warnings, :overruled_at, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index fd4633d695..8842dcd8c0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2022_01_18_183123) do +ActiveRecord::Schema.define(version: 2022_02_10_153119) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -135,6 +135,7 @@ ActiveRecord::Schema.define(version: 2022_01_18_183123) do t.datetime "updated_at", null: false t.bigint "report_id" t.string "status_ids", array: true + t.datetime "overruled_at" t.index ["account_id"], name: "index_account_warnings_on_account_id" t.index ["target_account_id"], name: "index_account_warnings_on_target_account_id" end @@ -243,6 +244,22 @@ ActiveRecord::Schema.define(version: 2022_01_18_183123) do t.bigint "status_ids", array: true end + create_table "appeals", force: :cascade do |t| + t.bigint "account_id", null: false + t.bigint "account_warning_id", null: false + t.text "text", default: "", null: false + t.datetime "approved_at" + t.bigint "approved_by_account_id" + t.datetime "rejected_at" + t.bigint "rejected_by_account_id" + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + t.index ["account_id"], name: "index_appeals_on_account_id" + t.index ["account_warning_id"], name: "index_appeals_on_account_warning_id", unique: true + t.index ["approved_by_account_id"], name: "index_appeals_on_approved_by_account_id" + t.index ["rejected_by_account_id"], name: "index_appeals_on_rejected_by_account_id" + end + create_table "backups", force: :cascade do |t| t.bigint "user_id" t.string "dump_file_name" @@ -1031,6 +1048,10 @@ ActiveRecord::Schema.define(version: 2022_01_18_183123) do add_foreign_key "announcement_reactions", "accounts", on_delete: :cascade add_foreign_key "announcement_reactions", "announcements", on_delete: :cascade add_foreign_key "announcement_reactions", "custom_emojis", on_delete: :cascade + add_foreign_key "appeals", "account_warnings", on_delete: :cascade + add_foreign_key "appeals", "accounts", column: "approved_by_account_id", on_delete: :nullify + add_foreign_key "appeals", "accounts", column: "rejected_by_account_id", on_delete: :nullify + add_foreign_key "appeals", "accounts", on_delete: :cascade add_foreign_key "backups", "users", on_delete: :nullify add_foreign_key "blocks", "accounts", column: "target_account_id", name: "fk_9571bfabc1", on_delete: :cascade add_foreign_key "blocks", "accounts", name: "fk_4269e03e65", on_delete: :cascade diff --git a/spec/controllers/admin/disputes/appeals_controller_spec.rb b/spec/controllers/admin/disputes/appeals_controller_spec.rb new file mode 100644 index 0000000000..6a06f94069 --- /dev/null +++ b/spec/controllers/admin/disputes/appeals_controller_spec.rb @@ -0,0 +1,53 @@ +require 'rails_helper' + +RSpec.describe Admin::Disputes::AppealsController, type: :controller do + render_views + + before { sign_in current_user, scope: :user } + + let(:target_account) { Fabricate(:account) } + let(:strike) { Fabricate(:account_warning, target_account: target_account, action: :suspend) } + let(:appeal) { Fabricate(:appeal, strike: strike, account: target_account) } + + before do + target_account.suspend! + end + + describe 'POST #approve' do + let(:current_user) { Fabricate(:user, admin: true) } + + before do + allow(UserMailer).to receive(:appeal_approved).and_return(double('email', deliver_later: nil)) + post :approve, params: { id: appeal.id } + end + + it 'unsuspends a suspended account' do + expect(target_account.reload.suspended?).to be false + end + + it 'redirects back to the strike page' do + expect(response).to redirect_to(disputes_strike_path(appeal.strike)) + end + + it 'notifies target account about approved appeal' do + expect(UserMailer).to have_received(:appeal_approved).with(target_account.user, appeal) + end + end + + describe 'POST #reject' do + let(:current_user) { Fabricate(:user, admin: true) } + + before do + allow(UserMailer).to receive(:appeal_rejected).and_return(double('email', deliver_later: nil)) + post :reject, params: { id: appeal.id } + end + + it 'redirects back to the strike page' do + expect(response).to redirect_to(disputes_strike_path(appeal.strike)) + end + + it 'notifies target account about rejected appeal' do + expect(UserMailer).to have_received(:appeal_rejected).with(target_account.user, appeal) + end + end +end diff --git a/spec/controllers/disputes/appeals_controller_spec.rb b/spec/controllers/disputes/appeals_controller_spec.rb new file mode 100644 index 0000000000..faa571fc9e --- /dev/null +++ b/spec/controllers/disputes/appeals_controller_spec.rb @@ -0,0 +1,27 @@ +require 'rails_helper' + +RSpec.describe Disputes::AppealsController, type: :controller do + render_views + + before { sign_in current_user, scope: :user } + + let!(:admin) { Fabricate(:user, admin: true) } + + describe '#create' do + let(:current_user) { Fabricate(:user) } + let(:strike) { Fabricate(:account_warning, target_account: current_user.account) } + + before do + allow(AdminMailer).to receive(:new_appeal).and_return(double('email', deliver_later: nil)) + post :create, params: { strike_id: strike.id, appeal: { text: 'Foo' } } + end + + it 'notifies staff about new appeal' do + expect(AdminMailer).to have_received(:new_appeal).with(admin.account, Appeal.last) + end + + it 'redirects back to the strike page' do + expect(response).to redirect_to(disputes_strike_path(strike.id)) + end + end +end diff --git a/spec/controllers/disputes/strikes_controller_spec.rb b/spec/controllers/disputes/strikes_controller_spec.rb new file mode 100644 index 0000000000..157f9ec3c7 --- /dev/null +++ b/spec/controllers/disputes/strikes_controller_spec.rb @@ -0,0 +1,30 @@ +require 'rails_helper' + +RSpec.describe Disputes::StrikesController, type: :controller do + render_views + + before { sign_in current_user, scope: :user } + + describe '#show' do + let(:current_user) { Fabricate(:user) } + let(:strike) { Fabricate(:account_warning, target_account: current_user.account) } + + before do + get :show, params: { id: strike.id } + end + + context 'when meant for the user' do + it 'returns http success' do + expect(response).to have_http_status(:success) + end + end + + context 'when meant for a different user' do + let(:strike) { Fabricate(:account_warning) } + + it 'returns http forbidden' do + expect(response).to have_http_status(:forbidden) + end + end + end +end diff --git a/spec/fabricators/account_warning_fabricator.rb b/spec/fabricators/account_warning_fabricator.rb index db161d4464..72fe835d9a 100644 --- a/spec/fabricators/account_warning_fabricator.rb +++ b/spec/fabricators/account_warning_fabricator.rb @@ -1,5 +1,6 @@ Fabricator(:account_warning) do - account nil - target_account nil - text "MyText" + account + target_account(fabricator: :account) + text { Faker::Lorem.paragraph } + action 'suspend' end diff --git a/spec/fabricators/appeal_fabricator.rb b/spec/fabricators/appeal_fabricator.rb new file mode 100644 index 0000000000..339363822d --- /dev/null +++ b/spec/fabricators/appeal_fabricator.rb @@ -0,0 +1,5 @@ +Fabricator(:appeal) do + strike(fabricator: :account_warning) + account { |attrs| attrs[:strike].target_account } + text { Faker::Lorem.paragraph } +end diff --git a/spec/mailers/previews/admin_mailer_preview.rb b/spec/mailers/previews/admin_mailer_preview.rb index 75ffbbf40f..9c0372b47f 100644 --- a/spec/mailers/previews/admin_mailer_preview.rb +++ b/spec/mailers/previews/admin_mailer_preview.rb @@ -15,4 +15,9 @@ class AdminMailerPreview < ActionMailer::Preview def new_trending_links AdminMailer.new_trending_links(Account.first, PreviewCard.limit(3)) end + + # Preview this email at http://localhost:3000/rails/mailers/admin_mailer/new_appeal + def new_appeal + AdminMailer.new_appeal(Account.first, Appeal.first) + end end diff --git a/spec/mailers/previews/user_mailer_preview.rb b/spec/mailers/previews/user_mailer_preview.rb index 69b9b971ee..8de7d86696 100644 --- a/spec/mailers/previews/user_mailer_preview.rb +++ b/spec/mailers/previews/user_mailer_preview.rb @@ -82,6 +82,11 @@ class UserMailerPreview < ActionMailer::Preview UserMailer.warning(User.first, AccountWarning.last) end + # Preview this email at http://localhost:3000/rails/mailers/user_mailer/appeal_approved + def appeal_approved + UserMailer.appeal_approved(User.first, Appeal.last) + end + # Preview this email at http://localhost:3000/rails/mailers/user_mailer/sign_in_token def sign_in_token UserMailer.sign_in_token(User.first.tap { |user| user.generate_sign_in_token }, '127.0.0.1', 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:75.0) Gecko/20100101 Firefox/75.0', Time.now.utc) diff --git a/spec/models/appeal_spec.rb b/spec/models/appeal_spec.rb new file mode 100644 index 0000000000..14062dc4f4 --- /dev/null +++ b/spec/models/appeal_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Appeal, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end From 5b0102a0fa62014b91f807e42e753eeaa028de34 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Feb 2022 21:49:40 +0100 Subject: [PATCH 12/35] Bump dotenv from 10.0.0 to 16.0.0 (#17476) Bumps [dotenv](https://github.com/motdotla/dotenv) from 10.0.0 to 16.0.0. - [Release notes](https://github.com/motdotla/dotenv/releases) - [Changelog](https://github.com/motdotla/dotenv/blob/master/CHANGELOG.md) - [Commits](https://github.com/motdotla/dotenv/compare/v10.0.0...v16.0.0) --- updated-dependencies: - dependency-name: dotenv dependency-type: direct:production update-type: version-update:semver-major ... 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 017bbc0539..5f642d7e6a 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "css-loader": "^5.2.7", "cssnano": "^4.1.11", "detect-passive-events": "^2.0.3", - "dotenv": "^10.0.0", + "dotenv": "^16.0.0", "emoji-mart": "npm:emoji-mart-lazyload", "es6-symbol": "^3.1.3", "escape-html": "^1.0.3", diff --git a/yarn.lock b/yarn.lock index e9bcf882c8..20e670656c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4073,10 +4073,10 @@ dot-prop@^5.2.0: dependencies: is-obj "^2.0.0" -dotenv@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" - integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== +dotenv@^16.0.0: + version "16.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.0.tgz#c619001253be89ebb638d027b609c75c26e47411" + integrity sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q== duplexer@^0.1.2: version "0.1.2" From a6ebb358448c46691bca4adfc97b2df97ce45626 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Feb 2022 11:05:18 +0900 Subject: [PATCH 13/35] Bump @babel/runtime from 7.17.0 to 7.17.2 (#17544) Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.17.0 to 7.17.2. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.17.2/packages/babel-runtime) --- updated-dependencies: - dependency-name: "@babel/runtime" dependency-type: direct:production update-type: version-update:semver-patch ... 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 5f642d7e6a..005808a0a6 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "@babel/plugin-transform-runtime": "^7.17.0", "@babel/preset-env": "^7.16.11", "@babel/preset-react": "^7.16.7", - "@babel/runtime": "^7.17.0", + "@babel/runtime": "^7.17.2", "@gamestdio/websocket": "^0.3.2", "@github/webauthn-json": "^0.5.7", "@rails/ujs": "^6.1.4", diff --git a/yarn.lock b/yarn.lock index 20e670656c..a72b015e9f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1024,10 +1024,10 @@ dependencies: regenerator-runtime "^0.12.0" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.0", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.0.tgz#b8d142fc0f7664fb3d9b5833fd40dcbab89276c0" - integrity sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ== +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.2", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": + version "7.17.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.2.tgz#66f68591605e59da47523c631416b18508779941" + integrity sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw== dependencies: regenerator-runtime "^0.13.4" From 3a5f4b6cf0c09963f850a459e502222791d7001f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Feb 2022 11:06:06 +0900 Subject: [PATCH 14/35] Bump babel-jest from 27.5.0 to 27.5.1 (#17549) Bumps [babel-jest](https://github.com/facebook/jest/tree/HEAD/packages/babel-jest) from 27.5.0 to 27.5.1. - [Release notes](https://github.com/facebook/jest/releases) - [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md) - [Commits](https://github.com/facebook/jest/commits/v27.5.1/packages/babel-jest) --- updated-dependencies: - dependency-name: babel-jest dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 120 +-------------------------------------------------- 2 files changed, 2 insertions(+), 120 deletions(-) diff --git a/package.json b/package.json index 005808a0a6..d5c1f96513 100644 --- a/package.json +++ b/package.json @@ -175,7 +175,7 @@ "@testing-library/jest-dom": "^5.16.2", "@testing-library/react": "^12.1.2", "babel-eslint": "^10.1.0", - "babel-jest": "^27.5.0", + "babel-jest": "^27.5.1", "eslint": "^7.32.0", "eslint-plugin-import": "~2.25.4", "eslint-plugin-jsx-a11y": "~6.5.1", diff --git a/yarn.lock b/yarn.lock index a72b015e9f..79a900a36d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1338,27 +1338,6 @@ jest-haste-map "^27.5.1" jest-runtime "^27.5.1" -"@jest/transform@^27.5.0": - version "27.5.0" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.5.0.tgz#a4941e69ac51e8aa9a255ff4855b564c228c400b" - integrity sha512-yXUy/iO3TH1itxJ9BF7LLjuXt8TtgtjAl0PBQbUaCvRa+L0yYBob6uayW9dFRX/CDQweouLhvmXh44zRiaB+yA== - dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^27.5.0" - babel-plugin-istanbul "^6.1.1" - chalk "^4.0.0" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.2.9" - jest-haste-map "^27.5.0" - jest-regex-util "^27.5.0" - jest-util "^27.5.0" - micromatch "^4.0.4" - pirates "^4.0.4" - slash "^3.0.0" - source-map "^0.6.1" - write-file-atomic "^3.0.0" - "@jest/transform@^27.5.1": version "27.5.1" resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.5.1.tgz#6c3501dcc00c4c08915f292a600ece5ecfe1f409" @@ -1390,18 +1369,7 @@ "@types/yargs" "^15.0.0" chalk "^3.0.0" -"@jest/types@^27.0.2", "@jest/types@^27.5.0": - version "27.5.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.0.tgz#6ad04a5c5355fd9f46e5cf761850e0edb3c209dd" - integrity sha512-oDHEp7gwSgA82RZ6pzUL3ugM2njP/lVB1MsxRZNOBk+CoNvh9SpH1lQixPFc/kDlV50v59csiW4HLixWmhmgPQ== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^16.0.0" - chalk "^4.0.0" - -"@jest/types@^27.5.1": +"@jest/types@^27.0.2", "@jest/types@^27.5.1": version "27.5.1" resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80" integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw== @@ -2359,20 +2327,6 @@ babel-eslint@^10.1.0: eslint-visitor-keys "^1.0.0" resolve "^1.12.0" -babel-jest@^27.5.0: - version "27.5.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.0.tgz#c653985241af3c76f59d70d65a570860c2594a50" - integrity sha512-puhCyvBTNLevhbd1oyw6t3gWBicWoUARQYKCBB/B1moif17NbyhxbsfadqZIw8zfJJD+W7Vw0Nb20pEjLxkXqQ== - dependencies: - "@jest/transform" "^27.5.0" - "@jest/types" "^27.5.0" - "@types/babel__core" "^7.1.14" - babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^27.5.0" - chalk "^4.0.0" - graceful-fs "^4.2.9" - slash "^3.0.0" - babel-jest@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444" @@ -2415,16 +2369,6 @@ babel-plugin-istanbul@^6.1.1: istanbul-lib-instrument "^5.0.4" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^27.5.0: - version "27.5.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.0.tgz#8fdf07835f2165a068de3ce95fd7749a89801b51" - integrity sha512-ztwNkHl+g1GaoQcb8f2BER4C3LMvSXuF7KVqtUioXQgScSEnkl6lLgCILUYIR+CPTwL8H3F/PNLze64HPWF9JA== - dependencies: - "@babel/template" "^7.3.3" - "@babel/types" "^7.3.3" - "@types/babel__core" "^7.0.0" - "@types/babel__traverse" "^7.0.6" - babel-plugin-jest-hoist@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz#9be98ecf28c331eb9f5df9c72d6f89deb8181c2e" @@ -2525,14 +2469,6 @@ babel-preset-current-node-syntax@^1.0.0: "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-top-level-await" "^7.8.3" -babel-preset-jest@^27.5.0: - version "27.5.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.5.0.tgz#4e308711c3d2ff1f45cf5d9a23646e37b621fc9f" - integrity sha512-7bfu1cJBlgK/nKfTvMlElzA3jpi6GzDWX3fntnyP2cQSzoi/KUz6ewGlcb3PSRYZGyv+uPnVHY0Im3JbsViqgA== - dependencies: - babel-plugin-jest-hoist "^27.5.0" - babel-preset-current-node-syntax "^1.0.0" - babel-preset-jest@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz#91f10f58034cb7989cb4f962b69fa6eef6a6bc81" @@ -6466,26 +6402,6 @@ jest-get-type@^27.5.1: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== -jest-haste-map@^27.5.0: - version "27.5.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.0.tgz#7cc3a920caf304c89fbfceb5d5717b929873f175" - integrity sha512-0KfckSBEKV+D6e0toXmIj4zzp72EiBnvkC0L+xYxenkLhAdkp2/8tye4AgMzz7Fqb1r8SWtz7+s1UQLrxMBang== - dependencies: - "@jest/types" "^27.5.0" - "@types/graceful-fs" "^4.1.2" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.9" - jest-regex-util "^27.5.0" - jest-serializer "^27.5.0" - jest-util "^27.5.0" - jest-worker "^27.5.0" - micromatch "^4.0.4" - walker "^1.0.7" - optionalDependencies: - fsevents "^2.3.2" - jest-haste-map@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f" @@ -6575,11 +6491,6 @@ jest-pnp-resolver@^1.2.2: resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== -jest-regex-util@^27.5.0: - version "27.5.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.0.tgz#26c26cf15a73edba13cb8930e261443d25ed8608" - integrity sha512-e9LqSd6HsDsqd7KS3rNyYwmQAaG9jq4U3LbnwVxN/y3nNlDzm2OFs596uo9zrUY+AV1opXq6ome78tRDUCRWfA== - jest-regex-util@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95" @@ -6665,14 +6576,6 @@ jest-runtime@^27.5.1: slash "^3.0.0" strip-bom "^4.0.0" -jest-serializer@^27.5.0: - version "27.5.0" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.0.tgz#439a110df27f97a40c114a429b708c2ada15a81f" - integrity sha512-aSDFqQlVXtBH+Zb5dl9mCvTSFkabixk/9P9cpngL4yJKpmEi9USxfDhONFMzJrtftPvZw3PcltUVmtFZTB93rg== - dependencies: - "@types/node" "*" - graceful-fs "^4.2.9" - jest-serializer@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64" @@ -6709,18 +6612,6 @@ jest-snapshot@^27.5.1: pretty-format "^27.5.1" semver "^7.3.2" -jest-util@^27.5.0: - version "27.5.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.0.tgz#0b9540d91b0de65d288f235fa9899e6eeeab8d35" - integrity sha512-FUUqOx0gAzJy3ytatT1Ss372M1kmhczn8x7aE0++11oPGW1FyD/5NjYBI8w1KOXFm6IVjtaZm2szfJJL+CHs0g== - dependencies: - "@jest/types" "^27.5.0" - "@types/node" "*" - chalk "^4.0.0" - ci-info "^3.2.0" - graceful-fs "^4.2.9" - picomatch "^2.2.3" - jest-util@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9" @@ -6767,15 +6658,6 @@ jest-worker@^26.5.0: merge-stream "^2.0.0" supports-color "^7.0.0" -jest-worker@^27.5.0: - version "27.5.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.0.tgz#99ee77e4d06168107c27328bd7f54e74c3a48d59" - integrity sha512-8OEHiPNOPTfaWnJ2SUHM8fmgeGq37uuGsQBvGKQJl1f+6WIy6g7G3fE2ruI5294bUKUI9FaCWt5hDvO8HSwsSg== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^8.0.0" - jest-worker@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" From 36a988e6dbf9e17aeb401f6af7866af34a7989c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Feb 2022 11:06:25 +0900 Subject: [PATCH 15/35] Bump @babel/plugin-proposal-decorators from 7.17.0 to 7.17.2 (#17548) Bumps [@babel/plugin-proposal-decorators](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-proposal-decorators) from 7.17.0 to 7.17.2. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.17.2/packages/babel-plugin-proposal-decorators) --- updated-dependencies: - dependency-name: "@babel/plugin-proposal-decorators" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index d5c1f96513..65eef34039 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "private": true, "dependencies": { "@babel/core": "^7.17.2", - "@babel/plugin-proposal-decorators": "^7.17.0", + "@babel/plugin-proposal-decorators": "^7.17.2", "@babel/plugin-transform-react-inline-elements": "^7.16.7", "@babel/plugin-transform-runtime": "^7.17.0", "@babel/preset-env": "^7.16.11", diff --git a/yarn.lock b/yarn.lock index 79a900a36d..c0bef8fc5b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -91,7 +91,7 @@ browserslist "^4.17.5" semver "^6.3.0" -"@babel/helper-create-class-features-plugin@^7.16.10", "@babel/helper-create-class-features-plugin@^7.16.7", "@babel/helper-create-class-features-plugin@^7.17.0": +"@babel/helper-create-class-features-plugin@^7.16.10", "@babel/helper-create-class-features-plugin@^7.16.7", "@babel/helper-create-class-features-plugin@^7.17.1": version "7.17.1" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.1.tgz#9699f14a88833a7e055ce57dcd3ffdcd25186b21" integrity sha512-JBdSr/LtyYIno/pNnJ75lBcqc3Z1XXujzPanHqjvvrhOA+DTceTFuJi8XjmWTZh4r3fsdfqaCMN0iZemdkxZHQ== @@ -357,12 +357,12 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-syntax-class-static-block" "^7.14.5" -"@babel/plugin-proposal-decorators@^7.17.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.0.tgz#fc0f689fe2535075056c587bc10c176fa9990443" - integrity sha512-JR8HTf3T1CsdMqfENrZ9pqncwsH4sPcvsyDLpvmv8iIbpDmeyBD7HPfGAIqkQph2j5d3B84hTm+m3qHPAedaPw== +"@babel/plugin-proposal-decorators@^7.17.2": + version "7.17.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.2.tgz#c36372ddfe0360cac1ee331a238310bddca11493" + integrity sha512-WH8Z95CwTq/W8rFbMqb9p3hicpt4RX4f0K659ax2VHxgOyT6qQmUaEVEjIh4WR9Eh9NymkVn5vwsrE68fAQNUw== dependencies: - "@babel/helper-create-class-features-plugin" "^7.17.0" + "@babel/helper-create-class-features-plugin" "^7.17.1" "@babel/helper-plugin-utils" "^7.16.7" "@babel/helper-replace-supers" "^7.16.7" "@babel/plugin-syntax-decorators" "^7.17.0" From 7cf98285dd838d51a968be40dd654b143c423d24 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Feb 2022 11:07:14 +0900 Subject: [PATCH 16/35] Bump npmlog from 6.0.0 to 6.0.1 (#17545) Bumps [npmlog](https://github.com/npm/npmlog) from 6.0.0 to 6.0.1. - [Release notes](https://github.com/npm/npmlog/releases) - [Changelog](https://github.com/npm/npmlog/blob/main/CHANGELOG.md) - [Commits](https://github.com/npm/npmlog/compare/v6.0.0...v6.0.1) --- updated-dependencies: - dependency-name: npmlog dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 65eef34039..01582b5f97 100644 --- a/package.json +++ b/package.json @@ -112,7 +112,7 @@ "marky": "^1.2.2", "mini-css-extract-plugin": "^1.6.2", "mkdirp": "^1.0.4", - "npmlog": "^6.0.0", + "npmlog": "^6.0.1", "object-assign": "^4.1.1", "object-fit-images": "^3.2.3", "object.values": "^1.1.5", diff --git a/yarn.lock b/yarn.lock index c0bef8fc5b..caefb1f440 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2116,10 +2116,10 @@ aproba@^1.1.1: resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== -are-we-there-yet@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" - integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== +are-we-there-yet@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.0.tgz#ba20bd6b553e31d62fc8c31bd23d22b95734390d" + integrity sha512-0GWpv50YSOcLXaN6/FAKY3vfRbllXWV2xvfA/oKJF8pzFhWXPV+yjhJXDBbjscDYowv7Yw1A3uigpzn5iEGTyw== dependencies: delegates "^1.0.0" readable-stream "^3.6.0" @@ -7562,12 +7562,12 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" -npmlog@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.0.tgz#ba9ef39413c3d936ea91553db7be49c34ad0520c" - integrity sha512-03ppFRGlsyUaQFbGC2C8QWJN/C/K7PsfyD9aQdhVKAQIH4sQBc8WASqFBP7O+Ut4d2oo5LoeoboB3cGdBZSp6Q== +npmlog@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.1.tgz#06f1344a174c06e8de9c6c70834cfba2964bba17" + integrity sha512-BTHDvY6nrRHuRfyjt1MAufLxYdVXZfd099H4+i1f0lPywNQyI4foeNXJRObB/uy+TYqUW0vAD9gbdSOXPst7Eg== dependencies: - are-we-there-yet "^2.0.0" + are-we-there-yet "^3.0.0" console-control-strings "^1.1.0" gauge "^4.0.0" set-blocking "^2.0.0" From 1e275575d7f6dc4489c7504ced27a3328ae7b79e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Feb 2022 11:07:42 +0900 Subject: [PATCH 17/35] Bump rqrcode from 2.1.0 to 2.1.1 (#17542) Bumps [rqrcode](https://github.com/whomwah/rqrcode) from 2.1.0 to 2.1.1. - [Release notes](https://github.com/whomwah/rqrcode/releases) - [Changelog](https://github.com/whomwah/rqrcode/blob/master/CHANGELOG.md) - [Commits](https://github.com/whomwah/rqrcode/compare/v2.1.0...v2.1.1) --- updated-dependencies: - dependency-name: rqrcode dependency-type: direct:production update-type: version-update:semver-patch ... 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 71e8cf4cd4..5cb0676034 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -506,7 +506,7 @@ GEM rexml (3.2.5) rotp (6.2.0) rpam2 (4.0.2) - rqrcode (2.1.0) + rqrcode (2.1.1) chunky_png (~> 1.0) rqrcode_core (~> 1.0) rqrcode_core (1.2.0) From b3a6fa6a11e2015295a3d2f9fd6b9810d6d221cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Feb 2022 14:13:48 +0900 Subject: [PATCH 18/35] Bump rails from 6.1.4.4 to 6.1.4.6 (#17550) Bumps [rails](https://github.com/rails/rails) from 6.1.4.4 to 6.1.4.6. - [Release notes](https://github.com/rails/rails/releases) - [Commits](https://github.com/rails/rails/compare/v6.1.4.4...v6.1.4.6) --- updated-dependencies: - dependency-name: rails dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 106 +++++++++++++++++++++++++-------------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 5cb0676034..8c2062f58c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,40 +1,40 @@ GEM remote: https://rubygems.org/ specs: - actioncable (6.1.4.4) - actionpack (= 6.1.4.4) - activesupport (= 6.1.4.4) + actioncable (6.1.4.6) + actionpack (= 6.1.4.6) + activesupport (= 6.1.4.6) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.1.4.4) - actionpack (= 6.1.4.4) - activejob (= 6.1.4.4) - activerecord (= 6.1.4.4) - activestorage (= 6.1.4.4) - activesupport (= 6.1.4.4) + actionmailbox (6.1.4.6) + actionpack (= 6.1.4.6) + activejob (= 6.1.4.6) + activerecord (= 6.1.4.6) + activestorage (= 6.1.4.6) + activesupport (= 6.1.4.6) mail (>= 2.7.1) - actionmailer (6.1.4.4) - actionpack (= 6.1.4.4) - actionview (= 6.1.4.4) - activejob (= 6.1.4.4) - activesupport (= 6.1.4.4) + actionmailer (6.1.4.6) + actionpack (= 6.1.4.6) + actionview (= 6.1.4.6) + activejob (= 6.1.4.6) + activesupport (= 6.1.4.6) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.1.4.4) - actionview (= 6.1.4.4) - activesupport (= 6.1.4.4) + actionpack (6.1.4.6) + actionview (= 6.1.4.6) + activesupport (= 6.1.4.6) rack (~> 2.0, >= 2.0.9) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.1.4.4) - actionpack (= 6.1.4.4) - activerecord (= 6.1.4.4) - activestorage (= 6.1.4.4) - activesupport (= 6.1.4.4) + actiontext (6.1.4.6) + actionpack (= 6.1.4.6) + activerecord (= 6.1.4.6) + activestorage (= 6.1.4.6) + activesupport (= 6.1.4.6) nokogiri (>= 1.8.5) - actionview (6.1.4.4) - activesupport (= 6.1.4.4) + actionview (6.1.4.6) + activesupport (= 6.1.4.6) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) @@ -45,22 +45,22 @@ GEM case_transform (>= 0.2) jsonapi-renderer (>= 0.1.1.beta1, < 0.3) active_record_query_trace (1.8) - activejob (6.1.4.4) - activesupport (= 6.1.4.4) + activejob (6.1.4.6) + activesupport (= 6.1.4.6) globalid (>= 0.3.6) - activemodel (6.1.4.4) - activesupport (= 6.1.4.4) - activerecord (6.1.4.4) - activemodel (= 6.1.4.4) - activesupport (= 6.1.4.4) - activestorage (6.1.4.4) - actionpack (= 6.1.4.4) - activejob (= 6.1.4.4) - activerecord (= 6.1.4.4) - activesupport (= 6.1.4.4) + activemodel (6.1.4.6) + activesupport (= 6.1.4.6) + activerecord (6.1.4.6) + activemodel (= 6.1.4.6) + activesupport (= 6.1.4.6) + activestorage (6.1.4.6) + actionpack (= 6.1.4.6) + activejob (= 6.1.4.6) + activerecord (= 6.1.4.6) + activesupport (= 6.1.4.6) marcel (~> 1.0.0) mini_mime (>= 1.1.0) - activesupport (6.1.4.4) + activesupport (6.1.4.6) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) @@ -453,20 +453,20 @@ GEM rack rack-test (1.1.0) rack (>= 1.0, < 3) - rails (6.1.4.4) - actioncable (= 6.1.4.4) - actionmailbox (= 6.1.4.4) - actionmailer (= 6.1.4.4) - actionpack (= 6.1.4.4) - actiontext (= 6.1.4.4) - actionview (= 6.1.4.4) - activejob (= 6.1.4.4) - activemodel (= 6.1.4.4) - activerecord (= 6.1.4.4) - activestorage (= 6.1.4.4) - activesupport (= 6.1.4.4) + rails (6.1.4.6) + actioncable (= 6.1.4.6) + actionmailbox (= 6.1.4.6) + actionmailer (= 6.1.4.6) + actionpack (= 6.1.4.6) + actiontext (= 6.1.4.6) + actionview (= 6.1.4.6) + activejob (= 6.1.4.6) + activemodel (= 6.1.4.6) + activerecord (= 6.1.4.6) + activestorage (= 6.1.4.6) + activesupport (= 6.1.4.6) bundler (>= 1.15.0) - railties (= 6.1.4.4) + railties (= 6.1.4.6) sprockets-rails (>= 2.0.0) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) @@ -482,9 +482,9 @@ GEM railties (>= 6.0.0, < 7) rails-settings-cached (0.6.6) rails (>= 4.2.0) - railties (6.1.4.4) - actionpack (= 6.1.4.4) - activesupport (= 6.1.4.4) + railties (6.1.4.6) + actionpack (= 6.1.4.6) + activesupport (= 6.1.4.6) method_source rake (>= 0.13) thor (~> 1.0) From 0e9f79c0a4404a75c3cb8bf1f5d671086d0399d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Feb 2022 13:05:10 +0900 Subject: [PATCH 19/35] Bump pg from 1.3.1 to 1.3.2 (#17555) Bumps [pg](https://github.com/ged/ruby-pg) from 1.3.1 to 1.3.2. - [Release notes](https://github.com/ged/ruby-pg/releases) - [Changelog](https://github.com/ged/ruby-pg/blob/master/History.rdoc) - [Commits](https://github.com/ged/ruby-pg/compare/v1.3.1...v1.3.2) --- updated-dependencies: - dependency-name: pg dependency-type: direct:production update-type: version-update:semver-patch ... 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 8c2062f58c..988d507dc2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -416,7 +416,7 @@ GEM parslet (2.0.0) pastel (0.8.0) tty-color (~> 0.5) - pg (1.3.1) + pg (1.3.2) pghero (2.8.2) activerecord (>= 5) pkg-config (1.4.7) From 349e244fb80b721d101c8469ed8a575172e76ab0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Feb 2022 19:18:09 +0900 Subject: [PATCH 20/35] Bump scenic from 1.5.5 to 1.6.0 (#17547) Bumps [scenic](https://github.com/scenic-views/scenic) from 1.5.5 to 1.6.0. - [Release notes](https://github.com/scenic-views/scenic/releases) - [Changelog](https://github.com/scenic-views/scenic/blob/main/CHANGELOG.md) - [Commits](https://github.com/scenic-views/scenic/compare/v1.5.5...v1.6.0) --- updated-dependencies: - dependency-name: scenic dependency-type: direct:production update-type: version-update:semver-minor ... 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 ee5395bfcd..5ade2e8c4e 100644 --- a/Gemfile +++ b/Gemfile @@ -76,7 +76,7 @@ gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock' gem 'rqrcode', '~> 2.1' gem 'ruby-progressbar', '~> 1.11' gem 'sanitize', '~> 6.0' -gem 'scenic', '~> 1.5' +gem 'scenic', '~> 1.6' gem 'sidekiq', '~> 6.4' gem 'sidekiq-scheduler', '~> 3.1' gem 'sidekiq-unique-jobs', '~> 7.1' diff --git a/Gemfile.lock b/Gemfile.lock index 988d507dc2..37d101be53 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -559,7 +559,7 @@ GEM sanitize (6.0.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) - scenic (1.5.5) + scenic (1.6.0) activerecord (>= 4.0.0) railties (>= 4.0.0) securecompare (1.0.0) @@ -777,7 +777,7 @@ DEPENDENCIES rubocop-rails (~> 2.13) ruby-progressbar (~> 1.11) sanitize (~> 6.0) - scenic (~> 1.5) + scenic (~> 1.6) sidekiq (~> 6.4) sidekiq-bulk (~> 0.2.0) sidekiq-scheduler (~> 3.1) From 2d7e210cd844f23404525ee48caa8a21de7ee3cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Feb 2022 19:20:37 +0900 Subject: [PATCH 21/35] Bump axios from 0.25.0 to 0.26.0 (#17551) Bumps [axios](https://github.com/axios/axios) from 0.25.0 to 0.26.0. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/master/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v0.25.0...v0.26.0) --- updated-dependencies: - dependency-name: axios dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 01582b5f97..387fc4bb66 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "array-includes": "^3.1.4", "arrow-key-navigation": "^1.2.0", "autoprefixer": "^9.8.8", - "axios": "^0.25.0", + "axios": "^0.26.0", "babel-loader": "^8.2.3", "babel-plugin-lodash": "^3.3.4", "babel-plugin-preval": "^5.1.0", diff --git a/yarn.lock b/yarn.lock index caefb1f440..1d67179fc0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2303,12 +2303,12 @@ axe-core@^4.3.5: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.3.5.tgz#78d6911ba317a8262bfee292aeafcc1e04b49cc5" integrity sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA== -axios@^0.25.0: - version "0.25.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.25.0.tgz#349cfbb31331a9b4453190791760a8d35b093e0a" - integrity sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g== +axios@^0.26.0: + version "0.26.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.0.tgz#9a318f1c69ec108f8cd5f3c3d390366635e13928" + integrity sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og== dependencies: - follow-redirects "^1.14.7" + follow-redirects "^1.14.8" axobject-query@^2.2.0: version "2.2.0" @@ -4925,7 +4925,7 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" -follow-redirects@^1.0.0, follow-redirects@^1.14.7: +follow-redirects@^1.0.0, follow-redirects@^1.14.8: version "1.14.8" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc" integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA== From 52130064e1bc3bccd61f2c66996baeb0da7cabe7 Mon Sep 17 00:00:00 2001 From: Jeong Arm Date: Wed, 16 Feb 2022 21:14:53 +0900 Subject: [PATCH 22/35] Add test for user matching ip (#17572) --- spec/models/user_spec.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 406438c220..1645ab59e0 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -89,6 +89,19 @@ RSpec.describe User, type: :model do expect(User.matches_email('specified')).to match_array([specified]) end end + + describe 'matches_ip' do + it 'returns a relation of users whose ip address is matching with the given CIDR' do + user1 = Fabricate(:user) + user2 = Fabricate(:user) + Fabricate(:session_activation, user: user1, ip: '2160:2160::22', session_id: '1') + Fabricate(:session_activation, user: user1, ip: '2160:2160::23', session_id: '2') + Fabricate(:session_activation, user: user2, ip: '2160:8888::24', session_id: '3') + Fabricate(:session_activation, user: user2, ip: '2160:8888::25', session_id: '4') + + expect(User.matches_ip('2160:2160::/32')).to match_array([user1]) + end + end end let(:account) { Fabricate(:account, username: 'alice') } From 488c4e17122aa62a45377d50d5761c3c4f7b8efd Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 16 Feb 2022 13:17:28 +0100 Subject: [PATCH 23/35] =?UTF-8?q?Change=20dasbhoard=20links=20for=20?= =?UTF-8?q?=E2=80=9Cnew=20users=E2=80=9D=20and=20=E2=80=9Cactive=20users?= =?UTF-8?q?=E2=80=9D=20(#17570)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make them filter for local accounts by default --- app/views/admin/dashboard/index.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 59b75e0e1d..8354f0b9f5 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -19,10 +19,10 @@ .dashboard .dashboard__item - = react_admin_component :counter, measure: 'new_users', start_at: @time_period.first, end_at: @time_period.last, label: t('admin.dashboard.new_users'), href: admin_accounts_path + = react_admin_component :counter, measure: 'new_users', start_at: @time_period.first, end_at: @time_period.last, label: t('admin.dashboard.new_users'), href: admin_accounts_path(origin: 'local') .dashboard__item - = react_admin_component :counter, measure: 'active_users', start_at: @time_period.first, end_at: @time_period.last, label: t('admin.dashboard.active_users'), href: admin_accounts_path + = react_admin_component :counter, measure: 'active_users', start_at: @time_period.first, end_at: @time_period.last, label: t('admin.dashboard.active_users'), href: admin_accounts_path(origin: 'local') .dashboard__item = react_admin_component :counter, measure: 'interactions', start_at: @time_period.first, end_at: @time_period.last, label: t('admin.dashboard.interactions') From 4d49bb4b5203f23a64117b0c8f00b8244b5c7d9f Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 16 Feb 2022 14:28:45 +0100 Subject: [PATCH 24/35] Fix performance of server-side filtering (#17575) Fixes #17567 --- app/lib/feed_manager.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index 7840afee81..ccd4d36109 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -441,7 +441,7 @@ class FeedManager return false if active_filters.empty? - combined_regex = active_filters.reduce { |memo, obj| Regexp.union(memo, obj) } + combined_regex = Regexp.union(active_filters) status = status.reblog if status.reblog? combined_text = [ From efb23771485ebb993750fc95b6302734b526555d Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 16 Feb 2022 14:36:44 +0100 Subject: [PATCH 25/35] Change relays handling to not record boosts (#17571) * Change relays handling to not record boosts * Update tests --- app/lib/activitypub/activity/announce.rb | 1 + .../lib/activitypub/activity/announce_spec.rb | 32 +++++++------------ 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/app/lib/activitypub/activity/announce.rb b/app/lib/activitypub/activity/announce.rb index 1f93192905..12fad8da40 100644 --- a/app/lib/activitypub/activity/announce.rb +++ b/app/lib/activitypub/activity/announce.rb @@ -8,6 +8,7 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity original_status = status_from_object return reject_payload! if original_status.nil? || !announceable?(original_status) + return if requested_through_relay? @status = Status.find_by(account: @account, reblog: original_status) diff --git a/spec/lib/activitypub/activity/announce_spec.rb b/spec/lib/activitypub/activity/announce_spec.rb index b93fcbe665..41806b2582 100644 --- a/spec/lib/activitypub/activity/announce_spec.rb +++ b/spec/lib/activitypub/activity/announce_spec.rb @@ -113,26 +113,23 @@ RSpec.describe ActivityPub::Activity::Announce do let!(:relay_account) { Fabricate(:account, inbox_url: 'https://relay.example.com/inbox') } let!(:relay) { Fabricate(:relay, inbox_url: 'https://relay.example.com/inbox') } + let(:object_json) { 'https://example.com/actor/hello-world' } + subject { described_class.new(json, sender, relayed_through_account: relay_account) } + before do + stub_request(:get, 'https://example.com/actor/hello-world').to_return(body: Oj.dump(unknown_object_json)) + end + context 'and the relay is enabled' do before do relay.update(state: :accepted) subject.perform end - let(:object_json) do - { - id: 'https://example.com/actor#bar', - type: 'Note', - content: 'Lorem ipsum', - to: 'http://example.com/followers', - attributedTo: 'https://example.com/actor', - } - end - - it 'creates a reblog by sender of status' do - expect(sender.statuses.count).to eq 2 + it 'fetches the remote status' do + expect(a_request(:get, 'https://example.com/actor/hello-world')).to have_been_made + expect(Status.find_by(uri: 'https://example.com/actor/hello-world').text).to eq 'Hello world' end end @@ -141,14 +138,9 @@ RSpec.describe ActivityPub::Activity::Announce do subject.perform end - let(:object_json) do - { - id: 'https://example.com/actor#bar', - type: 'Note', - content: 'Lorem ipsum', - to: 'http://example.com/followers', - attributedTo: 'https://example.com/actor', - } + it 'does not fetch the remote status' do + expect(a_request(:get, 'https://example.com/actor/hello-world')).not_to have_been_made + expect(Status.find_by(uri: 'https://example.com/actor/hello-world')).to be_nil end it 'does not create anything' do From d8fde67ecaa880e53dd7614d9938eb2223a0eafa Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 16 Feb 2022 14:37:26 +0100 Subject: [PATCH 26/35] Change streaming server error messages when failing to parse client input (#17559) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #17541 - prefix JSON parsing error message by “Error parsing message from …” - output user id if a user is logged in, IP address otherwise - reduce log level from error to warning when a user is logged in, and to silly otherwise --- streaming/index.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/streaming/index.js b/streaming/index.js index 47f938b869..3db94b1600 100644 --- a/streaming/index.js +++ b/streaming/index.js @@ -92,13 +92,18 @@ const numWorkers = +process.env.STREAMING_CLUSTER_NUM || (env === 'development' /** * @param {string} json + * @param {any} req * @return {Object.|null} */ -const parseJSON = (json) => { +const parseJSON = (json, req) => { try { return JSON.parse(json); } catch (err) { - log.error(err); + if (req.accountId) { + log.warn(req.requestId, `Error parsing message from user ${req.accountId}: ${err}`); + } else { + log.silly(req.requestId, `Error parsing message from ${req.remoteAddress}: ${err}`); + } return null; } }; @@ -450,7 +455,7 @@ const startWorker = async (workerId) => { */ const createSystemMessageListener = (req, eventHandlers) => { return message => { - const json = parseJSON(message); + const json = parseJSON(message, req); if (!json) return; @@ -573,7 +578,7 @@ const startWorker = async (workerId) => { log.verbose(req.requestId, `Starting stream from ${ids.join(', ')} for ${accountId}`); const listener = message => { - const json = parseJSON(message); + const json = parseJSON(message, req); if (!json) return; @@ -1037,7 +1042,7 @@ const startWorker = async (workerId) => { ws.on('error', onEnd); ws.on('message', data => { - const json = parseJSON(data); + const json = parseJSON(data, session.request); if (!json) return; From 9239d7173c2ca61172281a0cbbf711a0ebfcd956 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 16 Feb 2022 14:57:57 +0100 Subject: [PATCH 27/35] Fix 0 pluralization for some localization strings (#17576) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently, when the `zero` case is not defined, the translation string used for `0` depends on the language. In French, `one` is used, causing some strings with hardcoded “one” or `1` to misrepresent the actual data. For instance, the dashboard would display « 1 utilisateur·rice en attente » for both 0 and 1 pending users. --- config/locales/en.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 05c64e18a7..cf4c2cc37e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -394,16 +394,16 @@ en: new_users: new users opened_reports: reports opened pending_appeals_html: - one: "1 pending appeal" + one: "%{count} pending appeal" other: "%{count} pending appeals" pending_reports_html: - one: "1 pending report" + one: "%{count} pending report" other: "%{count} pending reports" pending_tags_html: - one: "1 pending hashtag" + one: "%{count} pending hashtag" other: "%{count} pending hashtags" pending_users_html: - one: "1 pending user" + one: "%{count} pending user" other: "%{count} pending users" resolved_reports: reports resolved software: Software @@ -457,6 +457,7 @@ en: affected_accounts: one: One account in the database affected other: "%{count} accounts in the database affected" + zero: No account in the database is affected retroactive: silence: Undo limit of existing affected accounts from this domain suspend: Unsuspend existing affected accounts from this domain @@ -510,6 +511,7 @@ en: known_accounts: one: "%{count} known account" other: "%{count} known accounts" + zero: No known account moderation: all: All limited: Limited @@ -769,6 +771,7 @@ en: shared_by_over_week: one: Shared by one person over the last week other: Shared by %{count} people over the last week + zero: Shared by noone over the last week title: Trending links usage_comparison: Shared %{today} times today, compared to %{yesterday} yesterday pending_review: Pending review @@ -798,6 +801,7 @@ en: used_by_over_week: one: Used by one person over the last week other: Used by %{count} people over the last week + zero: Used by noone over the last week title: Trends warning_presets: add_new: Add new From ab98d2e539c2691953105edab940f90af59eea4d Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 16 Feb 2022 21:44:19 +0100 Subject: [PATCH 28/35] Fix edge case where settings/admin page sidebar would be incorrectly hidden (#17580) --- app/javascript/packs/public.js | 8 +------- app/javascript/styles/mastodon/admin.scss | 4 ++++ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/app/javascript/packs/public.js b/app/javascript/packs/public.js index c0c0886461..3d0a937e1f 100644 --- a/app/javascript/packs/public.js +++ b/app/javascript/packs/public.js @@ -276,13 +276,7 @@ function main() { }); delegate(document, '.sidebar__toggle__icon', 'click', () => { - const target = document.querySelector('.sidebar ul'); - - if (target.style.display === 'block') { - target.style.display = 'none'; - } else { - target.style.display = 'block'; - } + document.querySelector('.sidebar ul').classList.toggle('visible'); }); // Empty the honeypot fields in JS in case something like an extension diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss index f5741bd502..1921eb1466 100644 --- a/app/javascript/styles/mastodon/admin.scss +++ b/app/javascript/styles/mastodon/admin.scss @@ -322,6 +322,10 @@ $content-width: 840px; & > ul { display: none; + + &.visible { + display: block; + } } ul a, From 5b5b9deebd373e8e989db5903340a3ae917fb8f8 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 16 Feb 2022 21:44:47 +0100 Subject: [PATCH 29/35] Fix opening the emoji picker scrolling the single-column view to the top (#17579) Fixes #17577 --- .../compose/components/emoji_picker_dropdown.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js index 4a87714e64..f433e4de9f 100644 --- a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js +++ b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js @@ -170,7 +170,7 @@ class EmojiPickerMenu extends React.PureComponent { state = { modifierOpen: false, - placement: null, + readyToFocus: false, }; handleDocumentClick = e => { @@ -182,6 +182,16 @@ class EmojiPickerMenu extends React.PureComponent { componentDidMount () { document.addEventListener('click', this.handleDocumentClick, false); document.addEventListener('touchend', this.handleDocumentClick, listenerOptions); + + // Because of https://github.com/react-bootstrap/react-bootstrap/issues/2614 we need + // to wait for a frame before focusing + requestAnimationFrame(() => { + this.setState({ readyToFocus: true }); + if (this.node) { + const element = this.node.querySelector('input[type="search"]'); + if (element) element.focus(); + } + }); } componentWillUnmount () { @@ -281,7 +291,7 @@ class EmojiPickerMenu extends React.PureComponent { showSkinTones={false} backgroundImageFn={backgroundImageFn} notFound={notFoundFn} - autoFocus + autoFocus={this.state.readyToFocus} emojiTooltip /> @@ -314,6 +324,7 @@ class EmojiPickerDropdown extends React.PureComponent { state = { active: false, loading: false, + placement: null, }; setRef = (c) => { From 49e1162a308710b16dfc2cb7b11162953ddf60d5 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 16 Feb 2022 22:29:48 +0100 Subject: [PATCH 30/35] Fix issues when attempting to appeal an old strike (#17554) * Display an error when an appeal could not be submitted * Do not offer users to appeal old strikes * Fix 500 error when trying to appeal a strike that is too old * Avoid using an extra translatable string --- app/controllers/disputes/appeals_controller.rb | 3 ++- app/models/appeal.rb | 4 +++- app/policies/account_warning_policy.rb | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/controllers/disputes/appeals_controller.rb b/app/controllers/disputes/appeals_controller.rb index 15367c8792..eefd92b5a8 100644 --- a/app/controllers/disputes/appeals_controller.rb +++ b/app/controllers/disputes/appeals_controller.rb @@ -9,7 +9,8 @@ class Disputes::AppealsController < Disputes::BaseController @appeal = AppealService.new.call(@strike, appeal_params[:text]) redirect_to disputes_strike_path(@strike), notice: I18n.t('disputes.strikes.appealed_msg') - rescue ActiveRecord::RecordInvalid + rescue ActiveRecord::RecordInvalid => e + @appeal = e.record render template: 'disputes/strikes/show' end diff --git a/app/models/appeal.rb b/app/models/appeal.rb index 46f35ae375..1f32cfa8b2 100644 --- a/app/models/appeal.rb +++ b/app/models/appeal.rb @@ -16,6 +16,8 @@ # updated_at :datetime not null # class Appeal < ApplicationRecord + MAX_STRIKE_AGE = 20.days + belongs_to :account belongs_to :strike, class_name: 'AccountWarning', foreign_key: 'account_warning_id' belongs_to :approved_by_account, class_name: 'Account', optional: true @@ -53,6 +55,6 @@ class Appeal < ApplicationRecord private def validate_time_frame - errors.add(:base, I18n.t('strikes.errors.too_late')) if Time.now.utc > (strike.created_at + 20.days) + errors.add(:base, I18n.t('strikes.errors.too_late')) if strike.created_at < MAX_STRIKE_AGE.ago end end diff --git a/app/policies/account_warning_policy.rb b/app/policies/account_warning_policy.rb index 6b92da475b..65707dfa7c 100644 --- a/app/policies/account_warning_policy.rb +++ b/app/policies/account_warning_policy.rb @@ -6,7 +6,7 @@ class AccountWarningPolicy < ApplicationPolicy end def appeal? - target? + target? && record.created_at >= Appeal::MAX_STRIKE_AGE.ago end private From cdd0af5a1c02840cee4ec315a63a9ee5bef7f7e4 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 13 Feb 2022 02:52:34 +0100 Subject: [PATCH 31/35] [Glitch] Fix privacy policy link not being visible on small screens Port 77529aba869bff29fe386e264f4779495bd8fd37 to glitch-soc Signed-off-by: Claire --- .../flavours/glitch/styles/footer.scss | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/app/javascript/flavours/glitch/styles/footer.scss b/app/javascript/flavours/glitch/styles/footer.scss index 00d2908832..073ebda7e4 100644 --- a/app/javascript/flavours/glitch/styles/footer.scss +++ b/app/javascript/flavours/glitch/styles/footer.scss @@ -90,6 +90,20 @@ .column-4 { display: none; } + + .column-2 h4 { + display: none; + } + } + } + + .legal-xs { + display: none; + text-align: center; + padding-top: 20px; + + @media screen and (max-width: $no-gap-breakpoint) { + display: block; } } @@ -105,7 +119,8 @@ } } - ul a { + ul a, + .legal-xs a { text-decoration: none; color: lighten($ui-base-color, 34%); From 394042c91be822833e05879a7028b3f183c6a585 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 14 Feb 2022 21:27:53 +0100 Subject: [PATCH 32/35] [Glitch] Add appeals Port SCSS changes from 82f8d1942429e5b6a563dcaddbd0cb5f5a908424 to glitch-soc Signed-off-by: Claire --- .../flavours/glitch/styles/admin.scss | 89 +++++++++++++++++-- 1 file changed, 83 insertions(+), 6 deletions(-) diff --git a/app/javascript/flavours/glitch/styles/admin.scss b/app/javascript/flavours/glitch/styles/admin.scss index 66ce92ce2c..31f8839256 100644 --- a/app/javascript/flavours/glitch/styles/admin.scss +++ b/app/javascript/flavours/glitch/styles/admin.scss @@ -594,12 +594,16 @@ body, } .log-entry { + display: block; line-height: 20px; padding: 15px; padding-left: 15px * 2 + 40px; background: $ui-base-color; border-bottom: 1px solid darken($ui-base-color, 8%); position: relative; + text-decoration: none; + color: $darker-text-color; + font-size: 14px; &:first-child { border-top-left-radius: 4px; @@ -612,15 +616,12 @@ body, border-bottom: 0; } - &:hover { + &:hover, + &:focus, + &:active { background: lighten($ui-base-color, 4%); } - &__header { - color: $darker-text-color; - font-size: 14px; - } - &__avatar { position: absolute; left: 15px; @@ -656,6 +657,18 @@ body, text-decoration: underline; } } + + &--inactive { + .log-entry__title { + text-decoration: line-through; + } + + a, + .username, + .target { + color: $darker-text-color; + } + } } a.name-tag, @@ -1191,6 +1204,17 @@ a.sparkline { font-weight: 600; padding: 4px 0; } + + a { + color: $ui-highlight-color; + text-decoration: none; + + &:hover, + &:focus, + &:active { + text-decoration: underline; + } + } } &--horizontal { @@ -1467,3 +1491,56 @@ a.sparkline { } } } + +.strike-card { + padding: 15px; + border-radius: 4px; + background: $ui-base-color; + font-size: 15px; + line-height: 20px; + word-wrap: break-word; + font-weight: 400; + color: $primary-text-color; + + p { + margin-bottom: 20px; + unicode-bidi: plaintext; + + &:last-child { + margin-bottom: 0; + } + } + + &__statuses-list { + border-radius: 4px; + border: 1px solid darken($ui-base-color, 8%); + font-size: 13px; + line-height: 18px; + overflow: hidden; + + &__item { + padding: 16px; + background: lighten($ui-base-color, 2%); + border-bottom: 1px solid darken($ui-base-color, 8%); + + &:last-child { + border-bottom: 0; + } + + &__meta { + color: $darker-text-color; + } + + a { + color: inherit; + text-decoration: none; + + &:hover, + &:focus, + &:active { + text-decoration: underline; + } + } + } + } +} From 5718a2e2808b2166904cb7a6e79042f9b64dae2f Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 14 Feb 2022 21:54:01 +0100 Subject: [PATCH 33/35] Fix issue with glitch-soc's theming system --- app/controllers/disputes/base_controller.rb | 5 +++++ app/views/admin/disputes/appeals/index.html.haml | 3 --- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/controllers/disputes/base_controller.rb b/app/controllers/disputes/base_controller.rb index 865146b5cc..7830c55247 100644 --- a/app/controllers/disputes/base_controller.rb +++ b/app/controllers/disputes/base_controller.rb @@ -9,9 +9,14 @@ class Disputes::BaseController < ApplicationController before_action :set_body_classes before_action :authenticate_user! + before_action :set_pack private + def set_pack + use_pack 'admin' + end + def set_body_classes @body_classes = 'admin' end diff --git a/app/views/admin/disputes/appeals/index.html.haml b/app/views/admin/disputes/appeals/index.html.haml index dd6a6f403f..42e9c4b1d7 100644 --- a/app/views/admin/disputes/appeals/index.html.haml +++ b/app/views/admin/disputes/appeals/index.html.haml @@ -1,9 +1,6 @@ - content_for :page_title do = t('admin.disputes.appeals.title') -- content_for :header_tags do - = javascript_pack_tag 'admin', async: true, crossorigin: 'anonymous' - .filters .filter-subset %strong= t('admin.tags.review') From a564a067394ff4ec59c2e8addfe5a7d45adf0d0a Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 16 Feb 2022 21:44:19 +0100 Subject: [PATCH 34/35] [Glitch] Fix edge case where settings/admin page sidebar would be incorrectly hidden Port ab98d2e539c2691953105edab940f90af59eea4d to glitch-soc Signed-off-by: Claire --- app/javascript/flavours/glitch/packs/public.js | 8 +------- app/javascript/flavours/glitch/packs/settings.js | 8 +------- app/javascript/flavours/glitch/styles/admin.scss | 4 ++++ 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/app/javascript/flavours/glitch/packs/public.js b/app/javascript/flavours/glitch/packs/public.js index a92f3d5a84..84ec9fce74 100644 --- a/app/javascript/flavours/glitch/packs/public.js +++ b/app/javascript/flavours/glitch/packs/public.js @@ -147,13 +147,7 @@ function main() { }); delegate(document, '.sidebar__toggle__icon', 'click', () => { - const target = document.querySelector('.sidebar ul'); - - if (target.style.display === 'block') { - target.style.display = 'none'; - } else { - target.style.display = 'block'; - } + document.querySelector('.sidebar ul').classList.toggle('visible'); }); // Empty the honeypot fields in JS in case something like an extension diff --git a/app/javascript/flavours/glitch/packs/settings.js b/app/javascript/flavours/glitch/packs/settings.js index 9c4d119c1e..0a53e1c25a 100644 --- a/app/javascript/flavours/glitch/packs/settings.js +++ b/app/javascript/flavours/glitch/packs/settings.js @@ -7,13 +7,7 @@ function main() { const { delegate } = require('@rails/ujs'); delegate(document, '.sidebar__toggle__icon', 'click', () => { - const target = document.querySelector('.sidebar ul'); - - if (target.style.display === 'block') { - target.style.display = 'none'; - } else { - target.style.display = 'block'; - } + document.querySelector('.sidebar ul').classList.toggle('visible'); }); } diff --git a/app/javascript/flavours/glitch/styles/admin.scss b/app/javascript/flavours/glitch/styles/admin.scss index 31f8839256..33e115c1a0 100644 --- a/app/javascript/flavours/glitch/styles/admin.scss +++ b/app/javascript/flavours/glitch/styles/admin.scss @@ -322,6 +322,10 @@ $content-width: 840px; & > ul { display: none; + + &.visible { + display: block; + } } ul a, From bd4fb02bfbce1a5c1951fb1a248e45e9b922a7a7 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 16 Feb 2022 21:44:47 +0100 Subject: [PATCH 35/35] [Glitch] Fix opening the emoji picker scrolling the single-column view to the top Port 5b5b9deebd373e8e989db5903340a3ae917fb8f8 to glitch-soc Signed-off-by: Claire --- .../glitch/features/emoji_picker/index.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/app/javascript/flavours/glitch/features/emoji_picker/index.js b/app/javascript/flavours/glitch/features/emoji_picker/index.js index 78f691c980..5de9fe107f 100644 --- a/app/javascript/flavours/glitch/features/emoji_picker/index.js +++ b/app/javascript/flavours/glitch/features/emoji_picker/index.js @@ -250,7 +250,7 @@ class EmojiPickerMenu extends React.PureComponent { state = { modifierOpen: false, - placement: null, + readyToFocus: false, }; handleDocumentClick = e => { @@ -262,6 +262,16 @@ class EmojiPickerMenu extends React.PureComponent { componentDidMount () { document.addEventListener('click', this.handleDocumentClick, false); document.addEventListener('touchend', this.handleDocumentClick, listenerOptions); + + // Because of https://github.com/react-bootstrap/react-bootstrap/issues/2614 we need + // to wait for a frame before focusing + requestAnimationFrame(() => { + this.setState({ readyToFocus: true }); + if (this.node) { + const element = this.node.querySelector('input[type="search"]'); + if (element) element.focus(); + } + }); } componentWillUnmount () { @@ -361,7 +371,7 @@ class EmojiPickerMenu extends React.PureComponent { showSkinTones={false} backgroundImageFn={backgroundImageFn} notFound={notFoundFn} - autoFocus + autoFocus={this.state.readyToFocus} emojiTooltip native={useSystemEmojiFont} /> @@ -396,6 +406,7 @@ class EmojiPickerDropdown extends React.PureComponent { state = { active: false, loading: false, + placement: null, }; setRef = (c) => {