mirror of
https://github.com/discourse/discourse.git
synced 2024-11-27 10:50:22 +08:00
098ab29d41
This commit introduces a new plugin API to register a group of stats that will be included in about.json and also conditionally in the site about UI at /about. The usage is like this: ```ruby register_about_stat_group("chat_messages", show_in_ui: true) do { last_day: 1, "7_days" => 10, "30_days" => 100, count: 1000, previous_30_days: 120 } end ``` In reality the stats will be generated any way the implementer chooses within the plugin. The `last_day`, `7_days`, `30_days,` and `count` keys must be present but apart from that additional stats may be added. Only those core 4 stat keys will be shown in the UI, but everything will be shown in about.json. The stat group name is used to prefix the stats in about.json like so: ```json "chat_messages_last_day": 2322, "chat_messages_7_days": 2322, "chat_messages_30_days": 2322, "chat_messages_count": 2322, ``` The `show_in_ui` option (default false) is used to determine whether the group of stats is shown on the site About page in the Site Statistics table. Some stats may be needed purely for reporting purposes and thus do not need to be shown in the UI to admins/users. An extension to the Site serializer, `displayed_about_plugin_stat_groups`, has been added so this can be inspected on the client-side.
167 lines
4.8 KiB
Ruby
167 lines
4.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class About
|
|
cattr_reader :plugin_stat_groups
|
|
|
|
def self.add_plugin_stat_group(prefix, show_in_ui: false, &block)
|
|
@@displayed_plugin_stat_groups << prefix if show_in_ui
|
|
@@plugin_stat_groups[prefix] = block
|
|
end
|
|
|
|
def self.clear_plugin_stat_groups
|
|
@@displayed_plugin_stat_groups = Set.new
|
|
@@plugin_stat_groups = {}
|
|
end
|
|
|
|
def self.displayed_plugin_stat_groups
|
|
@@displayed_plugin_stat_groups.to_a
|
|
end
|
|
|
|
clear_plugin_stat_groups
|
|
|
|
class CategoryMods
|
|
include ActiveModel::Serialization
|
|
attr_reader :category_id, :moderators
|
|
|
|
def initialize(category_id, moderators)
|
|
@category_id = category_id
|
|
@moderators = moderators
|
|
end
|
|
end
|
|
|
|
include ActiveModel::Serialization
|
|
include StatsCacheable
|
|
|
|
attr_accessor :moderators,
|
|
:admins
|
|
|
|
def self.stats_cache_key
|
|
'about-stats'
|
|
end
|
|
|
|
def self.fetch_stats
|
|
About.new.stats
|
|
end
|
|
|
|
def initialize(user = nil)
|
|
@user = user
|
|
end
|
|
|
|
def version
|
|
Discourse::VERSION::STRING
|
|
end
|
|
|
|
def https
|
|
SiteSetting.force_https
|
|
end
|
|
|
|
def title
|
|
SiteSetting.title
|
|
end
|
|
|
|
def locale
|
|
SiteSetting.default_locale
|
|
end
|
|
|
|
def description
|
|
SiteSetting.site_description
|
|
end
|
|
|
|
def moderators
|
|
@moderators ||= User.where(moderator: true, admin: false)
|
|
.human_users
|
|
.order("last_seen_at DESC")
|
|
end
|
|
|
|
def admins
|
|
@admins ||= User.where(admin: true)
|
|
.human_users
|
|
.order("last_seen_at DESC")
|
|
end
|
|
|
|
def stats
|
|
@stats ||= {
|
|
topic_count: Topic.listable_topics.count,
|
|
topics_last_day: Topic.listable_topics.where('created_at > ?', 1.days.ago).count,
|
|
topics_7_days: Topic.listable_topics.where('created_at > ?', 7.days.ago).count,
|
|
topics_30_days: Topic.listable_topics.where('created_at > ?', 30.days.ago).count,
|
|
post_count: Post.count,
|
|
posts_last_day: Post.where('created_at > ?', 1.days.ago).count,
|
|
posts_7_days: Post.where('created_at > ?', 7.days.ago).count,
|
|
posts_30_days: Post.where('created_at > ?', 30.days.ago).count,
|
|
user_count: User.real.count,
|
|
users_last_day: User.real.where('created_at > ?', 1.days.ago).count,
|
|
users_7_days: User.real.where('created_at > ?', 7.days.ago).count,
|
|
users_30_days: User.real.where('created_at > ?', 30.days.ago).count,
|
|
active_users_last_day: User.where('last_seen_at > ?', 1.days.ago).count,
|
|
active_users_7_days: User.where('last_seen_at > ?', 7.days.ago).count,
|
|
active_users_30_days: User.where('last_seen_at > ?', 30.days.ago).count,
|
|
like_count: UserAction.where(action_type: UserAction::LIKE).count,
|
|
likes_last_day: UserAction.where(action_type: UserAction::LIKE).where("created_at > ?", 1.days.ago).count,
|
|
likes_7_days: UserAction.where(action_type: UserAction::LIKE).where("created_at > ?", 7.days.ago).count,
|
|
likes_30_days: UserAction.where(action_type: UserAction::LIKE).where("created_at > ?", 30.days.ago).count
|
|
}.merge(plugin_stats)
|
|
end
|
|
|
|
def plugin_stats
|
|
final_plugin_stats = {}
|
|
@@plugin_stat_groups.each do |plugin_stat_group_name, stat_group|
|
|
begin
|
|
stats = stat_group.call
|
|
rescue StandardError => err
|
|
Discourse.warn_exception(err, message: "Unexpected error when collecting #{plugin_stat_group_name} About stats.")
|
|
next
|
|
end
|
|
|
|
if !stats.key?(:last_day) || !stats.key?("7_days") || !stats.key?("30_days") || !stats.key?(:count)
|
|
Rails.logger.warn("Plugin stat group #{plugin_stat_group_name} for About stats does not have all required keys, skipping.")
|
|
else
|
|
final_plugin_stats.merge!(
|
|
stats.transform_keys do |key|
|
|
"#{plugin_stat_group_name}_#{key}".to_sym
|
|
end
|
|
)
|
|
end
|
|
end
|
|
final_plugin_stats
|
|
end
|
|
|
|
def category_moderators
|
|
allowed_cats = Guardian.new(@user).allowed_category_ids
|
|
return [] if allowed_cats.blank?
|
|
|
|
cats_with_mods = Category.where.not(reviewable_by_group_id: nil).pluck(:id)
|
|
|
|
category_ids = cats_with_mods & allowed_cats
|
|
return [] if category_ids.blank?
|
|
|
|
per_cat_limit = category_mods_limit / category_ids.size
|
|
per_cat_limit = 1 if per_cat_limit < 1
|
|
|
|
results = DB.query(<<~SQL, category_ids: category_ids)
|
|
SELECT c.id category_id
|
|
, (ARRAY_AGG(u.id ORDER BY u.last_seen_at DESC))[:#{per_cat_limit}] user_ids
|
|
FROM categories c
|
|
JOIN group_users gu ON gu.group_id = c.reviewable_by_group_id
|
|
JOIN users u ON u.id = gu.user_id
|
|
WHERE c.id IN (:category_ids)
|
|
GROUP BY c.id
|
|
ORDER BY c.position
|
|
SQL
|
|
|
|
mods = User.where(id: results.map(&:user_ids).flatten.uniq).index_by(&:id)
|
|
|
|
results.map do |row|
|
|
CategoryMods.new(row.category_id, mods.values_at(*row.user_ids))
|
|
end
|
|
end
|
|
|
|
def category_mods_limit
|
|
@category_mods_limit || 100
|
|
end
|
|
|
|
def category_mods_limit=(number)
|
|
@category_mods_limit = number
|
|
end
|
|
end
|