Merge branch 'hometown-dev' into hometown-dev-max-chars-patch
This commit is contained in:
commit
7c5f812c92
.circleci
.codeclimate.yml.dependabot
.env.nanobox.env.production.sample.env.test.env.vagrant.github
.gitignore.nvmrc.rubocop.yml.ruby-versionCHANGELOG.mdCONTRIBUTING.mdDockerfileGemfileGemfile.lockREADME.mdVagrantfileapp
chewy
controllers
account_follow_controller.rbaccounts_controller.rb
activitypub
admin
accounts_controller.rbaction_logs_controller.rbannouncements_controller.rbcustom_emojis_controller.rbemail_domain_blocks_controller.rbfollowers_controller.rbinstances_controller.rbinvites_controller.rbrelationships_controller.rbreports_controller.rbsite_uploads_controller.rbtags_controller.rbwarning_presets_controller.rb
api
base_controller.rboembed_controller.rbproofs_controller.rb
application_controller.rbv1
accounts
credentials_controller.rbfollower_accounts_controller.rbfollowing_accounts_controller.rbidentity_proofs_controller.rblists_controller.rbpins_controller.rbrelationships_controller.rbsearch_controller.rbstatuses_controller.rb
accounts_controller.rbannouncements
announcements_controller.rbapps
blocks_controller.rbbookmarks_controller.rbconversations_controller.rbcustom_emojis_controller.rbdomain_blocks_controller.rbendorsements_controller.rbfavourites_controller.rbfeatured_tags
filters_controller.rbinstances
instances_controller.rbmedia_controller.rbmutes_controller.rbnotifications_controller.rbpolls
polls_controller.rbpreferences_controller.rbpush
reports_controller.rbstatuses
bookmarks_controller.rbfavourited_by_accounts_controller.rbfavourites_controller.rbmutes_controller.rbpins_controller.rbreblogged_by_accounts_controller.rbreblogs_controller.rb
statuses_controller.rbstreaming_controller.rbsuggestions_controller.rbtimelines
trends_controller.rbv2
web
auth
authorize_interactions_controller.rb
|
@ -3,13 +3,15 @@ version: 2
|
|||
aliases:
|
||||
- &defaults
|
||||
docker:
|
||||
- image: circleci/ruby:2.6-stretch-node
|
||||
- image: circleci/ruby:2.7-buster-node
|
||||
environment: &ruby_environment
|
||||
BUNDLE_JOBS: 3
|
||||
BUNDLE_RETRY: 3
|
||||
BUNDLE_APP_CONFIG: ./.bundle/
|
||||
BUNDLE_PATH: ./vendor/bundle/
|
||||
DB_HOST: localhost
|
||||
DB_USER: root
|
||||
RAILS_ENV: test
|
||||
PARALLEL_TEST_PROCESSORS: 4
|
||||
ALLOW_NOPAM: true
|
||||
CONTINUOUS_INTEGRATION: true
|
||||
DISABLE_SIMPLECOV: true
|
||||
|
@ -31,25 +33,25 @@ aliases:
|
|||
- &restore_ruby_dependencies
|
||||
restore_cache:
|
||||
keys:
|
||||
- v2-ruby-dependencies-{{ checksum "/tmp/.ruby-version" }}-{{ checksum "Gemfile.lock" }}
|
||||
- v2-ruby-dependencies-{{ checksum "/tmp/.ruby-version" }}-
|
||||
- v2-ruby-dependencies-
|
||||
- v3-ruby-dependencies-{{ checksum "/tmp/.ruby-version" }}-{{ checksum "Gemfile.lock" }}
|
||||
- v3-ruby-dependencies-{{ checksum "/tmp/.ruby-version" }}-
|
||||
- v3-ruby-dependencies-
|
||||
|
||||
- &install_steps
|
||||
steps:
|
||||
- checkout
|
||||
- *attach_workspace
|
||||
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-node-dependencies-{{ checksum "yarn.lock" }}
|
||||
- v1-node-dependencies-
|
||||
- run: yarn install --frozen-lockfile
|
||||
- v2-node-dependencies-{{ checksum "yarn.lock" }}
|
||||
- v2-node-dependencies-
|
||||
- run:
|
||||
name: Install yarn dependencies
|
||||
command: yarn install --frozen-lockfile
|
||||
- save_cache:
|
||||
key: v1-node-dependencies-{{ checksum "yarn.lock" }}
|
||||
key: v2-node-dependencies-{{ checksum "yarn.lock" }}
|
||||
paths:
|
||||
- ./node_modules/
|
||||
|
||||
- *persist_to_workspace
|
||||
|
||||
- &install_system_dependencies
|
||||
|
@ -62,14 +64,24 @@ aliases:
|
|||
- &install_ruby_dependencies
|
||||
steps:
|
||||
- *attach_workspace
|
||||
|
||||
- *install_system_dependencies
|
||||
|
||||
- run: ruby -e 'puts RUBY_VERSION' | tee /tmp/.ruby-version
|
||||
- run:
|
||||
name: Set Ruby version
|
||||
command: ruby -e 'puts RUBY_VERSION' | tee /tmp/.ruby-version
|
||||
- *restore_ruby_dependencies
|
||||
- run: bundle install --clean --jobs 16 --path ./vendor/bundle/ --retry 3 --with pam_authentication --without development production && bundle clean
|
||||
- run:
|
||||
name: Set bundler settings
|
||||
command: |
|
||||
bundle config clean 'true'
|
||||
bundle config deployment 'true'
|
||||
bundle config with 'pam_authentication'
|
||||
bundle config without 'development production'
|
||||
bundle config frozen 'true'
|
||||
- run:
|
||||
name: Install bundler dependencies
|
||||
command: bundle check || (bundle install && bundle clean)
|
||||
- save_cache:
|
||||
key: v2-ruby-dependencies-{{ checksum "/tmp/.ruby-version" }}-{{ checksum "Gemfile.lock" }}
|
||||
key: v3-ruby-dependencies-{{ checksum "/tmp/.ruby-version" }}-{{ checksum "Gemfile.lock" }}
|
||||
paths:
|
||||
- ./.bundle/
|
||||
- ./vendor/bundle/
|
||||
|
@ -80,39 +92,39 @@ aliases:
|
|||
- ./mastodon/vendor/bundle/
|
||||
|
||||
- &test_steps
|
||||
parallelism: 4
|
||||
steps:
|
||||
- *attach_workspace
|
||||
|
||||
- *install_system_dependencies
|
||||
- run: sudo apt-get install -y ffmpeg
|
||||
|
||||
- run:
|
||||
name: Prepare Tests
|
||||
command: ./bin/rails parallel:create parallel:load_schema parallel:prepare
|
||||
name: Install FFMPEG
|
||||
command: sudo apt-get install -y ffmpeg
|
||||
- run:
|
||||
name: Run Tests
|
||||
command: ./bin/retry bundle exec parallel_test ./spec/ --group-by filesize --type rspec
|
||||
|
||||
name: Load database schema
|
||||
command: ./bin/rails db:create db:schema:load db:seed
|
||||
- run:
|
||||
name: Run rspec in parallel
|
||||
command: |
|
||||
bundle exec rspec --profile 10 \
|
||||
--format RspecJunitFormatter \
|
||||
--out test_results/rspec.xml \
|
||||
--format progress \
|
||||
$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)
|
||||
- store_test_results:
|
||||
path: test_results
|
||||
jobs:
|
||||
install:
|
||||
<<: *defaults
|
||||
<<: *install_steps
|
||||
|
||||
install-ruby2.7:
|
||||
<<: *defaults
|
||||
<<: *install_ruby_dependencies
|
||||
|
||||
install-ruby2.6:
|
||||
<<: *defaults
|
||||
<<: *install_ruby_dependencies
|
||||
|
||||
install-ruby2.5:
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/ruby:2.5-stretch-node
|
||||
environment: *ruby_environment
|
||||
<<: *install_ruby_dependencies
|
||||
|
||||
install-ruby2.4:
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/ruby:2.4-stretch-node
|
||||
- image: circleci/ruby:2.6-buster-node
|
||||
environment: *ruby_environment
|
||||
<<: *install_ruby_dependencies
|
||||
|
||||
|
@ -121,98 +133,116 @@ jobs:
|
|||
steps:
|
||||
- *attach_workspace
|
||||
- *install_system_dependencies
|
||||
- run: ./bin/rails assets:precompile
|
||||
- run:
|
||||
name: Precompile assets
|
||||
command: ./bin/rails assets:precompile
|
||||
- persist_to_workspace:
|
||||
root: ~/projects/
|
||||
paths:
|
||||
- ./mastodon/public/assets
|
||||
- ./mastodon/public/packs-test/
|
||||
|
||||
test-migrations:
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/ruby:2.7-buster-node
|
||||
environment: *ruby_environment
|
||||
- image: circleci/postgres:12.2
|
||||
environment:
|
||||
POSTGRES_USER: root
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
- image: circleci/redis:5-alpine
|
||||
steps:
|
||||
- *attach_workspace
|
||||
- *install_system_dependencies
|
||||
- run:
|
||||
name: Create database
|
||||
command: ./bin/rails db:create
|
||||
- run:
|
||||
name: Run migrations
|
||||
command: ./bin/rails db:migrate
|
||||
|
||||
test-ruby2.7:
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/ruby:2.7-buster-node
|
||||
environment: *ruby_environment
|
||||
- image: circleci/postgres:12.2
|
||||
environment:
|
||||
POSTGRES_USER: root
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
- image: circleci/redis:5-alpine
|
||||
<<: *test_steps
|
||||
|
||||
test-ruby2.6:
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/ruby:2.6-stretch-node
|
||||
- image: circleci/ruby:2.6-buster-node
|
||||
environment: *ruby_environment
|
||||
- image: circleci/postgres:10.6-alpine
|
||||
environment:
|
||||
POSTGRES_USER: root
|
||||
- image: circleci/redis:5-alpine
|
||||
<<: *test_steps
|
||||
|
||||
test-ruby2.5:
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/ruby:2.5-stretch-node
|
||||
environment: *ruby_environment
|
||||
- image: circleci/postgres:10.6-alpine
|
||||
environment:
|
||||
POSTGRES_USER: root
|
||||
- image: circleci/redis:5-alpine
|
||||
<<: *test_steps
|
||||
|
||||
test-ruby2.4:
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/ruby:2.4-stretch-node
|
||||
environment: *ruby_environment
|
||||
- image: circleci/postgres:10.6-alpine
|
||||
- image: circleci/postgres:12.2
|
||||
environment:
|
||||
POSTGRES_USER: root
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
- image: circleci/redis:5-alpine
|
||||
<<: *test_steps
|
||||
|
||||
test-webui:
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/node:12.9-stretch
|
||||
- image: circleci/node:12-buster
|
||||
steps:
|
||||
- *attach_workspace
|
||||
- run: ./bin/retry yarn test:jest
|
||||
- run:
|
||||
name: Run jest
|
||||
command: yarn test:jest
|
||||
|
||||
check-i18n:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- *attach_workspace
|
||||
- *install_system_dependencies
|
||||
- run: bundle exec i18n-tasks check-normalized
|
||||
- run: bundle exec i18n-tasks unused -l en
|
||||
- run: bundle exec i18n-tasks check-consistent-interpolations
|
||||
- run: bundle exec rake repo:check_locales_files
|
||||
- run:
|
||||
name: Check locale file normalization
|
||||
command: bundle exec i18n-tasks check-normalized
|
||||
- run:
|
||||
name: Check for unused strings
|
||||
command: bundle exec i18n-tasks unused -l en
|
||||
- run:
|
||||
name: Check for wrong string interpolations
|
||||
command: bundle exec i18n-tasks check-consistent-interpolations
|
||||
- run:
|
||||
name: Check that all required locale files exist
|
||||
command: bundle exec rake repo:check_locales_files
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build-and-test:
|
||||
jobs:
|
||||
- install
|
||||
- install-ruby2.7:
|
||||
requires:
|
||||
- install
|
||||
- install-ruby2.6:
|
||||
requires:
|
||||
- install
|
||||
- install-ruby2.5:
|
||||
requires:
|
||||
- install
|
||||
- install-ruby2.6
|
||||
- install-ruby2.4:
|
||||
requires:
|
||||
- install
|
||||
- install-ruby2.6
|
||||
- install-ruby2.7
|
||||
- build:
|
||||
requires:
|
||||
- install-ruby2.6
|
||||
- install-ruby2.7
|
||||
- test-migrations:
|
||||
requires:
|
||||
- install-ruby2.7
|
||||
- test-ruby2.7:
|
||||
requires:
|
||||
- install-ruby2.7
|
||||
- build
|
||||
- test-ruby2.6:
|
||||
requires:
|
||||
- install-ruby2.6
|
||||
- build
|
||||
- test-ruby2.5:
|
||||
requires:
|
||||
- install-ruby2.5
|
||||
- build
|
||||
- test-ruby2.4:
|
||||
requires:
|
||||
- install-ruby2.4
|
||||
- build
|
||||
- test-webui:
|
||||
requires:
|
||||
- install
|
||||
- check-i18n:
|
||||
requires:
|
||||
- install-ruby2.6
|
||||
- install-ruby2.7
|
||||
|
|
|
@ -27,10 +27,10 @@ plugins:
|
|||
enabled: true
|
||||
eslint:
|
||||
enabled: true
|
||||
channel: eslint-5
|
||||
channel: eslint-6
|
||||
rubocop:
|
||||
enabled: true
|
||||
channel: rubocop-0-71
|
||||
channel: rubocop-0-82
|
||||
sass-lint:
|
||||
enabled: true
|
||||
exclude_patterns:
|
||||
|
|
|
@ -4,7 +4,25 @@ update_configs:
|
|||
- package_manager: "ruby:bundler"
|
||||
directory: "/"
|
||||
update_schedule: "weekly"
|
||||
# Supported update schedule: live daily weekly monthly
|
||||
version_requirement_updates: "auto"
|
||||
# Supported version requirements: auto widen_ranges increase_versions increase_versions_if_necessary
|
||||
allowed_updates:
|
||||
- match:
|
||||
dependency_type: "all"
|
||||
# Supported dependency types: all indirect direct production development
|
||||
update_type: "all"
|
||||
# Supported update types: all security
|
||||
|
||||
- package_manager: "javascript"
|
||||
directory: "/"
|
||||
update_schedule: "weekly"
|
||||
# Supported update schedule: live daily weekly monthly
|
||||
version_requirement_updates: "auto"
|
||||
# Supported version requirements: auto widen_ranges increase_versions increase_versions_if_necessary
|
||||
allowed_updates:
|
||||
- match:
|
||||
dependency_type: "all"
|
||||
# Supported dependency types: all indirect direct production development
|
||||
update_type: "all"
|
||||
# Supported update types: all security
|
||||
|
|
|
@ -183,6 +183,11 @@ SMTP_FROM_ADDRESS=notifications@${APP_NAME}.nanoapp.io
|
|||
# LDAP_BIND_DN=
|
||||
# LDAP_PASSWORD=
|
||||
# LDAP_UID=cn
|
||||
# LDAP_MAIL=mail
|
||||
# LDAP_SEARCH_FILTER=(|(%{uid}=%{email})(%{mail}=%{email}))
|
||||
# LDAP_UID_CONVERSION_ENABLED=true
|
||||
# LDAP_UID_CONVERSION_SEARCH=., -
|
||||
# LDAP_UID_CONVERSION_REPLACE=_
|
||||
|
||||
# PAM authentication (optional)
|
||||
# PAM authentication uses for the email generation the "email" pam variable
|
||||
|
@ -226,8 +231,8 @@ SMTP_FROM_ADDRESS=notifications@${APP_NAME}.nanoapp.io
|
|||
|
||||
# Optional SAML authentication (cf. omniauth-saml)
|
||||
# SAML_ENABLED=true
|
||||
# SAML_ACS_URL=
|
||||
# SAML_ISSUER=http://localhost:3000/auth/auth/saml/callback
|
||||
# SAML_ACS_URL=http://localhost:3000/auth/auth/saml/callback
|
||||
# SAML_ISSUER=https://example.com
|
||||
# SAML_IDP_SSO_TARGET_URL=https://idp.testshib.org/idp/profile/SAML2/Redirect/SSO
|
||||
# SAML_IDP_CERT=
|
||||
# SAML_IDP_CERT_FINGERPRINT=
|
||||
|
|
|
@ -33,7 +33,7 @@ LOCAL_DOMAIN=example.com
|
|||
# ALTERNATE_DOMAINS=example1.com,example2.com
|
||||
|
||||
# Application secrets
|
||||
# Generate each with the `RAILS_ENV=production bundle exec rake secret` task (`docker-compose run --rm web rake secret` if you use docker compose)
|
||||
# Generate each with the `RAILS_ENV=production bundle exec rake secret` task (`docker-compose run --rm web bundle exec rake secret` if you use docker compose)
|
||||
SECRET_KEY_BASE=
|
||||
OTP_SECRET=
|
||||
|
||||
|
@ -42,7 +42,7 @@ OTP_SECRET=
|
|||
# You should only generate this once per instance. If you later decide to change it, all push subscription will
|
||||
# be invalidated, requiring the users to access the website again to resubscribe.
|
||||
#
|
||||
# Generate with `RAILS_ENV=production bundle exec rake mastodon:webpush:generate_vapid_key` task (`docker-compose run --rm web rake mastodon:webpush:generate_vapid_key` if you use docker compose)
|
||||
# Generate with `RAILS_ENV=production bundle exec rake mastodon:webpush:generate_vapid_key` task (`docker-compose run --rm web bundle exec rake mastodon:webpush:generate_vapid_key` if you use docker compose)
|
||||
#
|
||||
# For more information visit https://rossta.net/blog/using-the-web-push-api-with-vapid.html
|
||||
VAPID_PRIVATE_KEY=
|
||||
|
@ -181,7 +181,11 @@ STREAMING_CLUSTER_NUM=1
|
|||
# LDAP_BIND_DN=
|
||||
# LDAP_PASSWORD=
|
||||
# LDAP_UID=cn
|
||||
# LDAP_SEARCH_FILTER=%{uid}=%{email}
|
||||
# LDAP_MAIL=mail
|
||||
# LDAP_SEARCH_FILTER=(|(%{uid}=%{email})(%{mail}=%{email}))
|
||||
# LDAP_UID_CONVERSION_ENABLED=true
|
||||
# LDAP_UID_CONVERSION_SEARCH=., -
|
||||
# LDAP_UID_CONVERSION_REPLACE=_
|
||||
|
||||
# PAM authentication (optional)
|
||||
# PAM authentication uses for the email generation the "email" pam variable
|
||||
|
@ -225,8 +229,8 @@ STREAMING_CLUSTER_NUM=1
|
|||
|
||||
# Optional SAML authentication (cf. omniauth-saml)
|
||||
# SAML_ENABLED=true
|
||||
# SAML_ACS_URL=
|
||||
# SAML_ISSUER=http://localhost:3000/auth/auth/saml/callback
|
||||
# SAML_ACS_URL=http://localhost:3000/auth/auth/saml/callback
|
||||
# SAML_ISSUER=https://example.com
|
||||
# SAML_IDP_SSO_TARGET_URL=https://idp.testshib.org/idp/profile/SAML2/Redirect/SSO
|
||||
# SAML_IDP_CERT=
|
||||
# SAML_IDP_CERT_FINGERPRINT=
|
||||
|
@ -249,3 +253,13 @@ STREAMING_CLUSTER_NUM=1
|
|||
# http_proxy=http://gateway.local:8118
|
||||
# Access control for hidden service.
|
||||
# ALLOW_ACCESS_TO_HIDDEN_SERVICE=true
|
||||
|
||||
# Authorized fetch mode (optional)
|
||||
# Require remote servers to authentify when fetching toots, see
|
||||
# https://docs.joinmastodon.org/admin/config/#authorized_fetch
|
||||
# AUTHORIZED_FETCH=true
|
||||
|
||||
# Whitelist mode (optional)
|
||||
# Only allow federation with whitelisted domains, see
|
||||
# https://docs.joinmastodon.org/admin/config/#whitelist_mode
|
||||
# WHITELIST_MODE=true
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Node.js
|
||||
NODE_ENV=test
|
||||
NODE_ENV=tests
|
||||
# Federation
|
||||
LOCAL_DOMAIN=cb6e6126.ngrok.io
|
||||
LOCAL_HTTPS=true
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
VAGRANT=true
|
||||
LOCAL_DOMAIN=mastodon.local
|
||||
BIND=0.0.0.0
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Mastodon Meta Discussion Board
|
||||
url: https://discourse.joinmastodon.org/
|
||||
about: Please ask and answer questions here.
|
|
@ -0,0 +1,10 @@
|
|||
daysUntilStale: 120
|
||||
daysUntilClose: 7
|
||||
exemptLabels:
|
||||
- security
|
||||
staleLabel: wontfix
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
only: pulls
|
|
@ -13,6 +13,7 @@
|
|||
/db/*.sqlite3-journal
|
||||
|
||||
# Ignore all logfiles and tempfiles.
|
||||
.eslintcache
|
||||
/log/*
|
||||
!/log/.keep
|
||||
/tmp
|
||||
|
@ -23,6 +24,7 @@ public/packs
|
|||
public/packs-test
|
||||
.env
|
||||
.env.production
|
||||
.env.development
|
||||
node_modules/
|
||||
build/
|
||||
|
||||
|
@ -55,6 +57,8 @@ npm-debug.log
|
|||
yarn-error.log
|
||||
yarn-debug.log
|
||||
|
||||
# Ignore vagrant log files
|
||||
*-cloudimg-console.log
|
||||
|
||||
# Ignore Docker option files
|
||||
docker-compose.override.yml
|
||||
|
||||
|
|
10
.rubocop.yml
10
.rubocop.yml
|
@ -2,7 +2,7 @@ require:
|
|||
- rubocop-rails
|
||||
|
||||
AllCops:
|
||||
TargetRubyVersion: 2.3
|
||||
TargetRubyVersion: 2.4
|
||||
Exclude:
|
||||
- 'spec/**/*'
|
||||
- 'db/**/*'
|
||||
|
@ -46,7 +46,7 @@ Metrics/ClassLength:
|
|||
Metrics/CyclomaticComplexity:
|
||||
Max: 25
|
||||
|
||||
Metrics/LineLength:
|
||||
Layout/LineLength:
|
||||
AllowURI: true
|
||||
Enabled: false
|
||||
|
||||
|
@ -71,6 +71,9 @@ Naming/MemoizedInstanceVariableName:
|
|||
Rails:
|
||||
Enabled: true
|
||||
|
||||
Rails/EnumHash:
|
||||
Enabled: false
|
||||
|
||||
Rails/HasAndBelongsToMany:
|
||||
Enabled: false
|
||||
|
||||
|
@ -102,6 +105,9 @@ Style/Documentation:
|
|||
Style/DoubleNegation:
|
||||
Enabled: true
|
||||
|
||||
Style/FormatStringToken:
|
||||
Enabled: false
|
||||
|
||||
Style/FrozenStringLiteralComment:
|
||||
Enabled: true
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
2.6.5
|
||||
2.6.6
|
||||
|
|
335
CHANGELOG.md
335
CHANGELOG.md
|
@ -3,6 +3,341 @@ Changelog
|
|||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [v3.1.4] - 2020-05-14
|
||||
### Added
|
||||
|
||||
- Add `vi` to available locales ([taicv](https://github.com/tootsuite/mastodon/pull/13542))
|
||||
- Add ability to remove identity proofs from account ([Gargron](https://github.com/tootsuite/mastodon/pull/13682))
|
||||
- Add ability to exclude local content from federated timeline ([noellabo](https://github.com/tootsuite/mastodon/pull/13504), [noellabo](https://github.com/tootsuite/mastodon/pull/13745))
|
||||
- Add `remote` param to `GET /api/v1/timelines/public` REST API
|
||||
- Add `public/remote` / `public:remote` variants to streaming API
|
||||
- "Remote only" option in federated timeline column settings in web UI
|
||||
- Add ability to exclude remote content from hashtag timelines in web UI ([noellabo](https://github.com/tootsuite/mastodon/pull/13502))
|
||||
- No changes to REST API
|
||||
- "Local only" option in hashtag column settings in web UI
|
||||
- Add Capistrano tasks that reload the services after deploying ([berkes](https://github.com/tootsuite/mastodon/pull/12642))
|
||||
- Add `invites_enabled` attribute to `GET /api/v1/instance` in REST API ([ThibG](https://github.com/tootsuite/mastodon/pull/13501))
|
||||
- Add `tootctl emoji export` command ([lfuelling](https://github.com/tootsuite/mastodon/pull/13534))
|
||||
- Add separate cache directory for non-local uploads ([Gargron](https://github.com/tootsuite/mastodon/pull/12821), [Hanage999](https://github.com/tootsuite/mastodon/pull/13593), [mayaeh](https://github.com/tootsuite/mastodon/pull/13551))
|
||||
- Add `tootctl upgrade storage-schema` command to move old non-local uploads to the cache directory
|
||||
- Add buttons to delete header and avatar from profile settings ([sternenseemann](https://github.com/tootsuite/mastodon/pull/13234))
|
||||
- Add emoji graphics and shortcodes from Twemoji 12.1.5 ([DeeUnderscore](https://github.com/tootsuite/mastodon/pull/13021))
|
||||
|
||||
### Changed
|
||||
|
||||
- Change error message when trying to migrate to an account that does not have current account set as an alias to be more clear ([TheEvilSkeleton](https://github.com/tootsuite/mastodon/pull/13746))
|
||||
- Change delivery failure tracking to work with hostnames instead of URLs ([Gargron](https://github.com/tootsuite/mastodon/pull/13437), [noellabo](https://github.com/tootsuite/mastodon/pull/13481), [noellabo](https://github.com/tootsuite/mastodon/pull/13482), [noellabo](https://github.com/tootsuite/mastodon/pull/13535))
|
||||
- Change Content-Security-Policy to not need unsafe-inline style-src ([ThibG](https://github.com/tootsuite/mastodon/pull/13679), [ThibG](https://github.com/tootsuite/mastodon/pull/13692), [ThibG](https://github.com/tootsuite/mastodon/pull/13576), [ThibG](https://github.com/tootsuite/mastodon/pull/13575), [ThibG](https://github.com/tootsuite/mastodon/pull/13438))
|
||||
- Change how RSS items are titled and formatted ([ThibG](https://github.com/tootsuite/mastodon/pull/13592), [ykzts](https://github.com/tootsuite/mastodon/pull/13591))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix dropdown of muted and followed accounts offering option to hide boosts in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13748))
|
||||
- Fix "You are already signed in" alert being shown at wrong times ([ThibG](https://github.com/tootsuite/mastodon/pull/13547))
|
||||
- Fix retrying of failed-to-download media files not actually working ([noellabo](https://github.com/tootsuite/mastodon/pull/13741))
|
||||
- Fix first poll option not being focused when adding a poll in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13740))
|
||||
- Fix `sr` locale being selected over `sr-Latn` ([ThibG](https://github.com/tootsuite/mastodon/pull/13693))
|
||||
- Fix error within error when limiting backtrace to 3 lines ([Gargron](https://github.com/tootsuite/mastodon/pull/13120))
|
||||
- Fix `tootctl media remove-orphans` crashing on "Import" files ([ThibG](https://github.com/tootsuite/mastodon/pull/13685))
|
||||
- Fix regression in `tootctl media remove-orphans` ([Gargron](https://github.com/tootsuite/mastodon/pull/13405))
|
||||
- Fix old unique jobs digests not having been cleaned up ([Gargron](https://github.com/tootsuite/mastodon/pull/13683))
|
||||
- Fix own following/followers not showing muted users ([ThibG](https://github.com/tootsuite/mastodon/pull/13614))
|
||||
- Fix list of followed people ignoring sorting on Follows & Followers page ([taras2358](https://github.com/tootsuite/mastodon/pull/13676))
|
||||
- Fix wrong pgHero Content-Security-Policy when `CDN_HOST` is set ([ThibG](https://github.com/tootsuite/mastodon/pull/13595))
|
||||
- Fix needlessly deduplicating usernames on collisions with remote accounts when signing-up through SAML/CAS ([kaiyou](https://github.com/tootsuite/mastodon/pull/13581))
|
||||
- Fix page incorrectly scrolling when bringing up dropdown menus in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13574))
|
||||
- Fix messed up z-index when NoScript blocks media/previews in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13449))
|
||||
- Fix "See what's happening" page showing public instead of local timeline for logged-in users ([ThibG](https://github.com/tootsuite/mastodon/pull/13499))
|
||||
- Fix not being able to resolve public resources in development environment ([Gargron](https://github.com/tootsuite/mastodon/pull/13505))
|
||||
- Fix uninformative error message when uploading unsupported image files ([ThibG](https://github.com/tootsuite/mastodon/pull/13540))
|
||||
- Fix expanded video player issues in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13541), [eai04191](https://github.com/tootsuite/mastodon/pull/13533))
|
||||
- Fix and refactor keyboard navigation in dropdown menus in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13528))
|
||||
- Fix uploaded image orientation being messed up in some browsers in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13493))
|
||||
- Fix actions log crash when displaying updates of deleted announcements in admin UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13489))
|
||||
- Fix search not working due to proxy settings when using hidden services ([Gargron](https://github.com/tootsuite/mastodon/pull/13488))
|
||||
- Fix poll refresh button not being debounced in web UI ([rasjonell](https://github.com/tootsuite/mastodon/pull/13485), [ThibG](https://github.com/tootsuite/mastodon/pull/13490))
|
||||
- Fix confusing error when failing to add an alias to an unknown account ([ThibG](https://github.com/tootsuite/mastodon/pull/13480))
|
||||
- Fix "Email changed" notification sometimes having wrong e-mail ([ThibG](https://github.com/tootsuite/mastodon/pull/13475))
|
||||
- Fix varioues issues on the account aliases page ([ThibG](https://github.com/tootsuite/mastodon/pull/13452))
|
||||
- Fix API footer link in web UI ([bubblineyuri](https://github.com/tootsuite/mastodon/pull/13441))
|
||||
- Fix pagination of following, followers, follow requests, blocks and mutes lists in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13445))
|
||||
- Fix styling of polls in JS-less fallback on public pages ([ThibG](https://github.com/tootsuite/mastodon/pull/13436))
|
||||
- Fix trying to delete already deleted file when post-processing ([Gargron](https://github.com/tootsuite/mastodon/pull/13406))
|
||||
|
||||
### Security
|
||||
|
||||
- Fix Doorkeeper vulnerability that exposed app secret to users who authorized the app and reset secret of the web UI that could have been exposed ([dependabot-preview[bot]](https://github.com/tootsuite/mastodon/pull/13613), [Gargron](https://github.com/tootsuite/mastodon/pull/13688))
|
||||
- For apps that self-register on behalf of every individual user (such as most mobile apps), this is a non-issue
|
||||
- The issue only affects developers of apps who are shared between multiple users, such as server-side apps like cross-posters
|
||||
|
||||
## [v3.1.3] - 2020-04-05
|
||||
### Added
|
||||
|
||||
- Add ability to filter audit log in admin UI ([Gargron](https://github.com/tootsuite/mastodon/pull/13381))
|
||||
- Add titles to warning presets in admin UI ([Gargron](https://github.com/tootsuite/mastodon/pull/13252))
|
||||
- Add option to include resolved DNS records when blacklisting e-mail domains in admin UI ([Gargron](https://github.com/tootsuite/mastodon/pull/13254))
|
||||
- Add ability to delete files uploaded for settings in admin UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13192))
|
||||
- Add sorting by username, creation and last activity in admin UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13076))
|
||||
- Add explanation as to why unlocked accounts may have follow requests in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13385))
|
||||
- Add link to bookmarks to dropdown in web UI ([mayaeh](https://github.com/tootsuite/mastodon/pull/13273))
|
||||
- Add support for links to statuses in announcements to be opened in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13212), [ThibG](https://github.com/tootsuite/mastodon/pull/13250))
|
||||
- Add tooltips to audio/video player buttons in web UI ([ariasuni](https://github.com/tootsuite/mastodon/pull/13203))
|
||||
- Add submit button to the top of preferences pages ([guigeekz](https://github.com/tootsuite/mastodon/pull/13068))
|
||||
- Add specific rate limits for posting, following and reporting ([Gargron](https://github.com/tootsuite/mastodon/pull/13172), [Gargron](https://github.com/tootsuite/mastodon/pull/13390))
|
||||
- 300 posts every 3 hours
|
||||
- 400 follows or follow requests every 24 hours
|
||||
- 400 reports every 24 hours
|
||||
- Add federation support for the "hide network" preference ([ThibG](https://github.com/tootsuite/mastodon/pull/11673))
|
||||
- Add `--skip-media-remove` option to `tootctl statuses remove` ([tateisu](https://github.com/tootsuite/mastodon/pull/13080))
|
||||
|
||||
### Changed
|
||||
|
||||
- **Change design of polls in web UI** ([Sasha-Sorokin](https://github.com/tootsuite/mastodon/pull/13257), [ThibG](https://github.com/tootsuite/mastodon/pull/13313))
|
||||
- Change status click areas in web UI to be bigger ([ariasuni](https://github.com/tootsuite/mastodon/pull/13327))
|
||||
- **Change `tootctl media remove-orphans` to work for all classes** ([Gargron](https://github.com/tootsuite/mastodon/pull/13316))
|
||||
- **Change local media attachments to perform heavy processing asynchronously** ([Gargron](https://github.com/tootsuite/mastodon/pull/13210))
|
||||
- Change video uploads to always be converted to H264/MP4 ([Gargron](https://github.com/tootsuite/mastodon/pull/13220), [ThibG](https://github.com/tootsuite/mastodon/pull/13239), [ThibG](https://github.com/tootsuite/mastodon/pull/13242))
|
||||
- Change video uploads to enforce certain limits ([Gargron](https://github.com/tootsuite/mastodon/pull/13218))
|
||||
- Dimensions smaller than 1920x1200px
|
||||
- Frame rate at most 60fps
|
||||
- Change the tooltip "Toggle visibility" to "Hide media" in web UI ([ariasuni](https://github.com/tootsuite/mastodon/pull/13199))
|
||||
- Change description of privacy levels to be more intuitive in web UI ([ariasuni](https://github.com/tootsuite/mastodon/pull/13197))
|
||||
- Change GIF label to be displayed even when autoplay is enabled in web UI ([koyuawsmbrtn](https://github.com/tootsuite/mastodon/pull/13209))
|
||||
- Change the string "Hide everything from …" to "Block domain …" in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13178), [mayaeh](https://github.com/tootsuite/mastodon/pull/13221))
|
||||
- Change wording of media display preferences to be more intuitive ([ariasuni](https://github.com/tootsuite/mastodon/pull/13198))
|
||||
|
||||
### Deprecated
|
||||
|
||||
- `POST /api/v1/media` → `POST /api/v2/media` ([Gargron](https://github.com/tootsuite/mastodon/pull/13210))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix `tootctl media remove-orphans` ignoring `PAPERCLIP_ROOT_PATH` ([Gargron](https://github.com/tootsuite/mastodon/pull/13375))
|
||||
- Fix returning results when searching for URL with non-zero offset ([Gargron](https://github.com/tootsuite/mastodon/pull/13377))
|
||||
- Fix pinning a column in web UI sometimes redirecting out of web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/13376))
|
||||
- Fix background jobs not using locks like they are supposed to ([Gargron](https://github.com/tootsuite/mastodon/pull/13361))
|
||||
- Fix content warning being unnecessarily cleared when hiding content warning input in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13348))
|
||||
- Fix "Show more" not switching to "Show less" on public pages ([ThibG](https://github.com/tootsuite/mastodon/pull/13174))
|
||||
- Fix import overwrite option not being selectable ([noellabo](https://github.com/tootsuite/mastodon/pull/13347))
|
||||
- Fix wrong color for ellipsis in boost confirmation dialog in web UI ([ariasuni](https://github.com/tootsuite/mastodon/pull/13355))
|
||||
- Fix unnecessary unfollowing when importing follows with overwrite option ([noellabo](https://github.com/tootsuite/mastodon/pull/13350))
|
||||
- Fix 404 and 410 API errors being silently discarded in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13279))
|
||||
- Fix OCR not working on Safari because of unsupported worker-src CSP ([ThibG](https://github.com/tootsuite/mastodon/pull/13323))
|
||||
- Fix media not being marked sensitive when a content warning is set with no text ([ThibG](https://github.com/tootsuite/mastodon/pull/13277))
|
||||
- Fix crash after deleting announcements in web UI ([codesections](https://github.com/tootsuite/mastodon/pull/13283), [ThibG](https://github.com/tootsuite/mastodon/pull/13312))
|
||||
- Fix bookmarks not being searchable ([Kjwon15](https://github.com/tootsuite/mastodon/pull/13271), [noellabo](https://github.com/tootsuite/mastodon/pull/13293))
|
||||
- Fix reported accounts not being whitelisted from further spam checks when resolving a spam check report ([ThibG](https://github.com/tootsuite/mastodon/pull/13289))
|
||||
- Fix web UI crash in single-column mode on prehistoric browsers ([ThibG](https://github.com/tootsuite/mastodon/pull/13267))
|
||||
- Fix some timeouts when searching for URLs ([ThibG](https://github.com/tootsuite/mastodon/pull/13253))
|
||||
- Fix detailed view of direct messages displaying a 0 boost count in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13244))
|
||||
- Fix regression in “Edit media” modal in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13243))
|
||||
- Fix public posts from silenced accounts not being changed to unlisted visibility ([ThibG](https://github.com/tootsuite/mastodon/pull/13096))
|
||||
- Fix error when searching for URLs that contain the mention syntax ([ThibG](https://github.com/tootsuite/mastodon/pull/13151))
|
||||
- Fix text area above/right of emoji picker being accidentally clickable in web UI ([ariasuni](https://github.com/tootsuite/mastodon/pull/13148))
|
||||
- Fix too large announcements not being scrollable in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13211))
|
||||
- Fix `tootctl media remove-orphans` crashing when encountering invalid media ([ThibG](https://github.com/tootsuite/mastodon/pull/13170))
|
||||
- Fix installation failing when Redis password contains special characters ([ThibG](https://github.com/tootsuite/mastodon/pull/13156))
|
||||
- Fix announcements with fully-qualified mentions to local users crashing web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13164))
|
||||
|
||||
### Security
|
||||
|
||||
- Fix re-sending of e-mail confirmation not being rate limited ([Gargron](https://github.com/tootsuite/mastodon/pull/13360))
|
||||
|
||||
## [v3.1.2] - 2020-02-27
|
||||
### Added
|
||||
|
||||
- Add `--reset-password` option to `tootctl accounts modify` ([ThibG](https://github.com/tootsuite/mastodon/pull/13126))
|
||||
- Add source-mapped stacktrace to error message in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13082))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix dismissing an announcement twice raising an obscure error ([ThibG](https://github.com/tootsuite/mastodon/pull/13124))
|
||||
- Fix misleading error when attempting to re-send a pending follow request ([ThibG](https://github.com/tootsuite/mastodon/pull/13133))
|
||||
- Fix backups failing when files are missing from media attachments ([ThibG](https://github.com/tootsuite/mastodon/pull/13146))
|
||||
- Fix duplicate accounts being created when fetching an account for its key only ([ThibG](https://github.com/tootsuite/mastodon/pull/13147))
|
||||
- Fix `/web` redirecting to `/web/web` in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13128))
|
||||
- Fix previously OStatus-based accounts not being detected as ActivityPub ([ThibG](https://github.com/tootsuite/mastodon/pull/13129))
|
||||
- Fix account JSON/RSS not being cacheable due to wrong mime type comparison ([ThibG](https://github.com/tootsuite/mastodon/pull/13116))
|
||||
- Fix old browsers crashing because of missing `finally` polyfill in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13115))
|
||||
- Fix account's bio not being shown if there are no proofs/fields in admin UI ([ThibG](https://github.com/tootsuite/mastodon/pull/13075))
|
||||
- Fix sign-ups without checked user agreement being accepted through the web form ([ThibG](https://github.com/tootsuite/mastodon/pull/13088))
|
||||
- Fix non-x64 architectures not being able to build Docker image because of hardcoded Node.js architecture ([SaraSmiseth](https://github.com/tootsuite/mastodon/pull/13081))
|
||||
- Fix invite request input not being shown on sign-up error if left empty ([ThibG](https://github.com/tootsuite/mastodon/pull/13089))
|
||||
- Fix some migration hints mentioning GitLab instead of Mastodon ([saper](https://github.com/tootsuite/mastodon/pull/13084))
|
||||
|
||||
### Security
|
||||
|
||||
- Fix leak of arbitrary statuses through unfavourite action in REST API ([Gargron](https://github.com/tootsuite/mastodon/pull/13161))
|
||||
|
||||
## [3.1.1] - 2020-02-10
|
||||
### Fixed
|
||||
|
||||
- Fix yanked dependency preventing installation ([mayaeh](https://github.com/tootsuite/mastodon/pull/13059))
|
||||
|
||||
## [3.1.0] - 2020-02-09
|
||||
### Added
|
||||
|
||||
- Add bookmarks ([ThibG](https://github.com/tootsuite/mastodon/pull/7107), [Gargron](https://github.com/tootsuite/mastodon/pull/12494), [Gomasy](https://github.com/tootsuite/mastodon/pull/12381))
|
||||
- Add announcements ([Gargron](https://github.com/tootsuite/mastodon/pull/12662), [Gargron](https://github.com/tootsuite/mastodon/pull/12967), [Gargron](https://github.com/tootsuite/mastodon/pull/12970), [Gargron](https://github.com/tootsuite/mastodon/pull/12963), [Gargron](https://github.com/tootsuite/mastodon/pull/12950), [Gargron](https://github.com/tootsuite/mastodon/pull/12990), [Gargron](https://github.com/tootsuite/mastodon/pull/12949), [Gargron](https://github.com/tootsuite/mastodon/pull/12989), [Gargron](https://github.com/tootsuite/mastodon/pull/12964), [Gargron](https://github.com/tootsuite/mastodon/pull/12965), [ThibG](https://github.com/tootsuite/mastodon/pull/12958), [ThibG](https://github.com/tootsuite/mastodon/pull/12957), [Gargron](https://github.com/tootsuite/mastodon/pull/12955), [ThibG](https://github.com/tootsuite/mastodon/pull/12946), [ThibG](https://github.com/tootsuite/mastodon/pull/12954))
|
||||
- Add number animations in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/12948), [Gargron](https://github.com/tootsuite/mastodon/pull/12971))
|
||||
- Add `kab`, `is`, `kn`, `mr`, `ur` to available locales ([Gargron](https://github.com/tootsuite/mastodon/pull/12882), [BoFFire](https://github.com/tootsuite/mastodon/pull/12962), [Gargron](https://github.com/tootsuite/mastodon/pull/12379))
|
||||
- Add profile filter category ([ThibG](https://github.com/tootsuite/mastodon/pull/12918))
|
||||
- Add ability to add oneself to lists ([ThibG](https://github.com/tootsuite/mastodon/pull/12271))
|
||||
- Add hint how to contribute translations to preferences page ([Sasha-Sorokin](https://github.com/tootsuite/mastodon/pull/12736))
|
||||
- Add signatures to statuses in archive takeout ([noellabo](https://github.com/tootsuite/mastodon/pull/12649))
|
||||
- Add support for `magnet:` and `xmpp` links ([ThibG](https://github.com/tootsuite/mastodon/pull/12905), [ThibG](https://github.com/tootsuite/mastodon/pull/12709))
|
||||
- Add `follow_request` notification type ([ThibG](https://github.com/tootsuite/mastodon/pull/12198))
|
||||
- Add ability to filter reports by account domain in admin UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12154))
|
||||
- Add link to search for users connected from the same IP address to admin UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12157))
|
||||
- Add link to reports targeting a specific domain in admin view ([ThibG](https://github.com/tootsuite/mastodon/pull/12513))
|
||||
- Add support for EventSource streaming in web UI ([BenLubar](https://github.com/tootsuite/mastodon/pull/12887))
|
||||
- Add hotkey for opening media attachments in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12498), [Kjwon15](https://github.com/tootsuite/mastodon/pull/12546))
|
||||
- Add relationship-based options to status dropdowns in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/12377), [ThibG](https://github.com/tootsuite/mastodon/pull/12535), [Gargron](https://github.com/tootsuite/mastodon/pull/12430))
|
||||
- Add support for submitting media description with `ctrl`+`enter` in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12272))
|
||||
- Add download button to audio and video players in web UI ([NimaBoscarino](https://github.com/tootsuite/mastodon/pull/12179))
|
||||
- Add setting for whether to crop images in timelines in web UI ([duxovni](https://github.com/tootsuite/mastodon/pull/12126))
|
||||
- Add support for `Event` activities ([tcitworld](https://github.com/tootsuite/mastodon/pull/12637))
|
||||
- Add basic support for `Group` actors ([noellabo](https://github.com/tootsuite/mastodon/pull/12071))
|
||||
- Add `S3_OVERRIDE_PATH_STYLE` environment variable ([Gargron](https://github.com/tootsuite/mastodon/pull/12594))
|
||||
- Add `S3_OPEN_TIMEOUT` environment variable ([tateisu](https://github.com/tootsuite/mastodon/pull/12459))
|
||||
- Add `LDAP_MAIL` environment variable ([madmath03](https://github.com/tootsuite/mastodon/pull/12053))
|
||||
- Add `LDAP_UID_CONVERSION_ENABLED` environment variable ([madmath03](https://github.com/tootsuite/mastodon/pull/12461))
|
||||
- Add `--remote-only` option to `tootctl emoji purge` ([ThibG](https://github.com/tootsuite/mastodon/pull/12810))
|
||||
- Add `tootctl media remove-orphans` ([Gargron](https://github.com/tootsuite/mastodon/pull/12568), [Gargron](https://github.com/tootsuite/mastodon/pull/12571))
|
||||
- Add `tootctl media lookup` command ([irlcatgirl](https://github.com/tootsuite/mastodon/pull/12283))
|
||||
- Add cache for OEmbed endpoints to avoid extra HTTP requests ([Gargron](https://github.com/tootsuite/mastodon/pull/12403))
|
||||
- Add support for KaiOS arrow navigation to public pages ([nolanlawson](https://github.com/tootsuite/mastodon/pull/12251))
|
||||
- Add `discoverable` to accounts in REST API ([trwnh](https://github.com/tootsuite/mastodon/pull/12508))
|
||||
- Add admin setting to disable default follows ([ArisuOngaku](https://github.com/tootsuite/mastodon/pull/12566))
|
||||
- Add support for LDAP and PAM in the OAuth password grant strategy ([ntl-purism](https://github.com/tootsuite/mastodon/pull/12390), [Gargron](https://github.com/tootsuite/mastodon/pull/12743))
|
||||
- Allow support for `Accept`/`Reject` activities with a non-embedded object ([puckipedia](https://github.com/tootsuite/mastodon/pull/12199))
|
||||
- Add "Show thread" button to public profiles ([Sasha-Sorokin](https://github.com/tootsuite/mastodon/pull/13000))
|
||||
|
||||
### Changed
|
||||
|
||||
- Change `last_status_at` to be a date, not datetime in REST API ([ThibG](https://github.com/tootsuite/mastodon/pull/12966))
|
||||
- Change followers page to relationships page in admin UI ([Gargron](https://github.com/tootsuite/mastodon/pull/12927), [Gargron](https://github.com/tootsuite/mastodon/pull/12934))
|
||||
- Change reported media attachments to always be hidden in admin UI ([Gargron](https://github.com/tootsuite/mastodon/pull/12879), [ThibG](https://github.com/tootsuite/mastodon/pull/12907))
|
||||
- Change string from "Disable" to "Disable login" in admin UI ([nileshkumar](https://github.com/tootsuite/mastodon/pull/12201))
|
||||
- Change report page structure in admin UI ([Sasha-Sorokin](https://github.com/tootsuite/mastodon/pull/12615))
|
||||
- Change swipe sensitivity to be lower on small screens in web UI ([umonaca](https://github.com/tootsuite/mastodon/pull/12168))
|
||||
- Change audio/video playback to stop playback when out of view in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/12486))
|
||||
- Change media description label based on upload type in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12270))
|
||||
- Change large numbers to render without decimal units in web UI ([noellabo](https://github.com/tootsuite/mastodon/pull/12706))
|
||||
- Change "Add a choice" button to be disabled rather than hidden when poll limit reached in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12319), [hinaloe](https://github.com/tootsuite/mastodon/pull/12544))
|
||||
- Change `tootctl statuses remove` to keep statuses favourited or bookmarked by local users ([ThibG](https://github.com/tootsuite/mastodon/pull/11267), [Gomasy](https://github.com/tootsuite/mastodon/pull/12818))
|
||||
- Change domain block behavior to update user records (fast) before deleting data (slower) ([ThibG](https://github.com/tootsuite/mastodon/pull/12247))
|
||||
- Change behaviour to strip audio metadata on uploads ([hugogameiro](https://github.com/tootsuite/mastodon/pull/12171))
|
||||
- Change accepted length of remote media descriptions from 420 to 1,500 characters ([ThibG](https://github.com/tootsuite/mastodon/pull/12262))
|
||||
- Change preferences pages structure ([Sasha-Sorokin](https://github.com/tootsuite/mastodon/pull/12497), [mayaeh](https://github.com/tootsuite/mastodon/pull/12517), [Sasha-Sorokin](https://github.com/tootsuite/mastodon/pull/12801), [Sasha-Sorokin](https://github.com/tootsuite/mastodon/pull/12797), [Sasha-Sorokin](https://github.com/tootsuite/mastodon/pull/12799), [Sasha-Sorokin](https://github.com/tootsuite/mastodon/pull/12793))
|
||||
- Change format of titles in RSS ([devkral](https://github.com/tootsuite/mastodon/pull/8596))
|
||||
- Change favourite icon animation from spring-based motion to CSS animation in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12175))
|
||||
- Change minimum required Node.js version to 10, and default to 12 ([Shleeble](https://github.com/tootsuite/mastodon/pull/12791), [mkody](https://github.com/tootsuite/mastodon/pull/12906), [Shleeble](https://github.com/tootsuite/mastodon/pull/12703))
|
||||
- Change spam check to exempt server staff ([ThibG](https://github.com/tootsuite/mastodon/pull/12874))
|
||||
- Change to fallback to to `Create` audience when `object` has no defined audience ([ThibG](https://github.com/tootsuite/mastodon/pull/12249))
|
||||
- Change Twemoji library to 12.1.3 in web UI ([koyuawsmbrtn](https://github.com/tootsuite/mastodon/pull/12342))
|
||||
- Change blocked users to be hidden from following/followers lists ([ThibG](https://github.com/tootsuite/mastodon/pull/12733))
|
||||
- Change signature verification to ignore signatures with invalid host ([Gargron](https://github.com/tootsuite/mastodon/pull/13033))
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove unused dependencies ([ykzts](https://github.com/tootsuite/mastodon/pull/12861), [mayaeh](https://github.com/tootsuite/mastodon/pull/12826), [ThibG](https://github.com/tootsuite/mastodon/pull/12822), [ykzts](https://github.com/tootsuite/mastodon/pull/12533))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix some translatable strings being used wrongly ([Sasha-Sorokin](https://github.com/tootsuite/mastodon/pull/12569), [Sasha-Sorokin](https://github.com/tootsuite/mastodon/pull/12589), [Sasha-Sorokin](https://github.com/tootsuite/mastodon/pull/12502), [mayaeh](https://github.com/tootsuite/mastodon/pull/12231))
|
||||
- Fix headline of public timeline page when set to local-only ([ykzts](https://github.com/tootsuite/mastodon/pull/12224))
|
||||
- Fix space between tabs not being spread evenly in web UI ([Sasha-Sorokin](https://github.com/tootsuite/mastodon/pull/12944), [Sasha-Sorokin](https://github.com/tootsuite/mastodon/pull/12961), [Sasha-Sorokin](https://github.com/tootsuite/mastodon/pull/12446))
|
||||
- Fix interactive delays in database migrations with no TTY ([Gargron](https://github.com/tootsuite/mastodon/pull/12969))
|
||||
- Fix status overflowing in report dialog in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12959))
|
||||
- Fix unlocalized dropdown button title in web UI ([Sasha-Sorokin](https://github.com/tootsuite/mastodon/pull/12947))
|
||||
- Fix media attachments without file being uploadable ([Gargron](https://github.com/tootsuite/mastodon/pull/12562))
|
||||
- Fix unfollow confirmations in profile directory in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12922))
|
||||
- Fix duplicate `description` meta tag on accounts public pages ([ThibG](https://github.com/tootsuite/mastodon/pull/12923))
|
||||
- Fix slow query of federated timeline ([notozeki](https://github.com/tootsuite/mastodon/pull/12886))
|
||||
- Fix not all of account's active IPs showing up in admin UI ([Gargron](https://github.com/tootsuite/mastodon/pull/12909), [Gargron](https://github.com/tootsuite/mastodon/pull/12943))
|
||||
- Fix search by IP not using alternative browser sessions in admin UI ([Gargron](https://github.com/tootsuite/mastodon/pull/12904))
|
||||
- Fix “X new items” not showing up for slow mode on empty timelines in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12875))
|
||||
- Fix OEmbed endpoint being inaccessible in secure mode ([Gargron](https://github.com/tootsuite/mastodon/pull/12864))
|
||||
- Fix proofs API being inaccessible in secure mode ([Gargron](https://github.com/tootsuite/mastodon/pull/12495))
|
||||
- Fix Ruby 2.7 incompatibilities ([ThibG](https://github.com/tootsuite/mastodon/pull/12831), [ThibG](https://github.com/tootsuite/mastodon/pull/12824), [Shleeble](https://github.com/tootsuite/mastodon/pull/12759), [zunda](https://github.com/tootsuite/mastodon/pull/12769))
|
||||
- Fix invalid poll votes being accepted in REST API ([ThibG](https://github.com/tootsuite/mastodon/pull/12601))
|
||||
- Fix old migrations failing because of strong migrations update ([ThibG](https://github.com/tootsuite/mastodon/pull/12787), [ThibG](https://github.com/tootsuite/mastodon/pull/12692))
|
||||
- Fix reuse of detailed status components in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12792))
|
||||
- Fix base64-encoded file uploads not being possible in REST API ([Gargron](https://github.com/tootsuite/mastodon/pull/12748), [Gargron](https://github.com/tootsuite/mastodon/pull/12857))
|
||||
- Fix error due to missing authentication call in filters controller ([Gargron](https://github.com/tootsuite/mastodon/pull/12746))
|
||||
- Fix uncaught unknown format error in host meta controller ([Gargron](https://github.com/tootsuite/mastodon/pull/12747))
|
||||
- Fix URL search not returning private toots user has access to ([ThibG](https://github.com/tootsuite/mastodon/pull/12742), [ThibG](https://github.com/tootsuite/mastodon/pull/12336))
|
||||
- Fix cache digesting log noise on status embeds ([Gargron](https://github.com/tootsuite/mastodon/pull/12750))
|
||||
- Fix slowness due to layout thrashing when reloading a large set of statuses in web UI ([panarom](https://github.com/tootsuite/mastodon/pull/12661), [panarom](https://github.com/tootsuite/mastodon/pull/12744), [Gargron](https://github.com/tootsuite/mastodon/pull/12712))
|
||||
- Fix error when fetching followers/following from REST API when user has network hidden ([Gargron](https://github.com/tootsuite/mastodon/pull/12716))
|
||||
- Fix IDN mentions not being processed, IDN domains not being rendered ([Gargron](https://github.com/tootsuite/mastodon/pull/12715), [Gargron](https://github.com/tootsuite/mastodon/pull/13035), [Gargron](https://github.com/tootsuite/mastodon/pull/13030))
|
||||
- Fix error when searching for empty phrase ([Gargron](https://github.com/tootsuite/mastodon/pull/12711))
|
||||
- Fix backups stopping due to read timeouts ([chr-1x](https://github.com/tootsuite/mastodon/pull/12281))
|
||||
- Fix batch actions on non-pending tags in admin UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12537))
|
||||
- Fix sample `SAML_ACS_URL`, `SAML_ISSUER` ([orlea](https://github.com/tootsuite/mastodon/pull/12669))
|
||||
- Fix manual scrolling issue on Firefox/Windows in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12648))
|
||||
- Fix archive takeout failing if total dump size exceeds 2GB ([scd31](https://github.com/tootsuite/mastodon/pull/12602), [Gargron](https://github.com/tootsuite/mastodon/pull/12653))
|
||||
- Fix custom emoji category creation silently erroring out on duplicate category ([ThibG](https://github.com/tootsuite/mastodon/pull/12647))
|
||||
- Fix link crawler not specifying preferred content type ([ThibG](https://github.com/tootsuite/mastodon/pull/12646))
|
||||
- Fix featured hashtag setting page erroring out instead of rejecting invalid tags ([ThibG](https://github.com/tootsuite/mastodon/pull/12436))
|
||||
- Fix tooltip messages of single/multiple-choice polls switcher being reversed in web UI ([acid-chicken](https://github.com/tootsuite/mastodon/pull/12616))
|
||||
- Fix typo in help text of `tootctl statuses remove` ([trwnh](https://github.com/tootsuite/mastodon/pull/12603))
|
||||
- Fix generic HTTP 500 error on duplicate records ([Gargron](https://github.com/tootsuite/mastodon/pull/12563))
|
||||
- Fix old migration failing with new status default scope ([ThibG](https://github.com/tootsuite/mastodon/pull/12493))
|
||||
- Fix errors when using search API with no query ([Gargron](https://github.com/tootsuite/mastodon/pull/12541), [trwnh](https://github.com/tootsuite/mastodon/pull/12549))
|
||||
- Fix poll options not being selectable via keyboard in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12538))
|
||||
- Fix conversations not having an unread indicator in web UI ([Gargron](https://github.com/tootsuite/mastodon/pull/12506))
|
||||
- Fix lost focus when modals open/close in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12437))
|
||||
- Fix pending upload count not being decremented on error in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12499))
|
||||
- Fix empty poll options not being removed on remote poll update ([ThibG](https://github.com/tootsuite/mastodon/pull/12484))
|
||||
- Fix OCR with delete & redraft in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12465))
|
||||
- Fix blur behind closed registration message ([ThibG](https://github.com/tootsuite/mastodon/pull/12442))
|
||||
- Fix OEmbed discovery not handling different URL variants in query ([Gargron](https://github.com/tootsuite/mastodon/pull/12439))
|
||||
- Fix link crawler crashing on `<a>` tags without `href` ([ThibG](https://github.com/tootsuite/mastodon/pull/12159))
|
||||
- Fix whitelisted subdomains being ignored in whitelist mode ([noiob](https://github.com/tootsuite/mastodon/pull/12435))
|
||||
- Fix broken audit log in whitelist mode in admin UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12303))
|
||||
- Fix unread indicator not honoring "Only media" option in local and federated timelines in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12330))
|
||||
- Fix error when rebuilding home feeds ([dariusk](https://github.com/tootsuite/mastodon/pull/12324))
|
||||
- Fix relationship caches being broken as result of a follow request ([ThibG](https://github.com/tootsuite/mastodon/pull/12299))
|
||||
- Fix more items than the limit being uploadable in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12300))
|
||||
- Fix various issues with account migration ([ThibG](https://github.com/tootsuite/mastodon/pull/12301))
|
||||
- Fix filtered out items being counted as pending items in slow mode in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12266))
|
||||
- Fix notification filters not applying to poll options ([ThibG](https://github.com/tootsuite/mastodon/pull/12269))
|
||||
- Fix notification message for user's own poll saying it's a poll they voted on in web UI ([ykzts](https://github.com/tootsuite/mastodon/pull/12219))
|
||||
- Fix polls with an expiration not showing up as expired in web UI ([noellabo](https://github.com/tootsuite/mastodon/pull/12222))
|
||||
- Fix volume slider having an offset between cursor and slider in Chromium in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12158))
|
||||
- Fix Vagrant image not accepting connections ([shrft](https://github.com/tootsuite/mastodon/pull/12180))
|
||||
- Fix batch actions being hidden on small screens in admin UI ([ThibG](https://github.com/tootsuite/mastodon/pull/12183))
|
||||
- Fix incoming federation not working in whitelist mode ([ThibG](https://github.com/tootsuite/mastodon/pull/12185))
|
||||
- Fix error when passing empty `source` param to `PUT /api/v1/accounts/update_credentials` ([jglauche](https://github.com/tootsuite/mastodon/pull/12259))
|
||||
- Fix HTTP-based streaming API being cacheable by proxies ([BenLubar](https://github.com/tootsuite/mastodon/pull/12945))
|
||||
- Fix users being able to register while `tootctl self-destruct` is in progress ([Kjwon15](https://github.com/tootsuite/mastodon/pull/12877))
|
||||
- Fix microformats detection in link crawler not ignoring `h-card` links ([nightpool](https://github.com/tootsuite/mastodon/pull/12189))
|
||||
- Fix outline on full-screen video in web UI ([hinaloe](https://github.com/tootsuite/mastodon/pull/12176))
|
||||
- Fix TLD domain blocks not being editable ([ThibG](https://github.com/tootsuite/mastodon/pull/12805))
|
||||
- Fix Nanobox deploy hooks ([danhunsaker](https://github.com/tootsuite/mastodon/pull/12663))
|
||||
- Fix needlessly complicated SQL query when performing account search amongst followings ([ThibG](https://github.com/tootsuite/mastodon/pull/12302))
|
||||
- Fix favourites count not updating when unfavouriting in web UI ([NimaBoscarino](https://github.com/tootsuite/mastodon/pull/12140))
|
||||
- Fix occasional crash on scroll in Chromium in web UI ([hinaloe](https://github.com/tootsuite/mastodon/pull/12274))
|
||||
- Fix intersection observer not working in single-column mode web UI ([panarom](https://github.com/tootsuite/mastodon/pull/12735))
|
||||
- Fix voting issue with remote polls that contain trailing spaces ([ThibG](https://github.com/tootsuite/mastodon/pull/12515))
|
||||
- Fix dynamic elements not working in pgHero due to CSP rules ([ykzts](https://github.com/tootsuite/mastodon/pull/12489))
|
||||
- Fix overly verbose backtraces when delivering ActivityPub payloads ([zunda](https://github.com/tootsuite/mastodon/pull/12798))
|
||||
- Fix rendering `<a>` without `href` when scheme unsupported ([Gargron](https://github.com/tootsuite/mastodon/pull/13040))
|
||||
- Fix unfiltered params error when generating ActivityPub tag pagination ([Gargron](https://github.com/tootsuite/mastodon/pull/13049))
|
||||
- Fix malformed HTML causing uncaught error ([Gargron](https://github.com/tootsuite/mastodon/pull/13042))
|
||||
- Fix native share button not being displayed for unlisted toots ([ThibG](https://github.com/tootsuite/mastodon/pull/13045))
|
||||
- Fix remote convertible media attachments (e.g. GIFs) not being saved ([Gargron](https://github.com/tootsuite/mastodon/pull/13032))
|
||||
- Fix account query not using faster index ([abcang](https://github.com/tootsuite/mastodon/pull/13016))
|
||||
- Fix error when sending moderation notification ([renatolond](https://github.com/tootsuite/mastodon/pull/13014))
|
||||
|
||||
### Security
|
||||
|
||||
- Fix OEmbed leaking information about existence of non-public statuses ([Gargron](https://github.com/tootsuite/mastodon/pull/12930))
|
||||
- Fix password change/reset not immediately invalidating other sessions ([Gargron](https://github.com/tootsuite/mastodon/pull/12928))
|
||||
- Fix settings pages being cacheable by the browser ([Gargron](https://github.com/tootsuite/mastodon/pull/12714))
|
||||
|
||||
## [3.0.1] - 2019-10-10
|
||||
### Added
|
||||
|
||||
|
|
|
@ -14,13 +14,13 @@ If your contributions are accepted into Mastodon, you can request to be paid thr
|
|||
|
||||
## Bug reports
|
||||
|
||||
Bug reports and feature suggestions can be submitted to [GitHub Issues](https://github.com/tootsuite/mastodon/issues). Please make sure that you are not submitting duplicates, and that a similar report or request has not already been resolved or rejected in the past using the search function. Please also use descriptive, concise titles.
|
||||
Bug reports and feature suggestions must use descriptive and concise titles and be submitted to [GitHub Issues](https://github.com/tootsuite/mastodon/issues). Please use the search function to make sure that you are not submitting duplicates, and that a similar report or request has not already been resolved or rejected.
|
||||
|
||||
## Translations
|
||||
|
||||
You can submit translations via [Crowdin](https://crowdin.com/project/mastodon). They are periodically merged into the codebase.
|
||||
|
||||
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/mastodon/localized.svg)][crowdin]
|
||||
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/mastodon/localized.svg)](https://crowdin.com/project/mastodon)
|
||||
|
||||
## Pull requests
|
||||
|
||||
|
|
34
Dockerfile
34
Dockerfile
|
@ -3,16 +3,27 @@ FROM ubuntu:18.04 as build-dep
|
|||
# Use bash for the shell
|
||||
SHELL ["bash", "-c"]
|
||||
|
||||
# Install Node
|
||||
ENV NODE_VER="12.11.1"
|
||||
RUN echo "Etc/UTC" > /etc/localtime && \
|
||||
# Install Node v12 (LTS)
|
||||
ENV NODE_VER="12.16.1"
|
||||
RUN ARCH= && \
|
||||
dpkgArch="$(dpkg --print-architecture)" && \
|
||||
case "${dpkgArch##*-}" in \
|
||||
amd64) ARCH='x64';; \
|
||||
ppc64el) ARCH='ppc64le';; \
|
||||
s390x) ARCH='s390x';; \
|
||||
arm64) ARCH='arm64';; \
|
||||
armhf) ARCH='armv7l';; \
|
||||
i386) ARCH='x86';; \
|
||||
*) echo "unsupported architecture"; exit 1 ;; \
|
||||
esac && \
|
||||
echo "Etc/UTC" > /etc/localtime && \
|
||||
apt update && \
|
||||
apt -y install wget python && \
|
||||
cd ~ && \
|
||||
wget https://nodejs.org/download/release/v$NODE_VER/node-v$NODE_VER-linux-x64.tar.gz && \
|
||||
tar xf node-v$NODE_VER-linux-x64.tar.gz && \
|
||||
rm node-v$NODE_VER-linux-x64.tar.gz && \
|
||||
mv node-v$NODE_VER-linux-x64 /opt/node
|
||||
wget https://nodejs.org/download/release/v$NODE_VER/node-v$NODE_VER-linux-$ARCH.tar.gz && \
|
||||
tar xf node-v$NODE_VER-linux-$ARCH.tar.gz && \
|
||||
rm node-v$NODE_VER-linux-$ARCH.tar.gz && \
|
||||
mv node-v$NODE_VER-linux-$ARCH /opt/node
|
||||
|
||||
# Install jemalloc
|
||||
ENV JE_VER="5.2.1"
|
||||
|
@ -27,8 +38,8 @@ RUN apt update && \
|
|||
make -j$(nproc) > /dev/null && \
|
||||
make install_bin install_include install_lib
|
||||
|
||||
# Install ruby
|
||||
ENV RUBY_VER="2.6.5"
|
||||
# Install Ruby
|
||||
ENV RUBY_VER="2.6.6"
|
||||
ENV CPPFLAGS="-I/opt/jemalloc/include"
|
||||
ENV LDFLAGS="-L/opt/jemalloc/lib/"
|
||||
RUN apt update && \
|
||||
|
@ -58,7 +69,9 @@ RUN npm install -g yarn && \
|
|||
COPY Gemfile* package.json yarn.lock /opt/mastodon/
|
||||
|
||||
RUN cd /opt/mastodon && \
|
||||
bundle install -j$(nproc) --deployment --without development test && \
|
||||
bundle config set deployment 'true' && \
|
||||
bundle config set without 'development test' && \
|
||||
bundle install -j$(nproc) && \
|
||||
yarn install --pure-lockfile
|
||||
|
||||
FROM ubuntu:18.04
|
||||
|
@ -123,3 +136,4 @@ RUN cd ~ && \
|
|||
# Set the work dir and the container entry point
|
||||
WORKDIR /opt/mastodon
|
||||
ENTRYPOINT ["/tini", "--"]
|
||||
EXPOSE 3000 4000
|
||||
|
|
112
Gemfile
112
Gemfile
|
@ -1,21 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
source 'https://rubygems.org'
|
||||
ruby '>= 2.4.0', '< 2.7.0'
|
||||
ruby '>= 2.5.0', '< 3.0.0'
|
||||
|
||||
gem 'pkg-config', '~> 1.3'
|
||||
gem 'pkg-config', '~> 1.4'
|
||||
|
||||
gem 'puma', '~> 4.2'
|
||||
gem 'rails', '~> 5.2.3'
|
||||
gem 'puma', '~> 4.3'
|
||||
gem 'rails', '~> 5.2.4.2'
|
||||
gem 'sprockets', '~> 3.7.2'
|
||||
gem 'thor', '~> 0.20'
|
||||
gem 'rack', '~> 2.2.2'
|
||||
|
||||
gem 'thwait', '~> 0.1.0'
|
||||
gem 'e2mmap', '~> 0.1.0'
|
||||
|
||||
gem 'hamlit-rails', '~> 0.2'
|
||||
gem 'pg', '~> 1.1'
|
||||
gem 'pg', '~> 1.2'
|
||||
gem 'makara', '~> 0.4'
|
||||
gem 'pghero', '~> 2.3'
|
||||
gem 'pghero', '~> 2.4'
|
||||
gem 'dotenv-rails', '~> 2.7'
|
||||
|
||||
gem 'aws-sdk-s3', '~> 1.48', require: false
|
||||
gem 'aws-sdk-s3', '~> 1.64', require: false
|
||||
gem 'fog-core', '<= 2.1.0'
|
||||
gem 'fog-openstack', '~> 0.3', require: false
|
||||
gem 'paperclip', '~> 6.0'
|
||||
|
@ -27,10 +32,10 @@ gem 'active_model_serializers', '~> 0.10'
|
|||
gem 'addressable', '~> 2.7'
|
||||
gem 'bootsnap', '~> 1.4', require: false
|
||||
gem 'browser'
|
||||
gem 'charlock_holmes', '~> 0.7.6'
|
||||
gem 'charlock_holmes', '~> 0.7.7'
|
||||
gem 'iso-639'
|
||||
gem 'chewy', '~> 5.1'
|
||||
gem 'cld3', '~> 3.2.4'
|
||||
gem 'cld3', '~> 3.3.0'
|
||||
gem 'devise', '~> 4.7'
|
||||
gem 'devise-two-factor', '~> 3.1'
|
||||
|
||||
|
@ -38,75 +43,74 @@ group :pam_authentication, optional: true do
|
|||
gem 'devise_pam_authenticatable2', '~> 9.2'
|
||||
end
|
||||
|
||||
gem 'net-ldap', '~> 0.10'
|
||||
gem 'net-ldap', '~> 0.16'
|
||||
gem 'omniauth-cas', '~> 1.1'
|
||||
gem 'omniauth-saml', '~> 1.10'
|
||||
gem 'omniauth', '~> 1.9'
|
||||
|
||||
gem 'discard', '~> 1.1'
|
||||
gem 'doorkeeper', '~> 5.2'
|
||||
gem 'discard', '~> 1.2'
|
||||
gem 'doorkeeper', '~> 5.4'
|
||||
gem 'fast_blank', '~> 1.0'
|
||||
gem 'fastimage'
|
||||
gem 'goldfinger', '~> 2.1'
|
||||
gem 'hiredis', '~> 0.6'
|
||||
gem 'redis-namespace', '~> 1.5'
|
||||
gem 'redis-namespace', '~> 1.7'
|
||||
gem 'health_check', git: 'https://github.com/ianheggie/health_check', ref: '0b799ead604f900ed50685e9b2d469cd2befba5b'
|
||||
gem 'htmlentities', '~> 4.3'
|
||||
gem 'http', '~> 3.3'
|
||||
gem 'http', '~> 4.4'
|
||||
gem 'http_accept_language', '~> 2.1'
|
||||
gem 'http_parser.rb', '~> 0.6', git: 'https://github.com/tmm1/http_parser.rb', ref: '54b17ba8c7d8d20a16dfc65d1775241833219cf2', submodules: true
|
||||
gem 'httplog', '~> 1.3'
|
||||
gem 'httplog', '~> 1.4.2'
|
||||
gem 'idn-ruby', require: 'idn'
|
||||
gem 'kaminari', '~> 1.1'
|
||||
gem 'kaminari', '~> 1.2'
|
||||
gem 'link_header', '~> 0.0'
|
||||
gem 'mime-types', '~> 3.3', require: 'mime/types/columnar'
|
||||
gem 'mime-types', '~> 3.3.1', require: 'mime/types/columnar'
|
||||
gem 'nilsimsa', git: 'https://github.com/witgo/nilsimsa', ref: 'fd184883048b922b176939f851338d0a4971a532'
|
||||
gem 'nokogiri', '~> 1.10'
|
||||
gem 'nsa', '~> 0.2'
|
||||
gem 'oj', '~> 3.9'
|
||||
gem 'ostatus2', '~> 2.0'
|
||||
gem 'ox', '~> 2.11'
|
||||
gem 'oj', '~> 3.10'
|
||||
gem 'ox', '~> 2.13'
|
||||
gem 'parslet'
|
||||
gem 'parallel', '~> 1.17'
|
||||
gem 'parallel', '~> 1.19'
|
||||
gem 'posix-spawn', git: 'https://github.com/rtomayko/posix-spawn', ref: '58465d2e213991f8afb13b984854a49fcdcc980c'
|
||||
gem 'pundit', '~> 2.1'
|
||||
gem 'premailer-rails'
|
||||
gem 'rack-attack', '~> 6.1'
|
||||
gem 'rack-cors', '~> 1.0', require: 'rack/cors'
|
||||
gem 'rack-attack', '~> 6.3'
|
||||
gem 'rack-cors', '~> 1.1', require: 'rack/cors'
|
||||
gem 'rails-i18n', '~> 5.1'
|
||||
gem 'rails-settings-cached', '~> 0.6'
|
||||
gem 'redis', '~> 4.1', require: ['redis', 'redis/connection/hiredis']
|
||||
gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
|
||||
gem 'rqrcode', '~> 0.10'
|
||||
gem 'rqrcode', '~> 1.1'
|
||||
gem 'ruby-progressbar', '~> 1.10'
|
||||
gem 'sanitize', '~> 5.1'
|
||||
gem 'sidekiq', '~> 5.2'
|
||||
gem 'sidekiq', '~> 6.0'
|
||||
gem 'sidekiq-scheduler', '~> 3.0'
|
||||
gem 'sidekiq-unique-jobs', '~> 6.0'
|
||||
gem 'sidekiq-bulk', '~>0.2.0'
|
||||
gem 'simple-navigation', '~> 4.1'
|
||||
gem 'simple_form', '~> 4.1'
|
||||
gem 'simple_form', '~> 5.0'
|
||||
gem 'sprockets-rails', '~> 3.2', require: 'sprockets/railtie'
|
||||
gem 'stoplight', '~> 2.1.3'
|
||||
gem 'strong_migrations', '~> 0.4'
|
||||
gem 'stoplight', '~> 2.2.0'
|
||||
gem 'strong_migrations', '~> 0.6'
|
||||
gem 'tty-command', '~> 0.9', require: false
|
||||
gem 'tty-prompt', '~> 0.19', require: false
|
||||
gem 'tty-prompt', '~> 0.21', require: false
|
||||
gem 'twitter-text', '~> 1.14'
|
||||
gem 'tzinfo-data', '~> 1.2019'
|
||||
gem 'webpacker', '~> 4.0'
|
||||
gem 'tzinfo-data', '~> 1.2020'
|
||||
gem 'webpacker', '~> 5.1'
|
||||
gem 'webpush'
|
||||
|
||||
gem 'json-ld', git: 'https://github.com/ruby-rdf/json-ld.git', ref: 'e742697a0906e74e8bb777ef98137bc3955d981d'
|
||||
gem 'json-ld-preloaded', '~> 3.0'
|
||||
gem 'rdf-normalize', '~> 0.3'
|
||||
gem 'json-ld'
|
||||
gem 'json-ld-preloaded', '~> 3.1'
|
||||
gem 'rdf-normalize', '~> 0.4'
|
||||
|
||||
group :development, :test do
|
||||
gem 'fabrication', '~> 2.20'
|
||||
gem 'fuubar', '~> 2.4'
|
||||
gem 'fabrication', '~> 2.21'
|
||||
gem 'fuubar', '~> 2.5'
|
||||
gem 'i18n-tasks', '~> 0.9', require: false
|
||||
gem 'pry-byebug', '~> 3.7'
|
||||
gem 'pry-byebug', '~> 3.9'
|
||||
gem 'pry-rails', '~> 0.3'
|
||||
gem 'rspec-rails', '~> 3.8'
|
||||
gem 'rspec-rails', '~> 4.0'
|
||||
end
|
||||
|
||||
group :production, :test do
|
||||
|
@ -114,37 +118,37 @@ group :production, :test do
|
|||
end
|
||||
|
||||
group :test do
|
||||
gem 'capybara', '~> 3.29'
|
||||
gem 'capybara', '~> 3.32'
|
||||
gem 'climate_control', '~> 0.2'
|
||||
gem 'faker', '~> 2.5'
|
||||
gem 'microformats', '~> 4.1'
|
||||
gem 'faker', '~> 2.11'
|
||||
gem 'microformats', '~> 4.2'
|
||||
gem 'rails-controller-testing', '~> 1.0'
|
||||
gem 'rspec-sidekiq', '~> 3.0'
|
||||
gem 'simplecov', '~> 0.17', require: false
|
||||
gem 'webmock', '~> 3.7'
|
||||
gem 'parallel_tests', '~> 2.29'
|
||||
gem 'simplecov', '~> 0.18', require: false
|
||||
gem 'webmock', '~> 3.8'
|
||||
gem 'parallel_tests', '~> 2.32'
|
||||
gem 'rspec_junit_formatter', '~> 0.4'
|
||||
end
|
||||
|
||||
group :development do
|
||||
gem 'active_record_query_trace', '~> 1.6'
|
||||
gem 'annotate', '~> 2.7'
|
||||
gem 'better_errors', '~> 2.5'
|
||||
gem 'active_record_query_trace', '~> 1.7'
|
||||
gem 'annotate', '~> 3.1'
|
||||
gem 'better_errors', '~> 2.7'
|
||||
gem 'binding_of_caller', '~> 0.7'
|
||||
gem 'bullet', '~> 6.0'
|
||||
gem 'bullet', '~> 6.1'
|
||||
gem 'letter_opener', '~> 1.7'
|
||||
gem 'letter_opener_web', '~> 1.3'
|
||||
gem 'letter_opener_web', '~> 1.4'
|
||||
gem 'memory_profiler'
|
||||
gem 'rubocop', '~> 0.74', require: false
|
||||
gem 'rubocop-rails', '~> 2.3', require: false
|
||||
gem 'brakeman', '~> 4.6', require: false
|
||||
gem 'rubocop', '~> 0.82', require: false
|
||||
gem 'rubocop-rails', '~> 2.5', require: false
|
||||
gem 'brakeman', '~> 4.8', require: false
|
||||
gem 'bundler-audit', '~> 0.6', require: false
|
||||
|
||||
gem 'capistrano', '~> 3.11'
|
||||
gem 'capistrano', '~> 3.14'
|
||||
gem 'capistrano-rails', '~> 1.4'
|
||||
gem 'capistrano-rbenv', '~> 2.1'
|
||||
gem 'capistrano-yarn', '~> 2.0'
|
||||
|
||||
gem 'derailed_benchmarks'
|
||||
gem 'stackprof'
|
||||
end
|
||||
|
||||
|
|
663
Gemfile.lock
663
Gemfile.lock
File diff suppressed because it is too large
Load Diff
12
README.md
12
README.md
|
@ -64,13 +64,7 @@ What does this have to do with content types? Well, if we support an `Article` c
|
|||
|
||||
If Hometown is going to be a universal reader, you're going to need better control over organizing your feeds than mainline Mastodon provides.
|
||||
|
||||
### Exclusive lists
|
||||
|
||||
My first plan is to introduce a new kind of _exclusive list_. Right now if you add an account to your "friends I like" list in Mastodon, posts from people on that list appear on that list. But they also appear on your home timeline, and maybe you don't want that! You'd rather treat your "friends I like" list as your "real" home timeline, and then check your home timeline when you're bored.
|
||||
|
||||
Or another case: I might have all the blogs I read in one list, but I only check it on Saturdays when I have time to read things. In that case I don't want updates from those blogs clogging up my home timeline.
|
||||
|
||||
> This is not yet implemented but will be available in the first release.
|
||||
I've introduced a new kind of [exclusive list](https://github.com/hometown-fork/hometown/wiki/Exclusive-lists). In vanilla Mastodon, if you add an account to your "friends I like" list, posts from people on that list appear on that list. But they also appear on your home timeline, and maybe you don't want that! You'd rather treat your "friends I like" list as your "real" home timeline, and then check your home timeline when you're bored. Check out [more details about exclusive lists on the wiki](https://github.com/hometown-fork/hometown/wiki/Exclusive-lists).
|
||||
|
||||
## Better accessibility defaults
|
||||
|
||||
|
@ -88,11 +82,11 @@ Hometown uses [semantic versioning](https://semver.org) and follows a versioning
|
|||
|
||||
## Contributing to Hometown
|
||||
|
||||
Setting up your Hometown development environment is [exactly like setting up your Mastodon development environment](https://docs.joinmastodon.org/development/overview/). Pull requests should be made to the `hometown-dev` branch, which is our default branch in Github.
|
||||
Setting up your Hometown development environment is [exactly like setting up your Mastodon development environment](https://docs.joinmastodon.org/dev/overview/). Pull requests should be made to the `hometown-dev` branch, which is our default branch in Github.
|
||||
|
||||
## License
|
||||
|
||||
Copyright (C) 2016-2019 Eugen Rochko and other Mastodon contributors; see [AUTHORS.md](AUTHORS.md).
|
||||
Copyright (C) 2016-2020 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.
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
|
|||
sudo apt-add-repository 'deb https://dl.yarnpkg.com/debian/ stable main'
|
||||
|
||||
# Add repo for NodeJS
|
||||
curl -sL https://deb.nodesource.com/setup_8.x | sudo bash -
|
||||
curl -sL https://deb.nodesource.com/setup_10.x | sudo bash -
|
||||
|
||||
# Add firewall rule to redirect 80 to PORT and save
|
||||
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port #{ENV["PORT"]}
|
||||
|
@ -91,7 +91,7 @@ VAGRANTFILE_API_VERSION = "2"
|
|||
|
||||
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
|
||||
config.vm.box = "ubuntu/xenial64"
|
||||
config.vm.box = "ubuntu/bionic64"
|
||||
|
||||
config.vm.provider :virtualbox do |vb|
|
||||
vb.name = "mastodon"
|
||||
|
|
|
@ -47,6 +47,11 @@ class StatusesIndex < Chewy::Index
|
|||
data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
|
||||
end
|
||||
|
||||
crutch :bookmarks do |collection|
|
||||
data = ::Bookmark.where(status_id: collection.map(&:id)).where(account: Account.local).pluck(:status_id, :account_id)
|
||||
data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
|
||||
end
|
||||
|
||||
root date_detection: false do
|
||||
field :id, type: 'long'
|
||||
field :account_id, type: 'long'
|
||||
|
|
|
@ -6,7 +6,7 @@ class AccountFollowController < ApplicationController
|
|||
before_action :authenticate_user!
|
||||
|
||||
def create
|
||||
FollowService.new.call(current_user.account, @account.acct)
|
||||
FollowService.new.call(current_user.account, @account, with_rate_limit: true)
|
||||
redirect_to account_path(@account)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,7 +9,7 @@ class AccountsController < ApplicationController
|
|||
before_action :set_cache_headers
|
||||
before_action :set_body_classes
|
||||
|
||||
skip_around_action :set_locale, if: -> { [:json, :rss].include?(request.format) }
|
||||
skip_around_action :set_locale, if: -> { [:json, :rss].include?(request.format&.to_sym) }
|
||||
skip_before_action :require_functional!
|
||||
|
||||
def show
|
||||
|
@ -26,8 +26,12 @@ class AccountsController < ApplicationController
|
|||
return
|
||||
end
|
||||
|
||||
@pinned_statuses = cache_collection(@account.pinned_statuses, Status) if show_pinned_statuses?
|
||||
@statuses = filtered_status_page(params)
|
||||
if current_user.nil?
|
||||
@pinned_statuses = cache_collection(@account.pinned_statuses.without_local_only, Status) if show_pinned_statuses?
|
||||
else
|
||||
@pinned_statuses = cache_collection(@account.pinned_statuses, Status) if show_pinned_statuses?
|
||||
end
|
||||
@statuses = filtered_status_page
|
||||
@statuses = cache_collection(@statuses, Status)
|
||||
@rss_url = rss_url
|
||||
|
||||
|
@ -40,7 +44,7 @@ class AccountsController < ApplicationController
|
|||
format.rss do
|
||||
expires_in 1.minute, public: true
|
||||
|
||||
@statuses = filtered_statuses.without_local_only.without_reblogs.without_replies.limit(PAGE_SIZE)
|
||||
@statuses = filtered_statuses.without_reblogs.without_local_only.limit(PAGE_SIZE)
|
||||
@statuses = cache_collection(@statuses, Status)
|
||||
render xml: RSS::AccountSerializer.render(@account, @statuses, params[:tag])
|
||||
end
|
||||
|
@ -133,23 +137,23 @@ class AccountsController < ApplicationController
|
|||
end
|
||||
|
||||
def media_requested?
|
||||
request.path.ends_with?('/media') && !tag_requested?
|
||||
request.path.split('.').first.ends_with?('/media') && !tag_requested?
|
||||
end
|
||||
|
||||
def replies_requested?
|
||||
request.path.ends_with?('/with_replies') && !tag_requested?
|
||||
request.path.split('.').first.ends_with?('/with_replies') && !tag_requested?
|
||||
end
|
||||
|
||||
def tag_requested?
|
||||
request.path.split('.').first.ends_with?(Addressable::URI.parse("/tagged/#{params[:tag]}").normalize)
|
||||
end
|
||||
|
||||
def filtered_status_page(params)
|
||||
if params[:min_id].present?
|
||||
filtered_statuses.paginate_by_min_id(PAGE_SIZE, params[:min_id]).reverse
|
||||
else
|
||||
filtered_statuses.paginate_by_max_id(PAGE_SIZE, params[:max_id], params[:since_id]).to_a
|
||||
end
|
||||
def filtered_status_page
|
||||
filtered_statuses.paginate_by_id(PAGE_SIZE, params_slice(:max_id, :min_id, :since_id))
|
||||
end
|
||||
|
||||
def params_slice(*keys)
|
||||
params.slice(*keys).permit(*keys)
|
||||
end
|
||||
|
||||
def restrict_fields_to
|
||||
|
|
|
@ -24,20 +24,23 @@ class ActivityPub::CollectionsController < ActivityPub::BaseController
|
|||
def set_size
|
||||
case params[:id]
|
||||
when 'featured'
|
||||
@account.pinned_statuses.count
|
||||
@size = @account.pinned_statuses.count
|
||||
else
|
||||
raise ActiveRecord::RecordNotFound
|
||||
not_found
|
||||
end
|
||||
end
|
||||
|
||||
def scope_for_collection
|
||||
case params[:id]
|
||||
when 'featured'
|
||||
return Status.none if @account.blocking?(signed_request_account)
|
||||
|
||||
@account.pinned_statuses
|
||||
else
|
||||
raise ActiveRecord::RecordNotFound
|
||||
# Because in public fetch mode we cache the response, there would be no
|
||||
# benefit from performing the check below, since a blocked account or domain
|
||||
# would likely be served the cache from the reverse proxy anyway
|
||||
if authorized_fetch_mode? && !signed_request_account.nil? && (@account.blocking?(signed_request_account) || (!signed_request_account.domain.nil? && @account.domain_blocking?(signed_request_account.domain)))
|
||||
Status.none
|
||||
else
|
||||
@account.pinned_statuses
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ class ActivityPub::InboxesController < ActivityPub::BaseController
|
|||
|
||||
before_action :skip_unknown_actor_delete
|
||||
before_action :require_signature!
|
||||
skip_before_action :authenticate_user!
|
||||
|
||||
def create
|
||||
upgrade_account
|
||||
|
@ -48,7 +49,7 @@ class ActivityPub::InboxesController < ActivityPub::BaseController
|
|||
ResolveAccountWorker.perform_async(signed_request_account.acct)
|
||||
end
|
||||
|
||||
DeliveryFailureTracker.track_inverse_success!(signed_request_account)
|
||||
DeliveryFailureTracker.reset!(signed_request_account.inbox_url)
|
||||
end
|
||||
|
||||
def process_payload
|
||||
|
|
|
@ -11,7 +11,7 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
|
|||
before_action :set_cache_headers
|
||||
|
||||
def show
|
||||
expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode?)
|
||||
expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode? && !(signed_request_account.present? && page_requested?))
|
||||
render json: outbox_presenter, serializer: ActivityPub::OutboxSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
|
||||
end
|
||||
|
||||
|
@ -50,12 +50,12 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
|
|||
return unless page_requested?
|
||||
|
||||
@statuses = @account.statuses.permitted_for(@account, signed_request_account)
|
||||
@statuses = params[:min_id].present? ? @statuses.paginate_by_min_id(LIMIT, params[:min_id]).reverse : @statuses.paginate_by_max_id(LIMIT, params[:max_id])
|
||||
@statuses = @statuses.paginate_by_id(LIMIT, params_slice(:max_id, :min_id, :since_id))
|
||||
@statuses = cache_collection(@statuses, Status)
|
||||
end
|
||||
|
||||
def page_requested?
|
||||
params[:page] == 'true'
|
||||
truthy_param?(:page)
|
||||
end
|
||||
|
||||
def page_params
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub::RepliesController < ActivityPub::BaseController
|
||||
include SignatureAuthentication
|
||||
include SignatureVerification
|
||||
include Authorization
|
||||
include AccountOwnedConcern
|
||||
|
||||
|
@ -19,15 +19,19 @@ class ActivityPub::RepliesController < ActivityPub::BaseController
|
|||
|
||||
private
|
||||
|
||||
def pundit_user
|
||||
signed_request_account
|
||||
end
|
||||
|
||||
def set_status
|
||||
@status = @account.statuses.find(params[:status_id])
|
||||
authorize @status, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
raise ActiveRecord::RecordNotFound
|
||||
not_found
|
||||
end
|
||||
|
||||
def set_replies
|
||||
@replies = page_params[:only_other_accounts] ? Status.where.not(account_id: @account.id) : @account.statuses
|
||||
@replies = only_other_accounts? ? Status.where.not(account_id: @account.id) : @account.statuses
|
||||
@replies = @replies.where(in_reply_to_id: @status.id, visibility: [:public, :unlisted])
|
||||
@replies = @replies.paginate_by_min_id(DESCENDANTS_LIMIT, params[:min_id])
|
||||
end
|
||||
|
@ -38,7 +42,7 @@ class ActivityPub::RepliesController < ActivityPub::BaseController
|
|||
type: :unordered,
|
||||
part_of: account_status_replies_url(@account, @status),
|
||||
next: next_page,
|
||||
items: @replies.map { |status| status.local ? status : status.uri }
|
||||
items: @replies.map { |status| status.local? ? status : status.uri }
|
||||
)
|
||||
|
||||
return page if page_requested?
|
||||
|
@ -51,16 +55,21 @@ class ActivityPub::RepliesController < ActivityPub::BaseController
|
|||
end
|
||||
|
||||
def page_requested?
|
||||
params[:page] == 'true'
|
||||
truthy_param?(:page)
|
||||
end
|
||||
|
||||
def only_other_accounts?
|
||||
truthy_param?(:only_other_accounts)
|
||||
end
|
||||
|
||||
def next_page
|
||||
only_other_accounts = !(@replies&.last&.account_id == @account.id && @replies.size == DESCENDANTS_LIMIT)
|
||||
|
||||
account_status_replies_url(
|
||||
@account,
|
||||
@status,
|
||||
page: true,
|
||||
min_id: only_other_accounts && !page_params[:only_other_accounts] ? nil : @replies&.last&.id,
|
||||
min_id: only_other_accounts && !only_other_accounts? ? nil : @replies&.last&.id,
|
||||
only_other_accounts: only_other_accounts
|
||||
)
|
||||
end
|
||||
|
|
|
@ -109,21 +109,7 @@ module Admin
|
|||
end
|
||||
|
||||
def filter_params
|
||||
params.permit(
|
||||
:local,
|
||||
:remote,
|
||||
:by_domain,
|
||||
:active,
|
||||
:pending,
|
||||
:disabled,
|
||||
:silenced,
|
||||
:suspended,
|
||||
:username,
|
||||
:display_name,
|
||||
:email,
|
||||
:ip,
|
||||
:staff
|
||||
)
|
||||
params.slice(*AccountFilter::KEYS).permit(*AccountFilter::KEYS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,8 +2,18 @@
|
|||
|
||||
module Admin
|
||||
class ActionLogsController < BaseController
|
||||
def index
|
||||
@action_logs = Admin::ActionLog.page(params[:page])
|
||||
before_action :set_action_logs
|
||||
|
||||
def index; end
|
||||
|
||||
private
|
||||
|
||||
def set_action_logs
|
||||
@action_logs = Admin::ActionLogFilter.new(filter_params).results.page(params[:page])
|
||||
end
|
||||
|
||||
def filter_params
|
||||
params.slice(:page, *Admin::ActionLogFilter::KEYS).permit(:page, *Admin::ActionLogFilter::KEYS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Admin::AnnouncementsController < Admin::BaseController
|
||||
before_action :set_announcements, only: :index
|
||||
before_action :set_announcement, except: [:index, :new, :create]
|
||||
|
||||
def index
|
||||
authorize :announcement, :index?
|
||||
end
|
||||
|
||||
def new
|
||||
authorize :announcement, :create?
|
||||
|
||||
@announcement = Announcement.new
|
||||
end
|
||||
|
||||
def create
|
||||
authorize :announcement, :create?
|
||||
|
||||
@announcement = Announcement.new(resource_params)
|
||||
|
||||
if @announcement.save
|
||||
PublishScheduledAnnouncementWorker.perform_async(@announcement.id) if @announcement.published?
|
||||
log_action :create, @announcement
|
||||
redirect_to admin_announcements_path, notice: @announcement.published? ? I18n.t('admin.announcements.published_msg') : I18n.t('admin.announcements.scheduled_msg')
|
||||
else
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
authorize :announcement, :update?
|
||||
end
|
||||
|
||||
def update
|
||||
authorize :announcement, :update?
|
||||
|
||||
if @announcement.update(resource_params)
|
||||
PublishScheduledAnnouncementWorker.perform_async(@announcement.id) if @announcement.published?
|
||||
log_action :update, @announcement
|
||||
redirect_to admin_announcements_path, notice: I18n.t('admin.announcements.updated_msg')
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
def publish
|
||||
authorize :announcement, :update?
|
||||
@announcement.publish!
|
||||
PublishScheduledAnnouncementWorker.perform_async(@announcement.id)
|
||||
log_action :update, @announcement
|
||||
redirect_to admin_announcements_path, notice: I18n.t('admin.announcements.published_msg')
|
||||
end
|
||||
|
||||
def unpublish
|
||||
authorize :announcement, :update?
|
||||
@announcement.unpublish!
|
||||
UnpublishAnnouncementWorker.perform_async(@announcement.id)
|
||||
log_action :update, @announcement
|
||||
redirect_to admin_announcements_path, notice: I18n.t('admin.announcements.unpublished_msg')
|
||||
end
|
||||
|
||||
def destroy
|
||||
authorize :announcement, :destroy?
|
||||
@announcement.destroy!
|
||||
UnpublishAnnouncementWorker.perform_async(@announcement.id) if @announcement.published?
|
||||
log_action :destroy, @announcement
|
||||
redirect_to admin_announcements_path, notice: I18n.t('admin.announcements.destroyed_msg')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_announcements
|
||||
@announcements = AnnouncementFilter.new(filter_params).results.page(params[:page])
|
||||
end
|
||||
|
||||
def set_announcement
|
||||
@announcement = Announcement.find(params[:id])
|
||||
end
|
||||
|
||||
def filter_params
|
||||
params.slice(*AnnouncementFilter::KEYS).permit(*AnnouncementFilter::KEYS)
|
||||
end
|
||||
|
||||
def resource_params
|
||||
params.require(:announcement).permit(:text, :scheduled_at, :starts_at, :ends_at, :all_day)
|
||||
end
|
||||
end
|
|
@ -2,10 +2,6 @@
|
|||
|
||||
module Admin
|
||||
class CustomEmojisController < BaseController
|
||||
include ObfuscateFilename
|
||||
|
||||
obfuscate_filename [:custom_emoji, :image]
|
||||
|
||||
def index
|
||||
authorize :custom_emoji, :index?
|
||||
|
||||
|
@ -52,7 +48,7 @@ module Admin
|
|||
end
|
||||
|
||||
def filter_params
|
||||
params.slice(:local, :remote, :by_domain, :shortcode, :page).permit(:local, :remote, :by_domain, :shortcode, :page)
|
||||
params.slice(:page, *CustomEmojiFilter::KEYS).permit(:page, *CustomEmojiFilter::KEYS)
|
||||
end
|
||||
|
||||
def action_from_button
|
||||
|
|
|
@ -6,12 +6,12 @@ module Admin
|
|||
|
||||
def index
|
||||
authorize :email_domain_block, :index?
|
||||
@email_domain_blocks = EmailDomainBlock.page(params[:page])
|
||||
@email_domain_blocks = EmailDomainBlock.where(parent_id: nil).includes(:children).order(id: :desc).page(params[:page])
|
||||
end
|
||||
|
||||
def new
|
||||
authorize :email_domain_block, :create?
|
||||
@email_domain_block = EmailDomainBlock.new
|
||||
@email_domain_block = EmailDomainBlock.new(domain: params[:_domain])
|
||||
end
|
||||
|
||||
def create
|
||||
|
@ -21,6 +21,28 @@ module Admin
|
|||
|
||||
if @email_domain_block.save
|
||||
log_action :create, @email_domain_block
|
||||
|
||||
if @email_domain_block.with_dns_records?
|
||||
hostnames = []
|
||||
ips = []
|
||||
|
||||
Resolv::DNS.open do |dns|
|
||||
dns.timeouts = 1
|
||||
|
||||
hostnames = dns.getresources(@email_domain_block.domain, Resolv::DNS::Resource::IN::MX).to_a.map { |e| e.exchange.to_s }
|
||||
|
||||
([@email_domain_block.domain] + hostnames).uniq.each do |hostname|
|
||||
ips.concat(dns.getresources(hostname, Resolv::DNS::Resource::IN::A).to_a.map { |e| e.address.to_s })
|
||||
ips.concat(dns.getresources(hostname, Resolv::DNS::Resource::IN::AAAA).to_a.map { |e| e.address.to_s })
|
||||
end
|
||||
end
|
||||
|
||||
(hostnames + ips).each do |hostname|
|
||||
another_email_domain_block = EmailDomainBlock.new(domain: hostname, parent: @email_domain_block)
|
||||
log_action :create, another_email_domain_block if another_email_domain_block.save
|
||||
end
|
||||
end
|
||||
|
||||
redirect_to admin_email_domain_blocks_path, notice: I18n.t('admin.email_domain_blocks.created_msg')
|
||||
else
|
||||
render :new
|
||||
|
@ -41,7 +63,7 @@ module Admin
|
|||
end
|
||||
|
||||
def resource_params
|
||||
params.require(:email_domain_block).permit(:domain)
|
||||
params.require(:email_domain_block).permit(:domain, :with_dns_records)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Admin
|
||||
class FollowersController < BaseController
|
||||
before_action :set_account
|
||||
|
||||
PER_PAGE = 40
|
||||
|
||||
def index
|
||||
authorize :account, :index?
|
||||
@followers = @account.followers.local.recent.page(params[:page]).per(PER_PAGE)
|
||||
end
|
||||
|
||||
def set_account
|
||||
@account = Account.find(params[:account_id])
|
||||
end
|
||||
end
|
||||
end
|
|
@ -19,7 +19,7 @@ module Admin
|
|||
@followers_count = Follow.where(target_account: Account.where(domain: params[:id])).count
|
||||
@reports_count = Report.where(target_account: Account.where(domain: params[:id])).count
|
||||
@blocks_count = Block.where(target_account: Account.where(domain: params[:id])).count
|
||||
@available = DeliveryFailureTracker.available?(Account.select(:shared_inbox_url).where(domain: params[:id]).first&.shared_inbox_url)
|
||||
@available = DeliveryFailureTracker.available?(params[:id])
|
||||
@media_storage = MediaAttachment.where(account: Account.where(domain: params[:id])).sum(:file_file_size)
|
||||
@private_comment = @domain_block&.private_comment
|
||||
@public_comment = @domain_block&.public_comment
|
||||
|
@ -62,7 +62,7 @@ module Admin
|
|||
end
|
||||
|
||||
def filter_params
|
||||
params.permit(:limited, :by_domain)
|
||||
params.slice(*InstanceFilter::KEYS).permit(*InstanceFilter::KEYS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -47,7 +47,7 @@ module Admin
|
|||
end
|
||||
|
||||
def filter_params
|
||||
params.permit(:available, :expired)
|
||||
params.slice(*InviteFilter::KEYS).permit(*InviteFilter::KEYS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Admin
|
||||
class RelationshipsController < BaseController
|
||||
before_action :set_account
|
||||
|
||||
PER_PAGE = 40
|
||||
|
||||
def index
|
||||
authorize :account, :index?
|
||||
|
||||
@accounts = RelationshipFilter.new(@account, filter_params).results.page(params[:page]).per(PER_PAGE)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_account
|
||||
@account = Account.find(params[:account_id])
|
||||
end
|
||||
|
||||
def filter_params
|
||||
params.slice(*RelationshipFilter::KEYS).permit(*RelationshipFilter::KEYS)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -52,11 +52,7 @@ module Admin
|
|||
end
|
||||
|
||||
def filter_params
|
||||
params.permit(
|
||||
:account_id,
|
||||
:resolved,
|
||||
:target_account_id
|
||||
)
|
||||
params.slice(*ReportFilter::KEYS).permit(*ReportFilter::KEYS)
|
||||
end
|
||||
|
||||
def set_report
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Admin
|
||||
class SiteUploadsController < BaseController
|
||||
before_action :set_site_upload
|
||||
|
||||
def destroy
|
||||
authorize :settings, :destroy?
|
||||
|
||||
@site_upload.destroy!
|
||||
|
||||
redirect_to edit_admin_settings_path, notice: I18n.t('admin.site_uploads.destroyed_msg')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_site_upload
|
||||
@site_upload = SiteUpload.find(params[:id])
|
||||
end
|
||||
end
|
||||
end
|
|
@ -73,7 +73,7 @@ module Admin
|
|||
end
|
||||
|
||||
def filter_params
|
||||
params.slice(:directory, :reviewed, :unreviewed, :pending_review, :page, :popular, :active, :name).permit(:directory, :reviewed, :unreviewed, :pending_review, :page, :popular, :active, :name)
|
||||
params.slice(:page, *TagFilter::KEYS).permit(:page, *TagFilter::KEYS)
|
||||
end
|
||||
|
||||
def tag_params
|
||||
|
|
|
@ -7,7 +7,7 @@ module Admin
|
|||
def index
|
||||
authorize :account_warning_preset, :index?
|
||||
|
||||
@warning_presets = AccountWarningPreset.all
|
||||
@warning_presets = AccountWarningPreset.alphabetic
|
||||
@warning_preset = AccountWarningPreset.new
|
||||
end
|
||||
|
||||
|
@ -19,7 +19,7 @@ module Admin
|
|||
if @warning_preset.save
|
||||
redirect_to admin_warning_presets_path
|
||||
else
|
||||
@warning_presets = AccountWarningPreset.all
|
||||
@warning_presets = AccountWarningPreset.alphabetic
|
||||
render :index
|
||||
end
|
||||
end
|
||||
|
@ -52,7 +52,7 @@ module Admin
|
|||
end
|
||||
|
||||
def warning_preset_params
|
||||
params.require(:account_warning_preset).permit(:text)
|
||||
params.require(:account_warning_preset).permit(:title, :text)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,6 +20,10 @@ class Api::BaseController < ApplicationController
|
|||
render json: { error: e.to_s }, status: 422
|
||||
end
|
||||
|
||||
rescue_from ActiveRecord::RecordNotUnique do
|
||||
render json: { error: 'Duplicate record' }, status: 422
|
||||
end
|
||||
|
||||
rescue_from ActiveRecord::RecordNotFound do
|
||||
render json: { error: 'Record not found' }, status: 404
|
||||
end
|
||||
|
@ -40,6 +44,10 @@ class Api::BaseController < ApplicationController
|
|||
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 do |e|
|
||||
render json: { error: e.to_s }, status: 400
|
||||
end
|
||||
|
@ -81,7 +89,7 @@ class Api::BaseController < ApplicationController
|
|||
end
|
||||
|
||||
def require_authenticated_user!
|
||||
render json: { error: 'This API requires an authenticated user' }, status: 401 unless current_user
|
||||
render json: { error: 'This method requires an authenticated user' }, status: 401 unless current_user
|
||||
end
|
||||
|
||||
def require_user!
|
||||
|
|
|
@ -1,15 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::OEmbedController < Api::BaseController
|
||||
respond_to :json
|
||||
skip_before_action :require_authenticated_user!
|
||||
|
||||
before_action :set_status
|
||||
before_action :require_public_status!
|
||||
|
||||
def show
|
||||
@status = status_finder.status
|
||||
render json: @status, serializer: OEmbedSerializer, width: maxwidth_or_default, height: maxheight_or_default
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_status
|
||||
@status = status_finder.status
|
||||
end
|
||||
|
||||
def require_public_status!
|
||||
not_found if @status.hidden?
|
||||
end
|
||||
|
||||
def status_finder
|
||||
StatusFinder.new(params[:url])
|
||||
end
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
class Api::ProofsController < Api::BaseController
|
||||
include AccountOwnedConcern
|
||||
|
||||
skip_before_action :require_authenticated_user!
|
||||
|
||||
before_action :set_provider
|
||||
|
||||
def index
|
||||
|
|
|
@ -25,7 +25,7 @@ class Api::V1::Accounts::CredentialsController < Api::BaseController
|
|||
end
|
||||
|
||||
def user_settings_params
|
||||
return nil unless params.key?(:source)
|
||||
return nil if params[:source].blank?
|
||||
|
||||
source_params = params.require(:source)
|
||||
|
||||
|
|
|
@ -5,8 +5,6 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController
|
|||
before_action :set_account
|
||||
after_action :insert_pagination_headers
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
@accounts = load_accounts
|
||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||
|
@ -21,11 +19,13 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController
|
|||
def load_accounts
|
||||
return [] if hide_results?
|
||||
|
||||
default_accounts.merge(paginated_follows).to_a
|
||||
scope = default_accounts
|
||||
scope = scope.where.not(id: current_account.excluded_from_timeline_account_ids) unless current_account.nil? || current_account.id == @account.id
|
||||
scope.merge(paginated_follows).to_a
|
||||
end
|
||||
|
||||
def hide_results?
|
||||
(@account.user_hides_network? && current_account.id != @account.id) || (current_account && @account.blocking?(current_account))
|
||||
(@account.hides_followers? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account))
|
||||
end
|
||||
|
||||
def default_accounts
|
||||
|
|
|
@ -5,8 +5,6 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController
|
|||
before_action :set_account
|
||||
after_action :insert_pagination_headers
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
@accounts = load_accounts
|
||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||
|
@ -21,11 +19,13 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController
|
|||
def load_accounts
|
||||
return [] if hide_results?
|
||||
|
||||
default_accounts.merge(paginated_follows).to_a
|
||||
scope = default_accounts
|
||||
scope = scope.where.not(id: current_account.excluded_from_timeline_account_ids) unless current_account.nil? || current_account.id == @account.id
|
||||
scope.merge(paginated_follows).to_a
|
||||
end
|
||||
|
||||
def hide_results?
|
||||
(@account.user_hides_network? && current_account.id != @account.id) || (current_account && @account.blocking?(current_account))
|
||||
(@account.hides_following? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account))
|
||||
end
|
||||
|
||||
def default_accounts
|
||||
|
|
|
@ -4,8 +4,6 @@ class Api::V1::Accounts::IdentityProofsController < Api::BaseController
|
|||
before_action :require_user!
|
||||
before_action :set_account
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
@proofs = @account.identity_proofs.active
|
||||
render json: @proofs, each_serializer: REST::IdentityProofSerializer
|
||||
|
|
|
@ -5,8 +5,6 @@ class Api::V1::Accounts::ListsController < Api::BaseController
|
|||
before_action :require_user!
|
||||
before_action :set_account
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
@lists = @account.lists.where(account: current_account)
|
||||
render json: @lists, each_serializer: REST::ListSerializer
|
||||
|
|
|
@ -7,8 +7,6 @@ class Api::V1::Accounts::PinsController < Api::BaseController
|
|||
before_action :require_user!
|
||||
before_action :set_account
|
||||
|
||||
respond_to :json
|
||||
|
||||
def create
|
||||
AccountPin.create!(account: current_account, target_account: @account)
|
||||
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships_presenter
|
||||
|
|
|
@ -4,8 +4,6 @@ class Api::V1::Accounts::RelationshipsController < Api::BaseController
|
|||
before_action -> { doorkeeper_authorize! :read, :'read:follows' }
|
||||
before_action :require_user!
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
accounts = Account.where(id: account_ids).select('id')
|
||||
# .where doesn't guarantee that our results are in the same order
|
||||
|
|
|
@ -4,8 +4,6 @@ class Api::V1::Accounts::SearchController < Api::BaseController
|
|||
before_action -> { doorkeeper_authorize! :read, :'read:accounts' }
|
||||
before_action :require_user!
|
||||
|
||||
respond_to :json
|
||||
|
||||
def show
|
||||
@accounts = account_search
|
||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||
|
|
|
@ -6,8 +6,6 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
|
|||
|
||||
after_action :insert_pagination_headers, unless: -> { truthy_param?(:pinned) }
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
@statuses = load_statuses
|
||||
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
||||
|
|
|
@ -14,7 +14,7 @@ class Api::V1::AccountsController < Api::BaseController
|
|||
|
||||
skip_before_action :require_authenticated_user!, only: :create
|
||||
|
||||
respond_to :json
|
||||
override_rate_limit_headers :follow, family: :follows
|
||||
|
||||
def show
|
||||
render json: @account, serializer: REST::AccountSerializer
|
||||
|
@ -31,7 +31,7 @@ class Api::V1::AccountsController < Api::BaseController
|
|||
end
|
||||
|
||||
def follow
|
||||
FollowService.new.call(current_user.account, @account, reblogs: truthy_param?(:reblogs))
|
||||
FollowService.new.call(current_user.account, @account, reblogs: truthy_param?(:reblogs), with_rate_limit: true)
|
||||
|
||||
options = @account.locked? || current_user.account.silenced? ? {} : { following_map: { @account.id => { reblogs: truthy_param?(:reblogs) } }, requested_map: { @account.id => false } }
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::Announcements::ReactionsController < Api::BaseController
|
||||
before_action -> { doorkeeper_authorize! :write, :'write:favourites' }
|
||||
before_action :require_user!
|
||||
|
||||
before_action :set_announcement
|
||||
before_action :set_reaction, except: :update
|
||||
|
||||
def update
|
||||
@announcement.announcement_reactions.create!(account: current_account, name: params[:id])
|
||||
render_empty
|
||||
end
|
||||
|
||||
def destroy
|
||||
@reaction.destroy!
|
||||
render_empty
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_reaction
|
||||
@reaction = @announcement.announcement_reactions.where(account: current_account).find_by!(name: params[:id])
|
||||
end
|
||||
|
||||
def set_announcement
|
||||
@announcement = Announcement.published.find(params[:announcement_id])
|
||||
end
|
||||
end
|
|
@ -0,0 +1,29 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::AnnouncementsController < Api::BaseController
|
||||
before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: :dismiss
|
||||
before_action :require_user!
|
||||
before_action :set_announcements, only: :index
|
||||
before_action :set_announcement, except: :index
|
||||
|
||||
def index
|
||||
render json: @announcements, each_serializer: REST::AnnouncementSerializer
|
||||
end
|
||||
|
||||
def dismiss
|
||||
AnnouncementMute.find_or_create_by!(account: current_account, announcement: @announcement)
|
||||
render_empty
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_announcements
|
||||
@announcements = begin
|
||||
Announcement.published.chronological
|
||||
end
|
||||
end
|
||||
|
||||
def set_announcement
|
||||
@announcement = Announcement.published.find(params[:id])
|
||||
end
|
||||
end
|
|
@ -3,8 +3,6 @@
|
|||
class Api::V1::Apps::CredentialsController < Api::BaseController
|
||||
before_action -> { doorkeeper_authorize! :read }
|
||||
|
||||
respond_to :json
|
||||
|
||||
def show
|
||||
render json: doorkeeper_token.application, serializer: REST::ApplicationSerializer, fields: %i(name website vapid_key)
|
||||
end
|
||||
|
|
|
@ -5,8 +5,6 @@ class Api::V1::BlocksController < Api::BaseController
|
|||
before_action :require_user!
|
||||
after_action :insert_pagination_headers
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
@accounts = load_accounts
|
||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::BookmarksController < Api::BaseController
|
||||
before_action -> { doorkeeper_authorize! :read, :'read:bookmarks' }
|
||||
before_action :require_user!
|
||||
after_action :insert_pagination_headers
|
||||
|
||||
def index
|
||||
@statuses = load_statuses
|
||||
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_statuses
|
||||
cached_bookmarks
|
||||
end
|
||||
|
||||
def cached_bookmarks
|
||||
cache_collection(
|
||||
Status.reorder(nil).joins(:bookmarks).merge(results),
|
||||
Status
|
||||
)
|
||||
end
|
||||
|
||||
def results
|
||||
@_results ||= account_bookmarks.paginate_by_id(
|
||||
limit_param(DEFAULT_STATUSES_LIMIT),
|
||||
params_slice(:max_id, :since_id, :min_id)
|
||||
)
|
||||
end
|
||||
|
||||
def account_bookmarks
|
||||
current_account.bookmarks
|
||||
end
|
||||
|
||||
def insert_pagination_headers
|
||||
set_pagination_headers(next_path, prev_path)
|
||||
end
|
||||
|
||||
def next_path
|
||||
api_v1_bookmarks_url pagination_params(max_id: pagination_max_id) if records_continue?
|
||||
end
|
||||
|
||||
def prev_path
|
||||
api_v1_bookmarks_url pagination_params(min_id: pagination_since_id) unless results.empty?
|
||||
end
|
||||
|
||||
def pagination_max_id
|
||||
results.last.id
|
||||
end
|
||||
|
||||
def pagination_since_id
|
||||
results.first.id
|
||||
end
|
||||
|
||||
def records_continue?
|
||||
results.size == limit_param(DEFAULT_STATUSES_LIMIT)
|
||||
end
|
||||
|
||||
def pagination_params(core_params)
|
||||
params.slice(:limit).permit(:limit).merge(core_params)
|
||||
end
|
||||
end
|
|
@ -9,8 +9,6 @@ class Api::V1::ConversationsController < Api::BaseController
|
|||
before_action :set_conversation, except: :index
|
||||
after_action :insert_pagination_headers, only: :index
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
@conversations = paginated_conversations
|
||||
render json: @conversations, each_serializer: REST::ConversationSerializer
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::CustomEmojisController < Api::BaseController
|
||||
respond_to :json
|
||||
|
||||
skip_before_action :set_cache_headers
|
||||
|
||||
def index
|
||||
|
|
|
@ -8,8 +8,6 @@ class Api::V1::DomainBlocksController < Api::BaseController
|
|||
before_action :require_user!
|
||||
after_action :insert_pagination_headers, only: :show
|
||||
|
||||
respond_to :json
|
||||
|
||||
def show
|
||||
@blocks = load_domain_blocks
|
||||
render json: @blocks.map(&:domain)
|
||||
|
|
|
@ -5,8 +5,6 @@ class Api::V1::EndorsementsController < Api::BaseController
|
|||
before_action :require_user!
|
||||
after_action :insert_pagination_headers
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
@accounts = load_accounts
|
||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||
|
|
|
@ -5,8 +5,6 @@ class Api::V1::FavouritesController < Api::BaseController
|
|||
before_action :require_user!
|
||||
after_action :insert_pagination_headers
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
@statuses = load_statuses
|
||||
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
||||
|
|
|
@ -2,12 +2,9 @@
|
|||
|
||||
class Api::V1::FeaturedTags::SuggestionsController < Api::BaseController
|
||||
before_action -> { doorkeeper_authorize! :read, :'read:accounts' }, only: :index
|
||||
|
||||
before_action :require_user!
|
||||
before_action :set_most_used_tags, only: :index
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
render json: @most_used_tags, each_serializer: REST::TagSerializer
|
||||
end
|
||||
|
|
|
@ -7,8 +7,6 @@ class Api::V1::FiltersController < Api::BaseController
|
|||
before_action :set_filters, only: :index
|
||||
before_action :set_filter, only: [:show, :update, :destroy]
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
render json: @filters, each_serializer: REST::FilterSerializer
|
||||
end
|
||||
|
|
|
@ -6,8 +6,6 @@ class Api::V1::Instances::ActivityController < Api::BaseController
|
|||
skip_before_action :set_cache_headers
|
||||
skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
|
||||
|
||||
respond_to :json
|
||||
|
||||
def show
|
||||
expires_in 1.day, public: true
|
||||
render_with_cache json: :activity, expires_in: 1.day
|
||||
|
|
|
@ -6,8 +6,6 @@ class Api::V1::Instances::PeersController < Api::BaseController
|
|||
skip_before_action :set_cache_headers
|
||||
skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
expires_in 1.day, public: true
|
||||
render_with_cache(expires_in: 1.day) { Account.remote.domains }
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::InstancesController < Api::BaseController
|
||||
respond_to :json
|
||||
|
||||
skip_before_action :set_cache_headers
|
||||
skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
|
||||
|
||||
|
|
|
@ -3,30 +3,42 @@
|
|||
class Api::V1::MediaController < Api::BaseController
|
||||
before_action -> { doorkeeper_authorize! :write, :'write:media' }
|
||||
before_action :require_user!
|
||||
|
||||
include ObfuscateFilename
|
||||
obfuscate_filename :file
|
||||
|
||||
respond_to :json
|
||||
before_action :set_media_attachment, except: [:create]
|
||||
before_action :check_processing, except: [:create]
|
||||
|
||||
def create
|
||||
@media = current_account.media_attachments.create!(media_params)
|
||||
render json: @media, serializer: REST::MediaAttachmentSerializer
|
||||
@media_attachment = current_account.media_attachments.create!(media_attachment_params)
|
||||
render json: @media_attachment, serializer: REST::MediaAttachmentSerializer
|
||||
rescue Paperclip::Errors::NotIdentifiedByImageMagickError
|
||||
render json: file_type_error, status: 422
|
||||
rescue Paperclip::Error
|
||||
render json: processing_error, status: 500
|
||||
end
|
||||
|
||||
def show
|
||||
render json: @media_attachment, serializer: REST::MediaAttachmentSerializer, status: status_code_for_media_attachment
|
||||
end
|
||||
|
||||
def update
|
||||
@media = current_account.media_attachments.where(status_id: nil).find(params[:id])
|
||||
@media.update!(media_params)
|
||||
render json: @media, serializer: REST::MediaAttachmentSerializer
|
||||
@media_attachment.update!(media_attachment_params)
|
||||
render json: @media_attachment, serializer: REST::MediaAttachmentSerializer, status: status_code_for_media_attachment
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def media_params
|
||||
def status_code_for_media_attachment
|
||||
@media_attachment.not_processed? ? 206 : 200
|
||||
end
|
||||
|
||||
def set_media_attachment
|
||||
@media_attachment = current_account.media_attachments.unattached.find(params[:id])
|
||||
end
|
||||
|
||||
def check_processing
|
||||
render json: processing_error, status: 422 if @media_attachment.processing_failed?
|
||||
end
|
||||
|
||||
def media_attachment_params
|
||||
params.permit(:file, :description, :focus)
|
||||
end
|
||||
|
||||
|
|
|
@ -5,8 +5,6 @@ class Api::V1::MutesController < Api::BaseController
|
|||
before_action :require_user!
|
||||
after_action :insert_pagination_headers
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
@accounts = load_accounts
|
||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||
|
|
|
@ -6,8 +6,6 @@ class Api::V1::NotificationsController < Api::BaseController
|
|||
before_action :require_user!
|
||||
after_action :insert_pagination_headers, only: :index
|
||||
|
||||
respond_to :json
|
||||
|
||||
DEFAULT_NOTIFICATIONS_LIMIT = 15
|
||||
|
||||
def index
|
||||
|
|
|
@ -7,8 +7,6 @@ class Api::V1::Polls::VotesController < Api::BaseController
|
|||
before_action :require_user!
|
||||
before_action :set_poll
|
||||
|
||||
respond_to :json
|
||||
|
||||
def create
|
||||
VoteService.new.call(current_account, @poll, vote_params[:choices])
|
||||
render json: @poll, serializer: REST::PollSerializer
|
||||
|
@ -20,7 +18,7 @@ class Api::V1::Polls::VotesController < Api::BaseController
|
|||
@poll = Poll.attached.find(params[:poll_id])
|
||||
authorize @poll.status, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
raise ActiveRecord::RecordNotFound
|
||||
not_found
|
||||
end
|
||||
|
||||
def vote_params
|
||||
|
|
|
@ -7,8 +7,6 @@ class Api::V1::PollsController < Api::BaseController
|
|||
before_action :set_poll
|
||||
before_action :refresh_poll
|
||||
|
||||
respond_to :json
|
||||
|
||||
def show
|
||||
render json: @poll, serializer: REST::PollSerializer, include_results: true
|
||||
end
|
||||
|
@ -19,7 +17,7 @@ class Api::V1::PollsController < Api::BaseController
|
|||
@poll = Poll.attached.find(params[:id])
|
||||
authorize @poll.status, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
raise ActiveRecord::RecordNotFound
|
||||
not_found
|
||||
end
|
||||
|
||||
def refresh_poll
|
||||
|
|
|
@ -4,8 +4,6 @@ class Api::V1::PreferencesController < Api::BaseController
|
|||
before_action -> { doorkeeper_authorize! :read, :'read:accounts' }
|
||||
before_action :require_user!
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
render json: current_account, serializer: REST::PreferencesSerializer
|
||||
end
|
||||
|
|
|
@ -4,6 +4,7 @@ class Api::V1::Push::SubscriptionsController < Api::BaseController
|
|||
before_action -> { doorkeeper_authorize! :push }
|
||||
before_action :require_user!
|
||||
before_action :set_web_push_subscription
|
||||
before_action :check_web_push_subscription, only: [:show, :update]
|
||||
|
||||
def create
|
||||
@web_subscription&.destroy!
|
||||
|
@ -21,16 +22,11 @@ class Api::V1::Push::SubscriptionsController < Api::BaseController
|
|||
end
|
||||
|
||||
def show
|
||||
raise ActiveRecord::RecordNotFound if @web_subscription.nil?
|
||||
|
||||
render json: @web_subscription, serializer: REST::WebPushSubscriptionSerializer
|
||||
end
|
||||
|
||||
def update
|
||||
raise ActiveRecord::RecordNotFound if @web_subscription.nil?
|
||||
|
||||
@web_subscription.update!(data: data_params)
|
||||
|
||||
render json: @web_subscription, serializer: REST::WebPushSubscriptionSerializer
|
||||
end
|
||||
|
||||
|
@ -45,12 +41,17 @@ class Api::V1::Push::SubscriptionsController < Api::BaseController
|
|||
@web_subscription = ::Web::PushSubscription.find_by(access_token_id: doorkeeper_token.id)
|
||||
end
|
||||
|
||||
def check_web_push_subscription
|
||||
not_found if @web_subscription.nil?
|
||||
end
|
||||
|
||||
def subscription_params
|
||||
params.require(:subscription).permit(:endpoint, keys: [:auth, :p256dh])
|
||||
end
|
||||
|
||||
def data_params
|
||||
return {} if params[:data].blank?
|
||||
params.require(:data).permit(alerts: [:follow, :favourite, :reblog, :mention, :poll])
|
||||
|
||||
params.require(:data).permit(alerts: [:follow, :follow_request, :favourite, :reblog, :mention, :poll])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ class Api::V1::ReportsController < Api::BaseController
|
|||
before_action -> { doorkeeper_authorize! :write, :'write:reports' }, only: [:create]
|
||||
before_action :require_user!
|
||||
|
||||
respond_to :json
|
||||
override_rate_limit_headers :create, family: :reports
|
||||
|
||||
def create
|
||||
@report = ReportService.new.call(
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::Statuses::BookmarksController < Api::BaseController
|
||||
include Authorization
|
||||
|
||||
before_action -> { doorkeeper_authorize! :write, :'write:bookmarks' }
|
||||
before_action :require_user!
|
||||
before_action :set_status
|
||||
|
||||
def create
|
||||
current_account.bookmarks.find_or_create_by!(account: current_account, status: @status)
|
||||
render json: @status, serializer: REST::StatusSerializer
|
||||
end
|
||||
|
||||
def destroy
|
||||
bookmark = current_account.bookmarks.find_by(status: @status)
|
||||
bookmark&.destroy!
|
||||
|
||||
render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_account.id, bookmarks_map: { @status.id => false })
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_status
|
||||
@status = Status.find(params[:status_id])
|
||||
authorize @status, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
not_found
|
||||
end
|
||||
end
|
|
@ -7,8 +7,6 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::BaseController
|
|||
before_action :set_status
|
||||
after_action :insert_pagination_headers
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
@accounts = load_accounts
|
||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||
|
@ -17,7 +15,9 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::BaseController
|
|||
private
|
||||
|
||||
def load_accounts
|
||||
default_accounts.merge(paginated_favourites).to_a
|
||||
scope = default_accounts
|
||||
scope = scope.where.not(id: current_account.excluded_from_timeline_account_ids) unless current_account.nil?
|
||||
scope.merge(paginated_favourites).to_a
|
||||
end
|
||||
|
||||
def default_accounts
|
||||
|
@ -67,8 +67,7 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::BaseController
|
|||
@status = Status.find(params[:status_id])
|
||||
authorize @status, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
# Reraise in order to get a 404 instead of a 403 error code
|
||||
raise ActiveRecord::RecordNotFound
|
||||
not_found
|
||||
end
|
||||
|
||||
def pagination_params(core_params)
|
||||
|
|
|
@ -5,34 +5,24 @@ class Api::V1::Statuses::FavouritesController < Api::BaseController
|
|||
|
||||
before_action -> { doorkeeper_authorize! :write, :'write:favourites' }
|
||||
before_action :require_user!
|
||||
|
||||
respond_to :json
|
||||
before_action :set_status
|
||||
|
||||
def create
|
||||
@status = favourited_status
|
||||
FavouriteService.new.call(current_account, @status)
|
||||
render json: @status, serializer: REST::StatusSerializer
|
||||
end
|
||||
|
||||
def destroy
|
||||
@status = requested_status
|
||||
@favourites_map = { @status.id => false }
|
||||
|
||||
UnfavouriteWorker.perform_async(current_user.account_id, @status.id)
|
||||
|
||||
render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_user&.account_id, favourites_map: @favourites_map)
|
||||
UnfavouriteWorker.perform_async(current_account.id, @status.id)
|
||||
render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_account.id, favourites_map: { @status.id => false })
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def favourited_status
|
||||
service_result.status.reload
|
||||
end
|
||||
|
||||
def service_result
|
||||
FavouriteService.new.call(current_user.account, requested_status)
|
||||
end
|
||||
|
||||
def requested_status
|
||||
Status.find(params[:status_id])
|
||||
def set_status
|
||||
@status = Status.find(params[:status_id])
|
||||
authorize @status, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
not_found
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,8 +8,6 @@ class Api::V1::Statuses::MutesController < Api::BaseController
|
|||
before_action :set_status
|
||||
before_action :set_conversation
|
||||
|
||||
respond_to :json
|
||||
|
||||
def create
|
||||
current_account.mute_conversation!(@conversation)
|
||||
@mutes_map = { @conversation.id => true }
|
||||
|
@ -30,8 +28,7 @@ class Api::V1::Statuses::MutesController < Api::BaseController
|
|||
@status = Status.find(params[:status_id])
|
||||
authorize @status, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
# Reraise in order to get a 404 instead of a 403 error code
|
||||
raise ActiveRecord::RecordNotFound
|
||||
not_found
|
||||
end
|
||||
|
||||
def set_conversation
|
||||
|
|
|
@ -7,8 +7,6 @@ class Api::V1::Statuses::PinsController < Api::BaseController
|
|||
before_action :require_user!
|
||||
before_action :set_status
|
||||
|
||||
respond_to :json
|
||||
|
||||
def create
|
||||
StatusPin.create!(account: current_account, status: @status)
|
||||
distribute_add_activity!
|
||||
|
|
|
@ -7,8 +7,6 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController
|
|||
before_action :set_status
|
||||
after_action :insert_pagination_headers
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
@accounts = load_accounts
|
||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||
|
@ -17,7 +15,9 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController
|
|||
private
|
||||
|
||||
def load_accounts
|
||||
default_accounts.merge(paginated_statuses).to_a
|
||||
scope = default_accounts
|
||||
scope = scope.where.not(id: current_account.excluded_from_timeline_account_ids) unless current_account.nil?
|
||||
scope.merge(paginated_statuses).to_a
|
||||
end
|
||||
|
||||
def default_accounts
|
||||
|
@ -64,8 +64,7 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController
|
|||
@status = Status.find(params[:status_id])
|
||||
authorize @status, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
# Reraise in order to get a 404 instead of a 403 error code
|
||||
raise ActiveRecord::RecordNotFound
|
||||
not_found
|
||||
end
|
||||
|
||||
def pagination_params(core_params)
|
||||
|
|
|
@ -5,33 +5,35 @@ class Api::V1::Statuses::ReblogsController < Api::BaseController
|
|||
|
||||
before_action -> { doorkeeper_authorize! :write, :'write:statuses' }
|
||||
before_action :require_user!
|
||||
before_action :set_reblog
|
||||
|
||||
respond_to :json
|
||||
override_rate_limit_headers :create, family: :statuses
|
||||
|
||||
def create
|
||||
@status = ReblogService.new.call(current_user.account, status_for_reblog, reblog_params)
|
||||
@status = ReblogService.new.call(current_account, @reblog, reblog_params)
|
||||
|
||||
render json: @status, serializer: REST::StatusSerializer
|
||||
end
|
||||
|
||||
def destroy
|
||||
@status = status_for_destroy.reblog
|
||||
@reblogs_map = { @status.id => false }
|
||||
@status = current_account.statuses.find_by(reblog_of_id: @reblog.id)
|
||||
|
||||
authorize status_for_destroy, :unreblog?
|
||||
status_for_destroy.discard
|
||||
RemovalWorker.perform_async(status_for_destroy.id)
|
||||
if @status
|
||||
authorize @status, :unreblog?
|
||||
@status.discard
|
||||
RemovalWorker.perform_async(@status.id)
|
||||
end
|
||||
|
||||
render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_user&.account_id, reblogs_map: @reblogs_map)
|
||||
render json: @reblog, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_account.id, reblogs_map: { @reblog.id => false })
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def status_for_reblog
|
||||
Status.find params[:status_id]
|
||||
end
|
||||
|
||||
def status_for_destroy
|
||||
@status_for_destroy ||= current_user.account.statuses.where(reblog_of_id: params[:status_id]).first!
|
||||
def set_reblog
|
||||
@reblog = Status.find(params[:status_id])
|
||||
authorize @reblog, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
not_found
|
||||
end
|
||||
|
||||
def reblog_params
|
||||
|
|
|
@ -7,8 +7,9 @@ class Api::V1::StatusesController < Api::BaseController
|
|||
before_action -> { doorkeeper_authorize! :write, :'write:statuses' }, only: [:create, :destroy]
|
||||
before_action :require_user!, except: [:show, :context]
|
||||
before_action :set_status, only: [:show, :context]
|
||||
before_action :set_thread, only: [:create]
|
||||
|
||||
respond_to :json
|
||||
override_rate_limit_headers :create, family: :statuses
|
||||
|
||||
# This API was originally unlimited, pagination cannot be introduced without
|
||||
# breaking backwards-compatibility. Arbitrarily high number to cover most
|
||||
|
@ -36,7 +37,7 @@ class Api::V1::StatusesController < Api::BaseController
|
|||
def create
|
||||
@status = PostStatusService.new.call(current_user.account,
|
||||
text: status_params[:status],
|
||||
thread: status_params[:in_reply_to_id].blank? ? nil : Status.find(status_params[:in_reply_to_id]),
|
||||
thread: @thread,
|
||||
media_ids: status_params[:media_ids],
|
||||
sensitive: status_params[:sensitive],
|
||||
spoiler_text: status_params[:spoiler_text],
|
||||
|
@ -45,7 +46,8 @@ class Api::V1::StatusesController < Api::BaseController
|
|||
application: doorkeeper_token.application,
|
||||
poll: status_params[:poll],
|
||||
idempotency: request.headers['Idempotency-Key'],
|
||||
local_only: status_params[:local_only])
|
||||
local_only: status_params[:local_only],
|
||||
with_rate_limit: true)
|
||||
|
||||
render json: @status, serializer: @status.is_a?(ScheduledStatus) ? REST::ScheduledStatusSerializer : REST::StatusSerializer
|
||||
end
|
||||
|
@ -66,7 +68,13 @@ class Api::V1::StatusesController < Api::BaseController
|
|||
@status = Status.find(params[:id])
|
||||
authorize @status, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
raise ActiveRecord::RecordNotFound
|
||||
not_found
|
||||
end
|
||||
|
||||
def set_thread
|
||||
@thread = status_params[:in_reply_to_id].blank? ? nil : Status.find(status_params[:in_reply_to_id])
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
render json: { error: I18n.t('statuses.errors.in_reply_not_found') }, status: 404
|
||||
end
|
||||
|
||||
def status_params
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::StreamingController < Api::BaseController
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
if Rails.configuration.x.streaming_api_base_url != request.host
|
||||
redirect_to streaming_api_url, status: 301
|
||||
|
|
|
@ -7,8 +7,6 @@ class Api::V1::SuggestionsController < Api::BaseController
|
|||
before_action :require_user!
|
||||
before_action :set_accounts
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||
end
|
||||
|
|
|
@ -5,8 +5,6 @@ class Api::V1::Timelines::HomeController < Api::BaseController
|
|||
before_action :require_user!, only: [:show]
|
||||
after_action :insert_pagination_headers, unless: -> { @statuses.empty? }
|
||||
|
||||
respond_to :json
|
||||
|
||||
def show
|
||||
@statuses = load_statuses
|
||||
|
||||
|
|
|
@ -4,8 +4,6 @@ class Api::V1::Timelines::PublicController < Api::BaseController
|
|||
before_action :require_user!, only: [:show], if: :require_auth?
|
||||
after_action :insert_pagination_headers, unless: -> { @statuses.empty? }
|
||||
|
||||
respond_to :json
|
||||
|
||||
def show
|
||||
@statuses = load_statuses
|
||||
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
||||
|
@ -41,7 +39,7 @@ class Api::V1::Timelines::PublicController < Api::BaseController
|
|||
end
|
||||
|
||||
def public_timeline_statuses
|
||||
Status.as_public_timeline(current_account, truthy_param?(:local))
|
||||
Status.as_public_timeline(current_account, truthy_param?(:remote) ? :remote : truthy_param?(:local))
|
||||
end
|
||||
|
||||
def insert_pagination_headers
|
||||
|
@ -49,7 +47,7 @@ class Api::V1::Timelines::PublicController < Api::BaseController
|
|||
end
|
||||
|
||||
def pagination_params(core_params)
|
||||
params.slice(:local, :limit, :only_media).permit(:local, :limit, :only_media).merge(core_params)
|
||||
params.slice(:local, :remote, :limit, :only_media).permit(:local, :remote, :limit, :only_media).merge(core_params)
|
||||
end
|
||||
|
||||
def next_path
|
||||
|
|
|
@ -4,8 +4,6 @@ class Api::V1::Timelines::TagController < Api::BaseController
|
|||
before_action :load_tag
|
||||
after_action :insert_pagination_headers, unless: -> { @statuses.empty? }
|
||||
|
||||
respond_to :json
|
||||
|
||||
def show
|
||||
@statuses = load_statuses
|
||||
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
class Api::V1::TrendsController < Api::BaseController
|
||||
before_action :set_tags
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
render json: @tags, each_serializer: REST::TagSerializer
|
||||
end
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::V2::MediaController < Api::V1::MediaController
|
||||
def create
|
||||
@media_attachment = current_account.media_attachments.create!({ delay_processing: true }.merge(media_attachment_params))
|
||||
render json: @media_attachment, serializer: REST::MediaAttachmentSerializer, status: 202
|
||||
rescue Paperclip::Errors::NotIdentifiedByImageMagickError
|
||||
render json: file_type_error, status: 422
|
||||
rescue Paperclip::Error
|
||||
render json: processing_error, status: 500
|
||||
end
|
||||
end
|
|
@ -8,8 +8,6 @@ class Api::V2::SearchController < Api::BaseController
|
|||
before_action -> { doorkeeper_authorize! :read, :'read:search' }
|
||||
before_action :require_user!
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
@search = Search.new(search_results)
|
||||
render json: @search, serializer: REST::SearchSerializer
|
||||
|
|
|
@ -1,21 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::Web::EmbedsController < Api::Web::BaseController
|
||||
respond_to :json
|
||||
|
||||
before_action :require_user!
|
||||
|
||||
def create
|
||||
status = StatusFinder.new(params[:url]).status
|
||||
|
||||
return not_found if status.hidden?
|
||||
|
||||
render json: status, serializer: OEmbedSerializer, width: 400
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
oembed = FetchOEmbedService.new.call(params[:url])
|
||||
oembed[:html] = Formatter.instance.sanitize(oembed[:html], Sanitize::Config::MASTODON_OEMBED) if oembed[:html].present?
|
||||
|
||||
if oembed
|
||||
render json: oembed
|
||||
else
|
||||
render json: {}, status: :not_found
|
||||
return not_found if oembed.nil?
|
||||
|
||||
begin
|
||||
oembed[:html] = Formatter.instance.sanitize(oembed[:html], Sanitize::Config::MASTODON_OEMBED)
|
||||
rescue ArgumentError
|
||||
return not_found
|
||||
end
|
||||
|
||||
render json: oembed
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::Web::PushSubscriptionsController < Api::Web::BaseController
|
||||
respond_to :json
|
||||
|
||||
before_action :require_user!
|
||||
|
||||
def create
|
||||
|
@ -19,6 +17,7 @@ class Api::Web::PushSubscriptionsController < Api::Web::BaseController
|
|||
data = {
|
||||
alerts: {
|
||||
follow: alerts_enabled,
|
||||
follow_request: false,
|
||||
favourite: alerts_enabled,
|
||||
reblog: alerts_enabled,
|
||||
mention: alerts_enabled,
|
||||
|
@ -58,6 +57,6 @@ class Api::Web::PushSubscriptionsController < Api::Web::BaseController
|
|||
end
|
||||
|
||||
def data_params
|
||||
@data_params ||= params.require(:data).permit(alerts: [:follow, :favourite, :reblog, :mention, :poll])
|
||||
@data_params ||= params.require(:data).permit(alerts: [:follow, :follow_request, :favourite, :reblog, :mention, :poll])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::Web::SettingsController < Api::Web::BaseController
|
||||
respond_to :json
|
||||
|
||||
before_action :require_user!
|
||||
|
||||
def update
|
||||
|
|
|
@ -24,10 +24,12 @@ class ApplicationController < ActionController::Base
|
|||
rescue_from ActionController::InvalidAuthenticityToken, with: :unprocessable_entity
|
||||
rescue_from ActionController::UnknownFormat, with: :not_acceptable
|
||||
rescue_from ActionController::ParameterMissing, with: :bad_request
|
||||
rescue_from Paperclip::AdapterRegistry::NoHandlerError, with: :bad_request
|
||||
rescue_from ActiveRecord::RecordNotFound, with: :not_found
|
||||
rescue_from Mastodon::NotPermittedError, with: :forbidden
|
||||
rescue_from HTTP::Error, OpenSSL::SSL::SSLError, with: :internal_server_error
|
||||
rescue_from Mastodon::RaceConditionError, with: :service_unavailable
|
||||
rescue_from Mastodon::RateLimitExceededError, with: :too_many_requests
|
||||
|
||||
before_action :store_current_location, except: :raise_not_found, unless: :devise_controller?
|
||||
before_action :require_functional!, if: :user_signed_in?
|
||||
|
@ -110,6 +112,10 @@ class ApplicationController < ActionController::Base
|
|||
respond_with_error(503)
|
||||
end
|
||||
|
||||
def too_many_requests
|
||||
respond_with_error(429)
|
||||
end
|
||||
|
||||
def single_user_mode?
|
||||
@single_user_mode ||= Rails.configuration.x.single_user_mode && Account.where('id > 0').exists?
|
||||
end
|
||||
|
@ -137,8 +143,8 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
def respond_with_error(code)
|
||||
respond_to do |format|
|
||||
format.any { head code }
|
||||
format.html { render "errors/#{code}", layout: 'error', status: code }
|
||||
format.any { render "errors/#{code}", layout: 'error', status: code, formats: [:html] }
|
||||
format.json { render json: { error: Rack::Utils::HTTP_STATUS_CODES[code] }, status: code }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,6 +6,12 @@ class Auth::PasswordsController < Devise::PasswordsController
|
|||
|
||||
layout 'auth'
|
||||
|
||||
def update
|
||||
super do |resource|
|
||||
resource.session_activations.destroy_all if resource.errors.empty?
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_validity_of_reset_password_token
|
||||
|
|
|
@ -10,6 +10,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
|
|||
before_action :set_instance_presenter, only: [:new, :create, :update]
|
||||
before_action :set_body_classes, only: [:new, :create, :edit, :update]
|
||||
before_action :require_not_suspended!, only: [:update]
|
||||
before_action :set_cache_headers, only: [:edit, :update]
|
||||
|
||||
skip_before_action :require_functional!, only: [:edit, :update]
|
||||
|
||||
|
@ -21,10 +22,17 @@ class Auth::RegistrationsController < Devise::RegistrationsController
|
|||
not_found
|
||||
end
|
||||
|
||||
def update
|
||||
super do |resource|
|
||||
resource.clear_other_sessions(current_session.session_id) if resource.saved_change_to_encrypted_password?
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def update_resource(resource, params)
|
||||
params[:password] = nil if Devise.pam_authentication && resource.encrypted_password.blank?
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
|
@ -33,7 +41,6 @@ class Auth::RegistrationsController < Devise::RegistrationsController
|
|||
|
||||
resource.locale = I18n.locale
|
||||
resource.invite_code = params[:invite_code] if resource.invite_code.blank?
|
||||
resource.agreement = true
|
||||
resource.current_sign_in_ip = request.remote_ip
|
||||
|
||||
resource.build_account if resource.account.nil?
|
||||
|
@ -41,7 +48,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
|
|||
|
||||
def configure_sign_up_params
|
||||
devise_parameter_sanitizer.permit(:sign_up) do |u|
|
||||
u.permit({ account_attributes: [:username], invite_request_attributes: [:text] }, :email, :password, :password_confirmation, :invite_code)
|
||||
u.permit({ account_attributes: [:username], invite_request_attributes: [:text] }, :email, :password, :password_confirmation, :invite_code, :agreement)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -109,4 +116,8 @@ class Auth::RegistrationsController < Devise::RegistrationsController
|
|||
def require_not_suspended!
|
||||
forbidden if current_account.suspended?
|
||||
end
|
||||
|
||||
def set_cache_headers
|
||||
response.headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -111,6 +111,13 @@ class Auth::SessionsController < Devise::SessionsController
|
|||
render :two_factor
|
||||
end
|
||||
|
||||
def require_no_authentication
|
||||
super
|
||||
# Delete flash message that isn't entirely useful and may be confusing in
|
||||
# most cases because /web doesn't display/clear flash messages.
|
||||
flash.delete(:alert) if flash[:alert] == I18n.t('devise.failure.already_authenticated')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_instance_presenter
|
||||
|
|
|
@ -20,7 +20,7 @@ class AuthorizeInteractionsController < ApplicationController
|
|||
end
|
||||
|
||||
def create
|
||||
if @resource.is_a?(Account) && FollowService.new.call(current_account, @resource)
|
||||
if @resource.is_a?(Account) && FollowService.new.call(current_account, @resource, with_rate_limit: true)
|
||||
render :success
|
||||
else
|
||||
render :error
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue