2019-05-02 18:17:27 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2013-09-10 21:21:16 -04:00
|
|
|
# UserHistory stores information about actions that users have taken,
|
|
|
|
# like deleting users, changing site settings, dimissing notifications, etc.
|
|
|
|
# Use other classes, like StaffActionLogger, to log records to this table.
|
|
|
|
class UserHistory < ActiveRecord::Base
|
|
|
|
belongs_to :acting_user, class_name: 'User'
|
|
|
|
belongs_to :target_user, class_name: 'User'
|
2013-04-11 16:04:20 -04:00
|
|
|
|
2014-10-01 11:40:13 -04:00
|
|
|
belongs_to :post
|
|
|
|
belongs_to :topic
|
2015-09-17 03:51:32 -04:00
|
|
|
belongs_to :category
|
2014-10-01 11:40:13 -04:00
|
|
|
|
2013-04-11 16:04:20 -04:00
|
|
|
validates_presence_of :action
|
|
|
|
|
2013-09-10 21:21:16 -04:00
|
|
|
scope :only_staff_actions, -> { where("action IN (?)", UserHistory.staff_action_ids) }
|
|
|
|
|
2014-02-28 16:30:45 -05:00
|
|
|
before_save :set_admin_only
|
|
|
|
|
2013-04-11 16:04:20 -04:00
|
|
|
def self.actions
|
2018-03-13 15:59:12 -04:00
|
|
|
@actions ||= Enum.new(
|
|
|
|
delete_user: 1,
|
|
|
|
change_trust_level: 2,
|
|
|
|
change_site_setting: 3,
|
|
|
|
change_theme: 4,
|
|
|
|
delete_theme: 5,
|
|
|
|
checked_for_custom_avatar: 6, # not used anymore
|
|
|
|
notified_about_avatar: 7,
|
|
|
|
notified_about_sequential_replies: 8,
|
|
|
|
notified_about_dominating_topic: 9,
|
|
|
|
suspend_user: 10,
|
|
|
|
unsuspend_user: 11,
|
2018-11-28 10:49:24 -05:00
|
|
|
facebook_no_email: 12, # not used anymore
|
2018-03-13 15:59:12 -04:00
|
|
|
grant_badge: 13,
|
|
|
|
revoke_badge: 14,
|
|
|
|
auto_trust_level_change: 15,
|
|
|
|
check_email: 16,
|
|
|
|
delete_post: 17,
|
|
|
|
delete_topic: 18,
|
|
|
|
impersonate: 19,
|
|
|
|
roll_up: 20,
|
|
|
|
change_username: 21,
|
|
|
|
custom: 22,
|
|
|
|
custom_staff: 23,
|
|
|
|
anonymize_user: 24,
|
|
|
|
reviewed_post: 25,
|
|
|
|
change_category_settings: 26,
|
|
|
|
delete_category: 27,
|
|
|
|
create_category: 28,
|
|
|
|
change_site_text: 29,
|
|
|
|
silence_user: 30,
|
|
|
|
unsilence_user: 31,
|
|
|
|
grant_admin: 32,
|
|
|
|
revoke_admin: 33,
|
|
|
|
grant_moderation: 34,
|
|
|
|
revoke_moderation: 35,
|
|
|
|
backup_create: 36,
|
|
|
|
rate_limited_like: 37, # not used anymore
|
|
|
|
revoke_email: 38,
|
|
|
|
deactivate_user: 39,
|
|
|
|
wizard_step: 40,
|
|
|
|
lock_trust_level: 41,
|
|
|
|
unlock_trust_level: 42,
|
|
|
|
activate_user: 43,
|
|
|
|
change_readonly_mode: 44,
|
|
|
|
backup_download: 45,
|
|
|
|
backup_destroy: 46,
|
|
|
|
notified_about_get_a_room: 47,
|
|
|
|
change_name: 48,
|
|
|
|
post_locked: 49,
|
|
|
|
post_unlocked: 50,
|
|
|
|
check_personal_message: 51,
|
|
|
|
disabled_second_factor: 52,
|
|
|
|
post_edit: 53,
|
2018-03-21 00:15:16 -04:00
|
|
|
topic_published: 54,
|
2018-04-23 01:48:53 -04:00
|
|
|
recover_topic: 55,
|
2018-05-17 12:09:27 -04:00
|
|
|
post_approved: 56,
|
|
|
|
create_badge: 57,
|
|
|
|
change_badge: 58,
|
|
|
|
delete_badge: 59,
|
2018-05-25 11:45:42 -04:00
|
|
|
removed_silence_user: 60,
|
|
|
|
removed_suspend_user: 61,
|
|
|
|
removed_unsilence_user: 62,
|
|
|
|
removed_unsuspend_user: 63,
|
2018-06-08 10:48:26 -04:00
|
|
|
post_rejected: 64,
|
2018-09-18 17:46:45 -04:00
|
|
|
merge_user: 65,
|
2018-11-13 19:32:42 -05:00
|
|
|
entity_export: 66,
|
2019-02-22 04:03:52 -05:00
|
|
|
change_password: 67,
|
2019-03-12 04:16:56 -04:00
|
|
|
topic_timestamps_changed: 68,
|
2019-03-21 11:13:09 -04:00
|
|
|
approve_user: 69,
|
|
|
|
web_hook_create: 70,
|
|
|
|
web_hook_update: 71,
|
2019-03-29 12:05:51 -04:00
|
|
|
web_hook_destroy: 72,
|
|
|
|
embeddable_host_create: 73,
|
|
|
|
embeddable_host_update: 74,
|
2019-04-18 07:36:37 -04:00
|
|
|
embeddable_host_destroy: 75,
|
2019-06-21 13:49:14 -04:00
|
|
|
web_hook_deactivate: 76,
|
2019-07-03 04:18:11 -04:00
|
|
|
change_theme_setting: 77,
|
|
|
|
disable_theme_component: 78,
|
2019-11-05 09:10:23 -05:00
|
|
|
enable_theme_component: 79,
|
|
|
|
api_key_create: 80,
|
|
|
|
api_key_update: 81,
|
|
|
|
api_key_destroy: 82,
|
2019-11-08 00:34:24 -05:00
|
|
|
revoke_title: 83,
|
2019-11-27 16:32:17 -05:00
|
|
|
change_title: 84,
|
2020-04-08 12:52:36 -04:00
|
|
|
override_upload_secure_status: 85,
|
|
|
|
page_published: 86,
|
2020-06-10 12:11:49 -04:00
|
|
|
page_unpublished: 87,
|
|
|
|
add_email: 88,
|
|
|
|
update_email: 89,
|
|
|
|
destroy_email: 90,
|
2018-03-13 15:59:12 -04:00
|
|
|
)
|
2013-04-11 16:04:20 -04:00
|
|
|
end
|
2013-08-09 10:06:02 -04:00
|
|
|
|
2013-09-10 21:21:16 -04:00
|
|
|
# Staff actions is a subset of all actions, used to audit actions taken by staff users.
|
|
|
|
def self.staff_actions
|
2018-03-13 15:59:12 -04:00
|
|
|
@staff_actions ||= [
|
|
|
|
:delete_user,
|
|
|
|
:change_trust_level,
|
|
|
|
:change_site_setting,
|
|
|
|
:change_theme,
|
|
|
|
:delete_theme,
|
|
|
|
:change_site_text,
|
|
|
|
:suspend_user,
|
|
|
|
:unsuspend_user,
|
2018-05-25 11:45:42 -04:00
|
|
|
:removed_suspend_user,
|
|
|
|
:removed_unsuspend_user,
|
2018-03-13 15:59:12 -04:00
|
|
|
:grant_badge,
|
|
|
|
:revoke_badge,
|
|
|
|
:check_email,
|
|
|
|
:delete_post,
|
|
|
|
:delete_topic,
|
|
|
|
:impersonate,
|
|
|
|
:roll_up,
|
|
|
|
:change_username,
|
|
|
|
:custom_staff,
|
|
|
|
:anonymize_user,
|
|
|
|
:reviewed_post,
|
|
|
|
:change_category_settings,
|
|
|
|
:delete_category,
|
|
|
|
:create_category,
|
|
|
|
:silence_user,
|
|
|
|
:unsilence_user,
|
2018-05-25 11:45:42 -04:00
|
|
|
:removed_silence_user,
|
|
|
|
:removed_unsilence_user,
|
2018-03-13 15:59:12 -04:00
|
|
|
:grant_admin,
|
|
|
|
:revoke_admin,
|
|
|
|
:grant_moderation,
|
|
|
|
:revoke_moderation,
|
|
|
|
:backup_create,
|
|
|
|
:revoke_email,
|
|
|
|
:deactivate_user,
|
|
|
|
:lock_trust_level,
|
|
|
|
:unlock_trust_level,
|
|
|
|
:activate_user,
|
|
|
|
:change_readonly_mode,
|
|
|
|
:backup_download,
|
|
|
|
:backup_destroy,
|
|
|
|
:post_locked,
|
|
|
|
:post_unlocked,
|
|
|
|
:check_personal_message,
|
|
|
|
:disabled_second_factor,
|
|
|
|
:post_edit,
|
2018-03-21 00:15:16 -04:00
|
|
|
:topic_published,
|
2018-04-23 01:48:53 -04:00
|
|
|
:recover_topic,
|
2018-05-17 12:09:27 -04:00
|
|
|
:post_approved,
|
|
|
|
:create_badge,
|
|
|
|
:change_badge,
|
|
|
|
:delete_badge,
|
2018-06-08 10:48:26 -04:00
|
|
|
:post_rejected,
|
2018-09-18 17:46:45 -04:00
|
|
|
:merge_user,
|
2018-11-21 21:13:02 -05:00
|
|
|
:entity_export,
|
2019-02-22 04:03:52 -05:00
|
|
|
:change_name,
|
2019-03-12 04:16:56 -04:00
|
|
|
:topic_timestamps_changed,
|
2019-03-21 11:13:09 -04:00
|
|
|
:approve_user,
|
|
|
|
:web_hook_create,
|
|
|
|
:web_hook_update,
|
2019-03-29 12:05:51 -04:00
|
|
|
:web_hook_destroy,
|
2019-04-18 07:36:37 -04:00
|
|
|
:web_hook_deactivate,
|
2019-03-29 12:05:51 -04:00
|
|
|
:embeddable_host_create,
|
|
|
|
:embeddable_host_update,
|
2019-06-21 13:49:14 -04:00
|
|
|
:embeddable_host_destroy,
|
2019-07-03 08:33:25 -04:00
|
|
|
:change_theme_setting,
|
|
|
|
:disable_theme_component,
|
2019-11-05 09:10:23 -05:00
|
|
|
:enable_theme_component,
|
2019-11-08 00:34:24 -05:00
|
|
|
:revoke_title,
|
|
|
|
:change_title,
|
2019-11-05 09:10:23 -05:00
|
|
|
:api_key_create,
|
|
|
|
:api_key_update,
|
2019-11-27 16:32:17 -05:00
|
|
|
:api_key_destroy,
|
2020-04-08 12:52:36 -04:00
|
|
|
:override_upload_secure_status,
|
|
|
|
:page_published,
|
2020-06-10 12:11:49 -04:00
|
|
|
:page_unpublished,
|
|
|
|
:add_email,
|
|
|
|
:update_email,
|
|
|
|
:destroy_email
|
2018-03-13 15:59:12 -04:00
|
|
|
]
|
2013-09-10 21:21:16 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.staff_action_ids
|
|
|
|
@staff_action_ids ||= staff_actions.map { |a| actions[a] }
|
|
|
|
end
|
|
|
|
|
2014-02-28 16:30:45 -05:00
|
|
|
def self.admin_only_action_ids
|
|
|
|
@admin_only_action_ids ||= [actions[:change_site_setting]]
|
|
|
|
end
|
|
|
|
|
2013-08-09 10:06:02 -04:00
|
|
|
def self.with_filters(filters)
|
|
|
|
query = self
|
2015-02-05 14:34:57 -05:00
|
|
|
query = query.where(action: filters[:action_id]) if filters[:action_id].present?
|
|
|
|
query = query.where(custom_type: filters[:custom_type]) if filters[:custom_type].present?
|
|
|
|
|
2013-09-10 21:21:16 -04:00
|
|
|
[:acting_user, :target_user].each do |key|
|
2013-08-09 16:58:57 -04:00
|
|
|
if filters[key] && (obj_id = User.where(username_lower: filters[key].downcase).pluck(:id))
|
2014-08-14 14:20:52 -04:00
|
|
|
query = query.where("#{key}_id = ?", obj_id)
|
2013-08-09 16:58:57 -04:00
|
|
|
end
|
|
|
|
end
|
2013-08-20 13:50:51 -04:00
|
|
|
query = query.where("subject = ?", filters[:subject]) if filters[:subject]
|
2013-08-09 10:06:02 -04:00
|
|
|
query
|
|
|
|
end
|
2013-08-21 10:49:35 -04:00
|
|
|
|
2013-11-01 10:47:03 -04:00
|
|
|
def self.for(user, action_type)
|
|
|
|
self.where(target_user_id: user.id, action: UserHistory.actions[action_type])
|
|
|
|
end
|
|
|
|
|
2013-09-17 14:38:39 -04:00
|
|
|
def self.exists_for_user?(user, action_type, opts = nil)
|
|
|
|
opts = opts || {}
|
|
|
|
result = self.where(target_user_id: user.id, action: UserHistory.actions[action_type])
|
|
|
|
result = result.where(topic_id: opts[:topic_id]) if opts[:topic_id]
|
|
|
|
result.exists?
|
2013-09-12 17:46:43 -04:00
|
|
|
end
|
|
|
|
|
2015-02-05 14:34:57 -05:00
|
|
|
def self.staff_filters
|
2019-03-27 16:29:15 -04:00
|
|
|
[:action_id, :custom_type, :acting_user, :target_user, :subject, :action_name]
|
2015-02-05 14:34:57 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.staff_action_records(viewer, opts = nil)
|
|
|
|
opts ||= {}
|
2019-04-10 08:53:17 -04:00
|
|
|
custom_staff = opts[:action_id].to_i == actions[:custom_staff]
|
|
|
|
|
|
|
|
if custom_staff
|
|
|
|
opts[:custom_type] = opts[:action_name]
|
|
|
|
else
|
|
|
|
opts[:action_id] = self.actions[opts[:action_name].to_sym] if opts[:action_name]
|
|
|
|
end
|
|
|
|
|
2019-06-05 23:02:53 -04:00
|
|
|
query = self
|
|
|
|
.with_filters(opts.slice(*staff_filters))
|
|
|
|
.only_staff_actions
|
|
|
|
.order('id DESC')
|
|
|
|
.includes(:acting_user, :target_user)
|
2014-02-28 16:30:45 -05:00
|
|
|
query = query.where(admin_only: false) unless viewer && viewer.admin?
|
|
|
|
query
|
|
|
|
end
|
|
|
|
|
|
|
|
def set_admin_only
|
|
|
|
self.admin_only = UserHistory.admin_only_action_ids.include?(self.action)
|
|
|
|
self
|
|
|
|
end
|
|
|
|
|
2013-08-21 10:49:35 -04:00
|
|
|
def new_value_is_json?
|
2017-04-12 10:52:52 -04:00
|
|
|
[UserHistory.actions[:change_theme], UserHistory.actions[:delete_theme]].include?(action)
|
2013-08-21 10:49:35 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def previous_value_is_json?
|
|
|
|
new_value_is_json?
|
|
|
|
end
|
2013-04-11 16:04:20 -04:00
|
|
|
end
|
2013-05-23 22:48:32 -04:00
|
|
|
|
|
|
|
# == Schema Information
|
|
|
|
#
|
2013-10-03 23:28:49 -04:00
|
|
|
# Table name: user_histories
|
2013-05-23 22:48:32 -04:00
|
|
|
#
|
|
|
|
# id :integer not null, primary key
|
|
|
|
# action :integer not null
|
2013-10-03 23:28:49 -04:00
|
|
|
# acting_user_id :integer
|
2013-05-23 22:48:32 -04:00
|
|
|
# target_user_id :integer
|
|
|
|
# details :text
|
2014-08-27 01:19:25 -04:00
|
|
|
# created_at :datetime not null
|
|
|
|
# updated_at :datetime not null
|
2019-01-11 14:29:56 -05:00
|
|
|
# context :string
|
|
|
|
# ip_address :string
|
|
|
|
# email :string
|
2013-08-27 20:42:58 -04:00
|
|
|
# subject :text
|
|
|
|
# previous_value :text
|
|
|
|
# new_value :text
|
2013-10-03 23:28:49 -04:00
|
|
|
# topic_id :integer
|
2014-03-20 00:35:51 -04:00
|
|
|
# admin_only :boolean default(FALSE)
|
2014-11-19 22:53:15 -05:00
|
|
|
# post_id :integer
|
2019-01-11 14:29:56 -05:00
|
|
|
# custom_type :string
|
2015-09-17 03:51:32 -04:00
|
|
|
# category_id :integer
|
2013-08-13 16:09:27 -04:00
|
|
|
#
|
|
|
|
# Indexes
|
|
|
|
#
|
2019-01-11 12:19:23 -05:00
|
|
|
# index_user_histories_on_acting_user_id_and_action_and_id (acting_user_id,action,id)
|
2019-01-11 14:29:56 -05:00
|
|
|
# index_user_histories_on_action_and_id (action,id)
|
2019-01-11 12:19:23 -05:00
|
|
|
# index_user_histories_on_category_id (category_id)
|
2019-01-11 14:29:56 -05:00
|
|
|
# index_user_histories_on_subject_and_id (subject,id)
|
|
|
|
# index_user_histories_on_target_user_id_and_id (target_user_id,id)
|
2019-01-11 12:19:23 -05:00
|
|
|
# index_user_histories_on_topic_id_and_target_user_id_and_action (topic_id,target_user_id,action)
|
2013-05-23 22:48:32 -04:00
|
|
|
#
|