Documentation
¶
Index ¶
- Constants
- func AddBotRecord(ctx context.Context, store statsstore.StoreInterface, record BotRecord) error
- func AddBotRecords(ctx context.Context, store statsstore.StoreInterface, newRecords []BotRecord) error
- func AssertContains(t testing.TB, body, substr string)
- func Breadcrumbs(items []Breadcrumb) hb.TagInterface
- func FlagIPVisitorsAsBot(ctx context.Context, store statsstore.StoreInterface, ip string) (int, error)
- func FlashOrRedirect(opts ControllerOptions, w http.ResponseWriter, r *http.Request, message string, ...) string
- func GetBotIPs(ctx context.Context, store statsstore.StoreInterface) []string
- func NewTestControllerOptions(t testing.TB) (ControllerOptions, *FakeLayout, statsstore.StoreInterface)
- func NewTestStore(t testing.TB) statsstore.StoreInterface
- func PeriodOptions() []struct{ ... }
- func RemoveBotRecord(ctx context.Context, store statsstore.StoreInterface, ip string) error
- func SaveBotRecords(ctx context.Context, store statsstore.StoreInterface, records []BotRecord) error
- func SeedVisitor(t testing.TB, store statsstore.StoreInterface, ip, path, country string)
- type BotReason
- type BotReasonDisplay
- type BotRecord
- type Breadcrumb
- type ControllerOptions
- type CountEntry
- type CountryNameResolver
- type FakeLayout
- func (l *FakeLayout) Render(http.ResponseWriter, *http.Request) string
- func (l *FakeLayout) SetBody(body string)
- func (l *FakeLayout) SetCountryNameByIso2(func(string) (string, error))
- func (l *FakeLayout) SetScriptURLs(urls []string)
- func (l *FakeLayout) SetScripts(scripts []string)
- func (l *FakeLayout) SetStyleURLs(styles []string)
- func (l *FakeLayout) SetStyles(styles []string)
- func (l *FakeLayout) SetTitle(title string)
- type LayoutInterface
- type Links
- func (l *Links) Base() string
- func (l *Links) Dashboard(params map[string]string) string
- func (l *Links) IPDetails(params map[string]string) string
- func (l *Links) Sessions(params map[string]string) string
- func (l *Links) Settings(params map[string]string) string
- func (l *Links) Visitors(params map[string]string) string
- type PeriodBounds
- type VisitorLike
Constants ¶
const ( // BotReasonUserAgent indicates the visitor's User-Agent string // self-identified as a bot (matched statsstore.IsBot). BotReasonUserAgent = "user-agent:bot" // BotReasonDataCenterIP indicates the visitor's IP falls within a known // data-center CIDR range (matched statsstore.IsDataCenterIP). BotReasonDataCenterIP = "datacenter-ip" // BotReasonReferrerSpam indicates the visitor's referrer matched a known // referrer-spam domain (matched statsstore.IsReferrerSpam). BotReasonReferrerSpam = "referrer-spam" )
Reason pattern labels for signals that are not path substrings. These are shown in the UI as the reason "pattern" so the user understands which heuristic triggered the bot flag.
const ( CONTROLLER_DASHBOARD = "dashboard" CONTROLLER_VISITORS = "visitors" CONTROLLER_SESSIONS = "sessions" CONTROLLER_SETTINGS = "settings" CONTROLLER_IP_DETAILS = "ip-details" )
const ( ParamController = "controller" ParamAction = "action" ParamPeriod = "period" ParamCountry = "country" ParamDeviceType = "device_type" ParamPath = "path" ParamDateFrom = "date_from" ParamDateTo = "date_to" ParamPage = "page" ParamIP = "ip" )
Query parameter names
const ( PeriodToday = "today" PeriodYesterday = "yesterday" PeriodLast7Days = "last-7-days" PeriodThisMonth = "this-month" PeriodLastMonth = "last-month" PeriodAllTime = "all-time" PeriodDefault = PeriodLast7Days )
Period identifiers
const ( DefaultPageSize = 25 MaxPageSize = 100 )
Pagination
const BotSourceIdentified = "identified"
BotSourceIdentified means the IP was added via the "Identify Bots" scan.
const BotSourceManual = "manual"
BotSourceManual means the IP was added manually by the user.
const SettingKeyBotIPs = "bot_ips"
SettingKeyBotIPs is the key under which bot IP records are stored as a JSON array in the stats store's settings table.
Variables ¶
This section is empty.
Functions ¶
func AddBotRecord ¶ added in v1.25.0
func AddBotRecord(ctx context.Context, store statsstore.StoreInterface, record BotRecord) error
AddBotRecord adds a single bot record, avoiding duplicates by IP.
func AddBotRecords ¶ added in v1.25.0
func AddBotRecords(ctx context.Context, store statsstore.StoreInterface, newRecords []BotRecord) error
AddBotRecords batch-adds multiple bot records in a single store write, skipping any IPs that already exist in the list.
func AssertContains ¶ added in v1.25.0
AssertContains checks that the body contains a substring, failing the test with a clear message if not.
func Breadcrumbs ¶
func Breadcrumbs(items []Breadcrumb) hb.TagInterface
Breadcrumbs renders a breadcrumb navigation trail from the given entries. The last entry should have an empty URL to indicate the current page.
func FlagIPVisitorsAsBot ¶ added in v1.25.0
func FlagIPVisitorsAsBot(ctx context.Context, store statsstore.StoreInterface, ip string) (int, error)
FlagIPVisitorsAsBot sets bot='yes' on all visitor records for the given IP. Returns the number of visitor records that were found (regardless of whether they were already flagged). If no visitor records exist for the IP, returns (0, nil) — callers should check the count and warn the user accordingly.
func FlashOrRedirect ¶ added in v1.25.0
func FlashOrRedirect(opts ControllerOptions, w http.ResponseWriter, r *http.Request, message string, redirectURL string, delaySeconds int) string
FlashOrRedirect renders a flash error message via the FlashError callback when configured, otherwise falls back to a plain HTTP redirect. It returns the response body string (matching the controller Handler signature).
func GetBotIPs ¶ added in v1.25.0
func GetBotIPs(ctx context.Context, store statsstore.StoreInterface) []string
GetBotIPs returns just the IP strings from the bot records.
func NewTestControllerOptions ¶ added in v1.25.0
func NewTestControllerOptions(t testing.TB) (ControllerOptions, *FakeLayout, statsstore.StoreInterface)
NewTestControllerOptions builds a ControllerOptions wired to a test store and FakeLayout, suitable for controller tests.
func NewTestStore ¶ added in v1.25.0
func NewTestStore(t testing.TB) statsstore.StoreInterface
NewTestStore creates an in-memory SQLite statsstore for testing. It auto-migrates the visitor table and registers a cleanup via t.Cleanup.
func PeriodOptions ¶ added in v1.25.0
func PeriodOptions() []struct{ Value, Label string }
PeriodOptions returns the ordered list of selectable periods for the UI.
func RemoveBotRecord ¶ added in v1.25.0
func RemoveBotRecord(ctx context.Context, store statsstore.StoreInterface, ip string) error
RemoveBotRecord removes a bot record by IP.
func SaveBotRecords ¶ added in v1.25.0
func SaveBotRecords(ctx context.Context, store statsstore.StoreInterface, records []BotRecord) error
SaveBotRecords writes the full bot records to the stats store settings.
func SeedVisitor ¶ added in v1.25.0
func SeedVisitor(t testing.TB, store statsstore.StoreInterface, ip, path, country string)
SeedVisitor creates a single visitor record in the store for testing.
Types ¶
type BotReason ¶ added in v1.25.0
type BotReason struct {
Pattern string `json:"pattern"` // the matched bot-page pattern (e.g. "sitemap.xml")
Path string `json:"path"` // sample visitor paths
Hits int `json:"hits"` // how many times this pattern was hit
}
BotReason captures a single piece of evidence that caused an IP to be flagged as a bot (e.g. it visited sitemap.xml 3 times).
type BotReasonDisplay ¶ added in v1.26.0
type BotReasonDisplay struct {
Pattern string `json:"pattern"`
Hits int `json:"hits"`
Paths []string `json:"paths"`
}
BotReasonDisplay is a single reason an IP was flagged as a bot, formatted for display in the admin UI. It mirrors the JSON shape expected by the frontend (pattern, hits, sample paths).
func ComputeBotReasons ¶ added in v1.26.0
func ComputeBotReasons(visitors []statsstore.VisitorInterface, extraPathPatterns []string) []BotReasonDisplay
ComputeBotReasons derives the bot reasons for a set of visitor records belonging to a single IP. It checks all signals used at ingestion time (see store.VisitorRegister): user-agent self-identification, data-center IP, referrer spam, bot-only paths, and malicious paths. extraPathPatterns is an optional list of consumer-specific path substrings to also check (e.g. ".php", "/wp-admin"); pass nil to check only the universal statsstore patterns.
Universal bot/malicious path patterns use the same precise matching as statsstore.IsBotPath / statsstore.IsMaliciousPath (suffix on last path segment for file patterns, segment match for directory patterns). Extra consumer patterns use case-insensitive substring matching, consistent with the identify-bots scan. The returned slice is sorted by pattern for stable display.
type BotRecord ¶ added in v1.25.0
type BotRecord struct {
IP string `json:"ip"`
AddedAt string `json:"added_at"` // "YYYY-MM-DD HH:MM:SS" UTC
Source string `json:"source"` // "identified" or "manual"
Reasons []BotReason `json:"reasons"`
}
BotRecord is the full record for a single flagged bot IP.
func GetBotRecords ¶ added in v1.25.0
func GetBotRecords(ctx context.Context, store statsstore.StoreInterface) []BotRecord
GetBotRecords reads the full bot IP records from the stats store settings.
type Breadcrumb ¶
Breadcrumb represents a navigation breadcrumb entry.
type ControllerOptions ¶
type ControllerOptions struct {
// Store is the statsstore instance used for all visitor queries.
Store statsstore.StoreInterface
// Layout renders the full HTML page. Required.
Layout LayoutInterface
// HomeURL is the URL for the admin home page (e.g. "/admin").
HomeURL string
// WebsiteUrl is the public site URL.
WebsiteUrl string
// BaseURL is the base URL for the stats admin (e.g. "/admin/stats").
// Replaces the old internal/links dependency.
BaseURL string
// CountryNameByIso2 maps an ISO2 code to a human-readable country name.
// Optional; when nil, raw ISO2 codes are displayed.
CountryNameByIso2 func(iso2Code string) (string, error)
// AuthUserID returns the authenticated user ID from the request, or ""
// when unauthenticated. When nil, auth checks are skipped.
AuthUserID func(r *http.Request) string
// FlashError renders a flash error message and returns the redirect
// response body. When nil, controllers fall back to http.Redirect.
FlashError func(w http.ResponseWriter, r *http.Request, message string, redirectURL string, delaySeconds int) string
// Logger is used for internal logging. Defaults to slog.Default().
Logger *slog.Logger
}
ControllerOptions contains the dependencies and configuration for creating an admin controller. It extends the original statsstore admin options with optional callbacks for auth, flash messages, and base URL configuration so the package remains self-contained and reusable by any project.
func (ControllerOptions) CountryName ¶ added in v1.25.0
func (o ControllerOptions) CountryName(iso2 string) string
CountryName resolves an ISO2 code to a human-readable country name using the CountryNameByIso2 callback. Returns the raw code when the callback is nil or returns an error.
type CountEntry ¶ added in v1.25.0
CountEntry is a generic (label, count) pair used for top-N breakdowns.
func AggregateCounts ¶ added in v1.25.0
func AggregateCounts(visitors []VisitorLike, extract func(v VisitorLike) string) []CountEntry
AggregateCounts reduces a visitor slice to a frequency map keyed by the provided extractor. Empty labels are grouped under "—".
func TopN ¶ added in v1.25.0
func TopN(in []CountEntry, n int) []CountEntry
TopN returns at most n entries from a sorted slice.
type CountryNameResolver ¶ added in v1.25.0
type CountryNameResolver struct {
// contains filtered or unexported fields
}
CountryNameResolver wraps a CountryNameByIso2 callback with a simple pass-through cache. It is safe for concurrent use; the lookup runs once per resolver instance.
func NewCountryNameResolver ¶ added in v1.25.0
func NewCountryNameResolver(lookup func(iso2Code string) (string, error)) *CountryNameResolver
NewCountryNameResolver returns a fresh resolver bound to the given callback. If the callback is nil, Name always returns the raw code.
type FakeLayout ¶ added in v1.25.0
type FakeLayout struct {
Title string
Body string
Scripts []string
ScriptURLs []string
Styles []string
StyleURLs []string
}
FakeLayout implements LayoutInterface for testing. It captures all Set* calls and returns a fixed string from Render.
func (*FakeLayout) Render ¶ added in v1.25.0
func (l *FakeLayout) Render(http.ResponseWriter, *http.Request) string
func (*FakeLayout) SetBody ¶ added in v1.25.0
func (l *FakeLayout) SetBody(body string)
func (*FakeLayout) SetCountryNameByIso2 ¶ added in v1.25.0
func (l *FakeLayout) SetCountryNameByIso2(func(string) (string, error))
func (*FakeLayout) SetScriptURLs ¶ added in v1.25.0
func (l *FakeLayout) SetScriptURLs(urls []string)
func (*FakeLayout) SetScripts ¶ added in v1.25.0
func (l *FakeLayout) SetScripts(scripts []string)
func (*FakeLayout) SetStyleURLs ¶ added in v1.25.0
func (l *FakeLayout) SetStyleURLs(styles []string)
func (*FakeLayout) SetStyles ¶ added in v1.25.0
func (l *FakeLayout) SetStyles(styles []string)
func (*FakeLayout) SetTitle ¶ added in v1.25.0
func (l *FakeLayout) SetTitle(title string)
type LayoutInterface ¶
type LayoutInterface interface {
SetTitle(title string)
SetScriptURLs(scripts []string)
SetScripts(scripts []string)
SetStyleURLs(styles []string)
SetStyles(styles []string)
SetBody(string)
// SetCountryNameByIso2 provides country lookup helpers used by the admin UI.
SetCountryNameByIso2(func(iso2Code string) (string, error))
Render(w http.ResponseWriter, r *http.Request) string
}
LayoutInterface defines the layout methods needed by controllers. Consumers implement this to wrap admin pages in their own chrome.
type Links ¶ added in v1.25.0
type Links struct {
// contains filtered or unexported fields
}
Links builds stats admin URLs from a configured base URL. It mutates the passed params map by setting the controller key; callers should pass a fresh map each time.
func NewLinks ¶ added in v1.25.0
NewLinks returns a URL builder bound to the given base URL. If baseURL is empty, "/" is used as a safe default.
type PeriodBounds ¶ added in v1.25.0
type PeriodBounds struct {
From string // inclusive, "YYYY-MM-DD HH:MM:SS"
To string // inclusive
Label string
}
PeriodBounds holds the created_at >= / <= bounds for a selected period.
func ResolvePeriod ¶ added in v1.25.0
func ResolvePeriod(period string) PeriodBounds
ResolvePeriod maps a period identifier to concrete created_at bounds. Unknown or empty values fall back to the default period.
type VisitorLike ¶ added in v1.25.0
type VisitorLike interface {
GetPath() string
GetCountry() string
GetUserBrowser() string
GetUserOs() string
GetUserDeviceType() string
GetIpAddress() string
GetFingerprint() string
GetCreatedAt() string
GetBot() string
GetThreat() string
}
VisitorLike is the minimal subset of statsstore.VisitorInterface used by aggregation helpers. The real interface satisfies it structurally.