changes...
This commit is contained in:
parent
41944884b4
commit
ab4b53fd40
26 changed files with 600 additions and 51 deletions
21
cmd/main.go
21
cmd/main.go
|
|
@ -20,9 +20,12 @@ import (
|
||||||
"58team_blog/internal/infrastructure/db"
|
"58team_blog/internal/infrastructure/db"
|
||||||
"58team_blog/internal/infrastructure/db/repo"
|
"58team_blog/internal/infrastructure/db/repo"
|
||||||
"58team_blog/internal/interfaces"
|
"58team_blog/internal/interfaces"
|
||||||
|
"58team_blog/internal/utils"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/gin-gonic/gin/binding"
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
swaggerFiles "github.com/swaggo/files"
|
swaggerFiles "github.com/swaggo/files"
|
||||||
ginSwagger "github.com/swaggo/gin-swagger"
|
ginSwagger "github.com/swaggo/gin-swagger"
|
||||||
)
|
)
|
||||||
|
|
@ -30,6 +33,11 @@ import (
|
||||||
func main() {
|
func main() {
|
||||||
router := gin.Default()
|
router := gin.Default()
|
||||||
|
|
||||||
|
// Register custom validators
|
||||||
|
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
|
||||||
|
v.RegisterValidation("password", utils.PasswordValidator)
|
||||||
|
}
|
||||||
|
|
||||||
// Swagger setup
|
// Swagger setup
|
||||||
docs.SwaggerInfo.Title = "58team blog"
|
docs.SwaggerInfo.Title = "58team blog"
|
||||||
docs.SwaggerInfo.Description = "This is blog 58team"
|
docs.SwaggerInfo.Description = "This is blog 58team"
|
||||||
|
|
@ -38,14 +46,6 @@ func main() {
|
||||||
docs.SwaggerInfo.BasePath = "/api/v1/"
|
docs.SwaggerInfo.BasePath = "/api/v1/"
|
||||||
docs.SwaggerInfo.Schemes = []string{"http", "https"}
|
docs.SwaggerInfo.Schemes = []string{"http", "https"}
|
||||||
|
|
||||||
// router.GET("/swagger/*any", func(c *gin.Context) {
|
|
||||||
// path := c.Param("any")
|
|
||||||
// if strings.HasPrefix(path, "/doc.json") {
|
|
||||||
// c.File("docs/swagger.json")
|
|
||||||
// } else {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, ginSwagger.URL("http://localhost:8080/swag/doc/doc.json")))
|
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, ginSwagger.URL("http://localhost:8080/swag/doc/doc.json")))
|
||||||
router.StaticFile("/swag/doc/doc.json", "docs/swagger.json")
|
router.StaticFile("/swag/doc/doc.json", "docs/swagger.json")
|
||||||
|
|
||||||
|
|
@ -61,10 +61,15 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Database error: ", err)
|
log.Fatal("Database error: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
postRepository := repo.CreatePostRepository(d)
|
postRepository := repo.CreatePostRepository(d)
|
||||||
|
userRepository := repo.CreateUserRepository(d)
|
||||||
|
|
||||||
postService := services.CreatePostService(&postRepository)
|
postService := services.CreatePostService(&postRepository)
|
||||||
|
userService := services.CreateUserService(&userRepository)
|
||||||
|
|
||||||
interfaces.BindPostAdmin(&postService, g)
|
interfaces.BindPostAdmin(&postService, g)
|
||||||
|
interfaces.BindUser(&userService, g)
|
||||||
|
|
||||||
router.Run(":8080")
|
router.Run(":8080")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -21,6 +21,20 @@ definitions:
|
||||||
- title
|
- title
|
||||||
- userId
|
- userId
|
||||||
type: object
|
type: object
|
||||||
|
requests.CreateUserRequest:
|
||||||
|
properties:
|
||||||
|
password:
|
||||||
|
maxLength: 32
|
||||||
|
minLength: 6
|
||||||
|
type: string
|
||||||
|
username:
|
||||||
|
maxLength: 32
|
||||||
|
minLength: 3
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- password
|
||||||
|
- username
|
||||||
|
type: object
|
||||||
requests.PutPostRequest:
|
requests.PutPostRequest:
|
||||||
properties:
|
properties:
|
||||||
content:
|
content:
|
||||||
|
|
@ -30,6 +44,20 @@ definitions:
|
||||||
title:
|
title:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
requests.PutUserRequest:
|
||||||
|
properties:
|
||||||
|
password:
|
||||||
|
maxLength: 32
|
||||||
|
minLength: 6
|
||||||
|
type: string
|
||||||
|
username:
|
||||||
|
maxLength: 32
|
||||||
|
minLength: 3
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- password
|
||||||
|
- username
|
||||||
|
type: object
|
||||||
responses.ErrorResponse:
|
responses.ErrorResponse:
|
||||||
properties:
|
properties:
|
||||||
error_code:
|
error_code:
|
||||||
|
|
@ -63,6 +91,13 @@ definitions:
|
||||||
userId:
|
userId:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
responses.UserResponse:
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
host: localhost:8080
|
host: localhost:8080
|
||||||
info:
|
info:
|
||||||
contact:
|
contact:
|
||||||
|
|
@ -79,7 +114,7 @@ info:
|
||||||
paths:
|
paths:
|
||||||
/images/{path}:
|
/images/{path}:
|
||||||
get:
|
get:
|
||||||
description: Creates new user in system
|
description: get image by path
|
||||||
parameters:
|
parameters:
|
||||||
- description: Path to image
|
- description: Path to image
|
||||||
in: query
|
in: query
|
||||||
|
|
@ -87,11 +122,12 @@ paths:
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- image/png
|
||||||
|
- image/jpeg
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
summary: Create new user
|
summary: Get an image by path
|
||||||
/post:
|
/post:
|
||||||
get:
|
get:
|
||||||
description: Return first 5 posts
|
description: Return first 5 posts
|
||||||
|
|
@ -125,8 +161,8 @@ paths:
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"201":
|
||||||
description: OK
|
description: Created
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/responses.PostResponse'
|
$ref: '#/definitions/responses.PostResponse'
|
||||||
"400":
|
"400":
|
||||||
|
|
@ -238,6 +274,150 @@ paths:
|
||||||
summary: Get posts after offset
|
summary: Get posts after offset
|
||||||
tags:
|
tags:
|
||||||
- post
|
- post
|
||||||
|
/user/:
|
||||||
|
get:
|
||||||
|
description: Return all registered users
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/responses.UserResponse'
|
||||||
|
type: array
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/responses.ErrorResponse'
|
||||||
|
summary: Get all users
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Creates new user in system
|
||||||
|
parameters:
|
||||||
|
- description: User data
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/requests.CreateUserRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"201":
|
||||||
|
description: Created
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/responses.UserResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/responses.ErrorResponse'
|
||||||
|
summary: Create new user
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
|
/user/{id}:
|
||||||
|
delete:
|
||||||
|
description: Delete user
|
||||||
|
parameters:
|
||||||
|
- description: User id
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/responses.ErrorResponse'
|
||||||
|
summary: Delete user
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Find user by id
|
||||||
|
parameters:
|
||||||
|
- description: user id
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/responses.UserResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/responses.ErrorResponse'
|
||||||
|
summary: Find user by id
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
|
put:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Change the user's name and password
|
||||||
|
parameters:
|
||||||
|
- description: User id
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- description: User data
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/requests.PutUserRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/responses.UserResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/responses.ErrorResponse'
|
||||||
|
summary: Change user
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
|
/user/name/{name}:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Find user by username
|
||||||
|
parameters:
|
||||||
|
- description: User name
|
||||||
|
in: path
|
||||||
|
name: name
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/responses.UserResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/responses.ErrorResponse'
|
||||||
|
summary: Find user by username
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
securityDefinitions:
|
securityDefinitions:
|
||||||
BasicAuth:
|
BasicAuth:
|
||||||
type: basic
|
type: basic
|
||||||
|
|
|
||||||
15
internal/application/errors/db_error.go
Normal file
15
internal/application/errors/db_error.go
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
package errors
|
||||||
|
|
||||||
|
type DBError struct {
|
||||||
|
msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDBError(msg string) DBError {
|
||||||
|
return DBError{
|
||||||
|
msg: msg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *DBError) Error() string {
|
||||||
|
return e.msg
|
||||||
|
}
|
||||||
15
internal/application/errors/not_found_error.go
Normal file
15
internal/application/errors/not_found_error.go
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
package errors
|
||||||
|
|
||||||
|
type NotFoundError struct {
|
||||||
|
msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNotFoundError(msg string) *NotFoundError {
|
||||||
|
return &NotFoundError{
|
||||||
|
msg: msg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *NotFoundError) Error() string {
|
||||||
|
return e.msg
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ package services
|
||||||
import (
|
import (
|
||||||
"58team_blog/internal/application/commands"
|
"58team_blog/internal/application/commands"
|
||||||
"58team_blog/internal/application/common"
|
"58team_blog/internal/application/common"
|
||||||
|
ie "58team_blog/internal/application/errors"
|
||||||
"58team_blog/internal/application/mapper"
|
"58team_blog/internal/application/mapper"
|
||||||
"58team_blog/internal/application/queries"
|
"58team_blog/internal/application/queries"
|
||||||
"58team_blog/internal/domain/entities"
|
"58team_blog/internal/domain/entities"
|
||||||
|
|
@ -44,6 +45,10 @@ func (s *PostService) FindById(query queries.PostFindByIdQuery) (*queries.PostFi
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if post == nil {
|
||||||
|
return nil, ie.NewNotFoundError("Post")
|
||||||
|
}
|
||||||
|
|
||||||
if err := post.Validate(); err != nil {
|
if err := post.Validate(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ type UserService struct {
|
||||||
repo repository.UsersRepository
|
repo repository.UsersRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUserService(repo repository.UsersRepository) UserService {
|
func CreateUserService(repo repository.UsersRepository) UserService {
|
||||||
return UserService{
|
return UserService{
|
||||||
repo: repo,
|
repo: repo,
|
||||||
}
|
}
|
||||||
|
|
@ -26,7 +26,7 @@ func (s *UserService) Create(cmd commands.CreateUserCommand) (*common.UserResult
|
||||||
{
|
{
|
||||||
user, err := s.repo.FindByName(cmd.Username)
|
user, err := s.repo.FindByName(cmd.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("User.create findByName error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if user != nil {
|
if user != nil {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package repo
|
||||||
import (
|
import (
|
||||||
"58team_blog/internal/domain/entities"
|
"58team_blog/internal/domain/entities"
|
||||||
"58team_blog/internal/infrastructure/db"
|
"58team_blog/internal/infrastructure/db"
|
||||||
|
"database/sql"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
|
@ -28,7 +29,7 @@ func (r *PostRepository) Create(entity *entities.Post) (*entities.Post, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *PostRepository) FindById(id uuid.UUID) (*entities.Post, error) {
|
func (r *PostRepository) FindById(id uuid.UUID) (*entities.Post, error) {
|
||||||
var entity *entities.Post
|
var entity entities.Post
|
||||||
query := "SELECT * FROM " + entities.PostTable + " WHERE id=?"
|
query := "SELECT * FROM " + entities.PostTable + " WHERE id=?"
|
||||||
|
|
||||||
query, args, err := sqlx.In(query, id)
|
query, args, err := sqlx.In(query, id)
|
||||||
|
|
@ -37,9 +38,13 @@ func (r *PostRepository) FindById(id uuid.UUID) (*entities.Post, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
query = r.conn.Conn.Rebind(query)
|
query = r.conn.Conn.Rebind(query)
|
||||||
err = r.conn.Conn.Get(entity, query, args)
|
err = r.conn.Conn.Get(&entity, query, args...)
|
||||||
|
|
||||||
return entity, err
|
if err == sql.ErrNoRows {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &entity, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *PostRepository) FindAllByUserName(userName string) ([]*entities.Post, error) {
|
func (r *PostRepository) FindAllByUserName(userName string) ([]*entities.Post, error) {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package repo
|
||||||
import (
|
import (
|
||||||
"58team_blog/internal/domain/entities"
|
"58team_blog/internal/domain/entities"
|
||||||
"58team_blog/internal/infrastructure/db"
|
"58team_blog/internal/infrastructure/db"
|
||||||
|
"database/sql"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
|
|
@ -39,31 +40,29 @@ func (r *UserRepository) FindById(id uuid.UUID) (*entities.User, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
query = r.conn.Conn.Rebind(query)
|
query = r.conn.Conn.Rebind(query)
|
||||||
err = r.conn.Conn.Get(entity, query, arg...)
|
err = r.conn.Conn.Select(entity, query, arg...)
|
||||||
|
|
||||||
return entity, err
|
return entity, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *UserRepository) FindByName(username string) (*entities.User, error) {
|
func (r *UserRepository) FindByName(username string) (*entities.User, error) {
|
||||||
var entity *entities.User
|
var entity entities.User
|
||||||
|
|
||||||
query := "SELECT * FROM " + entities.UserTable + " WHERE username=?"
|
query := "SELECT * FROM " + entities.UserTable + " WHERE username=$1"
|
||||||
query, arg, err := sqlx.In(query, username)
|
|
||||||
if err != nil {
|
err := r.conn.Conn.Get(&entity, query, username)
|
||||||
return nil, err
|
if err == sql.ErrNoRows {
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
query = r.conn.Conn.Rebind(query)
|
return &entity, nil
|
||||||
err = r.conn.Conn.Get(entity, query, arg...)
|
|
||||||
|
|
||||||
return entity, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *UserRepository) GetAll() ([]*entities.User, error) {
|
func (r *UserRepository) GetAll() ([]*entities.User, error) {
|
||||||
var entity_list []*entities.User
|
var entity_list []*entities.User
|
||||||
|
|
||||||
query := "SELECT * FROM " + entities.UserTable
|
query := "SELECT * FROM " + entities.UserTable
|
||||||
err := r.conn.Conn.Select(entity_list, query)
|
err := r.conn.Conn.Select(&entity_list, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"58team_blog/internal/application/commands"
|
"58team_blog/internal/application/commands"
|
||||||
"58team_blog/internal/application/queries"
|
"58team_blog/internal/application/queries"
|
||||||
"58team_blog/internal/application/services"
|
"58team_blog/internal/application/services"
|
||||||
"58team_blog/internal/interfaces/api/dto"
|
"58team_blog/internal/interfaces/api/mapper"
|
||||||
"58team_blog/internal/interfaces/api/requests"
|
"58team_blog/internal/interfaces/api/requests"
|
||||||
"58team_blog/internal/interfaces/api/responses"
|
"58team_blog/internal/interfaces/api/responses"
|
||||||
"log"
|
"log"
|
||||||
|
|
@ -33,7 +33,7 @@ func CreatePostController(service *services.PostService) PostController {
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param request body requests.CreatePostRequest true "Post data"
|
// @Param request body requests.CreatePostRequest true "Post data"
|
||||||
// @Success 200 {object} responses.PostResponse
|
// @Success 201 {object} responses.PostResponse
|
||||||
// @Failure 400 {object} responses.ErrorResponse
|
// @Failure 400 {object} responses.ErrorResponse
|
||||||
// @Failure 500 {object} responses.ErrorResponse
|
// @Failure 500 {object} responses.ErrorResponse
|
||||||
// @Router /post [post]
|
// @Router /post [post]
|
||||||
|
|
@ -70,9 +70,9 @@ func (r *PostController) Post(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response := dto.ResponseFromPostResult(res)
|
response := mapper.ResponseFromPostResult(res)
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response)
|
c.JSON(http.StatusCreated, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAllPost godoc
|
// GetAllPost godoc
|
||||||
|
|
@ -93,7 +93,7 @@ func (r *PostController) GetAll(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
res := dto.ResponseFromPostGetAllResult(result)
|
res := mapper.ResponseFromPostGetAllResult(result)
|
||||||
|
|
||||||
c.JSON(http.StatusOK, res)
|
c.JSON(http.StatusOK, res)
|
||||||
}
|
}
|
||||||
|
|
@ -126,7 +126,7 @@ func (r *PostController) GetAllWithOffset(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
res := dto.ResponseFromPostGetAllResult(result)
|
res := mapper.ResponseFromPostGetAllResult(result)
|
||||||
|
|
||||||
c.JSON(http.StatusOK, res)
|
c.JSON(http.StatusOK, res)
|
||||||
}
|
}
|
||||||
|
|
@ -164,7 +164,7 @@ func (r *PostController) GetById(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
result := dto.ResponseFormPostFindByIdResult(posts)
|
result := mapper.ResponseFormPostFindByIdResult(posts)
|
||||||
|
|
||||||
c.JSON(http.StatusOK, result)
|
c.JSON(http.StatusOK, result)
|
||||||
}
|
}
|
||||||
|
|
@ -216,7 +216,7 @@ func (r *PostController) Put(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response := dto.ResponseFromPostResult(post)
|
response := mapper.ResponseFromPostResult(post)
|
||||||
c.JSON(http.StatusOK, response)
|
c.JSON(http.StatusOK, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,18 @@
|
||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"58team_blog/internal/application/commands"
|
||||||
|
"58team_blog/internal/application/queries"
|
||||||
"58team_blog/internal/application/services"
|
"58team_blog/internal/application/services"
|
||||||
|
"58team_blog/internal/interfaces/api/mapper"
|
||||||
|
"58team_blog/internal/interfaces/api/requests"
|
||||||
|
"58team_blog/internal/interfaces/api/responses"
|
||||||
|
"58team_blog/internal/utils"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UserController struct {
|
type UserController struct {
|
||||||
|
|
@ -18,33 +27,216 @@ func CreateUserController(service *services.UserService) UserController {
|
||||||
|
|
||||||
// @Summary Create new user
|
// @Summary Create new user
|
||||||
// @Description Creates new user in system
|
// @Description Creates new user in system
|
||||||
// @Param path query string true "Path to image"
|
// @Tags user
|
||||||
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200
|
// @Param request body requests.CreateUserRequest true "User data"
|
||||||
// @Router /images/{path} [get]
|
// @Success 201 {object} responses.UserResponse
|
||||||
|
// @Failure 400 {object} responses.ErrorResponse
|
||||||
|
// @Router /user/ [post]
|
||||||
func (r *UserController) Post(c *gin.Context) {
|
func (r *UserController) Post(c *gin.Context) {
|
||||||
// TODO: return image
|
var request requests.CreateUserRequest
|
||||||
panic("Not implemented")
|
if err := c.BindJSON(&request); err != nil {
|
||||||
|
log.Println("User invalid request: ", err)
|
||||||
|
resp := responses.CreateErrorResponse(http.StatusBadRequest, "Bad request")
|
||||||
|
c.JSON(resp.ErrorCode, resp)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
encrypted_password, err := utils.EncryptPassword(request.Password)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("User encrupt password error: ", err)
|
||||||
|
resp := responses.CreateErrorResponse(http.StatusInternalServerError, "Internal server error")
|
||||||
|
c.JSON(resp.ErrorCode, resp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := commands.CreateUserCommand{
|
||||||
|
Username: request.Username,
|
||||||
|
Password: encrypted_password,
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := r.service.Create(cmd)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("User service error: ", err)
|
||||||
|
resp := responses.CreateErrorResponse(http.StatusBadRequest, "Bad request")
|
||||||
|
c.JSON(resp.ErrorCode, resp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response := mapper.ResponseFromUserResult(user)
|
||||||
|
|
||||||
|
c.JSON(http.StatusCreated, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Find user by id
|
||||||
|
// @Description Find user by id
|
||||||
|
// @Tags user
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path string true "user id"
|
||||||
|
// @Success 200 {object} responses.UserResponse
|
||||||
|
// @Failure 400 {object} responses.ErrorResponse
|
||||||
|
// @Router /user/{id} [get]
|
||||||
func (r *UserController) FindById(c *gin.Context) {
|
func (r *UserController) FindById(c *gin.Context) {
|
||||||
|
id_path := c.Param("id")
|
||||||
|
|
||||||
|
id, err := uuid.Parse(id_path)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("User id error: ", err)
|
||||||
|
resp := responses.CreateErrorResponse(http.StatusBadRequest, "Bad request")
|
||||||
|
c.JSON(resp.ErrorCode, resp)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query := queries.UserFindByIdQuery{
|
||||||
|
Id: id,
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := r.service.FindById(query)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("User service error: ", err)
|
||||||
|
resp := responses.CreateErrorResponse(http.StatusNotFound, "Not found")
|
||||||
|
c.JSON(resp.ErrorCode, resp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response := mapper.ResponseFromUserFindByIdResult(user)
|
||||||
|
c.JSON(http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Find user by username
|
||||||
|
// @Description Find user by username
|
||||||
|
// @Tags user
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param name path string true "User name"
|
||||||
|
// @Success 200 {object} responses.UserResponse
|
||||||
|
// @Failure 400 {object} responses.ErrorResponse
|
||||||
|
// @Router /user/name/{name} [get]
|
||||||
func (r *UserController) FindByName(c *gin.Context) {
|
func (r *UserController) FindByName(c *gin.Context) {
|
||||||
|
name := c.Param("name")
|
||||||
|
|
||||||
|
query := queries.UserFindByNameQuery{
|
||||||
|
Name: name,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
user, err := r.service.FindByName(query)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("User service error: ", err)
|
||||||
|
resp := responses.CreateErrorResponse(http.StatusNotFound, "Not found")
|
||||||
|
c.JSON(resp.ErrorCode, resp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response := mapper.ResponseFromUserFindByNameResult(user)
|
||||||
|
c.JSON(http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Get all users
|
||||||
|
// @Description Return all registered users
|
||||||
|
// @Tags user
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} responses.UserResponseList
|
||||||
|
// @Failure 400 {object} responses.ErrorResponse
|
||||||
|
// @Router /user/ [get]
|
||||||
func (r *UserController) GetAll(c *gin.Context) {
|
func (r *UserController) GetAll(c *gin.Context) {
|
||||||
// TODO: return image
|
users, err := r.service.GetAll()
|
||||||
panic("Not implemented")
|
if err != nil {
|
||||||
|
log.Println("User service error: ", err)
|
||||||
|
resp := responses.CreateErrorResponse(http.StatusInternalServerError, "Internal server error")
|
||||||
|
c.JSON(resp.ErrorCode, resp)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
responses := mapper.ResponseFromUserGetAllResult(users)
|
||||||
|
c.JSON(http.StatusOK, responses)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Change user
|
||||||
|
// @Description Change the user's name and password
|
||||||
|
// @Tags user
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path string true "User id"
|
||||||
|
// @Param request body requests.PutUserRequest true "User data"
|
||||||
|
// @Success 200 {object} responses.UserResponse
|
||||||
|
// @Failure 400 {object} responses.ErrorResponse
|
||||||
|
// @Router /user/{id} [put]
|
||||||
func (r *UserController) Put(c *gin.Context) {
|
func (r *UserController) Put(c *gin.Context) {
|
||||||
|
var request requests.PutUserRequest
|
||||||
|
id_path := c.Param("id")
|
||||||
|
|
||||||
|
id, err := uuid.Parse(id_path)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("User id error: ", err)
|
||||||
|
resp := responses.CreateErrorResponse(http.StatusBadRequest, "Bad request")
|
||||||
|
c.JSON(resp.ErrorCode, resp)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := c.BindJSON(&request); err != nil {
|
||||||
|
log.Println("User request error: ", err)
|
||||||
|
resp := responses.CreateErrorResponse(http.StatusBadRequest, "Bad request")
|
||||||
|
c.JSON(resp.ErrorCode, resp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
password, err := utils.EncryptPassword(request.Password)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("User password encrypt error: ", err)
|
||||||
|
resp := responses.CreateErrorResponse(http.StatusInternalServerError, "Internal server error")
|
||||||
|
c.JSON(resp.ErrorCode, resp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := commands.UpdateUserCommand{
|
||||||
|
Id: id,
|
||||||
|
Username: request.Username,
|
||||||
|
Password: password,
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := r.service.Update(cmd)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("User service error: ", err)
|
||||||
|
resp := responses.CreateErrorResponse(http.StatusInternalServerError, "Internal server error")
|
||||||
|
c.JSON(resp.ErrorCode, resp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response := mapper.ResponseFromUserResult(user)
|
||||||
|
c.JSON(http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Delete user
|
||||||
|
// @Description Delete user
|
||||||
|
// @Tags user
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path string true "User id"
|
||||||
|
// @Success 200
|
||||||
|
// @Failure 400 {object} responses.ErrorResponse
|
||||||
|
// @Router /user/{id} [delete]
|
||||||
func (r *UserController) Delete(c *gin.Context) {
|
func (r *UserController) Delete(c *gin.Context) {
|
||||||
// TODO: return image
|
id_path := c.Param("id")
|
||||||
panic("Not implemented")
|
|
||||||
|
id, err := uuid.Parse(id_path)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("User id error: ", err)
|
||||||
|
resp := responses.CreateErrorResponse(http.StatusBadRequest, "Bad request")
|
||||||
|
c.JSON(resp.ErrorCode, resp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := commands.DeleteUserCommand{
|
||||||
|
Id: id,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.service.Delete(cmd); err != nil {
|
||||||
|
log.Println("User service error: ", err)
|
||||||
|
resp := responses.CreateErrorResponse(http.StatusNotFound, "User not found")
|
||||||
|
c.JSON(resp.ErrorCode, resp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Status(http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package dto
|
package mapper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"58team_blog/internal/application/queries"
|
"58team_blog/internal/application/queries"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package dto
|
package mapper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"58team_blog/internal/application/common"
|
"58team_blog/internal/application/common"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package dto
|
package mapper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"58team_blog/internal/application/common"
|
"58team_blog/internal/application/common"
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package mapper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"58team_blog/internal/application/queries"
|
||||||
|
"58team_blog/internal/interfaces/api/responses"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ResponseFromUserFindByIdResult(user *queries.UserFindByIdResult) responses.UserResponse {
|
||||||
|
return responses.UserResponse{
|
||||||
|
Id: user.Result.Id.String(),
|
||||||
|
UserName: user.Result.UserName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package mapper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"58team_blog/internal/application/queries"
|
||||||
|
"58team_blog/internal/interfaces/api/responses"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ResponseFromUserFindByNameResult(result *queries.UserFindByNameResult) responses.UserResponse {
|
||||||
|
return responses.UserResponse{
|
||||||
|
Id: result.Result.Id.String(),
|
||||||
|
UserName: result.Result.UserName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package mapper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"58team_blog/internal/application/queries"
|
||||||
|
"58team_blog/internal/interfaces/api/responses"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ResponseFromUserGetAllResult(result *queries.UserGetAllResult) responses.UserResponseList {
|
||||||
|
var list responses.UserResponseList
|
||||||
|
|
||||||
|
for _, i := range result.Result.Result {
|
||||||
|
list = append(list, ResponseFromUserResult(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
return list
|
||||||
|
}
|
||||||
13
internal/interfaces/api/mapper/response_from_user_result.go
Normal file
13
internal/interfaces/api/mapper/response_from_user_result.go
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
package mapper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"58team_blog/internal/application/common"
|
||||||
|
"58team_blog/internal/interfaces/api/responses"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ResponseFromUserResult(result *common.UserResult) responses.UserResponse {
|
||||||
|
return responses.UserResponse{
|
||||||
|
Id: result.Id.String(),
|
||||||
|
UserName: result.UserName,
|
||||||
|
}
|
||||||
|
}
|
||||||
6
internal/interfaces/api/requests/create_user_request.go
Normal file
6
internal/interfaces/api/requests/create_user_request.go
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
package requests
|
||||||
|
|
||||||
|
type CreateUserRequest struct {
|
||||||
|
Username string `json:"username" validate:"required,min=3,max=32"`
|
||||||
|
Password string `json:"password" validate:"required,min=6,max=32,password"`
|
||||||
|
}
|
||||||
6
internal/interfaces/api/requests/put_user_request.go
Normal file
6
internal/interfaces/api/requests/put_user_request.go
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
package requests
|
||||||
|
|
||||||
|
type PutUserRequest struct {
|
||||||
|
Username string `json:"username" validate:"required,min=3,max=32"`
|
||||||
|
Password string `json:"password" validate:"required,min=6,max=32,password"`
|
||||||
|
}
|
||||||
8
internal/interfaces/api/responses/user_response.go
Normal file
8
internal/interfaces/api/responses/user_response.go
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
package responses
|
||||||
|
|
||||||
|
type UserResponse struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
UserName string `json:"username"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserResponseList []UserResponse
|
||||||
|
|
@ -18,3 +18,15 @@ func BindPostAdmin(service *services.PostService, group *gin.RouterGroup) {
|
||||||
g.PUT("/:id", post.Put)
|
g.PUT("/:id", post.Put)
|
||||||
g.DELETE("/:id", post.Delete)
|
g.DELETE("/:id", post.Delete)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BindUser(service *services.UserService, group *gin.RouterGroup) {
|
||||||
|
user := controllers.CreateUserController(service)
|
||||||
|
|
||||||
|
g := group.Group("/user/")
|
||||||
|
g.POST("/", user.Post)
|
||||||
|
g.GET("/", user.GetAll)
|
||||||
|
g.GET("/:id", user.FindById)
|
||||||
|
g.GET("/name/:name", user.FindByName)
|
||||||
|
g.PUT("/:id", user.Put)
|
||||||
|
g.DELETE("/:id", user.Delete)
|
||||||
|
}
|
||||||
|
|
|
||||||
21
internal/utils/password_crypt.go
Normal file
21
internal/utils/password_crypt.go
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func EncryptPassword(pass string) (string, error) {
|
||||||
|
var salted string
|
||||||
|
salt := "58_team:%s:1205secret"
|
||||||
|
|
||||||
|
salted = fmt.Sprintf(salt, pass)
|
||||||
|
|
||||||
|
hashed, err := bcrypt.GenerateFromPassword([]byte(salted), 12)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(hashed), nil
|
||||||
|
}
|
||||||
25
internal/utils/password_validator.go
Normal file
25
internal/utils/password_validator.go
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unicode"
|
||||||
|
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PasswordValidator(fl validator.FieldLevel) bool {
|
||||||
|
password := fl.Field().Interface().(string)
|
||||||
|
|
||||||
|
var hasUpper, hasNumber, hasLower = false, false, false
|
||||||
|
|
||||||
|
for _, c := range password {
|
||||||
|
if unicode.IsUpper(c) {
|
||||||
|
hasUpper = true
|
||||||
|
} else if unicode.IsLower(c) {
|
||||||
|
hasLower = true
|
||||||
|
} else if unicode.IsDigit(c) {
|
||||||
|
hasNumber = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasUpper && hasNumber && hasLower
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue