Compare commits

...

2 Commits

Author SHA1 Message Date
Muyao CHEN
0dbf5c6234 fix: CHANGE NAMES AGAIN. Just want to be clearer
Some checks failed
Build and test / Build (push) Has been cancelled
2024-10-18 23:24:03 +02:00
Muyao CHEN
a55fd26f90 repo: add some more sql for events 2024-10-18 21:41:53 +02:00
19 changed files with 205 additions and 96 deletions

View File

@ -422,7 +422,7 @@ The following basic use cases are to be implemented at the first time.
- [X] A user signs up - [X] A user signs up
- [X] A user logs in - [X] A user logs in
- [X] A user lists their events (pagination) - [X] A user lists their events (pagination)
- [] A user sees the detail of an event (description, members, amount) - [X] A user sees the detail of an event (description, members, amount)
- [] A user sees the expenses of an event (total amount, personal expenses, pagination) - [] A user sees the expenses of an event (total amount, personal expenses, pagination)
- [] A user sees the detail of an expense: (time, amount, payers, recipients) - [] A user sees the detail of an expense: (time, amount, payers, recipients)
- [] A user adds an expense - [] A user adds an expense
@ -431,13 +431,18 @@ The following basic use cases are to be implemented at the first time.
- [] A user restore a deleted expense - [] A user restore a deleted expense
- [] A user can pay the debt to other members - [] A user can pay the debt to other members
- [X] A user creates an event (and participate to it) - [X] A user creates an event (and participate to it)
- [] A user updates the event info - [X] A user updates the event info
- [] A user invites another user by sending a mail with a token. - [X] A user invites another user by sending a mail with a token.
- [] A user joins an event by accepting an invitation - [X] A user joins an event by accepting an invitation
- [] A user quits an event (they cannot actually, but we can make as if they quitted) - [] ~A user quits an event (they cannot actually, but we can make as if they quitted)~
**No we can't quit!**
- [] A user cannot see other user's information - [] A user cannot see other user's information
- [] A user cannot see the events that they didn't participated in. - [] A user cannot see the events that they didn't participated in.
For the second stage:
- [] A user can archive an event
With those functionalities, there will be an usable product. And then we can With those functionalities, there will be an usable product. And then we can
work on other aspects. For example: work on other aspects. For example:

View File

