FEATURE: category dropdown in admin reports
This commit is contained in:
parent
80f258e51c
commit
f18098fd9b
|
@ -4,24 +4,26 @@ export default Ember.ObjectController.extend({
|
||||||
viewingBarChart: Em.computed.equal('viewMode', 'barChart'),
|
viewingBarChart: Em.computed.equal('viewMode', 'barChart'),
|
||||||
startDate: null,
|
startDate: null,
|
||||||
endDate: null,
|
endDate: null,
|
||||||
|
categoryId: null,
|
||||||
refreshing: false,
|
refreshing: false,
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
refreshReport: function() {
|
refreshReport() {
|
||||||
var self = this;
|
this.set("refreshing", true);
|
||||||
this.set('refreshing', true);
|
Discourse.Report.find(
|
||||||
Discourse.Report.find(this.get('type'), this.get('startDate'), this.get('endDate')).then(function(r) {
|
this.get("type"),
|
||||||
self.set('model', r);
|
this.get("startDate"),
|
||||||
}).finally(function() {
|
this.get("endDate"),
|
||||||
self.set('refreshing', false);
|
this.get("categoryId")
|
||||||
});
|
).then(m => this.set("model", m)
|
||||||
|
).finally(() => this.set("refreshing", false));
|
||||||
},
|
},
|
||||||
|
|
||||||
viewAsTable: function() {
|
viewAsTable() {
|
||||||
this.set('viewMode', 'table');
|
this.set('viewMode', 'table');
|
||||||
},
|
},
|
||||||
|
|
||||||
viewAsBarChart: function() {
|
viewAsBarChart() {
|
||||||
this.set('viewMode', 'barChart');
|
this.set('viewMode', 'barChart');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,23 +142,24 @@ const Report = Discourse.Model.extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
Report.reopenClass({
|
Report.reopenClass({
|
||||||
find: function(type, startDate, endDate) {
|
|
||||||
|
|
||||||
return Discourse.ajax("/admin/reports/" + type, {data: {
|
find(type, startDate, endDate, categoryId) {
|
||||||
start_date: startDate,
|
return Discourse.ajax("/admin/reports/" + type, {
|
||||||
end_date: endDate
|
data: {
|
||||||
}}).then(function (json) {
|
start_date: startDate,
|
||||||
|
end_date: endDate,
|
||||||
|
category_id: categoryId
|
||||||
|
}
|
||||||
|
}).then(json => {
|
||||||
// Add a percent field to each tuple
|
// Add a percent field to each tuple
|
||||||
var maxY = 0;
|
let maxY = 0;
|
||||||
json.report.data.forEach(function (row) {
|
json.report.data.forEach(row => {
|
||||||
if (row.y > maxY) maxY = row.y;
|
if (row.y > maxY) maxY = row.y;
|
||||||
});
|
});
|
||||||
if (maxY > 0) {
|
if (maxY > 0) {
|
||||||
json.report.data.forEach(function (row) {
|
json.report.data.forEach(row => row.percentage = Math.round((row.y / maxY) * 100));
|
||||||
row.percentage = Math.round((row.y / maxY) * 100);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
var model = Discourse.Report.create({type: type});
|
const model = Discourse.Report.create({ type: type });
|
||||||
model.setProperties(json.report);
|
model.setProperties(json.report);
|
||||||
return model;
|
return model;
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
<div>
|
<div>
|
||||||
{{i18n 'admin.dashboard.reports.start_date'}} {{input type="date" value=startDate}}
|
{{i18n 'admin.dashboard.reports.start_date'}} {{input type="date" value=startDate}}
|
||||||
{{i18n 'admin.dashboard.reports.end_date'}} {{input type="date" value=endDate}}
|
{{i18n 'admin.dashboard.reports.end_date'}} {{input type="date" value=endDate}}
|
||||||
|
{{category-chooser valueAttribute="id" value=categoryId source=categoryId}}
|
||||||
{{d-button action="refreshReport" class="btn-primary" label="admin.dashboard.reports.refresh_report" icon="refresh"}}
|
{{d-button action="refreshReport" class="btn-primary" label="admin.dashboard.reports.refresh_report" icon="refresh"}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,12 @@ class Admin::ReportsController < Admin::AdminController
|
||||||
end_date = start_date + 1.month
|
end_date = start_date + 1.month
|
||||||
end_date = Time.parse(params[:end_date]) if params[:end_date].present?
|
end_date = Time.parse(params[:end_date]) if params[:end_date].present?
|
||||||
|
|
||||||
report = Report.find(report_type, {start_date: start_date, end_date: end_date})
|
category_id = if params.has_key?(:category_id)
|
||||||
|
params[:category_id].blank? ? SiteSetting.uncategorized_category_id : params[:category_id].to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
report = Report.find(report_type, start_date: start_date, end_date: end_date, category_id: category_id)
|
||||||
|
|
||||||
raise Discourse::NotFound if report.blank?
|
raise Discourse::NotFound if report.blank?
|
||||||
|
|
||||||
render_json_dump(report: report)
|
render_json_dump(report: report)
|
||||||
|
|
|
@ -493,15 +493,16 @@ class Post < ActiveRecord::Base
|
||||||
Jobs.enqueue(:process_post, args)
|
Jobs.enqueue(:process_post, args)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.public_posts_count_per_day(start_date, end_date)
|
def self.public_posts_count_per_day(start_date, end_date, category_id=nil)
|
||||||
public_posts.where('posts.created_at >= ? AND posts.created_at <= ?', start_date, end_date).group('date(posts.created_at)').order('date(posts.created_at)').count
|
result = public_posts.where('posts.created_at >= ? AND posts.created_at <= ?', start_date, end_date)
|
||||||
|
result = result.where('topics.category_id = ?', category_id) if category_id
|
||||||
|
result.group('date(posts.created_at)').order('date(posts.created_at)').count
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.private_messages_count_per_day(since_days_ago, topic_subtype)
|
def self.private_messages_count_per_day(since_days_ago, topic_subtype)
|
||||||
private_posts.with_topic_subtype(topic_subtype).where('posts.created_at > ?', since_days_ago.days.ago).group('date(posts.created_at)').order('date(posts.created_at)').count
|
private_posts.with_topic_subtype(topic_subtype).where('posts.created_at > ?', since_days_ago.days.ago).group('date(posts.created_at)').order('date(posts.created_at)').count
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def reply_history(max_replies=100)
|
def reply_history(max_replies=100)
|
||||||
post_ids = Post.exec_sql("WITH RECURSIVE breadcrumb(id, reply_to_post_number) AS (
|
post_ids = Post.exec_sql("WITH RECURSIVE breadcrumb(id, reply_to_post_number) AS (
|
||||||
SELECT p.id, p.reply_to_post_number FROM posts AS p
|
SELECT p.id, p.reply_to_post_number FROM posts AS p
|
||||||
|
|
|
@ -39,11 +39,13 @@ class PostAction < ActiveRecord::Base
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.flag_count_by_date(start_date, end_date)
|
def self.flag_count_by_date(start_date, end_date, category_id=nil)
|
||||||
where('created_at >= ? and created_at <= ?', start_date, end_date)
|
result = where('post_actions.created_at >= ? AND post_actions.created_at <= ?', start_date, end_date)
|
||||||
.where(post_action_type_id: PostActionType.flag_types.values)
|
result = result.where(post_action_type_id: PostActionType.flag_types.values)
|
||||||
.group('date(created_at)').order('date(created_at)')
|
result = result.joins(post: :topic).where("topics.category_id = ?", category_id) if category_id
|
||||||
.count
|
result.group('date(post_actions.created_at)')
|
||||||
|
.order('date(post_actions.created_at)')
|
||||||
|
.count
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.update_flagged_posts_count
|
def self.update_flagged_posts_count
|
||||||
|
@ -122,12 +124,15 @@ SQL
|
||||||
user_actions
|
user_actions
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.count_per_day_for_type(post_action_type, since_days_ago=30)
|
def self.count_per_day_for_type(post_action_type, opts=nil)
|
||||||
unscoped.where(post_action_type_id: post_action_type)
|
opts ||= {}
|
||||||
.where('created_at >= ?', since_days_ago.days.ago)
|
opts[:since_days_ago] ||= 30
|
||||||
.group('date(created_at)')
|
result = unscoped.where(post_action_type_id: post_action_type)
|
||||||
.order('date(created_at)')
|
result = result.where('post_actions.created_at >= ?', opts[:since_days_ago].days.ago)
|
||||||
.count
|
result = result.joins(post: :topic).where('topics.category_id = ?', opts[:category_id]) if opts[:category_id]
|
||||||
|
result.group('date(post_actions.created_at)')
|
||||||
|
.order('date(post_actions.created_at)')
|
||||||
|
.count
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.agree_flags!(post, moderator, delete_post=false)
|
def self.agree_flags!(post, moderator, delete_post=false)
|
||||||
|
|
|
@ -2,7 +2,7 @@ require_dependency 'topic_subtype'
|
||||||
|
|
||||||
class Report
|
class Report
|
||||||
|
|
||||||
attr_accessor :type, :data, :total, :prev30Days, :start_date, :end_date
|
attr_accessor :type, :data, :total, :prev30Days, :start_date, :end_date, :category_id
|
||||||
|
|
||||||
def self.default_days
|
def self.default_days
|
||||||
30
|
30
|
||||||
|
@ -10,14 +10,11 @@ class Report
|
||||||
|
|
||||||
def initialize(type)
|
def initialize(type)
|
||||||
@type = type
|
@type = type
|
||||||
@data = nil
|
|
||||||
@total = nil
|
|
||||||
@prev30Days = nil
|
|
||||||
@start_date ||= 1.month.ago.beginning_of_day
|
@start_date ||= 1.month.ago.beginning_of_day
|
||||||
@end_date ||= Time.zone.now.end_of_day
|
@end_date ||= Time.zone.now.end_of_day
|
||||||
end
|
end
|
||||||
|
|
||||||
def as_json(options = nil)
|
def as_json(options=nil)
|
||||||
{
|
{
|
||||||
type: type,
|
type: type,
|
||||||
title: I18n.t("reports.#{type}.title"),
|
title: I18n.t("reports.#{type}.title"),
|
||||||
|
@ -27,6 +24,7 @@ class Report
|
||||||
total: total,
|
total: total,
|
||||||
start_date: start_date,
|
start_date: start_date,
|
||||||
end_date: end_date,
|
end_date: end_date,
|
||||||
|
category_id: category_id,
|
||||||
prev30Days: self.prev30Days
|
prev30Days: self.prev30Days
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -37,6 +35,7 @@ class Report
|
||||||
report = Report.new(type)
|
report = Report.new(type)
|
||||||
report.start_date = opts[:start_date] if opts[:start_date]
|
report.start_date = opts[:start_date] if opts[:start_date]
|
||||||
report.end_date = opts[:end_date] if opts[:end_date]
|
report.end_date = opts[:end_date] if opts[:end_date]
|
||||||
|
report.category_id = opts[:category_id] if opts[:category_id]
|
||||||
report_method = :"report_#{type}"
|
report_method = :"report_#{type}"
|
||||||
|
|
||||||
if respond_to?(report_method)
|
if respond_to?(report_method)
|
||||||
|
@ -46,6 +45,7 @@ class Report
|
||||||
else
|
else
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
report
|
report
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -60,13 +60,14 @@ class Report
|
||||||
end
|
end
|
||||||
|
|
||||||
filtered_results = data.where('date >= ? AND date <= ?', report.start_date.to_date, report.end_date.to_date)
|
filtered_results = data.where('date >= ? AND date <= ?', report.start_date.to_date, report.end_date.to_date)
|
||||||
|
filtered_results = filtered_results.where(category_id: report.category_id) if report.category_id
|
||||||
|
|
||||||
report.data = []
|
report.data = []
|
||||||
filtered_results.order(date: :asc)
|
filtered_results.order(date: :asc)
|
||||||
.group(:date)
|
.group(:date)
|
||||||
.sum(:count)
|
.sum(:count)
|
||||||
.each do |date, count|
|
.each do |date, count|
|
||||||
report.data << {x: date, y: count}
|
report.data << { x: date, y: count }
|
||||||
end
|
end
|
||||||
|
|
||||||
report.total = data.sum(:count)
|
report.total = data.sum(:count)
|
||||||
|
@ -84,28 +85,32 @@ class Report
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.report_topics(report)
|
def self.report_topics(report)
|
||||||
basic_report_about report, Topic, :listable_count_per_day, report.start_date, report.end_date
|
basic_report_about report, Topic, :listable_count_per_day, report.start_date, report.end_date, report.category_id
|
||||||
add_counts report, Topic.listable_topics, 'topics.created_at'
|
countable = Topic.listable_topics
|
||||||
|
countable = countable.where(category_id: report.category_id) if report.category_id
|
||||||
|
add_counts report, countable, 'topics.created_at'
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.report_posts(report)
|
def self.report_posts(report)
|
||||||
basic_report_about report, Post, :public_posts_count_per_day, report.start_date, report.end_date
|
basic_report_about report, Post, :public_posts_count_per_day, report.start_date, report.end_date, report.category_id
|
||||||
add_counts report, Post.public_posts, 'posts.created_at'
|
countable = Post.public_posts
|
||||||
|
countable = countable.joins(:topic).where("topics.category_id = ?", report.category_id) if report.category_id
|
||||||
|
add_counts report, countable, 'posts.created_at'
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.report_time_to_first_response(report)
|
def self.report_time_to_first_response(report)
|
||||||
report.data = []
|
report.data = []
|
||||||
Topic.time_to_first_response_per_day(report.start_date, report.end_date).each do |r|
|
Topic.time_to_first_response_per_day(report.start_date, report.end_date, report.category_id).each do |r|
|
||||||
report.data << { x: Date.parse(r["date"]), y: r["hours"].to_f.round(2) }
|
report.data << { x: Date.parse(r["date"]), y: r["hours"].to_f.round(2) }
|
||||||
end
|
end
|
||||||
report.total = Topic.time_to_first_response_total
|
report.total = Topic.time_to_first_response_total(category_id: report.category_id)
|
||||||
report.prev30Days = Topic.time_to_first_response_total(report.start_date - 30.days, report.start_date)
|
report.prev30Days = Topic.time_to_first_response_total(start_date: report.start_date - 30.days, end_date: report.start_date, category_id: report.category_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.report_topics_with_no_response(report)
|
def self.report_topics_with_no_response(report)
|
||||||
basic_report_about report, Topic, :with_no_response_per_day, report.start_date, report.end_date
|
basic_report_about report, Topic, :with_no_response_per_day, report.start_date, report.end_date, report.category_id
|
||||||
report.total = Topic.with_no_response_total
|
report.total = Topic.with_no_response_total(category_id: report.category_id)
|
||||||
report.prev30Days = Topic.with_no_response_total(report.start_date - 30.days, report.start_date)
|
report.prev30Days = Topic.with_no_response_total(start_date: report.start_date - 30.days, end_date: report.start_date, category_id: report.category_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.report_emails(report)
|
def self.report_emails(report)
|
||||||
|
@ -120,7 +125,7 @@ class Report
|
||||||
def self.basic_report_about(report, subject_class, report_method, *args)
|
def self.basic_report_about(report, subject_class, report_method, *args)
|
||||||
report.data = []
|
report.data = []
|
||||||
subject_class.send(report_method, *args).each do |date, count|
|
subject_class.send(report_method, *args).each do |date, count|
|
||||||
report.data << {x: date, y: count}
|
report.data << { x: date, y: count }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -132,14 +137,16 @@ class Report
|
||||||
def self.report_users_by_trust_level(report)
|
def self.report_users_by_trust_level(report)
|
||||||
report.data = []
|
report.data = []
|
||||||
User.real.group('trust_level').count.each do |level, count|
|
User.real.group('trust_level').count.each do |level, count|
|
||||||
report.data << {x: level.to_i, y: count}
|
report.data << { x: level.to_i, y: count }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Post action counts:
|
# Post action counts:
|
||||||
def self.report_flags(report)
|
def self.report_flags(report)
|
||||||
basic_report_about report, PostAction, :flag_count_by_date, report.start_date, report.end_date
|
basic_report_about report, PostAction, :flag_count_by_date, report.start_date, report.end_date, report.category_id
|
||||||
add_counts report, PostAction.where(post_action_type_id: PostActionType.flag_types.values), 'post_actions.created_at'
|
countable = PostAction.where(post_action_type_id: PostActionType.flag_types.values)
|
||||||
|
countable = countable.joins(post: :topic).where("topics.category_id = ?", report.category_id) if report.category_id
|
||||||
|
add_counts report, countable, 'post_actions.created_at'
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.report_likes(report)
|
def self.report_likes(report)
|
||||||
|
@ -152,10 +159,12 @@ class Report
|
||||||
|
|
||||||
def self.post_action_report(report, post_action_type)
|
def self.post_action_report(report, post_action_type)
|
||||||
report.data = []
|
report.data = []
|
||||||
PostAction.count_per_day_for_type(post_action_type).each do |date, count|
|
PostAction.count_per_day_for_type(post_action_type, category_id: report.category_id).each do |date, count|
|
||||||
report.data << { x: date, y: count }
|
report.data << { x: date, y: count }
|
||||||
end
|
end
|
||||||
add_counts report, PostAction.unscoped.where(post_action_type_id: post_action_type), 'post_actions.created_at'
|
countable = PostAction.unscoped.where(post_action_type_id: post_action_type)
|
||||||
|
countable = countable.joins(post: :topic).where("topics.category_id = ?", report.category_id) if report.category_id
|
||||||
|
add_counts report, countable, 'post_actions.created_at'
|
||||||
end
|
end
|
||||||
|
|
||||||
# Private messages counts:
|
# Private messages counts:
|
||||||
|
|
|
@ -359,8 +359,10 @@ class Topic < ActiveRecord::Base
|
||||||
custom_fields[key.to_s]
|
custom_fields[key.to_s]
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.listable_count_per_day(start_date, end_date)
|
def self.listable_count_per_day(start_date, end_date, category_id=nil)
|
||||||
listable_topics.where('created_at >= ? and created_at <= ?', start_date, end_date).group('date(created_at)').order('date(created_at)').count
|
result = listable_topics.where('created_at >= ? and created_at <= ?', start_date, end_date)
|
||||||
|
result = result.where(category_id: category_id) if category_id
|
||||||
|
result.group('date(created_at)').order('date(created_at)').count
|
||||||
end
|
end
|
||||||
|
|
||||||
def private_message?
|
def private_message?
|
||||||
|
@ -872,10 +874,12 @@ class Topic < ActiveRecord::Base
|
||||||
) t
|
) t
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
def self.time_to_first_response(sql, start_date=nil, end_date=nil)
|
def self.time_to_first_response(sql, opts=nil)
|
||||||
|
opts ||= {}
|
||||||
builder = SqlBuilder.new(sql)
|
builder = SqlBuilder.new(sql)
|
||||||
builder.where("t.created_at >= :start_date", start_date: start_date) if start_date
|
builder.where("t.created_at >= :start_date", start_date: opts[:start_date]) if opts[:start_date]
|
||||||
builder.where("t.created_at <= :end_date", end_date: end_date) if end_date
|
builder.where("t.created_at <= :end_date", end_date: opts[:end_date]) if opts[:end_date]
|
||||||
|
builder.where("t.category_id = :category_id", category_id: opts[:category_id]) if opts[:category_id]
|
||||||
builder.where("t.archetype <> '#{Archetype.private_message}'")
|
builder.where("t.archetype <> '#{Archetype.private_message}'")
|
||||||
builder.where("t.deleted_at IS NULL")
|
builder.where("t.deleted_at IS NULL")
|
||||||
builder.where("p.deleted_at IS NULL")
|
builder.where("p.deleted_at IS NULL")
|
||||||
|
@ -884,27 +888,30 @@ class Topic < ActiveRecord::Base
|
||||||
builder.exec
|
builder.exec
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.time_to_first_response_per_day(start_date, end_date)
|
def self.time_to_first_response_per_day(start_date, end_date, category_id=nil)
|
||||||
time_to_first_response(TIME_TO_FIRST_RESPONSE_SQL, start_date, end_date)
|
time_to_first_response(TIME_TO_FIRST_RESPONSE_SQL, start_date: start_date, end_date: end_date, category_id: category_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.time_to_first_response_total(start_date=nil, end_date=nil)
|
def self.time_to_first_response_total(opts=nil)
|
||||||
result = time_to_first_response(TIME_TO_FIRST_RESPONSE_TOTAL_SQL, start_date, end_date)
|
total = time_to_first_response(TIME_TO_FIRST_RESPONSE_TOTAL_SQL, opts)
|
||||||
result.first["hours"].to_f.round(2)
|
total.first["hours"].to_f.round(2)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.with_no_response_per_day(start_date, end_date)
|
def self.with_no_response_per_day(start_date, end_date, category_id=nil)
|
||||||
listable_topics.where(highest_post_number: 1)
|
result = listable_topics.where(highest_post_number: 1)
|
||||||
.where("created_at BETWEEN ? AND ?", start_date, end_date)
|
result = result.where("created_at BETWEEN ? AND ?", start_date, end_date)
|
||||||
.group("created_at::date")
|
result = result.where(category_id: category_id) if category_id
|
||||||
.order("created_at::date")
|
result.group("created_at::date")
|
||||||
.count
|
.order("created_at::date")
|
||||||
|
.count
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.with_no_response_total(start_date=nil, end_date=nil)
|
def self.with_no_response_total(opts=nil)
|
||||||
|
opts ||= {}
|
||||||
total = listable_topics.where(highest_post_number: 1)
|
total = listable_topics.where(highest_post_number: 1)
|
||||||
total = total.where("created_at >= ?", start_date) if start_date
|
total = total.where("created_at >= ?", opts[:start_date]) if opts[:start_date]
|
||||||
total = total.where("created_at <= ?", end_date) if end_date
|
total = total.where("created_at <= ?", opts[:end_date]) if opts[:end_date]
|
||||||
|
total = total.where(category_id: opts[:category_id]) if opts[:category_id]
|
||||||
total.count
|
total.count
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue