Merge pull request #1692 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes
This commit is contained in:
		
						commit
						c8ef003c6b
					
				
					 86 changed files with 1581 additions and 404 deletions
				
			
		| 
						 | 
					@ -32,7 +32,7 @@ commands:
 | 
				
			||||||
          name: Install system dependencies
 | 
					          name: Install system dependencies
 | 
				
			||||||
          command: |
 | 
					          command: |
 | 
				
			||||||
            sudo apt-get update
 | 
					            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:
 | 
					  install-ruby-dependencies:
 | 
				
			||||||
    parameters:
 | 
					    parameters:
 | 
				
			||||||
      ruby-version:
 | 
					      ruby-version:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										6
									
								
								.github/workflows/build-image.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/build-image.yml
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -6,6 +6,10 @@ on:
 | 
				
			||||||
      - "main"
 | 
					      - "main"
 | 
				
			||||||
    tags:
 | 
					    tags:
 | 
				
			||||||
      - "*"
 | 
					      - "*"
 | 
				
			||||||
 | 
					  pull_request:
 | 
				
			||||||
 | 
					    paths:
 | 
				
			||||||
 | 
					      - .github/workflows/build-image.yml
 | 
				
			||||||
 | 
					      - Dockerfile
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  build-image:
 | 
					  build-image:
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
| 
						 | 
					@ -31,7 +35,7 @@ jobs:
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          context: .
 | 
					          context: .
 | 
				
			||||||
          platforms: linux/amd64,linux/arm64
 | 
					          platforms: linux/amd64,linux/arm64
 | 
				
			||||||
          push: true
 | 
					          push: ${{ github.event_name != 'pull_request' }}
 | 
				
			||||||
          tags: ${{ steps.meta.outputs.tags }}
 | 
					          tags: ${{ steps.meta.outputs.tags }}
 | 
				
			||||||
          cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/mastodon:latest
 | 
					          cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/mastodon:latest
 | 
				
			||||||
          cache-to: type=inline
 | 
					          cache-to: type=inline
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								.github/workflows/check-i18n.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/check-i18n.yml
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -18,7 +18,7 @@ jobs:
 | 
				
			||||||
    - name: Install system dependencies
 | 
					    - name: Install system dependencies
 | 
				
			||||||
      run: |
 | 
					      run: |
 | 
				
			||||||
        sudo apt-get update
 | 
					        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
 | 
					    - name: Set up Ruby
 | 
				
			||||||
      uses: ruby/setup-ruby@v1
 | 
					      uses: ruby/setup-ruby@v1
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								Aptfile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Aptfile
									
									
									
									
									
								
							| 
						 | 
					@ -4,10 +4,8 @@ libicu-dev
 | 
				
			||||||
libidn11
 | 
					libidn11
 | 
				
			||||||
libidn11-dev
 | 
					libidn11-dev
 | 
				
			||||||
libpq-dev
 | 
					libpq-dev
 | 
				
			||||||
libprotobuf-dev
 | 
					 | 
				
			||||||
libxdamage1
 | 
					libxdamage1
 | 
				
			||||||
libxfixes3
 | 
					libxfixes3
 | 
				
			||||||
protobuf-compiler
 | 
					 | 
				
			||||||
zlib1g-dev
 | 
					zlib1g-dev
 | 
				
			||||||
libcairo2
 | 
					libcairo2
 | 
				
			||||||
libcroco3
 | 
					libcroco3
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -51,7 +51,7 @@ RUN npm install -g npm@latest && \
 | 
				
			||||||
	gem install bundler && \
 | 
						gem install bundler && \
 | 
				
			||||||
	apt-get update && \
 | 
						apt-get update && \
 | 
				
			||||||
	apt-get install -y --no-install-recommends git libicu-dev libidn11-dev \
 | 
						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/
 | 
					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 && \
 | 
					RUN apt-get update && \
 | 
				
			||||||
  apt-get -y --no-install-recommends install \
 | 
					  apt-get -y --no-install-recommends install \
 | 
				
			||||||
	  libssl1.1 libpq5 imagemagick ffmpeg libjemalloc2 \
 | 
						  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 && \
 | 
						  file ca-certificates tzdata libreadline8 gcc tini apt-utils && \
 | 
				
			||||||
	ln -s /opt/mastodon /mastodon && \
 | 
						ln -s /opt/mastodon /mastodon && \
 | 
				
			||||||
	gem install bundler && \
 | 
						gem install bundler && \
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										8
									
								
								Gemfile
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								Gemfile
									
									
									
									
									
								
							| 
						 | 
					@ -21,7 +21,7 @@ gem 'dotenv-rails', '~> 2.7'
 | 
				
			||||||
gem 'aws-sdk-s3', '~> 1.112', require: false
 | 
					gem 'aws-sdk-s3', '~> 1.112', require: false
 | 
				
			||||||
gem 'fog-core', '<= 2.1.0'
 | 
					gem 'fog-core', '<= 2.1.0'
 | 
				
			||||||
gem 'fog-openstack', '~> 0.3', require: false
 | 
					gem 'fog-openstack', '~> 0.3', require: false
 | 
				
			||||||
gem 'kt-paperclip', '~> 7.0'
 | 
					gem 'kt-paperclip', '~> 7.1'
 | 
				
			||||||
gem 'blurhash', '~> 0.1'
 | 
					gem 'blurhash', '~> 0.1'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
gem 'active_model_serializers', '~> 0.10'
 | 
					gem 'active_model_serializers', '~> 0.10'
 | 
				
			||||||
| 
						 | 
					@ -76,7 +76,7 @@ gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
 | 
				
			||||||
gem 'rqrcode', '~> 2.1'
 | 
					gem 'rqrcode', '~> 2.1'
 | 
				
			||||||
gem 'ruby-progressbar', '~> 1.11'
 | 
					gem 'ruby-progressbar', '~> 1.11'
 | 
				
			||||||
gem 'sanitize', '~> 6.0'
 | 
					gem 'sanitize', '~> 6.0'
 | 
				
			||||||
gem 'scenic', '~> 1.5'
 | 
					gem 'scenic', '~> 1.6'
 | 
				
			||||||
gem 'sidekiq', '~> 6.4'
 | 
					gem 'sidekiq', '~> 6.4'
 | 
				
			||||||
gem 'sidekiq-scheduler', '~> 3.1'
 | 
					gem 'sidekiq-scheduler', '~> 3.1'
 | 
				
			||||||
gem 'sidekiq-unique-jobs', '~> 7.1'
 | 
					gem 'sidekiq-unique-jobs', '~> 7.1'
 | 
				
			||||||
| 
						 | 
					@ -105,7 +105,7 @@ group :development, :test do
 | 
				
			||||||
  gem 'i18n-tasks', '~> 0.9', require: false
 | 
					  gem 'i18n-tasks', '~> 0.9', require: false
 | 
				
			||||||
  gem 'pry-byebug', '~> 3.9'
 | 
					  gem 'pry-byebug', '~> 3.9'
 | 
				
			||||||
  gem 'pry-rails', '~> 0.3'
 | 
					  gem 'pry-rails', '~> 0.3'
 | 
				
			||||||
  gem 'rspec-rails', '~> 5.0'
 | 
					  gem 'rspec-rails', '~> 5.1'
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
group :production, :test do
 | 
					group :production, :test do
 | 
				
			||||||
| 
						 | 
					@ -126,7 +126,7 @@ end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
group :development do
 | 
					group :development do
 | 
				
			||||||
  gem 'active_record_query_trace', '~> 1.8'
 | 
					  gem 'active_record_query_trace', '~> 1.8'
 | 
				
			||||||
  gem 'annotate', '~> 3.1'
 | 
					  gem 'annotate', '~> 3.2'
 | 
				
			||||||
  gem 'better_errors', '~> 2.9'
 | 
					  gem 'better_errors', '~> 2.9'
 | 
				
			||||||
  gem 'binding_of_caller', '~> 1.0'
 | 
					  gem 'binding_of_caller', '~> 1.0'
 | 
				
			||||||
  gem 'bullet', '~> 7.0'
 | 
					  gem 'bullet', '~> 7.0'
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										150
									
								
								Gemfile.lock
									
									
									
									
									
								
							
							
						
						
									
										150
									
								
								Gemfile.lock
									
									
									
									
									
								
							| 
						 | 
					@ -1,40 +1,40 @@
 | 
				
			||||||
GEM
 | 
					GEM
 | 
				
			||||||
  remote: https://rubygems.org/
 | 
					  remote: https://rubygems.org/
 | 
				
			||||||
  specs:
 | 
					  specs:
 | 
				
			||||||
    actioncable (6.1.4.4)
 | 
					    actioncable (6.1.4.6)
 | 
				
			||||||
      actionpack (= 6.1.4.4)
 | 
					      actionpack (= 6.1.4.6)
 | 
				
			||||||
      activesupport (= 6.1.4.4)
 | 
					      activesupport (= 6.1.4.6)
 | 
				
			||||||
      nio4r (~> 2.0)
 | 
					      nio4r (~> 2.0)
 | 
				
			||||||
      websocket-driver (>= 0.6.1)
 | 
					      websocket-driver (>= 0.6.1)
 | 
				
			||||||
    actionmailbox (6.1.4.4)
 | 
					    actionmailbox (6.1.4.6)
 | 
				
			||||||
      actionpack (= 6.1.4.4)
 | 
					      actionpack (= 6.1.4.6)
 | 
				
			||||||
      activejob (= 6.1.4.4)
 | 
					      activejob (= 6.1.4.6)
 | 
				
			||||||
      activerecord (= 6.1.4.4)
 | 
					      activerecord (= 6.1.4.6)
 | 
				
			||||||
      activestorage (= 6.1.4.4)
 | 
					      activestorage (= 6.1.4.6)
 | 
				
			||||||
      activesupport (= 6.1.4.4)
 | 
					      activesupport (= 6.1.4.6)
 | 
				
			||||||
      mail (>= 2.7.1)
 | 
					      mail (>= 2.7.1)
 | 
				
			||||||
    actionmailer (6.1.4.4)
 | 
					    actionmailer (6.1.4.6)
 | 
				
			||||||
      actionpack (= 6.1.4.4)
 | 
					      actionpack (= 6.1.4.6)
 | 
				
			||||||
      actionview (= 6.1.4.4)
 | 
					      actionview (= 6.1.4.6)
 | 
				
			||||||
      activejob (= 6.1.4.4)
 | 
					      activejob (= 6.1.4.6)
 | 
				
			||||||
      activesupport (= 6.1.4.4)
 | 
					      activesupport (= 6.1.4.6)
 | 
				
			||||||
      mail (~> 2.5, >= 2.5.4)
 | 
					      mail (~> 2.5, >= 2.5.4)
 | 
				
			||||||
      rails-dom-testing (~> 2.0)
 | 
					      rails-dom-testing (~> 2.0)
 | 
				
			||||||
    actionpack (6.1.4.4)
 | 
					    actionpack (6.1.4.6)
 | 
				
			||||||
      actionview (= 6.1.4.4)
 | 
					      actionview (= 6.1.4.6)
 | 
				
			||||||
      activesupport (= 6.1.4.4)
 | 
					      activesupport (= 6.1.4.6)
 | 
				
			||||||
      rack (~> 2.0, >= 2.0.9)
 | 
					      rack (~> 2.0, >= 2.0.9)
 | 
				
			||||||
      rack-test (>= 0.6.3)
 | 
					      rack-test (>= 0.6.3)
 | 
				
			||||||
      rails-dom-testing (~> 2.0)
 | 
					      rails-dom-testing (~> 2.0)
 | 
				
			||||||
      rails-html-sanitizer (~> 1.0, >= 1.2.0)
 | 
					      rails-html-sanitizer (~> 1.0, >= 1.2.0)
 | 
				
			||||||
    actiontext (6.1.4.4)
 | 
					    actiontext (6.1.4.6)
 | 
				
			||||||
      actionpack (= 6.1.4.4)
 | 
					      actionpack (= 6.1.4.6)
 | 
				
			||||||
      activerecord (= 6.1.4.4)
 | 
					      activerecord (= 6.1.4.6)
 | 
				
			||||||
      activestorage (= 6.1.4.4)
 | 
					      activestorage (= 6.1.4.6)
 | 
				
			||||||
      activesupport (= 6.1.4.4)
 | 
					      activesupport (= 6.1.4.6)
 | 
				
			||||||
      nokogiri (>= 1.8.5)
 | 
					      nokogiri (>= 1.8.5)
 | 
				
			||||||
    actionview (6.1.4.4)
 | 
					    actionview (6.1.4.6)
 | 
				
			||||||
      activesupport (= 6.1.4.4)
 | 
					      activesupport (= 6.1.4.6)
 | 
				
			||||||
      builder (~> 3.1)
 | 
					      builder (~> 3.1)
 | 
				
			||||||
      erubi (~> 1.4)
 | 
					      erubi (~> 1.4)
 | 
				
			||||||
      rails-dom-testing (~> 2.0)
 | 
					      rails-dom-testing (~> 2.0)
 | 
				
			||||||
| 
						 | 
					@ -45,22 +45,22 @@ GEM
 | 
				
			||||||
      case_transform (>= 0.2)
 | 
					      case_transform (>= 0.2)
 | 
				
			||||||
      jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
 | 
					      jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
 | 
				
			||||||
    active_record_query_trace (1.8)
 | 
					    active_record_query_trace (1.8)
 | 
				
			||||||
    activejob (6.1.4.4)
 | 
					    activejob (6.1.4.6)
 | 
				
			||||||
      activesupport (= 6.1.4.4)
 | 
					      activesupport (= 6.1.4.6)
 | 
				
			||||||
      globalid (>= 0.3.6)
 | 
					      globalid (>= 0.3.6)
 | 
				
			||||||
    activemodel (6.1.4.4)
 | 
					    activemodel (6.1.4.6)
 | 
				
			||||||
      activesupport (= 6.1.4.4)
 | 
					      activesupport (= 6.1.4.6)
 | 
				
			||||||
    activerecord (6.1.4.4)
 | 
					    activerecord (6.1.4.6)
 | 
				
			||||||
      activemodel (= 6.1.4.4)
 | 
					      activemodel (= 6.1.4.6)
 | 
				
			||||||
      activesupport (= 6.1.4.4)
 | 
					      activesupport (= 6.1.4.6)
 | 
				
			||||||
    activestorage (6.1.4.4)
 | 
					    activestorage (6.1.4.6)
 | 
				
			||||||
      actionpack (= 6.1.4.4)
 | 
					      actionpack (= 6.1.4.6)
 | 
				
			||||||
      activejob (= 6.1.4.4)
 | 
					      activejob (= 6.1.4.6)
 | 
				
			||||||
      activerecord (= 6.1.4.4)
 | 
					      activerecord (= 6.1.4.6)
 | 
				
			||||||
      activesupport (= 6.1.4.4)
 | 
					      activesupport (= 6.1.4.6)
 | 
				
			||||||
      marcel (~> 1.0.0)
 | 
					      marcel (~> 1.0.0)
 | 
				
			||||||
      mini_mime (>= 1.1.0)
 | 
					      mini_mime (>= 1.1.0)
 | 
				
			||||||
    activesupport (6.1.4.4)
 | 
					    activesupport (6.1.4.6)
 | 
				
			||||||
      concurrent-ruby (~> 1.0, >= 1.0.2)
 | 
					      concurrent-ruby (~> 1.0, >= 1.0.2)
 | 
				
			||||||
      i18n (>= 1.6, < 2)
 | 
					      i18n (>= 1.6, < 2)
 | 
				
			||||||
      minitest (>= 5.1)
 | 
					      minitest (>= 5.1)
 | 
				
			||||||
