package web import ( "io/fs" "net/http" "github.com/gin-gonic/gin" "github.com/mattnite/cairn/internal/blob" "github.com/mattnite/cairn/internal/forgejo" "github.com/mattnite/cairn/internal/handler" assets "github.com/mattnite/cairn/web" "gorm.io/gorm" ) type RouterConfig struct { DB *gorm.DB Store blob.Store ForgejoClient *forgejo.Client ForgejoURL string CairnURL string WebhookSecret string } func NewRouter(cfg RouterConfig) (*gin.Engine, error) { templates, err := LoadTemplates() if err != nil { return nil, err } forgejoSync := &forgejo.Sync{Client: cfg.ForgejoClient, DB: cfg.DB, CairnURL: cfg.CairnURL} pages := &PageHandler{DB: cfg.DB, Templates: templates, ForgejoURL: cfg.ForgejoURL} ingest := &handler.IngestHandler{DB: cfg.DB, Store: cfg.Store, ForgejoSync: forgejoSync} artifactAPI := &handler.ArtifactHandler{DB: cfg.DB} download := &handler.DownloadHandler{DB: cfg.DB, Store: cfg.Store} crashGroupAPI := &handler.CrashGroupHandler{DB: cfg.DB} searchAPI := &handler.SearchHandler{DB: cfg.DB} regressionAPI := &handler.RegressionHandler{DB: cfg.DB, ForgejoSync: forgejoSync} targetAPI := &handler.TargetHandler{DB: cfg.DB, Store: cfg.Store} runAPI := &handler.RunHandler{DB: cfg.DB} corpusAPI := &handler.CorpusHandler{DB: cfg.DB, Store: cfg.Store} dashboardAPI := &handler.DashboardHandler{DB: cfg.DB} webhookH := &handler.WebhookHandler{Sync: forgejoSync, Secret: cfg.WebhookSecret} gin.SetMode(gin.ReleaseMode) r := gin.New() r.Use(LoggingMiddleware(), RecoveryMiddleware()) // Static files staticFS, err := fs.Sub(assets.Assets, "static") if err != nil { return nil, err } r.StaticFS("/static", http.FS(staticFS)) // HTML pages r.GET("/", pages.Index) r.GET("/artifacts", pages.Artifacts) r.GET("/artifacts/:id", pages.ArtifactDetail) r.GET("/repos", pages.Repos) r.GET("/crashgroups", pages.CrashGroups) r.GET("/crashgroups/:id", pages.CrashGroupDetail) r.GET("/targets", pages.Targets) r.GET("/targets/:id", pages.TargetDetail) r.GET("/runs/:id", pages.RunDetail) r.GET("/search", pages.Search) r.GET("/regression", pages.Regression) // JSON API api := r.Group("/api/v1") api.POST("/artifacts", ingest.Create) api.GET("/artifacts", artifactAPI.List) api.GET("/artifacts/:id", artifactAPI.Detail) api.GET("/artifacts/:id/download", download.Download) api.GET("/crashgroups", crashGroupAPI.List) api.GET("/crashgroups/:id", crashGroupAPI.Detail) api.GET("/search", searchAPI.Search) api.POST("/regression/check", regressionAPI.Check) api.POST("/targets", targetAPI.Ensure) api.GET("/targets", targetAPI.List) api.GET("/targets/:id", targetAPI.Detail) api.POST("/targets/:id/corpus", corpusAPI.Upload) api.GET("/targets/:id/corpus", corpusAPI.List) api.GET("/targets/:id/corpus/download", corpusAPI.DownloadAll) api.GET("/targets/:id/corpus/:entry_id/download", corpusAPI.Download) api.POST("/runs", runAPI.Start) api.GET("/runs", runAPI.List) api.GET("/runs/:id", runAPI.Detail) api.POST("/runs/:id/finish", runAPI.Finish) api.GET("/dashboard", dashboardAPI.Stats) // Webhooks r.POST("/webhooks/forgejo", webhookH.Handle) return r, nil }