FEATURE: allow plugins to add custom admin reports

This commit is contained in:
Régis Hanol 2015-06-25 02:42:08 +02:00
parent 28a8b886c0
commit 18f887772d
5 changed files with 58 additions and 46 deletions

View File

@ -12,8 +12,9 @@ export default Discourse.Route.extend({
if (versionChecks) {
c.set('versionCheck', Discourse.VersionCheck.create(d.version_check));
}
_.each(d.reports,function(report){
c.set(report.type, Discourse.Report.create(report));
['global_reports', 'page_view_reports', 'private_message_reports', 'http_reports', 'user_reports'].forEach(name => {
c.set(name, d[name].map(r => Discourse.Report.create(r)));
});
var topReferrers = d.top_referrers;

View File

@ -17,7 +17,9 @@
</thead>
<tbody>
{{#unless loading}}
{{admin-report-trust-level-counts report=users_by_trust_level}}
{{#each r in user_reports}}
{{admin-report-trust-level-counts report=r}}
{{/each}}
{{/unless}}
</tbody>
</table>
@ -26,15 +28,15 @@
<div class="dashboard-stats totals">
<table>
<tr>
<td class="title"><i class='fa fa-shield'></i> {{i18n 'admin.dashboard.admins'}}</td>
<td class="title">{{fa-icon "shield"}} {{i18n 'admin.dashboard.admins'}}</td>
<td class="value">{{#link-to 'adminUsersList.show' 'admins'}}{{admins}}{{/link-to}}</td>
<td class="title"><i class='fa fa-ban'></i> {{i18n 'admin.dashboard.suspended'}}</td>
<td class="title">{{fa-icon "ban"}} {{i18n 'admin.dashboard.suspended'}}</td>
<td class="value">{{#link-to 'adminUsersList.show' 'suspended'}}{{suspended}}{{/link-to}}</td>
</tr>
<tr>
<td class="title"><i class='fa fa-shield'></i> {{i18n 'admin.dashboard.moderators'}}</td>
<td class="title">{{fa-icon "shield"}} {{i18n 'admin.dashboard.moderators'}}</td>
<td class="value">{{#link-to 'adminUsersList.show' 'moderators'}}{{moderators}}{{/link-to}}</td>
<td class="title"><i class='fa fa-ban'></i> {{i18n 'admin.dashboard.blocked'}}</td>
<td class="title">{{fa-icon "ban"}} {{i18n 'admin.dashboard.blocked'}}</td>
<td class="value">{{#link-to 'adminUsersList.show' 'blocked'}}{{blocked}}{{/link-to}}</td>
</tr>
</table>
@ -54,16 +56,9 @@
</thead>
<tbody>
{{#unless loading}}
{{admin-report-counts report=visits}}
{{admin-report-counts report=signups}}
{{admin-report-counts report=topics}}
{{admin-report-counts report=posts}}
{{admin-report-counts report=time_to_first_response}}
{{admin-report-counts report=topics_with_no_response}}
{{admin-report-counts report=likes}}
{{admin-report-counts report=flags}}
{{admin-report-counts report=bookmarks}}
{{admin-report-counts report=emails}}
{{#each r in global_reports}}
{{admin-report-counts report=r}}
{{/each}}
{{/unless}}
</tbody>
</table>
@ -83,21 +78,19 @@
</thead>
<tbody>
{{#unless loading}}
{{admin-report-counts report=page_view_anon_reqs}}
{{admin-report-counts report=page_view_logged_in_reqs}}
{{admin-report-counts report=page_view_crawler_reqs}}
{{admin-report-counts report=page_view_total_reqs}}
{{#each r in page_view_reports}}
{{admin-report-counts report=r}}
{{/each}}
{{/unless}}
</tbody>
</table>
</div>
<div class="dashboard-stats">
<table class="table table-condensed table-hover">
<thead>
<tr>
<th class="title" title="{{i18n 'admin.dashboard.private_messages_title'}}"><i class="fa fa-envelope"></i> {{i18n 'admin.dashboard.private_messages_short'}}</th>
<th class="title" title="{{i18n 'admin.dashboard.private_messages_title'}}">{{fa-icon "enveloppe"}} {{i18n 'admin.dashboard.private_messages_short'}}</th>
<th>{{i18n 'admin.dashboard.reports.today'}}</th>
<th>{{i18n 'admin.dashboard.reports.yesterday'}}</th>
<th>{{i18n 'admin.dashboard.reports.last_7_days'}}</th>
@ -107,11 +100,9 @@
</thead>
<tbody>
{{#unless loading}}
{{admin-report-counts report=user_to_user_private_messages}}
{{admin-report-counts report=system_private_messages}}
{{admin-report-counts report=notify_moderators_private_messages}}
{{admin-report-counts report=notify_user_private_messages}}
{{admin-report-counts report=moderator_warning_private_messages}}
{{#each r in private_message_reports}}
{{admin-report-counts report=r}}
{{/each}}
{{/unless}}
</tbody>
</table>
@ -156,12 +147,9 @@
</thead>
<tbody>
{{#unless loading}}
{{admin-report-counts report=http_2xx_reqs}}
{{admin-report-counts report=http_3xx_reqs}}
{{admin-report-counts report=http_4xx_reqs}}
{{admin-report-counts report=http_5xx_reqs}}
{{admin-report-counts report=http_background_reqs}}
{{admin-report-counts report=http_total_reqs}}
{{#each r in http_reports}}
{{admin-report-counts report=r}}
{{/each}}
{{/unless}}
</tbody>
</table>
@ -178,7 +166,7 @@
{{#if foundProblems}}
<div class="dashboard-stats detected-problems">
<div class="look-here"><i class="fa fa-exclamation-triangle"></i></div>
<div class="look-here">{{fa-icon "exclamation-triangle"}}</div>
<div class="problem-messages">
<p {{bind-attr class="loadingProblems:invisible"}}>
{{i18n 'admin.dashboard.problems_found'}}

View File

@ -3,13 +3,13 @@ module Jobs
every 30.minutes
def execute(args)
stats_json = AdminDashboardData.fetch_stats.as_json
stats = AdminDashboardData.fetch_stats.as_json
# Add some extra time to the expiry so that the next job run has plenty of time to
# finish before previous cached value expires.
$redis.setex AdminDashboardData.stats_cache_key, (AdminDashboardData.recalculate_interval + 5).minutes, stats_json.to_json
$redis.setex AdminDashboardData.stats_cache_key, (AdminDashboardData.recalculate_interval + 5).minutes, stats.to_json
stats_json
stats
end
end

View File

@ -2,25 +2,34 @@ require_dependency 'mem_info'
class AdminDashboardData
REPORTS = [
GLOBAL_REPORTS ||= [
'visits',
'signups',
'topics',
'posts',
'time_to_first_response',
'topics_with_no_response',
'flags',
'users_by_trust_level',
'likes',
'flags',
'bookmarks',
'emails',
]
PAGE_VIEW_REPORTS ||= ['page_view_total_reqs'] + ApplicationRequest.req_types.keys.select { |r| r =~ /^page_view_/ }.map { |r| r + "_reqs" }
PRIVATE_MESSAGE_REPORTS ||= [
'user_to_user_private_messages',
'system_private_messages',
'moderator_warning_private_messages',
'notify_moderators_private_messages',
'notify_user_private_messages',
'page_view_total_reqs'
] + ApplicationRequest.req_types.keys.map{|r| r + "_reqs"}
'moderator_warning_private_messages',
]
HTTP_REPORTS ||= ApplicationRequest.req_types.keys.select { |r| r =~ /^http_/ }.map { |r| r + "_reqs" }.sort
USER_REPORTS ||= ['users_by_trust_level']
# TODO: MOBILE_REPORTS
def problems
[ rails_env_check,
@ -50,11 +59,13 @@ class AdminDashboardData
def self.fetch_stats
AdminDashboardData.new
end
def self.fetch_cached_stats
# The DashboardStats job is responsible for generating and caching this.
stats = $redis.get(stats_cache_key)
stats ? JSON.parse(stats) : nil
end
def self.stats_cache_key
'dash-stats'
end
@ -65,7 +76,11 @@ class AdminDashboardData
def as_json(_options = nil)
@json ||= {
reports: REPORTS.map { |type| Report.find(type).as_json },
global_reports: AdminDashboardData.reports(GLOBAL_REPORTS),
page_view_reports: AdminDashboardData.reports(PAGE_VIEW_REPORTS),
private_message_reports: AdminDashboardData.reports(PRIVATE_MESSAGE_REPORTS),
http_reports: AdminDashboardData.reports(HTTP_REPORTS),
user_reports: AdminDashboardData.reports(USER_REPORTS),
admins: User.admins.count,
moderators: User.moderators.count,
suspended: User.suspended.count,
@ -77,8 +92,12 @@ class AdminDashboardData
}
end
def self.reports(source)
source.map { |type| Report.find(type).as_json }
end
# Could be configurable, multisite need to support it.
def self.recalculate_interval
# Could be configurable, multisite need to support it.
30 # minutes
end

View File

@ -29,6 +29,10 @@ class Report
}
end
def Report.add_report(name, &block)
singleton_class.instance_eval { define_method("report_#{name}", &block) }
end
def self.find(type, opts=nil)
opts ||= {}
# Load the report