Merge remote-tracking branch 'upstream/main'

This commit is contained in:
Essem 2023-03-27 11:58:10 -05:00
commit 2017add317
No known key found for this signature in database
GPG key ID: 7D497397CC3A2A8C
666 changed files with 9879 additions and 4447 deletions

View file

@ -1,128 +0,0 @@
version: 2.1
orbs:
ruby: circleci/ruby@2.0.0
node: circleci/node@5.0.3
executors:
default:
parameters:
ruby-version:
type: string
docker:
- image: cimg/ruby:<< parameters.ruby-version >>
environment:
BUNDLE_JOBS: 3
BUNDLE_RETRY: 3
CONTINUOUS_INTEGRATION: true
DB_HOST: localhost
DB_USER: root
DISABLE_SIMPLECOV: true
RAILS_ENV: test
- image: cimg/postgres:14.5
environment:
POSTGRES_USER: root
POSTGRES_HOST_AUTH_METHOD: trust
- image: cimg/redis:7.0
commands:
install-system-dependencies:
steps:
- run:
name: Install system dependencies
command: |
sudo apt-get update
sudo apt-get install -y libicu-dev libidn11-dev
install-ruby-dependencies:
parameters:
ruby-version:
type: string
steps:
- run:
command: |
bundle config clean 'true'
bundle config frozen 'true'
bundle config without 'development production'
name: Set bundler settings
- ruby/install-deps:
bundler-version: '2.3.26'
key: ruby<< parameters.ruby-version >>-gems-v2
wait-db:
steps:
- run:
command: dockerize -wait tcp://localhost:5432 -wait tcp://localhost:6379 -timeout 1m
name: Wait for PostgreSQL and Redis
jobs:
build:
docker:
- image: cimg/ruby:3.2-node
environment:
RAILS_ENV: test
steps:
- checkout
- install-system-dependencies
- install-ruby-dependencies:
ruby-version: '3.2'
- node/install-packages:
cache-version: v1
pkg-manager: yarn
- run:
command: |
export NODE_OPTIONS=--openssl-legacy-provider
./bin/rails assets:precompile
name: Precompile assets
- persist_to_workspace:
paths:
- public/assets
- public/packs-test
root: .
test:
parameters:
ruby-version:
type: string
executor:
name: default
ruby-version: << parameters.ruby-version >>
environment:
ALLOW_NOPAM: true
PAM_ENABLED: true
PAM_DEFAULT_SERVICE: pam_test
PAM_CONTROLLED_SERVICE: pam_test_controlled
parallelism: 4
steps:
- checkout
- install-system-dependencies
- run:
command: sudo apt-get install -y ffmpeg imagemagick libmagickcore-dev libmagickwand-dev libjpeg-dev libpng-dev libtiff-dev libwebp-dev libpam-dev
name: Install additional system dependencies
- run:
command: bundle config with 'pam_authentication'
name: Enable PAM authentication
- install-ruby-dependencies:
ruby-version: << parameters.ruby-version >>
- attach_workspace:
at: .
- wait-db
- run:
command: ./bin/rails db:create db:schema:load db:seed
name: Load database schema
- ruby/rspec-test
workflows:
version: 2
build-and-test:
jobs:
- build
- test:
matrix:
parameters:
ruby-version:
- '2.7'
- '3.0'
- '3.1'
- '3.2'
name: test-ruby<< matrix.ruby-version >>
requires:
- build

View file

@ -41,7 +41,7 @@ services:
- internal_network
redis:
image: redis:6-alpine
image: redis:7-alpine
restart: unless-stopped
volumes:
- redis-data:/data

View file

@ -32,10 +32,14 @@ module.exports = {
parserOptions: {
sourceType: 'module',
ecmaFeatures: {
experimentalObjectRestSpread: true,
jsx: true,
},
ecmaVersion: 2021,
requireConfigFile: false,
babelOptions: {
configFile: false,
presets: ['@babel/react', '@babel/env'],
},
},
settings: {
@ -214,4 +218,22 @@ module.exports = {
'promise/no-nesting': 'off',
'promise/no-promise-in-callback': 'off',
},
overrides: [
{
files: [
'*.config.js',
'.*rc.js',
'ide-helper.js',
],
env: {
commonjs: true,
},
parserOptions: {
sourceType: 'script',
},
},
],
};

View file

@ -25,12 +25,15 @@ jobs:
- uses: hadolint/hadolint-action@v3.1.0
- uses: docker/setup-qemu-action@v2
- uses: docker/setup-buildx-action@v2
- uses: docker/login-action@v2
- name: Log in to the Github Container registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
if: github.event_name != 'pull_request'
- uses: docker/metadata-action@v4
id: meta
with:
@ -39,6 +42,7 @@ jobs:
type=raw,value=latest,enable={{is_default_branch}}
type=edge,branch=main
type=sha,prefix=,format=long
- uses: docker/build-push-action@v4
with:
context: .
@ -47,5 +51,6 @@ jobs:
builder: ${{ steps.buildx.outputs.name }}
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

View file

@ -0,0 +1,17 @@
{
"problemMatcher": [
{
"owner": "haml-lint",
"severity": "warning",
"pattern": [
{
"regexp": "^(.*):(\\d+)\\s\\[W]\\s(.*):\\s(.*)$",
"file": 1,
"line": 2,
"code": 3,
"message": 4
}
]
}
]
}

44
.github/workflows/lint-haml.yml vendored Normal file
View file

@ -0,0 +1,44 @@
name: Haml Linting
on:
push:
branches-ignore:
- 'dependabot/**'
paths:
- '.github/workflows/haml-lint-problem-matcher.json'
- '.github/workflows/lint-haml.yml'
- '.haml-lint*.yml'
- '.rubocop*.yml'
- '.ruby-version'
- '**/*.haml'
- 'Gemfile*'
pull_request:
paths:
- '.github/workflows/haml-lint-problem-matcher.json'
- '.github/workflows/lint-haml.yml'
- '.haml-lint*.yml'
- '.rubocop*.yml'
- '.ruby-version'
- '**/*.haml'
- 'Gemfile*'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v3
- name: Install native Ruby dependencies
run: sudo apt-get install -y libicu-dev libidn11-dev
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: .ruby-version
bundler-cache: true
- name: Run haml-lint
run: |
echo "::add-matcher::.github/workflows/haml-lint-problem-matcher.json"
bundle exec haml-lint

View file

@ -2,7 +2,13 @@ name: PR Needs Rebase
on:
push:
branches-ignore:
- 'dependabot/**'
- 'l10n_main'
pull_request_target:
branches-ignore:
- 'dependabot/**'
- 'l10n_main'
types: [synchronize]
permissions:

View file

@ -25,7 +25,7 @@ jobs:
services:
postgres:
image: postgres:14.5
image: postgres:14-alpine
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
@ -38,7 +38,7 @@ jobs:
- 5432:5432
redis:
image: redis:7.0
image: redis:7-alpine
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s

View file

@ -25,7 +25,7 @@ jobs:
services:
postgres:
image: postgres:14.5
image: postgres:14-alpine
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
@ -37,7 +37,7 @@ jobs:
ports:
- 5432:5432
redis:
image: redis:7.0
image: redis:7-alpine
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s

141
.github/workflows/test-ruby.yml vendored Normal file
View file

@ -0,0 +1,141 @@
name: Ruby Testing
on:
push:
branches-ignore:
- 'dependabot/**'
pull_request:
env:
BUNDLE_CLEAN: true
BUNDLE_FROZEN: true
BUNDLE_WITHOUT: 'development production'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
env:
RAILS_ENV: test
steps:
- uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
cache: yarn
node-version-file: '.nvmrc'
- name: Install native Ruby dependencies
run: sudo apt-get install -y libicu-dev libidn11-dev
- name: Set up bundler cache
uses: ruby/setup-ruby@v1
with:
ruby-version: .ruby-version
bundler-cache: true
- run: yarn --frozen-lockfile --production
- name: Precompile assets
# Previously had set this, but it's not supported
# export NODE_OPTIONS=--openssl-legacy-provider
run: |-
./bin/rails assets:precompile
- uses: actions/upload-artifact@v3
with:
path: |-
./public/assets
./public/packs-test
name: ${{ github.sha }}
retention-days: 0
test:
runs-on: ubuntu-latest
needs:
- build
services:
postgres:
image: postgres:14-alpine
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
redis:
image: redis:7-alpine
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 6379:6379
env:
DB_HOST: localhost
DB_USER: postgres
DB_PASS: postgres
DISABLE_SIMPLECOV: true
RAILS_ENV: test
ALLOW_NOPAM: true
PAM_ENABLED: true
PAM_DEFAULT_SERVICE: pam_test
PAM_CONTROLLED_SERVICE: pam_test_controlled
BUNDLE_WITH: 'pam_authentication'
CI_JOBS: ${{ matrix.ci_job }}/4
strategy:
fail-fast: false
matrix:
ruby-version:
- '2.7'
- '3.0'
- '3.1'
- '.ruby-version'
ci_job:
- 1
- 2
- 3
- 4
steps:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v3
with:
path: './public'
name: ${{ github.sha }}
- name: Install native Ruby dependencies
run: sudo apt-get install -y libicu-dev libidn11-dev
- name: Install additional system dependencies
run: sudo apt-get install -y ffmpeg imagemagick libpam-dev
- name: Set up bundler cache
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version}}
bundler-cache: true
- name: Update system gems
if: matrix.ruby-version == '2.7'
run: gem update --system
- name: Load database schema
run: './bin/rails db:create db:schema:load db:seed'
- run: bundle exec rake rspec_chunked

View file

@ -1,108 +1,9 @@
# Whether to ignore frontmatter at the beginning of HAML documents for
# frameworks such as Jekyll/Middleman
skip_frontmatter: false
inherits_from: .haml-lint_todo.yml
exclude:
- 'vendor/**/*'
- 'spec/**/*'
- 'lib/templates/**/*'
- 'app/views/kaminari/**/*'
- lib/templates/haml/scaffold/_form.html.haml
linters:
AltText:
enabled: false
ClassAttributeWithStaticValue:
enabled: true
ClassesBeforeIds:
enabled: true
ConsecutiveComments:
enabled: true
ConsecutiveSilentScripts:
enabled: true
max_consecutive: 2
EmptyObjectReference:
enabled: true
EmptyScript:
enabled: true
FinalNewline:
enabled: true
present: true
HtmlAttributes:
enabled: true
ImplicitDiv:
enabled: true
LeadingCommentSpace:
enabled: true
LineLength:
enabled: false
max: 80
MultilinePipe:
enabled: true
MultilineScript:
enabled: true
ObjectReferenceAttributes:
enabled: true
RuboCop:
enabled: true
# These cops are incredibly noisy when it comes to HAML templates, so we
# ignore them.
ignored_cops:
- Lint/BlockAlignment
- Lint/EndAlignment
- Lint/Void
- Metrics/BlockLength
- Metrics/LineLength
- Style/AlignParameters
- Style/BlockNesting
- Style/ElseAlignment
- Style/EndOfLine
- Style/FileName
- Style/FinalNewline
- Style/FrozenStringLiteralComment
- Style/IfUnlessModifier
- Style/IndentationWidth
- Style/Next
- Style/TrailingBlankLines
- Style/TrailingWhitespace
- Style/WhileUntilModifier
RubyComments:
enabled: true
SpaceBeforeScript:
enabled: true
SpaceInsideHashAttributes:
enabled: true
style: space
Indentation:
enabled: true
character: space # or tab
TagName:
enabled: true
TrailingWhitespace:
enabled: true
UnnecessaryInterpolation:
enabled: true
UnnecessaryStringOutput:
enabled: true