| 
						 | 
					@ -71,8 +71,8 @@ GEM
 | 
				
			||||||
    airbrussh (1.4.0)
 | 
					    airbrussh (1.4.0)
 | 
				
			||||||
      sshkit (>= 1.6.1, != 1.7.0)
 | 
					      sshkit (>= 1.6.1, != 1.7.0)
 | 
				
			||||||
    android_key_attestation (0.3.0)
 | 
					    android_key_attestation (0.3.0)
 | 
				
			||||||
    annotate (3.1.1)
 | 
					    annotate (3.2.0)
 | 
				
			||||||
      activerecord (>= 3.2, < 7.0)
 | 
					      activerecord (>= 3.2, < 8.0)
 | 
				
			||||||
      rake (>= 10.4, < 14.0)
 | 
					      rake (>= 10.4, < 14.0)
 | 
				
			||||||
    ast (2.4.2)
 | 
					    ast (2.4.2)
 | 
				
			||||||
    attr_encrypted (3.1.0)
 | 
					    attr_encrypted (3.1.0)
 | 
				
			||||||
| 
						 | 
					@ -181,7 +181,7 @@ GEM
 | 
				
			||||||
    devise_pam_authenticatable2 (9.2.0)
 | 
					    devise_pam_authenticatable2 (9.2.0)
 | 
				
			||||||
      devise (>= 4.0.0)
 | 
					      devise (>= 4.0.0)
 | 
				
			||||||
      rpam2 (~> 4.0)
 | 
					      rpam2 (~> 4.0)
 | 
				
			||||||
    diff-lcs (1.4.4)
 | 
					    diff-lcs (1.5.0)
 | 
				
			||||||
    discard (1.2.1)
 | 
					    discard (1.2.1)
 | 
				
			||||||
      activerecord (>= 4.2, < 8)
 | 
					      activerecord (>= 4.2, < 8)
 | 
				
			||||||
    docile (1.3.4)
 | 
					    docile (1.3.4)
 | 
				
			||||||
| 
						 | 
					@ -332,7 +332,7 @@ GEM
 | 
				
			||||||
      activerecord
 | 
					      activerecord
 | 
				
			||||||
      kaminari-core (= 1.2.2)
 | 
					      kaminari-core (= 1.2.2)
 | 
				
			||||||
    kaminari-core (1.2.2)
 | 
					    kaminari-core (1.2.2)
 | 
				
			||||||
    kt-paperclip (7.0.1)
 | 
					    kt-paperclip (7.1.1)
 | 
				
			||||||
      activemodel (>= 4.2.0)
 | 
					      activemodel (>= 4.2.0)
 | 
				
			||||||
      activesupport (>= 4.2.0)
 | 
					      activesupport (>= 4.2.0)
 | 
				
			||||||
      marcel (~> 1.0.1)
 | 
					      marcel (~> 1.0.1)
 | 
				
			||||||
| 
						 | 
					@ -356,14 +356,14 @@ GEM
 | 
				
			||||||
      activesupport (>= 4)
 | 
					      activesupport (>= 4)
 | 
				
			||||||
      railties (>= 4)
 | 
					      railties (>= 4)
 | 
				
			||||||
      request_store (~> 1.0)
 | 
					      request_store (~> 1.0)
 | 
				
			||||||
    loofah (2.13.0)
 | 
					    loofah (2.14.0)
 | 
				
			||||||
      crass (~> 1.0.2)
 | 
					      crass (~> 1.0.2)
 | 
				
			||||||
      nokogiri (>= 1.5.9)
 | 
					      nokogiri (>= 1.5.9)
 | 
				
			||||||
    mail (2.7.1)
 | 
					    mail (2.7.1)
 | 
				
			||||||
      mini_mime (>= 0.1.1)
 | 
					      mini_mime (>= 0.1.1)
 | 
				
			||||||
    makara (0.5.1)
 | 
					    makara (0.5.1)
 | 
				
			||||||
      activerecord (>= 5.2.0)
 | 
					      activerecord (>= 5.2.0)
 | 
				
			||||||
    marcel (1.0.1)
 | 
					    marcel (1.0.2)
 | 
				
			||||||
    mario-redis-lock (1.2.1)
 | 
					    mario-redis-lock (1.2.1)
 | 
				
			||||||
      redis (>= 3.0.5)
 | 
					      redis (>= 3.0.5)
 | 
				
			||||||
    matrix (0.4.2)
 | 
					    matrix (0.4.2)
 | 
				
			||||||
| 
						 | 
					@ -374,7 +374,7 @@ GEM
 | 
				
			||||||
      nokogiri (~> 1.10)
 | 
					      nokogiri (~> 1.10)
 | 
				
			||||||
    mime-types (3.4.1)
 | 
					    mime-types (3.4.1)
 | 
				
			||||||
      mime-types-data (~> 3.2015)
 | 
					      mime-types-data (~> 3.2015)
 | 
				
			||||||
    mime-types-data (3.2021.1115)
 | 
					    mime-types-data (3.2022.0105)
 | 
				
			||||||
    mini_mime (1.1.2)
 | 
					    mini_mime (1.1.2)
 | 
				
			||||||
    mini_portile2 (2.7.1)
 | 
					    mini_portile2 (2.7.1)
 | 
				
			||||||
    minitest (5.15.0)
 | 
					    minitest (5.15.0)
 | 
				
			||||||
| 
						 | 
					@ -418,7 +418,7 @@ GEM
 | 
				
			||||||
    parslet (2.0.0)
 | 
					    parslet (2.0.0)
 | 
				
			||||||
    pastel (0.8.0)
 | 
					    pastel (0.8.0)
 | 
				
			||||||
      tty-color (~> 0.5)
 | 
					      tty-color (~> 0.5)
 | 
				
			||||||
    pg (1.3.1)
 | 
					    pg (1.3.2)
 | 
				
			||||||
    pghero (2.8.2)
 | 
					    pghero (2.8.2)
 | 
				
			||||||
      activerecord (>= 5)
 | 
					      activerecord (>= 5)
 | 
				
			||||||
    pkg-config (1.4.7)
 | 
					    pkg-config (1.4.7)
 | 
				
			||||||
| 
						 | 
					@ -455,20 +455,20 @@ GEM
 | 
				
			||||||
      rack
 | 
					      rack
 | 
				
			||||||
    rack-test (1.1.0)
 | 
					    rack-test (1.1.0)
 | 
				
			||||||
      rack (>= 1.0, < 3)
 | 
					      rack (>= 1.0, < 3)
 | 
				
			||||||
    rails (6.1.4.4)
 | 
					    rails (6.1.4.6)
 | 
				
			||||||
      actioncable (= 6.1.4.4)
 | 
					      actioncable (= 6.1.4.6)
 | 
				
			||||||
      actionmailbox (= 6.1.4.4)
 | 
					      actionmailbox (= 6.1.4.6)
 | 
				
			||||||
      actionmailer (= 6.1.4.4)
 | 
					      actionmailer (= 6.1.4.6)
 | 
				
			||||||
      actionpack (= 6.1.4.4)
 | 
					      actionpack (= 6.1.4.6)
 | 
				
			||||||
      actiontext (= 6.1.4.4)
 | 
					      actiontext (= 6.1.4.6)
 | 
				
			||||||
      actionview (= 6.1.4.4)
 | 
					      actionview (= 6.1.4.6)
 | 
				
			||||||
      activejob (= 6.1.4.4)
 | 
					      activejob (= 6.1.4.6)
 | 
				
			||||||
      activemodel (= 6.1.4.4)
 | 
					      activemodel (= 6.1.4.6)
 | 
				
			||||||
      activerecord (= 6.1.4.4)
 | 
					      activerecord (= 6.1.4.6)
 | 
				
			||||||
      activestorage (= 6.1.4.4)
 | 
					      activestorage (= 6.1.4.6)
 | 
				
			||||||
      activesupport (= 6.1.4.4)
 | 
					      activesupport (= 6.1.4.6)
 | 
				
			||||||
      bundler (>= 1.15.0)
 | 
					      bundler (>= 1.15.0)
 | 
				
			||||||
      railties (= 6.1.4.4)
 | 
					      railties (= 6.1.4.6)
 | 
				
			||||||
      sprockets-rails (>= 2.0.0)
 | 
					      sprockets-rails (>= 2.0.0)
 | 
				
			||||||
    rails-controller-testing (1.0.5)
 | 
					    rails-controller-testing (1.0.5)
 | 
				
			||||||
      actionpack (>= 5.0.1.rc1)
 | 
					      actionpack (>= 5.0.1.rc1)
 | 
				
			||||||
| 
						 | 
					@ -484,9 +484,9 @@ GEM
 | 
				
			||||||
      railties (>= 6.0.0, < 7)
 | 
					      railties (>= 6.0.0, < 7)
 | 
				
			||||||
    rails-settings-cached (0.6.6)
 | 
					    rails-settings-cached (0.6.6)
 | 
				
			||||||
      rails (>= 4.2.0)
 | 
					      rails (>= 4.2.0)
 | 
				
			||||||
    railties (6.1.4.4)
 | 
					    railties (6.1.4.6)
 | 
				
			||||||
      actionpack (= 6.1.4.4)
 | 
					      actionpack (= 6.1.4.6)
 | 
				
			||||||
      activesupport (= 6.1.4.4)
 | 
					      activesupport (= 6.1.4.6)
 | 
				
			||||||
      method_source
 | 
					      method_source
 | 
				
			||||||
      rake (>= 0.13)
 | 
					      rake (>= 0.13)
 | 
				
			||||||
      thor (~> 1.0)
 | 
					      thor (~> 1.0)
 | 
				
			||||||
| 
						 | 
					@ -509,19 +509,19 @@ GEM
 | 
				
			||||||
    rexml (3.2.5)
 | 
					    rexml (3.2.5)
 | 
				
			||||||
    rotp (6.2.0)
 | 
					    rotp (6.2.0)
 | 
				
			||||||
    rpam2 (4.0.2)
 | 
					    rpam2 (4.0.2)
 | 
				
			||||||
    rqrcode (2.1.0)
 | 
					    rqrcode (2.1.1)
 | 
				
			||||||
      chunky_png (~> 1.0)
 | 
					      chunky_png (~> 1.0)
 | 
				
			||||||
      rqrcode_core (~> 1.0)
 | 
					      rqrcode_core (~> 1.0)
 | 
				
			||||||
    rqrcode_core (1.2.0)
 | 
					    rqrcode_core (1.2.0)
 | 
				
			||||||
    rspec-core (3.10.1)
 | 
					    rspec-core (3.11.0)
 | 
				
			||||||
      rspec-support (~> 3.10.0)
 | 
					      rspec-support (~> 3.11.0)
 | 
				
			||||||
    rspec-expectations (3.10.1)
 | 
					    rspec-expectations (3.11.0)
 | 
				
			||||||
      diff-lcs (>= 1.2.0, < 2.0)
 | 
					      diff-lcs (>= 1.2.0, < 2.0)
 | 
				
			||||||
      rspec-support (~> 3.10.0)
 | 
					      rspec-support (~> 3.11.0)
 | 
				
			||||||
    rspec-mocks (3.10.2)
 | 
					    rspec-mocks (3.11.0)
 | 
				
			||||||
      diff-lcs (>= 1.2.0, < 2.0)
 | 
					      diff-lcs (>= 1.2.0, < 2.0)
 | 
				
			||||||
      rspec-support (~> 3.10.0)
 | 
					      rspec-support (~> 3.11.0)
 | 
				
			||||||
    rspec-rails (5.0.2)
 | 
					    rspec-rails (5.1.0)
 | 
				
			||||||
      actionpack (>= 5.2)
 | 
					      actionpack (>= 5.2)
 | 
				
			||||||
      activesupport (>= 5.2)
 | 
					      activesupport (>= 5.2)
 | 
				
			||||||
      railties (>= 5.2)
 | 
					      railties (>= 5.2)
 | 
				
			||||||
| 
						 | 
					@ -532,7 +532,7 @@ GEM
 | 
				
			||||||
    rspec-sidekiq (3.1.0)
 | 
					    rspec-sidekiq (3.1.0)
 | 
				
			||||||
      rspec-core (~> 3.0, >= 3.0.0)
 | 
					      rspec-core (~> 3.0, >= 3.0.0)
 | 
				
			||||||
      sidekiq (>= 2.4.0)
 | 
					      sidekiq (>= 2.4.0)
 | 
				
			||||||
    rspec-support (3.10.3)
 | 
					    rspec-support (3.11.0)
 | 
				
			||||||
    rspec_junit_formatter (0.5.1)
 | 
					    rspec_junit_formatter (0.5.1)
 | 
				
			||||||
      rspec-core (>= 2, < 4, != 2.12.0)
 | 
					      rspec-core (>= 2, < 4, != 2.12.0)
 | 
				
			||||||
    rubocop (1.25.1)
 | 
					    rubocop (1.25.1)
 | 
				
			||||||
| 
						 | 
					@ -562,7 +562,7 @@ GEM
 | 
				
			||||||
    sanitize (6.0.0)
 | 
					    sanitize (6.0.0)
 | 
				
			||||||
      crass (~> 1.0.2)
 | 
					      crass (~> 1.0.2)
 | 
				
			||||||
      nokogiri (>= 1.12.0)
 | 
					      nokogiri (>= 1.12.0)
 | 
				
			||||||
    scenic (1.5.5)
 | 
					    scenic (1.6.0)
 | 
				
			||||||
      activerecord (>= 4.0.0)
 | 
					      activerecord (>= 4.0.0)
 | 
				
			||||||
      railties (>= 4.0.0)
 | 
					      railties (>= 4.0.0)
 | 
				
			||||||
    securecompare (1.0.0)
 | 
					    securecompare (1.0.0)
 | 
				
			||||||
| 
						 | 
					@ -685,7 +685,7 @@ DEPENDENCIES
 | 
				
			||||||
  active_model_serializers (~> 0.10)
 | 
					  active_model_serializers (~> 0.10)
 | 
				
			||||||
  active_record_query_trace (~> 1.8)
 | 
					  active_record_query_trace (~> 1.8)
 | 
				
			||||||
  addressable (~> 2.8)
 | 
					  addressable (~> 2.8)
 | 
				
			||||||
  annotate (~> 3.1)
 | 
					  annotate (~> 3.2)
 | 
				
			||||||
  aws-sdk-s3 (~> 1.112)
 | 
					  aws-sdk-s3 (~> 1.112)
 | 
				
			||||||
  better_errors (~> 2.9)
 | 
					  better_errors (~> 2.9)
 | 
				
			||||||
  binding_of_caller (~> 1.0)
 | 
					  binding_of_caller (~> 1.0)
 | 
				
			||||||
| 
						 | 
					@ -732,7 +732,7 @@ DEPENDENCIES
 | 
				
			||||||
  json-ld
 | 
					  json-ld
 | 
				
			||||||
  json-ld-preloaded (~> 3.2)
 | 
					  json-ld-preloaded (~> 3.2)
 | 
				
			||||||
  kaminari (~> 1.2)
 | 
					  kaminari (~> 1.2)
 | 
				
			||||||
  kt-paperclip (~> 7.0)
 | 
					  kt-paperclip (~> 7.1)
 | 
				
			||||||
  letter_opener (~> 1.7)
 | 
					  letter_opener (~> 1.7)
 | 
				
			||||||
  letter_opener_web (~> 2.0)
 | 
					  letter_opener_web (~> 2.0)
 | 
				
			||||||
  link_header (~> 0.0)
 | 
					  link_header (~> 0.0)
 | 
				
			||||||
