fix user endpoint

This commit is contained in:
nochill 2023-09-12 17:07:57 +07:00
parent d1ba0251c0
commit dcacc9288d
4 changed files with 93 additions and 13 deletions

View File

@ -13,7 +13,7 @@ type Server struct {
config util.Config config util.Config
store db.Store store db.Store
tokenMaker token.Maker tokenMaker token.Maker
router *gin.Engine Router *gin.Engine
} }
func NewServer(config util.Config, store db.Store) (*Server, error) { func NewServer(config util.Config, store db.Store) (*Server, error) {
@ -35,11 +35,11 @@ func NewServer(config util.Config, store db.Store) (*Server, error) {
func (server *Server) getRoutes() { func (server *Server) getRoutes() {
router := gin.Default() router := gin.Default()
router.POST("/user/create", server.createUser) router.POST("/user/signup", server.createUser)
server.router = router server.Router = router
} }
func (server *Server) Start(address string) error { func (server *Server) Start(address string) error {
return server.router.Run(address) return server.Router.Run(address)
} }

View File

@ -1,27 +1,106 @@
package api package api
import ( import (
"database/sql"
"errors"
"fmt"
"net/http" "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/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/lib/pq"
) )
type CreateUserRequest struct { type createUserRequest struct {
ClientIpV4 string `json:"client_ip" binding:"required"` 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) { func (server *Server) createUser(ctx *gin.Context) {
var req CreateUserRequest var req createUserRequest
if err := ctx.ShouldBindJSON(&req); err != nil { if err := ctx.ShouldBindJSON(&req); err != nil {
ctx.JSON(http.StatusBadRequest, errorResponse(err, "")) if err != nil {
return 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
}
} }
err := server.store.CreateUser(ctx, req.ClientIpV4) hashedPassword, err := util.HashPassword(req.Password)
if err != nil { if err != nil {
ctx.JSON(http.StatusInternalServerError, errorResponse(err, "")) ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Something went wrong"))
return return
} }
ctx.Writer.WriteHeader(http.StatusOK) 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)
} }

View File

@ -9,6 +9,7 @@ import (
type Config struct { type Config struct {
DBDriver string `mapstructure:"DB_TYPE"` DBDriver string `mapstructure:"DB_TYPE"`
DBSource string `mapstructure:"DB_SOURCE"` DBSource string `mapstructure:"DB_SOURCE"`
DBSourceTest string `mapstructure:"DB_SOURCE_TEST"`
ServerAddress string `mapstructure:"SERVER_ADDRESS"` ServerAddress string `mapstructure:"SERVER_ADDRESS"`
TokenSymmetricKey string `mapstructure:"TOKEN_SYMMETRIC_KEY"` TokenSymmetricKey string `mapstructure:"TOKEN_SYMMETRIC_KEY"`
TokenDuration time.Duration `mapstructure:"TOKEN_DURATION"` TokenDuration time.Duration `mapstructure:"TOKEN_DURATION"`

View File

@ -9,7 +9,7 @@ import (
func HashPassword(password string) (string, error) { func HashPassword(password string) (string, error) {
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil { if err != nil {
return "", fmt.Errorf("Failed to hash password: %w", err) return "", fmt.Errorf("failed to hash password: %w", err)
} }
return string(hashedPassword), nil return string(hashedPassword), nil
} }