Files
work-queue-api/internal/api/handlers_projects.go
2026-04-11 18:38:52 +00:00

133 lines
3.4 KiB
Go

package api
import (
"database/sql"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/google/uuid"
"work-queue-api/internal/model"
)
type createProjectRequest struct {
Name string `json:"name"`
ExternalRef *string `json:"external_ref"`
}
type patchProjectRequest struct {
Name *string `json:"name"`
ExternalRef *string `json:"external_ref"`
}
func (s *Server) handleCreateProject(w http.ResponseWriter, r *http.Request) {
var req createProjectRequest
if err := decodeJSON(r, &req); err != nil {
writeError(w, http.StatusBadRequest, "invalid json body")
return
}
if req.Name == "" {
writeError(w, http.StatusBadRequest, "name is required")
return
}
now := nowUTC()
project := model.Project{
ID: uuid.NewString(),
Name: req.Name,
ExternalRef: req.ExternalRef,
CreatedAt: now,
UpdatedAt: now,
}
_, err := s.db.Exec(`INSERT INTO projects (id, name, external_ref, created_at, updated_at) VALUES (?, ?, ?, ?, ?)`,
project.ID, project.Name, project.ExternalRef, project.CreatedAt.Format(timeLayout), project.UpdatedAt.Format(timeLayout),
)
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
writeJSON(w, http.StatusCreated, project)
}
func (s *Server) handleListProjects(w http.ResponseWriter, r *http.Request) {
rows, err := s.db.Query(`SELECT id, name, external_ref, created_at, updated_at FROM projects ORDER BY created_at ASC`)
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
defer rows.Close()
var projects []model.Project
for rows.Next() {
project, err := scanProject(rows)
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
projects = append(projects, project)
}
writeJSON(w, http.StatusOK, projects)
}
func (s *Server) handleGetProject(w http.ResponseWriter, r *http.Request) {
project, err := s.fetchProject(chi.URLParam(r, "id"))
if err == sql.ErrNoRows {
writeError(w, http.StatusNotFound, "project not found")
return
}
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
writeJSON(w, http.StatusOK, project)
}
func (s *Server) handlePatchProject(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
project, err := s.fetchProject(id)
if err == sql.ErrNoRows {
writeError(w, http.StatusNotFound, "project not found")
return
}
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
var req patchProjectRequest
if err := decodeJSON(r, &req); err != nil {
writeError(w, http.StatusBadRequest, "invalid json body")
return
}
if req.Name != nil {
if *req.Name == "" {
writeError(w, http.StatusBadRequest, "name cannot be empty")
return
}
project.Name = *req.Name
}
if req.ExternalRef != nil {
project.ExternalRef = req.ExternalRef
}
project.UpdatedAt = nowUTC()
_, err = s.db.Exec(`UPDATE projects SET name = ?, external_ref = ?, updated_at = ? WHERE id = ?`,
project.Name, project.ExternalRef, project.UpdatedAt.Format(timeLayout), project.ID,
)
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
writeJSON(w, http.StatusOK, project)
}
func (s *Server) fetchProject(id string) (model.Project, error) {
row := s.db.QueryRow(`SELECT id, name, external_ref, created_at, updated_at FROM projects WHERE id = ?`, id)
return scanProject(row)
}