Compare commits

..

1 commit

Author SHA1 Message Date
Essem
ac70e6955e
Add Tenor GIF picker
Co-authored-by: koyu <me@koyu.space>
2024-02-28 23:07:35 -06:00
1555 changed files with 16957 additions and 47441 deletions

View file

@ -1,9 +1,7 @@
[production] [production]
defaults defaults
> 0.2% not IE 11
ios >= 15.6
not dead not dead
not OperaMini all
[development] [development]
supports es6-module supports es6-module

View file

@ -70,7 +70,7 @@ services:
hard: -1 hard: -1
libretranslate: libretranslate:
image: libretranslate/libretranslate:v1.5.7 image: libretranslate/libretranslate:v1.5.5
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- lt-data:/home/libretranslate/.local - lt-data:/home/libretranslate/.local

View file

@ -1,4 +0,0 @@
# Required by ActiveRecord encryption feature
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=fkSxKD2bF396kdQbrP1EJ7WbU7ZgNokR
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=r0hvVmzBVsjxC7AMlwhOzmtc36ZCOS1E
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=PhdFyyfy5xJ7WVd2lWBpcPScRQHzRTNr

View file

@ -274,9 +274,6 @@ MAX_POLL_OPTIONS=5
# Maximum allowed poll option characters # Maximum allowed poll option characters
MAX_POLL_OPTION_CHARS=100 MAX_POLL_OPTION_CHARS=100
# Maximum number of emoji reactions per toot and user (minimum 1)
MAX_REACTIONS=1
# Maximum image and video/audio upload sizes # Maximum image and video/audio upload sizes
# Units are in bytes # Units are in bytes
# 1048576 bytes equals 1 megabyte # 1048576 bytes equals 1 megabyte

View file

@ -3,9 +3,3 @@ NODE_ENV=production
# Federation # Federation
LOCAL_DOMAIN=cb6e6126.ngrok.io LOCAL_DOMAIN=cb6e6126.ngrok.io
LOCAL_HTTPS=true LOCAL_HTTPS=true
# Secret values required by ActiveRecord encryption feature
# Use `bin/rails db:encryption:init` to generate fresh secrets
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=test_determinist_key_DO_NOT_USE_IN_PRODUCTION
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=test_salt_DO_NOT_USE_IN_PRODUCTION
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=test_primary_key_DO_NOT_USE_IN_PRODUCTION

View file

@ -123,7 +123,7 @@ module.exports = defineConfig({
'react/react-in-jsx-scope': 'off', // not needed with new JSX transform 'react/react-in-jsx-scope': 'off', // not needed with new JSX transform
'react/self-closing-comp': 'error', 'react/self-closing-comp': 'error',
// recommended values found in https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/v6.8.0/src/index.js#L46 // recommended values found in https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/src/index.js
'jsx-a11y/accessible-emoji': 'warn', 'jsx-a11y/accessible-emoji': 'warn',
'jsx-a11y/click-events-have-key-events': 'off', 'jsx-a11y/click-events-have-key-events': 'off',
'jsx-a11y/label-has-associated-control': 'off', 'jsx-a11y/label-has-associated-control': 'off',
@ -176,7 +176,7 @@ module.exports = defineConfig({
}, },
], ],
// See https://github.com/import-js/eslint-plugin-import/blob/v2.29.1/config/recommended.js // See https://github.com/import-js/eslint-plugin-import/blob/main/config/recommended.js
'import/extensions': [ 'import/extensions': [
'error', 'error',
'always', 'always',
@ -380,7 +380,6 @@ module.exports = defineConfig({
"message": "Use typed hooks `useAppDispatch` and `useAppSelector` instead." "message": "Use typed hooks `useAppDispatch` and `useAppSelector` instead."
} }
], ],
"@typescript-eslint/restrict-template-expressions": ['warn', { allowNumber: true }],
'jsdoc/require-jsdoc': 'off', 'jsdoc/require-jsdoc': 'off',
// Those rules set stricter rules for TS files // Those rules set stricter rules for TS files

4
.github/codecov.yml vendored
View file

@ -1,4 +1,3 @@
comment: false # Do not leave PR comments
coverage: coverage:
status: status:
project: project:
@ -9,3 +8,6 @@ coverage:
default: default:
# Github status check is not blocking # Github status check is not blocking
informational: true informational: true
comment:
# Only write a comment in PR if there are changes
require_changes: true

View file

@ -125,29 +125,6 @@
], ],
groupName: null, // We dont want them to belong to any group groupName: null, // We dont want them to belong to any group
}, },
{
// Group all RuboCop packages with `rubocop` in the same PR
matchManagers: ['bundler'],
matchPackageNames: ['rubocop'],
matchPackagePrefixes: ['rubocop-'],
matchUpdateTypes: ['patch', 'minor'],
groupName: 'RuboCop (non-major)',
},
{
// Group all RSpec packages with `rspec` in the same PR
matchManagers: ['bundler'],
matchPackageNames: ['rspec'],
matchPackagePrefixes: ['rspec-'],
matchUpdateTypes: ['patch', 'minor'],
groupName: 'RSpec (non-major)',
},
{
// Group all opentelemetry-ruby packages in the same PR
matchManagers: ['bundler'],
matchPackagePrefixes: ['opentelemetry-'],
matchUpdateTypes: ['patch', 'minor'],
groupName: 'opentelemetry-ruby (non-major)',
},
// Add labels depending on package manager // Add labels depending on package manager
{ matchManagers: ['npm', 'nvm'], addLabels: ['javascript'] }, { matchManagers: ['npm', 'nvm'], addLabels: ['javascript'] },
{ matchManagers: ['bundler', 'ruby-version'], addLabels: ['ruby'] }, { matchManagers: ['bundler', 'ruby-version'], addLabels: ['ruby'] },

21
.github/stylelint-matcher.json vendored Normal file
View file

@ -0,0 +1,21 @@
{
"problemMatcher": [
{
"owner": "stylelint",
"pattern": [
{
"regexp": "^([^\\s].*)$",
"file": 1
},
{
"regexp": "^\\s+((\\d+):(\\d+))?\\s+(✖|×)\\s+(.*)\\s{2,}(.*)$",
"line": 2,
"column": 3,
"message": 5,
"code": 6,
"loop": true
}
]
}
]
}

View file

@ -11,7 +11,7 @@ permissions:
jobs: jobs:
compute-suffix: compute-suffix:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.repository == 'TheEssem/mastodon' if: github.repository == 'glitch-soc/mastodon'
steps: steps:
- id: version_vars - id: version_vars
env: env:

View file

@ -53,7 +53,7 @@ jobs:
# Create or update the pull request # Create or update the pull request
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@v6.0.5 uses: peter-evans/create-pull-request@v6.0.0
with: with:
commit-message: 'New Crowdin translations' commit-message: 'New Crowdin translations'
title: 'New Crowdin Translations (automated)' title: 'New Crowdin Translations (automated)'

View file

@ -38,5 +38,9 @@ jobs:
- name: Set up Javascript environment - name: Set up Javascript environment
uses: ./.github/actions/setup-javascript uses: ./.github/actions/setup-javascript
- uses: xt0rted/stylelint-problem-matcher@v1
- run: echo "::add-matcher::.github/stylelint-matcher.json"
- name: Stylelint - name: Stylelint
run: yarn lint:css -f github run: yarn lint:css

View file

@ -38,5 +38,5 @@ jobs:
- name: Set up Javascript environment - name: Set up Javascript environment
uses: ./.github/actions/setup-javascript uses: ./.github/actions/setup-javascript
- name: JavaScript testing - name: Jest testing
run: yarn jest --reporters github-actions summary run: yarn jest --reporters github-actions summary

View file

@ -28,9 +28,6 @@ jobs:
env: env:
RAILS_ENV: ${{ matrix.mode }} RAILS_ENV: ${{ matrix.mode }}
BUNDLE_WITH: ${{ matrix.mode }} BUNDLE_WITH: ${{ matrix.mode }}
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY: precompile_placeholder
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT: precompile_placeholder
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY: precompile_placeholder
OTP_SECRET: precompile_placeholder OTP_SECRET: precompile_placeholder
SECRET_KEY_BASE: precompile_placeholder SECRET_KEY_BASE: precompile_placeholder
@ -114,8 +111,8 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
ruby-version: ruby-version:
- '3.0'
- '3.1' - '3.1'
- '3.2'
- '.ruby-version' - '.ruby-version'
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -145,8 +142,6 @@ jobs:
uses: codecov/codecov-action@v4 uses: codecov/codecov-action@v4
with: with:
files: coverage/lcov/mastodon.lcov files: coverage/lcov/mastodon.lcov
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
test-e2e: test-e2e:
name: End to End testing name: End to End testing
@ -186,15 +181,13 @@ jobs:
DISABLE_SIMPLECOV: true DISABLE_SIMPLECOV: true
RAILS_ENV: test RAILS_ENV: test
BUNDLE_WITH: test BUNDLE_WITH: test
LOCAL_DOMAIN: localhost:3000
LOCAL_HTTPS: false
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
ruby-version: ruby-version:
- '3.0'
- '3.1' - '3.1'
- '3.2'
- '.ruby-version' - '.ruby-version'
steps: steps:
@ -217,7 +210,7 @@ jobs:
- name: Load database schema - name: Load database schema
run: './bin/rails db:create db:schema:load db:seed' run: './bin/rails db:create db:schema:load db:seed'
- run: bin/rspec spec/system --tag streaming --tag js - run: bundle exec rake spec:system
- name: Archive logs - name: Archive logs
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
@ -264,8 +257,8 @@ jobs:
ports: ports:
- 6379:6379 - 6379:6379
elasticsearch: search:
image: ${{ contains(matrix.search-image, 'elasticsearch') && matrix.search-image || '' }} image: ${{ matrix.search-image }}
env: env:
discovery.type: single-node discovery.type: single-node
xpack.security.enabled: false xpack.security.enabled: false
@ -277,20 +270,6 @@ jobs:
ports: ports:
- 9200:9200 - 9200:9200
opensearch:
image: ${{ contains(matrix.search-image, 'opensearch') && matrix.search-image || '' }}
env:
discovery.type: single-node
DISABLE_INSTALL_DEMO_CONFIG: true
DISABLE_SECURITY_PLUGIN: true
options: >-
--health-cmd "curl http://localhost:9200/_cluster/health"
--health-interval 10s
--health-timeout 5s
--health-retries 10
ports:
- 9200:9200
env: env:
DB_HOST: localhost DB_HOST: localhost
DB_USER: postgres DB_USER: postgres
@ -306,16 +285,14 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
ruby-version: ruby-version:
- '3.0'
- '3.1' - '3.1'
- '3.2'
- '.ruby-version' - '.ruby-version'
search-image: search-image:
- docker.elastic.co/elasticsearch/elasticsearch:7.17.13 - docker.elastic.co/elasticsearch/elasticsearch:7.17.13
include: include:
- ruby-version: '.ruby-version' - ruby-version: '.ruby-version'
search-image: docker.elastic.co/elasticsearch/elasticsearch:8.10.2 search-image: docker.elastic.co/elasticsearch/elasticsearch:8.10.2
- ruby-version: '.ruby-version'
search-image: opensearchproject/opensearch:2
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4

4
.gitignore vendored
View file

@ -24,6 +24,7 @@
/public/packs-test /public/packs-test
.env .env
.env.production .env.production
.env.development
/node_modules/ /node_modules/
/build/ /build/
@ -68,6 +69,3 @@ yarn-debug.log
# Ignore Docker option files # Ignore Docker option files
docker-compose.override.yml docker-compose.override.yml
# Ignore dotenv .local files
.env*.local

View file

@ -1,5 +1,8 @@
inherits_from: .haml-lint_todo.yml
exclude: exclude:
- 'vendor/**/*' - 'vendor/**/*'
- lib/templates/haml/scaffold/_form.html.haml
require: require:
- ./lib/linter/haml_middle_dot.rb - ./lib/linter/haml_middle_dot.rb
@ -10,6 +13,4 @@ linters:
MiddleDot: MiddleDot:
enabled: true enabled: true
LineLength: LineLength:
max: 300 max: 320
ViewLength:
max: 200 # Override default value of 100 inherited from rubocop

13
.haml-lint_todo.yml Normal file
View file

@ -0,0 +1,13 @@
# This configuration was generated by
# `haml-lint --auto-gen-config`
# on 2024-01-09 11:30:07 -0500 using Haml-Lint version 0.53.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: 1
LineLength:
exclude:
- 'app/views/admin/roles/_form.html.haml'

2
.nvmrc
View file

@ -1 +1 @@
20.13 20.11

View file

@ -96,8 +96,3 @@ app/javascript/flavours/glitch/styles/reset.scss
# Ignore win95 theme # Ignore win95 theme
app/javascript/styles/win95.scss app/javascript/styles/win95.scss
# Ignore mastomodern theme
app/javascript/styles/modern/style.scss
app/javascript/flavours/glitch/styles/modern/style.scss
app/javascript/flavours/glitch/styles/modern/glitch-fixes.scss

View file

@ -9,13 +9,12 @@ inherit_mode:
require: require:
- rubocop-rails - rubocop-rails
- rubocop-rspec - rubocop-rspec
- rubocop-rspec_rails
- rubocop-performance - rubocop-performance
- rubocop-capybara - rubocop-capybara
- ./lib/linter/rubocop_middle_dot - ./lib/linter/rubocop_middle_dot
AllCops: AllCops:
TargetRubyVersion: 3.1 # Set to minimum supported version of CI TargetRubyVersion: 3.0 # Set to minimum supported version of CI
DisplayCopNames: true DisplayCopNames: true
DisplayStyleGuide: true DisplayStyleGuide: true
ExtraDetails: true ExtraDetails: true
@ -40,7 +39,13 @@ Layout/FirstHashElementIndentation:
# Reason: Currently disabled in .rubocop_todo.yml # Reason: Currently disabled in .rubocop_todo.yml
# https://docs.rubocop.org/rubocop/cops_layout.html#layoutlinelength # https://docs.rubocop.org/rubocop/cops_layout.html#layoutlinelength
Layout/LineLength: Layout/LineLength:
Max: 300 # Default of 120 causes a duplicate entry in generated todo file Max: 320 # Default of 120 causes a duplicate entry in generated todo file
# Reason:
# https://docs.rubocop.org/rubocop/cops_lint.html#lintuselessaccessmodifier
Lint/UselessAccessModifier:
ContextCreatingMethods:
- class_methods
## Disable most Metrics/*Length cops ## Disable most Metrics/*Length cops
# Reason: those are often triggered and force significant refactors when this happend # Reason: those are often triggered and force significant refactors when this happend
@ -81,11 +86,6 @@ Metrics/CyclomaticComplexity:
Metrics/ParameterLists: Metrics/ParameterLists:
CountKeywordArgs: false CountKeywordArgs: false
# Reason: Prefer seeing a variable name
# https://docs.rubocop.org/rubocop/cops_naming.html#namingblockforwarding
Naming/BlockForwarding:
EnforcedStyle: explicit
# Reason: Prevailing style is argument file paths # Reason: Prevailing style is argument file paths
# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsfilepath # https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsfilepath
Rails/FilePath: Rails/FilePath:
@ -148,6 +148,11 @@ RSpec/NamedSubject:
RSpec/NotToNot: RSpec/NotToNot:
EnforcedStyle: to_not EnforcedStyle: to_not
# Reason: Prevailing style uses numeric status codes, matches Rails/HttpStatus
# https://docs.rubocop.org/rubocop-rspec/cops_rspec_rails.html#rspecrailshttpstatus
RSpec/Rails/HttpStatus:
EnforcedStyle: numeric
# Reason: Match overrides from Rspec/FilePath rule above # Reason: Match overrides from Rspec/FilePath rule above
# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecspecfilepathformat # https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecspecfilepathformat
RSpec/SpecFilePathFormat: RSpec/SpecFilePathFormat:
@ -158,11 +163,6 @@ RSpec/SpecFilePathFormat:
OEmbedController: oembed_controller OEmbedController: oembed_controller
OStatus: ostatus OStatus: ostatus
# Reason: Prevailing style uses numeric status codes, matches Rails/HttpStatus
# https://docs.rubocop.org/rubocop-rspec/cops_rspec_rails.html#rspecrailshttpstatus
RSpecRails/HttpStatus:
EnforcedStyle: numeric
# Reason: # Reason:
# https://docs.rubocop.org/rubocop/cops_style.html#styleclassandmodulechildren # https://docs.rubocop.org/rubocop/cops_style.html#styleclassandmodulechildren
Style/ClassAndModuleChildren: Style/ClassAndModuleChildren:
@ -182,16 +182,10 @@ Style/FormatStringToken:
AllowedMethods: AllowedMethods:
- redirect_with_vary - redirect_with_vary
# Reason: Prevailing style choice
# https://docs.rubocop.org/rubocop/cops_style.html#stylehashaslastarrayitem
Style/HashAsLastArrayItem:
Enabled: false
# Reason: Enforce modern Ruby style # Reason: Enforce modern Ruby style
# https://docs.rubocop.org/rubocop/cops_style.html#stylehashsyntax # https://docs.rubocop.org/rubocop/cops_style.html#stylehashsyntax
Style/HashSyntax: Style/HashSyntax:
EnforcedStyle: ruby19_no_mixed_keys EnforcedStyle: ruby19_no_mixed_keys
EnforcedShorthandSyntax: either
# Reason: # Reason:
# https://docs.rubocop.org/rubocop/cops_style.html#stylenumericliterals # https://docs.rubocop.org/rubocop/cops_style.html#stylenumericliterals
@ -211,11 +205,6 @@ Style/PercentLiteralDelimiters:
Style/RedundantBegin: Style/RedundantBegin:
Enabled: false Enabled: false
# Reason: Prevailing style choice
# https://docs.rubocop.org/rubocop/cops_style.html#styleredundantfetchblock
Style/RedundantFetchBlock:
Enabled: false
# Reason: Overridden to reduce implicit StandardError rescues # Reason: Overridden to reduce implicit StandardError rescues
# https://docs.rubocop.org/rubocop/cops_style.html#stylerescuestandarderror # https://docs.rubocop.org/rubocop/cops_style.html#stylerescuestandarderror
Style/RescueStandardError: Style/RescueStandardError:

View file

