From cd3b103b46894861e1cbb47acb29d5988b350bc9 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Fri, 5 Jan 2024 23:02:08 +0700 Subject: [PATCH 01/41] feat: usersvc findone --- src/app/constant/error.constant.go | 2 + src/app/dto/user.dto.go | 12 +++--- src/app/handler/user/user.handler.go | 5 ++- src/app/service/user/user.service.go | 55 +++++++++++++++++++++++++-- src/mocks/service/image/image.mock.go | 24 ++++++------ src/mocks/service/pet/pet.mock.go | 19 ++++----- src/mocks/service/user/user.mock.go | 6 +-- src/mocks/user/user.mock.go | 2 +- src/pkg/service/user/user.service.go | 4 +- 9 files changed, 88 insertions(+), 41 deletions(-) diff --git a/src/app/constant/error.constant.go b/src/app/constant/error.constant.go index cf607bc..fe4edb8 100644 --- a/src/app/constant/error.constant.go +++ b/src/app/constant/error.constant.go @@ -11,3 +11,5 @@ const UnavailableServiceMessage = "Unavailable Service" const PetNotFoundMessage = "Pet not found" const InvalidArgument = "Invalid Argument" + +const UserNotFoundMessage = "User not found" diff --git a/src/app/dto/user.dto.go b/src/app/dto/user.dto.go index 30d1320..0658faa 100644 --- a/src/app/dto/user.dto.go +++ b/src/app/dto/user.dto.go @@ -1,13 +1,13 @@ package dto -type UserDto struct { - Email string `json:"email" validate:"required,email"` - Password string `json:"password" validate:"required,gte=6,lte=30"` - Firstname string `json:"firstname" validate:"required"` - Lastname string `json:"lastname" validate:"required"` +type FindOneUserResponse struct { + Id string `json:"id"` + Email string `json:"email"` + Firstname string `json:"firstname"` + Lastname string `json:"lastname"` } -type UpdateUserDto struct { +type UpdateUserRequest struct { Password string `json:"password" validate:"required,gte=6,lte=30"` Firstname string `json:"firstname" validate:"required"` Lastname string `json:"lastname" validate:"required"` diff --git a/src/app/handler/user/user.handler.go b/src/app/handler/user/user.handler.go index 9e25ed6..3ac1e8b 100644 --- a/src/app/handler/user/user.handler.go +++ b/src/app/handler/user/user.handler.go @@ -1,11 +1,12 @@ package user import ( + "net/http" + "github.com/isd-sgcu/johnjud-gateway/src/app/dto" "github.com/isd-sgcu/johnjud-gateway/src/app/router" "github.com/isd-sgcu/johnjud-gateway/src/app/validator" "github.com/isd-sgcu/johnjud-gateway/src/pkg/service/user" - "net/http" ) type Handler struct { @@ -41,7 +42,7 @@ func (h *Handler) FindOne(c *router.FiberCtx) { func (h *Handler) Update(c *router.FiberCtx) { usrId := c.UserID() - usrDto := dto.UpdateUserDto{} + usrDto := dto.UpdateUserRequest{} err := c.Bind(&usrDto) if err != nil { diff --git a/src/app/service/user/user.service.go b/src/app/service/user/user.service.go index 382bb3f..76d8abc 100644 --- a/src/app/service/user/user.service.go +++ b/src/app/service/user/user.service.go @@ -1,8 +1,16 @@ package user import ( + "context" + "net/http" + "time" + + "github.com/isd-sgcu/johnjud-gateway/src/app/constant" "github.com/isd-sgcu/johnjud-gateway/src/app/dto" proto "github.com/isd-sgcu/johnjud-go-proto/johnjud/auth/user/v1" + "github.com/rs/zerolog/log" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) type Service struct { @@ -15,10 +23,51 @@ func NewService(client proto.UserServiceClient) *Service { } } -func (s *Service) FindOne(id string) (*proto.User, *dto.ResponseErr) { - return nil, nil +func (s *Service) FindOne(id string) (*dto.FindOneUserResponse, *dto.ResponseErr) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + response, err := s.client.FindOne(ctx, &proto.FindOneUserRequest{ + Id: id, + }) + if err != nil { + st, _ := status.FromError(err) + log.Error(). + Err(err). + Str("service", "user"). + Str("module", "find one"). + Msg(st.Message()) + switch st.Code() { + case codes.NotFound: + return nil, &dto.ResponseErr{ + StatusCode: http.StatusNotFound, + Message: constant.UserNotFoundMessage, + Data: nil, + } + + case codes.Unavailable: + return nil, &dto.ResponseErr{ + StatusCode: http.StatusServiceUnavailable, + Message: constant.UnavailableServiceMessage, + Data: nil, + } + default: + return nil, &dto.ResponseErr{ + StatusCode: http.StatusInternalServerError, + Message: constant.InternalErrorMessage, + Data: nil, + } + } + } + + return &dto.FindOneUserResponse{ + Id: response.User.Id, + Firstname: response.User.Firstname, + Lastname: response.User.Lastname, + Email: response.User.Email, + }, nil } -func (s *Service) Update(id string, in *dto.UpdateUserDto) (*proto.User, *dto.ResponseErr) { +func (s *Service) Update(id string, in *dto.UpdateUserRequest) (*proto.User, *dto.ResponseErr) { return nil, nil } diff --git a/src/mocks/service/image/image.mock.go b/src/mocks/service/image/image.mock.go index 09a1ae0..c09925a 100644 --- a/src/mocks/service/image/image.mock.go +++ b/src/mocks/service/image/image.mock.go @@ -36,46 +36,46 @@ func (m *MockService) EXPECT() *MockServiceMockRecorder { } // Delete mocks base method. -func (m *MockService) Delete(id string) (bool, *dto.ResponseErr) { +func (m *MockService) Delete(arg0 string) (bool, *dto.ResponseErr) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Delete", id) + ret := m.ctrl.Call(m, "Delete", arg0) ret0, _ := ret[0].(bool) ret1, _ := ret[1].(*dto.ResponseErr) return ret0, ret1 } // Delete indicates an expected call of Delete. -func (mr *MockServiceMockRecorder) Delete(id interface{}) *gomock.Call { +func (mr *MockServiceMockRecorder) Delete(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockService)(nil).Delete), id) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockService)(nil).Delete), arg0) } // FindByPetId mocks base method. -func (m *MockService) FindByPetId(id string) ([]*v1.Image, *dto.ResponseErr) { +func (m *MockService) FindByPetId(arg0 string) ([]*v1.Image, *dto.ResponseErr) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FindByPetId", id) + ret := m.ctrl.Call(m, "FindByPetId", arg0) ret0, _ := ret[0].([]*v1.Image) ret1, _ := ret[1].(*dto.ResponseErr) return ret0, ret1 } // FindByPetId indicates an expected call of FindByPetId. -func (mr *MockServiceMockRecorder) FindByPetId(id interface{}) *gomock.Call { +func (mr *MockServiceMockRecorder) FindByPetId(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindByPetId", reflect.TypeOf((*MockService)(nil).FindByPetId), id) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindByPetId", reflect.TypeOf((*MockService)(nil).FindByPetId), arg0) } // Upload mocks base method. -func (m *MockService) Upload(in *dto.ImageDto) (*v1.Image, *dto.ResponseErr) { +func (m *MockService) Upload(arg0 *dto.ImageDto) (*v1.Image, *dto.ResponseErr) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Upload", in) + ret := m.ctrl.Call(m, "Upload", arg0) ret0, _ := ret[0].(*v1.Image) ret1, _ := ret[1].(*dto.ResponseErr) return ret0, ret1 } // Upload indicates an expected call of Upload. -func (mr *MockServiceMockRecorder) Upload(in interface{}) *gomock.Call { +func (mr *MockServiceMockRecorder) Upload(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Upload", reflect.TypeOf((*MockService)(nil).Upload), in) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Upload", reflect.TypeOf((*MockService)(nil).Upload), arg0) } diff --git a/src/mocks/service/pet/pet.mock.go b/src/mocks/service/pet/pet.mock.go index 1673704..b0e81c5 100644 --- a/src/mocks/service/pet/pet.mock.go +++ b/src/mocks/service/pet/pet.mock.go @@ -1,10 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. // Source: ./src/pkg/service/pet/pet.service.go -// -// Generated by this command: -// -// mockgen -source ./src/pkg/service/pet/pet.service.go -destination ./src/mocks/service/pet/pet.mock.go -// // Package mock_pet is a generated GoMock package. package mock_pet @@ -12,8 +7,8 @@ package mock_pet import ( reflect "reflect" - dto "github.com/isd-sgcu/johnjud-gateway/src/app/dto" gomock "github.com/golang/mock/gomock" + dto "github.com/isd-sgcu/johnjud-gateway/src/app/dto" ) // MockService is a mock of Service interface. @@ -49,7 +44,7 @@ func (m *MockService) Adopt(arg0 *dto.AdoptDto) (bool, *dto.ResponseErr) { } // Adopt indicates an expected call of Adopt. -func (mr *MockServiceMockRecorder) Adopt(arg0 any) *gomock.Call { +func (mr *MockServiceMockRecorder) Adopt(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Adopt", reflect.TypeOf((*MockService)(nil).Adopt), arg0) } @@ -64,7 +59,7 @@ func (m *MockService) ChangeView(arg0 string, arg1 *dto.ChangeViewPetRequest) (* } // ChangeView indicates an expected call of ChangeView. -func (mr *MockServiceMockRecorder) ChangeView(arg0, arg1 any) *gomock.Call { +func (mr *MockServiceMockRecorder) ChangeView(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeView", reflect.TypeOf((*MockService)(nil).ChangeView), arg0, arg1) } @@ -79,7 +74,7 @@ func (m *MockService) Create(arg0 *dto.CreatePetRequest) (*dto.PetResponse, *dto } // Create indicates an expected call of Create. -func (mr *MockServiceMockRecorder) Create(arg0 any) *gomock.Call { +func (mr *MockServiceMockRecorder) Create(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockService)(nil).Create), arg0) } @@ -94,7 +89,7 @@ func (m *MockService) Delete(arg0 string) (*dto.DeleteResponse, *dto.ResponseErr } // Delete indicates an expected call of Delete. -func (mr *MockServiceMockRecorder) Delete(arg0 any) *gomock.Call { +func (mr *MockServiceMockRecorder) Delete(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockService)(nil).Delete), arg0) } @@ -124,7 +119,7 @@ func (m *MockService) FindOne(arg0 string) (*dto.PetResponse, *dto.ResponseErr) } // FindOne indicates an expected call of FindOne. -func (mr *MockServiceMockRecorder) FindOne(arg0 any) *gomock.Call { +func (mr *MockServiceMockRecorder) FindOne(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOne", reflect.TypeOf((*MockService)(nil).FindOne), arg0) } @@ -139,7 +134,7 @@ func (m *MockService) Update(arg0 string, arg1 *dto.UpdatePetRequest) (*dto.PetR } // Update indicates an expected call of Update. -func (mr *MockServiceMockRecorder) Update(arg0, arg1 any) *gomock.Call { +func (mr *MockServiceMockRecorder) Update(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockService)(nil).Update), arg0, arg1) } diff --git a/src/mocks/service/user/user.mock.go b/src/mocks/service/user/user.mock.go index daa4fdb..581da09 100644 --- a/src/mocks/service/user/user.mock.go +++ b/src/mocks/service/user/user.mock.go @@ -36,10 +36,10 @@ func (m *MockService) EXPECT() *MockServiceMockRecorder { } // FindOne mocks base method. -func (m *MockService) FindOne(arg0 string) (*v1.User, *dto.ResponseErr) { +func (m *MockService) FindOne(arg0 string) (*dto.FindOneUserResponse, *dto.ResponseErr) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "FindOne", arg0) - ret0, _ := ret[0].(*v1.User) + ret0, _ := ret[0].(*dto.FindOneUserResponse) ret1, _ := ret[1].(*dto.ResponseErr) return ret0, ret1 } @@ -51,7 +51,7 @@ func (mr *MockServiceMockRecorder) FindOne(arg0 interface{}) *gomock.Call { } // Update mocks base method. -func (m *MockService) Update(arg0 string, arg1 *dto.UpdateUserDto) (*v1.User, *dto.ResponseErr) { +func (m *MockService) Update(arg0 string, arg1 *dto.UpdateUserRequest) (*v1.User, *dto.ResponseErr) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Update", arg0, arg1) ret0, _ := ret[0].(*v1.User) diff --git a/src/mocks/user/user.mock.go b/src/mocks/user/user.mock.go index 909dab8..b5a4a70 100644 --- a/src/mocks/user/user.mock.go +++ b/src/mocks/user/user.mock.go @@ -27,7 +27,7 @@ func (s *ServiceMock) FindOne(id string) (result *user_proto.User, err *dto.Resp return } -func (s *ServiceMock) Update(id string, in *dto.UpdateUserDto) (result *user_proto.User, err *dto.ResponseErr) { +func (s *ServiceMock) Update(id string, in *dto.UpdateUserRequest) (result *user_proto.User, err *dto.ResponseErr) { args := s.Called(id, in) if args.Get(0) != nil { diff --git a/src/pkg/service/user/user.service.go b/src/pkg/service/user/user.service.go index 1002d1d..99d6802 100644 --- a/src/pkg/service/user/user.service.go +++ b/src/pkg/service/user/user.service.go @@ -6,6 +6,6 @@ import ( ) type Service interface { - FindOne(string) (*user_proto.User, *dto.ResponseErr) - Update(string, *dto.UpdateUserDto) (*user_proto.User, *dto.ResponseErr) + FindOne(string) (*dto.FindOneUserResponse, *dto.ResponseErr) + Update(string, *dto.UpdateUserRequest) (*user_proto.User, *dto.ResponseErr) } From ce0e52f094ba98f6f0d50f2e03934792f55286bd Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Fri, 5 Jan 2024 23:03:11 +0700 Subject: [PATCH 02/41] fix: typo --- src/app/service/pet/pet.service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/service/pet/pet.service.go b/src/app/service/pet/pet.service.go index 147b22c..fe0b4c7 100644 --- a/src/app/service/pet/pet.service.go +++ b/src/app/service/pet/pet.service.go @@ -94,7 +94,7 @@ func (s *Service) FindOne(id string) (result *dto.PetResponse, err *dto.Response return findOneResponse, nil } -func (s *Service) Create(in *dto.CreatePetRequest) (ressult *dto.PetResponse, err *dto.ResponseErr) { +func (s *Service) Create(in *dto.CreatePetRequest) (result *dto.PetResponse, err *dto.ResponseErr) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() From dc549036e8b81607e94a76335735043fe9739450 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Fri, 5 Jan 2024 23:11:59 +0700 Subject: [PATCH 03/41] feat: usersvc update --- src/app/dto/user.dto.go | 7 +++++ src/app/service/user/user.service.go | 47 ++++++++++++++++++++++++++-- src/mocks/service/user/user.mock.go | 5 ++- src/pkg/service/user/user.service.go | 3 +- 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/app/dto/user.dto.go b/src/app/dto/user.dto.go index 0658faa..b2e67ed 100644 --- a/src/app/dto/user.dto.go +++ b/src/app/dto/user.dto.go @@ -12,3 +12,10 @@ type UpdateUserRequest struct { Firstname string `json:"firstname" validate:"required"` Lastname string `json:"lastname" validate:"required"` } + +type UpdateUserResponse struct { + Id string `json:"id"` + Email string `json:"email"` + Firstname string `json:"firstname"` + Lastname string `json:"lastname"` +} diff --git a/src/app/service/user/user.service.go b/src/app/service/user/user.service.go index 76d8abc..24f6f3a 100644 --- a/src/app/service/user/user.service.go +++ b/src/app/service/user/user.service.go @@ -68,6 +68,49 @@ func (s *Service) FindOne(id string) (*dto.FindOneUserResponse, *dto.ResponseErr }, nil } -func (s *Service) Update(id string, in *dto.UpdateUserRequest) (*proto.User, *dto.ResponseErr) { - return nil, nil +func (s *Service) Update(id string, in *dto.UpdateUserRequest) (*dto.UpdateUserResponse, *dto.ResponseErr) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + response, err := s.client.Update(ctx, &proto.UpdateUserRequest{ + Id: id, + Firstname: in.Firstname, + Lastname: in.Lastname, + }) + if err != nil { + st, _ := status.FromError(err) + log.Error(). + Err(err). + Str("service", "user"). + Str("module", "update"). + Msg(st.Message()) + switch st.Code() { + case codes.NotFound: + return nil, &dto.ResponseErr{ + StatusCode: http.StatusNotFound, + Message: constant.UserNotFoundMessage, + Data: nil, + } + + case codes.Unavailable: + return nil, &dto.ResponseErr{ + StatusCode: http.StatusServiceUnavailable, + Message: constant.UnavailableServiceMessage, + Data: nil, + } + default: + return nil, &dto.ResponseErr{ + StatusCode: http.StatusInternalServerError, + Message: constant.InternalErrorMessage, + Data: nil, + } + } + } + + return &dto.UpdateUserResponse{ + Id: response.User.Id, + Firstname: response.User.Firstname, + Lastname: response.User.Lastname, + Email: response.User.Email, + }, nil } diff --git a/src/mocks/service/user/user.mock.go b/src/mocks/service/user/user.mock.go index 581da09..92f7776 100644 --- a/src/mocks/service/user/user.mock.go +++ b/src/mocks/service/user/user.mock.go @@ -9,7 +9,6 @@ import ( gomock "github.com/golang/mock/gomock" dto "github.com/isd-sgcu/johnjud-gateway/src/app/dto" - v1 "github.com/isd-sgcu/johnjud-go-proto/johnjud/auth/user/v1" ) // MockService is a mock of Service interface. @@ -51,10 +50,10 @@ func (mr *MockServiceMockRecorder) FindOne(arg0 interface{}) *gomock.Call { } // Update mocks base method. -func (m *MockService) Update(arg0 string, arg1 *dto.UpdateUserRequest) (*v1.User, *dto.ResponseErr) { +func (m *MockService) Update(arg0 string, arg1 *dto.UpdateUserRequest) (*dto.UpdateUserResponse, *dto.ResponseErr) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Update", arg0, arg1) - ret0, _ := ret[0].(*v1.User) + ret0, _ := ret[0].(*dto.UpdateUserResponse) ret1, _ := ret[1].(*dto.ResponseErr) return ret0, ret1 } diff --git a/src/pkg/service/user/user.service.go b/src/pkg/service/user/user.service.go index 99d6802..a3bae68 100644 --- a/src/pkg/service/user/user.service.go +++ b/src/pkg/service/user/user.service.go @@ -2,10 +2,9 @@ package user import ( "github.com/isd-sgcu/johnjud-gateway/src/app/dto" - user_proto "github.com/isd-sgcu/johnjud-go-proto/johnjud/auth/user/v1" ) type Service interface { FindOne(string) (*dto.FindOneUserResponse, *dto.ResponseErr) - Update(string, *dto.UpdateUserRequest) (*user_proto.User, *dto.ResponseErr) + Update(string, *dto.UpdateUserRequest) (*dto.UpdateUserResponse, *dto.ResponseErr) } From 59baa4869bbdb62345a60c6aa909e15ce983875c Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Fri, 5 Jan 2024 23:18:36 +0700 Subject: [PATCH 04/41] fix: remove validation in resp --- src/app/dto/pet.dto.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/dto/pet.dto.go b/src/app/dto/pet.dto.go index 0d7c5b1..1e99090 100644 --- a/src/app/dto/pet.dto.go +++ b/src/app/dto/pet.dto.go @@ -55,7 +55,7 @@ type ChangeViewPetRequest struct { } type ChangeViewPetResponse struct { - Success bool `json:"success" validate:"required"` + Success bool `json:"success"` } type UpdatePetRequest struct { @@ -81,5 +81,5 @@ type DeleteRequest struct { Id string `json:"id" validate:"required"` } type DeleteResponse struct { - Success bool `json:"success" validate:"required"` + Success bool `json:"success"` } From 3ac9671df6aaadf128a5cdec2ab1a0ba17309808 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Fri, 5 Jan 2024 23:25:16 +0700 Subject: [PATCH 05/41] feat: user svc delete --- src/app/dto/user.dto.go | 4 ++++ src/app/service/user/user.service.go | 31 ++++++++++++++++++++++++++-- src/mocks/service/user/user.mock.go | 15 ++++++++++++++ src/pkg/service/user/user.service.go | 1 + 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/app/dto/user.dto.go b/src/app/dto/user.dto.go index b2e67ed..dcabf42 100644 --- a/src/app/dto/user.dto.go +++ b/src/app/dto/user.dto.go @@ -19,3 +19,7 @@ type UpdateUserResponse struct { Firstname string `json:"firstname"` Lastname string `json:"lastname"` } + +type DeleteUserResponse struct { + Success bool `json:"success" validate:"required"` +} diff --git a/src/app/service/user/user.service.go b/src/app/service/user/user.service.go index 24f6f3a..d5d5a3d 100644 --- a/src/app/service/user/user.service.go +++ b/src/app/service/user/user.service.go @@ -85,10 +85,10 @@ func (s *Service) Update(id string, in *dto.UpdateUserRequest) (*dto.UpdateUserR Str("module", "update"). Msg(st.Message()) switch st.Code() { - case codes.NotFound: + case codes.AlreadyExists: return nil, &dto.ResponseErr{ StatusCode: http.StatusNotFound, - Message: constant.UserNotFoundMessage, + Message: constant.DuplicateEmailMessage, Data: nil, } @@ -114,3 +114,30 @@ func (s *Service) Update(id string, in *dto.UpdateUserRequest) (*dto.UpdateUserR Email: response.User.Email, }, nil } + +func (s *Service) Delete(id string) (*dto.DeleteUserResponse, *dto.ResponseErr) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + response, err := s.client.Delete(ctx, &proto.DeleteUserRequest{ + Id: id, + }) + if err != nil { + st, _ := status.FromError(err) + log.Error(). + Err(err). + Str("service", "user"). + Str("module", "delete"). + Msg(st.Message()) + + return nil, &dto.ResponseErr{ + StatusCode: http.StatusInternalServerError, + Message: constant.InternalErrorMessage, + Data: nil, + } + } + + return &dto.DeleteUserResponse{ + Success: response.Success, + }, nil +} diff --git a/src/mocks/service/user/user.mock.go b/src/mocks/service/user/user.mock.go index 92f7776..d48aad4 100644 --- a/src/mocks/service/user/user.mock.go +++ b/src/mocks/service/user/user.mock.go @@ -34,6 +34,21 @@ func (m *MockService) EXPECT() *MockServiceMockRecorder { return m.recorder } +// Delete mocks base method. +func (m *MockService) Delete(arg0 string) (*dto.DeleteUserResponse, *dto.ResponseErr) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", arg0) + ret0, _ := ret[0].(*dto.DeleteUserResponse) + ret1, _ := ret[1].(*dto.ResponseErr) + return ret0, ret1 +} + +// Delete indicates an expected call of Delete. +func (mr *MockServiceMockRecorder) Delete(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockService)(nil).Delete), arg0) +} + // FindOne mocks base method. func (m *MockService) FindOne(arg0 string) (*dto.FindOneUserResponse, *dto.ResponseErr) { m.ctrl.T.Helper() diff --git a/src/pkg/service/user/user.service.go b/src/pkg/service/user/user.service.go index a3bae68..15d58fb 100644 --- a/src/pkg/service/user/user.service.go +++ b/src/pkg/service/user/user.service.go @@ -7,4 +7,5 @@ import ( type Service interface { FindOne(string) (*dto.FindOneUserResponse, *dto.ResponseErr) Update(string, *dto.UpdateUserRequest) (*dto.UpdateUserResponse, *dto.ResponseErr) + Delete(string) (*dto.DeleteUserResponse, *dto.ResponseErr) } From 3059615aabe49be0149b7167134f4646aa999a51 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Fri, 5 Jan 2024 23:28:31 +0700 Subject: [PATCH 06/41] fix: pet svc delete return nil --- src/app/service/pet/pet.service.go | 31 +++++++++++-------------- src/app/service/pet/pet.service_test.go | 4 ++-- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/app/service/pet/pet.service.go b/src/app/service/pet/pet.service.go index fe0b4c7..6cfe664 100644 --- a/src/app/service/pet/pet.service.go +++ b/src/app/service/pet/pet.service.go @@ -196,29 +196,24 @@ func (s *Service) Delete(id string) (result *dto.DeleteResponse, err *dto.Respon Msg(st.Message()) switch st.Code() { case codes.NotFound: - return &dto.DeleteResponse{ - Success: false, - }, &dto.ResponseErr{ - StatusCode: http.StatusNotFound, - Message: constant.PetNotFoundMessage, - Data: nil, - } + return nil, &dto.ResponseErr{ + StatusCode: http.StatusNotFound, + Message: constant.PetNotFoundMessage, + Data: nil, + } case codes.Unavailable: - return &dto.DeleteResponse{ - Success: false, - }, &dto.ResponseErr{ - StatusCode: http.StatusServiceUnavailable, - Message: constant.UnavailableServiceMessage, - Data: nil, - } - } - return &dto.DeleteResponse{ - Success: false, - }, &dto.ResponseErr{ + return nil, &dto.ResponseErr{ + StatusCode: http.StatusServiceUnavailable, + Message: constant.UnavailableServiceMessage, + Data: nil, + } + default: + return nil, &dto.ResponseErr{ StatusCode: http.StatusInternalServerError, Message: constant.InternalErrorMessage, Data: nil, } + } } return &dto.DeleteResponse{ Success: res.Success, diff --git a/src/app/service/pet/pet.service_test.go b/src/app/service/pet/pet.service_test.go index abab448..aaa2b73 100644 --- a/src/app/service/pet/pet.service_test.go +++ b/src/app/service/pet/pet.service_test.go @@ -434,7 +434,7 @@ func (t *PetServiceTest) TestDeleteNotFound() { svc := NewService(client) actual, err := svc.Delete(t.Pet.Id) - assert.Equal(t.T(), &dto.DeleteResponse{Success: false}, actual) + assert.Nil(t.T(), actual) assert.Equal(t.T(), expected, err) } @@ -455,7 +455,7 @@ func (t *PetServiceTest) TestDeleteServiceUnavailableError() { svc := NewService(client) actual, err := svc.Delete(t.Pet.Id) - assert.Equal(t.T(), &dto.DeleteResponse{Success: false}, actual) + assert.Nil(t.T(), actual) assert.Equal(t.T(), expected, err) } From ba9a37e837ec295175f016b40bb73f165040780c Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Sun, 7 Jan 2024 01:07:14 +0700 Subject: [PATCH 07/41] fix: auth config --- config/auth/config.example.yaml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 config/auth/config.example.yaml diff --git a/config/auth/config.example.yaml b/config/auth/config.example.yaml new file mode 100644 index 0000000..6db63c4 --- /dev/null +++ b/config/auth/config.example.yaml @@ -0,0 +1,23 @@ +app: + port: 3002 + debug: true + secret: + +database: + host: local-db + port: 5432 + name: johnjud_db + username: root + password: root + +jwt: + secret: + expires_in: 3600 + refresh_token_ttl: 604800 + issuer: + +redis: + host: localhost + port: 6379 + password: "" + dbnum: 0 \ No newline at end of file From 0c1b3974b37a8e61e926dd637ae253a1766c8b97 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Sun, 7 Jan 2024 10:35:34 +0700 Subject: [PATCH 08/41] feat: pr template --- .../PULL_REQUEST_TEMPLATE/pull_request_template.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE/pull_request_template.md diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md new file mode 100644 index 0000000..4615521 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md @@ -0,0 +1,13 @@ +## Change made + +- [ ]  New features +- [ ]  Bug fixes +- [ ]  Breaking changes +## Describe what you have done +- +### New Features +- +### Fix +- +### Others +- \ No newline at end of file From 5876f32a0e947f56d854ab25a434247abec1a3bb Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Sun, 7 Jan 2024 11:12:54 +0700 Subject: [PATCH 09/41] feat: pr template --- .github/PULL_REQUEST_TEMPLATE/pull_request_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md index 4615521..7748e23 100644 --- a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md @@ -4,7 +4,7 @@ - [ ]  Bug fixes - [ ]  Breaking changes ## Describe what you have done -- +- ### New Features - ### Fix From 6bead9774a04e8144965f4a580d9205273c45ed5 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Sun, 7 Jan 2024 11:13:05 +0700 Subject: [PATCH 10/41] fix: remove user old svc mock --- src/mocks/user/user.mock.go | 76 ------------------------------------- 1 file changed, 76 deletions(-) delete mode 100644 src/mocks/user/user.mock.go diff --git a/src/mocks/user/user.mock.go b/src/mocks/user/user.mock.go deleted file mode 100644 index b5a4a70..0000000 --- a/src/mocks/user/user.mock.go +++ /dev/null @@ -1,76 +0,0 @@ -package user - -import ( - "context" - - "github.com/isd-sgcu/johnjud-gateway/src/app/dto" - user_proto "github.com/isd-sgcu/johnjud-go-proto/johnjud/auth/user/v1" - "github.com/stretchr/testify/mock" - "google.golang.org/grpc" -) - -type ServiceMock struct { - mock.Mock -} - -func (s *ServiceMock) FindOne(id string) (result *user_proto.User, err *dto.ResponseErr) { - args := s.Called(id) - - if args.Get(0) != nil { - result = args.Get(0).(*user_proto.User) - } - - if args.Get(1) != nil { - err = args.Get(1).(*dto.ResponseErr) - } - - return -} - -func (s *ServiceMock) Update(id string, in *dto.UpdateUserRequest) (result *user_proto.User, err *dto.ResponseErr) { - args := s.Called(id, in) - - if args.Get(0) != nil { - result = args.Get(0).(*user_proto.User) - } - - if args.Get(1) != nil { - err = args.Get(1).(*dto.ResponseErr) - } - - return -} - -type ClientMock struct { - mock.Mock -} - -func (c *ClientMock) FindOne(_ context.Context, in *user_proto.FindOneUserRequest, _ ...grpc.CallOption) (res *user_proto.FindOneUserResponse, err error) { - args := c.Called(in) - - if args.Get(0) != nil { - res = args.Get(0).(*user_proto.FindOneUserResponse) - } - - return res, args.Error(1) -} - -func (c *ClientMock) Update(_ context.Context, in *user_proto.UpdateUserRequest, _ ...grpc.CallOption) (res *user_proto.UpdateUserResponse, err error) { - args := c.Called(in) - - if args.Get(0) != nil { - res = args.Get(0).(*user_proto.UpdateUserResponse) - } - - return res, args.Error(1) -} - -func (c *ClientMock) Delete(_ context.Context, in *user_proto.DeleteUserRequest, _ ...grpc.CallOption) (res *user_proto.DeleteUserResponse, err error) { - args := c.Called(in) - - if args.Get(0) != nil { - res = args.Get(0).(*user_proto.DeleteUserResponse) - } - - return res, args.Error(1) -} From 898a26ca05e74cac22f621dd57800a89fc430459 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Sun, 7 Jan 2024 11:27:20 +0700 Subject: [PATCH 11/41] fix: update user add password, email --- src/app/dto/user.dto.go | 1 + src/app/service/user/user.service.go | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/app/dto/user.dto.go b/src/app/dto/user.dto.go index dcabf42..ca19e4e 100644 --- a/src/app/dto/user.dto.go +++ b/src/app/dto/user.dto.go @@ -8,6 +8,7 @@ type FindOneUserResponse struct { } type UpdateUserRequest struct { + Email string `json:"email" validate:"required,email"` Password string `json:"password" validate:"required,gte=6,lte=30"` Firstname string `json:"firstname" validate:"required"` Lastname string `json:"lastname" validate:"required"` diff --git a/src/app/service/user/user.service.go b/src/app/service/user/user.service.go index d5d5a3d..3340f9a 100644 --- a/src/app/service/user/user.service.go +++ b/src/app/service/user/user.service.go @@ -76,6 +76,8 @@ func (s *Service) Update(id string, in *dto.UpdateUserRequest) (*dto.UpdateUserR Id: id, Firstname: in.Firstname, Lastname: in.Lastname, + Password: in.Password, + Email: in.Email, }) if err != nil { st, _ := status.FromError(err) From 97a2beb2bd8ed20b511ef11a521a3a9d20b61dbb Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Sun, 7 Jan 2024 22:52:39 +0700 Subject: [PATCH 12/41] chore: gen mock --- src/mocks/service/like/like.mock.go | 13 ++++--------- src/mocks/service/pet/pet.mock.go | 2 +- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/mocks/service/like/like.mock.go b/src/mocks/service/like/like.mock.go index a40c24a..1e05b67 100644 --- a/src/mocks/service/like/like.mock.go +++ b/src/mocks/service/like/like.mock.go @@ -1,10 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. // Source: ./src/pkg/service/like/like.service.go -// -// Generated by this command: -// -// mockgen -source ./src/pkg/service/like/like.service.go -destination ./src/mocks/service/like/like.mock.go -// // Package mock_like is a generated GoMock package. package mock_like @@ -12,8 +7,8 @@ package mock_like import ( reflect "reflect" - dto "github.com/isd-sgcu/johnjud-gateway/src/app/dto" gomock "github.com/golang/mock/gomock" + dto "github.com/isd-sgcu/johnjud-gateway/src/app/dto" ) // MockService is a mock of Service interface. @@ -49,7 +44,7 @@ func (m *MockService) Create(arg0 *dto.CreateLikeRequest) (*dto.LikeResponse, *d } // Create indicates an expected call of Create. -func (mr *MockServiceMockRecorder) Create(arg0 any) *gomock.Call { +func (mr *MockServiceMockRecorder) Create(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockService)(nil).Create), arg0) } @@ -64,7 +59,7 @@ func (m *MockService) Delete(arg0 string) (*dto.DeleteLikeResponse, *dto.Respons } // Delete indicates an expected call of Delete. -func (mr *MockServiceMockRecorder) Delete(arg0 any) *gomock.Call { +func (mr *MockServiceMockRecorder) Delete(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockService)(nil).Delete), arg0) } @@ -79,7 +74,7 @@ func (m *MockService) FindByUserId(arg0 string) ([]*dto.LikeResponse, *dto.Respo } // FindByUserId indicates an expected call of FindByUserId. -func (mr *MockServiceMockRecorder) FindByUserId(arg0 any) *gomock.Call { +func (mr *MockServiceMockRecorder) FindByUserId(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindByUserId", reflect.TypeOf((*MockService)(nil).FindByUserId), arg0) } diff --git a/src/mocks/service/pet/pet.mock.go b/src/mocks/service/pet/pet.mock.go index a9787c9..d1689f4 100644 --- a/src/mocks/service/pet/pet.mock.go +++ b/src/mocks/service/pet/pet.mock.go @@ -44,7 +44,7 @@ func (m *MockService) Adopt(arg0 string, arg1 *dto.AdoptByRequest) (*dto.AdoptBy } // Adopt indicates an expected call of Adopt. -func (mr *MockServiceMockRecorder) Adopt(arg0, arg1 any) *gomock.Call { +func (mr *MockServiceMockRecorder) Adopt(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Adopt", reflect.TypeOf((*MockService)(nil).Adopt), arg0, arg1) } From 5714a97e799b73004b1bdaeb94ef4503ed336a25 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Sun, 7 Jan 2024 23:25:54 +0700 Subject: [PATCH 13/41] feat: user client mock --- src/mocks/client/user/user.mock.go | 41 ++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/mocks/client/user/user.mock.go diff --git a/src/mocks/client/user/user.mock.go b/src/mocks/client/user/user.mock.go new file mode 100644 index 0000000..7e54f5f --- /dev/null +++ b/src/mocks/client/user/user.mock.go @@ -0,0 +1,41 @@ +package user + +import ( + "context" + + proto "github.com/isd-sgcu/johnjud-go-proto/johnjud/auth/user/v1" + "github.com/stretchr/testify/mock" + "google.golang.org/grpc" +) + +type UserClientMock struct { + mock.Mock +} + +func (c *UserClientMock) FindOne(_ context.Context, in *proto.FindOneUserRequest, _ ...grpc.CallOption) (res *proto.FindOneUserResponse, err error) { + args := c.Called(in) + + if args.Get(0) != nil { + res = args.Get(0).(*proto.FindOneUserResponse) + } + return res, args.Error(1) +} +func (c *UserClientMock) Update(_ context.Context, in *proto.UpdateUserRequest, _ ...grpc.CallOption) (res *proto.UpdateUserResponse, err error) { + args := c.Called(in) + + if args.Get(0) != nil { + res = args.Get(0).(*proto.UpdateUserResponse) + } + + return res, args.Error(1) +} + +func (c *UserClientMock) Delete(_ context.Context, in *proto.DeleteUserRequest, _ ...grpc.CallOption) (res *proto.DeleteUserResponse, err error) { + args := c.Called(in) + + if args.Get(0) != nil { + res = args.Get(0).(*proto.DeleteUserResponse) + } + + return res, args.Error(1) +} From ba8edcc65ca9fea3413a648c69018e22fd4da9a3 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Sun, 7 Jan 2024 23:26:16 +0700 Subject: [PATCH 14/41] feat: user delete add unavailable --- src/app/service/user/user.service.go | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/app/service/user/user.service.go b/src/app/service/user/user.service.go index 3340f9a..d1f3948 100644 --- a/src/app/service/user/user.service.go +++ b/src/app/service/user/user.service.go @@ -89,7 +89,7 @@ func (s *Service) Update(id string, in *dto.UpdateUserRequest) (*dto.UpdateUserR switch st.Code() { case codes.AlreadyExists: return nil, &dto.ResponseErr{ - StatusCode: http.StatusNotFound, + StatusCode: http.StatusConflict, Message: constant.DuplicateEmailMessage, Data: nil, } @@ -131,11 +131,19 @@ func (s *Service) Delete(id string) (*dto.DeleteUserResponse, *dto.ResponseErr) Str("service", "user"). Str("module", "delete"). Msg(st.Message()) - - return nil, &dto.ResponseErr{ - StatusCode: http.StatusInternalServerError, - Message: constant.InternalErrorMessage, - Data: nil, + switch st.Code() { + case codes.Unavailable: + return nil, &dto.ResponseErr{ + StatusCode: http.StatusServiceUnavailable, + Message: constant.UnavailableServiceMessage, + Data: nil, + } + default: + return nil, &dto.ResponseErr{ + StatusCode: http.StatusInternalServerError, + Message: constant.InternalErrorMessage, + Data: nil, + } } } From fd4c0cff497de1f6cb05d7bee01c469eb91f5af6 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Sun, 7 Jan 2024 23:26:28 +0700 Subject: [PATCH 15/41] feat: user svc test --- src/app/service/user/user.service_test.go | 278 ++++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 src/app/service/user/user.service_test.go diff --git a/src/app/service/user/user.service_test.go b/src/app/service/user/user.service_test.go new file mode 100644 index 0000000..8f9103c --- /dev/null +++ b/src/app/service/user/user.service_test.go @@ -0,0 +1,278 @@ +package user + +import ( + "net/http" + "testing" + + "github.com/go-faker/faker/v4" + "github.com/isd-sgcu/johnjud-gateway/src/app/constant" + "github.com/isd-sgcu/johnjud-gateway/src/app/dto" + "github.com/isd-sgcu/johnjud-gateway/src/mocks/client/user" + proto "github.com/isd-sgcu/johnjud-go-proto/johnjud/auth/user/v1" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type UserServiceTest struct { + suite.Suite + User *proto.User + FindOneUserReq *proto.FindOneUserRequest + UpdateUserReq *proto.UpdateUserRequest + UpdateUserDto *dto.UpdateUserRequest + DeleteUserReq *proto.DeleteUserRequest + NotFoundErr *dto.ResponseErr + UnavailableServiceErr *dto.ResponseErr + ConflictErr *dto.ResponseErr + InternalErr *dto.ResponseErr +} + +func TestUserService(t *testing.T) { + suite.Run(t, new(UserServiceTest)) +} + +func (t *UserServiceTest) SetupTest() { + t.User = &proto.User{ + Id: faker.UUIDDigit(), + Email: faker.Email(), + Password: faker.Password(), + Firstname: faker.FirstName(), + Lastname: faker.LastName(), + Role: "user", + } + + t.FindOneUserReq = &proto.FindOneUserRequest{ + Id: t.User.Id, + } + + t.UpdateUserDto = &dto.UpdateUserRequest{ + Email: faker.Email(), + Password: faker.Password(), + Firstname: faker.FirstName(), + Lastname: faker.LastName(), + } + + t.UpdateUserReq = &proto.UpdateUserRequest{ + Id: t.User.Id, + Email: t.UpdateUserDto.Email, + Password: t.UpdateUserDto.Password, + Firstname: t.UpdateUserDto.Firstname, + Lastname: t.UpdateUserDto.Lastname, + } + + t.DeleteUserReq = &proto.DeleteUserRequest{ + Id: t.User.Id, + } + + t.UnavailableServiceErr = &dto.ResponseErr{ + StatusCode: http.StatusServiceUnavailable, + Message: constant.UnavailableServiceMessage, + Data: nil, + } + + t.NotFoundErr = &dto.ResponseErr{ + StatusCode: http.StatusNotFound, + Message: constant.UserNotFoundMessage, + Data: nil, + } + + t.ConflictErr = &dto.ResponseErr{ + StatusCode: http.StatusConflict, + Message: constant.DuplicateEmailMessage, + Data: nil, + } + + t.InternalErr = &dto.ResponseErr{ + StatusCode: http.StatusInternalServerError, + Message: constant.InternalErrorMessage, + Data: nil, + } +} + +func (t *UserServiceTest) TestFindOneSuccess() { + protoResp := &proto.FindOneUserResponse{ + User: &proto.User{ + Id: t.User.Id, + Email: t.User.Email, + Firstname: t.User.Firstname, + Lastname: t.User.Lastname, + Role: t.User.Role, + }, + } + + expected := &dto.FindOneUserResponse{ + Id: t.User.Id, + Email: t.User.Email, + Firstname: t.User.Firstname, + Lastname: t.User.Lastname, + } + + client := user.UserClientMock{} + client.On("FindOne", t.FindOneUserReq).Return(protoResp, nil) + + svc := NewService(&client) + actual, err := svc.FindOne(t.User.Id) + + assert.Nil(t.T(), err) + assert.Equal(t.T(), expected, actual) +} + +func (t *UserServiceTest) TestFindOneNotFoundError() { + expected := t.NotFoundErr + + client := user.UserClientMock{} + clienErr := status.Error(codes.NotFound, constant.UserNotFoundMessage) + client.On("FindOne", t.FindOneUserReq).Return(nil, clienErr) + + svc := NewService(&client) + actual, err := svc.FindOne(t.User.Id) + + assert.Nil(t.T(), actual) + assert.Equal(t.T(), expected, err) +} + +func (t *UserServiceTest) TestFindOneUnavailableServiceError() { + expected := t.UnavailableServiceErr + + client := user.UserClientMock{} + clientErr := status.Error(codes.Unavailable, constant.UnavailableServiceMessage) + client.On("FindOne", t.FindOneUserReq).Return(nil, clientErr) + + svc := NewService(&client) + actual, err := svc.FindOne(t.User.Id) + + assert.Nil(t.T(), actual) + assert.Equal(t.T(), expected, err) +} + +func (t *UserServiceTest) TestFindOneInternalError() { + expected := t.InternalErr + + client := user.UserClientMock{} + clientErr := status.Error(codes.Internal, constant.InternalErrorMessage) + client.On("FindOne", t.FindOneUserReq).Return(nil, clientErr) + + svc := NewService(&client) + actual, err := svc.FindOne(t.User.Id) + + assert.Nil(t.T(), actual) + assert.Equal(t.T(), expected, err) +} + +func (t *UserServiceTest) TestUpdateSuccess() { + protoResp := &proto.UpdateUserResponse{ + User: &proto.User{ + Id: t.User.Id, + Email: t.User.Email, + Firstname: t.User.Firstname, + Lastname: t.User.Lastname, + Role: t.User.Role, + }, + } + + expected := &dto.UpdateUserResponse{ + Id: t.User.Id, + Email: t.User.Email, + Firstname: t.User.Firstname, + Lastname: t.User.Lastname, + } + + client := user.UserClientMock{} + client.On("Update", t.UpdateUserReq).Return(protoResp, nil) + + svc := NewService(&client) + actual, err := svc.Update(t.User.Id, t.UpdateUserDto) + + assert.Nil(t.T(), err) + assert.Equal(t.T(), expected, actual) +} + +func (t *UserServiceTest) TestUpdateDuplicateEmail() { + expected := t.ConflictErr + + client := user.UserClientMock{} + clientErr := status.Error(codes.AlreadyExists, constant.DuplicateEmailMessage) + client.On("Update", t.UpdateUserReq).Return(nil, clientErr) + + svc := NewService(&client) + actual, err := svc.Update(t.User.Id, t.UpdateUserDto) + + assert.Nil(t.T(), actual) + assert.Equal(t.T(), expected, err) +} + +func (t *UserServiceTest) TestUpdateUnavailableServiceError() { + expected := t.UnavailableServiceErr + + client := user.UserClientMock{} + clientErr := status.Error(codes.Unavailable, constant.UnavailableServiceMessage) + client.On("Update", t.UpdateUserReq).Return(nil, clientErr) + + svc := NewService(&client) + actual, err := svc.Update(t.User.Id, t.UpdateUserDto) + + assert.Nil(t.T(), actual) + assert.Equal(t.T(), expected, err) +} + +func (t *UserServiceTest) TestUpdateInternalError() { + expected := t.InternalErr + + client := user.UserClientMock{} + clientErr := status.Error(codes.Internal, constant.InternalErrorMessage) + client.On("Update", t.UpdateUserReq).Return(nil, clientErr) + + svc := NewService(&client) + actual, err := svc.Update(t.User.Id, t.UpdateUserDto) + + assert.Nil(t.T(), actual) + assert.Equal(t.T(), expected, err) +} + +func (t *UserServiceTest) TestDeleteSuccess() { + protoResp := &proto.DeleteUserResponse{ + Success: true, + } + + expected := &dto.DeleteUserResponse{ + Success: true, + } + + client := user.UserClientMock{} + client.On("Delete", t.DeleteUserReq).Return(protoResp, nil) + + svc := NewService(&client) + actual, err := svc.Delete(t.User.Id) + + assert.Nil(t.T(), err) + assert.Equal(t.T(), expected, actual) +} + +func (t *UserServiceTest) TestDeleteUnavailableServiceError() { + expected := t.UnavailableServiceErr + + client := user.UserClientMock{} + clientErr := status.Error(codes.Unavailable, constant.UnavailableServiceMessage) + client.On("Delete", t.DeleteUserReq).Return(nil, clientErr) + + svc := NewService(&client) + actual, err := svc.Delete(t.User.Id) + + assert.Nil(t.T(), actual) + assert.Equal(t.T(), expected, err) +} + +func (t *UserServiceTest) TestDeleteInternalError() { + expected := t.InternalErr + + client := user.UserClientMock{} + clientErr := status.Error(codes.Internal, constant.InternalErrorMessage) + client.On("Delete", t.DeleteUserReq).Return(nil, clientErr) + + svc := NewService(&client) + actual, err := svc.Delete(t.User.Id) + + assert.Nil(t.T(), actual) + assert.Equal(t.T(), expected, err) +} From 2cae2d99e5a209949227178452f9fabeb4f38a3c Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Sun, 7 Jan 2024 23:45:53 +0700 Subject: [PATCH 16/41] feat: findone swagger --- src/app/handler/user/user.handler.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/app/handler/user/user.handler.go b/src/app/handler/user/user.handler.go index 3ac1e8b..9bdca07 100644 --- a/src/app/handler/user/user.handler.go +++ b/src/app/handler/user/user.handler.go @@ -18,6 +18,18 @@ func NewHandler(service user.Service, validate validator.IDtoValidator) *Handler return &Handler{service, validate} } +// FindOne is a function that returns a user by id from database +// @Summary finds one user +// @Description Returns the data of user if successful +// @Param id path string true "user id" +// @Tags user +// @Accept json +// @Produce json +// @Success 200 {object} dto.User +// @Failure 400 {object} dto.ResponseBadRequestErr "Invalid request body" +// @Failure 500 {object} dto.ResponseInternalErr "Internal service error" +// @Failure 503 {object} dto.ResponseServiceDownErr "Service is down" +// @Router /v1/users/{id} [get] func (h *Handler) FindOne(c *router.FiberCtx) { id, err := c.ID() if err != nil { From 6e11f07379e7aeeed89906f948d3f8618108b13e Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Sun, 7 Jan 2024 23:49:25 +0700 Subject: [PATCH 17/41] fix: merge update, findone dto -> dto.User --- src/app/dto/user.dto.go | 9 +-------- src/app/service/user/user.service.go | 8 ++++---- src/app/service/user/user.service_test.go | 4 ++-- src/mocks/service/user/user.mock.go | 8 ++++---- src/pkg/service/user/user.service.go | 4 ++-- 5 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/app/dto/user.dto.go b/src/app/dto/user.dto.go index ca19e4e..c96fcab 100644 --- a/src/app/dto/user.dto.go +++ b/src/app/dto/user.dto.go @@ -1,6 +1,6 @@ package dto -type FindOneUserResponse struct { +type User struct { Id string `json:"id"` Email string `json:"email"` Firstname string `json:"firstname"` @@ -14,13 +14,6 @@ type UpdateUserRequest struct { Lastname string `json:"lastname" validate:"required"` } -type UpdateUserResponse struct { - Id string `json:"id"` - Email string `json:"email"` - Firstname string `json:"firstname"` - Lastname string `json:"lastname"` -} - type DeleteUserResponse struct { Success bool `json:"success" validate:"required"` } diff --git a/src/app/service/user/user.service.go b/src/app/service/user/user.service.go index d1f3948..d4186f2 100644 --- a/src/app/service/user/user.service.go +++ b/src/app/service/user/user.service.go @@ -23,7 +23,7 @@ func NewService(client proto.UserServiceClient) *Service { } } -func (s *Service) FindOne(id string) (*dto.FindOneUserResponse, *dto.ResponseErr) { +func (s *Service) FindOne(id string) (*dto.User, *dto.ResponseErr) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() @@ -60,7 +60,7 @@ func (s *Service) FindOne(id string) (*dto.FindOneUserResponse, *dto.ResponseErr } } - return &dto.FindOneUserResponse{ + return &dto.User{ Id: response.User.Id, Firstname: response.User.Firstname, Lastname: response.User.Lastname, @@ -68,7 +68,7 @@ func (s *Service) FindOne(id string) (*dto.FindOneUserResponse, *dto.ResponseErr }, nil } -func (s *Service) Update(id string, in *dto.UpdateUserRequest) (*dto.UpdateUserResponse, *dto.ResponseErr) { +func (s *Service) Update(id string, in *dto.UpdateUserRequest) (*dto.User, *dto.ResponseErr) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() @@ -109,7 +109,7 @@ func (s *Service) Update(id string, in *dto.UpdateUserRequest) (*dto.UpdateUserR } } - return &dto.UpdateUserResponse{ + return &dto.User{ Id: response.User.Id, Firstname: response.User.Firstname, Lastname: response.User.Lastname, diff --git a/src/app/service/user/user.service_test.go b/src/app/service/user/user.service_test.go index 8f9103c..9630508 100644 --- a/src/app/service/user/user.service_test.go +++ b/src/app/service/user/user.service_test.go @@ -101,7 +101,7 @@ func (t *UserServiceTest) TestFindOneSuccess() { }, } - expected := &dto.FindOneUserResponse{ + expected := &dto.User{ Id: t.User.Id, Email: t.User.Email, Firstname: t.User.Firstname, @@ -171,7 +171,7 @@ func (t *UserServiceTest) TestUpdateSuccess() { }, } - expected := &dto.UpdateUserResponse{ + expected := &dto.User{ Id: t.User.Id, Email: t.User.Email, Firstname: t.User.Firstname, diff --git a/src/mocks/service/user/user.mock.go b/src/mocks/service/user/user.mock.go index d48aad4..ba40d67 100644 --- a/src/mocks/service/user/user.mock.go +++ b/src/mocks/service/user/user.mock.go @@ -50,10 +50,10 @@ func (mr *MockServiceMockRecorder) Delete(arg0 interface{}) *gomock.Call { } // FindOne mocks base method. -func (m *MockService) FindOne(arg0 string) (*dto.FindOneUserResponse, *dto.ResponseErr) { +func (m *MockService) FindOne(arg0 string) (*dto.User, *dto.ResponseErr) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "FindOne", arg0) - ret0, _ := ret[0].(*dto.FindOneUserResponse) + ret0, _ := ret[0].(*dto.User) ret1, _ := ret[1].(*dto.ResponseErr) return ret0, ret1 } @@ -65,10 +65,10 @@ func (mr *MockServiceMockRecorder) FindOne(arg0 interface{}) *gomock.Call { } // Update mocks base method. -func (m *MockService) Update(arg0 string, arg1 *dto.UpdateUserRequest) (*dto.UpdateUserResponse, *dto.ResponseErr) { +func (m *MockService) Update(arg0 string, arg1 *dto.UpdateUserRequest) (*dto.User, *dto.ResponseErr) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Update", arg0, arg1) - ret0, _ := ret[0].(*dto.UpdateUserResponse) + ret0, _ := ret[0].(*dto.User) ret1, _ := ret[1].(*dto.ResponseErr) return ret0, ret1 } diff --git a/src/pkg/service/user/user.service.go b/src/pkg/service/user/user.service.go index 15d58fb..731063b 100644 --- a/src/pkg/service/user/user.service.go +++ b/src/pkg/service/user/user.service.go @@ -5,7 +5,7 @@ import ( ) type Service interface { - FindOne(string) (*dto.FindOneUserResponse, *dto.ResponseErr) - Update(string, *dto.UpdateUserRequest) (*dto.UpdateUserResponse, *dto.ResponseErr) + FindOne(string) (*dto.User, *dto.ResponseErr) + Update(string, *dto.UpdateUserRequest) (*dto.User, *dto.ResponseErr) Delete(string) (*dto.DeleteUserResponse, *dto.ResponseErr) } From d2d291cc20bd4123e6b480128f1a1ee5fc2fd03b Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Mon, 8 Jan 2024 08:44:18 +0700 Subject: [PATCH 18/41] feat: user handler update --- src/app/handler/user/user.handler.go | 58 +++++++++++++++++++++++----- src/constant/user/user.constant.go | 5 +++ 2 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 src/constant/user/user.constant.go diff --git a/src/app/handler/user/user.handler.go b/src/app/handler/user/user.handler.go index 9bdca07..db905cd 100644 --- a/src/app/handler/user/user.handler.go +++ b/src/app/handler/user/user.handler.go @@ -2,10 +2,13 @@ package user import ( "net/http" + "strings" + "github.com/isd-sgcu/johnjud-gateway/src/app/constant" "github.com/isd-sgcu/johnjud-gateway/src/app/dto" "github.com/isd-sgcu/johnjud-gateway/src/app/router" "github.com/isd-sgcu/johnjud-gateway/src/app/validator" + userconst "github.com/isd-sgcu/johnjud-gateway/src/constant/user" "github.com/isd-sgcu/johnjud-gateway/src/pkg/service/user" ) @@ -33,9 +36,9 @@ func NewHandler(service user.Service, validate validator.IDtoValidator) *Handler func (h *Handler) FindOne(c *router.FiberCtx) { id, err := c.ID() if err != nil { - c.JSON(http.StatusInternalServerError, dto.ResponseErr{ - StatusCode: http.StatusInternalServerError, - Message: "Invalid ID", + c.JSON(http.StatusBadRequest, dto.ResponseErr{ + StatusCode: http.StatusBadRequest, + Message: err.Error(), Data: nil, }) return @@ -47,27 +50,64 @@ func (h *Handler) FindOne(c *router.FiberCtx) { return } - c.JSON(http.StatusCreated, user) + c.JSON(http.StatusCreated, dto.ResponseSuccess{ + StatusCode: http.StatusOK, + Message: userconst.FindOneUserSuccessMessage, + Data: user, + }) return } +// Update is a function that updates user in database +// @Summary updates user +// @Description Returns the data of user if successfully +// @Param update body dto.UpdateUserRequest true "update user dto" +// @Tags auth +// @Accept json +// @Produce json +// @Success 201 {object} dto.User +// @Failure 400 {object} dto.ResponseBadRequestErr "Invalid request body" +// @Failure 500 {object} dto.ResponseInternalErr "Internal service error" +// @Failure 503 {object} dto.ResponseServiceDownErr "Service is down" +// @Router /v1/users [put] func (h *Handler) Update(c *router.FiberCtx) { usrId := c.UserID() - usrDto := dto.UpdateUserRequest{} + request := &dto.UpdateUserRequest{} - err := c.Bind(&usrDto) + err := c.Bind(request) if err != nil { - c.JSON(http.StatusBadRequest, err) + c.JSON(http.StatusBadRequest, dto.ResponseErr{ + StatusCode: http.StatusBadRequest, + Message: constant.BindingRequestErrorMessage + err.Error(), + Data: nil, + }) + return + } + + if err := h.validate.Validate(request); err != nil { + var errorMessage []string + for _, reqErr := range err { + errorMessage = append(errorMessage, reqErr.Message) + } + c.JSON(http.StatusBadRequest, dto.ResponseErr{ + StatusCode: http.StatusBadRequest, + Message: constant.InvalidRequestBodyMessage + strings.Join(errorMessage, ", "), + Data: nil, + }) return } - user, errRes := h.service.Update(usrId, &usrDto) + user, errRes := h.service.Update(usrId, request) if errRes != nil { c.JSON(errRes.StatusCode, errRes) return } - c.JSON(http.StatusOK, user) + c.JSON(http.StatusOK, dto.ResponseSuccess{ + StatusCode: http.StatusOK, + Message: userconst.UpdateUserSuccessMessage, + Data: user, + }) return } diff --git a/src/constant/user/user.constant.go b/src/constant/user/user.constant.go new file mode 100644 index 0000000..7d84a6a --- /dev/null +++ b/src/constant/user/user.constant.go @@ -0,0 +1,5 @@ +package user + +const FindOneUserSuccessMessage = "find one user success" +const UpdateUserSuccessMessage = "update user success" +const DeleteUserSuccessMessage = "delete user success" From 746e744d090b9db8180dca751789cc5dbe5b0bff Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Mon, 8 Jan 2024 08:48:38 +0700 Subject: [PATCH 19/41] feat: add context Role() --- src/app/router/context.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/app/router/context.go b/src/app/router/context.go index 4a1b00f..244c11d 100644 --- a/src/app/router/context.go +++ b/src/app/router/context.go @@ -32,6 +32,10 @@ func (c *FiberCtx) UserID() string { return c.Ctx.Locals("UserId").(string) } +func (c *FiberCtx) Role() string { + return c.Ctx.Locals("Role").(string) +} + func (c *FiberCtx) Bind(v interface{}) error { return c.Ctx.BodyParser(v) } From 915c17b0190f3e87d72630df50f4a7571a67b4a1 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Mon, 8 Jan 2024 08:56:12 +0700 Subject: [PATCH 20/41] chore: gen mock --- src/app/router/context.go | 1 + src/mocks/router/context.mock.go | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/app/router/context.go b/src/app/router/context.go index 244c11d..4d55e9d 100644 --- a/src/app/router/context.go +++ b/src/app/router/context.go @@ -9,6 +9,7 @@ import ( type IContext interface { UserID() string + Role() string Bind(interface{}) error JSON(int, interface{}) ID() (string, error) diff --git a/src/mocks/router/context.mock.go b/src/mocks/router/context.mock.go index f2238b6..df02a3c 100644 --- a/src/mocks/router/context.mock.go +++ b/src/mocks/router/context.mock.go @@ -131,6 +131,20 @@ func (mr *MockIContextMockRecorder) Path() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Path", reflect.TypeOf((*MockIContext)(nil).Path)) } +// Role mocks base method. +func (m *MockIContext) Role() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Role") + ret0, _ := ret[0].(string) + return ret0 +} + +// Role indicates an expected call of Role. +func (mr *MockIContextMockRecorder) Role() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Role", reflect.TypeOf((*MockIContext)(nil).Role)) +} + // StoreValue mocks base method. func (m *MockIContext) StoreValue(arg0, arg1 string) { m.ctrl.T.Helper() From 8f8f8bd674d15b4f655e95a7bbb83b9833bb5d7d Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Mon, 8 Jan 2024 08:56:22 +0700 Subject: [PATCH 21/41] feat: role const --- src/constant/user/user.constant.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/constant/user/user.constant.go b/src/constant/user/user.constant.go index 7d84a6a..cf1991e 100644 --- a/src/constant/user/user.constant.go +++ b/src/constant/user/user.constant.go @@ -3,3 +3,10 @@ package user const FindOneUserSuccessMessage = "find one user success" const UpdateUserSuccessMessage = "update user success" const DeleteUserSuccessMessage = "delete user success" + +type Role string + +const ( + USER Role = "user" + ADMIN Role = "admin" +) From 35e22425127bdc48547463dbe037aca85c916646 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Mon, 8 Jan 2024 09:52:09 +0700 Subject: [PATCH 22/41] feat: add admin path --- src/app/middleware/auth/auth.middleware.go | 17 +++++++++++++++-- src/constant/auth/auth.constant.go | 2 ++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/app/middleware/auth/auth.middleware.go b/src/app/middleware/auth/auth.middleware.go index 70db9b5..0d2430d 100644 --- a/src/app/middleware/auth/auth.middleware.go +++ b/src/app/middleware/auth/auth.middleware.go @@ -1,26 +1,30 @@ package auth import ( + "net/http" + "github.com/isd-sgcu/johnjud-gateway/src/app/dto" "github.com/isd-sgcu/johnjud-gateway/src/app/router" "github.com/isd-sgcu/johnjud-gateway/src/app/utils" "github.com/isd-sgcu/johnjud-gateway/src/app/utils/auth" "github.com/isd-sgcu/johnjud-gateway/src/config" + "github.com/isd-sgcu/johnjud-gateway/src/constant/user" authPkg "github.com/isd-sgcu/johnjud-gateway/src/pkg/service/auth" - "net/http" ) type Guard struct { service authPkg.Service excludes map[string]struct{} + adminpath map[string]struct{} conf config.App versionList map[string]struct{} } -func NewAuthGuard(s authPkg.Service, e map[string]struct{}, conf config.App, versionList map[string]struct{}) Guard { +func NewAuthGuard(s authPkg.Service, e map[string]struct{}, a map[string]struct{}, conf config.App, versionList map[string]struct{}) Guard { return Guard{ service: s, excludes: e, + adminpath: a, conf: conf, versionList: versionList, } @@ -53,5 +57,14 @@ func (m *Guard) Use(ctx router.IContext) error { ctx.StoreValue("UserId", payload.UserId) ctx.StoreValue("Role", payload.Role) + if utils.IsExisted(m.adminpath, path) && payload.Role != string(user.ADMIN) { + ctx.JSON(http.StatusUnauthorized, dto.ResponseErr{ + StatusCode: http.StatusUnauthorized, + Message: "Unauthorized", + Data: nil, + }) + return nil + } + return ctx.Next() } diff --git a/src/constant/auth/auth.constant.go b/src/constant/auth/auth.constant.go index 2273fbe..663e711 100644 --- a/src/constant/auth/auth.constant.go +++ b/src/constant/auth/auth.constant.go @@ -8,6 +8,8 @@ var ExcludePath = map[string]struct{}{ "GET /adopt/": {}, } +var AdminPath = map[string]struct{}{} + var VersionList = map[string]struct{}{ "v1": {}, } From e31bf92c990bbf283e7e5bd326b03b02a6c3f7d6 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Mon, 8 Jan 2024 10:02:35 +0700 Subject: [PATCH 23/41] feat: user handler delete --- src/app/handler/user/user.handler.go | 42 ++++++++++++++++++++++++++-- src/app/router/user.router.go | 11 ++++++-- src/main.go | 3 +- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/app/handler/user/user.handler.go b/src/app/handler/user/user.handler.go index db905cd..0c3c208 100644 --- a/src/app/handler/user/user.handler.go +++ b/src/app/handler/user/user.handler.go @@ -33,7 +33,7 @@ func NewHandler(service user.Service, validate validator.IDtoValidator) *Handler // @Failure 500 {object} dto.ResponseInternalErr "Internal service error" // @Failure 503 {object} dto.ResponseServiceDownErr "Service is down" // @Router /v1/users/{id} [get] -func (h *Handler) FindOne(c *router.FiberCtx) { +func (h *Handler) FindOne(c router.IContext) { id, err := c.ID() if err != nil { c.JSON(http.StatusBadRequest, dto.ResponseErr{ @@ -70,7 +70,7 @@ func (h *Handler) FindOne(c *router.FiberCtx) { // @Failure 500 {object} dto.ResponseInternalErr "Internal service error" // @Failure 503 {object} dto.ResponseServiceDownErr "Service is down" // @Router /v1/users [put] -func (h *Handler) Update(c *router.FiberCtx) { +func (h *Handler) Update(c router.IContext) { usrId := c.UserID() request := &dto.UpdateUserRequest{} @@ -111,3 +111,41 @@ func (h *Handler) Update(c *router.FiberCtx) { }) return } + +// Delete is a function that deletes user in database +// @Summary deletes user +// @Description Returns successful status if user is successfully deleted +// @Param id path string true "user id" +// @Tags user +// @Accept json +// @Produce json +// @Success 201 {object} bool +// @Success 201 {object} dto.DeleteUserResponse +// @Failure 400 {object} dto.ResponseBadRequestErr "Invalid request body" +// @Failure 500 {object} dto.ResponseInternalErr "Internal service error" +// @Failure 503 {object} dto.ResponseServiceDownErr "Service is down" +// @Router /v1/users/{id} [delete] +func (h *Handler) Delete(c router.IContext) { + id, err := c.ID() + if err != nil { + c.JSON(http.StatusBadRequest, dto.ResponseErr{ + StatusCode: http.StatusBadRequest, + Message: err.Error(), + Data: nil, + }) + return + } + + res, errRes := h.service.Delete(id) + if errRes != nil { + c.JSON(errRes.StatusCode, errRes) + return + } + + c.JSON(http.StatusOK, dto.ResponseSuccess{ + StatusCode: http.StatusOK, + Message: userconst.DeleteUserSuccessMessage, + Data: res, + }) + return +} diff --git a/src/app/router/user.router.go b/src/app/router/user.router.go index f506484..f2da894 100644 --- a/src/app/router/user.router.go +++ b/src/app/router/user.router.go @@ -2,16 +2,23 @@ package router import "github.com/gofiber/fiber/v2" -func (r *FiberRouter) GetUser(path string, h func(ctx *FiberCtx)) { +func (r *FiberRouter) GetUser(path string, h func(ctx IContext)) { r.user.Get(path, func(c *fiber.Ctx) error { h(NewFiberCtx(c)) return nil }) } -func (r *FiberRouter) PutUser(path string, h func(ctx *FiberCtx)) { +func (r *FiberRouter) PutUser(path string, h func(ctx IContext)) { r.user.Put(path, func(c *fiber.Ctx) error { h(NewFiberCtx(c)) return nil }) } + +func (r *FiberRouter) DeleteUser(path string, h func(ctx IContext)) { + r.user.Delete(path, func(c *fiber.Ctx) error { + h(NewFiberCtx(c)) + return nil + }) +} diff --git a/src/main.go b/src/main.go index 2d354c7..c5cc95e 100644 --- a/src/main.go +++ b/src/main.go @@ -103,7 +103,7 @@ func main() { authService := authSvc.NewService(authClient) authHandler := authHdr.NewHandler(authService, userService, v) - authGuard := guard.NewAuthGuard(authService, auth.ExcludePath, conf.App, auth.VersionList) + authGuard := guard.NewAuthGuard(authService, auth.ExcludePath, auth.AdminPath, conf.App, auth.VersionList) imageClient := imageProto.NewImageServiceClient(fileConn) imageService := imageSvc.NewService(imageClient) @@ -120,6 +120,7 @@ func main() { r.GetUser("/:id", userHandler.FindOne) r.PutUser("/", userHandler.Update) + r.DeleteUser("/:id", userHandler.Delete) r.PostAuth("/signup", authHandler.Signup) r.PostAuth("/signin", authHandler.SignIn) From 81b350163c8125a079ebc552f2079e0b814bca4d Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Tue, 9 Jan 2024 16:28:47 +0700 Subject: [PATCH 24/41] fix: handler pass by ref --- src/app/handler/user/user.handler.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/app/handler/user/user.handler.go b/src/app/handler/user/user.handler.go index 0c3c208..f281c60 100644 --- a/src/app/handler/user/user.handler.go +++ b/src/app/handler/user/user.handler.go @@ -36,7 +36,7 @@ func NewHandler(service user.Service, validate validator.IDtoValidator) *Handler func (h *Handler) FindOne(c router.IContext) { id, err := c.ID() if err != nil { - c.JSON(http.StatusBadRequest, dto.ResponseErr{ + c.JSON(http.StatusBadRequest, &dto.ResponseErr{ StatusCode: http.StatusBadRequest, Message: err.Error(), Data: nil, @@ -50,7 +50,7 @@ func (h *Handler) FindOne(c router.IContext) { return } - c.JSON(http.StatusCreated, dto.ResponseSuccess{ + c.JSON(http.StatusOK, &dto.ResponseSuccess{ StatusCode: http.StatusOK, Message: userconst.FindOneUserSuccessMessage, Data: user, @@ -77,7 +77,7 @@ func (h *Handler) Update(c router.IContext) { err := c.Bind(request) if err != nil { - c.JSON(http.StatusBadRequest, dto.ResponseErr{ + c.JSON(http.StatusBadRequest, &dto.ResponseErr{ StatusCode: http.StatusBadRequest, Message: constant.BindingRequestErrorMessage + err.Error(), Data: nil, @@ -90,7 +90,7 @@ func (h *Handler) Update(c router.IContext) { for _, reqErr := range err { errorMessage = append(errorMessage, reqErr.Message) } - c.JSON(http.StatusBadRequest, dto.ResponseErr{ + c.JSON(http.StatusBadRequest, &dto.ResponseErr{ StatusCode: http.StatusBadRequest, Message: constant.InvalidRequestBodyMessage + strings.Join(errorMessage, ", "), Data: nil, @@ -104,7 +104,7 @@ func (h *Handler) Update(c router.IContext) { return } - c.JSON(http.StatusOK, dto.ResponseSuccess{ + c.JSON(http.StatusOK, &dto.ResponseSuccess{ StatusCode: http.StatusOK, Message: userconst.UpdateUserSuccessMessage, Data: user, @@ -128,7 +128,7 @@ func (h *Handler) Update(c router.IContext) { func (h *Handler) Delete(c router.IContext) { id, err := c.ID() if err != nil { - c.JSON(http.StatusBadRequest, dto.ResponseErr{ + c.JSON(http.StatusBadRequest, &dto.ResponseErr{ StatusCode: http.StatusBadRequest, Message: err.Error(), Data: nil, @@ -142,7 +142,7 @@ func (h *Handler) Delete(c router.IContext) { return } - c.JSON(http.StatusOK, dto.ResponseSuccess{ + c.JSON(http.StatusOK, &dto.ResponseSuccess{ StatusCode: http.StatusOK, Message: userconst.DeleteUserSuccessMessage, Data: res, From fb02398bb3a7b1c3ee6739c9468cd7adf05be948 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Tue, 9 Jan 2024 17:22:49 +0700 Subject: [PATCH 25/41] feat: user handler test --- src/app/handler/user/user.handler_test.go | 378 ++++++++++++++++++++++ 1 file changed, 378 insertions(+) create mode 100644 src/app/handler/user/user.handler_test.go diff --git a/src/app/handler/user/user.handler_test.go b/src/app/handler/user/user.handler_test.go new file mode 100644 index 0000000..e219baa --- /dev/null +++ b/src/app/handler/user/user.handler_test.go @@ -0,0 +1,378 @@ +package user + +import ( + "errors" + "net/http" + "strings" + "testing" + + "github.com/go-faker/faker/v4" + "github.com/golang/mock/gomock" + "github.com/isd-sgcu/johnjud-gateway/src/app/constant" + "github.com/isd-sgcu/johnjud-gateway/src/app/dto" + routerMock "github.com/isd-sgcu/johnjud-gateway/src/mocks/router" + userMock "github.com/isd-sgcu/johnjud-gateway/src/mocks/service/user" + validatorMock "github.com/isd-sgcu/johnjud-gateway/src/mocks/validator" + + errConst "github.com/isd-sgcu/johnjud-gateway/src/app/constant" + userConst "github.com/isd-sgcu/johnjud-gateway/src/constant/user" + proto "github.com/isd-sgcu/johnjud-go-proto/johnjud/auth/user/v1" + + "github.com/stretchr/testify/suite" +) + +type UserHandlerTest struct { + suite.Suite + User *proto.User + UserDto *dto.User + UpdateUserRequest *dto.UpdateUserRequest + BindErr *dto.ResponseErr + NotFoundErr *dto.ResponseErr + InvalidIDErr *dto.ResponseErr + ServiceDownErr *dto.ResponseErr + DuplicateEmailErr *dto.ResponseErr + InternalErr *dto.ResponseErr +} + +func TestUserHandler(t *testing.T) { + suite.Run(t, new(UserHandlerTest)) +} + +func (t *UserHandlerTest) SetupTest() { + t.User = &proto.User{ + Id: faker.UUIDDigit(), + Email: faker.Email(), + Password: faker.Password(), + Firstname: faker.FirstName(), + Lastname: faker.LastName(), + Role: "user", + } + t.UserDto = &dto.User{ + Id: t.User.Id, + Firstname: t.User.Firstname, + Lastname: t.User.Lastname, + Email: t.User.Email, + } + + t.UpdateUserRequest = &dto.UpdateUserRequest{} + + t.ServiceDownErr = &dto.ResponseErr{ + StatusCode: http.StatusServiceUnavailable, + Message: "Service is down", + Data: nil, + } + + t.NotFoundErr = &dto.ResponseErr{ + StatusCode: http.StatusNotFound, + Message: errConst.UserNotFoundMessage, + Data: nil, + } + + t.InvalidIDErr = &dto.ResponseErr{ + StatusCode: http.StatusBadRequest, + Message: errConst.InvalidIDMessage, + Data: nil, + } + + t.BindErr = &dto.ResponseErr{ + StatusCode: http.StatusBadRequest, + Message: errConst.InvalidIDMessage, + } + + t.DuplicateEmailErr = &dto.ResponseErr{ + StatusCode: http.StatusConflict, + Message: errConst.DuplicateEmailMessage, + Data: nil, + } + + t.InternalErr = &dto.ResponseErr{ + StatusCode: http.StatusInternalServerError, + Message: errConst.InternalErrorMessage, + Data: nil, + } +} + +func (t *UserHandlerTest) TestFindOneSuccess() { + svcResp := t.UserDto + expectedResp := &dto.ResponseSuccess{ + StatusCode: http.StatusOK, + Message: userConst.FindOneUserSuccessMessage, + Data: t.UserDto, + } + + controller := gomock.NewController(t.T()) + + userSvc := userMock.NewMockService(controller) + validator := validatorMock.NewMockIDtoValidator(controller) + context := routerMock.NewMockIContext(controller) + + context.EXPECT().ID().Return(t.User.Id, nil) + userSvc.EXPECT().FindOne(t.User.Id).Return(svcResp, nil) + context.EXPECT().JSON(http.StatusOK, expectedResp) + + handler := NewHandler(userSvc, validator) + handler.FindOne(context) +} + +func (t *UserHandlerTest) TestFindOneNotFoundErr() { + controller := gomock.NewController(t.T()) + + userSvc := userMock.NewMockService(controller) + validator := validatorMock.NewMockIDtoValidator(controller) + context := routerMock.NewMockIContext(controller) + + context.EXPECT().ID().Return(t.User.Id, nil) + userSvc.EXPECT().FindOne(t.User.Id).Return(nil, t.NotFoundErr) + context.EXPECT().JSON(http.StatusNotFound, t.NotFoundErr) + + handler := NewHandler(userSvc, validator) + handler.FindOne(context) +} + +func (t *UserHandlerTest) TestFindOneInvalidIDErr() { + controller := gomock.NewController(t.T()) + + userSvc := userMock.NewMockService(controller) + validator := validatorMock.NewMockIDtoValidator(controller) + context := routerMock.NewMockIContext(controller) + + context.EXPECT().ID().Return("", errors.New("Invalid ID")) + context.EXPECT().JSON(http.StatusBadRequest, t.InvalidIDErr) + + handler := NewHandler(userSvc, validator) + handler.FindOne(context) +} + +func (t *UserHandlerTest) TestFindOneInternalErr() { + controller := gomock.NewController(t.T()) + + userSvc := userMock.NewMockService(controller) + validator := validatorMock.NewMockIDtoValidator(controller) + context := routerMock.NewMockIContext(controller) + + context.EXPECT().ID().Return(t.User.Id, nil) + userSvc.EXPECT().FindOne(t.User.Id).Return(nil, t.InternalErr) + context.EXPECT().JSON(http.StatusInternalServerError, t.InternalErr) + + handler := NewHandler(userSvc, validator) + handler.FindOne(context) +} + +func (t *UserHandlerTest) TestFindOneGrpcErr() { + controller := gomock.NewController(t.T()) + + userSvc := userMock.NewMockService(controller) + validator := validatorMock.NewMockIDtoValidator(controller) + context := routerMock.NewMockIContext(controller) + + context.EXPECT().ID().Return(t.User.Id, nil) + userSvc.EXPECT().FindOne(t.User.Id).Return(nil, t.ServiceDownErr) + context.EXPECT().JSON(http.StatusServiceUnavailable, t.ServiceDownErr) + + handler := NewHandler(userSvc, validator) + handler.FindOne(context) +} + +func (t *UserHandlerTest) TestUpdateSuccess() { + svcResp := t.UserDto + expectedResp := &dto.ResponseSuccess{ + StatusCode: http.StatusOK, + Message: userConst.UpdateUserSuccessMessage, + Data: t.UserDto, + } + + controller := gomock.NewController(t.T()) + + userSvc := userMock.NewMockService(controller) + validator := validatorMock.NewMockIDtoValidator(controller) + context := routerMock.NewMockIContext(controller) + + context.EXPECT().UserID().Return(t.User.Id) + context.EXPECT().Bind(t.UpdateUserRequest).Return(nil) + validator.EXPECT().Validate(t.UpdateUserRequest).Return(nil) + userSvc.EXPECT().Update(t.User.Id, t.UpdateUserRequest).Return(svcResp, nil) + context.EXPECT().JSON(http.StatusOK, expectedResp) + + handler := NewHandler(userSvc, validator) + handler.Update(context) +} + +func (t *UserHandlerTest) TestUpdateBindErr() { + bindErr := errors.New("Bind err") + expectedResp := &dto.ResponseErr{ + StatusCode: http.StatusBadRequest, + Message: constant.BindingRequestErrorMessage + bindErr.Error(), + Data: nil, + } + + controller := gomock.NewController(t.T()) + + userSvc := userMock.NewMockService(controller) + validator := validatorMock.NewMockIDtoValidator(controller) + context := routerMock.NewMockIContext(controller) + + context.EXPECT().UserID().Return(t.User.Id) + context.EXPECT().Bind(t.UpdateUserRequest).Return(bindErr) + context.EXPECT().JSON(http.StatusBadRequest, expectedResp) + + handler := NewHandler(userSvc, validator) + handler.Update(context) +} + +func (t *UserHandlerTest) TestUpdateValidateErr() { + errorMessage := []string{"First name is required", "Last name is required"} + validateErr := []*dto.BadReqErrResponse{ + { + Message: errorMessage[0], + FailedField: "firstname", + }, + { + Message: errorMessage[1], + FailedField: "lastname", + }, + } + expectedResp := &dto.ResponseErr{ + StatusCode: http.StatusBadRequest, + Message: constant.InvalidRequestBodyMessage + strings.Join(errorMessage, ", "), + Data: nil, + } + + controller := gomock.NewController(t.T()) + + userSvc := userMock.NewMockService(controller) + validator := validatorMock.NewMockIDtoValidator(controller) + context := routerMock.NewMockIContext(controller) + + context.EXPECT().UserID().Return(t.User.Id) + context.EXPECT().Bind(t.UpdateUserRequest).Return(nil) + validator.EXPECT().Validate(t.UpdateUserRequest).Return(validateErr) + context.EXPECT().JSON(http.StatusBadRequest, expectedResp) + + handler := NewHandler(userSvc, validator) + handler.Update(context) +} + +func (t *UserHandlerTest) TestUpdateDuplicateEmailErr() { + expectedResp := &dto.ResponseErr{ + StatusCode: http.StatusConflict, + Message: constant.DuplicateEmailMessage, + Data: nil, + } + + controller := gomock.NewController(t.T()) + + userSvc := userMock.NewMockService(controller) + validator := validatorMock.NewMockIDtoValidator(controller) + context := routerMock.NewMockIContext(controller) + + context.EXPECT().UserID().Return(t.User.Id) + context.EXPECT().Bind(t.UpdateUserRequest).Return(nil) + validator.EXPECT().Validate(t.UpdateUserRequest).Return(nil) + userSvc.EXPECT().Update(t.User.Id, t.UpdateUserRequest).Return(nil, t.DuplicateEmailErr) + context.EXPECT().JSON(http.StatusConflict, expectedResp) + + handler := NewHandler(userSvc, validator) + handler.Update(context) +} + +func (t *UserHandlerTest) TestUpdateInternalErr() { + controller := gomock.NewController(t.T()) + + userSvc := userMock.NewMockService(controller) + validator := validatorMock.NewMockIDtoValidator(controller) + context := routerMock.NewMockIContext(controller) + + context.EXPECT().UserID().Return(t.User.Id) + context.EXPECT().Bind(t.UpdateUserRequest).Return(nil) + validator.EXPECT().Validate(t.UpdateUserRequest).Return(nil) + userSvc.EXPECT().Update(t.User.Id, t.UpdateUserRequest).Return(nil, t.InternalErr) + context.EXPECT().JSON(http.StatusInternalServerError, t.InternalErr) + + handler := NewHandler(userSvc, validator) + handler.Update(context) +} + +func (t *UserHandlerTest) TestUpdateGrpcErr() { + controller := gomock.NewController(t.T()) + + userSvc := userMock.NewMockService(controller) + validator := validatorMock.NewMockIDtoValidator(controller) + context := routerMock.NewMockIContext(controller) + + context.EXPECT().UserID().Return(t.User.Id) + context.EXPECT().Bind(t.UpdateUserRequest).Return(nil) + validator.EXPECT().Validate(t.UpdateUserRequest).Return(nil) + userSvc.EXPECT().Update(t.User.Id, t.UpdateUserRequest).Return(nil, t.ServiceDownErr) + context.EXPECT().JSON(http.StatusServiceUnavailable, t.ServiceDownErr) + + handler := NewHandler(userSvc, validator) + handler.Update(context) +} + +func (t *UserHandlerTest) TestDeleteSuccess() { + deleteResp := &dto.DeleteUserResponse{ + Success: true, + } + expectedResp := &dto.ResponseSuccess{ + StatusCode: http.StatusOK, + Message: userConst.DeleteUserSuccessMessage, + Data: deleteResp, + } + + controller := gomock.NewController(t.T()) + + userSvc := userMock.NewMockService(controller) + validator := validatorMock.NewMockIDtoValidator(controller) + context := routerMock.NewMockIContext(controller) + + context.EXPECT().ID().Return(t.User.Id, nil) + userSvc.EXPECT().Delete(t.User.Id).Return(deleteResp, nil) + context.EXPECT().JSON(http.StatusOK, expectedResp) + + handler := NewHandler(userSvc, validator) + handler.Delete(context) +} + +func (t *UserHandlerTest) TestDeleteInvalidIDErr() { + controller := gomock.NewController(t.T()) + + userSvc := userMock.NewMockService(controller) + validator := validatorMock.NewMockIDtoValidator(controller) + context := routerMock.NewMockIContext(controller) + + context.EXPECT().ID().Return("", errors.New("Invalid ID")) + context.EXPECT().JSON(http.StatusBadRequest, t.InvalidIDErr) + + handler := NewHandler(userSvc, validator) + handler.Delete(context) +} + +func (t *UserHandlerTest) TestDeleteInternalErr() { + controller := gomock.NewController(t.T()) + + userSvc := userMock.NewMockService(controller) + validator := validatorMock.NewMockIDtoValidator(controller) + context := routerMock.NewMockIContext(controller) + + context.EXPECT().ID().Return(t.User.Id, nil) + userSvc.EXPECT().Delete(t.User.Id).Return(nil, t.InternalErr) + context.EXPECT().JSON(http.StatusInternalServerError, t.InternalErr) + + handler := NewHandler(userSvc, validator) + handler.Delete(context) +} + +func (t *UserHandlerTest) TestDeleteGrpcErr() { + controller := gomock.NewController(t.T()) + + userSvc := userMock.NewMockService(controller) + validator := validatorMock.NewMockIDtoValidator(controller) + context := routerMock.NewMockIContext(controller) + + context.EXPECT().ID().Return(t.User.Id, nil) + userSvc.EXPECT().Delete(t.User.Id).Return(nil, t.ServiceDownErr) + context.EXPECT().JSON(http.StatusServiceUnavailable, t.ServiceDownErr) + + handler := NewHandler(userSvc, validator) + handler.Delete(context) +} From 0c82d9b9c784678c74af7eb73e34e03a0832456e Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Tue, 9 Jan 2024 22:29:24 +0700 Subject: [PATCH 26/41] fix: remove validate in resp --- src/app/dto/user.dto.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/dto/user.dto.go b/src/app/dto/user.dto.go index c96fcab..8fc8b3a 100644 --- a/src/app/dto/user.dto.go +++ b/src/app/dto/user.dto.go @@ -15,5 +15,5 @@ type UpdateUserRequest struct { } type DeleteUserResponse struct { - Success bool `json:"success" validate:"required"` + Success bool `json:"success"` } From 974c192539ed4224d0b7e2f044bdf7a46c03c23e Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Tue, 9 Jan 2024 22:47:14 +0700 Subject: [PATCH 27/41] fix: user handler lighter sucess respo --- src/app/handler/user/user.handler.go | 19 +++---------------- src/app/handler/user/user.handler_test.go | 19 +++---------------- 2 files changed, 6 insertions(+), 32 deletions(-) diff --git a/src/app/handler/user/user.handler.go b/src/app/handler/user/user.handler.go index f281c60..4277361 100644 --- a/src/app/handler/user/user.handler.go +++ b/src/app/handler/user/user.handler.go @@ -8,7 +8,6 @@ import ( "github.com/isd-sgcu/johnjud-gateway/src/app/dto" "github.com/isd-sgcu/johnjud-gateway/src/app/router" "github.com/isd-sgcu/johnjud-gateway/src/app/validator" - userconst "github.com/isd-sgcu/johnjud-gateway/src/constant/user" "github.com/isd-sgcu/johnjud-gateway/src/pkg/service/user" ) @@ -50,11 +49,7 @@ func (h *Handler) FindOne(c router.IContext) { return } - c.JSON(http.StatusOK, &dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: userconst.FindOneUserSuccessMessage, - Data: user, - }) + c.JSON(http.StatusOK, user) return } @@ -104,11 +99,7 @@ func (h *Handler) Update(c router.IContext) { return } - c.JSON(http.StatusOK, &dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: userconst.UpdateUserSuccessMessage, - Data: user, - }) + c.JSON(http.StatusOK, user) return } @@ -142,10 +133,6 @@ func (h *Handler) Delete(c router.IContext) { return } - c.JSON(http.StatusOK, &dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: userconst.DeleteUserSuccessMessage, - Data: res, - }) + c.JSON(http.StatusOK, res) return } diff --git a/src/app/handler/user/user.handler_test.go b/src/app/handler/user/user.handler_test.go index e219baa..8757d2f 100644 --- a/src/app/handler/user/user.handler_test.go +++ b/src/app/handler/user/user.handler_test.go @@ -15,7 +15,6 @@ import ( validatorMock "github.com/isd-sgcu/johnjud-gateway/src/mocks/validator" errConst "github.com/isd-sgcu/johnjud-gateway/src/app/constant" - userConst "github.com/isd-sgcu/johnjud-gateway/src/constant/user" proto "github.com/isd-sgcu/johnjud-go-proto/johnjud/auth/user/v1" "github.com/stretchr/testify/suite" @@ -94,11 +93,7 @@ func (t *UserHandlerTest) SetupTest() { func (t *UserHandlerTest) TestFindOneSuccess() { svcResp := t.UserDto - expectedResp := &dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: userConst.FindOneUserSuccessMessage, - Data: t.UserDto, - } + expectedResp := t.UserDto controller := gomock.NewController(t.T()) @@ -175,11 +170,7 @@ func (t *UserHandlerTest) TestFindOneGrpcErr() { func (t *UserHandlerTest) TestUpdateSuccess() { svcResp := t.UserDto - expectedResp := &dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: userConst.UpdateUserSuccessMessage, - Data: t.UserDto, - } + expectedResp := t.UserDto controller := gomock.NewController(t.T()) @@ -313,11 +304,7 @@ func (t *UserHandlerTest) TestDeleteSuccess() { deleteResp := &dto.DeleteUserResponse{ Success: true, } - expectedResp := &dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: userConst.DeleteUserSuccessMessage, - Data: deleteResp, - } + expectedResp := deleteResp controller := gomock.NewController(t.T()) From 71c317591f9a5706269a88dcbb94b62131f8a684 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Tue, 9 Jan 2024 22:47:23 +0700 Subject: [PATCH 28/41] fix: pet handler lighter sucess resp --- src/app/handler/pet/pet.handler.go | 43 ++++--------------------- src/app/handler/pet/pet.handler_test.go | 43 ++++--------------------- 2 files changed, 14 insertions(+), 72 deletions(-) diff --git a/src/app/handler/pet/pet.handler.go b/src/app/handler/pet/pet.handler.go index 7dae48c..b249905 100644 --- a/src/app/handler/pet/pet.handler.go +++ b/src/app/handler/pet/pet.handler.go @@ -8,7 +8,6 @@ import ( "github.com/isd-sgcu/johnjud-gateway/src/app/dto" "github.com/isd-sgcu/johnjud-gateway/src/app/router" "github.com/isd-sgcu/johnjud-gateway/src/app/validator" - petconst "github.com/isd-sgcu/johnjud-gateway/src/constant/pet" imageSvc "github.com/isd-sgcu/johnjud-gateway/src/pkg/service/image" petSvc "github.com/isd-sgcu/johnjud-gateway/src/pkg/service/pet" ) @@ -40,11 +39,7 @@ func (h *Handler) FindAll(c router.IContext) { return } - c.JSON(http.StatusOK, dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: petconst.FindAllPetSuccessMessage, - Data: response, - }) + c.JSON(http.StatusOK, response) return } @@ -77,11 +72,7 @@ func (h *Handler) FindOne(c router.IContext) { return } - c.JSON(http.StatusOK, dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: petconst.FindOnePetSuccessMessage, - Data: response, - }) + c.JSON(http.StatusOK, response) return } @@ -128,11 +119,7 @@ func (h *Handler) Create(c router.IContext) { return } - c.JSON(http.StatusCreated, dto.ResponseSuccess{ - StatusCode: http.StatusCreated, - Message: petconst.CreatePetSuccessMessage, - Data: response, - }) + c.JSON(http.StatusCreated, response) return } @@ -191,11 +178,7 @@ func (h *Handler) Update(c router.IContext) { return } - c.JSON(http.StatusOK, dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: petconst.UpdatePetSuccessMessage, - Data: pet, - }) + c.JSON(http.StatusOK, pet) return } @@ -254,11 +237,7 @@ func (h *Handler) ChangeView(c router.IContext) { return } - c.JSON(http.StatusOK, dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: petconst.ChangeViewPetSuccessMessage, - Data: res, - }) + c.JSON(http.StatusOK, res) return } @@ -291,11 +270,7 @@ func (h *Handler) Delete(c router.IContext) { return } - c.JSON(http.StatusOK, dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: petconst.DeletePetSuccessMessage, - Data: res, - }) + c.JSON(http.StatusOK, res) return } @@ -354,10 +329,6 @@ func (h *Handler) Adopt(c router.IContext) { return } - c.JSON(http.StatusOK, dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: petconst.AdoptPetSuccessMessage, - Data: res, - }) + c.JSON(http.StatusOK, res) return } diff --git a/src/app/handler/pet/pet.handler_test.go b/src/app/handler/pet/pet.handler_test.go index 659e221..fc96046 100644 --- a/src/app/handler/pet/pet.handler_test.go +++ b/src/app/handler/pet/pet.handler_test.go @@ -16,7 +16,6 @@ import ( errConst "github.com/isd-sgcu/johnjud-gateway/src/app/constant" utils "github.com/isd-sgcu/johnjud-gateway/src/app/utils/pet" - petConst "github.com/isd-sgcu/johnjud-gateway/src/constant/pet" petProto "github.com/isd-sgcu/johnjud-go-proto/johnjud/backend/pet/v1" imgProto "github.com/isd-sgcu/johnjud-go-proto/johnjud/file/image/v1" @@ -131,11 +130,7 @@ func (t *PetHandlerTest) SetupTest() { func (t *PetHandlerTest) TestFindAllSuccess() { findAllResponse := utils.ProtoToDtoList(t.Pets, t.ImagesList) - expectedResponse := dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: petConst.FindAllPetSuccessMessage, - Data: findAllResponse, - } + expectedResponse := findAllResponse controller := gomock.NewController(t.T()) @@ -153,11 +148,7 @@ func (t *PetHandlerTest) TestFindAllSuccess() { func (t *PetHandlerTest) TestFindOneSuccess() { findOneResponse := utils.ProtoToDto(t.Pet, t.Images) - expectedResponse := dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: petConst.FindOnePetSuccessMessage, - Data: findOneResponse, - } + expectedResponse := findOneResponse controller := gomock.NewController(t.T()) @@ -212,11 +203,7 @@ func (t *PetHandlerTest) TestFindOneGrpcErr() { func (t *PetHandlerTest) TestCreateSuccess() { createResponse := utils.ProtoToDto(t.Pet, t.Images) - expectedResponse := dto.ResponseSuccess{ - StatusCode: http.StatusCreated, - Message: petConst.CreatePetSuccessMessage, - Data: createResponse, - } + expectedResponse := createResponse controller := gomock.NewController(t.T()) @@ -255,11 +242,7 @@ func (t *PetHandlerTest) TestCreateGrpcErr() { func (t *PetHandlerTest) TestUpdateSuccess() { updateResponse := utils.ProtoToDto(t.Pet, t.Images) - expectedResponse := dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: petConst.UpdatePetSuccessMessage, - Data: updateResponse, - } + expectedResponse := updateResponse controller := gomock.NewController(t.T()) @@ -322,11 +305,7 @@ func (t *PetHandlerTest) TestDeleteSuccess() { deleteResponse := &dto.DeleteResponse{ Success: true, } - expectedResponse := dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: petConst.DeletePetSuccessMessage, - Data: deleteResponse, - } + expectedResponse := deleteResponse controller := gomock.NewController(t.T()) @@ -386,11 +365,7 @@ func (t *PetHandlerTest) TestChangeViewSuccess() { changeViewResponse := &dto.ChangeViewPetResponse{ Success: true, } - expectedResponse := dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: petConst.ChangeViewPetSuccessMessage, - Data: changeViewResponse, - } + expectedResponse := changeViewResponse controller := gomock.NewController(t.T()) @@ -457,11 +432,7 @@ func (t *PetHandlerTest) TestAdoptSuccess() { adoptByResponse := &dto.AdoptByResponse{ Success: true, } - expectedResponse := dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: petConst.AdoptPetSuccessMessage, - Data: adoptByResponse, - } + expectedResponse := adoptByResponse controller := gomock.NewController(t.T()) From 797e5a473056c26a50fbcec33a1a49a6671a73ef Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Tue, 9 Jan 2024 22:51:22 +0700 Subject: [PATCH 29/41] fix: like handler use lighter success resp --- src/app/dto/common.dto.go | 6 ------ src/app/handler/like/like.handler.go | 19 +++---------------- src/app/handler/like/like.handler_test.go | 19 +++---------------- 3 files changed, 6 insertions(+), 38 deletions(-) diff --git a/src/app/dto/common.dto.go b/src/app/dto/common.dto.go index ba64d2d..611c90e 100644 --- a/src/app/dto/common.dto.go +++ b/src/app/dto/common.dto.go @@ -67,9 +67,3 @@ type ResponseGatewayTimeoutErr struct { Message string `json:"message" example:"Connection timeout"` Data interface{} `json:"data"` } - -type ResponseSuccess struct { - StatusCode int `json:"status_code" example:"200"` - Message string `json:"message" example:"success"` - Data interface{} `json:"data"` -} diff --git a/src/app/handler/like/like.handler.go b/src/app/handler/like/like.handler.go index ab57fd8..accafc0 100644 --- a/src/app/handler/like/like.handler.go +++ b/src/app/handler/like/like.handler.go @@ -8,7 +8,6 @@ import ( "github.com/isd-sgcu/johnjud-gateway/src/app/dto" "github.com/isd-sgcu/johnjud-gateway/src/app/router" "github.com/isd-sgcu/johnjud-gateway/src/app/validator" - likeConst "github.com/isd-sgcu/johnjud-gateway/src/constant/like" likeSvc "github.com/isd-sgcu/johnjud-gateway/src/pkg/service/like" ) @@ -38,11 +37,7 @@ func (h *Handler) FindByUserId(c router.IContext) { return } - c.JSON(http.StatusOK, dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: likeConst.FindLikeSuccessMessage, - Data: response, - }) + c.JSON(http.StatusOK, response) return } @@ -77,11 +72,7 @@ func (h *Handler) Create(c router.IContext) { return } - c.JSON(http.StatusCreated, dto.ResponseSuccess{ - StatusCode: http.StatusCreated, - Message: likeConst.CreateLikeSuccessMessage, - Data: response, - }) + c.JSON(http.StatusCreated, response) return } @@ -102,10 +93,6 @@ func (h *Handler) Delete(c router.IContext) { return } - c.JSON(http.StatusOK, dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: likeConst.DelteLikeSuccessMessage, - Data: res, - }) + c.JSON(http.StatusOK, res) return } diff --git a/src/app/handler/like/like.handler_test.go b/src/app/handler/like/like.handler_test.go index db72655..ed7debe 100644 --- a/src/app/handler/like/like.handler_test.go +++ b/src/app/handler/like/like.handler_test.go @@ -9,7 +9,6 @@ import ( errConst "github.com/isd-sgcu/johnjud-gateway/src/app/constant" "github.com/isd-sgcu/johnjud-gateway/src/app/dto" utils "github.com/isd-sgcu/johnjud-gateway/src/app/utils/like" - likeConst "github.com/isd-sgcu/johnjud-gateway/src/constant/like" routerMock "github.com/isd-sgcu/johnjud-gateway/src/mocks/router" likeMock "github.com/isd-sgcu/johnjud-gateway/src/mocks/service/like" validatorMock "github.com/isd-sgcu/johnjud-gateway/src/mocks/validator" @@ -74,11 +73,7 @@ func (t *LikeHandlerTest) SetupTest() { func (t *LikeHandlerTest) TestFindLikesSuccess() { findLikeResponse := utils.ProtoToDtoList(t.Likes) - expectedResponse := dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: likeConst.FindLikeSuccessMessage, - Data: findLikeResponse, - } + expectedResponse := findLikeResponse controller := gomock.NewController(t.T()) @@ -147,11 +142,7 @@ func (t *LikeHandlerTest) TestFindLikeInternalError() { func (t *LikeHandlerTest) TestCreateSuccess() { createLikeResponse := utils.ProtoToDto(t.Like) - expectedResponse := dto.ResponseSuccess{ - StatusCode: http.StatusCreated, - Message: likeConst.CreateLikeSuccessMessage, - Data: createLikeResponse, - } + expectedResponse := createLikeResponse controller := gomock.NewController(t.T()) @@ -208,11 +199,7 @@ func (t *LikeHandlerTest) TestDeleteSuccess() { deleteResponse := &dto.DeleteLikeResponse{ Success: true, } - expectedResponse := dto.ResponseSuccess{ - StatusCode: http.StatusOK, - Message: likeConst.DelteLikeSuccessMessage, - Data: deleteResponse, - } + expectedResponse := deleteResponse controller := gomock.NewController(t.T()) From 88d4f6d1dea20d6cf72ad5b350e3ecaeeca9684a Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Tue, 9 Jan 2024 23:22:51 +0700 Subject: [PATCH 30/41] fix: pet create url --- src/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.go b/src/main.go index c5cc95e..d5d3306 100644 --- a/src/main.go +++ b/src/main.go @@ -132,7 +132,7 @@ func main() { r.GetPet("/", petHandler.FindAll) r.GetPet("/:id", petHandler.FindOne) - r.PostPet("/create", petHandler.Create) + r.PostPet("/", petHandler.Create) r.PutPet("/:id", petHandler.Update) r.PutPet("/:id/adopt", petHandler.Adopt) r.PutPet("/:id/visible", petHandler.ChangeView) From b625e8d33dc384b749cda2face6b1c0e067ad648 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Tue, 9 Jan 2024 23:24:30 +0700 Subject: [PATCH 31/41] feat: add admin paths --- src/constant/auth/auth.constant.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/constant/auth/auth.constant.go b/src/constant/auth/auth.constant.go index 663e711..aef786f 100644 --- a/src/constant/auth/auth.constant.go +++ b/src/constant/auth/auth.constant.go @@ -4,11 +4,18 @@ var ExcludePath = map[string]struct{}{ "POST /auth/signup": {}, "POST /auth/signin": {}, "POST /auth/verify": {}, - "GET /pet/": {}, + "GET /pets/": {}, "GET /adopt/": {}, } -var AdminPath = map[string]struct{}{} +var AdminPath = map[string]struct{}{ + "DELETE /users/:id": {}, + "POST /pets/": {}, + "PUT /pets/:id": {}, + "PUT /pets/:id/visible": {}, + "DELETE /pets/:id": {}, + //need to add image upload, delete, assignpet +} var VersionList = map[string]struct{}{ "v1": {}, From 4e497d0e5cd50164a4ba11959adcc2f7ee817211 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Tue, 9 Jan 2024 23:39:24 +0700 Subject: [PATCH 32/41] fix: auth config --- config/config.example.yaml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/config/config.example.yaml b/config/config.example.yaml index f5e400a..1a12b6b 100644 --- a/config/config.example.yaml +++ b/config/config.example.yaml @@ -3,6 +3,10 @@ app: debug: true service: - auth: auth:3002 - backend: backend:3003 - file: file:3004 \ No newline at end of file + auth: localhost:3002 + backend: localhost:3003 + file: localhost:3004 + # Production, when gateway in a container in same network + # auth: auth:3002 + # backend: backend:3003 + # file: file:3004 \ No newline at end of file From 4de877ffea1bc9b3ea2a103d0ba9be4ed69b2331 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Wed, 10 Jan 2024 00:13:32 +0700 Subject: [PATCH 33/41] fix: url endpoints not ending in / --- src/main.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main.go b/src/main.go index d5d3306..f180270 100644 --- a/src/main.go +++ b/src/main.go @@ -119,7 +119,7 @@ func main() { r := router.NewFiberRouter(&authGuard, conf.App) r.GetUser("/:id", userHandler.FindOne) - r.PutUser("/", userHandler.Update) + r.PutUser("", userHandler.Update) r.DeleteUser("/:id", userHandler.Delete) r.PostAuth("/signup", authHandler.Signup) @@ -128,18 +128,18 @@ func main() { //r.PostAuth("/me", authHandler.Validate) r.PostAuth("/refreshToken", authHandler.RefreshToken) - r.GetHealthCheck("/", hc.HealthCheck) + r.GetHealthCheck("", hc.HealthCheck) - r.GetPet("/", petHandler.FindAll) + r.GetPet("", petHandler.FindAll) r.GetPet("/:id", petHandler.FindOne) - r.PostPet("/", petHandler.Create) + r.PostPet("", petHandler.Create) r.PutPet("/:id", petHandler.Update) r.PutPet("/:id/adopt", petHandler.Adopt) r.PutPet("/:id/visible", petHandler.ChangeView) r.DeletePet("/:id", petHandler.Delete) r.GetLike("/:id", likeHandler.FindByUserId) - r.PostLike("/", likeHandler.Create) + r.PostLike("", likeHandler.Create) r.DeleteLike("/:id", likeHandler.Delete) v1 := router.NewAPIv1(r, conf.App) From 44cd89ffb732250aa20dc6d0be771af6442a4f5e Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Wed, 10 Jan 2024 00:13:55 +0700 Subject: [PATCH 34/41] fix: auth middleware detect :id --- src/app/middleware/auth/auth.middleware.go | 4 +- src/app/utils/auth/auth.utils.go | 59 +++++++++++++++++++++- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/app/middleware/auth/auth.middleware.go b/src/app/middleware/auth/auth.middleware.go index 0d2430d..8fe46ed 100644 --- a/src/app/middleware/auth/auth.middleware.go +++ b/src/app/middleware/auth/auth.middleware.go @@ -33,8 +33,10 @@ func NewAuthGuard(s authPkg.Service, e map[string]struct{}, a map[string]struct{ func (m *Guard) Use(ctx router.IContext) error { method := ctx.Method() path := ctx.Path() + path = utils.TrimInList(path, "/", m.versionList) - path = auth.FormatPath(method, path) + ids := auth.FindIDFromPath(path) + path = auth.FormatPath(method, path, ids) if utils.IsExisted(m.excludes, path) { return ctx.Next() } diff --git a/src/app/utils/auth/auth.utils.go b/src/app/utils/auth/auth.utils.go index 18de087..5a05f51 100644 --- a/src/app/utils/auth/auth.utils.go +++ b/src/app/utils/auth/auth.utils.go @@ -2,8 +2,65 @@ package auth import ( "fmt" + "strconv" + "strings" + + "github.com/google/uuid" ) -func FormatPath(method string, path string) string { +func IsExisted(e map[string]struct{}, key string) bool { + _, ok := e[key] + if ok { + return true + } + return false +} + +func FormatPath(method string, path string, keys []string) string { + for _, key := range keys { + path = strings.Replace(path, key, ":id", 1) + } + return fmt.Sprintf("%v %v", method, path) } + +func FindIntFromStr(s string, sep string) []string { + spliteds := strings.Split(s, sep) + + var result []string + + for _, splited := range spliteds { + _, err := strconv.Atoi(splited) + if err == nil { + result = append(result, splited) + } + } + + return result +} + +func FindUUIDFromStr(s string, sep string) []string { + spliteds := strings.Split(s, sep) + + var result []string + + for _, splited := range spliteds { + _, err := uuid.Parse(splited) + if err == nil { + result = append(result, splited) + } + } + + return result +} + +func MergeStringSlice(s1 []string, s2 []string) []string { + return append(s1, s2...) +} + +func FindIDFromPath(path string) []string { + uuids := FindUUIDFromStr(path, "/") + ids := FindIntFromStr(path, "/") + + return MergeStringSlice(ids, uuids) +} From 6fb9623ba50bb52182a293d923bf0384b811104e Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Wed, 10 Jan 2024 00:14:06 +0700 Subject: [PATCH 35/41] fix: paths --- src/constant/auth/auth.constant.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/constant/auth/auth.constant.go b/src/constant/auth/auth.constant.go index aef786f..3cf5931 100644 --- a/src/constant/auth/auth.constant.go +++ b/src/constant/auth/auth.constant.go @@ -4,13 +4,14 @@ var ExcludePath = map[string]struct{}{ "POST /auth/signup": {}, "POST /auth/signin": {}, "POST /auth/verify": {}, - "GET /pets/": {}, - "GET /adopt/": {}, + "GET /user/:id": {}, + "GET /pets": {}, + "GET /adopt": {}, } var AdminPath = map[string]struct{}{ "DELETE /users/:id": {}, - "POST /pets/": {}, + "POST /pets": {}, "PUT /pets/:id": {}, "PUT /pets/:id/visible": {}, "DELETE /pets/:id": {}, From 46f26d82a1e14394035036a34cb81087ceb1b982 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Wed, 10 Jan 2024 00:45:59 +0700 Subject: [PATCH 36/41] fix: auth cache --- config/auth/config.example.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/auth/config.example.yaml b/config/auth/config.example.yaml index 6db63c4..50d989a 100644 --- a/config/auth/config.example.yaml +++ b/config/auth/config.example.yaml @@ -17,7 +17,7 @@ jwt: issuer: redis: - host: localhost + host: local-cache port: 6379 password: "" dbnum: 0 \ No newline at end of file From f9a2f07ce217879597c68b54ad452377a61c9f7a Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Wed, 10 Jan 2024 00:53:31 +0700 Subject: [PATCH 37/41] fix: pet dto --- go.mod | 2 +- go.sum | 2 ++ src/app/dto/pet.dto.go | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index c0a6d31..ea78af7 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/gofiber/fiber/v2 v2.52.0 github.com/golang/mock v1.6.0 github.com/google/uuid v1.5.0 - github.com/isd-sgcu/johnjud-go-proto v0.2.2 + github.com/isd-sgcu/johnjud-go-proto v0.3.1 github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.31.0 github.com/spf13/viper v1.18.2 diff --git a/go.sum b/go.sum index d5858c6..13ffa07 100644 --- a/go.sum +++ b/go.sum @@ -68,6 +68,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/isd-sgcu/johnjud-go-proto v0.2.2 h1:TOAmbwy/I+8/J5LPZH0ZN7lSLczBiZe1fs88gH8XrhY= github.com/isd-sgcu/johnjud-go-proto v0.2.2/go.mod h1:1OK6aiCgtXQiLhxp0r6iLEejYIRpckWQZDrCZ9Trbo4= +github.com/isd-sgcu/johnjud-go-proto v0.3.1 h1:WyWfzl+5nWOw3AmINtcTfojg4CJh8ZRNbZC6qA//OXU= +github.com/isd-sgcu/johnjud-go-proto v0.3.1/go.mod h1:1OK6aiCgtXQiLhxp0r6iLEejYIRpckWQZDrCZ9Trbo4= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= diff --git a/src/app/dto/pet.dto.go b/src/app/dto/pet.dto.go index d6b7ce3..6d4532e 100644 --- a/src/app/dto/pet.dto.go +++ b/src/app/dto/pet.dto.go @@ -36,6 +36,8 @@ type CreatePetRequest struct { Name string `json:"name" validate:"required"` Birthdate string `json:"birthdate" validate:"required"` Gender pet.Gender `json:"gender" validate:"required" example:"1"` + Color string `json:"color" validate:"required"` + Pattern string `json:"pattern" validate:"required"` Habit string `json:"habit" validate:"required"` Caption string `json:"caption"` Status pet.Status `json:"status" validate:"required" example:"1"` @@ -43,7 +45,7 @@ type CreatePetRequest struct { IsVaccinated *bool `json:"is_vaccinated" validate:"required"` IsVisible *bool `json:"is_visible" validate:"required"` IsClubPet *bool `json:"is_club_pet" validate:"required"` - Background string `json:"background"` + Origin string `json:"origin"` Address string `json:"address"` Contact string `json:"contact"` AdoptBy string `json:"adopt_by"` From a3370027ca4e585030afeaf573b9a50c1c1daafb Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Wed, 10 Jan 2024 01:03:42 +0700 Subject: [PATCH 38/41] feat: new pet type --- src/app/dto/pet.dto.go | 14 ++++++---- src/app/utils/pet/pet.utils.go | 46 +++++++++++++++++++------------- src/constant/pet/pet.constant.go | 22 +++++++-------- 3 files changed, 47 insertions(+), 35 deletions(-) diff --git a/src/app/dto/pet.dto.go b/src/app/dto/pet.dto.go index 6d4532e..717717d 100644 --- a/src/app/dto/pet.dto.go +++ b/src/app/dto/pet.dto.go @@ -16,6 +16,8 @@ type PetResponse struct { Name string `json:"name"` Birthdate string `json:"birthdate"` Gender pet.Gender `json:"gender"` + Color string `json:"color"` + Pattern string `json:"pattern"` Habit string `json:"habit"` Caption string `json:"caption"` Status pet.Status `json:"status"` @@ -23,7 +25,7 @@ type PetResponse struct { IsVaccinated *bool `json:"is_vaccinated"` IsVisible *bool `json:"is_visible"` IsClubPet *bool `json:"is_club_pet"` - Background string `json:"background"` + Origin string `json:"origin"` Address string `json:"address"` Contact string `json:"contact"` AdoptBy string `json:"adopt_by"` @@ -35,17 +37,17 @@ type CreatePetRequest struct { Species string `json:"species" validate:"required"` Name string `json:"name" validate:"required"` Birthdate string `json:"birthdate" validate:"required"` - Gender pet.Gender `json:"gender" validate:"required" example:"1"` + Gender pet.Gender `json:"gender" validate:"required" example:"male"` Color string `json:"color" validate:"required"` Pattern string `json:"pattern" validate:"required"` Habit string `json:"habit" validate:"required"` Caption string `json:"caption"` - Status pet.Status `json:"status" validate:"required" example:"1"` + Status pet.Status `json:"status" validate:"required" example:"findhome"` IsSterile *bool `json:"is_sterile" validate:"required"` IsVaccinated *bool `json:"is_vaccinated" validate:"required"` IsVisible *bool `json:"is_visible" validate:"required"` IsClubPet *bool `json:"is_club_pet" validate:"required"` - Origin string `json:"origin"` + Origin string `json:"origin" validate:"required"` Address string `json:"address"` Contact string `json:"contact"` AdoptBy string `json:"adopt_by"` @@ -75,6 +77,8 @@ type UpdatePetRequest struct { Name string `json:"name"` Birthdate string `json:"birthdate"` Gender pet.Gender `json:"gender"` + Color string `json:"color"` + Pattern string `json:"pattern"` Habit string `json:"habit"` Caption string `json:"caption"` Status pet.Status `json:"status"` @@ -82,7 +86,7 @@ type UpdatePetRequest struct { IsVaccinated *bool `json:"is_vaccinated"` IsVisible *bool `json:"is_visible"` IsClubPet *bool `json:"is_club_pet"` - Background string `json:"background"` + Origin string `json:"origin"` Address string `json:"address"` Contact string `json:"contact"` AdoptBy string `json:"adopt_by"` diff --git a/src/app/utils/pet/pet.utils.go b/src/app/utils/pet/pet.utils.go index 1f68987..434f820 100644 --- a/src/app/utils/pet/pet.utils.go +++ b/src/app/utils/pet/pet.utils.go @@ -35,6 +35,8 @@ func ProtoToDto(in *petproto.Pet, images []*imgproto.Image) *dto.PetResponse { Name: in.Name, Birthdate: in.Birthdate, Gender: pet.Gender(in.Gender), + Color: in.Color, + Pattern: in.Pattern, Habit: in.Habit, Caption: in.Caption, Status: pet.Status(in.Status), @@ -42,7 +44,7 @@ func ProtoToDto(in *petproto.Pet, images []*imgproto.Image) *dto.PetResponse { IsVaccinated: &in.IsVaccinated, IsVisible: &in.IsVisible, IsClubPet: &in.IsClubPet, - Background: in.Background, + Origin: in.Origin, Address: in.Address, Contact: in.Contact, AdoptBy: in.AdoptBy, @@ -58,16 +60,18 @@ func CreateDtoToProto(in *dto.CreatePetRequest) *petproto.CreatePetRequest { Species: in.Species, Name: in.Name, Birthdate: in.Birthdate, - Gender: petproto.Gender(in.Gender), + Gender: string(in.Gender), + Color: in.Color, + Pattern: in.Pattern, Habit: in.Habit, Caption: in.Caption, Images: []*imgproto.Image{}, - Status: petproto.PetStatus(in.Status), + Status: string(in.Status), IsSterile: *in.IsSterile, IsVaccinated: *in.IsVaccinated, IsVisible: *in.IsVisible, IsClubPet: *in.IsClubPet, - Background: in.Background, + Origin: in.Origin, Address: in.Address, Contact: in.Contact, AdoptBy: in.AdoptBy, @@ -78,20 +82,22 @@ func CreateDtoToProto(in *dto.CreatePetRequest) *petproto.CreatePetRequest { func UpdateDtoToProto(id string, in *dto.UpdatePetRequest) *petproto.UpdatePetRequest { req := &petproto.UpdatePetRequest{ Pet: &petproto.Pet{ - Id: id, - Type: in.Type, - Species: in.Species, - Name: in.Name, - Birthdate: in.Birthdate, - Gender: petproto.Gender(in.Gender), - Habit: in.Habit, - Caption: in.Caption, - Images: []*imgproto.Image{}, - Status: petproto.PetStatus(in.Status), - Background: in.Background, - Address: in.Address, - Contact: in.Contact, - AdoptBy: in.AdoptBy, + Id: id, + Type: in.Type, + Species: in.Species, + Name: in.Name, + Birthdate: in.Birthdate, + Gender: string(in.Gender), + Color: in.Color, + Pattern: in.Pattern, + Habit: in.Habit, + Caption: in.Caption, + Images: []*imgproto.Image{}, + Status: string(in.Status), + Origin: in.Origin, + Address: in.Address, + Contact: in.Contact, + AdoptBy: in.AdoptBy, }, } @@ -132,6 +138,8 @@ func ProtoToDtoList(in []*petproto.Pet, imagesList [][]*imgproto.Image) []*dto.P Name: p.Name, Birthdate: p.Birthdate, Gender: pet.Gender(p.Gender), + Color: p.Color, + Pattern: p.Pattern, Habit: p.Habit, Caption: p.Caption, Status: pet.Status(p.Status), @@ -139,7 +147,7 @@ func ProtoToDtoList(in []*petproto.Pet, imagesList [][]*imgproto.Image) []*dto.P IsVaccinated: &p.IsVaccinated, IsVisible: &p.IsVisible, IsClubPet: &p.IsClubPet, - Background: p.Background, + Origin: p.Origin, Address: p.Address, Contact: p.Contact, AdoptBy: p.AdoptBy, diff --git a/src/constant/pet/pet.constant.go b/src/constant/pet/pet.constant.go index 4ff078c..d2428f6 100644 --- a/src/constant/pet/pet.constant.go +++ b/src/constant/pet/pet.constant.go @@ -6,18 +6,18 @@ import ( "strings" ) -type Gender int +type Gender string const ( - MALE = 1 - FEMALE = 2 + MALE Gender = "male" + FEMALE Gender = "female" ) -type Status int +type Status string const ( - ADOPTED = 1 - FINDHOME = 2 + ADOPTED Status = "adopted" + FINDHOME Status = "findhome" ) func (g *Gender) UnmarshalJSON(data []byte) error { @@ -28,10 +28,10 @@ func (g *Gender) UnmarshalJSON(data []byte) error { s = strings.ToUpper(s) switch s { case "MALE": - *g = Gender(1) + *g = MALE return nil case "FEMALE": - *g = Gender(2) + *g = FEMALE return nil default: @@ -47,14 +47,14 @@ func (st *Status) UnmarshalJSON(data []byte) error { s = strings.ToUpper(s) switch s { case "ADOPTED": - *st = Status(1) + *st = ADOPTED return nil case "FINDHOME": - *st = Status(2) + *st = FINDHOME return nil default: - return errors.New("invalid gender") + return errors.New("invalid status") } } From 66522a52bfc1eedebd0f47a2246ec8e0513eae83 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Wed, 10 Jan 2024 01:03:51 +0700 Subject: [PATCH 39/41] fix: auth client mock --- src/mocks/client/auth/auth.mock.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/mocks/client/auth/auth.mock.go b/src/mocks/client/auth/auth.mock.go index 873ce2e..7474f16 100644 --- a/src/mocks/client/auth/auth.mock.go +++ b/src/mocks/client/auth/auth.mock.go @@ -2,6 +2,7 @@ package auth import ( "context" + authProto "github.com/isd-sgcu/johnjud-go-proto/johnjud/auth/auth/v1" "github.com/stretchr/testify/mock" "google.golang.org/grpc" @@ -45,3 +46,17 @@ func (m *AuthClientMock) SignOut(_ context.Context, in *authProto.SignOutRequest err, _ := args.Get(1).(error) return resp, err } + +func (m *AuthClientMock) ForgotPassword(_ context.Context, in *authProto.ForgotPasswordRequest, _ ...grpc.CallOption) (*authProto.ForgotPasswordResponse, error) { + args := m.Called(in) + resp, _ := args.Get(0).(*authProto.ForgotPasswordResponse) + err, _ := args.Get(1).(error) + return resp, err +} + +func (m *AuthClientMock) ResetPassword(_ context.Context, in *authProto.ResetPasswordRequest, _ ...grpc.CallOption) (*authProto.ResetPasswordResponse, error) { + args := m.Called(in) + resp, _ := args.Get(0).(*authProto.ResetPasswordResponse) + err, _ := args.Get(1).(error) + return resp, err +} From 73d4a048aee8b70d50fe224b3c1a2cb09f02f801 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Wed, 10 Jan 2024 01:03:58 +0700 Subject: [PATCH 40/41] fix: pet tests --- src/app/handler/pet/pet.handler_test.go | 15 +++++++++++---- src/app/service/pet/pet.service_test.go | 22 ++++++++++++++++------ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/app/handler/pet/pet.handler_test.go b/src/app/handler/pet/pet.handler_test.go index 659e221..d720170 100644 --- a/src/app/handler/pet/pet.handler_test.go +++ b/src/app/handler/pet/pet.handler_test.go @@ -49,6 +49,9 @@ func (t *PetHandlerTest) SetupTest() { t.ImagesList = imagesList t.Images = imagesList[0] var pets []*petProto.Pet + genders := []petConst.Gender{petConst.MALE, petConst.FEMALE} + statuses := []petConst.Status{petConst.ADOPTED, petConst.FINDHOME} + for i := 0; i <= 3; i++ { pet := &petProto.Pet{ Id: faker.UUIDDigit(), @@ -56,16 +59,18 @@ func (t *PetHandlerTest) SetupTest() { Species: faker.Word(), Name: faker.Name(), Birthdate: faker.Word(), - Gender: petProto.Gender(rand.Intn(1) + 1), + Gender: string(genders[rand.Intn(2)]), + Color: faker.Word(), + Pattern: faker.Word(), Habit: faker.Paragraph(), Caption: faker.Paragraph(), Images: []*imgProto.Image{}, - Status: petProto.PetStatus(rand.Intn(1) + 1), + Status: string(statuses[rand.Intn(2)]), IsSterile: true, IsVaccinated: true, IsVisible: true, IsClubPet: true, - Background: faker.Paragraph(), + Origin: faker.Paragraph(), Address: faker.Paragraph(), Contact: faker.Paragraph(), AdoptBy: "", @@ -84,6 +89,8 @@ func (t *PetHandlerTest) SetupTest() { Name: t.Pet.Name, Birthdate: t.Pet.Birthdate, Gender: pet.Gender(t.Pet.Gender), + Color: t.Pet.Color, + Pattern: t.Pet.Pattern, Habit: t.Pet.Habit, Caption: t.Pet.Caption, Status: pet.Status(t.Pet.Status), @@ -91,7 +98,7 @@ func (t *PetHandlerTest) SetupTest() { IsVaccinated: &t.Pet.IsVaccinated, IsVisible: &t.Pet.IsVisible, IsClubPet: &t.Pet.IsClubPet, - Background: t.Pet.Background, + Origin: t.Pet.Origin, Address: t.Pet.Address, Contact: t.Pet.Contact, AdoptBy: t.Pet.AdoptBy, diff --git a/src/app/service/pet/pet.service_test.go b/src/app/service/pet/pet.service_test.go index 5705c12..f32efac 100644 --- a/src/app/service/pet/pet.service_test.go +++ b/src/app/service/pet/pet.service_test.go @@ -51,6 +51,8 @@ func (t *PetServiceTest) SetupTest() { imagesList := utils.MockImageList(3) t.ImagesList = imagesList t.Images = imagesList[0] + genders := []pet.Gender{pet.MALE, pet.FEMALE} + statuses := []pet.Status{pet.ADOPTED, pet.FINDHOME} var pets []*petproto.Pet for i := 0; i <= 3; i++ { @@ -60,16 +62,18 @@ func (t *PetServiceTest) SetupTest() { Species: faker.Word(), Name: faker.Name(), Birthdate: faker.Word(), - Gender: petproto.Gender(rand.Intn(1) + 1), + Gender: string(genders[rand.Intn(2)]), + Color: faker.Word(), + Pattern: faker.Word(), Habit: faker.Paragraph(), Caption: faker.Paragraph(), Images: imagesList[i], - Status: petproto.PetStatus(rand.Intn(1) + 1), + Status: string(statuses[rand.Intn(2)]), IsSterile: true, IsVaccinated: true, IsVisible: true, IsClubPet: true, - Background: faker.Paragraph(), + Origin: faker.Paragraph(), Address: faker.Paragraph(), Contact: faker.Paragraph(), AdoptBy: faker.UUIDDigit(), @@ -88,6 +92,8 @@ func (t *PetServiceTest) SetupTest() { Name: t.Pet.Name, Birthdate: t.Pet.Birthdate, Gender: t.Pet.Gender, + Color: t.Pet.Color, + Pattern: t.Pet.Pattern, Habit: t.Pet.Habit, Caption: t.Pet.Caption, Images: t.Pet.Images, @@ -96,7 +102,7 @@ func (t *PetServiceTest) SetupTest() { IsVaccinated: t.Pet.IsVaccinated, IsVisible: false, IsClubPet: t.Pet.IsClubPet, - Background: t.Pet.Background, + Origin: t.Pet.Origin, Address: t.Pet.Address, Contact: t.Pet.Contact, AdoptBy: t.Pet.AdoptBy, @@ -110,6 +116,8 @@ func (t *PetServiceTest) SetupTest() { Name: t.Pet.Name, Birthdate: t.Pet.Birthdate, Gender: pet.Gender(t.Pet.Gender), + Color: t.Pet.Color, + Pattern: t.Pet.Pattern, Habit: t.Pet.Habit, Caption: t.Pet.Caption, Images: []string{}, @@ -118,7 +126,7 @@ func (t *PetServiceTest) SetupTest() { IsVaccinated: &t.Pet.IsVaccinated, IsVisible: &t.Pet.IsVisible, IsClubPet: &t.Pet.IsClubPet, - Background: t.Pet.Background, + Origin: t.Pet.Origin, Address: t.Pet.Address, Contact: t.Pet.Contact, AdoptBy: t.Pet.AdoptBy, @@ -130,6 +138,8 @@ func (t *PetServiceTest) SetupTest() { Name: t.Pet.Name, Birthdate: t.Pet.Birthdate, Gender: pet.Gender(t.Pet.Gender), + Color: t.Pet.Color, + Pattern: t.Pet.Pattern, Habit: t.Pet.Habit, Caption: t.Pet.Caption, Images: []string{}, @@ -138,7 +148,7 @@ func (t *PetServiceTest) SetupTest() { IsVaccinated: &t.Pet.IsVaccinated, IsVisible: &t.Pet.IsVisible, IsClubPet: &t.Pet.IsClubPet, - Background: t.Pet.Background, + Origin: t.Pet.Origin, Address: t.Pet.Address, Contact: t.Pet.Contact, AdoptBy: t.Pet.AdoptBy, From d0a1854a4a4d829a04c039a6bf6a02987a78df01 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Wed, 10 Jan 2024 01:21:39 +0700 Subject: [PATCH 41/41] fix: admin paths --- src/app/middleware/auth/auth.middleware.go | 2 +- src/constant/auth/auth.constant.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/middleware/auth/auth.middleware.go b/src/app/middleware/auth/auth.middleware.go index 8fe46ed..3660164 100644 --- a/src/app/middleware/auth/auth.middleware.go +++ b/src/app/middleware/auth/auth.middleware.go @@ -62,7 +62,7 @@ func (m *Guard) Use(ctx router.IContext) error { if utils.IsExisted(m.adminpath, path) && payload.Role != string(user.ADMIN) { ctx.JSON(http.StatusUnauthorized, dto.ResponseErr{ StatusCode: http.StatusUnauthorized, - Message: "Unauthorized", + Message: "Limited access", Data: nil, }) return nil diff --git a/src/constant/auth/auth.constant.go b/src/constant/auth/auth.constant.go index 3cf5931..e25d157 100644 --- a/src/constant/auth/auth.constant.go +++ b/src/constant/auth/auth.constant.go @@ -10,7 +10,7 @@ var ExcludePath = map[string]struct{}{ } var AdminPath = map[string]struct{}{ - "DELETE /users/:id": {}, + "DELETE /user/:id": {}, "POST /pets": {}, "PUT /pets/:id": {}, "PUT /pets/:id/visible": {},