Features: - Add article view tracking with automatic deduplication (per user/IP) - Implement intelligent bot detection (35+ patterns: Google, Bing, Baidu, GPTBot, etc) - Create admin analytics dashboard with statistics and filtering - Display view count and comment count on article cards - Add search-based article filter (replaced dropdown for scalability) Analytics Dashboard: - Global stats: total views, human/bot views, unique IPs/users - Top 20 articles ranking with detailed metrics - Detailed view records with time, article, user, IP, user-agent - Filters: article title search, IP search, show/hide bots - Pagination support (50 records per page) Technical Implementation: - Async view recording (non-blocking) - Dual deduplication (application + database layer) - Database indexes for performance optimization - Batch query for comment counts - Full i18n support (Chinese/English) Files Added: - models/article_view.go: View tracking model - models/bot_detector.go: Bot detection logic - handlers/admin_analytics.go: Analytics page handler - templates/admin/analytics_views.html: Analytics UI - test_analytics.sh: Testing script - Documentation: implementation guide, usage guide, changelog Files Modified: - handlers/home.go: Add view recording and comment count queries - models/db.go: Add ArticleView to auto-migration - main.go: Add analytics routes - i18n/i18n.go: Add 35+ translation keys - templates/admin/dashboard.html: Add analytics entry link - templates/pages/home.html: Display view/comment counts on cards Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
39 lines
1.0 KiB
Go
39 lines
1.0 KiB
Go
package models
|
|
|
|
import (
|
|
"strings"
|
|
)
|
|
|
|
// botPatterns contains common bot/crawler/spider User-Agent patterns.
|
|
var botPatterns = []string{
|
|
"bot", "crawler", "spider", "scraper", "scraping",
|
|
"googlebot", "bingbot", "baiduspider", "yandexbot",
|
|
"duckduckbot", "slurp", "teoma", "ia_archiver",
|
|
"facebookexternalhit", "facebot", "twitterbot",
|
|
"whatsapp", "telegram", "slackbot", "discordbot",
|
|
"linkedinbot", "pinterestbot", "tumblr",
|
|
"semrushbot", "ahrefsbot", "mj12bot", "dotbot",
|
|
"archive.org_bot", "serpstatbot", "dataforseo",
|
|
"petalbot", "gptbot", "claudebot", "anthropic-ai",
|
|
"bytespider", "applebot", "seznambot",
|
|
"headless", "phantom", "selenium", "puppeteer",
|
|
}
|
|
|
|
// IsBot checks if the given User-Agent string matches known bot patterns.
|
|
// It performs a case-insensitive substring match against common bot identifiers.
|
|
func IsBot(userAgent string) bool {
|
|
if userAgent == "" {
|
|
return false
|
|
}
|
|
|
|
ua := strings.ToLower(userAgent)
|
|
|
|
for _, pattern := range botPatterns {
|
|
if strings.Contains(ua, pattern) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|