236 lines
6.3 KiB
Go
236 lines
6.3 KiB
Go
package handler
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
|
|
"github.com/daniil/homelab-api/internal/middleware"
|
|
"github.com/daniil/homelab-api/internal/model"
|
|
"github.com/daniil/homelab-api/internal/repository"
|
|
"github.com/daniil/homelab-api/internal/service"
|
|
)
|
|
|
|
type HabitHandler struct {
|
|
habitService *service.HabitService
|
|
}
|
|
|
|
func NewHabitHandler(habitService *service.HabitService) *HabitHandler {
|
|
return &HabitHandler{habitService: habitService}
|
|
}
|
|
|
|
func (h *HabitHandler) List(w http.ResponseWriter, r *http.Request) {
|
|
userID := middleware.GetUserID(r.Context())
|
|
includeArchived := r.URL.Query().Get("archived") == "true"
|
|
|
|
habits, err := h.habitService.List(userID, includeArchived)
|
|
if err != nil {
|
|
writeError(w, "failed to fetch habits", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
writeJSON(w, habits, http.StatusOK)
|
|
}
|
|
|
|
func (h *HabitHandler) Create(w http.ResponseWriter, r *http.Request) {
|
|
userID := middleware.GetUserID(r.Context())
|
|
|
|
var req model.CreateHabitRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeError(w, "invalid request body", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if req.Name == "" {
|
|
writeError(w, "name is required", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
habit, err := h.habitService.Create(userID, &req)
|
|
if err != nil {
|
|
writeError(w, "failed to create habit", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
writeJSON(w, habit, http.StatusCreated)
|
|
}
|
|
|
|
func (h *HabitHandler) Get(w http.ResponseWriter, r *http.Request) {
|
|
userID := middleware.GetUserID(r.Context())
|
|
habitID, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
|
if err != nil {
|
|
writeError(w, "invalid habit id", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
habit, err := h.habitService.Get(habitID, userID)
|
|
if err != nil {
|
|
if errors.Is(err, repository.ErrHabitNotFound) {
|
|
writeError(w, "habit not found", http.StatusNotFound)
|
|
return
|
|
}
|
|
writeError(w, "failed to fetch habit", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
writeJSON(w, habit, http.StatusOK)
|
|
}
|
|
|
|
func (h *HabitHandler) Update(w http.ResponseWriter, r *http.Request) {
|
|
userID := middleware.GetUserID(r.Context())
|
|
habitID, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
|
if err != nil {
|
|
writeError(w, "invalid habit id", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var req model.UpdateHabitRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeError(w, "invalid request body", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
habit, err := h.habitService.Update(habitID, userID, &req)
|
|
if err != nil {
|
|
if errors.Is(err, repository.ErrHabitNotFound) {
|
|
writeError(w, "habit not found", http.StatusNotFound)
|
|
return
|
|
}
|
|
writeError(w, "failed to update habit", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
writeJSON(w, habit, http.StatusOK)
|
|
}
|
|
|
|
func (h *HabitHandler) Delete(w http.ResponseWriter, r *http.Request) {
|
|
userID := middleware.GetUserID(r.Context())
|
|
habitID, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
|
if err != nil {
|
|
writeError(w, "invalid habit id", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if err := h.habitService.Delete(habitID, userID); err != nil {
|
|
if errors.Is(err, repository.ErrHabitNotFound) {
|
|
writeError(w, "habit not found", http.StatusNotFound)
|
|
return
|
|
}
|
|
writeError(w, "failed to delete habit", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|
|
|
|
func (h *HabitHandler) Log(w http.ResponseWriter, r *http.Request) {
|
|
userID := middleware.GetUserID(r.Context())
|
|
habitID, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
|
if err != nil {
|
|
writeError(w, "invalid habit id", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var req model.LogHabitRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
// Allow empty body - means log today with count=1
|
|
req = model.LogHabitRequest{}
|
|
}
|
|
|
|
log, err := h.habitService.Log(habitID, userID, &req)
|
|
if err != nil {
|
|
if errors.Is(err, repository.ErrHabitNotFound) {
|
|
writeError(w, "habit not found", http.StatusNotFound)
|
|
return
|
|
}
|
|
writeError(w, "failed to log habit", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
writeJSON(w, log, http.StatusCreated)
|
|
}
|
|
|
|
func (h *HabitHandler) GetLogs(w http.ResponseWriter, r *http.Request) {
|
|
userID := middleware.GetUserID(r.Context())
|
|
habitID, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
|
if err != nil {
|
|
writeError(w, "invalid habit id", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
days := 30
|
|
if d := r.URL.Query().Get("days"); d != "" {
|
|
if parsed, err := strconv.Atoi(d); err == nil && parsed > 0 {
|
|
days = parsed
|
|
}
|
|
}
|
|
|
|
logs, err := h.habitService.GetLogs(habitID, userID, days)
|
|
if err != nil {
|
|
if errors.Is(err, repository.ErrHabitNotFound) {
|
|
writeError(w, "habit not found", http.StatusNotFound)
|
|
return
|
|
}
|
|
writeError(w, "failed to fetch logs", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
writeJSON(w, logs, http.StatusOK)
|
|
}
|
|
|
|
func (h *HabitHandler) DeleteLog(w http.ResponseWriter, r *http.Request) {
|
|
userID := middleware.GetUserID(r.Context())
|
|
logID, err := strconv.ParseInt(chi.URLParam(r, "logId"), 10, 64)
|
|
if err != nil {
|
|
writeError(w, "invalid log id", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if err := h.habitService.DeleteLog(logID, userID); err != nil {
|
|
if errors.Is(err, repository.ErrLogNotFound) {
|
|
writeError(w, "log not found", http.StatusNotFound)
|
|
return
|
|
}
|
|
writeError(w, "failed to delete log", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|
|
|
|
func (h *HabitHandler) Stats(w http.ResponseWriter, r *http.Request) {
|
|
userID := middleware.GetUserID(r.Context())
|
|
|
|
stats, err := h.habitService.GetOverallStats(userID)
|
|
if err != nil {
|
|
writeError(w, "failed to fetch stats", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
writeJSON(w, stats, http.StatusOK)
|
|
}
|
|
|
|
func (h *HabitHandler) HabitStats(w http.ResponseWriter, r *http.Request) {
|
|
userID := middleware.GetUserID(r.Context())
|
|
habitID, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
|
if err != nil {
|
|
writeError(w, "invalid habit id", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
stats, err := h.habitService.GetHabitStats(habitID, userID)
|
|
if err != nil {
|
|
if errors.Is(err, repository.ErrHabitNotFound) {
|
|
writeError(w, "habit not found", http.StatusNotFound)
|
|
return
|
|
}
|
|
writeError(w, "failed to fetch stats", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
writeJSON(w, stats, http.StatusOK)
|
|
}
|