package handlers import ( "encoding/json" "fmt" "net/http" "github.com/go-chi/chi/v5" "github.com/photoplaces/backend/internal/middleware" "github.com/photoplaces/backend/internal/models" "github.com/photoplaces/backend/internal/repository" ) type UserHandler struct { userRepo *repository.UserRepo } func NewUserHandler(userRepo *repository.UserRepo) *UserHandler { return &UserHandler{userRepo: userRepo} } func (h *UserHandler) GetProfile(w http.ResponseWriter, r *http.Request) { userID := chi.URLParam(r, "id") if userID == "" { userID = middleware.GetUserID(r.Context()) } user, err := h.userRepo.GetByID(r.Context(), userID) if err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } if user == nil { writeError(w, http.StatusNotFound, "user not found") return } writeJSON(w, http.StatusOK, user) } func (h *UserHandler) UpdateMe(w http.ResponseWriter, r *http.Request) { userID := middleware.GetUserID(r.Context()) user, err := h.userRepo.GetByID(r.Context(), userID) if err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } var req struct { Name *string `json:"name"` Phone *string `json:"phone"` Bio *string `json:"bio"` AvatarURL *string `json:"avatar_url"` Country *string `json:"country"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if req.Name != nil { user.Name = req.Name } if req.Phone != nil { user.Phone = req.Phone } if req.Bio != nil { user.Bio = req.Bio } if req.AvatarURL != nil { user.AvatarURL = req.AvatarURL } if req.Country != nil { user.Country = req.Country } if err := h.userRepo.Update(r.Context(), user); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, user) } // Admin endpoints type adminUpdateUserRequest struct { Role *string `json:"role"` Status *string `json:"status"` } func (h *UserHandler) AdminUpdateUser(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "id") var req adminUpdateUserRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if req.Role != nil { validRoles := map[string]bool{"superadmin": true, "moderator": true, "landlord": true, "executor": true, "customer": true} if !validRoles[*req.Role] { writeError(w, http.StatusBadRequest, "invalid role") return } if err := h.userRepo.UpdateRole(r.Context(), id, *req.Role); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } } if req.Status != nil { validStatuses := map[string]bool{"active": true, "banned": true, "pending_verification": true} if !validStatuses[*req.Status] { writeError(w, http.StatusBadRequest, "invalid status") return } if err := h.userRepo.UpdateStatus(r.Context(), id, *req.Status); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } } user, err := h.userRepo.GetByID(r.Context(), id) if err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } writeJSON(w, http.StatusOK, user) } func (h *UserHandler) AdminListUsers(w http.ResponseWriter, r *http.Request) { filter := models.UserFilter{ Role: r.URL.Query().Get("role"), Status: r.URL.Query().Get("status"), } if limit := r.URL.Query().Get("limit"); limit != "" { if v, err := parseInt(limit); err == nil { filter.Limit_ = v } } users, err := h.userRepo.List(r.Context(), filter) if err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } if users == nil { users = []*models.User{} } writeJSON(w, http.StatusOK, map[string]interface{}{"data": users}) } func parseInt(s string) (int, error) { var n int for _, c := range s { if c < '0' || c > '9' { return 0, fmt.Errorf("not a number") } n = n*10 + int(c-'0') } return n, nil }