diff --git a/.circleci/config.yml b/.circleci/config.yml
index 3ba027d953..a343fc654a 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -6,6 +6,7 @@ aliases:
- image: circleci/ruby:2.7-buster-node
environment: &ruby_environment
BUNDLE_APP_CONFIG: ./.bundle/
+ BUNDLE_PATH: ./vendor/bundle/
DB_HOST: localhost
DB_USER: root
RAILS_ENV: test
diff --git a/Gemfile b/Gemfile
index 852def278b..46757eadfe 100644
--- a/Gemfile
+++ b/Gemfile
@@ -49,7 +49,7 @@ gem 'omniauth-saml', '~> 1.10'
gem 'omniauth', '~> 1.9'
gem 'discard', '~> 1.1'
-gem 'doorkeeper', '~> 5.2'
+gem 'doorkeeper', '~> 5.3'
gem 'fast_blank', '~> 1.0'
gem 'fastimage'
gem 'goldfinger', '~> 2.1'
@@ -92,7 +92,7 @@ gem 'simple-navigation', '~> 4.1'
gem 'simple_form', '~> 5.0'
gem 'sprockets-rails', '~> 3.2', require: 'sprockets/railtie'
gem 'stoplight', '~> 2.2.0'
-gem 'strong_migrations', '~> 0.5'
+gem 'strong_migrations', '~> 0.6'
gem 'tty-command', '~> 0.9', require: false
gem 'tty-prompt', '~> 0.20', require: false
gem 'twitter-text', '~> 1.14'
diff --git a/Gemfile.lock b/Gemfile.lock
index c05fac36b5..49b2a8fe8f 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -195,7 +195,7 @@ GEM
docile (1.3.2)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
- doorkeeper (5.2.3)
+ doorkeeper (5.3.1)
railties (>= 5)
dotenv (2.7.5)
dotenv-rails (2.7.5)
@@ -311,7 +311,7 @@ GEM
multi_json (~> 1.14)
rack (~> 2.0)
rdf (~> 3.1)
- json-ld-preloaded (3.1.0)
+ json-ld-preloaded (3.1.1)
json-ld (~> 3.1)
rdf (~> 3.1)
jsonapi-renderer (0.2.2)
@@ -383,7 +383,7 @@ GEM
concurrent-ruby (~> 1.0, >= 1.0.2)
sidekiq (>= 3.5)
statsd-ruby (~> 1.4, >= 1.4.0)
- oj (3.10.1)
+ oj (3.10.3)
omniauth (1.9.0)
hashie (>= 3.4.6, < 3.7.0)
rack (>= 1.6.2, < 3)
@@ -603,7 +603,7 @@ GEM
stoplight (2.2.0)
streamio-ffmpeg (3.0.2)
multi_json (~> 1.8)
- strong_migrations (0.5.1)
+ strong_migrations (0.6.2)
activerecord (>= 5)
temple (0.8.2)
terminal-table (1.8.0)
@@ -690,7 +690,7 @@ DEPENDENCIES
devise-two-factor (~> 3.1)
devise_pam_authenticatable2 (~> 9.2)
discard (~> 1.1)
- doorkeeper (~> 5.2)
+ doorkeeper (~> 5.3)
dotenv-rails (~> 2.7)
e2mmap (~> 0.1.0)
fabrication (~> 2.21)
@@ -779,7 +779,7 @@ DEPENDENCIES
stackprof
stoplight (~> 2.2.0)
streamio-ffmpeg (~> 3.0)
- strong_migrations (~> 0.5)
+ strong_migrations (~> 0.6)
thor (~> 0.20)
thwait (~> 0.1.0)
tty-command (~> 0.9)
diff --git a/app/controllers/account_follow_controller.rb b/app/controllers/account_follow_controller.rb
index 185a355f8f..33394074db 100644
--- a/app/controllers/account_follow_controller.rb
+++ b/app/controllers/account_follow_controller.rb
@@ -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
diff --git a/app/controllers/admin/site_uploads_controller.rb b/app/controllers/admin/site_uploads_controller.rb
new file mode 100644
index 0000000000..cacecedb0a
--- /dev/null
+++ b/app/controllers/admin/site_uploads_controller.rb
@@ -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
diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb
index 68bf425f4d..153ade253d 100644
--- a/app/controllers/api/base_controller.rb
+++ b/app/controllers/api/base_controller.rb
@@ -44,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
diff --git a/app/controllers/api/v1/accounts/follower_accounts_controller.rb b/app/controllers/api/v1/accounts/follower_accounts_controller.rb
index e360b8a929..850702ccac 100644
--- a/app/controllers/api/v1/accounts/follower_accounts_controller.rb
+++ b/app/controllers/api/v1/accounts/follower_accounts_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/accounts/following_accounts_controller.rb b/app/controllers/api/v1/accounts/following_accounts_controller.rb
index a405b365f2..830dcd8a1f 100644
--- a/app/controllers/api/v1/accounts/following_accounts_controller.rb
+++ b/app/controllers/api/v1/accounts/following_accounts_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/accounts/identity_proofs_controller.rb b/app/controllers/api/v1/accounts/identity_proofs_controller.rb
index bea51ae119..8dad6fee96 100644
--- a/app/controllers/api/v1/accounts/identity_proofs_controller.rb
+++ b/app/controllers/api/v1/accounts/identity_proofs_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/accounts/lists_controller.rb b/app/controllers/api/v1/accounts/lists_controller.rb
index 72392453c4..ccb751f8f7 100644
--- a/app/controllers/api/v1/accounts/lists_controller.rb
+++ b/app/controllers/api/v1/accounts/lists_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/accounts/pins_controller.rb b/app/controllers/api/v1/accounts/pins_controller.rb
index 0a0239c424..3915b56693 100644
--- a/app/controllers/api/v1/accounts/pins_controller.rb
+++ b/app/controllers/api/v1/accounts/pins_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/accounts/relationships_controller.rb b/app/controllers/api/v1/accounts/relationships_controller.rb
index ab8a0461f5..1d3992a285 100644
--- a/app/controllers/api/v1/accounts/relationships_controller.rb
+++ b/app/controllers/api/v1/accounts/relationships_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/accounts/search_controller.rb b/app/controllers/api/v1/accounts/search_controller.rb
index 4217b527a5..3061fcb7e7 100644
--- a/app/controllers/api/v1/accounts/search_controller.rb
+++ b/app/controllers/api/v1/accounts/search_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/accounts/statuses_controller.rb b/app/controllers/api/v1/accounts/statuses_controller.rb
index 333db96186..114ee0a824 100644
--- a/app/controllers/api/v1/accounts/statuses_controller.rb
+++ b/app/controllers/api/v1/accounts/statuses_controller.rb
@@ -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)
diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb
index d68d2715f7..0080faf330 100644
--- a/app/controllers/api/v1/accounts_controller.rb
+++ b/app/controllers/api/v1/accounts_controller.rb
@@ -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 } }
diff --git a/app/controllers/api/v1/apps/credentials_controller.rb b/app/controllers/api/v1/apps/credentials_controller.rb
index 8b63d0490d..0475b2d4a2 100644
--- a/app/controllers/api/v1/apps/credentials_controller.rb
+++ b/app/controllers/api/v1/apps/credentials_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/blocks_controller.rb b/app/controllers/api/v1/blocks_controller.rb
index 4cff04cad7..a2baeef900 100644
--- a/app/controllers/api/v1/blocks_controller.rb
+++ b/app/controllers/api/v1/blocks_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/bookmarks_controller.rb b/app/controllers/api/v1/bookmarks_controller.rb
index e1b244e76f..c15212f0a9 100644
--- a/app/controllers/api/v1/bookmarks_controller.rb
+++ b/app/controllers/api/v1/bookmarks_controller.rb
@@ -5,8 +5,6 @@ class Api::V1::BookmarksController < 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)
diff --git a/app/controllers/api/v1/conversations_controller.rb b/app/controllers/api/v1/conversations_controller.rb
index b19f27ebfb..bc80133794 100644
--- a/app/controllers/api/v1/conversations_controller.rb
+++ b/app/controllers/api/v1/conversations_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/custom_emojis_controller.rb b/app/controllers/api/v1/custom_emojis_controller.rb
index 4e6d5d7c61..08b3474cc8 100644
--- a/app/controllers/api/v1/custom_emojis_controller.rb
+++ b/app/controllers/api/v1/custom_emojis_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/domain_blocks_controller.rb b/app/controllers/api/v1/domain_blocks_controller.rb
index af9e7a20f7..5bb02d834c 100644
--- a/app/controllers/api/v1/domain_blocks_controller.rb
+++ b/app/controllers/api/v1/domain_blocks_controller.rb
@@ -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)
diff --git a/app/controllers/api/v1/endorsements_controller.rb b/app/controllers/api/v1/endorsements_controller.rb
index 2770c7aef6..c87dbc4ce8 100644
--- a/app/controllers/api/v1/endorsements_controller.rb
+++ b/app/controllers/api/v1/endorsements_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/favourites_controller.rb b/app/controllers/api/v1/favourites_controller.rb
index db827f9d4a..3e242905da 100644
--- a/app/controllers/api/v1/favourites_controller.rb
+++ b/app/controllers/api/v1/favourites_controller.rb
@@ -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)
diff --git a/app/controllers/api/v1/featured_tags/suggestions_controller.rb b/app/controllers/api/v1/featured_tags/suggestions_controller.rb
index fb27ef88b9..8c1b81a0f0 100644
--- a/app/controllers/api/v1/featured_tags/suggestions_controller.rb
+++ b/app/controllers/api/v1/featured_tags/suggestions_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/filters_controller.rb b/app/controllers/api/v1/filters_controller.rb
index e5ebaff4d3..b0ace3af04 100644
--- a/app/controllers/api/v1/filters_controller.rb
+++ b/app/controllers/api/v1/filters_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/instances/activity_controller.rb b/app/controllers/api/v1/instances/activity_controller.rb
index b30e8464c3..4f6b4bcbfa 100644
--- a/app/controllers/api/v1/instances/activity_controller.rb
+++ b/app/controllers/api/v1/instances/activity_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/instances/peers_controller.rb b/app/controllers/api/v1/instances/peers_controller.rb
index cc00d8a6bc..9fa4409357 100644
--- a/app/controllers/api/v1/instances/peers_controller.rb
+++ b/app/controllers/api/v1/instances/peers_controller.rb
@@ -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 }
diff --git a/app/controllers/api/v1/instances_controller.rb b/app/controllers/api/v1/instances_controller.rb
index c323b60b42..5b5058a7bf 100644
--- a/app/controllers/api/v1/instances_controller.rb
+++ b/app/controllers/api/v1/instances_controller.rb
@@ -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?
diff --git a/app/controllers/api/v1/media_controller.rb b/app/controllers/api/v1/media_controller.rb
index 81825db155..d87d7b9466 100644
--- a/app/controllers/api/v1/media_controller.rb
+++ b/app/controllers/api/v1/media_controller.rb
@@ -4,8 +4,6 @@ class Api::V1::MediaController < Api::BaseController
before_action -> { doorkeeper_authorize! :write, :'write:media' }
before_action :require_user!
- respond_to :json
-
def create
@media = current_account.media_attachments.create!(media_params)
render json: @media, serializer: REST::MediaAttachmentSerializer
diff --git a/app/controllers/api/v1/mutes_controller.rb b/app/controllers/api/v1/mutes_controller.rb
index 3b3a399432..5dc047b43d 100644
--- a/app/controllers/api/v1/mutes_controller.rb
+++ b/app/controllers/api/v1/mutes_controller.rb
@@ -5,8 +5,6 @@ class Api::V1::MutesController < Api::BaseController
before_action :require_user!
after_action :insert_pagination_headers
- respond_to :json
-
def index
@data = @accounts = load_accounts
render json: @accounts, each_serializer: REST::AccountSerializer
diff --git a/app/controllers/api/v1/notifications_controller.rb b/app/controllers/api/v1/notifications_controller.rb
index c91753ae7a..9dce9b8074 100644
--- a/app/controllers/api/v1/notifications_controller.rb
+++ b/app/controllers/api/v1/notifications_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/polls/votes_controller.rb b/app/controllers/api/v1/polls/votes_controller.rb
index 3fa0b6a760..e1d26106af 100644
--- a/app/controllers/api/v1/polls/votes_controller.rb
+++ b/app/controllers/api/v1/polls/votes_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/polls_controller.rb b/app/controllers/api/v1/polls_controller.rb
index 031e6d42d6..744baf7bb4 100644
--- a/app/controllers/api/v1/polls_controller.rb
+++ b/app/controllers/api/v1/polls_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/preferences_controller.rb b/app/controllers/api/v1/preferences_controller.rb
index 077d39f5d7..1640a8224b 100644
--- a/app/controllers/api/v1/preferences_controller.rb
+++ b/app/controllers/api/v1/preferences_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/reports_controller.rb b/app/controllers/api/v1/reports_controller.rb
index 1b0b4b05b2..66c40f6f4d 100644
--- a/app/controllers/api/v1/reports_controller.rb
+++ b/app/controllers/api/v1/reports_controller.rb
@@ -4,8 +4,6 @@ class Api::V1::ReportsController < Api::BaseController
before_action -> { doorkeeper_authorize! :write, :'write:reports' }, only: [:create]
before_action :require_user!
- respond_to :json
-
def create
@report = ReportService.new.call(
current_account,
diff --git a/app/controllers/api/v1/statuses/bookmarks_controller.rb b/app/controllers/api/v1/statuses/bookmarks_controller.rb
index a7f1eed003..3954af3c9b 100644
--- a/app/controllers/api/v1/statuses/bookmarks_controller.rb
+++ b/app/controllers/api/v1/statuses/bookmarks_controller.rb
@@ -7,8 +7,6 @@ class Api::V1::Statuses::BookmarksController < Api::BaseController
before_action :require_user!
before_action :set_status
- respond_to :json
-
def create
current_account.bookmarks.find_or_create_by!(account: current_account, status: @status)
render json: @status, serializer: REST::StatusSerializer
diff --git a/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb b/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb
index 05f4acc331..8229786d6c 100644
--- a/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb
+++ b/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/statuses/favourites_controller.rb b/app/controllers/api/v1/statuses/favourites_controller.rb
index f18ace996c..7afa822ed8 100644
--- a/app/controllers/api/v1/statuses/favourites_controller.rb
+++ b/app/controllers/api/v1/statuses/favourites_controller.rb
@@ -7,8 +7,6 @@ class Api::V1::Statuses::FavouritesController < Api::BaseController
before_action :require_user!
before_action :set_status
- respond_to :json
-
def create
FavouriteService.new.call(current_account, @status)
render json: @status, serializer: REST::StatusSerializer
diff --git a/app/controllers/api/v1/statuses/mutes_controller.rb b/app/controllers/api/v1/statuses/mutes_controller.rb
index b02469b4f4..43c7a525ad 100644
--- a/app/controllers/api/v1/statuses/mutes_controller.rb
+++ b/app/controllers/api/v1/statuses/mutes_controller.rb
@@ -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 }
diff --git a/app/controllers/api/v1/statuses/pins_controller.rb b/app/controllers/api/v1/statuses/pins_controller.rb
index 4118a8ce4e..51b1621b6f 100644
--- a/app/controllers/api/v1/statuses/pins_controller.rb
+++ b/app/controllers/api/v1/statuses/pins_controller.rb
@@ -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!
diff --git a/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb b/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb
index fa60e7d846..6c9e49d903 100644
--- a/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb
+++ b/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/statuses/reblogs_controller.rb b/app/controllers/api/v1/statuses/reblogs_controller.rb
index 67106ccbe8..7fa774a4d7 100644
--- a/app/controllers/api/v1/statuses/reblogs_controller.rb
+++ b/app/controllers/api/v1/statuses/reblogs_controller.rb
@@ -7,10 +7,11 @@ class Api::V1::Statuses::ReblogsController < Api::BaseController
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_account, @reblog, reblog_params)
+
render json: @status, serializer: REST::StatusSerializer
end
diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb
index 486004f9cd..544e8e3c93 100644
--- a/app/controllers/api/v1/statuses_controller.rb
+++ b/app/controllers/api/v1/statuses_controller.rb
@@ -8,7 +8,7 @@ class Api::V1::StatusesController < Api::BaseController
before_action :require_user!, except: [:show, :context]
before_action :set_status, only: [:show, :context]
- 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
@@ -45,7 +45,8 @@ class Api::V1::StatusesController < Api::BaseController
application: doorkeeper_token.application,
poll: status_params[:poll],
content_type: status_params[:content_type],
- idempotency: request.headers['Idempotency-Key'])
+ idempotency: request.headers['Idempotency-Key'],
+ with_rate_limit: true)
render json: @status, serializer: @status.is_a?(ScheduledStatus) ? REST::ScheduledStatusSerializer : REST::StatusSerializer
end
diff --git a/app/controllers/api/v1/streaming_controller.rb b/app/controllers/api/v1/streaming_controller.rb
index ebb17608c1..7cd60615ab 100644
--- a/app/controllers/api/v1/streaming_controller.rb
+++ b/app/controllers/api/v1/streaming_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/suggestions_controller.rb b/app/controllers/api/v1/suggestions_controller.rb
index 9da2b60ae2..52054160df 100644
--- a/app/controllers/api/v1/suggestions_controller.rb
+++ b/app/controllers/api/v1/suggestions_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/timelines/home_controller.rb b/app/controllers/api/v1/timelines/home_controller.rb
index ff5ede1385..ae6dbcb8b3 100644
--- a/app/controllers/api/v1/timelines/home_controller.rb
+++ b/app/controllers/api/v1/timelines/home_controller.rb
@@ -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
diff --git a/app/controllers/api/v1/timelines/public_controller.rb b/app/controllers/api/v1/timelines/public_controller.rb
index ccc10f966c..581befef13 100644
--- a/app/controllers/api/v1/timelines/public_controller.rb
+++ b/app/controllers/api/v1/timelines/public_controller.rb
@@ -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)
diff --git a/app/controllers/api/v1/timelines/tag_controller.rb b/app/controllers/api/v1/timelines/tag_controller.rb
index 9adc4ad291..2d6ad5a80c 100644
--- a/app/controllers/api/v1/timelines/tag_controller.rb
+++ b/app/controllers/api/v1/timelines/tag_controller.rb
@@ -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)
diff --git a/app/controllers/api/v1/trends_controller.rb b/app/controllers/api/v1/trends_controller.rb
index bcea9857e8..c875e90414 100644
--- a/app/controllers/api/v1/trends_controller.rb
+++ b/app/controllers/api/v1/trends_controller.rb
@@ -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
diff --git a/app/controllers/api/v2/search_controller.rb b/app/controllers/api/v2/search_controller.rb
index 76decdb253..ddcf922009 100644
--- a/app/controllers/api/v2/search_controller.rb
+++ b/app/controllers/api/v2/search_controller.rb
@@ -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
diff --git a/app/controllers/api/web/embeds_controller.rb b/app/controllers/api/web/embeds_controller.rb
index 4aa31695c7..741ba910fb 100644
--- a/app/controllers/api/web/embeds_controller.rb
+++ b/app/controllers/api/web/embeds_controller.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
class Api::Web::EmbedsController < Api::Web::BaseController
- respond_to :json
-
before_action :require_user!
def create
diff --git a/app/controllers/api/web/push_subscriptions_controller.rb b/app/controllers/api/web/push_subscriptions_controller.rb
index f388b17e5d..7916b82fa0 100644
--- a/app/controllers/api/web/push_subscriptions_controller.rb
+++ b/app/controllers/api/web/push_subscriptions_controller.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
class Api::Web::PushSubscriptionsController < Api::Web::BaseController
- respond_to :json
-
before_action :require_user!
def create
diff --git a/app/controllers/api/web/settings_controller.rb b/app/controllers/api/web/settings_controller.rb
index e3178bf48b..3d65e46ed9 100644
--- a/app/controllers/api/web/settings_controller.rb
+++ b/app/controllers/api/web/settings_controller.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
class Api::Web::SettingsController < Api::Web::BaseController
- respond_to :json
-
before_action :require_user!
def update
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index c882d40ab0..63d9f91fb5 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -30,6 +30,7 @@ class ApplicationController < ActionController::Base
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?
@@ -181,6 +182,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
diff --git a/app/controllers/authorize_interactions_controller.rb b/app/controllers/authorize_interactions_controller.rb
index 20b3fa94b6..f0bcac75ba 100644
--- a/app/controllers/authorize_interactions_controller.rb
+++ b/app/controllers/authorize_interactions_controller.rb
@@ -21,7 +21,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
diff --git a/app/controllers/concerns/rate_limit_headers.rb b/app/controllers/concerns/rate_limit_headers.rb
index b79c558d81..86fe58a71c 100644
--- a/app/controllers/concerns/rate_limit_headers.rb
+++ b/app/controllers/concerns/rate_limit_headers.rb
@@ -3,6 +3,20 @@
module RateLimitHeaders
extend ActiveSupport::Concern
+ class_methods do
+ def override_rate_limit_headers(method_name, options = {})
+ around_action(only: method_name, if: :current_account) do |_controller, block|
+ begin
+ block.call
+ ensure
+ rate_limiter = RateLimiter.new(current_account, options)
+ rate_limit_headers = rate_limiter.to_headers
+ response.headers.merge!(rate_limit_headers) unless response.headers['X-RateLimit-Remaining'].present? && rate_limit_headers['X-RateLimit-Remaining'].to_i > response.headers['X-RateLimit-Remaining'].to_i
+ end
+ end
+ end
+ end
+
included do
before_action :set_rate_limit_headers, if: :rate_limited_request?
end
@@ -44,7 +58,7 @@ module RateLimitHeaders
end
def api_throttle_data
- most_limited_type, = request.env['rack.attack.throttle_data'].min_by { |_, v| v[:limit] }
+ most_limited_type, = request.env['rack.attack.throttle_data'].min_by { |_, v| v[:limit] - v[:count] }
request.env['rack.attack.throttle_data'][most_limited_type]
end
diff --git a/app/helpers/admin/settings_helper.rb b/app/helpers/admin/settings_helper.rb
new file mode 100644
index 0000000000..baf14ab257
--- /dev/null
+++ b/app/helpers/admin/settings_helper.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Admin::SettingsHelper
+ def site_upload_delete_hint(hint, var)
+ upload = SiteUpload.find_by(var: var.to_s)
+ return hint unless upload
+
+ link = link_to t('admin.site_uploads.delete'), admin_site_upload_path(upload), data: { method: :delete }
+ safe_join([hint, link], '
'.html_safe)
+ end
+end
diff --git a/app/javascript/mastodon/actions/accounts.js b/app/javascript/mastodon/actions/accounts.js
index d4a824e2c9..4af36e9983 100644
--- a/app/javascript/mastodon/actions/accounts.js
+++ b/app/javascript/mastodon/actions/accounts.js
@@ -106,7 +106,7 @@ export function fetchAccount(id) {
dispatch,
getState,
db.transaction('accounts', 'read').objectStore('accounts').index('id'),
- id
+ id,
).then(() => db.close(), error => {
db.close();
throw error;
diff --git a/app/javascript/mastodon/components/intersection_observer_article.js b/app/javascript/mastodon/components/intersection_observer_article.js
index e453730ba4..124b34b02f 100644
--- a/app/javascript/mastodon/components/intersection_observer_article.js
+++ b/app/javascript/mastodon/components/intersection_observer_article.js
@@ -44,7 +44,7 @@ export default class IntersectionObserverArticle extends React.Component {
intersectionObserverWrapper.observe(
id,
this.node,
- this.handleIntersection
+ this.handleIntersection,
);
this.componentMounted = true;
diff --git a/app/javascript/mastodon/components/media_gallery.js b/app/javascript/mastodon/components/media_gallery.js
index cfe164a507..283d7e0a50 100644
--- a/app/javascript/mastodon/components/media_gallery.js
+++ b/app/javascript/mastodon/components/media_gallery.js
@@ -10,7 +10,7 @@ import { autoPlayGif, cropImages, displayMedia, useBlurhash } from '../initial_s
import { decode } from 'blurhash';
const messages = defineMessages({
- toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: 'Toggle visibility' },
+ toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: 'Hide media' },
});
class Item extends React.PureComponent {
diff --git a/app/javascript/mastodon/components/status_action_bar.js b/app/javascript/mastodon/components/status_action_bar.js
index e2c8d43c98..bebbbcb5ab 100644
--- a/app/javascript/mastodon/components/status_action_bar.js
+++ b/app/javascript/mastodon/components/status_action_bar.js
@@ -36,8 +36,8 @@ const messages = defineMessages({
admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
admin_status: { id: 'status.admin_status', defaultMessage: 'Open this status in the moderation interface' },
copy: { id: 'status.copy', defaultMessage: 'Copy link to status' },
- blockDomain: { id: 'account.block_domain', defaultMessage: 'Hide everything from {domain}' },
- unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
+ blockDomain: { id: 'account.block_domain', defaultMessage: 'Block domain {domain}' },
+ unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' },
unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
});
diff --git a/app/javascript/mastodon/features/account/components/header.js b/app/javascript/mastodon/features/account/components/header.js
index 8bd7f2db5f..35cc3952f8 100644
--- a/app/javascript/mastodon/features/account/components/header.js
+++ b/app/javascript/mastodon/features/account/components/header.js
@@ -29,8 +29,8 @@ const messages = defineMessages({
report: { id: 'account.report', defaultMessage: 'Report @{name}' },
share: { id: 'account.share', defaultMessage: 'Share @{name}\'s profile' },
media: { id: 'account.media', defaultMessage: 'Media' },
- blockDomain: { id: 'account.block_domain', defaultMessage: 'Hide everything from {domain}' },
- unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
+ blockDomain: { id: 'account.block_domain', defaultMessage: 'Block domain {domain}' },
+ unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
hideReblogs: { id: 'account.hide_reblogs', defaultMessage: 'Hide boosts from @{name}' },
showReblogs: { id: 'account.show_reblogs', defaultMessage: 'Show boosts from @{name}' },
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' },
diff --git a/app/javascript/mastodon/features/audio/index.js b/app/javascript/mastodon/features/audio/index.js
index fda5a074fe..95c9c7751a 100644
--- a/app/javascript/mastodon/features/audio/index.js
+++ b/app/javascript/mastodon/features/audio/index.js
@@ -214,8 +214,8 @@ class Audio extends React.PureComponent {
-
-
+
+
@@ -236,7 +236,7 @@ class Audio extends React.PureComponent {
-