FEATURE: Only count topic views for explicit/deferred tracked views (#27533)

Followup 2f2da7274732cba30d03b6c5c3a4194652cb6783

This commit moves topic view tracking from happening
every time a Topic is requested, which is susceptible
to inflating numbers of views from web crawlers, to
our request tracker middleware.

In this new location, topic views are only tracked when
the following headers are sent:

* HTTP_DISCOURSE_TRACK_VIEW - This is sent on every page navigation when
  clicking around the ember app. We count these as browser page views
  because we know it comes from the AJAX call in our app. The topic ID
  is extracted from HTTP_DISCOURSE_TRACK_VIEW_TOPIC_ID
* HTTP_DISCOURSE_DEFERRED_TRACK_VIEW - Sent when MessageBus initializes
  after first loading the page to count the initial page load view. The
  topic ID is extracted from HTTP_DISCOURSE_DEFERRED_TRACK_VIEW.

This will bring topic views more in line with the change we
made to page views in the referenced commit and result in
more realistic topic view counts.
This commit is contained in:
Martin Brennan
2024-07-03 10:38:49 +10:00
committed by GitHub
parent 57af5d6f0d
commit 527f02e99f
12 changed files with 641 additions and 183 deletions

View File

@ -75,11 +75,11 @@ describe "Topic Map - Private Message", type: :system do
expect(topic_map.expanded_map_avatars_details.length).to eq 4
# views count
expect {
sign_in(other_user)
topic_page.visit_topic(topic)
page.refresh
}.to change(topic_map, :views_count).by 1
sign_in(other_user)
topic_page.visit_topic(topic)
try_until_success { expect(TopicViewItem.count).to eq(2) }
page.refresh
expect(topic_map.views_count).to eq(2)
# likes count
expect(topic_map).to have_no_likes

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
describe "request tracking", type: :system do
describe "Request tracking", type: :system do
before do
ApplicationRequest.enable
CachedCounting.reset
@ -13,176 +13,262 @@ describe "request tracking", type: :system do
CachedCounting.disable
end
it "tracks an anonymous visit correctly" do
visit "/"
describe "pageviews" do
it "tracks an anonymous visit correctly" do
visit "/"
try_until_success do
CachedCounting.flush
expect(ApplicationRequest.stats).to include(
"page_view_anon_total" => 1,
"page_view_anon_browser_total" => 1,
"page_view_logged_in_total" => 0,
"page_view_crawler_total" => 0,
)
try_until_success do
CachedCounting.flush
expect(ApplicationRequest.stats).to include(
"page_view_anon_total" => 1,
"page_view_anon_browser_total" => 1,
"page_view_logged_in_total" => 0,
"page_view_crawler_total" => 0,
)
end
find(".nav-item_categories a").click
try_until_success do
CachedCounting.flush
expect(ApplicationRequest.stats).to include(
"page_view_anon_total" => 2,
"page_view_anon_browser_total" => 2,
"page_view_logged_in_total" => 0,
"page_view_crawler_total" => 0,
)
end
end
find(".nav-item_categories a").click
it "tracks a crawler visit correctly" do
# Can't change Selenium's user agent... so change site settings to make Discourse detect chrome as a crawler
SiteSetting.crawler_user_agents += "|chrome"
try_until_success do
CachedCounting.flush
expect(ApplicationRequest.stats).to include(
"page_view_anon_total" => 2,
"page_view_anon_browser_total" => 2,
"page_view_logged_in_total" => 0,
"page_view_crawler_total" => 0,
)
visit "/"
try_until_success do
CachedCounting.flush
expect(ApplicationRequest.stats).to include(
"page_view_anon_total" => 0,
"page_view_anon_browser_total" => 0,
"page_view_logged_in_total" => 0,
"page_view_crawler_total" => 1,
)
end
end
it "tracks a logged-in session correctly" do
sign_in Fabricate(:user)
visit "/"
try_until_success do
CachedCounting.flush
expect(ApplicationRequest.stats).to include(
"page_view_anon_total" => 0,
"page_view_anon_browser_total" => 0,
"page_view_logged_in_total" => 1,
"page_view_crawler_total" => 0,
"page_view_logged_in_browser_total" => 1,
)
end
find(".nav-item_categories a").click
try_until_success do
CachedCounting.flush
expect(ApplicationRequest.stats).to include(
"page_view_anon_total" => 0,
"page_view_anon_browser_total" => 0,
"page_view_logged_in_total" => 2,
"page_view_crawler_total" => 0,
"page_view_logged_in_browser_total" => 2,
)
end
end
it "tracks normal error pages correctly" do
SiteSetting.bootstrap_error_pages = false
visit "/foobar"
try_until_success do
CachedCounting.flush
# Does not count error as a pageview
expect(ApplicationRequest.stats).to include(
"http_4xx_total" => 1,
"page_view_anon_total" => 0,
"page_view_anon_browser_total" => 0,
"page_view_logged_in_total" => 0,
"page_view_crawler_total" => 0,
)
end
find("#site-logo").click
try_until_success do
CachedCounting.flush
expect(ApplicationRequest.stats).to include(
"http_4xx_total" => 1,
"page_view_anon_total" => 1,
"page_view_anon_browser_total" => 1,
"page_view_logged_in_total" => 0,
"page_view_crawler_total" => 0,
)
end
end
it "tracks non-ember pages correctly" do
visit "/safe-mode"
try_until_success do
CachedCounting.flush
# Does not count error as a pageview
expect(ApplicationRequest.stats).to include(
"page_view_anon_total" => 1,
"page_view_anon_browser_total" => 1,
"page_view_logged_in_total" => 0,
"page_view_crawler_total" => 0,
)
end
end
it "tracks bootstrapped error pages correctly" do
SiteSetting.bootstrap_error_pages = true
visit "/foobar"
try_until_success do
CachedCounting.flush
# Does not count error as a pageview
expect(ApplicationRequest.stats).to include(
"http_4xx_total" => 1,
"page_view_anon_total" => 0,
"page_view_anon_browser_total" => 0,
"page_view_logged_in_total" => 0,
"page_view_crawler_total" => 0,
)
end
find("#site-logo").click
try_until_success do
CachedCounting.flush
expect(ApplicationRequest.stats).to include(
"http_4xx_total" => 1,
"page_view_anon_total" => 1,
"page_view_anon_browser_total" => 1,
"page_view_logged_in_total" => 0,
"page_view_crawler_total" => 0,
)
end
end
it "tracks published pages correctly" do
SiteSetting.enable_page_publishing = true
page =
Fabricate(:published_page, public: true, slug: "some-page", topic: Fabricate(:post).topic)
visit "/pub/some-page"
try_until_success do
CachedCounting.flush
# Does not count error as a pageview
expect(ApplicationRequest.stats).to include(
"page_view_anon_total" => 1,
"page_view_anon_browser_total" => 1,
"page_view_logged_in_total" => 0,
"page_view_crawler_total" => 0,
)
end
end
end
it "tracks a crawler visit correctly" do
# Can't change Selenium's user agent... so change site settings to make Discourse detect chrome as a crawler
SiteSetting.crawler_user_agents += "|chrome"
describe "topic views" do
fab!(:current_user) { Fabricate(:user) }
fab!(:topic)
fab!(:post) { Fabricate(:post, topic: topic) }
visit "/"
context "when logged in" do
before { sign_in(current_user) }
try_until_success do
CachedCounting.flush
expect(ApplicationRequest.stats).to include(
"page_view_anon_total" => 0,
"page_view_anon_browser_total" => 0,
"page_view_logged_in_total" => 0,
"page_view_crawler_total" => 1,
)
end
end
it "tracks user viewing a topic correctly with deferred tracking" do
visit topic.url
it "tracks a logged-in session correctly" do
sign_in Fabricate(:user)
try_until_success do
CachedCounting.flush
expect(TopicViewItem.exists?(topic_id: topic.id, user_id: current_user.id)).to eq(true)
expect(
TopicViewStat.exists?(
topic_id: topic.id,
viewed_at: Time.zone.now.to_date,
anonymous_views: 0,
logged_in_views: 1,
),
).to eq(true)
end
end
visit "/"
it "tracks user viewing a topic correctly with explicit tracking" do
visit "/"
try_until_success do
CachedCounting.flush
expect(ApplicationRequest.stats).to include(
"page_view_anon_total" => 0,
"page_view_anon_browser_total" => 0,
"page_view_logged_in_total" => 1,
"page_view_crawler_total" => 0,
"page_view_logged_in_browser_total" => 1,
)
find(".topic-list-item .raw-topic-link[data-topic-id='#{topic.id}']").click
try_until_success do
CachedCounting.flush
expect(TopicViewItem.exists?(topic_id: topic.id, user_id: current_user.id)).to eq(true)
expect(
TopicViewStat.exists?(
topic_id: topic.id,
viewed_at: Time.zone.now.to_date,
anonymous_views: 0,
logged_in_views: 1,
),
).to eq(true)
end
end
end
find(".nav-item_categories a").click
context "when anonymous" do
it "tracks an anonymous user viewing a topic correctly with deferred tracking" do
visit topic.url
try_until_success do
CachedCounting.flush
expect(ApplicationRequest.stats).to include(
"page_view_anon_total" => 0,
"page_view_anon_browser_total" => 0,
"page_view_logged_in_total" => 2,
"page_view_crawler_total" => 0,
"page_view_logged_in_browser_total" => 2,
)
end
end
try_until_success do
CachedCounting.flush
expect(TopicViewItem.exists?(topic_id: topic.id, user_id: nil)).to eq(true)
expect(
TopicViewStat.exists?(
topic_id: topic.id,
viewed_at: Time.zone.now.to_date,
anonymous_views: 1,
logged_in_views: 0,
),
).to eq(true)
end
end
it "tracks normal error pages correctly" do
SiteSetting.bootstrap_error_pages = false
it "tracks an anonymous user viewing a topic correctly with explicit tracking" do
visit "/"
visit "/foobar"
find(".topic-list-item .raw-topic-link[data-topic-id='#{topic.id}']").click
try_until_success do
CachedCounting.flush
# Does not count error as a pageview
expect(ApplicationRequest.stats).to include(
"http_4xx_total" => 1,
"page_view_anon_total" => 0,
"page_view_anon_browser_total" => 0,
"page_view_logged_in_total" => 0,
"page_view_crawler_total" => 0,
)
end
find("#site-logo").click
try_until_success do
CachedCounting.flush
expect(ApplicationRequest.stats).to include(
"http_4xx_total" => 1,
"page_view_anon_total" => 1,
"page_view_anon_browser_total" => 1,
"page_view_logged_in_total" => 0,
"page_view_crawler_total" => 0,
)
end
end
it "tracks non-ember pages correctly" do
visit "/safe-mode"
try_until_success do
CachedCounting.flush
# Does not count error as a pageview
expect(ApplicationRequest.stats).to include(
"page_view_anon_total" => 1,
"page_view_anon_browser_total" => 1,
"page_view_logged_in_total" => 0,
"page_view_crawler_total" => 0,
)
end
end
it "tracks bootstrapped error pages correctly" do
SiteSetting.bootstrap_error_pages = true
visit "/foobar"
try_until_success do
CachedCounting.flush
# Does not count error as a pageview
expect(ApplicationRequest.stats).to include(
"http_4xx_total" => 1,
"page_view_anon_total" => 0,
"page_view_anon_browser_total" => 0,
"page_view_logged_in_total" => 0,
"page_view_crawler_total" => 0,
)
end
find("#site-logo").click
try_until_success do
CachedCounting.flush
expect(ApplicationRequest.stats).to include(
"http_4xx_total" => 1,
"page_view_anon_total" => 1,
"page_view_anon_browser_total" => 1,
"page_view_logged_in_total" => 0,
"page_view_crawler_total" => 0,
)
end
end
it "tracks published pages correctly" do
SiteSetting.enable_page_publishing = true
page =
Fabricate(:published_page, public: true, slug: "some-page", topic: Fabricate(:post).topic)
visit "/pub/some-page"
try_until_success do
CachedCounting.flush
# Does not count error as a pageview
expect(ApplicationRequest.stats).to include(
"page_view_anon_total" => 1,
"page_view_anon_browser_total" => 1,
"page_view_logged_in_total" => 0,
"page_view_crawler_total" => 0,
)
try_until_success do
CachedCounting.flush
expect(TopicViewItem.exists?(topic_id: topic.id, user_id: nil)).to eq(true)
expect(
TopicViewStat.exists?(
topic_id: topic.id,
viewed_at: Time.zone.now.to_date,
anonymous_views: 1,
logged_in_views: 0,
),
).to eq(true)
end
end
end
end
end

View File

@ -63,11 +63,11 @@ describe "Topic Map", type: :system do
expect(topic_map.expanded_map_avatars_details.length).to eq 4
# views count
expect {
sign_in(other_user)
topic_page.visit_topic(topic)
page.refresh
}.to change(topic_map, :views_count).by 1
sign_in(other_user)
topic_page.visit_topic(topic)
try_until_success { expect(TopicViewItem.count).to eq(2) }
page.refresh
expect(topic_map.views_count).to eq(2)
# likes count
expect(topic_map).to have_no_likes