auth.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. package handlers
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "net/http"
  6. "github.com/photoplaces/backend/internal/middleware"
  7. "github.com/photoplaces/backend/internal/services"
  8. )
  9. type AuthHandler struct {
  10. authSvc *services.AuthService
  11. }
  12. func NewAuthHandler(authSvc *services.AuthService) *AuthHandler {
  13. return &AuthHandler{authSvc: authSvc}
  14. }
  15. type registerRequest struct {
  16. Email string `json:"email"`
  17. Password string `json:"password"`
  18. Role string `json:"role"`
  19. Name string `json:"name"`
  20. }
  21. func (h *AuthHandler) Register(w http.ResponseWriter, r *http.Request) {
  22. var req registerRequest
  23. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  24. writeError(w, http.StatusBadRequest, "invalid request body")
  25. return
  26. }
  27. if req.Email == "" || req.Password == "" {
  28. writeError(w, http.StatusBadRequest, "email and password are required")
  29. return
  30. }
  31. validRoles := map[string]bool{"customer": true, "landlord": true, "executor": true}
  32. if !validRoles[req.Role] {
  33. req.Role = "customer"
  34. }
  35. result, err := h.authSvc.Register(r.Context(), services.RegisterInput{
  36. Email: req.Email,
  37. Password: req.Password,
  38. Role: req.Role,
  39. Name: req.Name,
  40. })
  41. if err != nil {
  42. if errors.Is(err, services.ErrEmailExists) {
  43. writeError(w, http.StatusConflict, "email already exists")
  44. return
  45. }
  46. writeError(w, http.StatusInternalServerError, err.Error())
  47. return
  48. }
  49. writeJSON(w, http.StatusCreated, result)
  50. }
  51. type loginRequest struct {
  52. Email string `json:"email"`
  53. Password string `json:"password"`
  54. }
  55. func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) {
  56. var req loginRequest
  57. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  58. writeError(w, http.StatusBadRequest, "invalid request body")
  59. return
  60. }
  61. result, err := h.authSvc.Login(r.Context(), services.LoginInput{
  62. Email: req.Email,
  63. Password: req.Password,
  64. })
  65. if err != nil {
  66. if errors.Is(err, services.ErrInvalidCreds) {
  67. writeError(w, http.StatusUnauthorized, "invalid email or password")
  68. return
  69. }
  70. if errors.Is(err, services.ErrUserBanned) {
  71. writeError(w, http.StatusForbidden, "account is banned")
  72. return
  73. }
  74. writeError(w, http.StatusInternalServerError, err.Error())
  75. return
  76. }
  77. writeJSON(w, http.StatusOK, result)
  78. }
  79. func (h *AuthHandler) Refresh(w http.ResponseWriter, r *http.Request) {
  80. refreshToken := r.Header.Get("X-Refresh-Token")
  81. if refreshToken == "" {
  82. writeError(w, http.StatusBadRequest, "refresh token required")
  83. return
  84. }
  85. result, err := h.authSvc.RefreshSession(r.Context(), refreshToken)
  86. if err != nil {
  87. writeError(w, http.StatusUnauthorized, "invalid or expired refresh token")
  88. return
  89. }
  90. writeJSON(w, http.StatusOK, result)
  91. }
  92. func (h *AuthHandler) Logout(w http.ResponseWriter, r *http.Request) {
  93. w.WriteHeader(http.StatusNoContent)
  94. }
  95. func (h *AuthHandler) Me(w http.ResponseWriter, r *http.Request) {
  96. userID := middleware.GetUserID(r.Context())
  97. if userID == "" {
  98. writeError(w, http.StatusUnauthorized, "not authenticated")
  99. return
  100. }
  101. writeJSON(w, http.StatusOK, map[string]string{"user_id": userID, "role": middleware.GetUserRole(r.Context())})
  102. }
  103. func writeJSON(w http.ResponseWriter, status int, v interface{}) {
  104. w.Header().Set("Content-Type", "application/json")
  105. w.WriteHeader(status)
  106. json.NewEncoder(w).Encode(v)
  107. }
  108. func writeError(w http.ResponseWriter, status int, msg string) {
  109. writeJSON(w, status, map[string]string{"error": msg})
  110. }