package user import ( "errors" "net/http" "github.com/gin-gonic/gin" "go.uber.org/zap" "openteam/server/internal/config" "openteam/server/internal/pkg/httpx" ) type Handler struct { svc *Service cfg *config.Config log *zap.Logger } func NewHandler(svc *Service, cfg *config.Config, log *zap.Logger) *Handler { return &Handler{svc: svc, cfg: cfg, log: log} } // Register handles POST /api/v1/auth/register. func (h *Handler) Register(c *gin.Context) { var in RegisterInput if !httpx.Bind(c, &in) { return } u, pair, err := h.svc.Register(in) if err != nil { if errors.Is(err, ErrUserExists) { httpx.Fail(c, http.StatusConflict, err.Error()) return } h.log.Warn("register failed", zap.Error(err)) httpx.Fail(c, http.StatusBadRequest, err.Error()) return } h.setRefreshCookie(c, pair.RefreshToken) httpx.Created(c, gin.H{"user": GetPublic(u), "token": pair}) } // Login handles POST /api/v1/auth/login. func (h *Handler) Login(c *gin.Context) { var in LoginInput if !httpx.Bind(c, &in) { return } u, pair, err := h.svc.Login(in) if err != nil { if errors.Is(err, ErrBadCredentials) || errors.Is(err, ErrUserDisabled) { httpx.Fail(c, http.StatusUnauthorized, err.Error()) return } h.log.Warn("login failed", zap.Error(err)) httpx.Fail(c, http.StatusInternalServerError, "login failed") return } h.setRefreshCookie(c, pair.RefreshToken) httpx.OK(c, gin.H{"user": GetPublic(u), "token": pair}) } // Refresh handles POST /api/v1/auth/refresh. func (h *Handler) Refresh(c *gin.Context) { token, err := c.Cookie(h.cfg.Auth.RefreshCookieName) if err != nil || token == "" { httpx.Fail(c, http.StatusUnauthorized, "missing refresh token") return } pair, err := h.svc.Refresh(token) if err != nil { httpx.Fail(c, http.StatusUnauthorized, "invalid refresh token") return } h.setRefreshCookie(c, pair.RefreshToken) httpx.OK(c, gin.H{"token": pair}) } // Logout handles POST /api/v1/auth/logout. func (h *Handler) Logout(c *gin.Context) { c.SetCookie(h.cfg.Auth.RefreshCookieName, "", -1, "/", "", h.cfg.Auth.RefreshCookieSecure, true) httpx.OK(c, gin.H{"ok": true}) } // Me handles GET /api/v1/auth/me. func (h *Handler) Me(c *gin.Context) { u := Current(c) httpx.OK(c, GetPublic(u)) } // Profile handles GET /api/v1/user/profile. func (h *Handler) Profile(c *gin.Context) { u := Current(c) httpx.OK(c, GetPublic(u)) } // Balance handles GET /api/v1/user/balance. func (h *Handler) Balance(c *gin.Context) { u := Current(c) httpx.OK(c, gin.H{"balance": u.Balance.String()}) } func (h *Handler) setRefreshCookie(c *gin.Context, token string) { c.SetCookie(h.cfg.Auth.RefreshCookieName, token, int(h.cfg.Auth.RefreshTokenTTL.Seconds()), "/", "", h.cfg.Auth.RefreshCookieSecure, true) }