FEATURE: Make report filters reusable (#9444)
This commit also adds 'include subcategories' report filter
This commit is contained in:
parent
a511bea4cc
commit
e733701887
|
@ -7,7 +7,6 @@ import Component from "@ember/component";
|
||||||
import ReportLoader from "discourse/lib/reports-loader";
|
import ReportLoader from "discourse/lib/reports-loader";
|
||||||
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 { isNumeric } from "discourse/lib/utilities";
|
|
||||||
import Report, { SCHEMA_VERSION } from "admin/models/report";
|
import Report, { SCHEMA_VERSION } from "admin/models/report";
|
||||||
import ENV from "discourse-common/config/environment";
|
import ENV from "discourse-common/config/environment";
|
||||||
|
|
||||||
|
@ -167,10 +166,9 @@ export default Component.extend({
|
||||||
ENV.environment === "test" ? "end" : endDate.replace(/-/g, ""),
|
ENV.environment === "test" ? "end" : endDate.replace(/-/g, ""),
|
||||||
"[:prev_period]",
|
"[:prev_period]",
|
||||||
this.get("reportOptions.table.limit"),
|
this.get("reportOptions.table.limit"),
|
||||||
|
// Convert all filter values to strings to ensure unique serialization
|
||||||
customFilters
|
customFilters
|
||||||
? JSON.stringify(customFilters, (key, value) =>
|
? JSON.stringify(customFilters, (k, v) => (k ? `${v}` : v))
|
||||||
isNumeric(value) ? value.toString() : value
|
|
||||||
)
|
|
||||||
: null,
|
: null,
|
||||||
SCHEMA_VERSION
|
SCHEMA_VERSION
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import FilterComponent from "admin/components/report-filters/filter";
|
||||||
|
|
||||||
|
export default FilterComponent.extend({
|
||||||
|
checked: false,
|
||||||
|
|
||||||
|
didReceiveAttrs() {
|
||||||
|
this._super(...arguments);
|
||||||
|
this.set("checked", !!this.filter.default);
|
||||||
|
},
|
||||||
|
|
||||||
|
@action
|
||||||
|
onChange() {
|
||||||
|
this.applyFilter(this.filter.id, !this.checked || undefined);
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,16 +1,12 @@
|
||||||
|
import { action } from "@ember/object";
|
||||||
import { readOnly } from "@ember/object/computed";
|
import { readOnly } from "@ember/object/computed";
|
||||||
import FilterComponent from "admin/components/report-filters/filter";
|
import FilterComponent from "admin/components/report-filters/filter";
|
||||||
|
|
||||||
export default FilterComponent.extend({
|
export default FilterComponent.extend({
|
||||||
classNames: ["category-filter"],
|
|
||||||
|
|
||||||
layoutName: "admin/templates/components/report-filters/category",
|
|
||||||
|
|
||||||
category: readOnly("filter.default"),
|
category: readOnly("filter.default"),
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
onChange(categoryId) {
|
onChange(categoryId) {
|
||||||
this.applyFilter(this.get("filter.id"), categoryId || undefined);
|
this.applyFilter(this.filter.id, categoryId || undefined);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
import FilterComponent from "admin/components/report-filters/filter";
|
|
||||||
|
|
||||||
export default FilterComponent.extend({
|
|
||||||
classNames: ["file-extension-filter"],
|
|
||||||
|
|
||||||
layoutName: "admin/templates/components/report-filters/file-extension"
|
|
||||||
});
|
|
|
@ -1,8 +1,9 @@
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
actions: {
|
@action
|
||||||
onChange(value) {
|
onChange(value) {
|
||||||
this.applyFilter(this.get("filter.id"), value);
|
this.applyFilter(this.filter.id, value);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,20 +1,18 @@
|
||||||
|
import { computed } from "@ember/object";
|
||||||
import FilterComponent from "admin/components/report-filters/filter";
|
import FilterComponent from "admin/components/report-filters/filter";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
|
||||||
|
|
||||||
export default FilterComponent.extend({
|
export default FilterComponent.extend({
|
||||||
classNames: ["group-filter"],
|
classNames: ["group-filter"],
|
||||||
|
|
||||||
layoutName: "admin/templates/components/report-filters/group",
|
@computed
|
||||||
|
get groupOptions() {
|
||||||
@discourseComputed()
|
|
||||||
groupOptions() {
|
|
||||||
return (this.site.groups || []).map(group => {
|
return (this.site.groups || []).map(group => {
|
||||||
return { name: group["name"], value: group["id"] };
|
return { name: group["name"], value: group["id"] };
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@discourseComputed("filter.default")
|
@computed("filter.default")
|
||||||
groupId(filterDefault) {
|
get groupId() {
|
||||||
return filterDefault ? parseInt(filterDefault, 10) : null;
|
return this.filter.default ? parseInt(this.filter.default, 10) : null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
import FilterComponent from "admin/components/report-filters/filter";
|
||||||
|
|
||||||
|
export default FilterComponent.extend();
|
|
@ -3,7 +3,7 @@ import { ajax } from "discourse/lib/ajax";
|
||||||
|
|
||||||
export default DiscourseRoute.extend({
|
export default DiscourseRoute.extend({
|
||||||
model() {
|
model() {
|
||||||
return ajax("/admin/reports").then(json => json);
|
return ajax("/admin/reports");
|
||||||
},
|
},
|
||||||
|
|
||||||
setupController(controller, model) {
|
setupController(controller, model) {
|
||||||
|
|
|
@ -165,7 +165,8 @@
|
||||||
|
|
||||||
<div class="input">
|
<div class="input">
|
||||||
{{component
|
{{component
|
||||||
(concat "report-filters/" filter.id)
|
(concat "report-filters/" filter.type)
|
||||||
|
model=model
|
||||||
filter=filter
|
filter=filter
|
||||||
applyFilter=(action "applyFilter")}}
|
applyFilter=(action "applyFilter")}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
{{input
|
||||||
|
type="checkbox"
|
||||||
|
checked=checked
|
||||||
|
click=(action "onChange")
|
||||||
|
}}
|
|
@ -1,7 +1,5 @@
|
||||||
{{search-advanced-category-chooser
|
{{search-advanced-category-chooser
|
||||||
value=category
|
value=category
|
||||||
onChange=(action "onChange")
|
onChange=(action "onChange")
|
||||||
options=(hash
|
options=(hash filterable=true)
|
||||||
filterable=true
|
|
||||||
)
|
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -2,13 +2,14 @@
|
||||||
|
|
||||||
class IncomingLinksReport
|
class IncomingLinksReport
|
||||||
|
|
||||||
attr_accessor :type, :data, :y_titles, :start_date, :end_date, :limit, :category_id
|
attr_accessor :type, :data, :y_titles, :start_date, :end_date, :limit, :category_id, :include_subcategories
|
||||||
|
|
||||||
def initialize(type)
|
def initialize(type)
|
||||||
@type = type
|
@type = type
|
||||||
@y_titles = {}
|
@y_titles = {}
|
||||||
@data = nil
|
@data = nil
|
||||||
@category_id = nil
|
@category_id = nil
|
||||||
|
@include_subcategories = false
|
||||||
end
|
end
|
||||||
|
|
||||||
def as_json(_options = nil)
|
def as_json(_options = nil)
|
||||||
|
@ -34,6 +35,7 @@ class IncomingLinksReport
|
||||||
report.end_date = _opts[:end_date] || Time.now.end_of_day
|
report.end_date = _opts[:end_date] || Time.now.end_of_day
|
||||||
report.limit = _opts[:limit].to_i if _opts[:limit]
|
report.limit = _opts[:limit].to_i if _opts[:limit]
|
||||||
report.category_id = _opts[:category_id] if _opts[:category_id]
|
report.category_id = _opts[:category_id] if _opts[:category_id]
|
||||||
|
report.include_subcategories = _opts[:include_subcategories] if _opts[:include_subcategories]
|
||||||
|
|
||||||
public_send(report_method, report)
|
public_send(report_method, report)
|
||||||
report
|
report
|
||||||
|
@ -44,8 +46,8 @@ class IncomingLinksReport
|
||||||
report.y_titles[:num_clicks] = I18n.t("reports.#{report.type}.num_clicks")
|
report.y_titles[:num_clicks] = I18n.t("reports.#{report.type}.num_clicks")
|
||||||
report.y_titles[:num_topics] = I18n.t("reports.#{report.type}.num_topics")
|
report.y_titles[:num_topics] = I18n.t("reports.#{report.type}.num_topics")
|
||||||
|
|
||||||
num_clicks = link_count_per_user(start_date: report.start_date, end_date: report.end_date, category_id: report.category_id)
|
num_clicks = link_count_per_user(start_date: report.start_date, end_date: report.end_date, category_id: report.category_id, include_subcategories: report.include_subcategories)
|
||||||
num_topics = topic_count_per_user(start_date: report.start_date, end_date: report.end_date, category_id: report.category_id)
|
num_topics = topic_count_per_user(start_date: report.start_date, end_date: report.end_date, category_id: report.category_id, include_subcategories: report.include_subcategories)
|
||||||
user_id_lookup = User
|
user_id_lookup = User
|
||||||
.where(username: num_clicks.keys)
|
.where(username: num_clicks.keys)
|
||||||
.select(:id, :username, :uploaded_avatar_id)
|
.select(:id, :username, :uploaded_avatar_id)
|
||||||
|
@ -70,19 +72,19 @@ class IncomingLinksReport
|
||||||
report.data = report.data.sort_by { |x| x[:num_clicks] }.reverse[0, 10]
|
report.data = report.data.sort_by { |x| x[:num_clicks] }.reverse[0, 10]
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.per_user(start_date:, end_date:, category_id:)
|
def self.per_user(start_date:, end_date:, category_id:, include_subcategories:)
|
||||||
public_incoming_links(category_id: category_id)
|
public_incoming_links(category_id: category_id, include_subcategories: include_subcategories)
|
||||||
.where('incoming_links.created_at > ? AND incoming_links.created_at < ? AND incoming_links.user_id IS NOT NULL', start_date, end_date)
|
.where('incoming_links.created_at > ? AND incoming_links.created_at < ? AND incoming_links.user_id IS NOT NULL', start_date, end_date)
|
||||||
.joins(:user)
|
.joins(:user)
|
||||||
.group('users.username')
|
.group('users.username')
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.link_count_per_user(start_date:, end_date:, category_id:)
|
def self.link_count_per_user(start_date:, end_date:, category_id:, include_subcategories:)
|
||||||
per_user(start_date: start_date, end_date: end_date, category_id: category_id).count
|
per_user(start_date: start_date, end_date: end_date, category_id: category_id, include_subcategories: include_subcategories).count
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.topic_count_per_user(start_date:, end_date:, category_id:)
|
def self.topic_count_per_user(start_date:, end_date:, category_id:, include_subcategories:)
|
||||||
per_user(start_date: start_date, end_date: end_date, category_id: category_id).joins(:post).count("DISTINCT posts.topic_id")
|
per_user(start_date: start_date, end_date: end_date, category_id: category_id, include_subcategories: include_subcategories).joins(:post).count("DISTINCT posts.topic_id")
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return top 10 domains that brought traffic to the site within the last 30 days
|
# Return top 10 domains that brought traffic to the site within the last 30 days
|
||||||
|
@ -91,8 +93,8 @@ class IncomingLinksReport
|
||||||
report.y_titles[:num_topics] = I18n.t("reports.#{report.type}.num_topics")
|
report.y_titles[:num_topics] = I18n.t("reports.#{report.type}.num_topics")
|
||||||
report.y_titles[:num_users] = I18n.t("reports.#{report.type}.num_users")
|
report.y_titles[:num_users] = I18n.t("reports.#{report.type}.num_users")
|
||||||
|
|
||||||
num_clicks = link_count_per_domain(start_date: report.start_date, end_date: report.end_date, category_id: report.category_id)
|
num_clicks = link_count_per_domain(start_date: report.start_date, end_date: report.end_date, category_id: report.category_id, include_subcategories: report.include_subcategories)
|
||||||
num_topics = topic_count_per_domain(num_clicks.keys, category_id: report.category_id)
|
num_topics = topic_count_per_domain(num_clicks.keys, category_id: report.category_id, include_subcategories: report.include_subcategories)
|
||||||
report.data = []
|
report.data = []
|
||||||
num_clicks.each_key do |domain|
|
num_clicks.each_key do |domain|
|
||||||
report.data << { domain: domain, num_clicks: num_clicks[domain], num_topics: num_topics[domain] }
|
report.data << { domain: domain, num_clicks: num_clicks[domain], num_topics: num_topics[domain] }
|
||||||
|
@ -100,8 +102,8 @@ class IncomingLinksReport
|
||||||
report.data = report.data.sort_by { |x| x[:num_clicks] }.reverse[0, 10]
|
report.data = report.data.sort_by { |x| x[:num_clicks] }.reverse[0, 10]
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.link_count_per_domain(limit: 10, start_date:, end_date:, category_id:)
|
def self.link_count_per_domain(limit: 10, start_date:, end_date:, category_id:, include_subcategories:)
|
||||||
public_incoming_links(category_id: category_id)
|
public_incoming_links(category_id: category_id, include_subcategories: include_subcategories)
|
||||||
.where('incoming_links.created_at > ? AND incoming_links.created_at < ?', start_date, end_date)
|
.where('incoming_links.created_at > ? AND incoming_links.created_at < ?', start_date, end_date)
|
||||||
.joins(incoming_referer: :incoming_domain)
|
.joins(incoming_referer: :incoming_domain)
|
||||||
.group('incoming_domains.name')
|
.group('incoming_domains.name')
|
||||||
|
@ -111,7 +113,7 @@ class IncomingLinksReport
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.per_domain(domains, options = {})
|
def self.per_domain(domains, options = {})
|
||||||
public_incoming_links(category_id: options[:category_id])
|
public_incoming_links(category_id: options[:category_id], include_subcategories: options[:include_subcategories])
|
||||||
.joins(incoming_referer: :incoming_domain)
|
.joins(incoming_referer: :incoming_domain)
|
||||||
.where('incoming_links.created_at > ? AND incoming_domains.name IN (?)', 30.days.ago, domains)
|
.where('incoming_links.created_at > ? AND incoming_domains.name IN (?)', 30.days.ago, domains)
|
||||||
.group('incoming_domains.name')
|
.group('incoming_domains.name')
|
||||||
|
@ -124,11 +126,13 @@ class IncomingLinksReport
|
||||||
|
|
||||||
def self.report_top_referred_topics(report)
|
def self.report_top_referred_topics(report)
|
||||||
report.y_titles[:num_clicks] = I18n.t("reports.#{report.type}.labels.num_clicks")
|
report.y_titles[:num_clicks] = I18n.t("reports.#{report.type}.labels.num_clicks")
|
||||||
num_clicks = link_count_per_topic(start_date: report.start_date, end_date: report.end_date, category_id: report.category_id)
|
num_clicks = link_count_per_topic(start_date: report.start_date, end_date: report.end_date, category_id: report.category_id, include_subcategories: report.include_subcategories)
|
||||||
num_clicks = num_clicks.to_a.sort_by { |x| x[1] }.last(report.limit || 10).reverse
|
num_clicks = num_clicks.to_a.sort_by { |x| x[1] }.last(report.limit || 10).reverse
|
||||||
report.data = []
|
report.data = []
|
||||||
topics = Topic.select('id, slug, title').where('id in (?)', num_clicks.map { |z| z[0] })
|
topics = Topic.select('id, slug, title').where('id in (?)', num_clicks.map { |z| z[0] })
|
||||||
topics = topics.in_category_and_subcategories(report.category_id) if report.category_id
|
if report.category_id
|
||||||
|
topics = topics.where(category_id: report.include_subcategories ? Category.subcategory_ids(report.category_id) : report.category_id)
|
||||||
|
end
|
||||||
num_clicks.each do |topic_id, num_clicks_element|
|
num_clicks.each do |topic_id, num_clicks_element|
|
||||||
topic = topics.find { |t| t.id == topic_id }
|
topic = topics.find { |t| t.id == topic_id }
|
||||||
if topic
|
if topic
|
||||||
|
@ -138,17 +142,26 @@ class IncomingLinksReport
|
||||||
report.data
|
report.data
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.link_count_per_topic(start_date:, end_date:, category_id:)
|
def self.link_count_per_topic(start_date:, end_date:, category_id:, include_subcategories:)
|
||||||
public_incoming_links(category_id: category_id)
|
public_incoming_links(category_id: category_id, include_subcategories: include_subcategories)
|
||||||
.where('incoming_links.created_at > ? AND incoming_links.created_at < ? AND topic_id IS NOT NULL', start_date, end_date)
|
.where('incoming_links.created_at > ? AND incoming_links.created_at < ? AND topic_id IS NOT NULL', start_date, end_date)
|
||||||
.group('topic_id')
|
.group('topic_id')
|
||||||
.count
|
.count
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.public_incoming_links(category_id: nil)
|
def self.public_incoming_links(category_id: nil, include_subcategories: nil)
|
||||||
IncomingLink
|
links = IncomingLink
|
||||||
.joins(post: :topic)
|
.joins(post: :topic)
|
||||||
.where("topics.archetype = ?", Archetype.default)
|
.where("topics.archetype = ?", Archetype.default)
|
||||||
.merge(Topic.in_category_and_subcategories(category_id))
|
|
||||||
|
if category_id
|
||||||
|
if include_subcategories
|
||||||
|
links = links.where("topics.category_id IN (?)", Category.subcategory_ids(category_id))
|
||||||
|
else
|
||||||
|
links = links.where("topics.category_id = ?", category_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
links
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -765,10 +765,19 @@ class Post < ActiveRecord::Base
|
||||||
DiscourseEvent.trigger(:after_trigger_post_process, self)
|
DiscourseEvent.trigger(:after_trigger_post_process, self)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.public_posts_count_per_day(start_date, end_date, category_id = nil)
|
def self.public_posts_count_per_day(start_date, end_date, category_id = nil, include_subcategories = false)
|
||||||
result = public_posts.where('posts.created_at >= ? AND posts.created_at <= ?', start_date, end_date)
|
result = public_posts
|
||||||
|
.where('posts.created_at >= ? AND posts.created_at <= ?', start_date, end_date)
|
||||||
.where(post_type: Post.types[:regular])
|
.where(post_type: Post.types[:regular])
|
||||||
result = result.where('topics.category_id IN (?)', Category.subcategory_ids(category_id.to_i)) if category_id
|
|
||||||
|
if category_id
|
||||||
|
if include_subcategories
|
||||||
|
result = result.where('topics.category_id IN (?)', Category.subcategory_ids(category_id))
|
||||||
|
else
|
||||||
|
result = result.where('topics.category_id = ?', category_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
result
|
result
|
||||||
.group('date(posts.created_at)')
|
.group('date(posts.created_at)')
|
||||||
.order('date(posts.created_at)')
|
.order('date(posts.created_at)')
|
||||||
|
|
|
@ -67,7 +67,13 @@ class PostAction < ActiveRecord::Base
|
||||||
result = unscoped.where(post_action_type_id: post_action_type)
|
result = unscoped.where(post_action_type_id: post_action_type)
|
||||||
result = result.where('post_actions.created_at >= ?', opts[:start_date] || (opts[:since_days_ago] || 30).days.ago)
|
result = result.where('post_actions.created_at >= ?', opts[:start_date] || (opts[:since_days_ago] || 30).days.ago)
|
||||||
result = result.where('post_actions.created_at <= ?', opts[:end_date]) if opts[:end_date]
|
result = result.where('post_actions.created_at <= ?', opts[:end_date]) if opts[:end_date]
|
||||||
result = result.joins(post: :topic).merge(Topic.in_category_and_subcategories(opts[:category_id])) if opts[:category_id]
|
if opts[:category_id]
|
||||||
|
if opts[:include_subcategories]
|
||||||
|
result = result.joins(post: :topic).where('topics.category_id IN (?)', Category.subcategory_ids(opts[:category_id]))
|
||||||
|
else
|
||||||
|
result = result.joins(post: :topic).where('topics.category_id = ?', opts[:category_id])
|
||||||
|
end
|
||||||
|
end
|
||||||
result.group('date(post_actions.created_at)')
|
result.group('date(post_actions.created_at)')
|
||||||
.order('date(post_actions.created_at)')
|
.order('date(post_actions.created_at)')
|
||||||
.count
|
.count
|
||||||
|
|
|
@ -50,8 +50,8 @@ class Report
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.cache_key(report)
|
def self.cache_key(report)
|
||||||
(+"reports:") <<
|
|
||||||
[
|
[
|
||||||
|
"reports",
|
||||||
report.type,
|
report.type,
|
||||||
report.start_date.to_date.strftime("%Y%m%d"),
|
report.start_date.to_date.strftime("%Y%m%d"),
|
||||||
report.end_date.to_date.strftime("%Y%m%d"),
|
report.end_date.to_date.strftime("%Y%m%d"),
|
||||||
|
@ -63,14 +63,30 @@ class Report
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_filter(name, options = {})
|
def add_filter(name, options = {})
|
||||||
default_filter = { allow_any: false, choices: [], default: nil }
|
if options[:type].blank?
|
||||||
available_filters[name] = default_filter.merge(options)
|
options[:type] = name
|
||||||
|
Discourse.deprecate("#{name} filter should define a `:type` option. Temporarily setting type to #{name}.")
|
||||||
|
end
|
||||||
|
|
||||||
|
available_filters[name] = options
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_filter(name)
|
def remove_filter(name)
|
||||||
available_filters.delete(name)
|
available_filters.delete(name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def add_category_filter
|
||||||
|
category_id = filters[:category].to_i if filters[:category].present?
|
||||||
|
add_filter('category', type: 'category', default: category_id)
|
||||||
|
return if category_id.blank?
|
||||||
|
|
||||||
|
include_subcategories = filters[:'include-subcategories']
|
||||||
|
include_subcategories = !!ActiveRecord::Type::Boolean.new.cast(include_subcategories)
|
||||||
|
add_filter('include-subcategories', type: 'bool', default: include_subcategories)
|
||||||
|
|
||||||
|
[category_id, include_subcategories]
|
||||||
|
end
|
||||||
|
|
||||||
def self.clear_cache(type = nil)
|
def self.clear_cache(type = nil)
|
||||||
pattern = type ? "reports:#{type}:*" : "reports:*"
|
pattern = type ? "reports:#{type}:*" : "reports:*"
|
||||||
|
|
||||||
|
@ -285,15 +301,22 @@ class Report
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.post_action_report(report, post_action_type)
|
def self.post_action_report(report, post_action_type)
|
||||||
category_filter = report.filters.dig(:category)
|
category_id, include_subcategories = report.add_category_filter
|
||||||
report.add_filter('category', default: category_filter)
|
|
||||||
|
|
||||||
report.data = []
|
report.data = []
|
||||||
PostAction.count_per_day_for_type(post_action_type, category_id: category_filter, start_date: report.start_date, end_date: report.end_date).each do |date, count|
|
PostAction.count_per_day_for_type(post_action_type, category_id: category_id, include_subcategories: include_subcategories, start_date: report.start_date, end_date: report.end_date).each do |date, count|
|
||||||
report.data << { x: date, y: count }
|
report.data << { x: date, y: count }
|
||||||
end
|
end
|
||||||
|
|
||||||
countable = PostAction.unscoped.where(post_action_type_id: post_action_type)
|
countable = PostAction.unscoped.where(post_action_type_id: post_action_type)
|
||||||
countable = countable.joins(post: :topic).merge(Topic.in_category_and_subcategories(category_filter)) if category_filter
|
if category_id
|
||||||
|
if include_subcategories
|
||||||
|
countable = countable.joins(post: :topic).where('topics.category_id IN (?)', Category.subcategory_ids(category_id))
|
||||||
|
else
|
||||||
|
countable = countable.joins(post: :topic).where('topics.category_id = ?', category_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
add_counts report, countable, 'post_actions.created_at'
|
add_counts report, countable, 'post_actions.created_at'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
Report.add_report('flags') do |report|
|
Report.add_report('flags') do |report|
|
||||||
category_filter = report.filters.dig(:category)
|
category_id, include_subcategories = report.add_category_filter
|
||||||
report.add_filter('category', default: category_filter)
|
|
||||||
|
|
||||||
report.icon = 'flag'
|
report.icon = 'flag'
|
||||||
report.higher_is_better = false
|
report.higher_is_better = false
|
||||||
|
@ -13,13 +12,18 @@ Report.add_report('flags') do |report|
|
||||||
:count_by_date,
|
:count_by_date,
|
||||||
report.start_date,
|
report.start_date,
|
||||||
report.end_date,
|
report.end_date,
|
||||||
category_filter
|
category_id,
|
||||||
|
include_subcategories
|
||||||
)
|
)
|
||||||
|
|
||||||
countable = ReviewableFlaggedPost.scores_with_topics
|
countable = ReviewableFlaggedPost.scores_with_topics
|
||||||
|
|
||||||
if category_filter
|
if category_id
|
||||||
countable.merge!(Topic.in_category_and_subcategories(category_filter))
|
if include_subcategories
|
||||||
|
countable = countable.where('topics.category_id IN (?)', Category.subcategory_ids(category_id))
|
||||||
|
else
|
||||||
|
countable = countable.where('topics.category_id = ?', category_id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
add_counts report, countable, 'reviewable_scores.created_at'
|
add_counts report, countable, 'reviewable_scores.created_at'
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
Report.add_report('post_edits') do |report|
|
Report.add_report('post_edits') do |report|
|
||||||
category_filter = report.filters.dig(:category)
|
category_id, include_subcategories = report.add_category_filter
|
||||||
report.add_filter('category', default: category_filter)
|
|
||||||
|
|
||||||
report.modes = [:table]
|
report.modes = [:table]
|
||||||
|
|
||||||
|
@ -77,13 +76,13 @@ Report.add_report('post_edits') do |report|
|
||||||
/*limit*/
|
/*limit*/
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
if category_filter
|
if category_id
|
||||||
builder.join "topics t ON t.id = p.topic_id"
|
builder.join "topics t ON t.id = p.topic_id"
|
||||||
builder.where("t.category_id = :category_id
|
if include_subcategories
|
||||||
OR t.category_id IN (
|
builder.where("t.category_id IN (?)", Category.subcategory_ids(category_id))
|
||||||
SELECT id FROM categories
|
else
|
||||||
WHERE categories.parent_category_id = :category_id
|
builder.where("t.category_id = ?", category_id)
|
||||||
)", category_id: category_filter)
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
builder.where("editor.id > 0 AND editor.id != author.id")
|
builder.where("editor.id > 0 AND editor.id != author.id")
|
||||||
|
|
|
@ -3,14 +3,18 @@
|
||||||
Report.add_report('posts') do |report|
|
Report.add_report('posts') do |report|
|
||||||
report.modes = [:table, :chart]
|
report.modes = [:table, :chart]
|
||||||
|
|
||||||
category_filter = report.filters.dig(:category)
|
category_id, include_subcategories = report.add_category_filter
|
||||||
report.add_filter('category', default: category_filter)
|
|
||||||
|
|
||||||
basic_report_about report, Post, :public_posts_count_per_day, report.start_date, report.end_date, category_filter
|
basic_report_about report, Post, :public_posts_count_per_day, report.start_date, report.end_date, category_id, include_subcategories
|
||||||
|
|
||||||
countable = Post.public_posts.where(post_type: Post.types[:regular])
|
countable = Post.public_posts.where(post_type: Post.types[:regular])
|
||||||
if category_filter
|
if category_id
|
||||||
countable = countable.joins(:topic).merge(Topic.in_category_and_subcategories(category_filter))
|
if include_subcategories
|
||||||
|
countable = countable.joins(:topic).where('topics.category_id IN (?)', Category.subcategory_ids(category_id))
|
||||||
|
else
|
||||||
|
countable = countable.joins(:topic).where('topics.category_id = ?', category_id)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
add_counts report, countable, 'posts.created_at'
|
add_counts report, countable, 'posts.created_at'
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
Report.add_report('profile_views') do |report|
|
Report.add_report('profile_views') do |report|
|
||||||
group_filter = report.filters.dig(:group)
|
group_filter = report.filters.dig(:group)
|
||||||
report.add_filter('group', default: group_filter)
|
report.add_filter('group', type: 'group', default: group_filter)
|
||||||
|
|
||||||
start_date = report.start_date
|
start_date = report.start_date
|
||||||
end_date = report.end_date
|
end_date = report.end_date
|
||||||
|
|
|
@ -4,7 +4,7 @@ Report.add_report('signups') do |report|
|
||||||
report.icon = 'user-plus'
|
report.icon = 'user-plus'
|
||||||
|
|
||||||
group_filter = report.filters.dig(:group)
|
group_filter = report.filters.dig(:group)
|
||||||
report.add_filter('group', default: group_filter)
|
report.add_filter('group', type: 'group', default: group_filter)
|
||||||
|
|
||||||
if group_filter
|
if group_filter
|
||||||
basic_report_about report, User.real, :count_by_signup_date, report.start_date, report.end_date, group_filter
|
basic_report_about report, User.real, :count_by_signup_date, report.start_date, report.end_date, group_filter
|
||||||
|
|
|
@ -2,17 +2,17 @@
|
||||||
|
|
||||||
Report.add_report('time_to_first_response') do |report|
|
Report.add_report('time_to_first_response') do |report|
|
||||||
category_filter = report.filters.dig(:category)
|
category_filter = report.filters.dig(:category)
|
||||||
report.add_filter('category', default: category_filter)
|
category_id, include_subcategories = report.add_category_filter
|
||||||
|
|
||||||
report.icon = 'reply'
|
report.icon = 'reply'
|
||||||
report.higher_is_better = false
|
report.higher_is_better = false
|
||||||
report.data = []
|
report.data = []
|
||||||
|
|
||||||
Topic.time_to_first_response_per_day(report.start_date, report.end_date, category_id: category_filter).each do |r|
|
Topic.time_to_first_response_per_day(report.start_date, report.end_date, category_id: category_id, include_subcategories: include_subcategories).each do |r|
|
||||||
report.data << { x: r['date'], y: r['hours'].to_f.round(2) }
|
report.data << { x: r['date'], y: r['hours'].to_f.round(2) }
|
||||||
end
|
end
|
||||||
|
|
||||||
report.total = Topic.time_to_first_response_total(category_id: category_filter)
|
report.total = Topic.time_to_first_response_total(category_id: category_id, include_subcategories: include_subcategories)
|
||||||
|
|
||||||
report.prev30Days = Topic.time_to_first_response_total(start_date: report.start_date - 30.days, end_date: report.start_date, category_id: category_filter)
|
report.prev30Days = Topic.time_to_first_response_total(start_date: report.start_date - 30.days, end_date: report.start_date, category_id: category_id, include_subcategories: include_subcategories)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
Report.add_report('top_referred_topics') do |report|
|
Report.add_report('top_referred_topics') do |report|
|
||||||
category_filter = report.filters.dig(:category)
|
category_id, include_subcategories = report.add_category_filter
|
||||||
report.add_filter('category', default: category_filter)
|
|
||||||
|
|
||||||
report.modes = [:table]
|
report.modes = [:table]
|
||||||
|
|
||||||
|
@ -26,7 +25,8 @@ Report.add_report('top_referred_topics') do |report|
|
||||||
end_date: report.end_date,
|
end_date: report.end_date,
|
||||||
start_date: report.start_date,
|
start_date: report.start_date,
|
||||||
limit: report.limit || 8,
|
limit: report.limit || 8,
|
||||||
category_id: category_filter
|
category_id: category_id,
|
||||||
|
include_subcategories: include_subcategories
|
||||||
}
|
}
|
||||||
result = nil
|
result = nil
|
||||||
result = IncomingLinksReport.find(:top_referred_topics, options)
|
result = IncomingLinksReport.find(:top_referred_topics, options)
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
Report.add_report('top_traffic_sources') do |report|
|
Report.add_report('top_traffic_sources') do |report|
|
||||||
category_filter = report.filters.dig(:category)
|
category_id, include_subcategories = report.add_category_filter
|
||||||
report.add_filter('category', default: category_filter)
|
|
||||||
|
|
||||||
report.modes = [:table]
|
report.modes = [:table]
|
||||||
|
|
||||||
|
@ -27,7 +26,8 @@ Report.add_report('top_traffic_sources') do |report|
|
||||||
end_date: report.end_date,
|
end_date: report.end_date,
|
||||||
start_date: report.start_date,
|
start_date: report.start_date,
|
||||||
limit: report.limit || 8,
|
limit: report.limit || 8,
|
||||||
category_id: category_filter
|
category_id: category_id,
|
||||||
|
include_subcategories: include_subcategories
|
||||||
}
|
}
|
||||||
|
|
||||||
result = IncomingLinksReport.find(:top_traffic_sources, options)
|
result = IncomingLinksReport.find(:top_traffic_sources, options)
|
||||||
|
|
|
@ -5,10 +5,9 @@ Report.add_report('top_uploads') do |report|
|
||||||
|
|
||||||
extension_filter = report.filters.dig(:"file-extension")
|
extension_filter = report.filters.dig(:"file-extension")
|
||||||
report.add_filter('file-extension',
|
report.add_filter('file-extension',
|
||||||
|
type: 'list',
|
||||||
default: extension_filter || 'any',
|
default: extension_filter || 'any',
|
||||||
choices: (
|
choices: (SiteSetting.authorized_extensions.split('|') + Array(extension_filter)).uniq
|
||||||
SiteSetting.authorized_extensions.split('|') + Array(extension_filter)
|
|
||||||
).uniq
|
|
||||||
)
|
)
|
||||||
|
|
||||||
report.labels = [
|
report.labels = [
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
Report.add_report('topics') do |report|
|
Report.add_report('topics') do |report|
|
||||||
category_filter = report.filters.dig(:category)
|
category_id, include_subcategories = report.add_category_filter
|
||||||
report.add_filter('category', default: category_filter)
|
|
||||||
|
|
||||||
basic_report_about report, Topic, :listable_count_per_day, report.start_date, report.end_date, category_filter
|
basic_report_about report, Topic, :listable_count_per_day, report.start_date, report.end_date, category_id, include_subcategories
|
||||||
|
|
||||||
countable = Topic.listable_topics
|
countable = Topic.listable_topics
|
||||||
if category_filter
|
countable = countable.where(category_id: include_subcategories ? Category.subcategory_ids(category_id) : category_id) if category_id
|
||||||
countable = countable.in_category_and_subcategories(category_filter)
|
|
||||||
end
|
|
||||||
add_counts report, countable, 'topics.created_at'
|
add_counts report, countable, 'topics.created_at'
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
Report.add_report('topics_with_no_response') do |report|
|
Report.add_report('topics_with_no_response') do |report|
|
||||||
category_filter = report.filters.dig(:category)
|
category_id, include_subcategories = report.add_category_filter
|
||||||
report.add_filter('category', default: category_filter)
|
|
||||||
|
|
||||||
report.data = []
|
report.data = []
|
||||||
Topic.with_no_response_per_day(report.start_date, report.end_date, category_filter).each do |r|
|
Topic.with_no_response_per_day(report.start_date, report.end_date, category_id, include_subcategories).each do |r|
|
||||||
report.data << { x: r['date'], y: r['count'].to_i }
|
report.data << { x: r['date'], y: r['count'].to_i }
|
||||||
end
|
end
|
||||||
|
|
||||||
report.total = Topic.with_no_response_total(category_id: category_filter)
|
report.total = Topic.with_no_response_total(category_id: category_id, include_subcategories: include_subcategories)
|
||||||
|
|
||||||
report.prev30Days = Topic.with_no_response_total(start_date: report.start_date - 30.days, end_date: report.start_date, category_id: category_filter)
|
report.prev30Days = Topic.with_no_response_total(start_date: report.start_date - 30.days, end_date: report.start_date, category_id: category_id, include_subcategories: include_subcategories)
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
Report.add_report('visits') do |report|
|
Report.add_report('visits') do |report|
|
||||||
group_filter = report.filters.dig(:group)
|
group_filter = report.filters.dig(:group)
|
||||||
report.add_filter('group', default: group_filter)
|
report.add_filter('group', type: 'group', default: group_filter)
|
||||||
|
|
||||||
report.icon = 'user'
|
report.icon = 'user'
|
||||||
|
|
||||||
|
|
|
@ -534,10 +534,18 @@ class Reviewable < ActiveRecord::Base
|
||||||
ReviewableScore.joins(reviewable: :topic).where("reviewables.type = ?", name)
|
ReviewableScore.joins(reviewable: :topic).where("reviewables.type = ?", name)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.count_by_date(start_date, end_date, category_id = nil)
|
def self.count_by_date(start_date, end_date, category_id = nil, include_subcategories = false)
|
||||||
scores_with_topics
|
query = scores_with_topics.where('reviewable_scores.created_at BETWEEN ? AND ?', start_date, end_date)
|
||||||
.where('reviewable_scores.created_at BETWEEN ? AND ?', start_date, end_date)
|
|
||||||
.where("topics.category_id = COALESCE(?, topics.category_id)", category_id)
|
if category_id
|
||||||
|
if include_subcategories
|
||||||
|
query = query.where("topics.category_id IN (?)", Category.subcategory_ids(category_id))
|
||||||
|
else
|
||||||
|
query = query.where("topics.category_id = ?", category_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
query
|
||||||
.group("date(reviewable_scores.created_at)")
|
.group("date(reviewable_scores.created_at)")
|
||||||
.order('date(reviewable_scores.created_at)')
|
.order('date(reviewable_scores.created_at)')
|
||||||
.count
|
.count
|
||||||
|
|
|
@ -454,10 +454,10 @@ class Topic < ActiveRecord::Base
|
||||||
((Time.zone.now - created_at) / 1.minute).round
|
((Time.zone.now - created_at) / 1.minute).round
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.listable_count_per_day(start_date, end_date, category_id = nil)
|
def self.listable_count_per_day(start_date, end_date, category_id = nil, include_subcategories = false)
|
||||||
result = listable_topics.where("topics.created_at >= ? AND topics.created_at <= ?", start_date, end_date)
|
result = listable_topics.where("topics.created_at >= ? AND topics.created_at <= ?", start_date, end_date)
|
||||||
result = result.group('date(topics.created_at)').order('date(topics.created_at)')
|
result = result.group('date(topics.created_at)').order('date(topics.created_at)')
|
||||||
result = result.where(category_id: category_id) if category_id
|
result = result.where(category_id: include_subcategories ? Category.subcategory_ids(category_id) : category_id) if category_id
|
||||||
result.count
|
result.count
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1294,7 +1294,13 @@ class Topic < ActiveRecord::Base
|
||||||
builder = DB.build(sql)
|
builder = DB.build(sql)
|
||||||
builder.where("t.created_at >= :start_date", start_date: opts[:start_date]) if opts[: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: opts[:end_date]) if opts[:end_date]
|
builder.where("t.created_at < :end_date", end_date: opts[:end_date]) if opts[:end_date]
|
||||||
builder.where("t.category_id IN (:subcategory_ids)", subcategory_ids: Category.subcategory_ids(opts[:category_id].to_i)) if opts[:category_id]
|
if opts[:category_id]
|
||||||
|
if opts[:include_subcategories]
|
||||||
|
builder.where("t.category_id IN (?)", Category.subcategory_ids(opts[:category_id]))
|
||||||
|
else
|
||||||
|
builder.where("t.category_id = ?", opts[:category_id])
|
||||||
|
end
|
||||||
|
end
|
||||||
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")
|
||||||
|
@ -1329,11 +1335,17 @@ class Topic < ActiveRecord::Base
|
||||||
ORDER BY tt.created_at
|
ORDER BY tt.created_at
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
def self.with_no_response_per_day(start_date, end_date, category_id = nil)
|
def self.with_no_response_per_day(start_date, end_date, category_id = nil, include_subcategories = nil)
|
||||||
builder = DB.build(WITH_NO_RESPONSE_SQL)
|
builder = DB.build(WITH_NO_RESPONSE_SQL)
|
||||||
builder.where("t.created_at >= :start_date", start_date: start_date) if start_date
|
builder.where("t.created_at >= :start_date", start_date: start_date) if 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: end_date) if end_date
|
||||||
builder.where("t.category_id IN (:subcategory_ids)", subcategory_ids: Category.subcategory_ids(category_id.to_i)) if category_id
|
if category_id
|
||||||
|
if include_subcategories
|
||||||
|
builder.where("t.category_id IN (?)", Category.subcategory_ids(category_id))
|
||||||
|
else
|
||||||
|
builder.where("t.category_id = ?", category_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
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.query_hash
|
builder.query_hash
|
||||||
|
@ -1353,7 +1365,13 @@ class Topic < ActiveRecord::Base
|
||||||
|
|
||||||
def self.with_no_response_total(opts = {})
|
def self.with_no_response_total(opts = {})
|
||||||
builder = DB.build(WITH_NO_RESPONSE_TOTAL_SQL)
|
builder = DB.build(WITH_NO_RESPONSE_TOTAL_SQL)
|
||||||
builder.where("t.category_id IN (:subcategory_ids)", subcategory_ids: Category.subcategory_ids(opts[:category_id].to_i)) if opts[:category_id]
|
if opts[:category_id]
|
||||||
|
if opts[:include_subcategories]
|
||||||
|
builder.where("t.category_id IN (?)", Category.subcategory_ids(opts[:category_id]))
|
||||||
|
else
|
||||||
|
builder.where("t.category_id = ?", opts[:category_id])
|
||||||
|
end
|
||||||
|
end
|
||||||
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.query_single.first.to_i
|
builder.query_single.first.to_i
|
||||||
|
|
|
@ -3411,6 +3411,8 @@ en:
|
||||||
label: Group
|
label: Group
|
||||||
category:
|
category:
|
||||||
label: Category
|
label: Category
|
||||||
|
include-subcategories:
|
||||||
|
label: "Include Subcategories"
|
||||||
|
|
||||||
commits:
|
commits:
|
||||||
latest_changes: "Latest changes: please update often!"
|
latest_changes: "Latest changes: please update often!"
|
||||||
|
|
|
@ -771,7 +771,7 @@ describe Report do
|
||||||
include_examples 'category filtering'
|
include_examples 'category filtering'
|
||||||
|
|
||||||
context "on subcategories" do
|
context "on subcategories" do
|
||||||
let(:report) { Report.find('flags', filters: { category: c0.id }) }
|
let(:report) { Report.find('flags', filters: { category: c0.id, 'include-subcategories': true }) }
|
||||||
|
|
||||||
include_examples 'category filtering on subcategories'
|
include_examples 'category filtering on subcategories'
|
||||||
end
|
end
|
||||||
|
@ -801,7 +801,7 @@ describe Report do
|
||||||
include_examples 'category filtering'
|
include_examples 'category filtering'
|
||||||
|
|
||||||
context "on subcategories" do
|
context "on subcategories" do
|
||||||
let(:report) { Report.find('topics', filters: { category: c0.id }) }
|
let(:report) { Report.find('topics', filters: { category: c0.id, 'include-subcategories': true }) }
|
||||||
|
|
||||||
include_examples 'category filtering on subcategories'
|
include_examples 'category filtering on subcategories'
|
||||||
end
|
end
|
||||||
|
@ -892,7 +892,7 @@ describe Report do
|
||||||
include_examples 'category filtering'
|
include_examples 'category filtering'
|
||||||
|
|
||||||
context "on subcategories" do
|
context "on subcategories" do
|
||||||
let(:report) { Report.find('posts', filters: { category: c0.id }) }
|
let(:report) { Report.find('posts', filters: { category: c0.id, 'include-subcategories': true }) }
|
||||||
|
|
||||||
include_examples 'category filtering on subcategories'
|
include_examples 'category filtering on subcategories'
|
||||||
end
|
end
|
||||||
|
@ -924,7 +924,7 @@ describe Report do
|
||||||
include_examples 'category filtering'
|
include_examples 'category filtering'
|
||||||
|
|
||||||
context "on subcategories" do
|
context "on subcategories" do
|
||||||
let(:report) { Report.find('topics_with_no_response', filters: { category: c0.id }) }
|
let(:report) { Report.find('topics_with_no_response', filters: { category: c0.id, 'include-subcategories': true }) }
|
||||||
|
|
||||||
include_examples 'category filtering on subcategories'
|
include_examples 'category filtering on subcategories'
|
||||||
end
|
end
|
||||||
|
@ -960,7 +960,7 @@ describe Report do
|
||||||
include_examples 'category filtering'
|
include_examples 'category filtering'
|
||||||
|
|
||||||
context "on subcategories" do
|
context "on subcategories" do
|
||||||
let(:report) { Report.find('likes', filters: { category: c0.id }) }
|
let(:report) { Report.find('likes', filters: { category: c0.id, 'include-subcategories': true }) }
|
||||||
|
|
||||||
include_examples 'category filtering on subcategories'
|
include_examples 'category filtering on subcategories'
|
||||||
end
|
end
|
||||||
|
|
|
@ -2359,7 +2359,7 @@ describe Topic do
|
||||||
Fabricate(:post, topic: topic, user: topic.user, post_number: 1, created_at: 3.hours.ago)
|
Fabricate(:post, topic: topic, user: topic.user, post_number: 1, created_at: 3.hours.ago)
|
||||||
Fabricate(:post, topic: topic, post_number: 2, created_at: 2.hours.ago)
|
Fabricate(:post, topic: topic, post_number: 2, created_at: 2.hours.ago)
|
||||||
|
|
||||||
expect(Topic.time_to_first_response_total(category_id: category.id)).to eq(1)
|
expect(Topic.time_to_first_response_total(category_id: category.id, include_subcategories: true)).to eq(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should only count regular posts as the first response" do
|
it "should only count regular posts as the first response" do
|
||||||
|
|
|
@ -61,7 +61,7 @@ let signups = {
|
||||||
dates_filtering: true,
|
dates_filtering: true,
|
||||||
report_key: 'reports:signups:start:end:[:prev_period]:50:{"group":"88"}:4',
|
report_key: 'reports:signups:start:end:[:prev_period]:50:{"group":"88"}:4',
|
||||||
available_filters: [
|
available_filters: [
|
||||||
{ id: "group", allow_any: false, choices: [], default: "88" }
|
{ id: "group", type: "group", allow_any: false, choices: [], default: "88" }
|
||||||
],
|
],
|
||||||
labels: [
|
labels: [
|
||||||
{ type: "date", properties: ["x"], title: "Day" },
|
{ type: "date", properties: ["x"], title: "Day" },
|
||||||
|
|
Loading…
Reference in New Issue