106
.haml-lint_todo.yml Normal file
View file

@ -0,0 +1,106 @@
# This configuration was generated by
# `haml-lint --auto-gen-config`
# on 2023-03-15 00:55:01 -0400 using Haml-Lint version 0.45.0.
# The point is for the user to remove these configuration records
# one by one as the lints are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of Haml-Lint, may require this file to be generated again.
linters:
# Offense count: 63
RuboCop:
exclude:
- 'app/views/accounts/_og.html.haml'
- 'app/views/admin/account_warnings/_account_warning.html.haml'
- 'app/views/admin/accounts/index.html.haml'
- 'app/views/admin/accounts/show.html.haml'
- 'app/views/admin/announcements/edit.html.haml'
- 'app/views/admin/announcements/new.html.haml'
- 'app/views/admin/disputes/appeals/_appeal.html.haml'
- 'app/views/admin/domain_blocks/edit.html.haml'
- 'app/views/admin/domain_blocks/new.html.haml'
- 'app/views/admin/ip_blocks/new.html.haml'
- 'app/views/admin/reports/actions/preview.html.haml'
- 'app/views/admin/reports/index.html.haml'
- 'app/views/admin/reports/show.html.haml'
- 'app/views/admin/roles/_form.html.haml'
- 'app/views/admin/settings/about/show.html.haml'
- 'app/views/admin/settings/appearance/show.html.haml'
- 'app/views/admin/settings/registrations/show.html.haml'
- 'app/views/admin/statuses/show.html.haml'
- 'app/views/auth/registrations/new.html.haml'
- 'app/views/disputes/strikes/show.html.haml'
- 'app/views/filters/_filter_fields.html.haml'
- 'app/views/invites/_form.html.haml'
- 'app/views/layouts/application.html.haml'
- 'app/views/layouts/error.html.haml'
- 'app/views/notification_mailer/_status.html.haml'
- 'app/views/settings/applications/_fields.html.haml'
- 'app/views/settings/imports/show.html.haml'
- 'app/views/settings/preferences/appearance/show.html.haml'
- 'app/views/settings/preferences/other/show.html.haml'
- 'app/views/statuses/_detailed_status.html.haml'
- 'app/views/statuses/_poll.html.haml'
- 'app/views/statuses/show.html.haml'
- 'app/views/statuses_cleanup/show.html.haml'
- 'app/views/user_mailer/warning.html.haml'
# Offense count: 913
LineLength:
enabled: false
# Offense count: 22
UnnecessaryStringOutput:
exclude:
- 'app/views/accounts/show.html.haml'
- 'app/views/admin/custom_emojis/_custom_emoji.html.haml'
- 'app/views/admin/relays/_relay.html.haml'
- 'app/views/admin/rules/_rule.html.haml'
- 'app/views/admin/statuses/index.html.haml'
- 'app/views/auth/registrations/_sessions.html.haml'
- 'app/views/disputes/strikes/show.html.haml'
- 'app/views/notification_mailer/_status.html.haml'
- 'app/views/settings/two_factor_authentication_methods/index.html.haml'
- 'app/views/statuses/_detailed_status.html.haml'
- 'app/views/statuses/_poll.html.haml'
- 'app/views/statuses/_simple_status.html.haml'
- 'app/views/user_mailer/suspicious_sign_in.html.haml'
- 'app/views/user_mailer/webauthn_credential_added.html.haml'
- 'app/views/user_mailer/webauthn_credential_deleted.html.haml'
- 'app/views/user_mailer/welcome.html.haml'
# Offense count: 3
ViewLength:
exclude:
- 'app/views/admin/accounts/show.html.haml'
- 'app/views/admin/reports/show.html.haml'
- 'app/views/disputes/strikes/show.html.haml'
# Offense count: 41
InstanceVariables:
exclude:
- 'app/views/admin/reports/_actions.html.haml'
- 'app/views/admin/roles/_form.html.haml'
- 'app/views/admin/webhooks/_form.html.haml'
- 'app/views/auth/registrations/_sessions.html.haml'
- 'app/views/auth/registrations/_status.html.haml'
- 'app/views/auth/sessions/two_factor/_otp_authentication_form.html.haml'
- 'app/views/authorize_interactions/_post_follow_actions.html.haml'
- 'app/views/invites/_form.html.haml'
- 'app/views/relationships/_account.html.haml'
- 'app/views/shared/_og.html.haml'
- 'app/views/statuses/_status.html.haml'
# Offense count: 6
ConsecutiveSilentScripts:
exclude:
- 'app/views/admin/settings/shared/_links.html.haml'
- 'app/views/settings/login_activities/_login_activity.html.haml'
- 'app/views/statuses/_poll.html.haml'
# Offense count: 3
IdNames:
exclude:
- 'app/views/authorize_interactions/error.html.haml'
- 'app/views/oauth/authorizations/error.html.haml'
- 'app/views/shared/_error_messages.html.haml'

View file

@ -8,6 +8,7 @@ require:
- rubocop-rails
- rubocop-rspec
- rubocop-performance
- rubocop-capybara
AllCops:
TargetRubyVersion: 2.7
@ -19,7 +20,6 @@ AllCops:
NewCops: enable
Exclude:
- db/schema.rb
- 'config/**/*'
- 'bin/*'
- 'Rakefile'
- 'node_modules/**/*'
@ -32,7 +32,6 @@ Layout/FirstHashElementIndentation:
EnforcedStyle: consistent
Layout/LineLength:
Max: 140 # RuboCop default 120
AllowedPatterns:
# Allow comments to be long lines
- !ruby/regexp / \# .*$/
@ -47,13 +46,11 @@ Lint/UselessAccessModifier:
- class_methods
Metrics/AbcSize:
Max: 34 # RuboCop default 17
Exclude:
- 'lib/**/*cli*.rb'
- db/*migrate/**/*
Metrics/BlockLength:
Max: 55 # Default 25
CountAsOne: [array, heredoc]
Exclude:
- 'lib/mastodon/*_cli.rb'
@ -62,31 +59,63 @@ Metrics/BlockNesting:
Exclude:
- 'lib/mastodon/*_cli.rb'
# Reason: Some Excluded files would be candidates for refactoring but not currently addressed
# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsclasslength
Metrics/ClassLength:
Max: 500 # Default 100
CountAsOne: [array, heredoc]
CountAsOne: ['array', 'hash', 'heredoc', 'method_call']
Exclude:
- 'lib/mastodon/*_cli.rb'
- 'app/controllers/admin/accounts_controller.rb'
- 'app/controllers/api/base_controller.rb'
- 'app/controllers/api/v1/admin/accounts_controller.rb'
- 'app/controllers/application_controller.rb'
- 'app/controllers/auth/registrations_controller.rb'
- 'app/controllers/auth/sessions_controller.rb'
- 'app/lib/activitypub/activity.rb'
- 'app/lib/activitypub/activity/create.rb'
- 'app/lib/activitypub/tag_manager.rb'
- 'app/lib/feed_manager.rb'
- 'app/lib/link_details_extractor.rb'
- 'app/lib/request.rb'
- 'app/lib/text_formatter.rb'
- 'app/lib/user_settings_decorator.rb'
- 'app/mailers/user_mailer.rb'
- 'app/models/account.rb'
- 'app/models/admin/account_action.rb'
- 'app/models/form/account_batch.rb'
- 'app/models/media_attachment.rb'
- 'app/models/status.rb'
- 'app/models/tag.rb'
- 'app/models/user.rb'
- 'app/serializers/activitypub/actor_serializer.rb'
- 'app/serializers/activitypub/note_serializer.rb'
- 'app/serializers/rest/status_serializer.rb'
- 'app/services/account_search_service.rb'
- 'app/services/activitypub/process_account_service.rb'
- 'app/services/activitypub/process_status_update_service.rb'
- 'app/services/backup_service.rb'
- 'app/services/delete_account_service.rb'
- 'app/services/fan_out_on_write_service.rb'
- 'app/services/fetch_link_card_service.rb'
- 'app/services/import_service.rb'
- 'app/services/notify_service.rb'
- 'app/services/post_status_service.rb'
- 'app/services/update_status_service.rb'
- 'lib/paperclip/color_extractor.rb'
Metrics/CyclomaticComplexity:
Max: 12 # Default 7
Exclude:
- lib/mastodon/*cli*.rb
- db/*migrate/**/*
Metrics/MethodLength:
Max: 25 # RuboCop default 10
CountAsOne: [array, heredoc]
Exclude:
- 'lib/mastodon/*_cli.rb'
Metrics/ModuleLength:
Max: 200 # Default 100
CountAsOne: [array, heredoc]
Metrics/PerceivedComplexity:
Max: 16 # RuboCop default 8
Rails/HttpStatus:
EnforcedStyle: numeric
@ -96,9 +125,26 @@ Rails/Exit:
- 'lib/mastodon/cli_helper.rb'
- 'lib/cli.rb'
# Reason: Some single letter camel case files shouldn't be split
# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecfilepath
RSpec/FilePath:
CustomTransform:
ActivityPub: activitypub # Ignore the snake_case due to the amount of files to rename
DeepL: deepl
FetchOEmbedService: fetch_oembed_service
JsonLdHelper: jsonld_helper
OEmbedController: oembed_controller
OStatus: ostatus
NodeInfoController: nodeinfo_controller # NodeInfo isn't snake_cased for any of the instances
Exclude:
- 'spec/config/initializers/rack_attack_spec.rb' # namespaces usually have separate folder
- 'spec/lib/sanitize_config_spec.rb' # namespaces usually have separate folder
- 'spec/controllers/concerns/account_controller_concern_spec.rb' # Concerns describe ApplicationController and don't fit naming
- 'spec/controllers/concerns/export_controller_concern_spec.rb'
- 'spec/controllers/concerns/localized_spec.rb'
- 'spec/controllers/concerns/rate_limit_headers_spec.rb'
- 'spec/controllers/concerns/signature_verification_spec.rb'
- 'spec/controllers/concerns/user_tracking_concern_spec.rb'
RSpec/NotToNot:
EnforcedStyle: to_not
@ -106,6 +152,16 @@ RSpec/NotToNot:
RSpec/Rails/HttpStatus:
EnforcedStyle: numeric
# Reason:
# https://docs.rubocop.org/rubocop/cops_style.html#styleclassandmodulechildren
Style/ClassAndModuleChildren:
Enabled: false
# Reason: Classes mostly self-document with their names
# https://docs.rubocop.org/rubocop/cops_style.html#styledocumentation
Style/Documentation:
Enabled: false
Style/HashSyntax:
EnforcedStyle: ruby19_no_mixed_keys