@ -1,11 +1,18 @@
# This configuration was generated by # This configuration was generated by
# `rubocop --auto-gen-config --auto-gen-only-exclude --no-exclude-limit --no-offense-counts --no-auto-gen-timestamp` # `rubocop --auto-gen-config --auto-gen-only-exclude --no-exclude-limit --no-offense-counts --no-auto-gen-timestamp`
# using RuboCop version 1.63.5. # using RuboCop version 1.60.2.
# The point is for the user to remove these configuration records # The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base. # one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new # Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again. # versions of RuboCop, may require this file to be generated again.
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: TreatCommentsAsGroupSeparators, ConsiderPunctuation, Include.
# Include: **/*.gemfile, **/Gemfile, **/gems.rb
Bundler/OrderedGems:
Exclude:
- 'Gemfile'
Lint/NonLocalExitFromIterator: Lint/NonLocalExitFromIterator:
Exclude: Exclude:
- 'app/helpers/jsonld_helper.rb' - 'app/helpers/jsonld_helper.rb'
@ -29,7 +36,7 @@ Metrics/PerceivedComplexity:
# Configuration parameters: CountAsOne. # Configuration parameters: CountAsOne.
RSpec/ExampleLength: RSpec/ExampleLength:
Max: 18 Max: 20 # Override default of 5
RSpec/MultipleExpectations: RSpec/MultipleExpectations:
Max: 7 Max: 7
@ -42,10 +49,27 @@ RSpec/MultipleMemoizedHelpers:
RSpec/NestedGroups: RSpec/NestedGroups:
Max: 6 Max: 6
# Configuration parameters: Include.
# Include: app/models/**/*.rb
Rails/HasAndBelongsToMany:
Exclude:
- 'app/models/concerns/account/associations.rb'
- 'app/models/status.rb'
- 'app/models/tag.rb'
Rails/OutputSafety: Rails/OutputSafety:
Exclude: Exclude:
- 'config/initializers/simple_form.rb' - 'config/initializers/simple_form.rb'
# Configuration parameters: Include.
# Include: app/models/**/*.rb
Rails/UniqueValidationWithoutIndex:
Exclude:
- 'app/models/account_alias.rb'
- 'app/models/custom_filter_status.rb'
- 'app/models/identity.rb'
- 'app/models/webauthn_credential.rb'
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: AllowedMethods, AllowedPatterns. # Configuration parameters: AllowedMethods, AllowedPatterns.
# AllowedMethods: ==, equal?, eql? # AllowedMethods: ==, equal?, eql?
@ -54,12 +78,17 @@ Style/ClassEqualityComparison:
- 'app/helpers/jsonld_helper.rb' - 'app/helpers/jsonld_helper.rb'
- 'app/serializers/activitypub/outbox_serializer.rb' - 'app/serializers/activitypub/outbox_serializer.rb'
Style/ClassVars:
Exclude:
- 'config/initializers/devise.rb'
# This cop supports safe autocorrection (--autocorrect). # This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AllowedVars. # Configuration parameters: AllowedVars.
Style/FetchEnvVar: Style/FetchEnvVar:
Exclude: Exclude:
- 'app/lib/redis_configuration.rb' - 'app/lib/redis_configuration.rb'
- 'app/lib/translation_service.rb' - 'app/lib/translation_service.rb'
- 'config/environments/development.rb'
- 'config/environments/production.rb' - 'config/environments/production.rb'
- 'config/initializers/2_limited_federation_mode.rb' - 'config/initializers/2_limited_federation_mode.rb'
- 'config/initializers/3_omniauth.rb' - 'config/initializers/3_omniauth.rb'
@ -69,8 +98,9 @@ Style/FetchEnvVar:
- 'config/initializers/paperclip.rb' - 'config/initializers/paperclip.rb'
- 'config/initializers/vapid.rb' - 'config/initializers/vapid.rb'
- 'lib/mastodon/redis_config.rb' - 'lib/mastodon/redis_config.rb'
- 'lib/premailer_webpack_strategy.rb'
- 'lib/tasks/repo.rake' - 'lib/tasks/repo.rake'
- 'spec/system/profile_spec.rb' - 'spec/features/profile_spec.rb'
# This cop supports safe autocorrection (--autocorrect). # This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle, MaxUnannotatedPlaceholdersAllowed, AllowedMethods, AllowedPatterns. # Configuration parameters: EnforcedStyle, MaxUnannotatedPlaceholdersAllowed, AllowedMethods, AllowedPatterns.
@ -114,14 +144,35 @@ Style/GuardClause:
- 'lib/mastodon/cli/accounts.rb' - 'lib/mastodon/cli/accounts.rb'
- 'lib/mastodon/cli/maintenance.rb' - 'lib/mastodon/cli/maintenance.rb'
- 'lib/mastodon/cli/media.rb' - 'lib/mastodon/cli/media.rb'
- 'lib/paperclip/attachment_extensions.rb'
- 'lib/tasks/repo.rake' - 'lib/tasks/repo.rake'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle.
# SupportedStyles: braces, no_braces
Style/HashAsLastArrayItem:
Exclude:
- 'app/controllers/admin/statuses_controller.rb'
- 'app/controllers/api/v1/statuses_controller.rb'
- 'app/models/concerns/account/counters.rb'
- 'app/models/concerns/status/threading_concern.rb'
- 'app/models/status.rb'
- 'app/services/batched_remove_status_service.rb'
- 'app/services/notify_service.rb'
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
Style/HashTransformValues: Style/HashTransformValues:
Exclude: Exclude:
- 'app/serializers/rest/web_push_subscription_serializer.rb' - 'app/serializers/rest/web_push_subscription_serializer.rb'
- 'app/services/import_service.rb' - 'app/services/import_service.rb'
# This cop supports safe autocorrection (--autocorrect).
Style/IfUnlessModifier:
Exclude:
- 'config/environments/production.rb'
- 'config/initializers/devise.rb'
- 'config/initializers/ffmpeg.rb'
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
Style/MapToHash: Style/MapToHash:
Exclude: Exclude:
@ -156,6 +207,13 @@ Style/OptionalBooleanParameter:
- 'app/workers/unfollow_follow_worker.rb' - 'app/workers/unfollow_follow_worker.rb'
- 'lib/mastodon/redis_config.rb' - 'lib/mastodon/redis_config.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: PreferredDelimiters.
Style/PercentLiteralDelimiters:
Exclude:
- 'config/deploy.rb'
- 'config/initializers/doorkeeper.rb'
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: short, verbose # SupportedStyles: short, verbose
@ -169,6 +227,16 @@ Style/RedundantConstantBase:
- 'config/environments/production.rb' - 'config/environments/production.rb'
- 'config/initializers/sidekiq.rb' - 'config/initializers/sidekiq.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: SafeForConstants.
Style/RedundantFetchBlock:
Exclude:
- 'config/initializers/1_hosts.rb'
- 'config/initializers/chewy.rb'
- 'config/initializers/devise.rb'
- 'config/initializers/paperclip.rb'
- 'config/puma.rb'
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods, MaxChainLength. # Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods, MaxChainLength.
# AllowedMethods: present?, blank?, presence, try, try! # AllowedMethods: present?, blank?, presence, try, try!
@ -176,12 +244,52 @@ Style/SafeNavigation:
Exclude: Exclude:
- 'app/models/concerns/account/finder_concern.rb' - 'app/models/concerns/account/finder_concern.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle.
# SupportedStyles: only_raise, only_fail, semantic
Style/SignalException:
Exclude:
- 'lib/devise/strategies/two_factor_ldap_authenticatable.rb'
- 'lib/devise/strategies/two_factor_pam_authenticatable.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
Style/SingleArgumentDig:
Exclude:
- 'lib/webpacker/manifest_extensions.rb'
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: Mode. # Configuration parameters: Mode.
Style/StringConcatenation: Style/StringConcatenation:
Exclude: Exclude:
- 'config/initializers/paperclip.rb' - 'config/initializers/paperclip.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline.
# SupportedStyles: single_quotes, double_quotes
Style/StringLiterals:
Exclude:
- 'config/environments/production.rb'
- 'config/initializers/backtrace_silencers.rb'
- 'config/initializers/http_client_proxy.rb'
- 'config/initializers/rack_attack.rb'
- 'config/initializers/webauthn.rb'
- 'config/routes.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyleForMultiline.
# SupportedStylesForMultiline: comma, consistent_comma, no_comma
Style/TrailingCommaInArguments:
Exclude:
- 'config/initializers/paperclip.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyleForMultiline.
# SupportedStylesForMultiline: comma, consistent_comma, no_comma
Style/TrailingCommaInHashLiteral:
Exclude:
- 'config/environments/production.rb'
- 'config/environments/test.rb'
# This cop supports safe autocorrection (--autocorrect). # This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: WordRegex. # Configuration parameters: WordRegex.
# SupportedStyles: percent, brackets # SupportedStyles: percent, brackets

View file

@ -1 +1 @@
3.3.1 3.2.3

22
.simplecov Normal file
View file

@ -0,0 +1,22 @@
# frozen_string_literal: true
if ENV['CI']
require 'simplecov-lcov'
SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = true
SimpleCov.formatter = SimpleCov::Formatter::LcovFormatter
else
SimpleCov.formatter = SimpleCov::Formatter::HTMLFormatter
end
SimpleCov.start 'rails' do
enable_coverage :branch
add_filter 'lib/linter'
add_group 'Libraries', 'lib'
add_group 'Policies', 'app/policies'
add_group 'Presenters', 'app/presenters'
add_group 'Serializers', 'app/serializers'
add_group 'Services', 'app/services'
add_group 'Validators', 'app/validators'
end

View file

@ -1,23 +0,0 @@
---
include:
- '**/*.rb'
exclude:
- spec/**/*
- test/**/*
- vendor/**/*
- '.bundle/**/*'
require: []
domains: []
reporters:
- rubocop
- require_not_found
formatter:
rubocop:
cops: safe
except: []
only: []
extra_args: []
require_paths: []
plugins:
- solargraph-rails
max_files: 5000

View file

@ -1,4 +1,4 @@
# syntax=docker/dockerfile:1.7 # syntax=docker/dockerfile:1.4
# Please see https://docs.docker.com/engine/reference/builder for information about # Please see https://docs.docker.com/engine/reference/builder for information about
# the extended buildx capabilities used in this file. # the extended buildx capabilities used in this file.
@ -7,20 +7,20 @@
ARG TARGETPLATFORM=${TARGETPLATFORM} ARG TARGETPLATFORM=${TARGETPLATFORM}
ARG BUILDPLATFORM=${BUILDPLATFORM} ARG BUILDPLATFORM=${BUILDPLATFORM}
# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.3.1"] # Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.2.3"]
ARG RUBY_VERSION="3.3.1" ARG RUBY_VERSION="3.2.3"
# # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"] # # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"]
ARG NODE_MAJOR_VERSION="20" ARG NODE_MAJOR_VERSION="20"
# Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"] # Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"]
ARG DEBIAN_VERSION="bookworm" ARG DEBIAN_VERSION="bookworm"
# Node image to use for base image based on combined variables (ex: 20-bookworm-slim) # Node image to use for base image based on combined variables (ex: 20-bookworm-slim)
FROM docker.io/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim as node FROM docker.io/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim as node
# Ruby image to use for base image based on combined variables (ex: 3.3.1-slim-bookworm) # Ruby image to use for base image based on combined variables (ex: 3.2.3-slim-bookworm)
FROM docker.io/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} as ruby FROM docker.io/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} as ruby
# Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA # Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA
# Example: v4.2.0-nightly.2023.11.09+something # Example: v4.2.0-nightly.2023.11.09+something
# Overwrite existence of 'alpha.0' in version.rb [--build-arg MASTODON_VERSION_PRERELEASE="nightly.2023.11.09"] # Overwrite existance of 'alpha.0' in version.rb [--build-arg MASTODON_VERSION_PRERELEASE="nightly.2023.11.09"]
ARG MASTODON_VERSION_PRERELEASE="" ARG MASTODON_VERSION_PRERELEASE=""
# Append build metadata or fork information to version.rb [--build-arg MASTODON_VERSION_METADATA="something"] # Append build metadata or fork information to version.rb [--build-arg MASTODON_VERSION_METADATA="something"]
ARG MASTODON_VERSION_METADATA="" ARG MASTODON_VERSION_METADATA=""
@ -29,7 +29,7 @@ ARG MASTODON_VERSION_METADATA=""
# See: https://docs.joinmastodon.org/admin/config/#rails_serve_static_files # See: https://docs.joinmastodon.org/admin/config/#rails_serve_static_files
ARG RAILS_SERVE_STATIC_FILES="true" ARG RAILS_SERVE_STATIC_FILES="true"
# Allow to use YJIT compiler # Allow to use YJIT compiler
# See: https://github.com/ruby/ruby/blob/v3_2_4/doc/yjit/yjit.md # See: https://github.com/ruby/ruby/blob/master/doc/yjit/yjit.md
ARG RUBY_YJIT_ENABLE="1" ARG RUBY_YJIT_ENABLE="1"
# Timezone used by the Docker container and runtime, change with [--build-arg TZ=Europe/Berlin] # Timezone used by the Docker container and runtime, change with [--build-arg TZ=Europe/Berlin]
ARG TZ="Etc/UTC" ARG TZ="Etc/UTC"
@ -205,12 +205,7 @@ ARG TARGETPLATFORM
RUN \ RUN \
# Use Ruby on Rails to create Mastodon assets # Use Ruby on Rails to create Mastodon assets
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=precompile_placeholder \ OTP_SECRET=precompile_placeholder SECRET_KEY_BASE=precompile_placeholder bundle exec rails assets:precompile; \
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=precompile_placeholder \
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=precompile_placeholder \
OTP_SECRET=precompile_placeholder \
SECRET_KEY_BASE=precompile_placeholder \
bundle exec rails assets:precompile; \
# Cleanup temporary files # Cleanup temporary files
rm -fr /opt/mastodon/tmp; rm -fr /opt/mastodon/tmp;

70
Gemfile
View file

@ -1,37 +1,37 @@
# frozen_string_literal: true # frozen_string_literal: true
source 'https://rubygems.org' source 'https://rubygems.org'
ruby '>= 3.1.0' ruby '>= 3.0.0'
gem 'propshaft'
gem 'puma', '~> 6.3' gem 'puma', '~> 6.3'
gem 'rack', '~> 2.2.7'
gem 'rails', '~> 7.1.1' gem 'rails', '~> 7.1.1'
gem 'propshaft'
gem 'thor', '~> 1.2' gem 'thor', '~> 1.2'
gem 'rack', '~> 2.2.7'
# For why irb is in the Gemfile, see: https://ruby.social/@st0012/111444685161478182 # For why irb is in the Gemfile, see: https://ruby.social/@st0012/111444685161478182
gem 'irb', '~> 1.8' gem 'irb', '~> 1.8'
gem 'dotenv'
gem 'haml-rails', '~>2.0' gem 'haml-rails', '~>2.0'
gem 'pg', '~> 1.5' gem 'pg', '~> 1.5'
gem 'pghero' gem 'pghero'
gem 'dotenv-rails', '~> 2.8'
gem 'aws-sdk-s3', '~> 1.123', require: false gem 'aws-sdk-s3', '~> 1.123', require: false
gem 'blurhash', '~> 0.1'
gem 'fog-core', '<= 2.4.0' gem 'fog-core', '<= 2.4.0'
gem 'fog-openstack', '~> 1.0', require: false gem 'fog-openstack', '~> 1.0', require: false
gem 'kt-paperclip', '~> 7.2' gem 'kt-paperclip', '~> 7.2'
gem 'md-paperclip-azure', '~> 2.2', require: false gem 'md-paperclip-azure', '~> 2.2', require: false
gem 'blurhash', '~> 0.1'
gem 'active_model_serializers', '~> 0.10' gem 'active_model_serializers', '~> 0.10'
gem 'addressable', '~> 2.8' gem 'addressable', '~> 2.8'
gem 'bootsnap', '~> 1.18.0', require: false gem 'bootsnap', '~> 1.18.0', require: false
gem 'browser' gem 'browser'
gem 'charlock_holmes', github: 'TheEssem/charlock_holmes', ref: '226932af4b03eb60d2e31d58b6c3efd72a3ace68' gem 'charlock_holmes', '~> 0.7.7'
gem 'chewy', '~> 7.3' gem 'chewy', '~> 7.3'
gem 'devise', '~> 4.9' gem 'devise', '~> 4.9'
gem 'devise-two-factor' gem 'devise-two-factor', '~> 4.1'
group :pam_authentication, optional: true do group :pam_authentication, optional: true do
gem 'devise_pam_authenticatable2', '~> 9.2' gem 'devise_pam_authenticatable2', '~> 9.2'
@ -39,11 +39,11 @@ end
gem 'net-ldap', '~> 0.18' gem 'net-ldap', '~> 0.18'
gem 'omniauth', '~> 2.0'
gem 'omniauth-cas', '~> 3.0.0.beta.1' gem 'omniauth-cas', '~> 3.0.0.beta.1'
gem 'omniauth_openid_connect', '~> 0.6.1'
gem 'omniauth-rails_csrf_protection', '~> 1.0'
gem 'omniauth-saml', '~> 2.0' gem 'omniauth-saml', '~> 2.0'
gem 'omniauth_openid_connect', '~> 0.6.1'
gem 'omniauth', '~> 2.0'
gem 'omniauth-rails_csrf_protection', '~> 1.0'
gem 'color_diff', '~> 0.1' gem 'color_diff', '~> 0.1'
gem 'csv', '~> 3.2' gem 'csv', '~> 3.2'
@ -53,49 +53,48 @@ gem 'ed25519', '~> 1.3'
gem 'fast_blank', '~> 1.0' gem 'fast_blank', '~> 1.0'
gem 'fastimage' gem 'fastimage'
gem 'hiredis', '~> 0.6' gem 'hiredis', '~> 0.6'
gem 'redis-namespace', '~> 1.10'
gem 'htmlentities', '~> 4.3' gem 'htmlentities', '~> 4.3'
gem 'http', '~> 5.2.0' gem 'http', '~> 5.1'
gem 'http_accept_language', '~> 2.1' gem 'http_accept_language', '~> 2.1'
gem 'httplog', '~> 1.6.2' gem 'httplog', '~> 1.6.2'
gem 'i18n'
gem 'idn-ruby', require: 'idn' gem 'idn-ruby', require: 'idn'
gem 'inline_svg'
gem 'kaminari', '~> 1.2' gem 'kaminari', '~> 1.2'
gem 'link_header', '~> 0.0' gem 'link_header', '~> 0.0'
gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
gem 'mime-types', '~> 3.5.0', require: 'mime/types/columnar' gem 'mime-types', '~> 3.5.0', require: 'mime/types/columnar'
gem 'nokogiri', '~> 1.15' gem 'nokogiri', '~> 1.15'
gem 'nsa' gem 'nsa'
gem 'oj', '~> 3.14' gem 'oj', '~> 3.14'
gem 'ox', '~> 2.14' gem 'ox', '~> 2.14'
gem 'parslet' gem 'parslet'
gem 'premailer-rails' gem 'posix-spawn'
gem 'public_suffix', '~> 5.0' gem 'public_suffix', '~> 5.0'
gem 'pundit', '~> 2.3' gem 'pundit', '~> 2.3'
gem 'premailer-rails'
gem 'rack-attack', '~> 6.6' gem 'rack-attack', '~> 6.6'
gem 'rack-cors', '~> 2.0', require: 'rack/cors' gem 'rack-cors', '~> 2.0', require: 'rack/cors'
gem 'rails-i18n', '~> 7.0' gem 'rails-i18n', '~> 7.0'
gem 'redcarpet', '~> 3.6' gem 'redcarpet', '~> 3.6'
gem 'redis', '~> 4.5', require: ['redis', 'redis/connection/hiredis'] gem 'redis', '~> 4.5', require: ['redis', 'redis/connection/hiredis']
gem 'redis-namespace', '~> 1.10' gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
gem 'rqrcode', '~> 2.2' gem 'rqrcode', '~> 2.2'
gem 'ruby-progressbar', '~> 1.13' gem 'ruby-progressbar', '~> 1.13'
gem 'sanitize', '~> 6.0' gem 'sanitize', '~> 6.0'
gem 'scenic', '~> 1.7' gem 'scenic', '~> 1.7'
gem 'sidekiq', '~> 6.5' gem 'sidekiq', '~> 6.5'
gem 'sidekiq-bulk', '~> 0.2.0'
gem 'sidekiq-scheduler', '~> 5.0' gem 'sidekiq-scheduler', '~> 5.0'
gem 'sidekiq-unique-jobs', '~> 7.1' gem 'sidekiq-unique-jobs', '~> 7.1'
gem 'simple_form', '~> 5.2' gem 'sidekiq-bulk', '~> 0.2.0'
gem 'simple-navigation', '~> 4.4' gem 'simple-navigation', '~> 4.4'
gem 'stoplight', '~> 4.1' gem 'simple_form', '~> 5.2'
gem 'strong_migrations', '1.8.0' gem 'stoplight', '~> 3.0.1'
gem 'strong_migrations', '1.7.0'
gem 'tty-prompt', '~> 0.23', require: false gem 'tty-prompt', '~> 0.23', require: false
gem 'twitter-text', '~> 3.1.0' gem 'twitter-text', '~> 3.1.0'
gem 'tzinfo-data', '~> 1.2023' gem 'tzinfo-data', '~> 1.2023'
gem 'webauthn', '~> 3.0'
gem 'webpacker', '~> 5.4' gem 'webpacker', '~> 5.4'
gem 'webpush', github: 'ClearlyClaire/webpush', ref: 'f14a4d52e201128b1b00245d11b6de80d6cfdcd9' gem 'webpush', github: 'ClearlyClaire/webpush', ref: 'f14a4d52e201128b1b00245d11b6de80d6cfdcd9'
gem 'webauthn', '~> 3.0'
gem 'json-ld' gem 'json-ld'
gem 'json-ld-preloaded', '~> 3.2' gem 'json-ld-preloaded', '~> 3.2'
@ -103,24 +102,6 @@ gem 'rdf-normalize', '~> 0.5'
gem 'private_address_check', '~> 0.5' gem 'private_address_check', '~> 0.5'
group :opentelemetry do
gem 'opentelemetry-exporter-otlp', '~> 0.26.3', require: false
gem 'opentelemetry-instrumentation-active_job', '~> 0.7.1', require: false
gem 'opentelemetry-instrumentation-active_model_serializers', '~> 0.20.1', require: false
gem 'opentelemetry-instrumentation-concurrent_ruby', '~> 0.21.2', require: false
gem 'opentelemetry-instrumentation-excon', '~> 0.22.0', require: false
gem 'opentelemetry-instrumentation-faraday', '~> 0.24.1', require: false
gem 'opentelemetry-instrumentation-http', '~> 0.23.2', require: false
gem 'opentelemetry-instrumentation-http_client', '~> 0.22.3', require: false
gem 'opentelemetry-instrumentation-net_http', '~> 0.22.4', require: false
gem 'opentelemetry-instrumentation-pg', '~> 0.27.1', require: false
gem 'opentelemetry-instrumentation-rack', '~> 0.24.1', require: false
gem 'opentelemetry-instrumentation-rails', '~> 0.30.0', require: false
gem 'opentelemetry-instrumentation-redis', '~> 0.25.3', require: false
gem 'opentelemetry-instrumentation-sidekiq', '~> 0.25.2', require: false
gem 'opentelemetry-sdk', '~> 1.4', require: false
end
group :test do group :test do
# Adds RSpec Error/Warning annotations to GitHub PRs on the Files tab # Adds RSpec Error/Warning annotations to GitHub PRs on the Files tab
gem 'rspec-github', '~> 2.4', require: false gem 'rspec-github', '~> 2.4', require: false
@ -131,8 +112,8 @@ group :test do
# RSpec helpers for email specs # RSpec helpers for email specs
gem 'email_spec' gem 'email_spec'
# Extra RSpec extension methods and helpers for sidekiq # Extra RSpec extenion methods and helpers for sidekiq
gem 'rspec-sidekiq', '~> 5.0' gem 'rspec-sidekiq', '~> 4.0'
# Browser integration testing # Browser integration testing
gem 'capybara', '~> 3.39' gem 'capybara', '~> 3.39'
@ -178,7 +159,7 @@ group :development do
# Preview mail in the browser # Preview mail in the browser
gem 'letter_opener', '~> 1.8' gem 'letter_opener', '~> 1.8'
gem 'letter_opener_web', '~> 3.0' gem 'letter_opener_web', '~> 2.0'
# Security analysis CLI tools # Security analysis CLI tools
gem 'brakeman', '~> 6.0', require: false gem 'brakeman', '~> 6.0', require: false
@ -215,14 +196,13 @@ group :production do
gem 'lograge', '~> 0.12' gem 'lograge', '~> 0.12'
end end
gem 'cocoon', '~> 1.2'
gem 'concurrent-ruby', require: false gem 'concurrent-ruby', require: false
gem 'connection_pool', require: false gem 'connection_pool', require: false
gem 'xorcist', '~> 1.1' gem 'xorcist', '~> 1.1'
gem 'cocoon', '~> 1.2'
gem 'net-http', '~> 0.4.0' gem 'net-http', '~> 0.4.0'
gem 'rubyzip', '~> 2.3' gem 'rubyzip', '~> 2.3'
gem 'hcaptcha', '~> 7.1' gem 'hcaptcha', '~> 7.1'
gem 'mail', '~> 2.8'

