@@ -2,24 +2,30 @@ package handlers
22
33import (
44 "bullet-cloud-api/internal/auth"
5+ "bullet-cloud-api/internal/models"
56 "bullet-cloud-api/internal/users"
67 "bullet-cloud-api/internal/webutils"
8+ "context"
9+ "encoding/json"
710 "errors"
811 "net/http"
12+ "strings"
913 "time"
1014)
1115
1216// AuthHandler handles authentication requests.
1317type AuthHandler struct {
1418 UserRepo users.UserRepository
19+ Hasher auth.PasswordHasher
1520 JwtSecret string
1621 TokenExpiryDuration time.Duration
1722}
1823
1924// NewAuthHandler creates a new AuthHandler.
20- func NewAuthHandler (userRepo users.UserRepository , jwtSecret string , tokenExpiry time.Duration ) * AuthHandler {
25+ func NewAuthHandler (userRepo users.UserRepository , hasher auth. PasswordHasher , jwtSecret string , tokenExpiry time.Duration ) * AuthHandler {
2126 return & AuthHandler {
2227 UserRepo : userRepo ,
28+ Hasher : hasher ,
2329 JwtSecret : jwtSecret ,
2430 TokenExpiryDuration : tokenExpiry ,
2531 }
@@ -46,79 +52,100 @@ type LoginResponse struct {
4652
4753// Register handles new user registration.
4854func (h * AuthHandler ) Register (w http.ResponseWriter , r * http.Request ) {
49- var req RegisterRequest
50- if err := webutils .ReadJSON (r , & req ); err != nil {
55+ var req struct {
56+ Name string `json:"name"`
57+ Email string `json:"email"`
58+ Password string `json:"password"`
59+ }
60+
61+ if err := json .NewDecoder (r .Body ).Decode (& req ); err != nil {
5162 webutils .ErrorJSON (w , errors .New ("invalid request body" ), http .StatusBadRequest )
5263 return
5364 }
5465
55- // Basic validation
66+ req .Name = strings .TrimSpace (req .Name )
67+ req .Email = strings .TrimSpace (strings .ToLower (req .Email ))
68+
5669 if req .Name == "" || req .Email == "" || req .Password == "" {
5770 webutils .ErrorJSON (w , errors .New ("name, email, and password are required" ), http .StatusBadRequest )
5871 return
5972 }
60- // TODO: Add more robust validation (email format, password strength)
6173
62- // Hash password
63- hashedPassword , err := auth .HashPassword (req .Password )
74+ // Check if email already exists
75+ _ , err := h .UserRepo .FindByEmail (context .Background (), req .Email )
76+ if err == nil {
77+ webutils .ErrorJSON (w , errors .New ("email already registered" ), http .StatusConflict )
78+ return
79+ } else if ! errors .Is (err , users .ErrUserNotFound ) {
80+ webutils .ErrorJSON (w , errors .New ("failed to check email existence" ), http .StatusInternalServerError )
81+ return
82+ }
83+
84+ // Hash the password using the injected hasher
85+ hashedPassword , err := h .Hasher .HashPassword (req .Password )
6486 if err != nil {
65- webutils .ErrorJSON (w , errors .New ("failed to hash password " ), http .StatusInternalServerError )
87+ webutils .ErrorJSON (w , errors .New ("failed to register user " ), http .StatusInternalServerError )
6688 return
6789 }
6890
69- // Create user
70- newUser , err := h .UserRepo .Create (r .Context (), req .Name , req .Email , hashedPassword )
91+ user := & models.User {
92+ Name : req .Name ,
93+ Email : req .Email ,
94+ PasswordHash : hashedPassword ,
95+ }
96+
97+ // Call UserRepo.Create with individual fields as per current repo signature
98+ createdUser , err := h .UserRepo .Create (context .Background (), user .Name , user .Email , user .PasswordHash )
7199 if err != nil {
72- if errors .Is (err , users .ErrEmailAlreadyExists ) {
73- webutils .ErrorJSON (w , err , http .StatusConflict )
74- } else {
75- webutils .ErrorJSON (w , errors .New ("failed to create user" ), http .StatusInternalServerError )
76- }
100+ webutils .ErrorJSON (w , errors .New ("failed to register user" ), http .StatusInternalServerError )
77101 return
78102 }
79103
80- // Return created user (ensure password hash is not included)
81- newUser .PasswordHash = "" // Already done in repository, but good practice to double-check
82- webutils .WriteJSON (w , http .StatusCreated , newUser )
104+ webutils .WriteJSON (w , http .StatusCreated , createdUser )
83105}
84106
85107// Login handles user login and JWT generation.
86108func (h * AuthHandler ) Login (w http.ResponseWriter , r * http.Request ) {
87- var req LoginRequest
88- if err := webutils .ReadJSON (r , & req ); err != nil {
109+ var req struct {
110+ Email string `json:"email"`
111+ Password string `json:"password"`
112+ }
113+
114+ if err := json .NewDecoder (r .Body ).Decode (& req ); err != nil {
89115 webutils .ErrorJSON (w , errors .New ("invalid request body" ), http .StatusBadRequest )
90116 return
91117 }
92118
119+ req .Email = strings .TrimSpace (strings .ToLower (req .Email ))
120+
93121 if req .Email == "" || req .Password == "" {
94122 webutils .ErrorJSON (w , errors .New ("email and password are required" ), http .StatusBadRequest )
95123 return
96124 }
97125
98- // Find user by email
99- user , err := h .UserRepo .FindByEmail (r .Context (), req .Email )
126+ user , err := h .UserRepo .FindByEmail (context .Background (), req .Email )
100127 if err != nil {
101128 if errors .Is (err , users .ErrUserNotFound ) {
102129 webutils .ErrorJSON (w , errors .New ("invalid email or password" ), http .StatusUnauthorized )
103130 } else {
104- webutils .ErrorJSON (w , errors .New ("failed to find user " ), http .StatusInternalServerError )
131+ webutils .ErrorJSON (w , errors .New ("login failed " ), http .StatusInternalServerError )
105132 }
106133 return
107134 }
108135
109- // Check password
110- if ! auth .CheckPasswordHash (req .Password , user .PasswordHash ) {
136+ // Check the password using the injected hasher
137+ err = h .Hasher .CheckPassword (user .PasswordHash , req .Password )
138+ if err != nil { // bcrypt.CompareHashAndPassword returns error on mismatch
111139 webutils .ErrorJSON (w , errors .New ("invalid email or password" ), http .StatusUnauthorized )
112140 return
113141 }
114142
115- // Generate JWT
116- tokenString , err := auth .GenerateToken (user .ID , h .JwtSecret , h .TokenExpiryDuration )
143+ // Generate JWT using the correct function name
144+ token , err := auth .GenerateToken (user .ID , h .JwtSecret , h .TokenExpiryDuration )
117145 if err != nil {
118- webutils .ErrorJSON (w , errors .New ("failed to generate token " ), http .StatusInternalServerError )
146+ webutils .ErrorJSON (w , errors .New ("login failed " ), http .StatusInternalServerError )
119147 return
120148 }
121149
122- // Return token
123- webutils .WriteJSON (w , http .StatusOK , LoginResponse {Token : tokenString })
150+ webutils .WriteJSON (w , http .StatusOK , map [string ]string {"token" : token })
124151}
0 commit comments