diff --git a/.github/workflows/build-container-image.yml b/.github/workflows/build-container-image.yml index a1aeddf20..532921b1f 100644 --- a/.github/workflows/build-container-image.yml +++ b/.github/workflows/build-container-image.yml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: docker/setup-qemu-action@v2 if: contains(inputs.platforms, 'linux/arm64') && !inputs.use_native_arm64_builder diff --git a/.github/workflows/build-push-pr.yml b/.github/workflows/build-push-pr.yml index b95e3c14e..1f647e2a1 100644 --- a/.github/workflows/build-push-pr.yml +++ b/.github/workflows/build-push-pr.yml @@ -18,7 +18,7 @@ jobs: steps: # Repository needs to be cloned so `git rev-parse` below works - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - id: version_vars run: | echo mastodon_version_metadata=pr-${{ github.event.pull_request.number }}-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT diff --git a/.github/workflows/bundler-audit.yml b/.github/workflows/bundler-audit.yml index 6c4869f12..bfb93a36c 100644 --- a/.github/workflows/bundler-audit.yml +++ b/.github/workflows/bundler-audit.yml @@ -25,7 +25,7 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install native Ruby dependencies run: sudo apt-get install -y libicu-dev libidn11-dev diff --git a/.github/workflows/check-i18n.yml b/.github/workflows/check-i18n.yml index b67c503e9..39cf32ddc 100644 --- a/.github/workflows/check-i18n.yml +++ b/.github/workflows/check-i18n.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install system dependencies run: | diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 8534501d4..3b40c3fd0 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -27,7 +27,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/crowdin-download.yml b/.github/workflows/crowdin-download.yml index f6b2579ce..e5385808d 100644 --- a/.github/workflows/crowdin-download.yml +++ b/.github/workflows/crowdin-download.yml @@ -14,7 +14,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Increase Git http.postBuffer # This is needed due to a bug in Ubuntu's cURL version? diff --git a/.github/workflows/crowdin-upload.yml b/.github/workflows/crowdin-upload.yml index 8bc9f5193..705af12c0 100644 --- a/.github/workflows/crowdin-upload.yml +++ b/.github/workflows/crowdin-upload.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: crowdin action uses: crowdin/github-action@v1 diff --git a/.github/workflows/lint-css.yml b/.github/workflows/lint-css.yml index 4d3c2ce5a..bd775dba2 100644 --- a/.github/workflows/lint-css.yml +++ b/.github/workflows/lint-css.yml @@ -33,7 +33,7 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v3 diff --git a/.github/workflows/lint-haml.yml b/.github/workflows/lint-haml.yml index 56d817123..ca9bd66a4 100644 --- a/.github/workflows/lint-haml.yml +++ b/.github/workflows/lint-haml.yml @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install native Ruby dependencies run: | diff --git a/.github/workflows/lint-js.yml b/.github/workflows/lint-js.yml index 1f0cfd1e7..67d28589c 100644 --- a/.github/workflows/lint-js.yml +++ b/.github/workflows/lint-js.yml @@ -37,7 +37,7 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v3 diff --git a/.github/workflows/lint-json.yml b/.github/workflows/lint-json.yml index 8712d8bd8..1d98c5267 100644 --- a/.github/workflows/lint-json.yml +++ b/.github/workflows/lint-json.yml @@ -29,7 +29,7 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v3 diff --git a/.github/workflows/lint-md.yml b/.github/workflows/lint-md.yml index d19a0470d..1b3f92c97 100644 --- a/.github/workflows/lint-md.yml +++ b/.github/workflows/lint-md.yml @@ -29,7 +29,7 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v3 diff --git a/.github/workflows/lint-ruby.yml b/.github/workflows/lint-ruby.yml index c898b2632..92882a084 100644 --- a/.github/workflows/lint-ruby.yml +++ b/.github/workflows/lint-ruby.yml @@ -29,7 +29,7 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install native Ruby dependencies run: sudo apt-get install -y libicu-dev libidn11-dev diff --git a/.github/workflows/lint-yml.yml b/.github/workflows/lint-yml.yml index 295e9610b..e77cc9889 100644 --- a/.github/workflows/lint-yml.yml +++ b/.github/workflows/lint-yml.yml @@ -31,7 +31,7 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v3 diff --git a/.github/workflows/test-js.yml b/.github/workflows/test-js.yml index 3306105f9..0ef1d9b7c 100644 --- a/.github/workflows/test-js.yml +++ b/.github/workflows/test-js.yml @@ -33,7 +33,7 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v3 diff --git a/.github/workflows/test-migrations-one-step.yml b/.github/workflows/test-migrations-one-step.yml index a91fd819a..59287e88c 100644 --- a/.github/workflows/test-migrations-one-step.yml +++ b/.github/workflows/test-migrations-one-step.yml @@ -70,7 +70,7 @@ jobs: BUNDLE_RETRY: 3 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install native Ruby dependencies run: | diff --git a/.github/workflows/test-migrations-two-step.yml b/.github/workflows/test-migrations-two-step.yml index 50266fb8a..8f3c84d8f 100644 --- a/.github/workflows/test-migrations-two-step.yml +++ b/.github/workflows/test-migrations-two-step.yml @@ -69,7 +69,7 @@ jobs: BUNDLE_RETRY: 3 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install native Ruby dependencies run: | diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml index ff135867f..343dc36ca 100644 --- a/.github/workflows/test-ruby.yml +++ b/.github/workflows/test-ruby.yml @@ -32,7 +32,7 @@ jobs: SECRET_KEY_BASE: precompile_placeholder steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v3 @@ -127,7 +127,7 @@ jobs: - 3 - 4 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/download-artifact@v3 with: @@ -202,7 +202,7 @@ jobs: - '.ruby-version' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/download-artifact@v3 with: @@ -250,3 +250,116 @@ jobs: with: name: e2e-screenshots path: tmp/screenshots/ + + test-search: + name: Testing search + runs-on: ubuntu-latest + + needs: + - build + + services: + postgres: + image: postgres:14-alpine + env: + POSTGRES_PASSWORD: postgres + POSTGRES_USER: postgres + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + + redis: + image: redis:7-alpine + options: >- + --health-cmd "redis-cli ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 6379:6379 + + elasticsearch: + image: docker.elastic.co/elasticsearch/elasticsearch:7.17.13 + env: + discovery.type: single-node + xpack.security.enabled: false + options: >- + --health-cmd "curl http://localhost:9200/_cluster/health" + --health-interval 10s + --health-timeout 5s + --health-retries 10 + ports: + - 9200:9200 + + env: + DB_HOST: localhost + DB_USER: postgres + DB_PASS: postgres + DISABLE_SIMPLECOV: true + RAILS_ENV: test + BUNDLE_WITH: test + ES_ENABLED: true + ES_HOST: localhost + ES_PORT: 9200 + + strategy: + fail-fast: false + matrix: + ruby-version: + - '3.0' + - '3.1' + - '.ruby-version' + + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v3 + with: + path: './public' + name: ${{ github.sha }} + + - name: Update package index + run: sudo apt-get update + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + cache: yarn + node-version-file: '.nvmrc' + + - name: Install native Ruby dependencies + run: sudo apt-get install -y libicu-dev libidn11-dev + + - name: Install additional system dependencies + run: sudo apt-get install -y ffmpeg imagemagick + + - name: Set up bundler cache + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby-version}} + bundler-cache: true + + - run: yarn --frozen-lockfile + + - name: Load database schema + run: './bin/rails db:create db:schema:load db:seed' + + - run: bundle exec rake spec:search + + - name: Archive logs + uses: actions/upload-artifact@v3 + if: failure() + with: + name: test-search-logs-${{ matrix.ruby-version }} + path: log/ + + - name: Archive test screenshots + uses: actions/upload-artifact@v3 + if: failure() + with: + name: test-search-screenshots + path: tmp/screenshots/ diff --git a/.nvmrc b/.nvmrc index 59ea99ee6..541b047dd 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -16.20 +20.6 diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 945d7514a..adfd47689 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -37,7 +37,7 @@ Layout/HashAlignment: Layout/LeadingCommentSpace: Exclude: - 'config/application.rb' - - 'config/initializers/omniauth.rb' + - 'config/initializers/3_omniauth.rb' # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: Max, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns. @@ -86,7 +86,7 @@ Lint/UnusedBlockArgument: Lint/UselessAssignment: Exclude: - 'app/services/activitypub/process_status_update_service.rb' - - 'config/initializers/omniauth.rb' + - 'config/initializers/3_omniauth.rb' - 'db/migrate/20190511134027_add_silenced_at_suspended_at_to_accounts.rb' - 'db/post_migrate/20190511152737_remove_suspended_silenced_account_fields.rb' - 'spec/controllers/api/v1/favourites_controller_spec.rb' @@ -573,11 +573,11 @@ Style/FetchEnvVar: - 'config/environments/development.rb' - 'config/environments/production.rb' - 'config/initializers/2_limited_federation_mode.rb' + - 'config/initializers/3_omniauth.rb' - 'config/initializers/blacklists.rb' - 'config/initializers/cache_buster.rb' - 'config/initializers/content_security_policy.rb' - 'config/initializers/devise.rb' - - 'config/initializers/omniauth.rb' - 'config/initializers/paperclip.rb' - 'config/initializers/vapid.rb' - 'lib/mastodon/premailer_webpack_strategy.rb' @@ -811,7 +811,7 @@ Style/StringLiterals: # AllowedMethods: define_method, mail, respond_to Style/SymbolProc: Exclude: - - 'config/initializers/omniauth.rb' + - 'config/initializers/3_omniauth.rb' # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: EnforcedStyle, AllowSafeAssignment. diff --git a/CHANGELOG.md b/CHANGELOG.md index d7cb1ede3..37116f738 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ The following changelog entries focus on changes visible to users, administrator ### Added -- **Add full-text search of opted-in public posts and rework search operators** ([Gargron](https://github.com/mastodon/mastodon/pull/26485), [jsgoldstein](https://github.com/mastodon/mastodon/pull/26344), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26657), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26650), [jsgoldstein](https://github.com/mastodon/mastodon/pull/26659), [Gargron](https://github.com/mastodon/mastodon/pull/26660), [Gargron](https://github.com/mastodon/mastodon/pull/26663), [Gargron](https://github.com/mastodon/mastodon/pull/26688), [Gargron](https://github.com/mastodon/mastodon/pull/26689), [Gargron](https://github.com/mastodon/mastodon/pull/26686), [Gargron](https://github.com/mastodon/mastodon/pull/26687), [Gargron](https://github.com/mastodon/mastodon/pull/26692), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26697), [Gargron](https://github.com/mastodon/mastodon/pull/26699), [Gargron](https://github.com/mastodon/mastodon/pull/26701), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26710), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26739), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26754), [Gargron](https://github.com/mastodon/mastodon/pull/26662), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26755), [Gargron](https://github.com/mastodon/mastodon/pull/26781), [Gargron](https://github.com/mastodon/mastodon/pull/26782), [Gargron](https://github.com/mastodon/mastodon/pull/26760)) +- **Add full-text search of opted-in public posts and rework search operators** ([Gargron](https://github.com/mastodon/mastodon/pull/26485), [jsgoldstein](https://github.com/mastodon/mastodon/pull/26344), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26657), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26650), [jsgoldstein](https://github.com/mastodon/mastodon/pull/26659), [Gargron](https://github.com/mastodon/mastodon/pull/26660), [Gargron](https://github.com/mastodon/mastodon/pull/26663), [Gargron](https://github.com/mastodon/mastodon/pull/26688), [Gargron](https://github.com/mastodon/mastodon/pull/26689), [Gargron](https://github.com/mastodon/mastodon/pull/26686), [Gargron](https://github.com/mastodon/mastodon/pull/26687), [Gargron](https://github.com/mastodon/mastodon/pull/26692), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26697), [Gargron](https://github.com/mastodon/mastodon/pull/26699), [Gargron](https://github.com/mastodon/mastodon/pull/26701), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26710), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26739), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26754), [Gargron](https://github.com/mastodon/mastodon/pull/26662), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26755), [Gargron](https://github.com/mastodon/mastodon/pull/26781), [Gargron](https://github.com/mastodon/mastodon/pull/26782), [Gargron](https://github.com/mastodon/mastodon/pull/26760), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26756), [Gargron](https://github.com/mastodon/mastodon/pull/26784), [Gargron](https://github.com/mastodon/mastodon/pull/26807), [Gargron](https://github.com/mastodon/mastodon/pull/26835), [Gargron](https://github.com/mastodon/mastodon/pull/26847), [Gargron](https://github.com/mastodon/mastodon/pull/26834), [arbolitoloco1](https://github.com/mastodon/mastodon/pull/26893), [tribela](https://github.com/mastodon/mastodon/pull/26896)) This introduces a new `public_statuses` Elasticsearch index for public posts by users who have opted in to their posts being searchable (`toot#indexable` flag). This also revisits the other indexes to provide more useful indexing, and adds new search operators such as `from:me`, `before:2022-11-01`, `after:2022-11-01`, `during:2022-11-01`, `language:fr`, `has:poll`, or `in:library` (for searching only in posts you have written or interacted with). Results are now ordered chronologically. @@ -24,7 +24,7 @@ The following changelog entries focus on changes visible to users, administrator The `forward` parameter still needs to be set for `forward_to_domains` to be taken into account. The forwarded-to domains can only include that of the original author and people being replied to. - **Add forwarding of reported replies to servers being replied to** ([Gargron](https://github.com/mastodon/mastodon/pull/25341), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26189)) -- Add direct link to the Single-Sign On provider if there is only one sign up method available ([CSDUMMI](https://github.com/mastodon/mastodon/pull/26083), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26368)) +- Add `ONE_CLICK_SSO_LOGIN` environment variable to directly link to the Single-Sign On provider if there is only one sign up method available ([CSDUMMI](https://github.com/mastodon/mastodon/pull/26083), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26368), [CSDUMMI](https://github.com/mastodon/mastodon/pull/26857), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26901)) - **Add webhook templating** ([Gargron](https://github.com/mastodon/mastodon/pull/23289)) - **Add webhooks for local `status.created`, `status.updated`, `account.updated` and `report.updated`** ([VyrCossont](https://github.com/mastodon/mastodon/pull/24133), [VyrCossont](https://github.com/mastodon/mastodon/pull/24243), [VyrCossont](https://github.com/mastodon/mastodon/pull/24211)) - **Add exclusive lists** ([dariusk](https://github.com/mastodon/mastodon/pull/22048), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/25324)) @@ -36,9 +36,12 @@ The following changelog entries focus on changes visible to users, administrator - **Add `S3_DISABLE_CHECKSUM_MODE` environment variable for compatibility with some S3-compatible providers** ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26435)) - **Add auto-refresh of accounts we get new messages/edits of** ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26510)) - **Add Elasticsearch cluster health check and indexes mismatch check to dashboard** ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26448), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26605), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26658)) +- Add admin API for managing tags ([rrgeorge](https://github.com/mastodon/mastodon/pull/26872)) +- Add a link to hashtag timelines from the Trending hashtags moderation interface ([gunchleoc](https://github.com/mastodon/mastodon/pull/26724)) +- Add timezone to datetimes in e-mails ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26822)) - Add `authorized_fetch` server setting in addition to env var ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/25798)) - Add avatar image to webfinger responses ([tvler](https://github.com/mastodon/mastodon/pull/26558)) -- Add debug logging on signature verification failure ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26637)) +- Add debug logging on signature verification failure ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26637), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26812)) - Add explicit error messages when DeepL quota is exceeded ([lutoma](https://github.com/mastodon/mastodon/pull/26704)) - Add Elasticsearch/OpenSearch version to “Software” in admin dashboard ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26652)) - Add `data-nosnippet` attribute to remote posts and local posts with `noindex` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26648)) @@ -47,7 +50,6 @@ The following changelog entries focus on changes visible to users, administrator - Add `DELETE /api/v1/profile/avatar` and `DELETE /api/v1/profile/header` to the REST API ([danielmbrasil](https://github.com/mastodon/mastodon/pull/25124), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26573)) - Add `ES_PRESET` option to customize numbers of shards and replicas ([Gargron](https://github.com/mastodon/mastodon/pull/26483), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26489)) This can have a value of `single_node_cluster` (default), `small_cluster` (uses one replica) or `large_cluster` (uses one replica and a higher number of shards). -- Add missing `instances` option to `tootctl search deploy` ([tribela](https://github.com/mastodon/mastodon/pull/26461)) - Add `CACHE_BUSTER_HTTP_METHOD` environment variable ([renchap](https://github.com/mastodon/mastodon/pull/26528), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26542)) - Add support for `DB_PASS` when using `DATABASE_URL` ([ThisIsMissEm](https://github.com/mastodon/mastodon/pull/26295)) - Add `GET /api/v1/instance/languages` to REST API ([danielmbrasil](https://github.com/mastodon/mastodon/pull/24443)) @@ -64,7 +66,7 @@ The following changelog entries focus on changes visible to users, administrator - Add users index on `unconfirmed_email` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/25672), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/25702)) - Add superapp index on `oauth_applications` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/25670)) - Add index to backups on `user_id` column ([mjankowski](https://github.com/mastodon/mastodon/pull/25647)) -- Add onboarding prompt when home feed too slow in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/25267), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/25556), [Gargron](https://github.com/mastodon/mastodon/pull/25579), [renchap](https://github.com/mastodon/mastodon/pull/25580), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/25581), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/25617), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/25917)) +- Add onboarding prompt when home feed too slow in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/25267), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/25556), [Gargron](https://github.com/mastodon/mastodon/pull/25579), [renchap](https://github.com/mastodon/mastodon/pull/25580), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/25581), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/25617), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/25917), [Gargron](https://github.com/mastodon/mastodon/pull/26829)) - Add `POST /api/v1/conversations/:id/unread` API endpoint to mark a conversation as unread ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/25509)) - Add `translate="no"` to outgoing mentions and links ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/25524)) - Add unsubscribe link and headers to e-mails ([Gargron](https://github.com/mastodon/mastodon/pull/25378), [c960657](https://github.com/mastodon/mastodon/pull/26085)) @@ -109,7 +111,7 @@ The following changelog entries focus on changes visible to users, administrator - **Change hashtags to be displayed separately when they are the last line of a post** ([renchap](https://github.com/mastodon/mastodon/pull/26499), [renchap](https://github.com/mastodon/mastodon/pull/26614), [renchap](https://github.com/mastodon/mastodon/pull/26615)) - **Change reblogs to be excluded from "Posts and replies" tab in web UI** ([Gargron](https://github.com/mastodon/mastodon/pull/26302)) -- **Change interaction modal in web interface** ([Gargron, ClearlyClaire](https://github.com/mastodon/mastodon/pull/26075), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26269), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26268), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26267), [mgmn](https://github.com/mastodon/mastodon/pull/26459), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26593)) +- **Change interaction modal in web interface** ([Gargron, ClearlyClaire](https://github.com/mastodon/mastodon/pull/26075), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26269), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26268), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26267), [mgmn](https://github.com/mastodon/mastodon/pull/26459), [tribela](https://github.com/mastodon/mastodon/pull/26461), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26593), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26795)) - **Change design of link previews in web UI** ([Gargron](https://github.com/mastodon/mastodon/pull/26136), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26151), [Gargron](https://github.com/mastodon/mastodon/pull/26153), [Gargron](https://github.com/mastodon/mastodon/pull/26250), [Gargron](https://github.com/mastodon/mastodon/pull/26287), [Gargron](https://github.com/mastodon/mastodon/pull/26286), [c960657](https://github.com/mastodon/mastodon/pull/26184)) - **Change "direct message" nomenclature to "private mention" in web UI** ([Gargron](https://github.com/mastodon/mastodon/pull/24248)) - **Change translation feature to cover Content Warnings, poll options and media descriptions** ([c960657](https://github.com/mastodon/mastodon/pull/24175), [S-H-GAMELINKS](https://github.com/mastodon/mastodon/pull/25251), [c960657](https://github.com/mastodon/mastodon/pull/26168), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26452)) @@ -122,9 +124,10 @@ The following changelog entries focus on changes visible to users, administrator This deprecates `statsd` support and disables the sidekiq integration unless `STATSD_SIDEKIQ` is set to `true`. This is because the `nsa` gem is unmaintained, and its sidekiq integration is known to add very significant overhead. Later versions of Mastodon will have other ways to get the same metrics. -- **Change replica support to native Rails adapter** ([krainboltgreene](https://github.com/mastodon/mastodon/pull/25693), [Gargron](https://github.com/mastodon/mastodon/pull/25849), [Gargron](https://github.com/mastodon/mastodon/pull/25874), [Gargron](https://github.com/mastodon/mastodon/pull/25851), [Gargron](https://github.com/mastodon/mastodon/pull/25977), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26074), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26326), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26386)) +- **Change replica support to native Rails adapter** ([krainboltgreene](https://github.com/mastodon/mastodon/pull/25693), [Gargron](https://github.com/mastodon/mastodon/pull/25849), [Gargron](https://github.com/mastodon/mastodon/pull/25874), [Gargron](https://github.com/mastodon/mastodon/pull/25851), [Gargron](https://github.com/mastodon/mastodon/pull/25977), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26074), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26326), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26386), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26856)) This is a breaking change, dropping `makara` support, and requiring you to update your database configuration if you are using replicas. To tell Mastodon to use a read replica, you can either set the `REPLICA_DB_NAME` environment variable (along with `REPLICA_DB_USER`, `REPLICA_DB_PASS`, `REPLICA_DB_HOST`, and `REPLICA_DB_PORT`, if they differ from the primary database), or the `REPLICA_DATABASE_URL` environment variable if your configuration is based on `DATABASE_URL`. +- Change DCT method used for JPEG encoding to float ([electroCutie](https://github.com/mastodon/mastodon/pull/26675)) - Change from `node-redis` to `ioredis` for streaming ([gmemstr](https://github.com/mastodon/mastodon/pull/26581)) - Change private statuses index to index without crutches ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26713)) - Change video compression parameters ([Gargron](https://github.com/mastodon/mastodon/pull/26631), [Gargron](https://github.com/mastodon/mastodon/pull/26745), [Gargron](https://github.com/mastodon/mastodon/pull/26766)) @@ -161,7 +164,7 @@ The following changelog entries focus on changes visible to users, administrator - Change vacuum scheduler to also delete expired tokens and unused application records ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/24868), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/24871)) - Change "Sign in" to "Login" ([Gargron](https://github.com/mastodon/mastodon/pull/24942)) - Change domain suspensions to also be checked before trying to fetch unknown remote resources ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/24535)) -- Change media components to use aspect-ratio rather than compute height themselves ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/24686), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/24943)) +- Change media components to use aspect-ratio rather than compute height themselves ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/24686), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/24943), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26801)) - Change logo version in header based on screen size in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/24707)) - Change label from "For you" to "People" on explore screen in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/24706)) - Change logged-out WebUI HTML pages to be cached for a few seconds ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/24708)) @@ -172,7 +175,7 @@ The following changelog entries focus on changes visible to users, administrator - Change account search in moderation interface to allow searching by username including the leading `@` ([HeitorMC](https://github.com/mastodon/mastodon/pull/24242)) - Change all components to use the same error page in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/24512)) - Change search pop-out in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/24305)) -- Change user settings to be stored in a more optimal way ([Gargron](https://github.com/mastodon/mastodon/pull/23630), [c960657](https://github.com/mastodon/mastodon/pull/24321), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/24453), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/24460), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/24558), [Gargron](https://github.com/mastodon/mastodon/pull/24761), [Gargron](https://github.com/mastodon/mastodon/pull/24783), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/25508), [jsgoldstein](https://github.com/mastodon/mastodon/pull/25340)) +- Change user settings to be stored in a more optimal way ([Gargron](https://github.com/mastodon/mastodon/pull/23630), [c960657](https://github.com/mastodon/mastodon/pull/24321), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/24453), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/24460), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/24558), [Gargron](https://github.com/mastodon/mastodon/pull/24761), [Gargron](https://github.com/mastodon/mastodon/pull/24783), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/25508), [jsgoldstein](https://github.com/mastodon/mastodon/pull/25340), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26884)) - Change media upload limits and remove client-side resizing ([Gargron](https://github.com/mastodon/mastodon/pull/23726)) - Change design of account rows in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/24247), [Gargron](https://github.com/mastodon/mastodon/pull/24343), [Gargron](https://github.com/mastodon/mastodon/pull/24956), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/25131)) - Change log-out to use Single Logout when using external log-in through OIDC ([CSDUMMI](https://github.com/mastodon/mastodon/pull/24020)) @@ -195,6 +198,7 @@ The following changelog entries focus on changes visible to users, administrator - **Remove support for Ruby 2.7** ([nschonni](https://github.com/mastodon/mastodon/pull/24237)) - **Remove clustering from streaming API** ([ThisIsMissEm](https://github.com/mastodon/mastodon/pull/24655)) - **Remove anonymous access to the streaming API** ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/23989)) +- Remove obfuscation of reply count in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/26768)) - Remove `kmr` from language selection, as it was a duplicate for `ku` ([gunchleoc](https://github.com/mastodon/mastodon/pull/26014), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26787)) - Remove 16:9 cropping from web UI ([Gargron](https://github.com/mastodon/mastodon/pull/26132)) - Remove back button from bookmarks, favourites and lists screens in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/26126)) @@ -211,6 +215,14 @@ The following changelog entries focus on changes visible to users, administrator - **Fix broken links in account gallery** ([c960657](https://github.com/mastodon/mastodon/pull/24218)) - **Fix blocking subdomains of an already-blocked domain** ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26392)) - **Fix migration handler not updating lists** ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/24808)) +- Fix paragraph margins resulting in irregular read-more cut-off in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/26828)) +- Fix notification permissions being requested immediately after login ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26472)) +- Fix performances of profile directory ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26840), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26842)) +- Fix mute button and volume slider feeling disconnected in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/26827), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/26860)) +- Fix “Scoped order is ignored, it's forced to be batch order.” warnings ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26793)) +- Fix blocked domain appearing in account feeds ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26823)) +- Fix moderator rights inconsistencies ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26729)) +- Fix crash when encountering invalid URL ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26814)) - Fix invalid `Content-Type` header for WebP images ([c960657](https://github.com/mastodon/mastodon/pull/26773)) - Fix minor inefficiencies in `tootctl search deploy` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26721)) - Fix filter form in profiles directory overflowing instead of wrapping ([arbolitoloco1](https://github.com/mastodon/mastodon/pull/26682)) diff --git a/Dockerfile b/Dockerfile index cdabc4c7c..3fe4a62bd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1.4 -# This needs to be bullseye-slim because the Ruby image is built on bullseye-slim -ARG NODE_VERSION="16.20-bullseye-slim" +# This needs to be bookworm-slim because the Ruby image is built on bookworm-slim +ARG NODE_VERSION="20.6-bookworm-slim" FROM ghcr.io/moritzheiber/ruby-jemalloc:3.2.2-slim as ruby FROM node:${NODE_VERSION} as build @@ -20,7 +20,7 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends build-essential \ git \ libicu-dev \ - libidn11-dev \ + libidn-dev \ libpq-dev \ libjemalloc-dev \ zlib1g-dev \ @@ -64,13 +64,13 @@ RUN apt-get update && \ apt-get -y --no-install-recommends install whois \ wget \ procps \ - libssl1.1 \ + libssl3 \ libpq5 \ imagemagick \ ffmpeg \ libjemalloc2 \ - libicu67 \ - libidn11 \ + libicu72 \ + libidn12 \ libyaml-0-2 \ file \ ca-certificates \ diff --git a/FEDERATION.md b/FEDERATION.md index cd1957cbd..e3721d724 100644 --- a/FEDERATION.md +++ b/FEDERATION.md @@ -27,4 +27,5 @@ More information on HTTP Signatures, as well as examples, can be found here: htt - Linked-Data Signatures: https://docs.joinmastodon.org/spec/security/#ld - Bearcaps: https://docs.joinmastodon.org/spec/bearcaps/ -- Followers collection synchronization: https://git.activitypub.dev/ActivityPubDev/Fediverse-Enhancement-Proposals/src/branch/main/feps/fep-8fcf.md +- Followers collection synchronization: https://codeberg.org/fediverse/fep/src/branch/main/fep/8fcf/fep-8fcf.md +- Search indexing consent for actors: https://codeberg.org/fediverse/fep/src/branch/main/fep/5feb/fep-5feb.md diff --git a/Gemfile.lock b/Gemfile.lock index 642be3f9a..13bca58a5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -39,47 +39,47 @@ GIT GEM remote: https://rubygems.org/ specs: - actioncable (7.0.7.2) - actionpack (= 7.0.7.2) - activesupport (= 7.0.7.2) + actioncable (7.0.8) + actionpack (= 7.0.8) + activesupport (= 7.0.8) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (7.0.7.2) - actionpack (= 7.0.7.2) - activejob (= 7.0.7.2) - activerecord (= 7.0.7.2) - activestorage (= 7.0.7.2) - activesupport (= 7.0.7.2) + actionmailbox (7.0.8) + actionpack (= 7.0.8) + activejob (= 7.0.8) + activerecord (= 7.0.8) + activestorage (= 7.0.8) + activesupport (= 7.0.8) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.0.7.2) - actionpack (= 7.0.7.2) - actionview (= 7.0.7.2) - activejob (= 7.0.7.2) - activesupport (= 7.0.7.2) + actionmailer (7.0.8) + actionpack (= 7.0.8) + actionview (= 7.0.8) + activejob (= 7.0.8) + activesupport (= 7.0.8) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp rails-dom-testing (~> 2.0) - actionpack (7.0.7.2) - actionview (= 7.0.7.2) - activesupport (= 7.0.7.2) + actionpack (7.0.8) + actionview (= 7.0.8) + activesupport (= 7.0.8) rack (~> 2.0, >= 2.2.4) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (7.0.7.2) - actionpack (= 7.0.7.2) - activerecord (= 7.0.7.2) - activestorage (= 7.0.7.2) - activesupport (= 7.0.7.2) + actiontext (7.0.8) + actionpack (= 7.0.8) + activerecord (= 7.0.8) + activestorage (= 7.0.8) + activesupport (= 7.0.8) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.0.7.2) - activesupport (= 7.0.7.2) + actionview (7.0.8) + activesupport (= 7.0.8) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) @@ -89,22 +89,22 @@ GEM activemodel (>= 4.1, < 7.1) case_transform (>= 0.2) jsonapi-renderer (>= 0.1.1.beta1, < 0.3) - activejob (7.0.7.2) - activesupport (= 7.0.7.2) + activejob (7.0.8) + activesupport (= 7.0.8) globalid (>= 0.3.6) - activemodel (7.0.7.2) - activesupport (= 7.0.7.2) - activerecord (7.0.7.2) - activemodel (= 7.0.7.2) - activesupport (= 7.0.7.2) - activestorage (7.0.7.2) - actionpack (= 7.0.7.2) - activejob (= 7.0.7.2) - activerecord (= 7.0.7.2) - activesupport (= 7.0.7.2) + activemodel (7.0.8) + activesupport (= 7.0.8) + activerecord (7.0.8) + activemodel (= 7.0.8) + activesupport (= 7.0.8) + activestorage (7.0.8) + actionpack (= 7.0.8) + activejob (= 7.0.8) + activerecord (= 7.0.8) + activesupport (= 7.0.8) marcel (~> 1.0) mini_mime (>= 1.1.0) - activesupport (7.0.7.2) + activesupport (7.0.8) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) @@ -409,7 +409,7 @@ GEM activerecord kaminari-core (= 1.2.2) kaminari-core (1.2.2) - kt-paperclip (7.2.0) + kt-paperclip (7.2.1) activemodel (>= 4.2.0) activesupport (>= 4.2.0) marcel (~> 1.0.1) @@ -520,7 +520,7 @@ GEM pastel (0.8.0) tty-color (~> 0.5) pg (1.5.4) - pghero (3.3.3) + pghero (3.3.4) activerecord (>= 6) posix-spawn (0.3.15) premailer (1.21.0) @@ -556,20 +556,20 @@ GEM rack rack-test (2.1.0) rack (>= 1.3) - rails (7.0.7.2) - actioncable (= 7.0.7.2) - actionmailbox (= 7.0.7.2) - actionmailer (= 7.0.7.2) - actionpack (= 7.0.7.2) - actiontext (= 7.0.7.2) - actionview (= 7.0.7.2) - activejob (= 7.0.7.2) - activemodel (= 7.0.7.2) - activerecord (= 7.0.7.2) - activestorage (= 7.0.7.2) - activesupport (= 7.0.7.2) + rails (7.0.8) + actioncable (= 7.0.8) + actionmailbox (= 7.0.8) + actionmailer (= 7.0.8) + actionpack (= 7.0.8) + actiontext (= 7.0.8) + actionview (= 7.0.8) + activejob (= 7.0.8) + activemodel (= 7.0.8) + activerecord (= 7.0.8) + activestorage (= 7.0.8) + activesupport (= 7.0.8) bundler (>= 1.15.0) - railties (= 7.0.7.2) + railties (= 7.0.8) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) @@ -584,9 +584,9 @@ GEM rails-i18n (7.0.7) i18n (>= 0.7, < 2) railties (>= 6.0.0, < 8) - railties (7.0.7.2) - actionpack (= 7.0.7.2) - activesupport (= 7.0.7.2) + railties (7.0.8) + actionpack (= 7.0.8) + activesupport (= 7.0.8) method_source rake (>= 12.2) thor (~> 1.0) @@ -640,7 +640,7 @@ GEM sidekiq (>= 5, < 8) rspec-support (3.12.1) rspec_chunked (0.6) - rubocop (1.56.2) + rubocop (1.56.3) base64 (~> 0.1.1) json (~> 2.3) language_server-protocol (>= 3.17.0) @@ -745,7 +745,7 @@ GEM unicode-display_width (>= 1.1.1, < 3) terrapin (0.6.0) climate_control (>= 0.0.3, < 1.0) - test-prof (1.2.2) + test-prof (1.2.3) thor (1.2.2) tilt (2.2.0) timeout (0.4.0) diff --git a/SECURITY.md b/SECURITY.md index 7a79d9f91..9a08c4e25 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -13,9 +13,9 @@ A "vulnerability in Mastodon" is a vulnerability in the code distributed through ## Supported Versions -| Version | Supported | -| ------- | --------- | -| 4.1.x | Yes | -| 4.0.x | Yes | -| 3.5.x | Yes | -| < 3.5 | No | +| Version | Supported | +| ------- | ---------------- | +| 4.1.x | Yes | +| 4.0.x | Until 2023-10-31 | +| 3.5.x | Until 2023-12-31 | +| < 3.5 | No | diff --git a/Vagrantfile b/Vagrantfile index 1117d62ff..4303f8e06 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -76,7 +76,8 @@ path.logs: /var/log/elasticsearch network.host: 0.0.0.0 http.port: 9200 discovery.seed_hosts: ["localhost"] -cluster.initial_master_nodes: ["node-1"]' > /etc/elasticsearch/elasticsearch.yml +cluster.initial_master_nodes: ["node-1"] +xpack.security.enabled: false' > /etc/elasticsearch/elasticsearch.yml sudo systemctl restart elasticsearch diff --git a/app/controllers/api/v1/admin/tags_controller.rb b/app/controllers/api/v1/admin/tags_controller.rb new file mode 100644 index 000000000..6a7c9f5bf --- /dev/null +++ b/app/controllers/api/v1/admin/tags_controller.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +class Api::V1::Admin::TagsController < Api::BaseController + include Authorization + before_action -> { authorize_if_got_token! :'admin:read' }, only: [:index, :show] + before_action -> { authorize_if_got_token! :'admin:write' }, only: :update + + before_action :set_tags, only: :index + before_action :set_tag, except: :index + + after_action :insert_pagination_headers, only: :index + after_action :verify_authorized + + LIMIT = 100 + PAGINATION_PARAMS = %i(limit).freeze + + def index + authorize :tag, :index? + render json: @tags, each_serializer: REST::Admin::TagSerializer + end + + def show + authorize @tag, :show? + render json: @tag, serializer: REST::Admin::TagSerializer + end + + def update + authorize @tag, :update? + @tag.update!(tag_params.merge(reviewed_at: Time.now.utc)) + render json: @tag, serializer: REST::Admin::TagSerializer + end + + private + + def set_tag + @tag = Tag.find(params[:id]) + end + + def set_tags + @tags = Tag.all.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id)) + end + + def tag_params + params.permit(:display_name, :trendable, :usable, :listable) + end + + def insert_pagination_headers + set_pagination_headers(next_path, prev_path) + end + + def next_path + api_v1_admin_tags_url(pagination_params(max_id: pagination_max_id)) if records_continue? + end + + def prev_path + api_v1_admin_tags_url(pagination_params(min_id: pagination_since_id)) unless @tags.empty? + end + + def pagination_max_id + @tags.last.id + end + + def pagination_since_id + @tags.first.id + end + + def records_continue? + @tags.size == limit_param(LIMIT) + end + + def pagination_params(core_params) + params.slice(*PAGINATION_PARAMS).permit(*PAGINATION_PARAMS).merge(core_params) + end +end diff --git a/app/controllers/api/v1/directories_controller.rb b/app/controllers/api/v1/directories_controller.rb index 110943550..35c504a7f 100644 --- a/app/controllers/api/v1/directories_controller.rb +++ b/app/controllers/api/v1/directories_controller.rb @@ -16,7 +16,9 @@ class Api::V1::DirectoriesController < Api::BaseController end def set_accounts - @accounts = accounts_scope.offset(params[:offset]).limit(limit_param(DEFAULT_ACCOUNTS_LIMIT)) + with_read_replica do + @accounts = accounts_scope.offset(params[:offset]).limit(limit_param(DEFAULT_ACCOUNTS_LIMIT)) + end end def accounts_scope diff --git a/app/controllers/api/v1/peers/search_controller.rb b/app/controllers/api/v1/peers/search_controller.rb index 2c0eacdca..0c503d9bc 100644 --- a/app/controllers/api/v1/peers/search_controller.rb +++ b/app/controllers/api/v1/peers/search_controller.rb @@ -41,5 +41,7 @@ class Api::V1::Peers::SearchController < Api::BaseController domain = TagManager.instance.normalize_domain(domain) @domains = Instance.searchable.where(Instance.arel_table[:domain].matches("#{Instance.sanitize_sql_like(domain)}%", false, true)).limit(10).pluck(:domain) end + rescue Addressable::URI::InvalidURIError + @domains = [] end end diff --git a/app/controllers/concerns/signature_verification.rb b/app/controllers/concerns/signature_verification.rb index b0c4fff8b..f0a344f1c 100644 --- a/app/controllers/concerns/signature_verification.rb +++ b/app/controllers/concerns/signature_verification.rb @@ -119,7 +119,7 @@ module SignatureVerification private def fail_with!(message, **options) - Rails.logger.warn { "Signature verification failed: #{message}" } + Rails.logger.debug { "Signature verification failed: #{message}" } @signature_verification_failure_reason = { error: message }.merge(options) @signed_request_actor = nil diff --git a/app/controllers/concerns/web_app_controller_concern.rb b/app/controllers/concerns/web_app_controller_concern.rb index 3a40ea382..273d7344c 100644 --- a/app/controllers/concerns/web_app_controller_concern.rb +++ b/app/controllers/concerns/web_app_controller_concern.rb @@ -11,7 +11,7 @@ module WebAppControllerConcern end def skip_csrf_meta_tags? - !(ENV['OMNIAUTH_ONLY'] == 'true' && Devise.omniauth_providers.length == 1) && current_user.nil? + !(ENV['ONE_CLICK_SSO_LOGIN'] == 'true' && ENV['OMNIAUTH_ONLY'] == 'true' && Devise.omniauth_providers.length == 1) && current_user.nil? end def set_app_body_class diff --git a/app/helpers/media_component_helper.rb b/app/helpers/media_component_helper.rb index a57d0b4b6..fa8f34fb4 100644 --- a/app/helpers/media_component_helper.rb +++ b/app/helpers/media_component_helper.rb @@ -14,6 +14,7 @@ module MediaComponentHelper blurhash: video.blurhash, frameRate: meta.dig('original', 'frame_rate'), inline: true, + aspectRatio: "#{meta.dig('original', 'width')} / #{meta.dig('original', 'height')}", media: [ serialize_media_attachment(video), ].as_json, diff --git a/app/javascript/mastodon/actions/account_notes.js b/app/javascript/mastodon/actions/account_notes.js deleted file mode 100644 index 72b943300..000000000 --- a/app/javascript/mastodon/actions/account_notes.js +++ /dev/null @@ -1,37 +0,0 @@ -import api from '../api'; - -export const ACCOUNT_NOTE_SUBMIT_REQUEST = 'ACCOUNT_NOTE_SUBMIT_REQUEST'; -export const ACCOUNT_NOTE_SUBMIT_SUCCESS = 'ACCOUNT_NOTE_SUBMIT_SUCCESS'; -export const ACCOUNT_NOTE_SUBMIT_FAIL = 'ACCOUNT_NOTE_SUBMIT_FAIL'; - -export function submitAccountNote(id, value) { - return (dispatch, getState) => { - dispatch(submitAccountNoteRequest()); - - api(getState).post(`/api/v1/accounts/${id}/note`, { - comment: value, - }).then(response => { - dispatch(submitAccountNoteSuccess(response.data)); - }).catch(error => dispatch(submitAccountNoteFail(error))); - }; -} - -export function submitAccountNoteRequest() { - return { - type: ACCOUNT_NOTE_SUBMIT_REQUEST, - }; -} - -export function submitAccountNoteSuccess(relationship) { - return { - type: ACCOUNT_NOTE_SUBMIT_SUCCESS, - relationship, - }; -} - -export function submitAccountNoteFail(error) { - return { - type: ACCOUNT_NOTE_SUBMIT_FAIL, - error, - }; -} diff --git a/app/javascript/mastodon/actions/account_notes.ts b/app/javascript/mastodon/actions/account_notes.ts new file mode 100644 index 000000000..eeef23e36 --- /dev/null +++ b/app/javascript/mastodon/actions/account_notes.ts @@ -0,0 +1,18 @@ +import { createAppAsyncThunk } from 'mastodon/store/typed_functions'; + +import api from '../api'; + +export const submitAccountNote = createAppAsyncThunk( + 'account_note/submit', + async (args: { id: string; value: string }, { getState }) => { + // TODO: replace `unknown` with `ApiRelationshipJSON` when it is merged + const response = await api(getState).post( + `/api/v1/accounts/${args.id}/note`, + { + comment: args.value, + }, + ); + + return { relationship: response.data }; + }, +); diff --git a/app/javascript/mastodon/actions/notifications.js b/app/javascript/mastodon/actions/notifications.js index 6e8ddb227..02fe10ba5 100644 --- a/app/javascript/mastodon/actions/notifications.js +++ b/app/javascript/mastodon/actions/notifications.js @@ -18,6 +18,7 @@ import { importFetchedStatuses, } from './importer'; import { submitMarkers } from './markers'; +import { register as registerPushNotifications } from './push_notifications'; import { saveSettings } from './settings'; export const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE'; @@ -293,6 +294,10 @@ export function requestBrowserPermission(callback = noOp) { requestNotificationPermission((permission) => { dispatch(setBrowserPermission(permission)); callback(permission); + + if (permission === 'granted') { + dispatch(registerPushNotifications()); + } }); }; } diff --git a/app/javascript/mastodon/actions/search.js b/app/javascript/mastodon/actions/search.js index 94e7f2ed7..7aea346e6 100644 --- a/app/javascript/mastodon/actions/search.js +++ b/app/javascript/mastodon/actions/search.js @@ -1,3 +1,7 @@ +import { fromJS } from 'immutable'; + +import { searchHistory } from 'mastodon/settings'; + import api from '../api'; import { fetchRelationships } from './accounts'; @@ -15,8 +19,7 @@ export const SEARCH_EXPAND_REQUEST = 'SEARCH_EXPAND_REQUEST'; export const SEARCH_EXPAND_SUCCESS = 'SEARCH_EXPAND_SUCCESS'; export const SEARCH_EXPAND_FAIL = 'SEARCH_EXPAND_FAIL'; -export const SEARCH_RESULT_CLICK = 'SEARCH_RESULT_CLICK'; -export const SEARCH_RESULT_FORGET = 'SEARCH_RESULT_FORGET'; +export const SEARCH_HISTORY_UPDATE = 'SEARCH_HISTORY_UPDATE'; export function changeSearch(value) { return { @@ -37,17 +40,17 @@ export function submitSearch(type) { const signedIn = !!getState().getIn(['meta', 'me']); if (value.length === 0) { - dispatch(fetchSearchSuccess({ accounts: [], statuses: [], hashtags: [] }, '')); + dispatch(fetchSearchSuccess({ accounts: [], statuses: [], hashtags: [] }, '', type)); return; } - dispatch(fetchSearchRequest()); + dispatch(fetchSearchRequest(type)); api(getState).get('/api/v2/search', { params: { q: value, resolve: signedIn, - limit: 5, + limit: 11, type, }, }).then(response => { @@ -59,7 +62,7 @@ export function submitSearch(type) { dispatch(importFetchedStatuses(response.data.statuses)); } - dispatch(fetchSearchSuccess(response.data, value)); + dispatch(fetchSearchSuccess(response.data, value, type)); dispatch(fetchRelationships(response.data.accounts.map(item => item.id))); }).catch(error => { dispatch(fetchSearchFail(error)); @@ -67,16 +70,18 @@ export function submitSearch(type) { }; } -export function fetchSearchRequest() { +export function fetchSearchRequest(searchType) { return { type: SEARCH_FETCH_REQUEST, + searchType, }; } -export function fetchSearchSuccess(results, searchTerm) { +export function fetchSearchSuccess(results, searchTerm, searchType) { return { type: SEARCH_FETCH_SUCCESS, results, + searchType, searchTerm, }; } @@ -90,15 +95,16 @@ export function fetchSearchFail(error) { export const expandSearch = type => (dispatch, getState) => { const value = getState().getIn(['search', 'value']); - const offset = getState().getIn(['search', 'results', type]).size; + const offset = getState().getIn(['search', 'results', type]).size - 1; - dispatch(expandSearchRequest()); + dispatch(expandSearchRequest(type)); api(getState).get('/api/v2/search', { params: { q: value, type, offset, + limit: 11, }, }).then(({ data }) => { if (data.accounts) { @@ -116,8 +122,9 @@ export const expandSearch = type => (dispatch, getState) => { }); }; -export const expandSearchRequest = () => ({ +export const expandSearchRequest = (searchType) => ({ type: SEARCH_EXPAND_REQUEST, + searchType, }); export const expandSearchSuccess = (results, searchTerm, searchType) => ({ @@ -166,16 +173,34 @@ export const openURL = (value, history, onFailure) => (dispatch, getState) => { }); }; -export const clickSearchResult = (q, type) => ({ - type: SEARCH_RESULT_CLICK, +export const clickSearchResult = (q, type) => (dispatch, getState) => { + const previous = getState().getIn(['search', 'recent']); + const me = getState().getIn(['meta', 'me']); + const current = previous.add(fromJS({ type, q })).takeLast(4); - result: { - type, - q, - }, + searchHistory.set(me, current.toJS()); + dispatch(updateSearchHistory(current)); +}; + +export const forgetSearchResult = q => (dispatch, getState) => { + const previous = getState().getIn(['search', 'recent']); + const me = getState().getIn(['meta', 'me']); + const current = previous.filterNot(result => result.get('q') === q); + + searchHistory.set(me, current.toJS()); + dispatch(updateSearchHistory(current)); +}; + +export const updateSearchHistory = recent => ({ + type: SEARCH_HISTORY_UPDATE, + recent, }); -export const forgetSearchResult = q => ({ - type: SEARCH_RESULT_FORGET, - q, -}); +export const hydrateSearch = () => (dispatch, getState) => { + const me = getState().getIn(['meta', 'me']); + const history = searchHistory.get(me); + + if (history !== null) { + dispatch(updateSearchHistory(history)); + } +}; \ No newline at end of file diff --git a/app/javascript/mastodon/actions/store.js b/app/javascript/mastodon/actions/store.js index 6b0743439..682b0f5db 100644 --- a/app/javascript/mastodon/actions/store.js +++ b/app/javascript/mastodon/actions/store.js @@ -2,6 +2,7 @@ import { Iterable, fromJS } from 'immutable'; import { hydrateCompose } from './compose'; import { importFetchedAccounts } from './importer'; +import { hydrateSearch } from './search'; export const STORE_HYDRATE = 'STORE_HYDRATE'; export const STORE_HYDRATE_LAZY = 'STORE_HYDRATE_LAZY'; @@ -20,6 +21,7 @@ export function hydrateStore(rawState) { }); dispatch(hydrateCompose()); + dispatch(hydrateSearch()); dispatch(importFetchedAccounts(Object.values(rawState.accounts))); }; } diff --git a/app/javascript/mastodon/api.js b/app/javascript/mastodon/api.js deleted file mode 100644 index 1c171a1c4..000000000 --- a/app/javascript/mastodon/api.js +++ /dev/null @@ -1,76 +0,0 @@ -// @ts-check - -import axios from 'axios'; -import LinkHeader from 'http-link-header'; - -import ready from './ready'; - -/** - * @param {import('axios').AxiosResponse} response - * @returns {LinkHeader} - */ -export const getLinks = response => { - const value = response.headers.link; - - if (!value) { - return new LinkHeader(); - } - - return LinkHeader.parse(value); -}; - -/** @type {import('axios').RawAxiosRequestHeaders} */ -const csrfHeader = {}; - -/** - * @returns {void} - */ -const setCSRFHeader = () => { - /** @type {HTMLMetaElement | null} */ - const csrfToken = document.querySelector('meta[name=csrf-token]'); - - if (csrfToken) { - csrfHeader['X-CSRF-Token'] = csrfToken.content; - } -}; - -ready(setCSRFHeader); - -/** - * @param {() => import('immutable').Map} getState - * @returns {import('axios').RawAxiosRequestHeaders} - */ -const authorizationHeaderFromState = getState => { - const accessToken = getState && getState().getIn(['meta', 'access_token'], ''); - - if (!accessToken) { - return {}; - } - - return { - 'Authorization': `Bearer ${accessToken}`, - }; -}; - -/** - * @param {() => import('immutable').Map} getState - * @returns {import('axios').AxiosInstance} - */ -export default function api(getState) { - return axios.create({ - headers: { - ...csrfHeader, - ...authorizationHeaderFromState(getState), - }, - - transformResponse: [ - function (data) { - try { - return JSON.parse(data); - } catch { - return data; - } - }, - ], - }); -} diff --git a/app/javascript/mastodon/api.ts b/app/javascript/mastodon/api.ts new file mode 100644 index 000000000..f262fd857 --- /dev/null +++ b/app/javascript/mastodon/api.ts @@ -0,0 +1,63 @@ +import type { AxiosResponse, RawAxiosRequestHeaders } from 'axios'; +import axios from 'axios'; +import LinkHeader from 'http-link-header'; + +import ready from './ready'; +import type { GetState } from './store'; + +export const getLinks = (response: AxiosResponse) => { + const value = response.headers.link as string | undefined; + + if (!value) { + return new LinkHeader(); + } + + return LinkHeader.parse(value); +}; + +const csrfHeader: RawAxiosRequestHeaders = {}; + +const setCSRFHeader = () => { + const csrfToken = document.querySelector( + 'meta[name=csrf-token]', + ); + + if (csrfToken) { + csrfHeader['X-CSRF-Token'] = csrfToken.content; + } +}; + +void ready(setCSRFHeader); + +const authorizationHeaderFromState = (getState?: GetState) => { + const accessToken = + getState && (getState().meta.get('access_token', '') as string); + + if (!accessToken) { + return {}; + } + + return { + Authorization: `Bearer ${accessToken}`, + } as RawAxiosRequestHeaders; +}; + +// eslint-disable-next-line import/no-default-export +export default function api(getState: GetState) { + return axios.create({ + headers: { + ...csrfHeader, + ...authorizationHeaderFromState(getState), + }, + + transformResponse: [ + function (data: unknown) { + try { + return JSON.parse(data as string) as unknown; + } catch { + return data; + } + }, + ], + }); +} diff --git a/app/javascript/mastodon/components/animated_number.tsx b/app/javascript/mastodon/components/animated_number.tsx index 05a7e0189..e98e30b24 100644 --- a/app/javascript/mastodon/components/animated_number.tsx +++ b/app/javascript/mastodon/components/animated_number.tsx @@ -6,21 +6,10 @@ import { reduceMotion } from '../initial_state'; import { ShortNumber } from './short_number'; -const obfuscatedCount = (count: number) => { - if (count < 0) { - return 0; - } else if (count <= 1) { - return count; - } else { - return '1+'; - } -}; - interface Props { value: number; - obfuscate?: boolean; } -export const AnimatedNumber: React.FC = ({ value, obfuscate }) => { +export const AnimatedNumber: React.FC = ({ value }) => { const [previousValue, setPreviousValue] = useState(value); const [direction, setDirection] = useState<1 | -1>(1); @@ -36,11 +25,7 @@ export const AnimatedNumber: React.FC = ({ value, obfuscate }) => { ); if (reduceMotion) { - return obfuscate ? ( - <>{obfuscatedCount(value)} - ) : ( - - ); + return ; } const styles = [ @@ -67,11 +52,7 @@ export const AnimatedNumber: React.FC = ({ value, obfuscate }) => { transform: `translateY(${style.y * 100}%)`, }} > - {obfuscate ? ( - obfuscatedCount(data as number) - ) : ( - - )} + ))} diff --git a/app/javascript/mastodon/components/icon_button.tsx b/app/javascript/mastodon/components/icon_button.tsx index 9dbee2cc2..da6f19e9e 100644 --- a/app/javascript/mastodon/components/icon_button.tsx +++ b/app/javascript/mastodon/components/icon_button.tsx @@ -24,7 +24,6 @@ interface Props { overlay: boolean; tabIndex: number; counter?: number; - obfuscateCount?: boolean; href?: string; ariaHidden: boolean; } @@ -105,7 +104,6 @@ export class IconButton extends PureComponent { tabIndex, title, counter, - obfuscateCount, href, ariaHidden, } = this.props; @@ -131,7 +129,7 @@ export class IconButton extends PureComponent {