280 lines
9.5 KiB
Go
280 lines
9.5 KiB
Go
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(®ister); 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)
|
||
}
|