FEATURE: filter admin reports via user group
This commit is contained in:
parent
7d992cb4c5
commit
eec8436cfe
|
@ -1,6 +1,7 @@
|
||||||
import { exportEntity } from 'discourse/lib/export-csv';
|
import { exportEntity } from 'discourse/lib/export-csv';
|
||||||
import { outputExportResult } from 'discourse/lib/export-result';
|
import { outputExportResult } from 'discourse/lib/export-result';
|
||||||
import Report from 'admin/models/report';
|
import Report from 'admin/models/report';
|
||||||
|
import computed from 'ember-addons/ember-computed-decorators';
|
||||||
|
|
||||||
export default Ember.Controller.extend({
|
export default Ember.Controller.extend({
|
||||||
viewMode: 'table',
|
viewMode: 'table',
|
||||||
|
@ -9,22 +10,32 @@ export default Ember.Controller.extend({
|
||||||
startDate: null,
|
startDate: null,
|
||||||
endDate: null,
|
endDate: null,
|
||||||
categoryId: null,
|
categoryId: null,
|
||||||
|
groupId: null,
|
||||||
refreshing: false,
|
refreshing: false,
|
||||||
|
|
||||||
categoryOptions: function() {
|
@computed()
|
||||||
var arr = [{name: I18n.t('category.all'), value: 'all'}];
|
categoryOptions() {
|
||||||
return arr.concat( Discourse.Site.currentProp('sortedCategories').map(function(i) { return {name: i.get('name'), value: i.get('id') }; }) );
|
const arr = [{name: I18n.t('category.all'), value: 'all'}];
|
||||||
}.property(),
|
return arr.concat(Discourse.Site.currentProp('sortedCategories').map((i) => {return {name: i.get('name'), value: i.get('id')};}));
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed()
|
||||||
|
groupOptions() {
|
||||||
|
const arr = [{name: I18n.t('admin.dashboard.reports.groups'), value: 'all'}];
|
||||||
|
return arr.concat(this.site.groups.map((i) => {return {name: i['name'], value: i['id']};}));
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed('model.type')
|
||||||
|
showGroupOptions(modelType) {
|
||||||
|
return modelType === "visits" || modelType === "signups" || modelType === "profile_views";
|
||||||
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
refreshReport() {
|
refreshReport() {
|
||||||
var q;
|
var q;
|
||||||
this.set("refreshing", true);
|
this.set("refreshing", true);
|
||||||
if (this.get('categoryId') === "all") {
|
|
||||||
q = Report.find(this.get("model.type"), this.get("startDate"), this.get("endDate"));
|
q = Report.find(this.get("model.type"), this.get("startDate"), this.get("endDate"), this.get("categoryId"), this.get("groupId"));
|
||||||
} else {
|
|
||||||
q = Report.find(this.get("model.type"), this.get("startDate"), this.get("endDate"), this.get("categoryId"));
|
|
||||||
}
|
|
||||||
q.then(m => this.set("model", m)).finally(() => this.set("refreshing", false));
|
q.then(m => this.set("model", m)).finally(() => this.set("refreshing", false));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -41,7 +52,8 @@ export default Ember.Controller.extend({
|
||||||
name: this.get("model.type"),
|
name: this.get("model.type"),
|
||||||
start_date: this.get('startDate'),
|
start_date: this.get('startDate'),
|
||||||
end_date: this.get('endDate'),
|
end_date: this.get('endDate'),
|
||||||
category_id: this.get('categoryId') === 'all' ? undefined : this.get('categoryId')
|
category_id: this.get('categoryId') === 'all' ? undefined : this.get('categoryId'),
|
||||||
|
group_id: this.get('groupId') === 'all' ? undefined : this.get('groupId')
|
||||||
}).then(outputExportResult);
|
}).then(outputExportResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,12 +131,13 @@ const Report = Discourse.Model.extend({
|
||||||
|
|
||||||
Report.reopenClass({
|
Report.reopenClass({
|
||||||
|
|
||||||
find(type, startDate, endDate, categoryId) {
|
find(type, startDate, endDate, categoryId, groupId) {
|
||||||
return Discourse.ajax("/admin/reports/" + type, {
|
return Discourse.ajax("/admin/reports/" + type, {
|
||||||
data: {
|
data: {
|
||||||
start_date: startDate,
|
start_date: startDate,
|
||||||
end_date: endDate,
|
end_date: endDate,
|
||||||
category_id: categoryId
|
category_id: categoryId,
|
||||||
|
group_id: groupId
|
||||||
}
|
}
|
||||||
}).then(json => {
|
}).then(json => {
|
||||||
// Add a percent field to each tuple
|
// Add a percent field to each tuple
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
<h3>{{model.title}}</h3>
|
<h3>{{model.title}}</h3>
|
||||||
|
|
||||||
<div>
|
<div class="admin-reports-filter">
|
||||||
{{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}}
|
||||||
{{combo-box valueAttribute="value" content=categoryOptions value=categoryId}}
|
{{combo-box valueAttribute="value" content=categoryOptions value=categoryId}}
|
||||||
|
{{#if showGroupOptions}}
|
||||||
|
{{combo-box valueAttribute="value" content=groupOptions value=groupId}}
|
||||||
|
{{/if}}
|
||||||
{{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"}}
|
||||||
{{d-button action="exportCsv" label="admin.export_csv.button_text" icon="download"}}
|
{{d-button action="exportCsv" label="admin.export_csv.button_text" icon="download"}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -38,6 +38,12 @@ $mobile-breakpoint: 700px;
|
||||||
.filters input { margin-bottom: 0; }
|
.filters input { margin-bottom: 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.admin-contents .admin-reports-filter {
|
||||||
|
input[type="date"] {
|
||||||
|
width: 140px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
td.flaggers td {
|
td.flaggers td {
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
|
|
|
@ -13,11 +13,19 @@ 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?
|
||||||
|
|
||||||
category_id = if params.has_key?(:category_id)
|
if params.has_key?(:category_id) && params[:category_id].to_i > 0
|
||||||
params[:category_id].blank? ? SiteSetting.uncategorized_category_id : params[:category_id].to_i
|
category_id = params[:category_id].to_i
|
||||||
|
else
|
||||||
|
category_id = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
report = Report.find(report_type, start_date: start_date, end_date: end_date, category_id: category_id)
|
if params.has_key?(:group_id) && params[:group_id].to_i > 0
|
||||||
|
group_id = params[:group_id].to_i
|
||||||
|
else
|
||||||
|
group_id = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
report = Report.find(report_type, start_date: start_date, end_date: end_date, category_id: category_id, group_id: group_id)
|
||||||
|
|
||||||
raise Discourse::NotFound if report.blank?
|
raise Discourse::NotFound if report.blank?
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ class ExportCsvController < ApplicationController
|
||||||
@_export_params ||= begin
|
@_export_params ||= begin
|
||||||
params.require(:entity)
|
params.require(:entity)
|
||||||
params.require(:entity_type)
|
params.require(:entity_type)
|
||||||
params.permit(:entity, :entity_type, args: [:name, :start_date, :end_date, :category_id])
|
params.permit(:entity, :entity_type, args: [:name, :start_date, :end_date, :category_id, :group_id])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -151,6 +151,7 @@ module Jobs
|
||||||
@extra[:start_date] = @extra[:start_date].to_date if @extra[:start_date].is_a?(String)
|
@extra[:start_date] = @extra[:start_date].to_date if @extra[:start_date].is_a?(String)
|
||||||
@extra[:end_date] = @extra[:end_date].to_date if @extra[:end_date].is_a?(String)
|
@extra[:end_date] = @extra[:end_date].to_date if @extra[:end_date].is_a?(String)
|
||||||
@extra[:category_id] = @extra[:category_id].to_i if @extra[:category_id]
|
@extra[:category_id] = @extra[:category_id].to_i if @extra[:category_id]
|
||||||
|
@extra[:group_id] = @extra[:group_id].to_i if @extra[:group_id]
|
||||||
r = Report.find(@extra[:name], @extra)
|
r = Report.find(@extra[:name], @extra)
|
||||||
r.data.map do |row|
|
r.data.map do |row|
|
||||||
[row[:x].to_s(:db), row[:y].to_s(:db)]
|
[row[:x].to_s(:db), row[:y].to_s(:db)]
|
||||||
|
|
|
@ -2,7 +2,7 @@ require_dependency 'topic_subtype'
|
||||||
|
|
||||||
class Report
|
class Report
|
||||||
|
|
||||||
attr_accessor :type, :data, :total, :prev30Days, :start_date, :end_date, :category_id
|
attr_accessor :type, :data, :total, :prev30Days, :start_date, :end_date, :category_id, :group_id
|
||||||
|
|
||||||
def self.default_days
|
def self.default_days
|
||||||
30
|
30
|
||||||
|
@ -25,6 +25,7 @@ class Report
|
||||||
start_date: start_date,
|
start_date: start_date,
|
||||||
end_date: end_date,
|
end_date: end_date,
|
||||||
category_id: category_id,
|
category_id: category_id,
|
||||||
|
group_id: group_id,
|
||||||
prev30Days: self.prev30Days
|
prev30Days: self.prev30Days
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -41,6 +42,7 @@ class Report
|
||||||
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.category_id = opts[:category_id] if opts[:category_id]
|
||||||
|
report.group_id = opts[:group_id] if opts[:group_id]
|
||||||
report_method = :"report_#{type}"
|
report_method = :"report_#{type}"
|
||||||
|
|
||||||
if respond_to?(report_method)
|
if respond_to?(report_method)
|
||||||
|
@ -85,7 +87,8 @@ class Report
|
||||||
|
|
||||||
|
|
||||||
def self.report_visits(report)
|
def self.report_visits(report)
|
||||||
basic_report_about report, UserVisit, :by_day, report.start_date, report.end_date
|
basic_report_about report, UserVisit, :by_day, report.start_date, report.end_date, report.group_id
|
||||||
|
|
||||||
add_counts report, UserVisit, 'visited_at'
|
add_counts report, UserVisit, 'visited_at'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -96,13 +99,19 @@ class Report
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.report_signups(report)
|
def self.report_signups(report)
|
||||||
report_about report, User.real, :count_by_signup_date
|
if report.group_id
|
||||||
|
basic_report_about report, User.real, :count_by_signup_date, report.start_date, report.end_date, report.group_id
|
||||||
|
add_counts report, User.real, 'users.created_at'
|
||||||
|
else
|
||||||
|
report_about report, User.real, :count_by_signup_date
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.report_profile_views(report)
|
def self.report_profile_views(report)
|
||||||
start_date = report.start_date.to_date
|
start_date = report.start_date.to_date
|
||||||
end_date = report.end_date.to_date
|
end_date = report.end_date.to_date
|
||||||
basic_report_about report, UserProfileView, :profile_views_by_day, start_date, end_date
|
basic_report_about report, UserProfileView, :profile_views_by_day, start_date, end_date, report.group_id
|
||||||
|
|
||||||
report.total = UserProfile.sum(:views)
|
report.total = UserProfile.sum(:views)
|
||||||
report.prev30Days = UserProfileView.where("viewed_at >= ? AND viewed_at < ?", start_date - 30.days, start_date + 1).count
|
report.prev30Days = UserProfileView.where("viewed_at >= ? AND viewed_at < ?", start_date - 30.days, start_date + 1).count
|
||||||
end
|
end
|
||||||
|
|
|
@ -110,7 +110,7 @@ class User < ActiveRecord::Base
|
||||||
attr_accessor :import_mode
|
attr_accessor :import_mode
|
||||||
|
|
||||||
# excluding fake users like the system user or anonymous users
|
# excluding fake users like the system user or anonymous users
|
||||||
scope :real, -> { where('id > 0').where('NOT EXISTS(
|
scope :real, -> { where('users.id > 0').where('NOT EXISTS(
|
||||||
SELECT 1
|
SELECT 1
|
||||||
FROM user_custom_fields ucf
|
FROM user_custom_fields ucf
|
||||||
WHERE
|
WHERE
|
||||||
|
@ -637,8 +637,14 @@ class User < ActiveRecord::Base
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.count_by_signup_date(start_date, end_date)
|
def self.count_by_signup_date(start_date, end_date, group_id=nil)
|
||||||
where('created_at >= ? and created_at <= ?', start_date, end_date).group('date(created_at)').order('date(created_at)').count
|
result = where('users.created_at >= ? and users.created_at <= ?', start_date, end_date)
|
||||||
|
|
||||||
|
if group_id
|
||||||
|
result = result.joins("INNER JOIN group_users ON group_users.user_id = users.id")
|
||||||
|
result = result.where("group_users.group_id = ?", group_id)
|
||||||
|
end
|
||||||
|
result.group('date(users.created_at)').order('date(users.created_at)').count
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -40,8 +40,13 @@ class UserProfileView < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.profile_views_by_day(start_date, end_date)
|
def self.profile_views_by_day(start_date, end_date, group_id=nil)
|
||||||
profile_views = self.where("viewed_at >= ? AND viewed_at < ?", start_date, end_date + 1.day)
|
profile_views = self.where("viewed_at >= ? AND viewed_at < ?", start_date, end_date + 1.day)
|
||||||
|
if group_id
|
||||||
|
profile_views = profile_views.joins("INNER JOIN users ON users.id = user_profile_views.user_id")
|
||||||
|
profile_views = profile_views.joins("INNER JOIN group_users ON group_users.user_id = users.id")
|
||||||
|
profile_views = profile_views.where("group_users.group_id = ?", group_id)
|
||||||
|
end
|
||||||
profile_views.group("date(viewed_at)").order("date(viewed_at)").count
|
profile_views.group("date(viewed_at)").order("date(viewed_at)").count
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,16 +1,23 @@
|
||||||
class UserVisit < ActiveRecord::Base
|
class UserVisit < ActiveRecord::Base
|
||||||
|
|
||||||
def self.counts_by_day_query(start_date, end_date)
|
def self.counts_by_day_query(start_date, end_date, group_id=nil)
|
||||||
where('visited_at >= ? and visited_at <= ?', start_date.to_date, end_date.to_date).group(:visited_at).order(:visited_at)
|
result = where('visited_at >= ? and visited_at <= ?', start_date.to_date, end_date.to_date)
|
||||||
|
|
||||||
|
if group_id
|
||||||
|
result = result.joins("INNER JOIN users ON users.id = user_visits.user_id")
|
||||||
|
result = result.joins("INNER JOIN group_users ON group_users.user_id = users.id")
|
||||||
|
result = result.where("group_users.group_id = ?", group_id)
|
||||||
|
end
|
||||||
|
result.group(:visited_at).order(:visited_at)
|
||||||
end
|
end
|
||||||
|
|
||||||
# A count of visits in a date range by day
|
# A count of visits in a date range by day
|
||||||
def self.by_day(start_date, end_date)
|
def self.by_day(start_date, end_date, group_id=nil)
|
||||||
counts_by_day_query(start_date, end_date).count
|
counts_by_day_query(start_date, end_date, group_id).count
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.mobile_by_day(start_date, end_date)
|
def self.mobile_by_day(start_date, end_date, group_id=nil)
|
||||||
counts_by_day_query(start_date, end_date).where(mobile: true).count
|
counts_by_day_query(start_date, end_date, group_id).where(mobile: true).count
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.ensure_consistency!
|
def self.ensure_consistency!
|
||||||
|
|
|
@ -1929,6 +1929,7 @@ en:
|
||||||
refresh_report: "Refresh Report"
|
refresh_report: "Refresh Report"
|
||||||
start_date: "Start Date"
|
start_date: "Start Date"
|
||||||
end_date: "End Date"
|
end_date: "End Date"
|
||||||
|
groups: "All groups"
|
||||||
|
|
||||||
commits:
|
commits:
|
||||||
latest_changes: "Latest changes: please update often!"
|
latest_changes: "Latest changes: please update often!"
|
||||||
|
|
Loading…
Reference in New Issue