diff --git a/.circleci/config.yml b/.circleci/config.yml index 3ba027d95..a343fc654 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 07959fd3d..f6c705765 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 bd0d0430d..fda4d5dd0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -195,21 +195,21 @@ 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) dotenv (= 2.7.5) railties (>= 3.2, < 6.1) e2mmap (0.1.0) - elasticsearch (7.3.0) - elasticsearch-api (= 7.3.0) - elasticsearch-transport (= 7.3.0) - elasticsearch-api (7.3.0) + elasticsearch (7.5.0) + elasticsearch-api (= 7.5.0) + elasticsearch-transport (= 7.5.0) + elasticsearch-api (7.5.0) multi_json elasticsearch-dsl (0.1.8) - elasticsearch-transport (7.3.0) - faraday + elasticsearch-transport (7.5.0) + faraday (>= 0.14, < 1) multi_json encryptor (3.0.0) equatable (0.6.1) @@ -220,7 +220,7 @@ GEM fabrication (2.21.0) faker (2.10.1) i18n (>= 1.6, < 2) - faraday (1.0.0) + faraday (0.17.3) multipart-post (>= 1.2, < 3) fast_blank (1.0.0) fastimage (2.1.7) @@ -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) @@ -435,7 +435,7 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.3) - puma (4.3.1) + puma (4.3.3) nio4r (~> 2.0) pundit (2.1.0) activesupport (>= 3.0.0) @@ -602,7 +602,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) @@ -689,7 +689,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) @@ -777,7 +777,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 185a355f8..33394074d 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 000000000..cacecedb0 --- /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 68bf425f4..153ade253 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 e360b8a92..850702cca 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 a405b365f..830dcd8a1 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 bea51ae11..8dad6fee9 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 72392453c..ccb751f8f 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 0a0239c42..3915b5669 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 ab8a0461f..1d3992a28 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 4217b527a..3061fcb7e 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 333db9618..114ee0a82 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 d68d2715f..0080faf33 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 8b63d0490..0475b2d4a 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 4cff04cad..a2baeef90 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 e1b244e76..c15212f0a 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 b19f27ebf..bc8013379 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 4e6d5d7c6..08b3474cc 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 af9e7a20f..5bb02d834 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 2770c7aef..c87dbc4ce 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 db827f9d4..3e242905d 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 fb27ef88b..8c1b81a0f 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 e5ebaff4d..b0ace3af0 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 b30e8464c..4f6b4bcbf 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 cc00d8a6b..9fa440935 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 c323b60b4..5b5058a7b 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 81825db15..d87d7b946 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 df6c8e86c..65439fe9b 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 @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 bf3002e79..8ac227765 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 3fa0b6a76..e1d26106a 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 031e6d42d..744baf7bb 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 077d39f5d..1640a8224 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 1b0b4b05b..66c40f6f4 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 a7f1eed00..3954af3c9 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 05f4acc33..8229786d6 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 f18ace996..7afa822ed 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 b02469b4f..43c7a525a 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 4118a8ce4..51b1621b6 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 fa60e7d84..6c9e49d90 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 67106ccbe..7fa774a4d 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 bba3c0651..2f55e95fd 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 @@ -44,7 +44,8 @@ class Api::V1::StatusesController < Api::BaseController scheduled_at: status_params[:scheduled_at], application: doorkeeper_token.application, poll: status_params[:poll], - 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 ebb17608c..7cd60615a 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 9da2b60ae..52054160d 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 ff5ede138..ae6dbcb8b 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 ccc10f966..581befef1 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 9adc4ad29..2d6ad5a80 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 bcea9857e..c875e9041 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 cbd9b551d..f17431dd1 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 4aa31695c..741ba910f 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 f388b17e5..7916b82fa 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 e3178bf48..3d65e46ed 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 0cfa2b386..973db6aca 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -29,6 +29,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? @@ -111,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 diff --git a/app/controllers/authorize_interactions_controller.rb b/app/controllers/authorize_interactions_controller.rb index e27366ea3..29c0288d0 100644 --- a/app/controllers/authorize_interactions_controller.rb +++ b/app/controllers/authorize_interactions_controller.rb @@ -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 diff --git a/app/controllers/concerns/rate_limit_headers.rb b/app/controllers/concerns/rate_limit_headers.rb index b79c558d8..86fe58a71 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 000000000..baf14ab25 --- /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/components/media_gallery.js b/app/javascript/mastodon/components/media_gallery.js index cfe164a50..283d7e0a5 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 7f9c17293..bebbbcb5a 100644 --- a/app/javascript/mastodon/components/status_action_bar.js +++ b/app/javascript/mastodon/components/status_action_bar.js @@ -6,54 +6,49 @@ import IconButton from './icon_button'; import DropdownMenuContainer from '../containers/dropdown_menu_container'; import { defineMessages, injectIntl } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { isStaff, me } from '../initial_state'; +import { me, isStaff } from '../initial_state'; const messages = defineMessages({ - delete : { id: 'status.delete', defaultMessage: 'Delete' }, - redraft : { id: 'status.redraft', defaultMessage: 'Delete & re-draft' }, - direct : { id: 'status.direct', defaultMessage: 'Direct message @{name}' }, - mention : { id: 'status.mention', defaultMessage: 'Mention @{name}' }, - mute : { id: 'account.mute', defaultMessage: 'Mute @{name}' }, - block : { id: 'account.block', defaultMessage: 'Block @{name}' }, - reply : { id: 'status.reply', defaultMessage: 'Reply' }, - share : { id: 'status.share', defaultMessage: 'Share' }, - more : { id: 'status.more', defaultMessage: 'More' }, - replyAll : { id: 'status.replyAll', defaultMessage: 'Reply to thread' }, - reblog : { id: 'status.reblog', defaultMessage: 'Boost' }, - reblog_private : { id: 'status.reblog_private', defaultMessage: 'Boost to original audience' }, + delete: { id: 'status.delete', defaultMessage: 'Delete' }, + redraft: { id: 'status.redraft', defaultMessage: 'Delete & re-draft' }, + direct: { id: 'status.direct', defaultMessage: 'Direct message @{name}' }, + mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' }, + mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' }, + block: { id: 'account.block', defaultMessage: 'Block @{name}' }, + reply: { id: 'status.reply', defaultMessage: 'Reply' }, + share: { id: 'status.share', defaultMessage: 'Share' }, + more: { id: 'status.more', defaultMessage: 'More' }, + replyAll: { id: 'status.replyAll', defaultMessage: 'Reply to thread' }, + reblog: { id: 'status.reblog', defaultMessage: 'Boost' }, + reblog_private: { id: 'status.reblog_private', defaultMessage: 'Boost to original audience' }, cancel_reblog_private: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' }, - cannot_reblog : { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' }, - favourite : { id: 'status.favourite', defaultMessage: 'Favourite' }, - bookmark : { id: 'status.bookmark', defaultMessage: 'Bookmark' }, - removeBookmark : { id: 'status.remove_bookmark', defaultMessage: 'Remove bookmark' }, - open : { id: 'status.open', defaultMessage: 'Expand this status' }, - report : { id: 'status.report', defaultMessage: 'Report @{name}' }, - muteConversation : { id: 'status.mute_conversation', defaultMessage: 'Mute conversation' }, - unmuteConversation : { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' }, - pin : { id: 'status.pin', defaultMessage: 'Pin on profile' }, - unpin : { id: 'status.unpin', defaultMessage: 'Unpin from profile' }, - embed : { id: 'status.embed', defaultMessage: 'Embed' }, - 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}' }, - unmute : { id: 'account.unmute', defaultMessage: 'Unmute @{name}' }, - unblock : { id: 'account.unblock', defaultMessage: 'Unblock @{name}' }, + cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' }, + favourite: { id: 'status.favourite', defaultMessage: 'Favourite' }, + bookmark: { id: 'status.bookmark', defaultMessage: 'Bookmark' }, + removeBookmark: { id: 'status.remove_bookmark', defaultMessage: 'Remove bookmark' }, + open: { id: 'status.open', defaultMessage: 'Expand this status' }, + report: { id: 'status.report', defaultMessage: 'Report @{name}' }, + muteConversation: { id: 'status.mute_conversation', defaultMessage: 'Mute conversation' }, + unmuteConversation: { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' }, + pin: { id: 'status.pin', defaultMessage: 'Pin on profile' }, + unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' }, + embed: { id: 'status.embed', defaultMessage: 'Embed' }, + 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: '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}' }, }); -const ObfuscateCountReplies = false; -const obfuscatedCount = count => { - if (ObfuscateCountReplies) { - if (count < 0) { - return 0; - } else if (count <= 1) { - return count; - } else { - return '1+'; - } - } else { +const obfuscatedCount = count => { + if (count < 0) { + return 0; + } else if (count <= 1) { return count; + } else { + return '1+'; } }; @@ -70,28 +65,27 @@ class StatusActionBar extends ImmutablePureComponent { }; static propTypes = { - status : ImmutablePropTypes.map.isRequired, - relationship : ImmutablePropTypes.map, - onReply : PropTypes.func, - onFavourite : PropTypes.func, - onReblog : PropTypes.func, - onDelete : PropTypes.func, - onDirect : PropTypes.func, - onMention : PropTypes.func, - onMute : PropTypes.func, - onUnmute : PropTypes.func, - onBlock : PropTypes.func, - onUnblock : PropTypes.func, - onBlockDomain : PropTypes.func, - onUnblockDomain : PropTypes.func, - onReport : PropTypes.func, - onEmbed : PropTypes.func, + status: ImmutablePropTypes.map.isRequired, + relationship: ImmutablePropTypes.map, + onReply: PropTypes.func, + onFavourite: PropTypes.func, + onReblog: PropTypes.func, + onDelete: PropTypes.func, + onDirect: PropTypes.func, + onMention: PropTypes.func, + onMute: PropTypes.func, + onUnmute: PropTypes.func, + onBlock: PropTypes.func, + onUnblock: PropTypes.func, + onBlockDomain: PropTypes.func, + onUnblockDomain: PropTypes.func, + onReport: PropTypes.func, + onEmbed: PropTypes.func, onMuteConversation: PropTypes.func, - onPin : PropTypes.func, - onBookmark : PropTypes.func, - withDismiss : PropTypes.bool, - showReplyFormUnder: PropTypes.bool, - intl : PropTypes.object.isRequired, + onPin: PropTypes.func, + onBookmark: PropTypes.func, + withDismiss: PropTypes.bool, + intl: PropTypes.object.isRequired, }; // Avoid checking props that are functions (and whose equality will always @@ -100,7 +94,7 @@ class StatusActionBar extends ImmutablePureComponent { 'status', 'relationship', 'withDismiss', - ]; + ] handleReplyClick = () => { if (me) { @@ -108,20 +102,16 @@ class StatusActionBar extends ImmutablePureComponent { } else { this._openInteractionDialog('reply'); } - }; - handleReplyUnderClick = () => { - console.info('hop show'); - this.handleReplyClick(); - }; + } handleShareClick = () => { navigator.share({ text: this.props.status.get('search_index'), - url : this.props.status.get('url'), + url: this.props.status.get('url'), }).catch((e) => { if (e.name !== 'AbortError') console.error(e); }); - }; + } handleFavouriteClick = () => { if (me) { @@ -129,7 +119,7 @@ class StatusActionBar extends ImmutablePureComponent { } else { this._openInteractionDialog('favourite'); } - }; + } handleReblogClick = e => { if (me) { @@ -137,35 +127,35 @@ class StatusActionBar extends ImmutablePureComponent { } else { this._openInteractionDialog('reblog'); } - }; + } _openInteractionDialog = type => { window.open(`/interact/${this.props.status.get('id')}?type=${type}`, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes'); - }; + } handleBookmarkClick = () => { this.props.onBookmark(this.props.status); - }; + } handleDeleteClick = () => { this.props.onDelete(this.props.status, this.context.router.history); - }; + } handleRedraftClick = () => { this.props.onDelete(this.props.status, this.context.router.history, true); - }; + } handlePinClick = () => { this.props.onPin(this.props.status); - }; + } handleMentionClick = () => { this.props.onMention(this.props.status.get('account'), this.context.router.history); - }; + } handleDirectClick = () => { this.props.onDirect(this.props.status.get('account'), this.context.router.history); - }; + } handleMuteClick = () => { const { status, relationship, onMute, onUnmute } = this.props; @@ -176,7 +166,7 @@ class StatusActionBar extends ImmutablePureComponent { } else { onMute(account); } - }; + } handleBlockClick = () => { const { status, relationship, onBlock, onUnblock } = this.props; @@ -187,43 +177,43 @@ class StatusActionBar extends ImmutablePureComponent { } else { onBlock(status); } - }; + } handleBlockDomain = () => { const { status, onBlockDomain } = this.props; const account = status.get('account'); onBlockDomain(account.get('acct').split('@')[1]); - }; + } handleUnblockDomain = () => { const { status, onUnblockDomain } = this.props; const account = status.get('account'); onUnblockDomain(account.get('acct').split('@')[1]); - }; + } handleOpen = () => { this.context.router.history.push(`/statuses/${this.props.status.get('id')}`); - }; + } handleEmbed = () => { this.props.onEmbed(this.props.status); - }; + } handleReport = () => { this.props.onReport(this.props.status); - }; + } handleConversationMuteClick = () => { this.props.onMuteConversation(this.props.status); - }; + } handleCopy = () => { - const url = this.props.status.get('url'); + const url = this.props.status.get('url'); const textarea = document.createElement('textarea'); - textarea.textContent = url; + textarea.textContent = url; textarea.style.position = 'fixed'; document.body.appendChild(textarea); @@ -236,16 +226,15 @@ class StatusActionBar extends ImmutablePureComponent { } finally { document.body.removeChild(textarea); } - }; + } - render() { + render () { const { status, relationship, intl, withDismiss } = this.props; - console.log('this.props', this.props); const mutingConversation = status.get('muted'); - const anonymousAccess = !me; - const publicStatus = ['public', 'unlisted'].includes(status.get('visibility')); - const account = status.get('account'); + const anonymousAccess = !me; + const publicStatus = ['public', 'unlisted'].includes(status.get('visibility')); + const account = status.get('account'); let menu = []; let reblogIcon = 'retweet'; @@ -259,76 +248,43 @@ class StatusActionBar extends ImmutablePureComponent { menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed }); } - menu.push({ - text : intl.formatMessage(status.get('bookmarked') ? messages.removeBookmark : messages.bookmark), - action: this.handleBookmarkClick, - }); + menu.push({ text: intl.formatMessage(status.get('bookmarked') ? messages.removeBookmark : messages.bookmark), action: this.handleBookmarkClick }); menu.push(null); if (status.getIn(['account', 'id']) === me || withDismiss) { - menu.push({ - text : intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), - action: this.handleConversationMuteClick, - }); + menu.push({ text: intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick }); menu.push(null); } if (status.getIn(['account', 'id']) === me) { if (publicStatus) { - menu.push({ - text : intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), - action: this.handlePinClick, - }); + menu.push({ text: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick }); } else { if (status.get('visibility') === 'private') { - menu.push({ - text : intl.formatMessage(status.get('reblogged') ? messages.cancel_reblog_private : messages.reblog_private), - action: this.handleReblogClick, - }); + menu.push({ text: intl.formatMessage(status.get('reblogged') ? messages.cancel_reblog_private : messages.reblog_private), action: this.handleReblogClick }); } } menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick }); menu.push({ text: intl.formatMessage(messages.redraft), action: this.handleRedraftClick }); } else { - menu.push({ - text : intl.formatMessage(messages.mention, { name: account.get('username') }), - action: this.handleMentionClick, - }); - menu.push({ - text : intl.formatMessage(messages.direct, { name: account.get('username') }), - action: this.handleDirectClick, - }); + menu.push({ text: intl.formatMessage(messages.mention, { name: account.get('username') }), action: this.handleMentionClick }); + menu.push({ text: intl.formatMessage(messages.direct, { name: account.get('username') }), action: this.handleDirectClick }); menu.push(null); if (relationship && relationship.get('muting')) { - menu.push({ - text : intl.formatMessage(messages.unmute, { name: account.get('username') }), - action: this.handleMuteClick, - }); + menu.push({ text: intl.formatMessage(messages.unmute, { name: account.get('username') }), action: this.handleMuteClick }); } else { - menu.push({ - text : intl.formatMessage(messages.mute, { name: account.get('username') }), - action: this.handleMuteClick, - }); + menu.push({ text: intl.formatMessage(messages.mute, { name: account.get('username') }), action: this.handleMuteClick }); } if (relationship && relationship.get('blocking')) { - menu.push({ - text : intl.formatMessage(messages.unblock, { name: account.get('username') }), - action: this.handleBlockClick, - }); + menu.push({ text: intl.formatMessage(messages.unblock, { name: account.get('username') }), action: this.handleBlockClick }); } else { - menu.push({ - text : intl.formatMessage(messages.block, { name: account.get('username') }), - action: this.handleBlockClick, - }); + menu.push({ text: intl.formatMessage(messages.block, { name: account.get('username') }), action: this.handleBlockClick }); } - menu.push({ - text : intl.formatMessage(messages.report, { name: account.get('username') }), - action: this.handleReport, - }); + menu.push({ text: intl.formatMessage(messages.report, { name: account.get('username') }), action: this.handleReport }); if (account.get('acct') !== account.get('username')) { const domain = account.get('acct').split('@')[1]; @@ -344,14 +300,8 @@ class StatusActionBar extends ImmutablePureComponent { if (isStaff) { menu.push(null); - menu.push({ - text: intl.formatMessage(messages.admin_account, { name: account.get('username') }), - href: `/admin/accounts/${status.getIn(['account', 'id'])}`, - }); - menu.push({ - text: intl.formatMessage(messages.admin_status), - href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}`, - }); + menu.push({ text: intl.formatMessage(messages.admin_account, { name: account.get('username') }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` }); + menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` }); } } @@ -369,73 +319,21 @@ class StatusActionBar extends ImmutablePureComponent { replyTitle = intl.formatMessage(messages.replyAll); } - const shareButton = ('share' in navigator) && status.get('visibility') === 'public' && ( - + const shareButton = ('share' in navigator) && publicStatus && ( + ); return (
-
- - - {/*{this.state.showReplyFormUnder && (*/} - {/* */} - {/* yes*/} - {/* */} - {/*)}*/} - {/*{obfuscatedCount(status.get('replies_count'))}*/} - - {obfuscatedCount(status.get('replies_count'))} - -
- - +
{obfuscatedCount(status.get('replies_count'))}
+ + {shareButton}
- -
- - {this.props.showReplyFormUnder && ( -
- form de reply -
- )} -
+ + + ); } diff --git a/app/javascript/mastodon/features/account/components/header.js b/app/javascript/mastodon/features/account/components/header.js index 8bd7f2db5..35cc3952f 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 fda5a074f..95c9c7751 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 {
- + {/* eslint-disable-next-line jsx-a11y/no-onchange */}