File diff suppressed because it is too large Load diff

View file

@ -2,6 +2,57 @@
All notable changes to this project will be documented in this file.
## [4.1.1] - 2023-03-16
### Added
- Add redirection from paths with url-encoded `@` to their decoded form ([thijskh](https://github.com/mastodon/mastodon/pull/23593))
- Add `lang` attribute to native language names in language picker in Web UI ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23749))
- Add headers to outgoing mails to avoid auto-replies ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23597))
- Add support for refreshing many accounts at once with `tootctl accounts refresh` ([9p4](https://github.com/mastodon/mastodon/pull/23304))
- Add confirmation modal when clicking to edit a post with a non-empty compose form ([PauloVilarinho](https://github.com/mastodon/mastodon/pull/23936))
- Add support for the HAproxy PROXY protocol through the `PROXY_PROTO_V1` environment variable ([CSDUMMI](https://github.com/mastodon/mastodon/pull/24064))
- Add `SENDFILE_HEADER` environment variable ([Gargron](https://github.com/mastodon/mastodon/pull/24123))
- Add cache headers to static files served through Rails ([Gargron](https://github.com/mastodon/mastodon/pull/24120))
### Changed
- Increase contrast of upload progress bar background ([toolmantim](https://github.com/mastodon/mastodon/pull/23836))
- Change post auto-deletion throttling constants to better scale with server size ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23320))
- Change order of bookmark and favourite sidebar entries in single-column UI for consistency ([TerryGarcia](https://github.com/mastodon/mastodon/pull/23701))
- Change `ActivityPub::DeliveryWorker` retries to be spread out more ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/21956))
### Fixed
- Fix “Remove all followers from the selected domains” also removing follows and notifications ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23805))
- Fix streaming metrics format ([emilweth](https://github.com/mastodon/mastodon/pull/23519), [emilweth](https://github.com/mastodon/mastodon/pull/23520))
- Fix case-sensitive check for previously used hashtags in hashtag autocompletion ([deanveloper](https://github.com/mastodon/mastodon/pull/23526))
- Fix focus point of already-attached media not saving after edit ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23566))
- Fix sidebar behavior in settings/admin UI on mobile ([wxt2005](https://github.com/mastodon/mastodon/pull/23764))
- Fix inefficiency when searching accounts per username in admin interface ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23801))
- Fix duplicate “Publish” button on mobile ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23804))
- Fix server error when failing to follow back followers from `/relationships` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23787))
- Fix server error when attempting to display the edit history of a trendable post in the admin interface ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23574))
- Fix `tootctl accounts migrate` crashing because of a typo ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23567))
- Fix original account being unfollowed on migration before the follow request to the new account could be sent ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/21957))
- Fix the “Back” button in column headers sometimes leaving Mastodon ([c960657](https://github.com/mastodon/mastodon/pull/23953))
- Fix pgBouncer resetting application name on every transaction ([Gargron](https://github.com/mastodon/mastodon/pull/23958))
- Fix unconfirmed accounts being counted as active users ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23803))
- Fix `/api/v1/streaming` sub-paths not being redirected ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23988))
- Fix drag'n'drop upload area text that spans multiple lines not being centered ([vintprox](https://github.com/mastodon/mastodon/pull/24029))
- Fix sidekiq jobs not triggering Elasticsearch index updates ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/24046))
- Fix tags being unnecessarily stripped from plain-text short site description ([c960657](https://github.com/mastodon/mastodon/pull/23975))
- Fix HTML entities not being un-escaped in extracted plain-text from remote posts ([c960657](https://github.com/mastodon/mastodon/pull/24019))
- Fix dashboard crash on ElasticSearch server error ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23751))
- Fix incorrect post links in strikes when the account is remote ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23611))
- Fix misleading error code when receiving invalid WebAuthn credentials ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23568))
- Fix duplicate mails being sent when the SMTP server is too slow to close the connection ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23750))
### Security
- Change user backups to use expiring URLs for download when possible ([Gargron](https://github.com/mastodon/mastodon/pull/24136))
- Add warning for object storage misconfiguration ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/24137))
## [4.1.0] - 2023-02-10
### Added

View file