@ -64,7 +64,7 @@ type createParams struct {
// Since we use JWT method, this token is not stored anywhere. Thus it // Since we use JWT method, this token is not stored anywhere. Thus it
// stops at the controller level. // stops at the controller level.
func (sc *SessionController) Create(ctx *gin.Context) { func (sc *SessionController) Create(ctx *gin.Context) {
var user model.UserExistDTO var user model.UserExistRequest
if err := ctx.Bind(&user); err != nil { if err := ctx.Bind(&user); err != nil {
log.ErrorLog("param error", "err", err) log.ErrorLog("param error", "err", err)

View File

@ -37,12 +37,12 @@ func NewtestUserUsecase() usecase.User {
func (*testUserUsecase) Create( func (*testUserUsecase) Create(
ctx context.Context, ctx context.Context,
u *model.UserCreateDTO, u *model.UserCreateRequest,
) (*model.UserInfoVO, error) { ) (*model.UserInfoResponse, error) {
return nil, nil return nil, nil
} }
func (*testUserUsecase) Exist(ctx context.Context, u *model.UserExistDTO) error { func (*testUserUsecase) Exist(ctx context.Context, u *model.UserExistRequest) error {
switch u.Email { switch u.Email {
case "a@b.c": case "a@b.c":
if u.Password == "strong password" { if u.Password == "strong password" {
@ -57,10 +57,10 @@ func (*testUserUsecase) Exist(ctx context.Context, u *model.UserExistDTO) error
return nil return nil
} }
func (*testUserUsecase) GetUserBaseVOByID( func (*testUserUsecase) GetUserBaseResponseByID(
ctx context.Context, ctx context.Context,
userID int, userID int,
) (*model.UserBaseVO, error) { ) (*model.UserBaseResponse, error) {
// TODO: // TODO:
return nil, nil return nil, nil
} }

View File

@ -57,14 +57,14 @@ func NewUserController(us usecase.User) User {
} }
func (uc *UserController) Create(ctx core.Context) { func (uc *UserController) Create(ctx core.Context) {
var userDTO model.UserCreateDTO var userRequest model.UserCreateRequest
if err := ctx.Bind(&userDTO); err != nil { if err := ctx.Bind(&userRequest); err != nil {
core.WriteResponse(ctx, UserParamsErr, nil) core.WriteResponse(ctx, UserParamsErr, nil)
return return
} }
_, err := uc.userUsecase.Create(ctx, &userDTO) _, err := uc.userUsecase.Create(ctx, &userRequest)
if err != nil { if err != nil {
core.WriteResponse(ctx, err, nil) core.WriteResponse(ctx, err, nil)
return return

View File

@ -56,3 +56,9 @@ GROUP BY
e.total_amount, e.default_currency, e.total_amount, e.default_currency,
o.id, o.first_name, o.last_name; o.id, o.first_name, o.last_name;
-- name: UpdateEventByID :exec
UPDATE "event"
SET name = $2, description = $3, updated_at = $4
WHERE id = $1;

View File

@ -172,3 +172,26 @@ func (q *Queries) ListEventsByUserID(ctx context.Context, userID int32) ([]ListE
} }
return items, nil return items, nil
} }
const updateEventByID = `-- name: UpdateEventByID :exec
UPDATE "event"
SET name = $2, description = $3, updated_at = $4
WHERE id = $1
`
type UpdateEventByIDParams struct {
ID int32
Name string
Description sql.NullString
UpdatedAt time.Time
}
func (q *Queries) UpdateEventByID(ctx context.Context, arg UpdateEventByIDParams) error {
_, err := q.db.ExecContext(ctx, updateEventByID,
arg.ID,
arg.Name,
arg.Description,
arg.UpdatedAt,
)
return err
}

View File

@ -5,6 +5,7 @@
package sqlc package sqlc
import ( import (
"database/sql"
"time" "time"
) )
@ -15,6 +16,26 @@ type Admin struct {
AccessLevel int32 AccessLevel int32
} }
type Event struct {
ID int32
Name string
Description sql.NullString
DefaultCurrency string
OwnerID int32
CreatedAt time.Time
UpdatedAt time.Time
TotalAmount sql.NullInt32
}
type Participation struct {
ID int32
UserID int32
EventID int32
InvitedByUserID sql.NullInt32
CreatedAt time.Time
UpdatedAt time.Time
}
type User struct { type User struct {
ID int32 ID int32
Email string Email string

View File

@ -50,8 +50,8 @@ func NewUserRepository(db *sql.DB) repo.UserRepository {
func (ur *userRepository) Create( func (ur *userRepository) Create(
ctx context.Context, ctx context.Context,
transaction interface{}, transaction interface{},
u *model.UserPO, u *model.UserEntity ,
) (*model.UserPO, error) { ) (*model.UserEntity , error) {
timeoutCtx, cancel := context.WithTimeout(ctx, insertTimeout) timeoutCtx, cancel := context.WithTimeout(ctx, insertTimeout)
defer cancel() defer cancel()
@ -76,7 +76,7 @@ func (ur *userRepository) Create(
return nil, err return nil, err
} }
return &model.UserPO{ return &model.UserEntity {
ID: int(userDB.ID), ID: int(userDB.ID),
Email: userDB.Email, Email: userDB.Email,
FirstName: userDB.FirstName, FirstName: userDB.FirstName,
@ -88,7 +88,7 @@ func (ur *userRepository) Create(
} }
// GetByEmail if not found, return nil for user but not error. // GetByEmail if not found, return nil for user but not error.
func (ur *userRepository) GetByEmail(ctx context.Context, email string) (*model.UserPO, error) { func (ur *userRepository) GetByEmail(ctx context.Context, email string) (*model.UserEntity , error) {
queries := sqlc.New(ur.db) queries := sqlc.New(ur.db)
userDB, err := queries.GetUserByEmail(ctx, email) userDB, err := queries.GetUserByEmail(ctx, email)
if errors.Is(err, pgx.ErrNoRows) { if errors.Is(err, pgx.ErrNoRows) {
@ -98,7 +98,7 @@ func (ur *userRepository) GetByEmail(ctx context.Context, email string) (*model.
return nil, err return nil, err
} }
return &model.UserPO{ return &model.UserEntity {
ID: int(userDB.ID), ID: int(userDB.ID),
Email: userDB.Email, Email: userDB.Email,
FirstName: userDB.FirstName, FirstName: userDB.FirstName,
@ -109,7 +109,7 @@ func (ur *userRepository) GetByEmail(ctx context.Context, email string) (*model.
}, nil }, nil
} }
func (ur *userRepository) GetByID(ctx context.Context, id int) (*model.UserPO, error) { func (ur *userRepository) GetByID(ctx context.Context, id int) (*model.UserEntity , error) {
queries := sqlc.New(ur.db) queries := sqlc.New(ur.db)
userDB, err := queries.GetUserByID(ctx, int32(id)) userDB, err := queries.GetUserByID(ctx, int32(id))
if errors.Is(err, pgx.ErrNoRows) { if errors.Is(err, pgx.ErrNoRows) {
@ -119,7 +119,7 @@ func (ur *userRepository) GetByID(ctx context.Context, id int) (*model.UserPO, e
return nil, err return nil, err
} }
return &model.UserPO{ return &model.UserEntity {
ID: int(userDB.ID), ID: int(userDB.ID),
Email: userDB.Email, Email: userDB.Email,
FirstName: userDB.FirstName, FirstName: userDB.FirstName,

View File

@ -24,9 +24,9 @@ package model
import "time" import "time"
// {{{ DTO Data Transfer Object (from controller to service) // {{{ Request Object (from controller to service)
type EventCreateDTO struct { type EventCreateRequest struct {
Name string `json:"name" binding:"requiered"` Name string `json:"name" binding:"requiered"`
Description string `json:"description"` Description string `json:"description"`
OwnerID int `json:"owner_id" binding:"requiered,number"` OwnerID int `json:"owner_id" binding:"requiered,number"`
@ -34,9 +34,17 @@ type EventCreateDTO struct {
} }
// }}} // }}}
// {{{ VO View Object (from service to controller) // {{{ Response View Object (from service to controller)
type EventInfoVO struct { type EventBaseItemResponse struct {
ID int
Name string
Description string
Owner *UserBaseResponse
CreatedAt time.Time
}
type EventInfoResponse struct {
ID int ID int
Name string Name string
@ -44,18 +52,26 @@ type EventInfoVO struct {
TotalAmount Money TotalAmount Money
Owner *UserBaseVO Owner *UserBaseResponse
CreatedAt time.Time CreatedAt time.Time
UpdatedAt time.Time UpdatedAt time.Time
Users []*UserBaseVO Users []*UserBaseResponse
} }
// }}} // }}}
// {{{ PO Persistant Object (Between the service and the repository) // {{{ Entity Persistant Object (Between the service and the repository)
type EventPO struct { type EventBaseItemEntity struct {
ID int
Name string
Description string
OwnerID int
CreatedAt time.Time
}
type EventEntity struct {
ID int ID int
Name string Name string

View File

@ -24,7 +24,7 @@ package model
import "time" import "time"
type ExpenseDTO struct { type ExpenseRequest struct {
Amount Money `json:"money" binding:"required,number"` Amount Money `json:"money" binding:"required,number"`
PayerIDs []int `json:"payer_ids" binding:"required"` PayerIDs []int `json:"payer_ids" binding:"required"`
RecipientIDs []int `json:"recipient_ids" binding:"required"` RecipientIDs []int `json:"recipient_ids" binding:"required"`
@ -32,7 +32,7 @@ type ExpenseDTO struct {
Detail ExpenseDetail `json:"detail"` Detail ExpenseDetail `json:"detail"`
} }
type ExpensePO struct { type ExpenseEntity struct {
ID int ID int
Amount int Amount int

View File

@ -24,7 +24,7 @@ package model
import "time" import "time"
type ParticipationPO Participation type ParticipationEntity Participation
// Participation is the association between Users and Events // Participation is the association between Users and Events
type Participation struct { type Participation struct {

View File

@ -24,7 +24,7 @@ package model
import "time" import "time"
type TransactionPO Transaction type TransactionEntity Transaction
// Transaction is the association between Expenses and Users // Transaction is the association between Expenses and Users
type Transaction struct { type Transaction struct {

View File

@ -24,31 +24,31 @@ package model
import "time" import "time"
// {{{ DTO Data Transfer Object (from controller to service) // {{{ Request (from controller to service)
type UserCreateDTO struct { type UserCreateRequest struct {
Email string `json:"email" binding:"required,email"` Email string `json:"email" binding:"required,email"`
FirstName string `json:"first_name" binding:"required"` FirstName string `json:"first_name" binding:"required"`
LastName string `json:"last_name" binding:"required"` LastName string `json:"last_name" binding:"required"`
Password string `json:"password" binding:"required"` Password string `json:"password" binding:"required"`
} }
type UserExistDTO struct { type UserExistRequest struct {
Email string `json:"email" binding:"required,email"` Email string `json:"email" binding:"required,email"`
Password string `json:"password" binding:"required"` Password string `json:"password" binding:"required"`
} }
// }}} // }}}
// {{{ VO View Object (from service to controller) // {{{ Response View Object (from service to controller)
type UserBaseVO struct { type UserBaseResponse struct {
ID int `json:"id"` ID int `json:"id"`
FirstName string `json:"first_name"` FirstName string `json:"first_name"`
LastName string `json:"last_name"` LastName string `json:"last_name"`
} }
type UserInfoVO struct { type UserInfoResponse struct {
// UserBaseVO // UserBaseResponse
ID int `json:"id"` ID int `json:"id"`
FirstName string `json:"first_name"` FirstName string `json:"first_name"`
LastName string `json:"last_name"` LastName string `json:"last_name"`
@ -59,9 +59,9 @@ type UserInfoVO struct {
} }
// }}} // }}}
// {{{ PO Persistant Object (Between the service and the repository) // {{{ Entity Persistant Object (Between the service and the repository)
type UserPO struct { type UserEntity struct {
ID int ID int
Email string Email string

View File

@ -29,19 +29,19 @@ import (
) )
type EventRepository interface { type EventRepository interface {
Create(ctx context.Context, evPO *model.EventPO) (*model.EventPO, error) Create(ctx context.Context, evEntity *model.EventEntity) (*model.EventEntity, error)
// UpdateInfo updates the event related information (name, descriptions) // UpdateInfo updates the event related information (name, descriptions)
UpdateInfo() UpdateInfo()
Delete() // XXX: Pay attention to the foreign key relationships Delete() // XXX: Pay attention to the foreign key relationships
GetByID() GetByID(ctx context.Context, eventID int) (*model.EventEntity, error)
ListExpensesByUserID() ListExpensesByUserID()
// related to events of a user // related to events of a user
ListEventsByUserID() ListEventsByUserID(ctx context.Context, userID int) ([]model.EventBaseItemEntity, error)
} }
type ExpenseRepository interface { type ExpenseRepository interface {
@ -55,6 +55,7 @@ type ExpenseRepository interface {
type ParticipationRepository interface { type ParticipationRepository interface {
Create() Create()
Delete() Delete()
CheckParticipation(ctx context.Context, userID, eventID int) error
} }
type TransactionRepository interface { type TransactionRepository interface {

View File

@ -29,7 +29,7 @@ import (
) )
type UserRepository interface { type UserRepository interface {
Create(ctx context.Context, transaction interface{}, u *model.UserPO) (*model.UserPO, error) Create(ctx context.Context, transaction interface{}, u *model.UserEntity ) (*model.UserEntity , error)
GetByEmail(ctx context.Context, email string) (*model.UserPO, error) GetByEmail(ctx context.Context, email string) (*model.UserEntity , error)
GetByID(ctx context.Context, id int) (*model.UserPO, error) GetByID(ctx context.Context, id int) (*model.UserEntity , error)
} }

View File

@ -23,8 +23,11 @@
package usecase package usecase
import ( import (
"net/http"
"git.vinchent.xyz/vinchent/howmuch/internal/howmuch/model" "git.vinchent.xyz/vinchent/howmuch/internal/howmuch/model"
"git.vinchent.xyz/vinchent/howmuch/internal/howmuch/usecase/repo" "git.vinchent.xyz/vinchent/howmuch/internal/howmuch/usecase/repo"
"git.vinchent.xyz/vinchent/howmuch/internal/pkg/errno"
"git.vinchent.xyz/vinchent/howmuch/internal/pkg/log" "git.vinchent.xyz/vinchent/howmuch/internal/pkg/log"
"golang.org/x/net/context" "golang.org/x/net/context"
) )
@ -39,6 +42,12 @@ type eventUsecase struct {
dbRepo repo.DBRepository dbRepo repo.DBRepository
} }
var ErrNoParticipation = &errno.Errno{
HTTP: http.StatusUnauthorized,
Code: errno.ErrorCode(errno.AuthFailureCode, "NoParticipation"),
Message: "user doesn't have access to this event",
}
// For the controller // For the controller
type Event interface{} type Event interface{}
@ -46,8 +55,8 @@ func NewEventUsecase(
uuc User, uuc User,
ev repo.EventRepository, ev repo.EventRepository,
ex repo.ExpenseRepository, ex repo.ExpenseRepository,
pa repo.ParticipationRepository, pa repo.ParticipationRepository, // XXX: Might be handled in event
tr repo.TransactionRepository, tr repo.TransactionRepository, // XXX: Might be handled in event
db repo.DBRepository, db repo.DBRepository,
) Event { ) Event {
return &eventUsecase{uuc, ev, ex, pa, tr, db} return &eventUsecase{uuc, ev, ex, pa, tr, db}
@ -55,22 +64,22 @@ func NewEventUsecase(
func (evuc *eventUsecase) CreateEvent( func (evuc *eventUsecase) CreateEvent(
ctx context.Context, ctx context.Context,
evDTO *model.EventCreateDTO, evRequest *model.EventCreateRequest,
) (*model.EventInfoVO, error) { ) (*model.EventInfoResponse, error) {
// transfer evDTO to PO // transfer evRequest to PO
evPO := &model.EventPO{ evEntity := &model.EventEntity{
Name: evDTO.Name, Name: evRequest.Name,
Description: evDTO.Description, Description: evRequest.Description,
OwnerID: evDTO.OwnerID, OwnerID: evRequest.OwnerID,
TotalAmount: 0, TotalAmount: 0,
DefaultCurrency: string(evDTO.DefaultCurrency), DefaultCurrency: string(evRequest.DefaultCurrency),
} }
data, err := evuc.dbRepo.Transaction( data, err := evuc.dbRepo.Transaction(
ctx, ctx,
func(txCtx context.Context, tx interface{}) (interface{}, error) { func(txCtx context.Context, tx interface{}) (interface{}, error) {
created, err := evuc.eventRepo.Create(ctx, evPO) created, err := evuc.eventRepo.Create(ctx, evEntity)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -84,12 +93,12 @@ func (evuc *eventUsecase) CreateEvent(
created.OwnerID, created.OwnerID,
) )
ownerVO, err := evuc.userUC.GetUserBaseVOByID(ctx, created.OwnerID) ownerResponse, err := evuc.userUC.GetUserBaseResponseByID(ctx, created.OwnerID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
evVO := &model.EventInfoVO{ evResponse := &model.EventInfoResponse{
ID: created.ID, ID: created.ID,
Name: created.Name, Name: created.Name,
Description: created.Description, Description: created.Description,
@ -97,16 +106,40 @@ func (evuc *eventUsecase) CreateEvent(
created.TotalAmount, created.TotalAmount,
model.Currency(created.DefaultCurrency), model.Currency(created.DefaultCurrency),
), ),
Owner: ownerVO, Owner: ownerResponse,
CreatedAt: created.CreatedAt, CreatedAt: created.CreatedAt,
} }
return evVO, err return evResponse, err
}) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
res := data.(*model.EventInfoVO) res := data.(*model.EventInfoResponse)
return res, err return res, err
} }
func (evuc *eventUsecase) ListEvents(
ctx context.Context,
userID int,
) ([]model.EventBaseItemResponse, error) {
return nil, nil
}
// GetEventDetail
func (evuc *eventUsecase) GetEventDetail(
ctx context.Context,
userID, eventID int,
) (*model.EventInfoResponse, error) {
// Check if the user has the right to get this event
err := evuc.participationRepo.CheckParticipation(ctx, userID, eventID)
if err != nil {
return nil, ErrNoParticipation
}
// Get the eventDetail
// TODO: This can also be put into the cache
return nil, nil
}

View File

@ -37,8 +37,8 @@ type TestUserRepository struct{}
func (tur *TestUserRepository) Create( func (tur *TestUserRepository) Create(
ctx context.Context, ctx context.Context,
transaction interface{}, transaction interface{},
u *model.UserPO, u *model.UserEntity,
) (*model.UserPO, error) { ) (*model.UserEntity, error) {
user := *u user := *u
user.ID = 123 user.ID = 123
@ -53,11 +53,11 @@ func (tur *TestUserRepository) Create(
func (tur *TestUserRepository) GetByEmail( func (tur *TestUserRepository) GetByEmail(
ctx context.Context, ctx context.Context,
email string, email string,
) (*model.UserPO, error) { ) (*model.UserEntity, error) {
hashedPwd, _ := bcrypt.GenerateFromPassword([]byte("strongHashed"), 12) hashedPwd, _ := bcrypt.GenerateFromPassword([]byte("strongHashed"), 12)
switch email { switch email {
case "a@b.c": case "a@b.c":
return &model.UserPO{ return &model.UserEntity{
ID: 123, ID: 123,
Email: "a@b.c", Email: "a@b.c",
Password: string(hashedPwd), Password: string(hashedPwd),
@ -71,11 +71,11 @@ func (tur *TestUserRepository) GetByEmail(
return nil, UserTestDummyErr return nil, UserTestDummyErr
} }
func (tur *TestUserRepository) GetByID(ctx context.Context, id int) (*model.UserPO, error) { func (tur *TestUserRepository) GetByID(ctx context.Context, id int) (*model.UserEntity, error) {
hashedPwd, _ := bcrypt.GenerateFromPassword([]byte("strongHashed"), 12) hashedPwd, _ := bcrypt.GenerateFromPassword([]byte("strongHashed"), 12)
switch id { switch id {
case 123: case 123:
return &model.UserPO{ return &model.UserEntity{
ID: 123, ID: 123,
Email: "a@b.c", Email: "a@b.c",
Password: string(hashedPwd), Password: string(hashedPwd),

View File

@ -60,9 +60,9 @@ type userUsecase struct {
} }
type User interface { type User interface {
Create(ctx context.Context, u *model.UserCreateDTO) (*model.UserInfoVO, error) Create(ctx context.Context, u *model.UserCreateRequest) (*model.UserInfoResponse, error)
Exist(ctx context.Context, u *model.UserExistDTO) error Exist(ctx context.Context, u *model.UserExistRequest) error
GetUserBaseVOByID(ctx context.Context, userID int) (*model.UserBaseVO, error) GetUserBaseResponseByID(ctx context.Context, userID int) (*model.UserBaseResponse, error)
} }
func NewUserUsecase(r repo.UserRepository, d repo.DBRepository) User { func NewUserUsecase(r repo.UserRepository, d repo.DBRepository) User {
@ -74,8 +74,8 @@ func NewUserUsecase(r repo.UserRepository, d repo.DBRepository) User {
func (uuc *userUsecase) Create( func (uuc *userUsecase) Create(
ctx context.Context, ctx context.Context,
u *model.UserCreateDTO, u *model.UserCreateRequest,
) (*model.UserInfoVO, error) { ) (*model.UserInfoResponse, error) {
// Hash the password // Hash the password
encrypted, err := bcrypt.GenerateFromPassword([]byte(u.Password), 12) encrypted, err := bcrypt.GenerateFromPassword([]byte(u.Password), 12)
if err != nil { if err != nil {
@ -86,7 +86,7 @@ func (uuc *userUsecase) Create(
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) {
created, err := uuc.userRepo.Create(txCtx, tx, &model.UserPO{ created, err := uuc.userRepo.Create(txCtx, tx, &model.UserEntity{
Email: u.Email, Email: u.Email,
Password: u.Password, Password: u.Password,
FirstName: u.FirstName, FirstName: u.FirstName,
@ -117,21 +117,21 @@ func (uuc *userUsecase) Create(
return nil, err return nil, err
} }
userPO := data.(*model.UserPO) userEntity := data.(*model.UserEntity)
user := &model.UserInfoVO{ user := &model.UserInfoResponse{
ID: userPO.ID, ID: userEntity.ID,
Email: userPO.Email, Email: userEntity.Email,
FirstName: userPO.FirstName, FirstName: userEntity.FirstName,
LastName: userPO.LastName, LastName: userEntity.LastName,
CreatedAt: userPO.CreatedAt, CreatedAt: userEntity.CreatedAt,
UpdatedAt: userPO.UpdatedAt, UpdatedAt: userEntity.UpdatedAt,
} }
return user, nil return user, nil
} }
func (uuc *userUsecase) Exist(ctx context.Context, u *model.UserExistDTO) error { func (uuc *userUsecase) Exist(ctx context.Context, u *model.UserExistRequest) error {
got, err := uuc.userRepo.GetByEmail(ctx, u.Email) got, err := uuc.userRepo.GetByEmail(ctx, u.Email)
// Any query error? // Any query error?
if err != nil { if err != nil {
@ -152,15 +152,19 @@ func (uuc *userUsecase) Exist(ctx context.Context, u *model.UserExistDTO) error
return nil return nil
} }
func (uuc *userUsecase) GetUserBaseVOByID( func (uuc *userUsecase) GetUserBaseResponseByID(
ctx context.Context, ctx context.Context,
userID int, userID int,
) (*model.UserBaseVO, error) { ) (*model.UserBaseResponse, error) {
// TODO: should try first to get from the cache
// If not exists, get from the DB. And then put back
// into the cache with a timeout.
// Refresh the cache when the user data is updated (for now it cannot be updated)
got, err := uuc.userRepo.GetByID(ctx, userID) got, err := uuc.userRepo.GetByID(ctx, userID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
userBaseVo := &model.UserBaseVO{ userBaseVo := &model.UserBaseResponse{
ID: got.ID, ID: got.ID,
FirstName: got.FirstName, FirstName: got.FirstName,
LastName: got.LastName, LastName: got.LastName,

View File

@ -35,13 +35,13 @@ func TestCreateUser(t *testing.T) {
t.Run("normal create", func(t *testing.T) { t.Run("normal create", func(t *testing.T) {
ctx := context.Background() ctx := context.Background()
userUsecase := NewUserUsecase(&repomock.TestUserRepository{}, &repomock.TestDBRepository{}) userUsecase := NewUserUsecase(&repomock.TestUserRepository{}, &repomock.TestDBRepository{})
input := &model.UserCreateDTO{ input := &model.UserCreateRequest{
Email: "a@b.c", Email: "a@b.c",
FirstName: "James", FirstName: "James",
LastName: "Bond", LastName: "Bond",
Password: "verystrong", Password: "verystrong",
} }
want := &model.UserInfoVO{ want := &model.UserInfoResponse{
ID: 123, ID: 123,
} }
@ -53,7 +53,7 @@ func TestCreateUser(t *testing.T) {
t.Run("duplicate create", func(t *testing.T) { t.Run("duplicate create", func(t *testing.T) {
ctx := context.Background() ctx := context.Background()
userUsecase := NewUserUsecase(&repomock.TestUserRepository{}, &repomock.TestDBRepository{}) userUsecase := NewUserUsecase(&repomock.TestUserRepository{}, &repomock.TestDBRepository{})
input := &model.UserCreateDTO{ input := &model.UserCreateRequest{
Email: "duplicate@error.com", Email: "duplicate@error.com",
FirstName: "James", FirstName: "James",
LastName: "Bond", LastName: "Bond",
@ -68,22 +68,22 @@ func TestCreateUser(t *testing.T) {
func TestUserExist(t *testing.T) { func TestUserExist(t *testing.T) {
testCases := []struct { testCases := []struct {
Name string Name string
User *model.UserExistDTO User *model.UserExistRequest
ExpErr error ExpErr error
}{ }{
{"user exists", &model.UserExistDTO{ {"user exists", &model.UserExistRequest{
Email: "a@b.c", Email: "a@b.c",
Password: "strongHashed", Password: "strongHashed",
}, nil}, }, nil},
{"query error", &model.UserExistDTO{ {"query error", &model.UserExistRequest{
Email: "query@error.com", Email: "query@error.com",
Password: "strongHashed", Password: "strongHashed",
}, repomock.UserTestDummyErr}, }, repomock.UserTestDummyErr},
{"user doesn not exist", &model.UserExistDTO{ {"user doesn not exist", &model.UserExistRequest{
Email: "inexist@error.com", Email: "inexist@error.com",
Password: "strongHashed", Password: "strongHashed",
}, UserNotExist}, }, UserNotExist},
{"wrong password", &model.UserExistDTO{ {"wrong password", &model.UserExistRequest{
Email: "a@b.c", Email: "a@b.c",
Password: "wrongHashed", Password: "wrongHashed",
}, UserWrongPassword}, }, UserWrongPassword},