Files
training-tracker/backend/internal/api/plans.go
2026-01-19 19:50:09 +01:00

128 lines
2.9 KiB
Go

package api
import (
"database/sql"
"net/http"
"training-tracker/internal/models"
)
type PlanHandler struct {
repo PlanRepository
}
func NewPlanHandler(repo PlanRepository) *PlanHandler {
return &PlanHandler{repo: repo}
}
func (h *PlanHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
id, _ := parseID(r, "/api/plans/")
switch r.Method {
case http.MethodGet:
if id > 0 {
h.getByID(w, r, id)
} else {
h.list(w, r)
}
case http.MethodPost:
h.create(w, r)
case http.MethodPut:
if id > 0 {
h.update(w, r, id)
} else {
respondError(w, http.StatusBadRequest, "plan ID required")
}
case http.MethodDelete:
if id > 0 {
h.delete(w, r, id)
} else {
respondError(w, http.StatusBadRequest, "plan ID required")
}
default:
respondError(w, http.StatusMethodNotAllowed, "method not allowed")
}
}
func (h *PlanHandler) list(w http.ResponseWriter, r *http.Request) {
plans, err := h.repo.List(r.Context())
if err != nil {
respondError(w, http.StatusInternalServerError, "failed to list plans")
return
}
if plans == nil {
plans = []models.TrainingPlan{}
}
respondJSON(w, http.StatusOK, plans)
}
func (h *PlanHandler) getByID(w http.ResponseWriter, r *http.Request, id int64) {
plan, err := h.repo.GetByID(r.Context(), id)
if err != nil {
respondError(w, http.StatusInternalServerError, "failed to get plan")
return
}
if plan == nil {
respondError(w, http.StatusNotFound, "plan not found")
return
}
respondJSON(w, http.StatusOK, plan)
}
func (h *PlanHandler) create(w http.ResponseWriter, r *http.Request) {
var req models.CreatePlanRequest
if err := decodeJSON(r, &req); err != nil {
respondError(w, http.StatusBadRequest, "invalid request body")
return
}
if req.Name == "" {
respondError(w, http.StatusBadRequest, "name is required")
return
}
plan, err := h.repo.Create(r.Context(), &req)
if err != nil {
respondError(w, http.StatusInternalServerError, "failed to create plan")
return
}
respondJSON(w, http.StatusCreated, plan)
}
func (h *PlanHandler) update(w http.ResponseWriter, r *http.Request, id int64) {
var req models.CreatePlanRequest
if err := decodeJSON(r, &req); err != nil {
respondError(w, http.StatusBadRequest, "invalid request body")
return
}
if req.Name == "" {
respondError(w, http.StatusBadRequest, "name is required")
return
}
plan, err := h.repo.Update(r.Context(), id, &req)
if err != nil {
respondError(w, http.StatusInternalServerError, "failed to update plan")
return
}
if plan == nil {
respondError(w, http.StatusNotFound, "plan not found")
return
}
respondJSON(w, http.StatusOK, plan)
}
func (h *PlanHandler) delete(w http.ResponseWriter, r *http.Request, id int64) {
err := h.repo.Delete(r.Context(), id)
if err == sql.ErrNoRows {
respondError(w, http.StatusNotFound, "plan not found")
return
}
if err != nil {
respondError(w, http.StatusInternalServerError, "failed to delete plan")
return
}
w.WriteHeader(http.StatusNoContent)
}