View file

@ -7,45 +7,38 @@ GIT
hkdf (~> 0.2) hkdf (~> 0.2)
jwt (~> 2.0) jwt (~> 2.0)
GIT
remote: https://github.com/TheEssem/charlock_holmes.git
revision: 226932af4b03eb60d2e31d58b6c3efd72a3ace68
ref: 226932af4b03eb60d2e31d58b6c3efd72a3ace68
specs:
charlock_holmes (0.7.7)
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actioncable (7.1.3.3) actioncable (7.1.3.2)
actionpack (= 7.1.3.3) actionpack (= 7.1.3.2)
activesupport (= 7.1.3.3) activesupport (= 7.1.3.2)
nio4r (~> 2.0) nio4r (~> 2.0)
websocket-driver (>= 0.6.1) websocket-driver (>= 0.6.1)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
actionmailbox (7.1.3.3) actionmailbox (7.1.3.2)
actionpack (= 7.1.3.3) actionpack (= 7.1.3.2)
activejob (= 7.1.3.3) activejob (= 7.1.3.2)
activerecord (= 7.1.3.3) activerecord (= 7.1.3.2)
activestorage (= 7.1.3.3) activestorage (= 7.1.3.2)
activesupport (= 7.1.3.3) activesupport (= 7.1.3.2)
mail (>= 2.7.1) mail (>= 2.7.1)
net-imap net-imap
net-pop net-pop
net-smtp net-smtp
actionmailer (7.1.3.3) actionmailer (7.1.3.2)
actionpack (= 7.1.3.3) actionpack (= 7.1.3.2)
actionview (= 7.1.3.3) actionview (= 7.1.3.2)
activejob (= 7.1.3.3) activejob (= 7.1.3.2)
activesupport (= 7.1.3.3) activesupport (= 7.1.3.2)
mail (~> 2.5, >= 2.5.4) mail (~> 2.5, >= 2.5.4)
net-imap net-imap
net-pop net-pop
net-smtp net-smtp
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
actionpack (7.1.3.3) actionpack (7.1.3.2)
actionview (= 7.1.3.3) actionview (= 7.1.3.2)
activesupport (= 7.1.3.3) activesupport (= 7.1.3.2)
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
racc racc
rack (>= 2.2.4) rack (>= 2.2.4)
@ -53,15 +46,15 @@ GEM
rack-test (>= 0.6.3) rack-test (>= 0.6.3)
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6) rails-html-sanitizer (~> 1.6)
actiontext (7.1.3.3) actiontext (7.1.3.2)
actionpack (= 7.1.3.3) actionpack (= 7.1.3.2)
activerecord (= 7.1.3.3) activerecord (= 7.1.3.2)
activestorage (= 7.1.3.3) activestorage (= 7.1.3.2)
activesupport (= 7.1.3.3) activesupport (= 7.1.3.2)
globalid (>= 0.6.0) globalid (>= 0.6.0)
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
actionview (7.1.3.3) actionview (7.1.3.2)
activesupport (= 7.1.3.3) activesupport (= 7.1.3.2)
builder (~> 3.1) builder (~> 3.1)
erubi (~> 1.11) erubi (~> 1.11)
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
@ -71,22 +64,22 @@ GEM
activemodel (>= 4.1) activemodel (>= 4.1)
case_transform (>= 0.2) case_transform (>= 0.2)
jsonapi-renderer (>= 0.1.1.beta1, < 0.3) jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
activejob (7.1.3.3) activejob (7.1.3.2)
activesupport (= 7.1.3.3) activesupport (= 7.1.3.2)
globalid (>= 0.3.6) globalid (>= 0.3.6)
activemodel (7.1.3.3) activemodel (7.1.3.2)
activesupport (= 7.1.3.3) activesupport (= 7.1.3.2)
activerecord (7.1.3.3) activerecord (7.1.3.2)
activemodel (= 7.1.3.3) activemodel (= 7.1.3.2)
activesupport (= 7.1.3.3) activesupport (= 7.1.3.2)
timeout (>= 0.4.0) timeout (>= 0.4.0)
activestorage (7.1.3.3) activestorage (7.1.3.2)
actionpack (= 7.1.3.3) actionpack (= 7.1.3.2)
activejob (= 7.1.3.3) activejob (= 7.1.3.2)
activerecord (= 7.1.3.3) activerecord (= 7.1.3.2)
activesupport (= 7.1.3.3) activesupport (= 7.1.3.2)
marcel (~> 1.0) marcel (~> 1.0)
activesupport (7.1.3.3) activesupport (7.1.3.2)
base64 base64
bigdecimal bigdecimal
concurrent-ruby (~> 1.0, >= 1.0.2) concurrent-ruby (~> 1.0, >= 1.0.2)
@ -104,20 +97,22 @@ GEM
activerecord (>= 3.2, < 8.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_required (1.0.2) attr_encrypted (4.0.0)
encryptor (~> 3.0.0)
attr_required (1.0.1)
awrence (1.2.1) awrence (1.2.1)
aws-eventstream (1.3.0) aws-eventstream (1.3.0)
aws-partitions (1.929.0) aws-partitions (1.873.0)
aws-sdk-core (3.196.1) aws-sdk-core (3.190.1)
aws-eventstream (~> 1, >= 1.3.0) aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0) aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.8) aws-sigv4 (~> 1.8)
jmespath (~> 1, >= 1.6.1) jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.81.0) aws-sdk-kms (1.75.0)
aws-sdk-core (~> 3, >= 3.193.0) aws-sdk-core (~> 3, >= 3.188.0)
aws-sigv4 (~> 1.1) aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.151.0) aws-sdk-s3 (1.142.0)
aws-sdk-core (~> 3, >= 3.194.0) aws-sdk-core (~> 3, >= 3.189.0)
aws-sdk-kms (~> 1) aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.8) aws-sigv4 (~> 1.8)
aws-sigv4 (1.8.0) aws-sigv4 (1.8.0)
@ -137,10 +132,17 @@ GEM
erubi (>= 1.0.0) erubi (>= 1.0.0)
rack (>= 0.9.0) rack (>= 0.9.0)
rouge (>= 1.0.0) rouge (>= 1.0.0)
bigdecimal (3.1.8) better_html (2.0.2)
bindata (2.5.0) actionview (>= 6.0)
binding_of_caller (1.0.1) activesupport (>= 6.0)
debug_inspector (>= 1.2.0) ast (~> 2.0)
erubi (~> 1.4)
parser (>= 2.4)
smart_properties
bigdecimal (3.1.6)
bindata (2.4.15)
binding_of_caller (1.0.0)
debug_inspector (>= 0.0.1)
blurhash (0.1.7) blurhash (0.1.7)
bootsnap (1.18.3) bootsnap (1.18.3)
msgpack (~> 1.2) msgpack (~> 1.2)
@ -165,10 +167,11 @@ GEM
xpath (~> 3.2) xpath (~> 3.2)
case_transform (0.2) case_transform (0.2)
activesupport activesupport
cbor (0.5.9.8) cbor (0.5.9.6)
chewy (7.6.0) charlock_holmes (0.7.7)
chewy (7.5.1)
activesupport (>= 5.2) activesupport (>= 5.2)
elasticsearch (>= 7.14.0, < 8) elasticsearch (>= 7.12.0, < 7.14.0)
elasticsearch-dsl elasticsearch-dsl
chunky_png (1.4.0) chunky_png (1.4.0)
climate_control (1.2.0) climate_control (1.2.0)
@ -179,65 +182,72 @@ GEM
cose (1.3.0) cose (1.3.0)
cbor (~> 0.5.9) cbor (~> 0.5.9)
openssl-signature_algorithm (~> 1.0) openssl-signature_algorithm (~> 1.0)
crack (1.0.0) crack (0.4.6)
bigdecimal bigdecimal
rexml rexml
crass (1.0.6) crass (1.0.6)
css_parser (1.17.1) css_parser (1.14.0)
addressable addressable
csv (3.3.0) csv (3.2.8)
database_cleaner-active_record (2.1.0) database_cleaner-active_record (2.1.0)
activerecord (>= 5.a) activerecord (>= 5.a)
database_cleaner-core (~> 2.0.0) database_cleaner-core (~> 2.0.0)
database_cleaner-core (2.0.1) database_cleaner-core (2.0.1)
date (3.3.4) date (3.3.4)
debug (1.9.2) debug (1.9.1)
irb (~> 1.10) irb (~> 1.10)
reline (>= 0.3.8) reline (>= 0.3.8)
debug_inspector (1.2.0) debug_inspector (1.1.0)
devise (4.9.4) devise (4.9.3)
bcrypt (~> 3.0) bcrypt (~> 3.0)
orm_adapter (~> 0.1) orm_adapter (~> 0.1)
railties (>= 4.1.0) railties (>= 4.1.0)
responders responders
warden (~> 1.2.3) warden (~> 1.2.3)
devise-two-factor (5.0.0) devise-two-factor (4.1.1)
activesupport (~> 7.0) activesupport (~> 7.0)
attr_encrypted (>= 1.3, < 5, != 2)
devise (~> 4.0) devise (~> 4.0)
railties (~> 7.0) railties (~> 7.0)
rotp (~> 6.0) rotp (~> 6.0)
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.5.1) diff-lcs (1.5.0)
discard (1.3.0) discard (1.3.0)
activerecord (>= 4.2, < 8) activerecord (>= 4.2, < 8)
docile (1.4.0) docile (1.4.0)
domain_name (0.6.20240107) domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
doorkeeper (5.6.9) doorkeeper (5.6.9)
railties (>= 5) railties (>= 5)
dotenv (3.1.2) dotenv (2.8.1)
drb (2.2.1) dotenv-rails (2.8.1)
dotenv (= 2.8.1)
railties (>= 3.2)
drb (2.2.0)
ruby2_keywords
ed25519 (1.3.0) ed25519 (1.3.0)
elasticsearch (7.17.10) elasticsearch (7.13.3)
elasticsearch-api (= 7.17.10) elasticsearch-api (= 7.13.3)
elasticsearch-transport (= 7.17.10) elasticsearch-transport (= 7.13.3)
elasticsearch-api (7.17.10) elasticsearch-api (7.13.3)
multi_json multi_json
elasticsearch-dsl (0.1.10) elasticsearch-dsl (0.1.10)
elasticsearch-transport (7.17.10) elasticsearch-transport (7.13.3)
faraday (>= 1, < 3) faraday (~> 1)
multi_json multi_json
email_spec (2.2.2) email_spec (2.2.2)
htmlentities (~> 4.3.3) htmlentities (~> 4.3.3)
launchy (~> 2.1) launchy (~> 2.1)
mail (~> 2.7) mail (~> 2.7)
encryptor (3.0.0)
erubi (1.12.0) erubi (1.12.0)
et-orbi (1.2.11) et-orbi (1.2.7)
tzinfo tzinfo
excon (0.110.0) excon (0.109.0)
fabrication (2.31.0) fabrication (2.31.0)
faker (3.3.1) faker (3.2.3)
i18n (>= 1.8.11, < 2) i18n (>= 1.8.11, < 2)
faraday (1.10.3) faraday (1.10.3)
faraday-em_http (~> 1.0) faraday-em_http (~> 1.0)
@ -265,10 +275,10 @@ GEM
faraday_middleware (1.2.0) faraday_middleware (1.2.0)
faraday (~> 1.0) faraday (~> 1.0)
fast_blank (1.0.1) fast_blank (1.0.1)
fastimage (2.3.1) fastimage (2.3.0)
ffi (1.16.3) ffi (1.15.5)
ffi-compiler (1.3.2) ffi-compiler (1.0.1)
ffi (>= 1.15.5) ffi (>= 1.0.0)
rake rake
fog-core (2.4.0) fog-core (2.4.0)
builder builder
@ -278,11 +288,11 @@ GEM
fog-json (1.2.0) fog-json (1.2.0)
fog-core fog-core
multi_json (~> 1.10) multi_json (~> 1.10)
fog-openstack (1.1.1) fog-openstack (1.1.0)
fog-core (~> 2.1) fog-core (~> 2.1)
fog-json (>= 1.0) fog-json (>= 1.0)
formatador (1.1.0) formatador (1.1.0)
fugit (1.10.1) fugit (1.8.1)
et-orbi (~> 1, >= 1.2.7) et-orbi (~> 1, >= 1.2.7)
raabro (~> 1.4) raabro (~> 1.4)
fuubar (2.5.1) fuubar (2.5.1)
@ -290,9 +300,6 @@ GEM
ruby-progressbar (~> 1.4) ruby-progressbar (~> 1.4)
globalid (1.2.1) globalid (1.2.1)
activesupport (>= 6.1) activesupport (>= 6.1)
google-protobuf (3.25.3)
googleapis-common-protos-types (1.14.0)
google-protobuf (~> 3.18)
haml (6.3.0) haml (6.3.0)
temple (>= 0.8.2) temple (>= 0.8.2)
thor thor
@ -302,7 +309,7 @@ GEM
activesupport (>= 5.1) activesupport (>= 5.1)
haml (>= 4.0.6) haml (>= 4.0.6)
railties (>= 5.1) railties (>= 5.1)
haml_lint (0.58.0) haml_lint (0.57.0)
haml (>= 5.0) haml (>= 5.0)
parallel (~> 1.10) parallel (~> 1.10)
rainbow rainbow
@ -312,16 +319,15 @@ GEM
hashie (5.0.0) hashie (5.0.0)
hcaptcha (7.1.0) hcaptcha (7.1.0)
json json
highline (3.0.1) highline (2.1.0)
hiredis (0.6.3) hiredis (0.6.3)
hkdf (0.3.0) hkdf (0.3.0)
htmlentities (4.3.4) htmlentities (4.3.4)
http (5.2.0) http (5.1.1)
addressable (~> 2.8) addressable (~> 2.8)
base64 (~> 0.1)
http-cookie (~> 1.0) http-cookie (~> 1.0)
http-form_data (~> 2.2) http-form_data (~> 2.2)
llhttp-ffi (~> 0.5.0) llhttp-ffi (~> 0.4.0)
http-cookie (1.0.5) http-cookie (1.0.5)
domain_name (~> 0.5) domain_name (~> 0.5)
http-form_data (2.3.0) http-form_data (2.3.0)
@ -330,11 +336,12 @@ GEM
httplog (1.6.3) httplog (1.6.3)
rack (>= 2.0) rack (>= 2.0)
rainbow (>= 2.0.0) rainbow (>= 2.0.0)
i18n (1.14.5) i18n (1.14.1)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
i18n-tasks (1.0.14) i18n-tasks (1.0.13)
activesupport (>= 4.0.2) activesupport (>= 4.0.2)
ast (>= 2.1.0) ast (>= 2.1.0)
better_html (>= 1.0, < 3.0)
erubi erubi
highline (>= 2.0.0) highline (>= 2.0.0)
i18n i18n
@ -343,17 +350,14 @@ GEM
rainbow (>= 2.2.2, < 4.0) rainbow (>= 2.2.2, < 4.0)
terminal-table (>= 1.5.1) terminal-table (>= 1.5.1)
idn-ruby (0.1.5) idn-ruby (0.1.5)
inline_svg (1.9.0)
activesupport (>= 3.0)
nokogiri (>= 1.6)
io-console (0.7.2) io-console (0.7.2)
irb (1.13.1) irb (1.11.2)
rdoc (>= 4.0.0) rdoc
reline (>= 0.4.2) reline (>= 0.4.2)
jmespath (1.6.2) jmespath (1.6.2)
json (2.7.2) json (2.7.1)
json-canonicalization (1.0.0) json-canonicalization (1.0.0)
json-jwt (1.15.3.1) json-jwt (1.15.3)
activesupport (>= 4.2) activesupport (>= 4.2)
aes_key_wrap aes_key_wrap
bindata bindata
@ -368,7 +372,7 @@ GEM
json-ld-preloaded (3.3.0) json-ld-preloaded (3.3.0)
json-ld (~> 3.3) json-ld (~> 3.3)
rdf (~> 3.3) rdf (~> 3.3)
json-schema (4.3.0) json-schema (4.1.1)
addressable (>= 2.8) addressable (>= 2.8)
jsonapi-renderer (0.2.2) jsonapi-renderer (0.2.2)
jwt (2.7.1) jwt (2.7.1)
@ -393,15 +397,15 @@ GEM
language_server-protocol (3.17.0.3) language_server-protocol (3.17.0.3)
launchy (2.5.2) launchy (2.5.2)
addressable (~> 2.8) addressable (~> 2.8)
letter_opener (1.10.0) letter_opener (1.8.1)
launchy (>= 2.2, < 4) launchy (>= 2.2, < 3)
letter_opener_web (3.0.0) letter_opener_web (2.0.0)
actionmailer (>= 6.1) actionmailer (>= 5.2)
letter_opener (~> 1.9) letter_opener (~> 1.7)
railties (>= 6.1) railties (>= 5.2)
rexml rexml
link_header (0.0.8) link_header (0.0.8)
llhttp-ffi (0.5.0) llhttp-ffi (0.4.0)
ffi-compiler (~> 1.0) ffi-compiler (~> 1.0)
rake (~> 13.0) rake (~> 13.0)
lograge (0.14.0) lograge (0.14.0)
@ -417,7 +421,7 @@ GEM
net-imap net-imap
net-pop net-pop
net-smtp net-smtp
marcel (1.0.4) 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)
@ -428,19 +432,19 @@ GEM
memory_profiler (1.0.1) memory_profiler (1.0.1)
mime-types (3.5.2) mime-types (3.5.2)
mime-types-data (~> 3.2015) mime-types-data (~> 3.2015)
mime-types-data (3.2024.0507) mime-types-data (3.2023.1205)
mini_mime (1.1.5) mini_mime (1.1.5)
mini_portile2 (2.8.6) mini_portile2 (2.8.5)
minitest (5.22.3) minitest (5.21.2)
msgpack (1.7.2) msgpack (1.7.2)
multi_json (1.15.0) multi_json (1.15.0)
multipart-post (2.4.0) multipart-post (2.3.0)
mutex_m (0.2.0) mutex_m (0.2.0)
net-http (0.4.1) net-http (0.4.1)
uri uri
net-http-persistent (4.0.2) net-http-persistent (4.0.2)
connection_pool (~> 2.2) connection_pool (~> 2.2)
net-imap (0.4.11) net-imap (0.4.10)
date date
net-protocol net-protocol
net-ldap (0.19.0) net-ldap (0.19.0)
@ -448,10 +452,10 @@ GEM
net-protocol net-protocol
net-protocol (0.2.2) net-protocol (0.2.2)
timeout timeout
net-smtp (0.5.0) net-smtp (0.4.0.1)
net-protocol net-protocol
nio4r (2.7.3) nio4r (2.5.9)
nokogiri (1.16.5) nokogiri (1.16.2)
mini_portile2 (~> 2.8.2) mini_portile2 (~> 2.8.2)
racc (~> 1.4) racc (~> 1.4)
nsa (0.3.0) nsa (0.3.0)
@ -461,11 +465,11 @@ GEM
statsd-ruby (~> 1.4, >= 1.4.0) statsd-ruby (~> 1.4, >= 1.4.0)
oj (3.16.3) oj (3.16.3)
bigdecimal (>= 3.0) bigdecimal (>= 3.0)
omniauth (2.1.2) omniauth (2.1.1)
hashie (>= 3.4.6) hashie (>= 3.4.6)
rack (>= 2.2.3) rack (>= 2.2.3)
rack-protection rack-protection
omniauth-cas (3.0.0) omniauth-cas (3.0.0.beta.1)
addressable (~> 2.8) addressable (~> 2.8)
nokogiri (~> 1.12) nokogiri (~> 1.12)
omniauth (~> 2.1) omniauth (~> 2.1)
@ -492,109 +496,20 @@ GEM
openssl (3.2.0) openssl (3.2.0)
openssl-signature_algorithm (1.3.0) openssl-signature_algorithm (1.3.0)
openssl (> 2.0) openssl (> 2.0)
opentelemetry-api (1.2.5)
opentelemetry-common (0.20.1)
opentelemetry-api (~> 1.0)
opentelemetry-exporter-otlp (0.26.3)
google-protobuf (~> 3.14)
googleapis-common-protos-types (~> 1.3)
opentelemetry-api (~> 1.1)
opentelemetry-common (~> 0.20)
opentelemetry-sdk (~> 1.2)
opentelemetry-semantic_conventions
opentelemetry-helpers-sql-obfuscation (0.1.0)
opentelemetry-common (~> 0.20)
opentelemetry-instrumentation-action_pack (0.9.0)
opentelemetry-api (~> 1.0)
opentelemetry-instrumentation-base (~> 0.22.1)
opentelemetry-instrumentation-rack (~> 0.21)
opentelemetry-instrumentation-action_view (0.7.0)
opentelemetry-api (~> 1.0)
opentelemetry-instrumentation-active_support (~> 0.1)
opentelemetry-instrumentation-base (~> 0.22.1)
opentelemetry-instrumentation-active_job (0.7.1)
opentelemetry-api (~> 1.0)
opentelemetry-instrumentation-base (~> 0.22.1)
opentelemetry-instrumentation-active_model_serializers (0.20.1)
opentelemetry-api (~> 1.0)
opentelemetry-instrumentation-base (~> 0.22.1)
opentelemetry-instrumentation-active_record (0.7.2)
opentelemetry-api (~> 1.0)
opentelemetry-instrumentation-base (~> 0.22.1)
opentelemetry-instrumentation-active_support (0.5.1)
opentelemetry-api (~> 1.0)
opentelemetry-instrumentation-base (~> 0.22.1)
opentelemetry-instrumentation-base (0.22.3)
opentelemetry-api (~> 1.0)
opentelemetry-registry (~> 0.1)
opentelemetry-instrumentation-concurrent_ruby (0.21.3)
opentelemetry-api (~> 1.0)
opentelemetry-instrumentation-base (~> 0.22.1)
opentelemetry-instrumentation-excon (0.22.1)
opentelemetry-api (~> 1.0)
opentelemetry-common (~> 0.20.0)
opentelemetry-instrumentation-base (~> 0.22.1)
opentelemetry-instrumentation-faraday (0.24.2)
opentelemetry-api (~> 1.0)
opentelemetry-common (~> 0.20.0)
opentelemetry-instrumentation-base (~> 0.22.1)
opentelemetry-instrumentation-http (0.23.3)
opentelemetry-api (~> 1.0)
opentelemetry-instrumentation-base (~> 0.22.1)
opentelemetry-instrumentation-http_client (0.22.4)
opentelemetry-api (~> 1.0)
opentelemetry-common (~> 0.20.0)
opentelemetry-instrumentation-base (~> 0.22.1)
opentelemetry-instrumentation-net_http (0.22.4)
opentelemetry-api (~> 1.0)
opentelemetry-common (~> 0.20.0)
opentelemetry-instrumentation-base (~> 0.22.1)
opentelemetry-instrumentation-pg (0.27.3)
opentelemetry-api (~> 1.0)
opentelemetry-helpers-sql-obfuscation
opentelemetry-instrumentation-base (~> 0.22.1)
opentelemetry-instrumentation-rack (0.24.3)
opentelemetry-api (~> 1.0)
opentelemetry-common (~> 0.20.0)
opentelemetry-instrumentation-base (~> 0.22.1)
opentelemetry-instrumentation-rails (0.30.1)
opentelemetry-api (~> 1.0)
opentelemetry-instrumentation-action_pack (~> 0.9.0)
opentelemetry-instrumentation-action_view (~> 0.7.0)
opentelemetry-instrumentation-active_job (~> 0.7.0)
opentelemetry-instrumentation-active_record (~> 0.7.0)
opentelemetry-instrumentation-active_support (~> 0.5.0)
opentelemetry-instrumentation-base (~> 0.22.1)
opentelemetry-instrumentation-redis (0.25.4)
opentelemetry-api (~> 1.0)
opentelemetry-common (~> 0.20.0)
opentelemetry-instrumentation-base (~> 0.22.1)
opentelemetry-instrumentation-sidekiq (0.25.3)
opentelemetry-api (~> 1.0)
opentelemetry-common (~> 0.20.0)
opentelemetry-instrumentation-base (~> 0.22.1)
opentelemetry-registry (0.3.1)
opentelemetry-api (~> 1.1)
opentelemetry-sdk (1.4.1)
opentelemetry-api (~> 1.1)
opentelemetry-common (~> 0.20)
opentelemetry-registry (~> 0.2)
opentelemetry-semantic_conventions
opentelemetry-semantic_conventions (1.10.0)
opentelemetry-api (~> 1.0)
orm_adapter (0.5.0) orm_adapter (0.5.0)
ox (2.14.18) ox (2.14.17)
parallel (1.24.0) parallel (1.24.0)
parser (3.3.1.0) parser (3.3.0.5)
ast (~> 2.4.1) ast (~> 2.4.1)
racc racc
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.5.6) pg (1.5.5)
pghero (3.4.1) pghero (3.4.1)
activerecord (>= 6) activerecord (>= 6)
premailer (1.23.0) posix-spawn (0.3.15)
premailer (1.21.0)
addressable addressable
css_parser (>= 1.12.0) css_parser (>= 1.12.0)
htmlentities (>= 4.0.0) htmlentities (>= 4.0.0)
@ -610,17 +525,17 @@ GEM
railties (>= 7.0.0) railties (>= 7.0.0)
psych (5.1.2) psych (5.1.2)
stringio stringio
public_suffix (5.0.5) public_suffix (5.0.4)
puma (6.4.2) puma (6.4.2)
nio4r (~> 2.0) nio4r (~> 2.0)
pundit (2.3.2) pundit (2.3.1)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
raabro (1.4.0) raabro (1.4.0)
racc (1.7.3) racc (1.7.3)
rack (2.2.9) rack (2.2.8.1)
rack-attack (6.7.0) rack-attack (6.7.0)
rack (>= 1.0, < 4) rack (>= 1.0, < 4)
rack-cors (2.0.2) rack-cors (2.0.1)
rack (>= 2.0.0) rack (>= 2.0.0)
rack-oauth2 (1.21.3) rack-oauth2 (1.21.3)
activesupport activesupport
@ -628,10 +543,9 @@ GEM
httpclient httpclient
json-jwt (>= 1.11.0) json-jwt (>= 1.11.0)
rack (>= 2.1.0) rack (>= 2.1.0)
rack-protection (3.2.0) rack-protection (3.0.5)
base64 (>= 0.1.0) rack
rack (~> 2.2, >= 2.2.4) rack-proxy (0.7.6)
rack-proxy (0.7.7)
rack rack
rack-session (1.0.2) rack-session (1.0.2)
rack (< 3) rack (< 3)
@ -640,20 +554,20 @@ GEM
rackup (1.0.0) rackup (1.0.0)
rack (< 3) rack (< 3)
webrick webrick
rails (7.1.3.3) rails (7.1.3.2)
actioncable (= 7.1.3.3) actioncable (= 7.1.3.2)
actionmailbox (= 7.1.3.3) actionmailbox (= 7.1.3.2)
actionmailer (= 7.1.3.3) actionmailer (= 7.1.3.2)
actionpack (= 7.1.3.3) actionpack (= 7.1.3.2)
actiontext (= 7.1.3.3) actiontext (= 7.1.3.2)
actionview (= 7.1.3.3) actionview (= 7.1.3.2)
activejob (= 7.1.3.3) activejob (= 7.1.3.2)
activemodel (= 7.1.3.3) activemodel (= 7.1.3.2)
activerecord (= 7.1.3.3) activerecord (= 7.1.3.2)
activestorage (= 7.1.3.3) activestorage (= 7.1.3.2)
activesupport (= 7.1.3.3) activesupport (= 7.1.3.2)
bundler (>= 1.15.0) bundler (>= 1.15.0)
railties (= 7.1.3.3) railties (= 7.1.3.2)
rails-controller-testing (1.0.5) rails-controller-testing (1.0.5)
actionpack (>= 5.0.1.rc1) actionpack (>= 5.0.1.rc1)
actionview (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1)
@ -665,25 +579,25 @@ GEM
rails-html-sanitizer (1.6.0) rails-html-sanitizer (1.6.0)
loofah (~> 2.21) loofah (~> 2.21)
nokogiri (~> 1.14) nokogiri (~> 1.14)
rails-i18n (7.0.9) rails-i18n (7.0.8)
i18n (>= 0.7, < 2) i18n (>= 0.7, < 2)
railties (>= 6.0.0, < 8) railties (>= 6.0.0, < 8)
railties (7.1.3.3) railties (7.1.3.2)
actionpack (= 7.1.3.3) actionpack (= 7.1.3.2)
activesupport (= 7.1.3.3) activesupport (= 7.1.3.2)
irb irb
rackup (>= 1.0.0) rackup (>= 1.0.0)
rake (>= 12.2) rake (>= 12.2)
thor (~> 1.0, >= 1.2.2) thor (~> 1.0, >= 1.2.2)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
rainbow (3.1.1) rainbow (3.1.1)
rake (13.2.1) rake (13.1.0)
rdf (3.3.1) rdf (3.3.1)
bcp47_spec (~> 0.2) bcp47_spec (~> 0.2)
link_header (~> 0.0, >= 0.0.8) link_header (~> 0.0, >= 0.0.8)
rdf-normalize (0.7.0) rdf-normalize (0.7.0)
rdf (~> 3.3) rdf (~> 3.3)
rdoc (6.6.3.1) rdoc (6.6.2)
psych (>= 4.0.0) psych (>= 4.0.0)
redcarpet (3.6.0) redcarpet (3.6.0)
redis (4.8.1) redis (4.8.1)
@ -692,47 +606,46 @@ GEM
redlock (1.3.2) redlock (1.3.2)
redis (>= 3.0.0, < 6.0) redis (>= 3.0.0, < 6.0)
regexp_parser (2.9.0) regexp_parser (2.9.0)
reline (0.5.7) reline (0.4.2)
io-console (~> 0.5) io-console (~> 0.5)
request_store (1.6.0) request_store (1.5.1)
rack (>= 1.4) rack (>= 1.4)
responders (3.1.1) responders (3.1.1)
actionpack (>= 5.2) actionpack (>= 5.2)
railties (>= 5.2) railties (>= 5.2)
rexml (3.2.8) rexml (3.2.6)
strscan (>= 3.0.9)
rotp (6.3.0) rotp (6.3.0)
rouge (4.2.1) rouge (4.1.2)
rpam2 (4.0.2) rpam2 (4.0.2)
rqrcode (2.2.0) rqrcode (2.2.0)
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.13.0) rspec-core (3.12.2)
rspec-support (~> 3.13.0) rspec-support (~> 3.12.0)
rspec-expectations (3.13.0) rspec-expectations (3.12.3)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0) rspec-support (~> 3.12.0)
rspec-github (2.4.0) rspec-github (2.4.0)
rspec-core (~> 3.0) rspec-core (~> 3.0)
rspec-mocks (3.13.1) rspec-mocks (3.12.6)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0) rspec-support (~> 3.12.0)
rspec-rails (6.1.2) rspec-rails (6.1.1)
actionpack (>= 6.1) actionpack (>= 6.1)
activesupport (>= 6.1) activesupport (>= 6.1)
railties (>= 6.1) railties (>= 6.1)
rspec-core (~> 3.13) rspec-core (~> 3.12)
rspec-expectations (~> 3.13) rspec-expectations (~> 3.12)
rspec-mocks (~> 3.13) rspec-mocks (~> 3.12)
rspec-support (~> 3.13) rspec-support (~> 3.12)
rspec-sidekiq (5.0.0) rspec-sidekiq (4.1.0)
rspec-core (~> 3.0) rspec-core (~> 3.0)
rspec-expectations (~> 3.0) rspec-expectations (~> 3.0)
rspec-mocks (~> 3.0) rspec-mocks (~> 3.0)
sidekiq (>= 5, < 8) sidekiq (>= 5, < 8)
rspec-support (3.13.1) rspec-support (3.12.1)
rubocop (1.63.5) rubocop (1.60.2)
json (~> 2.3) json (~> 2.3)
language_server-protocol (>= 3.17.0) language_server-protocol (>= 3.17.0)
parallel (~> 1.10) parallel (~> 1.10)
@ -740,33 +653,30 @@ GEM
rainbow (>= 2.2.2, < 4.0) rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0) regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0) rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.31.1, < 2.0) rubocop-ast (>= 1.30.0, < 2.0)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0) unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.31.3) rubocop-ast (1.30.0)
parser (>= 3.3.1.0) parser (>= 3.2.1.0)
rubocop-capybara (2.20.0) rubocop-capybara (2.20.0)
rubocop (~> 1.41) rubocop (~> 1.41)
rubocop-factory_bot (2.25.1) rubocop-factory_bot (2.25.0)
rubocop (~> 1.41) rubocop (~> 1.33)
rubocop-performance (1.21.0) rubocop-performance (1.20.2)
rubocop (>= 1.48.1, < 2.0) rubocop (>= 1.48.1, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0) rubocop-ast (>= 1.30.0, < 2.0)
rubocop-rails (2.24.1) rubocop-rails (2.23.1)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
rack (>= 1.1) rack (>= 1.1)
rubocop (>= 1.33.0, < 2.0) rubocop (>= 1.33.0, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0) rubocop-ast (>= 1.30.0, < 2.0)
rubocop-rspec (2.29.2) rubocop-rspec (2.26.1)
rubocop (~> 1.40) rubocop (~> 1.40)
rubocop-capybara (~> 2.17) rubocop-capybara (~> 2.17)
rubocop-factory_bot (~> 2.22) rubocop-factory_bot (~> 2.22)
rubocop-rspec_rails (~> 2.28)
rubocop-rspec_rails (2.28.3)
rubocop (~> 1.40)
ruby-prof (1.7.0) ruby-prof (1.7.0)
ruby-progressbar (1.13.0) ruby-progressbar (1.13.0)
ruby-saml (1.16.0) ruby-saml (1.15.0)
nokogiri (>= 1.13.10) nokogiri (>= 1.13.10)
rexml rexml
ruby2_keywords (0.0.5) ruby2_keywords (0.0.5)
@ -778,10 +688,10 @@ GEM
sanitize (6.1.0) sanitize (6.1.0)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.12.0) nokogiri (>= 1.12.0)
scenic (1.8.0) scenic (1.7.0)
activerecord (>= 4.0.0) activerecord (>= 4.0.0)
railties (>= 4.0.0) railties (>= 4.0.0)
selenium-webdriver (4.21.1) selenium-webdriver (4.18.1)
base64 (~> 0.2) base64 (~> 0.2)
rexml (~> 3.2, >= 3.2.5) rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0) rubyzip (>= 1.2.2, < 3.0)
@ -815,14 +725,14 @@ GEM
simplecov-html (0.12.3) simplecov-html (0.12.3)
simplecov-lcov (0.8.0) simplecov-lcov (0.8.0)
simplecov_json_formatter (0.1.4) simplecov_json_formatter (0.1.4)
smart_properties (1.17.0)
stackprof (0.2.26) stackprof (0.2.26)
statsd-ruby (1.5.0) statsd-ruby (1.5.0)
stoplight (4.1.0) stoplight (3.0.2)
redlock (~> 1.0) redlock (~> 1.0)
stringio (3.1.0) stringio (3.1.0)
strong_migrations (1.8.0) strong_migrations (1.7.0)
activerecord (>= 5.2) activerecord (>= 5.2)
strscan (3.1.0)
swd (1.3.0) swd (1.3.0)
activesupport (>= 3) activesupport (>= 3)
attr_required (>= 0.0.5) attr_required (>= 0.0.5)
@ -833,7 +743,7 @@ GEM
unicode-display_width (>= 1.1.1, < 3) unicode-display_width (>= 1.1.1, < 3)
terrapin (1.0.1) terrapin (1.0.1)
climate_control climate_control
test-prof (1.3.3) test-prof (1.3.1)
thor (1.3.1) thor (1.3.1)
tilt (2.3.0) tilt (2.3.0)
timeout (0.4.1) timeout (0.4.1)
@ -850,7 +760,7 @@ GEM
tty-cursor (~> 0.7) tty-cursor (~> 0.7)
tty-screen (~> 0.8) tty-screen (~> 0.8)
wisper (~> 2.0) wisper (~> 2.0)
tty-screen (0.8.2) tty-screen (0.8.1)
twitter-text (3.1.0) twitter-text (3.1.0)
idn-ruby idn-ruby
unf (~> 0.1.0) unf (~> 0.1.0)
@ -860,9 +770,9 @@ GEM
tzinfo (>= 1.0.0) tzinfo (>= 1.0.0)
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.9.1) unf_ext (0.0.8.2)
unicode-display_width (2.5.0) unicode-display_width (2.5.0)
uri (0.13.0) uri (0.12.2)
validate_email (0.1.6) validate_email (0.1.6)
activemodel (>= 3.0) activemodel (>= 3.0)
mail (>= 2.2.5) mail (>= 2.2.5)
@ -883,7 +793,7 @@ GEM
webfinger (1.2.0) webfinger (1.2.0)
activesupport activesupport
httpclient (>= 2.4) httpclient (>= 2.4)
webmock (3.23.0) webmock (3.22.0)
addressable (>= 2.8.0) addressable (>= 2.8.0)
crack (>= 0.3.2) crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0) hashdiff (>= 0.4.0, < 2.0.0)
@ -901,7 +811,7 @@ GEM
xorcist (1.1.3) xorcist (1.1.3)
xpath (3.2.0) xpath (3.2.0)
nokogiri (~> 1.8) nokogiri (~> 1.8)
zeitwerk (2.6.14) zeitwerk (2.6.13)
PLATFORMS PLATFORMS
ruby ruby
@ -919,7 +829,7 @@ DEPENDENCIES
browser browser
bundler-audit (~> 0.9) bundler-audit (~> 0.9)
capybara (~> 3.39) capybara (~> 3.39)
charlock_holmes! charlock_holmes (~> 0.7.7)
chewy (~> 7.3) chewy (~> 7.3)
climate_control climate_control
cocoon (~> 1.2) cocoon (~> 1.2)
@ -930,11 +840,11 @@ DEPENDENCIES
database_cleaner-active_record database_cleaner-active_record
debug (~> 1.8) debug (~> 1.8)
devise (~> 4.9) devise (~> 4.9)
devise-two-factor devise-two-factor (~> 4.1)
devise_pam_authenticatable2 (~> 9.2) devise_pam_authenticatable2 (~> 9.2)
discard (~> 1.2) discard (~> 1.2)
doorkeeper (~> 5.6) doorkeeper (~> 5.6)
dotenv dotenv-rails (~> 2.8)
ed25519 (~> 1.3) ed25519 (~> 1.3)
email_spec email_spec
fabrication (~> 2.30) fabrication (~> 2.30)
@ -949,13 +859,11 @@ DEPENDENCIES
hcaptcha (~> 7.1) hcaptcha (~> 7.1)
hiredis (~> 0.6) hiredis (~> 0.6)
htmlentities (~> 4.3) htmlentities (~> 4.3)
http (~> 5.2.0) http (~> 5.1)
http_accept_language (~> 2.1) http_accept_language (~> 2.1)
httplog (~> 1.6.2) httplog (~> 1.6.2)
i18n
i18n-tasks (~> 1.0) i18n-tasks (~> 1.0)
idn-ruby idn-ruby
inline_svg
irb (~> 1.8) irb (~> 1.8)
json-ld json-ld
json-ld-preloaded (~> 3.2) json-ld-preloaded (~> 3.2)
@ -963,10 +871,9 @@ DEPENDENCIES
kaminari (~> 1.2) kaminari (~> 1.2)
kt-paperclip (~> 7.2) kt-paperclip (~> 7.2)
letter_opener (~> 1.8) letter_opener (~> 1.8)
letter_opener_web (~> 3.0) letter_opener_web (~> 2.0)
link_header (~> 0.0) link_header (~> 0.0)
lograge (~> 0.12) lograge (~> 0.12)
mail (~> 2.8)
mario-redis-lock (~> 1.2) mario-redis-lock (~> 1.2)
md-paperclip-azure (~> 2.2) md-paperclip-azure (~> 2.2)
memory_profiler memory_profiler
@ -981,25 +888,11 @@ DEPENDENCIES
omniauth-rails_csrf_protection (~> 1.0) omniauth-rails_csrf_protection (~> 1.0)
omniauth-saml (~> 2.0) omniauth-saml (~> 2.0)
omniauth_openid_connect (~> 0.6.1) omniauth_openid_connect (~> 0.6.1)
opentelemetry-exporter-otlp (~> 0.26.3)
opentelemetry-instrumentation-active_job (~> 0.7.1)
opentelemetry-instrumentation-active_model_serializers (~> 0.20.1)
opentelemetry-instrumentation-concurrent_ruby (~> 0.21.2)
opentelemetry-instrumentation-excon (~> 0.22.0)
opentelemetry-instrumentation-faraday (~> 0.24.1)
opentelemetry-instrumentation-http (~> 0.23.2)
opentelemetry-instrumentation-http_client (~> 0.22.3)
opentelemetry-instrumentation-net_http (~> 0.22.4)
opentelemetry-instrumentation-pg (~> 0.27.1)
opentelemetry-instrumentation-rack (~> 0.24.1)
opentelemetry-instrumentation-rails (~> 0.30.0)
opentelemetry-instrumentation-redis (~> 0.25.3)
opentelemetry-instrumentation-sidekiq (~> 0.25.2)
opentelemetry-sdk (~> 1.4)
ox (~> 2.14) ox (~> 2.14)
parslet parslet
pg (~> 1.5) pg (~> 1.5)
pghero pghero
posix-spawn
premailer-rails premailer-rails
private_address_check (~> 0.5) private_address_check (~> 0.5)
propshaft propshaft
@ -1020,7 +913,7 @@ DEPENDENCIES
rqrcode (~> 2.2) rqrcode (~> 2.2)
rspec-github (~> 2.4) rspec-github (~> 2.4)
rspec-rails (~> 6.0) rspec-rails (~> 6.0)
rspec-sidekiq (~> 5.0) rspec-sidekiq (~> 4.0)
rubocop rubocop
rubocop-capybara rubocop-capybara
rubocop-performance rubocop-performance
@ -1041,8 +934,8 @@ DEPENDENCIES
simplecov (~> 0.22) simplecov (~> 0.22)
simplecov-lcov (~> 0.8) simplecov-lcov (~> 0.8)
stackprof stackprof
stoplight (~> 4.1) stoplight (~> 3.0.1)
strong_migrations (= 1.8.0) strong_migrations (= 1.7.0)
test-prof test-prof
thor (~> 1.2) thor (~> 1.2)
tty-prompt (~> 0.23) tty-prompt (~> 0.23)
@ -1055,7 +948,7 @@ DEPENDENCIES
xorcist (~> 1.1) xorcist (~> 1.1)
RUBY VERSION RUBY VERSION
ruby 3.3.1p55 ruby 3.2.2p53
BUNDLED WITH BUNDLED WITH
2.5.9 2.5.4

