Compare commits
	
		
			1 Commits
		
	
	
		
			main
			...
			6f9ff9ab96
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 6f9ff9ab96 | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -25,3 +25,4 @@ go.work.sum
 | 
			
		||||
# Custom
 | 
			
		||||
/_output
 | 
			
		||||
/deployment/db_data
 | 
			
		||||
/tmp/**
 | 
			
		||||
 | 
			
		||||
@ -39,7 +39,7 @@ tags:
 | 
			
		||||
  - name: user
 | 
			
		||||
 | 
			
		||||
paths:
 | 
			
		||||
  /signup:
 | 
			
		||||
  /user/signup:
 | 
			
		||||
    post:
 | 
			
		||||
      tags:
 | 
			
		||||
        - 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 (
 | 
			
		||||
	"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/errno"
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// User is the user controller interface, it describes all the handlers
 | 
			
		||||
// that need to be implemented for the /user endpoint
 | 
			
		||||
type User interface {
 | 
			
		||||
	Signup(core.Context)
 | 
			
		||||
	UpdateInfo(core.Context)
 | 
			
		||||
	Login(core.Context)
 | 
			
		||||
	Logout(core.Context)
 | 
			
		||||
	ChangePassword(core.Context)
 | 
			
		||||
	UpdateInfo(*gin.Context)
 | 
			
		||||
	Login(*gin.Context)
 | 
			
		||||
	Logout(*gin.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) {
 | 
			
		||||
	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"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 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 {
 | 
			
		||||
	db *pgx.Conn
 | 
			
		||||
}
 | 
			
		||||
@ -67,9 +64,9 @@ func (ur *userRepository) Create(
 | 
			
		||||
		UpdatedAt: pgtype.Timestamp{Time: time.Now(), Valid: true},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tx, ok := transaction.(*pgx.Conn)
 | 
			
		||||
	tx, ok := transaction.(pgx.Tx)
 | 
			
		||||
	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)
 | 
			
		||||
 | 
			
		||||
@ -48,7 +48,13 @@ func Routes(engine *gin.Engine, c controller.AppController) *gin.Engine {
 | 
			
		||||
		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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -22,9 +22,14 @@
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
func (r *registry) NewUserController() controller.User {
 | 
			
		||||
	return &controller.UserController{}
 | 
			
		||||
	u := usecase.NewUserUsecase(repo.NewUserRepository(r.db), repo.NewDBRepository(r.db))
 | 
			
		||||
	return controller.NewUserController(u)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -68,11 +68,11 @@ func (uuc *userUsecase) Create(ctx context.Context, u *model.User) (*model.User,
 | 
			
		||||
			return u, err
 | 
			
		||||
		},
 | 
			
		||||
	)
 | 
			
		||||
	user := data.(*model.User)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	user := data.(*model.User)
 | 
			
		||||
 | 
			
		||||
	return user, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -22,6 +22,18 @@
 | 
			
		||||
 | 
			
		||||
package core
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -24,18 +24,28 @@ package errno
 | 
			
		||||
 | 
			
		||||
import "net/http"
 | 
			
		||||
 | 
			
		||||
type PlatformLevelErrCode string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	InternalErrorCode    = "InternalError"
 | 
			
		||||
	InvalidParameterCode = "InvalidParameter"
 | 
			
		||||
	AuthFailureCode      = "AuthFailure"
 | 
			
		||||
	ResourceNotFoundCode = "ResourceNotFound"
 | 
			
		||||
	FailedOperationCode  = "FailedOperation"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	OK = &Errno{HTTP: http.StatusOK, Code: "", Message: ""}
 | 
			
		||||
 | 
			
		||||
	InternalServerErr = &Errno{
 | 
			
		||||
		HTTP:    http.StatusInternalServerError,
 | 
			
		||||
		Code:    "InternalError",
 | 
			
		||||
		Code:    InternalErrorCode,
 | 
			
		||||
		Message: "Internal server error",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	PageNotFoundErr = &Errno{
 | 
			
		||||
		HTTP:    http.StatusNotFound,
 | 
			
		||||
		Code:    "ResourceNotFound.PageNotFound",
 | 
			
		||||
		Code:    ErrorCode(ResourceNotFoundCode, "PageNotFound"),
 | 
			
		||||
		Message: "Page not found",
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@ -28,6 +28,10 @@ type Errno struct {
 | 
			
		||||
	Message string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ErrorCode(platformErrCode string, resourceErrCode string) string {
 | 
			
		||||
	return platformErrCode + "." + resourceErrCode
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Error implements Error() method in error interface
 | 
			
		||||
func (err *Errno) Error() string {
 | 
			
		||||
	return err.Message
 | 
			
		||||
 | 
			
		||||
@ -1 +0,0 @@
 | 
			
		||||
exit status 2exit status 2exit status 2exit status 2exit status 2
 | 
			
		||||
		Reference in New Issue
	
	Block a user