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) { if (versionChecks) {
c.set('versionCheck', Discourse.VersionCheck.create(d.version_check)); 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; var topReferrers = d.top_referrers;

View File

@ -17,7 +17,9 @@
</thead> </thead>
<tbody> <tbody>
{{#unless loading}} {{#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}} {{/unless}}
</tbody> </tbody>
</table> </table>
@ -26,15 +28,15 @@
<div class="dashboard-stats totals"> <div class="dashboard-stats totals">
<table> <table>
<tr> <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="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> <td class="value">{{#link-to 'adminUsersList.show' 'suspended'}}{{suspended}}{{/link-to}}</td>
</tr> </tr>
<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="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> <td class="value">{{#link-to 'adminUsersList.show' 'blocked'}}{{blocked}}{{/link-to}}</td>
</tr> </tr>
</table> </table>
@ -54,16 +56,9 @@
</thead> </thead>
<tbody> <tbody>
{{#unless loading}} {{#unless loading}}
{{admin-report-counts report=visits}} {{#each r in global_reports}}
{{admin-report-counts report=signups}} {{admin-report-counts report=r}}
{{admin-report-counts report=topics}} {{/each}}
{{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}}
{{/unless}} {{/unless}}
</tbody> </tbody>
</table> </table>
@ -83,21 +78,19 @@
</thead> </thead>
<tbody> <tbody>
{{#unless loading}} {{#unless loading}}
{{admin-report-counts report=page_view_anon_reqs}} {{#each r in page_view_reports}}
{{admin-report-counts report=page_view_logged_in_reqs}} {{admin-report-counts report=r}}
{{admin-report-counts report=page_view_crawler_reqs}} {{/each}}
{{admin-report-counts report=page_view_total_reqs}}
{{/unless}} {{/unless}}
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="dashboard-stats"> <div class="dashboard-stats">
<table class="table table-condensed table-hover"> <table class="table table-condensed table-hover">
<thead> <thead>
<tr> <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.today'}}</th>
<th>{{i18n 'admin.dashboard.reports.yesterday'}}</th> <th>{{i18n 'admin.dashboard.reports.yesterday'}}</th>
<th>{{i18n 'admin.dashboard.reports.last_7_days'}}</th> <th>{{i18n 'admin.dashboard.reports.last_7_days'}}</th>
@ -107,11 +100,9 @@
</thead> </thead>
<tbody> <tbody>
{{#unless loading}} {{#unless loading}}
{{admin-report-counts report=user_to_user_private_messages}} {{#each r in private_message_reports}}
{{admin-report-counts report=system_private_messages}} {{admin-report-counts report=r}}
{{admin-report-counts report=notify_moderators_private_messages}} {{/each}}
{{admin-report-counts report=notify_user_private_messages}}
{{admin-report-counts report=moderator_warning_private_messages}}
{{/unless}} {{/unless}}
</tbody> </tbody>
</table> </table>
@ -156,12 +147,9 @@
</thead> </thead>
<tbody> <tbody>
{{#unless loading}} {{#unless loading}}
{{admin-report-counts report=http_2xx_reqs}} {{#each r in http_reports}}
{{admin-report-counts report=http_3xx_reqs}} {{admin-report-counts report=r}}
{{admin-report-counts report=http_4xx_reqs}} {{/each}}
{{admin-report-counts report=http_5xx_reqs}}
{{admin-report-counts report=http_background_reqs}}
{{admin-report-counts report=http_total_reqs}}
{{/unless}} {{/unless}}
</tbody> </tbody>
</table> </table>
@ -178,7 +166,7 @@
{{#if foundProblems}} {{#if foundProblems}}
<div class="dashboard-stats detected-problems"> <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"> <div class="problem-messages">
<p {{bind-attr class="loadingProblems:invisible"}}> <p {{bind-attr class="loadingProblems:invisible"}}>
{{i18n 'admin.dashboard.problems_found'}} {{i18n 'admin.dashboard.problems_found'}}

View File

@ -3,13 +3,13 @@ module Jobs
every 30.minutes every 30.minutes
def execute(args) 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 # Add some extra time to the expiry so that the next job run has plenty of time to
# finish before previous cached value expires. # 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
end end

View File

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

View File

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