cairn/internal/handler/dashboard.go

99 lines
2.6 KiB
Go

package handler
import (
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/jackc/pgx/v5/pgxpool"
)
type DashboardHandler struct {
Pool *pgxpool.Pool
}
type DashboardStats struct {
TotalArtifacts int `json:"total_artifacts"`
TotalRepos int `json:"total_repos"`
TotalCrashGroups int `json:"total_crash_groups"`
OpenCrashGroups int `json:"open_crash_groups"`
ActiveCampaigns int `json:"active_campaigns"`
}
type TrendPoint struct {
Date string `json:"date"`
Count int `json:"count"`
}
type TopCrasher struct {
Title string `json:"title"`
OccurrenceCount int `json:"occurrence_count"`
RepoName string `json:"repo_name"`
CrashGroupID string `json:"crash_group_id"`
}
type DashboardResponse struct {
Stats DashboardStats `json:"stats"`
Trend []TrendPoint `json:"trend"`
TopCrashers []TopCrasher `json:"top_crashers"`
}
func (h *DashboardHandler) Stats(c *gin.Context) {
ctx := c.Request.Context()
var stats DashboardStats
_ = h.Pool.QueryRow(ctx, "SELECT COUNT(*) FROM artifacts").Scan(&stats.TotalArtifacts)
_ = h.Pool.QueryRow(ctx, "SELECT COUNT(*) FROM repositories").Scan(&stats.TotalRepos)
_ = h.Pool.QueryRow(ctx, "SELECT COUNT(*) FROM crash_groups").Scan(&stats.TotalCrashGroups)
_ = h.Pool.QueryRow(ctx, "SELECT COUNT(*) FROM crash_groups WHERE status = 'open'").Scan(&stats.OpenCrashGroups)
_ = h.Pool.QueryRow(ctx, "SELECT COUNT(*) FROM campaigns WHERE status = 'running'").Scan(&stats.ActiveCampaigns)
// Artifact trend for the last 30 days.
var trend []TrendPoint
rows, err := h.Pool.Query(ctx, `
SELECT DATE(created_at) as day, COUNT(*)
FROM artifacts
WHERE created_at >= $1
GROUP BY day
ORDER BY day
`, time.Now().AddDate(0, 0, -30))
if err == nil {
defer rows.Close()
for rows.Next() {
var tp TrendPoint
var d time.Time
if rows.Scan(&d, &tp.Count) == nil {
tp.Date = d.Format("2006-01-02")
trend = append(trend, tp)
}
}
}
// Top crashers (most frequent open crash groups).
var topCrashers []TopCrasher
rows2, err := h.Pool.Query(ctx, `
SELECT cg.id, cg.title, cs.occurrence_count, r.name
FROM crash_groups cg
JOIN crash_signatures cs ON cs.id = cg.crash_signature_id
JOIN repositories r ON r.id = cg.repository_id
WHERE cg.status = 'open'
ORDER BY cs.occurrence_count DESC
LIMIT 10
`)
if err == nil {
defer rows2.Close()
for rows2.Next() {
var tc TopCrasher
if rows2.Scan(&tc.CrashGroupID, &tc.Title, &tc.OccurrenceCount, &tc.RepoName) == nil {
topCrashers = append(topCrashers, tc)
}
}
}
c.JSON(http.StatusOK, DashboardResponse{
Stats: stats,
Trend: trend,
TopCrashers: topCrashers,
})
}