| 
						 | 
					@ -775,14 +775,14 @@ DEPENDENCIES
 | 
				
			||||||
  redis-namespace (~> 1.8)
 | 
					  redis-namespace (~> 1.8)
 | 
				
			||||||
  rexml (~> 3.2)
 | 
					  rexml (~> 3.2)
 | 
				
			||||||
  rqrcode (~> 2.1)
 | 
					  rqrcode (~> 2.1)
 | 
				
			||||||
  rspec-rails (~> 5.0)
 | 
					  rspec-rails (~> 5.1)
 | 
				
			||||||
  rspec-sidekiq (~> 3.1)
 | 
					  rspec-sidekiq (~> 3.1)
 | 
				
			||||||
  rspec_junit_formatter (~> 0.5)
 | 
					  rspec_junit_formatter (~> 0.5)
 | 
				
			||||||
  rubocop (~> 1.25)
 | 
					  rubocop (~> 1.25)
 | 
				
			||||||
  rubocop-rails (~> 2.13)
 | 
					  rubocop-rails (~> 2.13)
 | 
				
			||||||
  ruby-progressbar (~> 1.11)
 | 
					  ruby-progressbar (~> 1.11)
 | 
				
			||||||
  sanitize (~> 6.0)
 | 
					  sanitize (~> 6.0)
 | 
				
			||||||
  scenic (~> 1.5)
 | 
					  scenic (~> 1.6)
 | 
				
			||||||
  sidekiq (~> 6.4)
 | 
					  sidekiq (~> 6.4)
 | 
				
			||||||
  sidekiq-bulk (~> 0.2.0)
 | 
					  sidekiq-bulk (~> 0.2.0)
 | 
				
			||||||
  sidekiq-scheduler (~> 3.1)
 | 
					  sidekiq-scheduler (~> 3.1)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								Vagrantfile
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								Vagrantfile
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -33,11 +33,9 @@ sudo apt-get install \
 | 
				
			||||||
  redis-tools \
 | 
					  redis-tools \
 | 
				
			||||||
  postgresql \
 | 
					  postgresql \
 | 
				
			||||||
  postgresql-contrib \
 | 
					  postgresql-contrib \
 | 
				
			||||||
  protobuf-compiler \
 | 
					 | 
				
			||||||
  yarn \
 | 
					  yarn \
 | 
				
			||||||
  libicu-dev \
 | 
					  libicu-dev \
 | 
				
			||||||
  libidn11-dev \
 | 
					  libidn11-dev \
 | 
				
			||||||
  libprotobuf-dev \
 | 
					 | 
				
			||||||
  libreadline-dev \
 | 
					  libreadline-dev \
 | 
				
			||||||
  libpam0g-dev \
 | 
					  libpam0g-dev \
 | 
				
			||||||
  -y
 | 
					  -y
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@ module Admin
 | 
				
			||||||
      @deletion_request        = @account.deletion_request
 | 
					      @deletion_request        = @account.deletion_request
 | 
				
			||||||
      @account_moderation_note = current_account.account_moderation_notes.new(target_account: @account)
 | 
					      @account_moderation_note = current_account.account_moderation_notes.new(target_account: @account)
 | 
				
			||||||
      @moderation_notes        = @account.targeted_moderation_notes.latest
 | 
					      @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)
 | 
					      @domain_block            = DomainBlock.rule_for(@account.domain)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -146,7 +146,7 @@ module Admin
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def filter_params
 | 
					    def filter_params
 | 
				
			||||||
      params.slice(*AccountFilter::KEYS).permit(*AccountFilter::KEYS)
 | 
					      params.slice(:page, *AccountFilter::KEYS).permit(:page, *AccountFilter::KEYS)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def form_account_batch_params
 | 
					    def form_account_batch_params
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@ module Admin
 | 
				
			||||||
      @pending_users_count   = User.pending.count
 | 
					      @pending_users_count   = User.pending.count
 | 
				
			||||||
      @pending_reports_count = Report.unresolved.count
 | 
					      @pending_reports_count = Report.unresolved.count
 | 
				
			||||||
      @pending_tags_count    = Tag.pending_review.count
 | 
					      @pending_tags_count    = Tag.pending_review.count
 | 
				
			||||||
 | 
					      @pending_appeals_count = Appeal.pending.count
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private
 | 
					    private
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										40
									
								
								app/controllers/admin/disputes/appeals_controller.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								app/controllers/admin/disputes/appeals_controller.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
 | 
				
			||||||
  before_action :configure_sign_up_params, only: [:create]
 | 
					  before_action :configure_sign_up_params, only: [:create]
 | 
				
			||||||
  before_action :set_pack
 | 
					  before_action :set_pack
 | 
				
			||||||
  before_action :set_sessions, only: [:edit, :update]
 | 
					  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_instance_presenter, only: [:new, :create, :update]
 | 
				
			||||||
  before_action :set_body_classes, only: [:new, :create, :edit, :update]
 | 
					  before_action :set_body_classes, only: [:new, :create, :edit, :update]
 | 
				
			||||||
  before_action :require_not_suspended!, only: [:update]
 | 
					  before_action :require_not_suspended!, only: [:update]
 | 
				
			||||||
| 
						 | 
					@ -116,8 +117,10 @@ class Auth::RegistrationsController < Devise::RegistrationsController
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def set_invite
 | 
					  def set_invite
 | 
				
			||||||
    invite = invite_code.present? ? Invite.find_by(code: invite_code) : nil
 | 
					    @invite = begin
 | 
				
			||||||
    @invite = invite&.valid_for_use? ? invite : nil
 | 
					      invite = Invite.find_by(code: invite_code) if invite_code.present?
 | 
				
			||||||
 | 
					      invite if invite&.valid_for_use?
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def determine_layout
 | 
					  def determine_layout
 | 
				
			||||||
| 
						 | 
					@ -128,6 +131,10 @@ class Auth::RegistrationsController < Devise::RegistrationsController
 | 
				
			||||||
    @sessions = current_user.session_activations
 | 
					    @sessions = current_user.session_activations
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def set_strikes
 | 
				
			||||||
 | 
					    @strikes = current_account.strikes.active.latest
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def require_not_suspended!
 | 
					  def require_not_suspended!
 | 
				
			||||||
    forbidden if current_account.suspended?
 | 
					    forbidden if current_account.suspended?
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										26
									
								
								app/controllers/disputes/appeals_controller.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								app/controllers/disputes/appeals_controller.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					# 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 => e
 | 
				
			||||||
 | 
					    @appeal = e.record
 | 
				
			||||||
 | 
					    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
 | 
				
			||||||
							
								
								
									
										23
									
								
								app/controllers/disputes/base_controller.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								app/controllers/disputes/base_controller.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,23 @@
 | 
				
			||||||
 | 
					# 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!
 | 
				
			||||||
 | 
					  before_action :set_pack
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def set_pack
 | 
				
			||||||
 | 
					    use_pack 'admin'
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def set_body_classes
 | 
				
			||||||
 | 
					    @body_classes = 'admin'
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										17
									
								
								app/controllers/disputes/strikes_controller.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								app/controllers/disputes/strikes_controller.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,10 @@
 | 
				
			||||||
