Skip to content

Commit

Permalink
Add account sensitized
Browse files Browse the repository at this point in the history
Fix i18n

Fix spec
  • Loading branch information
umonaca committed Oct 29, 2020
1 parent 44ec8e9 commit a398fb1
Show file tree
Hide file tree
Showing 25 changed files with 134 additions and 15 deletions.
7 changes: 7 additions & 0 deletions app/controllers/admin/accounts_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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!
Expand Down
8 changes: 8 additions & 0 deletions app/controllers/api/v1/admin/accounts_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class Api::V1::Admin::AccountsController < Api::BaseController
active
pending
disabled
sensitized
silenced
suspended
username
Expand Down Expand Up @@ -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!
Expand Down
8 changes: 8 additions & 0 deletions app/helpers/statuses_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion app/lib/activitypub/activity/create.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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']),
Expand Down
14 changes: 14 additions & 0 deletions app/models/account.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
# avatar_storage_schema_version :integer
# header_storage_schema_version :integer
# devices_url :string
# sensitized_at :datetime
#

class Account < ApplicationRecord
Expand Down Expand Up @@ -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) }
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion app/models/account_warning.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions app/models/admin/account_action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class Admin::AccountAction
TYPES = %w(
none
disable
sensitive
silence
suspend
).freeze
Expand Down Expand Up @@ -64,6 +65,8 @@ def process_action!
case type
when 'disable'
handle_disable!
when 'sensitive'
handle_sensitive!
when 'silence'
handle_silence!
when 'suspend'
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions app/models/admin/action_log_filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
8 changes: 8 additions & 0 deletions app/policies/account_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions app/serializers/activitypub/note_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions app/serializers/rest/status_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions app/views/admin/accounts/show.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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?
Expand Down
6 changes: 3 additions & 3 deletions app/views/statuses/_detailed_status.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
4 changes: 2 additions & 2 deletions app/views/statuses/_quote_status.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -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
6 changes: 3 additions & 3 deletions app/views/statuses/_simple_status.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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}"
Expand Down Expand Up @@ -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}.
Expand All @@ -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:
Expand Down
Loading

0 comments on commit a398fb1

Please sign in to comment.