Added completed user. Some fixes and more more more...

This commit is contained in:
KamilM1205 2026-01-02 22:56:25 +04:00
parent b96dd39795
commit ea8ab7c0ed
33 changed files with 576 additions and 212 deletions

View file

@ -1,6 +1,17 @@
package commands
import "time"
type CreateUserCommand struct {
Username string
Password string
Username string
Password string
Name string
Role string
Speciality string
Description string
Skills string
Avatar string
JoinDate time.Time
Projects string
Motto string
}

View file

@ -3,7 +3,15 @@ package commands
import "github.com/google/uuid"
type UpdateUserCommand struct {
Id uuid.UUID
Username string
Password string
Id uuid.UUID
Username string
Password string
Name string
Role string
Speciality string
Description string
Skills string
Avatar string
Projects string
Motto string
}

View file

@ -1,11 +1,24 @@
package common
import "github.com/google/uuid"
import (
"time"
"github.com/google/uuid"
)
type UserResult struct {
Id uuid.UUID
UserName string
Password string
Id uuid.UUID
UserName string
Password string
Name string
Role string
Speciality string
Description string
Skills string
Avatar string
JoinDate time.Time
Projects string
Motto string
}
type UserResultList struct {

View file

@ -8,9 +8,18 @@ import (
func CreateUserResultFromEntity(entity *entities.User) *common.UserResult {
return &common.UserResult{
Id: entity.Id,
UserName: entity.UserName,
Password: entity.Password,
Id: entity.Id,
UserName: entity.UserName,
Password: entity.Password,
Name: entity.Name,
Role: entity.Role,
Speciality: entity.Speciality,
Description: entity.Description,
Skills: entity.Skills,
Avatar: entity.Avatar,
JoinDate: entity.JoinDate,
Projects: entity.Projects,
Motto: entity.Motto,
}
}

View file

@ -8,6 +8,7 @@ import (
"58team_blog/internal/application/queries"
"58team_blog/internal/domain/entities"
"58team_blog/internal/domain/repository"
"fmt"
)
type UserService struct {
@ -29,12 +30,15 @@ func (s *UserService) Create(cmd commands.CreateUserCommand) (*common.UserResult
}
if user != nil {
return nil, errors.NewAlreadyExistsError("user: " + cmd.Username)
fmt.Println(user)
return nil, errors.NewAlreadyExistsError("user: " + user.UserName)
}
}
// Create new user
user, err := entities.CreateUser(cmd.Username, cmd.Password)
user, err := entities.CreateUser(cmd.Username, cmd.Password,
cmd.Name, cmd.Role, cmd.Speciality, cmd.Description,
cmd.Skills, cmd.Avatar, cmd.JoinDate, cmd.Projects, cmd.Motto)
if err != nil {
return nil, errors.NewValidationError(err.Error())
}
@ -70,6 +74,10 @@ func (s *UserService) FindByName(query queries.UserFindByNameQuery) (*queries.Us
return nil, errors.NewDBError(err.Error())
}
if entity == nil {
return nil, errors.NewNotFoundError("User not found.")
}
if err := entity.Validate(); err != nil {
return nil, errors.NewValidationError(err.Error())
}
@ -109,6 +117,14 @@ func (s *UserService) Update(cmd commands.UpdateUserCommand) (*common.UserResult
}
entity.Password = cmd.Password
entity.Name = cmd.Name
entity.Role = cmd.Role
entity.Speciality = cmd.Speciality
entity.Description = cmd.Description
entity.Skills = cmd.Skills
entity.Avatar = cmd.Avatar
entity.Projects = cmd.Projects
entity.Motto = cmd.Motto
if err := entity.Validate(); err != nil {
return nil, errors.NewValidationError(err.Error())

View file

@ -2,6 +2,7 @@ package entities
import (
"errors"
"time"
"github.com/google/uuid"
)
@ -9,16 +10,47 @@ import (
const UserTable = "users"
type User struct {
Id uuid.UUID `db:"id"`
UserName string `db:"username"`
Password string `db:"password"`
Id uuid.UUID `db:"id"`
UserName string `db:"username"`
Password string `db:"password"`
Name string `db:"name"`
Role string `db:"role"`
Speciality string `db:"speciality"`
Description string `db:"description"`
Skills string `db:"skills"`
Avatar string `db:"avatar"`
JoinDate time.Time `db:"joindate"`
Projects string `db:"projects"`
Motto string `db:"motto"`
}
func CreateUser(userName string, password string) (user User, err error) {
func CreateUser(
userName string,
password string,
name string,
role string,
speciality string,
description string,
skills string,
avatar string,
joinDate time.Time,
projects string,
motto string,
) (user User, err error) {
user = User{
Id: uuid.New(),
UserName: userName,
Password: password,
Id: uuid.New(),
UserName: userName,
Password: password,
Name: name,
Role: role,
Speciality: speciality,
Description: description,
Skills: skills,
Avatar: avatar,
JoinDate: joinDate,
Projects: projects,
Motto: motto,
}
err = user.Validate()
@ -28,14 +60,51 @@ func CreateUser(userName string, password string) (user User, err error) {
func (u *User) Validate() error {
if err := uuid.Validate(u.Id.String()); err != nil {
return errors.New("Invalid user.id")
return errors.New("invalid user.id")
}
if u.UserName == "" {
return errors.New("Empty user.name")
return errors.New("empty user.username")
}
if u.Password == "" {
return errors.New("Empty user.password")
return errors.New("empty user.password")
}
if u.Role == "" {
return errors.New("empty user.role")
}
if u.Name == "" {
return errors.New("empty user.name")
}
if u.Speciality == "" {
return errors.New("empty user.speciality")
}
if u.Description == "" {
return errors.New("empty user.description")
}
if u.Skills == "" {
return errors.New("empty user.skills")
}
if u.Avatar == "" {
return errors.New("empty user.avatar")
}
if u.Projects == "" {
return errors.New("empty user.projects")
}
if u.Motto == "" {
return errors.New("empty user.motto")
}
if u.JoinDate.IsZero() {
return errors.New("empty user.joinDate")
}
return nil

View file

@ -20,7 +20,9 @@ func CreateUserRepository(conn *db.Database) UserRepository {
}
func (r *UserRepository) Create(entity *entities.User) (*entities.User, error) {
query := "INSERT INTO " + entities.UserTable + "(id, username, password) VALUES (:id, :username, :password)"
query := "INSERT INTO " + entities.UserTable +
"(id, username, password, name, role, speciality, description, skills, avatar, joindate, projects, motto) " +
"VALUES (:id, :username, :password, :name, :role, :speciality, :description, :skills, :avatar, :joindate, :projects, :motto)"
_, err := r.conn.Conn.NamedExec(query, entity)
if err != nil {

View file

@ -36,6 +36,7 @@ func CreateImagesController(images_path string, service *services.ImagesService)
// @Success 200 {object} responses.ImageResponse
// @Failure 500 {object} responses.ErrorResponse
// @Router /images/ [post]
// @Security BasicAuth
func (r *ImagesController) PostImage(c *gin.Context) {
file, err := c.FormFile("file")
if err != nil {
@ -139,6 +140,21 @@ func (r *ImagesController) GetImage(c *gin.Context) {
c.File(filePath)
}
// @Summary Delete image by path
// @Description Delete image from server by given path
// @Tags images
// @Param filename path string true "Path to image"
// @Produce image/png
// @Produce image/jpeg
// @Success 200 {object} responses.GetAllImagesList
// @Failure 400 {object} responses.ErrorResponse
// @Failure 404 {object} responses.ErrorResponse
// @Failure 500 {object} responses.ErrorResponse
// @Router /images [get]
func (r *ImagesController) GetAllImage(c *gin.Context) {
panic("Not implemented")
}
// @Summary Delete image by path
// @Description Delete image from server by given path
// @Tags images
@ -150,6 +166,7 @@ func (r *ImagesController) GetImage(c *gin.Context) {
// @Failure 404 {object} responses.ErrorResponse
// @Failure 500 {object} responses.ErrorResponse
// @Router /images/{path} [delete]
// @Security BasicAuth
func (r *ImagesController) DeleteImage(c *gin.Context) {
panic("Not implemented")
}

View file

@ -40,6 +40,8 @@ func CreatePostController(service *services.PostService, userService *services.U
// @Failure 400 {object} responses.ErrorResponse
// @Failure 500 {object} responses.ErrorResponse
// @Router /post [post]
//
// @Security BasicAuth
func (r *PostController) Post(c *gin.Context) {
var request requests.CreatePostRequest
@ -227,6 +229,8 @@ func (r *PostController) GetById(c *gin.Context) {
// @Failure 404 {object} responses.ErrorResponse
// @Failure 500 {object} responses.ErrorResponse
// @Router /post/{id} [put]
//
// @Security BasicAuth
func (r *PostController) Put(c *gin.Context) {
var request requests.PutPostRequest
@ -276,6 +280,8 @@ func (r *PostController) Put(c *gin.Context) {
// @Failure 404 {object} responses.ErrorResponse
// @Failure 500 {object} responses.ErrorResponse
// @Router /post/{id} [delete]
//
// @Security BasicAuth
func (r *PostController) Delete(c *gin.Context) {
id := c.Param("id")
id_valid, err := uuid.Parse(id)

View file

@ -10,6 +10,7 @@ import (
"58team_blog/internal/utils"
"log"
"net/http"
"strings"
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
@ -107,6 +108,7 @@ func (r *UserController) Login(c *gin.Context) {
// @Failure 400 {object} responses.ErrorResponse
// @Failure 500 {object} responses.ErrorResponse
// @Router /logout [get]
// @Security BasicAuth
func (r *UserController) Logout(c *gin.Context) {
session := sessions.Default(c)
user := session.Get("user")
@ -132,7 +134,8 @@ func (r *UserController) Logout(c *gin.Context) {
// @Failure 400 {object} responses.ErrorResponse
// @Failure 409 {object} responses.ErrorResponse
// @Failure 500 {object} responses.ErrorResponse
// @Router /user/ [post]
// @Router /team/ [post]
// @Security BasicAuth
func (r *UserController) Post(c *gin.Context) {
var request requests.CreateUserRequest
if err := c.BindJSON(&request); err != nil {
@ -151,8 +154,17 @@ func (r *UserController) Post(c *gin.Context) {
}
cmd := commands.CreateUserCommand{
Username: request.Username,
Password: encrypted_password,
Username: request.Username,
Password: encrypted_password,
Role: request.Role,
Name: request.Name,
Speciality: request.Speciality,
Description: request.Description,
Skills: strings.Join(request.Skills, ";"),
Avatar: request.Avatar,
JoinDate: request.JoinDate,
Projects: strings.Join(request.Projects, ";"),
Motto: request.Motto,
}
user, err := r.service.Create(cmd)
@ -177,7 +189,7 @@ func (r *UserController) Post(c *gin.Context) {
// @Failure 400 {object} responses.ErrorResponse
// @Failure 404 {object} responses.ErrorResponse
// @Failure 500 {object} responses.ErrorResponse
// @Router /user/{id} [get]
// @Router /team/{id} [get]
func (r *UserController) FindById(c *gin.Context) {
id_path := c.Param("id")
@ -214,7 +226,7 @@ func (r *UserController) FindById(c *gin.Context) {
// @Failure 400 {object} responses.ErrorResponse
// @Failure 404 {object} responses.ErrorResponse
// @Failure 500 {object} responses.ErrorResponse
// @Router /user/name/{name} [get]
// @Router /team/name/{name} [get]
func (r *UserController) FindByName(c *gin.Context) {
name := c.Param("name")
@ -230,6 +242,7 @@ func (r *UserController) FindByName(c *gin.Context) {
}
response := mapper.ResponseFromUserFindByNameResult(user)
c.JSON(http.StatusOK, response)
}
@ -240,7 +253,7 @@ func (r *UserController) FindByName(c *gin.Context) {
// @Success 200 {object} responses.UserResponseList
// @Failure 400 {object} responses.ErrorResponse
// @Failure 500 {object} responses.ErrorResponse
// @Router /user/ [get]
// @Router /members/ [get]
func (r *UserController) GetAll(c *gin.Context) {
users, err := r.service.GetAll()
if err != nil {
@ -249,8 +262,9 @@ func (r *UserController) GetAll(c *gin.Context) {
return
}
responses := mapper.ResponseFromUserGetAllResult(users)
c.JSON(http.StatusOK, responses)
resp := mapper.ResponseFromUserGetAllResult(users)
c.JSON(http.StatusOK, resp)
}
// @Summary Change user
@ -264,7 +278,8 @@ func (r *UserController) GetAll(c *gin.Context) {
// @Failure 400 {object} responses.ErrorResponse
// @Failure 404 {object} responses.ErrorResponse
// @Failure 500 {object} responses.ErrorResponse
// @Router /user/{id} [put]
// @Router /team/{id} [put]
// @Security BasicAuth
func (r *UserController) Put(c *gin.Context) {
var request requests.PutUserRequest
id_path := c.Param("id")
@ -292,10 +307,21 @@ func (r *UserController) Put(c *gin.Context) {
return
}
skills := strings.Join(request.Skills, ";")
projects := strings.Join(request.Projects, ";")
cmd := commands.UpdateUserCommand{
Id: id,
Username: request.Username,
Password: password,
Id: id,
Username: request.Username,
Name: request.Name,
Password: password,
Role: request.Role,
Speciality: request.Speciality,
Description: request.Description,
Skills: skills,
Avatar: request.Avatar,
Projects: projects,
Motto: request.Motto,
}
user, err := r.service.Update(cmd)
@ -318,7 +344,8 @@ func (r *UserController) Put(c *gin.Context) {
// @Failure 400 {object} responses.ErrorResponse
// @Failure 404 {object} responses.ErrorResponse
// @Failure 500 {object} responses.ErrorResponse
// @Router /user/{id} [delete]
// @Router /team/{id} [delete]
// @Security BasicAuth
func (r *UserController) Delete(c *gin.Context) {
id_path := c.Param("id")

View file

@ -12,14 +12,14 @@ func itemFromResult(item *common.PostResult) responses.GetListPostResponseItem {
UserId: item.UserId.String(),
Title: item.Title,
Description: item.Description,
UpdatedAt: item.UpdatedAt.String(),
UpdatedAt: item.UpdatedAt,
Tags: item.Tags,
Category: item.Category,
}
}
func ResponseFromPostGetAllResult(result *queries.PostGetAllResult) responses.GetListPostResponse {
var resp []responses.GetListPostResponseItem
resp := responses.GetListPostResponse{}
for _, r := range result.Result.Result {
resp = append(resp, itemFromResult(r))

View file

@ -3,11 +3,25 @@ package mapper
import (
"58team_blog/internal/application/queries"
"58team_blog/internal/interfaces/api/responses"
"strings"
)
func ResponseFromUserFindByIdResult(user *queries.UserFindByIdResult) responses.UserResponse {
res := user.Result
skills := strings.Split(res.Skills, ";")
projects := strings.Split(res.Projects, ";")
return responses.UserResponse{
Id: user.Result.Id.String(),
UserName: user.Result.UserName,
Id: res.Id.String(),
UserName: res.UserName,
Name: res.Name,
Role: res.Role,
Speciality: res.Speciality,
Description: res.Description,
Skills: skills,
Avatar: res.Avatar,
JoinDate: res.JoinDate,
Projects: projects,
Motto: res.Motto,
}
}

View file

@ -3,11 +3,25 @@ package mapper
import (
"58team_blog/internal/application/queries"
"58team_blog/internal/interfaces/api/responses"
"strings"
)
func ResponseFromUserFindByNameResult(result *queries.UserFindByNameResult) responses.UserResponse {
res := result.Result
skills := strings.Split(res.Skills, ";")
projects := strings.Split(res.Projects, ";")
return responses.UserResponse{
Id: result.Result.Id.String(),
UserName: result.Result.UserName,
Id: res.Id.String(),
UserName: res.UserName,
Name: res.Name,
Role: res.Role,
Speciality: res.Speciality,
Description: res.Description,
Skills: skills,
Avatar: res.Avatar,
JoinDate: res.JoinDate,
Projects: projects,
Motto: res.Motto,
}
}

View file

@ -6,7 +6,7 @@ import (
)
func ResponseFromUserGetAllResult(result *queries.UserGetAllResult) responses.UserResponseList {
var list responses.UserResponseList
list := responses.UserResponseList{}
for _, i := range result.Result.Result {
list = append(list, ResponseFromUserResult(i))

View file

@ -3,11 +3,24 @@ package mapper
import (
"58team_blog/internal/application/common"
"58team_blog/internal/interfaces/api/responses"
"strings"
)
func ResponseFromUserResult(result *common.UserResult) responses.UserResponse {
skills := strings.Split(result.Skills, ";")
projects := strings.Split(result.Projects, ";")
return responses.UserResponse{
Id: result.Id.String(),
UserName: result.UserName,
Id: result.Id.String(),
UserName: result.UserName,
Name: result.Name,
Role: result.Role,
Speciality: result.Speciality,
Description: result.Description,
Skills: skills,
Avatar: result.Avatar,
JoinDate: result.JoinDate,
Projects: projects,
Motto: result.Motto,
}
}

View file

@ -1,10 +1,10 @@
package requests
type CreatePostRequest struct {
Title string `json:"title" validate:"required,min=8,max=255"`
Description string `json:"description" validate:"required,min=8,max=255"`
Content string `json:"content" validate:"required,min=36"`
UserId string `json:"userId" validate:"required,uuid5"`
Title string `json:"title" binding:"required,min=8,max=255"`
Description string `json:"description" binding:"required,min=8,max=255"`
Content string `json:"content" binding:"required,min=36"`
UserId string `json:"userId" binding:"required,uuid5"`
Category string `json:"category"`
Tags []string `json:"tags"`
}

View file

@ -1,6 +1,17 @@
package requests
import "time"
type CreateUserRequest struct {
Username string `json:"username" validate:"required,min=3,max=32"`
Password string `json:"password" validate:"required,min=6,max=32,password"`
Username string `json:"username" binding:"required,min=3,max=32"`
Password string `json:"password" binding:"required,min=6,max=32,password"`
Name string `json:"name" binding:"required,min=2,max=100"`
Role string `json:"role" binding:"required"`
Speciality string `json:"speciality" binding:"required,min=2,max=100"`
Description string `json:"description" binding:"required,min=10,max=500"`
Skills []string `json:"skills" binding:"required,min=1,inlineList"`
Avatar string `json:"avatar" binding:"required"`
JoinDate time.Time `json:"joinDate" binding:"required"`
Projects []string `json:"projects" binding:"required,min=1,inlineList"`
Motto string `json:"motto" binding:"required,min=2,max=200"`
}

View file

@ -1,6 +1,6 @@
package requests
type LoginUserRequest struct {
Username string `json:"username" validate:"required,min=3,max=32"`
Password string `json:"password" validate:"required,min=6,max=32,password"`
Username string `json:"username" binding:"required,min=3,max=32"`
Password string `json:"password" binding:"required,min=6,max=32,password"`
}

View file

@ -1,6 +1,14 @@
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"`
Username string `json:"username" binding:"required,min=3,max=32"`
Password string `json:"password" binding:"required,min=6,max=32,password"`
Name string `json:"name" binding:"required,min=2,max=100"`
Role string `json:"role" binding:"required"`
Speciality string `json:"speciality" binding:"required,min=2,max=100"`
Description string `json:"description" binding:"required,min=10,max=500"`
Skills []string `json:"skills" binding:"required,min=1,inlineList"`
Avatar string `json:"avatar" binding:"required"`
Projects []string `json:"projects" binding:"required,min=1,inlineList"`
Motto string `json:"motto" binding:"required,min=2,max=200"`
}

View file

@ -1,14 +1,16 @@
package responses
import "time"
type GetListPostResponseItem struct {
Id string `json:"id"`
UserId string `json:"userId"`
Title string `json:"title"`
Description string `json:"description"`
UpdatedAt string `json:"updatedAt"`
Tags []string `json:"tags"`
Category string `json:"category"`
Username string `json:"username"`
Id string `json:"id"`
UserId string `json:"userId"`
Title string `json:"title"`
Description string `json:"description"`
UpdatedAt time.Time `json:"updatedAt"`
Tags []string `json:"tags"`
Category string `json:"category"`
Username string `json:"username"`
}
type GetListPostResponse []GetListPostResponseItem

View file

@ -0,0 +1,4 @@
package responses
type GetAllImagesList struct {
}

View file

@ -1,8 +1,18 @@
package responses
type UserResponse struct {
Id string `json:"id"`
UserName string `json:"username"`
}
import "time"
type UserResponse struct {
Id string `json:"id"`
UserName string `json:"username"`
Name string `json:"name"`
Role string `json:"role"`
Speciality string `json:"speciality"`
Description string `json:"description"`
Skills []string `json:"skills"`
Avatar string `json:"avatar"`
JoinDate time.Time `json:"joinDate"`
Projects []string `json:"projects"`
Motto string `json:"motto"`
}
type UserResponseList []UserResponse

View file

@ -34,13 +34,15 @@ func BindUser(adminName string, adminPass string, service *services.UserService,
group.POST("/login", user.Login)
group.GET("/logout", user.Logout)
g := group.Group("/user/")
g_all := group.Group("/members")
g_all.GET("/", user.GetAll)
g_all.GET("/:id", user.FindById)
g_all.GET("/name/:name", user.FindByName)
g := group.Group("/team/")
g.Use(infrastructure.AuthRequired)
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)
}

View file

@ -14,17 +14,24 @@ func HandleError(err error) responses.ErrorResponse {
log.Println(err)
if errors.Is(&ie.ValidationError{}, err) {
var validationErr *ie.ValidationError
var readFileErr *ie.ReadFileError
var notFoundErr *ie.NotFoundError
var alreadyExistsErr *ie.AlreadyExistsError
var dbErr *ie.DBError
switch {
case errors.As(err, &validationErr):
errorCode = http.StatusBadRequest
} else if errors.Is(&ie.ReadFileError{}, err) {
case errors.As(err, &readFileErr):
errorCode = http.StatusInternalServerError
} else if errors.Is(&ie.NotFoundError{}, err) {
case errors.As(err, &notFoundErr):
errorCode = http.StatusNotFound
} else if errors.Is(&ie.AlreadyExistsError{}, err) {
case errors.As(err, &alreadyExistsErr):
errorCode = http.StatusConflict
} else if errors.Is(&ie.DBError{}, err) {
case errors.As(err, &dbErr):
errorCode = http.StatusInternalServerError
} else {
default:
errorCode = http.StatusInternalServerError
}

View file

@ -0,0 +1,21 @@
package utils
import (
"strings"
"github.com/go-playground/validator/v10"
)
func InlineListValidator(fl validator.FieldLevel) bool {
str, ok := fl.Field().Interface().(string)
if ok {
for _, char := range str {
if strings.ContainsRune(";", char) {
return false
}
}
}
return true
}