package api import ( "database/sql" "errors" "fmt" "net/http" db "git.nochill.in/nochill/hiling_go/db/sqlc" "git.nochill.in/nochill/hiling_go/util" "github.com/gin-gonic/gin" "github.com/go-playground/validator/v10" "github.com/lib/pq" ) type createUserRequest struct { Username string `json:"username" binding:"required,alphanum"` Password string `json:"password" binding:"required,min=7"` } type createUserResponse struct { ID int32 `json:"id"` Username string `json:"username"` AvatarPicture string `json:"avatar_picture"` // avatar_url BannedAt sql.NullTime `json:"banned_at"` BannedUntil sql.NullTime `json:"banned_until"` BanReason string `json:"ban_reason"` IsPermaban sql.NullBool `json:"is_permaban"` IsAdmin sql.NullBool `json:"is_admin"` IsCritics sql.NullBool `json:"is_critics"` IsVerified sql.NullBool `json:"is_verified"` CreatedAt sql.NullTime `json:"created_at"` UpdatedAt sql.NullTime `json:"updated_at"` } type ApiError struct { Field string Msg string } func msgForTag(field string, param string, tag string) string { switch tag { case "min": return fmt.Sprintf("%s character min %s", field, param) default: return fmt.Sprintf("%s %s", field, tag) } } func (server *Server) createUser(ctx *gin.Context) { var req createUserRequest if err := ctx.ShouldBindJSON(&req); err != nil { if err != nil { var ve validator.ValidationErrors if errors.As(err, &ve) { out := make([]ApiError, len(ve)) for i, fe := range ve { out[i] = ApiError{fe.Field(), msgForTag(fe.Field(), fe.Param(), fe.Tag())} } ctx.JSON(http.StatusBadRequest, gin.H{"errors": out}) } return } } hashedPassword, err := util.HashPassword(req.Password) if err != nil { ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Something went wrong")) return } arg := db.CreateUserParams{ Username: req.Username, Password: hashedPassword, } user, err := server.store.CreateUser(ctx, arg) if err != nil { if pqErr, ok := err.(*pq.Error); ok { switch pqErr.Code.Name() { case "foreign_key_violation", "unique_violation": ctx.JSON(http.StatusConflict, ErrorResponse(err, "Something went wrong while try to save")) } } ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Something went wrong")) return } res := createUserResponse{ ID: user.ID, Username: user.Username, AvatarPicture: user.AvatarPicture.String, BannedAt: sql.NullTime{Valid: user.BannedAt.Valid, Time: user.BannedAt.Time}, BannedUntil: sql.NullTime{Valid: user.BannedUntil.Valid, Time: user.BannedUntil.Time}, BanReason: user.BanReason.String, IsPermaban: user.IsPermaban, IsAdmin: user.IsAdmin, IsCritics: user.IsCritics, IsVerified: user.IsVerified, CreatedAt: sql.NullTime{Valid: true, Time: user.CreatedAt.Time}, UpdatedAt: sql.NullTime{Valid: true, Time: user.UpdatedAt.Time}, } ctx.JSON(http.StatusOK, res) }