80ea17227d
Load config eagerly during server startup so sortByUrgency never hits a nil config. Add nil-guard in BuildUrgencyCoefficients as belt-and-suspenders defense. Fix OAuth callback to support both GET and POST, and resolve issuer URLs properly with path.Dir. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
90 lines
2.2 KiB
Go
90 lines
2.2 KiB
Go
package api
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"git.jnss.me/joakim/opal/internal/api/handlers"
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/go-chi/chi/v5/middleware"
|
|
)
|
|
|
|
// Server represents the API server
|
|
type Server struct {
|
|
router chi.Router
|
|
addr string
|
|
}
|
|
|
|
// NewServer creates a new API server
|
|
func NewServer(addr string) *Server {
|
|
s := &Server{
|
|
router: chi.NewRouter(),
|
|
addr: addr,
|
|
}
|
|
s.setupRoutes()
|
|
return s
|
|
}
|
|
|
|
// setupRoutes configures all API routes
|
|
func (s *Server) setupRoutes() {
|
|
r := s.router
|
|
|
|
// Global middleware
|
|
r.Use(middleware.Logger)
|
|
r.Use(middleware.Recoverer)
|
|
r.Use(CORSMiddleware())
|
|
|
|
// Health check (no auth required)
|
|
r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
|
|
JSON(w, http.StatusOK, map[string]string{"status": "ok"})
|
|
})
|
|
|
|
// OAuth endpoints (no auth required)
|
|
r.Get("/auth/login", handlers.GetLoginURL)
|
|
r.Get("/auth/callback", handlers.OAuthCallback)
|
|
r.Post("/auth/callback", handlers.OAuthCallback)
|
|
r.Post("/auth/refresh", handlers.RefreshToken)
|
|
r.Post("/auth/logout", handlers.Logout)
|
|
|
|
// Protected routes
|
|
r.Group(func(r chi.Router) {
|
|
r.Use(AuthMiddleware())
|
|
|
|
// Tasks
|
|
r.Route("/tasks", func(r chi.Router) {
|
|
r.Get("/", handlers.ListTasks)
|
|
r.Post("/", handlers.CreateTask)
|
|
r.Post("/parse", handlers.ParseTask)
|
|
r.Get("/{uuid}", handlers.GetTask)
|
|
r.Put("/{uuid}", handlers.UpdateTask)
|
|
r.Delete("/{uuid}", handlers.DeleteTask)
|
|
r.Post("/{uuid}/complete", handlers.CompleteTask)
|
|
r.Post("/{uuid}/start", handlers.StartTask)
|
|
r.Post("/{uuid}/stop", handlers.StopTask)
|
|
|
|
// Tags
|
|
r.Get("/{uuid}/tags", handlers.GetTaskTags)
|
|
r.Post("/{uuid}/tags", handlers.AddTaskTag)
|
|
r.Delete("/{uuid}/tags/{tag}", handlers.RemoveTaskTag)
|
|
})
|
|
|
|
// Metadata
|
|
r.Get("/tags", handlers.ListAllTags)
|
|
r.Get("/projects", handlers.ListProjects)
|
|
|
|
// Sync endpoints
|
|
r.Post("/sync/changes", handlers.GetChanges)
|
|
r.Post("/sync/push", handlers.PushChanges)
|
|
|
|
// Key management
|
|
r.Get("/auth/keys", handlers.ListAPIKeys)
|
|
r.Delete("/auth/keys/{id}", handlers.RevokeAPIKey)
|
|
})
|
|
}
|
|
|
|
// Start starts the HTTP server
|
|
func (s *Server) Start() error {
|
|
fmt.Printf("Starting opal API server on %s\n", s.addr)
|
|
return http.ListenAndServe(s.addr, s.router)
|
|
}
|