100 lines
2.7 KiB
Go
100 lines
2.7 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/mattnite/cairn/internal/models"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type DashboardHandler struct {
|
|
DB *gorm.DB
|
|
}
|
|
|
|
type DashboardStats struct {
|
|
TotalArtifacts int64 `json:"total_artifacts"`
|
|
TotalRepos int64 `json:"total_repos"`
|
|
TotalCrashGroups int64 `json:"total_crash_groups"`
|
|
OpenCrashGroups int64 `json:"open_crash_groups"`
|
|
TotalTargets int64 `json:"total_targets"`
|
|
}
|
|
|
|
type TrendPoint struct {
|
|
Date string `json:"date"`
|
|
Count int64 `json:"count"`
|
|
}
|
|
|
|
type TopCrasher struct {
|
|
Title string `json:"title"`
|
|
OccurrenceCount uint `json:"occurrence_count"`
|
|
RepoName string `json:"repo_name"`
|
|
CrashGroupID uint `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.DB.WithContext(ctx).Model(&models.Artifact{}).Count(&stats.TotalArtifacts).Error
|
|
_ = h.DB.WithContext(ctx).Model(&models.Repository{}).Count(&stats.TotalRepos).Error
|
|
_ = h.DB.WithContext(ctx).Model(&models.CrashGroup{}).Count(&stats.TotalCrashGroups).Error
|
|
_ = h.DB.WithContext(ctx).Model(&models.CrashGroup{}).Where("status = ?", "open").Count(&stats.OpenCrashGroups).Error
|
|
_ = h.DB.WithContext(ctx).Model(&models.Target{}).Count(&stats.TotalTargets).Error
|
|
|
|
// Artifact trend for the last 30 days.
|
|
var trend []TrendPoint
|
|
type trendRow struct {
|
|
Day time.Time
|
|
Count int64
|
|
}
|
|
var rows []trendRow
|
|
err := h.DB.WithContext(ctx).
|
|
Table("artifacts").
|
|
Select("DATE(created_at) as day, COUNT(*) as count").
|
|
Where("created_at >= ?", time.Now().AddDate(0, 0, -30)).
|
|
Group("day").
|
|
Order("day").
|
|
Scan(&rows).Error
|
|
if err == nil {
|
|
for _, row := range rows {
|
|
trend = append(trend, TrendPoint{Date: row.Day.Format("2006-01-02"), Count: row.Count})
|
|
}
|
|
}
|
|
|
|
// Top crashers (most frequent open crash groups).
|
|
var groups []models.CrashGroup
|
|
err = h.DB.WithContext(ctx).Where("status = ?", "open").Order("last_seen_at DESC").Limit(50).Find(&groups).Error
|
|
topCrashers := make([]TopCrasher, 0, 10)
|
|
if err == nil {
|
|
for _, group := range groups {
|
|
fullGroup, fullErr := models.GetCrashGroup(ctx, h.DB, group.ID)
|
|
if fullErr != nil {
|
|
continue
|
|
}
|
|
topCrashers = append(topCrashers, TopCrasher{
|
|
CrashGroupID: fullGroup.ID,
|
|
Title: fullGroup.Title,
|
|
OccurrenceCount: fullGroup.OccurrenceCount,
|
|
RepoName: fullGroup.RepoName,
|
|
})
|
|
if len(topCrashers) == 10 {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, DashboardResponse{
|
|
Stats: stats,
|
|
Trend: trend,
|
|
TopCrashers: topCrashers,
|
|
})
|
|
}
|