From a398fb125804c698dfc6ccd263b9fcd27a192663 Mon Sep 17 00:00:00 2001 From: umonaca Date: Thu, 29 Oct 2020 00:30:32 -0400 Subject: [PATCH] Add account sensitized Fix i18n Fix spec --- app/controllers/admin/accounts_controller.rb | 7 +++++++ .../api/v1/admin/accounts_controller.rb | 8 ++++++++ app/helpers/statuses_helper.rb | 8 ++++++++ app/lib/activitypub/activity/create.rb | 2 +- app/models/account.rb | 14 ++++++++++++++ app/models/account_warning.rb | 2 +- app/models/admin/account_action.rb | 9 +++++++++ app/models/admin/action_log_filter.rb | 2 ++ app/policies/account_policy.rb | 8 ++++++++ app/serializers/activitypub/note_serializer.rb | 4 ++++ app/serializers/rest/status_serializer.rb | 8 ++++++++ app/views/admin/accounts/show.html.haml | 7 +++++++ app/views/statuses/_detailed_status.html.haml | 6 +++--- app/views/statuses/_quote_status.html.haml | 4 ++-- app/views/statuses/_simple_status.html.haml | 6 +++--- config/locales/en.yml | 8 ++++++++ config/locales/ja.yml | 8 ++++++++ config/locales/simple_form.en.yml | 1 + config/locales/simple_form.ja.yml | 1 + config/routes.rb | 2 ++ ...0200614002136_add_sensitized_to_accounts.rb | 5 +++++ db/schema.rb | 1 + .../api/v1/admin/accounts_controller_spec.rb | 18 ++++++++++++++++++ spec/models/admin/account_action_spec.rb | 8 ++++---- spec/policies/account_policy_spec.rb | 2 +- 25 files changed, 134 insertions(+), 15 deletions(-) create mode 100644 db/migrate/20200614002136_add_sensitized_to_accounts.rb diff --git a/app/controllers/admin/accounts_controller.rb b/app/controllers/admin/accounts_controller.rb index b9b75727dd9d21..1dd7430e098295 100644 --- a/app/controllers/admin/accounts_controller.rb +++ b/app/controllers/admin/accounts_controller.rb @@ -53,6 +53,13 @@ def destroy redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.destroyed_msg', username: @account.acct) end + def unsensitive + authorize @account, :unsensitive? + @account.unsensitize! + log_action :unsensitive, @account + redirect_to admin_account_path(@account.id) + end + def unsilence authorize @account, :unsilence? @account.unsilence! diff --git a/app/controllers/api/v1/admin/accounts_controller.rb b/app/controllers/api/v1/admin/accounts_controller.rb index 3af572f25ef1f8..63cc521ed01199 100644 --- a/app/controllers/api/v1/admin/accounts_controller.rb +++ b/app/controllers/api/v1/admin/accounts_controller.rb @@ -22,6 +22,7 @@ class Api::V1::Admin::AccountsController < Api::BaseController active pending disabled + sensitized silenced suspended username @@ -68,6 +69,13 @@ def destroy render json: @account, serializer: REST::Admin::AccountSerializer end + def unsensitive + authorize @account, :unsensitive? + @account.unsensitize! + log_action :unsensitive, @account + render json: @account, serializer: REST::Admin::AccountSerializer + end + def unsilence authorize @account, :unsilence? @account.unsilence! diff --git a/app/helpers/statuses_helper.rb b/app/helpers/statuses_helper.rb index a51597cf353e01..adb7918c53fd14 100644 --- a/app/helpers/statuses_helper.rb +++ b/app/helpers/statuses_helper.rb @@ -117,6 +117,14 @@ def fa_visibility_icon(status) end end + def sensitized?(status, account) + if !account.nil? && account.id == status.account_id + status.sensitive + else + status.account.sensitized? || status.sensitive + end + end + private def simplified_text(text) diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index 710baab14ebffa..f45590b4968478 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -112,7 +112,7 @@ def process_status_params created_at: @object['published'], override_timestamps: @options[:override_timestamps], reply: @object['inReplyTo'].present?, - sensitive: @object['sensitive'] || false, + sensitive: @account.sensitized? || @object['sensitive'] || false, visibility: visibility_from_audience, thread: replied_to_status, conversation: conversation_from_uri(@object['conversation']), diff --git a/app/models/account.rb b/app/models/account.rb index 59d338f5af15e0..d2112a13df6359 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -50,6 +50,7 @@ # avatar_storage_schema_version :integer # header_storage_schema_version :integer # devices_url :string +# sensitized_at :datetime # class Account < ApplicationRecord @@ -92,6 +93,7 @@ class Account < ApplicationRecord scope :partitioned, -> { order(Arel.sql('row_number() over (partition by domain)')) } scope :silenced, -> { where.not(silenced_at: nil) } scope :suspended, -> { where.not(suspended_at: nil) } + scope :sensitized, -> { where.not(sensitized_at: nil) } scope :without_suspended, -> { where(suspended_at: nil) } scope :without_silenced, -> { where(silenced_at: nil) } scope :recent, -> { reorder(id: :desc) } @@ -234,6 +236,18 @@ def unsuspend! end end + def sensitized? + sensitized_at.present? + end + + def sensitize!(date = Time.now.utc) + update!(sensitized_at: date) + end + + def unsensitize! + update!(sensitized_at: nil) + end + def memorialize! update!(memorial: true) end diff --git a/app/models/account_warning.rb b/app/models/account_warning.rb index 157e6c04d1eb39..5efc924d5f7ae3 100644 --- a/app/models/account_warning.rb +++ b/app/models/account_warning.rb @@ -13,7 +13,7 @@ # class AccountWarning < ApplicationRecord - enum action: %i(none disable silence suspend), _suffix: :action + enum action: %i(none disable sensitive silence suspend), _suffix: :action belongs_to :account, inverse_of: :account_warnings belongs_to :target_account, class_name: 'Account', inverse_of: :targeted_account_warnings diff --git a/app/models/admin/account_action.rb b/app/models/admin/account_action.rb index c4ac09520ef275..11ce737f3e02d6 100644 --- a/app/models/admin/account_action.rb +++ b/app/models/admin/account_action.rb @@ -8,6 +8,7 @@ class Admin::AccountAction TYPES = %w( none disable + sensitive silence suspend ).freeze @@ -64,6 +65,8 @@ def process_action! case type when 'disable' handle_disable! + when 'sensitive' + handle_sensitive! when 'silence' handle_silence! when 'suspend' @@ -109,6 +112,12 @@ def handle_disable! target_account.user&.disable! end + def handle_sensitive! + authorize(target_account, :sensitive?) + log_action(:sensitive, target_account) + target_account.sensitize! + end + def handle_silence! authorize(target_account, :silence?) log_action(:silence, target_account) diff --git a/app/models/admin/action_log_filter.rb b/app/models/admin/action_log_filter.rb index 0ba7e1609449eb..3a1b67e06752c7 100644 --- a/app/models/admin/action_log_filter.rb +++ b/app/models/admin/action_log_filter.rb @@ -35,9 +35,11 @@ class Admin::ActionLogFilter reopen_report: { target_type: 'Report', action: 'reopen' }.freeze, reset_password_user: { target_type: 'User', action: 'reset_password' }.freeze, resolve_report: { target_type: 'Report', action: 'resolve' }.freeze, + sensitive_account: { target_type: 'Account', action: 'sensitive' }.freeze, silence_account: { target_type: 'Account', action: 'silence' }.freeze, suspend_account: { target_type: 'Account', action: 'suspend' }.freeze, unassigned_report: { target_type: 'Report', action: 'unassigned' }.freeze, + unsensitive_account: { target_type: 'Account', action: 'unsensitive' }.freeze, unsilence_account: { target_type: 'Account', action: 'unsilence' }.freeze, unsuspend_account: { target_type: 'Account', action: 'unsuspend' }.freeze, update_announcement: { target_type: 'Announcement', action: 'update' }.freeze, diff --git a/app/policies/account_policy.rb b/app/policies/account_policy.rb index 1b105e92aa8e95..679119075e15f5 100644 --- a/app/policies/account_policy.rb +++ b/app/policies/account_policy.rb @@ -25,6 +25,14 @@ def unsuspend? staff? end + def sensitive? + staff? && !record.user&.staff? + end + + def unsensitive? + staff? + end + def silence? staff? && !record.user&.staff? end diff --git a/app/serializers/activitypub/note_serializer.rb b/app/serializers/activitypub/note_serializer.rb index 31a1e239adcab1..43e6e626ce09a8 100644 --- a/app/serializers/activitypub/note_serializer.rb +++ b/app/serializers/activitypub/note_serializer.rb @@ -98,6 +98,10 @@ def cc ActivityPub::TagManager.instance.cc(object) end + def sensitive + object.account.sensitized? || object.sensitive + end + def virtual_tags object.active_mentions.to_a.sort_by(&:id) + object.tags + object.emojis end diff --git a/app/serializers/rest/status_serializer.rb b/app/serializers/rest/status_serializer.rb index b1110e5be3dae5..af4548e7f71802 100644 --- a/app/serializers/rest/status_serializer.rb +++ b/app/serializers/rest/status_serializer.rb @@ -64,6 +64,14 @@ def visibility end end + def sensitive + if current_user? && current_user.account_id == object.account_id + object.sensitive + else + object.account.sensitized? || object.sensitive + end + end + def uri ActivityPub::TagManager.instance.uri_for(object) end diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml index f0a216f6b8f622..03071a04f84269 100644 --- a/app/views/admin/accounts/show.html.haml +++ b/app/views/admin/accounts/show.html.haml @@ -69,6 +69,8 @@ = t('admin.accounts.confirming') - elsif @account.local? && !@account.user_approved? = t('admin.accounts.pending') + - elsif @account.sensitized? + = t('admin.accounts.sensitive') - else = t('admin.accounts.no_limits_imposed') .dashboard__counters__label= t 'admin.accounts.login_status' @@ -192,6 +194,11 @@ - else = link_to t('admin.accounts.disable'), new_admin_account_action_path(@account.id, type: 'disable'), class: 'button' if can?(:disable, @account.user) + - if @account.sensitized? + = link_to t('admin.accounts.undo_sensitized'), unsensitive_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unsensitive, @account) + - elsif !@account.local? || @account.user_approved? + = link_to t('admin.accounts.sensitive'), new_admin_account_action_path(@account.id, type: 'sensitive'), class: 'button button--destructive' if can?(:sensitive, @account) + - if @account.silenced? = link_to t('admin.accounts.undo_silenced'), unsilence_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unsilence, @account) - elsif !@account.local? || @account.user_approved? diff --git a/app/views/statuses/_detailed_status.html.haml b/app/views/statuses/_detailed_status.html.haml index 50ec3d14c5bcff..c3794616f12de1 100644 --- a/app/views/statuses/_detailed_status.html.haml +++ b/app/views/statuses/_detailed_status.html.haml @@ -32,17 +32,17 @@ - if !status.media_attachments.empty? - if status.media_attachments.first.video? - video = status.media_attachments.first - = react_component :video, src: full_asset_url(video.file.url(:original)), preview: full_asset_url(video.thumbnail.present? ? video.thumbnail.url : video.file.url(:small)), blurhash: video.blurhash, sensitive: status.sensitive?, width: 670, height: 380, detailed: true, inline: true, alt: video.description do + = react_component :video, src: full_asset_url(video.file.url(:original)), preview: full_asset_url(video.thumbnail.present? ? video.thumbnail.url : video.file.url(:small)), blurhash: video.blurhash, sensitive: sensitized?(status, current_account), width: 670, height: 380, detailed: true, inline: true, alt: video.description do = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } - elsif status.media_attachments.first.audio? - audio = status.media_attachments.first = react_component :audio, src: full_asset_url(audio.file.url(:original)), poster: full_asset_url(audio.thumbnail.present? ? audio.thumbnail.url : status.account.avatar_static_url), backgroundColor: audio.file.meta.dig('colors', 'background'), foregroundColor: audio.file.meta.dig('colors', 'foreground'), accentColor: audio.file.meta.dig('colors', 'accent'), width: 670, height: 380, alt: audio.description, duration: audio.file.meta.dig('original', 'duration') do = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } - else - = react_component :media_gallery, height: 380, sensitive: status.sensitive?, standalone: true, autoplay: autoplay, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } do + = react_component :media_gallery, height: 380, sensitive: sensitized?(status, current_account), standalone: true, autoplay: autoplay, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } do = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } - elsif status.preview_card - = react_component :card, sensitive: status.sensitive?, 'maxDescription': 160, card: ActiveModelSerializers::SerializableResource.new(status.preview_card, serializer: REST::PreviewCardSerializer).as_json + = react_component :card, sensitive: sensitized?(status, current_account), 'maxDescription': 160, card: ActiveModelSerializers::SerializableResource.new(status.preview_card, serializer: REST::PreviewCardSerializer).as_json .detailed-status__meta %data.dt-published{ value: status.created_at.to_time.iso8601 } diff --git a/app/views/statuses/_quote_status.html.haml b/app/views/statuses/_quote_status.html.haml index de5fb6762827ec..373eff5aa2c9a7 100644 --- a/app/views/statuses/_quote_status.html.haml +++ b/app/views/statuses/_quote_status.html.haml @@ -22,14 +22,14 @@ - if !status.media_attachments.empty? - if status.media_attachments.first.video? - video = status.media_attachments.first - = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), blurhash: video.blurhash, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, width: 610, height: 343, inline: true, alt: video.description, quote: true do + = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), blurhash: video.blurhash, sensitive: !current_account&.user&.show_all_media? && sensitized?(status, current_account) || current_account&.user&.hide_all_media?, width: 610, height: 343, inline: true, alt: video.description, quote: true do = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } - elsif status.media_attachments.first.audio? - audio = status.media_attachments.first = react_component :audio, src: audio.file.url(:original), height: 60, alt: audio.description, duration: audio.file.meta.dig(:original, :duration) do = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } - else - = react_component :media_gallery, height: 343, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, 'autoPlayGif': current_account&.user&.setting_auto_play_gif, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }, quote: true do + = react_component :media_gallery, height: 343, sensitive: !current_account&.user&.show_all_media? && sensitized?(status, current_account) || current_account&.user&.hide_all_media?, 'autoPlayGif': current_account&.user&.setting_auto_play_gif, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }, quote: true do = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } - elsif status.preview_card = react_component :card, maxDescription: 10, card: ActiveModelSerializers::SerializableResource.new(status.preview_card, serializer: REST::PreviewCardSerializer).as_json, quote: true diff --git a/app/views/statuses/_simple_status.html.haml b/app/views/statuses/_simple_status.html.haml index 404696ec5eeaad..3019b777169272 100644 --- a/app/views/statuses/_simple_status.html.haml +++ b/app/views/statuses/_simple_status.html.haml @@ -38,17 +38,17 @@ - if !status.media_attachments.empty? - if status.media_attachments.first.video? - video = status.media_attachments.first - = react_component :video, src: full_asset_url(video.file.url(:original)), preview: full_asset_url(video.thumbnail.present? ? video.thumbnail.url : video.file.url(:small)), blurhash: video.blurhash, sensitive: status.sensitive?, width: 610, height: 343, inline: true, alt: video.description do + = react_component :video, src: full_asset_url(video.file.url(:original)), preview: full_asset_url(video.thumbnail.present? ? video.thumbnail.url : video.file.url(:small)), blurhash: video.blurhash, sensitive: sensitized?(status, current_account), width: 610, height: 343, inline: true, alt: video.description do = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } - elsif status.media_attachments.first.audio? - audio = status.media_attachments.first = react_component :audio, src: full_asset_url(audio.file.url(:original)), poster: full_asset_url(audio.thumbnail.present? ? audio.thumbnail.url : status.account.avatar_static_url), backgroundColor: audio.file.meta.dig('colors', 'background'), foregroundColor: audio.file.meta.dig('colors', 'foreground'), accentColor: audio.file.meta.dig('colors', 'accent'), width: 610, height: 343, alt: audio.description, duration: audio.file.meta.dig('original', 'duration') do = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } - else - = react_component :media_gallery, height: 343, sensitive: status.sensitive?, autoplay: autoplay, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } do + = react_component :media_gallery, height: 343, sensitive: sensitized?(status, current_account), autoplay: autoplay, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } do = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } - elsif status.preview_card - = react_component :card, sensitive: status.sensitive?, 'maxDescription': 160, card: ActiveModelSerializers::SerializableResource.new(status.preview_card, serializer: REST::PreviewCardSerializer).as_json + = react_component :card, sensitive: sensitized?(status, current_account), 'maxDescription': 160, card: ActiveModelSerializers::SerializableResource.new(status.preview_card, serializer: REST::PreviewCardSerializer).as_json - if !status.in_reply_to_id.nil? && status.in_reply_to_account_id == status.account.id = link_to ActivityPub::TagManager.instance.url_for(status), class: 'status__content__read-more-button', target: stream_link_target, rel: 'noopener noreferrer' do diff --git a/config/locales/en.yml b/config/locales/en.yml index 01f0ad760c4cf4..8ec9f9711f29fe 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -211,6 +211,7 @@ en: time_in_queue: Waiting in queue %{time} title: Accounts unconfirmed_email: Unconfirmed email + undo_sensitized: Undo sensitive undo_silenced: Undo silence undo_suspension: Undo suspension unsilenced_msg: Successfully unlimited %{username}'s account @@ -252,9 +253,11 @@ en: reopen_report: Reopen Report reset_password_user: Reset Password resolve_report: Resolve Report + sensitive_account: Sensitive Account silence_account: Silence Account suspend_account: Suspend Account unassigned_report: Unassign Report + unsensitive_account: Unsensitive Account unsilence_account: Unsilence Account unsuspend_account: Unsuspend Account update_announcement: Update Announcement @@ -290,9 +293,11 @@ en: reopen_report: "%{name} reopened report %{target}" reset_password_user: "%{name} reset password of user %{target}" resolve_report: "%{name} resolved report %{target}" + sensitive_account: "%{name} sensitized %{target}'s account" silence_account: "%{name} silenced %{target}'s account" suspend_account: "%{name} suspended %{target}'s account" unassigned_report: "%{name} unassigned report %{target}" + unsensitive_account: "%{name} unsensitized %{target}'s account" unsilence_account: "%{name} unsilenced %{target}'s account" unsuspend_account: "%{name} unsuspended %{target}'s account" update_announcement: "%{name} updated announcement %{target}" @@ -1435,6 +1440,7 @@ en: warning: explanation: disable: You can no longer login to your account or use it in any other way, but your profile and other data remains intact. + sensitive: Your uploaded media file is treated as sensitive. silence: You can still use your account but only people who are already following you will see your toots on this server, and you may be excluded from various public listings. However, others may still manually follow you. suspend: You can no longer use your account, and your profile and other data are no longer accessible. You can still login to request a backup of your data until the data is fully removed, but we will retain some data to prevent you from evading the suspension. get_in_touch: You can reply to this e-mail to get in touch with the staff of %{instance}. @@ -1443,11 +1449,13 @@ en: subject: disable: Your account %{acct} has been frozen none: Warning for %{acct} + sensitive: Your account %{acct} has been sensitized silence: Your account %{acct} has been limited suspend: Your account %{acct} has been suspended title: disable: Account frozen none: Warning + sensitive: Account sensitized silence: Account limited suspend: Account suspended welcome: diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 9b3baa11c40e32..ac5b51ee60dbb7 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -193,6 +193,7 @@ ja: time_in_queue: "%{time} 待ち" title: アカウント unconfirmed_email: 確認待ちのメールアドレス + undo_sensitized: 閲覧注意から戻す undo_silenced: サイレンスから戻す undo_suspension: 停止から戻す unsubscribe: 購読の解除 @@ -229,9 +230,11 @@ ja: reopen_report: 通報を再度開く reset_password_user: パスワードをリセット resolve_report: 通報を解決済みにする + sensitive_account: アカウントを閲覧注意 silence_account: アカウントをサイレンス suspend_account: アカウントを停止 unassigned_report: 通報の担当を解除 + unsensitive_account: アカウントの閲覧注意を解除 unsilence_account: アカウントのサイレンスを解除 unsuspend_account: アカウントの停止を解除 update_announcement: お知らせを更新 @@ -265,9 +268,11 @@ ja: reopen_report: "%{name} さんが通報 %{target} を再び開きました" reset_password_user: "%{name} さんが %{target} さんのパスワードをリセットしました" resolve_report: "%{name} さんが通報 %{target} を解決済みにしました" + sensitive_account: "%{name} さんが %{target} さんを閲覧注意にしました" silence_account: "%{name} さんが %{target} さんをサイレンスにしました" suspend_account: "%{name} さんが %{target} さんを停止しました" unassigned_report: "%{name} さんが通報 %{target} の担当を外しました" + unsensitive_account: "%{name} さんが %{target} さんの閲覧注意を解除しました" unsilence_account: "%{name} さんが %{target} さんのサイレンスを解除しました" unsuspend_account: "%{name} さんが %{target} さんの停止を解除しました" update_announcement: "%{name} さんがお知らせ %{target} を更新しました" @@ -1340,6 +1345,7 @@ ja: warning: explanation: disable: アカウントが凍結されている間、データはそのまま残りますが、凍結が解除されるまでは何の操作もできません。 + sensitive: あなたのアップロードしたメディアファイルは閲覧注意として扱われています。 silence: あなたのアカウントは制限されていますが、あなたをフォローしているユーザーのみ、このサーバー上の投稿を見ることができます。そしてあなたは様々な公開リストから除外されるかもしれません。ただし、他のユーザーは手動であなたをフォローすることができます。 suspend: あなたのアカウントは停止されています。あなたの投稿とアップロードされたメディアファイルは、このサーバーとあなたのフォロワーが参加していたサーバーから完全に削除されました。 get_in_touch: このメールに返信することで %{instance} のスタッフと連絡を取ることができます。 @@ -1348,11 +1354,13 @@ ja: subject: disable: あなたのアカウント %{acct} は凍結されました none: "%{acct} に対する警告" + sensitive: あなたのアカウント %{acct} は閲覧注意にされました silence: あなたのアカウント %{acct} はサイレンスにされました suspend: あなたのアカウント %{acct} は停止されました title: disable: アカウントが凍結されました none: 警告 + sensitive: アカウントが閲覧注意にされました silence: アカウントがサイレンスにされました suspend: アカウントが停止されました welcome: diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index 056fefc68b5555..79053196942784 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -121,6 +121,7 @@ en: types: disable: Freeze none: Send a warning + sensitive: Sensitive silence: Limit suspend: Suspend warning_preset_id: Use a warning preset diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml index cb989c100fa75e..bcc4c99c0b8efd 100644 --- a/config/locales/simple_form.ja.yml +++ b/config/locales/simple_form.ja.yml @@ -110,6 +110,7 @@ ja: types: disable: ログインを無効化 none: 何もしない + sensitive: 閲覧注意 silence: サイレンス suspend: 停止しアカウントのデータを恒久的に削除する warning_preset_id: プリセット警告文を使用 diff --git a/config/routes.rb b/config/routes.rb index 37538b83b5c38e..35f4d46d0b4516 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -242,6 +242,7 @@ resources :accounts, only: [:index, :show, :destroy] do member do post :enable + post :unsensitive post :unsilence post :unsuspend post :redownload @@ -491,6 +492,7 @@ resources :accounts, only: [:index, :show, :destroy] do member do post :enable + post :unsensitive post :unsilence post :unsuspend post :approve diff --git a/db/migrate/20200614002136_add_sensitized_to_accounts.rb b/db/migrate/20200614002136_add_sensitized_to_accounts.rb new file mode 100644 index 00000000000000..bc2dfcb6363bad --- /dev/null +++ b/db/migrate/20200614002136_add_sensitized_to_accounts.rb @@ -0,0 +1,5 @@ +class AddSensitizedToAccounts < ActiveRecord::Migration[5.2] + def change + add_column :accounts, :sensitized_at, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index 354d374cea9bd7..2c54de8e277bfb 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -202,6 +202,7 @@ t.integer "avatar_storage_schema_version" t.integer "header_storage_schema_version" t.string "devices_url" + t.datetime "sensitized_at" 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), COALESCE(lower((domain)::text), ''::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/controllers/api/v1/admin/accounts_controller_spec.rb b/spec/controllers/api/v1/admin/accounts_controller_spec.rb index f3f9946baac2db..89cadb222b8a97 100644 --- a/spec/controllers/api/v1/admin/accounts_controller_spec.rb +++ b/spec/controllers/api/v1/admin/accounts_controller_spec.rb @@ -127,6 +127,24 @@ end end + describe 'POST #unsensitive' do + before do + account.touch(:sensitized_at) + post :unsensitive, params: { id: account.id } + end + + it_behaves_like 'forbidden for wrong scope', 'write:statuses' + it_behaves_like 'forbidden for wrong role', 'user' + + it 'returns http success' do + expect(response).to have_http_status(200) + end + + it 'unsensitives account' do + expect(account.reload.sensitized?).to be false + end + end + describe 'POST #unsilence' do before do account.touch(:silenced_at) diff --git a/spec/models/admin/account_action_spec.rb b/spec/models/admin/account_action_spec.rb index e5f4c93677e1ce..b9655b38c24329 100644 --- a/spec/models/admin/account_action_spec.rb +++ b/spec/models/admin/account_action_spec.rb @@ -115,16 +115,16 @@ context 'account.local?' do let(:account) { Fabricate(:account, domain: nil) } - it 'returns ["none", "disable", "silence", "suspend"]' do - expect(subject).to eq %w(none disable silence suspend sensitive) + it 'returns ["none", "disable", "sensitive", "silence", "suspend"]' do + expect(subject).to eq %w(none disable sensitive silence suspend ) end end context '!account.local?' do let(:account) { Fabricate(:account, domain: 'hoge.com') } - it 'returns ["silence", "suspend"]' do - expect(subject).to eq %w(silence suspend sensitive) + it 'returns ["sensitive", "silence", "suspend"]' do + expect(subject).to eq %w(sensitive silence suspend) end end end diff --git a/spec/policies/account_policy_spec.rb b/spec/policies/account_policy_spec.rb index 6648b0888bf6e8..d27e9d5b07e161 100644 --- a/spec/policies/account_policy_spec.rb +++ b/spec/policies/account_policy_spec.rb @@ -8,7 +8,7 @@ let(:admin) { Fabricate(:user, admin: true).account } let(:john) { Fabricate(:user).account } - permissions :index?, :show?, :unsuspend?, :unsilence?, :remove_avatar?, :remove_header? do + permissions :index?, :show?, :unsuspend?, :unsensitive?, :unsilence?, :remove_avatar?, :remove_header? do context 'staff' do it 'permits' do expect(subject).to permit(admin)