|
|
@@ -10,6 +10,7 @@ import (
|
|
|
"github.com/photoplaces/backend/internal/middleware"
|
|
|
"github.com/photoplaces/backend/internal/models"
|
|
|
"github.com/photoplaces/backend/internal/services"
|
|
|
+ "github.com/photoplaces/backend/internal/validator"
|
|
|
)
|
|
|
|
|
|
type PlaceHandler struct {
|
|
|
@@ -102,19 +103,39 @@ func (h *PlaceHandler) GetByID(w http.ResponseWriter, r *http.Request) {
|
|
|
}
|
|
|
|
|
|
type createPlaceRequest struct {
|
|
|
- Title string `json:"title"`
|
|
|
- Description *string `json:"description"`
|
|
|
- Address *string `json:"address"`
|
|
|
- Lat float64 `json:"lat"`
|
|
|
- Lng float64 `json:"lng"`
|
|
|
- Type string `json:"type"`
|
|
|
- AccessInfo *string `json:"access_info"`
|
|
|
- CoverImage *string `json:"cover_image"`
|
|
|
- Tags []string `json:"tags"`
|
|
|
- Features []string `json:"features"`
|
|
|
- HourlyRate *int `json:"hourly_rate"`
|
|
|
- Currency string `json:"currency"`
|
|
|
- MinHours int `json:"min_hours"`
|
|
|
+ Title string `json:"title" validate:"required,min=1,max=255"`
|
|
|
+ Description *string `json:"description" validate:"omitempty,max=5000"`
|
|
|
+ Address *string `json:"address" validate:"omitempty,max=500"`
|
|
|
+ Lat float64 `json:"lat" validate:"required,latitude"`
|
|
|
+ Lng float64 `json:"lng" validate:"required,longitude"`
|
|
|
+ Type string `json:"type" validate:"required,place_type"`
|
|
|
+ AccessInfo *string `json:"access_info" validate:"omitempty,max=2000"`
|
|
|
+ CoverImage *string `json:"cover_image" validate:"omitempty,url,max=500"`
|
|
|
+ Tags []string `json:"tags" validate:"dive,slug,max=50"`
|
|
|
+ Features []string `json:"features" validate:"dive,slug,max=50"`
|
|
|
+ HourlyRate *int `json:"hourly_rate" validate:"omitempty,min=0"`
|
|
|
+ Currency string `json:"currency" validate:"omitempty,currency,len=3"`
|
|
|
+ MinHours int `json:"min_hours" validate:"min=0,max=100"`
|
|
|
+}
|
|
|
+
|
|
|
+type updatePlaceRequest struct {
|
|
|
+ Title *string `json:"title" validate:"omitempty,min=1,max=255"`
|
|
|
+ Description *string `json:"description" validate:"omitempty,max=5000"`
|
|
|
+ Address *string `json:"address" validate:"omitempty,max=500"`
|
|
|
+ Lat *float64 `json:"lat" validate:"omitempty,latitude"`
|
|
|
+ Lng *float64 `json:"lng" validate:"omitempty,longitude"`
|
|
|
+ AccessInfo *string `json:"access_info" validate:"omitempty,max=2000"`
|
|
|
+ CoverImage *string `json:"cover_image" validate:"omitempty,url,max=500"`
|
|
|
+ Tags []string `json:"tags" validate:"dive,slug,max=50"`
|
|
|
+ Features []string `json:"features" validate:"dive,slug,max=50"`
|
|
|
+ HourlyRate *int `json:"hourly_rate" validate:"omitempty,min=0"`
|
|
|
+ Currency *string `json:"currency" validate:"omitempty,currency,len=3"`
|
|
|
+ MinHours *int `json:"min_hours" validate:"omitempty,min=0,max=100"`
|
|
|
+}
|
|
|
+
|
|
|
+type moderatePlaceRequest struct {
|
|
|
+ Action string `json:"action" validate:"required,oneof=approve reject"`
|
|
|
+ Comment *string `json:"comment" validate:"omitempty,max=1000"`
|
|
|
}
|
|
|
|
|
|
func (h *PlaceHandler) Create(w http.ResponseWriter, r *http.Request) {
|
|
|
@@ -127,13 +148,8 @@ func (h *PlaceHandler) Create(w http.ResponseWriter, r *http.Request) {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- if req.Title == "" {
|
|
|
- writeError(w, http.StatusBadRequest, "title is required")
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- if req.Type == "" {
|
|
|
- writeError(w, http.StatusBadRequest, "type is required (place or studio)")
|
|
|
+ if err := validator.Validate(req); err != nil {
|
|
|
+ writeValidationError(w, err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
@@ -184,12 +200,17 @@ func (h *PlaceHandler) Update(w http.ResponseWriter, r *http.Request) {
|
|
|
userID := middleware.GetUserID(r.Context())
|
|
|
role := middleware.GetUserRole(r.Context())
|
|
|
|
|
|
- var req createPlaceRequest
|
|
|
+ var req updatePlaceRequest
|
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
|
writeError(w, http.StatusBadRequest, "invalid request body")
|
|
|
return
|
|
|
}
|
|
|
|
|
|
+ if err := validator.Validate(req); err != nil {
|
|
|
+ writeValidationError(w, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
isModerator := role == "moderator" || role == "superadmin"
|
|
|
|
|
|
input := services.UpdatePlaceInput{
|
|
|
@@ -197,15 +218,15 @@ func (h *PlaceHandler) Update(w http.ResponseWriter, r *http.Request) {
|
|
|
OwnerID: userID,
|
|
|
}
|
|
|
|
|
|
- if req.Title != "" { input.Title = &req.Title }
|
|
|
+ if req.Title != nil { input.Title = req.Title }
|
|
|
input.Description = req.Description
|
|
|
input.Address = req.Address
|
|
|
- if req.Lat != 0 { input.Lat = &req.Lat }
|
|
|
- if req.Lng != 0 { input.Lng = &req.Lng }
|
|
|
+ input.Lat = req.Lat
|
|
|
+ input.Lng = req.Lng
|
|
|
input.AccessInfo = req.AccessInfo
|
|
|
input.HourlyRate = req.HourlyRate
|
|
|
- if req.Currency != "" { input.Currency = &req.Currency }
|
|
|
- if req.MinHours != 0 { input.MinHours = &req.MinHours }
|
|
|
+ input.Currency = req.Currency
|
|
|
+ input.MinHours = req.MinHours
|
|
|
|
|
|
place, err := h.placeSvc.Update(r.Context(), input, isModerator)
|
|
|
if err != nil {
|
|
|
@@ -224,15 +245,17 @@ func (h *PlaceHandler) Moderate(w http.ResponseWriter, r *http.Request) {
|
|
|
id := chi.URLParam(r, "id")
|
|
|
userID := middleware.GetUserID(r.Context())
|
|
|
|
|
|
- var req struct {
|
|
|
- Action string `json:"action"`
|
|
|
- Comment string `json:"comment"`
|
|
|
- }
|
|
|
+ var req moderatePlaceRequest
|
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
|
writeError(w, http.StatusBadRequest, "invalid request body")
|
|
|
return
|
|
|
}
|
|
|
|
|
|
+ if err := validator.Validate(req); err != nil {
|
|
|
+ writeValidationError(w, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
if err := h.placeSvc.Moderate(r.Context(), id, req.Action, req.Comment, userID); err != nil {
|
|
|
writeError(w, http.StatusInternalServerError, err.Error())
|
|
|
return
|