From 82ef5c0461509cbc2ada01e6e124218a030c39df Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 3 Jan 2019 06:40:16 +0100 Subject: Fix list of local followers showing remote followers in admin UI (#9700) --- app/controllers/admin/followers_controller.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'app/controllers') diff --git a/app/controllers/admin/followers_controller.rb b/app/controllers/admin/followers_controller.rb index 819628b20..d826f47c5 100644 --- a/app/controllers/admin/followers_controller.rb +++ b/app/controllers/admin/followers_controller.rb @@ -8,15 +8,11 @@ module Admin def index authorize :account, :index? - @followers = followers.recent.page(params[:page]).per(PER_PAGE) + @followers = @account.followers.local.recent.page(params[:page]).per(PER_PAGE) end def set_account @account = Account.find(params[:account_id]) end - - def followers - Follow.includes(:account).where(target_account: @account) - end end end -- cgit From 6f9a7bd02ca9efe5e798d8f4642f94ad4b5b88a2 Mon Sep 17 00:00:00 2001 From: ThibG Date: Fri, 4 Jan 2019 13:10:43 +0100 Subject: Add quick links to the admin interface in the WebUI (#8545) * Allow to show a specific status in the admin interface * Let the front-end know the current account is a moderator * Add admin links to status and account menus If the current logged-in user is an admin, add quick links to the admin interface in account and toot dropdown menu. Suggestion by @ashkitten * Use @statuses.first instead of @statuses[0] --- app/controllers/admin/statuses_controller.rb | 9 ++++++++ .../mastodon/components/status_action_bar.js | 9 +++++++- .../features/account/components/action_bar.js | 8 ++++++- .../features/status/components/action_bar.js | 9 +++++++- app/javascript/mastodon/initial_state.js | 1 + app/serializers/initial_state_serializer.rb | 1 + app/views/admin/statuses/show.html.haml | 27 ++++++++++++++++++++++ config/routes.rb | 2 +- 8 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 app/views/admin/statuses/show.html.haml (limited to 'app/controllers') diff --git a/app/controllers/admin/statuses_controller.rb b/app/controllers/admin/statuses_controller.rb index a69f12084..650195034 100644 --- a/app/controllers/admin/statuses_controller.rb +++ b/app/controllers/admin/statuses_controller.rb @@ -22,6 +22,15 @@ module Admin @form = Form::StatusBatch.new end + def show + authorize :status, :index? + + @statuses = @account.statuses.where(id: params[:id]) + authorize @statuses.first, :show? + + @form = Form::StatusBatch.new + end + def create authorize :status, :update? diff --git a/app/javascript/mastodon/components/status_action_bar.js b/app/javascript/mastodon/components/status_action_bar.js index becd44ec0..0995a1490 100644 --- a/app/javascript/mastodon/components/status_action_bar.js +++ b/app/javascript/mastodon/components/status_action_bar.js @@ -5,7 +5,7 @@ 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 { me } from '../initial_state'; +import { me, isStaff } from '../initial_state'; const messages = defineMessages({ delete: { id: 'status.delete', defaultMessage: 'Delete' }, @@ -30,6 +30,8 @@ const messages = defineMessages({ 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' }, }); const obfuscatedCount = count => { @@ -182,6 +184,11 @@ class StatusActionBar extends ImmutablePureComponent { menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick }); menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick }); menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport }); + if (isStaff) { + menu.push(null); + menu.push({ text: intl.formatMessage(messages.admin_account, { name: status.getIn(['account', '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')}` }); + } } if (status.get('visibility') === 'direct') { diff --git a/app/javascript/mastodon/features/account/components/action_bar.js b/app/javascript/mastodon/features/account/components/action_bar.js index e6ae1a2fd..8ed4c917a 100644 --- a/app/javascript/mastodon/features/account/components/action_bar.js +++ b/app/javascript/mastodon/features/account/components/action_bar.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import DropdownMenuContainer from '../../../containers/dropdown_menu_container'; import { NavLink } from 'react-router-dom'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import { me } from '../../../initial_state'; +import { me, isStaff } from '../../../initial_state'; import { shortNumberFormat } from '../../../utils/numbers'; const messages = defineMessages({ @@ -35,6 +35,7 @@ const messages = defineMessages({ endorse: { id: 'account.endorse', defaultMessage: 'Feature on profile' }, unendorse: { id: 'account.unendorse', defaultMessage: 'Don\'t feature on profile' }, add_or_remove_from_list: { id: 'account.add_or_remove_from_list', defaultMessage: 'Add or Remove from lists' }, + admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' }, }); export default @injectIntl @@ -151,6 +152,11 @@ class ActionBar extends React.PureComponent { } } + if (account.get('id') !== me && isStaff) { + menu.push(null); + menu.push({ text: intl.formatMessage(messages.admin_account, { name: account.get('username') }), href: `/admin/accounts/${account.get('id')}` }); + } + return (
{extraInfo} diff --git a/app/javascript/mastodon/features/status/components/action_bar.js b/app/javascript/mastodon/features/status/components/action_bar.js index 3b30d33b2..d3b725283 100644 --- a/app/javascript/mastodon/features/status/components/action_bar.js +++ b/app/javascript/mastodon/features/status/components/action_bar.js @@ -4,7 +4,7 @@ import IconButton from '../../../components/icon_button'; import ImmutablePropTypes from 'react-immutable-proptypes'; import DropdownMenuContainer from '../../../containers/dropdown_menu_container'; import { defineMessages, injectIntl } from 'react-intl'; -import { me } from '../../../initial_state'; +import { me, isStaff } from '../../../initial_state'; const messages = defineMessages({ delete: { id: 'status.delete', defaultMessage: 'Delete' }, @@ -26,6 +26,8 @@ const messages = defineMessages({ 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' }, }); export default @injectIntl @@ -145,6 +147,11 @@ class ActionBar extends React.PureComponent { menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick }); menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick }); menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport }); + if (isStaff) { + menu.push(null); + menu.push({ text: intl.formatMessage(messages.admin_account, { name: status.getIn(['account', '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')}` }); + } } const shareButton = ('share' in navigator) && status.get('visibility') === 'public' && ( diff --git a/app/javascript/mastodon/initial_state.js b/app/javascript/mastodon/initial_state.js index b496c57d2..8c2e9d2de 100644 --- a/app/javascript/mastodon/initial_state.js +++ b/app/javascript/mastodon/initial_state.js @@ -16,5 +16,6 @@ export const invitesEnabled = getMeta('invites_enabled'); export const version = getMeta('version'); export const mascot = getMeta('mascot'); export const profile_directory = getMeta('profile_directory'); +export const isStaff = getMeta('is_staff'); export default initialState; diff --git a/app/serializers/initial_state_serializer.rb b/app/serializers/initial_state_serializer.rb index d40379d43..a7a3d770c 100644 --- a/app/serializers/initial_state_serializer.rb +++ b/app/serializers/initial_state_serializer.rb @@ -29,6 +29,7 @@ class InitialStateSerializer < ActiveModel::Serializer store[:display_media] = object.current_account.user.setting_display_media store[:expand_spoilers] = object.current_account.user.setting_expand_spoilers store[:reduce_motion] = object.current_account.user.setting_reduce_motion + store[:is_staff] = object.current_account.user.staff? end store diff --git a/app/views/admin/statuses/show.html.haml b/app/views/admin/statuses/show.html.haml new file mode 100644 index 000000000..a7a392272 --- /dev/null +++ b/app/views/admin/statuses/show.html.haml @@ -0,0 +1,27 @@ +- content_for :page_title do + = t('admin.statuses.title') + \- + = "@#{@account.acct}" + +.filters + .back-link{ style: 'flex: 1 1 auto; text-align: right' } + = link_to admin_account_path(@account.id) do + %i.fa.fa-chevron-left.fa-fw + = t('admin.statuses.back_to_account') + +%hr.spacer/ + += form_for(@form, url: admin_account_statuses_path(@account.id)) do |f| + = hidden_field_tag :page, params[:page] + = hidden_field_tag :media, params[:media] + + .batch-table + .batch-table__toolbar + %label.batch-table__toolbar__select.batch-checkbox-all + = check_box_tag :batch_checkbox_all, nil, false + .batch-table__toolbar__actions + = f.button safe_join([fa_icon('eye-slash'), t('admin.statuses.batch.nsfw_on')]), name: :nsfw_on, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } + = f.button safe_join([fa_icon('eye'), t('admin.statuses.batch.nsfw_off')]), name: :nsfw_off, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } + = f.button safe_join([fa_icon('trash'), t('admin.statuses.batch.delete')]), name: :delete, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } + .batch-table__body + = render partial: 'admin/reports/status', collection: @statuses, locals: { f: f } diff --git a/config/routes.rb b/config/routes.rb index 6e4da48a0..5bdd1986c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -192,7 +192,7 @@ Rails.application.routes.draw do resource :change_email, only: [:show, :update] resource :reset, only: [:create] resource :action, only: [:new, :create], controller: 'account_actions' - resources :statuses, only: [:index, :create, :update, :destroy] + resources :statuses, only: [:index, :show, :create, :update, :destroy] resources :followers, only: [:index] resource :confirmation, only: [:create] do -- cgit From a49d43d1121ac10f96d5a9cbf78112c707e7a59e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 5 Jan 2019 12:43:28 +0100 Subject: Add scheduled statuses (#9706) Fix #340 --- .../api/v1/scheduled_statuses_controller.rb | 77 ++++++++++ app/controllers/api/v1/statuses_controller.rb | 9 +- app/models/concerns/account_associations.rb | 1 + app/models/media_attachment.rb | 38 ++--- app/models/scheduled_status.rb | 39 +++++ .../rest/scheduled_status_serializer.rb | 11 ++ app/services/post_status_service.rb | 169 +++++++++++++++------ app/services/suspend_account_service.rb | 1 + app/workers/publish_scheduled_status_worker.rb | 24 +++ .../scheduler/scheduled_statuses_scheduler.rb | 19 +++ config/locales/en.yml | 4 + config/routes.rb | 1 + config/sidekiq.yml | 3 + .../20190103124649_create_scheduled_statuses.rb | 9 ++ ...add_scheduled_status_id_to_media_attachments.rb | 8 + db/schema.rb | 14 +- .../api/v1/conversations_controller_spec.rb | 2 +- .../api/v1/notifications_controller_spec.rb | 4 +- .../api/v1/timelines/home_controller_spec.rb | 2 +- .../api/v1/timelines/list_controller_spec.rb | 2 +- .../api/v1/timelines/public_controller_spec.rb | 4 +- .../api/v1/timelines/tag_controller_spec.rb | 2 +- spec/fabricators/scheduled_status_fabricator.rb | 4 + spec/lib/feed_manager_spec.rb | 6 +- spec/models/scheduled_status_spec.rb | 4 + .../services/batched_remove_status_service_spec.rb | 4 +- spec/services/post_status_service_spec.rb | 44 +++--- spec/services/remove_status_service_spec.rb | 2 +- .../publish_scheduled_status_worker_spec.rb | 23 +++ 29 files changed, 432 insertions(+), 98 deletions(-) create mode 100644 app/controllers/api/v1/scheduled_statuses_controller.rb create mode 100644 app/models/scheduled_status.rb create mode 100644 app/serializers/rest/scheduled_status_serializer.rb create mode 100644 app/workers/publish_scheduled_status_worker.rb create mode 100644 app/workers/scheduler/scheduled_statuses_scheduler.rb create mode 100644 db/migrate/20190103124649_create_scheduled_statuses.rb create mode 100644 db/migrate/20190103124754_add_scheduled_status_id_to_media_attachments.rb create mode 100644 spec/fabricators/scheduled_status_fabricator.rb create mode 100644 spec/models/scheduled_status_spec.rb create mode 100644 spec/workers/publish_scheduled_status_worker_spec.rb (limited to 'app/controllers') diff --git a/app/controllers/api/v1/scheduled_statuses_controller.rb b/app/controllers/api/v1/scheduled_statuses_controller.rb new file mode 100644 index 000000000..9950296f3 --- /dev/null +++ b/app/controllers/api/v1/scheduled_statuses_controller.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +class Api::V1::ScheduledStatusesController < Api::BaseController + include Authorization + + before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, except: [:update, :destroy] + before_action -> { doorkeeper_authorize! :write, :'write:statuses' }, only: [:update, :destroy] + + before_action :set_statuses, only: :index + before_action :set_status, except: :index + + after_action :insert_pagination_headers, only: :index + + def index + render json: @statuses, each_serializer: REST::ScheduledStatusSerializer + end + + def show + render json: @status, serializer: REST::ScheduledStatusSerializer + end + + def update + @status.update!(scheduled_status_params) + render json: @status, serializer: REST::ScheduledStatusSerializer + end + + def destroy + @status.destroy! + render_empty + end + + private + + def set_statuses + @statuses = current_account.scheduled_statuses.paginate_by_id(limit_param(DEFAULT_STATUSES_LIMIT), params_slice(:max_id, :since_id, :min_id)) + end + + def set_status + @status = current_account.scheduled_statuses.find(params[:id]) + end + + def scheduled_status_params + params.permit(:scheduled_at) + end + + def pagination_params(core_params) + params.slice(:limit).permit(:limit).merge(core_params) + end + + def insert_pagination_headers + set_pagination_headers(next_path, prev_path) + end + + def next_path + if records_continue? + api_v1_scheduled_statuses_url pagination_params(max_id: pagination_max_id) + end + end + + def prev_path + unless @statuses.empty? + api_v1_scheduled_statuses_url pagination_params(min_id: pagination_since_id) + end + end + + def records_continue? + @statuses.size == limit_param(DEFAULT_STATUSES_LIMIT) + end + + def pagination_max_id + @statuses.last.id + end + + def pagination_since_id + @statuses.first.id + end +end diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb index 49a52f7a6..29b420c67 100644 --- a/app/controllers/api/v1/statuses_controller.rb +++ b/app/controllers/api/v1/statuses_controller.rb @@ -45,16 +45,17 @@ class Api::V1::StatusesController < Api::BaseController def create @status = PostStatusService.new.call(current_user.account, - status_params[:status], - status_params[:in_reply_to_id].blank? ? nil : Status.find(status_params[:in_reply_to_id]), + text: status_params[:status], + thread: status_params[:in_reply_to_id].blank? ? nil : Status.find(status_params[:in_reply_to_id]), media_ids: status_params[:media_ids], sensitive: status_params[:sensitive], spoiler_text: status_params[:spoiler_text], visibility: status_params[:visibility], + scheduled_at: status_params[:scheduled_at], application: doorkeeper_token.application, idempotency: request.headers['Idempotency-Key']) - render json: @status, serializer: REST::StatusSerializer + render json: @status, serializer: @status.is_a?(ScheduledStatus) ? REST::ScheduledStatusSerializer : REST::StatusSerializer end def destroy @@ -77,7 +78,7 @@ class Api::V1::StatusesController < Api::BaseController end def status_params - params.permit(:status, :in_reply_to_id, :sensitive, :spoiler_text, :visibility, media_ids: []) + params.permit(:status, :in_reply_to_id, :sensitive, :spoiler_text, :visibility, :scheduled_at, media_ids: []) end def pagination_params(core_params) diff --git a/app/models/concerns/account_associations.rb b/app/models/concerns/account_associations.rb index a894b5eed..7dafeee34 100644 --- a/app/models/concerns/account_associations.rb +++ b/app/models/concerns/account_associations.rb @@ -14,6 +14,7 @@ module AccountAssociations has_many :mentions, inverse_of: :account, dependent: :destroy has_many :notifications, inverse_of: :account, dependent: :destroy has_many :conversations, class_name: 'AccountConversation', dependent: :destroy, inverse_of: :account + has_many :scheduled_statuses, inverse_of: :account, dependent: :destroy # Pinned statuses has_many :status_pins, inverse_of: :account, dependent: :destroy diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index 62a11185a..6b939124f 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -3,20 +3,21 @@ # # Table name: media_attachments # -# id :bigint(8) not null, primary key -# status_id :bigint(8) -# file_file_name :string -# file_content_type :string -# file_file_size :integer -# file_updated_at :datetime -# remote_url :string default(""), not null -# created_at :datetime not null -# updated_at :datetime not null -# shortcode :string -# type :integer default("image"), not null -# file_meta :json -# account_id :bigint(8) -# description :text +# id :bigint(8) not null, primary key +# status_id :bigint(8) +# file_file_name :string +# file_content_type :string +# file_file_size :integer +# file_updated_at :datetime +# remote_url :string default(""), not null +# created_at :datetime not null +# updated_at :datetime not null +# shortcode :string +# type :integer default("image"), not null +# file_meta :json +# account_id :bigint(8) +# description :text +# scheduled_status_id :bigint(8) # class MediaAttachment < ApplicationRecord @@ -76,8 +77,9 @@ class MediaAttachment < ApplicationRecord IMAGE_LIMIT = 8.megabytes VIDEO_LIMIT = 40.megabytes - belongs_to :account, inverse_of: :media_attachments, optional: true - belongs_to :status, inverse_of: :media_attachments, optional: true + belongs_to :account, inverse_of: :media_attachments, optional: true + belongs_to :status, inverse_of: :media_attachments, optional: true + belongs_to :scheduled_status, inverse_of: :media_attachments, optional: true has_attached_file :file, styles: ->(f) { file_styles f }, @@ -94,8 +96,8 @@ class MediaAttachment < ApplicationRecord validates :account, presence: true validates :description, length: { maximum: 420 }, if: :local? - scope :attached, -> { where.not(status_id: nil) } - scope :unattached, -> { where(status_id: nil) } + scope :attached, -> { where.not(status_id: nil).or(where.not(scheduled_status_id: nil)) } + scope :unattached, -> { where(status_id: nil, scheduled_status_id: nil) } scope :local, -> { where(remote_url: '') } scope :remote, -> { where.not(remote_url: '') } diff --git a/app/models/scheduled_status.rb b/app/models/scheduled_status.rb new file mode 100644 index 000000000..c95470fc8 --- /dev/null +++ b/app/models/scheduled_status.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: scheduled_statuses +# +# id :bigint(8) not null, primary key +# account_id :bigint(8) +# scheduled_at :datetime +# params :jsonb +# + +class ScheduledStatus < ApplicationRecord + include Paginable + + TOTAL_LIMIT = 300 + DAILY_LIMIT = 25 + + belongs_to :account, inverse_of: :scheduled_statuses + has_many :media_attachments, inverse_of: :scheduled_status, dependent: :destroy + + validate :validate_future_date + validate :validate_total_limit + validate :validate_daily_limit + + private + + def validate_future_date + errors.add(:scheduled_at, I18n.t('scheduled_statuses.too_soon')) if scheduled_at.present? && scheduled_at <= Time.now.utc + PostStatusService::MIN_SCHEDULE_OFFSET + end + + def validate_total_limit + errors.add(:base, I18n.t('scheduled_statuses.over_total_limit', limit: TOTAL_LIMIT)) if account.scheduled_statuses.count >= TOTAL_LIMIT + end + + def validate_daily_limit + errors.add(:base, I18n.t('scheduled_statuses.over_daily_limit', limit: DAILY_LIMIT)) if account.scheduled_statuses.where('scheduled_at::date = ?::date', scheduled_at).count >= DAILY_LIMIT + end +end diff --git a/app/serializers/rest/scheduled_status_serializer.rb b/app/serializers/rest/scheduled_status_serializer.rb new file mode 100644 index 000000000..522991bcf --- /dev/null +++ b/app/serializers/rest/scheduled_status_serializer.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class REST::ScheduledStatusSerializer < ActiveModel::Serializer + attributes :id, :scheduled_at + + has_many :media_attachments, serializer: REST::MediaAttachmentSerializer + + def id + object.id.to_s + end +end diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb index eff1b1461..07fd969e5 100644 --- a/app/services/post_status_service.rb +++ b/app/services/post_status_service.rb @@ -1,71 +1,96 @@ # frozen_string_literal: true class PostStatusService < BaseService + MIN_SCHEDULE_OFFSET = 5.minutes.freeze + # Post a text status update, fetch and notify remote users mentioned # @param [Account] account Account from which to post - # @param [String] text Message - # @param [Status] in_reply_to Optional status to reply to # @param [Hash] options + # @option [String] :text Message + # @option [Status] :thread Optional status to reply to # @option [Boolean] :sensitive # @option [String] :visibility # @option [String] :spoiler_text + # @option [String] :language + # @option [String] :scheduled_at # @option [Enumerable] :media_ids Optional array of media IDs to attach # @option [Doorkeeper::Application] :application # @option [String] :idempotency Optional idempotency key # @return [Status] - def call(account, text, in_reply_to = nil, **options) - if options[:idempotency].present? - existing_id = redis.get("idempotency:status:#{account.id}:#{options[:idempotency]}") - return Status.find(existing_id) if existing_id + def call(account, options = {}) + @account = account + @options = options + @text = @options[:text] || '' + @in_reply_to = @options[:thread] + + return idempotency_duplicate if idempotency_given? && idempotency_duplicate? + + validate_media! + preprocess_attributes! + + if scheduled? + schedule_status! + else + process_status! + postprocess_status! + bump_potential_friendship! end - media = validate_media!(options[:media_ids]) - status = nil - text = options.delete(:spoiler_text) if text.blank? && options[:spoiler_text].present? + redis.setex(idempotency_key, 3_600, @status.id) if idempotency_given? - visibility = options[:visibility] || account.user&.setting_default_privacy - visibility = :unlisted if visibility == :public && account.silenced + @status + end - ApplicationRecord.transaction do - status = account.statuses.create!(text: text, - media_attachments: media || [], - thread: in_reply_to, - sensitive: (options[:sensitive].nil? ? account.user&.setting_default_sensitive : options[:sensitive]) || options[:spoiler_text].present?, - spoiler_text: options[:spoiler_text] || '', - visibility: visibility, - language: language_from_option(options[:language]) || account.user&.setting_default_language&.presence || LanguageDetector.instance.detect(text, account), - application: options[:application]) - end + private - process_hashtags_service.call(status) - process_mentions_service.call(status) + def preprocess_attributes! + @text = @options.delete(:spoiler_text) if @text.blank? && @options[:spoiler_text].present? + @visibility = @options[:visibility] || @account.user&.setting_default_privacy + @visibility = :unlisted if @visibility == :public && @account.silenced + @scheduled_at = @options[:scheduled_at]&.to_datetime + @scheduled_at = nil if scheduled_in_the_past? + end - LinkCrawlWorker.perform_async(status.id) unless status.spoiler_text? - DistributionWorker.perform_async(status.id) - Pubsubhubbub::DistributionWorker.perform_async(status.stream_entry.id) - ActivityPub::DistributionWorker.perform_async(status.id) + def process_status! + # The following transaction block is needed to wrap the UPDATEs to + # the media attachments when the status is created - if options[:idempotency].present? - redis.setex("idempotency:status:#{account.id}:#{options[:idempotency]}", 3_600, status.id) + ApplicationRecord.transaction do + @status = @account.statuses.create!(status_attributes) end - bump_potential_friendship(account, status) - - status + process_hashtags_service.call(@status) + process_mentions_service.call(@status) end - private + def schedule_status! + if @account.statuses.build(status_attributes).valid? + # The following transaction block is needed to wrap the UPDATEs to + # the media attachments when the scheduled status is created - def validate_media!(media_ids) - return if media_ids.blank? || !media_ids.is_a?(Enumerable) + ApplicationRecord.transaction do + @status = @account.scheduled_statuses.create!(scheduled_status_attributes) + end + else + raise ActiveRecord::RecordInvalid + end + end + + def postprocess_status! + LinkCrawlWorker.perform_async(@status.id) unless @status.spoiler_text? + DistributionWorker.perform_async(@status.id) + Pubsubhubbub::DistributionWorker.perform_async(@status.stream_entry.id) + ActivityPub::DistributionWorker.perform_async(@status.id) + end - raise Mastodon::ValidationError, I18n.t('media_attachments.validations.too_many') if media_ids.size > 4 + def validate_media! + return if @options[:media_ids].blank? || !@options[:media_ids].is_a?(Enumerable) - media = MediaAttachment.where(status_id: nil).where(id: media_ids.take(4).map(&:to_i)) + raise Mastodon::ValidationError, I18n.t('media_attachments.validations.too_many') if @options[:media_ids].size > 4 - raise Mastodon::ValidationError, I18n.t('media_attachments.validations.images_and_video') if media.size > 1 && media.find(&:video?) + @media = MediaAttachment.where(status_id: nil).where(id: @options[:media_ids].take(4).map(&:to_i)) - media + raise Mastodon::ValidationError, I18n.t('media_attachments.validations.images_and_video') if @media.size > 1 && @media.find(&:video?) end def language_from_option(str) @@ -84,10 +109,68 @@ class PostStatusService < BaseService Redis.current end - def bump_potential_friendship(account, status) - return if !status.reply? || account.id == status.in_reply_to_account_id + def scheduled? + @scheduled_at.present? + end + + def idempotency_key + "idempotency:status:#{@account.id}:#{@options[:idempotency]}" + end + + def idempotency_given? + @options[:idempotency].present? + end + + def idempotency_duplicate + if scheduled? + @account.schedule_statuses.find(@idempotency_duplicate) + else + @account.statuses.find(@idempotency_duplicate) + end + end + + def idempotency_duplicate? + @idempotency_duplicate = redis.get(idempotency_key) + end + + def scheduled_in_the_past? + @scheduled_at.present? && @scheduled_at <= Time.now.utc + MIN_SCHEDULE_OFFSET + end + + def bump_potential_friendship! + return if !@status.reply? || @account.id == @status.in_reply_to_account_id ActivityTracker.increment('activity:interactions') - return if account.following?(status.in_reply_to_account_id) - PotentialFriendshipTracker.record(account.id, status.in_reply_to_account_id, :reply) + return if @account.following?(@status.in_reply_to_account_id) + PotentialFriendshipTracker.record(@account.id, @status.in_reply_to_account_id, :reply) + end + + def status_attributes + { + text: @text, + media_attachments: @media || [], + thread: @in_reply_to, + sensitive: (@options[:sensitive].nil? ? @account.user&.setting_default_sensitive : @options[:sensitive]) || @options[:spoiler_text].present?, + spoiler_text: @options[:spoiler_text] || '', + visibility: @visibility, + language: language_from_option(@options[:language]) || @account.user&.setting_default_language&.presence || LanguageDetector.instance.detect(@text, @account), + application: @options[:application], + } + end + + def scheduled_status_attributes + { + scheduled_at: @scheduled_at, + media_attachments: @media || [], + params: scheduled_options, + } + end + + def scheduled_options + @options.tap do |options_hash| + options_hash[:in_reply_to_status_id] = options_hash.delete(:thread)&.id + options_hash[:application_id] = options_hash.delete(:application)&.id + options_hash[:scheduled_at] = nil + options_hash[:idempotency] = nil + end end end diff --git a/app/services/suspend_account_service.rb b/app/services/suspend_account_service.rb index 6ab6b2901..1bc2314de 100644 --- a/app/services/suspend_account_service.rb +++ b/app/services/suspend_account_service.rb @@ -20,6 +20,7 @@ class SuspendAccountService < BaseService owned_lists passive_relationships report_notes + scheduled_statuses status_pins stream_entries subscriptions diff --git a/app/workers/publish_scheduled_status_worker.rb b/app/workers/publish_scheduled_status_worker.rb new file mode 100644 index 000000000..298a13001 --- /dev/null +++ b/app/workers/publish_scheduled_status_worker.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +class PublishScheduledStatusWorker + include Sidekiq::Worker + + def perform(scheduled_status_id) + scheduled_status = ScheduledStatus.find(scheduled_status_id) + scheduled_status.destroy! + + PostStatusService.new.call( + scheduled_status.account, + options_with_objects(scheduled_status.params.with_indifferent_access) + ) + rescue ActiveRecord::RecordNotFound, ActiveRecord::RecordInvalid + true + end + + def options_with_objects(options) + options.tap do |options_hash| + options_hash[:application] = Doorkeeper::Application.find(options_hash.delete(:application_id)) if options[:application_id] + options_hash[:thread] = Status.find(options_hash.delete(:in_reply_to_status_id)) if options_hash[:in_reply_to_status_id] + end + end +end diff --git a/app/workers/scheduler/scheduled_statuses_scheduler.rb b/app/workers/scheduler/scheduled_statuses_scheduler.rb new file mode 100644 index 000000000..70a45846b --- /dev/null +++ b/app/workers/scheduler/scheduled_statuses_scheduler.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class Scheduler::ScheduledStatusesScheduler + include Sidekiq::Worker + + sidekiq_options unique: :until_executed, retry: 0 + + def perform + due_statuses.find_each do |scheduled_status| + PublishScheduledStatusWorker.perform_at(scheduled_status.scheduled_at) + end + end + + private + + def due_statuses + ScheduledStatus.where('scheduled_at <= ?', Time.now.utc + PostStatusService::MIN_SCHEDULE_OFFSET) + end +end diff --git a/config/locales/en.yml b/config/locales/en.yml index 6c78b9fc9..7e05568f1 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -728,6 +728,10 @@ en: error: Error title: Title unfollowed: Unfollowed + scheduled_statuses: + over_daily_limit: You have exceeded the limit of %{limit} scheduled toots for that day + over_total_limit: You have exceeded the limit of %{limit} scheduled toots + too_soon: The scheduled date must be in the future sessions: activity: Last activity browser: Browser diff --git a/config/routes.rb b/config/routes.rb index 5bdd1986c..3ae2735d1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -283,6 +283,7 @@ Rails.application.routes.draw do resources :streaming, only: [:index] resources :custom_emojis, only: [:index] resources :suggestions, only: [:index, :destroy] + resources :scheduled_statuses, only: [:index, :show, :update, :destroy] resources :conversations, only: [:index, :destroy] do member do diff --git a/config/sidekiq.yml b/config/sidekiq.yml index c44af5b6c..0ec1742ab 100644 --- a/config/sidekiq.yml +++ b/config/sidekiq.yml @@ -6,6 +6,9 @@ - [mailers, 2] - [pull] :schedule: + scheduled_statuses_scheduler: + every: '5m' + class: Scheduler::ScheduledStatusesScheduler subscriptions_scheduler: cron: '<%= Random.rand(0..59) %> <%= Random.rand(4..6) %> * * *' class: Scheduler::SubscriptionsScheduler diff --git a/db/migrate/20190103124649_create_scheduled_statuses.rb b/db/migrate/20190103124649_create_scheduled_statuses.rb new file mode 100644 index 000000000..2b78073b8 --- /dev/null +++ b/db/migrate/20190103124649_create_scheduled_statuses.rb @@ -0,0 +1,9 @@ +class CreateScheduledStatuses < ActiveRecord::Migration[5.2] + def change + create_table :scheduled_statuses do |t| + t.belongs_to :account, foreign_key: { on_delete: :cascade } + t.datetime :scheduled_at, index: true + t.jsonb :params + end + end +end diff --git a/db/migrate/20190103124754_add_scheduled_status_id_to_media_attachments.rb b/db/migrate/20190103124754_add_scheduled_status_id_to_media_attachments.rb new file mode 100644 index 000000000..6f6cf2351 --- /dev/null +++ b/db/migrate/20190103124754_add_scheduled_status_id_to_media_attachments.rb @@ -0,0 +1,8 @@ +class AddScheduledStatusIdToMediaAttachments < ActiveRecord::Migration[5.2] + disable_ddl_transaction! + + def change + add_reference :media_attachments, :scheduled_status, foreign_key: { on_delete: :nullify }, index: false + add_index :media_attachments, :scheduled_status_id, algorithm: :concurrently + end +end diff --git a/db/schema.rb b/db/schema.rb index 066a90b52..9380362e1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2018_12_26_021420) do +ActiveRecord::Schema.define(version: 2019_01_03_124754) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -336,7 +336,9 @@ ActiveRecord::Schema.define(version: 2018_12_26_021420) do t.json "file_meta" t.bigint "account_id" t.text "description" + t.bigint "scheduled_status_id" t.index ["account_id"], name: "index_media_attachments_on_account_id" + t.index ["scheduled_status_id"], name: "index_media_attachments_on_scheduled_status_id" t.index ["shortcode"], name: "index_media_attachments_on_shortcode", unique: true t.index ["status_id"], name: "index_media_attachments_on_status_id" end @@ -487,6 +489,14 @@ ActiveRecord::Schema.define(version: 2018_12_26_021420) do t.index ["target_account_id"], name: "index_reports_on_target_account_id" end + create_table "scheduled_statuses", force: :cascade do |t| + t.bigint "account_id" + t.datetime "scheduled_at" + t.jsonb "params" + t.index ["account_id"], name: "index_scheduled_statuses_on_account_id" + t.index ["scheduled_at"], name: "index_scheduled_statuses_on_scheduled_at" + end + create_table "session_activations", force: :cascade do |t| t.string "session_id", null: false t.datetime "created_at", null: false @@ -700,6 +710,7 @@ ActiveRecord::Schema.define(version: 2018_12_26_021420) do add_foreign_key "list_accounts", "lists", on_delete: :cascade add_foreign_key "lists", "accounts", on_delete: :cascade add_foreign_key "media_attachments", "accounts", name: "fk_96dd81e81b", on_delete: :nullify + add_foreign_key "media_attachments", "scheduled_statuses", on_delete: :nullify add_foreign_key "media_attachments", "statuses", on_delete: :nullify add_foreign_key "mentions", "accounts", name: "fk_970d43f9d1", on_delete: :cascade add_foreign_key "mentions", "statuses", on_delete: :cascade @@ -718,6 +729,7 @@ ActiveRecord::Schema.define(version: 2018_12_26_021420) do add_foreign_key "reports", "accounts", column: "assigned_account_id", on_delete: :nullify add_foreign_key "reports", "accounts", column: "target_account_id", name: "fk_eb37af34f0", on_delete: :cascade add_foreign_key "reports", "accounts", name: "fk_4b81f7522c", on_delete: :cascade + add_foreign_key "scheduled_statuses", "accounts", on_delete: :cascade add_foreign_key "session_activations", "oauth_access_tokens", column: "access_token_id", name: "fk_957e5bda89", on_delete: :cascade add_foreign_key "session_activations", "users", name: "fk_e5fda67334", on_delete: :cascade add_foreign_key "status_pins", "accounts", name: "fk_d4cb435b62", on_delete: :cascade diff --git a/spec/controllers/api/v1/conversations_controller_spec.rb b/spec/controllers/api/v1/conversations_controller_spec.rb index 2e9525855..070f65061 100644 --- a/spec/controllers/api/v1/conversations_controller_spec.rb +++ b/spec/controllers/api/v1/conversations_controller_spec.rb @@ -15,7 +15,7 @@ RSpec.describe Api::V1::ConversationsController, type: :controller do let(:scopes) { 'read:statuses' } before do - PostStatusService.new.call(other.account, 'Hey @alice', nil, visibility: 'direct') + PostStatusService.new.call(other.account, text: 'Hey @alice', visibility: 'direct') end it 'returns http success' do diff --git a/spec/controllers/api/v1/notifications_controller_spec.rb b/spec/controllers/api/v1/notifications_controller_spec.rb index 9f679cb8a..d0f82e79f 100644 --- a/spec/controllers/api/v1/notifications_controller_spec.rb +++ b/spec/controllers/api/v1/notifications_controller_spec.rb @@ -50,9 +50,9 @@ RSpec.describe Api::V1::NotificationsController, type: :controller do let(:scopes) { 'read:notifications' } before do - first_status = PostStatusService.new.call(user.account, 'Test') + first_status = PostStatusService.new.call(user.account, text: 'Test') @reblog_of_first_status = ReblogService.new.call(other.account, first_status) - mentioning_status = PostStatusService.new.call(other.account, 'Hello @alice') + mentioning_status = PostStatusService.new.call(other.account, text: 'Hello @alice') @mention_from_status = mentioning_status.mentions.first @favourite = FavouriteService.new.call(other.account, first_status) @follow = FollowService.new.call(other.account, 'alice') diff --git a/spec/controllers/api/v1/timelines/home_controller_spec.rb b/spec/controllers/api/v1/timelines/home_controller_spec.rb index 63d624c35..e953e4649 100644 --- a/spec/controllers/api/v1/timelines/home_controller_spec.rb +++ b/spec/controllers/api/v1/timelines/home_controller_spec.rb @@ -17,7 +17,7 @@ describe Api::V1::Timelines::HomeController do describe 'GET #show' do before do follow = Fabricate(:follow, account: user.account) - PostStatusService.new.call(follow.target_account, 'New status for user home timeline.') + PostStatusService.new.call(follow.target_account, text: 'New status for user home timeline.') end it 'returns http success' do diff --git a/spec/controllers/api/v1/timelines/list_controller_spec.rb b/spec/controllers/api/v1/timelines/list_controller_spec.rb index 93a2be6e6..45e4bf34c 100644 --- a/spec/controllers/api/v1/timelines/list_controller_spec.rb +++ b/spec/controllers/api/v1/timelines/list_controller_spec.rb @@ -19,7 +19,7 @@ describe Api::V1::Timelines::ListController do before do follow = Fabricate(:follow, account: user.account) list.accounts << follow.target_account - PostStatusService.new.call(follow.target_account, 'New status for user home timeline.') + PostStatusService.new.call(follow.target_account, text: 'New status for user home timeline.') end it 'returns http success' do diff --git a/spec/controllers/api/v1/timelines/public_controller_spec.rb b/spec/controllers/api/v1/timelines/public_controller_spec.rb index a0f778cdc..737aedba6 100644 --- a/spec/controllers/api/v1/timelines/public_controller_spec.rb +++ b/spec/controllers/api/v1/timelines/public_controller_spec.rb @@ -16,7 +16,7 @@ describe Api::V1::Timelines::PublicController do describe 'GET #show' do before do - PostStatusService.new.call(user.account, 'New status from user for federated public timeline.') + PostStatusService.new.call(user.account, text: 'New status from user for federated public timeline.') end it 'returns http success' do @@ -29,7 +29,7 @@ describe Api::V1::Timelines::PublicController do describe 'GET #show with local only' do before do - PostStatusService.new.call(user.account, 'New status from user for local public timeline.') + PostStatusService.new.call(user.account, text: 'New status from user for local public timeline.') end it 'returns http success' do diff --git a/spec/controllers/api/v1/timelines/tag_controller_spec.rb b/spec/controllers/api/v1/timelines/tag_controller_spec.rb index 472779f54..f71ca2a39 100644 --- a/spec/controllers/api/v1/timelines/tag_controller_spec.rb +++ b/spec/controllers/api/v1/timelines/tag_controller_spec.rb @@ -16,7 +16,7 @@ describe Api::V1::Timelines::TagController do describe 'GET #show' do before do - PostStatusService.new.call(user.account, 'It is a #test') + PostStatusService.new.call(user.account, text: 'It is a #test') end it 'returns http success' do diff --git a/spec/fabricators/scheduled_status_fabricator.rb b/spec/fabricators/scheduled_status_fabricator.rb new file mode 100644 index 000000000..52384d137 --- /dev/null +++ b/spec/fabricators/scheduled_status_fabricator.rb @@ -0,0 +1,4 @@ +Fabricator(:scheduled_status) do + account + scheduled_at { 20.hours.from_now } +end diff --git a/spec/lib/feed_manager_spec.rb b/spec/lib/feed_manager_spec.rb index 64e109aec..c506cd87f 100644 --- a/spec/lib/feed_manager_spec.rb +++ b/spec/lib/feed_manager_spec.rb @@ -108,14 +108,14 @@ RSpec.describe FeedManager do it 'returns false for status by followee mentioning another account' do bob.follow!(alice) - status = PostStatusService.new.call(alice, 'Hey @jeff') + status = PostStatusService.new.call(alice, text: 'Hey @jeff') expect(FeedManager.instance.filter?(:home, status, bob.id)).to be false end it 'returns true for status by followee mentioning blocked account' do bob.block!(jeff) bob.follow!(alice) - status = PostStatusService.new.call(alice, 'Hey @jeff') + status = PostStatusService.new.call(alice, text: 'Hey @jeff') expect(FeedManager.instance.filter?(:home, status, bob.id)).to be true end @@ -155,7 +155,7 @@ RSpec.describe FeedManager do context 'for mentions feed' do it 'returns true for status that mentions blocked account' do bob.block!(jeff) - status = PostStatusService.new.call(alice, 'Hey @jeff') + status = PostStatusService.new.call(alice, text: 'Hey @jeff') expect(FeedManager.instance.filter?(:mentions, status, bob.id)).to be true end diff --git a/spec/models/scheduled_status_spec.rb b/spec/models/scheduled_status_spec.rb new file mode 100644 index 000000000..f8c9d8b81 --- /dev/null +++ b/spec/models/scheduled_status_spec.rb @@ -0,0 +1,4 @@ +require 'rails_helper' + +RSpec.describe ScheduledStatus, type: :model do +end diff --git a/spec/services/batched_remove_status_service_spec.rb b/spec/services/batched_remove_status_service_spec.rb index c66214555..e53623449 100644 --- a/spec/services/batched_remove_status_service_spec.rb +++ b/spec/services/batched_remove_status_service_spec.rb @@ -8,8 +8,8 @@ RSpec.describe BatchedRemoveStatusService, type: :service do let!(:jeff) { Fabricate(:user).account } let!(:hank) { Fabricate(:account, username: 'hank', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } - let(:status1) { PostStatusService.new.call(alice, 'Hello @bob@example.com') } - let(:status2) { PostStatusService.new.call(alice, 'Another status') } + let(:status1) { PostStatusService.new.call(alice, text: 'Hello @bob@example.com') } + let(:status2) { PostStatusService.new.call(alice, text: 'Another status') } before do allow(Redis.current).to receive_messages(publish: nil) diff --git a/spec/services/post_status_service_spec.rb b/spec/services/post_status_service_spec.rb index 8f3552224..3774fed6f 100644 --- a/spec/services/post_status_service_spec.rb +++ b/spec/services/post_status_service_spec.rb @@ -7,7 +7,7 @@ RSpec.describe PostStatusService, type: :service do account = Fabricate(:account) text = "test status update" - status = subject.call(account, text) + status = subject.call(account, text: text) expect(status).to be_persisted expect(status.text).to eq text @@ -18,20 +18,31 @@ RSpec.describe PostStatusService, type: :service do account = Fabricate(:account) text = "test status update" - status = subject.call(account, text, in_reply_to_status) + status = subject.call(account, text: text, thread: in_reply_to_status) expect(status).to be_persisted expect(status.text).to eq text expect(status.thread).to eq in_reply_to_status end + it 'schedules a status' do + account = Fabricate(:account) + future = Time.now.utc + 2.hours + + status = subject.call(account, text: 'Hi future!', scheduled_at: future) + + expect(status).to be_a ScheduledStatus + expect(status.scheduled_at).to eq future + expect(status.params['text']).to eq 'Hi future!' + end + it 'creates response to the original status of boost' do boosted_status = Fabricate(:status) in_reply_to_status = Fabricate(:status, reblog: boosted_status) account = Fabricate(:account) text = "test status update" - status = subject.call(account, text, in_reply_to_status) + status = subject.call(account, text: text, thread: in_reply_to_status) expect(status).to be_persisted expect(status.text).to eq text @@ -69,7 +80,7 @@ RSpec.describe PostStatusService, type: :service do end it 'creates a status with limited visibility for silenced users' do - status = subject.call(Fabricate(:account, silenced: true), 'test', nil, visibility: :public) + status = subject.call(Fabricate(:account, silenced: true), text: 'test', visibility: :public) expect(status).to be_persisted expect(status.visibility).to eq "unlisted" @@ -88,7 +99,7 @@ RSpec.describe PostStatusService, type: :service do account = Fabricate(:account) text = 'This is an English text.' - status = subject.call(account, text) + status = subject.call(account, text: text) expect(status.language).to eq 'en' end @@ -99,7 +110,7 @@ RSpec.describe PostStatusService, type: :service do allow(ProcessMentionsService).to receive(:new).and_return(mention_service) account = Fabricate(:account) - status = subject.call(account, "test status update") + status = subject.call(account, text: "test status update") expect(ProcessMentionsService).to have_received(:new) expect(mention_service).to have_received(:call).with(status) @@ -111,7 +122,7 @@ RSpec.describe PostStatusService, type: :service do allow(ProcessHashtagsService).to receive(:new).and_return(hashtags_service) account = Fabricate(:account) - status = subject.call(account, "test status update") + status = subject.call(account, text: "test status update") expect(ProcessHashtagsService).to have_received(:new) expect(hashtags_service).to have_received(:call).with(status) @@ -124,7 +135,7 @@ RSpec.describe PostStatusService, type: :service do account = Fabricate(:account) - status = subject.call(account, "test status update") + status = subject.call(account, text: "test status update") expect(DistributionWorker).to have_received(:perform_async).with(status.id) expect(Pubsubhubbub::DistributionWorker).to have_received(:perform_async).with(status.stream_entry.id) @@ -135,7 +146,7 @@ RSpec.describe PostStatusService, type: :service do allow(LinkCrawlWorker).to receive(:perform_async) account = Fabricate(:account) - status = subject.call(account, "test status update") + status = subject.call(account, text: "test status update") expect(LinkCrawlWorker).to have_received(:perform_async).with(status.id) end @@ -146,8 +157,7 @@ RSpec.describe PostStatusService, type: :service do status = subject.call( account, - "test status update", - nil, + text: "test status update", media_ids: [media.id], ) @@ -160,8 +170,7 @@ RSpec.describe PostStatusService, type: :service do expect do subject.call( account, - "test status update", - nil, + text: "test status update", media_ids: [ Fabricate(:media_attachment, account: account), Fabricate(:media_attachment, account: account), @@ -182,8 +191,7 @@ RSpec.describe PostStatusService, type: :service do expect do subject.call( account, - "test status update", - nil, + text: "test status update", media_ids: [ Fabricate(:media_attachment, type: :video, account: account), Fabricate(:media_attachment, type: :image, account: account), @@ -197,12 +205,12 @@ RSpec.describe PostStatusService, type: :service do it 'returns existing status when used twice with idempotency key' do account = Fabricate(:account) - status1 = subject.call(account, 'test', nil, idempotency: 'meepmeep') - status2 = subject.call(account, 'test', nil, idempotency: 'meepmeep') + status1 = subject.call(account, text: 'test', idempotency: 'meepmeep') + status2 = subject.call(account, text: 'test', idempotency: 'meepmeep') expect(status2.id).to eq status1.id end def create_status_with_options(**options) - subject.call(Fabricate(:account), 'test', nil, options) + subject.call(Fabricate(:account), options.merge(text: 'test')) end end diff --git a/spec/services/remove_status_service_spec.rb b/spec/services/remove_status_service_spec.rb index 2134f51fd..7bba83a60 100644 --- a/spec/services/remove_status_service_spec.rb +++ b/spec/services/remove_status_service_spec.rb @@ -19,7 +19,7 @@ RSpec.describe RemoveStatusService, type: :service do jeff.follow!(alice) hank.follow!(alice) - @status = PostStatusService.new.call(alice, 'Hello @bob@example.com') + @status = PostStatusService.new.call(alice, text: 'Hello @bob@example.com') Fabricate(:status, account: bill, reblog: @status, uri: 'hoge') subject.call(@status) end diff --git a/spec/workers/publish_scheduled_status_worker_spec.rb b/spec/workers/publish_scheduled_status_worker_spec.rb new file mode 100644 index 000000000..f8547e6fe --- /dev/null +++ b/spec/workers/publish_scheduled_status_worker_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe PublishScheduledStatusWorker do + subject { described_class.new } + + let(:scheduled_status) { Fabricate(:scheduled_status, params: { text: 'Hello world, future!' }) } + + describe 'perform' do + before do + subject.perform(scheduled_status.id) + end + + it 'creates a status' do + expect(scheduled_status.account.statuses.first.text).to eq 'Hello world, future!' + end + + it 'removes the scheduled status' do + expect(ScheduledStatus.find_by(id: scheduled_status.id)).to be_nil + end + end +end -- cgit From 5dbe1865851923f27528248726a7170298fa3f2e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 6 Jan 2019 23:52:58 +0100 Subject: Add cache to custom emojis API (#9732) Fix #9729 --- app/controllers/api/v1/custom_emojis_controller.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'app/controllers') diff --git a/app/controllers/api/v1/custom_emojis_controller.rb b/app/controllers/api/v1/custom_emojis_controller.rb index f8cd64455..7bac27da4 100644 --- a/app/controllers/api/v1/custom_emojis_controller.rb +++ b/app/controllers/api/v1/custom_emojis_controller.rb @@ -4,6 +4,8 @@ class Api::V1::CustomEmojisController < Api::BaseController respond_to :json def index - render json: CustomEmoji.local.where(disabled: false), each_serializer: REST::CustomEmojiSerializer + render_cached_json('api:v1:custom_emojis', expires_in: 1.minute) do + ActiveModelSerializers::SerializableResource.new(CustomEmoji.local.where(disabled: false), each_serializer: REST::CustomEmojiSerializer) + end end end -- cgit From 43c61bca60016cad5d3fae210fd57622b40225a8 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 7 Jan 2019 14:50:20 +0100 Subject: Add locale param to sign-up API (#9747) Fix #9627 --- app/controllers/api/v1/accounts_controller.rb | 2 +- app/services/app_sign_up_service.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'app/controllers') diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb index 6e4084c4e..2ccbc3cbb 100644 --- a/app/controllers/api/v1/accounts_controller.rb +++ b/app/controllers/api/v1/accounts_controller.rb @@ -76,7 +76,7 @@ class Api::V1::AccountsController < Api::BaseController end def account_params - params.permit(:username, :email, :password, :agreement) + params.permit(:username, :email, :password, :agreement, :locale) end def check_enabled_registrations diff --git a/app/services/app_sign_up_service.rb b/app/services/app_sign_up_service.rb index 1878587e8..d621cc462 100644 --- a/app/services/app_sign_up_service.rb +++ b/app/services/app_sign_up_service.rb @@ -4,7 +4,7 @@ class AppSignUpService < BaseService def call(app, params) return unless allowed_registrations? - user_params = params.slice(:email, :password, :agreement) + user_params = params.slice(:email, :password, :agreement, :locale) account_params = params.slice(:username) user = User.create!(user_params.merge(created_by_application: app, password_confirmation: user_params[:password], account_attributes: account_params)) -- cgit From 5654535728f3017615b801a1b9163d61f0cf623e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 7 Jan 2019 15:36:26 +0100 Subject: Change remote interaction dialog to use specific actions (#9743) * Change remote interaction dialog to use specific actions Instead of just "interact", use different strings based on whether it's a reply, reblog or favourite. Add explanation why the step is necessary in the first place * Remove obsolete strings --- app/controllers/remote_interaction_controller.rb | 5 +++++ app/views/remote_follow/new.html.haml | 4 +++- app/views/remote_interaction/new.html.haml | 10 +++++++--- app/views/stream_entries/_detailed_status.html.haml | 6 +++--- app/views/stream_entries/_simple_status.html.haml | 6 +++--- config/locales/ar.yml | 3 --- config/locales/ast.yml | 3 --- config/locales/ca.yml | 3 --- config/locales/co.yml | 3 --- config/locales/cs.yml | 3 --- config/locales/cy.yml | 3 --- config/locales/da.yml | 3 --- config/locales/de.yml | 3 --- config/locales/el.yml | 3 --- config/locales/en.yml | 12 ++++++++++-- config/locales/eo.yml | 3 --- config/locales/es.yml | 3 --- config/locales/eu.yml | 3 --- config/locales/fa.yml | 3 --- config/locales/fr.yml | 3 --- config/locales/gl.yml | 3 --- config/locales/it.yml | 3 --- config/locales/ja.yml | 3 --- config/locales/ka.yml | 3 --- config/locales/ko.yml | 3 --- config/locales/nl.yml | 3 --- config/locales/oc.yml | 3 --- config/locales/pl.yml | 3 --- config/locales/pt-BR.yml | 3 --- config/locales/ru.yml | 3 --- config/locales/sk.yml | 3 --- config/locales/sl.yml | 2 -- config/locales/sr.yml | 3 --- 33 files changed, 31 insertions(+), 92 deletions(-) (limited to 'app/controllers') diff --git a/app/controllers/remote_interaction_controller.rb b/app/controllers/remote_interaction_controller.rb index 6299a1e13..cc6993c52 100644 --- a/app/controllers/remote_interaction_controller.rb +++ b/app/controllers/remote_interaction_controller.rb @@ -5,6 +5,7 @@ class RemoteInteractionController < ApplicationController layout 'modal' + before_action :set_interaction_type before_action :set_status before_action :set_body_classes @@ -45,4 +46,8 @@ class RemoteInteractionController < ApplicationController @body_classes = 'modal-layout' @hide_header = true end + + def set_interaction_type + @interaction_type = %w(reply reblog favourite).include?(params[:type]) ? params[:type] : 'reply' + end end diff --git a/app/views/remote_follow/new.html.haml b/app/views/remote_follow/new.html.haml index 9b679015f..5cf6977ba 100644 --- a/app/views/remote_follow/new.html.haml +++ b/app/views/remote_follow/new.html.haml @@ -16,4 +16,6 @@ .actions = f.button :button, t('remote_follow.proceed'), type: :submit - %p.hint.subtle-hint= t('remote_follow.no_account_html', sign_up_path: open_registrations? ? new_user_registration_path : 'https://joinmastodon.org/#getting-started') + %p.hint.subtle-hint + = t('remote_follow.reason_html', instance: site_hostname) + = t('remote_follow.no_account_html', sign_up_path: open_registrations? ? new_user_registration_path : 'https://joinmastodon.org/#getting-started') diff --git a/app/views/remote_interaction/new.html.haml b/app/views/remote_interaction/new.html.haml index 7357546b6..a0b106814 100644 --- a/app/views/remote_interaction/new.html.haml +++ b/app/views/remote_interaction/new.html.haml @@ -1,6 +1,6 @@ .form-container .follow-prompt - %h2= t('remote_interaction.prompt') + %h2= t("remote_interaction.#{@interaction_type}.prompt") .public-layout .activity-stream.activity-stream--highlighted @@ -9,9 +9,13 @@ = simple_form_for @remote_follow, as: :remote_follow, url: remote_interaction_path(@status) do |f| = render 'shared/error_messages', object: @remote_follow + = hidden_field_tag :type, @interaction_type + = f.input :acct, placeholder: t('remote_follow.acct'), input_html: { autocapitalize: 'none', autocorrect: 'off' } .actions - = f.button :button, t('remote_interaction.proceed'), type: :submit + = f.button :button, t("remote_interaction.#{@interaction_type}.proceed"), type: :submit - %p.hint.subtle-hint= t('remote_follow.no_account_html', sign_up_path: open_registrations? ? new_user_registration_path : 'https://joinmastodon.org/#getting-started') + %p.hint.subtle-hint + = t('remote_follow.reason_html', instance: site_hostname) + = t('remote_follow.no_account_html', sign_up_path: open_registrations? ? new_user_registration_path : 'https://joinmastodon.org/#getting-started') diff --git a/app/views/stream_entries/_detailed_status.html.haml b/app/views/stream_entries/_detailed_status.html.haml index b30729970..41d4714b9 100644 --- a/app/views/stream_entries/_detailed_status.html.haml +++ b/app/views/stream_entries/_detailed_status.html.haml @@ -43,7 +43,7 @@ - else = link_to status.application.name, status.application.website, class: 'detailed-status__application', target: '_blank', rel: 'noopener' · - = link_to remote_interaction_path(status), class: 'modal-button detailed-status__link' do + = link_to remote_interaction_path(status, type: :reply), class: 'modal-button detailed-status__link' do = fa_icon('reply') %span.detailed-status__reblogs>= number_to_human status.replies_count, strip_insignificant_zeros: true = " " @@ -55,12 +55,12 @@ %span.detailed-status__link< = fa_icon('lock') - else - = link_to remote_interaction_path(status), class: 'modal-button detailed-status__link' do + = link_to remote_interaction_path(status, type: :reblog), class: 'modal-button detailed-status__link' do = fa_icon('retweet') %span.detailed-status__reblogs>= number_to_human status.reblogs_count, strip_insignificant_zeros: true = " " · - = link_to remote_interaction_path(status), class: 'modal-button detailed-status__link' do + = link_to remote_interaction_path(status, type: :favourite), class: 'modal-button detailed-status__link' do = fa_icon('star') %span.detailed-status__favorites>= number_to_human status.favourites_count, strip_insignificant_zeros: true = " " diff --git a/app/views/stream_entries/_simple_status.html.haml b/app/views/stream_entries/_simple_status.html.haml index f92fac86b..89a6fe048 100644 --- a/app/views/stream_entries/_simple_status.html.haml +++ b/app/views/stream_entries/_simple_status.html.haml @@ -37,15 +37,15 @@ .status__action-bar .status__action-bar__counter - = link_to remote_interaction_path(status), class: 'status__action-bar-button icon-button modal-button', style: 'font-size: 18px; width: 23.1429px; height: 23.1429px; line-height: 23.15px;' do + = link_to remote_interaction_path(status, type: :reply), class: 'status__action-bar-button icon-button modal-button', style: 'font-size: 18px; width: 23.1429px; height: 23.1429px; line-height: 23.15px;' do = fa_icon 'reply fw' .status__action-bar__counter__label= obscured_counter status.replies_count - = link_to remote_interaction_path(status), class: 'status__action-bar-button icon-button modal-button', style: 'font-size: 18px; width: 23.1429px; height: 23.1429px; line-height: 23.15px;' do + = link_to remote_interaction_path(status, type: :reblog), class: 'status__action-bar-button icon-button modal-button', style: 'font-size: 18px; width: 23.1429px; height: 23.1429px; line-height: 23.15px;' do - if status.public_visibility? || status.unlisted_visibility? = fa_icon 'retweet fw' - elsif status.private_visibility? = fa_icon 'lock fw' - else = fa_icon 'envelope fw' - = link_to remote_interaction_path(status), class: 'status__action-bar-button icon-button modal-button', style: 'font-size: 18px; width: 23.1429px; height: 23.1429px; line-height: 23.15px;' do + = link_to remote_interaction_path(status, type: :favourite), class: 'status__action-bar-button icon-button modal-button', style: 'font-size: 18px; width: 23.1429px; height: 23.1429px; line-height: 23.15px;' do = fa_icon 'star fw' diff --git a/config/locales/ar.yml b/config/locales/ar.yml index 49ee567f3..8766190e3 100644 --- a/config/locales/ar.yml +++ b/config/locales/ar.yml @@ -730,9 +730,6 @@ ar: no_account_html: أليس عندك حساب بعدُ ؟ يُمْكنك التسجيل مِن هنا proceed: أكمل المتابعة prompt: 'إنك بصدد متابعة :' - remote_interaction: - proceed: إبدأ التفاعل - prompt: 'تريد التفاعُل مع هذا التبويق:' remote_unfollow: error: خطأ title: العنوان diff --git a/config/locales/ast.yml b/config/locales/ast.yml index c18c398eb..6c7ffc9bd 100644 --- a/config/locales/ast.yml +++ b/config/locales/ast.yml @@ -268,9 +268,6 @@ ast: no_account_html: "¿Nun tienes una cuenta? Pues rexistrate equí" proceed: Siguir prompt: 'Vas siguir a:' - remote_interaction: - proceed: Interactuar - prompt: 'Quies interactuar con esti toot:' remote_unfollow: error: Fallu sessions: diff --git a/config/locales/ca.yml b/config/locales/ca.yml index ed23a0e8b..9cb9722c1 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -702,9 +702,6 @@ ca: no_account_html: No tens cap compte? Pots registrar-te aquí proceed: Comença a seguir prompt: 'Seguiràs a:' - remote_interaction: - proceed: Procedeix a interactuar - prompt: 'Vols interactuar amb aquest toot:' remote_unfollow: error: Error title: Títol diff --git a/config/locales/co.yml b/config/locales/co.yml index 47c094f43..1529c4fa3 100644 --- a/config/locales/co.yml +++ b/config/locales/co.yml @@ -704,9 +704,6 @@ co: no_account_html: Ùn avete micca un contu? Pudete arregistravi quì proceed: Cuntinuà per siguità prompt: 'Avete da siguità:' - remote_interaction: - proceed: Cunfirmà l'interazzione - prompt: 'Vulete interagisce cù u statutu:' remote_unfollow: error: Errore title: Titulu diff --git a/config/locales/cs.yml b/config/locales/cs.yml index f7b1fbef0..0b666a23b 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -714,9 +714,6 @@ cs: no_account_html: Ještě nemáte účet? Můžete se registrovat zde proceed: Pokračovat ke sledování prompt: 'Budete sledovat:' - remote_interaction: - proceed: Pokračovat k interakci - prompt: 'Chcete interagovat s tímto tootem:' remote_unfollow: error: Chyba title: Nadpis diff --git a/config/locales/cy.yml b/config/locales/cy.yml index af37278e2..22b70d1fd 100644 --- a/config/locales/cy.yml +++ b/config/locales/cy.yml @@ -660,9 +660,6 @@ cy: no_account_html: Heb gyfrif? Mae modd i chi gofrestru yma proceed: Ymlaen i ddilyn prompt: 'Yr ydych am ddilyn:' - remote_interaction: - proceed: Ymlaen i ryngweithio - prompt: 'Rydych eisiau rhyngweithio a''r tŵt hwn:' remote_unfollow: error: Gwall title: Teitl diff --git a/config/locales/da.yml b/config/locales/da.yml index 074a774f0..5a9fb7881 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -675,9 +675,6 @@ da: no_account_html: Har du ikke en konto? Du kan oprette dig her proceed: Fortsæt for at følge prompt: 'Du er ved at følge:' - remote_interaction: - proceed: Fortsæt for at interagere - prompt: 'Du ønsker at interagere med dette trut:' remote_unfollow: error: Fejl title: Titel diff --git a/config/locales/de.yml b/config/locales/de.yml index 5be292896..c505bd8bb 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -704,9 +704,6 @@ de: no_account_html: Noch keinen Account? Du kannst dich hier anmelden proceed: Weiter prompt: 'Du wirst dieser Person folgen:' - remote_interaction: - proceed: Fortfahren zum Interagieren - prompt: 'Du wirst mit diesem Beitrag interagieren:' remote_unfollow: error: Fehler title: Titel diff --git a/config/locales/el.yml b/config/locales/el.yml index 9f2da4c73..e453b581f 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -703,9 +703,6 @@ el: no_account_html: Δεν έχεις λογαριασμό; Μπορείς να γραφτείς εδώ proceed: Συνέχισε για να ακολουθήσεις prompt: 'Θα ακολουθήσεις:' - remote_interaction: - proceed: Συνέχισε για να αλληλεπιδράσεις - prompt: 'Θέλεις να αλληλεπιδράσεις με αυτό το τουτ:' remote_unfollow: error: Σφάλμα title: Τίτλος diff --git a/config/locales/en.yml b/config/locales/en.yml index 1f240f272..0d01ad466 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -723,9 +723,17 @@ en: no_account_html: Don't have an account? You can sign up here proceed: Proceed to follow prompt: 'You are going to follow:' + reason_html: "Why is this step necessary? %{instance} might not be the server where you are registered, so we need to redirect you to your home server first." remote_interaction: - proceed: Proceed to interact - prompt: 'You want to interact with this toot:' + favourite: + proceed: Proceed to favourite + prompt: 'You want to favourite this toot:' + reblog: + proceed: Proceed to boost + prompt: 'You want to boost this toot:' + reply: + proceed: Proceed to reply + prompt: 'You want to reply to this toot:' remote_unfollow: error: Error title: Title diff --git a/config/locales/eo.yml b/config/locales/eo.yml index 8e30ed679..c05b21108 100644 --- a/config/locales/eo.yml +++ b/config/locales/eo.yml @@ -696,9 +696,6 @@ eo: no_account_html: Ĉu vi ne havas konton? Vi povas registriĝi tie proceed: Daŭrigi por eksekvi prompt: 'Vi eksekvos:' - remote_interaction: - proceed: Efektivigi la interagon - prompt: 'Vi volas interagi kun ĉi tiu mesaĝo:' remote_unfollow: error: Eraro title: Titolo diff --git a/config/locales/es.yml b/config/locales/es.yml index 957d852b8..bf4cc29fe 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -681,9 +681,6 @@ es: no_account_html: "¿No tienes una cuenta? Puedes registrarte aqui" proceed: Proceder a seguir prompt: 'Vas a seguir a:' - remote_interaction: - proceed: Proceder para interactuar - prompt: 'Quieres interactuar con este toot:' remote_unfollow: error: Error title: Título diff --git a/config/locales/eu.yml b/config/locales/eu.yml index 819e22b26..78fd48958 100644 --- a/config/locales/eu.yml +++ b/config/locales/eu.yml @@ -698,9 +698,6 @@ eu: no_account_html: Ez duzu konturik? Izena eman dezakezu proceed: Ekin jarraitzeari prompt: 'Hau jarraituko duzu:' - remote_interaction: - proceed: Jarraitu interakziora - prompt: 'Toot honekin interakzioa nahi duzu:' remote_unfollow: error: Errorea title: Izenburua diff --git a/config/locales/fa.yml b/config/locales/fa.yml index d8f89a91b..5fccefc6d 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -681,9 +681,6 @@ fa: no_account_html: هنوز عضو نیستید؟ این‌جا می‌توانید حساب باز کنید proceed: درخواست پیگیری prompt: 'شما قرار است این حساب را پیگیری کنید:' - remote_interaction: - proceed: ادامهٔ برهم‌کنش - prompt: 'شما می‌خواهید دربارهٔ این بوق کاری کنید:' remote_unfollow: error: خطا title: عنوان diff --git a/config/locales/fr.yml b/config/locales/fr.yml index b38e9f8e4..857288110 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -704,9 +704,6 @@ fr: no_account_html: Vous n’avez pas de compte ? Vous pouvez vous inscrire ici proceed: Confirmer l’abonnement prompt: 'Vous allez suivre :' - remote_interaction: - proceed: Confirmer l’interaction - prompt: 'Vous désirez interagir avec ce pouet :' remote_unfollow: error: Erreur title: Titre diff --git a/config/locales/gl.yml b/config/locales/gl.yml index ac7d55cda..5908e773b 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -704,9 +704,6 @@ gl: no_account_html: Non ten unha conta? Pode rexistrarse aquí proceed: Proceda para seguir prompt: 'Vostede vai seguir:' - remote_interaction: - proceed: Proceda para interactuar - prompt: 'Vostede quere interactuar con este toot:' remote_unfollow: error: Fallo title: Título diff --git a/config/locales/it.yml b/config/locales/it.yml index cc23b8cf7..0b96ef46a 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -660,9 +660,6 @@ it: no_account_html: Non hai un account? Puoi iscriverti qui proceed: Conferma prompt: 'Stai per seguire:' - remote_interaction: - proceed: Continua per interagire - prompt: 'Vuoi interagire con questo toot:' remote_unfollow: error: Errore title: Titolo diff --git a/config/locales/ja.yml b/config/locales/ja.yml index a8773c4d2..22965a595 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -703,9 +703,6 @@ ja: no_account_html: アカウントをお持ちではないですか?こちらからサインアップできます proceed: フォローする prompt: 'フォローしようとしています:' - remote_interaction: - proceed: 進む - prompt: 'このトゥートに返信しようとしています:' remote_unfollow: error: エラー title: タイトル diff --git a/config/locales/ka.yml b/config/locales/ka.yml index 21e01c8c9..7dd586aee 100644 --- a/config/locales/ka.yml +++ b/config/locales/ka.yml @@ -651,9 +651,6 @@ ka: no_account_html: არ გაქვთ ანგარიში? შეგიძლიათ დარეგისტრირდეთ აქ proceed: გააგრძელეთ გასაყოლად prompt: 'თქვენ გაჰყვებით:' - remote_interaction: - proceed: გააგრძელეთ ურთიერთქმედება - prompt: 'თქვენ გსურთ ურთიერთქმედება ამ ტუტთან:' remote_unfollow: error: შეცდომა title: სათაური diff --git a/config/locales/ko.yml b/config/locales/ko.yml index 9ac1cd6b9..acfc811f3 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -706,9 +706,6 @@ ko: no_account_html: 계정이 없나요? 여기에서 가입 할 수 있습니다 proceed: 팔로우 하기 prompt: '팔로우 하려 하고 있습니다:' - remote_interaction: - proceed: 진행 - prompt: '이 게시물에 상호작용하려 하고 있습니다:' remote_unfollow: error: 에러 title: 타이틀 diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 1d85ab4c9..92acb71d1 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -704,9 +704,6 @@ nl: no_account_html: Heb je geen account? Je kunt er hier een registreren proceed: Ga verder om te volgen prompt: 'Jij gaat volgen:' - remote_interaction: - proceed: Ga de interactie aan - prompt: 'Jij wilt de interactie aangaan met deze toot:' remote_unfollow: error: Fout title: Titel diff --git a/config/locales/oc.yml b/config/locales/oc.yml index daabea18a..e81b10dac 100644 --- a/config/locales/oc.yml +++ b/config/locales/oc.yml @@ -760,9 +760,6 @@ oc: no_account_html: Avètz pas cap de compte ? Podètz vos marcar aquí proceed: Clicatz per sègre prompt: 'Sètz per sègre :' - remote_interaction: - proceed: Confirmar l’interaccion - prompt: 'Volètz interagir amb aqueste tut :' remote_unfollow: error: Error title: Títol diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 7478d0ea7..80259d013 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -715,9 +715,6 @@ pl: no_account_html: Nie masz konta? Możesz zarejestrować się tutaj proceed: Śledź prompt: 'Zamierzasz śledzić:' - remote_interaction: - proceed: Przejdź do interakcji - prompt: 'Chcesz dokonać interakcji z tym wpisem:' remote_unfollow: error: Błąd title: Tytuł diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index bd5cd7b36..efb8b1bf8 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -702,9 +702,6 @@ pt-BR: no_account_html: Não tem uma conta? Você pode cadastrar-se aqui proceed: Prosseguir para seguir prompt: 'Você irá seguir:' - remote_interaction: - proceed: Continue para interagir - prompt: 'Você quer interagir com este toot:' remote_unfollow: error: Erro title: Título diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 3b81c9ebc..40e66ceac 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -683,9 +683,6 @@ ru: no_account_html: Нет учётной записи? Вы можете зарегистрироваться здесь proceed: Продолжить подписку prompt: 'Вы хотите подписаться на:' - remote_interaction: - proceed: Продолжить - prompt: 'Вы собираетесь взаимодействовать со статусом:' remote_unfollow: error: Ошибка title: Заголовок diff --git a/config/locales/sk.yml b/config/locales/sk.yml index d30978e46..36399d752 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -714,9 +714,6 @@ sk: no_account_html: Nemáš ešte účet? Môžeš sa zaregistrovať tu proceed: Začni následovať prompt: 'Budeš sledovať:' - remote_interaction: - proceed: Pokračuj k interakcii - prompt: 'Chceš narábať s týmto príspevkom:' remote_unfollow: error: Chyba title: Názov diff --git a/config/locales/sl.yml b/config/locales/sl.yml index f35d5f09e..594c58acc 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -130,8 +130,6 @@ sl: most_recent_activity: Zadnja aktivnost most_recent_ip: Zadnji IP promote: Spodbujanje - remote_interaction: - prompt: 'Želite interakcijo s tem trobom:' statuses: pin_errors: ownership: Trob nekoga drugega ne more biti pripet diff --git a/config/locales/sr.yml b/config/locales/sr.yml index 8dc869c8f..009281339 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -701,9 +701,6 @@ sr: no_account_html: Немате налог? Можете се пријавити овде proceed: Наставите да би сте запратили prompt: 'Запратићете:' - remote_interaction: - proceed: Наставите за интеракцију - prompt: 'Желите да интерактирате са овом трубом:' remote_unfollow: error: Грешка title: Наслов -- cgit From 28b482874ab4393639a77fdd895658096bcbfd57 Mon Sep 17 00:00:00 2001 From: ThibG Date: Mon, 7 Jan 2019 21:45:13 +0100 Subject: Improvements to signature verification (#9667) * Refactor signature verification a bit * Rescue signature verification if recorded public key is invalid Fixes #8822 * Always re-fetch AP signing key when HTTP Signature verification fails But when the account is not marked as stale, avoid fetching collections and media, and avoid webfinger round-trip. * Apply stoplight to key/account update as well as initial key retrieval --- app/controllers/concerns/signature_verification.rb | 45 +++++++++++++++------- .../activitypub/fetch_remote_account_service.rb | 8 ++-- .../activitypub/process_account_service.rb | 10 +++-- 3 files changed, 41 insertions(+), 22 deletions(-) (limited to 'app/controllers') diff --git a/app/controllers/concerns/signature_verification.rb b/app/controllers/concerns/signature_verification.rb index 887096e8b..91566c4fa 100644 --- a/app/controllers/concerns/signature_verification.rb +++ b/app/controllers/concerns/signature_verification.rb @@ -60,23 +60,26 @@ module SignatureVerification signature = Base64.decode64(signature_params['signature']) compare_signed_string = build_signed_string(signature_params['headers']) - if account.keypair.public_key.verify(OpenSSL::Digest::SHA256.new, signature, compare_signed_string) - @signed_request_account = account - @signed_request_account - elsif account.possibly_stale? - account = account.refresh! + return account unless verify_signature(account, signature, compare_signed_string).nil? - if account.keypair.public_key.verify(OpenSSL::Digest::SHA256.new, signature, compare_signed_string) - @signed_request_account = account - @signed_request_account - else - @signature_verification_failure_reason = "Verification failed for #{account.username}@#{account.domain} #{account.uri}" - @signed_request_account = nil - end - else - @signature_verification_failure_reason = "Verification failed for #{account.username}@#{account.domain} #{account.uri}" + account_stoplight = Stoplight("source:#{request.ip}") { account.possibly_stale? ? account.refresh! : account_refresh_key(account) } + .with_fallback { nil } + .with_threshold(1) + .with_cool_off_time(5.minutes.seconds) + .with_error_handler { |error, handle| error.is_a?(HTTP::Error) ? handle.call(error) : raise(error) } + + account = account_stoplight.run + + if account.nil? + @signature_verification_failure_reason = "Public key not found for key #{signature_params['keyId']}" @signed_request_account = nil + return end + + return account unless verify_signature(account, signature, compare_signed_string).nil? + + @signature_verification_failure_reason = "Verification failed for #{account.username}@#{account.domain} #{account.uri}" + @signed_request_account = nil end def request_body @@ -85,6 +88,15 @@ module SignatureVerification private + def verify_signature(account, signature, compare_signed_string) + if account.keypair.public_key.verify(OpenSSL::Digest::SHA256.new, signature, compare_signed_string) + @signed_request_account = account + @signed_request_account + end + rescue OpenSSL::PKey::RSAError + nil + end + def build_signed_string(signed_headers) signed_headers = 'date' if signed_headers.blank? @@ -131,4 +143,9 @@ module SignatureVerification account end end + + def account_refresh_key(account) + return if account.local? || !account.activitypub? + ActivityPub::FetchRemoteAccountService.new.call(account.uri, only_key: true) + end end diff --git a/app/services/activitypub/fetch_remote_account_service.rb b/app/services/activitypub/fetch_remote_account_service.rb index 8430d12d5..3c2044941 100644 --- a/app/services/activitypub/fetch_remote_account_service.rb +++ b/app/services/activitypub/fetch_remote_account_service.rb @@ -5,8 +5,8 @@ class ActivityPub::FetchRemoteAccountService < BaseService SUPPORTED_TYPES = %w(Application Group Organization Person Service).freeze - # Does a WebFinger roundtrip on each call - def call(uri, id: true, prefetched_body: nil, break_on_redirect: false) + # Does a WebFinger roundtrip on each call, unless `only_key` is true + def call(uri, id: true, prefetched_body: nil, break_on_redirect: false, only_key: false) return ActivityPub::TagManager.instance.uri_to_resource(uri, Account) if ActivityPub::TagManager.instance.local_uri?(uri) @json = if prefetched_body.nil? @@ -21,9 +21,9 @@ class ActivityPub::FetchRemoteAccountService < BaseService @username = @json['preferredUsername'] @domain = Addressable::URI.parse(@uri).normalized_host - return unless verified_webfinger? + return unless only_key || verified_webfinger? - ActivityPub::ProcessAccountService.new.call(@username, @domain, @json) + ActivityPub::ProcessAccountService.new.call(@username, @domain, @json, only_key: only_key) rescue Oj::ParseError nil end diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb index d6480028f..d6c791b44 100644 --- a/app/services/activitypub/process_account_service.rb +++ b/app/services/activitypub/process_account_service.rb @@ -33,8 +33,10 @@ class ActivityPub::ProcessAccountService < BaseService after_protocol_change! if protocol_changed? after_key_change! if key_changed? && !@options[:signed_with_known_key] - check_featured_collection! if @account.featured_collection_url.present? - check_links! unless @account.fields.empty? + unless @options[:only_key] + check_featured_collection! if @account.featured_collection_url.present? + check_links! unless @account.fields.empty? + end @account rescue Oj::ParseError @@ -54,11 +56,11 @@ class ActivityPub::ProcessAccountService < BaseService end def update_account - @account.last_webfingered_at = Time.now.utc + @account.last_webfingered_at = Time.now.utc unless @options[:only_key] @account.protocol = :activitypub set_immediate_attributes! - set_fetchable_attributes! + set_fetchable_attributes! unless @options[:only_keys] @account.save_with_optional_media! end -- cgit From 1c6588accca23599ea1537ec527a5be04408b2af Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 8 Jan 2019 13:39:49 +0100 Subject: Redesign admin instances area (#9645) --- app/controllers/admin/domain_blocks_controller.rb | 11 ++--- app/controllers/admin/instances_controller.rb | 27 ++++++------ app/helpers/admin/filter_helper.rb | 3 +- app/javascript/styles/mastodon/admin.scss | 14 +++++++ app/javascript/styles/mastodon/dashboard.scss | 1 + app/models/instance.rb | 21 ++++++++-- app/models/instance_filter.rb | 17 ++------ app/policies/instance_policy.rb | 2 +- .../admin/domain_blocks/_domain_block.html.haml | 13 ------ app/views/admin/domain_blocks/index.html.haml | 17 -------- app/views/admin/instances/_instance.html.haml | 4 +- app/views/admin/instances/index.html.haml | 48 ++++++++++++++-------- app/views/admin/instances/show.html.haml | 44 ++++++++++++++++++++ config/locales/ar.yml | 10 ----- config/locales/ast.yml | 2 - config/locales/ca.yml | 10 ----- config/locales/co.yml | 10 ----- config/locales/cs.yml | 10 ----- config/locales/cy.yml | 10 ----- config/locales/da.yml | 10 ----- config/locales/de.yml | 10 ----- config/locales/el.yml | 10 ----- config/locales/en.yml | 34 +++++++++------ config/locales/eo.yml | 10 ----- config/locales/es.yml | 10 ----- config/locales/eu.yml | 10 ----- config/locales/fa.yml | 10 ----- config/locales/fi.yml | 10 ----- config/locales/fr.yml | 10 ----- config/locales/gl.yml | 10 ----- config/locales/he.yml | 7 ---- config/locales/hu.yml | 10 ----- config/locales/id.yml | 7 ---- config/locales/io.yml | 7 ---- config/locales/it.yml | 10 ----- config/locales/ja.yml | 10 ----- config/locales/ka.yml | 10 ----- config/locales/ko.yml | 10 ----- config/locales/ms.yml | 10 ----- config/locales/nl.yml | 10 ----- config/locales/no.yml | 10 ----- config/locales/oc.yml | 10 ----- config/locales/pl.yml | 10 ----- config/locales/pt-BR.yml | 10 ----- config/locales/pt.yml | 10 ----- config/locales/ru.yml | 10 ----- config/locales/sk.yml | 10 ----- config/locales/sr-Latn.yml | 10 ----- config/locales/sr.yml | 10 ----- config/locales/sv.yml | 10 ----- config/locales/th.yml | 7 ---- config/locales/tr.yml | 7 ---- config/locales/uk.yml | 10 ----- config/locales/zh-CN.yml | 10 ----- config/locales/zh-HK.yml | 10 ----- config/locales/zh-TW.yml | 10 ----- config/navigation.rb | 3 +- config/routes.rb | 8 +--- .../admin/domain_blocks_controller_spec.rb | 24 +---------- spec/policies/instance_policy_spec.rb | 2 +- 60 files changed, 159 insertions(+), 531 deletions(-) delete mode 100644 app/views/admin/domain_blocks/_domain_block.html.haml delete mode 100644 app/views/admin/domain_blocks/index.html.haml create mode 100644 app/views/admin/instances/show.html.haml (limited to 'app/controllers') diff --git a/app/controllers/admin/domain_blocks_controller.rb b/app/controllers/admin/domain_blocks_controller.rb index 90c70275a..5f307ddee 100644 --- a/app/controllers/admin/domain_blocks_controller.rb +++ b/app/controllers/admin/domain_blocks_controller.rb @@ -4,14 +4,9 @@ module Admin class DomainBlocksController < BaseController before_action :set_domain_block, only: [:show, :destroy] - def index - authorize :domain_block, :index? - @domain_blocks = DomainBlock.page(params[:page]) - end - def new authorize :domain_block, :create? - @domain_block = DomainBlock.new + @domain_block = DomainBlock.new(domain: params[:_domain]) end def create @@ -22,7 +17,7 @@ module Admin if @domain_block.save DomainBlockWorker.perform_async(@domain_block.id) log_action :create, @domain_block - redirect_to admin_domain_blocks_path, notice: I18n.t('admin.domain_blocks.created_msg') + redirect_to admin_instances_path(limited: '1'), notice: I18n.t('admin.domain_blocks.created_msg') else render :new end @@ -36,7 +31,7 @@ module Admin authorize @domain_block, :destroy? UnblockDomainService.new.call(@domain_block, retroactive_unblock?) log_action :destroy, @domain_block - redirect_to admin_domain_blocks_path, notice: I18n.t('admin.domain_blocks.destroyed_msg') + redirect_to admin_instances_path(limited: '1'), notice: I18n.t('admin.domain_blocks.destroyed_msg') end private diff --git a/app/controllers/admin/instances_controller.rb b/app/controllers/admin/instances_controller.rb index 6f8eaf65c..431ce6f4d 100644 --- a/app/controllers/admin/instances_controller.rb +++ b/app/controllers/admin/instances_controller.rb @@ -4,14 +4,21 @@ module Admin class InstancesController < BaseController def index authorize :instance, :index? + @instances = ordered_instances end - def resubscribe - authorize :instance, :resubscribe? - params.require(:by_domain) - Pubsubhubbub::SubscribeWorker.push_bulk(subscribeable_accounts.pluck(:id)) - redirect_to admin_instances_path + def show + authorize :instance, :show? + + @instance = Instance.new(Account.by_domain_accounts.find_by(domain: params[:id]) || DomainBlock.find_by!(domain: params[:id])) + @following_count = Follow.where(account: Account.where(domain: params[:id])).count + @followers_count = Follow.where(target_account: Account.where(domain: params[:id])).count + @reports_count = Report.where(target_account: Account.where(domain: params[:id])).count + @blocks_count = Block.where(target_account: Account.where(domain: params[:id])).count + @available = DeliveryFailureTracker.available?(Account.select(:shared_inbox_url).where(domain: params[:id]).first&.shared_inbox_url) + @media_storage = MediaAttachment.where(account: Account.where(domain: params[:id])).sum(:file_file_size) + @domain_block = DomainBlock.find_by(domain: params[:id]) end private @@ -27,17 +34,11 @@ module Admin helper_method :paginated_instances def ordered_instances - paginated_instances.map { |account| Instance.new(account) } - end - - def subscribeable_accounts - Account.remote.where(protocol: :ostatus).where(domain: params[:by_domain]) + paginated_instances.map { |resource| Instance.new(resource) } end def filter_params - params.permit( - :domain_name - ) + params.permit(:limited) end end end diff --git a/app/helpers/admin/filter_helper.rb b/app/helpers/admin/filter_helper.rb index 8807cc784..97beb587f 100644 --- a/app/helpers/admin/filter_helper.rb +++ b/app/helpers/admin/filter_helper.rb @@ -6,8 +6,9 @@ module Admin::FilterHelper INVITE_FILTER = %i(available expired).freeze CUSTOM_EMOJI_FILTERS = %i(local remote by_domain shortcode).freeze TAGS_FILTERS = %i(hidden).freeze + INSTANCES_FILTERS = %i(limited).freeze - FILTERS = ACCOUNT_FILTERS + REPORT_FILTERS + INVITE_FILTER + CUSTOM_EMOJI_FILTERS + TAGS_FILTERS + FILTERS = ACCOUNT_FILTERS + REPORT_FILTERS + INVITE_FILTER + CUSTOM_EMOJI_FILTERS + TAGS_FILTERS + INSTANCES_FILTERS def filter_link_to(text, link_to_params, link_class_params = link_to_params) new_url = filtered_url_for(link_to_params) diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss index e8f331932..375c655f5 100644 --- a/app/javascript/styles/mastodon/admin.scss +++ b/app/javascript/styles/mastodon/admin.scss @@ -151,6 +151,20 @@ $no-columns-breakpoint: 600px; font-weight: 500; } + .directory__tag a { + box-shadow: none; + } + + .directory__tag h4 { + font-size: 18px; + font-weight: 700; + color: $primary-text-color; + text-transform: none; + padding-bottom: 0; + margin-bottom: 0; + border-bottom: none; + } + & > p { font-size: 14px; line-height: 18px; diff --git a/app/javascript/styles/mastodon/dashboard.scss b/app/javascript/styles/mastodon/dashboard.scss index 1f96e7368..e4564f062 100644 --- a/app/javascript/styles/mastodon/dashboard.scss +++ b/app/javascript/styles/mastodon/dashboard.scss @@ -39,6 +39,7 @@ color: $primary-text-color; font-family: $font-display, sans-serif; margin-bottom: 20px; + line-height: 30px; } &__text { diff --git a/app/models/instance.rb b/app/models/instance.rb index 6d5c9c2ab..7448d465c 100644 --- a/app/models/instance.rb +++ b/app/models/instance.rb @@ -3,10 +3,23 @@ class Instance include ActiveModel::Model - attr_accessor :domain, :accounts_count + attr_accessor :domain, :accounts_count, :domain_block - def initialize(account) - @domain = account.domain - @accounts_count = account.accounts_count + def initialize(resource) + @domain = resource.domain + @accounts_count = resource.accounts_count + @domain_block = resource.is_a?(DomainBlock) ? resource : DomainBlock.find_by(domain: domain) + end + + def cached_sample_accounts + Rails.cache.fetch("#{cache_key}/sample_accounts", expires_in: 12.hours) { Account.where(domain: domain).searchable.joins(:account_stat).popular.limit(3) } + end + + def to_param + domain + end + + def cache_key + domain end end diff --git a/app/models/instance_filter.rb b/app/models/instance_filter.rb index 5073cf1fa..3483d8cd6 100644 --- a/app/models/instance_filter.rb +++ b/app/models/instance_filter.rb @@ -8,21 +8,10 @@ class InstanceFilter end def results - scope = Account.remote.by_domain_accounts - params.each do |key, value| - scope.merge!(scope_for(key, value)) if value.present? - end - scope - end - - private - - def scope_for(key, value) - case key.to_s - when 'domain_name' - Account.matches_domain(value) + if params[:limited].present? + DomainBlock.order(id: :desc) else - raise "Unknown filter: #{key}" + Account.remote.by_domain_accounts end end end diff --git a/app/policies/instance_policy.rb b/app/policies/instance_policy.rb index d1956e2de..a73823556 100644 --- a/app/policies/instance_policy.rb +++ b/app/policies/instance_policy.rb @@ -5,7 +5,7 @@ class InstancePolicy < ApplicationPolicy admin? end - def resubscribe? + def show? admin? end end diff --git a/app/views/admin/domain_blocks/_domain_block.html.haml b/app/views/admin/domain_blocks/_domain_block.html.haml deleted file mode 100644 index 7bfea3574..000000000 --- a/app/views/admin/domain_blocks/_domain_block.html.haml +++ /dev/null @@ -1,13 +0,0 @@ -%tr - %td - %samp= domain_block.domain - %td.severity - = t("admin.domain_blocks.severities.#{domain_block.severity}") - %td.reject_media - - if domain_block.reject_media? || domain_block.suspend? - %i.fa.fa-check - %td.reject_reports - - if domain_block.reject_reports? || domain_block.suspend? - %i.fa.fa-check - %td - = table_link_to 'undo', t('admin.domain_blocks.undo'), admin_domain_block_path(domain_block) diff --git a/app/views/admin/domain_blocks/index.html.haml b/app/views/admin/domain_blocks/index.html.haml deleted file mode 100644 index 4c5221c42..000000000 --- a/app/views/admin/domain_blocks/index.html.haml +++ /dev/null @@ -1,17 +0,0 @@ -- content_for :page_title do - = t('admin.domain_blocks.title') - -.table-wrapper - %table.table - %thead - %tr - %th= t('admin.domain_blocks.domain') - %th= t('admin.domain_blocks.severity') - %th= t('admin.domain_blocks.reject_media') - %th= t('admin.domain_blocks.reject_reports') - %th - %tbody - = render @domain_blocks - -= paginate @domain_blocks -= link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path, class: 'button' diff --git a/app/views/admin/instances/_instance.html.haml b/app/views/admin/instances/_instance.html.haml index e36ebae47..57d3e0b06 100644 --- a/app/views/admin/instances/_instance.html.haml +++ b/app/views/admin/instances/_instance.html.haml @@ -1,7 +1,5 @@ %tr %td - = link_to instance.domain, admin_accounts_path(by_domain: instance.domain) + = link_to instance.domain, admin_instance_path(instance) %td.count = instance.accounts_count - %td - = table_link_to 'paper-plane-o', t('admin.accounts.resubscribe'), resubscribe_admin_instances_url(by_domain: instance.domain), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } diff --git a/app/views/admin/instances/index.html.haml b/app/views/admin/instances/index.html.haml index 3314ce077..ce35b5db4 100644 --- a/app/views/admin/instances/index.html.haml +++ b/app/views/admin/instances/index.html.haml @@ -1,23 +1,39 @@ - content_for :page_title do = t('admin.instances.title') -= form_tag admin_instances_url, method: 'GET', class: 'simple_form' do - .fields-group - - %i(domain_name).each do |key| - .input.string.optional - = text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.instances.#{key}") +.filters + .filter-subset + %strong= t('admin.instances.moderation.title') + %ul + %li= filter_link_to t('admin.instances.moderation.all'), limited: nil + %li= filter_link_to t('admin.instances.moderation.limited'), limited: '1' - .actions - %button= t('admin.instances.search') - = link_to t('admin.instances.reset'), admin_instances_path, class: 'button negative' + %div{ style: 'flex: 1 1 auto; text-align: right' } + = link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path, class: 'button' -.table-wrapper - %table.table - %thead - %tr - %th= t('admin.instances.domain_name') - %th= t('admin.instances.account_count') - %tbody - = render @instances +%hr.spacer/ + +- @instances.each do |instance| + .directory__tag + = link_to admin_instance_path(instance) do + %h4 + = instance.domain + %small + = t('admin.instances.known_accounts', count: instance.accounts_count) + + - if instance.domain_block + - if !instance.domain_block.noop? + • + = t("admin.domain_blocks.severity.#{instance.domain_block.severity}") + - if instance.domain_block.reject_media? + • + = t('admin.domain_blocks.rejecting_media') + - if instance.domain_block.reject_reports? + • + = t('admin.domain_blocks.rejecting_reports') + + .avatar-stack + - instance.cached_sample_accounts.each do |account| + = image_tag current_account&.user&.setting_auto_play_gif ? account.avatar_original_url : account.avatar_static_url, width: 48, height: 48, alt: '', class: 'account__avatar' = paginate paginated_instances diff --git a/app/views/admin/instances/show.html.haml b/app/views/admin/instances/show.html.haml new file mode 100644 index 000000000..c7992a490 --- /dev/null +++ b/app/views/admin/instances/show.html.haml @@ -0,0 +1,44 @@ +- content_for :page_title do + = @instance.domain + +.dashboard__counters + %div + %div + .dashboard__counters__num= number_with_delimiter @following_count + .dashboard__counters__label= t 'admin.instances.total_followed_by_them' + %div + %div + .dashboard__counters__num= number_with_delimiter @followers_count + .dashboard__counters__label= t 'admin.instances.total_followed_by_us' + %div + %div + .dashboard__counters__num= number_to_human_size @media_storage + .dashboard__counters__label= t 'admin.instances.total_storage' + %div + %div + .dashboard__counters__num= number_with_delimiter @blocks_count + .dashboard__counters__label= t 'admin.instances.total_blocked_by_us' + %div + %div + .dashboard__counters__num= number_with_delimiter @reports_count + .dashboard__counters__label= t 'admin.instances.total_reported' + %div + %div + .dashboard__counters__num + - if @available + = fa_icon 'check' + - else + = fa_icon 'times' + .dashboard__counters__label= t 'admin.instances.delivery_available' + +%hr.spacer/ + +%div{ style: 'overflow: hidden' } + %div{ style: 'float: left' } + = link_to t('admin.accounts.title'), admin_accounts_path(remote: '1', by_domain: @instance.domain), class: 'button' + + %div{ style: 'float: right' } + - if @domain_block + = link_to t('admin.domain_blocks.undo'), admin_domain_block_path(@domain_block), class: 'button' + - else + = link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: @instance.domain), class: 'button' diff --git a/config/locales/ar.yml b/config/locales/ar.yml index 8766190e3..abbfa38aa 100644 --- a/config/locales/ar.yml +++ b/config/locales/ar.yml @@ -280,11 +280,6 @@ ar: reject_media: رفض ملفات الوسائط reject_media_hint: يزيل ملفات الوسائط المخزنة محليًا ويرفض تنزيل أي ملفات في المستقبل. غير ذي صلة للتعليق reject_reports: رفض التقارير - severities: - noop: لا شيء - silence: إخفاء أو كتم - suspend: تعليق - severity: الشدة show: affected_accounts: few: "%{count} حسابات معنية في قاعدة البيانات" @@ -298,7 +293,6 @@ ar: suspend: إلغاء التعليق المفروض على كافة حسابات هذا النطاق title: رفع حظر النطاق عن %{domain} undo: إلغاء - title: حظر النطاقات undo: إلغاء email_domain_blocks: add_new: إضافة @@ -311,10 +305,6 @@ ar: title: إضافة نطاق بريد جديد إلى اللائحة السوداء title: القائمة السوداء للبريد الإلكتروني instances: - account_count: الحسابات المعروفة - domain_name: النطاق - reset: إعادة تعيين - search: البحث title: مثيلات الخوادم المعروفة invites: deactivate_all: تعطيلها كافة diff --git a/config/locales/ast.yml b/config/locales/ast.yml index 6c7ffc9bd..78ad796a0 100644 --- a/config/locales/ast.yml +++ b/config/locales/ast.yml @@ -96,8 +96,6 @@ ast: email_domain_blocks: domain: Dominiu instances: - account_count: Cuentes conocíes - domain_name: Dominiu title: Instancies conocíes invites: filter: diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 9cb9722c1..271fc3581 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -263,11 +263,6 @@ ca: reject_media_hint: Elimina els fitxers multimèdia emmagatzemats localment i impedeix baixar-ne cap en el futur. Irrellevant en les suspensions reject_reports: Rebutja informes reject_reports_hint: Ignora tots els informes procedents d'aquest domini. No és rellevant per a les suspensions - severities: - noop: Cap - silence: Silenci - suspend: Suspensió - severity: Severitat show: affected_accounts: one: Un compte afectat en la base de dades @@ -277,7 +272,6 @@ ca: suspend: Desfés la suspensió de tots els comptes d'aquest domini title: Desfés el bloqueig de domini de %{domain} undo: Desfés - title: Bloquejos de domini undo: Desfés email_domain_blocks: add_new: Afegeix @@ -290,10 +284,6 @@ ca: title: Nova adreça de correu en la llista negra title: Llista negra de correus electrònics instances: - account_count: Comptes coneguts - domain_name: Domini - reset: Restableix - search: Cerca title: Instàncies conegudes invites: deactivate_all: Desactiva-ho tot diff --git a/config/locales/co.yml b/config/locales/co.yml index 1529c4fa3..7a87219ab 100644 --- a/config/locales/co.yml +++ b/config/locales/co.yml @@ -265,11 +265,6 @@ co: reject_media_hint: Sguassa tutti i media caricati è ricusa caricamenti futuri. Inutile per una suspensione reject_reports: Righjittà i rapporti reject_reports_hint: Ignurà tutti i signalamenti chì venenu d'issu duminiu. Senz'oghjettu pè e suspensione - severities: - noop: Nisuna - silence: Silenzà - suspend: Suspende - severity: Severità show: affected_accounts: one: Un contu tuccatu indè a database @@ -279,7 +274,6 @@ co: suspend: Ùn suspende più i conti nant’à stu duminiu title: Ùn bluccà più u duminiu %{domain} undo: Annullà - title: Blucchimi di duminiu undo: Annullà email_domain_blocks: add_new: Aghjustà @@ -292,10 +286,6 @@ co: title: Nova iscrizzione nant’a lista nera e-mail title: Lista nera e-mail instances: - account_count: Conti cunnisciuti - domain_name: Duminiu - reset: Riinizializà - search: Cercà title: Istanze cunnisciute invites: deactivate_all: Disattivà tuttu diff --git a/config/locales/cs.yml b/config/locales/cs.yml index 0b666a23b..d2caeb999 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -269,11 +269,6 @@ cs: reject_media_hint: Odstraní lokálně uložené soubory a odmítne jejich stažení v budoucnosti. Irelevantní pro suspenzace reject_reports: Odmítnout nahlášení reject_reports_hint: Ignorovat všechna nahlášení pocházející z této domény. Nepodstatné pro suspenzace - severities: - noop: Žádné - silence: Utišit - suspend: Suspendovat - severity: Přísnost show: affected_accounts: few: "%{count} účty v databázi byly ovlivněny" @@ -284,7 +279,6 @@ cs: suspend: Zrušit suspenzaci všech existujících účtů z této domény title: Zrušit blokaci domény %{domain} undo: Odvolat - title: Doménové blokace undo: Odvolat email_domain_blocks: add_new: Přidat nový @@ -297,10 +291,6 @@ cs: title: Nový e-mail pro zablokování title: Černá listina e-mailů instances: - account_count: Známé účty - domain_name: Doména - reset: Resetovat - search: Hledat title: Známé instance invites: deactivate_all: Deaktivovat vše diff --git a/config/locales/cy.yml b/config/locales/cy.yml index 22b70d1fd..40cb1cac0 100644 --- a/config/locales/cy.yml +++ b/config/locales/cy.yml @@ -252,11 +252,6 @@ cy: reject_media_hint: Dileu dogfennau cyfryngau wedi eu cadw yn lleol ac yn gwrthod i lawrlwytho unrhyw rai yn y dyfodol. Amherthnasol i ataliadau reject_reports: Gwrthod adroddiadau reject_reports_hint: Anwybyddu'r holl adroddiadau sy'n dod o'r parth hwn. Amherthnasol i ataliadau - severities: - noop: Dim - silence: Tawelu - suspend: Atal - severity: Difrifoldeb show: affected_accounts: "%{count} o gyfrifoedd yn y bas data wedi eu hefeithio" retroactive: @@ -264,7 +259,6 @@ cy: suspend: Dad-atal pob cyfrif o'r parth hwn sy'n bodoli title: Dadwneud blocio parth ar gyfer %{domain} undo: Dadwneud - title: Blociau parth undo: Dadwneud email_domain_blocks: add_new: Ychwanegu @@ -277,10 +271,6 @@ cy: title: Cofnod newydd yng nghosbrestr e-byst title: Cosbrestr e-bost instances: - account_count: Cyfrifau hysbys - domain_name: Parth - reset: Ailosod - search: Chwilio title: Achosion hysbys invites: deactivate_all: Diffodd pob un diff --git a/config/locales/da.yml b/config/locales/da.yml index 5a9fb7881..e4286d156 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -257,11 +257,6 @@ da: reject_media: Afvis medie filer reject_media_hint: Fjerner lokalt lagrede multimedie filer og nægter at hente nogen i fremtiden. Irrelevant for udelukkelser reject_reports: Afvis anmeldelser - severities: - noop: Ingen - silence: Dæmp - suspend: Udeluk - severity: Alvorlighed show: affected_accounts: one: En konto i databasen påvirket @@ -271,7 +266,6 @@ da: suspend: Fjern udelukkelsen af alle eksisterende konti fra dette domæne title: Annuller domæne blokeringen for domænet %{domain} undo: Fortryd - title: Domæne blokeringer undo: Fortryd email_domain_blocks: add_new: Tilføj ny @@ -284,10 +278,6 @@ da: title: Ny email blokade opslag title: Email sortliste instances: - account_count: Kendte konti - domain_name: Domæne - reset: Nulstil - search: Søg title: Kendte instanser invites: deactivate_all: Deaktiver alle diff --git a/config/locales/de.yml b/config/locales/de.yml index c505bd8bb..081895c9c 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -265,11 +265,6 @@ de: reject_media_hint: Entfernt lokal gespeicherte Mediendateien und verhindert deren künftiges Herunterladen. Für Sperren irrelevant reject_reports: Meldungen ablehnen reject_reports_hint: Ignoriere alle Meldungen von dieser Domain. Irrelevant für Sperrungen - severities: - noop: Kein - silence: Stummschaltung - suspend: Sperren - severity: Schweregrad show: affected_accounts: one: Ein Konto in der Datenbank betroffen @@ -279,7 +274,6 @@ de: suspend: Alle existierenden Konten dieser Domain entsperren title: Domain-Blockade für %{domain} zurücknehmen undo: Zurücknehmen - title: Domain-Blockaden undo: Zurücknehmen email_domain_blocks: add_new: Neue hinzufügen @@ -292,10 +286,6 @@ de: title: Neue E-Mail-Domain-Blockade title: E-Mail-Domain-Blockade instances: - account_count: Bekannte Konten - domain_name: Domain - reset: Zurücksetzen - search: Suchen title: Bekannte Instanzen invites: deactivate_all: Alle deaktivieren diff --git a/config/locales/el.yml b/config/locales/el.yml index e453b581f..dd998ce5c 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -265,11 +265,6 @@ el: reject_media_hint: Αφαιρεί τα τοπικά αποθηκευμένα αρχεία πολυμέσων και αποτρέπει τη λήψη άλλων στο μέλλον. Δεν έχει σημασία για τις αναστολές reject_reports: Απόρριψη καταγγελιών reject_reports_hint: Αγνόηση όσων καταγγελιών προέρχονται από αυτό τον τομέα. Δεν σχετίζεται με τις παύσεις - severities: - noop: Κανένα - silence: Αποσιώπηση - suspend: Αναστολή - severity: Βαρύτητα show: affected_accounts: one: Επηρεάζεται ένας λογαριασμός στη βάση δεδομένων @@ -279,7 +274,6 @@ el: suspend: Αναίρεση αναστολής όλων των λογαριασμών του τομέα title: Αναίρεση αποκλεισμού για τον τομέα %{domain} undo: Αναίρεση - title: Αποκλεισμένοι τομείς undo: Αναίρεση email_domain_blocks: add_new: Πρόσθεση νέου @@ -292,10 +286,6 @@ el: title: Νέα εγγραφή email στη μαύρη λίστα title: Μαύρη λίστα email instances: - account_count: Γνωστοί λογαριασμοί - domain_name: Τομέας - reset: Επαναφορά - search: Αναζήτηση title: Γνωστοί κόμβοι invites: deactivate_all: Απενεργοποίηση όλων diff --git a/config/locales/en.yml b/config/locales/en.yml index 0d01ad466..8ad5ecb06 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -256,7 +256,7 @@ en: week_users_active: active this week week_users_new: users this week domain_blocks: - add_new: Add new + add_new: Add new domain block created_msg: Domain block is now being processed destroyed_msg: Domain block has been undone domain: Domain @@ -273,11 +273,11 @@ en: reject_media_hint: Removes locally stored media files and refuses to download any in the future. Irrelevant for suspensions reject_reports: Reject reports reject_reports_hint: Ignore all reports coming from this domain. Irrelevant for suspensions - severities: - noop: None - silence: Silence - suspend: Suspend - severity: Severity + rejecting_media: rejecting media files + rejecting_reports: rejecting reports + severity: + silence: silenced + suspend: suspended show: affected_accounts: one: One account in the database affected @@ -287,8 +287,7 @@ en: suspend: Unsuspend all existing accounts from this domain title: Undo domain block for %{domain} undo: Undo - title: Domain blocks - undo: Undo + undo: Undo domain block email_domain_blocks: add_new: Add new created_msg: Successfully added e-mail domain to blacklist @@ -303,11 +302,20 @@ en: back_to_account: Back To Account title: "%{acct}'s Followers" instances: - account_count: Known accounts - domain_name: Domain - reset: Reset - search: Search - title: Known instances + delivery_available: Delivery is available + known_accounts: + one: "%{count} known account" + other: "%{count} known accounts" + moderation: + all: All + limited: Limited + title: Moderation + title: Federation + total_blocked_by_us: Blocked by us + total_followed_by_them: Followed by them + total_followed_by_us: Followed by us + total_reported: Reports about them + total_storage: Media attachments invites: deactivate_all: Deactivate all filter: diff --git a/config/locales/eo.yml b/config/locales/eo.yml index c05b21108..b7dd7ca8b 100644 --- a/config/locales/eo.yml +++ b/config/locales/eo.yml @@ -261,11 +261,6 @@ eo: title: Nova domajna blokado reject_media: Malakcepti aŭdovidajn dosierojn reject_media_hint: Forigas aŭdovidaĵojn loke konservitajn kaj rifuzas alŝuti ajnan estonte. Senzorge pri haltigoj - severities: - noop: Nenio - silence: Kaŝi - suspend: Haltigi - severity: Severeco show: affected_accounts: one: Unu konto en la datumbazo esta influita @@ -275,7 +270,6 @@ eo: suspend: Malhaltigi ĉiujn kontojn, kiuj ekzistas en ĉi tiu domajno title: Malfari domajnan blokadon por %{domain} undo: Malfari - title: Domajnaj blokadoj undo: Malfari email_domain_blocks: add_new: Aldoni novan @@ -288,10 +282,6 @@ eo: title: Nova blokado de retadresa domajno title: Nigra listo de retadresaj domajnoj instances: - account_count: Konataj kontoj - domain_name: Domajno - reset: Restarigi - search: Serĉi title: Konataj nodoj invites: deactivate_all: Malaktivigi ĉion diff --git a/config/locales/es.yml b/config/locales/es.yml index bf4cc29fe..b221989e8 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -260,11 +260,6 @@ es: reject_media_hint: Remueve localmente archivos multimedia almacenados para descargar cualquiera en el futuro. Irrelevante para suspensiones reject_reports: Rechazar informes reject_reports_hint: Ignore todos los reportes de este dominio. Irrelevante para suspensiones - severities: - noop: Ninguno - silence: Silenciar - suspend: Suspender - severity: Severidad show: affected_accounts: one: Una cuenta en la base de datos afectada @@ -274,7 +269,6 @@ es: suspend: Des-suspender todas las cuentas existentes de este dominio title: Deshacer bloque de dominio para %{domain} undo: Deshacer - title: Bloques de Dominio undo: Deshacer email_domain_blocks: add_new: Añadir nuevo @@ -287,10 +281,6 @@ es: title: Nueva entrada en la lista negra de correo title: Lista negra de correo instances: - account_count: Cuentas conocidas - domain_name: Dominio - reset: Reiniciar - search: Buscar title: Instancias conocidas invites: deactivate_all: Desactivar todos diff --git a/config/locales/eu.yml b/config/locales/eu.yml index 78fd48958..6399fac83 100644 --- a/config/locales/eu.yml +++ b/config/locales/eu.yml @@ -262,11 +262,6 @@ eu: reject_media_hint: Lokalki gordetako multimedia fitxategiak ezabatzen ditu eta etorkizunean fitxategi berriak deskargatzeari uko egingo dio. Ez du garrantzirik kanporaketetan reject_reports: Errefusatu salaketak reject_reports_hint: Ezikusi domeinu honetatik jasotako salaketak. Kanporatzeentzako garrantzirik gabekoa - severities: - noop: Bat ere ez - silence: Isilarazi - suspend: Kanporatu - severity: Larritasuna show: affected_accounts: one: Datu-baseko kontu bati eragiten dio @@ -276,7 +271,6 @@ eu: suspend: Kendu kanporatzeko agindua domeinu honetako kontu guztiei title: Desegin %{domain} domeinuko blokeoa undo: Desegin - title: Domeinuen blokeoak undo: Desegin email_domain_blocks: add_new: Gehitu berria @@ -289,10 +283,6 @@ eu: title: Sarrera berria e-mail zerrenda beltzean title: E-mail zerrenda beltza instances: - account_count: Kontu ezagunak - domain_name: Domeinua - reset: Berrezarri - search: Bilatu title: Instantzia ezagunak invites: deactivate_all: Desgaitu guztiak diff --git a/config/locales/fa.yml b/config/locales/fa.yml index 5fccefc6d..e7dd86025 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -260,11 +260,6 @@ fa: reject_media_hint: تصویرهای ذخیره‌شده در این‌جا را پاک می‌کند و جلوی دریافت تصویرها را در آینده می‌گیرد. بی‌تأثیر برای معلق‌شده‌ها reject_reports: نپذیرفتن گزارش‌ها reject_reports_hint: گزارش‌هایی را که از این دامین می‌آید نادیده می‌گیرد. بی‌تأثیر برای معلق‌شده‌ها - severities: - noop: هیچ - silence: بی‌صداکردن - suspend: معلق‌کردن - severity: شدت show: affected_accounts: one: روی یک حساب در پایگاه داده تأثیر گذاشت @@ -274,7 +269,6 @@ fa: suspend: معلق‌شدن همهٔ حساب‌های این دامین را لغو کن title: واگردانی مسدودسازی دامنه برای %{domain} undo: واگردانی - title: دامین‌های مسدودشده undo: واگردانی email_domain_blocks: add_new: افزودن تازه @@ -287,10 +281,6 @@ fa: title: مسدودسازی دامین ایمیل تازه title: مسدودسازی دامین‌های ایمیل instances: - account_count: حساب‌های شناخته‌شده - domain_name: دامین - reset: بازنشانی - search: جستجو title: سرورهای شناخته‌شده invites: deactivate_all: غیرفعال‌کردن همه diff --git a/config/locales/fi.yml b/config/locales/fi.yml index b48635e21..e7b8b18ae 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -211,11 +211,6 @@ fi: title: Uusi verkkotunnuksen esto reject_media: Hylkää mediatiedostot reject_media_hint: Poistaa paikallisesti tallennetut mediatiedostot eikä lataa niitä enää jatkossa. Ei merkitystä jäähyn kohdalla - severities: - noop: Ei mitään - silence: Hiljennys - suspend: Jäähy - severity: Vakavuus show: affected_accounts: one: Vaikuttaa yhteen tiliin tietokannassa @@ -225,7 +220,6 @@ fi: suspend: Peru kaikkien tässä verkkotunnuksessa jo olemassa olevien tilien jäähy title: Peru verkkotunnuksen %{domain} esto undo: Peru - title: Verkkotunnusten estot undo: Peru email_domain_blocks: add_new: Lisää uusi @@ -238,10 +232,6 @@ fi: title: Uusi sähköpostiestolistan merkintä title: Sähköpostiestolista instances: - account_count: Tiedossa olevat tilit - domain_name: Verkkotunnus - reset: Palauta - search: Hae title: Tiedossa olevat instanssit invites: filter: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 857288110..2faed982e 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -265,11 +265,6 @@ fr: reject_media_hint: Supprime localement les fichiers média stockés et refuse d’en télécharger ultérieurement. Ne concerne pas les suspensions reject_reports: Rapports de rejet reject_reports_hint: Ignorez tous les rapports provenant de ce domaine. Sans objet pour les suspensions - severities: - noop: Aucune - silence: Masquer - suspend: Suspendre - severity: Séverité show: affected_accounts: one: Un compte affecté dans la base de données @@ -279,7 +274,6 @@ fr: suspend: Annuler la suspension sur tous les comptes existants pour ce domaine title: Annuler le blocage de domaine pour %{domain} undo: Annuler - title: Blocage de domaines undo: Annuler email_domain_blocks: add_new: Ajouter @@ -292,10 +286,6 @@ fr: title: Nouveau blocage de domaine de courriel title: Blocage de domaines de courriel instances: - account_count: Comptes connus - domain_name: Domaine - reset: Réinitialiser - search: Rechercher title: Instances connues invites: deactivate_all: Tout désactiver diff --git a/config/locales/gl.yml b/config/locales/gl.yml index 5908e773b..eb6261909 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -265,11 +265,6 @@ gl: reject_media_hint: Eliminar ficheiros de medios almacenados localmente e rexeita descargalos no futuro. Irrelevante para as suspensións reject_reports: Rexeitar informes reject_reports_hint: Ignorar todos os informes procedentes de este dominio. Irrelevante para as suspensións - severities: - noop: Ningún - silence: Silenciar - suspend: Suspender - severity: Severidade show: affected_accounts: one: Afectoulle a unha conta na base de datos @@ -279,7 +274,6 @@ gl: suspend: Non suspender todas as contas existentes de este dominio title: Desfacer o bloqueo de dominio para %{domain} undo: Desfacer - title: Bloqueos de domino undo: Desfacer email_domain_blocks: add_new: Engadir novo @@ -292,10 +286,6 @@ gl: title: Nova entrada la lista negra de e-mail title: Lista negra de E-mail instances: - account_count: Contas coñecidas - domain_name: Dominio - reset: Restablecer - search: Buscar title: Instancias coñecidas invites: deactivate_all: Desactivar todo diff --git a/config/locales/he.yml b/config/locales/he.yml index f45afe3a1..bc92ed908 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -156,10 +156,6 @@ he: title: חסימת שרת חדשה reject_media: חסימת קבצי מדיה reject_media_hint: מסירה קבצי מדיה השמורים מקומית ומונעת מהורדת קבצים נוספים בעתיד. לא רלוונטי להשעיות - severities: - silence: השתקה - suspend: השעייה - severity: חוּמרה show: affected_accounts: one: חשבון אחד במסד הנתונים מושפע @@ -169,11 +165,8 @@ he: suspend: הסרת השעייה מכל החשבונות על שרת זה title: ביטול חסימת שרת עבור %{domain} undo: ביטול - title: חסימת שרתים undo: ביטול instances: - account_count: חשבונות מוכרים - domain_name: שם מתחם title: שרתים מוכרים reports: are_you_sure: 100% על בטוח? diff --git a/config/locales/hu.yml b/config/locales/hu.yml index 4fa74228d..79363b9ee 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -195,11 +195,6 @@ hu: title: Új domain-tiltás reject_media: Médiafájlok elutasítása reject_media_hint: Eltávolítja a helyben tárolt médiafájlokat és a továbbiakban letiltja az új médiafájlok letöltését. Felfüggesztett fiókok esetében irreleváns opció - severities: - noop: Egyik sem - silence: Némítás - suspend: Felfüggesztés - severity: Súlyosság show: affected_accounts: one: Összesen egy fiók érintett az adatbázisban @@ -209,7 +204,6 @@ hu: suspend: Minden felhasználó felfüggesztésének feloldása ezen a domainen title: "%{domain} domain tiltásának feloldása" undo: Visszavonás - title: Tiltott domainek undo: Visszavonás email_domain_blocks: add_new: Új hozzáadása @@ -222,10 +216,6 @@ hu: title: Új e-mail feketelista bejegyzés title: E-mail feketelista instances: - account_count: Nyilvántartott fiókok - domain_name: Domain - reset: Visszaállítás - search: Keresés title: Nyilvántartott instanciák invites: filter: diff --git a/config/locales/id.yml b/config/locales/id.yml index 5cc928823..ae38b3f7d 100644 --- a/config/locales/id.yml +++ b/config/locales/id.yml @@ -85,10 +85,6 @@ id: title: Pemblokiran domain baru reject_media: Tolak berkas media reject_media_hint: Hapus file media yang tersimpan dan menolak semua unduhan nantinya. Tidak terpengaruh dengan suspen - severities: - silence: Diamkan - suspend: Suspen - severity: Keparahan show: affected_accounts: one: Satu akun di dalam database terpengaruh @@ -98,10 +94,7 @@ id: suspend: Hapus suspen terhadap akun pada domain ini title: Hapus pemblokiran domain %{domain} undo: Undo - title: Pemblokiran Domain instances: - account_count: Akun yang diketahui - domain_name: Domain title: Server yang diketahui reports: comment: diff --git a/config/locales/io.yml b/config/locales/io.yml index 358ce4ca9..73c981a98 100644 --- a/config/locales/io.yml +++ b/config/locales/io.yml @@ -75,10 +75,6 @@ io: title: New domain block reject_media: Reject media files reject_media_hint: Removes locally stored media files and refuses to download any in the future. Irrelevant for suspensions - severities: - silence: Silence - suspend: Suspend - severity: Severity show: affected_accounts: one: One account in the database affected @@ -88,11 +84,8 @@ io: suspend: Unsuspend all existing accounts from this domain title: Undo domain block for %{domain} undo: Undo - title: Domain Blocks undo: Undo instances: - account_count: Known accounts - domain_name: Domain title: Known Instances reports: comment: diff --git a/config/locales/it.yml b/config/locales/it.yml index 0b96ef46a..339dadaf4 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -260,11 +260,6 @@ it: reject_media_hint: Rimuovi i file media salvati in locale e blocca i download futuri. Irrilevante per le sospensioni reject_reports: Respingi rapporti reject_reports_hint: Ignora tutti i rapporti provenienti da questo dominio. Irrilevante per sospensioni - severities: - noop: Nessuno - silence: Silenzia - suspend: Sospendi - severity: Severità show: affected_accounts: one: Interessato un solo account nel database @@ -274,7 +269,6 @@ it: suspend: Annulla la sospensione di tutti gli account esistenti da questo dominio title: Annulla il blocco del dominio per %{domain} undo: Annulla - title: Blocchi dominio undo: Annulla email_domain_blocks: add_new: Aggiungi nuovo @@ -287,10 +281,6 @@ it: title: Nuova voce della lista nera delle email title: Lista nera email instances: - account_count: Accounts conosciuti - domain_name: Dominio - reset: Reimposta - search: Cerca title: Istanze conosciute invites: deactivate_all: Disattiva tutto diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 22965a595..60c8fff87 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -265,11 +265,6 @@ ja: reject_media_hint: ローカルに保存されたメディアファイルを削除し、今後のダウンロードを拒否します。停止とは無関係です reject_reports: レポートを拒否 reject_reports_hint: このドメインからのレポートをすべて無視します。停止とは無関係です - severities: - noop: なし - silence: サイレンス - suspend: 停止 - severity: 深刻度 show: affected_accounts: one: データベース中の一つのアカウントに影響します @@ -279,7 +274,6 @@ ja: suspend: このドメインからの存在するすべてのアカウントの停止を戻す title: "%{domain}のドメインブロックを戻す" undo: 元に戻す - title: ドメインブロック undo: 元に戻す email_domain_blocks: add_new: 新規追加 @@ -292,10 +286,6 @@ ja: title: メールアドレス用ブラックリスト新規追加 title: メールブラックリスト instances: - account_count: 既知のアカウント数 - domain_name: ドメイン名 - reset: リセット - search: 検索 title: 既知のインスタンス invites: deactivate_all: すべて無効化 diff --git a/config/locales/ka.yml b/config/locales/ka.yml index 7dd586aee..056942ecd 100644 --- a/config/locales/ka.yml +++ b/config/locales/ka.yml @@ -244,11 +244,6 @@ ka: title: ახალი დომენის ბლოკი reject_media: მედია ფაილების უარყოფა reject_media_hint: შლის ლოკალურად შენახულ მედია ფაილებს და უარყოფს სამომავლო გადმოტვირთებს. შეუსაბამო შეჩერებებისთვის - severities: - noop: არც ერთი - silence: გაჩუმება - suspend: შეჩერება - severity: სიმძიმე show: affected_accounts: one: გავლენა იქონია მონაცემთა ბაზაში ერთ ანგარიშზე @@ -258,7 +253,6 @@ ka: suspend: ამ დომენში ყველა არსებულ ანგარიშზე შეჩერების მოშორება title: უკუაქციეთ დომენის ბლოკი %{domain} დომენზე undo: უკუქცევა - title: დომენის ბლოკები undo: უკუქცევა email_domain_blocks: add_new: ახლის დამატება @@ -271,10 +265,6 @@ ka: title: ელ-ფოსტის ახალი შენატანი შავ სიაში title: ელ-ფოსტის შავი სია instances: - account_count: ცნობილი ანგარიშები - domain_name: დომენი - reset: გადატვირთვა - search: ძებნა title: ცნობილი ინსტანციები invites: deactivate_all: ყველას დეაქტივაცია diff --git a/config/locales/ko.yml b/config/locales/ko.yml index acfc811f3..e0b4bbd0f 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -267,11 +267,6 @@ ko: reject_media_hint: 로컬에 저장된 미디어 파일을 삭제하고, 이후로도 다운로드를 거부합니다. 정지와는 관계 없습니다 reject_reports: 신고 거부 reject_reports_hint: 이 도메인으로부터의 모든 신고를 무시합니다. 정지와는 무관합니다 - severities: - noop: 없음 - silence: 침묵 - suspend: 정지 - severity: 심각도 show: affected_accounts: one: 데이터베이스 중 1개의 계정에 영향을 끼칩니다 @@ -281,7 +276,6 @@ ko: suspend: 이 도메인에 존재하는 모든 계정의 계정 정지를 해제 title: "%{domain}의 도메인 차단을 해제" undo: 실행 취소 - title: 도메인 차단 undo: 실행 취소 email_domain_blocks: add_new: 새로 추가 @@ -294,10 +288,6 @@ ko: title: 새 이메일 도메인 차단 title: Email 도메인 차단 instances: - account_count: 알려진 계정의 수 - domain_name: 도메인 이름 - reset: 리셋 - search: 검색 title: 알려진 인스턴스들 invites: deactivate_all: 전부 비활성화 diff --git a/config/locales/ms.yml b/config/locales/ms.yml index 7c6148e3b..e3c901eff 100644 --- a/config/locales/ms.yml +++ b/config/locales/ms.yml @@ -260,11 +260,6 @@ ms: reject_media_hint: Buang fail media yang disimpan di sini dan menolak sebarang muat turun pada masa depan. Tidak berkaitan dengan penggantungan reject_reports: Tolak laporan reject_reports_hint: Abaikan semua laporan daripada domain ini. Tidak dikira untuk penggantungan - severities: - noop: Tiada - silence: Senyapkan - suspend: Gantungkan - severity: Tahap teruk show: affected_accounts: one: Satu akaun dalam pangkalan data menerima kesan @@ -274,7 +269,6 @@ ms: suspend: Buang penggantungan semua akaun sedia ada daripada domain ini title: Buang sekatan domain %{domain} undo: Buang - title: Sekatan domain undo: Buang email_domain_blocks: add_new: Tambah @@ -287,10 +281,6 @@ ms: title: Entri senarai hitam emel baru title: Senarai hitam emel instances: - account_count: Akaun diketahui - domain_name: Domain - reset: Set semula - search: Cari title: Tika diketahui invites: deactivate_all: Nyahaktifkan semua diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 92acb71d1..50fda80af 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -265,11 +265,6 @@ nl: reject_media_hint: Verwijderd lokaal opgeslagen mediabestanden en weigert deze in de toekomst te downloaden. Irrelevant voor opgeschorte domeinen reject_reports: Rapportages weigeren reject_reports_hint: Alle rapportages die vanaf dit domein komen negeren. Irrelevant voor opgeschorte domeinen - severities: - noop: Geen - silence: Negeren - suspend: Opschorten - severity: Zwaarte show: affected_accounts: one: Eén account in de database aangepast @@ -279,7 +274,6 @@ nl: suspend: Alle opgeschorte accounts van dit domein niet langer opschorten title: Domeinblokkade voor %{domain} ongedaan maken undo: Ongedaan maken - title: Domeinblokkades undo: Ongedaan maken email_domain_blocks: add_new: Nieuwe toevoegen @@ -292,10 +286,6 @@ nl: title: Nieuw e-maildomein blokkeren title: E-maildomeinen blokkeren instances: - account_count: Bekende accounts - domain_name: Domein - reset: Opnieuw - search: Zoeken title: Bekende servers invites: deactivate_all: Alles deactiveren diff --git a/config/locales/no.yml b/config/locales/no.yml index a446fa1f6..cf8f77b4c 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -195,11 +195,6 @@ title: Ny domeneblokkering reject_media: Avvis mediefiler reject_media_hint: Fjerner lokalt lagrede mediefiler og nekter å laste dem ned i fremtiden. Irrelevant for utvisninger - severities: - noop: Ingen - silence: Målbind - suspend: Utvis - severity: Alvorlighet show: affected_accounts: one: En konto i databasen påvirket @@ -209,7 +204,6 @@ suspend: Avutvis alle eksisterende kontoer fra dette domenet title: Angre domeneblokkering for %{domain} undo: Angre - title: Domeneblokkeringer undo: Angre email_domain_blocks: add_new: Lag ny @@ -222,10 +216,6 @@ title: Ny blokkeringsoppføring av e-postdomene title: Blokkering av e-postdomene instances: - account_count: Kjente kontoer - domain_name: Domene - reset: Tilbakestill - search: Søk title: Kjente instanser invites: filter: diff --git a/config/locales/oc.yml b/config/locales/oc.yml index e81b10dac..6d4a6833b 100644 --- a/config/locales/oc.yml +++ b/config/locales/oc.yml @@ -265,11 +265,6 @@ oc: reject_media_hint: Lèva los fichièrs gardats localament e regèta las demandas de telecargament dins lo futur. Servís pas a res per las suspensions reject_reports: Regetar los senhalaments reject_reports_hint: Ignorar totes los senhalaments que venon d’aqueste domeni. Pas pertiment per las suspensions - severities: - noop: Cap - silence: Silenci - suspend: Suspendre - severity: Severitat show: affected_accounts: one: Un compte de la basa de donadas tocat @@ -279,7 +274,6 @@ oc: suspend: Levar la suspension de totes los comptes d’aqueste domeni title: Restablir lo blocatge de domeni de %{domain} undo: Restablir - title: Blòc de domeni undo: Restablir email_domain_blocks: add_new: Ajustar @@ -292,10 +286,6 @@ oc: title: Nòu blocatge de domeni de corrièl title: Blocatge de domeni de corrièl instances: - account_count: Comptes coneguts - domain_name: Domeni - reset: Reïnicializar - search: Cercar title: Instàncias conegudas invites: deactivate_all: O desactivar tot diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 80259d013..7d9a05919 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -271,11 +271,6 @@ pl: reject_media_hint: Usuwa przechowywane lokalnie pliki multimedialne i nie pozwala na ich pobieranie. Nieprzydatne przy zawieszeniu reject_reports: Odrzucaj zgłoszenia reject_reports_hint: Zgłoszenia z tej instancji będą ignorowane. Nieprzydatne przy zawieszeniu - severities: - noop: Nic nie rób - silence: Wycisz - suspend: Zawieś - severity: Priorytet show: affected_accounts: Dotyczy %{count} kont w bazie danych retroactive: @@ -283,7 +278,6 @@ pl: suspend: Odwołaj zawieszenie wszystkich kont w tej domenie title: Odwołaj blokadę dla domeny %{domain} undo: Cofnij - title: Zablokowane domeny undo: Cofnij email_domain_blocks: add_new: Dodaj nową @@ -296,10 +290,6 @@ pl: title: Nowa blokada domeny e-mail title: Blokowanie domen e-mail instances: - account_count: Znane konta - domain_name: Domena - reset: Przywróć - search: Szukaj title: Znane instancje invites: deactivate_all: Unieważnij wszystkie diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index efb8b1bf8..a475209ee 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -263,11 +263,6 @@ pt-BR: reject_media_hint: Remove arquivos de mídia armazenados localmente e recusa quaisquer outros no futuro. Irrelevante para suspensões reject_reports: Rejeitar denúncias reject_reports_hint: Ignorar todas as denúncias vindas deste domíno. Irrelevante para suspensões - severities: - noop: Nenhum - silence: Silêncio - suspend: Suspensão - severity: Rigidez show: affected_accounts: one: Uma conta no banco de dados foi afetada @@ -277,7 +272,6 @@ pt-BR: suspend: Retirar suspensão de todas as contas neste domínio title: Retirar bloqueio de domínio de %{domain} undo: Retirar - title: Bloqueios de domínio undo: Retirar email_domain_blocks: add_new: Adicionar novo @@ -290,10 +284,6 @@ pt-BR: title: Novo bloqueio de domínio de e-mail title: Bloqueio de Domínio de E-mail instances: - account_count: Contas conhecidas - domain_name: Domínio - reset: Resetar - search: Buscar title: Instâncias conhecidas invites: deactivate_all: Desativar todos diff --git a/config/locales/pt.yml b/config/locales/pt.yml index a67223069..037582f34 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -195,11 +195,6 @@ pt: title: Novo bloqueio de domínio reject_media: Rejeitar ficheiros de media reject_media_hint: Remove localmente arquivos armazenados e rejeita fazer guardar novos no futuro. Irrelevante na suspensão - severities: - noop: Nenhum - silence: Silenciar - suspend: Suspender - severity: Severidade show: affected_accounts: one: Uma conta na base de dados afectada @@ -209,7 +204,6 @@ pt: suspend: Não suspender todas as contas existentes nesse domínio title: Remover o bloqueio de domínio de %{domain} undo: Anular - title: Bloqueio de domínio undo: Anular email_domain_blocks: add_new: Adicionar novo @@ -222,10 +216,6 @@ pt: title: Novo bloqueio de domínio de email title: Bloqueio de Domínio de Email instances: - account_count: Contas conhecidas - domain_name: Domínio - reset: Restaurar - search: Pesquisar title: Instâncias conhecidas invites: filter: diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 40e66ceac..3e37391a8 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -260,11 +260,6 @@ ru: title: Новая доменная блокировка reject_media: Запретить медиаконтент reject_media_hint: Удаляет локально хранимый медиаконтент и запрещает его загрузку в будущем. Не имеет значения в случае блокировки - severities: - noop: Ничего - silence: Глушение - suspend: Блокировка - severity: Строгость show: affected_accounts: few: Влияет на %{count} аккаунта в базе данных @@ -276,7 +271,6 @@ ru: suspend: Снять блокировку со всех существующих аккаунтов этого домена title: Снять блокировку с домена %{domain} undo: Отменить - title: Доменные блокировки undo: Отменить email_domain_blocks: add_new: Добавить новую @@ -289,10 +283,6 @@ ru: title: Новая доменная блокировка еmail title: Доменная блокировка email instances: - account_count: Известных аккаунтов - domain_name: Домен - reset: Сбросить - search: Поиск title: Известные узлы invites: deactivate_all: Отключить все diff --git a/config/locales/sk.yml b/config/locales/sk.yml index 36399d752..4b386e352 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -269,11 +269,6 @@ sk: reject_media_hint: Zmaže lokálne uložené súbory médií a odmietne ich sťahovanie v budúcnosti. Irelevantné pre suspendáciu reject_reports: Zamietni hlásenia reject_reports_hint: Ignoruj všetky hlásenia prichádzajúce z tejto domény. Nevplýva na blokovania - severities: - noop: Žiadne - silence: Stíšiť - suspend: Suspendovať - severity: Závažnosť show: affected_accounts: few: "%{count} účty v databáze ovplyvnených" @@ -284,7 +279,6 @@ sk: suspend: Zrušiť suspendáciu všetkých existujúcich účtov z tejto domény title: Zrušiť blokovanie domény pre %{domain} undo: Vrátiť späť - title: Blokovanie domén undo: Späť email_domain_blocks: add_new: Pridať nový @@ -297,10 +291,6 @@ sk: title: Nový email na zablokovanie title: Blokované emailové adresy instances: - account_count: Známe účty - domain_name: Doména - reset: Resetovať - search: Hľadať title: Známe instancie invites: deactivate_all: Pozastaviť všetky diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml index 62ad744f3..82739c9bb 100644 --- a/config/locales/sr-Latn.yml +++ b/config/locales/sr-Latn.yml @@ -195,11 +195,6 @@ sr-Latn: title: Novo blokiranje domena reject_media: Odbaci multimediju reject_media_hint: Uklanja lokalno uskladištene multimedijske fajlove i odbija da ih skida na dalje. Nebitno je za suspenziju - severities: - noop: Ništa - silence: Ućutkavanje - suspend: Suspenzija - severity: Oštrina show: affected_accounts: few: Utiče na %{count} naloga u bazi @@ -211,7 +206,6 @@ sr-Latn: suspend: Ugasi suspenzije za sve postojeće naloge sa ovog domena title: Poništi blokadu domena za domen %{domain} undo: Poništi - title: Blokade domena undo: Poništi email_domain_blocks: add_new: Dodaj novuAdd new @@ -224,10 +218,6 @@ sr-Latn: title: Nova stavka u crnoj listi e-pošti title: Crna lista adresa e-pošte instances: - account_count: Poznati nalozi - domain_name: Domen - reset: Resetuj - search: Pretraga title: Poznate instance invites: filter: diff --git a/config/locales/sr.yml b/config/locales/sr.yml index 009281339..e78a9b817 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -268,11 +268,6 @@ sr: reject_media_hint: Уклања локално ускладиштене мултимедијске фајлове и одбија да их скида убудуће. Небитно је за суспензију reject_reports: Одбаци извештај reject_reports_hint: Игнориши све извештаје који долазе са овог домена. Небитно је за суспензије - severities: - noop: Ништа - silence: Ућуткавање - suspend: Суспензија - severity: Оштрина show: affected_accounts: few: Утиче на %{count} налога у бази @@ -284,7 +279,6 @@ sr: suspend: Уклони суспензије за све постојеће налоге са овог домена title: Поништи блокаду домена за %{domain} undo: Поништи - title: Блокаде домена undo: Поништи email_domain_blocks: add_new: Додај нови @@ -297,10 +291,6 @@ sr: title: Нова ставка е-поштe у црној листи title: Црна листа E-поште instances: - account_count: Познати налози - domain_name: Домен - reset: Ресетуј - search: Претрага title: Познате инстанце invites: deactivate_all: Деактивирај све diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 79040b46c..aa5b3420d 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -213,11 +213,6 @@ sv: title: Nytt domänblock reject_media: Avvisa mediafiler reject_media_hint: Raderar lokalt lagrade mediefiler och förhindrar möjligheten att ladda ner något i framtiden. Irrelevant för suspensioner - severities: - noop: Ingen - silence: Tysta ner - suspend: Suspendera - severity: Svårighet show: affected_accounts: one: Ett konto i databasen drabbades @@ -227,7 +222,6 @@ sv: suspend: Ta bort suspendering från alla befintliga konton på den här domänen title: Ångra domänblockering för %{domain} undo: Ångra - title: Domänblockering undo: Ångra email_domain_blocks: add_new: Lägg till ny @@ -240,10 +234,6 @@ sv: title: Ny E-postdomänblocklistningsinmatning title: E-postdomänblock instances: - account_count: Kända konton - domain_name: Domän - reset: Återställa - search: Sök title: Kända instanser invites: filter: diff --git a/config/locales/th.yml b/config/locales/th.yml index 1a1ffae3b..5be8e02c0 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -84,10 +84,6 @@ th: title: การบล๊อกโดเมนใหม่ reject_media: ไม่อนุมัติไฟล์สื่อ reject_media_hint: ลบไฟล์สื่อที่เก็บไว้ในเครื่อง และ ป้องกันการดาวน์โหลดในอนาคต. Irrelevant for suspensions - severities: - silence: ปิดเสียง - suspend: หยุดไว้ - severity: Severity show: affected_accounts: one: มีผลต่อหนึ่งแอคเค๊าท์ในฐานข้อมูล @@ -97,11 +93,8 @@ th: suspend: ยกเลิกการหยุดทุกแอคเค๊าท์จากโดเมน title: ยกเลิกการบล๊อกโดเมน %{domain} undo: ยกเลิก - title: บล๊อกโดเมน undo: ยกเลิก instances: - account_count: Known accounts - domain_name: ชื่อโดเมน title: Known Instances reports: comment: diff --git a/config/locales/tr.yml b/config/locales/tr.yml index aae1549f7..c38b73f2e 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -83,10 +83,6 @@ tr: title: Yeni domain bloğu reject_media: Ortam dosyalarını reddetme reject_media_hint: Yerel olarak depolanmış ortam dosyalarını ve gelecekte indirilecek olanları reddeder. Uzaklaştırma için uygun değildir - severities: - silence: Sustur - suspend: Uzaklaştır - severity: İşlem show: affected_accounts: one: Veritabanındaki bir hesap etkilendi @@ -96,11 +92,8 @@ tr: suspend: Bu domaindeki tüm hesapların üzerindeki uzaklaştırma işlemini kaldır title: "%{domain} domain'i için yapılan işlemi geri al" undo: Geri al - title: Domain Blokları undo: Geri al instances: - account_count: Bilinen hesaplar - domain_name: Domain title: Bilinen Sunucular reports: comment: diff --git a/config/locales/uk.yml b/config/locales/uk.yml index b3fc4cd36..9a63854b5 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -237,11 +237,6 @@ uk: title: Нове блокування домену reject_media: Заборонити медіаконтент reject_media_hint: Видаляє медіаконтент, збережений локально, і забороняє його завантаження у майбутньому. Не має значення у випадку блокування - severities: - noop: Нічого - silence: Глушення - suspend: Блокування - severity: Суворість show: affected_accounts: few: Впливає на %{count} акаунти у базі даних @@ -253,7 +248,6 @@ uk: suspend: Зняти блокування з усіх існуючих акаунтів цього домену title: Зняти блокування з домена %{domain} undo: Відмінити - title: Доменні блокування undo: Відмінити email_domain_blocks: add_new: Додати @@ -266,10 +260,6 @@ uk: title: Нове доменне блокування домену email title: Чорний список поштових доменів instances: - account_count: Відомі аккаунти - domain_name: Домен - reset: Скинути - search: Пошук title: Відомі інстанції invites: filter: diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index d03bf1217..e482e9c41 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -246,11 +246,6 @@ zh-CN: title: 添加域名屏蔽 reject_media: 拒绝接收媒体文件 reject_media_hint: 删除本地已缓存的媒体文件,并且不再接收来自该域名的任何媒体文件。此选项不影响封禁 - severities: - noop: 无 - silence: 自动隐藏 - suspend: 自动封禁 - severity: 屏蔽级别 show: affected_accounts: one: 将会影响到数据库中的 1 个帐户 @@ -260,7 +255,6 @@ zh-CN: suspend: 对此域名的所有帐户解除封禁 title: 撤销对 %{domain} 的域名屏蔽 undo: 撤销 - title: 域名屏蔽 undo: 撤销 email_domain_blocks: add_new: 添加新条目 @@ -273,10 +267,6 @@ zh-CN: title: 添加电子邮件域名屏蔽 title: 电子邮件域名屏蔽 instances: - account_count: 已知帐户 - domain_name: 域名 - reset: 重置 - search: 搜索 title: 已知实例 invites: deactivate_all: 撤销所有邀请链接 diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml index 35b774120..737ca000c 100644 --- a/config/locales/zh-HK.yml +++ b/config/locales/zh-HK.yml @@ -213,11 +213,6 @@ zh-HK: title: 新增域名阻隔 reject_media: 拒絕媒體檔案 reject_media_hint: 刪除本地緩存的媒體檔案,再也不在未來下載這個站點的檔案。和自動刪除無關 - severities: - noop: 無 - silence: 自動靜音 - suspend: 自動刪除 - severity: 阻隔分級 show: affected_accounts: 資料庫中有%{count}個用戶受影響 retroactive: @@ -225,7 +220,6 @@ zh-HK: suspend: 對此域名的所有用戶取消除名 title: 撤銷 %{domain} 的域名阻隔 undo: 撤銷 - title: 域名阻隔 undo: 撤銷 email_domain_blocks: add_new: 加入新項目 @@ -238,10 +232,6 @@ zh-HK: title: 新增電郵網域阻隔 title: 電郵網域阻隔 instances: - account_count: 已知帳號 - domain_name: 域名 - reset: 重設 - search: 搜索 title: 已知服務站 invites: filter: diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index 5e209d2ff..f4bda0f34 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -218,11 +218,6 @@ zh-TW: title: 新增封鎖網域 reject_media: 拒絕媒體檔案 reject_media_hint: 刪除本地緩存的媒體檔案,並且不再接收來自該網域的任何媒體檔案。與自動封鎖無關 - severities: - noop: 無 - silence: 自動靜音 - suspend: 自動封鎖 - severity: 嚴重度 show: affected_accounts: 資料庫中有%{count}個使用者受影響 retroactive: @@ -230,7 +225,6 @@ zh-TW: suspend: 對此網域的所有使用者取消封鎖 title: 撤銷 %{domain} 的網域封鎖 undo: 撤銷 - title: 網域封鎖 undo: 撤銷 email_domain_blocks: add_new: 加入新項目 @@ -243,10 +237,6 @@ zh-TW: title: 新增E-mail封鎖 title: E-mail封鎖 instances: - account_count: 已知帳戶 - domain_name: 網域 - reset: 重設 - search: 搜尋 title: 已知站點 invites: filter: diff --git a/config/navigation.rb b/config/navigation.rb index 1b3c05ef7..2365191dc 100644 --- a/config/navigation.rb +++ b/config/navigation.rb @@ -29,8 +29,7 @@ SimpleNavigation::Configuration.run do |navigation| admin.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_url, highlights_on: %r{/admin/accounts} admin.item :invites, safe_join([fa_icon('user-plus fw'), t('admin.invites.title')]), admin_invites_path admin.item :tags, safe_join([fa_icon('tag fw'), t('admin.tags.title')]), admin_tags_path - admin.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_url, highlights_on: %r{/admin/instances}, if: -> { current_user.admin? } - admin.item :domain_blocks, safe_join([fa_icon('lock fw'), t('admin.domain_blocks.title')]), admin_domain_blocks_url, highlights_on: %r{/admin/domain_blocks}, if: -> { current_user.admin? } + admin.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_url, highlights_on: %r{/admin/instances|/admin/domain_blocks}, if: -> { current_user.admin? } admin.item :email_domain_blocks, safe_join([fa_icon('envelope fw'), t('admin.email_domain_blocks.title')]), admin_email_domain_blocks_url, highlights_on: %r{/admin/email_domain_blocks}, if: -> { current_user.admin? } end diff --git a/config/routes.rb b/config/routes.rb index 3ae2735d1..af49845cc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -138,7 +138,7 @@ Rails.application.routes.draw do get '/dashboard', to: 'dashboard#index' resources :subscriptions, only: [:index] - resources :domain_blocks, only: [:index, :new, :create, :show, :destroy] + resources :domain_blocks, only: [:new, :create, :show, :destroy] resources :email_domain_blocks, only: [:index, :new, :create, :destroy] resources :action_logs, only: [:index] resources :warning_presets, except: [:new] @@ -157,11 +157,7 @@ Rails.application.routes.draw do end end - resources :instances, only: [:index] do - collection do - post :resubscribe - end - end + resources :instances, only: [:index, :show], constraints: { id: /[^\/]+/ } resources :reports, only: [:index, :show] do member do diff --git a/spec/controllers/admin/domain_blocks_controller_spec.rb b/spec/controllers/admin/domain_blocks_controller_spec.rb index 79e7fea42..129bf8883 100644 --- a/spec/controllers/admin/domain_blocks_controller_spec.rb +++ b/spec/controllers/admin/domain_blocks_controller_spec.rb @@ -7,26 +7,6 @@ RSpec.describe Admin::DomainBlocksController, type: :controller do sign_in Fabricate(:user, admin: true), scope: :user end - describe 'GET #index' do - around do |example| - default_per_page = DomainBlock.default_per_page - DomainBlock.paginates_per 1 - example.run - DomainBlock.paginates_per default_per_page - end - - it 'renders domain blocks' do - 2.times { Fabricate(:domain_block) } - - get :index, params: { page: 2 } - - assigned = assigns(:domain_blocks) - expect(assigned.count).to eq 1 - expect(assigned.klass).to be DomainBlock - expect(response).to have_http_status(200) - end - end - describe 'GET #new' do it 'assigns a new domain block' do get :new @@ -53,7 +33,7 @@ RSpec.describe Admin::DomainBlocksController, type: :controller do expect(DomainBlockWorker).to have_received(:perform_async) expect(flash[:notice]).to eq I18n.t('admin.domain_blocks.created_msg') - expect(response).to redirect_to(admin_domain_blocks_path) + expect(response).to redirect_to(admin_instances_path(limited: '1')) end it 'renders new when failed to save' do @@ -76,7 +56,7 @@ RSpec.describe Admin::DomainBlocksController, type: :controller do expect(service).to have_received(:call).with(domain_block, true) expect(flash[:notice]).to eq I18n.t('admin.domain_blocks.destroyed_msg') - expect(response).to redirect_to(admin_domain_blocks_path) + expect(response).to redirect_to(admin_instances_path(limited: '1')) end end end diff --git a/spec/policies/instance_policy_spec.rb b/spec/policies/instance_policy_spec.rb index fbfddd72f..77a3bde3f 100644 --- a/spec/policies/instance_policy_spec.rb +++ b/spec/policies/instance_policy_spec.rb @@ -8,7 +8,7 @@ RSpec.describe InstancePolicy do let(:admin) { Fabricate(:user, admin: true).account } let(:john) { Fabricate(:user).account } - permissions :index?, :resubscribe? do + permissions :index? do context 'admin' do it 'permits' do expect(subject).to permit(admin, Instance) -- cgit