109 lines
2.9 KiB
Go
109 lines
2.9 KiB
Go
package handlers
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/google/uuid"
|
|
|
|
"git.threesix.ai/jordan/slate-test-1770505673/pkg/app"
|
|
"git.threesix.ai/jordan/slate-test-1770505673/pkg/auth"
|
|
"git.threesix.ai/jordan/slate-test-1770505673/pkg/httperror"
|
|
"git.threesix.ai/jordan/slate-test-1770505673/pkg/httpresponse"
|
|
"git.threesix.ai/jordan/slate-test-1770505673/pkg/logging"
|
|
"git.threesix.ai/jordan/slate-test-1770505673/services/preferences-api/internal/domain"
|
|
"git.threesix.ai/jordan/slate-test-1770505673/services/preferences-api/internal/service"
|
|
)
|
|
|
|
// Preference handles HTTP requests for user preference resources.
|
|
type Preference struct {
|
|
svc *service.PreferenceService
|
|
logger *logging.Logger
|
|
}
|
|
|
|
// NewPreference creates a new Preference handler with injected dependencies.
|
|
func NewPreference(svc *service.PreferenceService, logger *logging.Logger) *Preference {
|
|
return &Preference{
|
|
svc: svc,
|
|
logger: logger.WithComponent("PreferenceHandler"),
|
|
}
|
|
}
|
|
|
|
// Get returns all preferences for a user.
|
|
func (h *Preference) Get(w http.ResponseWriter, r *http.Request) error {
|
|
userID := chi.URLParam(r, "user_id")
|
|
|
|
if _, err := uuid.Parse(userID); err != nil {
|
|
return httperror.BadRequest("invalid user ID format")
|
|
}
|
|
|
|
if err := h.checkOwnership(r, userID); err != nil {
|
|
return err
|
|
}
|
|
|
|
prefs, err := h.svc.Get(r.Context(), userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
httpresponse.OK(w, r, prefs)
|
|
return nil
|
|
}
|
|
|
|
// Update creates or updates preferences for a user.
|
|
func (h *Preference) Update(w http.ResponseWriter, r *http.Request) error {
|
|
userID := chi.URLParam(r, "user_id")
|
|
|
|
if _, err := uuid.Parse(userID); err != nil {
|
|
return httperror.BadRequest("invalid user ID format")
|
|
}
|
|
|
|
if err := h.checkOwnership(r, userID); err != nil {
|
|
return err
|
|
}
|
|
|
|
var prefs map[string]string
|
|
if err := app.Bind(r, &prefs); err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(prefs) == 0 {
|
|
return httperror.BadRequest("request body is required")
|
|
}
|
|
|
|
result, err := h.svc.Upsert(r.Context(), userID, prefs)
|
|
if err != nil {
|
|
return mapDomainError(err)
|
|
}
|
|
|
|
httpresponse.OK(w, r, result)
|
|
return nil
|
|
}
|
|
|
|
// checkOwnership verifies that the authenticated user matches the requested user_id.
|
|
func (h *Preference) checkOwnership(r *http.Request, userID string) error {
|
|
user := auth.GetUser(r.Context())
|
|
if user == nil {
|
|
return httperror.Unauthorized("authentication required")
|
|
}
|
|
if user.ID != userID {
|
|
return httperror.Forbidden("cannot access preferences for another user")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// mapDomainError converts domain errors to HTTP errors.
|
|
func mapDomainError(err error) error {
|
|
switch {
|
|
case errors.Is(err, domain.ErrUnknownKey):
|
|
return httperror.BadRequest(err.Error())
|
|
case errors.Is(err, domain.ErrInvalidValue):
|
|
return httperror.BadRequest(err.Error())
|
|
case errors.Is(err, domain.ErrForbidden):
|
|
return httperror.Forbidden(err.Error())
|
|
default:
|
|
return err
|
|
}
|
|
}
|