fix: make user signup work for the minimum
A lot of work is still to be done ...
This commit is contained in:
parent
7b8abf8e5c
commit
344485d082
1
.gitignore
vendored
1
.gitignore
vendored
@ -25,3 +25,4 @@ go.work.sum
|
|||||||
# Custom
|
# Custom
|
||||||
/_output
|
/_output
|
||||||
/deployment/db_data
|
/deployment/db_data
|
||||||
|
/tmp/**
|
||||||
|
@ -39,7 +39,7 @@ tags:
|
|||||||
- name: user
|
- name: user
|
||||||
|
|
||||||
paths:
|
paths:
|
||||||
/signup:
|
/user/signup:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- user
|
- user
|
||||||
|
7
docs/error_code.md
Normal file
7
docs/error_code.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Platform level error code design
|
||||||
|
|
||||||
|
- InternalError
|
||||||
|
- InvalidParameter
|
||||||
|
- AuthFailure
|
||||||
|
- ResourceNotFound
|
||||||
|
- FailedOperation
|
@ -25,33 +25,66 @@ package controller
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"git.vinchent.xyz/vinchent/howmuch/internal/howmuch/model"
|
||||||
|
"git.vinchent.xyz/vinchent/howmuch/internal/howmuch/usecase/usecase"
|
||||||
"git.vinchent.xyz/vinchent/howmuch/internal/pkg/core"
|
"git.vinchent.xyz/vinchent/howmuch/internal/pkg/core"
|
||||||
|
"git.vinchent.xyz/vinchent/howmuch/internal/pkg/errno"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
// User is the user controller interface, it describes all the handlers
|
// User is the user controller interface, it describes all the handlers
|
||||||
// that need to be implemented for the /user endpoint
|
// that need to be implemented for the /user endpoint
|
||||||
type User interface {
|
type User interface {
|
||||||
Signup(core.Context)
|
Signup(core.Context)
|
||||||
UpdateInfo(core.Context)
|
UpdateInfo(*gin.Context)
|
||||||
Login(core.Context)
|
Login(*gin.Context)
|
||||||
Logout(core.Context)
|
Logout(*gin.Context)
|
||||||
ChangePassword(core.Context)
|
ChangePassword(*gin.Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserController struct{}
|
type UserController struct {
|
||||||
|
userUsecase usecase.User
|
||||||
|
}
|
||||||
|
|
||||||
|
var UserParamsErr = &errno.Errno{
|
||||||
|
HTTP: http.StatusBadRequest,
|
||||||
|
Code: errno.ErrorCode(errno.InvalidParameterCode, "UserParamsErr"),
|
||||||
|
Message: "user info is not correct",
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUserController(us usecase.User) User {
|
||||||
|
return &UserController{
|
||||||
|
userUsecase: us,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (uc *UserController) Signup(ctx core.Context) {
|
func (uc *UserController) Signup(ctx core.Context) {
|
||||||
ctx.JSON(http.StatusOK, "hello")
|
var params model.User
|
||||||
|
|
||||||
|
if err := ctx.Bind(¶ms); err != nil {
|
||||||
|
core.WriteResponse(ctx, UserParamsErr, nil)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uc *UserController) UpdateInfo(ctx core.Context) {
|
// TODO: check params validity (govalidator)
|
||||||
|
|
||||||
|
_, err := uc.userUsecase.Create(ctx, ¶ms)
|
||||||
|
if err != nil {
|
||||||
|
core.WriteResponse(ctx, err, nil)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uc *UserController) Login(ctx core.Context) {
|
core.WriteResponse(ctx, errno.OK, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uc *UserController) Logout(ctx core.Context) {
|
func (uc *UserController) UpdateInfo(ctx *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uc *UserController) ChangePassword(ctx core.Context) {
|
func (uc *UserController) Login(ctx *gin.Context) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (uc *UserController) Logout(ctx *gin.Context) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (uc *UserController) ChangePassword(ctx *gin.Context) {
|
||||||
}
|
}
|
||||||
|
@ -34,9 +34,6 @@ import (
|
|||||||
"github.com/jackc/pgx/v5/pgtype"
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Get business service model, convert to the DB model (generated by sqlc)
|
|
||||||
// To test repo's methods, I have to mock a pgx.Conn
|
|
||||||
|
|
||||||
type userRepository struct {
|
type userRepository struct {
|
||||||
db *pgx.Conn
|
db *pgx.Conn
|
||||||
}
|
}
|
||||||
@ -67,9 +64,9 @@ func (ur *userRepository) Create(
|
|||||||
UpdatedAt: pgtype.Timestamp{Time: time.Now(), Valid: true},
|
UpdatedAt: pgtype.Timestamp{Time: time.Now(), Valid: true},
|
||||||
}
|
}
|
||||||
|
|
||||||
tx, ok := transaction.(*pgx.Conn)
|
tx, ok := transaction.(pgx.Tx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("transaction is not a *pgx.Conn")
|
return nil, errors.New("transaction is not a pgx.Tx")
|
||||||
}
|
}
|
||||||
|
|
||||||
queries := sqlc.New(tx)
|
queries := sqlc.New(tx)
|
||||||
|
@ -48,7 +48,13 @@ func Routes(engine *gin.Engine, c controller.AppController) *gin.Engine {
|
|||||||
core.WriteResponse(ctx, errno.PageNotFoundErr, nil)
|
core.WriteResponse(ctx, errno.PageNotFoundErr, nil)
|
||||||
})
|
})
|
||||||
|
|
||||||
engine.POST("/signup", func(ctx *gin.Context) { c.User.Signup(ctx) })
|
v1 := engine.Group("/v1")
|
||||||
|
{
|
||||||
|
userV1 := v1.Group("/user")
|
||||||
|
{
|
||||||
|
userV1.POST("/signup", func(ctx *gin.Context) { c.User.Signup(ctx) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return engine
|
return engine
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,14 @@
|
|||||||
|
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
import "git.vinchent.xyz/vinchent/howmuch/internal/howmuch/adapter/controller"
|
import (
|
||||||
|
"git.vinchent.xyz/vinchent/howmuch/internal/howmuch/adapter/controller"
|
||||||
|
"git.vinchent.xyz/vinchent/howmuch/internal/howmuch/adapter/repo"
|
||||||
|
"git.vinchent.xyz/vinchent/howmuch/internal/howmuch/usecase/usecase"
|
||||||
|
)
|
||||||
|
|
||||||
// NewUserController returns a user controller's implementation
|
// NewUserController returns a user controller's implementation
|
||||||
func (r *registry) NewUserController() controller.User {
|
func (r *registry) NewUserController() controller.User {
|
||||||
return &controller.UserController{}
|
u := usecase.NewUserUsecase(repo.NewUserRepository(r.db), repo.NewDBRepository(r.db))
|
||||||
|
return controller.NewUserController(u)
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,10 @@ func (uuc *userUsecase) Create(ctx context.Context, u *model.User) (*model.User,
|
|||||||
data, err := uuc.dbRepo.Transaction(
|
data, err := uuc.dbRepo.Transaction(
|
||||||
ctx,
|
ctx,
|
||||||
func(txCtx context.Context, tx interface{}) (interface{}, error) {
|
func(txCtx context.Context, tx interface{}) (interface{}, error) {
|
||||||
|
// TODO: should check if the user exists
|
||||||
|
// DB will return an error since we have set email to UNIQUE.
|
||||||
|
// But we may not want to expose the exact db error.
|
||||||
|
|
||||||
u, err := uuc.userRepo.Create(txCtx, tx, u)
|
u, err := uuc.userRepo.Create(txCtx, tx, u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -68,11 +72,12 @@ func (uuc *userUsecase) Create(ctx context.Context, u *model.User) (*model.User,
|
|||||||
return u, err
|
return u, err
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
user := data.(*model.User)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// TODO: We should wrap the error at service level
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
user := data.(*model.User)
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,18 @@
|
|||||||
|
|
||||||
package core
|
package core
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
type Context interface {
|
type Context interface {
|
||||||
|
// Context
|
||||||
|
Deadline() (deadline time.Time, ok bool)
|
||||||
|
Done() <-chan struct{}
|
||||||
|
Err() error
|
||||||
|
Value(key any) any
|
||||||
|
|
||||||
|
// Request
|
||||||
|
Bind(obj any) error
|
||||||
|
|
||||||
|
// Response
|
||||||
JSON(code int, obj any)
|
JSON(code int, obj any)
|
||||||
}
|
}
|
||||||
|
@ -24,18 +24,28 @@ package errno
|
|||||||
|
|
||||||
import "net/http"
|
import "net/http"
|
||||||
|
|
||||||
|
type PlatformLevelErrCode string
|
||||||
|
|
||||||
|
const (
|
||||||
|
InternalErrorCode = "InternalError"
|
||||||
|
InvalidParameterCode = "InvalidParameter"
|
||||||
|
AuthFailureCode = "AuthFailure"
|
||||||
|
ResourceNotFoundCode = "ResourceNotFound"
|
||||||
|
FailedOperationCode = "FailedOperation"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
OK = &Errno{HTTP: http.StatusOK, Code: "", Message: ""}
|
OK = &Errno{HTTP: http.StatusOK, Code: "", Message: ""}
|
||||||
|
|
||||||
InternalServerErr = &Errno{
|
InternalServerErr = &Errno{
|
||||||
HTTP: http.StatusInternalServerError,
|
HTTP: http.StatusInternalServerError,
|
||||||
Code: "InternalError",
|
Code: InternalErrorCode,
|
||||||
Message: "Internal server error",
|
Message: "Internal server error",
|
||||||
}
|
}
|
||||||
|
|
||||||
PageNotFoundErr = &Errno{
|
PageNotFoundErr = &Errno{
|
||||||
HTTP: http.StatusNotFound,
|
HTTP: http.StatusNotFound,
|
||||||
Code: "ResourceNotFound.PageNotFound",
|
Code: ErrorCode(ResourceNotFoundCode, "PageNotFound"),
|
||||||
Message: "Page not found",
|
Message: "Page not found",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -28,6 +28,10 @@ type Errno struct {
|
|||||||
Message string
|
Message string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ErrorCode(platformErrCode string, resourceErrCode string) string {
|
||||||
|
return platformErrCode + "." + resourceErrCode
|
||||||
|
}
|
||||||
|
|
||||||
// Error implements Error() method in error interface
|
// Error implements Error() method in error interface
|
||||||
func (err *Errno) Error() string {
|
func (err *Errno) Error() string {
|
||||||
return err.Message
|
return err.Message
|
||||||
|
@ -1 +0,0 @@
|
|||||||
exit status 2exit status 2exit status 2exit status 2exit status 2
|
|
Loading…
Reference in New Issue
Block a user