package user import ( "context" "encoding/json" "fmt" "net/http" "time" "gitea.local/admin/hspguard/internal/auth" "gitea.local/admin/hspguard/internal/repository" "gitea.local/admin/hspguard/internal/web" "github.com/go-chi/chi/v5" "github.com/golang-jwt/jwt/v5" ) type UserHandler struct { repo *repository.Queries } func NewUserHandler(repo *repository.Queries) *UserHandler { return &UserHandler{ repo: repo, } } func (h *UserHandler) RegisterRoutes(router chi.Router, api chi.Router) { router.Get("/login", h.loginPage) router.Get("/register", h.registerPage) api.Post("/register", h.register) api.Post("/login", h.login) } func (h *UserHandler) loginPage(w http.ResponseWriter, r *http.Request) { data := map[string]any{ "Title": "Login", } web.RenderTemplate(w, "login", data) } func (h *UserHandler) registerPage(w http.ResponseWriter, r *http.Request) { data := map[string]any{ "Title": "Register", } web.RenderTemplate(w, "register", data) } type RegisterParams struct { FullName string `json:"full_name"` Email string `json:"email"` PhoneNumber string `json:"phone"` Password string `json:"password"` } func (h *UserHandler) register(w http.ResponseWriter, r *http.Request) { var params RegisterParams decoder := json.NewDecoder(r.Body) if err := decoder.Decode(¶ms); err != nil { web.Error(w, "failed to parse request body", http.StatusBadRequest) return } if params.Email == "" || params.FullName == "" || params.Password == "" { web.Error(w, "missing required fields", http.StatusBadRequest) return } _, err := h.repo.FindUserEmail(context.Background(), params.Email) if err == nil { web.Error(w, "user with provided email already exists", http.StatusBadRequest) return } id, err := h.repo.InsertUser(context.Background(), repository.InsertUserParams{ FullName: params.FullName, Email: params.Email, PasswordHash: params.Password, IsAdmin: false, }) if err != nil { web.Error(w, "failed to create new user", http.StatusInternalServerError) return } encoder := json.NewEncoder(w) type Response struct { Id string `json:"id"` } if err := encoder.Encode(Response{ Id: id.String(), }); err != nil { web.Error(w, "failed to encode response", http.StatusInternalServerError) } } type LoginParams struct { Email string `json:"email"` Password string `json:"password"` } type UserClaims struct { UserID string `json:"user_id"` // Role jwt.RegisteredClaims } func (h *UserHandler) login(w http.ResponseWriter, r *http.Request) { var params LoginParams decoder := json.NewDecoder(r.Body) if err := decoder.Decode(¶ms); err != nil { web.Error(w, "failed to parse request body", http.StatusBadRequest) return } if params.Email == "" || params.Password == "" { web.Error(w, "missing required fields", http.StatusBadRequest) return } user, err := h.repo.FindUserEmail(context.Background(), params.Email) if err != nil { web.Error(w, "user with provided email does not exists", http.StatusBadRequest) return } claims := UserClaims{ UserID: user.ID.String(), RegisteredClaims: jwt.RegisteredClaims{ Issuer: "hspguard", Subject: user.Email, IssuedAt: jwt.NewNumericDate(time.Now()), ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour)), }, } token, err := auth.SignJwtToken(claims) if err != nil { web.Error(w, fmt.Sprintf("failed to generate access token: %v", err), http.StatusBadRequest) return } encoder := json.NewEncoder(w) type Response struct { Token string `json:"token"` } if err := encoder.Encode(Response{ Token: token, }); err != nil { web.Error(w, "failed to encode response", http.StatusInternalServerError) } }