52ecc2fab5
- Add Swagger dependencies to go.mod - Annotate all API endpoints with Swagger comments - Add Swagger UI at /api/v1/docs endpoint - Auto-generate Swagger docs in Dockerfile build - Update README with API documentation link
143 lines
3.6 KiB
Go
143 lines
3.6 KiB
Go
package http
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
"apocapoc-api/internal/application/commands"
|
|
"apocapoc-api/internal/application/queries"
|
|
"apocapoc-api/internal/infrastructure/auth"
|
|
"apocapoc-api/internal/shared/errors"
|
|
)
|
|
|
|
type AuthHandlers struct {
|
|
registerHandler *commands.RegisterUserHandler
|
|
loginHandler *queries.LoginUserHandler
|
|
jwtService *auth.JWTService
|
|
}
|
|
|
|
func NewAuthHandlers(
|
|
registerHandler *commands.RegisterUserHandler,
|
|
loginHandler *queries.LoginUserHandler,
|
|
jwtService *auth.JWTService,
|
|
) *AuthHandlers {
|
|
return &AuthHandlers{
|
|
registerHandler: registerHandler,
|
|
loginHandler: loginHandler,
|
|
jwtService: jwtService,
|
|
}
|
|
}
|
|
|
|
type RegisterRequest struct {
|
|
Email string `json:"email"`
|
|
Password string `json:"password"`
|
|
Timezone string `json:"timezone"`
|
|
}
|
|
|
|
type LoginRequest struct {
|
|
Email string `json:"email"`
|
|
Password string `json:"password"`
|
|
}
|
|
|
|
type AuthResponse struct {
|
|
Token string `json:"token"`
|
|
UserID string `json:"user_id"`
|
|
}
|
|
|
|
// Register godoc
|
|
// @Summary Register a new user
|
|
// @Description Create a new user account
|
|
// @Tags auth
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body RegisterRequest true "Registration data"
|
|
// @Success 201 {object} AuthResponse
|
|
// @Failure 400 {object} ErrorResponse
|
|
// @Failure 409 {object} ErrorResponse
|
|
// @Failure 500 {object} ErrorResponse
|
|
// @Router /auth/register [post]
|
|
func (h *AuthHandlers) Register(w http.ResponseWriter, r *http.Request) {
|
|
var req RegisterRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
respondError(w, http.StatusBadRequest, "Invalid request body")
|
|
return
|
|
}
|
|
|
|
cmd := commands.RegisterUserCommand{
|
|
Email: req.Email,
|
|
Password: req.Password,
|
|
Timezone: req.Timezone,
|
|
}
|
|
|
|
userID, err := h.registerHandler.Handle(r.Context(), cmd)
|
|
if err != nil {
|
|
if err == errors.ErrInvalidInput {
|
|
respondError(w, http.StatusBadRequest, "Invalid email or password (min 8 characters)")
|
|
return
|
|
}
|
|
if err == errors.ErrAlreadyExists {
|
|
respondError(w, http.StatusConflict, "Email already registered")
|
|
return
|
|
}
|
|
respondError(w, http.StatusInternalServerError, "Failed to register user")
|
|
return
|
|
}
|
|
|
|
token, err := h.jwtService.GenerateToken(userID, req.Email)
|
|
if err != nil {
|
|
respondError(w, http.StatusInternalServerError, "Failed to generate token")
|
|
return
|
|
}
|
|
|
|
respondJSON(w, http.StatusCreated, AuthResponse{
|
|
Token: token,
|
|
UserID: userID,
|
|
})
|
|
}
|
|
|
|
// Login godoc
|
|
// @Summary Login user
|
|
// @Description Authenticate user and get JWT token
|
|
// @Tags auth
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body LoginRequest true "Login credentials"
|
|
// @Success 200 {object} AuthResponse
|
|
// @Failure 400 {object} ErrorResponse
|
|
// @Failure 401 {object} ErrorResponse
|
|
// @Failure 500 {object} ErrorResponse
|
|
// @Router /auth/login [post]
|
|
func (h *AuthHandlers) Login(w http.ResponseWriter, r *http.Request) {
|
|
var req LoginRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
respondError(w, http.StatusBadRequest, "Invalid request body")
|
|
return
|
|
}
|
|
|
|
query := queries.LoginUserQuery{
|
|
Email: req.Email,
|
|
Password: req.Password,
|
|
}
|
|
|
|
result, err := h.loginHandler.Handle(r.Context(), query)
|
|
if err != nil {
|
|
if err == errors.ErrNotFound || err == errors.ErrInvalidInput {
|
|
respondError(w, http.StatusUnauthorized, "Invalid email or password")
|
|
return
|
|
}
|
|
respondError(w, http.StatusInternalServerError, "Failed to login")
|
|
return
|
|
}
|
|
|
|
token, err := h.jwtService.GenerateToken(result.UserID, result.Email)
|
|
if err != nil {
|
|
respondError(w, http.StatusInternalServerError, "Failed to generate token")
|
|
return
|
|
}
|
|
|
|
respondJSON(w, http.StatusOK, AuthResponse{
|
|
Token: token,
|
|
UserID: result.UserID,
|
|
})
|
|
}
|