package services import ( "net/http" "wm-backend/global" "wm-backend/internal/models" "wm-backend/internal/models/requests" "wm-backend/internal/models/responses" "wm-backend/internal/repositories" "wm-backend/pkg/helper" "wm-backend/response" db "wm-backend/sqlc_gen" "github.com/gin-gonic/gin" "github.com/jackc/pgx/v5/pgtype" "github.com/rs/zerolog/log" ) // Register handles user registration. // It validates the request body, checks for duplicate email, // hashes the password, and creates the user in the database. // // @Summary Register a new user // @Description Register with email, username and password // @Tags auth // @Accept json // @Produce json // @Param body body requests.BodyRegisterRequest true "Register request" // @Success 201 {object} response.SuccessResponse{data=responses.BodyRegisterResponse} // @Failure 400 {object} response.ErrorResponse // @Failure 409 {object} response.ErrorResponse // @Failure 500 {object} response.ErrorResponse // @Router /auth/register [post] func Register(c *gin.Context) error { // 1. Bind & validate request body requestBody := requests.BodyRegisterRequest{} if helper.IsShouldBindJSON(c, &requestBody) { return nil } // 2. Check if user already exists by email existingUser, err := repositories.GetUserByEmail(c.Request.Context(), global.Queries, requestBody.Email) if err != nil { response.InternalServerError(c, http.StatusInternalServerError) log.Error().Err(err).Msg("Error checking existing user") return nil } if existingUser != nil { response.ConflictError(c, http.StatusConflict, "Email already registered") return nil } // 3. Hash the password hashedPassword, err := helper.HashPassword(requestBody.Password) if err != nil { response.InternalServerError(c, http.StatusInternalServerError) log.Error().Err(err).Msg("Password hashing error") return nil } // 4. Create user in database userID, err := repositories.CreateUser(c.Request.Context(), global.Queries, db.CreateUserParams{ Username: requestBody.Username, Email: requestBody.Email, PasswordHash: hashedPassword, FullName: pgtype.Text{String: requestBody.FullName, Valid: requestBody.FullName != ""}, CreatedBy: pgtype.Text{String: requestBody.Username, Valid: true}, }) if err != nil { response.InternalServerError(c, http.StatusInternalServerError) log.Error().Err(err).Msg("Error creating user") return nil } // 5. Return success response response.Created(c, "User registered successfully", responses.BodyRegisterResponse{ ID: userID, }) return nil } func Login(c *gin.Context) error { loginRequestBody := requests.BodyLoginRequest{} if helper.IsShouldBindJSON(c, &loginRequestBody) { return nil } var user *models.User var err error if helper.IsEmail(loginRequestBody.Username) { user, err = repositories.GetUserByEmail(c.Request.Context(), global.Queries, loginRequestBody.Username) } else { user, err = repositories.GetUserByUsername(c.Request.Context(), global.Queries, loginRequestBody.Username) } if err != nil { response.InternalServerError(c, http.StatusInternalServerError) log.Error().Err(err).Msg("Error finding user") return nil } if user == nil { response.UnauthorizedError(c, http.StatusUnauthorized, "Invalid credentials") return nil } // 2. Check if user is active if !user.IsActive { response.UnauthorizedError(c, http.StatusUnauthorized, "Account is disabled") return nil } // 3. Compare password if err := helper.ComparePassword(loginRequestBody.Password, user.PasswordHash); err != nil { response.UnauthorizedError(c, http.StatusUnauthorized, "Invalid credentials") return nil } // 4. Generate JWT token token, err := helper.GenerateToken(user.ID) if err != nil { response.InternalServerError(c, http.StatusInternalServerError) log.Error().Err(err).Msg("Error generating token") return nil } // 5. Return token response.Ok(c, "Login successful", responses.BodyLoginResponse{ Token: token, }) return nil }