From 19abf4ef0bafb12c2c44ddf92f72354ec409e540 Mon Sep 17 00:00:00 2001 From: ysksn Date: Thu, 3 Jan 2019 13:10:02 +0900 Subject: Add specs for UnreservedUsernameValidator (#9698) * Add specs for UnreservedUsernameValidator * Use instance variable --- .../unreserved_username_validator_spec.rb | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 spec/validators/unreserved_username_validator_spec.rb (limited to 'spec') diff --git a/spec/validators/unreserved_username_validator_spec.rb b/spec/validators/unreserved_username_validator_spec.rb new file mode 100644 index 000000000..0187941b0 --- /dev/null +++ b/spec/validators/unreserved_username_validator_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe UnreservedUsernameValidator, type: :validator do + describe '#validate' do + before do + allow(validator).to receive(:reserved_username?) { reserved_username } + validator.validate(account) + end + + let(:validator) { described_class.new } + let(:account) { double(username: username, errors: errors) } + let(:errors ) { double(add: nil) } + + context '@username.nil?' do + let(:username) { nil } + + it 'not calls errors.add' do + expect(errors).not_to have_received(:add).with(:username, any_args) + end + end + + context '!@username.nil?' do + let(:username) { '' } + + context 'reserved_username?' do + let(:reserved_username) { true } + + it 'calls erros.add' do + expect(errors).to have_received(:add).with(:username, I18n.t('accounts.reserved_username')) + end + end + + context '!reserved_username?' do + let(:reserved_username) { false } + + it 'not calls erros.add' do + expect(errors).not_to have_received(:add).with(:username, any_args) + end + end + end + end +end -- cgit From 5efedb5d5e071dd419be276f8ede93dc8ecfe3ce Mon Sep 17 00:00:00 2001 From: ysksn Date: Thu, 3 Jan 2019 13:10:20 +0900 Subject: Add specs for UrlValidator (#9699) --- spec/validators/url_validator_spec.rb | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 spec/validators/url_validator_spec.rb (limited to 'spec') diff --git a/spec/validators/url_validator_spec.rb b/spec/validators/url_validator_spec.rb new file mode 100644 index 000000000..e8d0e6494 --- /dev/null +++ b/spec/validators/url_validator_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe UrlValidator, type: :validator do + describe '#validate_each' do + before do + allow(validator).to receive(:compliant?).with(value) { compliant } + validator.validate_each(record, attribute, value) + end + + let(:validator) { described_class.new(attributes: [attribute]) } + let(:record) { double(errors: errors) } + let(:errors) { double(add: nil) } + let(:value) { '' } + let(:attribute) { :foo } + + context 'unless compliant?' do + let(:compliant) { false } + + it 'calls errors.add' do + expect(errors).to have_received(:add).with(attribute, I18n.t('applications.invalid_url')) + end + end + + context 'if compliant?' do + let(:compliant) { true } + + it 'not calls errors.add' do + expect(errors).not_to have_received(:add).with(attribute, any_args) + end + end + end +end -- 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 'spec') 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 88deca16cae2cb6e0b32e28ace68db5b96407cc9 Mon Sep 17 00:00:00 2001 From: ysksn Date: Tue, 8 Jan 2019 12:18:27 +0900 Subject: Add pending specs for jsonld helper (#9750) * Add specs for JsonLdHelper#first_of_value * Add specs for JsonLdHelper#supported_context? --- spec/helpers/jsonld_helper_spec.rb | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/helpers/jsonld_helper_spec.rb b/spec/helpers/jsonld_helper_spec.rb index a5ab249c2..883a88b14 100644 --- a/spec/helpers/jsonld_helper_spec.rb +++ b/spec/helpers/jsonld_helper_spec.rb @@ -22,11 +22,35 @@ describe JsonLdHelper do end describe '#first_of_value' do - pending + context 'value.is_a?(Array)' do + it 'returns value.first' do + value = ['a'] + expect(helper.first_of_value(value)).to be 'a' + end + end + + context '!value.is_a?(Array)' do + it 'returns value' do + value = 'a' + expect(helper.first_of_value(value)).to be 'a' + end + end end describe '#supported_context?' do - pending + context "!json.nil? && equals_or_includes?(json['@context'], ActivityPub::TagManager::CONTEXT)" do + it 'returns true' do + json = { '@context' => ActivityPub::TagManager::CONTEXT }.as_json + expect(helper.supported_context?(json)).to be true + end + end + + context 'else' do + it 'returns false' do + json = nil + expect(helper.supported_context?(json)).to be false + end + end end describe '#fetch_resource' do -- cgit From 274109e9f3e3f95bc14b3cd00333fce294ee7b79 Mon Sep 17 00:00:00 2001 From: ysksn Date: Tue, 8 Jan 2019 12:18:46 +0900 Subject: Remove spec files (#9751) Nothing to test. --- spec/models/account_warning_preset_spec.rb | 5 ----- spec/models/account_warning_spec.rb | 5 ----- 2 files changed, 10 deletions(-) delete mode 100644 spec/models/account_warning_preset_spec.rb delete mode 100644 spec/models/account_warning_spec.rb (limited to 'spec') diff --git a/spec/models/account_warning_preset_spec.rb b/spec/models/account_warning_preset_spec.rb deleted file mode 100644 index a859a305f..000000000 --- a/spec/models/account_warning_preset_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'rails_helper' - -RSpec.describe AccountWarningPreset, type: :model do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/models/account_warning_spec.rb b/spec/models/account_warning_spec.rb deleted file mode 100644 index 5286f9177..000000000 --- a/spec/models/account_warning_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'rails_helper' - -RSpec.describe AccountWarning, type: :model do - pending "add some examples to (or delete) #{__FILE__}" -end -- cgit From 9a38357111049c7587c898b2b623cf9c853a4d35 Mon Sep 17 00:00:00 2001 From: ysksn Date: Tue, 8 Jan 2019 17:42:56 +0900 Subject: Remove `pending` (#9752) Some specs have already been added. --- spec/services/resolve_account_service_spec.rb | 2 -- 1 file changed, 2 deletions(-) (limited to 'spec') diff --git a/spec/services/resolve_account_service_spec.rb b/spec/services/resolve_account_service_spec.rb index dd7561587..27a85af7c 100644 --- a/spec/services/resolve_account_service_spec.rb +++ b/spec/services/resolve_account_service_spec.rb @@ -119,8 +119,6 @@ RSpec.describe ResolveAccountService, type: :service do expect(account.actor_type).to eq 'Person' end end - - pending end it 'processes one remote account at a time using locks' do -- 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 'spec') 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 From 61ecda15751a73262903f22c0ac163476b7ae75f Mon Sep 17 00:00:00 2001 From: ysksn Date: Thu, 10 Jan 2019 23:12:31 +0900 Subject: Not to skip executable specs (#9753) * Not to skip executable specs * Combine specs Combine specs to one to reduce multiple slow http post. --- spec/controllers/api/v1/media_controller_spec.rb | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'spec') diff --git a/spec/controllers/api/v1/media_controller_spec.rb b/spec/controllers/api/v1/media_controller_spec.rb index f01fcd942..4e3037208 100644 --- a/spec/controllers/api/v1/media_controller_spec.rb +++ b/spec/controllers/api/v1/media_controller_spec.rb @@ -84,19 +84,17 @@ RSpec.describe Api::V1::MediaController, type: :controller do post :create, params: { file: fixture_file_upload('files/attachment.webm', 'video/webm') } end - xit 'returns http success' do + it do + # returns http success expect(response).to have_http_status(200) - end - xit 'creates a media attachment' do + # creates a media attachment expect(MediaAttachment.first).to_not be_nil - end - xit 'uploads a file' do + # uploads a file expect(MediaAttachment.first).to have_attached_file(:file) - end - xit 'returns media ID in JSON' do + # returns media ID in JSON expect(body_as_json[:id]).to eq MediaAttachment.first.id.to_s end end -- cgit From fb0c906c717f2b21bb63610742a357850142b522 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Thu, 10 Jan 2019 18:46:17 +0100 Subject: Revert "Revert "Add handler for Move activity (#9629)"" This reverts commit bb96a7463758687f8187ae4483becd346c2482b3. --- app/lib/activitypub/activity.rb | 2 + app/lib/activitypub/activity/follow.rb | 2 +- app/lib/activitypub/activity/move.rb | 43 ++++++++++++++++++ app/lib/activitypub/adapter.rb | 1 + app/models/account.rb | 5 +++ app/serializers/activitypub/actor_serializer.rb | 5 +++ .../activitypub/process_account_service.rb | 1 + app/services/follow_service.rb | 2 +- app/workers/unfollow_follow_worker.rb | 18 ++++++++ ...20181226021420_add_also_known_as_to_accounts.rb | 5 +++ db/schema.rb | 3 +- spec/lib/activitypub/activity/move_spec.rb | 52 ++++++++++++++++++++++ 12 files changed, 136 insertions(+), 3 deletions(-) create mode 100644 app/lib/activitypub/activity/move.rb create mode 100644 app/workers/unfollow_follow_worker.rb create mode 100644 db/migrate/20181226021420_add_also_known_as_to_accounts.rb create mode 100644 spec/lib/activitypub/activity/move_spec.rb (limited to 'spec') diff --git a/app/lib/activitypub/activity.rb b/app/lib/activitypub/activity.rb index 0a729011f..87318fb1c 100644 --- a/app/lib/activitypub/activity.rb +++ b/app/lib/activitypub/activity.rb @@ -50,6 +50,8 @@ class ActivityPub::Activity ActivityPub::Activity::Add when 'Remove' ActivityPub::Activity::Remove + when 'Move' + ActivityPub::Activity::Move end end end diff --git a/app/lib/activitypub/activity/follow.rb b/app/lib/activitypub/activity/follow.rb index 5e703dc61..1e805c0d1 100644 --- a/app/lib/activitypub/activity/follow.rb +++ b/app/lib/activitypub/activity/follow.rb @@ -6,7 +6,7 @@ class ActivityPub::Activity::Follow < ActivityPub::Activity return if target_account.nil? || !target_account.local? || delete_arrived_first?(@json['id']) || @account.requested?(target_account) - if target_account.blocking?(@account) || target_account.domain_blocking?(@account.domain) + if target_account.blocking?(@account) || target_account.domain_blocking?(@account.domain) || target_account.moved? reject_follow_request!(target_account) return end diff --git a/app/lib/activitypub/activity/move.rb b/app/lib/activitypub/activity/move.rb new file mode 100644 index 000000000..d7a5f595c --- /dev/null +++ b/app/lib/activitypub/activity/move.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +class ActivityPub::Activity::Move < ActivityPub::Activity + PROCESSING_COOLDOWN = 7.days.seconds + + def perform + return if origin_account.uri != object_uri || processed? + + mark_as_processing! + + target_account = ActivityPub::FetchRemoteAccountService.new.call(target_uri) + + return if target_account.nil? || !target_account.also_known_as.include?(origin_account.uri) + + # In case for some reason we didn't have a redirect for the profile already, set it + origin_account.update(moved_to_account: target_account) if origin_account.moved_to_account_id.nil? + + # Initiate a re-follow for each follower + origin_account.followers.local.select(:id).find_in_batches do |follower_accounts| + UnfollowFollowWorker.push_bulk(follower_accounts.map(&:id)) do |follower_account_id| + [follower_account_id, origin_account.id, target_account.id] + end + end + end + + private + + def origin_account + @account + end + + def target_uri + value_or_id(@json['target']) + end + + def processed? + redis.exists("move_in_progress:#{@account.id}") + end + + def mark_as_processing! + redis.setex("move_in_progress:#{@account.id}", PROCESSING_COOLDOWN, true) + end +end diff --git a/app/lib/activitypub/adapter.rb b/app/lib/activitypub/adapter.rb index d35cae889..99f4d9305 100644 --- a/app/lib/activitypub/adapter.rb +++ b/app/lib/activitypub/adapter.rb @@ -10,6 +10,7 @@ class ActivityPub::Adapter < ActiveModelSerializers::Adapter::Base 'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers', 'sensitive' => 'as:sensitive', 'movedTo' => { '@id' => 'as:movedTo', '@type' => '@id' }, + 'alsoKnownAs' => { '@id' => 'as:alsoKnownAs', '@type' => '@id' }, 'Hashtag' => 'as:Hashtag', 'ostatus' => 'http://ostatus.org#', 'atomUri' => 'ostatus:atomUri', diff --git a/app/models/account.rb b/app/models/account.rb index 722e47d65..67d9a583e 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -44,6 +44,7 @@ # fields :jsonb # actor_type :string # discoverable :boolean +# also_known_as :string is an Array # class Account < ApplicationRecord @@ -232,6 +233,10 @@ class Account < ApplicationRecord end end + def also_known_as + self[:also_known_as] || [] + end + def fields (self[:fields] || []).map { |f| Field.new(self, f) } end diff --git a/app/serializers/activitypub/actor_serializer.rb b/app/serializers/activitypub/actor_serializer.rb index 72c30dc73..6746c1782 100644 --- a/app/serializers/activitypub/actor_serializer.rb +++ b/app/serializers/activitypub/actor_serializer.rb @@ -14,6 +14,7 @@ class ActivityPub::ActorSerializer < ActiveModel::Serializer has_many :virtual_attachments, key: :attachment attribute :moved_to, if: :moved? + attribute :also_known_as, if: :also_known_as? class EndpointsSerializer < ActiveModel::Serializer include RoutingHelper @@ -116,6 +117,10 @@ class ActivityPub::ActorSerializer < ActiveModel::Serializer ActivityPub::TagManager.instance.uri_for(object.moved_to_account) end + def also_known_as? + !object.also_known_as.empty? + end + class CustomEmojiSerializer < ActivityPub::EmojiSerializer end diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb index 5c865dae2..d6480028f 100644 --- a/app/services/activitypub/process_account_service.rb +++ b/app/services/activitypub/process_account_service.rb @@ -75,6 +75,7 @@ class ActivityPub::ProcessAccountService < BaseService @account.note = @json['summary'] || '' @account.locked = @json['manuallyApprovesFollowers'] || false @account.fields = property_values || {} + @account.also_known_as = as_array(@json['alsoKnownAs'] || []).map { |item| value_or_id(item) } @account.actor_type = actor_type end diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb index 24b3e1f70..9d36a1449 100644 --- a/app/services/follow_service.rb +++ b/app/services/follow_service.rb @@ -10,7 +10,7 @@ class FollowService < BaseService target_account = ResolveAccountService.new.call(target_account, skip_webfinger: true) raise ActiveRecord::RecordNotFound if target_account.nil? || target_account.id == source_account.id || target_account.suspended? - raise Mastodon::NotPermittedError if target_account.blocking?(source_account) || source_account.blocking?(target_account) + raise Mastodon::NotPermittedError if target_account.blocking?(source_account) || source_account.blocking?(target_account) || target_account.moved? if source_account.following?(target_account) # We're already following this account, but we'll call follow! again to diff --git a/app/workers/unfollow_follow_worker.rb b/app/workers/unfollow_follow_worker.rb new file mode 100644 index 000000000..a2133bb8c --- /dev/null +++ b/app/workers/unfollow_follow_worker.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class UnfollowFollowWorker + include Sidekiq::Worker + + sidekiq_options queue: 'pull' + + def perform(follower_account_id, old_target_account_id, new_target_account_id) + follower_account = Account.find(follower_account_id) + old_target_account = Account.find(old_target_account_id) + new_target_account = Account.find(new_target_account_id) + + UnfollowService.new.call(follower_account, old_target_account) + FollowService.new.call(follower_account, new_target_account) + rescue ActiveRecord::RecordNotFound + true + end +end diff --git a/db/migrate/20181226021420_add_also_known_as_to_accounts.rb b/db/migrate/20181226021420_add_also_known_as_to_accounts.rb new file mode 100644 index 000000000..1fd956680 --- /dev/null +++ b/db/migrate/20181226021420_add_also_known_as_to_accounts.rb @@ -0,0 +1,5 @@ +class AddAlsoKnownAsToAccounts < ActiveRecord::Migration[5.2] + def change + add_column :accounts, :also_known_as, :string, array: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 48ffea3dd..b8a9f8c58 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_19_235220) do +ActiveRecord::Schema.define(version: 2018_12_26_021420) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -134,6 +134,7 @@ ActiveRecord::Schema.define(version: 2018_12_19_235220) do t.jsonb "fields" t.string "actor_type" t.boolean "discoverable" + t.string "also_known_as", array: true t.index "(((setweight(to_tsvector('simple'::regconfig, (display_name)::text), 'A'::\"char\") || setweight(to_tsvector('simple'::regconfig, (username)::text), 'B'::\"char\")) || setweight(to_tsvector('simple'::regconfig, (COALESCE(domain, ''::character varying))::text), 'C'::\"char\")))", name: "search_index", using: :gin t.index "lower((username)::text), lower((domain)::text)", name: "index_accounts_on_username_and_domain_lower", unique: true t.index ["moved_to_account_id"], name: "index_accounts_on_moved_to_account_id" diff --git a/spec/lib/activitypub/activity/move_spec.rb b/spec/lib/activitypub/activity/move_spec.rb new file mode 100644 index 000000000..3574f273a --- /dev/null +++ b/spec/lib/activitypub/activity/move_spec.rb @@ -0,0 +1,52 @@ +require 'rails_helper' + +RSpec.describe ActivityPub::Activity::Move do + let(:follower) { Fabricate(:account) } + let(:old_account) { Fabricate(:account) } + let(:new_account) { Fabricate(:account) } + + before do + follower.follow!(old_account) + + old_account.update!(uri: 'https://example.org/alice', domain: 'example.org', protocol: :activitypub, inbox_url: 'https://example.org/inbox') + new_account.update!(uri: 'https://example.com/alice', domain: 'example.com', protocol: :activitypub, inbox_url: 'https://example.com/inbox', also_known_as: [old_account.uri]) + + stub_request(:post, 'https://example.org/inbox').to_return(status: 200) + stub_request(:post, 'https://example.com/inbox').to_return(status: 200) + + service_stub = double + allow(ActivityPub::FetchRemoteAccountService).to receive(:new).and_return(service_stub) + allow(service_stub).to receive(:call).and_return(new_account) + end + + let(:json) do + { + '@context': 'https://www.w3.org/ns/activitystreams', + id: 'foo', + type: 'Move', + actor: old_account.uri, + object: old_account.uri, + target: new_account.uri, + }.with_indifferent_access + end + + describe '#perform' do + subject { described_class.new(json, old_account) } + + before do + subject.perform + end + + it 'sets moved account on old account' do + expect(old_account.reload.moved_to_account_id).to eq new_account.id + end + + it 'makes followers unfollow old account' do + expect(follower.following?(old_account)).to be false + end + + it 'makes followers follow-request the new account' do + expect(follower.requested?(new_account)).to be true + end + end +end -- cgit