created: user module
This commit is contained in:
parent
bc2038ef34
commit
77dbb1953e
6 changed files with 325 additions and 0 deletions
152
internal/api/user/controller.go
Normal file
152
internal/api/user/controller.go
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"merch-parser-api/internal/interfaces"
|
||||||
|
"merch-parser-api/internal/shared"
|
||||||
|
"merch-parser-api/pkg/responses"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type controller struct {
|
||||||
|
service *service
|
||||||
|
utils interfaces.Utils
|
||||||
|
}
|
||||||
|
|
||||||
|
func newController(service *service, utils interfaces.Utils) *controller {
|
||||||
|
return &controller{
|
||||||
|
service: service,
|
||||||
|
utils: utils,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) RegisterRoutes(r *gin.RouterGroup) {
|
||||||
|
userGroup := r.Group("/user")
|
||||||
|
|
||||||
|
userGroup.POST("/", h.controller.register)
|
||||||
|
userGroup.GET("/", h.controller.get)
|
||||||
|
userGroup.PUT("/", h.controller.update)
|
||||||
|
userGroup.DELETE("/", h.controller.delete)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) ExcludeRoutes() []shared.ExcludeRoute {
|
||||||
|
return []shared.ExcludeRoute{
|
||||||
|
{Route: "/user", Method: http.MethodPost},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Регистрация нового пользователя
|
||||||
|
// @Description Регистрация нового пользователя
|
||||||
|
// @Tags Users
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @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)
|
||||||
|
}
|
||||||
18
internal/api/user/dto.go
Normal file
18
internal/api/user/dto.go
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
package user
|
||||||
|
|
||||||
|
type Register struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Info struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
CreatedAt string `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Update struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
}
|
||||||
29
internal/api/user/handler.go
Normal file
29
internal/api/user/handler.go
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"merch-parser-api/internal/interfaces"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handler struct {
|
||||||
|
controller *controller
|
||||||
|
service *service
|
||||||
|
repo UserRepo
|
||||||
|
}
|
||||||
|
|
||||||
|
type Deps struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
Utils interfaces.Utils
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandler(deps Deps) *Handler {
|
||||||
|
r := newRepo(deps.DB)
|
||||||
|
s := newService(r)
|
||||||
|
c := newController(s, deps.Utils)
|
||||||
|
|
||||||
|
return &Handler{
|
||||||
|
controller: c,
|
||||||
|
service: s,
|
||||||
|
repo: r,
|
||||||
|
}
|
||||||
|
}
|
||||||
22
internal/api/user/model.go
Normal file
22
internal/api/user/model.go
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Id uint `gorm:"primary_key"`
|
||||||
|
CreatedAt time.Time `gorm:"column:created_at"`
|
||||||
|
UpdatedAt sql.NullTime `gorm:"column:updated_at"`
|
||||||
|
DeletedAt sql.NullTime `gorm:"column:deleted_at"`
|
||||||
|
Uuid string `gorm:"column:uuid"`
|
||||||
|
Username string `gorm:"column:username"`
|
||||||
|
Password string `gorm:"column:password"`
|
||||||
|
Email string `gorm:"column:email"`
|
||||||
|
Verified int `gorm:"column:verified"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (User) TableName() string {
|
||||||
|
return "users"
|
||||||
|
}
|
||||||
38
internal/api/user/repository.go
Normal file
38
internal/api/user/repository.go
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type repo struct {
|
||||||
|
db *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRepo(db *gorm.DB) *repo {
|
||||||
|
return &repo{db: db}
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserRepo interface {
|
||||||
|
register(user User) error
|
||||||
|
getByUuid(userUuid string) (User, error)
|
||||||
|
update(user map[string]any) error
|
||||||
|
delete(userUuid string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *repo) register(user User) error {
|
||||||
|
return r.db.Create(&user).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *repo) getByUuid(userUuid string) (user User, err error) {
|
||||||
|
err = r.db.Where("uuid = ?", userUuid).First(&user).Error
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *repo) update(user map[string]any) error {
|
||||||
|
return r.db.Where("uuid = ?", user["uuid"]).Updates(&user).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *repo) delete(userUuid string) error {
|
||||||
|
return r.db.Model(&User{}).Where("uuid = ?", userUuid).Update("deleted_at", time.Now().UTC()).Error
|
||||||
|
}
|
||||||
66
internal/api/user/service.go
Normal file
66
internal/api/user/service.go
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type service struct {
|
||||||
|
repo UserRepo
|
||||||
|
}
|
||||||
|
|
||||||
|
func newService(repo UserRepo) *service {
|
||||||
|
return &service{repo: repo}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) register(dto Register) error {
|
||||||
|
user := User{
|
||||||
|
CreatedAt: time.Now().UTC(),
|
||||||
|
UpdatedAt: sql.NullTime{Valid: false},
|
||||||
|
DeletedAt: sql.NullTime{Valid: false},
|
||||||
|
Uuid: uuid.NewString(),
|
||||||
|
Username: dto.Username,
|
||||||
|
Password: dto.Password,
|
||||||
|
Email: dto.Email,
|
||||||
|
Verified: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.repo.register(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) get(userUuid string) (Info, error) {
|
||||||
|
user, err := s.repo.getByUuid(userUuid)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("User | Failed to get user by uuid")
|
||||||
|
return Info{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return Info{
|
||||||
|
Username: user.Username,
|
||||||
|
Email: user.Email,
|
||||||
|
CreatedAt: user.CreatedAt.String(),
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) update(userUuid string, update Update) error {
|
||||||
|
user := make(map[string]any)
|
||||||
|
|
||||||
|
if update.Username != "" {
|
||||||
|
user["username"] = update.Username
|
||||||
|
}
|
||||||
|
|
||||||
|
if update.Email != "" {
|
||||||
|
user["email"] = update.Email
|
||||||
|
}
|
||||||
|
|
||||||
|
user["updated_at"] = time.Now().UTC()
|
||||||
|
user["uuid"] = userUuid
|
||||||
|
|
||||||
|
return s.repo.update(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) delete(userUuid string) error {
|
||||||
|
return s.repo.delete(userUuid)
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue