api/internal/api/user/controller.go
2025-09-14 19:34:06 +03:00

280 lines
9.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package user
import (
"fmt"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
"merch-parser-api/internal/interfaces"
"merch-parser-api/pkg/responses"
"net/http"
"time"
)
type controller struct {
service *service
utils interfaces.Utils
authPath string
}
func newController(service *service, utils interfaces.Utils) *controller {
return &controller{
service: service,
utils: utils,
}
}
func (h *Handler) RegisterRoutes(r *gin.RouterGroup, authMW gin.HandlerFunc, refreshMW gin.HandlerFunc) {
userGroup := r.Group("/user")
userGroup.POST("/", h.controller.register)
userGroup.GET("/", authMW, h.controller.get)
userGroup.PUT("/", authMW, h.controller.update)
userGroup.DELETE("/", authMW, h.controller.delete)
//auth
h.controller.authPath = fmt.Sprintf("%s/user/auth", h.apiPrefix)
authGroup := r.Group("/user/auth")
authGroup.POST("/login", h.controller.login)
authGroup.POST("/logout", refreshMW, h.controller.logout)
authGroup.POST("/refresh", refreshMW, h.controller.refresh)
authGroup.GET("/current-session", authMW, refreshMW, h.controller.getCurrentSession)
}
// @Summary Регистрация нового пользователя
// @Description Регистрация нового пользователя
// @Tags Users
// @Accept json
// @Param body body Register true "новый пользователь"
// @Success 200
// @Failure 400 {object} responses.ErrorResponse400
// @Failure 500 {object} responses.ErrorResponse500
// @Router /user [post]
func (co *controller) register(c *gin.Context) {
var register Register
if err := c.ShouldBindJSON(&register); err != nil {
c.JSON(http.StatusBadRequest, responses.ErrorResponse400{Error: err.Error()})
log.WithError(err).Error("User | Failed to bind JSON on register")
return
}
if err := co.service.register(register); err != nil {
c.JSON(http.StatusInternalServerError, responses.ErrorResponse500{Error: err.Error()})
log.WithError(err).Error("User | Failed to register user")
return
}
c.Status(http.StatusOK)
}
// @Summary Получить информацию о пользователе
// @Description Получает информацию о пользователе по его uuid из токена
// @Tags Users
// @Security BearerAuth
// @Success 200 {object} Info
// @Failure 400 {object} responses.ErrorResponse400
// @Failure 401 {object} responses.ErrorResponse401
// @Failure 500 {object} responses.ErrorResponse500
// @Router /user [get]
func (co *controller) get(c *gin.Context) {
userUuid, err := co.utils.GetUserUuidFromContext(c)
if err != nil {
c.JSON(http.StatusBadRequest, responses.ErrorResponse400{Error: err.Error()})
log.WithError(err).Error("User | Failed to get user uuid from context on get")
return
}
response, err := co.service.get(userUuid)
if err != nil {
c.JSON(http.StatusInternalServerError, responses.ErrorResponse500{Error: err.Error()})
log.WithError(err).Error("User | Failed to get user info")
return
}
c.JSON(http.StatusOK, response)
}
// @Summary Обновить информацию о пользователе
// @Description Обновить информацию о пользователе по его uuid из токена
// @Tags Users
// @Security BearerAuth
// @Accept json
// @Param body body Update true "изменения"
// @Success 200
// @Failure 400 {object} responses.ErrorResponse400
// @Failure 401 {object} responses.ErrorResponse401
// @Failure 500 {object} responses.ErrorResponse500
// @Router /user [put]
func (co *controller) update(c *gin.Context) {
userUuid, err := co.utils.GetUserUuidFromContext(c)
if err != nil {
c.JSON(http.StatusBadRequest, responses.ErrorResponse400{Error: err.Error()})
log.WithError(err).Error("User | Failed to get user uuid from context on update")
return
}
var update Update
if err = c.ShouldBindJSON(&update); err != nil {
c.JSON(http.StatusBadRequest, responses.ErrorResponse400{Error: err.Error()})
log.WithError(err).Error("User | Failed to bind JSON on update")
return
}
if err = co.service.update(userUuid, update); err != nil {
c.JSON(http.StatusInternalServerError, responses.ErrorResponse500{Error: err.Error()})
log.WithError(err).Error("User | Failed to update user info")
return
}
c.Status(http.StatusOK)
}
// @Summary Удалить пользователя
// @Description Помечает пользователя как удаленного по его uuid из токена
// @Tags Users
// @Security BearerAuth
// @Success 200
// @Failure 400 {object} responses.ErrorResponse400
// @Failure 401 {object} responses.ErrorResponse401
// @Failure 500 {object} responses.ErrorResponse500
// @Router /user [delete]
func (co *controller) delete(c *gin.Context) {
userUuid, err := co.utils.GetUserUuidFromContext(c)
if err != nil {
c.JSON(http.StatusBadRequest, responses.ErrorResponse400{Error: err.Error()})
log.WithError(err).Error("User | Failed to get user uuid from context on delete")
return
}
if err = co.service.delete(userUuid); err != nil {
c.JSON(http.StatusInternalServerError, responses.ErrorResponse500{Error: err.Error()})
log.WithError(err).Error("User | Failed to delete user info")
return
}
c.Status(http.StatusOK)
}
// @Summary Логин
// @Description Логин
// @Tags Users - auth
// @Accept json
// @Param body body Login true "логин"
// @Success 200 {object} LoginResponse
// @Failure 400 {object} responses.ErrorResponse400
// @Failure 500 {object} responses.ErrorResponse500
// @Router /user/auth/login [post]
func (co *controller) login(c *gin.Context) {
var login Login
if err := c.ShouldBindJSON(&login); err != nil {
c.JSON(http.StatusBadRequest, responses.ErrorResponse400{Error: err.Error()})
log.WithError(err).Error("User | Failed to bind JSON on login")
return
}
response, err := co.service.login(login)
if err != nil {
c.JSON(http.StatusInternalServerError, responses.ErrorResponse500{Error: err.Error()})
log.WithError(err).Error("User | Failed to login")
return
}
c.SetCookie(
response.RefreshCookie.Name,
response.RefreshCookie.Value,
int(time.Until(response.RefreshCookie.Expires).Seconds()),
co.authPath,
"",
response.RefreshCookie.Secure,
response.RefreshCookie.HttpOnly,
)
c.JSON(http.StatusOK, LoginResponse{AccessToken: response.AccessToken})
log.Debug("User | Successfully logged in")
}
// @Summary Логаут
// @Description Логаут. Для логаута надо передать refresh token, он будет инвалидирован.
// @Tags Users - auth
// @Success 200
// @Failure 400 {object} responses.ErrorResponse400
// @Failure 500 {object} responses.ErrorResponse500
// @Router /user/auth/logout [post]
func (co *controller) logout(c *gin.Context) {
refreshUuid, err := co.utils.GetRefreshUuidFromContext(c)
if err != nil {
c.JSON(http.StatusBadRequest, responses.ErrorResponse400{Error: err.Error()})
log.WithError(err).Error("User | Failed to get refresh uuid from context on logout")
return
}
if err = co.service.logout(refreshUuid); err != nil {
c.JSON(http.StatusInternalServerError, responses.ErrorResponse500{Error: err.Error()})
log.WithError(err).Error("User | Failed to logout")
return
}
c.Status(http.StatusOK)
}
// @Summary Обновление аксесс токена по рефреш токену.
// @Description Принимает рефреш токен в http only куки
// @Tags Users - auth
// @Success 200 {object} LoginResponse
// @Failure 400 {object} responses.ErrorResponse400
// @Failure 500 {object} responses.ErrorResponse500
// @Router /user/auth/refresh [post]
func (co *controller) refresh(c *gin.Context) {
refreshUuid, err := co.utils.GetRefreshUuidFromContext(c)
if err != nil {
c.JSON(http.StatusBadRequest, responses.ErrorResponse400{Error: err.Error()})
log.WithError(err).Error("User | Failed to get refresh uuid from context on refresh")
return
}
response, err := co.service.refresh(refreshUuid)
if err != nil {
c.JSON(http.StatusInternalServerError, responses.ErrorResponse500{Error: err.Error()})
log.WithError(err).Error("User | Failed to refresh user info")
return
}
c.SetCookie(
response.RefreshCookie.Name,
response.RefreshCookie.Value,
int(time.Until(response.RefreshCookie.Expires).Seconds()),
co.authPath,
"",
response.RefreshCookie.Secure,
response.RefreshCookie.HttpOnly,
)
c.JSON(http.StatusOK, LoginResponse{AccessToken: response.AccessToken})
}
// @Summary Возвращает информацию о текущей сессии пользователя
// @Description Возвращает информацию о текущей сессии пользователя
// @Tags Users
// @Security BearerAuth
// @Success 200 {object} shared.CurrentSession
// @Failure 400 {object} responses.ErrorResponse400
// @Failure 401 {object} responses.ErrorResponse401
// @Failure 500 {object} responses.ErrorResponse500
// @Router /user/auth/current-session [get]
func (co *controller) getCurrentSession(c *gin.Context) {
refreshUuid, err := co.utils.GetRefreshUuidFromContext(c)
if err != nil {
c.JSON(http.StatusBadRequest, responses.ErrorResponse400{Error: err.Error()})
log.WithError(err).Error("User | Failed to get refresh uuid from context on refresh")
return
}
response, err := co.service.getCurrentSession(refreshUuid)
if err != nil {
c.JSON(http.StatusInternalServerError, responses.ErrorResponse500{Error: err.Error()})
log.WithError(err).Error("User | Failed to get user info")
return
}
c.JSON(http.StatusOK, response)
}