fix user endpoint
This commit is contained in:
parent
d1ba0251c0
commit
dcacc9288d
@ -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)
|
||||||
}
|
}
|
||||||
|
95
api/user.go
95
api/user.go
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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"`
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user