Add /user_actions page.
Add a /user_actions page. This page shows you a global timeline of (almost) all activity on the site, including uploads, comments, votes, edits, forum posts, and so on. The main things it doesn't include are post edits, pool edits, and favorites (posts and pools live in a separate database, and favorites don't have the timestamps we need for ordering). This page is useful for moderation purposes because it lets you see a history of almost all of a user's activity on a single page. Currently this page is mod-only. In the future it will be open to all users, so you can view the history of your own site activity, or the activity of others.
This commit is contained in:
@@ -234,6 +234,10 @@ class ApplicationRecord < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
def revised?
|
||||
updated_at > created_at
|
||||
end
|
||||
|
||||
def warnings
|
||||
@warnings ||= ActiveModel::Errors.new(self)
|
||||
end
|
||||
|
||||
@@ -69,6 +69,10 @@ class Ban < ApplicationRecord
|
||||
ApplicationController.helpers.humanized_duration(duration)
|
||||
end
|
||||
|
||||
def forever?
|
||||
duration.present? && duration >= 100.years
|
||||
end
|
||||
|
||||
def expired?
|
||||
persisted? && expires_at < Time.zone.now
|
||||
end
|
||||
|
||||
@@ -76,7 +76,11 @@ class Dmail < ApplicationRecord
|
||||
|
||||
module SearchMethods
|
||||
def visible(user)
|
||||
where(owner: user)
|
||||
if user.is_anonymous?
|
||||
none
|
||||
else
|
||||
where(owner: user)
|
||||
end
|
||||
end
|
||||
|
||||
def sent_by(user)
|
||||
|
||||
@@ -8,7 +8,7 @@ class Favorite < ApplicationRecord
|
||||
after_create :upvote_post_on_create
|
||||
after_destroy :unvote_post_on_destroy
|
||||
|
||||
scope :public_favorites, -> { where(user: User.has_public_favorites) }
|
||||
scope :public_favorites, -> { where.not(user: User.has_private_favorites) }
|
||||
|
||||
def self.visible(user)
|
||||
if user.is_admin?
|
||||
|
||||
@@ -17,6 +17,9 @@ class FavoriteGroup < ApplicationRecord
|
||||
|
||||
array_attribute :post_ids, parse: /\d+/, cast: :to_i
|
||||
|
||||
scope :is_public, -> { where(is_public: true) }
|
||||
scope :is_private, -> { where(is_public: false) }
|
||||
|
||||
module SearchMethods
|
||||
def for_post(post_id)
|
||||
where_array_includes_any(:post_ids, [post_id])
|
||||
@@ -29,7 +32,13 @@ class FavoriteGroup < ApplicationRecord
|
||||
end
|
||||
|
||||
def visible(user)
|
||||
where(is_public: true).or(where(creator_id: user.id))
|
||||
if user.is_owner?
|
||||
all
|
||||
elsif user.is_anonymous?
|
||||
is_public
|
||||
else
|
||||
is_public.or(where(creator: user))
|
||||
end
|
||||
end
|
||||
|
||||
def search(params)
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
class ForumPostVote < ApplicationRecord
|
||||
belongs_to :creator, class_name: "User"
|
||||
belongs_to :forum_post
|
||||
belongs_to :bulk_update_request, primary_key: :forum_post_id, foreign_key: :forum_post_id, optional: true
|
||||
|
||||
validates :creator_id, uniqueness: {scope: :forum_post_id}
|
||||
validates :score, inclusion: {in: [-1, 0, 1]}
|
||||
|
||||
|
||||
@@ -35,8 +35,10 @@ class ModerationReport < ApplicationRecord
|
||||
def self.visible(user)
|
||||
if user.is_moderator?
|
||||
all
|
||||
else
|
||||
elsif !user.is_anonymous?
|
||||
where(creator: user)
|
||||
else
|
||||
none
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ class PostVote < ApplicationRecord
|
||||
|
||||
scope :positive, -> { where("post_votes.score > 0") }
|
||||
scope :negative, -> { where("post_votes.score < 0") }
|
||||
scope :public_votes, -> { active.positive.where(user: User.has_public_favorites) }
|
||||
scope :public_votes, -> { active.positive.where.not(user: User.has_private_favorites) }
|
||||
|
||||
deletable
|
||||
|
||||
|
||||
@@ -18,7 +18,11 @@ class SavedSearch < ApplicationRecord
|
||||
scope :has_tag, ->(name) { where_regex(:query, "(^| )[~-]?#{Regexp.escape(name)}( |$)", flags: "i") }
|
||||
|
||||
def self.visible(user)
|
||||
where(user: user)
|
||||
if user.is_anonymous?
|
||||
none
|
||||
else
|
||||
where(user: user)
|
||||
end
|
||||
end
|
||||
|
||||
concerning :Redis do
|
||||
|
||||
@@ -39,4 +39,8 @@ class TagVersion < ApplicationRecord
|
||||
def category_name
|
||||
TagCategory.reverse_mapping[category].capitalize
|
||||
end
|
||||
|
||||
def pretty_name
|
||||
name.tr("_", " ")
|
||||
end
|
||||
end
|
||||
|
||||
122
app/models/user_action.rb
Normal file
122
app/models/user_action.rb
Normal file
@@ -0,0 +1,122 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class UserAction < ApplicationRecord
|
||||
belongs_to :model, polymorphic: true
|
||||
belongs_to :user
|
||||
|
||||
attribute :model_type, :string
|
||||
attribute :model_id, :integer
|
||||
attribute :user_id, :integer
|
||||
attribute :event_type, :string
|
||||
attribute :event_at, :time
|
||||
|
||||
def self.model_types
|
||||
%w[ArtistVersion ArtistCommentaryVersion Ban BulkUpdateRequest Comment
|
||||
CommentVote Dmail FavoriteGroup ForumPost ForumPostVote ForumTopic
|
||||
ModAction ModerationReport NoteVersion Post PostAppeal PostApproval
|
||||
PostDisapproval PostFlag PostReplacement PostVote SavedSearch TagAlias
|
||||
TagImplication TagVersion Upload User UserEvent UserFeedback UserUpgrade
|
||||
UserNameChangeRequest WikiPageVersion]
|
||||
end
|
||||
|
||||
def self.for_user(user)
|
||||
sql = <<~SQL.squish
|
||||
(#{ArtistVersion.visible(user).select("'ArtistVersion'::character varying AS model_type, id AS model_id, updater_id AS user_id, 'create'::character varying AS event_type, created_at AS event_at").to_sql})
|
||||
UNION ALL
|
||||
(#{ArtistCommentaryVersion.visible(user).select("'ArtistCommentaryVersion', id, updater_id, 'create', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{Ban.visible(user).select("'Ban', id, user_id, 'subject', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{BulkUpdateRequest.visible(user).select("'BulkUpdateRequest', id, user_id, 'create', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{Comment.visible(user).select("'Comment', id, creator_id, 'create', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{CommentVote.visible(user).select("'CommentVote', id, user_id, 'create', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{Dmail.visible(user).sent.select("'Dmail', id, from_id, 'create', created_at").order(created_at: :desc).to_sql})
|
||||
UNION ALL
|
||||
(#{FavoriteGroup.visible(user).select("'FavoriteGroup', id, creator_id, 'create', created_at").order(created_at: :desc).to_sql})
|
||||
UNION ALL
|
||||
(#{ForumPost.visible(user).select("'ForumPost', id, creator_id, 'create', created_at").order(created_at: :desc).to_sql})
|
||||
UNION ALL
|
||||
(#{ForumPostVote.visible(user).select("'ForumPostVote', id, creator_id, 'create', created_at").order(created_at: :desc).to_sql})
|
||||
UNION ALL
|
||||
(#{ForumTopic.visible(user).select("'ForumTopic', id, creator_id, 'create', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{ModAction.visible(user).select("'ModAction', id, creator_id, 'create', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{ModerationReport.visible(user).select("'ModerationReport', id, creator_id, 'create', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{NoteVersion.visible(user).select("'NoteVersion', id, updater_id, 'create', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{Post.visible(user).select("'Post', id, uploader_id, 'create', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{PostAppeal.visible(user).select("'PostAppeal', id, creator_id, 'create', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{PostApproval.visible(user).select("'PostApproval', id, user_id, 'create', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{PostDisapproval.visible(user).select("'PostDisapproval', id, user_id, 'create', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{PostFlag.visible(user).select("'PostFlag', id, creator_id, 'create', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{PostReplacement.visible(user).select("'PostReplacement', id, creator_id, 'create', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{PostVote.visible(user).select("'PostVote', id, user_id, 'create', created_at").order(created_at: :desc).to_sql})
|
||||
UNION ALL
|
||||
(#{SavedSearch.visible(user).select("'SavedSearch', id, user_id, 'create', created_at").order(created_at: :desc).to_sql})
|
||||
UNION ALL
|
||||
(#{TagAlias.visible(user).select("'TagAlias', id, creator_id, 'create', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{TagImplication.visible(user).select("'TagImplication', id, creator_id, 'create', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{TagVersion.visible(user).select("'TagVersion', id, updater_id, 'create', created_at").where("updater_id IS NOT NULL").order(created_at: :desc).to_sql})
|
||||
UNION ALL
|
||||
(#{Upload.visible(user).select("'Upload', id, uploader_id, 'create', created_at").order(created_at: :desc).to_sql})
|
||||
UNION ALL
|
||||
(#{User.visible(user).select("'User', id, id, 'create', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{UserEvent.visible(user).select("'UserEvent', id, user_id, 'create', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{UserFeedback.visible(user).select("'UserFeedback', id, creator_id, 'create', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{UserFeedback.visible(user).select("'UserFeedback', id, user_id, 'subject', created_at").to_sql})
|
||||
UNION ALL (
|
||||
(#{UserUpgrade.visible(user).select("'UserUpgrade', id, purchaser_id, 'create', created_at").where(status: [:complete, :refunded]).order(created_at: :desc).to_sql})
|
||||
) UNION ALL
|
||||
(#{UserNameChangeRequest.visible(user).select("'UserNameChangeRequest', id, user_id, 'create', created_at").to_sql})
|
||||
UNION ALL
|
||||
(#{WikiPageVersion.visible(user).select("'WikiPageVersion', id, updater_id, 'create', created_at").to_sql})
|
||||
SQL
|
||||
|
||||
from("(#{sql}) user_actions")
|
||||
end
|
||||
|
||||
def self.visible(user)
|
||||
all
|
||||
end
|
||||
|
||||
def self.search(params)
|
||||
q = search_attributes(params, :event_type, :user, :model)
|
||||
|
||||
case params[:order]
|
||||
when "event_at_asc"
|
||||
q = q.order(event_at: :asc, model_id: :asc)
|
||||
else
|
||||
q = q.apply_default_order(params)
|
||||
end
|
||||
|
||||
q
|
||||
end
|
||||
|
||||
def self.default_order
|
||||
order(event_at: :desc, model_id: :desc)
|
||||
end
|
||||
|
||||
def self.available_includes
|
||||
[:user, :model]
|
||||
end
|
||||
|
||||
def readonly?
|
||||
true
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user