180
README.md
View file

@ -1,182 +1,14 @@
# <img src="https://github.com/TheEssem/mastodon/raw/main/public/chuckya.png" width="128"> Chuckya
Chuckya is a close-to-upstream soft fork of Mastodon Glitch Edition (more commonly known as glitch-soc) that aims to introduce more experimental features/fixes with the goal of making the overall experience more enjoyable. Although it's mainly developed for and used on the [wetdry.world](https://wetdry.world) instance, it can be deployed by any server admin as a drop-in, backwards-compatible replacement for Mastodon.
Here are some of the changes compared to glitch-soc:
- Emoji reactions (glitch-soc/mastodon#2462)
- Tenor GIF picker (originally from [koyu.space](https://github.com/koyuspace/mastodon))
- Mastodon Modern theme (licensed under CC-BY-SA 4.0, [original repo](https://codeberg.org/Freeplay/Mastodon-Modern))
- Workaround for OpenGraph video embeds when using [Jortage](https://jortage.com)
- Multiple fixes for oEmbed/OpenGraph embeds
- Polls can be posted alongside media (glitch-soc/mastodon#2524)
- Polls can have only one option
- Restores status trend half-life to 2 hours
- Allows dashes in custom emote names
- Emojis can be put side-by-side
- Minor media attachment tweaks
Changes previously in Chuckya that made their way into vanilla Mastodon:
- Unicode emojis use [`jdecked/twemoji`](https://github.com/jdecked/twemoji) v15 graphics (mastodon/mastodon#28404)
Setup instructions are the same as [glitch-soc's](https://glitch-soc.github.io/docs); just replace the glitch-soc repo URL with `https://github.com/TheEssem/mastodon`.
Original glitch-soc readme is below.
# Mastodon Glitch Edition # Mastodon Glitch Edition
[![Ruby Testing](https://github.com/glitch-soc/mastodon/actions/workflows/test-ruby.yml/badge.svg)](https://github.com/glitch-soc/mastodon/actions/workflows/test-ruby.yml) > Now with automated deploys!
[![Crowdin](https://badges.crowdin.net/glitch-soc/localized.svg)][glitch-crowdin]
[glitch-crowdin]: https://crowdin.com/project/glitch-soc [![Build Status](https://img.shields.io/circleci/project/github/glitch-soc/mastodon.svg)][circleci]
[![Code Climate](https://img.shields.io/codeclimate/maintainability/glitch-soc/mastodon.svg)][code_climate]
[circleci]: https://circleci.com/gh/glitch-soc/mastodon
[code_climate]: https://codeclimate.com/github/glitch-soc/mastodon
So here's the deal: we all work on this code, and anyone who uses that does so absolutely at their own risk. can you dig it? So here's the deal: we all work on this code, and anyone who uses that does so absolutely at their own risk. can you dig it?
- You can view documentation for this project at [glitch-soc.github.io/docs/](https://glitch-soc.github.io/docs/). - You can view documentation for this project at [glitch-soc.github.io/docs/](https://glitch-soc.github.io/docs/).
- And contributing guidelines are available [here](CONTRIBUTING.md) and [here](https://glitch-soc.github.io/docs/contributing/). - And contributing guidelines are available [here](CONTRIBUTING.md) and [here](https://glitch-soc.github.io/docs/contributing/).
Mastodon Glitch Edition is a fork of [Mastodon](https://github.com/mastodon/mastodon). Upstream's README file is reproduced below.
---
<h1><picture>
<source media="(prefers-color-scheme: dark)" srcset="./lib/assets/wordmark.dark.png?raw=true">
<source media="(prefers-color-scheme: light)" srcset="./lib/assets/wordmark.light.png?raw=true">
<img alt="Mastodon" src="./lib/assets/wordmark.light.png?raw=true" height="34">
</picture></h1>
[![GitHub release](https://img.shields.io/github/release/mastodon/mastodon.svg)][releases]
[![Ruby Testing](https://github.com/mastodon/mastodon/actions/workflows/test-ruby.yml/badge.svg)](https://github.com/mastodon/mastodon/actions/workflows/test-ruby.yml)
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/mastodon/localized.svg)][crowdin]
[releases]: https://github.com/mastodon/mastodon/releases
[crowdin]: https://crowdin.com/project/mastodon
Mastodon is a **free, open-source social network server** based on ActivityPub where users can follow friends and discover new ones. On Mastodon, users can publish anything they want: links, pictures, text, and video. All Mastodon servers are interoperable as a federated network (users on one server can seamlessly communicate with users from another one, including non-Mastodon software that implements ActivityPub!)
Click below to **learn more** in a video:
[![Screenshot](https://blog.joinmastodon.org/2018/06/why-activitypub-is-the-future/ezgif-2-60f1b00403.gif)][youtube_demo]
[youtube_demo]: https://www.youtube.com/watch?v=IPSbNdBmWKE
## Navigation
- [Project homepage 🐘](https://joinmastodon.org)
- [Support the development via Patreon][patreon]
- [View sponsors](https://joinmastodon.org/sponsors)
- [Blog](https://blog.joinmastodon.org)
- [Documentation](https://docs.joinmastodon.org)
- [Roadmap](https://joinmastodon.org/roadmap)
- [Official Docker image](https://github.com/mastodon/mastodon/pkgs/container/mastodon)
- [Browse Mastodon servers](https://joinmastodon.org/communities)
- [Browse Mastodon apps](https://joinmastodon.org/apps)
[patreon]: https://www.patreon.com/mastodon
## Features
<img src="/app/javascript/images/elephant_ui_working.svg?raw=true" align="right" width="30%" />
### No vendor lock-in: Fully interoperable with any conforming platform
It doesn't have to be Mastodon; whatever implements ActivityPub is part of the social network! [Learn more](https://blog.joinmastodon.org/2018/06/why-activitypub-is-the-future/)
### Real-time, chronological timeline updates
Updates of people you're following appear in real-time in the UI via WebSockets. There's a firehose view as well!
### Media attachments like images and short videos
Upload and view images and WebM/MP4 videos attached to the updates. Videos with no audio track are treated like GIFs; normal videos loop continuously!
### Safety and moderation tools
Mastodon includes private posts, locked accounts, phrase filtering, muting, blocking, and all sorts of other features, along with a reporting and moderation system. [Learn more](https://blog.joinmastodon.org/2018/07/cage-the-mastodon/)
### OAuth2 and a straightforward REST API
Mastodon acts as an OAuth2 provider, so 3rd party apps can use the REST and Streaming APIs. This results in a rich app ecosystem with a lot of choices!
## Deployment
### Tech stack
- **Ruby on Rails** powers the REST API and other web pages
- **React.js** and Redux are used for the dynamic parts of the interface
- **Node.js** powers the streaming API
### Requirements
- **PostgreSQL** 12+
- **Redis** 4+
- **Ruby** 3.1+
- **Node.js** 18+
The repository includes deployment configurations for **Docker and docker-compose** as well as specific platforms like **Heroku**, **Scalingo**, and **Nanobox**. For Helm charts, reference the [mastodon/chart repository](https://github.com/mastodon/chart). The [**standalone** installation guide](https://docs.joinmastodon.org/admin/install/) is available in the documentation.
## Development
### Vagrant
A **Vagrant** configuration is included for development purposes. To use it, complete the following steps:
- Install Vagrant and Virtualbox
- Install the `vagrant-hostsupdater` plugin: `vagrant plugin install vagrant-hostsupdater`
- Run `vagrant up`
- Run `vagrant ssh -c "cd /vagrant && bin/dev"`
- Open `http://mastodon.local` in your browser
### MacOS
To set up **MacOS** for native development, complete the following steps:
- Use a Ruby version manager to install the specified version from `.ruby-version`
- Run `bundle` to install required gems
- Run `brew install postgresql@14 redis imagemagick libidn` to install required dependencies
- Navigate to Mastodon's root directory and run `brew install nvm` then `nvm use` to use the version from `.nvmrc`
- Run `yarn` to install required packages
- Run `corepack enable && corepack prepare`
- Run `RAILS_ENV=development bundle exec rails db:setup`
- Finally, run `bin/dev` which will launch the local services via `overmind` (if installed) or `foreman`
### Docker
For development with **Docker**, complete the following steps:
- Install Docker Desktop
- Run `docker compose -f .devcontainer/docker-compose.yml up -d`
- Run `docker compose -f .devcontainer/docker-compose.yml exec app .devcontainer/post-create.sh`
- Finally, run `docker compose -f .devcontainer/docker-compose.yml exec app bin/dev`
If you are using an IDE with [support for the Development Container specification](https://containers.dev/supporting), it will run the above `docker compose` commands automatically. For **Visual Studio Code** this requires the [Dev Container extension](https://containers.dev/supporting#dev-containers).
### GitHub Codespaces
To get you coding in just a few minutes, GitHub Codespaces provides a web-based version of Visual Studio Code and a cloud-hosted development environment fully configured with the software needed for this project..
- Click this button to create a new codespace:<br>
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=52281283&devcontainer_path=.devcontainer%2Fcodespaces%2Fdevcontainer.json)
- Wait for the environment to build. This will take a few minutes.
- When the editor is ready, run `bin/dev` in the terminal.
- After a few seconds, a popup will appear with a button labeled _Open in Browser_. This will open Mastodon.
- On the _Ports_ tab, right click on the “stream” row and select _Port visibility__Public_.
## Contributing
Mastodon is **free, open-source software** licensed under **AGPLv3**.
You can open issues for bugs you've found or features you think are missing. You can also submit pull requests to this repository or submit translations using Crowdin. To get started, take a look at [CONTRIBUTING.md](CONTRIBUTING.md). If your contributions are accepted into Mastodon, you can request to be paid through [our OpenCollective](https://opencollective.com/mastodon).
**IRC channel**: #mastodon on irc.libera.chat
## License
Copyright (C) 2016-2024 Eugen Rochko & other Mastodon contributors (see [AUTHORS.md](AUTHORS.md))
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.

3
Vagrantfile vendored
View file

@ -173,7 +173,6 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# Otherwise, you can access the site at http://localhost:3000 and http://localhost:4000 , http://localhost:8080 # Otherwise, you can access the site at http://localhost:3000 and http://localhost:4000 , http://localhost:8080
config.vm.network :forwarded_port, guest: 3000, host: 3000 config.vm.network :forwarded_port, guest: 3000, host: 3000
config.vm.network :forwarded_port, guest: 3035, host: 3035
config.vm.network :forwarded_port, guest: 4000, host: 4000 config.vm.network :forwarded_port, guest: 4000, host: 4000
config.vm.network :forwarded_port, guest: 8080, host: 8080 config.vm.network :forwarded_port, guest: 8080, host: 8080
config.vm.network :forwarded_port, guest: 9200, host: 9200 config.vm.network :forwarded_port, guest: 9200, host: 9200
@ -189,7 +188,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.post_up_message = <<MESSAGE config.vm.post_up_message = <<MESSAGE
To start server To start server
$ vagrant ssh -c "cd /vagrant && bin/dev" $ vagrant ssh -c "cd /vagrant && foreman start"
MESSAGE MESSAGE
end end

View file

@ -25,7 +25,7 @@ class AccountsController < ApplicationController
limit = params[:limit].present? ? [params[:limit].to_i, PAGE_SIZE_MAX].min : PAGE_SIZE limit = params[:limit].present? ? [params[:limit].to_i, PAGE_SIZE_MAX].min : PAGE_SIZE
@statuses = filtered_statuses.without_reblogs.limit(limit) @statuses = filtered_statuses.without_reblogs.limit(limit)
@statuses = preload_collection(@statuses, Status) @statuses = cache_collection(@statuses, Status)
end end
format.json do format.json do
@ -46,7 +46,7 @@ class AccountsController < ApplicationController
end end
def default_statuses def default_statuses
@account.statuses.not_local_only.distributable_visibility @account.statuses.not_local_only.where(visibility: [:public, :unlisted])
end end
def only_media_scope def only_media_scope

View file

@ -1,9 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
class ActivityPub::BaseController < Api::BaseController class ActivityPub::BaseController < Api::BaseController
include SignatureVerification
include AccountOwnedConcern
skip_before_action :require_authenticated_user! skip_before_action :require_authenticated_user!
skip_before_action :require_not_suspended! skip_before_action :require_not_suspended!
skip_around_action :set_locale skip_around_action :set_locale

View file

@ -1,6 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
class ActivityPub::ClaimsController < ActivityPub::BaseController class ActivityPub::ClaimsController < ActivityPub::BaseController
include SignatureVerification
include AccountOwnedConcern
skip_before_action :authenticate_user! skip_before_action :authenticate_user!
before_action :require_account_signature! before_action :require_account_signature!

View file

@ -1,6 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
class ActivityPub::CollectionsController < ActivityPub::BaseController class ActivityPub::CollectionsController < ActivityPub::BaseController
include SignatureVerification
include AccountOwnedConcern
vary_by -> { 'Signature' if authorized_fetch_mode? } vary_by -> { 'Signature' if authorized_fetch_mode? }
before_action :require_account_signature!, if: :authorized_fetch_mode? before_action :require_account_signature!, if: :authorized_fetch_mode?
@ -18,7 +21,7 @@ class ActivityPub::CollectionsController < ActivityPub::BaseController
def set_items def set_items
case params[:id] case params[:id]
when 'featured' when 'featured'
@items = for_signed_account { preload_collection(@account.pinned_statuses.not_local_only, Status) } @items = for_signed_account { cache_collection(@account.pinned_statuses.not_local_only, Status) }
@items = @items.map { |item| item.distributable? ? item : ActivityPub::TagManager.instance.uri_for(item) } @items = @items.map { |item| item.distributable? ? item : ActivityPub::TagManager.instance.uri_for(item) }
when 'tags' when 'tags'
@items = for_signed_account { @account.featured_tags } @items = for_signed_account { @account.featured_tags }

View file

@ -1,6 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
class ActivityPub::FollowersSynchronizationsController < ActivityPub::BaseController class ActivityPub::FollowersSynchronizationsController < ActivityPub::BaseController
include SignatureVerification
include AccountOwnedConcern
vary_by -> { 'Signature' if authorized_fetch_mode? } vary_by -> { 'Signature' if authorized_fetch_mode? }
before_action :require_account_signature! before_action :require_account_signature!

View file

@ -1,7 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
class ActivityPub::InboxesController < ActivityPub::BaseController class ActivityPub::InboxesController < ActivityPub::BaseController
include SignatureVerification
include JsonLdHelper include JsonLdHelper
include AccountOwnedConcern
before_action :skip_unknown_actor_activity before_action :skip_unknown_actor_activity
before_action :require_actor_signature! before_action :require_actor_signature!

View file

@ -3,6 +3,9 @@
class ActivityPub::OutboxesController < ActivityPub::BaseController class ActivityPub::OutboxesController < ActivityPub::BaseController
LIMIT = 20 LIMIT = 20
include SignatureVerification
include AccountOwnedConcern
vary_by -> { 'Signature' if authorized_fetch_mode? || page_requested? } vary_by -> { 'Signature' if authorized_fetch_mode? || page_requested? }
before_action :require_account_signature!, if: :authorized_fetch_mode? before_action :require_account_signature!, if: :authorized_fetch_mode?
@ -60,7 +63,7 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
def set_statuses def set_statuses
return unless page_requested? return unless page_requested?
@statuses = preload_collection_paginated_by_id( @statuses = cache_collection_paginated_by_id(
AccountStatusesFilter.new(@account, signed_request_account).results, AccountStatusesFilter.new(@account, signed_request_account).results,
Status, Status,
LIMIT, LIMIT,

View file

@ -1,7 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
class ActivityPub::RepliesController < ActivityPub::BaseController class ActivityPub::RepliesController < ActivityPub::BaseController
include SignatureVerification
include Authorization include Authorization
include AccountOwnedConcern
DESCENDANTS_LIMIT = 60 DESCENDANTS_LIMIT = 60
@ -31,7 +33,7 @@ class ActivityPub::RepliesController < ActivityPub::BaseController
def set_replies def set_replies
@replies = only_other_accounts? ? Status.where.not(account_id: @account.id).joins(:account).merge(Account.without_suspended) : @account.statuses @replies = only_other_accounts? ? Status.where.not(account_id: @account.id).joins(:account).merge(Account.without_suspended) : @account.statuses
@replies = @replies.distributable_visibility.where(in_reply_to_id: @status.id) @replies = @replies.where(in_reply_to_id: @status.id, visibility: [:public, :unlisted])
@replies = @replies.paginate_by_min_id(DESCENDANTS_LIMIT, params[:min_id]) @replies = @replies.paginate_by_min_id(DESCENDANTS_LIMIT, params[:min_id])
end end

View file

@ -128,7 +128,7 @@ module Admin
def unblock_email def unblock_email
authorize @account, :unblock_email? authorize @account, :unblock_email?
CanonicalEmailBlock.matching_account(@account).delete_all CanonicalEmailBlock.where(reference_account: @account).delete_all
log_action :unblock_email, @account log_action :unblock_email, @account

View file

@ -7,6 +7,7 @@ module Admin
layout 'admin' layout 'admin'
before_action :set_pack
before_action :set_body_classes before_action :set_body_classes
before_action :set_cache_headers before_action :set_cache_headers
@ -18,6 +19,10 @@ module Admin
@body_classes = 'admin' @body_classes = 'admin'
end end
def set_pack
use_pack 'admin'
end
def set_cache_headers def set_cache_headers
response.cache_control.replace(private: true, no_store: true) response.cache_control.replace(private: true, no_store: true)
end end

View file

@ -25,8 +25,6 @@ class Admin::DomainAllowsController < Admin::BaseController
def destroy def destroy
authorize @domain_allow, :destroy? authorize @domain_allow, :destroy?
UnallowDomainService.new.call(@domain_allow) UnallowDomainService.new.call(@domain_allow)
log_action :destroy, @domain_allow
redirect_to admin_instances_path, notice: I18n.t('admin.domain_allows.destroyed_msg') redirect_to admin_instances_path, notice: I18n.t('admin.domain_allows.destroyed_msg')
end end

View file

@ -53,7 +53,7 @@ module Admin
end end
def resource_params def resource_params
params.require(:rule).permit(:text, :hint, :priority) params.require(:rule).permit(:text, :priority)
end end
end end
end end

View file

@ -9,7 +9,7 @@ module Admin
@site_upload.destroy! @site_upload.destroy!
redirect_back fallback_location: admin_settings_path, notice: I18n.t('admin.site_uploads.destroyed_msg') redirect_to admin_settings_path, notice: I18n.t('admin.site_uploads.destroyed_msg')
end end
private private

View file

@ -8,8 +8,6 @@ class Api::BaseController < ApplicationController
include Api::AccessTokenTrackingConcern include Api::AccessTokenTrackingConcern
include Api::CachingConcern include Api::CachingConcern
include Api::ContentSecurityPolicy include Api::ContentSecurityPolicy
include Api::ErrorHandling
include Api::Pagination
skip_before_action :require_functional!, unless: :limited_federation_mode? skip_before_action :require_functional!, unless: :limited_federation_mode?
@ -20,6 +18,51 @@ class Api::BaseController < ApplicationController
protect_from_forgery with: :null_session protect_from_forgery with: :null_session
rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e|
render json: { error: e.to_s }, status: 422
end
rescue_from ActiveRecord::RecordNotUnique do
render json: { error: 'Duplicate record' }, status: 422
end
rescue_from Date::Error do
render json: { error: 'Invalid date supplied' }, status: 422
end
rescue_from ActiveRecord::RecordNotFound do
render json: { error: 'Record not found' }, status: 404
end
rescue_from HTTP::Error, Mastodon::UnexpectedResponseError do
render json: { error: 'Remote data could not be fetched' }, status: 503
end
rescue_from OpenSSL::SSL::SSLError do
render json: { error: 'Remote SSL certificate could not be verified' }, status: 503
end
rescue_from Mastodon::NotPermittedError do
render json: { error: 'This action is not allowed' }, status: 403
end
rescue_from Seahorse::Client::NetworkingError do |e|
Rails.logger.warn "Storage server error: #{e}"
render json: { error: 'There was a temporary problem serving your request, please try again' }, status: 503
end
rescue_from Mastodon::RaceConditionError, Stoplight::Error::RedLight do
render json: { error: 'There was a temporary problem serving your request, please try again' }, status: 503
end
rescue_from Mastodon::RateLimitExceededError do
render json: { error: I18n.t('errors.429') }, status: 429
end
rescue_from ActionController::ParameterMissing, Mastodon::InvalidParameterError do |e|
render json: { error: e.to_s }, status: 400
end
def doorkeeper_unauthorized_render_options(error: nil) def doorkeeper_unauthorized_render_options(error: nil)
{ json: { error: error.try(:description) || 'Not authorized' } } { json: { error: error.try(:description) || 'Not authorized' } }
end end
@ -30,6 +73,13 @@ class Api::BaseController < ApplicationController
protected protected
def set_pagination_headers(next_path = nil, prev_path = nil)
links = []
links << [next_path, [%w(rel next)]] if next_path
links << [prev_path, [%w(rel prev)]] if prev_path
response.headers['Link'] = LinkHeader.new(links) unless links.empty?
end
def limit_param(default_limit) def limit_param(default_limit)
return default_limit unless params[:limit] return default_limit unless params[:limit]
@ -58,6 +108,10 @@ class Api::BaseController < ApplicationController
render json: { error: 'Your login is currently disabled' }, status: 403 if current_user&.account&.unavailable? render json: { error: 'Your login is currently disabled' }, status: 403 if current_user&.account&.unavailable?
end end
def require_valid_pagination_options!
render json: { error: 'Pagination values for `offset` and `limit` must be positive' }, status: 400 if pagination_options_invalid?
end
def require_user! def require_user!
if !current_user if !current_user
render json: { error: 'This method requires an authenticated user' }, status: 422 render json: { error: 'This method requires an authenticated user' }, status: 422
@ -86,6 +140,10 @@ class Api::BaseController < ApplicationController
private private
def pagination_options_invalid?
params.slice(:limit, :offset).values.map(&:to_i).any?(&:negative?)
end
def respond_with_error(code) def respond_with_error(code)
render json: { error: Rack::Utils::HTTP_STATUS_CODES[code] }, status: code render json: { error: Rack::Utils::HTTP_STATUS_CODES[code] }, status: code
end end

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class Api::V1::Accounts::CredentialsController < Api::BaseController class Api::V1::Accounts::CredentialsController < Api::BaseController
before_action -> { doorkeeper_authorize! :read, :'read:accounts', :'read:me' }, except: [:update] before_action -> { doorkeeper_authorize! :read, :'read:accounts' }, except: [:update]
before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:update] before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:update]
before_action :require_user! before_action :require_user!

View file

@ -41,6 +41,10 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController
) )
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_account_followers_url pagination_params(max_id: pagination_max_id) if records_continue? api_v1_account_followers_url pagination_params(max_id: pagination_max_id) if records_continue?
end end

View file

@ -41,6 +41,10 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController
) )
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_account_following_index_url pagination_params(max_id: pagination_max_id) if records_continue? api_v1_account_following_index_url pagination_params(max_id: pagination_max_id) if records_continue?
end end

View file

@ -4,7 +4,7 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
before_action -> { authorize_if_got_token! :read, :'read:statuses' } before_action -> { authorize_if_got_token! :read, :'read:statuses' }
before_action :set_account before_action :set_account
after_action :insert_pagination_headers after_action :insert_pagination_headers, unless: -> { truthy_param?(:pinned) }
def index def index
cache_if_unauthenticated! cache_if_unauthenticated!
@ -19,11 +19,11 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
end end
def load_statuses def load_statuses
@account.unavailable? ? [] : preloaded_account_statuses @account.unavailable? ? [] : cached_account_statuses
end end
def preloaded_account_statuses def cached_account_statuses
preload_collection_paginated_by_id( cache_collection_paginated_by_id(
AccountStatusesFilter.new(@account, current_account, params).results, AccountStatusesFilter.new(@account, current_account, params).results,
Status, Status,
limit_param(DEFAULT_STATUSES_LIMIT), limit_param(DEFAULT_STATUSES_LIMIT),
@ -35,6 +35,10 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
params.slice(:limit, *AccountStatusesFilter::KEYS).permit(:limit, *AccountStatusesFilter::KEYS).merge(core_params) params.slice(:limit, *AccountStatusesFilter::KEYS).permit(:limit, *AccountStatusesFilter::KEYS).merge(core_params)
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_account_statuses_url pagination_params(max_id: pagination_max_id) if records_continue? api_v1_account_statuses_url pagination_params(max_id: pagination_max_id) if records_continue?
end end
@ -47,7 +51,11 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
@statuses.size == limit_param(DEFAULT_STATUSES_LIMIT) @statuses.size == limit_param(DEFAULT_STATUSES_LIMIT)
end end
def pagination_collection def pagination_max_id
@statuses @statuses.last.id
end
def pagination_since_id
@statuses.first.id
end end
end end

View file

@ -9,22 +9,16 @@ class Api::V1::AccountsController < Api::BaseController
before_action -> { doorkeeper_authorize! :follow, :write, :'write:blocks' }, only: [:block, :unblock] before_action -> { doorkeeper_authorize! :follow, :write, :'write:blocks' }, only: [:block, :unblock]
before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:create] before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:create]
before_action :require_user!, except: [:index, :show, :create] before_action :require_user!, except: [:show, :create]
before_action :set_account, except: [:index, :create] before_action :set_account, except: [:create]
before_action :set_accounts, only: [:index] before_action :check_account_approval, except: [:create]
before_action :check_account_approval, except: [:index, :create] before_action :check_account_confirmation, except: [:create]
before_action :check_account_confirmation, except: [:index, :create]
before_action :check_enabled_registrations, only: [:create] before_action :check_enabled_registrations, only: [:create]
before_action :check_accounts_limit, only: [:index]
skip_before_action :require_authenticated_user!, only: :create skip_before_action :require_authenticated_user!, only: :create
override_rate_limit_headers :follow, family: :follows override_rate_limit_headers :follow, family: :follows
def index
render json: @accounts, each_serializer: REST::AccountSerializer
end
def show def show
cache_if_unauthenticated! cache_if_unauthenticated!
render json: @account, serializer: REST::AccountSerializer render json: @account, serializer: REST::AccountSerializer
@ -85,10 +79,6 @@ class Api::V1::AccountsController < Api::BaseController
@account = Account.find(params[:id]) @account = Account.find(params[:id])
end end
def set_accounts
@accounts = Account.where(id: account_ids).without_unapproved
end
def check_account_approval def check_account_approval
raise(ActiveRecord::RecordNotFound) if @account.local? && @account.user_pending? raise(ActiveRecord::RecordNotFound) if @account.local? && @account.user_pending?
end end
@ -97,22 +87,10 @@ class Api::V1::AccountsController < Api::BaseController
raise(ActiveRecord::RecordNotFound) if @account.local? && !@account.user_confirmed? raise(ActiveRecord::RecordNotFound) if @account.local? && !@account.user_confirmed?
end end
def check_accounts_limit
raise(Mastodon::ValidationError) if account_ids.size > DEFAULT_ACCOUNTS_LIMIT
end
def relationships(**options) def relationships(**options)
AccountRelationshipsPresenter.new([@account], current_user.account_id, **options) AccountRelationshipsPresenter.new([@account], current_user.account_id, **options)
end end
def account_ids
Array(accounts_params[:ids]).uniq.map(&:to_i)
end
def accounts_params
params.permit(ids: [])
end
def account_params def account_params
params.permit(:username, :email, :password, :agreement, :locale, :reason, :time_zone, :invite_code) params.permit(:username, :email, :password, :agreement, :locale, :reason, :time_zone, :invite_code)
end end

View file

@ -125,6 +125,10 @@ class Api::V1::Admin::AccountsController < Api::BaseController
translated_params translated_params
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_admin_accounts_url(pagination_params(max_id: pagination_max_id)) if records_continue? api_v1_admin_accounts_url(pagination_params(max_id: pagination_max_id)) if records_continue?
end end
@ -133,8 +137,12 @@ class Api::V1::Admin::AccountsController < Api::BaseController
api_v1_admin_accounts_url(pagination_params(min_id: pagination_since_id)) unless @accounts.empty? api_v1_admin_accounts_url(pagination_params(min_id: pagination_since_id)) unless @accounts.empty?
end end
def pagination_collection def pagination_max_id
@accounts @accounts.last.id
end
def pagination_since_id
@accounts.first.id
end end
def records_continue? def records_continue?

View file

@ -65,6 +65,10 @@ class Api::V1::Admin::CanonicalEmailBlocksController < Api::BaseController
@canonical_email_block = CanonicalEmailBlock.find(params[:id]) @canonical_email_block = CanonicalEmailBlock.find(params[:id])
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_admin_canonical_email_blocks_url(pagination_params(max_id: pagination_max_id)) if records_continue? api_v1_admin_canonical_email_blocks_url(pagination_params(max_id: pagination_max_id)) if records_continue?
end end
@ -73,8 +77,12 @@ class Api::V1::Admin::CanonicalEmailBlocksController < Api::BaseController
api_v1_admin_canonical_email_blocks_url(pagination_params(min_id: pagination_since_id)) unless @canonical_email_blocks.empty? api_v1_admin_canonical_email_blocks_url(pagination_params(min_id: pagination_since_id)) unless @canonical_email_blocks.empty?
end end
def pagination_collection def pagination_max_id
@canonical_email_blocks @canonical_email_blocks.last.id
end
def pagination_since_id
@canonical_email_blocks.first.id
end end
def records_continue? def records_continue?

View file

@ -61,6 +61,10 @@ class Api::V1::Admin::DomainAllowsController < Api::BaseController
DomainAllow.all DomainAllow.all
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_admin_domain_allows_url(pagination_params(max_id: pagination_max_id)) if records_continue? api_v1_admin_domain_allows_url(pagination_params(max_id: pagination_max_id)) if records_continue?
end end
@ -69,8 +73,12 @@ class Api::V1::Admin::DomainAllowsController < Api::BaseController
api_v1_admin_domain_allows_url(pagination_params(min_id: pagination_since_id)) unless @domain_allows.empty? api_v1_admin_domain_allows_url(pagination_params(min_id: pagination_since_id)) unless @domain_allows.empty?
end end
def pagination_collection def pagination_max_id
@domain_allows @domain_allows.last.id
end
def pagination_since_id
@domain_allows.first.id
end end
def records_continue? def records_continue?

View file

@ -29,11 +29,10 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController
def create def create
authorize :domain_block, :create? authorize :domain_block, :create?
@domain_block = DomainBlock.new(resource_params)
existing_domain_block = resource_params[:domain].present? ? DomainBlock.rule_for(resource_params[:domain]) : nil existing_domain_block = resource_params[:domain].present? ? DomainBlock.rule_for(resource_params[:domain]) : nil
return render json: existing_domain_block, serializer: REST::Admin::ExistingDomainBlockErrorSerializer, status: 422 if conflicts_with_existing_block?(@domain_block, existing_domain_block) return render json: existing_domain_block, serializer: REST::Admin::ExistingDomainBlockErrorSerializer, status: 422 if existing_domain_block.present?
@domain_block.save! @domain_block = DomainBlock.create!(resource_params)
DomainBlockWorker.perform_async(@domain_block.id) DomainBlockWorker.perform_async(@domain_block.id)
log_action :create, @domain_block log_action :create, @domain_block
render json: @domain_block, serializer: REST::Admin::DomainBlockSerializer render json: @domain_block, serializer: REST::Admin::DomainBlockSerializer
@ -56,10 +55,6 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController
private private
def conflicts_with_existing_block?(domain_block, existing_domain_block)
existing_domain_block.present? && (existing_domain_block.domain == TagManager.instance.normalize_domain(domain_block.domain) || !domain_block.stricter_than?(existing_domain_block))
end
def set_domain_blocks def set_domain_blocks
@domain_blocks = filtered_domain_blocks.order(id: :desc).to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id)) @domain_blocks = filtered_domain_blocks.order(id: :desc).to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
end end
@ -77,6 +72,10 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController
params.permit(:severity, :reject_media, :reject_reports, :private_comment, :public_comment, :obfuscate) params.permit(:severity, :reject_media, :reject_reports, :private_comment, :public_comment, :obfuscate)
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_admin_domain_blocks_url(pagination_params(max_id: pagination_max_id)) if records_continue? api_v1_admin_domain_blocks_url(pagination_params(max_id: pagination_max_id)) if records_continue?
end end
@ -85,8 +84,12 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController
api_v1_admin_domain_blocks_url(pagination_params(min_id: pagination_since_id)) unless @domain_blocks.empty? api_v1_admin_domain_blocks_url(pagination_params(min_id: pagination_since_id)) unless @domain_blocks.empty?
end end
def pagination_collection def pagination_max_id
@domain_blocks @domain_blocks.last.id
end
def pagination_since_id
@domain_blocks.first.id
end end
def records_continue? def records_continue?

View file

@ -58,6 +58,10 @@ class Api::V1::Admin::EmailDomainBlocksController < Api::BaseController
params.permit(:domain, :allow_with_approval) params.permit(:domain, :allow_with_approval)
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_admin_email_domain_blocks_url(pagination_params(max_id: pagination_max_id)) if records_continue? api_v1_admin_email_domain_blocks_url(pagination_params(max_id: pagination_max_id)) if records_continue?
end end
@ -66,8 +70,12 @@ class Api::V1::Admin::EmailDomainBlocksController < Api::BaseController
api_v1_admin_email_domain_blocks_url(pagination_params(min_id: pagination_since_id)) unless @email_domain_blocks.empty? api_v1_admin_email_domain_blocks_url(pagination_params(min_id: pagination_since_id)) unless @email_domain_blocks.empty?
end end
def pagination_collection def pagination_max_id
@email_domain_blocks @email_domain_blocks.last.id
end
def pagination_since_id
@email_domain_blocks.first.id
end end
def records_continue? def records_continue?

View file

@ -63,6 +63,10 @@ class Api::V1::Admin::IpBlocksController < Api::BaseController
params.permit(:ip, :severity, :comment, :expires_in) params.permit(:ip, :severity, :comment, :expires_in)
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_admin_ip_blocks_url(pagination_params(max_id: pagination_max_id)) if records_continue? api_v1_admin_ip_blocks_url(pagination_params(max_id: pagination_max_id)) if records_continue?
end end
@ -71,8 +75,12 @@ class Api::V1::Admin::IpBlocksController < Api::BaseController
api_v1_admin_ip_blocks_url(pagination_params(min_id: pagination_since_id)) unless @ip_blocks.empty? api_v1_admin_ip_blocks_url(pagination_params(min_id: pagination_since_id)) unless @ip_blocks.empty?
end end
def pagination_collection def pagination_max_id
@ip_blocks @ip_blocks.last.id
end
def pagination_since_id
@ip_blocks.first.id
end end
def records_continue? def records_continue?

View file

@ -89,6 +89,10 @@ class Api::V1::Admin::ReportsController < Api::BaseController
params.permit(*FILTER_PARAMS) params.permit(*FILTER_PARAMS)
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_admin_reports_url(pagination_params(max_id: pagination_max_id)) if records_continue? api_v1_admin_reports_url(pagination_params(max_id: pagination_max_id)) if records_continue?
end end
@ -97,8 +101,12 @@ class Api::V1::Admin::ReportsController < Api::BaseController
api_v1_admin_reports_url(pagination_params(min_id: pagination_since_id)) unless @reports.empty? api_v1_admin_reports_url(pagination_params(min_id: pagination_since_id)) unless @reports.empty?
end end
def pagination_collection def pagination_max_id
@reports @reports.last.id
end
def pagination_since_id
@reports.first.id
end end
def records_continue? def records_continue?

View file

@ -44,6 +44,10 @@ class Api::V1::Admin::TagsController < Api::BaseController
params.permit(:display_name, :trendable, :usable, :listable) params.permit(:display_name, :trendable, :usable, :listable)
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_admin_tags_url(pagination_params(max_id: pagination_max_id)) if records_continue? api_v1_admin_tags_url(pagination_params(max_id: pagination_max_id)) if records_continue?
end end
@ -52,8 +56,12 @@ class Api::V1::Admin::TagsController < Api::BaseController
api_v1_admin_tags_url(pagination_params(min_id: pagination_since_id)) unless @tags.empty? api_v1_admin_tags_url(pagination_params(min_id: pagination_since_id)) unless @tags.empty?
end end
def pagination_collection def pagination_max_id
@tags @tags.last.id
end
def pagination_since_id
@tags.first.id
end end
def records_continue? def records_continue?

View file

@ -42,6 +42,10 @@ class Api::V1::Admin::Trends::Links::PreviewCardProvidersController < Api::BaseC
@providers = PreviewCardProvider.all.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id)) @providers = PreviewCardProvider.all.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_admin_trends_links_preview_card_providers_url(pagination_params(max_id: pagination_max_id)) if records_continue? api_v1_admin_trends_links_preview_card_providers_url(pagination_params(max_id: pagination_max_id)) if records_continue?
end end
@ -50,8 +54,12 @@ class Api::V1::Admin::Trends::Links::PreviewCardProvidersController < Api::BaseC
api_v1_admin_trends_links_preview_card_providers_url(pagination_params(min_id: pagination_since_id)) unless @providers.empty? api_v1_admin_trends_links_preview_card_providers_url(pagination_params(min_id: pagination_since_id)) unless @providers.empty?
end end
def pagination_collection def pagination_max_id
@providers @providers.last.id
end
def pagination_since_id
@providers.first.id
end end
def records_continue? def records_continue?

View file

@ -4,6 +4,6 @@ class Api::V1::Apps::CredentialsController < Api::BaseController
def show def show
return doorkeeper_render_error unless valid_doorkeeper_token? return doorkeeper_render_error unless valid_doorkeeper_token?
render json: doorkeeper_token.application, serializer: REST::ApplicationSerializer render json: doorkeeper_token.application, serializer: REST::ApplicationSerializer, fields: %i(name website vapid_key client_id scopes)
end end
end end

View file

@ -5,7 +5,7 @@ class Api::V1::AppsController < Api::BaseController
def create def create
@app = Doorkeeper::Application.create!(application_options) @app = Doorkeeper::Application.create!(application_options)
render json: @app, serializer: REST::CredentialApplicationSerializer render json: @app, serializer: REST::ApplicationSerializer
end end
private private
@ -24,6 +24,6 @@ class Api::V1::AppsController < Api::BaseController
end end
def app_params def app_params
params.permit(:client_name, :scopes, :website, :redirect_uris, redirect_uris: []) params.permit(:client_name, :redirect_uris, :scopes, :website)
end end
end end

View file

@ -28,6 +28,10 @@ class Api::V1::BlocksController < Api::BaseController
) )
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_blocks_url pagination_params(max_id: pagination_max_id) if records_continue? api_v1_blocks_url pagination_params(max_id: pagination_max_id) if records_continue?
end end
@ -36,8 +40,12 @@ class Api::V1::BlocksController < Api::BaseController
api_v1_blocks_url pagination_params(since_id: pagination_since_id) unless paginated_blocks.empty? api_v1_blocks_url pagination_params(since_id: pagination_since_id) unless paginated_blocks.empty?
end end
def pagination_collection def pagination_max_id
paginated_blocks paginated_blocks.last.id
end
def pagination_since_id
paginated_blocks.first.id
end end
def records_continue? def records_continue?

View file

@ -13,11 +13,11 @@ class Api::V1::BookmarksController < Api::BaseController
private private
def load_statuses def load_statuses
preloaded_bookmarks cached_bookmarks
end end
def preloaded_bookmarks def cached_bookmarks
preload_collection(results.map(&:status), Status) cache_collection(results.map(&:status), Status)
end end
def results def results
@ -31,6 +31,10 @@ class Api::V1::BookmarksController < Api::BaseController
current_account.bookmarks current_account.bookmarks
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_bookmarks_url pagination_params(max_id: pagination_max_id) if records_continue? api_v1_bookmarks_url pagination_params(max_id: pagination_max_id) if records_continue?
end end
@ -39,8 +43,12 @@ class Api::V1::BookmarksController < Api::BaseController
api_v1_bookmarks_url pagination_params(min_id: pagination_since_id) unless results.empty? api_v1_bookmarks_url pagination_params(min_id: pagination_since_id) unless results.empty?
end end
def pagination_collection def pagination_max_id
results results.last.id
end
def pagination_since_id
results.first.id
end end
def records_continue? def records_continue?

View file

@ -53,6 +53,10 @@ class Api::V1::ConversationsController < Api::BaseController
.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id)) .to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_conversations_url pagination_params(max_id: pagination_max_id) if records_continue? api_v1_conversations_url pagination_params(max_id: pagination_max_id) if records_continue?
end end

View file

@ -29,6 +29,10 @@ class Api::V1::Crypto::EncryptedMessagesController < Api::BaseController
@encrypted_messages = @current_device.encrypted_messages.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id)) @encrypted_messages = @current_device.encrypted_messages.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_crypto_encrypted_messages_url pagination_params(max_id: pagination_max_id) if records_continue? api_v1_crypto_encrypted_messages_url pagination_params(max_id: pagination_max_id) if records_continue?
end end
@ -37,8 +41,12 @@ class Api::V1::Crypto::EncryptedMessagesController < Api::BaseController
api_v1_crypto_encrypted_messages_url pagination_params(min_id: pagination_since_id) unless @encrypted_messages.empty? api_v1_crypto_encrypted_messages_url pagination_params(min_id: pagination_since_id) unless @encrypted_messages.empty?
end end
def pagination_collection def pagination_max_id
@encrypted_messages @encrypted_messages.last.id
end
def pagination_since_id
@encrypted_messages.first.id
end end
def records_continue? def records_continue?

View file

@ -38,6 +38,10 @@ class Api::V1::DomainBlocksController < Api::BaseController
current_account.domain_blocks current_account.domain_blocks
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_domain_blocks_url pagination_params(max_id: pagination_max_id) if records_continue? api_v1_domain_blocks_url pagination_params(max_id: pagination_max_id) if records_continue?
end end
@ -46,8 +50,12 @@ class Api::V1::DomainBlocksController < Api::BaseController
api_v1_domain_blocks_url pagination_params(since_id: pagination_since_id) unless @blocks.empty? api_v1_domain_blocks_url pagination_params(since_id: pagination_since_id) unless @blocks.empty?
end end
def pagination_collection def pagination_max_id
@blocks @blocks.last.id
end
def pagination_since_id
@blocks.first.id
end end
def records_continue? def records_continue?

View file

@ -28,6 +28,10 @@ class Api::V1::EndorsementsController < Api::BaseController
current_account.endorsed_accounts.includes(:account_stat, :user).without_suspended current_account.endorsed_accounts.includes(:account_stat, :user).without_suspended
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
return if unlimited? return if unlimited?
@ -40,8 +44,12 @@ class Api::V1::EndorsementsController < Api::BaseController
api_v1_endorsements_url pagination_params(since_id: pagination_since_id) unless @accounts.empty? api_v1_endorsements_url pagination_params(since_id: pagination_since_id) unless @accounts.empty?
end end
def pagination_collection def pagination_max_id
@accounts @accounts.last.id
end
def pagination_since_id
@accounts.first.id
end end
def records_continue? def records_continue?

View file

@ -13,11 +13,11 @@ class Api::V1::FavouritesController < Api::BaseController
private private
def load_statuses def load_statuses
preloaded_favourites cached_favourites
end end
def preloaded_favourites def cached_favourites
preload_collection(results.map(&:status), Status) cache_collection(results.map(&:status), Status)
end end
def results def results
@ -31,6 +31,10 @@ class Api::V1::FavouritesController < Api::BaseController
current_account.favourites current_account.favourites
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_favourites_url pagination_params(max_id: pagination_max_id) if records_continue? api_v1_favourites_url pagination_params(max_id: pagination_max_id) if records_continue?
end end
@ -39,8 +43,12 @@ class Api::V1::FavouritesController < Api::BaseController
api_v1_favourites_url pagination_params(min_id: pagination_since_id) unless results.empty? api_v1_favourites_url pagination_params(min_id: pagination_since_id) unless results.empty?
end end
def pagination_collection def pagination_max_id
results results.last.id
end
def pagination_since_id
results.first.id
end end
def records_continue? def records_continue?

View file

@ -12,6 +12,6 @@ class Api::V1::FeaturedTags::SuggestionsController < Api::BaseController
private private
def set_recently_used_tags def set_recently_used_tags
@recently_used_tags = Tag.suggestions_for_account(current_account).limit(10) @recently_used_tags = Tag.recently_used(current_account).where.not(id: current_account.featured_tags).limit(10)
end end
end end

View file

@ -48,6 +48,10 @@ class Api::V1::FollowRequestsController < Api::BaseController
) )
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_follow_requests_url pagination_params(max_id: pagination_max_id) if records_continue? api_v1_follow_requests_url pagination_params(max_id: pagination_max_id) if records_continue?
end end

View file

@ -22,6 +22,10 @@ class Api::V1::FollowedTagsController < Api::BaseController
) )
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_followed_tags_url pagination_params(max_id: pagination_max_id) if records_continue? api_v1_followed_tags_url pagination_params(max_id: pagination_max_id) if records_continue?
end end
@ -30,8 +34,12 @@ class Api::V1::FollowedTagsController < Api::BaseController
api_v1_followed_tags_url pagination_params(since_id: pagination_since_id) unless @results.empty? api_v1_followed_tags_url pagination_params(since_id: pagination_since_id) unless @results.empty?
end end
def pagination_collection def pagination_max_id
@results @results.last.id
end
def pagination_since_id
@results.first.id
end end
def records_continue? def records_continue?

View file

@ -55,6 +55,10 @@ class Api::V1::Lists::AccountsController < Api::BaseController
params.permit(account_ids: []) params.permit(account_ids: [])
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
return if unlimited? return if unlimited?
@ -67,8 +71,12 @@ class Api::V1::Lists::AccountsController < Api::BaseController
api_v1_list_accounts_url pagination_params(since_id: pagination_since_id) unless @accounts.empty? api_v1_list_accounts_url pagination_params(since_id: pagination_since_id) unless @accounts.empty?
end end
def pagination_collection def pagination_max_id
@accounts @accounts.last.id
end
def pagination_since_id
@accounts.first.id
end end
def records_continue? def records_continue?

View file

@ -28,6 +28,10 @@ class Api::V1::MutesController < Api::BaseController
) )
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_mutes_url pagination_params(max_id: pagination_max_id) if records_continue? api_v1_mutes_url pagination_params(max_id: pagination_max_id) if records_continue?
end end
@ -36,8 +40,12 @@ class Api::V1::MutesController < Api::BaseController
api_v1_mutes_url pagination_params(since_id: pagination_since_id) unless paginated_mutes.empty? api_v1_mutes_url pagination_params(since_id: pagination_since_id) unless paginated_mutes.empty?
end end
def pagination_collection def pagination_max_id
paginated_mutes paginated_mutes.last.id
end
def pagination_since_id
paginated_mutes.first.id
end end
def records_continue? def records_continue?

View file

@ -1,37 +0,0 @@
# frozen_string_literal: true
class Api::V1::Notifications::PoliciesController < Api::BaseController
before_action -> { doorkeeper_authorize! :read, :'read:notifications' }, only: :show
before_action -> { doorkeeper_authorize! :write, :'write:notifications' }, only: :update
before_action :require_user!
before_action :set_policy
def show
render json: @policy, serializer: REST::NotificationPolicySerializer
end
def update
@policy.update!(resource_params)
render json: @policy, serializer: REST::NotificationPolicySerializer
end
private
def set_policy
@policy = NotificationPolicy.find_or_initialize_by(account: current_account)
with_read_replica do
@policy.summarize!
end
end
def resource_params
params.permit(
:filter_not_following,
:filter_not_followers,
:filter_new_accounts,
:filter_private_mentions
)
end
end

View file

@ -1,75 +0,0 @@
# frozen_string_literal: true
class Api::V1::Notifications::RequestsController < Api::BaseController
before_action -> { doorkeeper_authorize! :read, :'read:notifications' }, only: :index
before_action -> { doorkeeper_authorize! :write, :'write:notifications' }, except: :index
before_action :require_user!
before_action :set_request, except: :index
after_action :insert_pagination_headers, only: :index
def index
with_read_replica do
@requests = load_requests
@relationships = relationships
end
render json: @requests, each_serializer: REST::NotificationRequestSerializer, relationships: @relationships
end
def show
render json: @request, serializer: REST::NotificationRequestSerializer
end
def accept
AcceptNotificationRequestService.new.call(@request)
render_empty
end
def dismiss
@request.update!(dismissed: true)
render_empty
end
private
def load_requests
requests = NotificationRequest.where(account: current_account).where(dismissed: truthy_param?(:dismissed) || false).includes(:last_status, from_account: [:account_stat, :user]).to_a_paginated_by_id(
limit_param(DEFAULT_ACCOUNTS_LIMIT),
params_slice(:max_id, :since_id, :min_id)
)
NotificationRequest.preload_cache_collection(requests) do |statuses|
preload_collection(statuses, Status)
end
end
def relationships
StatusRelationshipsPresenter.new(@requests.map(&:last_status), current_user&.account_id)
end
def set_request
@request = NotificationRequest.where(account: current_account).find(params[:id])
end
def next_path
api_v1_notifications_requests_url pagination_params(max_id: pagination_max_id) unless @requests.empty?
end
def prev_path
api_v1_notifications_requests_url pagination_params(min_id: pagination_since_id) unless @requests.empty?
end
def pagination_max_id
@requests.last.id
end
def pagination_since_id
@requests.first.id
end
def pagination_params(core_params)
params.slice(:dismissed).permit(:dismissed).merge(core_params)
end
end

View file

@ -50,7 +50,7 @@ class Api::V1::NotificationsController < Api::BaseController
) )
Notification.preload_cache_collection_target_statuses(notifications) do |target_statuses| Notification.preload_cache_collection_target_statuses(notifications) do |target_statuses|
preload_collection(target_statuses, Status) cache_collection(target_statuses, Status)
end end
end end
@ -58,8 +58,7 @@ class Api::V1::NotificationsController < Api::BaseController
current_account.notifications.without_suspended.browserable( current_account.notifications.without_suspended.browserable(
types: Array(browserable_params[:types]), types: Array(browserable_params[:types]),
exclude_types: Array(browserable_params[:exclude_types]), exclude_types: Array(browserable_params[:exclude_types]),
from_account_id: browserable_params[:account_id], from_account_id: browserable_params[:account_id]
include_filtered: truthy_param?(:include_filtered)
) )
end end
@ -67,6 +66,10 @@ class Api::V1::NotificationsController < Api::BaseController
@notifications.reject { |notification| notification.target_status.nil? }.map(&:target_status) @notifications.reject { |notification| notification.target_status.nil? }.map(&:target_status)
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_notifications_url pagination_params(max_id: pagination_max_id) unless @notifications.empty? api_v1_notifications_url pagination_params(max_id: pagination_max_id) unless @notifications.empty?
end end
@ -75,15 +78,19 @@ class Api::V1::NotificationsController < Api::BaseController
api_v1_notifications_url pagination_params(min_id: pagination_since_id) unless @notifications.empty? api_v1_notifications_url pagination_params(min_id: pagination_since_id) unless @notifications.empty?
end end
def pagination_collection def pagination_max_id
@notifications @notifications.last.id
end
def pagination_since_id
@notifications.first.id
end end
def browserable_params def browserable_params
params.permit(:account_id, :include_filtered, types: [], exclude_types: []) params.permit(:account_id, types: [], exclude_types: [])
end end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:limit, :account_id, :types, :exclude_types, :include_filtered).permit(:limit, :account_id, :include_filtered, types: [], exclude_types: []).merge(core_params) params.slice(:limit, :account_id, :types, :exclude_types).permit(:limit, :account_id, types: [], exclude_types: []).merge(core_params)
end end
end end

View file

@ -1,12 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
class Api::V1::Push::SubscriptionsController < Api::BaseController class Api::V1::Push::SubscriptionsController < Api::BaseController
include Redisable
include Lockable
before_action -> { doorkeeper_authorize! :push } before_action -> { doorkeeper_authorize! :push }
before_action :require_user! before_action :require_user!
before_action :set_push_subscription, only: [:show, :update] before_action :set_push_subscription
before_action :check_push_subscription, only: [:show, :update] before_action :check_push_subscription, only: [:show, :update]
def show def show
@ -14,8 +11,7 @@ class Api::V1::Push::SubscriptionsController < Api::BaseController
end end
def create def create
with_redis_lock("push_subscription:#{current_user.id}") do @push_subscription&.destroy!
destroy_web_push_subscriptions!
@push_subscription = Web::PushSubscription.create!( @push_subscription = Web::PushSubscription.create!(
endpoint: subscription_params[:endpoint], endpoint: subscription_params[:endpoint],
@ -25,7 +21,6 @@ class Api::V1::Push::SubscriptionsController < Api::BaseController
user_id: current_user.id, user_id: current_user.id,
access_token_id: doorkeeper_token.id access_token_id: doorkeeper_token.id
) )
end
render json: @push_subscription, serializer: REST::WebPushSubscriptionSerializer render json: @push_subscription, serializer: REST::WebPushSubscriptionSerializer
end end
@ -36,18 +31,14 @@ class Api::V1::Push::SubscriptionsController < Api::BaseController
end end
def destroy def destroy
destroy_web_push_subscriptions! @push_subscription&.destroy!
render_empty render_empty
end end
private private
def destroy_web_push_subscriptions!
doorkeeper_token.web_push_subscriptions.destroy_all
end
def set_push_subscription def set_push_subscription
@push_subscription = doorkeeper_token.web_push_subscriptions.first @push_subscription = Web::PushSubscription.find_by(access_token_id: doorkeeper_token.id)
end end
def check_push_subscription def check_push_subscription

View file

@ -47,6 +47,10 @@ class Api::V1::ScheduledStatusesController < Api::BaseController
params.slice(:limit).permit(:limit).merge(core_params) params.slice(:limit).permit(:limit).merge(core_params)
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_scheduled_statuses_url pagination_params(max_id: pagination_max_id) if records_continue? api_v1_scheduled_statuses_url pagination_params(max_id: pagination_max_id) if records_continue?
end end
@ -59,7 +63,11 @@ class Api::V1::ScheduledStatusesController < Api::BaseController
@statuses.size == limit_param(DEFAULT_STATUSES_LIMIT) @statuses.size == limit_param(DEFAULT_STATUSES_LIMIT)
end end
def pagination_collection def pagination_max_id
@statuses @statuses.last.id
end
def pagination_since_id
@statuses.first.id
end end
end end

View file

@ -34,6 +34,10 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::V1::Statuses::Bas
) )
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_status_favourited_by_index_url pagination_params(max_id: pagination_max_id) if records_continue? api_v1_status_favourited_by_index_url pagination_params(max_id: pagination_max_id) if records_continue?
end end

View file

@ -1,19 +0,0 @@
# frozen_string_literal: true
class Api::V1::Statuses::ReactionsController < Api::V1::Statuses::BaseController
before_action -> { doorkeeper_authorize! :write, :'write:favourites' }
before_action :require_user!
def create
ReactService.new.call(current_account, @status, params[:id])
render json: @status, serializer: REST::StatusSerializer
end
def destroy
UnreactWorker.perform_async(current_account.id, @status.id, params[:id])
render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_account.id, reactions_map: { @status.id => false })
rescue Mastodon::NotPermittedError
not_found
end
end

View file

@ -23,13 +23,17 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::V1::Statuses::Base
end end
def paginated_statuses def paginated_statuses
Status.where(reblog_of_id: @status.id).distributable_visibility.paginate_by_max_id( Status.where(reblog_of_id: @status.id).where(visibility: [:public, :unlisted]).paginate_by_max_id(
limit_param(DEFAULT_ACCOUNTS_LIMIT), limit_param(DEFAULT_ACCOUNTS_LIMIT),
params[:max_id], params[:max_id],
params[:since_id] params[:since_id]
) )
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path def next_path
api_v1_status_reblogged_by_index_url pagination_params(max_id: pagination_max_id) if records_continue? api_v1_status_reblogged_by_index_url pagination_params(max_id: pagination_max_id) if records_continue?
end end

View file

@ -5,11 +5,9 @@ class Api::V1::StatusesController < Api::BaseController
before_action -> { authorize_if_got_token! :read, :'read:statuses' }, except: [:create, :update, :destroy] before_action -> { authorize_if_got_token! :read, :'read:statuses' }, except: [:create, :update, :destroy]
before_action -> { doorkeeper_authorize! :write, :'write:statuses' }, only: [:create, :update, :destroy] before_action -> { doorkeeper_authorize! :write, :'write:statuses' }, only: [:create, :update, :destroy]
before_action :require_user!, except: [:index, :show, :context] before_action :require_user!, except: [:show, :context]
before_action :set_statuses, only: [:index]
before_action :set_status, only: [:show, :context] before_action :set_status, only: [:show, :context]
before_action :set_thread, only: [:create] before_action :set_thread, only: [:create]
before_action :check_statuses_limit, only: [:index]
override_rate_limit_headers :create, family: :statuses override_rate_limit_headers :create, family: :statuses
override_rate_limit_headers :update, family: :statuses override_rate_limit_headers :update, family: :statuses
@ -25,14 +23,9 @@ class Api::V1::StatusesController < Api::BaseController
DESCENDANTS_LIMIT = 60 DESCENDANTS_LIMIT = 60
DESCENDANTS_DEPTH_LIMIT = 20 DESCENDANTS_DEPTH_LIMIT = 20
def index
@statuses = preload_collection(@statuses, Status)
render json: @statuses, each_serializer: REST::StatusSerializer
end
def show def show
cache_if_unauthenticated! cache_if_unauthenticated!
@status = preload_collection([@status], Status).first @status = cache_collection([@status], Status).first
render json: @status, serializer: REST::StatusSerializer render json: @status, serializer: REST::StatusSerializer
end end
@ -51,8 +44,8 @@ class Api::V1::StatusesController < Api::BaseController
ancestors_results = @status.in_reply_to_id.nil? ? [] : @status.ancestors(ancestors_limit, current_account) ancestors_results = @status.in_reply_to_id.nil? ? [] : @status.ancestors(ancestors_limit, current_account)
descendants_results = @status.descendants(descendants_limit, current_account, descendants_depth_limit) descendants_results = @status.descendants(descendants_limit, current_account, descendants_depth_limit)
loaded_ancestors = preload_collection(ancestors_results, Status) loaded_ancestors = cache_collection(ancestors_results, Status)
loaded_descendants = preload_collection(descendants_results, Status) loaded_descendants = cache_collection(descendants_results, Status)
@context = Context.new(ancestors: loaded_ancestors, descendants: loaded_descendants) @context = Context.new(ancestors: loaded_ancestors, descendants: loaded_descendants)
statuses = [@status] + @context.ancestors + @context.descendants statuses = [@status] + @context.ancestors + @context.descendants
@ -120,10 +113,6 @@ class Api::V1::StatusesController < Api::BaseController
private private
def set_statuses
@statuses = Status.permitted_statuses_from_ids(status_ids, current_account)
end
def set_status def set_status
@status = Status.find(params[:id]) @status = Status.find(params[:id])
authorize @status, :show? authorize @status, :show?
@ -138,18 +127,6 @@ class Api::V1::StatusesController < Api::BaseController
render json: { error: I18n.t('statuses.errors.in_reply_not_found') }, status: 404 render json: { error: I18n.t('statuses.errors.in_reply_not_found') }, status: 404
end end
def check_statuses_limit
raise(Mastodon::ValidationError) if status_ids.size > DEFAULT_STATUSES_LIMIT
end
def status_ids
Array(statuses_params[:ids]).uniq.map(&:to_i)
end
def statuses_params
params.permit(ids: [])
end
def status_params def status_params
params.permit( params.permit(
:status, :status,

View file

@ -5,8 +5,16 @@ class Api::V1::Timelines::BaseController < Api::BaseController
private private
def pagination_collection def insert_pagination_headers
@statuses set_pagination_headers(next_path, prev_path)
end
def pagination_max_id
@statuses.last.id
end
def pagination_since_id
@statuses.first.id
end end
def next_path_params def next_path_params

View file

@ -15,11 +15,11 @@ class Api::V1::Timelines::DirectController < Api::BaseController
private private
def load_statuses def load_statuses
preloaded_direct_statuses cached_direct_statuses
end end
def preloaded_direct_statuses def cached_direct_statuses
preload_collection direct_statuses, Status cache_collection direct_statuses, Status
end end
def direct_statuses def direct_statuses

View file

@ -21,11 +21,11 @@ class Api::V1::Timelines::HomeController < Api::V1::Timelines::BaseController
private private
def load_statuses def load_statuses
preloaded_home_statuses cached_home_statuses
end end
def preloaded_home_statuses def cached_home_statuses
preload_collection home_statuses, Status cache_collection home_statuses, Status
end end
def home_statuses def home_statuses

View file

@ -21,11 +21,11 @@ class Api::V1::Timelines::ListController < Api::V1::Timelines::BaseController
end end
def set_statuses def set_statuses
@statuses = preloaded_list_statuses @statuses = cached_list_statuses
end end
def preloaded_list_statuses def cached_list_statuses
preload_collection list_statuses, Status cache_collection list_statuses, Status
end end
def list_statuses def list_statuses

View file

@ -18,11 +18,11 @@ class Api::V1::Timelines::PublicController < Api::V1::Timelines::BaseController
end end
def load_statuses def load_statuses
preloaded_public_statuses_page cached_public_statuses_page
end end
def preloaded_public_statuses_page def cached_public_statuses_page
preload_collection(public_statuses, Status) cache_collection(public_statuses, Status)
end end
def public_statuses def public_statuses

View file

@ -23,11 +23,11 @@ class Api::V1::Timelines::TagController < Api::V1::Timelines::BaseController
end end
def load_statuses def load_statuses
preloaded_tagged_statuses cached_tagged_statuses
end end
def preloaded_tagged_statuses def cached_tagged_statuses
@tag.nil? ? [] : preload_collection(tag_timeline_statuses, Status) @tag.nil? ? [] : cache_collection(tag_timeline_statuses, Status)
end end
def tag_timeline_statuses def tag_timeline_statuses

View file

@ -34,6 +34,10 @@ class Api::V1::Trends::LinksController < Api::BaseController
scope scope
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:limit).permit(:limit).merge(core_params) params.slice(:limit).permit(:limit).merge(core_params)
end end

View file

@ -20,7 +20,7 @@ class Api::V1::Trends::StatusesController < Api::BaseController
def set_statuses def set_statuses
@statuses = if enabled? @statuses = if enabled?
preload_collection(statuses_from_trends.offset(offset_param).limit(limit_param(DEFAULT_STATUSES_LIMIT)), Status) cache_collection(statuses_from_trends.offset(offset_param).limit(limit_param(DEFAULT_STATUSES_LIMIT)), Status)
else else
[] []
end end
@ -32,6 +32,10 @@ class Api::V1::Trends::StatusesController < Api::BaseController
scope scope
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:limit).permit(:limit).merge(core_params) params.slice(:limit).permit(:limit).merge(core_params)
end end

View file

@ -30,6 +30,10 @@ class Api::V1::Trends::TagsController < Api::BaseController
Trends.tags.query.allowed Trends.tags.query.allowed
end end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def pagination_params(core_params) def pagination_params(core_params)
params.slice(:limit).permit(:limit).merge(core_params) params.slice(:limit).permit(:limit).merge(core_params)
end end

View file

@ -9,7 +9,6 @@ class ApplicationController < ActionController::Base
include UserTrackingConcern include UserTrackingConcern
include SessionTrackingConcern include SessionTrackingConcern
include CacheConcern include CacheConcern
include PreloadingConcern
include DomainControlHelper include DomainControlHelper
include ThemingConcern include ThemingConcern
include DatabaseHelper include DatabaseHelper
@ -20,7 +19,6 @@ class ApplicationController < ActionController::Base
helper_method :current_session helper_method :current_session
helper_method :current_flavour helper_method :current_flavour
helper_method :current_skin helper_method :current_skin
helper_method :current_theme
helper_method :single_user_mode? helper_method :single_user_mode?
helper_method :use_seamless_external_login? helper_method :use_seamless_external_login?
helper_method :omniauth_only? helper_method :omniauth_only?
@ -133,7 +131,7 @@ class ApplicationController < ActionController::Base
end end
def single_user_mode? def single_user_mode?
@single_user_mode ||= Rails.configuration.x.single_user_mode && Account.without_internal.exists? @single_user_mode ||= Rails.configuration.x.single_user_mode && Account.where('id > 0').exists?
end end
def use_seamless_external_login? def use_seamless_external_login?
@ -166,7 +164,10 @@ class ApplicationController < ActionController::Base
def respond_with_error(code) def respond_with_error(code)
respond_to do |format| respond_to do |format|
format.any { render "errors/#{code}", layout: 'error', status: code, formats: [:html] } format.any do
use_pack 'error'
render "errors/#{code}", layout: 'error', status: code, formats: [:html]
end
format.json { render json: { error: Rack::Utils::HTTP_STATUS_CODES[code] }, status: code } format.json { render json: { error: Rack::Utils::HTTP_STATUS_CODES[code] }, status: code }
end end
end end
@ -175,7 +176,10 @@ class ApplicationController < ActionController::Base
return unless self_destruct? return unless self_destruct?
respond_to do |format| respond_to do |format|
format.any { render 'errors/self_destruct', layout: 'auth', status: 410, formats: [:html] } format.any do
use_pack 'error'
render 'errors/self_destruct', layout: 'auth', status: 410, formats: [:html]
end
format.json { render json: { error: Rack::Utils::HTTP_STATUS_CODES[410] }, status: 410 } format.json { render json: { error: Rack::Utils::HTTP_STATUS_CODES[410] }, status: 410 }
end end
end end

View file

@ -5,6 +5,7 @@ class Auth::ChallengesController < ApplicationController
layout 'auth' layout 'auth'
before_action :set_pack
before_action :authenticate_user! before_action :authenticate_user!
skip_before_action :check_self_destruct! skip_before_action :check_self_destruct!
@ -20,4 +21,10 @@ class Auth::ChallengesController < ApplicationController
render_challenge render_challenge
end end
end end
private
def set_pack
use_pack 'auth'
end
end end

View file

@ -6,6 +6,7 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController
layout 'auth' layout 'auth'
before_action :set_body_classes before_action :set_body_classes
before_action :set_pack
before_action :set_confirmation_user!, only: [:show, :confirm_captcha] before_action :set_confirmation_user!, only: [:show, :confirm_captcha]
before_action :redirect_confirmed_user, if: :signed_in_confirmed_user? before_action :redirect_confirmed_user, if: :signed_in_confirmed_user?
@ -65,6 +66,10 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController
@confirmation_user.nil? || @confirmation_user.confirmed? @confirmation_user.nil? || @confirmation_user.confirmed?
end end
def set_pack
use_pack 'auth'
end
def redirect_confirmed_user def redirect_confirmed_user
redirect_to(current_user.approved? ? root_path : edit_user_registration_path) redirect_to(current_user.approved? ? root_path : edit_user_registration_path)
end end

View file

@ -3,6 +3,7 @@
class Auth::PasswordsController < Devise::PasswordsController class Auth::PasswordsController < Devise::PasswordsController
skip_before_action :check_self_destruct! skip_before_action :check_self_destruct!
before_action :redirect_invalid_reset_token, only: :edit, unless: :reset_password_token_is_valid? before_action :redirect_invalid_reset_token, only: :edit, unless: :reset_password_token_is_valid?
before_action :set_pack
before_action :set_body_classes before_action :set_body_classes
layout 'auth' layout 'auth'
@ -31,4 +32,8 @@ class Auth::PasswordsController < Devise::PasswordsController
def reset_password_token_is_valid? def reset_password_token_is_valid?
resource_class.with_reset_password_token(params[:reset_password_token]).present? resource_class.with_reset_password_token(params[:reset_password_token]).present?
end end
def set_pack
use_pack 'auth'
end
end end

View file

@ -9,6 +9,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
before_action :set_invite, only: [:new, :create] before_action :set_invite, only: [:new, :create]
before_action :check_enabled_registrations, only: [:new, :create] before_action :check_enabled_registrations, only: [:new, :create]
before_action :configure_sign_up_params, only: [:create] before_action :configure_sign_up_params, only: [:create]
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_strikes, only: [:edit, :update]
before_action :set_body_classes, only: [:new, :create, :edit, :update] before_action :set_body_classes, only: [:new, :create, :edit, :update]
@ -96,6 +97,10 @@ class Auth::RegistrationsController < Devise::RegistrationsController
private private
def set_pack
use_pack %w(edit update).include?(action_name) ? 'admin' : 'auth'
end
def set_body_classes def set_body_classes
@body_classes = %w(edit update).include?(action_name) ? 'admin' : 'lighter' @body_classes = %w(edit update).include?(action_name) ? 'admin' : 'lighter'
end end

View file

@ -12,6 +12,7 @@ class Auth::SessionsController < Devise::SessionsController
skip_before_action :require_functional! skip_before_action :require_functional!
skip_before_action :update_user_sign_in skip_before_action :update_user_sign_in
prepend_before_action :set_pack
prepend_before_action :check_suspicious!, only: [:create] prepend_before_action :check_suspicious!, only: [:create]
include Auth::TwoFactorAuthenticationConcern include Auth::TwoFactorAuthenticationConcern
@ -103,6 +104,10 @@ class Auth::SessionsController < Devise::SessionsController
private private
def set_pack
use_pack 'auth'
end
def set_body_classes def set_body_classes
@body_classes = 'lighter' @body_classes = 'lighter'
end end

View file

@ -3,6 +3,7 @@
class Auth::SetupController < ApplicationController class Auth::SetupController < ApplicationController
layout 'auth' layout 'auth'
before_action :set_pack
before_action :authenticate_user! before_action :authenticate_user!
before_action :require_unconfirmed_or_pending! before_action :require_unconfirmed_or_pending!
before_action :set_body_classes before_action :set_body_classes
@ -42,4 +43,8 @@ class Auth::SetupController < ApplicationController
def user_params def user_params
params.require(:user).permit(:email) params.require(:user).permit(:email)
end end
def set_pack
use_pack 'sign_up'
end
end end

View file

@ -1,52 +0,0 @@
# frozen_string_literal: true
module Api::ErrorHandling
extend ActiveSupport::Concern
included do
rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e|
render json: { error: e.to_s }, status: 422
end
rescue_from ActiveRecord::RecordNotUnique do
render json: { error: 'Duplicate record' }, status: 422
end
rescue_from Date::Error do
render json: { error: 'Invalid date supplied' }, status: 422
end
rescue_from ActiveRecord::RecordNotFound do
render json: { error: 'Record not found' }, status: 404
end
rescue_from HTTP::Error, Mastodon::UnexpectedResponseError do
render json: { error: 'Remote data could not be fetched' }, status: 503
end
rescue_from OpenSSL::SSL::SSLError do
render json: { error: 'Remote SSL certificate could not be verified' }, status: 503
end
rescue_from Mastodon::NotPermittedError do
render json: { error: 'This action is not allowed' }, status: 403
end
rescue_from Seahorse::Client::NetworkingError do |e|
Rails.logger.warn "Storage server error: #{e}"
render json: { error: 'There was a temporary problem serving your request, please try again' }, status: 503
end
rescue_from Mastodon::RaceConditionError, Stoplight::Error::RedLight do
render json: { error: 'There was a temporary problem serving your request, please try again' }, status: 503
end
rescue_from Mastodon::RateLimitExceededError do
render json: { error: I18n.t('errors.429') }, status: 429
end
rescue_from ActionController::ParameterMissing, Mastodon::InvalidParameterError do |e|
render json: { error: e.to_s }, status: 400
end
end
end

View file

@ -1,36 +0,0 @@
# frozen_string_literal: true
module Api::Pagination
extend ActiveSupport::Concern
protected
def pagination_max_id
pagination_collection.last.id
end
def pagination_since_id
pagination_collection.first.id
end
def set_pagination_headers(next_path = nil, prev_path = nil)
links = []
links << [next_path, [%w(rel next)]] if next_path
links << [prev_path, [%w(rel prev)]] if prev_path
response.headers['Link'] = LinkHeader.new(links) unless links.empty?
end
def require_valid_pagination_options!
render json: { error: 'Pagination values for `offset` and `limit` must be positive' }, status: 400 if pagination_options_invalid?
end
private
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def pagination_options_invalid?
params.slice(:limit, :offset).values.map(&:to_i).any?(&:negative?)
end
end

View file

@ -83,6 +83,8 @@ module Auth::TwoFactorAuthenticationConcern
def prompt_for_two_factor(user) def prompt_for_two_factor(user)
register_attempt_in_session(user) register_attempt_in_session(user)
use_pack 'auth'
@body_classes = 'lighter' @body_classes = 'lighter'
@webauthn_enabled = user.webauthn_enabled? @webauthn_enabled = user.webauthn_enabled?
@scheme_type = if user.webauthn_enabled? && user_params[:otp_attempt].blank? @scheme_type = if user.webauthn_enabled? && user_params[:otp_attempt].blank?

View file

@ -45,4 +45,28 @@ module CacheConcern
Rails.cache.write(key, response.body, expires_in: expires_in, raw: true) Rails.cache.write(key, response.body, expires_in: expires_in, raw: true)
end end
end end
def cache_collection(raw, klass)
return raw unless klass.respond_to?(:with_includes)
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
klass.reload_stale_associations!(cached_keys_with_value.values) if klass.respond_to?(:reload_stale_associations!)
unless uncached_ids.empty?
uncached = klass.where(id: uncached_ids).with_includes.index_by(&:id)
Rails.cache.write_multi(uncached.values.to_h { |i| [i, i] })
end
raw.filter_map { |item| cached_keys_with_value[item.id] || uncached[item.id] }
end
def cache_collection_paginated_by_id(raw, klass, limit, options)
cache_collection raw.cache_ids.to_a_paginated_by_id(limit, options), klass
end
end end

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