FEATURE: Add creator and logging for CustomEmoji (#28004)

* FEATURE: Add logging for CustomEmoji

We didn't provide any logs for CustomEmoji before, nor did we record the
person who added any emoji in the database. As a result, the staff had
no way to trace back who added a certain emoji.

This commit adds a new column `user_id` to `custom_emojis` to record the
creator of an emoji. At the same time, a log is added for staff logs to
record who added or deleted a custom emoji.
This commit is contained in:
锦心 2024-07-22 14:44:49 +08:00 committed by GitHub
parent 23d7800ff1
commit 199f980e6a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 77 additions and 2 deletions

View File

@ -28,9 +28,12 @@ class Admin::EmojisController < Admin::AdminController
data = data =
if upload.persisted? if upload.persisted?
custom_emoji = CustomEmoji.new(name: name, upload: upload, group: group) custom_emoji =
CustomEmoji.new(name: name, upload: upload, group: group, user: current_user)
if custom_emoji.save if custom_emoji.save
StaffActionLogger.new(current_user).log_custom_emoji_create(name, group: group)
Emoji.clear_cache Emoji.clear_cache
{ name: custom_emoji.name, url: custom_emoji.upload.url, group: group } { name: custom_emoji.name, url: custom_emoji.upload.url, group: group }
else else
@ -50,7 +53,12 @@ class Admin::EmojisController < Admin::AdminController
name = params.require(:id) name = params.require(:id)
# NOTE: the upload will automatically be removed by the 'clean_up_uploads' job # NOTE: the upload will automatically be removed by the 'clean_up_uploads' job
CustomEmoji.find_by(name: name)&.destroy! emoji = CustomEmoji.find_by(name: name)
if emoji.present?
StaffActionLogger.new(current_user).log_custom_emoji_destroy(name)
emoji.destroy!
end
Emoji.clear_cache Emoji.clear_cache

View File

@ -2,17 +2,27 @@
class CustomEmoji < ActiveRecord::Base class CustomEmoji < ActiveRecord::Base
belongs_to :upload belongs_to :upload
belongs_to :user
has_many :upload_references, as: :target, dependent: :destroy has_many :upload_references, as: :target, dependent: :destroy
validates :name, presence: true, uniqueness: true validates :name, presence: true, uniqueness: true
validates :upload_id, presence: true validates :upload_id, presence: true
validates :user_id, presence: true
before_validation :set_default_user_id, on: :create
after_save do after_save do
if saved_change_to_upload_id? if saved_change_to_upload_id?
UploadReference.ensure_exist!(upload_ids: [self.upload_id], target: self) UploadReference.ensure_exist!(upload_ids: [self.upload_id], target: self)
end end
end end
private
def set_default_user_id
self.user_id ||= Discourse.system_user.id
end
end end
# == Schema Information # == Schema Information
@ -25,6 +35,7 @@ end
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# group :string(20) # group :string(20)
# user_id :integer default(-1), not null
# #
# Indexes # Indexes
# #

View File

@ -148,6 +148,8 @@ class UserHistory < ActiveRecord::Base
filled_in_required_fields: 109, filled_in_required_fields: 109,
topic_slow_mode_set: 110, topic_slow_mode_set: 110,
topic_slow_mode_removed: 111, topic_slow_mode_removed: 111,
custom_emoji_create: 112,
custom_emoji_destroy: 113,
) )
end end
@ -258,6 +260,8 @@ class UserHistory < ActiveRecord::Base
delete_watched_word_group delete_watched_word_group
topic_slow_mode_set topic_slow_mode_set
topic_slow_mode_removed topic_slow_mode_removed
custom_emoji_create
custom_emoji_destroy
] ]
end end

View File

@ -1030,6 +1030,20 @@ class StaffActionLogger
) )
end end
def log_custom_emoji_create(name, opts = {})
opts[:details] = "Group: #{opts[:group]}" if opts[:group].present?
UserHistory.create!(
params(opts).merge(action: UserHistory.actions[:custom_emoji_create], new_value: name),
)
end
def log_custom_emoji_destroy(name, opts = {})
UserHistory.create!(
params(opts).merge(action: UserHistory.actions[:custom_emoji_destroy], previous_value: name),
)
end
private private
def json_params(previous_value, new_value) def json_params(previous_value, new_value)

View File

@ -6226,6 +6226,8 @@ en:
delete_flag: "delete flag" delete_flag: "delete flag"
topic_slow_mode_set: "set topic slow mode" topic_slow_mode_set: "set topic slow mode"
topic_slow_mode_removed: "remove topic slow mode" topic_slow_mode_removed: "remove topic slow mode"
custom_emoji_create: "create custom emoji"
custom_emoji_destroy: "delete custom emoji"
screened_emails: screened_emails:
title: "Screened Emails" title: "Screened Emails"
description: "When someone tries to create a new account, the following email addresses will be checked and the registration will be blocked, or some other action performed." description: "When someone tries to create a new account, the following email addresses will be checked and the registration will be blocked, or some other action performed."

View File

@ -0,0 +1,6 @@
# frozen_string_literal: true
class AddUserIdToCustomEmojis < ActiveRecord::Migration[7.1]
def change
add_column :custom_emojis, :user_id, :integer, null: false, default: -1
end
end

View File

@ -101,6 +101,23 @@ RSpec.describe Admin::EmojisController do
expect(data["name"]).to eq(custom_emoji.name) expect(data["name"]).to eq(custom_emoji.name)
expect(data["url"]).to eq(upload.url) expect(data["url"]).to eq(upload.url)
expect(custom_emoji.group).to eq(nil) expect(custom_emoji.group).to eq(nil)
expect(custom_emoji.user_id).to eq(admin.id)
end
it "should log the action" do
Emoji.expects(:clear_cache)
post "/admin/customize/emojis.json",
params: {
name: "test",
file: fixture_file_upload("#{Rails.root}/spec/fixtures/images/logo.png"),
}
last_log = UserHistory.last
expect(last_log.action).to eq(UserHistory.actions[:custom_emoji_create])
expect(last_log.acting_user_id).to eq(admin.id)
expect(last_log.new_value).to eq("test")
end end
it "should allow an admin to add a custom emoji with a custom group" do it "should allow an admin to add a custom emoji with a custom group" do
@ -196,6 +213,19 @@ RSpec.describe Admin::EmojisController do
delete "/admin/customize/emojis/#{custom_emoji.name}.json", params: { name: "test" } delete "/admin/customize/emojis/#{custom_emoji.name}.json", params: { name: "test" }
end.to change { CustomEmoji.count }.by(-1) end.to change { CustomEmoji.count }.by(-1)
end end
it "should log the action" do
custom_emoji = CustomEmoji.create!(name: "test", upload: upload)
Emoji.clear_cache
delete "/admin/customize/emojis/#{custom_emoji.name}.json", params: { name: "test" }
last_log = UserHistory.last
expect(last_log.action).to eq(UserHistory.actions[:custom_emoji_destroy])
expect(last_log.acting_user_id).to eq(admin.id)
expect(last_log.previous_value).to eq("test")
end
end end
shared_examples "custom emoji deletion not allowed" do shared_examples "custom emoji deletion not allowed" do