initial commit
This commit is contained in:
308
internal/api/handlers/users.go
Normal file
308
internal/api/handlers/users.go
Normal file
@@ -0,0 +1,308 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"git.kirlllll.ru/volontery/backend/internal/api/middleware"
|
||||
"git.kirlllll.ru/volontery/backend/internal/service"
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
// UserHandler обрабатывает запросы пользователей
|
||||
type UserHandler struct {
|
||||
userService *service.UserService
|
||||
}
|
||||
|
||||
// NewUserHandler создает новый UserHandler
|
||||
func NewUserHandler(userService *service.UserService) *UserHandler {
|
||||
return &UserHandler{
|
||||
userService: userService,
|
||||
}
|
||||
}
|
||||
|
||||
// GetProfile возвращает профиль пользователя
|
||||
// GET /api/v1/users/{id}
|
||||
func (h *UserHandler) GetProfile(w http.ResponseWriter, r *http.Request) {
|
||||
idStr := chi.URLParam(r, "id")
|
||||
userID, err := strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusBadRequest, "invalid user id")
|
||||
return
|
||||
}
|
||||
|
||||
profile, err := h.userService.GetUserProfile(r.Context(), userID)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusNotFound, "user not found")
|
||||
return
|
||||
}
|
||||
|
||||
respondJSON(w, http.StatusOK, profile)
|
||||
}
|
||||
|
||||
// GetMyProfile возвращает профиль текущего пользователя
|
||||
// GET /api/v1/users/me
|
||||
func (h *UserHandler) GetMyProfile(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := middleware.GetUserIDFromContext(r.Context())
|
||||
if !ok {
|
||||
respondError(w, http.StatusUnauthorized, "unauthorized")
|
||||
return
|
||||
}
|
||||
|
||||
profile, err := h.userService.GetUserProfile(r.Context(), userID)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusNotFound, "user not found")
|
||||
return
|
||||
}
|
||||
|
||||
respondJSON(w, http.StatusOK, profile)
|
||||
}
|
||||
|
||||
// UpdateProfile обновляет профиль текущего пользователя
|
||||
// PATCH /api/v1/users/me
|
||||
func (h *UserHandler) UpdateProfile(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := middleware.GetUserIDFromContext(r.Context())
|
||||
if !ok {
|
||||
respondError(w, http.StatusUnauthorized, "unauthorized")
|
||||
return
|
||||
}
|
||||
|
||||
var input service.UpdateProfileInput
|
||||
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
||||
respondError(w, http.StatusBadRequest, "invalid request body")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.userService.UpdateUserProfile(r.Context(), userID, input); err != nil {
|
||||
respondError(w, http.StatusInternalServerError, "failed to update profile")
|
||||
return
|
||||
}
|
||||
|
||||
respondJSON(w, http.StatusOK, map[string]string{"message": "profile updated successfully"})
|
||||
}
|
||||
|
||||
// UpdateLocation обновляет местоположение пользователя
|
||||
// POST /api/v1/users/me/location
|
||||
func (h *UserHandler) UpdateLocation(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := middleware.GetUserIDFromContext(r.Context())
|
||||
if !ok {
|
||||
respondError(w, http.StatusUnauthorized, "unauthorized")
|
||||
return
|
||||
}
|
||||
|
||||
var input struct {
|
||||
Latitude float64 `json:"latitude"`
|
||||
Longitude float64 `json:"longitude"`
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
||||
respondError(w, http.StatusBadRequest, "invalid request body")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.userService.UpdateUserLocation(r.Context(), userID, input.Latitude, input.Longitude); err != nil {
|
||||
respondError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
respondJSON(w, http.StatusOK, map[string]string{"message": "location updated successfully"})
|
||||
}
|
||||
|
||||
// GetMyRoles возвращает роли текущего пользователя
|
||||
// GET /api/v1/users/me/roles
|
||||
func (h *UserHandler) GetMyRoles(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := middleware.GetUserIDFromContext(r.Context())
|
||||
if !ok {
|
||||
respondError(w, http.StatusUnauthorized, "unauthorized")
|
||||
return
|
||||
}
|
||||
|
||||
roles, err := h.userService.GetUserRoles(r.Context(), userID)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, "failed to get roles")
|
||||
return
|
||||
}
|
||||
|
||||
respondJSON(w, http.StatusOK, roles)
|
||||
}
|
||||
|
||||
// GetMyPermissions возвращает разрешения текущего пользователя
|
||||
// GET /api/v1/users/me/permissions
|
||||
func (h *UserHandler) GetMyPermissions(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := middleware.GetUserIDFromContext(r.Context())
|
||||
if !ok {
|
||||
respondError(w, http.StatusUnauthorized, "unauthorized")
|
||||
return
|
||||
}
|
||||
|
||||
permissions, err := h.userService.GetUserPermissions(r.Context(), userID)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, "failed to get permissions")
|
||||
return
|
||||
}
|
||||
|
||||
respondJSON(w, http.StatusOK, permissions)
|
||||
}
|
||||
|
||||
// VerifyEmail подтверждает email пользователя
|
||||
// POST /api/v1/users/me/verify-email
|
||||
func (h *UserHandler) VerifyEmail(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := middleware.GetUserIDFromContext(r.Context())
|
||||
if !ok {
|
||||
respondError(w, http.StatusUnauthorized, "unauthorized")
|
||||
return
|
||||
}
|
||||
|
||||
// В реальной системе здесь должна быть проверка токена из письма
|
||||
// Сейчас просто подтверждаем email для текущего пользователя
|
||||
if err := h.userService.VerifyEmail(r.Context(), userID); err != nil {
|
||||
respondError(w, http.StatusInternalServerError, "failed to verify email")
|
||||
return
|
||||
}
|
||||
|
||||
respondJSON(w, http.StatusOK, map[string]string{"message": "email verified successfully"})
|
||||
}
|
||||
|
||||
// CheckPermission проверяет наличие разрешения у пользователя
|
||||
// GET /api/v1/users/me/permissions/{permission_name}/check
|
||||
func (h *UserHandler) CheckPermission(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := middleware.GetUserIDFromContext(r.Context())
|
||||
if !ok {
|
||||
respondError(w, http.StatusUnauthorized, "unauthorized")
|
||||
return
|
||||
}
|
||||
|
||||
permissionName := chi.URLParam(r, "permission_name")
|
||||
if permissionName == "" {
|
||||
respondError(w, http.StatusBadRequest, "permission_name is required")
|
||||
return
|
||||
}
|
||||
|
||||
hasPermission, err := h.userService.HasPermission(r.Context(), userID, permissionName)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, "failed to check permission")
|
||||
return
|
||||
}
|
||||
|
||||
respondJSON(w, http.StatusOK, map[string]interface{}{
|
||||
"has_permission": hasPermission,
|
||||
"permission_name": permissionName,
|
||||
})
|
||||
}
|
||||
|
||||
// ========== AdminHandler - новый хендлер для административных функций ==========
|
||||
|
||||
// AdminHandler обрабатывает административные запросы
|
||||
type AdminHandler struct {
|
||||
userService *service.UserService
|
||||
}
|
||||
|
||||
// NewAdminHandler создает новый AdminHandler
|
||||
func NewAdminHandler(userService *service.UserService) *AdminHandler {
|
||||
return &AdminHandler{
|
||||
userService: userService,
|
||||
}
|
||||
}
|
||||
|
||||
// AssignRole назначает роль пользователю
|
||||
// POST /api/v1/admin/users/{user_id}/roles/{role_id}
|
||||
func (h *AdminHandler) AssignRole(w http.ResponseWriter, r *http.Request) {
|
||||
adminID, ok := middleware.GetUserIDFromContext(r.Context())
|
||||
if !ok {
|
||||
respondError(w, http.StatusUnauthorized, "unauthorized")
|
||||
return
|
||||
}
|
||||
|
||||
// Проверка, что текущий пользователь является администратором
|
||||
// В реальной системе это должно быть в middleware
|
||||
isAdmin, err := h.userService.HasPermission(r.Context(), adminID, "manage_users")
|
||||
if err != nil {
|
||||
respondError(w, http.StatusInternalServerError, "failed to check permissions")
|
||||
return
|
||||
}
|
||||
if !isAdmin {
|
||||
respondError(w, http.StatusForbidden, "admin role required")
|
||||
return
|
||||
}
|
||||
|
||||
userIDStr := chi.URLParam(r, "user_id")
|
||||
userID, err := strconv.ParseInt(userIDStr, 10, 64)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusBadRequest, "invalid user_id")
|
||||
return
|
||||
}
|
||||
|
||||
roleIDStr := chi.URLParam(r, "role_id")
|
||||
roleID, err := strconv.ParseInt(roleIDStr, 10, 64)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusBadRequest, "invalid role_id")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.userService.AssignRole(r.Context(), userID, roleID, adminID); err != nil {
|
||||
respondError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
respondJSON(w, http.StatusOK, map[string]interface{}{
|
||||
"message": "role assigned successfully",
|
||||
"user_id": userID,
|
||||
"role_id": roleID,
|
||||
})
|
||||
}
|
||||
|
||||
// ========== RequestHandler - дополнительный метод ==========
|
||||
|
||||
// ModerateRequestProcedure модерирует заявку через stored procedure
|
||||
// POST /api/v1/moderation/requests/{id}/moderate
|
||||
func (h *RequestHandler) ModerateRequestProcedure(w http.ResponseWriter, r *http.Request) {
|
||||
moderatorID, ok := middleware.GetUserIDFromContext(r.Context())
|
||||
if !ok {
|
||||
respondError(w, http.StatusUnauthorized, "unauthorized")
|
||||
return
|
||||
}
|
||||
|
||||
idStr := chi.URLParam(r, "id")
|
||||
requestID, err := strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusBadRequest, "invalid request id")
|
||||
return
|
||||
}
|
||||
|
||||
var input struct {
|
||||
Action string `json:"action"`
|
||||
Comment *string `json:"comment"`
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
||||
respondError(w, http.StatusBadRequest, "invalid request body")
|
||||
return
|
||||
}
|
||||
|
||||
if input.Action != "approve" && input.Action != "reject" {
|
||||
respondError(w, http.StatusBadRequest, "action must be 'approve' or 'reject'")
|
||||
return
|
||||
}
|
||||
|
||||
if input.Action == "reject" && (input.Comment == nil || *input.Comment == "") {
|
||||
respondError(w, http.StatusBadRequest, "comment is required when rejecting")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.requestService.ModerateRequestProcedure(r.Context(), requestID, moderatorID, input.Action, input.Comment)
|
||||
if err != nil {
|
||||
respondError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if !result.Success {
|
||||
respondError(w, http.StatusBadRequest, result.Message)
|
||||
return
|
||||
}
|
||||
|
||||
respondJSON(w, http.StatusOK, map[string]interface{}{
|
||||
"success": result.Success,
|
||||
"message": result.Message,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user