mirror of
https://github.com/mastodon/mastodon.git
synced 2026-09-12 08:15:39 -05:00
Add audit logs for Hashtags (#39337)
This commit is contained in:
@@ -17,12 +17,15 @@ module Admin
|
||||
authorize @tag, :show?
|
||||
|
||||
@time_period = report_range
|
||||
@action_logs = Admin::ActionLogFilter.new(target_tag: @tag.formatted_name).results.limit(5)
|
||||
end
|
||||
|
||||
def update
|
||||
authorize @tag, :update?
|
||||
|
||||
if @tag.update(tag_params.merge(reviewed_at: Time.now.utc))
|
||||
log_action_from_change if @tag.saved_changes?
|
||||
|
||||
redirect_to admin_tag_path(@tag.id), notice: I18n.t('admin.tags.updated_msg')
|
||||
else
|
||||
@time_period = report_range
|
||||
@@ -33,6 +36,13 @@ module Admin
|
||||
|
||||
private
|
||||
|
||||
def log_action_from_change
|
||||
action_log = current_account.action_logs.new(action: 'update', target: @tag)
|
||||
|
||||
action_log.recorded_changes = @tag.saved_changes.slice('usable', 'trendable', 'listable').transform_values(&:last)
|
||||
action_log.save
|
||||
end
|
||||
|
||||
def set_tag
|
||||
@tag = Tag.find(params[:id])
|
||||
end
|
||||
|
||||
@@ -37,9 +37,29 @@ module Admin::ActionLogsHelper
|
||||
end
|
||||
when 'Relay'
|
||||
link_to log.human_identifier, admin_relays_path
|
||||
when 'Tag'
|
||||
link_to log.human_identifier, admin_tag_path(log.target_id)
|
||||
end
|
||||
end
|
||||
|
||||
def chain_multiple_translations(action_log)
|
||||
case action_log.target_type
|
||||
when 'Tag'
|
||||
%i(usable trendable listable).filter_map do |key|
|
||||
fetch_key = permutation_of_key(action_log, key)
|
||||
next if fetch_key.nil?
|
||||
|
||||
t "admin.trends.tags.#{fetch_key}"
|
||||
end.join('; ')
|
||||
end
|
||||
end
|
||||
|
||||
def permutation_of_key(log, key)
|
||||
return if log.public_send(key).nil?
|
||||
|
||||
log.public_send(key) ? key : :"not_#{key}"
|
||||
end
|
||||
|
||||
def sorted_action_log_types
|
||||
Admin::ActionLogFilter::ACTION_TYPE_MAP
|
||||
.keys
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#
|
||||
|
||||
class Admin::ActionLog < ApplicationRecord
|
||||
LOG_ATTRIBUTES = %i(usable trendable listable).freeze
|
||||
|
||||
belongs_to :account
|
||||
belongs_to :target, polymorphic: true, optional: true
|
||||
|
||||
@@ -26,6 +28,8 @@ class Admin::ActionLog < ApplicationRecord
|
||||
before_validation :set_route_param
|
||||
before_validation :set_permalink
|
||||
|
||||
store_accessor :recorded_changes, *LOG_ATTRIBUTES
|
||||
|
||||
scope :latest, -> { order(id: :desc) }
|
||||
|
||||
def action
|
||||
|
||||
@@ -6,6 +6,7 @@ class Admin::ActionLogFilter
|
||||
account_id
|
||||
target_account_id
|
||||
target_domain
|
||||
target_tag
|
||||
).freeze
|
||||
|
||||
INSTANCE_TARGET_TYPES = %w(
|
||||
@@ -77,6 +78,7 @@ class Admin::ActionLogFilter
|
||||
update_user_role: { target_type: 'UserRole', action: 'update' }.freeze,
|
||||
update_ip_block: { target_type: 'IpBlock', action: 'update' }.freeze,
|
||||
unblock_email_account: { target_type: 'Account', action: 'unblock_email' }.freeze,
|
||||
update_tag: { target_type: 'Tag', action: 'update' }.freeze,
|
||||
create_username_block: { target_type: 'UsernameBlock', action: 'create' }.freeze,
|
||||
update_username_block: { target_type: 'UsernameBlock', action: 'update' }.freeze,
|
||||
destroy_username_block: { target_type: 'UsernameBlock', action: 'destroy' }.freeze,
|
||||
@@ -116,6 +118,8 @@ class Admin::ActionLogFilter
|
||||
when 'target_domain'
|
||||
normalized_domain = TagManager.instance.normalize_domain(value)
|
||||
latest_action_logs.where(human_identifier: normalized_domain, target_type: INSTANCE_TARGET_TYPES)
|
||||
when 'target_tag'
|
||||
latest_action_logs.where(human_identifier: value)
|
||||
else
|
||||
raise Mastodon::InvalidParameterError, "Unknown filter: #{key}"
|
||||
end
|
||||
|
||||
@@ -111,6 +111,10 @@ class Tag < ApplicationRecord
|
||||
@history ||= Trends::History.new('tags', id)
|
||||
end
|
||||
|
||||
def to_log_human_identifier
|
||||
formatted_name
|
||||
end
|
||||
|
||||
class << self
|
||||
def find_or_create_by_names(name_or_names)
|
||||
names = Array(name_or_names).map { |str| [normalize_value_for(:name, str), str] }.uniq(&:first)
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
= image_tag action_log.account.avatar.url(:original), alt: '', width: 40, height: 40, class: 'avatar'
|
||||
.log-entry__content
|
||||
.log-entry__title
|
||||
= t "admin.action_logs.actions.#{action_log.action}_#{action_log.target_type.underscore}_html",
|
||||
= t("admin.action_logs.actions.#{action_log.action}_#{action_log.target_type.underscore}_html",
|
||||
name: content_tag(:span, action_log.account.username, class: 'username'),
|
||||
target: content_tag(:span, log_target(action_log), class: 'target')
|
||||
target: content_tag(:span, log_target(action_log), class: 'target'))
|
||||
- if action_log.recorded_changes.present?
|
||||
= t(chain_multiple_translations(action_log))
|
||||
|
||||
.log-entry__timestamp
|
||||
%time.formatted{ datetime: action_log.created_at.iso8601 }
|
||||
|
||||
@@ -90,3 +90,14 @@
|
||||
|
||||
.actions
|
||||
= f.button :button, t('generic.save_changes'), type: :submit
|
||||
|
||||
- if @tag.persisted?
|
||||
%hr.spacer/
|
||||
|
||||
%h3= t('admin.instances.audit_log.title')
|
||||
- if @action_logs.blank?
|
||||
%p= t('accounts.nothing_here')
|
||||
- else
|
||||
.report-notes
|
||||
= render partial: 'admin/action_logs/action_log', collection: @action_logs
|
||||
= link_to t('admin.instances.audit_log.view_all'), admin_action_logs_path(target_tag: @tag.formatted_name), class: 'button'
|
||||
|
||||
@@ -243,6 +243,7 @@ en-GB:
|
||||
update_ip_block: Update IP rule
|
||||
update_report: Update Report
|
||||
update_status: Update Post
|
||||
update_tag: Update Hashtag
|
||||
update_user_role: Update Role
|
||||
update_username_block: Update Username Rule
|
||||
actions:
|
||||
@@ -313,6 +314,7 @@ en-GB:
|
||||
update_ip_block_html: "%{name} changed rule for IP %{target}"
|
||||
update_report_html: "%{name} updated report %{target}"
|
||||
update_status_html: "%{name} updated post by %{target}"
|
||||
update_tag_html: "%{name} changed %{target} settings to: "
|
||||
update_user_role_html: "%{name} changed %{target} role"
|
||||
update_username_block_html: "%{name} updated rule for usernames containing %{target}"
|
||||
deleted_account: deleted account
|
||||
|
||||
@@ -289,7 +289,11 @@ en:
|
||||
enable_relay_html: "%{name} enabled the relay %{target}"
|
||||
enable_sign_in_token_auth_user_html: "%{name} enabled email token authentication for %{target}"
|
||||
enable_user_html: "%{name} enabled login for user %{target}"
|
||||
listable_tag_html: can be suggested
|
||||
memorialize_account_html: "%{name} turned %{target}'s account into a memoriam page"
|
||||
not_listable_tag_html: won't be suggested
|
||||
not_trendable_tag_html: won't appear under trends
|
||||
not_usable_tag_html: cannot be used
|
||||
promote_user_html: "%{name} promoted user %{target}"
|
||||
publish_terms_of_service_html: "%{name} published updates to the terms of service"
|
||||
reject_appeal_html: "%{name} rejected moderation decision appeal from %{target}"
|
||||
@@ -302,6 +306,7 @@ en:
|
||||
sensitive_account_html: "%{name} marked %{target}'s media as sensitive"
|
||||
silence_account_html: "%{name} limited %{target}'s account"
|
||||
suspend_account_html: "%{name} suspended %{target}'s account"
|
||||
trendable_tag_html: can appear under trends
|
||||
unassigned_report_html: "%{name} unassigned report %{target}"
|
||||
unblock_email_account_html: "%{name} unblocked %{target}'s email address"
|
||||
unsensitive_account_html: "%{name} unmarked %{target}'s media as sensitive"
|
||||
@@ -314,8 +319,10 @@ en:
|
||||
update_ip_block_html: "%{name} changed rule for IP %{target}"
|
||||
update_report_html: "%{name} updated report %{target}"
|
||||
update_status_html: "%{name} updated post by %{target}"
|
||||
update_tag_html: "%{name} changed %{target} settings to: "
|
||||
update_user_role_html: "%{name} changed %{target} role"
|
||||
update_username_block_html: "%{name} updated rule for usernames containing %{target}"
|
||||
usable_tag_html: can be used;
|
||||
deleted_account: deleted account
|
||||
empty: No logs found.
|
||||
filter_by_action: Filter by action
|
||||
|
||||
27
spec/helpers/admin/action_logs_helper_spec.rb
Normal file
27
spec/helpers/admin/action_logs_helper_spec.rb
Normal file
@@ -0,0 +1,27 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Admin::ActionLogsHelper do
|
||||
before { sign_in Fabricate(:admin_user) }
|
||||
|
||||
describe 'with Tags' do
|
||||
let(:tag) { Fabricate(:tag, name: '#supertag') }
|
||||
let(:account) { Fabricate(:account) }
|
||||
let!(:log) { Fabricate(:action_log, target: tag, account: account, usable: false, listable: true) }
|
||||
|
||||
describe '#permutation_of_key' do
|
||||
it 'returns different permutations for all different states' do
|
||||
expect(helper.permutation_of_key(log, :usable)).to eq(:not_usable)
|
||||
expect(helper.permutation_of_key(log, :trendable)).to be_nil
|
||||
expect(helper.permutation_of_key(log, :listable)).to eq(:listable)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#chain_multiple_translations' do
|
||||
it 'returns translation keys for all different states' do
|
||||
expect(helper.chain_multiple_translations(log)).to eq('Cannot be used; Can be suggested')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3,9 +3,9 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Admin Tags' do
|
||||
describe 'PUT /admin/tags/:id' do
|
||||
before { sign_in Fabricate(:admin_user) }
|
||||
before { sign_in Fabricate(:admin_user) }
|
||||
|
||||
describe 'PUT /admin/tags/:id' do
|
||||
let(:tag) { Fabricate :tag }
|
||||
|
||||
it 'gracefully handles invalid nested params' do
|
||||
@@ -15,4 +15,17 @@ RSpec.describe 'Admin Tags' do
|
||||
.to have_http_status(400)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'update tag' do
|
||||
let(:tag) { Fabricate :tag, name: '#supertag' }
|
||||
|
||||
it 'redirects to tag page and saves update log action for all attribute statuses' do
|
||||
put admin_tag_path(tag.id, params: { tag: { trendable: true, listable: false } })
|
||||
|
||||
expect(response).to have_http_status(302)
|
||||
expect(Admin::ActionLog.last.human_identifier).to eq('#supertag')
|
||||
expect(Admin::ActionLog.pluck(:action)).to eq(%w(update))
|
||||
expect(Admin::ActionLog.pluck(:recorded_changes)).to eq([{ 'listable' => false, 'trendable' => true }])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user