mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-26 19:22:18 +08:00
This commit adds two new cards to the redesigned admin dashboard's Site
Traffic section: top countries and top referrers, both sourced from
`browser_pageview_events`.
Key technical decisions:
1. Gate the cards on the `persist_browser_pageview_events` site setting.
The cards have no data source unless browser pageview events are being
persisted, so they are omitted from the dashboard.
2. Normalize referrers at write time. A new `normalized_referrer` column
on `browser_pageview_events` is populated by
`BrowserPageviewReferrerInspector`, which strips scheme, `www.`, port,
fragment, trailing slashes, and common tracking query params. Doing this
at insert time avoids per-row string operations at query time.
3. Count browser pageviews by country and by referrer in two new report
concerns. `Reports::TopCountriesByBrowserPageviews` groups by
`country_code` and `Reports::TopReferrersByBrowserPageviews` groups by
`normalized_referrer`. Both compute share of total browser pageviews and
rank the top 5 in SQL. The country report drops MaxMind reserved codes
(unknown, anonymous proxy, satellite). The referrer report drops
same-host referrals. Both also exclude anonymous browser pageviews
(`user_id IS NULL`) when the `login_required` site setting is enabled,
since only logged-in browser pageviews are meaningful on a closed forum.
4. Fetch each report through the existing dashboard service.
`AdminDashboardSiteTraffic#build` returns one entry per card with a `{
rows:, error: }` shape, e.g.:
```ruby
{
top_countries: {
rows: [
{ country_code: "US", count: 142, percent: 35 },
{ country_code: "GB", count: 89, percent: 22 }
],
error: nil
},
top_referrers: {
rows: [
{ normalized_referrer: "news.ycombinator.com/item?id=1", count: 47,
percent: 12 },
{ normalized_referrer: "reddit.com/r/discourse", count: 31, percent: 8 }
],
error: nil
}
}
```
On report failure, `rows: []` and `error: :timeout` (or another symbol).
This lets the UI render rows, error, or empty state independently.
Healthy responses are cached via `Report.find_cached`.
`SiteSetting.login_required` and `Discourse.current_hostname` flow into
`opts[:filters]` so toggling either invalidates the cache. Timeouts skip
the cache so the next request retries.
5. Use `Intl.DisplayNames` for country names instead of locale files.
`Intl.DisplayNames` is a built-in browser API that returns a localized
country name for an ISO 3166-1 alpha-2 code, avoiding ~250 translation
strings per locale.
76 lines
2.1 KiB
Ruby
Vendored
76 lines
2.1 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
desc "Creates sample categories"
|
|
task "groups:populate" => ["db:load_config"] do |_, args|
|
|
DiscourseDev::Group.populate!
|
|
end
|
|
|
|
desc "Creates sample user accounts"
|
|
task "users:populate" => ["db:load_config"] do |_, args|
|
|
DiscourseDev::User.populate!
|
|
end
|
|
|
|
desc "Creates sample categories"
|
|
task "categories:populate" => ["db:load_config"] do |_, args|
|
|
DiscourseDev::Category.populate!
|
|
end
|
|
|
|
desc "Creates sample tags"
|
|
task "tags:populate" => ["db:load_config"] do |_, args|
|
|
DiscourseDev::Tag.populate!
|
|
end
|
|
|
|
desc "Creates sample topics"
|
|
task "topics:populate" => ["db:load_config"] do |_, args|
|
|
if ENV["IGNORE_CURRENT_COUNT"] == "true"
|
|
DiscourseDev::Topic.populate!(ignore_current_count: true)
|
|
else
|
|
DiscourseDev::Topic.populate!
|
|
end
|
|
end
|
|
|
|
desc "Creates sample reviewables"
|
|
task "reviewables:populate" => ["db:load_config"] do |_, args|
|
|
DiscourseDev::Reviewable.populate!
|
|
end
|
|
|
|
desc "Creates sample private messages"
|
|
task "private_messages:populate", [:recipient] => ["db:load_config"] do |_, args|
|
|
args.with_defaults(type: "string")
|
|
|
|
if !args[:recipient]
|
|
puts "ERROR: Expecting rake private_messages:populate[recipient]"
|
|
exit 1
|
|
end
|
|
|
|
DiscourseDev::Topic.populate!(
|
|
private_messages: true,
|
|
recipient: args[:recipient],
|
|
ignore_current_count: true,
|
|
)
|
|
end
|
|
|
|
desc "Create post revisions"
|
|
task "post_revisions:populate" => ["db:load_config"] do |_, args|
|
|
DiscourseDev::PostRevision.populate!
|
|
end
|
|
|
|
desc "Add replies to a topic"
|
|
task "replies:populate", %i[topic_id count] => ["db:load_config"] do |_, args|
|
|
DiscourseDev::Post.add_replies!(args)
|
|
end
|
|
|
|
desc "Creates sample email logs"
|
|
task "email_logs:populate" => ["db:load_config"] do |_, args|
|
|
DiscourseDev::EmailLog.populate!
|
|
end
|
|
|
|
desc "Populates sample data for the admin dashboard"
|
|
task "admin_dashboard:populate" => ["db:load_config"] do |_, args|
|
|
DiscourseDev::ApplicationRequest.populate!
|
|
end
|
|
|
|
desc "Enables persist_browser_pageview_events and seeds matching events + application_requests"
|
|
task "browser_pageview_events:populate", [:count] => ["db:load_config"] do |_, args|
|
|
DiscourseDev::BrowserPageviewEvent.populate!(count: args[:count]&.to_i)
|
|
end
|