package volunteer import ( "encoding/json" "errors" "net/http" "strconv" "git.unsupervised.ca/walkies/internal/auth" "git.unsupervised.ca/walkies/internal/respond" "github.com/go-chi/chi/v5" ) type Handler struct { store *Store authSvc *auth.Service } func NewHandler(store *Store, authSvc *auth.Service) *Handler { return &Handler{store: store, authSvc: authSvc} } // POST /api/v1/auth/register func (h *Handler) Register(w http.ResponseWriter, r *http.Request) { var in CreateInput if err := json.NewDecoder(r.Body).Decode(&in); err != nil { respond.Error(w, http.StatusBadRequest, "invalid request body") return } if in.Name == "" || in.Email == "" || in.Password == "" { respond.Error(w, http.StatusBadRequest, "name, email, and password are required") return } if in.Role == "" { in.Role = "volunteer" } hash, err := auth.HashPassword(in.Password) if err != nil { respond.Error(w, http.StatusInternalServerError, "could not hash password") return } v, err := h.store.Create(r.Context(), in.Name, in.Email, hash, in.Role) if err != nil { respond.Error(w, http.StatusConflict, "email already in use") return } respond.JSON(w, http.StatusCreated, v) } // POST /api/v1/auth/login func (h *Handler) Login(w http.ResponseWriter, r *http.Request) { var body struct { Email string `json:"email"` Password string `json:"password"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil { respond.Error(w, http.StatusBadRequest, "invalid request body") return } token, err := h.authSvc.Login(r.Context(), body.Email, body.Password) if err != nil { respond.Error(w, http.StatusUnauthorized, "invalid credentials") return } respond.JSON(w, http.StatusOK, map[string]string{"token": token}) } // GET /api/v1/volunteers func (h *Handler) List(w http.ResponseWriter, r *http.Request) { volunteers, err := h.store.List(r.Context(), true) if err != nil { respond.Error(w, http.StatusInternalServerError, "could not list volunteers") return } if volunteers == nil { volunteers = []Volunteer{} } respond.JSON(w, http.StatusOK, volunteers) } // GET /api/v1/volunteers/{id} func (h *Handler) Get(w http.ResponseWriter, r *http.Request) { id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64) if err != nil { respond.Error(w, http.StatusBadRequest, "invalid id") return } v, err := h.store.GetByID(r.Context(), id) if errors.Is(err, ErrNotFound) { respond.Error(w, http.StatusNotFound, "volunteer not found") return } if err != nil { respond.Error(w, http.StatusInternalServerError, "could not get volunteer") return } respond.JSON(w, http.StatusOK, v) } // PUT /api/v1/volunteers/{id} func (h *Handler) Update(w http.ResponseWriter, r *http.Request) { id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64) if err != nil { respond.Error(w, http.StatusBadRequest, "invalid id") return } var in UpdateInput if err := json.NewDecoder(r.Body).Decode(&in); err != nil { respond.Error(w, http.StatusBadRequest, "invalid request body") return } v, err := h.store.Update(r.Context(), id, in) if errors.Is(err, ErrNotFound) { respond.Error(w, http.StatusNotFound, "volunteer not found") return } if err != nil { respond.Error(w, http.StatusInternalServerError, "could not update volunteer") return } respond.JSON(w, http.StatusOK, v) }