package server import ( "bytes" "math/rand" "net/http" "os" "strconv" "time" "github.com/writekitapp/writekit/internal/auth" "github.com/writekitapp/writekit/internal/db" "github.com/writekitapp/writekit/internal/tenant" ) type ctxKey string const ( tenantIDKey ctxKey = "tenantID" demoInfoKey ctxKey = "demoInfo" ) type DemoInfo struct { IsDemo bool ExpiresAt time.Time } func GetDemoInfo(r *http.Request) DemoInfo { if info, ok := r.Context().Value(demoInfoKey).(DemoInfo); ok { return info } return DemoInfo{} } func demoAwareSessionMiddleware(database *db.DB) func(http.Handler) http.Handler { sessionMW := auth.SessionMiddleware(database) return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if GetDemoInfo(r).IsDemo { next.ServeHTTP(w, r) return } sessionMW(next).ServeHTTP(w, r) }) } } func (s *Server) injectDemoBanner(html []byte, expiresAt time.Time) []byte { scheme := "https" if os.Getenv("ENV") != "prod" { scheme = "http" } redirectURL := scheme + "://" + s.domain banner := demoBannerHTML(expiresAt, redirectURL) return bytes.Replace(html, []byte(""), append([]byte(banner), []byte("")...), 1) } func demoBannerHTML(expiresAt time.Time, redirectURL string) string { expiresUnix := expiresAt.Unix() return `
Open Studio
` } func generateFakeAnalytics(days int) *tenant.AnalyticsSummary { if days <= 0 { days = 30 } baseViews := 25 + rand.Intn(20) var totalViews, totalVisitors int64 viewsByDay := make([]tenant.DailyStats, days) for i := 0; i < days; i++ { date := time.Now().AddDate(0, 0, -days+i+1) weekday := date.Weekday() multiplier := 1.0 if weekday == time.Saturday || weekday == time.Sunday { multiplier = 0.6 } else if weekday == time.Monday { multiplier = 1.2 } dailyViews := int64(float64(baseViews+rand.Intn(15)) * multiplier) dailyVisitors := dailyViews * int64(65+rand.Intn(15)) / 100 totalViews += dailyViews totalVisitors += dailyVisitors viewsByDay[i] = tenant.DailyStats{ Date: date.Format("2006-01-02"), Views: dailyViews, Visitors: dailyVisitors, } } return &tenant.AnalyticsSummary{ TotalViews: totalViews, TotalPageViews: totalViews, UniqueVisitors: totalVisitors, TotalBandwidth: totalViews * 45000, ViewsChange: float64(rand.Intn(300)-100) / 10, ViewsByDay: viewsByDay, TopPages: []tenant.PageStats{ {Path: "/", Views: totalViews * 25 / 100}, {Path: "/posts/shipping-a-side-project", Views: totalViews * 22 / 100}, {Path: "/posts/debugging-production-like-a-detective", Views: totalViews * 18 / 100}, {Path: "/posts/sqlite-in-production", Views: totalViews * 15 / 100}, {Path: "/posts", Views: totalViews * 12 / 100}, {Path: "/posts/my-2024-reading-list", Views: totalViews * 8 / 100}, }, TopReferrers: []tenant.ReferrerStats{ {Referrer: "Google", Views: totalViews * 30 / 100}, {Referrer: "Twitter/X", Views: totalViews * 20 / 100}, {Referrer: "GitHub", Views: totalViews * 15 / 100}, {Referrer: "Hacker News", Views: totalViews * 12 / 100}, {Referrer: "LinkedIn", Views: totalViews * 10 / 100}, {Referrer: "YouTube", Views: totalViews * 8 / 100}, {Referrer: "Reddit", Views: totalViews * 5 / 100}, }, Browsers: []tenant.NamedStat{ {Name: "Chrome", Count: totalVisitors * 55 / 100}, {Name: "Safari", Count: totalVisitors * 25 / 100}, {Name: "Firefox", Count: totalVisitors * 12 / 100}, {Name: "Edge", Count: totalVisitors * 8 / 100}, }, OS: []tenant.NamedStat{ {Name: "macOS", Count: totalVisitors * 45 / 100}, {Name: "Windows", Count: totalVisitors * 30 / 100}, {Name: "iOS", Count: totalVisitors * 15 / 100}, {Name: "Linux", Count: totalVisitors * 7 / 100}, {Name: "Android", Count: totalVisitors * 3 / 100}, }, Devices: []tenant.NamedStat{ {Name: "Desktop", Count: totalVisitors * 70 / 100}, {Name: "Mobile", Count: totalVisitors * 25 / 100}, {Name: "Tablet", Count: totalVisitors * 5 / 100}, }, Countries: []tenant.NamedStat{ {Name: "United States", Count: totalVisitors * 40 / 100}, {Name: "United Kingdom", Count: totalVisitors * 12 / 100}, {Name: "Germany", Count: totalVisitors * 10 / 100}, {Name: "Canada", Count: totalVisitors * 8 / 100}, {Name: "France", Count: totalVisitors * 6 / 100}, {Name: "Australia", Count: totalVisitors * 5 / 100}, }, } } func generateFakePostAnalytics(days int) *tenant.AnalyticsSummary { if days <= 0 { days = 30 } baseViews := 5 + rand.Intn(8) var totalViews int64 viewsByDay := make([]tenant.DailyStats, days) for i := 0; i < days; i++ { date := time.Now().AddDate(0, 0, -days+i+1) dailyViews := int64(baseViews + rand.Intn(6)) totalViews += dailyViews viewsByDay[i] = tenant.DailyStats{ Date: date.Format("2006-01-02"), Views: dailyViews, } } return &tenant.AnalyticsSummary{ TotalViews: totalViews, ViewsByDay: viewsByDay, } }