@ -80,8 +80,6 @@ It is not always possible to phrase every change in such a manner, but it is des
- Code style rules (rubocop, eslint)
- Normalization of locale files (i18n-tasks)
**Note**: You may need to log in and authorise the GitHub account your fork of this repository belongs to with CircleCI to enable some of the automated checks to run.
## Documentation
The [Mastodon documentation](https://docs.joinmastodon.org) is a statically generated site. You can [submit merge requests to mastodon/documentation](https://github.com/mastodon/documentation).

View file

@ -37,7 +37,7 @@ RUN apt-get update && \
bundle config set --local without 'development test' && \
bundle config set silence_root_warning true && \
bundle install -j"$(nproc)" && \
yarn install --pure-lockfile --network-timeout 600000 && \
yarn install --pure-lockfile --production --network-timeout 600000 && \
yarn cache clean
FROM node:${NODE_VERSION}

14
Gemfile
View file

@ -4,7 +4,6 @@ source 'https://rubygems.org'
ruby '>= 2.7.0', '< 3.3.0'
gem 'pkg-config', '~> 1.5'
gem 'rexml', '~> 3.2'
gem 'puma', '~> 6.1'
gem 'rails', '~> 6.1.7'
@ -40,7 +39,7 @@ end
gem 'net-ldap', '~> 0.17'
gem 'omniauth-cas', '~> 2.0'
gem 'omniauth-saml', '~> 1.10'
gem 'omniauth_openid_connect', '~> 0.6.0'
gem 'omniauth_openid_connect', '~> 0.6.1'
gem 'omniauth', '~> 1.9'
gem 'omniauth-rails_csrf_protection', '~> 0.1'
@ -70,7 +69,7 @@ gem 'public_suffix', '~> 5.0'
gem 'pundit', '~> 2.3'
gem 'premailer-rails'
gem 'rack-attack', '~> 6.6'
gem 'rack-cors', '~> 1.1', require: 'rack/cors'
gem 'rack-cors', '~> 2.0', require: 'rack/cors'
gem 'rails-i18n', '~> 6.0'
gem 'rails-settings-cached', '~> 0.6', git: 'https://github.com/mastodon/rails-settings-cached.git', branch: 'v0.6.6-aliases-true'
gem 'redcarpet', '~> 3.6'
@ -105,6 +104,9 @@ group :development, :test do
gem 'fuubar', '~> 2.5'
gem 'i18n-tasks', '~> 1.0', require: false
gem 'rspec-rails', '~> 6.0'
gem 'rspec_chunked', '~> 0.6'
gem 'rubocop-capybara', require: false
gem 'rubocop-performance', require: false
gem 'rubocop-rails', require: false
gem 'rubocop-rspec', require: false
@ -117,9 +119,10 @@ end
group :test do
gem 'capybara', '~> 3.38'
gem 'climate_control'
gem 'faker', '~> 3.1'
gem 'json-schema', '~> 3.0'
gem 'rack-test', '~> 2.0'
gem 'rack-test', '~> 2.1'
gem 'rails-controller-testing', '~> 1.0'
gem 'rspec_junit_formatter', '~> 0.6'
gem 'rspec-sidekiq', '~> 3.1'
@ -128,16 +131,15 @@ group :test do
end
group :development do
gem 'active_record_query_trace', '~> 1.8'
gem 'annotate', '~> 3.2'
gem 'better_errors', '~> 2.9'
gem 'binding_of_caller', '~> 1.0'
gem 'bullet', '~> 7.0'
gem 'letter_opener', '~> 1.8'
gem 'letter_opener_web', '~> 2.0'
gem 'memory_profiler'
gem 'brakeman', '~> 5.4', require: false
gem 'bundler-audit', '~> 0.9', require: false
gem 'haml_lint', require: false
gem 'capistrano', '~> 3.17'
gem 'capistrano-rails', '~> 1.6'

View file

@ -30,40 +30,40 @@ GIT
GEM
remote: https://rubygems.org/
specs:
actioncable (6.1.7.2)
actionpack (= 6.1.7.2)
activesupport (= 6.1.7.2)
actioncable (6.1.7.3)
actionpack (= 6.1.7.3)
activesupport (= 6.1.7.3)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailbox (6.1.7.2)
actionpack (= 6.1.7.2)
activejob (= 6.1.7.2)
activerecord (= 6.1.7.2)
activestorage (= 6.1.7.2)
activesupport (= 6.1.7.2)
actionmailbox (6.1.7.3)
actionpack (= 6.1.7.3)
activejob (= 6.1.7.3)
activerecord (= 6.1.7.3)
activestorage (= 6.1.7.3)
activesupport (= 6.1.7.3)
mail (>= 2.7.1)
actionmailer (6.1.7.2)
actionpack (= 6.1.7.2)
actionview (= 6.1.7.2)
activejob (= 6.1.7.2)
activesupport (= 6.1.7.2)
actionmailer (6.1.7.3)
actionpack (= 6.1.7.3)
actionview (= 6.1.7.3)
activejob (= 6.1.7.3)
activesupport (= 6.1.7.3)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (6.1.7.2)
actionview (= 6.1.7.2)
activesupport (= 6.1.7.2)
actionpack (6.1.7.3)
actionview (= 6.1.7.3)
activesupport (= 6.1.7.3)
rack (~> 2.0, >= 2.0.9)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
actiontext (6.1.7.2)
actionpack (= 6.1.7.2)
activerecord (= 6.1.7.2)
activestorage (= 6.1.7.2)
activesupport (= 6.1.7.2)
actiontext (6.1.7.3)
actionpack (= 6.1.7.3)
activerecord (= 6.1.7.3)
activestorage (= 6.1.7.3)
activesupport (= 6.1.7.3)
nokogiri (>= 1.8.5)
actionview (6.1.7.2)
activesupport (= 6.1.7.2)
actionview (6.1.7.3)
activesupport (= 6.1.7.3)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
@ -73,23 +73,22 @@ GEM
activemodel (>= 4.1, < 7.1)
case_transform (>= 0.2)
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
active_record_query_trace (1.8)
activejob (6.1.7.2)
activesupport (= 6.1.7.2)
activejob (6.1.7.3)
activesupport (= 6.1.7.3)
globalid (>= 0.3.6)
activemodel (6.1.7.2)
activesupport (= 6.1.7.2)
activerecord (6.1.7.2)
activemodel (= 6.1.7.2)
activesupport (= 6.1.7.2)
activestorage (6.1.7.2)
actionpack (= 6.1.7.2)
activejob (= 6.1.7.2)
activerecord (= 6.1.7.2)
activesupport (= 6.1.7.2)
activemodel (6.1.7.3)
activesupport (= 6.1.7.3)
activerecord (6.1.7.3)
activemodel (= 6.1.7.3)
activesupport (= 6.1.7.3)
activestorage (6.1.7.3)
actionpack (= 6.1.7.3)
activejob (= 6.1.7.3)
activerecord (= 6.1.7.3)
activesupport (= 6.1.7.3)
marcel (~> 1.0)
mini_mime (>= 1.1.0)
activesupport (6.1.7.2)
activesupport (6.1.7.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
@ -149,9 +148,6 @@ GEM
concurrent-ruby (~> 1.0, >= 1.0.5)
redis (>= 1.0, < 6)
builder (3.2.4)
bullet (7.0.7)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.11)
bundler-audit (0.9.1)
bundler (>= 1.2.0, < 3)
thor (~> 1.0)
@ -225,7 +221,7 @@ GEM
docile (1.4.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
doorkeeper (5.6.4)
doorkeeper (5.6.5)
railties (>= 5)
dotenv (2.8.1)
dotenv-rails (2.8.1)
@ -308,6 +304,12 @@ GEM
activesupport (>= 5.1)
haml (>= 4.0.6)
railties (>= 5.1)
haml_lint (0.45.0)
haml (>= 4.0, < 6.2)
parallel (~> 1.10)
rainbow
rubocop (>= 0.50.0)
sysexits (~> 1.1)
hashdiff (1.0.1)
hashie (5.0.0)
hcaptcha (7.1.0)
@ -399,7 +401,7 @@ GEM
loofah (2.19.1)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.8.0.1)
mail (2.8.1)
mini_mime (>= 0.1.1)
net-imap
net-pop
@ -417,7 +419,7 @@ GEM
mime-types-data (3.2022.0105)
mini_mime (1.1.2)
mini_portile2 (2.8.1)
minitest (5.17.0)
minitest (5.18.0)
msgpack (1.6.0)
multi_json (1.15.0)
multipart-post (2.3.0)
@ -459,7 +461,7 @@ GEM
omniauth-saml (1.10.3)
omniauth (~> 1.3, >= 1.3.2)
ruby-saml (~> 1.9)
omniauth_openid_connect (0.6.0)
omniauth_openid_connect (0.6.1)
omniauth (>= 1.9, < 3)
openid_connect (~> 1.1)
openid_connect (1.4.2)
@ -479,13 +481,13 @@ GEM
orm_adapter (0.5.0)
ox (2.14.14)
parallel (1.22.1)
parser (3.2.1.0)
parser (3.2.1.1)
ast (~> 2.4.1)
parslet (2.0.0)
pastel (0.8.0)
tty-color (~> 0.5)
pg (1.4.5)
pghero (3.1.0)
pg (1.4.6)
pghero (3.3.1)
activerecord (>= 6)
pkg-config (1.5.1)
posix-spawn (0.3.15)
@ -499,16 +501,16 @@ GEM
premailer (~> 1.7, >= 1.7.9)
private_address_check (0.5.0)
public_suffix (5.0.1)
puma (6.1.0)
puma (6.1.1)
nio4r (~> 2.0)
pundit (2.3.0)
activesupport (>= 3.0.0)
raabro (1.4.0)
racc (1.6.2)
rack (2.2.6.2)
rack (2.2.6.4)
rack-attack (6.6.1)
rack (>= 1.0, < 3)
rack-cors (1.1.1)
rack-cors (2.0.1)
rack (>= 2.0.0)
rack-oauth2 (1.21.3)
activesupport
@ -518,22 +520,22 @@ GEM
rack (>= 2.1.0)
rack-proxy (0.7.6)
rack
rack-test (2.0.2)
rack-test (2.1.0)
rack (>= 1.3)
rails (6.1.7.2)
actioncable (= 6.1.7.2)
actionmailbox (= 6.1.7.2)
actionmailer (= 6.1.7.2)
actionpack (= 6.1.7.2)
actiontext (= 6.1.7.2)
actionview (= 6.1.7.2)
activejob (= 6.1.7.2)
activemodel (= 6.1.7.2)
activerecord (= 6.1.7.2)
activestorage (= 6.1.7.2)
activesupport (= 6.1.7.2)
rails (6.1.7.3)
actioncable (= 6.1.7.3)
actionmailbox (= 6.1.7.3)
actionmailer (= 6.1.7.3)
actionpack (= 6.1.7.3)
actiontext (= 6.1.7.3)
actionview (= 6.1.7.3)
activejob (= 6.1.7.3)
activemodel (= 6.1.7.3)
activerecord (= 6.1.7.3)
activestorage (= 6.1.7.3)
activesupport (= 6.1.7.3)
bundler (>= 1.15.0)
railties (= 6.1.7.2)
railties (= 6.1.7.3)
sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.5)
actionpack (>= 5.0.1.rc1)
@ -547,9 +549,9 @@ GEM
rails-i18n (6.0.0)
i18n (>= 0.7, < 2)
railties (>= 6.0.0, < 7)
railties (6.1.7.2)
actionpack (= 6.1.7.2)
activesupport (= 6.1.7.2)
railties (6.1.7.3)
actionpack (= 6.1.7.3)
activesupport (= 6.1.7.3)
method_source
rake (>= 12.2)
thor (~> 1.0)
@ -598,33 +600,34 @@ GEM
rspec-core (~> 3.0, >= 3.0.0)
sidekiq (>= 2.4.0)
rspec-support (3.12.0)
rspec_chunked (0.6)
rspec_junit_formatter (0.6.0)
rspec-core (>= 2, < 4, != 2.12.0)
rubocop (1.45.1)
rubocop (1.48.1)
json (~> 2.3)
parallel (~> 1.10)
parser (>= 3.2.0.0)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.24.1, < 2.0)
rubocop-ast (>= 1.26.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.24.1)
parser (>= 3.1.1.0)
rubocop-capybara (2.17.0)
rubocop-ast (1.27.0)
parser (>= 3.2.1.0)
rubocop-capybara (2.17.1)
rubocop (~> 1.41)
rubocop-performance (1.16.0)
rubocop (>= 1.7.0, < 2.0)
rubocop-ast (>= 0.4.0)
rubocop-rails (2.17.4)
rubocop-rails (2.18.0)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 1.33.0, < 2.0)
rubocop-rspec (2.18.1)
rubocop-rspec (2.19.0)
rubocop (~> 1.33)
rubocop-capybara (~> 2.17)
ruby-progressbar (1.11.0)
ruby-progressbar (1.13.0)
ruby-saml (1.13.0)
nokogiri (>= 1.10.5)
rexml
@ -646,9 +649,9 @@ GEM
redis (>= 4.5.0, < 5)
sidekiq-bulk (0.2.0)
sidekiq
sidekiq-scheduler (5.0.1)
sidekiq-scheduler (5.0.2)
rufus-scheduler (~> 3.2)
sidekiq (>= 4, < 8)
sidekiq (>= 6, < 8)
tilt (>= 1.4.0)
sidekiq-unique-jobs (7.1.29)
brpoplpush-redis_script (> 0.1.1, <= 2.0.0)
@ -678,7 +681,7 @@ GEM
sshkit (1.21.4)
net-scp (>= 1.1.2)
net-ssh (>= 2.8.0)
stackprof (0.2.23)
stackprof (0.2.24)
statsd-ruby (1.5.0)
stoplight (3.0.1)
redlock (~> 1.0)
@ -688,14 +691,15 @@ GEM
activesupport (>= 3)
attr_required (>= 0.0.5)
httpclient (>= 2.4)
sysexits (1.2.0)
temple (0.10.0)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
terrapin (0.6.0)
climate_control (>= 0.0.3, < 1.0)
thor (1.2.1)
tilt (2.0.11)
timeout (0.3.1)
tilt (2.1.0)
timeout (0.3.2)
tpm-key_attestation (0.12.0)
bindata (~> 2.4)
openssl (> 2.0)
@ -721,7 +725,6 @@ GEM
unf_ext
unf_ext (0.0.8.2)
unicode-display_width (2.4.2)
uniform_notifier (1.16.0)
uri (0.12.0)
validate_email (0.1.6)
activemodel (>= 3.0)
@ -766,7 +769,6 @@ PLATFORMS
DEPENDENCIES
active_model_serializers (~> 0.10)
active_record_query_trace (~> 1.8)
addressable (~> 2.8)
annotate (~> 3.2)
aws-sdk-s3 (~> 1.119)
@ -776,7 +778,6 @@ DEPENDENCIES
bootsnap (~> 1.16.0)
brakeman (~> 5.4)
browser
bullet (~> 7.0)
bundler-audit (~> 0.9)
capistrano (~> 3.17)
capistrano-rails (~> 1.6)
@ -785,6 +786,7 @@ DEPENDENCIES
capybara (~> 3.38)
charlock_holmes (~> 0.7.7)
chewy (~> 7.2)
climate_control
cocoon (~> 1.2)
color_diff (~> 0.1)
concurrent-ruby
@ -804,6 +806,7 @@ DEPENDENCIES
fog-openstack (~> 0.3)
fuubar (~> 2.5)
haml-rails (~> 2.0)
haml_lint
hcaptcha (~> 7.1)
hiredis (~> 0.6)
htmlentities (~> 4.3)
@ -834,7 +837,7 @@ DEPENDENCIES
omniauth-cas (~> 2.0)
omniauth-rails_csrf_protection (~> 0.1)
omniauth-saml (~> 1.10)
omniauth_openid_connect (~> 0.6.0)
omniauth_openid_connect (~> 0.6.1)
ox (~> 2.14)
parslet
pg (~> 1.4)
@ -848,8 +851,8 @@ DEPENDENCIES
pundit (~> 2.3)
rack (~> 2.2.6)
rack-attack (~> 6.6)
rack-cors (~> 1.1)
rack-test (~> 2.0)
rack-cors (~> 2.0)
rack-test (~> 2.1)
rails (~> 6.1.7)
rails-controller-testing (~> 1.0)
rails-i18n (~> 6.0)
@ -858,12 +861,13 @@ DEPENDENCIES
redcarpet (~> 3.6)
redis (~> 4.5)
redis-namespace (~> 1.10)
rexml (~> 3.2)
rqrcode (~> 2.1)
rspec-rails (~> 6.0)
rspec-sidekiq (~> 3.1)
rspec_chunked (~> 0.6)
rspec_junit_formatter (~> 0.6)
rubocop
rubocop-capybara
rubocop-performance
rubocop-rails
rubocop-rspec