# frozen_string_literal: true
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module Admin::AccountModerationNotesHelper
 | 
					module Admin::AccountModerationNotesHelper
 | 
				
			||||||
  def admin_account_link_to(account)
 | 
					  def admin_account_link_to(account, path: nil)
 | 
				
			||||||
    return if account.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([
 | 
					      safe_join([
 | 
				
			||||||
                  image_tag(account.avatar.url, width: 15, height: 15, alt: display_name(account), class: 'avatar'),
 | 
					                  image_tag(account.avatar.url, width: 15, height: 15, alt: display_name(account), class: 'avatar'),
 | 
				
			||||||
                  content_tag(:span, account.acct, class: 'username'),
 | 
					                  content_tag(:span, account.acct, class: 'username'),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +33,8 @@ module Admin::ActionLogsHelper
 | 
				
			||||||
      "#{record.ip}/#{record.ip.prefix} (#{I18n.t("simple_form.labels.ip_block.severities.#{record.severity}")})"
 | 
					      "#{record.ip}/#{record.ip.prefix} (#{I18n.t("simple_form.labels.ip_block.severities.#{record.severity}")})"
 | 
				
			||||||
    when 'Instance'
 | 
					    when 'Instance'
 | 
				
			||||||
      record.domain
 | 
					      record.domain
 | 
				
			||||||
 | 
					    when 'Appeal'
 | 
				
			||||||
 | 
					      link_to record.account.acct, disputes_strike_path(record.strike)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										20
									
								
								app/helpers/admin/trends/statuses_helper.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								app/helpers/admin/trends/statuses_helper.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					@ -250,7 +250,7 @@ class EmojiPickerMenu extends React.PureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  state = {
 | 
					  state = {
 | 
				
			||||||
    modifierOpen: false,
 | 
					    modifierOpen: false,
 | 
				
			||||||
    placement: null,
 | 
					    readyToFocus: false,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handleDocumentClick = e => {
 | 
					  handleDocumentClick = e => {
 | 
				
			||||||
| 
						 | 
					@ -262,6 +262,16 @@ class EmojiPickerMenu extends React.PureComponent {
 | 
				
			||||||
  componentDidMount () {
 | 
					  componentDidMount () {
 | 
				
			||||||
    document.addEventListener('click', this.handleDocumentClick, false);
 | 
					    document.addEventListener('click', this.handleDocumentClick, false);
 | 
				
			||||||
    document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
 | 
					    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 () {
 | 
					  componentWillUnmount () {
 | 
				
			||||||
| 
						 | 
					@ -361,7 +371,7 @@ class EmojiPickerMenu extends React.PureComponent {
 | 
				
			||||||
          showSkinTones={false}
 | 
					          showSkinTones={false}
 | 
				
			||||||
          backgroundImageFn={backgroundImageFn}
 | 
					          backgroundImageFn={backgroundImageFn}
 | 
				
			||||||
          notFound={notFoundFn}
 | 
					          notFound={notFoundFn}
 | 
				
			||||||
          autoFocus
 | 
					          autoFocus={this.state.readyToFocus}
 | 
				
			||||||
          emojiTooltip
 | 
					          emojiTooltip
 | 
				
			||||||
          native={useSystemEmojiFont}
 | 
					          native={useSystemEmojiFont}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
| 
						 | 
					@ -396,6 +406,7 @@ class EmojiPickerDropdown extends React.PureComponent {
 | 
				
			||||||
  state = {
 | 
					  state = {
 | 
				
			||||||
    active: false,
 | 
					    active: false,
 | 
				
			||||||
    loading: false,
 | 
					    loading: false,
 | 
				
			||||||
 | 
					    placement: null,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  setRef = (c) => {
 | 
					  setRef = (c) => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -147,13 +147,7 @@ function main() {
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  delegate(document, '.sidebar__toggle__icon', 'click', () => {
 | 
					  delegate(document, '.sidebar__toggle__icon', 'click', () => {
 | 
				
			||||||
    const target = document.querySelector('.sidebar ul');
 | 
					    document.querySelector('.sidebar ul').classList.toggle('visible');
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (target.style.display === 'block') {
 | 
					 | 
				
			||||||
      target.style.display = 'none';
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      target.style.display = 'block';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Empty the honeypot fields in JS in case something like an extension
 | 
					  // Empty the honeypot fields in JS in case something like an extension
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,13 +7,7 @@ function main() {
 | 
				
			||||||
  const { delegate } = require('@rails/ujs');
 | 
					  const { delegate } = require('@rails/ujs');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  delegate(document, '.sidebar__toggle__icon', 'click', () => {
 | 
					  delegate(document, '.sidebar__toggle__icon', 'click', () => {
 | 
				
			||||||
    const target = document.querySelector('.sidebar ul');
 | 
					    document.querySelector('.sidebar ul').classList.toggle('visible');
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (target.style.display === 'block') {
 | 
					 | 
				
			||||||
      target.style.display = 'none';
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      target.style.display = 'block';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -322,6 +322,10 @@ $content-width: 840px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      & > ul {
 | 
					      & > ul {
 | 
				
			||||||
        display: none;
 | 
					        display: none;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        &.visible {
 | 
				
			||||||
 | 
					          display: block;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      ul a,
 | 
					      ul a,
 | 
				
			||||||
| 
						 | 
					@ -594,12 +598,16 @@ body,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.log-entry {
 | 
					.log-entry {
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
  line-height: 20px;
 | 
					  line-height: 20px;
 | 
				
			||||||
  padding: 15px;
 | 
					  padding: 15px;
 | 
				
			||||||
  padding-left: 15px * 2 + 40px;
 | 
					  padding-left: 15px * 2 + 40px;
 | 
				
			||||||
  background: $ui-base-color;
 | 
					  background: $ui-base-color;
 | 
				
			||||||
  border-bottom: 1px solid darken($ui-base-color, 8%);
 | 
					  border-bottom: 1px solid darken($ui-base-color, 8%);
 | 
				
			||||||
  position: relative;
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  text-decoration: none;
 | 
				
			||||||
 | 
					  color: $darker-text-color;
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &:first-child {
 | 
					  &:first-child {
 | 
				
			||||||
    border-top-left-radius: 4px;
 | 
					    border-top-left-radius: 4px;
 | 
				
			||||||
| 
						 | 
					@ -612,15 +620,12 @@ body,
 | 
				
			||||||
    border-bottom: 0;
 | 
					    border-bottom: 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &:hover {
 | 
					  &:hover,
 | 
				
			||||||
 | 
					  &:focus,
 | 
				
			||||||
 | 
					  &:active {
 | 
				
			||||||
    background: lighten($ui-base-color, 4%);
 | 
					    background: lighten($ui-base-color, 4%);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &__header {
 | 
					 | 
				
			||||||
    color: $darker-text-color;
 | 
					 | 
				
			||||||
    font-size: 14px;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  &__avatar {
 | 
					  &__avatar {
 | 
				
			||||||
    position: absolute;
 | 
					    position: absolute;
 | 
				
			||||||
    left: 15px;
 | 
					    left: 15px;
 | 
				
			||||||
| 
						 | 
					@ -656,6 +661,18 @@ body,
 | 
				
			||||||
      text-decoration: underline;
 | 
					      text-decoration: underline;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &--inactive {
 | 
				
			||||||
 | 
					    .log-entry__title {
 | 
				
			||||||
 | 
					      text-decoration: line-through;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    a,
 | 
				
			||||||
 | 
					    .username,
 | 
				
			||||||
 | 
					    .target {
 | 
				
			||||||
 | 
					      color: $darker-text-color;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
a.name-tag,
 | 
					a.name-tag,
 | 
				
			||||||
| 
						 | 
					@ -1191,6 +1208,17 @@ a.sparkline {
 | 
				
			||||||
        font-weight: 600;
 | 
					        font-weight: 600;
 | 
				
			||||||
        padding: 4px 0;
 | 
					        padding: 4px 0;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      a {
 | 
				
			||||||
 | 
					        color: $ui-highlight-color;
 | 
				
			||||||
 | 
					        text-decoration: none;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        &:hover,
 | 
				
			||||||
 | 
					        &:focus,
 | 
				
			||||||
 | 
					        &:active {
 | 
				
			||||||
 | 
					          text-decoration: underline;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    &--horizontal {
 | 
					    &--horizontal {
 | 
				
			||||||
| 
						 | 
					@ -1467,3 +1495,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;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -90,6 +90,20 @@
 | 
				
			||||||
        .column-4 {
 | 
					        .column-4 {
 | 
				
			||||||
          display: none;
 | 
					          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;
 | 
					      text-decoration: none;
 | 
				
			||||||
      color: lighten($ui-base-color, 34%);
 | 
					      color: lighten($ui-base-color, 34%);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -170,7 +170,7 @@ class EmojiPickerMenu extends React.PureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  state = {
 | 
					  state = {
 | 
				
			||||||
    modifierOpen: false,
 | 
					    modifierOpen: false,
 | 
				
			||||||
    placement: null,
 | 
					    readyToFocus: false,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handleDocumentClick = e => {
 | 
					  handleDocumentClick = e => {
 | 
				
			||||||
| 
						 | 
					@ -182,6 +182,16 @@ class EmojiPickerMenu extends React.PureComponent {
 | 
				
			||||||
  componentDidMount () {
 | 
					  componentDidMount () {
 | 
				
			||||||
    document.addEventListener('click', this.handleDocumentClick, false);
 | 
					    document.addEventListener('click', this.handleDocumentClick, false);
 | 
				
			||||||
    document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
 | 
					    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 () {
 | 
					  componentWillUnmount () {
 | 
				
			||||||
| 
						 | 
					@ -281,7 +291,7 @@ class EmojiPickerMenu extends React.PureComponent {
 | 
				
			||||||
          showSkinTones={false}
 | 
					          showSkinTones={false}
 | 
				
			||||||
          backgroundImageFn={backgroundImageFn}
 | 
					          backgroundImageFn={backgroundImageFn}
 | 
				
			||||||
          notFound={notFoundFn}
 | 
					          notFound={notFoundFn}
 | 
				
			||||||
          autoFocus
 | 
					          autoFocus={this.state.readyToFocus}
 | 
				
			||||||
          emojiTooltip
 | 
					          emojiTooltip
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -314,6 +324,7 @@ class EmojiPickerDropdown extends React.PureComponent {
 | 
				
			||||||
  state = {
 | 
					  state = {
 | 
				
			||||||
    active: false,
 | 
					    active: false,
 | 
				
			||||||
    loading: false,
 | 
					    loading: false,
 | 
				
			||||||
 | 
					    placement: null,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  setRef = (c) => {
 | 
					  setRef = (c) => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -151,13 +151,7 @@ function main() {
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  delegate(document, '.sidebar__toggle__icon', 'click', () => {
 | 
					  delegate(document, '.sidebar__toggle__icon', 'click', () => {
 | 
				
			||||||
    const target = document.querySelector('.sidebar ul');
 | 
					    document.querySelector('.sidebar ul').classList.toggle('visible');
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (target.style.display === 'block') {
 | 
					 | 
				
			||||||
      target.style.display = 'none';
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      target.style.display = 'block';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Empty the honeypot fields in JS in case something like an extension
 | 
					  // Empty the honeypot fields in JS in case something like an extension
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -322,6 +322,10 @@ $content-width: 840px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      & > ul {
 | 
					      & > ul {
 | 
				
			||||||
        display: none;
 | 
					        display: none;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        &.visible {
 | 
				
			||||||
 | 
					          display: block;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      ul a,
 | 
					      ul a,
 | 
				
			||||||
| 
						 | 
					@ -594,12 +598,16 @@ body,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.log-entry {
 | 
					.log-entry {
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
  line-height: 20px;
 | 
					  line-height: 20px;
 | 
				
			||||||
  padding: 15px;
 | 
					  padding: 15px;
 | 
				
			||||||
  padding-left: 15px * 2 + 40px;
 | 
					  padding-left: 15px * 2 + 40px;
 | 
				
			||||||
  background: $ui-base-color;
 | 
					  background: $ui-base-color;
 | 
				
			||||||
  border-bottom: 1px solid darken($ui-base-color, 8%);
 | 
					  border-bottom: 1px solid darken($ui-base-color, 8%);
 | 
				
			||||||
  position: relative;
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  text-decoration: none;
 | 
				
			||||||
 | 
					  color: $darker-text-color;
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &:first-child {
 | 
					  &:first-child {
 | 
				
			||||||
    border-top-left-radius: 4px;
 | 
					    border-top-left-radius: 4px;
 | 
				
			||||||
| 
						 | 
					@ -612,15 +620,12 @@ body,
 | 
				
			||||||
    border-bottom: 0;
 | 
					    border-bottom: 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &:hover {
 | 
					  &:hover,
 | 
				
			||||||
 | 
					  &:focus,
 | 
				
			||||||
 | 
					  &:active {
 | 
				
			||||||
    background: lighten($ui-base-color, 4%);
 | 
					    background: lighten($ui-base-color, 4%);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  &__header {
 | 
					 | 
				
			||||||
    color: $darker-text-color;
 | 
					 | 
				
			||||||
    font-size: 14px;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  &__avatar {
 | 
					  &__avatar {
 | 
				
			||||||
    position: absolute;
 | 
					    position: absolute;
 | 
				
			||||||
    left: 15px;
 | 
					    left: 15px;
 | 
				
			||||||
| 
						 | 
					@ -656,6 +661,18 @@ body,
 | 
				
			||||||
      text-decoration: underline;
 | 
					      text-decoration: underline;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &--inactive {
 | 
				
			||||||
 | 
					    .log-entry__title {
 | 
				
			||||||
 | 
					      text-decoration: line-through;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    a,
 | 
				
			||||||
 | 
					    .username,
 | 
				
			||||||
 | 
					    .target {
 | 
				
			||||||
 | 
					      color: $darker-text-color;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
a.name-tag,
 | 
					a.name-tag,
 | 
				
			||||||
| 
						 | 
					@ -1191,6 +1208,17 @@ a.sparkline {
 | 
				
			||||||
        font-weight: 600;
 | 
					        font-weight: 600;
 | 
				
			||||||
        padding: 4px 0;
 | 
					        padding: 4px 0;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      a {
 | 
				
			||||||
 | 
					        color: $ui-highlight-color;
 | 
				
			||||||
 | 
					        text-decoration: none;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        &:hover,
 | 
				
			||||||
 | 
					        &:focus,
 | 
				
			||||||
 | 
					        &:active {
 | 
				
			||||||
 | 
					          text-decoration: underline;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    &--horizontal {
 | 
					    &--horizontal {
 | 
				
			||||||
| 
						 | 
					@ -1467,3 +1495,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;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -90,6 +90,20 @@
 | 
				
			||||||
        .column-4 {
 | 
					        .column-4 {
 | 
				
			||||||
          display: none;
 | 
					          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;
 | 
					      text-decoration: none;
 | 
				
			||||||
      color: lighten($ui-base-color, 34%);
 | 
					      color: lighten($ui-base-color, 34%);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity
 | 
				
			||||||
      original_status = status_from_object
 | 
					      original_status = status_from_object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return reject_payload! if original_status.nil? || !announceable?(original_status)
 | 
					      return reject_payload! if original_status.nil? || !announceable?(original_status)
 | 
				
			||||||
 | 
					      return if requested_through_relay?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      @status = Status.find_by(account: @account, reblog: original_status)
 | 
					      @status = Status.find_by(account: @account, reblog: original_status)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -499,7 +499,7 @@ class FeedManager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return false if active_filters.empty?
 | 
					    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?
 | 
					    status         = status.reblog if status.reblog?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    combined_text = [
 | 
					    combined_text = [
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,19 +2,21 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SearchQueryTransformer < Parslet::Transform
 | 
					class SearchQueryTransformer < Parslet::Transform
 | 
				
			||||||
  class Query
 | 
					  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)
 | 
					    def initialize(clauses)
 | 
				
			||||||
      grouped = clauses.chunk(&:operator).to_h
 | 
					      grouped = clauses.chunk(&:operator).to_h
 | 
				
			||||||
      @should_clauses = grouped.fetch(:should, [])
 | 
					      @should_clauses = grouped.fetch(:should, [])
 | 
				
			||||||
      @must_not_clauses = grouped.fetch(:must_not, [])
 | 
					      @must_not_clauses = grouped.fetch(:must_not, [])
 | 
				
			||||||
      @must_clauses = grouped.fetch(:must, [])
 | 
					      @must_clauses = grouped.fetch(:must, [])
 | 
				
			||||||
 | 
					      @filter_clauses = grouped.fetch(:filter, [])
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def apply(search)
 | 
					    def apply(search)
 | 
				
			||||||
      should_clauses.each { |clause| search = search.query.should(clause_to_query(clause)) }
 | 
					      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_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)) }
 | 
					      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)
 | 
					      search.query.minimum_should_match(1)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,6 +32,15 @@ class SearchQueryTransformer < Parslet::Transform
 | 
				
			||||||
        raise "Unexpected clause type: #{clause}"
 | 
					        raise "Unexpected clause type: #{clause}"
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    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
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  class Operator
 | 
					  class Operator
 | 
				
			||||||
| 
						 | 
					@ -69,11 +80,33 @@ class SearchQueryTransformer < Parslet::Transform
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  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
 | 
					  rule(clause: subtree(:clause)) do
 | 
				
			||||||
    prefix   = clause[:prefix][:term].to_s if clause[:prefix]
 | 
					    prefix   = clause[:prefix][:term].to_s if clause[:prefix]
 | 
				
			||||||
    operator = clause[:operator]&.to_s
 | 
					    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)
 | 
					      TermClause.new(prefix, operator, clause[:term].to_s)
 | 
				
			||||||
    elsif clause[:shortcode]
 | 
					    elsif clause[:shortcode]
 | 
				
			||||||
      TermClause.new(prefix, operator, ":#{clause[:term]}:")
 | 
					      TermClause.new(prefix, operator, ":#{clause[:term]}:")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,16 @@ class AdminMailer < ApplicationMailer
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  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)
 | 
					  def new_pending_account(recipient, user)
 | 
				
			||||||
    @account  = user.account
 | 
					    @account  = user.account
 | 
				
			||||||
    @me       = recipient
 | 
					    @me       = recipient
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -173,6 +173,26 @@ class UserMailer < Devise::Mailer
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  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)
 | 
					  def sign_in_token(user, remote_ip, user_agent, timestamp)
 | 
				
			||||||
    @resource   = user
 | 
					    @resource   = user
 | 
				
			||||||
    @instance   = Rails.configuration.x.local_domain
 | 
					    @instance   = Rails.configuration.x.local_domain
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -274,6 +274,10 @@ class Account < ApplicationRecord
 | 
				
			||||||
    true
 | 
					    true
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def previous_strikes_count
 | 
				
			||||||
 | 
					    strikes.where(overruled_at: nil).count
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def keypair
 | 
					  def keypair
 | 
				
			||||||
    @keypair ||= OpenSSL::PKey::RSA.new(private_key || public_key)
 | 
					    @keypair ||= OpenSSL::PKey::RSA.new(private_key || public_key)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,8 @@ class AccountFilter
 | 
				
			||||||
    scope = Account.includes(:account_stat, user: [:ips, :invite_request]).without_instance_actor.reorder(nil)
 | 
					    scope = Account.includes(:account_stat, user: [:ips, :invite_request]).without_instance_actor.reorder(nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    params.each do |key, value|
 | 
					    params.each do |key, value|
 | 
				
			||||||
 | 
					      next if key.to_s == 'page'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      scope.merge!(scope_for(key, value.to_s.strip)) if value.present?
 | 
					      scope.merge!(scope_for(key, value.to_s.strip)) if value.present?
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,7 +51,7 @@ class AccountFilter
 | 
				
			||||||
    when 'email'
 | 
					    when 'email'
 | 
				
			||||||
      accounts_with_users.merge(User.matches_email(value))
 | 
					      accounts_with_users.merge(User.matches_email(value))
 | 
				
			||||||
    when 'ip'
 | 
					    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'
 | 
					    when 'invited_by'
 | 
				
			||||||
      invited_by_scope(value)
 | 
					      invited_by_scope(value)
 | 
				
			||||||
    when 'order'
 | 
					    when 'order'
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,7 @@
 | 
				
			||||||
#  updated_at        :datetime         not null
 | 
					#  updated_at        :datetime         not null
 | 
				
			||||||
#  report_id         :bigint(8)
 | 
					#  report_id         :bigint(8)
 | 
				
			||||||
#  status_ids        :string           is an Array
 | 
					#  status_ids        :string           is an Array
 | 
				
			||||||
 | 
					#  overruled_at      :datetime
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AccountWarning < ApplicationRecord
 | 
					class AccountWarning < ApplicationRecord
 | 
				
			||||||
| 
						 | 
					@ -28,12 +29,17 @@ class AccountWarning < ApplicationRecord
 | 
				
			||||||
  belongs_to :target_account, class_name: 'Account', inverse_of: :strikes
 | 
					  belongs_to :target_account, class_name: 'Account', inverse_of: :strikes
 | 
				
			||||||
  belongs_to :report, optional: true
 | 
					  belongs_to :report, optional: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  has_one :appeal, dependent: :destroy
 | 
					  has_one :appeal, dependent: :destroy, inverse_of: :strike
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  scope :latest, -> { order(id: :desc) }
 | 
					  scope :latest, -> { order(id: :desc) }
 | 
				
			||||||
  scope :custom, -> { where.not(text: '') }
 | 
					  scope :custom, -> { where.not(text: '') }
 | 
				
			||||||
 | 
					  scope :active, -> { where(overruled_at: nil).or(where('account_warnings.overruled_at >= ?', 30.days.ago)) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def statuses
 | 
					  def statuses
 | 
				
			||||||
    Status.with_discarded.where(id: status_ids || [])
 | 
					    Status.with_discarded.where(id: status_ids || [])
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def overruled?
 | 
				
			||||||
 | 
					    overruled_at.present?
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,8 @@ class Admin::ActionLogFilter
 | 
				
			||||||
  ).freeze
 | 
					  ).freeze
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ACTION_TYPE_MAP = {
 | 
					  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,
 | 
					    assigned_to_self_report: { target_type: 'Report', action: 'assigned_to_self' }.freeze,
 | 
				
			||||||
    change_email_user: { target_type: 'User', action: 'change_email' }.freeze,
 | 
					    change_email_user: { target_type: 'User', action: 'change_email' }.freeze,
 | 
				
			||||||
    confirm_user: { target_type: 'User', action: 'confirm' }.freeze,
 | 
					    confirm_user: { target_type: 'User', action: 'confirm' }.freeze,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										49
									
								
								app/models/admin/appeal_filter.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								app/models/admin/appeal_filter.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					@ -31,7 +31,7 @@ class Admin::StatusFilter
 | 
				
			||||||
  def scope_for(key, value)
 | 
					  def scope_for(key, value)
 | 
				
			||||||
    case key.to_s
 | 
					    case key.to_s
 | 
				
			||||||
    when 'media'
 | 
					    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'
 | 
					    when 'id'
 | 
				
			||||||
      Status.where(id: value)
 | 
					      Status.where(id: value)
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										60
									
								
								app/models/appeal.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								app/models/appeal.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,60 @@
 | 
				
			||||||
 | 
					# 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
 | 
				
			||||||
 | 
					  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
 | 
				
			||||||
 | 
					  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 strike.created_at < MAX_STRIKE_AGE.ago
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					@ -111,7 +111,7 @@ class User < ApplicationRecord
 | 
				
			||||||
  scope :inactive, -> { where(arel_table[:current_sign_in_at].lt(ACTIVE_DURATION.ago)) }
 | 
					  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 :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_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) }
 | 
					  scope :emailable, -> { confirmed.enabled.joins(:account).merge(Account.searchable) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  before_validation :sanitize_languages
 | 
					  before_validation :sanitize_languages
 | 
				
			||||||
| 
						 | 
					@ -265,6 +265,10 @@ class User < ApplicationRecord
 | 
				
			||||||
    settings.notification_emails['pending_account']
 | 
					    settings.notification_emails['pending_account']
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def allows_appeal_emails?
 | 
				
			||||||
 | 
					    settings.notification_emails['appeal']
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def allows_trending_tag_emails?
 | 
					  def allows_trending_tag_emails?
 | 
				
			||||||
    settings.notification_emails['trending_tag']
 | 
					    settings.notification_emails['trending_tag']
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										17
									
								
								app/policies/account_warning_policy.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								app/policies/account_warning_policy.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AccountWarningPolicy < ApplicationPolicy
 | 
				
			||||||
 | 
					  def show?
 | 
				
			||||||
 | 
					    target? || staff?
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def appeal?
 | 
				
			||||||
 | 
					    target? && record.created_at >= Appeal::MAX_STRIKE_AGE.ago
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def target?
 | 
				
			||||||
 | 
					    record.target_account_id == current_account&.id
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										13
									
								
								app/policies/appeal_policy.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								app/policies/appeal_policy.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										28
									
								
								app/services/appeal_service.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								app/services/appeal_service.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										74
									
								
								app/services/approve_appeal_service.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								app/services/approve_appeal_service.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					@ -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)
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,24 @@
 | 
				
			||||||
.speech-bubble.warning
 | 
					= link_to disputes_strike_path(account_warning), class: ['log-entry', account_warning.overruled? && 'log-entry--inactive'] do
 | 
				
			||||||
  .speech-bubble__bubble
 | 
					  .log-entry__header
 | 
				
			||||||
    = Formatter.instance.linkify(account_warning.text)
 | 
					    .log-entry__avatar
 | 
				
			||||||
  .speech-bubble__owner
 | 
					      = image_tag account_warning.target_account.avatar.url(:original), alt: '', width: 40, height: 40, class: 'avatar'
 | 
				
			||||||
    = admin_account_link_to account_warning.account
 | 
					    .log-entry__content
 | 
				
			||||||
    %time.formatted{ datetime: account_warning.created_at.iso8601 }= l account_warning.created_at
 | 
					      .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')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -246,18 +246,29 @@
 | 
				
			||||||
  %hr.spacer/
 | 
					  %hr.spacer/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  - unless @warnings.empty?
 | 
					  - 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/
 | 
					    %hr.spacer/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  = render @moderation_notes
 | 
					  %h3= t 'admin.reports.notes.title'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  %p= t 'admin.reports.notes_description_html'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .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|
 | 
					  = simple_form_for @account_moderation_note, url: admin_account_moderation_notes_path do |f|
 | 
				
			||||||
    = render 'shared/error_messages', object: @account_moderation_note
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    = f.input :content, placeholder: t('admin.reports.notes.placeholder'), rows: 6
 | 
					 | 
				
			||||||
    = f.hidden_field :target_account_id
 | 
					    = f.hidden_field :target_account_id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .field-group
 | 
				
			||||||
 | 
					      = f.input :content, placeholder: t('admin.reports.notes.placeholder'), rows: 6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .actions
 | 
					    .actions
 | 
				
			||||||
      = f.button :button, t('admin.account_moderation_notes.create'), type: :submit
 | 
					      = f.button :button, t('admin.account_moderation_notes.create'), type: :submit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,10 +16,10 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.dashboard
 | 
					.dashboard
 | 
				
			||||||
  .dashboard__item
 | 
					  .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
 | 
					  .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
 | 
					  .dashboard__item
 | 
				
			||||||
    = react_admin_component :counter, measure: 'interactions', start_at: @time_period.first, end_at: @time_period.last, label: t('admin.dashboard.interactions')
 | 
					    = react_admin_component :counter, measure: 'interactions', start_at: @time_period.first, end_at: @time_period.last, label: t('admin.dashboard.interactions')
 | 
				
			||||||
| 
						 | 
					@ -43,6 +43,9 @@
 | 
				
			||||||
      %span= t('admin.dashboard.pending_tags_html', count: @pending_tags_count)
 | 
					      %span= t('admin.dashboard.pending_tags_html', count: @pending_tags_count)
 | 
				
			||||||
      = fa_icon 'chevron-right fw'
 | 
					      = 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
 | 
					  .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')
 | 
					    = react_admin_component :dimension, dimension: 'sources', start_at: @time_period.first, end_at: @time_period.last, limit: 8, label: t('admin.dashboard.sources')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										21
									
								
								app/views/admin/disputes/appeals/_appeal.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								app/views/admin/disputes/appeals/_appeal.html.haml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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')
 | 
				
			||||||
							
								
								
									
										19
									
								
								app/views/admin/disputes/appeals/index.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								app/views/admin/disputes/appeals/index.html.haml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					- content_for :page_title do
 | 
				
			||||||
 | 
					  = t('admin.disputes.appeals.title')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.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
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .report-notes__item__header
 | 
					  .report-notes__item__header
 | 
				
			||||||
    %span.username
 | 
					    %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) }
 | 
					    %time{ datetime: report_note.created_at.iso8601, title: l(report_note.created_at) }
 | 
				
			||||||
      - if report_note.created_at.today?
 | 
					      - if report_note.created_at.today?
 | 
				
			||||||
        = t('admin.report_notes.today_at', time: l(report_note.created_at, format: :time))
 | 
					        = t('admin.report_notes.today_at', time: l(report_note.created_at, format: :time))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,7 +53,7 @@
 | 
				
			||||||
        .report-header__details__item__header
 | 
					        .report-header__details__item__header
 | 
				
			||||||
          %strong= t('admin.accounts.strikes')
 | 
					          %strong= t('admin.accounts.strikes')
 | 
				
			||||||
        .report-header__details__item__content
 | 
					        .report-header__details__item__content
 | 
				
			||||||
          = @report.target_account.strikes.count
 | 
					          = @report.target_account.previous_strikes_count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .report-header__details
 | 
					  .report-header__details
 | 
				
			||||||
    .report-header__details__item
 | 
					    .report-header__details__item
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								app/views/admin_mailer/new_appeal.text.erb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								app/views/admin_mailer/new_appeal.text.erb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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) %>
 | 
				
			||||||
							
								
								
									
										20
									
								
								app/views/auth/registrations/_account_warning.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								app/views/auth/registrations/_account_warning.html.haml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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')
 | 
				
			||||||
| 
						 | 
					@ -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')
 | 
					%h3= t('auth.status.account_status')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.simple_form
 | 
					= render partial: 'account_warning', collection: @strikes
 | 
				
			||||||
  %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')
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
%hr.spacer/
 | 
					%hr.spacer/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										127
									
								
								app/views/disputes/strikes/show.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								app/views/disputes/strikes/show.html.haml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					@ -53,5 +53,9 @@
 | 
				
			||||||
            %ul
 | 
					            %ul
 | 
				
			||||||
              %li= link_to t('about.source_code'), Mastodon::Version.source_url
 | 
					              %li= link_to t('about.source_code'), Mastodon::Version.source_url
 | 
				
			||||||
              %li= link_to t('about.apps'), 'https://joinmastodon.org/apps'
 | 
					              %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'
 | 
					= render template: 'layouts/application'
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,6 +21,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - if current_user.staff?
 | 
					      - if current_user.staff?
 | 
				
			||||||
        = ff.input :report, as: :boolean, wrapper: :with_label
 | 
					        = 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 :pending_account, as: :boolean, wrapper: :with_label
 | 
				
			||||||
        = ff.input :trending_tag, as: :boolean, wrapper: :with_label
 | 
					        = ff.input :trending_tag, as: :boolean, wrapper: :with_label
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,7 +49,7 @@
 | 
				
			||||||
    %span.detailed-status__visibility-icon
 | 
					    %span.detailed-status__visibility-icon
 | 
				
			||||||
      = visibility_icon status
 | 
					      = 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?
 | 
					      - if status.application.website.blank?
 | 
				
			||||||
        %strong.detailed-status__application= status.application.name
 | 
					        %strong.detailed-status__application= status.application.name
 | 
				
			||||||
      - else
 | 
					      - else
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										59
									
								
								app/views/user_mailer/appeal_approved.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								app/views/user_mailer/appeal_approved.html.haml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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'
 | 
				
			||||||
							
								
								
									
										7
									
								
								app/views/user_mailer/appeal_approved.text.erb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								app/views/user_mailer/appeal_approved.text.erb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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 %>
 | 
				
			||||||
							
								
								
									
										59
									
								
								app/views/user_mailer/appeal_rejected.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								app/views/user_mailer/appeal_rejected.html.haml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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'
 | 
				
			||||||
							
								
								
									
										7
									
								
								app/views/user_mailer/appeal_rejected.text.erb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								app/views/user_mailer/appeal_rejected.text.erb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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 %>
 | 
				
			||||||
| 
						 | 
					@ -77,8 +77,8 @@
 | 
				
			||||||
                            %tbody
 | 
					                            %tbody
 | 
				
			||||||
                              %tr
 | 
					                              %tr
 | 
				
			||||||
                                %td.button-primary
 | 
					                                %td.button-primary
 | 
				
			||||||
                                  = link_to about_more_url do
 | 
					                                  = link_to disputes_strike_url(@warning) do
 | 
				
			||||||
                                    %span= t 'user_mailer.warning.review_server_policies'
 | 
					                                    %span= t 'user_mailer.warning.appeal'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%table.email-table{ cellspacing: 0, cellpadding: 0 }
 | 
					%table.email-table{ cellspacing: 0, cellpadding: 0 }
 | 
				
			||||||
  %tbody
 | 
					  %tbody
 | 
				
			||||||
| 
						 | 
					@ -95,4 +95,4 @@
 | 
				
			||||||
                        %tbody
 | 
					                        %tbody
 | 
				
			||||||
                          %tr
 | 
					                          %tr
 | 
				
			||||||
                            %td.column-cell.text-center
 | 
					                            %td.column-cell.text-center
 | 
				
			||||||
                              %p= t 'user_mailer.warning.get_in_touch', instance: @instance
 | 
					                              %p= t 'user_mailer.warning.appeal_description', instance: @instance
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,25 +1,5 @@
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  "ignored_warnings": [
 | 
					  "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_type": "SQL Injection",
 | 
				
			||||||
      "warning_code": 0,
 | 
					      "warning_code": 0,
 | 
				
			||||||
| 
						 | 
					@ -27,7 +7,7 @@
 | 
				
			||||||
      "check_name": "SQL",
 | 
					      "check_name": "SQL",
 | 
				
			||||||
      "message": "Possible SQL injection",
 | 
					      "message": "Possible SQL injection",
 | 
				
			||||||
      "file": "app/models/status.rb",
 | 
					      "file": "app/models/status.rb",
 | 
				
			||||||
      "line": 100,
 | 
					      "line": 104,
 | 
				
			||||||
      "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
 | 
					      "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}\")",
 | 
					      "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,
 | 
					      "render_path": null,
 | 
				
			||||||
| 
						 | 
					@ -107,7 +87,7 @@
 | 
				
			||||||
      "check_name": "PermitAttributes",
 | 
					      "check_name": "PermitAttributes",
 | 
				
			||||||
      "message": "Potentially dangerous key allowed for mass assignment",
 | 
					      "message": "Potentially dangerous key allowed for mass assignment",
 | 
				
			||||||
      "file": "app/controllers/api/v1/admin/reports_controller.rb",
 | 
					      "file": "app/controllers/api/v1/admin/reports_controller.rb",
 | 
				
			||||||
      "line": 78,
 | 
					      "line": 90,
 | 
				
			||||||
      "link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/",
 | 
					      "link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/",
 | 
				
			||||||
      "code": "params.permit(:resolved, :account_id, :target_account_id)",
 | 
					      "code": "params.permit(:resolved, :account_id, :target_account_id)",
 | 
				
			||||||
      "render_path": null,
 | 
					      "render_path": null,
 | 
				
			||||||
| 
						 | 
					@ -140,6 +120,36 @@
 | 
				
			||||||
      "confidence": "Medium",
 | 
					      "confidence": "Medium",
 | 
				
			||||||
      "note": ""
 | 
					      "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_type": "Redirect",
 | 
				
			||||||
      "warning_code": 18,
 | 
					      "warning_code": 18,
 | 
				
			||||||
| 
						 | 
					@ -194,7 +204,7 @@
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          "type": "template",
 | 
					          "type": "template",
 | 
				
			||||||
          "name": "admin/trends/links/index",
 | 
					          "name": "admin/trends/links/index",
 | 
				
			||||||
          "line": 37,
 | 
					          "line": 39,
 | 
				
			||||||
          "file": "app/views/admin/trends/links/index.html.haml",
 | 
					          "file": "app/views/admin/trends/links/index.html.haml",
 | 
				
			||||||
          "rendered": {
 | 
					          "rendered": {
 | 
				
			||||||
            "name": "admin/trends/links/_preview_card",
 | 
					            "name": "admin/trends/links/_preview_card",
 | 
				
			||||||
| 
						 | 
					@ -213,13 +223,13 @@
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      "warning_type": "Mass Assignment",
 | 
					      "warning_type": "Mass Assignment",
 | 
				
			||||||
      "warning_code": 105,
 | 
					      "warning_code": 105,
 | 
				
			||||||
      "fingerprint": "e867661b2c9812bc8b75a5df12b28e2a53ab97015de0638b4e732fe442561b28",
 | 
					      "fingerprint": "f9de0ca4b04ae4b51b74d98db14dcbb6dae6809e627b58e711019cf9b4a47866",
 | 
				
			||||||
      "check_name": "PermitAttributes",
 | 
					      "check_name": "PermitAttributes",
 | 
				
			||||||
      "message": "Potentially dangerous key allowed for mass assignment",
 | 
					      "message": "Potentially dangerous key allowed for mass assignment",
 | 
				
			||||||
      "file": "app/controllers/api/v1/reports_controller.rb",
 | 
					      "file": "app/controllers/api/v1/reports_controller.rb",
 | 
				
			||||||
      "line": 36,
 | 
					      "line": 36,
 | 
				
			||||||
      "link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/",
 | 
					      "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,
 | 
					      "render_path": null,
 | 
				
			||||||
      "location": {
 | 
					      "location": {
 | 
				
			||||||
        "type": "method",
 | 
					        "type": "method",
 | 
				
			||||||
| 
						 | 
					@ -231,6 +241,6 @@
 | 
				
			||||||
      "note": ""
 | 
					      "note": ""
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  "updated": "2021-11-14 05:26:09 +0100",
 | 
					  "updated": "2022-02-13 02:24:12 +0100",
 | 
				
			||||||
  "brakeman_version": "5.1.2"
 | 
					  "brakeman_version": "5.2.1"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -94,7 +94,6 @@ en:
 | 
				
			||||||
    account_moderation_notes:
 | 
					    account_moderation_notes:
 | 
				
			||||||
      create: Leave note
 | 
					      create: Leave note
 | 
				
			||||||
      created_msg: Moderation note successfully created!
 | 
					      created_msg: Moderation note successfully created!
 | 
				
			||||||
      delete: Delete
 | 
					 | 
				
			||||||
      destroyed_msg: Moderation note successfully destroyed!
 | 
					      destroyed_msg: Moderation note successfully destroyed!
 | 
				
			||||||
    accounts:
 | 
					    accounts:
 | 
				
			||||||
      add_email_domain_block: Block e-mail domain
 | 
					      add_email_domain_block: Block e-mail domain
 | 
				
			||||||
| 
						 | 
					@ -163,6 +162,11 @@ en:
 | 
				
			||||||
      not_subscribed: Not subscribed
 | 
					      not_subscribed: Not subscribed
 | 
				
			||||||
      pending: Pending review
 | 
					      pending: Pending review
 | 
				
			||||||
      perform_full_suspension: Suspend
 | 
					      perform_full_suspension: Suspend
 | 
				
			||||||
 | 
					      previous_strikes: Previous strikes
 | 
				
			||||||
 | 
					      previous_strikes_description_html:
 | 
				
			||||||
 | 
					        one: This account has <strong>one</strong> strike.
 | 
				
			||||||
 | 
					        other: This account has <strong>%{count}</strong> strikes.
 | 
				
			||||||
 | 
					        zero: This account is <strong>in good standing</strong>.
 | 
				
			||||||
      promote: Promote
 | 
					      promote: Promote
 | 
				
			||||||
      protocol: Protocol
 | 
					      protocol: Protocol
 | 
				
			||||||
      public: Public
 | 
					      public: Public
 | 
				
			||||||
| 
						 | 
					@ -227,6 +231,7 @@ en:
 | 
				
			||||||
      whitelisted: Allowed for federation
 | 
					      whitelisted: Allowed for federation
 | 
				
			||||||
    action_logs:
 | 
					    action_logs:
 | 
				
			||||||
      action_types:
 | 
					      action_types:
 | 
				
			||||||
 | 
					        approve_appeal: Approve Appeal
 | 
				
			||||||
        approve_user: Approve User
 | 
					        approve_user: Approve User
 | 
				
			||||||
        assigned_to_self_report: Assign Report
 | 
					        assigned_to_self_report: Assign Report
 | 
				
			||||||
        change_email_user: Change E-mail for User
 | 
					        change_email_user: Change E-mail for User
 | 
				
			||||||
| 
						 | 
					@ -258,6 +263,7 @@ en:
 | 
				
			||||||
        enable_user: Enable User
 | 
					        enable_user: Enable User
 | 
				
			||||||
        memorialize_account: Memorialize Account
 | 
					        memorialize_account: Memorialize Account
 | 
				
			||||||
        promote_user: Promote User
 | 
					        promote_user: Promote User
 | 
				
			||||||
 | 
					        reject_appeal: Reject Appeal
 | 
				
			||||||
        reject_user: Reject User
 | 
					        reject_user: Reject User
 | 
				
			||||||
        remove_avatar_user: Remove Avatar
 | 
					        remove_avatar_user: Remove Avatar
 | 
				
			||||||
        reopen_report: Reopen Report
 | 
					        reopen_report: Reopen Report
 | 
				
			||||||
| 
						 | 
					@ -276,6 +282,7 @@ en:
 | 
				
			||||||
        update_domain_block: Update Domain Block
 | 
					        update_domain_block: Update Domain Block
 | 
				
			||||||
        update_status: Update Post
 | 
					        update_status: Update Post
 | 
				
			||||||
      actions:
 | 
					      actions:
 | 
				
			||||||
 | 
					        approve_appeal_html: "%{name} approved moderation decision appeal from %{target}"
 | 
				
			||||||
        approve_user_html: "%{name} approved sign-up from %{target}"
 | 
					        approve_user_html: "%{name} approved sign-up from %{target}"
 | 
				
			||||||
        assigned_to_self_report_html: "%{name} assigned report %{target} to themselves"
 | 
					        assigned_to_self_report_html: "%{name} assigned report %{target} to themselves"
 | 
				
			||||||
        change_email_user_html: "%{name} changed the e-mail address of user %{target}"
 | 
					        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}"
 | 
					        enable_user_html: "%{name} enabled login for user %{target}"
 | 
				
			||||||
        memorialize_account_html: "%{name} turned %{target}'s account into a memoriam page"
 | 
					        memorialize_account_html: "%{name} turned %{target}'s account into a memoriam page"
 | 
				
			||||||
        promote_user_html: "%{name} promoted user %{target}"
 | 
					        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}"
 | 
					        reject_user_html: "%{name} rejected sign-up from %{target}"
 | 
				
			||||||
        remove_avatar_user_html: "%{name} removed %{target}'s avatar"
 | 
					        remove_avatar_user_html: "%{name} removed %{target}'s avatar"
 | 
				
			||||||
        reopen_report_html: "%{name} reopened report %{target}"
 | 
					        reopen_report_html: "%{name} reopened report %{target}"
 | 
				
			||||||
| 
						 | 
					@ -385,14 +393,17 @@ en:
 | 
				
			||||||
      media_storage: Media storage
 | 
					      media_storage: Media storage
 | 
				
			||||||
      new_users: new users
 | 
					      new_users: new users
 | 
				
			||||||
      opened_reports: reports opened
 | 
					      opened_reports: reports opened
 | 
				
			||||||
 | 
					      pending_appeals_html:
 | 
				
			||||||
 | 
					        one: "<strong>%{count}</strong> pending appeal"
 | 
				
			||||||
 | 
					        other: "<strong>%{count}</strong> pending appeals"
 | 
				
			||||||
      pending_reports_html:
 | 
					      pending_reports_html:
 | 
				
			||||||
        one: "<strong>1</strong> pending report"
 | 
					        one: "<strong>%{count}</strong> pending report"
 | 
				
			||||||
        other: "<strong>%{count}</strong> pending reports"
 | 
					        other: "<strong>%{count}</strong> pending reports"
 | 
				
			||||||
      pending_tags_html:
 | 
					      pending_tags_html:
 | 
				
			||||||
        one: "<strong>1</strong> pending hashtag"
 | 
					        one: "<strong>%{count}</strong> pending hashtag"
 | 
				
			||||||
        other: "<strong>%{count}</strong> pending hashtags"
 | 
					        other: "<strong>%{count}</strong> pending hashtags"
 | 
				
			||||||
      pending_users_html:
 | 
					      pending_users_html:
 | 
				
			||||||
        one: "<strong>1</strong> pending user"
 | 
					        one: "<strong>%{count}</strong> pending user"
 | 
				
			||||||
        other: "<strong>%{count}</strong> pending users"
 | 
					        other: "<strong>%{count}</strong> pending users"
 | 
				
			||||||
      resolved_reports: reports resolved
 | 
					      resolved_reports: reports resolved
 | 
				
			||||||
      software: Software
 | 
					      software: Software
 | 
				
			||||||
| 
						 | 
					@ -402,6 +413,10 @@ en:
 | 
				
			||||||
      top_languages: Top active languages
 | 
					      top_languages: Top active languages
 | 
				
			||||||
      top_servers: Top active servers
 | 
					      top_servers: Top active servers
 | 
				
			||||||
      website: Website
 | 
					      website: Website
 | 
				
			||||||
 | 
					    disputes:
 | 
				
			||||||
 | 
					      appeals:
 | 
				
			||||||
 | 
					        empty: No appeals found.
 | 
				
			||||||
 | 
					        title: Appeals
 | 
				
			||||||
    domain_allows:
 | 
					    domain_allows:
 | 
				
			||||||
      add_new: Allow federation with domain
 | 
					      add_new: Allow federation with domain
 | 
				
			||||||
      created_msg: Domain has been successfully allowed for federation
 | 
					      created_msg: Domain has been successfully allowed for federation
 | 
				
			||||||
| 
						 | 
					@ -442,6 +457,7 @@ en:
 | 
				
			||||||
        affected_accounts:
 | 
					        affected_accounts:
 | 
				
			||||||
          one: One account in the database affected
 | 
					          one: One account in the database affected
 | 
				
			||||||
          other: "%{count} accounts in the database affected"
 | 
					          other: "%{count} accounts in the database affected"
 | 
				
			||||||
 | 
					          zero: No account in the database is affected
 | 
				
			||||||
        retroactive:
 | 
					        retroactive:
 | 
				
			||||||
          silence: Undo limit of existing affected accounts from this domain
 | 
					          silence: Undo limit of existing affected accounts from this domain
 | 
				
			||||||
          suspend: Unsuspend existing affected accounts from this domain
 | 
					          suspend: Unsuspend existing affected accounts from this domain
 | 
				
			||||||
| 
						 | 
					@ -495,6 +511,7 @@ en:
 | 
				
			||||||
      known_accounts:
 | 
					      known_accounts:
 | 
				
			||||||
        one: "%{count} known account"
 | 
					        one: "%{count} known account"
 | 
				
			||||||
        other: "%{count} known accounts"
 | 
					        other: "%{count} known accounts"
 | 
				
			||||||
 | 
					        zero: No known account
 | 
				
			||||||
      moderation:
 | 
					      moderation:
 | 
				
			||||||
        all: All
 | 
					        all: All
 | 
				
			||||||
        limited: Limited
 | 
					        limited: Limited
 | 
				
			||||||
| 
						 | 
					@ -720,6 +737,16 @@ en:
 | 
				
			||||||
      no_status_selected: No posts were changed as none were selected
 | 
					      no_status_selected: No posts were changed as none were selected
 | 
				
			||||||
      title: Account posts
 | 
					      title: Account posts
 | 
				
			||||||
      with_media: With media
 | 
					      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:
 | 
					    system_checks:
 | 
				
			||||||
      database_schema_check:
 | 
					      database_schema_check:
 | 
				
			||||||
        message_html: There are pending database migrations. Please run them to ensure the application behaves as expected
 | 
					        message_html: There are pending database migrations. Please run them to ensure the application behaves as expected
 | 
				
			||||||
| 
						 | 
					@ -744,6 +771,7 @@ en:
 | 
				
			||||||
        shared_by_over_week:
 | 
					        shared_by_over_week:
 | 
				
			||||||
          one: Shared by one person over the last week
 | 
					          one: Shared by one person over the last week
 | 
				
			||||||
          other: Shared by %{count} people over the last week
 | 
					          other: Shared by %{count} people over the last week
 | 
				
			||||||
 | 
					          zero: Shared by noone over the last week
 | 
				
			||||||
        title: Trending links
 | 
					        title: Trending links
 | 
				
			||||||
        usage_comparison: Shared %{today} times today, compared to %{yesterday} yesterday
 | 
					        usage_comparison: Shared %{today} times today, compared to %{yesterday} yesterday
 | 
				
			||||||
      pending_review: Pending review
 | 
					      pending_review: Pending review
 | 
				
			||||||
| 
						 | 
					@ -773,6 +801,7 @@ en:
 | 
				
			||||||
        used_by_over_week:
 | 
					        used_by_over_week:
 | 
				
			||||||
          one: Used by one person over the last week
 | 
					          one: Used by one person over the last week
 | 
				
			||||||
          other: Used by %{count} people over the last week
 | 
					          other: Used by %{count} people over the last week
 | 
				
			||||||
 | 
					          zero: Used by noone over the last week
 | 
				
			||||||
      title: Trends
 | 
					      title: Trends
 | 
				
			||||||
    warning_presets:
 | 
					    warning_presets:
 | 
				
			||||||
      add_new: Add new
 | 
					      add_new: Add new
 | 
				
			||||||
| 
						 | 
					@ -781,6 +810,17 @@ en:
 | 
				
			||||||
      empty: You haven't defined any warning presets yet.
 | 
					      empty: You haven't defined any warning presets yet.
 | 
				
			||||||
      title: Manage warning presets
 | 
					      title: Manage warning presets
 | 
				
			||||||
  admin_mailer:
 | 
					  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:
 | 
					    new_pending_account:
 | 
				
			||||||
      body: The details of the new account are below. You can approve or reject this application.
 | 
					      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})
 | 
					      subject: New account up for review on %{instance} (%{username})
 | 
				
			||||||
| 
						 | 
					@ -871,7 +911,6 @@ en:
 | 
				
			||||||
    status:
 | 
					    status:
 | 
				
			||||||
      account_status: Account status
 | 
					      account_status: Account status
 | 
				
			||||||
      confirming: Waiting for e-mail confirmation to be completed.
 | 
					      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.
 | 
					      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}.
 | 
					      redirecting_to: Your account is inactive because it is currently redirecting to %{acct}.
 | 
				
			||||||
    too_fast: Form submitted too fast, try again.
 | 
					    too_fast: Form submitted too fast, try again.
 | 
				
			||||||
| 
						 | 
					@ -937,6 +976,32 @@ en:
 | 
				
			||||||
    directory: Profile directory
 | 
					    directory: Profile directory
 | 
				
			||||||
    explanation: Discover users based on their interests
 | 
					    explanation: Discover users based on their interests
 | 
				
			||||||
    explore_mastodon: Explore %{title}
 | 
					    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:
 | 
					  domain_validator:
 | 
				
			||||||
    invalid_domain: is not a valid domain name
 | 
					    invalid_domain: is not a valid domain name
 | 
				
			||||||
  errors:
 | 
					  errors:
 | 
				
			||||||
| 
						 | 
					@ -1501,6 +1566,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. <strong>Keep the recovery codes safe</strong>. For example, you may print them and store them with other important documents.
 | 
					    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. <strong>Keep the recovery codes safe</strong>. For example, you may print them and store them with other important documents.
 | 
				
			||||||
    webauthn: Security keys
 | 
					    webauthn: Security keys
 | 
				
			||||||
  user_mailer:
 | 
					  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:
 | 
					    backup_ready:
 | 
				
			||||||
      explanation: You requested a full backup of your Mastodon account. It's now ready for download!
 | 
					      explanation: You requested a full backup of your Mastodon account. It's now ready for download!
 | 
				
			||||||
      subject: Your archive is ready for download
 | 
					      subject: Your archive is ready for download
 | 
				
			||||||
| 
						 | 
					@ -1512,6 +1586,8 @@ en:
 | 
				
			||||||
      subject: Please confirm attempted sign in
 | 
					      subject: Please confirm attempted sign in
 | 
				
			||||||
      title: Sign in attempt
 | 
					      title: Sign in attempt
 | 
				
			||||||
    warning:
 | 
					    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:
 | 
					      categories:
 | 
				
			||||||
        spam: Spam
 | 
					        spam: Spam
 | 
				
			||||||
        violation: Content violates the following community guidelines
 | 
					        violation: Content violates the following community guidelines
 | 
				
			||||||
| 
						 | 
					@ -1523,7 +1599,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.
 | 
					        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}.
 | 
					      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:'
 | 
					      reason: 'Reason:'
 | 
				
			||||||
      review_server_policies: Review server policies
 | 
					 | 
				
			||||||
      statuses: 'Posts that have been found in violation:'
 | 
					      statuses: 'Posts that have been found in violation:'
 | 
				
			||||||
      subject:
 | 
					      subject:
 | 
				
			||||||
        delete_statuses: Your posts on %{acct} have been removed
 | 
					        delete_statuses: Your posts on %{acct} have been removed
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,6 +27,8 @@ en:
 | 
				
			||||||
        scheduled_at: Leave blank to publish the announcement immediately
 | 
					        scheduled_at: Leave blank to publish the announcement immediately
 | 
				
			||||||
        starts_at: Optional. In case your announcement is bound to a specific time range
 | 
					        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
 | 
					        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:
 | 
					      defaults:
 | 
				
			||||||
        autofollow: People who sign up through the invite will automatically follow you
 | 
					        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
 | 
					        avatar: PNG, GIF or JPG. At most %{size}. Will be downscaled to %{dimensions}px
 | 
				
			||||||
| 
						 | 
					@ -119,6 +121,8 @@ en:
 | 
				
			||||||
        scheduled_at: Schedule publication
 | 
					        scheduled_at: Schedule publication
 | 
				
			||||||
        starts_at: Start of event
 | 
					        starts_at: Start of event
 | 
				
			||||||
        text: Announcement
 | 
					        text: Announcement
 | 
				
			||||||
 | 
					      appeal:
 | 
				
			||||||
 | 
					        text: Explain why this decision should be reversed
 | 
				
			||||||
      defaults:
 | 
					      defaults:
 | 
				
			||||||
        autofollow: Invite to follow your account
 | 
					        autofollow: Invite to follow your account
 | 
				
			||||||
        avatar: Avatar
 | 
					        avatar: Avatar
 | 
				
			||||||
| 
						 | 
					@ -197,6 +201,7 @@ en:
 | 
				
			||||||
          sign_up_requires_approval: Limit sign-ups
 | 
					          sign_up_requires_approval: Limit sign-ups
 | 
				
			||||||
        severity: Rule
 | 
					        severity: Rule
 | 
				
			||||||
      notification_emails:
 | 
					      notification_emails:
 | 
				
			||||||
 | 
					        appeal: Someone appeals a moderator decision
 | 
				
			||||||
        digest: Send digest e-mails
 | 
					        digest: Send digest e-mails
 | 
				
			||||||
        favourite: Someone favourited your post
 | 
					        favourite: Someone favourited your post
 | 
				
			||||||
        follow: Someone followed you
 | 
					        follow: Someone followed you
 | 
				
			||||||
| 
						 | 
					@ -204,8 +209,8 @@ en:
 | 
				
			||||||
        mention: Someone mentioned you
 | 
					        mention: Someone mentioned you
 | 
				
			||||||
        pending_account: New account needs review
 | 
					        pending_account: New account needs review
 | 
				
			||||||
        reblog: Someone boosted your post
 | 
					        reblog: Someone boosted your post
 | 
				
			||||||
        report: A new report is submitted
 | 
					        report: New report is submitted
 | 
				
			||||||
        trending_tag: A new trend requires approval
 | 
					        trending_tag: New trend requires review
 | 
				
			||||||
      rule:
 | 
					      rule:
 | 
				
			||||||
        text: Rule
 | 
					        text: Rule
 | 
				
			||||||
      tag:
 | 
					      tag:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,7 +26,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 :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|
 | 
					    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 :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
 | 
					      s.item :authorized_apps, safe_join([fa_icon('list fw'), t('settings.authorized_apps')]), oauth_authorized_applications_url
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
| 
						 | 
					@ -47,7 +47,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|
 | 
					    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 :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 :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 :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 :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? }
 | 
					      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? }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -167,6 +167,12 @@ Rails.application.routes.draw do
 | 
				
			||||||
    resources :login_activities, only: [:index]
 | 
					    resources :login_activities, only: [:index]
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  namespace :disputes do
 | 
				
			||||||
 | 
					    resources :strikes, only: [:show] do
 | 
				
			||||||
 | 
					      resource :appeal, only: [:create]
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  resources :media, only: [:show] do
 | 
					  resources :media, only: [:show] do
 | 
				
			||||||
    get :player
 | 
					    get :player
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
| 
						 | 
					@ -327,6 +333,15 @@ Rails.application.routes.draw do
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    namespace :disputes do
 | 
				
			||||||
 | 
					      resources :appeals, only: [:index] do
 | 
				
			||||||
 | 
					        member do
 | 
				
			||||||
 | 
					          post :approve
 | 
				
			||||||
 | 
					          post :reject
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get '/admin', to: redirect('/admin/dashboard', status: 302)
 | 
					  get '/admin', to: redirect('/admin/dashboard', status: 302)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,6 +52,7 @@ defaults: &defaults
 | 
				
			||||||
    report: true
 | 
					    report: true
 | 
				
			||||||
    pending_account: true
 | 
					    pending_account: true
 | 
				
			||||||
    trending_tag: true
 | 
					    trending_tag: true
 | 
				
			||||||
 | 
					    appeal: true
 | 
				
			||||||
  interactions:
 | 
					  interactions:
 | 
				
			||||||
    must_be_follower: false
 | 
					    must_be_follower: false
 | 
				
			||||||
    must_be_following: false
 | 
					    must_be_following: false
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										14
									
								
								db/migrate/20220124141035_create_appeals.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								db/migrate/20220124141035_create_appeals.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					class AddOverruledAtToAccountWarnings < ActiveRecord::Migration[6.1]
 | 
				
			||||||
 | 
					  def change
 | 
				
			||||||
 | 
					    add_column :account_warnings, :overruled_at, :datetime
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										23
									
								
								db/schema.rb
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								db/schema.rb
									
									
									
									
									
								
							| 
						 | 
					@ -10,7 +10,7 @@
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# It's strongly recommended that you check this file into your version control system.
 | 
					# It's strongly recommended that you check this file into your version control system.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ActiveRecord::Schema.define(version: 2022_02_09_175231) do
 | 
					ActiveRecord::Schema.define(version: 2022_02_10_153119) do
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # These are extensions that must be enabled in order to support this database
 | 
					  # These are extensions that must be enabled in order to support this database
 | 
				
			||||||
  enable_extension "plpgsql"
 | 
					  enable_extension "plpgsql"
 | 
				
			||||||
| 
						 | 
					@ -135,6 +135,7 @@ ActiveRecord::Schema.define(version: 2022_02_09_175231) do
 | 
				
			||||||
    t.datetime "updated_at", null: false
 | 
					    t.datetime "updated_at", null: false
 | 
				
			||||||
    t.bigint "report_id"
 | 
					    t.bigint "report_id"
 | 
				
			||||||
    t.string "status_ids", array: true
 | 
					    t.string "status_ids", array: true
 | 
				
			||||||
 | 
					    t.datetime "overruled_at"
 | 
				
			||||||
    t.index ["account_id"], name: "index_account_warnings_on_account_id"
 | 
					    t.index ["account_id"], name: "index_account_warnings_on_account_id"
 | 
				
			||||||
    t.index ["target_account_id"], name: "index_account_warnings_on_target_account_id"
 | 
					    t.index ["target_account_id"], name: "index_account_warnings_on_target_account_id"
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
| 
						 | 
					@ -243,6 +244,22 @@ ActiveRecord::Schema.define(version: 2022_02_09_175231) do
 | 
				
			||||||
    t.bigint "status_ids", array: true
 | 
					    t.bigint "status_ids", array: true
 | 
				
			||||||
  end
 | 
					  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|
 | 
					  create_table "backups", force: :cascade do |t|
 | 
				
			||||||
    t.bigint "user_id"
 | 
					    t.bigint "user_id"
 | 
				
			||||||
    t.string "dump_file_name"
 | 
					    t.string "dump_file_name"
 | 
				
			||||||
| 
						 | 
					@ -1034,6 +1051,10 @@ ActiveRecord::Schema.define(version: 2022_02_09_175231) do
 | 
				
			||||||
  add_foreign_key "announcement_reactions", "accounts", on_delete: :cascade
 | 
					  add_foreign_key "announcement_reactions", "accounts", on_delete: :cascade
 | 
				
			||||||
  add_foreign_key "announcement_reactions", "announcements", 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 "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 "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", column: "target_account_id", name: "fk_9571bfabc1", on_delete: :cascade
 | 
				
			||||||
  add_foreign_key "blocks", "accounts", name: "fk_4269e03e65", on_delete: :cascade
 | 
					  add_foreign_key "blocks", "accounts", name: "fk_4269e03e65", on_delete: :cascade
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								package.json
									
									
									
									
									
								
							| 
						 | 
					@ -62,12 +62,12 @@
 | 
				
			||||||
  "private": true,
 | 
					  "private": true,
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@babel/core": "^7.17.2",
 | 
					    "@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-react-inline-elements": "^7.16.7",
 | 
				
			||||||
    "@babel/plugin-transform-runtime": "^7.17.0",
 | 
					    "@babel/plugin-transform-runtime": "^7.17.0",
 | 
				
			||||||
    "@babel/preset-env": "^7.16.11",
 | 
					    "@babel/preset-env": "^7.16.11",
 | 
				
			||||||
    "@babel/preset-react": "^7.16.7",
 | 
					    "@babel/preset-react": "^7.16.7",
 | 
				
			||||||
    "@babel/runtime": "^7.17.0",
 | 
					    "@babel/runtime": "^7.17.2",
 | 
				
			||||||
    "@gamestdio/websocket": "^0.3.2",
 | 
					    "@gamestdio/websocket": "^0.3.2",
 | 
				
			||||||
    "@github/webauthn-json": "^0.5.7",
 | 
					    "@github/webauthn-json": "^0.5.7",
 | 
				
			||||||
    "@rails/ujs": "^6.1.4",
 | 
					    "@rails/ujs": "^6.1.4",
 | 
				
			||||||
| 
						 | 
					@ -75,7 +75,7 @@
 | 
				
			||||||
    "atrament": "0.2.4",
 | 
					    "atrament": "0.2.4",
 | 
				
			||||||
    "arrow-key-navigation": "^1.2.0",
 | 
					    "arrow-key-navigation": "^1.2.0",
 | 
				
			||||||
    "autoprefixer": "^9.8.8",
 | 
					    "autoprefixer": "^9.8.8",
 | 
				
			||||||
    "axios": "^0.25.0",
 | 
					    "axios": "^0.26.0",
 | 
				
			||||||
    "babel-loader": "^8.2.3",
 | 
					    "babel-loader": "^8.2.3",
 | 
				
			||||||
    "babel-plugin-lodash": "^3.3.4",
 | 
					    "babel-plugin-lodash": "^3.3.4",
 | 
				
			||||||
    "babel-plugin-preval": "^5.1.0",
 | 
					    "babel-plugin-preval": "^5.1.0",
 | 
				
			||||||
| 
						 | 
					@ -90,7 +90,7 @@
 | 
				
			||||||
    "css-loader": "^5.2.7",
 | 
					    "css-loader": "^5.2.7",
 | 
				
			||||||
    "cssnano": "^4.1.11",
 | 
					    "cssnano": "^4.1.11",
 | 
				
			||||||
    "detect-passive-events": "^2.0.3",
 | 
					    "detect-passive-events": "^2.0.3",
 | 
				
			||||||
    "dotenv": "^10.0.0",
 | 
					    "dotenv": "^16.0.0",
 | 
				
			||||||
    "emoji-mart": "npm:emoji-mart-lazyload",
 | 
					    "emoji-mart": "npm:emoji-mart-lazyload",
 | 
				
			||||||
    "es6-symbol": "^3.1.3",
 | 
					    "es6-symbol": "^3.1.3",
 | 
				
			||||||
    "escape-html": "^1.0.3",
 | 
					    "escape-html": "^1.0.3",
 | 
				
			||||||
| 
						 | 
					@ -115,7 +115,7 @@
 | 
				
			||||||
    "marky": "^1.2.2",
 | 
					    "marky": "^1.2.2",
 | 
				
			||||||
    "mini-css-extract-plugin": "^1.6.2",
 | 
					    "mini-css-extract-plugin": "^1.6.2",
 | 
				
			||||||
    "mkdirp": "^1.0.4",
 | 
					    "mkdirp": "^1.0.4",
 | 
				
			||||||
    "npmlog": "^6.0.0",
 | 
					    "npmlog": "^6.0.1",
 | 
				
			||||||
    "object-assign": "^4.1.1",
 | 
					    "object-assign": "^4.1.1",
 | 
				
			||||||
    "object-fit-images": "^3.2.3",
 | 
					    "object-fit-images": "^3.2.3",
 | 
				
			||||||
    "object.values": "^1.1.5",
 | 
					    "object.values": "^1.1.5",
 | 
				
			||||||
| 
						 | 
					@ -178,7 +178,7 @@
 | 
				
			||||||
    "@testing-library/jest-dom": "^5.16.2",
 | 
					    "@testing-library/jest-dom": "^5.16.2",
 | 
				
			||||||
    "@testing-library/react": "^12.1.2",
 | 
					    "@testing-library/react": "^12.1.2",
 | 
				
			||||||
    "babel-eslint": "^10.1.0",
 | 
					    "babel-eslint": "^10.1.0",
 | 
				
			||||||
    "babel-jest": "^27.5.0",
 | 
					    "babel-jest": "^27.5.1",
 | 
				
			||||||
    "eslint": "^7.32.0",
 | 
					    "eslint": "^7.32.0",
 | 
				
			||||||
    "eslint-plugin-import": "~2.25.4",
 | 
					    "eslint-plugin-import": "~2.25.4",
 | 
				
			||||||
    "eslint-plugin-jsx-a11y": "~6.5.1",
 | 
					    "eslint-plugin-jsx-a11y": "~6.5.1",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										53
									
								
								spec/controllers/admin/disputes/appeals_controller_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								spec/controllers/admin/disputes/appeals_controller_spec.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										27
									
								
								spec/controllers/disputes/appeals_controller_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								spec/controllers/disputes/appeals_controller_spec.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
							
								
								
									
										30
									
								
								spec/controllers/disputes/strikes_controller_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								spec/controllers/disputes/strikes_controller_spec.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
Fabricator(:account_warning) do
 | 
					Fabricator(:account_warning) do
 | 
				
			||||||
  account        nil
 | 
					  account
 | 
				
			||||||
  target_account nil
 | 
					  target_account(fabricator: :account)
 | 
				
			||||||
  text           "MyText"
 | 
					  text { Faker::Lorem.paragraph }
 | 
				
			||||||
 | 
					  action 'suspend'
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										5
									
								
								spec/fabricators/appeal_fabricator.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								spec/fabricators/appeal_fabricator.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					Fabricator(:appeal) do
 | 
				
			||||||
 | 
					  strike(fabricator: :account_warning)
 | 
				
			||||||
 | 
					  account { |attrs| attrs[:strike].target_account }
 | 
				
			||||||
 | 
					  text { Faker::Lorem.paragraph }
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					@ -113,26 +113,23 @@ RSpec.describe ActivityPub::Activity::Announce do
 | 
				
			||||||
      let!(:relay_account) { Fabricate(:account, inbox_url: 'https://relay.example.com/inbox') }
 | 
					      let!(:relay_account) { Fabricate(:account, inbox_url: 'https://relay.example.com/inbox') }
 | 
				
			||||||
      let!(:relay) { Fabricate(:relay, 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) }
 | 
					      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
 | 
					      context 'and the relay is enabled' do
 | 
				
			||||||
        before do
 | 
					        before do
 | 
				
			||||||
          relay.update(state: :accepted)
 | 
					          relay.update(state: :accepted)
 | 
				
			||||||
          subject.perform
 | 
					          subject.perform
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let(:object_json) do
 | 
					        it 'fetches the remote status' do
 | 
				
			||||||
          {
 | 
					          expect(a_request(:get, 'https://example.com/actor/hello-world')).to have_been_made
 | 
				
			||||||
            id: 'https://example.com/actor#bar',
 | 
					          expect(Status.find_by(uri: 'https://example.com/actor/hello-world').text).to eq 'Hello world'
 | 
				
			||||||
            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
 | 
					 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -141,14 +138,9 @@ RSpec.describe ActivityPub::Activity::Announce do
 | 
				
			||||||
          subject.perform
 | 
					          subject.perform
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let(:object_json) do
 | 
					        it 'does not fetch the remote status' do
 | 
				
			||||||
          {
 | 
					          expect(a_request(:get, 'https://example.com/actor/hello-world')).not_to have_been_made
 | 
				
			||||||
            id: 'https://example.com/actor#bar',
 | 
					          expect(Status.find_by(uri: 'https://example.com/actor/hello-world')).to be_nil
 | 
				
			||||||
            type: 'Note',
 | 
					 | 
				
			||||||
            content: 'Lorem ipsum',
 | 
					 | 
				
			||||||
            to: 'http://example.com/followers',
 | 
					 | 
				
			||||||
            attributedTo: 'https://example.com/actor',
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        it 'does not create anything' do
 | 
					        it 'does not create anything' do
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,4 +15,9 @@ class AdminMailerPreview < ActionMailer::Preview
 | 
				
			||||||
  def new_trending_links
 | 
					  def new_trending_links
 | 
				
			||||||
    AdminMailer.new_trending_links(Account.first, PreviewCard.limit(3))
 | 
					    AdminMailer.new_trending_links(Account.first, PreviewCard.limit(3))
 | 
				
			||||||
  end
 | 
					  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
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -82,6 +82,11 @@ class UserMailerPreview < ActionMailer::Preview
 | 
				
			||||||
    UserMailer.warning(User.first, AccountWarning.last)
 | 
					    UserMailer.warning(User.first, AccountWarning.last)
 | 
				
			||||||
  end
 | 
					  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
 | 
					  # Preview this email at http://localhost:3000/rails/mailers/user_mailer/sign_in_token
 | 
				
			||||||
  def 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)
 | 
					    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)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										5
									
								
								spec/models/appeal_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								spec/models/appeal_spec.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					require 'rails_helper'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RSpec.describe Appeal, type: :model do
 | 
				
			||||||
 | 
					  pending "add some examples to (or delete) #{__FILE__}"
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					@ -89,6 +89,19 @@ RSpec.describe User, type: :model do
 | 
				
			||||||
        expect(User.matches_email('specified')).to match_array([specified])
 | 
					        expect(User.matches_email('specified')).to match_array([specified])
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    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
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let(:account) { Fabricate(:account, username: 'alice') }
 | 
					  let(:account) { Fabricate(:account, username: 'alice') }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -92,13 +92,18 @@ const numWorkers = +process.env.STREAMING_CLUSTER_NUM || (env === 'development'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @param {string} json
 | 
					 * @param {string} json
 | 
				
			||||||
 | 
					 * @param {any} req
 | 
				
			||||||
 * @return {Object.<string, any>|null}
 | 
					 * @return {Object.<string, any>|null}
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
const parseJSON = (json) => {
 | 
					const parseJSON = (json, req) => {
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    return JSON.parse(json);
 | 
					    return JSON.parse(json);
 | 
				
			||||||
  } catch (err) {
 | 
					  } 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;
 | 
					    return null;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -451,7 +456,7 @@ const startWorker = async (workerId) => {
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  const createSystemMessageListener = (req, eventHandlers) => {
 | 
					  const createSystemMessageListener = (req, eventHandlers) => {
 | 
				
			||||||
    return message => {
 | 
					    return message => {
 | 
				
			||||||
      const json = parseJSON(message);
 | 
					      const json = parseJSON(message, req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (!json) return;
 | 
					      if (!json) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -575,7 +580,7 @@ const startWorker = async (workerId) => {
 | 
				
			||||||
    log.verbose(req.requestId, `Starting stream from ${ids.join(', ')} for ${accountId}`);
 | 
					    log.verbose(req.requestId, `Starting stream from ${ids.join(', ')} for ${accountId}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const listener = message => {
 | 
					    const listener = message => {
 | 
				
			||||||
      const json = parseJSON(message);
 | 
					      const json = parseJSON(message, req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (!json) return;
 | 
					      if (!json) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1059,7 +1064,7 @@ const startWorker = async (workerId) => {
 | 
				
			||||||
    ws.on('error', onEnd);
 | 
					    ws.on('error', onEnd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ws.on('message', data => {
 | 
					    ws.on('message', data => {
 | 
				
			||||||
      const json = parseJSON(data);
 | 
					      const json = parseJSON(data, session.request);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (!json) return;
 | 
					      if (!json) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										178
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										178
									
								
								yarn.lock
									
									
									
									
									
								
							| 
						 | 
					@ -91,7 +91,7 @@
 | 
				
			||||||
    browserslist "^4.17.5"
 | 
					    browserslist "^4.17.5"
 | 
				
			||||||
    semver "^6.3.0"
 | 
					    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"
 | 
					  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"
 | 
					  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==
 | 
					  integrity sha512-JBdSr/LtyYIno/pNnJ75lBcqc3Z1XXujzPanHqjvvrhOA+DTceTFuJi8XjmWTZh4r3fsdfqaCMN0iZemdkxZHQ==
 | 
				
			||||||
| 
						 | 
					@ -357,12 +357,12 @@
 | 
				
			||||||
    "@babel/helper-plugin-utils" "^7.16.7"
 | 
					    "@babel/helper-plugin-utils" "^7.16.7"
 | 
				
			||||||
    "@babel/plugin-syntax-class-static-block" "^7.14.5"
 | 
					    "@babel/plugin-syntax-class-static-block" "^7.14.5"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@babel/plugin-proposal-decorators@^7.17.0":
 | 
					"@babel/plugin-proposal-decorators@^7.17.2":
 | 
				
			||||||
  version "7.17.0"
 | 
					  version "7.17.2"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.0.tgz#fc0f689fe2535075056c587bc10c176fa9990443"
 | 
					  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.2.tgz#c36372ddfe0360cac1ee331a238310bddca11493"
 | 
				
			||||||
  integrity sha512-JR8HTf3T1CsdMqfENrZ9pqncwsH4sPcvsyDLpvmv8iIbpDmeyBD7HPfGAIqkQph2j5d3B84hTm+m3qHPAedaPw==
 | 
					  integrity sha512-WH8Z95CwTq/W8rFbMqb9p3hicpt4RX4f0K659ax2VHxgOyT6qQmUaEVEjIh4WR9Eh9NymkVn5vwsrE68fAQNUw==
 | 
				
			||||||
  dependencies:
 | 
					  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-plugin-utils" "^7.16.7"
 | 
				
			||||||
    "@babel/helper-replace-supers" "^7.16.7"
 | 
					    "@babel/helper-replace-supers" "^7.16.7"
 | 
				
			||||||
    "@babel/plugin-syntax-decorators" "^7.17.0"
 | 
					    "@babel/plugin-syntax-decorators" "^7.17.0"
 | 
				
			||||||
| 
						 | 
					@ -1024,10 +1024,10 @@
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    regenerator-runtime "^0.12.0"
 | 
					    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":
 | 
					"@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.0"
 | 
					  version "7.17.2"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.0.tgz#b8d142fc0f7664fb3d9b5833fd40dcbab89276c0"
 | 
					  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.2.tgz#66f68591605e59da47523c631416b18508779941"
 | 
				
			||||||
  integrity sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ==
 | 
					  integrity sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    regenerator-runtime "^0.13.4"
 | 
					    regenerator-runtime "^0.13.4"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1338,27 +1338,6 @@
 | 
				
			||||||
    jest-haste-map "^27.5.1"
 | 
					    jest-haste-map "^27.5.1"
 | 
				
			||||||
    jest-runtime "^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":
 | 
					"@jest/transform@^27.5.1":
 | 
				
			||||||
  version "27.5.1"
 | 
					  version "27.5.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.5.1.tgz#6c3501dcc00c4c08915f292a600ece5ecfe1f409"
 | 
					  resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.5.1.tgz#6c3501dcc00c4c08915f292a600ece5ecfe1f409"
 | 
				
			||||||
| 
						 | 
					@ -1390,18 +1369,7 @@
 | 
				
			||||||
    "@types/yargs" "^15.0.0"
 | 
					    "@types/yargs" "^15.0.0"
 | 
				
			||||||
    chalk "^3.0.0"
 | 
					    chalk "^3.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@jest/types@^27.0.2", "@jest/types@^27.5.0":
 | 
					"@jest/types@^27.0.2", "@jest/types@^27.5.1":
 | 
				
			||||||
  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":
 | 
					 | 
				
			||||||
  version "27.5.1"
 | 
					  version "27.5.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80"
 | 
					  resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80"
 | 
				
			||||||
  integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==
 | 
					  integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==
 | 
				
			||||||
| 
						 | 
					@ -2148,10 +2116,10 @@ aproba@^1.1.1:
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
 | 
					  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
 | 
				
			||||||
  integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
 | 
					  integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
are-we-there-yet@^2.0.0:
 | 
					are-we-there-yet@^3.0.0:
 | 
				
			||||||
  version "2.0.0"
 | 
					  version "3.0.0"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c"
 | 
					  resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.0.tgz#ba20bd6b553e31d62fc8c31bd23d22b95734390d"
 | 
				
			||||||
  integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==
 | 
					  integrity sha512-0GWpv50YSOcLXaN6/FAKY3vfRbllXWV2xvfA/oKJF8pzFhWXPV+yjhJXDBbjscDYowv7Yw1A3uigpzn5iEGTyw==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    delegates "^1.0.0"
 | 
					    delegates "^1.0.0"
 | 
				
			||||||
    readable-stream "^3.6.0"
 | 
					    readable-stream "^3.6.0"
 | 
				
			||||||
| 
						 | 
					@ -2340,12 +2308,12 @@ axe-core@^4.3.5:
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.3.5.tgz#78d6911ba317a8262bfee292aeafcc1e04b49cc5"
 | 
					  resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.3.5.tgz#78d6911ba317a8262bfee292aeafcc1e04b49cc5"
 | 
				
			||||||
  integrity sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==
 | 
					  integrity sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
axios@^0.25.0:
 | 
					axios@^0.26.0:
 | 
				
			||||||
  version "0.25.0"
 | 
					  version "0.26.0"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/axios/-/axios-0.25.0.tgz#349cfbb31331a9b4453190791760a8d35b093e0a"
 | 
					  resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.0.tgz#9a318f1c69ec108f8cd5f3c3d390366635e13928"
 | 
				
			||||||
  integrity sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==
 | 
					  integrity sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    follow-redirects "^1.14.7"
 | 
					    follow-redirects "^1.14.8"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
axobject-query@^2.2.0:
 | 
					axobject-query@^2.2.0:
 | 
				
			||||||
  version "2.2.0"
 | 
					  version "2.2.0"
 | 
				
			||||||
| 
						 | 
					@ -2364,20 +2332,6 @@ babel-eslint@^10.1.0:
 | 
				
			||||||
    eslint-visitor-keys "^1.0.0"
 | 
					    eslint-visitor-keys "^1.0.0"
 | 
				
			||||||
    resolve "^1.12.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:
 | 
					babel-jest@^27.5.1:
 | 
				
			||||||
  version "27.5.1"
 | 
					  version "27.5.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444"
 | 
					  resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444"
 | 
				
			||||||
| 
						 | 
					@ -2420,16 +2374,6 @@ babel-plugin-istanbul@^6.1.1:
 | 
				
			||||||
    istanbul-lib-instrument "^5.0.4"
 | 
					    istanbul-lib-instrument "^5.0.4"
 | 
				
			||||||
    test-exclude "^6.0.0"
 | 
					    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:
 | 
					babel-plugin-jest-hoist@^27.5.1:
 | 
				
			||||||
  version "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"
 | 
					  resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz#9be98ecf28c331eb9f5df9c72d6f89deb8181c2e"
 | 
				
			||||||
| 
						 | 
					@ -2530,14 +2474,6 @@ babel-preset-current-node-syntax@^1.0.0:
 | 
				
			||||||
    "@babel/plugin-syntax-optional-chaining" "^7.8.3"
 | 
					    "@babel/plugin-syntax-optional-chaining" "^7.8.3"
 | 
				
			||||||
    "@babel/plugin-syntax-top-level-await" "^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:
 | 
					babel-preset-jest@^27.5.1:
 | 
				
			||||||
  version "27.5.1"
 | 
					  version "27.5.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz#91f10f58034cb7989cb4f962b69fa6eef6a6bc81"
 | 
					  resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz#91f10f58034cb7989cb4f962b69fa6eef6a6bc81"
 | 
				
			||||||
| 
						 | 
					@ -4078,10 +4014,10 @@ dot-prop@^5.2.0:
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    is-obj "^2.0.0"
 | 
					    is-obj "^2.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dotenv@^10.0.0:
 | 
					dotenv@^16.0.0:
 | 
				
			||||||
  version "10.0.0"
 | 
					  version "16.0.0"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81"
 | 
					  resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.0.tgz#c619001253be89ebb638d027b609c75c26e47411"
 | 
				
			||||||
  integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==
 | 
					  integrity sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
duplexer@^0.1.2:
 | 
					duplexer@^0.1.2:
 | 
				
			||||||
  version "0.1.2"
 | 
					  version "0.1.2"
 | 
				
			||||||
| 
						 | 
					@ -4999,7 +4935,7 @@ flush-write-stream@^1.0.0:
 | 
				
			||||||
    inherits "^2.0.3"
 | 
					    inherits "^2.0.3"
 | 
				
			||||||
    readable-stream "^2.3.6"
 | 
					    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"
 | 
					  version "1.14.8"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc"
 | 
					  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc"
 | 
				
			||||||
  integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==
 | 
					  integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==
 | 
				
			||||||
| 
						 | 
					@ -6476,26 +6412,6 @@ jest-get-type@^27.5.1:
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1"
 | 
					  resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1"
 | 
				
			||||||
  integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==
 | 
					  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:
 | 
					jest-haste-map@^27.5.1:
 | 
				
			||||||
  version "27.5.1"
 | 
					  version "27.5.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f"
 | 
					  resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f"
 | 
				
			||||||
| 
						 | 
					@ -6585,11 +6501,6 @@ jest-pnp-resolver@^1.2.2:
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c"
 | 
					  resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c"
 | 
				
			||||||
  integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==
 | 
					  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:
 | 
					jest-regex-util@^27.5.1:
 | 
				
			||||||
  version "27.5.1"
 | 
					  version "27.5.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95"
 | 
					  resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95"
 | 
				
			||||||
| 
						 | 
					@ -6675,14 +6586,6 @@ jest-runtime@^27.5.1:
 | 
				
			||||||
    slash "^3.0.0"
 | 
					    slash "^3.0.0"
 | 
				
			||||||
    strip-bom "^4.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:
 | 
					jest-serializer@^27.5.1:
 | 
				
			||||||
  version "27.5.1"
 | 
					  version "27.5.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64"
 | 
					  resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64"
 | 
				
			||||||
| 
						 | 
					@ -6719,18 +6622,6 @@ jest-snapshot@^27.5.1:
 | 
				
			||||||
    pretty-format "^27.5.1"
 | 
					    pretty-format "^27.5.1"
 | 
				
			||||||
    semver "^7.3.2"
 | 
					    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:
 | 
					jest-util@^27.5.1:
 | 
				
			||||||
  version "27.5.1"
 | 
					  version "27.5.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9"
 | 
					  resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9"
 | 
				
			||||||
| 
						 | 
					@ -6777,15 +6668,6 @@ jest-worker@^26.5.0:
 | 
				
			||||||
    merge-stream "^2.0.0"
 | 
					    merge-stream "^2.0.0"
 | 
				
			||||||
    supports-color "^7.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:
 | 
					jest-worker@^27.5.1:
 | 
				
			||||||
  version "27.5.1"
 | 
					  version "27.5.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0"
 | 
					  resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0"
 | 
				
			||||||
| 
						 | 
					@ -7690,12 +7572,12 @@ npm-run-path@^4.0.1:
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    path-key "^3.0.0"
 | 
					    path-key "^3.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
npmlog@^6.0.0:
 | 
					npmlog@^6.0.1:
 | 
				
			||||||
  version "6.0.0"
 | 
					  version "6.0.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.0.tgz#ba9ef39413c3d936ea91553db7be49c34ad0520c"
 | 
					  resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.1.tgz#06f1344a174c06e8de9c6c70834cfba2964bba17"
 | 
				
			||||||
  integrity sha512-03ppFRGlsyUaQFbGC2C8QWJN/C/K7PsfyD9aQdhVKAQIH4sQBc8WASqFBP7O+Ut4d2oo5LoeoboB3cGdBZSp6Q==
 | 
					  integrity sha512-BTHDvY6nrRHuRfyjt1MAufLxYdVXZfd099H4+i1f0lPywNQyI4foeNXJRObB/uy+TYqUW0vAD9gbdSOXPst7Eg==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    are-we-there-yet "^2.0.0"
 | 
					    are-we-there-yet "^3.0.0"
 | 
				
			||||||
    console-control-strings "^1.1.0"
 | 
					    console-control-strings "^1.1.0"
 | 
				
			||||||
    gauge "^4.0.0"
 | 
					    gauge "^4.0.0"
 | 
				
			||||||
    set-blocking "^2.0.0"
 | 
					    set-blocking "^2.0.0"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue