2019-04-30 08:27:42 +08:00
|
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
2022-07-28 10:27:38 +08:00
|
|
|
|
RSpec.describe Report do
|
2021-06-02 13:33:15 +08:00
|
|
|
|
let(:user) { Fabricate(:user) }
|
2024-07-09 13:39:10 +08:00
|
|
|
|
let(:category_1) { Fabricate(:category, user: user) }
|
|
|
|
|
let(:category_2) { Fabricate(:category, parent_category: category_1, user: user) } # id: 2
|
|
|
|
|
let(:category_3) { Fabricate(:category, user: user) }
|
2019-02-02 00:44:37 +08:00
|
|
|
|
|
2018-07-27 07:24:18 +08:00
|
|
|
|
shared_examples "no data" do
|
|
|
|
|
context "with no data" do
|
|
|
|
|
it "returns an empty report" do
|
|
|
|
|
expect(report.data).to be_blank
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
shared_examples "category filtering" do
|
|
|
|
|
it "returns the filtered data" do
|
|
|
|
|
expect(report.total).to eq 1
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2018-08-10 08:50:05 +08:00
|
|
|
|
shared_examples "category filtering on subcategories" do
|
2018-08-10 14:08:07 +08:00
|
|
|
|
it "returns the filtered data" do
|
|
|
|
|
expect(report.total).to eq(1)
|
2018-08-10 08:50:05 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2018-07-27 07:24:18 +08:00
|
|
|
|
shared_examples "with data x/y" do
|
|
|
|
|
it "returns today's data" do
|
|
|
|
|
expect(report.data.select { |v| v[:x].today? }).to be_present
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "returns correct data for period" do
|
|
|
|
|
expect(report.data[0][:y]).to eq 3
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "returns total" do
|
|
|
|
|
expect(report.total).to eq 4
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "returns previous 30 day’s data" do
|
|
|
|
|
expect(report.prev30Days).to be_present
|
|
|
|
|
end
|
|
|
|
|
end
|
2013-03-21 01:54:32 +08:00
|
|
|
|
|
2018-02-02 04:50:41 +08:00
|
|
|
|
describe "counting" do
|
|
|
|
|
describe "requests" do
|
2023-06-21 22:00:19 +08:00
|
|
|
|
subject(:json) { Report.find("http_total_reqs").as_json }
|
|
|
|
|
|
2018-02-02 04:50:41 +08:00
|
|
|
|
before do
|
2024-03-01 08:07:35 +08:00
|
|
|
|
freeze_time_safe
|
2018-02-02 04:50:41 +08:00
|
|
|
|
|
|
|
|
|
# today, an incomplete day:
|
2020-01-06 14:17:07 +08:00
|
|
|
|
application_requests = [
|
|
|
|
|
{
|
|
|
|
|
date: 0.days.ago.to_time,
|
|
|
|
|
req_type: ApplicationRequest.req_types["http_total"],
|
|
|
|
|
count: 1,
|
|
|
|
|
},
|
|
|
|
|
]
|
2018-02-02 04:50:41 +08:00
|
|
|
|
|
|
|
|
|
# 60 complete days:
|
2023-12-07 06:25:00 +08:00
|
|
|
|
30.times.each do |i|
|
|
|
|
|
application_requests.concat(
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
date: (i + 1).days.ago.to_time,
|
|
|
|
|
req_type: ApplicationRequest.req_types["http_total"],
|
|
|
|
|
count: 10,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
30.times.each do |i|
|
|
|
|
|
application_requests.concat(
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
date: (31 + i).days.ago.to_time,
|
|
|
|
|
req_type: ApplicationRequest.req_types["http_total"],
|
|
|
|
|
count: 100,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
)
|
|
|
|
|
end
|
2020-01-06 14:17:07 +08:00
|
|
|
|
|
|
|
|
|
ApplicationRequest.insert_all(application_requests)
|
2018-02-02 04:50:41 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "counts the correct records" do
|
|
|
|
|
expect(json[:data].size).to eq(31) # today and 30 full days
|
|
|
|
|
expect(json[:data][0..-2].sum { |d| d[:y] }).to eq(300)
|
|
|
|
|
expect(json[:prev30Days]).to eq(3000)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe "topics" do
|
|
|
|
|
before do
|
2018-05-11 11:30:21 +08:00
|
|
|
|
Report.clear_cache
|
2024-03-01 08:07:35 +08:00
|
|
|
|
freeze_time_safe
|
2020-01-06 14:17:07 +08:00
|
|
|
|
user = Fabricate(:user)
|
|
|
|
|
topics =
|
|
|
|
|
((0..32).to_a + [60, 61, 62, 63]).map do |i|
|
|
|
|
|
date = i.days.ago
|
|
|
|
|
{
|
|
|
|
|
user_id: user.id,
|
|
|
|
|
last_post_user_id: user.id,
|
|
|
|
|
title: "topic #{i}",
|
|
|
|
|
category_id: SiteSetting.uncategorized_category_id,
|
|
|
|
|
bumped_at: date,
|
|
|
|
|
created_at: date,
|
|
|
|
|
updated_at: date,
|
|
|
|
|
}
|
2018-02-02 04:50:41 +08:00
|
|
|
|
end
|
2020-01-06 14:17:07 +08:00
|
|
|
|
Topic.insert_all(topics)
|
2018-02-02 04:50:41 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "counts the correct records" do
|
2018-05-11 11:30:21 +08:00
|
|
|
|
json = Report.find("topics").as_json
|
2018-02-02 04:50:41 +08:00
|
|
|
|
expect(json[:data].size).to eq(31)
|
|
|
|
|
expect(json[:prev30Days]).to eq(3)
|
2018-05-11 11:30:21 +08:00
|
|
|
|
|
|
|
|
|
# lets make sure we can ask for the correct options for the report
|
|
|
|
|
json =
|
|
|
|
|
Report.find(
|
|
|
|
|
"topics",
|
|
|
|
|
start_date: 5.days.ago.beginning_of_day,
|
|
|
|
|
end_date: 1.day.ago.end_of_day,
|
|
|
|
|
facets: [:prev_period],
|
|
|
|
|
).as_json
|
|
|
|
|
|
|
|
|
|
expect(json[:prev_period]).to eq(5)
|
|
|
|
|
expect(json[:data].length).to eq(5)
|
|
|
|
|
expect(json[:prev30Days]).to eq(nil)
|
2018-02-02 04:50:41 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2013-04-04 01:25:52 +08:00
|
|
|
|
describe "visits report" do
|
|
|
|
|
let(:report) { Report.find("visits") }
|
|
|
|
|
|
2018-07-27 07:24:18 +08:00
|
|
|
|
include_examples "no data"
|
2013-04-04 01:25:52 +08:00
|
|
|
|
|
|
|
|
|
context "with visits" do
|
|
|
|
|
let(:user) { Fabricate(:user) }
|
|
|
|
|
|
2015-02-05 08:33:13 +08:00
|
|
|
|
it "returns a report with data" do
|
2024-03-01 08:07:35 +08:00
|
|
|
|
freeze_time_safe
|
2015-02-05 08:33:13 +08:00
|
|
|
|
user.user_visits.create(visited_at: 1.hour.from_now)
|
2013-04-04 01:25:52 +08:00
|
|
|
|
user.user_visits.create(visited_at: 1.day.ago)
|
2019-01-19 00:24:18 +08:00
|
|
|
|
user.user_visits.create(visited_at: 2.days.ago, mobile: true)
|
|
|
|
|
user.user_visits.create(visited_at: 45.days.ago)
|
|
|
|
|
user.user_visits.create(visited_at: 46.days.ago, mobile: true)
|
|
|
|
|
|
2015-01-06 00:04:23 +08:00
|
|
|
|
expect(report.data).to be_present
|
2019-01-19 00:24:18 +08:00
|
|
|
|
expect(report.data.count).to eq(3)
|
2015-01-06 00:04:23 +08:00
|
|
|
|
expect(report.data.select { |v| v[:x].today? }).to be_present
|
2019-01-19 00:24:18 +08:00
|
|
|
|
expect(report.prev30Days).to eq(2)
|
2014-12-29 20:29:09 +08:00
|
|
|
|
end
|
2013-04-04 01:25:52 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2019-01-19 00:24:18 +08:00
|
|
|
|
describe "mobile visits report" do
|
|
|
|
|
let(:report) { Report.find("mobile_visits") }
|
|
|
|
|
|
|
|
|
|
include_examples "no data"
|
|
|
|
|
|
|
|
|
|
context "with visits" do
|
|
|
|
|
let(:user) { Fabricate(:user) }
|
|
|
|
|
|
|
|
|
|
it "returns a report with data" do
|
2024-03-01 08:07:35 +08:00
|
|
|
|
freeze_time_safe
|
2019-01-19 00:24:18 +08:00
|
|
|
|
user.user_visits.create(visited_at: 1.hour.from_now)
|
|
|
|
|
user.user_visits.create(visited_at: 2.days.ago, mobile: true)
|
|
|
|
|
user.user_visits.create(visited_at: 45.days.ago)
|
|
|
|
|
user.user_visits.create(visited_at: 46.days.ago, mobile: true)
|
|
|
|
|
|
|
|
|
|
expect(report.data).to be_present
|
|
|
|
|
expect(report.data.count).to eq(1)
|
|
|
|
|
expect(report.data.select { |v| v[:x].today? }).not_to be_present
|
|
|
|
|
expect(report.prev30Days).to eq(1)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2013-04-04 01:25:52 +08:00
|
|
|
|
%i[signup topic post flag like email].each do |arg|
|
|
|
|
|
describe "#{arg} report" do
|
|
|
|
|
pluralized = arg.to_s.pluralize
|
|
|
|
|
|
|
|
|
|
let(:report) { Report.find(pluralized) }
|
|
|
|
|
|
2023-03-14 18:42:11 +08:00
|
|
|
|
context "with no #{pluralized}" do
|
2013-04-04 01:25:52 +08:00
|
|
|
|
it "returns an empty report" do
|
2014-12-31 22:55:03 +08:00
|
|
|
|
expect(report.data).to be_blank
|
2013-04-04 01:25:52 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with #{pluralized}" do
|
2014-12-30 22:06:15 +08:00
|
|
|
|
before(:each) do
|
2024-03-01 08:07:35 +08:00
|
|
|
|
freeze_time_safe
|
2019-01-04 01:03:01 +08:00
|
|
|
|
|
|
|
|
|
if arg == :flag
|
2023-12-13 17:18:42 +08:00
|
|
|
|
user = Fabricate(:user, refresh_auto_groups: true)
|
2020-01-06 14:17:07 +08:00
|
|
|
|
topic = Fabricate(:topic, user: user)
|
2023-11-29 13:38:07 +08:00
|
|
|
|
builder = ->(dt) do
|
2020-01-06 14:17:07 +08:00
|
|
|
|
PostActionCreator.create(
|
|
|
|
|
user,
|
|
|
|
|
Fabricate(:post, topic: topic, user: user),
|
|
|
|
|
:spam,
|
|
|
|
|
created_at: dt,
|
|
|
|
|
)
|
2023-11-29 13:38:07 +08:00
|
|
|
|
end
|
2020-01-06 14:17:07 +08:00
|
|
|
|
elsif arg == :signup
|
|
|
|
|
builder = ->(dt) { Fabricate(:user, created_at: dt) }
|
2013-04-04 01:25:52 +08:00
|
|
|
|
else
|
2020-01-06 14:17:07 +08:00
|
|
|
|
user = Fabricate(:user)
|
|
|
|
|
factories = { email: :email_log }
|
|
|
|
|
builder = ->(dt) { Fabricate(factories[arg] || arg, created_at: dt, user: user) }
|
2013-04-04 01:25:52 +08:00
|
|
|
|
end
|
2019-01-04 01:03:01 +08:00
|
|
|
|
|
|
|
|
|
[
|
|
|
|
|
DateTime.now,
|
|
|
|
|
1.hour.ago,
|
|
|
|
|
1.hour.ago,
|
|
|
|
|
1.day.ago,
|
|
|
|
|
2.days.ago,
|
|
|
|
|
30.days.ago,
|
|
|
|
|
35.days.ago,
|
|
|
|
|
].each(&builder)
|
2013-04-04 01:25:52 +08:00
|
|
|
|
end
|
|
|
|
|
|
2020-01-06 14:17:07 +08:00
|
|
|
|
it "returns today's, total and previous 30 day's data" do
|
2018-02-02 04:50:41 +08:00
|
|
|
|
expect(report.data.select { |v| v[:x].today? }).to be_present
|
|
|
|
|
expect(report.total).to eq 7
|
|
|
|
|
expect(report.prev30Days).to be_present
|
|
|
|
|
end
|
2013-04-04 01:25:52 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
2017-07-28 09:20:09 +08:00
|
|
|
|
end
|
2013-04-04 01:25:52 +08:00
|
|
|
|
|
2023-01-09 19:18:21 +08:00
|
|
|
|
%i[
|
2015-04-13 01:46:13 +08:00
|
|
|
|
http_total
|
|
|
|
|
http_2xx
|
|
|
|
|
http_background
|
|
|
|
|
http_3xx
|
|
|
|
|
http_4xx
|
|
|
|
|
http_5xx
|
|
|
|
|
page_view_crawler
|
|
|
|
|
page_view_logged_in
|
|
|
|
|
page_view_anon
|
|
|
|
|
].each do |request_type|
|
|
|
|
|
describe "#{request_type} request reports" do
|
2018-05-04 14:02:08 +08:00
|
|
|
|
let(:report) do
|
|
|
|
|
Report.find("#{request_type}_reqs", start_date: 10.days.ago.to_time, end_date: Time.now)
|
2023-01-09 19:18:21 +08:00
|
|
|
|
end
|
2015-04-13 01:46:13 +08:00
|
|
|
|
|
|
|
|
|
context "with no #{request_type} records" do
|
|
|
|
|
it "returns an empty report" do
|
|
|
|
|
expect(report.data).to be_blank
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with #{request_type}" do
|
2022-05-05 09:53:54 +08:00
|
|
|
|
before do
|
2024-03-01 08:07:35 +08:00
|
|
|
|
freeze_time_safe
|
2020-01-06 14:17:07 +08:00
|
|
|
|
application_requests = [
|
|
|
|
|
{
|
|
|
|
|
date: 35.days.ago.to_time,
|
|
|
|
|
req_type: ApplicationRequest.req_types[request_type.to_s],
|
|
|
|
|
count: 35,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
date: 7.days.ago.to_time,
|
|
|
|
|
req_type: ApplicationRequest.req_types[request_type.to_s],
|
|
|
|
|
count: 8,
|
2023-01-09 19:18:21 +08:00
|
|
|
|
},
|
2020-01-06 14:17:07 +08:00
|
|
|
|
{ date: Time.now, req_type: ApplicationRequest.req_types[request_type.to_s], count: 1 },
|
|
|
|
|
{
|
|
|
|
|
date: 1.day.ago.to_time,
|
|
|
|
|
req_type: ApplicationRequest.req_types[request_type.to_s],
|
|
|
|
|
count: 2,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
date: 2.days.ago.to_time,
|
|
|
|
|
req_type: ApplicationRequest.req_types[request_type.to_s],
|
|
|
|
|
count: 3,
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
ApplicationRequest.insert_all(application_requests)
|
2015-04-13 01:46:13 +08:00
|
|
|
|
end
|
|
|
|
|
|
2020-01-06 14:17:07 +08:00
|
|
|
|
it "returns a report with data" do
|
2021-05-21 09:43:47 +08:00
|
|
|
|
# expected number of records
|
2020-01-06 14:17:07 +08:00
|
|
|
|
expect(report.data.count).to eq 4
|
2015-04-13 01:46:13 +08:00
|
|
|
|
|
2020-01-06 14:17:07 +08:00
|
|
|
|
# sorts the data from oldest to latest dates
|
|
|
|
|
expect(report.data[0][:y]).to eq(8) # 7 days ago
|
|
|
|
|
expect(report.data[1][:y]).to eq(3) # 2 days ago
|
|
|
|
|
expect(report.data[2][:y]).to eq(2) # 1 day ago
|
|
|
|
|
expect(report.data[3][:y]).to eq(1) # today
|
2015-04-13 01:46:13 +08:00
|
|
|
|
|
2020-01-06 14:17:07 +08:00
|
|
|
|
# today's data
|
|
|
|
|
expect(report.data.find { |value| value[:x] == Date.today }).to be_present
|
2015-04-13 01:46:13 +08:00
|
|
|
|
|
2020-01-06 14:17:07 +08:00
|
|
|
|
# total data
|
|
|
|
|
expect(report.total).to eq 49
|
2015-04-13 01:46:13 +08:00
|
|
|
|
|
2020-01-06 14:17:07 +08:00
|
|
|
|
#previous 30 days of data
|
|
|
|
|
expect(report.prev30Days).to eq 35
|
2015-04-13 01:46:13 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2024-10-31 10:51:29 +08:00
|
|
|
|
describe "page_view_legacy_total_reqs" do
|
|
|
|
|
before do
|
|
|
|
|
freeze_time(Time.now.at_midnight)
|
|
|
|
|
Theme.clear_default!
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
let(:report) { Report.find("page_view_legacy_total_reqs") }
|
|
|
|
|
|
|
|
|
|
context "with no data" do
|
|
|
|
|
it "works" do
|
|
|
|
|
expect(report.data).to be_empty
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with data" do
|
|
|
|
|
before do
|
|
|
|
|
CachedCounting.reset
|
|
|
|
|
CachedCounting.enable
|
|
|
|
|
ApplicationRequest.enable
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
after do
|
|
|
|
|
CachedCounting.reset
|
|
|
|
|
ApplicationRequest.disable
|
|
|
|
|
CachedCounting.disable
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "works and does not count browser or mobile pageviews" do
|
|
|
|
|
3.times { ApplicationRequest.increment!(:page_view_crawler) }
|
|
|
|
|
8.times { ApplicationRequest.increment!(:page_view_logged_in) }
|
|
|
|
|
6.times { ApplicationRequest.increment!(:page_view_logged_in_browser) }
|
|
|
|
|
2.times { ApplicationRequest.increment!(:page_view_logged_in_mobile) }
|
|
|
|
|
2.times { ApplicationRequest.increment!(:page_view_anon) }
|
|
|
|
|
1.times { ApplicationRequest.increment!(:page_view_anon_browser) }
|
|
|
|
|
4.times { ApplicationRequest.increment!(:page_view_anon_mobile) }
|
|
|
|
|
|
|
|
|
|
CachedCounting.flush
|
|
|
|
|
|
|
|
|
|
expect(report.data.sum { |r| r[:y] }).to eq(13)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2024-07-04 08:16:09 +08:00
|
|
|
|
describe "page_view_total_reqs" do
|
|
|
|
|
before do
|
|
|
|
|
freeze_time(Time.now.at_midnight)
|
|
|
|
|
Theme.clear_default!
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
let(:report) { Report.find("page_view_total_reqs") }
|
|
|
|
|
|
|
|
|
|
context "with no data" do
|
|
|
|
|
it "works" do
|
|
|
|
|
expect(report.data).to be_empty
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with data" do
|
|
|
|
|
before do
|
|
|
|
|
CachedCounting.reset
|
|
|
|
|
CachedCounting.enable
|
|
|
|
|
ApplicationRequest.enable
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
after do
|
|
|
|
|
CachedCounting.reset
|
|
|
|
|
ApplicationRequest.disable
|
|
|
|
|
CachedCounting.disable
|
|
|
|
|
end
|
|
|
|
|
|
2024-09-10 07:51:49 +08:00
|
|
|
|
context "when use_legacy_pageviews is true" do
|
|
|
|
|
before { SiteSetting.use_legacy_pageviews = true }
|
2024-07-04 08:16:09 +08:00
|
|
|
|
|
2024-09-10 07:51:49 +08:00
|
|
|
|
it "works and does not count browser or mobile pageviews" do
|
|
|
|
|
3.times { ApplicationRequest.increment!(:page_view_crawler) }
|
|
|
|
|
8.times { ApplicationRequest.increment!(:page_view_logged_in) }
|
|
|
|
|
6.times { ApplicationRequest.increment!(:page_view_logged_in_browser) }
|
|
|
|
|
2.times { ApplicationRequest.increment!(:page_view_logged_in_mobile) }
|
|
|
|
|
2.times { ApplicationRequest.increment!(:page_view_anon) }
|
|
|
|
|
1.times { ApplicationRequest.increment!(:page_view_anon_browser) }
|
|
|
|
|
4.times { ApplicationRequest.increment!(:page_view_anon_mobile) }
|
2024-07-04 08:16:09 +08:00
|
|
|
|
|
2024-09-10 07:51:49 +08:00
|
|
|
|
CachedCounting.flush
|
|
|
|
|
|
|
|
|
|
expect(report.data.sum { |r| r[:y] }).to eq(13)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "when use_legacy_pageviews is false" do
|
|
|
|
|
before { SiteSetting.use_legacy_pageviews = false }
|
|
|
|
|
|
|
|
|
|
it "works and does not count mobile pageviews, and only counts browser pageviews" do
|
|
|
|
|
3.times { ApplicationRequest.increment!(:page_view_crawler) }
|
|
|
|
|
8.times { ApplicationRequest.increment!(:page_view_logged_in) }
|
|
|
|
|
6.times { ApplicationRequest.increment!(:page_view_logged_in_browser) }
|
|
|
|
|
2.times { ApplicationRequest.increment!(:page_view_logged_in_mobile) }
|
|
|
|
|
2.times { ApplicationRequest.increment!(:page_view_anon) }
|
|
|
|
|
1.times { ApplicationRequest.increment!(:page_view_anon_browser) }
|
|
|
|
|
4.times { ApplicationRequest.increment!(:page_view_anon_mobile) }
|
|
|
|
|
|
|
|
|
|
CachedCounting.flush
|
|
|
|
|
|
|
|
|
|
expect(report.data.sum { |r| r[:y] }).to eq(7)
|
|
|
|
|
end
|
2024-07-04 08:16:09 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2018-07-23 22:33:12 +08:00
|
|
|
|
describe "user to user private messages with replies" do
|
2018-03-27 16:30:08 +08:00
|
|
|
|
let(:report) { Report.find("user_to_user_private_messages_with_replies") }
|
2020-01-06 14:17:07 +08:00
|
|
|
|
let(:user) { Fabricate(:user) }
|
|
|
|
|
let(:topic) { Fabricate(:topic, created_at: 1.hour.ago, user: user) }
|
2013-04-04 01:25:52 +08:00
|
|
|
|
|
2015-01-06 00:04:23 +08:00
|
|
|
|
it "topic report).to not include private messages" do
|
2020-01-06 14:17:07 +08:00
|
|
|
|
Fabricate(:private_message_topic, created_at: 1.hour.ago, user: user)
|
|
|
|
|
topic
|
2013-04-04 01:25:52 +08:00
|
|
|
|
report = Report.find("topics")
|
2014-12-31 22:55:03 +08:00
|
|
|
|
expect(report.data[0][:y]).to eq(1)
|
|
|
|
|
expect(report.total).to eq(1)
|
2013-04-04 01:25:52 +08:00
|
|
|
|
end
|
|
|
|
|
|
2015-01-06 00:04:23 +08:00
|
|
|
|
it "post report).to not include private messages" do
|
2013-04-04 01:25:52 +08:00
|
|
|
|
Fabricate(:private_message_post, created_at: 1.hour.ago)
|
|
|
|
|
Fabricate(:post)
|
|
|
|
|
report = Report.find("posts")
|
2015-01-06 00:04:23 +08:00
|
|
|
|
expect(report.data[0][:y]).to eq 1
|
|
|
|
|
expect(report.total).to eq 1
|
2013-04-04 01:25:52 +08:00
|
|
|
|
end
|
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with no private messages" do
|
2013-04-04 01:25:52 +08:00
|
|
|
|
it "returns an empty report" do
|
2015-01-06 00:04:23 +08:00
|
|
|
|
expect(report.data).to be_blank
|
2013-04-04 01:25:52 +08:00
|
|
|
|
end
|
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with some public posts" do
|
2013-04-04 01:25:52 +08:00
|
|
|
|
it "returns an empty report" do
|
2020-01-06 14:17:07 +08:00
|
|
|
|
Fabricate(:post, topic: topic, user: user)
|
|
|
|
|
Fabricate(:post, topic: topic, user: user)
|
2015-01-06 00:04:23 +08:00
|
|
|
|
expect(report.data).to be_blank
|
|
|
|
|
expect(report.total).to eq 0
|
2013-04-04 01:25:52 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with some private messages" do
|
2013-04-04 01:25:52 +08:00
|
|
|
|
before do
|
2020-01-06 14:17:07 +08:00
|
|
|
|
Fabricate(:private_message_post, created_at: 25.hours.ago, user: user)
|
|
|
|
|
Fabricate(:private_message_post, created_at: 1.hour.ago, user: user)
|
|
|
|
|
Fabricate(:private_message_post, created_at: 1.hour.ago, user: user)
|
2013-04-04 01:25:52 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "returns correct data" do
|
2015-01-06 00:04:23 +08:00
|
|
|
|
expect(report.data[0][:y]).to eq 1
|
|
|
|
|
expect(report.data[1][:y]).to eq 2
|
|
|
|
|
expect(report.total).to eq 3
|
2013-04-04 01:25:52 +08:00
|
|
|
|
end
|
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with some public posts" do
|
2013-04-04 01:25:52 +08:00
|
|
|
|
before do
|
2020-01-06 14:17:07 +08:00
|
|
|
|
Fabricate(:post, user: user, topic: topic)
|
|
|
|
|
Fabricate(:post, user: user, topic: topic)
|
2013-04-04 01:25:52 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "returns correct data" do
|
2015-01-06 00:04:23 +08:00
|
|
|
|
expect(report.data[0][:y]).to eq 1
|
|
|
|
|
expect(report.data[1][:y]).to eq 2
|
|
|
|
|
expect(report.total).to eq 3
|
2013-04-04 01:25:52 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2018-07-23 22:33:12 +08:00
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with private message from system user" do
|
2018-07-23 22:33:12 +08:00
|
|
|
|
before do
|
|
|
|
|
Fabricate(:private_message_post, created_at: 1.hour.ago, user: Discourse.system_user)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "does not include system users" do
|
|
|
|
|
expect(report.data).to be_blank
|
|
|
|
|
expect(report.total).to eq 0
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe "user to user private messages" do
|
|
|
|
|
let(:report) { Report.find("user_to_user_private_messages") }
|
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with private message from system user" do
|
2018-07-23 22:33:12 +08:00
|
|
|
|
before do
|
|
|
|
|
Fabricate(:private_message_post, created_at: 1.hour.ago, user: Discourse.system_user)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "does not include system users" do
|
|
|
|
|
expect(report.data).to be_blank
|
|
|
|
|
expect(report.total).to eq 0
|
|
|
|
|
end
|
|
|
|
|
end
|
2013-04-04 01:25:52 +08:00
|
|
|
|
end
|
2013-03-21 01:54:32 +08:00
|
|
|
|
|
|
|
|
|
describe "users by trust level report" do
|
2013-04-04 01:25:52 +08:00
|
|
|
|
let(:report) { Report.find("users_by_trust_level") }
|
2013-03-21 01:54:32 +08:00
|
|
|
|
|
2018-07-27 07:24:18 +08:00
|
|
|
|
include_examples "no data"
|
2013-03-21 01:54:32 +08:00
|
|
|
|
|
|
|
|
|
context "with users at different trust levels" do
|
|
|
|
|
before do
|
2014-09-05 13:20:39 +08:00
|
|
|
|
3.times { Fabricate(:user, trust_level: TrustLevel[0]) }
|
|
|
|
|
2.times { Fabricate(:user, trust_level: TrustLevel[2]) }
|
|
|
|
|
Fabricate(:user, trust_level: TrustLevel[4])
|
2013-03-21 01:54:32 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "returns a report with data" do
|
2015-01-06 00:04:23 +08:00
|
|
|
|
expect(report.data).to be_present
|
|
|
|
|
expect(report.data.find { |d| d[:x] == TrustLevel[0] }[:y]).to eq 3
|
|
|
|
|
expect(report.data.find { |d| d[:x] == TrustLevel[2] }[:y]).to eq 2
|
|
|
|
|
expect(report.data.find { |d| d[:x] == TrustLevel[4] }[:y]).to eq 1
|
2021-07-01 02:19:15 +08:00
|
|
|
|
|
|
|
|
|
expect(
|
|
|
|
|
report.data.find { |d| d[:x] == TrustLevel[0] }[:url],
|
|
|
|
|
).to eq "/admin/users/list/newuser"
|
2013-03-21 01:54:32 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2015-01-06 00:04:23 +08:00
|
|
|
|
|
2018-04-26 20:49:41 +08:00
|
|
|
|
describe "new contributors report" do
|
|
|
|
|
let(:report) { Report.find("new_contributors") }
|
|
|
|
|
|
2018-07-27 07:24:18 +08:00
|
|
|
|
include_examples "no data"
|
2018-04-26 20:49:41 +08:00
|
|
|
|
|
|
|
|
|
context "with contributors" do
|
|
|
|
|
before do
|
|
|
|
|
jeff = Fabricate(:user)
|
|
|
|
|
jeff.user_stat = UserStat.new(new_since: 1.hour.ago, first_post_created_at: 1.day.ago)
|
|
|
|
|
|
|
|
|
|
regis = Fabricate(:user)
|
|
|
|
|
regis.user_stat = UserStat.new(new_since: 1.hour.ago, first_post_created_at: 2.days.ago)
|
|
|
|
|
|
|
|
|
|
hawk = Fabricate(:user)
|
|
|
|
|
hawk.user_stat = UserStat.new(new_since: 1.hour.ago, first_post_created_at: 2.days.ago)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "returns a report with data" do
|
|
|
|
|
expect(report.data).to be_present
|
|
|
|
|
|
|
|
|
|
expect(report.data[0][:y]).to eq 2
|
|
|
|
|
expect(report.data[1][:y]).to eq 1
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2018-04-16 19:03:43 +08:00
|
|
|
|
describe "users by types level report" do
|
2018-04-19 03:30:41 +08:00
|
|
|
|
let(:report) { Report.find("users_by_type") }
|
2018-04-16 19:03:43 +08:00
|
|
|
|
|
2018-07-27 07:24:18 +08:00
|
|
|
|
include_examples "no data"
|
2018-04-16 19:03:43 +08:00
|
|
|
|
|
|
|
|
|
context "with users at different trust levels" do
|
|
|
|
|
before do
|
|
|
|
|
3.times { Fabricate(:user, admin: true) }
|
|
|
|
|
2.times { Fabricate(:user, moderator: true) }
|
2023-12-13 17:18:42 +08:00
|
|
|
|
UserSilencer.silence(Fabricate(:user, refresh_auto_groups: true), Fabricate.build(:admin))
|
2018-04-16 19:03:43 +08:00
|
|
|
|
Fabricate(:user, suspended_till: 1.week.from_now, suspended_at: 1.day.ago)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "returns a report with data" do
|
|
|
|
|
expect(report.data).to be_present
|
2018-04-16 19:40:44 +08:00
|
|
|
|
|
2018-04-19 03:30:41 +08:00
|
|
|
|
label = Proc.new { |key| I18n.t("reports.users_by_type.xaxis_labels.#{key}") }
|
2018-04-16 19:40:44 +08:00
|
|
|
|
expect(report.data.find { |d| d[:x] == label.call("admin") }[:y]).to eq 3
|
|
|
|
|
expect(report.data.find { |d| d[:x] == label.call("moderator") }[:y]).to eq 2
|
|
|
|
|
expect(report.data.find { |d| d[:x] == label.call("silenced") }[:y]).to eq 1
|
|
|
|
|
expect(report.data.find { |d| d[:x] == label.call("suspended") }[:y]).to eq 1
|
2018-04-16 19:03:43 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2018-04-20 00:19:21 +08:00
|
|
|
|
describe "trending search report" do
|
|
|
|
|
let(:report) { Report.find("trending_search") }
|
|
|
|
|
|
2018-07-27 07:24:18 +08:00
|
|
|
|
include_examples "no data"
|
2018-04-20 00:19:21 +08:00
|
|
|
|
|
|
|
|
|
context "with different searches" do
|
|
|
|
|
before do
|
|
|
|
|
SearchLog.log(term: "ruby", search_type: :header, ip_address: "127.0.0.1")
|
2018-05-11 11:30:21 +08:00
|
|
|
|
|
|
|
|
|
SearchLog.create!(
|
|
|
|
|
term: "ruby",
|
|
|
|
|
search_result_id: 1,
|
|
|
|
|
search_type: 1,
|
|
|
|
|
ip_address: "127.0.0.1",
|
|
|
|
|
user_id: Fabricate(:user).id,
|
|
|
|
|
)
|
|
|
|
|
|
2018-04-20 00:19:21 +08:00
|
|
|
|
SearchLog.log(term: "ruby", search_type: :header, ip_address: "127.0.0.2")
|
|
|
|
|
SearchLog.log(term: "php", search_type: :header, ip_address: "127.0.0.1")
|
|
|
|
|
end
|
|
|
|
|
|
2018-04-23 10:00:37 +08:00
|
|
|
|
after { SearchLog.clear_debounce_cache! }
|
2018-04-20 00:19:21 +08:00
|
|
|
|
|
2018-04-23 10:00:37 +08:00
|
|
|
|
it "returns a report with data" do
|
2018-05-15 13:20:36 +08:00
|
|
|
|
expect(report.data[0][:term]).to eq("ruby")
|
2018-12-18 21:43:46 +08:00
|
|
|
|
expect(report.data[0][:searches]).to eq(3)
|
2018-07-20 02:33:11 +08:00
|
|
|
|
expect(report.data[0][:ctr]).to eq(33.4)
|
2018-04-20 00:19:21 +08:00
|
|
|
|
|
2018-05-15 13:20:36 +08:00
|
|
|
|
expect(report.data[1][:term]).to eq("php")
|
2018-12-18 21:43:46 +08:00
|
|
|
|
expect(report.data[1][:searches]).to eq(1)
|
2018-04-20 00:19:21 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2018-05-03 21:41:41 +08:00
|
|
|
|
describe "DAU/MAU report" do
|
|
|
|
|
let(:report) { Report.find("dau_by_mau") }
|
|
|
|
|
|
2018-07-27 07:24:18 +08:00
|
|
|
|
include_examples "no data"
|
2018-05-03 21:41:41 +08:00
|
|
|
|
|
|
|
|
|
context "with different users/visits" do
|
|
|
|
|
before do
|
2024-03-01 08:07:35 +08:00
|
|
|
|
freeze_time_safe
|
2018-05-03 21:41:41 +08:00
|
|
|
|
|
|
|
|
|
arpit = Fabricate(:user)
|
|
|
|
|
arpit.user_visits.create(visited_at: 1.day.ago)
|
|
|
|
|
|
|
|
|
|
sam = Fabricate(:user)
|
|
|
|
|
sam.user_visits.create(visited_at: 2.days.ago)
|
|
|
|
|
|
|
|
|
|
robin = Fabricate(:user)
|
|
|
|
|
robin.user_visits.create(visited_at: 2.days.ago)
|
|
|
|
|
|
|
|
|
|
michael = Fabricate(:user)
|
|
|
|
|
michael.user_visits.create(visited_at: 35.days.ago)
|
|
|
|
|
|
|
|
|
|
gerhard = Fabricate(:user)
|
|
|
|
|
gerhard.user_visits.create(visited_at: 45.days.ago)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "returns a report with data" do
|
|
|
|
|
expect(report.data.first[:y]).to eq(100)
|
2018-05-11 11:30:21 +08:00
|
|
|
|
expect(report.data.last[:y]).to eq(33.34)
|
2018-05-03 21:41:41 +08:00
|
|
|
|
expect(report.prev30Days).to eq(75)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe "Daily engaged users" do
|
|
|
|
|
let(:report) { Report.find("daily_engaged_users") }
|
|
|
|
|
|
2018-07-27 07:24:18 +08:00
|
|
|
|
include_examples "no data"
|
2018-05-03 21:41:41 +08:00
|
|
|
|
|
|
|
|
|
context "with different activities" do
|
|
|
|
|
before do
|
2024-03-01 08:07:35 +08:00
|
|
|
|
freeze_time_safe
|
2018-05-03 21:41:41 +08:00
|
|
|
|
|
2019-01-04 01:03:01 +08:00
|
|
|
|
UserActionManager.enable
|
2018-05-03 21:41:41 +08:00
|
|
|
|
|
|
|
|
|
arpit = Fabricate(:user)
|
|
|
|
|
sam = Fabricate(:user)
|
|
|
|
|
|
2023-12-13 11:50:13 +08:00
|
|
|
|
jeff = Fabricate(:user, created_at: 1.day.ago, refresh_auto_groups: true)
|
2019-01-04 01:03:01 +08:00
|
|
|
|
post = create_post(user: jeff, created_at: 1.day.ago)
|
|
|
|
|
PostActionCreator.like(arpit, post)
|
|
|
|
|
PostActionCreator.like(sam, post)
|
2018-05-03 21:41:41 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "returns a report with data" do
|
|
|
|
|
expect(report.data.first[:y]).to eq(1)
|
|
|
|
|
expect(report.data.last[:y]).to eq(2)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2017-02-22 03:45:34 +08:00
|
|
|
|
describe "posts counts" do
|
|
|
|
|
it "only counts regular posts" do
|
|
|
|
|
post = Fabricate(:post)
|
|
|
|
|
Fabricate(:moderator_post, topic: post.topic)
|
|
|
|
|
Fabricate.build(:post, post_type: Post.types[:whisper], topic: post.topic)
|
|
|
|
|
post.topic.add_small_action(Fabricate(:admin), "invited_group", "coolkids")
|
|
|
|
|
r = Report.find("posts")
|
|
|
|
|
expect(r.total).to eq(1)
|
2017-11-03 06:24:43 +08:00
|
|
|
|
expect(r.data[0][:y]).to eq(1)
|
2017-02-22 03:45:34 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
2018-07-20 02:33:11 +08:00
|
|
|
|
|
|
|
|
|
describe "flags_status" do
|
|
|
|
|
let(:report) { Report.find("flags_status") }
|
|
|
|
|
|
2018-07-27 07:24:18 +08:00
|
|
|
|
include_examples "no data"
|
2018-07-20 02:33:11 +08:00
|
|
|
|
|
|
|
|
|
context "with flags" do
|
2023-12-13 17:18:42 +08:00
|
|
|
|
let(:flagger) { Fabricate(:user, refresh_auto_groups: true) }
|
2020-01-06 14:17:07 +08:00
|
|
|
|
let(:post) { Fabricate(:post, user: flagger) }
|
2018-07-20 02:33:11 +08:00
|
|
|
|
|
2018-08-01 09:23:28 +08:00
|
|
|
|
before { freeze_time }
|
2018-07-20 02:33:11 +08:00
|
|
|
|
|
|
|
|
|
it "returns a report with data" do
|
2022-05-12 14:45:05 +08:00
|
|
|
|
result =
|
|
|
|
|
PostActionCreator.new(flagger, post, PostActionType.types[:spam], message: "bad").perform
|
|
|
|
|
|
|
|
|
|
expect(result.success).to eq(true)
|
2018-07-20 02:33:11 +08:00
|
|
|
|
expect(report.data).to be_present
|
|
|
|
|
|
|
|
|
|
row = report.data[0]
|
2018-12-26 17:29:33 +08:00
|
|
|
|
expect(row[:post_type]).to eq("spam")
|
2018-07-20 02:33:11 +08:00
|
|
|
|
expect(row[:staff_username]).to eq(nil)
|
|
|
|
|
expect(row[:staff_id]).to eq(nil)
|
|
|
|
|
expect(row[:poster_username]).to eq(post.user.username)
|
|
|
|
|
expect(row[:poster_id]).to eq(post.user.id)
|
2018-08-01 06:15:14 +08:00
|
|
|
|
expect(row[:poster_avatar_template]).to be_present
|
2018-07-20 02:33:11 +08:00
|
|
|
|
expect(row[:flagger_id]).to eq(flagger.id)
|
|
|
|
|
expect(row[:flagger_username]).to eq(flagger.username)
|
2018-08-01 06:15:14 +08:00
|
|
|
|
expect(row[:flagger_avatar_template]).to be_present
|
2018-07-20 02:33:11 +08:00
|
|
|
|
expect(row[:resolution]).to eq("No action")
|
|
|
|
|
expect(row[:response_time]).to eq(nil)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe "post_edits" do
|
|
|
|
|
let(:report) { Report.find("post_edits") }
|
|
|
|
|
|
2018-07-27 07:24:18 +08:00
|
|
|
|
include_examples "no data"
|
2018-07-20 02:33:11 +08:00
|
|
|
|
|
|
|
|
|
context "with edits" do
|
|
|
|
|
let(:editor) { Fabricate(:user) }
|
|
|
|
|
let(:post) { Fabricate(:post) }
|
|
|
|
|
|
|
|
|
|
before do
|
2018-08-01 09:23:28 +08:00
|
|
|
|
freeze_time
|
|
|
|
|
|
2019-05-10 01:39:17 +08:00
|
|
|
|
post.revise(
|
|
|
|
|
post.user,
|
|
|
|
|
{ raw: "updated body by author", edit_reason: "not cool" },
|
|
|
|
|
force_new_version: true,
|
|
|
|
|
)
|
2018-07-20 02:33:11 +08:00
|
|
|
|
post.revise(editor, raw: "updated body", edit_reason: "not cool")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "returns a report with data" do
|
|
|
|
|
expect(report.data).to be_present
|
|
|
|
|
expect(report.data.count).to be(1)
|
|
|
|
|
|
|
|
|
|
row = report.data[0]
|
|
|
|
|
expect(row[:editor_id]).to eq(editor.id)
|
|
|
|
|
expect(row[:editor_username]).to eq(editor.username)
|
2018-08-01 06:15:14 +08:00
|
|
|
|
expect(row[:editor_avatar_template]).to be_present
|
2018-07-20 02:33:11 +08:00
|
|
|
|
expect(row[:author_id]).to eq(post.user.id)
|
|
|
|
|
expect(row[:author_username]).to eq(post.user.username)
|
2018-08-01 06:15:14 +08:00
|
|
|
|
expect(row[:author_avatar_template]).to be_present
|
2018-07-20 02:33:11 +08:00
|
|
|
|
expect(row[:edit_reason]).to eq("not cool")
|
2018-08-01 06:15:14 +08:00
|
|
|
|
expect(row[:post_raw]).to eq("updated body")
|
|
|
|
|
expect(row[:post_number]).to eq(post.post_number)
|
|
|
|
|
expect(row[:topic_id]).to eq(post.topic.id)
|
2018-07-20 02:33:11 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
2021-08-02 22:15:53 +08:00
|
|
|
|
|
|
|
|
|
context "with editor filter" do
|
|
|
|
|
fab!(:posts) { Fabricate.times(3, :post) }
|
|
|
|
|
|
|
|
|
|
fab!(:editor_with_two_edits) do
|
|
|
|
|
Fabricate(:user).tap do |user|
|
|
|
|
|
2.times { |i| posts[i].revise(user, { raw: "edit #{i + 1}" }) }
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
fab!(:editor_with_one_edit) do
|
|
|
|
|
Fabricate(:user).tap { |user| posts.last.revise(user, { raw: "edit 3" }) }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
let(:report_with_one_edit) do
|
|
|
|
|
Report.find("post_edits", { filters: { "editor" => editor_with_one_edit.username } })
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
let(:report_with_two_edits) do
|
|
|
|
|
Report.find("post_edits", { filters: { "editor" => editor_with_two_edits.username } })
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "returns a report for a given editor" do
|
|
|
|
|
expect(report_with_one_edit.data.count).to be(1)
|
|
|
|
|
expect(report_with_two_edits.data.count).to be(2)
|
|
|
|
|
end
|
|
|
|
|
end
|
2018-07-20 02:33:11 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe "moderator activity" do
|
2018-08-01 11:40:45 +08:00
|
|
|
|
let(:report) { Report.find("moderators_activity") }
|
|
|
|
|
|
|
|
|
|
let(:sam) { Fabricate(:user, moderator: true, username: "sam") }
|
|
|
|
|
|
2023-12-13 17:18:42 +08:00
|
|
|
|
let(:jeff) { Fabricate(:user, moderator: true, username: "jeff", refresh_auto_groups: true) }
|
2018-07-20 02:33:11 +08:00
|
|
|
|
|
2018-07-27 07:24:18 +08:00
|
|
|
|
include_examples "no data"
|
2018-07-20 02:33:11 +08:00
|
|
|
|
|
|
|
|
|
context "with moderators" do
|
|
|
|
|
before { freeze_time(Date.today) }
|
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with moderators order" do
|
2018-08-10 08:51:31 +08:00
|
|
|
|
before do
|
|
|
|
|
Fabricate(:post, user: sam)
|
|
|
|
|
Fabricate(:post, user: jeff)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "returns the moderators in alphabetical order" do
|
|
|
|
|
expect(report.data[0][:username]).to eq("jeff")
|
|
|
|
|
expect(report.data[1][:username]).to eq("sam")
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with time read" do
|
2018-08-01 11:40:45 +08:00
|
|
|
|
before do
|
|
|
|
|
sam.user_visits.create(visited_at: 2.days.ago, time_read: 200)
|
|
|
|
|
sam.user_visits.create(visited_at: 1.day.ago, time_read: 100)
|
2018-07-20 02:33:11 +08:00
|
|
|
|
|
2018-08-01 11:40:45 +08:00
|
|
|
|
jeff.user_visits.create(visited_at: 2.days.ago, time_read: 1000)
|
|
|
|
|
jeff.user_visits.create(visited_at: 1.day.ago, time_read: 2000)
|
|
|
|
|
|
|
|
|
|
Fabricate(:topic, created_at: 1.day.ago)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "returns the correct read times" do
|
2018-08-10 08:51:31 +08:00
|
|
|
|
expect(report.data[0][:username]).to eq("jeff")
|
|
|
|
|
expect(report.data[0][:time_read]).to eq(3000)
|
|
|
|
|
expect(report.data[1][:username]).to eq("sam")
|
|
|
|
|
expect(report.data[1][:time_read]).to eq(300)
|
2018-08-01 11:40:45 +08:00
|
|
|
|
end
|
2018-07-20 02:33:11 +08:00
|
|
|
|
end
|
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with flags" do
|
2018-08-01 11:40:45 +08:00
|
|
|
|
before do
|
|
|
|
|
flagged_post = Fabricate(:post)
|
2019-01-04 01:03:01 +08:00
|
|
|
|
result = PostActionCreator.off_topic(jeff, flagged_post)
|
|
|
|
|
result.reviewable.perform(jeff, :agree_and_keep)
|
2018-08-01 11:40:45 +08:00
|
|
|
|
end
|
|
|
|
|
|
2018-08-10 08:51:31 +08:00
|
|
|
|
it "returns the correct flag counts" do
|
2018-08-01 11:40:45 +08:00
|
|
|
|
expect(report.data.count).to eq(1)
|
|
|
|
|
expect(report.data[0][:flag_count]).to eq(1)
|
|
|
|
|
expect(report.data[0][:username]).to eq("jeff")
|
|
|
|
|
end
|
2018-07-20 02:33:11 +08:00
|
|
|
|
end
|
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with topics" do
|
2018-08-01 11:40:45 +08:00
|
|
|
|
before do
|
|
|
|
|
Fabricate(:topic, user: sam)
|
|
|
|
|
Fabricate(:topic, user: sam)
|
|
|
|
|
Fabricate(:topic, user: jeff)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "returns the correct topic count" do
|
2018-08-10 08:51:31 +08:00
|
|
|
|
expect(report.data[0][:topic_count]).to eq(1)
|
|
|
|
|
expect(report.data[0][:username]).to eq("jeff")
|
|
|
|
|
expect(report.data[1][:topic_count]).to eq(2)
|
|
|
|
|
expect(report.data[1][:username]).to eq("sam")
|
2018-08-01 11:40:45 +08:00
|
|
|
|
end
|
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with private messages" do
|
2018-08-01 11:40:45 +08:00
|
|
|
|
before { Fabricate(:private_message_topic, user: jeff) }
|
|
|
|
|
|
|
|
|
|
it "doesn’t count private topic" do
|
2018-08-10 08:51:31 +08:00
|
|
|
|
expect(report.data[0][:topic_count]).to eq(1)
|
|
|
|
|
expect(report.data[1][:topic_count]).to eq(2)
|
2018-08-01 11:40:45 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
2018-07-20 02:33:11 +08:00
|
|
|
|
end
|
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with posts" do
|
2018-08-01 11:40:45 +08:00
|
|
|
|
before do
|
|
|
|
|
Fabricate(:post, user: sam)
|
|
|
|
|
Fabricate(:post, user: sam)
|
|
|
|
|
Fabricate(:post, user: jeff)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "returns the correct topic count" do
|
2018-08-10 08:51:31 +08:00
|
|
|
|
expect(report.data[0][:topic_count]).to eq(1)
|
|
|
|
|
expect(report.data[0][:username]).to eq("jeff")
|
|
|
|
|
expect(report.data[1][:topic_count]).to eq(2)
|
|
|
|
|
expect(report.data[1][:username]).to eq("sam")
|
2018-08-01 11:40:45 +08:00
|
|
|
|
end
|
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with private messages" do
|
2018-08-01 11:40:45 +08:00
|
|
|
|
before { Fabricate(:private_message_post, user: jeff) }
|
|
|
|
|
|
|
|
|
|
it "doesn’t count private post" do
|
2018-08-10 08:51:31 +08:00
|
|
|
|
expect(report.data[0][:post_count]).to eq(1)
|
|
|
|
|
expect(report.data[1][:post_count]).to eq(2)
|
2018-08-01 11:40:45 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
2018-07-20 02:33:11 +08:00
|
|
|
|
end
|
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with private messages" do
|
2018-08-01 11:40:45 +08:00
|
|
|
|
before do
|
|
|
|
|
Fabricate(:post, user: sam)
|
|
|
|
|
Fabricate(:post, user: jeff)
|
|
|
|
|
Fabricate(:private_message_post, user: jeff)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "returns the correct topic count" do
|
2018-08-10 08:51:31 +08:00
|
|
|
|
expect(report.data[0][:pm_count]).to eq(1)
|
|
|
|
|
expect(report.data[0][:username]).to eq("jeff")
|
|
|
|
|
expect(report.data[1][:pm_count]).to be_blank
|
|
|
|
|
expect(report.data[1][:username]).to eq("sam")
|
2018-08-01 11:40:45 +08:00
|
|
|
|
end
|
2018-07-20 02:33:11 +08:00
|
|
|
|
end
|
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with revisions" do
|
2018-08-01 11:40:45 +08:00
|
|
|
|
before do
|
|
|
|
|
post = Fabricate(:post)
|
|
|
|
|
post.revise(sam, raw: "updated body", edit_reason: "not cool")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "returns the correct revisions count" do
|
|
|
|
|
expect(report.data[0][:revision_count]).to eq(1)
|
|
|
|
|
expect(report.data[0][:username]).to eq("sam")
|
|
|
|
|
end
|
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "when revising own post" do
|
2018-08-01 11:40:45 +08:00
|
|
|
|
before do
|
|
|
|
|
post = Fabricate(:post, user: sam)
|
2018-08-10 08:51:31 +08:00
|
|
|
|
post.revise(sam, raw: "updated body")
|
2018-08-01 11:40:45 +08:00
|
|
|
|
end
|
|
|
|
|
|
2021-05-21 09:43:47 +08:00
|
|
|
|
it "doesn't count a revision on your own post" do
|
2018-08-10 08:51:31 +08:00
|
|
|
|
expect(report.data[0][:revision_count]).to eq(1)
|
2018-08-01 11:40:45 +08:00
|
|
|
|
expect(report.data[0][:username]).to eq("sam")
|
|
|
|
|
end
|
|
|
|
|
end
|
2018-07-20 02:33:11 +08:00
|
|
|
|
end
|
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with previous data" do
|
2018-08-01 11:40:45 +08:00
|
|
|
|
before { Fabricate(:topic, user: sam, created_at: 1.year.ago) }
|
2018-07-20 02:33:11 +08:00
|
|
|
|
|
2018-08-01 11:40:45 +08:00
|
|
|
|
it "doesn’t count old data" do
|
|
|
|
|
expect(report.data[0][:topic_count]).to be_blank
|
|
|
|
|
expect(report.data[0][:username]).to eq("sam")
|
|
|
|
|
end
|
2018-07-20 02:33:11 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2018-07-27 07:24:18 +08:00
|
|
|
|
|
|
|
|
|
describe "flags" do
|
|
|
|
|
let(:report) { Report.find("flags") }
|
|
|
|
|
|
|
|
|
|
include_examples "no data"
|
|
|
|
|
|
|
|
|
|
context "with data" do
|
|
|
|
|
include_examples "with data x/y"
|
|
|
|
|
|
|
|
|
|
before(:each) do
|
2023-12-13 17:18:42 +08:00
|
|
|
|
user = Fabricate(:user, refresh_auto_groups: true)
|
2020-01-06 14:17:07 +08:00
|
|
|
|
topic = Fabricate(:topic, user: user)
|
|
|
|
|
post0 = Fabricate(:post, topic: topic, user: user)
|
2024-07-09 13:39:10 +08:00
|
|
|
|
post1 =
|
|
|
|
|
Fabricate(:post, topic: Fabricate(:topic, category: category_2, user: user), user: user)
|
2020-01-06 14:17:07 +08:00
|
|
|
|
post2 = Fabricate(:post, topic: topic, user: user)
|
|
|
|
|
post3 = Fabricate(:post, topic: topic, user: user)
|
2019-01-04 01:03:01 +08:00
|
|
|
|
PostActionCreator.off_topic(user, post0)
|
|
|
|
|
PostActionCreator.off_topic(user, post1)
|
|
|
|
|
PostActionCreator.off_topic(user, post2)
|
|
|
|
|
PostActionCreator.create(user, post3, :off_topic, created_at: 45.days.ago)
|
2018-07-27 07:24:18 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with category filtering" do
|
2024-07-09 13:39:10 +08:00
|
|
|
|
let(:report) { Report.find("flags", filters: { category: category_2.id }) }
|
2018-07-27 07:24:18 +08:00
|
|
|
|
|
|
|
|
|
include_examples "category filtering"
|
2018-08-10 08:50:05 +08:00
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with subcategories" do
|
2020-06-10 23:57:39 +08:00
|
|
|
|
let(:report) do
|
2024-07-09 13:39:10 +08:00
|
|
|
|
Report.find("flags", filters: { category: category_1.id, include_subcategories: true })
|
2023-01-09 19:18:21 +08:00
|
|
|
|
end
|
2018-08-10 08:50:05 +08:00
|
|
|
|
|
|
|
|
|
include_examples "category filtering on subcategories"
|
|
|
|
|
end
|
2018-07-27 07:24:18 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe "topics" do
|
|
|
|
|
let(:report) { Report.find("topics") }
|
|
|
|
|
|
|
|
|
|
include_examples "no data"
|
|
|
|
|
|
|
|
|
|
context "with data" do
|
|
|
|
|
include_examples "with data x/y"
|
|
|
|
|
|
|
|
|
|
before(:each) do
|
2020-01-06 14:17:07 +08:00
|
|
|
|
user = Fabricate(:user)
|
|
|
|
|
Fabricate(:topic, user: user)
|
2024-07-09 13:39:10 +08:00
|
|
|
|
Fabricate(:topic, category: category_2, user: user)
|
2020-01-06 14:17:07 +08:00
|
|
|
|
Fabricate(:topic, user: user)
|
|
|
|
|
Fabricate(:topic, created_at: 45.days.ago, user: user)
|
2018-07-27 07:24:18 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with category filtering" do
|
2024-07-09 13:39:10 +08:00
|
|
|
|
let(:report) { Report.find("topics", filters: { category: category_2.id }) }
|
2018-07-27 07:24:18 +08:00
|
|
|
|
|
|
|
|
|
include_examples "category filtering"
|
2018-08-10 08:50:05 +08:00
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with subcategories" do
|
2020-06-10 23:57:39 +08:00
|
|
|
|
let(:report) do
|
2024-07-09 13:39:10 +08:00
|
|
|
|
Report.find("topics", filters: { category: category_1.id, include_subcategories: true })
|
2023-01-09 19:18:21 +08:00
|
|
|
|
end
|
2018-08-10 08:50:05 +08:00
|
|
|
|
|
|
|
|
|
include_examples "category filtering on subcategories"
|
|
|
|
|
end
|
2018-07-27 07:24:18 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2018-08-01 09:23:28 +08:00
|
|
|
|
|
|
|
|
|
describe "exception report" do
|
2024-09-11 13:24:19 +08:00
|
|
|
|
before(:each) { Report.stubs(:report_exception_test).raises(Exception) }
|
2018-08-01 09:23:28 +08:00
|
|
|
|
|
|
|
|
|
it "returns a report with an exception error" do
|
2019-02-09 00:25:32 +08:00
|
|
|
|
report = Report.find("exception_test", wrap_exceptions_in_test: true)
|
2018-08-01 09:23:28 +08:00
|
|
|
|
expect(report.error).to eq(:exception)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe "timeout report" do
|
2024-09-11 13:24:19 +08:00
|
|
|
|
before(:each) { Report.stubs(:report_timeout_test).raises(ActiveRecord::QueryCanceled) }
|
2018-08-01 09:23:28 +08:00
|
|
|
|
|
|
|
|
|
it "returns a report with a timeout error" do
|
|
|
|
|
report = Report.find("timeout_test")
|
|
|
|
|
expect(report.error).to eq(:timeout)
|
|
|
|
|
end
|
|
|
|
|
end
|
2018-08-10 08:50:05 +08:00
|
|
|
|
|
2018-09-13 23:36:55 +08:00
|
|
|
|
describe "unexpected error on report initialization" do
|
2018-10-10 09:34:50 +08:00
|
|
|
|
before do
|
|
|
|
|
@orig_logger = Rails.logger
|
|
|
|
|
Rails.logger = @fake_logger = FakeLogger.new
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
after { Rails.logger = @orig_logger }
|
|
|
|
|
|
2018-09-13 23:36:55 +08:00
|
|
|
|
it "returns no report" do
|
|
|
|
|
class ReportInitError < StandardError
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
Report.stubs(:new).raises(ReportInitError.new("x"))
|
|
|
|
|
|
2019-02-09 00:25:32 +08:00
|
|
|
|
report = Report.find("signups", wrap_exceptions_in_test: true)
|
2018-09-13 23:36:55 +08:00
|
|
|
|
|
|
|
|
|
expect(report).to be_nil
|
2018-10-10 09:34:50 +08:00
|
|
|
|
|
|
|
|
|
expect(@fake_logger.errors).to eq(["Couldn’t create report `signups`: <ReportInitError x>"])
|
2018-09-13 23:36:55 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2018-08-10 08:50:05 +08:00
|
|
|
|
describe "posts" do
|
|
|
|
|
let(:report) { Report.find("posts") }
|
|
|
|
|
|
|
|
|
|
include_examples "no data"
|
|
|
|
|
|
|
|
|
|
context "with data" do
|
|
|
|
|
include_examples "with data x/y"
|
|
|
|
|
|
|
|
|
|
before(:each) do
|
2020-01-06 14:17:07 +08:00
|
|
|
|
user = Fabricate(:user)
|
|
|
|
|
topic = Fabricate(:topic, user: user)
|
2024-07-09 13:39:10 +08:00
|
|
|
|
topic_with_category_id = Fabricate(:topic, category: category_2, user: user)
|
2020-01-06 14:17:07 +08:00
|
|
|
|
Fabricate(:post, topic: topic, user: user)
|
|
|
|
|
Fabricate(:post, topic: topic_with_category_id, user: user)
|
|
|
|
|
Fabricate(:post, topic: topic, user: user)
|
|
|
|
|
Fabricate(:post, created_at: 45.days.ago, topic: topic, user: user)
|
2018-08-10 08:50:05 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with category filtering" do
|
2024-07-09 13:39:10 +08:00
|
|
|
|
let(:report) { Report.find("posts", filters: { category: category_2.id }) }
|
2018-08-10 08:50:05 +08:00
|
|
|
|
|
|
|
|
|
include_examples "category filtering"
|
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with subcategories" do
|
2020-06-10 23:57:39 +08:00
|
|
|
|
let(:report) do
|
2024-07-09 13:39:10 +08:00
|
|
|
|
Report.find("posts", filters: { category: category_1.id, include_subcategories: true })
|
2023-01-09 19:18:21 +08:00
|
|
|
|
end
|
2018-08-10 08:50:05 +08:00
|
|
|
|
|
|
|
|
|
include_examples "category filtering on subcategories"
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# TODO: time_to_first_response
|
|
|
|
|
|
|
|
|
|
describe "topics_with_no_response" do
|
|
|
|
|
let(:report) { Report.find("topics_with_no_response") }
|
|
|
|
|
|
|
|
|
|
include_examples "no data"
|
|
|
|
|
|
|
|
|
|
context "with data" do
|
|
|
|
|
include_examples "with data x/y"
|
|
|
|
|
|
|
|
|
|
before(:each) do
|
2020-01-06 14:17:07 +08:00
|
|
|
|
user = Fabricate(:user)
|
2024-07-09 13:39:10 +08:00
|
|
|
|
Fabricate(:topic, category: category_2, user: user)
|
2020-01-06 14:17:07 +08:00
|
|
|
|
Fabricate(:post, topic: Fabricate(:topic, user: user), user: user)
|
|
|
|
|
Fabricate(:topic, user: user)
|
|
|
|
|
Fabricate(:topic, created_at: 45.days.ago, user: user)
|
2018-08-10 08:50:05 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with category filtering" do
|
2024-07-09 13:39:10 +08:00
|
|
|
|
let(:report) do
|
|
|
|
|
Report.find("topics_with_no_response", filters: { category: category_2.id })
|
|
|
|
|
end
|
2018-08-10 08:50:05 +08:00
|
|
|
|
|
|
|
|
|
include_examples "category filtering"
|
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with subcategories" do
|
2020-06-10 23:57:39 +08:00
|
|
|
|
let(:report) do
|
|
|
|
|
Report.find(
|
|
|
|
|
"topics_with_no_response",
|
|
|
|
|
filters: {
|
2024-07-09 13:39:10 +08:00
|
|
|
|
category: category_1.id,
|
2020-06-10 23:57:39 +08:00
|
|
|
|
include_subcategories: true,
|
|
|
|
|
},
|
|
|
|
|
)
|
2023-01-09 19:18:21 +08:00
|
|
|
|
end
|
2018-08-10 08:50:05 +08:00
|
|
|
|
|
|
|
|
|
include_examples "category filtering on subcategories"
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2018-10-02 17:27:43 +08:00
|
|
|
|
|
|
|
|
|
describe "likes" do
|
|
|
|
|
let(:report) { Report.find("likes") }
|
|
|
|
|
|
|
|
|
|
include_examples "no data"
|
|
|
|
|
|
|
|
|
|
context "with data" do
|
|
|
|
|
include_examples "with data x/y"
|
|
|
|
|
|
|
|
|
|
before(:each) do
|
2024-07-09 13:39:10 +08:00
|
|
|
|
topic = Fabricate(:topic, category: category_2)
|
2018-10-02 17:27:43 +08:00
|
|
|
|
post = Fabricate(:post, topic: topic)
|
2019-01-04 01:03:01 +08:00
|
|
|
|
PostActionCreator.like(Fabricate(:user), post)
|
2018-10-02 17:27:43 +08:00
|
|
|
|
|
2024-07-09 13:39:10 +08:00
|
|
|
|
topic = Fabricate(:topic, category: category_3)
|
2018-10-02 17:27:43 +08:00
|
|
|
|
post = Fabricate(:post, topic: topic)
|
2019-01-04 01:03:01 +08:00
|
|
|
|
PostActionCreator.like(Fabricate(:user), post)
|
|
|
|
|
PostActionCreator.like(Fabricate(:user), post)
|
|
|
|
|
PostActionCreator
|
|
|
|
|
.like(Fabricate(:user), post)
|
|
|
|
|
.post_action
|
2018-10-02 17:27:43 +08:00
|
|
|
|
.tap { |pa| pa.created_at = 45.days.ago }
|
|
|
|
|
.save!
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with category filtering" do
|
2024-07-09 13:39:10 +08:00
|
|
|
|
let(:report) { Report.find("likes", filters: { category: category_2.id }) }
|
2018-10-02 17:27:43 +08:00
|
|
|
|
|
|
|
|
|
include_examples "category filtering"
|
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
|
context "with subcategories" do
|
2020-06-10 23:57:39 +08:00
|
|
|
|
let(:report) do
|
2024-07-09 13:39:10 +08:00
|
|
|
|
Report.find("likes", filters: { category: category_1.id, include_subcategories: true })
|
2023-01-09 19:18:21 +08:00
|
|
|
|
end
|
2018-10-02 17:27:43 +08:00
|
|
|
|
|
|
|
|
|
include_examples "category filtering on subcategories"
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2018-10-26 21:59:04 +08:00
|
|
|
|
|
2018-11-13 05:23:10 +08:00
|
|
|
|
describe "user_flagging_ratio" do
|
2023-12-13 17:18:42 +08:00
|
|
|
|
let(:joffrey) { Fabricate(:user, username: "joffrey", refresh_auto_groups: true) }
|
|
|
|
|
let(:robin) { Fabricate(:user, username: "robin", refresh_auto_groups: true) }
|
2018-10-26 21:59:04 +08:00
|
|
|
|
let(:moderator) { Fabricate(:moderator) }
|
2020-01-06 14:17:07 +08:00
|
|
|
|
let(:user) { Fabricate(:user) }
|
2018-10-26 21:59:04 +08:00
|
|
|
|
|
|
|
|
|
context "with data" do
|
|
|
|
|
it "it works" do
|
2020-01-06 14:17:07 +08:00
|
|
|
|
topic = Fabricate(:topic, user: user)
|
|
|
|
|
2.times do
|
|
|
|
|
post_disagreed = Fabricate(:post, topic: topic, user: user)
|
2019-01-04 01:03:01 +08:00
|
|
|
|
result = PostActionCreator.spam(joffrey, post_disagreed)
|
|
|
|
|
result.reviewable.perform(moderator, :disagree)
|
2018-10-26 21:59:04 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
3.times do
|
2020-01-06 14:17:07 +08:00
|
|
|
|
post_disagreed = Fabricate(:post, topic: topic, user: user)
|
2019-01-04 01:03:01 +08:00
|
|
|
|
result = PostActionCreator.spam(robin, post_disagreed)
|
|
|
|
|
result.reviewable.perform(moderator, :disagree)
|
2018-10-26 21:59:04 +08:00
|
|
|
|
end
|
2020-01-06 14:17:07 +08:00
|
|
|
|
post_agreed = Fabricate(:post, user: user, topic: topic)
|
2019-01-04 01:03:01 +08:00
|
|
|
|
result = PostActionCreator.off_topic(robin, post_agreed)
|
|
|
|
|
result.reviewable.perform(moderator, :agree_and_keep)
|
2018-10-26 21:59:04 +08:00
|
|
|
|
|
2018-11-13 05:23:10 +08:00
|
|
|
|
report = Report.find("user_flagging_ratio")
|
2018-10-26 21:59:04 +08:00
|
|
|
|
|
|
|
|
|
first = report.data[0]
|
|
|
|
|
expect(first[:username]).to eq("joffrey")
|
2020-01-06 14:17:07 +08:00
|
|
|
|
expect(first[:score]).to eq(2)
|
2018-10-26 21:59:04 +08:00
|
|
|
|
expect(first[:agreed_flags]).to eq(0)
|
2020-01-06 14:17:07 +08:00
|
|
|
|
expect(first[:disagreed_flags]).to eq(2)
|
2018-10-26 21:59:04 +08:00
|
|
|
|
|
|
|
|
|
second = report.data[1]
|
|
|
|
|
expect(second[:username]).to eq("robin")
|
|
|
|
|
expect(second[:agreed_flags]).to eq(1)
|
|
|
|
|
expect(second[:disagreed_flags]).to eq(3)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2018-10-31 06:51:58 +08:00
|
|
|
|
|
|
|
|
|
describe "report_suspicious_logins" do
|
|
|
|
|
let(:joffrey) { Fabricate(:user, username: "joffrey") }
|
|
|
|
|
let(:robin) { Fabricate(:user, username: "robin") }
|
|
|
|
|
|
|
|
|
|
context "with data" do
|
|
|
|
|
it "works" do
|
2018-10-31 10:37:54 +08:00
|
|
|
|
SiteSetting.verbose_auth_token_logging = true
|
|
|
|
|
|
2019-02-13 02:17:29 +08:00
|
|
|
|
UserAuthToken.log(action: "suspicious", user_id: joffrey.id, created_at: 2.hours.ago)
|
|
|
|
|
UserAuthToken.log(action: "suspicious", user_id: joffrey.id, created_at: 3.hours.ago)
|
|
|
|
|
UserAuthToken.log(action: "suspicious", user_id: robin.id, created_at: 1.hour.ago)
|
2018-10-31 06:51:58 +08:00
|
|
|
|
|
|
|
|
|
report = Report.find("suspicious_logins")
|
|
|
|
|
|
|
|
|
|
expect(report.data.length).to eq(3)
|
|
|
|
|
expect(report.data[0][:username]).to eq("robin")
|
|
|
|
|
expect(report.data[1][:username]).to eq("joffrey")
|
|
|
|
|
expect(report.data[2][:username]).to eq("joffrey")
|
|
|
|
|
end
|
|
|
|
|
end
|
2018-12-14 20:47:59 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe "report_staff_logins" do
|
|
|
|
|
let(:joffrey) { Fabricate(:admin, username: "joffrey") }
|
|
|
|
|
let(:robin) { Fabricate(:admin, username: "robin") }
|
|
|
|
|
let(:james) { Fabricate(:user, username: "james") }
|
|
|
|
|
|
|
|
|
|
context "with data" do
|
|
|
|
|
it "works" do
|
2024-03-01 08:07:35 +08:00
|
|
|
|
freeze_time_safe
|
2018-12-14 20:47:59 +08:00
|
|
|
|
|
|
|
|
|
ip = [81, 2, 69, 142]
|
|
|
|
|
|
|
|
|
|
DiscourseIpInfo.open_db(File.join(Rails.root, "spec", "fixtures", "mmdb"))
|
|
|
|
|
Resolv::DNS
|
|
|
|
|
.any_instance
|
|
|
|
|
.stubs(:getname)
|
|
|
|
|
.with(ip.join("."))
|
|
|
|
|
.returns("ip-#{ip.join("-")}.example.com")
|
2023-01-09 19:18:21 +08:00
|
|
|
|
|
2018-12-14 20:47:59 +08:00
|
|
|
|
UserAuthToken.log(
|
|
|
|
|
action: "generate",
|
|
|
|
|
user_id: robin.id,
|
|
|
|
|
client_ip: ip.join("."),
|
|
|
|
|
created_at: 1.hour.ago,
|
|
|
|
|
)
|
|
|
|
|
UserAuthToken.log(action: "generate", user_id: joffrey.id, client_ip: "1.2.3.4")
|
|
|
|
|
UserAuthToken.log(
|
|
|
|
|
action: "generate",
|
|
|
|
|
user_id: joffrey.id,
|
|
|
|
|
client_ip: ip.join("."),
|
|
|
|
|
created_at: 2.hours.ago,
|
|
|
|
|
)
|
|
|
|
|
UserAuthToken.log(action: "generate", user_id: james.id)
|
|
|
|
|
|
|
|
|
|
report = Report.find("staff_logins")
|
|
|
|
|
|
|
|
|
|
expect(report.data.length).to eq(3)
|
|
|
|
|
expect(report.data[0][:username]).to eq("joffrey")
|
|
|
|
|
|
|
|
|
|
expect(report.data[1][:username]).to eq("robin")
|
|
|
|
|
expect(report.data[1][:location]).to eq("London, England, United Kingdom")
|
|
|
|
|
|
|
|
|
|
expect(report.data[2][:username]).to eq("joffrey")
|
|
|
|
|
end
|
|
|
|
|
end
|
2018-10-31 06:51:58 +08:00
|
|
|
|
end
|
2018-12-29 03:48:54 +08:00
|
|
|
|
|
|
|
|
|
describe "report_top_uploads" do
|
|
|
|
|
let(:report) { Report.find("top_uploads") }
|
|
|
|
|
let(:tarek) { Fabricate(:admin, username: "tarek") }
|
|
|
|
|
let(:khalil) { Fabricate(:admin, username: "khalil") }
|
|
|
|
|
|
|
|
|
|
context "with data" do
|
|
|
|
|
let!(:tarek_upload) do
|
|
|
|
|
Fabricate(
|
|
|
|
|
:upload,
|
|
|
|
|
user: tarek,
|
|
|
|
|
url: "/uploads/default/original/1X/tarek.jpg",
|
|
|
|
|
extension: "jpg",
|
|
|
|
|
original_filename: "tarek.jpg",
|
|
|
|
|
filesize: 1000,
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
let!(:khalil_upload) do
|
|
|
|
|
Fabricate(
|
|
|
|
|
:upload,
|
|
|
|
|
user: khalil,
|
|
|
|
|
url: "/uploads/default/original/1X/khalil.png",
|
|
|
|
|
extension: "png",
|
|
|
|
|
original_filename: "khalil.png",
|
|
|
|
|
filesize: 2000,
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "works" do
|
|
|
|
|
expect(report.data.length).to eq(2)
|
2019-03-26 21:23:57 +08:00
|
|
|
|
expect_uploads_report_data_to_be_equal(report.data, khalil, khalil_upload)
|
|
|
|
|
expect_uploads_report_data_to_be_equal(report.data, tarek, tarek_upload)
|
2018-12-29 03:48:54 +08:00
|
|
|
|
end
|
2019-03-26 21:23:57 +08:00
|
|
|
|
end
|
2018-12-29 03:48:54 +08:00
|
|
|
|
|
2019-03-26 21:23:57 +08:00
|
|
|
|
def expect_uploads_report_data_to_be_equal(data, user, upload)
|
|
|
|
|
row = data.find { |r| r[:author_id] == user.id }
|
|
|
|
|
expect(row[:author_id]).to eq(user.id)
|
|
|
|
|
expect(row[:author_username]).to eq(user.username)
|
|
|
|
|
expect(row[:author_avatar_template]).to eq(
|
|
|
|
|
User.avatar_template(user.username, user.uploaded_avatar_id),
|
|
|
|
|
)
|
|
|
|
|
expect(row[:filesize]).to eq(upload.filesize)
|
|
|
|
|
expect(row[:extension]).to eq(upload.extension)
|
|
|
|
|
expect(row[:file_url]).to eq(Discourse.store.cdn_url(upload.url))
|
|
|
|
|
expect(row[:file_name]).to eq(upload.original_filename.truncate(25))
|
2018-12-29 03:48:54 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
include_examples "no data"
|
|
|
|
|
end
|
2019-01-21 22:17:04 +08:00
|
|
|
|
|
2019-03-13 00:01:58 +08:00
|
|
|
|
describe "report_top_ignored_users" do
|
|
|
|
|
let(:report) { Report.find("top_ignored_users") }
|
|
|
|
|
let(:tarek) { Fabricate(:user, username: "tarek") }
|
|
|
|
|
let(:john) { Fabricate(:user, username: "john") }
|
|
|
|
|
let(:matt) { Fabricate(:user, username: "matt") }
|
|
|
|
|
|
|
|
|
|
context "with data" do
|
|
|
|
|
before do
|
|
|
|
|
Fabricate(:ignored_user, user: tarek, ignored_user: john)
|
|
|
|
|
Fabricate(:ignored_user, user: tarek, ignored_user: matt)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "works" do
|
|
|
|
|
expect(report.data.length).to eq(2)
|
|
|
|
|
|
2019-03-26 21:23:57 +08:00
|
|
|
|
expect_ignored_users_report_data_to_be_equal(report.data, john, 1, 0)
|
|
|
|
|
expect_ignored_users_report_data_to_be_equal(report.data, matt, 1, 0)
|
2019-03-21 21:31:45 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "when muted users exist" do
|
|
|
|
|
before do
|
|
|
|
|
Fabricate(:muted_user, user: tarek, muted_user: john)
|
|
|
|
|
Fabricate(:muted_user, user: tarek, muted_user: matt)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "works" do
|
|
|
|
|
expect(report.data.length).to eq(2)
|
2019-03-26 21:23:57 +08:00
|
|
|
|
expect_ignored_users_report_data_to_be_equal(report.data, john, 1, 1)
|
|
|
|
|
expect_ignored_users_report_data_to_be_equal(report.data, matt, 1, 1)
|
2019-03-21 21:31:45 +08:00
|
|
|
|
end
|
2019-03-13 00:01:58 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-26 21:23:57 +08:00
|
|
|
|
def expect_ignored_users_report_data_to_be_equal(data, user, ignores, mutes)
|
|
|
|
|
row = data.find { |r| r[:ignored_user_id] == user.id }
|
|
|
|
|
expect(row).to be_present
|
|
|
|
|
expect(row[:ignored_user_id]).to eq(user.id)
|
|
|
|
|
expect(row[:ignored_username]).to eq(user.username)
|
|
|
|
|
expect(row[:ignored_user_avatar_template]).to eq(
|
|
|
|
|
User.avatar_template(user.username, user.uploaded_avatar_id),
|
|
|
|
|
)
|
|
|
|
|
expect(row[:ignores_count]).to eq(ignores)
|
|
|
|
|
expect(row[:mutes_count]).to eq(mutes)
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-13 00:01:58 +08:00
|
|
|
|
include_examples "no data"
|
|
|
|
|
end
|
|
|
|
|
|
2024-07-04 08:16:09 +08:00
|
|
|
|
describe "consolidated_page_views_browser_detection" do
|
|
|
|
|
before do
|
|
|
|
|
freeze_time(Time.now.at_midnight)
|
|
|
|
|
Theme.clear_default!
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
let(:reports) { Report.find("consolidated_page_views_browser_detection") }
|
|
|
|
|
|
|
|
|
|
context "with no data" do
|
|
|
|
|
it "works" do
|
|
|
|
|
reports.data.each { |report| expect(report[:data]).to be_empty }
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with data" do
|
|
|
|
|
before do
|
|
|
|
|
CachedCounting.reset
|
|
|
|
|
CachedCounting.enable
|
|
|
|
|
ApplicationRequest.enable
|
2024-09-10 07:51:49 +08:00
|
|
|
|
SiteSetting.use_legacy_pageviews = true
|
2024-07-04 08:16:09 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
after do
|
|
|
|
|
CachedCounting.reset
|
|
|
|
|
ApplicationRequest.disable
|
|
|
|
|
CachedCounting.disable
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "works" do
|
|
|
|
|
3.times { ApplicationRequest.increment!(:page_view_crawler) }
|
|
|
|
|
8.times { ApplicationRequest.increment!(:page_view_logged_in) }
|
|
|
|
|
6.times { ApplicationRequest.increment!(:page_view_logged_in_browser) }
|
|
|
|
|
2.times { ApplicationRequest.increment!(:page_view_anon) }
|
|
|
|
|
1.times { ApplicationRequest.increment!(:page_view_anon_browser) }
|
|
|
|
|
|
|
|
|
|
CachedCounting.flush
|
|
|
|
|
|
|
|
|
|
page_view_crawler_report = reports.data.find { |r| r[:req] == "page_view_crawler" }
|
|
|
|
|
page_view_logged_in_browser_report =
|
|
|
|
|
reports.data.find { |r| r[:req] == "page_view_logged_in_browser" }
|
|
|
|
|
page_view_anon_browser_report =
|
|
|
|
|
reports.data.find { |r| r[:req] == "page_view_anon_browser" }
|
|
|
|
|
page_view_other_report = reports.data.find { |r| r[:req] == "page_view_other" }
|
|
|
|
|
|
|
|
|
|
expect(page_view_crawler_report[:data][0][:y]).to eql(3)
|
|
|
|
|
expect(page_view_logged_in_browser_report[:data][0][:y]).to eql(6)
|
|
|
|
|
expect(page_view_anon_browser_report[:data][0][:y]).to eql(1)
|
|
|
|
|
expect(page_view_other_report[:data][0][:y]).to eql(3)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "gives the same total as page_view_total_reqs" do
|
|
|
|
|
3.times { ApplicationRequest.increment!(:page_view_crawler) }
|
|
|
|
|
8.times { ApplicationRequest.increment!(:page_view_logged_in) }
|
|
|
|
|
6.times { ApplicationRequest.increment!(:page_view_logged_in_browser) }
|
|
|
|
|
2.times { ApplicationRequest.increment!(:page_view_anon) }
|
|
|
|
|
1.times { ApplicationRequest.increment!(:page_view_anon_browser) }
|
|
|
|
|
|
|
|
|
|
CachedCounting.flush
|
|
|
|
|
|
|
|
|
|
total_consolidated = reports.data.sum { |r| r[:data][0][:y] }
|
|
|
|
|
total_page_views = Report.find("page_view_total_reqs").data[0][:y]
|
|
|
|
|
|
|
|
|
|
expect(total_consolidated).to eq(total_page_views)
|
|
|
|
|
end
|
2024-09-10 07:51:49 +08:00
|
|
|
|
|
|
|
|
|
it "does not include any data before the first recorded browser page view (anon or logged in)" do
|
|
|
|
|
freeze_time DateTime.parse("2024-02-10")
|
|
|
|
|
|
|
|
|
|
3.times { ApplicationRequest.increment!(:page_view_logged_in) }
|
|
|
|
|
2.times { ApplicationRequest.increment!(:page_view_anon) }
|
|
|
|
|
|
|
|
|
|
CachedCounting.flush
|
|
|
|
|
|
|
|
|
|
freeze_time DateTime.parse("2024-03-10")
|
|
|
|
|
|
|
|
|
|
3.times { ApplicationRequest.increment!(:page_view_logged_in) }
|
|
|
|
|
2.times { ApplicationRequest.increment!(:page_view_anon) }
|
|
|
|
|
|
|
|
|
|
CachedCounting.flush
|
|
|
|
|
|
|
|
|
|
freeze_time DateTime.parse("2024-04-10")
|
|
|
|
|
|
|
|
|
|
3.times { ApplicationRequest.increment!(:page_view_crawler) }
|
|
|
|
|
8.times { ApplicationRequest.increment!(:page_view_logged_in) }
|
|
|
|
|
6.times { ApplicationRequest.increment!(:page_view_logged_in_browser) }
|
|
|
|
|
2.times { ApplicationRequest.increment!(:page_view_anon) }
|
|
|
|
|
1.times { ApplicationRequest.increment!(:page_view_anon_browser) }
|
|
|
|
|
|
|
|
|
|
CachedCounting.flush
|
|
|
|
|
|
|
|
|
|
report_in_range =
|
|
|
|
|
Report.find(
|
|
|
|
|
"consolidated_page_views_browser_detection",
|
|
|
|
|
start_date: DateTime.parse("2024-02-10").beginning_of_day,
|
|
|
|
|
end_date: DateTime.parse("2024-04-11").beginning_of_day,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
page_view_crawler_report = report_in_range.data.find { |r| r[:req] == "page_view_crawler" }
|
|
|
|
|
page_view_logged_in_browser_report =
|
|
|
|
|
report_in_range.data.find { |r| r[:req] == "page_view_logged_in_browser" }
|
|
|
|
|
page_view_anon_browser_report =
|
|
|
|
|
report_in_range.data.find { |r| r[:req] == "page_view_anon_browser" }
|
|
|
|
|
page_view_other_report = report_in_range.data.find { |r| r[:req] == "page_view_other" }
|
|
|
|
|
|
|
|
|
|
expect(page_view_crawler_report[:data].sum { |d| d[:y] }).to eql(3)
|
|
|
|
|
expect(page_view_logged_in_browser_report[:data].sum { |d| d[:y] }).to eql(6)
|
|
|
|
|
expect(page_view_anon_browser_report[:data].sum { |d| d[:y] }).to eql(1)
|
|
|
|
|
expect(page_view_other_report[:data].sum { |d| d[:y] }).to eql(3)
|
|
|
|
|
end
|
2024-07-04 08:16:09 +08:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2019-01-22 05:00:45 +08:00
|
|
|
|
describe "consolidated_page_views" do
|
|
|
|
|
before do
|
|
|
|
|
freeze_time(Time.now.at_midnight)
|
2019-02-21 22:12:20 +08:00
|
|
|
|
Theme.clear_default!
|
2019-01-21 22:17:04 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
let(:reports) { Report.find("consolidated_page_views") }
|
|
|
|
|
|
|
|
|
|
context "with no data" do
|
|
|
|
|
it "works" do
|
|
|
|
|
reports.data.each { |report| expect(report[:data]).to be_empty }
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with data" do
|
2022-02-23 00:45:25 +08:00
|
|
|
|
before do
|
|
|
|
|
CachedCounting.reset
|
|
|
|
|
CachedCounting.enable
|
2020-05-18 17:22:39 +08:00
|
|
|
|
ApplicationRequest.enable
|
2022-02-23 00:45:25 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
after do
|
2023-05-06 05:15:33 +08:00
|
|
|
|
CachedCounting.reset
|
2022-02-23 00:45:25 +08:00
|
|
|
|
ApplicationRequest.disable
|
|
|
|
|
CachedCounting.disable
|
|
|
|
|
end
|
2023-05-06 05:15:33 +08:00
|
|
|
|
|
2022-02-23 00:45:25 +08:00
|
|
|
|
it "works" do
|
2019-01-21 22:17:04 +08:00
|
|
|
|
3.times { ApplicationRequest.increment!(:page_view_crawler) }
|
|
|
|
|
2.times { ApplicationRequest.increment!(:page_view_logged_in) }
|
|
|
|
|
ApplicationRequest.increment!(:page_view_anon)
|
2022-02-23 00:45:25 +08:00
|
|
|
|
|
|
|
|
|
CachedCounting.flush
|
2019-01-21 22:17:04 +08:00
|
|
|
|
|
|
|
|
|
page_view_crawler_report = reports.data.find { |r| r[:req] == "page_view_crawler" }
|
|
|
|
|
page_view_logged_in_report = reports.data.find { |r| r[:req] == "page_view_logged_in" }
|
|
|
|
|
page_view_anon_report = reports.data.find { |r| r[:req] == "page_view_anon" }
|
|
|
|
|
|
2023-05-04 14:35:19 +08:00
|
|
|
|
expect(page_view_crawler_report[:color]).to eql("#721D8D")
|
2019-01-21 22:17:04 +08:00
|
|
|
|
expect(page_view_crawler_report[:data][0][:y]).to eql(3)
|
|
|
|
|
|
2023-05-04 14:35:19 +08:00
|
|
|
|
expect(page_view_logged_in_report[:color]).to eql("#1EB8D1")
|
2019-01-21 22:17:04 +08:00
|
|
|
|
expect(page_view_logged_in_report[:data][0][:y]).to eql(2)
|
|
|
|
|
|
2023-05-04 14:35:19 +08:00
|
|
|
|
expect(page_view_anon_report[:color]).to eql("#9BC53D")
|
2019-01-21 22:17:04 +08:00
|
|
|
|
expect(page_view_anon_report[:data][0][:y]).to eql(1)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2020-02-07 02:44:30 +08:00
|
|
|
|
|
2022-11-29 19:07:42 +08:00
|
|
|
|
describe ".report_consolidated_api_requests" do
|
|
|
|
|
before do
|
|
|
|
|
freeze_time(Time.now.at_midnight)
|
|
|
|
|
Theme.clear_default!
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
let(:reports) { Report.find("consolidated_api_requests") }
|
|
|
|
|
|
|
|
|
|
context "with no data" do
|
|
|
|
|
it "works" do
|
|
|
|
|
reports.data.each { |report| expect(report[:data]).to be_empty }
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with data" do
|
|
|
|
|
before do
|
|
|
|
|
CachedCounting.reset
|
|
|
|
|
CachedCounting.enable
|
|
|
|
|
ApplicationRequest.enable
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
after do
|
|
|
|
|
ApplicationRequest.disable
|
|
|
|
|
CachedCounting.disable
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "works" do
|
|
|
|
|
2.times { ApplicationRequest.increment!(:api) }
|
|
|
|
|
ApplicationRequest.increment!(:user_api)
|
|
|
|
|
|
|
|
|
|
CachedCounting.flush
|
|
|
|
|
|
|
|
|
|
api_report = reports.data.find { |r| r[:req] == "api" }
|
|
|
|
|
user_api_report = reports.data.find { |r| r[:req] == "user_api" }
|
|
|
|
|
|
2023-05-04 14:35:19 +08:00
|
|
|
|
expect(api_report[:color]).to eql("#1EB8D1")
|
2022-11-29 19:07:42 +08:00
|
|
|
|
expect(api_report[:data][0][:y]).to eql(2)
|
|
|
|
|
|
2023-05-04 14:35:19 +08:00
|
|
|
|
expect(user_api_report[:color]).to eql("#9BC53D")
|
2022-11-29 19:07:42 +08:00
|
|
|
|
expect(user_api_report[:data][0][:y]).to eql(1)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2020-02-07 02:44:30 +08:00
|
|
|
|
describe "trust_level_growth" do
|
|
|
|
|
before do
|
|
|
|
|
freeze_time(Time.now.at_midnight)
|
|
|
|
|
Theme.clear_default!
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
let(:reports) { Report.find("trust_level_growth") }
|
|
|
|
|
|
|
|
|
|
context "with no data" do
|
|
|
|
|
it "works" do
|
|
|
|
|
reports.data.each { |report| expect(report[:data]).to be_empty }
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with data" do
|
|
|
|
|
fab!(:gwen) { Fabricate(:user) }
|
|
|
|
|
fab!(:martin) { Fabricate(:user) }
|
|
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
UserHistory.create(
|
|
|
|
|
action: UserHistory.actions[:auto_trust_level_change],
|
|
|
|
|
target_user_id: gwen.id,
|
|
|
|
|
new_value: TrustLevel[2],
|
|
|
|
|
previous_value: 1,
|
|
|
|
|
)
|
|
|
|
|
UserHistory.create(
|
|
|
|
|
action: UserHistory.actions[:change_trust_level],
|
|
|
|
|
target_user_id: martin.id,
|
|
|
|
|
new_value: TrustLevel[4],
|
|
|
|
|
previous_value: 0,
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "works" do
|
|
|
|
|
tl1_reached = reports.data.find { |r| r[:req] == "tl1_reached" }
|
|
|
|
|
tl2_reached = reports.data.find { |r| r[:req] == "tl2_reached" }
|
|
|
|
|
tl3_reached = reports.data.find { |r| r[:req] == "tl3_reached" }
|
|
|
|
|
tl4_reached = reports.data.find { |r| r[:req] == "tl4_reached" }
|
|
|
|
|
|
|
|
|
|
expect(tl1_reached[:data][0][:y]).to eql(0)
|
|
|
|
|
expect(tl2_reached[:data][0][:y]).to eql(1)
|
|
|
|
|
expect(tl3_reached[:data][0][:y]).to eql(0)
|
|
|
|
|
expect(tl4_reached[:data][0][:y]).to eql(1)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2020-06-10 23:57:39 +08:00
|
|
|
|
|
2020-12-10 00:54:41 +08:00
|
|
|
|
describe ".cache" do
|
|
|
|
|
let(:exception_report) { Report.find("exception_test", wrap_exceptions_in_test: true) }
|
|
|
|
|
let(:valid_report) { Report.find("valid_test", wrap_exceptions_in_test: true) }
|
|
|
|
|
|
|
|
|
|
before(:each) do
|
2024-09-11 13:24:19 +08:00
|
|
|
|
Report.stubs(:report_exception_test).raises(Exception)
|
|
|
|
|
Report.stubs(:report_valid_test)
|
2020-12-10 00:54:41 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "caches exception reports for 1 minute" do
|
2022-11-02 17:47:59 +08:00
|
|
|
|
Discourse
|
|
|
|
|
.cache
|
|
|
|
|
.expects(:write)
|
|
|
|
|
.with(Report.cache_key(exception_report), exception_report.as_json, expires_in: 1.minute)
|
2020-12-10 00:54:41 +08:00
|
|
|
|
Report.cache(exception_report)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "caches valid reports for 35 minutes" do
|
2022-11-02 17:47:59 +08:00
|
|
|
|
Discourse
|
|
|
|
|
.cache
|
|
|
|
|
.expects(:write)
|
|
|
|
|
.with(Report.cache_key(valid_report), valid_report.as_json, expires_in: 35.minutes)
|
2020-12-10 00:54:41 +08:00
|
|
|
|
Report.cache(valid_report)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2020-06-10 23:57:39 +08:00
|
|
|
|
describe "top_uploads" do
|
|
|
|
|
context "with no data" do
|
|
|
|
|
it "works" do
|
|
|
|
|
report = Report.find("top_uploads")
|
|
|
|
|
|
|
|
|
|
expect(report.data).to be_empty
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with data" do
|
|
|
|
|
fab!(:jpg_upload) { Fabricate(:upload, extension: :jpg) }
|
|
|
|
|
fab!(:png_upload) { Fabricate(:upload, extension: :png) }
|
|
|
|
|
|
|
|
|
|
it "works" do
|
|
|
|
|
report = Report.find("top_uploads")
|
|
|
|
|
|
|
|
|
|
expect(report.data.length).to eq(2)
|
|
|
|
|
expect(report.data.map { |row| row[:extension] }).to contain_exactly("jpg", "png")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "works with filters" do
|
|
|
|
|
report = Report.find("top_uploads", filters: { file_extension: "jpg" })
|
|
|
|
|
|
|
|
|
|
expect(report.data.length).to eq(1)
|
|
|
|
|
expect(report.data[0][:extension]).to eq("jpg")
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2021-12-03 01:11:55 +08:00
|
|
|
|
|
|
|
|
|
describe "top_users_by_likes_received" do
|
|
|
|
|
let(:report) { Report.find("top_users_by_likes_received") }
|
|
|
|
|
|
|
|
|
|
include_examples "no data"
|
|
|
|
|
|
|
|
|
|
context "with data" do
|
|
|
|
|
before do
|
|
|
|
|
user_1 = Fabricate(:user, username: "jonah")
|
|
|
|
|
user_2 = Fabricate(:user, username: "jake")
|
|
|
|
|
user_3 = Fabricate(:user, username: "john")
|
|
|
|
|
|
|
|
|
|
3.times { UserAction.create!(user_id: user_1.id, action_type: UserAction::WAS_LIKED) }
|
|
|
|
|
9.times { UserAction.create!(user_id: user_2.id, action_type: UserAction::WAS_LIKED) }
|
|
|
|
|
6.times { UserAction.create!(user_id: user_3.id, action_type: UserAction::WAS_LIKED) }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "with category filtering" do
|
|
|
|
|
report = Report.find("top_users_by_likes_received")
|
|
|
|
|
|
|
|
|
|
expect(report.data.length).to eq(3)
|
|
|
|
|
expect(report.data[0][:username]).to eq("jake")
|
|
|
|
|
expect(report.data[1][:username]).to eq("john")
|
|
|
|
|
expect(report.data[2][:username]).to eq("jonah")
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe "top_users_by_likes_received_from_a_variety_of_people" do
|
|
|
|
|
let(:report) { Report.find("top_users_by_likes_received_from_a_variety_of_people") }
|
|
|
|
|
|
|
|
|
|
include_examples "no data"
|
|
|
|
|
|
|
|
|
|
context "with data" do
|
|
|
|
|
before do
|
|
|
|
|
user_1 = Fabricate(:user, username: "jonah")
|
|
|
|
|
user_2 = Fabricate(:user, username: "jake")
|
|
|
|
|
user_3 = Fabricate(:user, username: "john")
|
|
|
|
|
user_4 = Fabricate(:user, username: "joseph")
|
|
|
|
|
user_5 = Fabricate(:user, username: "joanne")
|
|
|
|
|
user_6 = Fabricate(:user, username: "jerome")
|
|
|
|
|
|
|
|
|
|
topic_1 = Fabricate(:topic, user: user_1)
|
|
|
|
|
topic_2 = Fabricate(:topic, user: user_2)
|
|
|
|
|
topic_3 = Fabricate(:topic, user: user_3)
|
|
|
|
|
|
|
|
|
|
post_1 = Fabricate(:post, topic: topic_1, user: user_1)
|
|
|
|
|
post_2 = Fabricate(:post, topic: topic_2, user: user_2)
|
|
|
|
|
post_3 = Fabricate(:post, topic: topic_3, user: user_3)
|
|
|
|
|
|
|
|
|
|
3.times do
|
|
|
|
|
UserAction.create!(
|
|
|
|
|
user_id: user_4.id,
|
|
|
|
|
target_post_id: post_1.id,
|
|
|
|
|
action_type: UserAction::LIKE,
|
|
|
|
|
)
|
2023-01-09 19:18:21 +08:00
|
|
|
|
end
|
2021-12-03 01:11:55 +08:00
|
|
|
|
6.times do
|
|
|
|
|
UserAction.create!(
|
|
|
|
|
user_id: user_5.id,
|
|
|
|
|
target_post_id: post_2.id,
|
|
|
|
|
action_type: UserAction::LIKE,
|
|
|
|
|
)
|
2023-01-09 19:18:21 +08:00
|
|
|
|
end
|
2021-12-03 01:11:55 +08:00
|
|
|
|
9.times do
|
|
|
|
|
UserAction.create!(
|
|
|
|
|
user_id: user_6.id,
|
|
|
|
|
target_post_id: post_3.id,
|
|
|
|
|
action_type: UserAction::LIKE,
|
2023-01-09 19:18:21 +08:00
|
|
|
|
)
|
|
|
|
|
end
|
2021-12-03 01:11:55 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "with category filtering" do
|
|
|
|
|
report = Report.find("top_users_by_likes_received_from_a_variety_of_people")
|
|
|
|
|
|
|
|
|
|
expect(report.data.length).to eq(3)
|
|
|
|
|
expect(report.data[0][:username]).to eq("jonah")
|
|
|
|
|
expect(report.data[1][:username]).to eq("jake")
|
|
|
|
|
expect(report.data[2][:username]).to eq("john")
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe "top_users_by_likes_received_from_inferior_trust_level" do
|
|
|
|
|
let(:report) { Report.find("top_users_by_likes_received_from_inferior_trust_level") }
|
|
|
|
|
|
|
|
|
|
include_examples "no data"
|
|
|
|
|
|
|
|
|
|
context "with data" do
|
|
|
|
|
before do
|
|
|
|
|
user_1 = Fabricate(:user, username: "jonah", trust_level: 2)
|
|
|
|
|
user_2 = Fabricate(:user, username: "jake", trust_level: 2)
|
|
|
|
|
user_3 = Fabricate(:user, username: "john", trust_level: 2)
|
|
|
|
|
user_4 = Fabricate(:user, username: "joseph", trust_level: 1)
|
|
|
|
|
user_5 = Fabricate(:user, username: "joanne", trust_level: 1)
|
|
|
|
|
user_6 = Fabricate(:user, username: "jerome", trust_level: 2)
|
|
|
|
|
|
|
|
|
|
topic_1 = Fabricate(:topic, user: user_1)
|
|
|
|
|
topic_2 = Fabricate(:topic, user: user_2)
|
|
|
|
|
topic_3 = Fabricate(:topic, user: user_3)
|
|
|
|
|
|
|
|
|
|
post_1 = Fabricate(:post, topic: topic_1, user: user_1)
|
|
|
|
|
post_2 = Fabricate(:post, topic: topic_2, user: user_2)
|
|
|
|
|
post_3 = Fabricate(:post, topic: topic_3, user: user_3)
|
|
|
|
|
|
|
|
|
|
3.times do
|
|
|
|
|
UserAction.create!(
|
|
|
|
|
user_id: user_4.id,
|
|
|
|
|
target_post_id: post_1.id,
|
|
|
|
|
action_type: UserAction::LIKE,
|
|
|
|
|
)
|
2023-01-09 19:18:21 +08:00
|
|
|
|
end
|
2021-12-03 01:11:55 +08:00
|
|
|
|
6.times do
|
|
|
|
|
UserAction.create!(
|
|
|
|
|
user_id: user_5.id,
|
|
|
|
|
target_post_id: post_2.id,
|
|
|
|
|
action_type: UserAction::LIKE,
|
|
|
|
|
)
|
2023-01-09 19:18:21 +08:00
|
|
|
|
end
|
2021-12-03 01:11:55 +08:00
|
|
|
|
9.times do
|
|
|
|
|
UserAction.create!(
|
|
|
|
|
user_id: user_6.id,
|
|
|
|
|
target_post_id: post_3.id,
|
|
|
|
|
action_type: UserAction::LIKE,
|
2023-01-09 19:18:21 +08:00
|
|
|
|
)
|
|
|
|
|
end
|
2021-12-03 01:11:55 +08:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "with category filtering" do
|
|
|
|
|
report = Report.find("top_users_by_likes_received_from_inferior_trust_level")
|
|
|
|
|
|
|
|
|
|
expect(report.data.length).to eq(2)
|
|
|
|
|
expect(report.data[0][:username]).to eq("jake")
|
|
|
|
|
expect(report.data[1][:username]).to eq("jonah")
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2024-07-09 13:39:10 +08:00
|
|
|
|
|
|
|
|
|
describe "topic_view_stats" do
|
|
|
|
|
let(:report) { Report.find("topic_view_stats") }
|
|
|
|
|
|
|
|
|
|
fab!(:topic_1) { Fabricate(:topic) }
|
|
|
|
|
fab!(:topic_2) { Fabricate(:topic) }
|
|
|
|
|
|
|
|
|
|
include_examples "no data"
|
|
|
|
|
|
|
|
|
|
context "with data" do
|
|
|
|
|
before do
|
|
|
|
|
freeze_time_safe
|
|
|
|
|
|
|
|
|
|
Fabricate(
|
|
|
|
|
:topic_view_stat,
|
|
|
|
|
topic: topic_1,
|
|
|
|
|
anonymous_views: 4,
|
|
|
|
|
logged_in_views: 2,
|
|
|
|
|
viewed_at: Time.zone.now - 5.days,
|
|
|
|
|
)
|
|
|
|
|
Fabricate(
|
|
|
|
|
:topic_view_stat,
|
|
|
|
|
topic: topic_1,
|
|
|
|
|
anonymous_views: 5,
|
|
|
|
|
logged_in_views: 18,
|
|
|
|
|
viewed_at: Time.zone.now - 3.days,
|
|
|
|
|
)
|
|
|
|
|
Fabricate(
|
|
|
|
|
:topic_view_stat,
|
|
|
|
|
topic: topic_2,
|
|
|
|
|
anonymous_views: 14,
|
|
|
|
|
logged_in_views: 21,
|
|
|
|
|
viewed_at: Time.zone.now - 5.days,
|
|
|
|
|
)
|
|
|
|
|
Fabricate(
|
|
|
|
|
:topic_view_stat,
|
|
|
|
|
topic: topic_2,
|
|
|
|
|
anonymous_views: 9,
|
|
|
|
|
logged_in_views: 13,
|
|
|
|
|
viewed_at: Time.zone.now - 1.days,
|
|
|
|
|
)
|
|
|
|
|
Fabricate(
|
|
|
|
|
:topic_view_stat,
|
|
|
|
|
topic: Fabricate(:topic),
|
|
|
|
|
anonymous_views: 1,
|
|
|
|
|
logged_in_views: 34,
|
|
|
|
|
viewed_at: Time.zone.now - 40.days,
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "works" do
|
|
|
|
|
expect(report.data.length).to eq(2)
|
|
|
|
|
expect(report.data[0]).to include(
|
|
|
|
|
topic_id: topic_2.id,
|
|
|
|
|
topic_title: topic_2.title,
|
|
|
|
|
total_anonymous_views: 23,
|
|
|
|
|
total_logged_in_views: 34,
|
|
|
|
|
total_views: 57,
|
|
|
|
|
)
|
|
|
|
|
expect(report.data[1]).to include(
|
|
|
|
|
topic_id: topic_1.id,
|
|
|
|
|
topic_title: topic_1.title,
|
|
|
|
|
total_anonymous_views: 9,
|
|
|
|
|
total_logged_in_views: 20,
|
|
|
|
|
total_views: 29,
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with category filtering" do
|
|
|
|
|
let(:report) { Report.find("topic_view_stats", filters: { category: category_1.id }) }
|
|
|
|
|
|
|
|
|
|
before { topic_1.update!(category: category_1) }
|
|
|
|
|
|
|
|
|
|
it "filters topics to that category" do
|
|
|
|
|
expect(report.data.length).to eq(1)
|
|
|
|
|
expect(report.data[0]).to include(
|
|
|
|
|
topic_id: topic_1.id,
|
|
|
|
|
topic_title: topic_1.title,
|
|
|
|
|
total_anonymous_views: 9,
|
|
|
|
|
total_logged_in_views: 20,
|
|
|
|
|
total_views: 29,
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2017-02-22 03:45:34 +08:00
|
|
|
|
end
|