View file

@ -2,7 +2,7 @@
module Admin
class DomainBlocksController < BaseController
before_action :set_domain_block, only: [:show, :destroy, :edit, :update]
before_action :set_domain_block, only: [:destroy, :edit, :update]
def batch
authorize :domain_block, :create?

View file

@ -2,8 +2,6 @@
module Admin
class EmailDomainBlocksController < BaseController
before_action :set_email_domain_block, only: [:show, :destroy]
def index
authorize :email_domain_block, :index?
@ -59,10 +57,6 @@ module Admin
private
def set_email_domain_block
@email_domain_block = EmailDomainBlock.find(params[:id])
end
def set_resolved_records
Resolv::DNS.open do |dns|
dns.timeouts = 5

View file

@ -0,0 +1,23 @@
# frozen_string_literal: true
class Api::V1::Instances::TranslationLanguagesController < Api::BaseController
skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
before_action :set_languages
def show
expires_in 1.day, public: true
render json: @languages
end
private
def set_languages
if TranslationService.configured?
@languages = Rails.cache.fetch('translation_service/languages', expires_in: 7.days, race_condition_ttl: 1.hour) { TranslationService.configured.languages }
@languages['und'] = @languages.delete(nil) if @languages.key?(nil)
else
@languages = {}
end
end
end

View file

@ -18,6 +18,8 @@ class ApplicationController < ActionController::Base
helper_method :current_skin
helper_method :single_user_mode?
helper_method :use_seamless_external_login?
helper_method :omniauth_only?
helper_method :sso_account_settings
helper_method :whitelist_mode?
rescue_from ActionController::ParameterMissing, Paperclip::AdapterRegistry::NoHandlerError, with: :bad_request
@ -63,7 +65,11 @@ class ApplicationController < ActionController::Base
end
def after_sign_out_path_for(_resource_or_scope)
new_user_session_path
if ENV['OMNIAUTH_ONLY'] == 'true' && ENV['OIDC_ENABLED'] == 'true'
'/auth/auth/openid_connect/logout'
else
new_user_session_path
end
end
protected
@ -116,6 +122,14 @@ class ApplicationController < ActionController::Base
Devise.pam_authentication || Devise.ldap_authentication
end
def omniauth_only?
ENV['OMNIAUTH_ONLY'] == 'true'
end
def sso_account_settings
ENV.fetch('SSO_ACCOUNT_SETTINGS')
end
def current_account
return @current_account if defined?(@current_account)

View file

@ -33,7 +33,7 @@ class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def after_sign_in_path_for(resource)
if resource.email_present?
root_path
stored_location_for(resource) || root_path
else
auth_setup_path(missing_email: '1')
end

View file

@ -0,0 +1,27 @@
# frozen_string_literal: true
class BackupsController < ApplicationController
include RoutingHelper
skip_before_action :require_functional!
before_action :authenticate_user!
before_action :set_backup
def download
case Paperclip::Attachment.default_options[:storage]
when :s3
redirect_to @backup.dump.expiring_url(10)
when :fog
redirect_to @backup.dump.expiring_url(Time.now.utc + 10)
when :filesystem
redirect_to full_asset_url(@backup.dump.url)
end
end
private
def set_backup
@backup = current_user.backups.find(params[:id])
end
end

View file

@ -3,6 +3,158 @@
module CacheConcern
extend ActiveSupport::Concern
module ActiveRecordCoder
EMPTY_HASH = {}.freeze
class << self
def dump(record)
instances = InstanceTracker.new
serialized_associations = serialize_associations(record, instances)
serialized_records = instances.map { |r| serialize_record(r) }
[serialized_associations, *serialized_records]
end
def load(payload)
instances = InstanceTracker.new
serialized_associations, *serialized_records = payload
serialized_records.each { |attrs| instances.push(deserialize_record(*attrs)) }
deserialize_associations(serialized_associations, instances)
end
private
# Records without associations, or which have already been visited before,
# are serialized by their id alone.
#
# Records with associations are serialized as a two-element array including
# their id and the record's association cache.
#
def serialize_associations(record, instances)
return unless record
if (id = instances.lookup(record))
payload = id
else
payload = instances.push(record)
cached_associations = record.class.reflect_on_all_associations.select do |reflection|
record.association_cached?(reflection.name)
end
unless cached_associations.empty?
serialized_associations = cached_associations.map do |reflection|
association = record.association(reflection.name)
serialized_target = if reflection.collection?
association.target.map { |target_record| serialize_associations(target_record, instances) }
else
serialize_associations(association.target, instances)
end
[reflection.name, serialized_target]
end
payload = [payload, serialized_associations]
end
end
payload
end
def deserialize_associations(payload, instances)
return unless payload
id, associations = payload
record = instances.fetch(id)
associations&.each do |name, serialized_target|
begin
association = record.association(name)
rescue ActiveRecord::AssociationNotFoundError
raise AssociationMissingError, "undefined association: #{name}"
end
target = if association.reflection.collection?
serialized_target.map! { |serialized_record| deserialize_associations(serialized_record, instances) }
else
deserialize_associations(serialized_target, instances)
end
association.target = target
end
record
end
def serialize_record(record)
arguments = [record.class.name, attributes_for_database(record)]
arguments << true if record.new_record?
arguments
end
if Rails.gem_version >= Gem::Version.new('7.0')
def attributes_for_database(record)
attributes = record.attributes_for_database
attributes.transform_values! { |attr| attr.is_a?(::ActiveModel::Type::Binary::Data) ? attr.to_s : attr }
attributes
end
else
def attributes_for_database(record)
attributes = record.instance_variable_get(:@attributes).send(:attributes).transform_values(&:value_for_database)
attributes.transform_values! { |attr| attr.is_a?(::ActiveModel::Type::Binary::Data) ? attr.to_s : attr }
attributes
end
end
def deserialize_record(class_name, attributes_from_database, new_record = false) # rubocop:disable Style/OptionalBooleanParameter
begin
klass = Object.const_get(class_name)
rescue NameError
raise ClassMissingError, "undefined class: #{class_name}"
end
# Ideally we'd like to call `klass.instantiate`, however it doesn't allow to pass
# wether the record was persisted or not.
attributes = klass.attributes_builder.build_from_database(attributes_from_database, EMPTY_HASH)
klass.allocate.init_with_attributes(attributes, new_record)
end
end
class Error < StandardError
end
class ClassMissingError < Error
end
class AssociationMissingError < Error
end
class InstanceTracker
def initialize
@instances = []
@ids = {}.compare_by_identity
end
def map(&block)
@instances.map(&block)
end
def fetch(...)
@instances.fetch(...)
end
def push(instance)
id = @ids[instance] = @instances.size
@instances << instance
id
end
def lookup(instance)
@ids[instance]
end
end
end
def render_with_cache(**options)
raise ArgumentError, 'only JSON render calls are supported' unless options.key?(:json) || block_given?
@ -34,8 +186,13 @@ module CacheConcern
raw = raw.cache_ids.to_a if raw.is_a?(ActiveRecord::Relation)
return [] if raw.empty?
cached_keys_with_value = Rails.cache.read_multi(*raw).transform_keys(&:id)
uncached_ids = raw.map(&:id) - cached_keys_with_value.keys
cached_keys_with_value = begin
Rails.cache.read_multi(*raw).transform_keys(&:id).transform_values { |r| ActiveRecordCoder.load(r) }
rescue ActiveRecordCoder::Error
{} # The serialization format may have changed, let's pretend it's a cache miss.
end
uncached_ids = raw.map(&:id) - cached_keys_with_value.keys
klass.reload_stale_associations!(cached_keys_with_value.values) if klass.respond_to?(:reload_stale_associations!)
@ -43,7 +200,7 @@ module CacheConcern
uncached = klass.where(id: uncached_ids).with_includes.index_by(&:id)
uncached.each_value do |item|
Rails.cache.write(item, item)
Rails.cache.write(item, ActiveRecordCoder.dump(item))
end
end

View file

@ -138,7 +138,7 @@ module SignatureVerification
end
def signed_headers
signature_params.fetch('headers', signature_algorithm == 'hs2019' ? '(created)' : 'date').downcase.split(' ')
signature_params.fetch('headers', signature_algorithm == 'hs2019' ? '(created)' : 'date').downcase.split
end
def verify_signature_strength!

View file

@ -52,7 +52,7 @@ module Settings
end
else
flash[:error] = I18n.t('webauthn_credentials.create.error')
status = :internal_server_error
status = :unprocessable_entity
end
else
flash[:error] = t('webauthn_credentials.create.error')

View file

