99 lines
2.6 KiB
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,
|
|
})
|
|
}
|