@ -112,7 +112,7 @@ module ApplicationHelper
def fa_icon(icon, attributes = {})
class_names = attributes[:class]&.split(' ') || []
class_names << 'fa'
class_names += icon.split(' ').map { |cl| "fa-#{cl}" }
class_names += icon.split.map { |cl| "fa-#{cl}" }
content_tag(:i, nil, attributes.merge(class: class_names.join(' ')))
end
@ -164,7 +164,7 @@ module ApplicationHelper
end
def body_classes
output = (@body_classes || '').split(' ')
output = (@body_classes || '').split
output << "flavour-#{current_flavour.parameterize}"
output << "skin-#{current_skin.parameterize}"
output << 'system-font' if current_account&.user&.setting_system_font_ui

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
# rubocop:disable Metrics/ModuleLength, Style/WordArray
# rubocop:disable Metrics/ModuleLength
module LanguagesHelper
ISO_639_1 = {
@ -275,4 +275,4 @@ module LanguagesHelper
end
end
# rubocop:enable Metrics/ModuleLength, Style/WordArray
# rubocop:enable Metrics/ModuleLength

View file

@ -5,6 +5,10 @@ export const SERVER_FETCH_REQUEST = 'Server_FETCH_REQUEST';
export const SERVER_FETCH_SUCCESS = 'Server_FETCH_SUCCESS';
export const SERVER_FETCH_FAIL = 'Server_FETCH_FAIL';
export const SERVER_TRANSLATION_LANGUAGES_FETCH_REQUEST = 'SERVER_TRANSLATION_LANGUAGES_FETCH_REQUEST';
export const SERVER_TRANSLATION_LANGUAGES_FETCH_SUCCESS = 'SERVER_TRANSLATION_LANGUAGES_FETCH_SUCCESS';
export const SERVER_TRANSLATION_LANGUAGES_FETCH_FAIL = 'SERVER_TRANSLATION_LANGUAGES_FETCH_FAIL';
export const EXTENDED_DESCRIPTION_REQUEST = 'EXTENDED_DESCRIPTION_REQUEST';
export const EXTENDED_DESCRIPTION_SUCCESS = 'EXTENDED_DESCRIPTION_SUCCESS';
export const EXTENDED_DESCRIPTION_FAIL = 'EXTENDED_DESCRIPTION_FAIL';
@ -37,6 +41,29 @@ const fetchServerFail = error => ({
error,
});
export const fetchServerTranslationLanguages = () => (dispatch, getState) => {
dispatch(fetchServerTranslationLanguagesRequest());
api(getState)
.get('/api/v1/instance/translation_languages').then(({ data }) => {
dispatch(fetchServerTranslationLanguagesSuccess(data));
}).catch(err => dispatch(fetchServerTranslationLanguagesFail(err)));
};
const fetchServerTranslationLanguagesRequest = () => ({
type: SERVER_TRANSLATION_LANGUAGES_FETCH_REQUEST,
});
const fetchServerTranslationLanguagesSuccess = translationLanguages => ({
type: SERVER_TRANSLATION_LANGUAGES_FETCH_SUCCESS,
translationLanguages,
});
const fetchServerTranslationLanguagesFail = error => ({
type: SERVER_TRANSLATION_LANGUAGES_FETCH_FAIL,
error,
});
export const fetchExtendedDescription = () => (dispatch, getState) => {
dispatch(fetchExtendedDescriptionRequest());

View file

@ -4,7 +4,6 @@ import 'es6-symbol/implement';
import includes from 'array-includes';
import assign from 'object-assign';
import values from 'object.values';
import isNaN from 'is-nan';
import { decode as decodeBase64 } from './utils/base64';
import promiseFinally from 'promise.prototype.finally';
@ -20,10 +19,6 @@ if (!Object.values) {
values.shim();
}
if (!Number.isNaN) {
Number.isNaN = isNaN;
}
promiseFinally.shim();
if (!HTMLCanvasElement.prototype.toBlob) {

View file

@ -23,7 +23,6 @@ const messages = defineMessages({
block: { id: 'account.block', defaultMessage: 'Block @{name}' },
});
export default @injectIntl
class Account extends ImmutablePureComponent {
static propTypes = {
@ -184,3 +183,5 @@ class Account extends ImmutablePureComponent {
}
}
export default injectIntl(Account);

View file

@ -84,7 +84,6 @@ class Rule extends React.PureComponent {
}
export default @injectIntl
class ReportReasonSelector extends React.PureComponent {
static propTypes = {
@ -157,3 +156,5 @@ class ReportReasonSelector extends React.PureComponent {
}
}
export default injectIntl(ReportReasonSelector);

View file

@ -12,7 +12,6 @@ const messages = defineMessages({
moveRight: { id: 'column_header.moveRight_settings', defaultMessage: 'Move column to the right' },
});
export default @injectIntl
class ColumnHeader extends React.PureComponent {
static contextTypes = {
@ -218,3 +217,5 @@ class ColumnHeader extends React.PureComponent {
}
}
export default injectIntl(ColumnHeader);

View file

@ -8,7 +8,6 @@ const messages = defineMessages({
dismiss: { id: 'dismissable_banner.dismiss', defaultMessage: 'Dismiss' },
});
export default @injectIntl
class DismissableBanner extends React.PureComponent {
static propTypes = {
@ -49,3 +48,5 @@ class DismissableBanner extends React.PureComponent {
}
}
export default injectIntl(DismissableBanner);

View file

@ -8,7 +8,6 @@ const messages = defineMessages({
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
});
export default @injectIntl
class Account extends ImmutablePureComponent {
static propTypes = {
@ -40,3 +39,5 @@ class Account extends ImmutablePureComponent {
}
}
export default injectIntl(Account);

View file

@ -16,8 +16,6 @@ const mapDispatchToProps = (dispatch, { statusId }) => ({
});
export default @connect(null, mapDispatchToProps)
@injectIntl
class EditedTimestamp extends React.PureComponent {
static propTypes = {
@ -68,3 +66,5 @@ class EditedTimestamp extends React.PureComponent {
}
}
export default connect(null, mapDispatchToProps)(injectIntl(EditedTimestamp));

View file

@ -14,7 +14,6 @@ const makeMapStateToProps = () => {
return mapStateToProps;
};
export default @connect(makeMapStateToProps)
class InlineAccount extends React.PureComponent {
static propTypes = {
@ -32,3 +31,5 @@ class InlineAccount extends React.PureComponent {
}
}
export default connect(makeMapStateToProps)(InlineAccount);

View file

@ -7,7 +7,6 @@ const messages = defineMessages({
load_more: { id: 'status.load_more', defaultMessage: 'Load more' },
});
export default @injectIntl
class LoadGap extends React.PureComponent {
static propTypes = {
@ -32,3 +31,5 @@ class LoadGap extends React.PureComponent {
}
}
export default injectIntl(LoadGap);

View file

@ -244,7 +244,6 @@ class Item extends React.PureComponent {
}
export default @injectIntl
class MediaGallery extends React.PureComponent {
static propTypes = {
@ -406,3 +405,5 @@ class MediaGallery extends React.PureComponent {
}
}
export default injectIntl(MediaGallery);

View file

@ -15,7 +15,6 @@ const DefaultNavigation = () => (
</>
);
export default @withRouter
class NavigationPortal extends React.PureComponent {
render () {
@ -33,3 +32,5 @@ class NavigationPortal extends React.PureComponent {
}
}
export default withRouter(NavigationPortal);

View file

@ -19,7 +19,6 @@ const messages = defineMessages({
btnApply : { id: 'notification_purge.btn_apply', defaultMessage: 'Clear\nselected' },
});
export default @injectIntl
class NotificationPurgeButtons extends ImmutablePureComponent {
static propTypes = {
@ -57,3 +56,5 @@ class NotificationPurgeButtons extends ImmutablePureComponent {
}
}
export default injectIntl(NotificationPurgeButtons);

View file

@ -6,7 +6,6 @@ import { connect } from 'react-redux';
import { debounce } from 'lodash';
import { FormattedMessage } from 'react-intl';
export default @connect()
class PictureInPicturePlaceholder extends React.PureComponent {
static propTypes = {
@ -67,3 +66,5 @@ class PictureInPicturePlaceholder extends React.PureComponent {
}
}
export default connect()(PictureInPicturePlaceholder);

View file

@ -31,7 +31,6 @@ const makeEmojiMap = record => record.get('emojis').reduce((obj, emoji) => {
return obj;
}, {});
export default @injectIntl
class Poll extends ImmutablePureComponent {
static contextTypes = {
@ -234,3 +233,5 @@ class Poll extends ImmutablePureComponent {
}
}
export default injectIntl(Poll);

View file

@ -121,7 +121,6 @@ const timeRemainingString = (intl, date, now, timeGiven = true) => {
return relativeTime;
};
export default @injectIntl
class RelativeTimestamp extends React.Component {
static propTypes = {
@ -197,3 +196,5 @@ class RelativeTimestamp extends React.Component {
}
}
export default injectIntl(RelativeTimestamp);

View file

@ -20,7 +20,6 @@ const mapStateToProps = (state, { scrollKey }) => {
};
};
export default @connect(mapStateToProps, null, null, { forwardRef: true })
class ScrollableList extends PureComponent {
static contextTypes = {
@ -352,3 +351,5 @@ class ScrollableList extends PureComponent {
}
}
export default connect(mapStateToProps, null, null, { forwardRef: true })(ScrollableList);

View file

@ -18,8 +18,6 @@ const mapStateToProps = state => ({
server: state.getIn(['server', 'server']),
});
export default @connect(mapStateToProps)
@injectIntl
class ServerBanner extends React.PureComponent {
static propTypes = {
@ -91,3 +89,5 @@ class ServerBanner extends React.PureComponent {
}
}
export default connect(mapStateToProps)(injectIntl(ServerBanner));

View file

@ -57,7 +57,6 @@ export const defaultMediaVisibility = (status, settings) => {
return (displayMedia !== 'hide_all' && !status.get('sensitive') || displayMedia === 'show_all');
};
export default @injectIntl
class Status extends ImmutablePureComponent {
static contextTypes = {
@ -844,3 +843,5 @@ class Status extends ImmutablePureComponent {
}
}
export default injectIntl(Status);

View file

@ -48,7 +48,6 @@ const messages = defineMessages({
openOriginalPage: { id: 'account.open_original_page', defaultMessage: 'Open original page' },
});
export default @injectIntl
class StatusActionBar extends ImmutablePureComponent {
static contextTypes = {
@ -369,3 +368,5 @@ class StatusActionBar extends ImmutablePureComponent {
}
}
export default injectIntl(StatusActionBar);

View file

@ -3,6 +3,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import { FormattedMessage, injectIntl } from 'react-intl';
import Permalink from './permalink';
import { connect } from 'react-redux';
import classnames from 'classnames';
import Icon from 'flavours/glitch/components/icon';
import { autoPlayGif, languages as preloadedLanguages } from 'flavours/glitch/initial_state';
@ -99,7 +100,10 @@ class TranslateButton extends React.PureComponent {
}
export default @injectIntl
const mapStateToProps = state => ({
languages: state.getIn(['server', 'translationLanguages', 'items']),
});
class StatusContent extends React.PureComponent {
static contextTypes = {
@ -120,6 +124,7 @@ class StatusContent extends React.PureComponent {
onUpdate: PropTypes.func,
tagLinks: PropTypes.bool,
rewriteMentions: PropTypes.string,
languages: ImmutablePropTypes.map,
intl: PropTypes.object,
};
@ -315,7 +320,9 @@ class StatusContent extends React.PureComponent {
} = this.props;
const hidden = this.props.onExpandedToggle ? !this.props.expanded : this.state.hidden;
const renderTranslate = this.props.onTranslate && status.get('translatable');
const contentLocale = intl.locale.replace(/[_-].*/, '');
const targetLanguages = this.props.languages?.get(status.get('language') || 'und');
const renderTranslate = this.props.onTranslate && this.context.identity.signedIn && ['public', 'unlisted'].includes(status.get('visibility')) && status.get('contentHtml').length > 0 && targetLanguages?.includes(contentLocale);
const content = { __html: status.get('translation') ? status.getIn(['translation', 'content']) : status.get('contentHtml') };
const spoilerContent = { __html: status.get('spoilerHtml') };
@ -459,3 +466,5 @@ class StatusContent extends React.PureComponent {
}
}
export default connect(mapStateToProps)(injectIntl(StatusContent));

View file

@ -40,7 +40,6 @@ LanguageIcon.propTypes = {
language: PropTypes.string.isRequired,
};
export default @injectIntl
class StatusIcons extends React.PureComponent {
static propTypes = {
@ -143,3 +142,5 @@ class StatusIcons extends React.PureComponent {
}
}
export default injectIntl(StatusIcons);

View file

@ -12,7 +12,6 @@ const messages = defineMessages({
direct: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' },
});
export default @injectIntl
class VisibilityIcon extends ImmutablePureComponent {
static propTypes = {
@ -49,3 +48,5 @@ class VisibilityIcon extends ImmutablePureComponent {
}
}
export default injectIntl(VisibilityIcon);

View file

@ -54,6 +54,8 @@ const messages = defineMessages({
redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.' },
replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
editConfirm: { id: 'confirmations.edit.confirm', defaultMessage: 'Edit' },
editMessage: { id: 'confirmations.edit.message', defaultMessage: 'Editing now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
unfilterConfirm: { id: 'confirmations.unfilter.confirm', defaultMessage: 'Show' },
author: { id: 'confirmations.unfilter.author', defaultMessage: 'Author' },
matchingFilters: { id: 'confirmations.unfilter.filters', defaultMessage: 'Matching {count, plural, one {filter} other {filters}}' },
@ -193,7 +195,18 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
},
onEdit (status, history) {
dispatch(editStatus(status.get('id'), history));
dispatch((_, getState) => {
let state = getState();
if (state.getIn(['compose', 'text']).trim().length !== 0) {
dispatch(openModal('CONFIRM', {
message: intl.formatMessage(messages.editMessage),
confirm: intl.formatMessage(messages.editConfirm),
onConfirm: () => dispatch(editStatus(status.get('id'), history)),
}));
} else {
dispatch(editStatus(status.get('id'), history));
}
});
},
onTranslate (status) {

View file

@ -80,8 +80,6 @@ class Section extends React.PureComponent {
}
export default @connect(mapStateToProps)
@injectIntl
class About extends React.PureComponent {
static propTypes = {
@ -218,3 +216,5 @@ class About extends React.PureComponent {
}
}
export default connect(mapStateToProps)(injectIntl(About));

View file

@ -10,7 +10,6 @@ const messages = defineMessages({
placeholder: { id: 'account_note.glitch_placeholder', defaultMessage: 'No comment provided' },
});
export default @injectIntl
class Header extends ImmutablePureComponent {
static propTypes = {
@ -102,3 +101,5 @@ class Header extends ImmutablePureComponent {
}
}
export default injectIntl(Header);

View file

@ -8,7 +8,6 @@ import { me, isStaff } from 'flavours/glitch/initial_state';
import { profileLink, accountAdminLink } from 'flavours/glitch/utils/backend_links';
import Icon from 'flavours/glitch/components/icon';
export default @injectIntl
class ActionBar extends React.PureComponent {
static propTypes = {
@ -83,3 +82,5 @@ class ActionBar extends React.PureComponent {
}
}
export default injectIntl(ActionBar);

View file

@ -10,7 +10,6 @@ const messages = defineMessages({
empty: { id: 'account.featured_tags.last_status_never', defaultMessage: 'No posts' },
});
export default @injectIntl
class FeaturedTags extends ImmutablePureComponent {
static contextTypes = {
@ -51,3 +50,5 @@ class FeaturedTags extends ImmutablePureComponent {
}
}
export default injectIntl(FeaturedTags);

View file

@ -76,7 +76,6 @@ const dateFormatOptions = {
minute: '2-digit',
};
export default @injectIntl
class Header extends ImmutablePureComponent {
static contextTypes = {
@ -403,3 +402,5 @@ class Header extends ImmutablePureComponent {
}
}
export default injectIntl(Header);

View file

@ -7,7 +7,6 @@ const messages = defineMessages({
profile: { id: 'column_header.profile', defaultMessage: 'Profile' },
});
export default @injectIntl
class ProfileColumnHeader extends React.PureComponent {
static propTypes = {
@ -31,3 +30,5 @@ class ProfileColumnHeader extends React.PureComponent {
}
}
export default injectIntl(ProfileColumnHeader);

View file

@ -19,7 +19,6 @@ const mapStateToProps = (state, { match: { params: { acct } } }) => {
};
};
export default @connect(mapStateToProps)
class AccountNavigation extends React.PureComponent {
static propTypes = {
@ -50,3 +49,5 @@ class AccountNavigation extends React.PureComponent {
}
}
export default connect(mapStateToProps)(AccountNavigation);

View file

@ -58,7 +58,6 @@ class LoadMoreMedia extends ImmutablePureComponent {
}
export default @connect(mapStateToProps)
class AccountGallery extends ImmutablePureComponent {
static propTypes = {
@ -223,3 +222,5 @@ class AccountGallery extends ImmutablePureComponent {
}
}
export default connect(mapStateToProps)(AccountGallery);

View file

@ -14,7 +14,6 @@ const mapDispatchToProps = (dispatch, { accountId }) => ({
});
export default @connect(() => {}, mapDispatchToProps)
class LimitedAccountHint extends React.PureComponent {
static propTypes = {
@ -34,3 +33,5 @@ class LimitedAccountHint extends React.PureComponent {
}
}
export default connect(() => {}, mapDispatchToProps)(LimitedAccountHint);

View file

@ -62,7 +62,6 @@ RemoteHint.propTypes = {
url: PropTypes.string.isRequired,
};
export default @connect(mapStateToProps)
class AccountTimeline extends ImmutablePureComponent {
static propTypes = {
@ -207,3 +206,5 @@ class AccountTimeline extends ImmutablePureComponent {
}
}
export default connect(mapStateToProps)(AccountTimeline);

View file

@ -22,7 +22,6 @@ const messages = defineMessages({
const TICK_SIZE = 10;
const PADDING = 180;
export default @injectIntl
class Audio extends React.PureComponent {
static propTypes = {
@ -575,3 +574,5 @@ class Audio extends React.PureComponent {
}
}
export default injectIntl(Audio);

View file

@ -22,8 +22,6 @@ const mapStateToProps = state => ({
isLoading: state.getIn(['user_lists', 'blocks', 'isLoading'], true),
});
export default @connect(mapStateToProps)
@injectIntl
class Blocks extends ImmutablePureComponent {
static propTypes = {
@ -77,3 +75,5 @@ class Blocks extends ImmutablePureComponent {
}
}
export default connect(mapStateToProps)(injectIntl(Blocks));

View file

@ -22,8 +22,6 @@ const mapStateToProps = state => ({
hasMore: !!state.getIn(['status_lists', 'bookmarks', 'next']),
});
export default @connect(mapStateToProps)
@injectIntl
class Bookmarks extends ImmutablePureComponent {
static propTypes = {
@ -106,3 +104,5 @@ class Bookmarks extends ImmutablePureComponent {
}
}
export default connect(mapStateToProps)(injectIntl(Bookmarks));

View file

@ -9,7 +9,6 @@ const mapStateToProps = state => ({
message: state.getIn(['server', 'server', 'registrations', 'message']),
});
export default @connect(mapStateToProps)
class ClosedRegistrationsModal extends ImmutablePureComponent {
componentDidMount () {
@ -73,3 +72,5 @@ class ClosedRegistrationsModal extends ImmutablePureComponent {
}
}
export default connect(mapStateToProps)(ClosedRegistrationsModal);

View file

@ -10,7 +10,6 @@ const messages = defineMessages({
settings: { id: 'home.settings', defaultMessage: 'Column settings' },
});
export default @injectIntl
class ColumnSettings extends React.PureComponent {
static propTypes = {
@ -39,3 +38,5 @@ class ColumnSettings extends React.PureComponent {
}
}
export default injectIntl(ColumnSettings);

View file

@ -32,8 +32,6 @@ const mapStateToProps = (state, { columnId }) => {
};
};
export default @connect(mapStateToProps)
@injectIntl
class CommunityTimeline extends React.PureComponent {
static defaultProps = {
@ -162,3 +160,5 @@ class CommunityTimeline extends React.PureComponent {
}
}
export default connect(mapStateToProps)(injectIntl(CommunityTimeline));

View file

@ -21,7 +21,6 @@ const messages = defineMessages({
bookmarks: { id: 'navigation_bar.bookmarks', defaultMessage: 'Bookmarks' },
});
export default @injectIntl
class ActionBar extends React.PureComponent {
static propTypes = {
@ -66,3 +65,5 @@ class ActionBar extends React.PureComponent {
}
}
export default injectIntl(ActionBar);

View file

@ -32,7 +32,6 @@ const messages = defineMessages({
spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Write your warning here' },
});
export default @injectIntl
class ComposeForm extends ImmutablePureComponent {
static contextTypes = {
@ -389,3 +388,5 @@ class ComposeForm extends ImmutablePureComponent {
}
}
export default injectIntl(ComposeForm);

View file

@ -145,8 +145,7 @@ class ModifierPicker extends React.PureComponent {
}
@injectIntl
class EmojiPickerMenu extends React.PureComponent {
class EmojiPickerMenuImpl extends React.PureComponent {
static propTypes = {
custom_emojis: ImmutablePropTypes.list,
@ -307,7 +306,8 @@ class EmojiPickerMenu extends React.PureComponent {
}
export default @injectIntl
const EmojiPickerMenu = injectIntl(EmojiPickerMenuImpl);
class EmojiPickerDropdown extends React.PureComponent {
static propTypes = {
@ -412,3 +412,5 @@ class EmojiPickerDropdown extends React.PureComponent {
}
}
export default injectIntl(EmojiPickerDropdown);

View file

@ -45,7 +45,6 @@ const messages = defineMessages({
},
});
export default @injectIntl
class Header extends ImmutablePureComponent {
static propTypes = {
@ -134,3 +133,5 @@ class Header extends ImmutablePureComponent {
}
}
export default injectIntl(Header);

View file

@ -237,7 +237,6 @@ class LanguageDropdownMenu extends React.PureComponent {
}
export default @injectIntl
class LanguageDropdown extends React.PureComponent {
static propTypes = {
@ -325,3 +324,5 @@ class LanguageDropdown extends React.PureComponent {
}
}
export default injectIntl(LanguageDropdown);

View file

@ -87,8 +87,11 @@ const messages = defineMessages({
},
});
@connect((state, { name }) => ({ checked: state.getIn(['compose', 'advanced_options', name]) }))
class ToggleOption extends ImmutablePureComponent {
const mapStateToProps = (state, { name }) => ({
checked: state.getIn(['compose', 'advanced_options', name]),
});
class ToggleOptionImpl extends ImmutablePureComponent {
static propTypes = {
name: PropTypes.string.isRequired,
@ -117,7 +120,8 @@ class ToggleOption extends ImmutablePureComponent {
}
export default @injectIntl
const ToggleOption = connect(mapStateToProps)(ToggleOptionImpl);
class ComposerOptions extends ImmutablePureComponent {
static propTypes = {
@ -332,3 +336,5 @@ class ComposerOptions extends ImmutablePureComponent {
}
}
export default injectIntl(ComposerOptions);

View file

@ -21,8 +21,7 @@ const messages = defineMessages({
days: { id: 'intervals.full.days', defaultMessage: '{number, plural, one {# day} other {# days}}' },
});
@injectIntl
class Option extends React.PureComponent {
class OptionIntl extends React.PureComponent {
static propTypes = {
title: PropTypes.string.isRequired,
@ -92,8 +91,8 @@ class Option extends React.PureComponent {
}
export default
@injectIntl
const Option = injectIntl(OptionIntl);
class PollForm extends ImmutablePureComponent {
static propTypes = {
@ -168,3 +167,5 @@ class PollForm extends ImmutablePureComponent {
}
}
export default injectIntl(PollForm);

View file

@ -16,7 +16,6 @@ const messages = defineMessages({
change_privacy: { id: 'privacy.change', defaultMessage: 'Adjust status privacy' },
});
export default @injectIntl
class PrivacyDropdown extends React.PureComponent {
static propTypes = {
@ -86,3 +85,5 @@ class PrivacyDropdown extends React.PureComponent {
}
}
export default injectIntl(PrivacyDropdown);

View file

@ -26,7 +26,6 @@ const messages = defineMessages({
saveChanges: { id: 'compose_form.save_changes', defaultMessage: 'Save changes' },
});
export default @injectIntl
class Publisher extends ImmutablePureComponent {
static propTypes = {
@ -97,3 +96,5 @@ class Publisher extends ImmutablePureComponent {
}
}
export default injectIntl(Publisher);

View file

@ -19,7 +19,6 @@ const messages = defineMessages({
});
export default @injectIntl
class ReplyIndicator extends ImmutablePureComponent {
static propTypes = {
@ -80,3 +79,5 @@ class ReplyIndicator extends ImmutablePureComponent {
}
}
export default injectIntl(ReplyIndicator);

View file

@ -45,7 +45,6 @@ class SearchPopout extends React.PureComponent {
}
// The component.
export default @injectIntl
class Search extends React.PureComponent {
static contextTypes = {
@ -166,3 +165,5 @@ class Search extends React.PureComponent {
}
}
export default injectIntl(Search);

View file

@ -14,7 +14,6 @@ const messages = defineMessages({
dismissSuggestion: { id: 'suggestions.dismiss', defaultMessage: 'Dismiss suggestion' },
});
export default @injectIntl
class SearchResults extends ImmutablePureComponent {
static propTypes = {
@ -139,3 +138,5 @@ class SearchResults extends ImmutablePureComponent {
}
}
export default injectIntl(SearchResults);

View file

@ -27,7 +27,6 @@ const iconMap = [
['threaded_mode', 'comments', messages.threadedMode],
];
export default @injectIntl
class TextareaIcons extends ImmutablePureComponent {
static propTypes = {
@ -58,3 +57,5 @@ class TextareaIcons extends ImmutablePureComponent {
}
}
export default injectIntl(TextareaIcons);

View file

@ -39,8 +39,6 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
},
});
export default @connect(mapStateToProps, mapDispatchToProps)
@injectIntl
class Compose extends React.PureComponent {
static propTypes = {
@ -114,3 +112,5 @@ class Compose extends React.PureComponent {
}
}
export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(Compose));

View file

@ -10,7 +10,6 @@ const messages = defineMessages({
settings: { id: 'home.settings', defaultMessage: 'Column settings' },
});
export default @injectIntl
class ColumnSettings extends React.PureComponent {
static propTypes = {
@ -40,3 +39,5 @@ class ColumnSettings extends React.PureComponent {
}
}
export default injectIntl(ColumnSettings);

View file

@ -24,7 +24,6 @@ const messages = defineMessages({
unmuteConversation: { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' },
});
export default @injectIntl
class Conversation extends ImmutablePureComponent {
static contextTypes = {
@ -230,3 +229,5 @@ class Conversation extends ImmutablePureComponent {
}
}
export default injectIntl(Conversation);

View file

@ -22,8 +22,6 @@ const mapStateToProps = state => ({
conversationsMode: state.getIn(['settings', 'direct', 'conversations']),
});
export default @connect(mapStateToProps)
@injectIntl
class DirectTimeline extends React.PureComponent {
static propTypes = {
@ -154,3 +152,5 @@ class DirectTimeline extends React.PureComponent {
}
}
export default connect(mapStateToProps)(injectIntl(DirectTimeline));

View file

@ -93,9 +93,6 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
});
export default
@injectIntl
@connect(makeMapStateToProps, mapDispatchToProps)
class AccountCard extends ImmutablePureComponent {
static propTypes = {
@ -246,3 +243,5 @@ class AccountCard extends ImmutablePureComponent {
}
}
export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(AccountCard));

View file

@ -29,8 +29,6 @@ const mapStateToProps = state => ({
domain: state.getIn(['meta', 'domain']),
});
export default @connect(mapStateToProps)
@injectIntl
class Directory extends React.PureComponent {
static contextTypes = {
@ -176,3 +174,5 @@ class Directory extends React.PureComponent {
}
}
export default connect(mapStateToProps)(injectIntl(Directory));

View file

@ -23,8 +23,6 @@ const mapStateToProps = state => ({
hasMore: !!state.getIn(['domain_lists', 'blocks', 'next']),
});
export default @connect(mapStateToProps)
@injectIntl
class Blocks extends ImmutablePureComponent {
static propTypes = {
@ -81,3 +79,5 @@ class Blocks extends ImmutablePureComponent {
}
}
export default connect(mapStateToProps)(injectIntl(Blocks));

View file

@ -24,8 +24,6 @@ const mapStateToProps = state => ({
isSearching: state.getIn(['search', 'submitted']) || !showTrends,
});
export default @connect(mapStateToProps)
@injectIntl
class Explore extends React.PureComponent {
static contextTypes = {
@ -105,3 +103,5 @@ class Explore extends React.PureComponent {
}
}
export default connect(mapStateToProps)(injectIntl(Explore));

View file

@ -13,7 +13,6 @@ const mapStateToProps = state => ({
isLoading: state.getIn(['trends', 'links', 'isLoading']),
});
export default @connect(mapStateToProps)
class Links extends React.PureComponent {
static propTypes = {
@ -68,3 +67,5 @@ class Links extends React.PureComponent {
}
}
export default connect(mapStateToProps)(Links);

View file

@ -42,8 +42,6 @@ const renderStatuses = (results, onLoadMore) => appendLoadMore('statuses', resul
<Status key={`status-${item}`} id={item} />
)), onLoadMore);
export default @connect(mapStateToProps)
@injectIntl
class Results extends React.PureComponent {
static propTypes = {
@ -124,3 +122,5 @@ class Results extends React.PureComponent {
}
}
export default connect(mapStateToProps)(injectIntl(Results));

View file

@ -14,7 +14,6 @@ const mapStateToProps = state => ({
hasMore: !!state.getIn(['status_lists', 'trending', 'next']),
});
export default @connect(mapStateToProps)
class Statuses extends React.PureComponent {
static propTypes = {
@ -62,3 +61,5 @@ class Statuses extends React.PureComponent {
}
}
export default connect(mapStateToProps)(Statuses);

View file

@ -12,7 +12,6 @@ const mapStateToProps = state => ({
isLoading: state.getIn(['suggestions', 'isLoading']),
});
export default @connect(mapStateToProps)
class Suggestions extends React.PureComponent {
static propTypes = {
@ -54,3 +53,5 @@ class Suggestions extends React.PureComponent {
}
}
export default connect(mapStateToProps)(Suggestions);

View file

@ -13,7 +13,6 @@ const mapStateToProps = state => ({
isLoadingHashtags: state.getIn(['trends', 'tags', 'isLoading']),
});
export default @connect(mapStateToProps)
class Tags extends React.PureComponent {
static propTypes = {
@ -60,3 +59,5 @@ class Tags extends React.PureComponent {
}
}
export default connect(mapStateToProps)(Tags);

View file

@ -22,8 +22,6 @@ const mapStateToProps = state => ({
hasMore: !!state.getIn(['status_lists', 'favourites', 'next']),
});
export default @connect(mapStateToProps)
@injectIntl
class Favourites extends ImmutablePureComponent {
static propTypes = {
@ -106,3 +104,5 @@ class Favourites extends ImmutablePureComponent {
}
}
export default connect(mapStateToProps)(injectIntl(Favourites));

View file

@ -22,8 +22,6 @@ const mapStateToProps = (state, props) => ({
accountIds: state.getIn(['user_lists', 'favourited_by', props.params.statusId]),
});
export default @connect(mapStateToProps)
@injectIntl
class Favourites extends ImmutablePureComponent {
static propTypes = {
@ -101,3 +99,5 @@ class Favourites extends ImmutablePureComponent {
}
}
export default connect(mapStateToProps)(injectIntl(Favourites));

View file

@ -10,7 +10,6 @@ const mapStateToProps = (state, { filterId }) => ({
filter: state.getIn(['filters', filterId]),
});
export default @connect(mapStateToProps)
class AddedToFilter extends React.PureComponent {
static propTypes = {
@ -100,3 +99,5 @@ class AddedToFilter extends React.PureComponent {
}
}
export default connect(mapStateToProps)(AddedToFilter);

View file

@ -22,8 +22,6 @@ const mapStateToProps = (state, { contextType }) => ({
]),
});
export default @connect(mapStateToProps)
@injectIntl
class SelectFilter extends React.PureComponent {
static propTypes = {
@ -190,3 +188,5 @@ class SelectFilter extends React.PureComponent {
}
}
export default connect(mapStateToProps)(injectIntl(SelectFilter));

Some files were not shown because too many files have changed in this diff Show more