From 3a2cf3216ff6fae62e49702675d43bacef9e14f0 Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Tue, 9 Jan 2024 11:14:46 +0700 Subject: [PATCH 01/30] fix: add `IsLike` to PetResponse --- src/app/dto/pet.dto.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/dto/pet.dto.go b/src/app/dto/pet.dto.go index 0d7c5b1..5ea4530 100644 --- a/src/app/dto/pet.dto.go +++ b/src/app/dto/pet.dto.go @@ -28,6 +28,7 @@ type PetResponse struct { Contact string `json:"contact"` AdoptBy string `json:"adopt_by"` Images []ImageResponse `json:"images"` + IsLike *bool `json:"is_like"` } type CreatePetRequest struct { From fcbbd593595c7e52f939b3156cf4e80067849691 Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Tue, 9 Jan 2024 11:15:10 +0700 Subject: [PATCH 02/30] feat: return `IsLike` when there're `bearer token` --- src/app/handler/pet/pet.handler.go | 28 ++++++- src/app/handler/pet/pet.handler_test.go | 99 +++++++++++++++++++------ 2 files changed, 100 insertions(+), 27 deletions(-) diff --git a/src/app/handler/pet/pet.handler.go b/src/app/handler/pet/pet.handler.go index 7dae48c..e47877d 100644 --- a/src/app/handler/pet/pet.handler.go +++ b/src/app/handler/pet/pet.handler.go @@ -10,17 +10,21 @@ import ( "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" + likeSvc "github.com/isd-sgcu/johnjud-gateway/src/pkg/service/like" petSvc "github.com/isd-sgcu/johnjud-gateway/src/pkg/service/pet" + + petUtils "github.com/isd-sgcu/johnjud-gateway/src/app/utils/pet" ) type Handler struct { service petSvc.Service imageService imageSvc.Service + likeService likeSvc.Service validate validator.IDtoValidator } -func NewHandler(service petSvc.Service, imageService imageSvc.Service, validate validator.IDtoValidator) *Handler { - return &Handler{service, imageService, validate} +func NewHandler(service petSvc.Service, imageService imageSvc.Service, likeService likeSvc.Service, validate validator.IDtoValidator) *Handler { + return &Handler{service, imageService, likeService, validate} } // FindAll is a function that return all pets in database @@ -34,17 +38,27 @@ func NewHandler(service petSvc.Service, imageService imageSvc.Service, validate // @Failure 503 {object} dto.ResponseServiceDownErr "Service is down" // @Router /v1/pets/ [get] func (h *Handler) FindAll(c router.IContext) { + userID := c.UserID() response, respErr := h.service.FindAll() if respErr != nil { c.JSON(respErr.StatusCode, respErr) return } + likeResponse, likeErr := h.likeService.FindByUserId(userID) + if likeErr != nil { + c.JSON(likeErr.StatusCode, likeErr) + return + + } + petWithLikeResponse := petUtils.MapIsLikeToPets(likeResponse, response) + c.JSON(http.StatusOK, dto.ResponseSuccess{ StatusCode: http.StatusOK, Message: petconst.FindAllPetSuccessMessage, - Data: response, + Data: petWithLikeResponse, }) + return } @@ -62,6 +76,7 @@ func (h *Handler) FindAll(c router.IContext) { // @Router /v1/pets/{id} [get] func (h *Handler) FindOne(c router.IContext) { id, err := c.Param("id") + userId := c.UserID() if err != nil { c.JSON(http.StatusInternalServerError, dto.ResponseErr{ StatusCode: http.StatusInternalServerError, @@ -77,6 +92,13 @@ func (h *Handler) FindOne(c router.IContext) { return } + likeResponse, likeErr := h.likeService.FindByUserId(userId) + if likeErr != nil { + c.JSON(likeErr.StatusCode, likeErr) + } + + response.IsLike = petUtils.IsLike(response.Id, likeResponse) + c.JSON(http.StatusOK, dto.ResponseSuccess{ StatusCode: http.StatusOK, Message: petconst.FindOnePetSuccessMessage, diff --git a/src/app/handler/pet/pet.handler_test.go b/src/app/handler/pet/pet.handler_test.go index 659e221..448bf26 100644 --- a/src/app/handler/pet/pet.handler_test.go +++ b/src/app/handler/pet/pet.handler_test.go @@ -11,12 +11,16 @@ import ( "github.com/isd-sgcu/johnjud-gateway/src/constant/pet" routerMock "github.com/isd-sgcu/johnjud-gateway/src/mocks/router" imageMock "github.com/isd-sgcu/johnjud-gateway/src/mocks/service/image" + likeMock "github.com/isd-sgcu/johnjud-gateway/src/mocks/service/like" petMock "github.com/isd-sgcu/johnjud-gateway/src/mocks/service/pet" validatorMock "github.com/isd-sgcu/johnjud-gateway/src/mocks/validator" errConst "github.com/isd-sgcu/johnjud-gateway/src/app/constant" - utils "github.com/isd-sgcu/johnjud-gateway/src/app/utils/pet" + likeUtils "github.com/isd-sgcu/johnjud-gateway/src/app/utils/like" + petUtils "github.com/isd-sgcu/johnjud-gateway/src/app/utils/pet" petConst "github.com/isd-sgcu/johnjud-gateway/src/constant/pet" + userProto "github.com/isd-sgcu/johnjud-go-proto/johnjud/auth/user/v1" + likeProto "github.com/isd-sgcu/johnjud-go-proto/johnjud/backend/like/v1" petProto "github.com/isd-sgcu/johnjud-go-proto/johnjud/backend/pet/v1" imgProto "github.com/isd-sgcu/johnjud-go-proto/johnjud/file/image/v1" @@ -26,6 +30,8 @@ import ( type PetHandlerTest struct { suite.Suite Pet *petProto.Pet + User *userProto.User + Likes []*likeProto.Like Pets []*petProto.Pet PetDto *dto.PetResponse CreatePetRequest *dto.CreatePetRequest @@ -45,7 +51,7 @@ func TestPetHandler(t *testing.T) { } func (t *PetHandlerTest) SetupTest() { - imagesList := utils.MockImageList(3) + imagesList := petUtils.MockImageList(3) t.ImagesList = imagesList t.Images = imagesList[0] var pets []*petProto.Pet @@ -74,6 +80,26 @@ func (t *PetHandlerTest) SetupTest() { pets = append(pets, pet) } + var likes []*likeProto.Like + for i := 0; i <= 3; i++ { + like := &likeProto.Like{ + Id: faker.UUIDDigit(), + UserId: faker.UUIDDigit(), + PetId: faker.UUIDDigit(), + } + likes = append(likes, like) + } + t.Likes = likes + + t.User = &userProto.User{ + Id: faker.UUIDDigit(), + Email: faker.Email(), + Password: faker.Password(), + Firstname: faker.FirstName(), + Lastname: faker.LastName(), + Role: "USER", + } + t.Pets = pets t.Pet = t.Pets[0] @@ -95,6 +121,7 @@ func (t *PetHandlerTest) SetupTest() { Address: t.Pet.Address, Contact: t.Pet.Contact, AdoptBy: t.Pet.AdoptBy, + IsLike: petUtils.BoolAddr(true), } t.CreatePetRequest = &dto.CreatePetRequest{} @@ -130,7 +157,7 @@ func (t *PetHandlerTest) SetupTest() { } func (t *PetHandlerTest) TestFindAllSuccess() { - findAllResponse := utils.ProtoToDtoList(t.Pets, t.ImagesList) + findAllResponse := petUtils.ProtoToDtoList(t.Pets, t.ImagesList) expectedResponse := dto.ResponseSuccess{ StatusCode: http.StatusOK, Message: petConst.FindAllPetSuccessMessage, @@ -141,18 +168,21 @@ func (t *PetHandlerTest) TestFindAllSuccess() { petSvc := petMock.NewMockService(controller) imageSvc := imageMock.NewMockService(controller) + likeSvc := likeMock.NewMockService(controller) validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) + context.EXPECT().UserID().Return(t.User.Id) petSvc.EXPECT().FindAll().Return(findAllResponse, nil) + likeSvc.EXPECT().FindByUserId(t.User.Id).Return(likeUtils.ProtoToDtoList(t.Likes), nil) context.EXPECT().JSON(http.StatusOK, expectedResponse) - handler := NewHandler(petSvc, imageSvc, validator) + handler := NewHandler(petSvc, imageSvc, likeSvc, validator) handler.FindAll(context) } func (t *PetHandlerTest) TestFindOneSuccess() { - findOneResponse := utils.ProtoToDto(t.Pet, t.Images) + findOneResponse := petUtils.ProtoToDto(t.Pet, t.Images) expectedResponse := dto.ResponseSuccess{ StatusCode: http.StatusOK, Message: petConst.FindOnePetSuccessMessage, @@ -163,14 +193,17 @@ func (t *PetHandlerTest) TestFindOneSuccess() { petSvc := petMock.NewMockService(controller) imageSvc := imageMock.NewMockService(controller) + likeSvc := likeMock.NewMockService(controller) validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) context.EXPECT().Param("id").Return(t.Pet.Id, nil) + context.EXPECT().UserID().Return(t.User.Id) petSvc.EXPECT().FindOne(t.Pet.Id).Return(findOneResponse, nil) + likeSvc.EXPECT().FindByUserId(t.User.Id).Return(likeUtils.ProtoToDtoList(t.Likes), nil) context.EXPECT().JSON(http.StatusOK, expectedResponse) - handler := NewHandler(petSvc, imageSvc, validator) + handler := NewHandler(petSvc, imageSvc, likeSvc, validator) handler.FindOne(context) } @@ -181,14 +214,16 @@ func (t *PetHandlerTest) TestFindOneNotFoundErr() { petSvc := petMock.NewMockService(controller) imageSvc := imageMock.NewMockService(controller) + likeSvc := likeMock.NewMockService(controller) validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) context.EXPECT().Param("id").Return(t.Pet.Id, nil) + context.EXPECT().UserID().Return(t.User.Id) petSvc.EXPECT().FindOne(t.Pet.Id).Return(nil, findOneResponse) context.EXPECT().JSON(http.StatusNotFound, findOneResponse) - handler := NewHandler(petSvc, imageSvc, validator) + handler := NewHandler(petSvc, imageSvc, likeSvc, validator) handler.FindOne(context) } @@ -199,19 +234,21 @@ func (t *PetHandlerTest) TestFindOneGrpcErr() { petSvc := petMock.NewMockService(controller) imageSvc := imageMock.NewMockService(controller) + likeSvc := likeMock.NewMockService(controller) validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) context.EXPECT().Param("id").Return(t.Pet.Id, nil) + context.EXPECT().UserID().Return(t.User.Id) petSvc.EXPECT().FindOne(t.Pet.Id).Return(nil, findOneResponse) context.EXPECT().JSON(http.StatusServiceUnavailable, findOneResponse) - handler := NewHandler(petSvc, imageSvc, validator) + handler := NewHandler(petSvc, imageSvc, likeSvc, validator) handler.FindOne(context) } func (t *PetHandlerTest) TestCreateSuccess() { - createResponse := utils.ProtoToDto(t.Pet, t.Images) + createResponse := petUtils.ProtoToDto(t.Pet, t.Images) expectedResponse := dto.ResponseSuccess{ StatusCode: http.StatusCreated, Message: petConst.CreatePetSuccessMessage, @@ -222,6 +259,7 @@ func (t *PetHandlerTest) TestCreateSuccess() { petSvc := petMock.NewMockService(controller) imageSvc := imageMock.NewMockService(controller) + likeSvc := likeMock.NewMockService(controller) validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) @@ -230,7 +268,7 @@ func (t *PetHandlerTest) TestCreateSuccess() { petSvc.EXPECT().Create(t.CreatePetRequest).Return(createResponse, nil) context.EXPECT().JSON(http.StatusCreated, expectedResponse) - handler := NewHandler(petSvc, imageSvc, validator) + handler := NewHandler(petSvc, imageSvc, likeSvc, validator) handler.Create(context) } @@ -241,6 +279,7 @@ func (t *PetHandlerTest) TestCreateGrpcErr() { petSvc := petMock.NewMockService(controller) imageSvc := imageMock.NewMockService(controller) + likeSvc := likeMock.NewMockService(controller) validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) @@ -249,12 +288,12 @@ func (t *PetHandlerTest) TestCreateGrpcErr() { petSvc.EXPECT().Create(t.CreatePetRequest).Return(nil, createErrorResponse) context.EXPECT().JSON(http.StatusServiceUnavailable, createErrorResponse) - handler := NewHandler(petSvc, imageSvc, validator) + handler := NewHandler(petSvc, imageSvc, likeSvc, validator) handler.Create(context) } func (t *PetHandlerTest) TestUpdateSuccess() { - updateResponse := utils.ProtoToDto(t.Pet, t.Images) + updateResponse := petUtils.ProtoToDto(t.Pet, t.Images) expectedResponse := dto.ResponseSuccess{ StatusCode: http.StatusOK, Message: petConst.UpdatePetSuccessMessage, @@ -265,6 +304,7 @@ func (t *PetHandlerTest) TestUpdateSuccess() { petSvc := petMock.NewMockService(controller) imageSvc := imageMock.NewMockService(controller) + likeSvc := likeMock.NewMockService(controller) validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) @@ -274,7 +314,7 @@ func (t *PetHandlerTest) TestUpdateSuccess() { petSvc.EXPECT().Update(t.Pet.Id, t.UpdatePetRequest).Return(updateResponse, nil) context.EXPECT().JSON(http.StatusOK, expectedResponse) - handler := NewHandler(petSvc, imageSvc, validator) + handler := NewHandler(petSvc, imageSvc, likeSvc, validator) handler.Update(context) } @@ -285,6 +325,7 @@ func (t *PetHandlerTest) TestUpdateNotFound() { petSvc := petMock.NewMockService(controller) imageSvc := imageMock.NewMockService(controller) + likeSvc := likeMock.NewMockService(controller) validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) @@ -294,7 +335,7 @@ func (t *PetHandlerTest) TestUpdateNotFound() { petSvc.EXPECT().Update(t.Pet.Id, t.UpdatePetRequest).Return(nil, updateResponse) context.EXPECT().JSON(http.StatusNotFound, updateResponse) - handler := NewHandler(petSvc, imageSvc, validator) + handler := NewHandler(petSvc, imageSvc, likeSvc, validator) handler.Update(context) } @@ -305,6 +346,7 @@ func (t *PetHandlerTest) TestUpdateGrpcErr() { petSvc := petMock.NewMockService(controller) imageSvc := imageMock.NewMockService(controller) + likeSvc := likeMock.NewMockService(controller) validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) @@ -314,7 +356,7 @@ func (t *PetHandlerTest) TestUpdateGrpcErr() { petSvc.EXPECT().Update(t.Pet.Id, t.UpdatePetRequest).Return(nil, updateResponse) context.EXPECT().JSON(http.StatusServiceUnavailable, updateResponse) - handler := NewHandler(petSvc, imageSvc, validator) + handler := NewHandler(petSvc, imageSvc, likeSvc, validator) handler.Update(context) } @@ -332,6 +374,7 @@ func (t *PetHandlerTest) TestDeleteSuccess() { petSvc := petMock.NewMockService(controller) imageSvc := imageMock.NewMockService(controller) + likeSvc := likeMock.NewMockService(controller) validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) @@ -339,7 +382,7 @@ func (t *PetHandlerTest) TestDeleteSuccess() { petSvc.EXPECT().Delete(t.Pet.Id).Return(deleteResponse, nil) context.EXPECT().JSON(http.StatusOK, expectedResponse) - handler := NewHandler(petSvc, imageSvc, validator) + handler := NewHandler(petSvc, imageSvc, likeSvc, validator) handler.Delete(context) } func (t *PetHandlerTest) TestDeleteNotFound() { @@ -351,6 +394,7 @@ func (t *PetHandlerTest) TestDeleteNotFound() { petSvc := petMock.NewMockService(controller) imageSvc := imageMock.NewMockService(controller) + likeSvc := likeMock.NewMockService(controller) validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) @@ -358,7 +402,7 @@ func (t *PetHandlerTest) TestDeleteNotFound() { petSvc.EXPECT().Delete(t.Pet.Id).Return(deleteResponse, t.NotFoundErr) context.EXPECT().JSON(http.StatusNotFound, t.NotFoundErr) - handler := NewHandler(petSvc, imageSvc, validator) + handler := NewHandler(petSvc, imageSvc, likeSvc, validator) handler.Delete(context) } @@ -371,6 +415,7 @@ func (t *PetHandlerTest) TestDeleteGrpcErr() { petSvc := petMock.NewMockService(controller) imageSvc := imageMock.NewMockService(controller) + likeSvc := likeMock.NewMockService(controller) validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) @@ -378,7 +423,7 @@ func (t *PetHandlerTest) TestDeleteGrpcErr() { petSvc.EXPECT().Delete(t.Pet.Id).Return(deleteResponse, t.ServiceDownErr) context.EXPECT().JSON(http.StatusServiceUnavailable, t.ServiceDownErr) - handler := NewHandler(petSvc, imageSvc, validator) + handler := NewHandler(petSvc, imageSvc, likeSvc, validator) handler.Delete(context) } @@ -396,6 +441,7 @@ func (t *PetHandlerTest) TestChangeViewSuccess() { petSvc := petMock.NewMockService(controller) imageSvc := imageMock.NewMockService(controller) + likeSvc := likeMock.NewMockService(controller) validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) @@ -405,7 +451,7 @@ func (t *PetHandlerTest) TestChangeViewSuccess() { petSvc.EXPECT().ChangeView(t.Pet.Id, t.ChangeViewPetRequest).Return(changeViewResponse, nil) context.EXPECT().JSON(http.StatusOK, expectedResponse) - handler := NewHandler(petSvc, imageSvc, validator) + handler := NewHandler(petSvc, imageSvc, likeSvc, validator) handler.ChangeView(context) } @@ -418,6 +464,7 @@ func (t *PetHandlerTest) TestChangeViewNotFound() { petSvc := petMock.NewMockService(controller) imageSvc := imageMock.NewMockService(controller) + likeSvc := likeMock.NewMockService(controller) validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) @@ -427,7 +474,7 @@ func (t *PetHandlerTest) TestChangeViewNotFound() { petSvc.EXPECT().ChangeView(t.Pet.Id, t.ChangeViewPetRequest).Return(changeViewResponse, t.NotFoundErr) context.EXPECT().JSON(http.StatusNotFound, t.NotFoundErr) - handler := NewHandler(petSvc, imageSvc, validator) + handler := NewHandler(petSvc, imageSvc, likeSvc, validator) handler.ChangeView(context) } @@ -440,6 +487,7 @@ func (t *PetHandlerTest) TestChangeViewGrpcErr() { petSvc := petMock.NewMockService(controller) imageSvc := imageMock.NewMockService(controller) + likeSvc := likeMock.NewMockService(controller) validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) @@ -449,7 +497,7 @@ func (t *PetHandlerTest) TestChangeViewGrpcErr() { petSvc.EXPECT().ChangeView(t.Pet.Id, t.ChangeViewPetRequest).Return(changeViewResponse, t.ServiceDownErr) context.EXPECT().JSON(http.StatusServiceUnavailable, t.ServiceDownErr) - handler := NewHandler(petSvc, imageSvc, validator) + handler := NewHandler(petSvc, imageSvc, likeSvc, validator) handler.ChangeView(context) } @@ -467,6 +515,7 @@ func (t *PetHandlerTest) TestAdoptSuccess() { petSvc := petMock.NewMockService(controller) imageSvc := imageMock.NewMockService(controller) + likeSvc := likeMock.NewMockService(controller) validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) @@ -476,7 +525,7 @@ func (t *PetHandlerTest) TestAdoptSuccess() { petSvc.EXPECT().Adopt(t.Pet.Id, t.AdoptByRequest).Return(adoptByResponse, nil) context.EXPECT().JSON(http.StatusOK, expectedResponse) - handler := NewHandler(petSvc, imageSvc, validator) + handler := NewHandler(petSvc, imageSvc, likeSvc, validator) handler.Adopt(context) } @@ -489,6 +538,7 @@ func (t *PetHandlerTest) TestAdoptNotFound() { petSvc := petMock.NewMockService(controller) imageSvc := imageMock.NewMockService(controller) + likeSvc := likeMock.NewMockService(controller) validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) @@ -498,7 +548,7 @@ func (t *PetHandlerTest) TestAdoptNotFound() { petSvc.EXPECT().Adopt(t.Pet.Id, t.AdoptByRequest).Return(adoptByResponse, t.NotFoundErr) context.EXPECT().JSON(http.StatusNotFound, t.NotFoundErr) - handler := NewHandler(petSvc, imageSvc, validator) + handler := NewHandler(petSvc, imageSvc, likeSvc, validator) handler.Adopt(context) } @@ -511,6 +561,7 @@ func (t *PetHandlerTest) TestAdoptGrpcErr() { petSvc := petMock.NewMockService(controller) imageSvc := imageMock.NewMockService(controller) + likeSvc := likeMock.NewMockService(controller) validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) @@ -520,6 +571,6 @@ func (t *PetHandlerTest) TestAdoptGrpcErr() { petSvc.EXPECT().Adopt(t.Pet.Id, t.AdoptByRequest).Return(adoptByResponse, t.ServiceDownErr) context.EXPECT().JSON(http.StatusServiceUnavailable, t.ServiceDownErr) - handler := NewHandler(petSvc, imageSvc, validator) + handler := NewHandler(petSvc, imageSvc, likeSvc, validator) handler.Adopt(context) } From 3c1d771997b2a689f49e15e8cf0022a122a763ac Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Tue, 9 Jan 2024 11:15:20 +0700 Subject: [PATCH 03/30] chore --- src/main.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main.go b/src/main.go index 2d354c7..a9dc228 100644 --- a/src/main.go +++ b/src/main.go @@ -108,14 +108,15 @@ func main() { imageClient := imageProto.NewImageServiceClient(fileConn) imageService := imageSvc.NewService(imageClient) - petClient := petProto.NewPetServiceClient(backendConn) - petService := petSvc.NewService(petClient) - petHandler := petHdr.NewHandler(petService, imageService, v) - likeClient := likeProto.NewLikeServiceClient(backendConn) likeService := likeSvc.NewService(likeClient) likeHandler := likeHdr.NewHandler(likeService, v) + petClient := petProto.NewPetServiceClient(backendConn) + petService := petSvc.NewService(petClient) + petHandler := petHdr.NewHandler(petService, imageService, likeService, v) + + r := router.NewFiberRouter(&authGuard, conf.App) r.GetUser("/:id", userHandler.FindOne) From 3e665d9c90636fdf1450a83d608ead6d10fce3b6 Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Tue, 9 Jan 2024 11:15:34 +0700 Subject: [PATCH 04/30] add utils --- src/app/utils/pet/pet.utils.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/app/utils/pet/pet.utils.go b/src/app/utils/pet/pet.utils.go index 1f68987..05f59cf 100644 --- a/src/app/utils/pet/pet.utils.go +++ b/src/app/utils/pet/pet.utils.go @@ -160,3 +160,22 @@ func extractImages(images []*imgproto.Image) []dto.ImageResponse { } return result } +func IsLike(petId string, likes []*dto.LikeResponse) *bool { + for _, like := range likes { + if like.PetID == petId { + return BoolAddr(true) + } + } + return BoolAddr(false) +} + +func MapIsLikeToPets(likes []*dto.LikeResponse, pets []*dto.PetResponse) []*dto.PetResponse { + for _, pet := range pets { + pet.IsLike = IsLike(pet.Id, likes) + } + return pets +} + +func BoolAddr(b bool) *bool { + return &b +} From 8449b72169921944cdb9b5170c48237683943d00 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Mon, 8 Jan 2024 00:25:49 +0700 Subject: [PATCH 05/30] fix: adoptdto in userdto file --- src/app/dto/adopt.dto.go | 15 --------------- src/app/dto/pet.dto.go | 13 +++++++++++-- 2 files changed, 11 insertions(+), 17 deletions(-) delete mode 100644 src/app/dto/adopt.dto.go diff --git a/src/app/dto/adopt.dto.go b/src/app/dto/adopt.dto.go deleted file mode 100644 index 56ecaef..0000000 --- a/src/app/dto/adopt.dto.go +++ /dev/null @@ -1,15 +0,0 @@ -package dto - -type AdoptDto struct { - UserID string `json:"user_id" validate:"required"` - PetID string `json:"pet_id" validate:"required"` -} - -type AdoptByRequest struct { - UserID string `json:"user_id" validate:"required"` - PetID string `json:"pet_id" validate:"required"` -} - -type AdoptByResponse struct { - Success bool `json:"success"` -} diff --git a/src/app/dto/pet.dto.go b/src/app/dto/pet.dto.go index 5ea4530..f3a8f79 100644 --- a/src/app/dto/pet.dto.go +++ b/src/app/dto/pet.dto.go @@ -36,10 +36,10 @@ 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:"male"` + Gender pet.Gender `json:"gender" validate:"required" example:"1"` Habit string `json:"habit" validate:"required"` Caption string `json:"caption"` - Status pet.Status `json:"status" validate:"required" example:"findhome"` + Status pet.Status `json:"status" validate:"required" example:"1"` IsSterile *bool `json:"is_sterile" validate:"required"` IsVaccinated *bool `json:"is_vaccinated" validate:"required"` IsVisible *bool `json:"is_visible" validate:"required"` @@ -59,6 +59,15 @@ type ChangeViewPetResponse struct { Success bool `json:"success" validate:"required"` } +type AdoptByRequest struct { + UserID string `json:"user_id" validate:"required"` + PetID string `json:"pet_id" validate:"required"` +} + +type AdoptByResponse struct { + Success bool `json:"success"` +} + type UpdatePetRequest struct { Type string `json:"type"` Species string `json:"species"` From 1e67dee6a9a2733f690925513f39103c74cd8625 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Mon, 8 Jan 2024 00:26:00 +0700 Subject: [PATCH 06/30] fix: pet swagger docs --- src/app/handler/pet/pet.handler.go | 77 +++++++++++++++--------------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/src/app/handler/pet/pet.handler.go b/src/app/handler/pet/pet.handler.go index e47877d..bfded94 100644 --- a/src/app/handler/pet/pet.handler.go +++ b/src/app/handler/pet/pet.handler.go @@ -27,13 +27,13 @@ func NewHandler(service petSvc.Service, imageService imageSvc.Service, likeServi return &Handler{service, imageService, likeService, validate} } -// FindAll is a function that return all pets in database -// @Summary find all pets -// @Description Return the data of pets if successfully -// @Tags auth +// FindAll is a function that returns all pets in database +// @Summary finds all pets +// @Description Returns the data of pets if successful +// @Tags pet // @Accept json // @Produce json -// @Success 200 {object} dto.PetDto +// @Success 200 {object} []dto.PetResponse // @Failure 500 {object} dto.ResponseInternalErr "Internal service error" // @Failure 503 {object} dto.ResponseServiceDownErr "Service is down" // @Router /v1/pets/ [get] @@ -62,14 +62,14 @@ func (h *Handler) FindAll(c router.IContext) { return } -// FindOne is a function that return all pet in database -// @Summary find one pet -// @Description Return the data of pets if successfully +// FindOne is a function that returns a pet by id in database +// @Summary finds one pet +// @Description Returns the data of a pet if successful // @Param id path string true "pet id" -// @Tags auth +// @Tags pet // @Accept json // @Produce json -// @Success 200 {object} dto.PetDto +// @Success 200 {object} dto.PetResponse // @Failure 400 {object} dto.ResponseBadRequestErr "Invalid request body" // @Failure 500 {object} dto.ResponseInternalErr "Internal service error" // @Failure 503 {object} dto.ResponseServiceDownErr "Service is down" @@ -107,14 +107,14 @@ func (h *Handler) FindOne(c router.IContext) { return } -// Create is a function that create pet in database -// @Summary create pet -// @Description Return the data of pet if successfully +// Create is a function that creates pet in database +// @Summary creates pet +// @Description Returns the data of pet if successful // @Param create body dto.CreatePetRequest true "pet dto" -// @Tags auth +// @Tags pet // @Accept json // @Produce json -// @Success 201 {object} dto.PetDto +// @Success 201 {object} dto.PetResponse // @Failure 400 {object} dto.ResponseBadRequestErr "Invalid request body" // @Failure 500 {object} dto.ResponseInternalErr "Internal service error" // @Failure 503 {object} dto.ResponseServiceDownErr "Service is down" @@ -158,15 +158,15 @@ func (h *Handler) Create(c router.IContext) { return } -// Update is a function that update pet in database -// @Summary update pet -// @Description Return the data of pet if successfully +// Update is a function that updates pet in database +// @Summary updates pet +// @Description Returns the data of pet if successfully // @Param update body dto.UpdatePetRequest true "update pet dto" -// @Param id path stirng true "pet id" -// @Tags auth +// @Param id path string true "pet id" +// @Tags pet // @Accept json // @Produce json -// @Success 201 {object} dto.PetDto +// @Success 201 {object} dto.PetResponse // @Failure 400 {object} dto.ResponseBadRequestErr "Invalid request body" // @Failure 500 {object} dto.ResponseInternalErr "Internal service error" // @Failure 503 {object} dto.ResponseServiceDownErr "Service is down" @@ -221,19 +221,19 @@ func (h *Handler) Update(c router.IContext) { return } -// Change is a function that change visibility of pet in database -// @Summary change view pet -// @Description Return the status true of pet if successfully else false -// @Param change view body dto.ChangeViewPetRequest true "change view pet dto" -// @Param id string true "pet id" -// @Tags auth +// ChangeView is a function that changes visibility of pet in database +// @Summary changes pet's public visiblility +// @Description Returns successful status if pet's IsVisible is successfully changed +// @Param changeViewDto body dto.ChangeViewPetRequest true "changeView pet dto" +// @Param id path string true "pet id" +// @Tags pet // @Accept json // @Produce json -// @Success 201 {object} bool +// @Success 201 {object} dto.ChangeViewPetResponse // @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/pets/ [put] +// @Router /v1/pets/{id}/visible [put] func (h *Handler) ChangeView(c router.IContext) { id, err := c.Param("id") if err != nil { @@ -284,14 +284,14 @@ func (h *Handler) ChangeView(c router.IContext) { return } -// Delete is a function that delete pet in database -// @Summary delete pet -// @Description Return the status true of pet if successfully else false -// @Param id string true "pet id" -// @Tags auth +// Delete is a function that deletes pet in database +// @Summary deletes pet +// @Description Returns successful status if pet is successfully deleted +// @Param id path string true "pet id" +// @Tags pet // @Accept json // @Produce json -// @Success 201 {object} bool +// @Success 201 {object} dto.DeleteResponse // @Failure 400 {object} dto.ResponseBadRequestErr "Invalid request body" // @Failure 500 {object} dto.ResponseInternalErr "Internal service error" // @Failure 503 {object} dto.ResponseServiceDownErr "Service is down" @@ -322,15 +322,14 @@ func (h *Handler) Delete(c router.IContext) { } // Adopt is a function that handles the adoption of a pet in the database -// @Summary Adopt a pet +// @Summary Change a pet's adoptBy status // @Description Return true if the pet is successfully adopted +// @Param adoptDto body dto.AdoptByRequest true "adopt pet dto" // @Param id path string true "Pet ID" -// @Param user_id body string true "User ID" -// @Param pet_id body string true "Pet ID" // @Tags pet // @Accept json // @Produce json -// @Success 201 {object} bool +// @Success 201 {object} dto.AdoptByResponse // @Failure 400 {object} dto.ResponseBadRequestErr "Invalid request body" // @Failure 500 {object} dto.ResponseInternalErr "Internal service error" // @Failure 503 {object} dto.ResponseServiceDownErr "Service is down" From 0d53fb6578c3e372903a39f2ff35953bcc7bb175 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Mon, 8 Jan 2024 00:26:05 +0700 Subject: [PATCH 07/30] chore: gen docs --- src/docs/docs.go | 593 ++++++++++++++++++++++++++++++++++++++++-- src/docs/swagger.json | 590 ++++++++++++++++++++++++++++++++++++++++- src/docs/swagger.yaml | 402 +++++++++++++++++++++++++++- 3 files changed, 1544 insertions(+), 41 deletions(-) diff --git a/src/docs/docs.go b/src/docs/docs.go index de72062..ee19d5a 100644 --- a/src/docs/docs.go +++ b/src/docs/docs.go @@ -1,5 +1,4 @@ -// Code generated by swaggo/swag. DO NOT EDIT. - +// Package docs Code generated by swaggo/swag. DO NOT EDIT package docs import "github.com/swaggo/swag" @@ -234,9 +233,9 @@ const docTemplate = `{ } } }, - "/v1/pet/": { + "/v1/pets/": { "get": { - "description": "Return the data of pets if successfully", + "description": "Returns the data of pets if successful", "consumes": [ "application/json" ], @@ -244,17 +243,103 @@ const docTemplate = `{ "application/json" ], "tags": [ - "auth" + "pet" + ], + "summary": "finds all pets", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/dto.PetResponse" + } + } + }, + "500": { + "description": "Internal service error", + "schema": { + "$ref": "#/definitions/dto.ResponseInternalErr" + } + }, + "503": { + "description": "Service is down", + "schema": { + "$ref": "#/definitions/dto.ResponseServiceDownErr" + } + } + } + }, + "delete": { + "description": "Returns successful status if pet is successfully deleted", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "pet" + ], + "summary": "deletes pet", + "parameters": [ + { + "type": "string", + "description": "pet id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/dto.DeleteResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/dto.ResponseBadRequestErr" + } + }, + "500": { + "description": "Internal service error", + "schema": { + "$ref": "#/definitions/dto.ResponseInternalErr" + } + }, + "503": { + "description": "Service is down", + "schema": { + "$ref": "#/definitions/dto.ResponseServiceDownErr" + } + } + } + } + }, + "/v1/pets/create": { + "post": { + "description": "Returns the data of pet if successful", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "pet" ], - "summary": "find all pets", + "summary": "creates pet", "parameters": [ { "description": "pet dto", - "name": "signup", + "name": "create", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/dto.PetDto" + "$ref": "#/definitions/dto.CreatePetRequest" } } ], @@ -262,7 +347,7 @@ const docTemplate = `{ "201": { "description": "Created", "schema": { - "$ref": "#/definitions/dto.PetDto" + "$ref": "#/definitions/dto.PetResponse" } }, "400": { @@ -271,10 +356,229 @@ const docTemplate = `{ "$ref": "#/definitions/dto.ResponseBadRequestErr" } }, - "409": { - "description": "Duplicate email", + "500": { + "description": "Internal service error", "schema": { - "$ref": "#/definitions/dto.ResponseConflictErr" + "$ref": "#/definitions/dto.ResponseInternalErr" + } + }, + "503": { + "description": "Service is down", + "schema": { + "$ref": "#/definitions/dto.ResponseServiceDownErr" + } + } + } + } + }, + "/v1/pets/{id}": { + "get": { + "description": "Returns the data of a pet if successful", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "pet" + ], + "summary": "finds one pet", + "parameters": [ + { + "type": "string", + "description": "pet id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dto.PetResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/dto.ResponseBadRequestErr" + } + }, + "500": { + "description": "Internal service error", + "schema": { + "$ref": "#/definitions/dto.ResponseInternalErr" + } + }, + "503": { + "description": "Service is down", + "schema": { + "$ref": "#/definitions/dto.ResponseServiceDownErr" + } + } + } + }, + "put": { + "description": "Returns the data of pet if successfully", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "pet" + ], + "summary": "updates pet", + "parameters": [ + { + "description": "update pet dto", + "name": "update", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.UpdatePetRequest" + } + }, + { + "type": "string", + "description": "pet id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/dto.PetResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/dto.ResponseBadRequestErr" + } + }, + "500": { + "description": "Internal service error", + "schema": { + "$ref": "#/definitions/dto.ResponseInternalErr" + } + }, + "503": { + "description": "Service is down", + "schema": { + "$ref": "#/definitions/dto.ResponseServiceDownErr" + } + } + } + } + }, + "/v1/pets/{id}/adopt": { + "put": { + "description": "Return true if the pet is successfully adopted", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "pet" + ], + "summary": "Change a pet's adoptBy status", + "parameters": [ + { + "description": "adopt pet dto", + "name": "adoptDto", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.AdoptByRequest" + } + }, + { + "type": "string", + "description": "Pet ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/dto.AdoptByResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/dto.ResponseBadRequestErr" + } + }, + "500": { + "description": "Internal service error", + "schema": { + "$ref": "#/definitions/dto.ResponseInternalErr" + } + }, + "503": { + "description": "Service is down", + "schema": { + "$ref": "#/definitions/dto.ResponseServiceDownErr" + } + } + } + } + }, + "/v1/pets/{id}/visible": { + "put": { + "description": "Returns successful status if pet's IsVisible is successfully changed", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "pet" + ], + "summary": "changes pet's public visiblility", + "parameters": [ + { + "description": "changeView pet dto", + "name": "changeViewDto", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.ChangeViewPetRequest" + } + }, + { + "type": "string", + "description": "pet id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/dto.ChangeViewPetResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/dto.ResponseBadRequestErr" } }, "500": { @@ -294,6 +598,29 @@ const docTemplate = `{ } }, "definitions": { + "dto.AdoptByRequest": { + "type": "object", + "required": [ + "pet_id", + "user_id" + ], + "properties": { + "pet_id": { + "type": "string" + }, + "user_id": { + "type": "string" + } + } + }, + "dto.AdoptByResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + } + }, "dto.BadReqErrResponse": { "type": "object", "properties": { @@ -306,6 +633,102 @@ const docTemplate = `{ "value": {} } }, + "dto.ChangeViewPetRequest": { + "type": "object", + "required": [ + "visible" + ], + "properties": { + "visible": { + "type": "boolean" + } + } + }, + "dto.ChangeViewPetResponse": { + "type": "object", + "required": [ + "success" + ], + "properties": { + "success": { + "type": "boolean" + } + } + }, + "dto.CreatePetRequest": { + "type": "object", + "required": [ + "birthdate", + "gender", + "habit", + "is_club_pet", + "is_sterile", + "is_vaccinated", + "is_visible", + "name", + "species", + "status", + "type" + ], + "properties": { + "address": { + "type": "string" + }, + "adopt_by": { + "type": "string" + }, + "background": { + "type": "string" + }, + "birthdate": { + "type": "string" + }, + "caption": { + "type": "string" + }, + "contact": { + "type": "string" + }, + "gender": { + "type": "integer", + "example": 1 + }, + "habit": { + "type": "string" + }, + "images": { + "type": "array", + "items": { + "type": "string" + } + }, + "is_club_pet": { + "type": "boolean" + }, + "is_sterile": { + "type": "boolean" + }, + "is_vaccinated": { + "type": "boolean" + }, + "is_visible": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "species": { + "type": "string" + }, + "status": { + "type": "integer", + "example": 1 + }, + "type": { + "type": "string" + } + } + }, "dto.Credential": { "type": "object", "properties": { @@ -323,6 +746,90 @@ const docTemplate = `{ } } }, + "dto.DeleteResponse": { + "type": "object", + "required": [ + "success" + ], + "properties": { + "success": { + "type": "boolean" + } + } + }, + "dto.ImageResponse": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "dto.PetResponse": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "adopt_by": { + "type": "string" + }, + "background": { + "type": "string" + }, + "birthdate": { + "type": "string" + }, + "caption": { + "type": "string" + }, + "contact": { + "type": "string" + }, + "gender": { + "type": "integer" + }, + "habit": { + "type": "string" + }, + "id": { + "type": "string" + }, + "images": { + "type": "array", + "items": { + "$ref": "#/definitions/dto.ImageResponse" + } + }, + "is_club_pet": { + "type": "boolean" + }, + "is_sterile": { + "type": "boolean" + }, + "is_vaccinated": { + "type": "boolean" + }, + "is_visible": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "species": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + }, "dto.RefreshTokenRequest": { "type": "object", "required": [ @@ -334,9 +841,6 @@ const docTemplate = `{ } } }, - "dto.PetDto": { - "type": "object" - }, "dto.ResponseBadRequestErr": { "type": "object", "properties": { @@ -492,6 +996,65 @@ const docTemplate = `{ "type": "string" } } + }, + "dto.UpdatePetRequest": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "adopt_by": { + "type": "string" + }, + "background": { + "type": "string" + }, + "birthdate": { + "type": "string" + }, + "caption": { + "type": "string" + }, + "contact": { + "type": "string" + }, + "gender": { + "type": "integer" + }, + "habit": { + "type": "string" + }, + "images": { + "type": "array", + "items": { + "type": "string" + } + }, + "is_club_pet": { + "type": "boolean" + }, + "is_sterile": { + "type": "boolean" + }, + "is_vaccinated": { + "type": "boolean" + }, + "is_visible": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "species": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "type": { + "type": "string" + } + } } }, "securityDefinitions": { diff --git a/src/docs/swagger.json b/src/docs/swagger.json index 1303f34..deaf951 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -229,9 +229,9 @@ } } }, - "/v1/pet/": { + "/v1/pets/": { "get": { - "description": "Return the data of pets if successfully", + "description": "Returns the data of pets if successful", "consumes": [ "application/json" ], @@ -239,17 +239,103 @@ "application/json" ], "tags": [ - "auth" + "pet" + ], + "summary": "finds all pets", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/dto.PetResponse" + } + } + }, + "500": { + "description": "Internal service error", + "schema": { + "$ref": "#/definitions/dto.ResponseInternalErr" + } + }, + "503": { + "description": "Service is down", + "schema": { + "$ref": "#/definitions/dto.ResponseServiceDownErr" + } + } + } + }, + "delete": { + "description": "Returns successful status if pet is successfully deleted", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "pet" + ], + "summary": "deletes pet", + "parameters": [ + { + "type": "string", + "description": "pet id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/dto.DeleteResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/dto.ResponseBadRequestErr" + } + }, + "500": { + "description": "Internal service error", + "schema": { + "$ref": "#/definitions/dto.ResponseInternalErr" + } + }, + "503": { + "description": "Service is down", + "schema": { + "$ref": "#/definitions/dto.ResponseServiceDownErr" + } + } + } + } + }, + "/v1/pets/create": { + "post": { + "description": "Returns the data of pet if successful", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "pet" ], - "summary": "find all pets", + "summary": "creates pet", "parameters": [ { "description": "pet dto", - "name": "signup", + "name": "create", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/dto.PetDto" + "$ref": "#/definitions/dto.CreatePetRequest" } } ], @@ -257,7 +343,7 @@ "201": { "description": "Created", "schema": { - "$ref": "#/definitions/dto.PetDto" + "$ref": "#/definitions/dto.PetResponse" } }, "400": { @@ -266,10 +352,229 @@ "$ref": "#/definitions/dto.ResponseBadRequestErr" } }, - "409": { - "description": "Duplicate email", + "500": { + "description": "Internal service error", "schema": { - "$ref": "#/definitions/dto.ResponseConflictErr" + "$ref": "#/definitions/dto.ResponseInternalErr" + } + }, + "503": { + "description": "Service is down", + "schema": { + "$ref": "#/definitions/dto.ResponseServiceDownErr" + } + } + } + } + }, + "/v1/pets/{id}": { + "get": { + "description": "Returns the data of a pet if successful", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "pet" + ], + "summary": "finds one pet", + "parameters": [ + { + "type": "string", + "description": "pet id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/dto.PetResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/dto.ResponseBadRequestErr" + } + }, + "500": { + "description": "Internal service error", + "schema": { + "$ref": "#/definitions/dto.ResponseInternalErr" + } + }, + "503": { + "description": "Service is down", + "schema": { + "$ref": "#/definitions/dto.ResponseServiceDownErr" + } + } + } + }, + "put": { + "description": "Returns the data of pet if successfully", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "pet" + ], + "summary": "updates pet", + "parameters": [ + { + "description": "update pet dto", + "name": "update", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.UpdatePetRequest" + } + }, + { + "type": "string", + "description": "pet id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/dto.PetResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/dto.ResponseBadRequestErr" + } + }, + "500": { + "description": "Internal service error", + "schema": { + "$ref": "#/definitions/dto.ResponseInternalErr" + } + }, + "503": { + "description": "Service is down", + "schema": { + "$ref": "#/definitions/dto.ResponseServiceDownErr" + } + } + } + } + }, + "/v1/pets/{id}/adopt": { + "put": { + "description": "Return true if the pet is successfully adopted", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "pet" + ], + "summary": "Change a pet's adoptBy status", + "parameters": [ + { + "description": "adopt pet dto", + "name": "adoptDto", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.AdoptByRequest" + } + }, + { + "type": "string", + "description": "Pet ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/dto.AdoptByResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/dto.ResponseBadRequestErr" + } + }, + "500": { + "description": "Internal service error", + "schema": { + "$ref": "#/definitions/dto.ResponseInternalErr" + } + }, + "503": { + "description": "Service is down", + "schema": { + "$ref": "#/definitions/dto.ResponseServiceDownErr" + } + } + } + } + }, + "/v1/pets/{id}/visible": { + "put": { + "description": "Returns successful status if pet's IsVisible is successfully changed", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "pet" + ], + "summary": "changes pet's public visiblility", + "parameters": [ + { + "description": "changeView pet dto", + "name": "changeViewDto", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.ChangeViewPetRequest" + } + }, + { + "type": "string", + "description": "pet id", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/dto.ChangeViewPetResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/dto.ResponseBadRequestErr" } }, "500": { @@ -289,6 +594,29 @@ } }, "definitions": { + "dto.AdoptByRequest": { + "type": "object", + "required": [ + "pet_id", + "user_id" + ], + "properties": { + "pet_id": { + "type": "string" + }, + "user_id": { + "type": "string" + } + } + }, + "dto.AdoptByResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + } + }, "dto.BadReqErrResponse": { "type": "object", "properties": { @@ -301,6 +629,102 @@ "value": {} } }, + "dto.ChangeViewPetRequest": { + "type": "object", + "required": [ + "visible" + ], + "properties": { + "visible": { + "type": "boolean" + } + } + }, + "dto.ChangeViewPetResponse": { + "type": "object", + "required": [ + "success" + ], + "properties": { + "success": { + "type": "boolean" + } + } + }, + "dto.CreatePetRequest": { + "type": "object", + "required": [ + "birthdate", + "gender", + "habit", + "is_club_pet", + "is_sterile", + "is_vaccinated", + "is_visible", + "name", + "species", + "status", + "type" + ], + "properties": { + "address": { + "type": "string" + }, + "adopt_by": { + "type": "string" + }, + "background": { + "type": "string" + }, + "birthdate": { + "type": "string" + }, + "caption": { + "type": "string" + }, + "contact": { + "type": "string" + }, + "gender": { + "type": "integer", + "example": 1 + }, + "habit": { + "type": "string" + }, + "images": { + "type": "array", + "items": { + "type": "string" + } + }, + "is_club_pet": { + "type": "boolean" + }, + "is_sterile": { + "type": "boolean" + }, + "is_vaccinated": { + "type": "boolean" + }, + "is_visible": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "species": { + "type": "string" + }, + "status": { + "type": "integer", + "example": 1 + }, + "type": { + "type": "string" + } + } + }, "dto.Credential": { "type": "object", "properties": { @@ -318,6 +742,90 @@ } } }, + "dto.DeleteResponse": { + "type": "object", + "required": [ + "success" + ], + "properties": { + "success": { + "type": "boolean" + } + } + }, + "dto.ImageResponse": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "dto.PetResponse": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "adopt_by": { + "type": "string" + }, + "background": { + "type": "string" + }, + "birthdate": { + "type": "string" + }, + "caption": { + "type": "string" + }, + "contact": { + "type": "string" + }, + "gender": { + "type": "integer" + }, + "habit": { + "type": "string" + }, + "id": { + "type": "string" + }, + "images": { + "type": "array", + "items": { + "$ref": "#/definitions/dto.ImageResponse" + } + }, + "is_club_pet": { + "type": "boolean" + }, + "is_sterile": { + "type": "boolean" + }, + "is_vaccinated": { + "type": "boolean" + }, + "is_visible": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "species": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + }, "dto.RefreshTokenRequest": { "type": "object", "required": [ @@ -329,9 +837,6 @@ } } }, - "dto.PetDto": { - "type": "object" - }, "dto.ResponseBadRequestErr": { "type": "object", "properties": { @@ -487,6 +992,65 @@ "type": "string" } } + }, + "dto.UpdatePetRequest": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "adopt_by": { + "type": "string" + }, + "background": { + "type": "string" + }, + "birthdate": { + "type": "string" + }, + "caption": { + "type": "string" + }, + "contact": { + "type": "string" + }, + "gender": { + "type": "integer" + }, + "habit": { + "type": "string" + }, + "images": { + "type": "array", + "items": { + "type": "string" + } + }, + "is_club_pet": { + "type": "boolean" + }, + "is_sterile": { + "type": "boolean" + }, + "is_vaccinated": { + "type": "boolean" + }, + "is_visible": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "species": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "type": { + "type": "string" + } + } } }, "securityDefinitions": { diff --git a/src/docs/swagger.yaml b/src/docs/swagger.yaml index b6ed6da..e585f99 100644 --- a/src/docs/swagger.yaml +++ b/src/docs/swagger.yaml @@ -1,4 +1,19 @@ definitions: + dto.AdoptByRequest: + properties: + pet_id: + type: string + user_id: + type: string + required: + - pet_id + - user_id + type: object + dto.AdoptByResponse: + properties: + success: + type: boolean + type: object dto.BadReqErrResponse: properties: failed_field: @@ -7,6 +22,73 @@ definitions: type: string value: {} type: object + dto.ChangeViewPetRequest: + properties: + visible: + type: boolean + required: + - visible + type: object + dto.ChangeViewPetResponse: + properties: + success: + type: boolean + required: + - success + type: object + dto.CreatePetRequest: + properties: + address: + type: string + adopt_by: + type: string + background: + type: string + birthdate: + type: string + caption: + type: string + contact: + type: string + gender: + example: 1 + type: integer + habit: + type: string + images: + items: + type: string + type: array + is_club_pet: + type: boolean + is_sterile: + type: boolean + is_vaccinated: + type: boolean + is_visible: + type: boolean + name: + type: string + species: + type: string + status: + example: 1 + type: integer + type: + type: string + required: + - birthdate + - gender + - habit + - is_club_pet + - is_sterile + - is_vaccinated + - is_visible + - name + - species + - status + - type + type: object dto.Credential: properties: access_token: @@ -19,6 +101,61 @@ definitions: example: e7e84d54-7518-4... type: string type: object + dto.DeleteResponse: + properties: + success: + type: boolean + required: + - success + type: object + dto.ImageResponse: + properties: + id: + type: string + url: + type: string + type: object + dto.PetResponse: + properties: + address: + type: string + adopt_by: + type: string + background: + type: string + birthdate: + type: string + caption: + type: string + contact: + type: string + gender: + type: integer + habit: + type: string + id: + type: string + images: + items: + $ref: '#/definitions/dto.ImageResponse' + type: array + is_club_pet: + type: boolean + is_sterile: + type: boolean + is_vaccinated: + type: boolean + is_visible: + type: boolean + name: + type: string + species: + type: string + status: + type: integer + type: + type: string + type: object dto.RefreshTokenRequest: properties: refresh_token: @@ -26,8 +163,6 @@ definitions: required: - refresh_token type: object - dto.PetDto: - type: object dto.ResponseBadRequestErr: properties: data: @@ -137,6 +272,45 @@ definitions: lastname: type: string type: object + dto.UpdatePetRequest: + properties: + address: + type: string + adopt_by: + type: string + background: + type: string + birthdate: + type: string + caption: + type: string + contact: + type: string + gender: + type: integer + habit: + type: string + images: + items: + type: string + type: array + is_club_pet: + type: boolean + is_sterile: + type: boolean + is_vaccinated: + type: boolean + is_visible: + type: boolean + name: + type: string + species: + type: string + status: + type: integer + type: + type: string + type: object info: contact: email: sd.team.sgcu@gmail.com @@ -287,33 +461,162 @@ paths: summary: Signup user tags: - auth - /v1/pet/: + /v1/pets/: + delete: + consumes: + - application/json + description: Returns successful status if pet is successfully deleted + parameters: + - description: pet id + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/dto.DeleteResponse' + "400": + description: Invalid request body + schema: + $ref: '#/definitions/dto.ResponseBadRequestErr' + "500": + description: Internal service error + schema: + $ref: '#/definitions/dto.ResponseInternalErr' + "503": + description: Service is down + schema: + $ref: '#/definitions/dto.ResponseServiceDownErr' + summary: deletes pet + tags: + - pet get: consumes: - application/json - description: Return the data of pets if successfully + description: Returns the data of pets if successful + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/dto.PetResponse' + type: array + "500": + description: Internal service error + schema: + $ref: '#/definitions/dto.ResponseInternalErr' + "503": + description: Service is down + schema: + $ref: '#/definitions/dto.ResponseServiceDownErr' + summary: finds all pets + tags: + - pet + /v1/pets/{id}: + get: + consumes: + - application/json + description: Returns the data of a pet if successful parameters: - - description: pet dto + - description: pet id + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/dto.PetResponse' + "400": + description: Invalid request body + schema: + $ref: '#/definitions/dto.ResponseBadRequestErr' + "500": + description: Internal service error + schema: + $ref: '#/definitions/dto.ResponseInternalErr' + "503": + description: Service is down + schema: + $ref: '#/definitions/dto.ResponseServiceDownErr' + summary: finds one pet + tags: + - pet + put: + consumes: + - application/json + description: Returns the data of pet if successfully + parameters: + - description: update pet dto in: body - name: signup + name: update required: true schema: - $ref: '#/definitions/dto.PetDto' + $ref: '#/definitions/dto.UpdatePetRequest' + - description: pet id + in: path + name: id + required: true + type: string produces: - application/json responses: "201": description: Created schema: - $ref: '#/definitions/dto.PetDto' + $ref: '#/definitions/dto.PetResponse' "400": description: Invalid request body schema: $ref: '#/definitions/dto.ResponseBadRequestErr' - "409": - description: Duplicate email + "500": + description: Internal service error schema: - $ref: '#/definitions/dto.ResponseConflictErr' + $ref: '#/definitions/dto.ResponseInternalErr' + "503": + description: Service is down + schema: + $ref: '#/definitions/dto.ResponseServiceDownErr' + summary: updates pet + tags: + - pet + /v1/pets/{id}/adopt: + put: + consumes: + - application/json + description: Return true if the pet is successfully adopted + parameters: + - description: adopt pet dto + in: body + name: adoptDto + required: true + schema: + $ref: '#/definitions/dto.AdoptByRequest' + - description: Pet ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/dto.AdoptByResponse' + "400": + description: Invalid request body + schema: + $ref: '#/definitions/dto.ResponseBadRequestErr' "500": description: Internal service error schema: @@ -322,9 +625,82 @@ paths: description: Service is down schema: $ref: '#/definitions/dto.ResponseServiceDownErr' - summary: find all pets + summary: Change a pet's adoptBy status tags: - - auth + - pet + /v1/pets/{id}/visible: + put: + consumes: + - application/json + description: Returns successful status if pet's IsVisible is successfully changed + parameters: + - description: changeView pet dto + in: body + name: changeViewDto + required: true + schema: + $ref: '#/definitions/dto.ChangeViewPetRequest' + - description: pet id + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/dto.ChangeViewPetResponse' + "400": + description: Invalid request body + schema: + $ref: '#/definitions/dto.ResponseBadRequestErr' + "500": + description: Internal service error + schema: + $ref: '#/definitions/dto.ResponseInternalErr' + "503": + description: Service is down + schema: + $ref: '#/definitions/dto.ResponseServiceDownErr' + summary: changes pet's public visiblility + tags: + - pet + /v1/pets/create: + post: + consumes: + - application/json + description: Returns the data of pet if successful + parameters: + - description: pet dto + in: body + name: create + required: true + schema: + $ref: '#/definitions/dto.CreatePetRequest' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/dto.PetResponse' + "400": + description: Invalid request body + schema: + $ref: '#/definitions/dto.ResponseBadRequestErr' + "500": + description: Internal service error + schema: + $ref: '#/definitions/dto.ResponseInternalErr' + "503": + description: Service is down + schema: + $ref: '#/definitions/dto.ResponseServiceDownErr' + summary: creates pet + tags: + - pet schemes: - https - http From a5244dfdd078def55e818c3e69c4377dbf6eaca8 Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Tue, 9 Jan 2024 23:55:45 +0700 Subject: [PATCH 08/30] chore: fix dto --- src/app/dto/pet.dto.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/app/dto/pet.dto.go b/src/app/dto/pet.dto.go index f3a8f79..15fa991 100644 --- a/src/app/dto/pet.dto.go +++ b/src/app/dto/pet.dto.go @@ -19,16 +19,16 @@ type PetResponse struct { Habit string `json:"habit"` Caption string `json:"caption"` Status pet.Status `json:"status"` - IsSterile *bool `json:"is_sterile"` - IsVaccinated *bool `json:"is_vaccinated"` - IsVisible *bool `json:"is_visible"` - IsClubPet *bool `json:"is_club_pet"` + IsSterile bool `json:"is_sterile"` + IsVaccinated bool `json:"is_vaccinated"` + IsVisible bool `json:"is_visible"` + IsClubPet bool `json:"is_club_pet"` Background string `json:"background"` Address string `json:"address"` Contact string `json:"contact"` AdoptBy string `json:"adopt_by"` Images []ImageResponse `json:"images"` - IsLike *bool `json:"is_like"` + IsLike bool `json:"is_like"` } type CreatePetRequest struct { @@ -40,10 +40,10 @@ type CreatePetRequest struct { Habit string `json:"habit" validate:"required"` Caption string `json:"caption"` Status pet.Status `json:"status" validate:"required" example:"1"` - 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"` + 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"` Background string `json:"background"` Address string `json:"address"` Contact string `json:"contact"` @@ -77,10 +77,10 @@ type UpdatePetRequest struct { Habit string `json:"habit"` Caption string `json:"caption"` Status pet.Status `json:"status"` - IsSterile *bool `json:"is_sterile"` - IsVaccinated *bool `json:"is_vaccinated"` - IsVisible *bool `json:"is_visible"` - IsClubPet *bool `json:"is_club_pet"` + IsSterile bool `json:"is_sterile"` + IsVaccinated bool `json:"is_vaccinated"` + IsVisible bool `json:"is_visible"` + IsClubPet bool `json:"is_club_pet"` Background string `json:"background"` Address string `json:"address"` Contact string `json:"contact"` From c1c44a19416c154c34f1d3d39376cc9088df80be Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Tue, 9 Jan 2024 23:56:27 +0700 Subject: [PATCH 09/30] fix: add mock context --- src/mocks/router/context.mock.go | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/mocks/router/context.mock.go b/src/mocks/router/context.mock.go index f2238b6..3836a61 100644 --- a/src/mocks/router/context.mock.go +++ b/src/mocks/router/context.mock.go @@ -34,7 +34,7 @@ func (m *MockIContext) EXPECT() *MockIContextMockRecorder { } // Bind mocks base method. -func (m *MockIContext) Bind(arg0 interface{}) error { +func (m *MockIContext) Bind(arg0 any) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Bind", arg0) ret0, _ := ret[0].(error) @@ -42,7 +42,7 @@ func (m *MockIContext) Bind(arg0 interface{}) error { } // Bind indicates an expected call of Bind. -func (mr *MockIContextMockRecorder) Bind(arg0 interface{}) *gomock.Call { +func (mr *MockIContextMockRecorder) Bind(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Bind", reflect.TypeOf((*MockIContext)(nil).Bind), arg0) } @@ -62,14 +62,28 @@ func (mr *MockIContextMockRecorder) ID() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockIContext)(nil).ID)) } +// IsAuth mocks base method. +func (m *MockIContext) IsAuth() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsAuth") + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsAuth indicates an expected call of IsAuth. +func (mr *MockIContextMockRecorder) IsAuth() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsAuth", reflect.TypeOf((*MockIContext)(nil).IsAuth)) +} + // JSON mocks base method. -func (m *MockIContext) JSON(arg0 int, arg1 interface{}) { +func (m *MockIContext) JSON(arg0 int, arg1 any) { m.ctrl.T.Helper() m.ctrl.Call(m, "JSON", arg0, arg1) } // JSON indicates an expected call of JSON. -func (mr *MockIContextMockRecorder) JSON(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockIContextMockRecorder) JSON(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JSON", reflect.TypeOf((*MockIContext)(nil).JSON), arg0, arg1) } @@ -112,7 +126,7 @@ func (m *MockIContext) Param(arg0 string) (string, error) { } // Param indicates an expected call of Param. -func (mr *MockIContextMockRecorder) Param(arg0 interface{}) *gomock.Call { +func (mr *MockIContextMockRecorder) Param(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Param", reflect.TypeOf((*MockIContext)(nil).Param), arg0) } @@ -138,7 +152,7 @@ func (m *MockIContext) StoreValue(arg0, arg1 string) { } // StoreValue indicates an expected call of StoreValue. -func (mr *MockIContextMockRecorder) StoreValue(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockIContextMockRecorder) StoreValue(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoreValue", reflect.TypeOf((*MockIContext)(nil).StoreValue), arg0, arg1) } From c60e7307698ba9e59287166f143a719d1e501ac5 Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Tue, 9 Jan 2024 23:57:09 +0700 Subject: [PATCH 10/30] chore: fix test --- src/app/handler/pet/pet.handler_test.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/app/handler/pet/pet.handler_test.go b/src/app/handler/pet/pet.handler_test.go index 448bf26..40f458d 100644 --- a/src/app/handler/pet/pet.handler_test.go +++ b/src/app/handler/pet/pet.handler_test.go @@ -113,15 +113,15 @@ func (t *PetHandlerTest) SetupTest() { Habit: t.Pet.Habit, Caption: t.Pet.Caption, Status: pet.Status(t.Pet.Status), - IsSterile: &t.Pet.IsSterile, - IsVaccinated: &t.Pet.IsVaccinated, - IsVisible: &t.Pet.IsVisible, - IsClubPet: &t.Pet.IsClubPet, + IsSterile: t.Pet.IsSterile, + IsVaccinated: t.Pet.IsVaccinated, + IsVisible: t.Pet.IsVisible, + IsClubPet: t.Pet.IsClubPet, Background: t.Pet.Background, Address: t.Pet.Address, Contact: t.Pet.Contact, AdoptBy: t.Pet.AdoptBy, - IsLike: petUtils.BoolAddr(true), + IsLike: false, } t.CreatePetRequest = &dto.CreatePetRequest{} @@ -172,6 +172,7 @@ func (t *PetHandlerTest) TestFindAllSuccess() { validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) + context.EXPECT().IsAuth().Return(true) context.EXPECT().UserID().Return(t.User.Id) petSvc.EXPECT().FindAll().Return(findAllResponse, nil) likeSvc.EXPECT().FindByUserId(t.User.Id).Return(likeUtils.ProtoToDtoList(t.Likes), nil) @@ -197,6 +198,7 @@ func (t *PetHandlerTest) TestFindOneSuccess() { validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) + context.EXPECT().IsAuth().Return(true) context.EXPECT().Param("id").Return(t.Pet.Id, nil) context.EXPECT().UserID().Return(t.User.Id) petSvc.EXPECT().FindOne(t.Pet.Id).Return(findOneResponse, nil) @@ -218,8 +220,8 @@ func (t *PetHandlerTest) TestFindOneNotFoundErr() { validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) + context.EXPECT().IsAuth().Return(true) context.EXPECT().Param("id").Return(t.Pet.Id, nil) - context.EXPECT().UserID().Return(t.User.Id) petSvc.EXPECT().FindOne(t.Pet.Id).Return(nil, findOneResponse) context.EXPECT().JSON(http.StatusNotFound, findOneResponse) @@ -238,8 +240,8 @@ func (t *PetHandlerTest) TestFindOneGrpcErr() { validator := validatorMock.NewMockIDtoValidator(controller) context := routerMock.NewMockIContext(controller) + context.EXPECT().IsAuth().Return(true) context.EXPECT().Param("id").Return(t.Pet.Id, nil) - context.EXPECT().UserID().Return(t.User.Id) petSvc.EXPECT().FindOne(t.Pet.Id).Return(nil, findOneResponse) context.EXPECT().JSON(http.StatusServiceUnavailable, findOneResponse) From 331cb01ca4889829eae2537118a52e1f3b92f131 Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Tue, 9 Jan 2024 23:58:45 +0700 Subject: [PATCH 11/30] feat: user `c.IsAuth()` for check if user is authenticated - if user not authenticate all `pet.IsLike` will be `false` --- src/app/handler/pet/pet.handler.go | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/app/handler/pet/pet.handler.go b/src/app/handler/pet/pet.handler.go index bfded94..86bc102 100644 --- a/src/app/handler/pet/pet.handler.go +++ b/src/app/handler/pet/pet.handler.go @@ -38,13 +38,23 @@ func NewHandler(service petSvc.Service, imageService imageSvc.Service, likeServi // @Failure 503 {object} dto.ResponseServiceDownErr "Service is down" // @Router /v1/pets/ [get] func (h *Handler) FindAll(c router.IContext) { - userID := c.UserID() + isAuth := c.IsAuth() response, respErr := h.service.FindAll() if respErr != nil { c.JSON(respErr.StatusCode, respErr) return } + if !isAuth { + c.JSON(http.StatusOK, dto.ResponseSuccess{ + StatusCode: http.StatusOK, + Message: petconst.FindAllPetSuccessMessage, + Data: response, + }) + return + } + + userID := c.UserID() likeResponse, likeErr := h.likeService.FindByUserId(userID) if likeErr != nil { c.JSON(likeErr.StatusCode, likeErr) @@ -58,7 +68,6 @@ func (h *Handler) FindAll(c router.IContext) { Message: petconst.FindAllPetSuccessMessage, Data: petWithLikeResponse, }) - return } @@ -76,7 +85,7 @@ func (h *Handler) FindAll(c router.IContext) { // @Router /v1/pets/{id} [get] func (h *Handler) FindOne(c router.IContext) { id, err := c.Param("id") - userId := c.UserID() + isAuth := c.IsAuth() if err != nil { c.JSON(http.StatusInternalServerError, dto.ResponseErr{ StatusCode: http.StatusInternalServerError, @@ -92,6 +101,16 @@ func (h *Handler) FindOne(c router.IContext) { return } + if !isAuth { + c.JSON(http.StatusOK, dto.ResponseSuccess{ + StatusCode: http.StatusOK, + Message: petconst.FindOnePetSuccessMessage, + Data: response, + }) + return + } + + userId := c.UserID() likeResponse, likeErr := h.likeService.FindByUserId(userId) if likeErr != nil { c.JSON(likeErr.StatusCode, likeErr) From 3e7f79519644cdbac762ed760f520ece3996aad2 Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Tue, 9 Jan 2024 23:59:32 +0700 Subject: [PATCH 12/30] feat: skip auth middleware for [GET] `/pets/` and `/pets/:id` --- src/app/middleware/auth/auth.middleware.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/app/middleware/auth/auth.middleware.go b/src/app/middleware/auth/auth.middleware.go index 70db9b5..6b267c4 100644 --- a/src/app/middleware/auth/auth.middleware.go +++ b/src/app/middleware/auth/auth.middleware.go @@ -1,13 +1,15 @@ 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" + petUtils "github.com/isd-sgcu/johnjud-gateway/src/app/utils/pet" "github.com/isd-sgcu/johnjud-gateway/src/config" authPkg "github.com/isd-sgcu/johnjud-gateway/src/pkg/service/auth" - "net/http" ) type Guard struct { @@ -37,6 +39,9 @@ func (m *Guard) Use(ctx router.IContext) error { token := ctx.Token() if token == "" { + if petUtils.CanSkipAuth(path) { + return ctx.Next() + } ctx.JSON(http.StatusUnauthorized, &dto.ResponseErr{ StatusCode: http.StatusUnauthorized, Message: "Invalid token", From 85dbb48a69d1c4e7c2542866548fb395e2b37301 Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Tue, 9 Jan 2024 23:59:52 +0700 Subject: [PATCH 13/30] feat: isAuth for check if user authenticated --- src/app/router/context.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/app/router/context.go b/src/app/router/context.go index 4a1b00f..8cedb2b 100644 --- a/src/app/router/context.go +++ b/src/app/router/context.go @@ -17,6 +17,7 @@ type IContext interface { Method() string Path() string StoreValue(string, string) + IsAuth() bool Next() error } @@ -29,7 +30,12 @@ func NewFiberCtx(c *fiber.Ctx) *FiberCtx { } func (c *FiberCtx) UserID() string { - return c.Ctx.Locals("UserId").(string) + userId := c.Ctx.Locals("UserId") + if userId != nil { + return userId.(string) + } + return "" + // return c.Ctx.Locals("UserId").(string) } func (c *FiberCtx) Bind(v interface{}) error { @@ -86,6 +92,16 @@ func (c *FiberCtx) StoreValue(k string, v string) { c.Locals(k, v) } +func (c *FiberCtx) IsAuth() bool { + raw := c.Ctx.Get(fiber.HeaderAuthorization, "") + parts := strings.Split(raw, " ") + + if len(parts) > 1 { + return true + } + return false +} + //func (c *FiberCtx) Next() { // err := c.Ctx.Next() // fmt.Println(c.Route().Path) From 292a82aa4942632d38271178b3d5070ef972ead2 Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Tue, 9 Jan 2024 23:59:55 +0700 Subject: [PATCH 14/30] chore --- src/app/service/pet/pet.service_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/app/service/pet/pet.service_test.go b/src/app/service/pet/pet.service_test.go index 5705c12..2e3b168 100644 --- a/src/app/service/pet/pet.service_test.go +++ b/src/app/service/pet/pet.service_test.go @@ -114,10 +114,10 @@ func (t *PetServiceTest) SetupTest() { Caption: t.Pet.Caption, Images: []string{}, Status: pet.Status(t.Pet.Status), - IsSterile: &t.Pet.IsSterile, - IsVaccinated: &t.Pet.IsVaccinated, - IsVisible: &t.Pet.IsVisible, - IsClubPet: &t.Pet.IsClubPet, + IsSterile: t.Pet.IsSterile, + IsVaccinated: t.Pet.IsVaccinated, + IsVisible: t.Pet.IsVisible, + IsClubPet: t.Pet.IsClubPet, Background: t.Pet.Background, Address: t.Pet.Address, Contact: t.Pet.Contact, @@ -134,10 +134,10 @@ func (t *PetServiceTest) SetupTest() { Caption: t.Pet.Caption, Images: []string{}, Status: pet.Status(t.Pet.Status), - IsSterile: &t.Pet.IsSterile, - IsVaccinated: &t.Pet.IsVaccinated, - IsVisible: &t.Pet.IsVisible, - IsClubPet: &t.Pet.IsClubPet, + IsSterile: t.Pet.IsSterile, + IsVaccinated: t.Pet.IsVaccinated, + IsVisible: t.Pet.IsVisible, + IsClubPet: t.Pet.IsClubPet, Background: t.Pet.Background, Address: t.Pet.Address, Contact: t.Pet.Contact, From 9bc862becc67c079db7a20c26cb7086d876e110a Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Wed, 10 Jan 2024 00:00:14 +0700 Subject: [PATCH 15/30] feat: CanSkipAuth check --- src/app/utils/pet/pet.utils.go | 62 ++++++++++++---------------------- 1 file changed, 21 insertions(+), 41 deletions(-) diff --git a/src/app/utils/pet/pet.utils.go b/src/app/utils/pet/pet.utils.go index 05f59cf..1552e55 100644 --- a/src/app/utils/pet/pet.utils.go +++ b/src/app/utils/pet/pet.utils.go @@ -2,6 +2,7 @@ package pet import ( "fmt" + "strings" "github.com/isd-sgcu/johnjud-gateway/src/app/dto" "github.com/isd-sgcu/johnjud-gateway/src/constant/pet" @@ -38,10 +39,10 @@ func ProtoToDto(in *petproto.Pet, images []*imgproto.Image) *dto.PetResponse { Habit: in.Habit, Caption: in.Caption, Status: pet.Status(in.Status), - IsSterile: &in.IsSterile, - IsVaccinated: &in.IsVaccinated, - IsVisible: &in.IsVisible, - IsClubPet: &in.IsClubPet, + IsSterile: in.IsSterile, + IsVaccinated: in.IsVaccinated, + IsVisible: in.IsVisible, + IsClubPet: in.IsClubPet, Background: in.Background, Address: in.Address, Contact: in.Contact, @@ -63,10 +64,10 @@ func CreateDtoToProto(in *dto.CreatePetRequest) *petproto.CreatePetRequest { Caption: in.Caption, Images: []*imgproto.Image{}, Status: petproto.PetStatus(in.Status), - IsSterile: *in.IsSterile, - IsVaccinated: *in.IsVaccinated, - IsVisible: *in.IsVisible, - IsClubPet: *in.IsClubPet, + IsSterile: in.IsSterile, + IsVaccinated: in.IsVaccinated, + IsVisible: in.IsVisible, + IsClubPet: in.IsClubPet, Background: in.Background, Address: in.Address, Contact: in.Contact, @@ -95,30 +96,6 @@ func UpdateDtoToProto(id string, in *dto.UpdatePetRequest) *petproto.UpdatePetRe }, } - if in.IsClubPet == nil { - req.Pet.IsClubPet = false - } else { - req.Pet.IsClubPet = *in.IsClubPet - } - - if in.IsSterile == nil { - req.Pet.IsSterile = false - } else { - req.Pet.IsSterile = *in.IsSterile - } - - if in.IsVaccinated == nil { - req.Pet.IsVaccinated = false - } else { - req.Pet.IsVaccinated = *in.IsVaccinated - } - - if in.IsVisible == nil { - req.Pet.IsVisible = false - } else { - req.Pet.IsVisible = *in.IsVisible - } - return req } @@ -135,10 +112,10 @@ func ProtoToDtoList(in []*petproto.Pet, imagesList [][]*imgproto.Image) []*dto.P Habit: p.Habit, Caption: p.Caption, Status: pet.Status(p.Status), - IsSterile: &p.IsSterile, - IsVaccinated: &p.IsVaccinated, - IsVisible: &p.IsVisible, - IsClubPet: &p.IsClubPet, + IsSterile: p.IsSterile, + IsVaccinated: p.IsVaccinated, + IsVisible: p.IsVisible, + IsClubPet: p.IsClubPet, Background: p.Background, Address: p.Address, Contact: p.Contact, @@ -160,13 +137,13 @@ func extractImages(images []*imgproto.Image) []dto.ImageResponse { } return result } -func IsLike(petId string, likes []*dto.LikeResponse) *bool { +func IsLike(petId string, likes []*dto.LikeResponse) bool { for _, like := range likes { if like.PetID == petId { - return BoolAddr(true) + return true } } - return BoolAddr(false) + return false } func MapIsLikeToPets(likes []*dto.LikeResponse, pets []*dto.PetResponse) []*dto.PetResponse { @@ -176,6 +153,9 @@ func MapIsLikeToPets(likes []*dto.LikeResponse, pets []*dto.PetResponse) []*dto. return pets } -func BoolAddr(b bool) *bool { - return &b +func CanSkipAuth(path string) bool { + s := strings.Split(path, "/") + m := strings.Trim(s[0], " ") + p := s[1] + return m == "GET" && p == "pets" } From 26230c69159b6c69d13fcc64f5e24c88da071345 Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Wed, 10 Jan 2024 00:00:45 +0700 Subject: [PATCH 16/30] fix: remove `GET /pet/` use `CanSkipAuth` instead --- src/constant/auth/auth.constant.go | 1 - 1 file changed, 1 deletion(-) diff --git a/src/constant/auth/auth.constant.go b/src/constant/auth/auth.constant.go index 2273fbe..7c67043 100644 --- a/src/constant/auth/auth.constant.go +++ b/src/constant/auth/auth.constant.go @@ -4,7 +4,6 @@ var ExcludePath = map[string]struct{}{ "POST /auth/signup": {}, "POST /auth/signin": {}, "POST /auth/verify": {}, - "GET /pet/": {}, "GET /adopt/": {}, } From 65f9e0d6c266ca0e5e72f95d2dca01975171e4ab Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:40:12 +0700 Subject: [PATCH 17/30] Revert "Merge remote-tracking branch 'origin/dev' into gear/joh-35-image-endpoints" This reverts commit ca107a29a5626c2229212038ac74929935f8e59e, reversing changes made to 26230c69159b6c69d13fcc64f5e24c88da071345. --- src/app/service/image/image.service_test.go | 80 --------------------- src/app/utils/image/image.utils.go | 54 -------------- src/constant/image/image.constant.go | 5 -- src/mocks/client/image/image.mock.go | 38 ---------- 4 files changed, 177 deletions(-) delete mode 100644 src/app/service/image/image.service_test.go delete mode 100644 src/app/utils/image/image.utils.go delete mode 100644 src/constant/image/image.constant.go delete mode 100644 src/mocks/client/image/image.mock.go diff --git a/src/app/service/image/image.service_test.go b/src/app/service/image/image.service_test.go deleted file mode 100644 index 843d5de..0000000 --- a/src/app/service/image/image.service_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package image - -import ( - "net/http" - "testing" - - "github.com/bxcodec/faker/v4" - "github.com/isd-sgcu/johnjud-gateway/src/app/constant" - "github.com/isd-sgcu/johnjud-gateway/src/app/dto" - imageUtils "github.com/isd-sgcu/johnjud-gateway/src/app/utils/image" - imageProto "github.com/isd-sgcu/johnjud-go-proto/johnjud/file/image/v1" - "github.com/stretchr/testify/suite" -) - -type ImageServiceTest struct { - suite.Suite - ImagesList [][]*imageProto.Image - Images []*imageProto.Image - ImagesListResponse [][]*dto.ImageResponse - ImagesResponse []*dto.ImageResponse - UploadImageProtoReq *imageProto.UploadImageRequest - UploadImageDtoReq *dto.UploadImageRequest - DeleteImageProtoReq *imageProto.DeleteImageRequest - - NotFoundErr *dto.ResponseErr - UnavailableServiceErr *dto.ResponseErr - InvalidArgumentErr *dto.ResponseErr - InternalErr *dto.ResponseErr -} - -func TestImageService(t *testing.T) { - suite.Run(t, new(ImageServiceTest)) -} - -func (t *ImageServiceTest) SetupTest() { - imagesList := imageUtils.MockImageList(3) - t.ImagesList = imagesList - t.Images = imagesList[0] - - t.UploadImageProtoReq = &imageProto.UploadImageRequest{ - Filename: faker.FirstName(), - Data: []byte(faker.Word()), - PetId: faker.UUIDDigit(), - } - - t.UploadImageDtoReq = &dto.UploadImageRequest{ - Filename: faker.FirstName(), - Data: []byte(faker.Word()), - PetId: faker.UUIDDigit(), - } - - t.DeleteImageProtoReq = &imageProto.DeleteImageRequest{ - Id: faker.UUIDDigit(), - ObjectKey: faker.Word(), - } - - 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.InternalErr = &dto.ResponseErr{ - StatusCode: http.StatusInternalServerError, - Message: constant.InternalErrorMessage, - Data: nil, - } - - t.InvalidArgumentErr = &dto.ResponseErr{ - StatusCode: http.StatusBadRequest, - Message: constant.InvalidArgumentMessage, - Data: nil, - } -} diff --git a/src/app/utils/image/image.utils.go b/src/app/utils/image/image.utils.go deleted file mode 100644 index 705c34f..0000000 --- a/src/app/utils/image/image.utils.go +++ /dev/null @@ -1,54 +0,0 @@ -package image - -import ( - "fmt" - - "github.com/isd-sgcu/johnjud-gateway/src/app/dto" - imageProto "github.com/isd-sgcu/johnjud-go-proto/johnjud/file/image/v1" -) - -func ProtoToDto(in *imageProto.Image) *dto.ImageResponse { - return &dto.ImageResponse{ - Id: in.Id, - Url: in.ImageUrl, - ObjectKey: in.ObjectKey, - } -} - -func ProtoToDtoList(in []*imageProto.Image) []*dto.ImageResponse { - var res []*dto.ImageResponse - for _, i := range in { - res = append(res, &dto.ImageResponse{ - Id: i.Id, - Url: i.ImageUrl, - ObjectKey: i.ObjectKey, - }) - } - return res -} - -func CreateDtoToProto(in *dto.UploadImageRequest) *imageProto.UploadImageRequest { - return &imageProto.UploadImageRequest{ - Filename: in.Filename, - Data: in.Data, - PetId: in.PetId, - } -} - -func MockImageList(n int) [][]*imageProto.Image { - var imagesList [][]*imageProto.Image - for i := 0; i <= n; i++ { - var images []*imageProto.Image - for j := 0; j <= 3; j++ { - images = append(images, &imageProto.Image{ - Id: fmt.Sprintf("%v%v", i, j), - PetId: fmt.Sprintf("%v%v", i, j), - ImageUrl: fmt.Sprintf("%v%v", i, j), - ObjectKey: fmt.Sprintf("%v%v", i, j), - }) - } - imagesList = append(imagesList, images) - } - - return imagesList -} diff --git a/src/constant/image/image.constant.go b/src/constant/image/image.constant.go deleted file mode 100644 index d20da60..0000000 --- a/src/constant/image/image.constant.go +++ /dev/null @@ -1,5 +0,0 @@ -package image - -const FindImageSuccessMessage = "find images success" -const UploadImageSuccessMessage = "upload image success" -const DelteImageSuccessMessage = "delete image success" diff --git a/src/mocks/client/image/image.mock.go b/src/mocks/client/image/image.mock.go deleted file mode 100644 index 677fd91..0000000 --- a/src/mocks/client/image/image.mock.go +++ /dev/null @@ -1,38 +0,0 @@ -package like - -import ( - "context" - - imageProto "github.com/isd-sgcu/johnjud-go-proto/johnjud/file/image/v1" - "github.com/stretchr/testify/mock" - "google.golang.org/grpc" -) - -type LikeClientMock struct { - mock.Mock -} - -func (c *LikeClientMock) FindByPetId(_ context.Context, in *imageProto.FindImageByPetIdRequest, _ ...grpc.CallOption) (res *imageProto.FindImageByPetIdResponse, err error) { - args := c.Called(in) - - if args.Get(0) != nil { - res = args.Get(0).(*imageProto.FindImageByPetIdResponse) - } - return res, args.Error(1) -} -func (c *LikeClientMock) Create(_ context.Context, in *imageProto.UploadImageRequest, _ ...grpc.CallOption) (res *imageProto.UploadImageResponse, err error) { - args := c.Called(in) - - if args.Get(0) != nil { - res = args.Get(0).(*imageProto.UploadImageResponse) - } - return res, args.Error(1) -} -func (c *LikeClientMock) Delete(_ context.Context, in *imageProto.DeleteImageRequest, _ ...grpc.CallOption) (res *imageProto.DeleteImageResponse, err error) { - args := c.Called(in) - - if args.Get(0) != nil { - res = args.Get(0).(*imageProto.DeleteImageResponse) - } - return res, args.Error(1) -} From 90c060f2416630ab69440e9dce396fc167c16de9 Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:48:10 +0700 Subject: [PATCH 18/30] chore --- src/app/constant/error.constant.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/constant/error.constant.go b/src/app/constant/error.constant.go index 6b9a24a..5e378d3 100644 --- a/src/app/constant/error.constant.go +++ b/src/app/constant/error.constant.go @@ -13,3 +13,4 @@ const InvalidArgumentMessage = "Invalid Argument" const PetNotFoundMessage = "Pet not found" const UserNotFoundMessage = "User not found" +const ImageNotFoundMessage = "Image not found" From 2d8cd5380abec8d0e190bb9050f76b8fa4a6582f Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:48:20 +0700 Subject: [PATCH 19/30] fix: dto --- src/app/dto/image.dto.go | 6 +++++- src/app/dto/pet.dto.go | 5 +++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/app/dto/image.dto.go b/src/app/dto/image.dto.go index f30947a..154a926 100644 --- a/src/app/dto/image.dto.go +++ b/src/app/dto/image.dto.go @@ -1,7 +1,11 @@ package dto -type ImageDto struct { +type UploadImageRequest struct { Filename string `json:"filename" validate:"required"` Data []byte `json:"data" validate:"required"` PetId string `json:"pet_id" validate:"required"` } + +type DeleteImageResponse struct { + Success bool `json:"success"` +} diff --git a/src/app/dto/pet.dto.go b/src/app/dto/pet.dto.go index 15fa991..ebf8a70 100644 --- a/src/app/dto/pet.dto.go +++ b/src/app/dto/pet.dto.go @@ -5,8 +5,9 @@ import ( ) type ImageResponse struct { - Id string `json:"id"` - Url string `json:"url"` + Id string `json:"id"` + Url string `json:"url"` + ObjectKey string `json:"object_key"` } type PetResponse struct { From cd25c511b6433a5239e58f68698dd9608808a72a Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:50:23 +0700 Subject: [PATCH 20/30] chore --- src/app/handler/image/image.handler.go | 89 +++++++++++++++++++++++++- src/app/handler/like/like.handler.go | 4 +- src/app/handler/pet/pet.handler.go | 2 +- 3 files changed, 90 insertions(+), 5 deletions(-) diff --git a/src/app/handler/image/image.handler.go b/src/app/handler/image/image.handler.go index 7e496cb..b32c1fb 100644 --- a/src/app/handler/image/image.handler.go +++ b/src/app/handler/image/image.handler.go @@ -1,28 +1,113 @@ package auth import ( + "fmt" + "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" + imageConst "github.com/isd-sgcu/johnjud-gateway/src/constant/image" imageSvc "github.com/isd-sgcu/johnjud-gateway/src/pkg/service/image" ) type Handler struct { service imageSvc.Service - validate *validator.DtoValidator + validate validator.IDtoValidator } -func NewHandler(service imageSvc.Service, validate *validator.DtoValidator) *Handler { +func NewHandler(service imageSvc.Service, validate validator.IDtoValidator) *Handler { return &Handler{service, validate} } func (h *Handler) FindByPetId(c *router.FiberCtx) { + id, err := c.ID() + if err != nil { + c.JSON(http.StatusBadRequest, dto.ResponseErr{ + StatusCode: http.StatusInternalServerError, + Message: constant.InvalidIDMessage, + Data: nil, + }) + return + } + + response, respErr := h.service.FindByPetId(id) + if respErr != nil { + c.JSON(respErr.StatusCode, respErr) + return + } + c.JSON(http.StatusOK, dto.ResponseSuccess{ + StatusCode: http.StatusOK, + Message: imageConst.FindImageSuccessMessage, + Data: response, + }) + return } func (h *Handler) Upload(c *router.FiberCtx) { + request := &dto.UploadImageRequest{} + err := c.Bind(request) + fmt.Println("request: ", request) + if err != nil { + 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 + } + response, respErr := h.service.Upload(request) + if respErr != nil { + c.JSON(respErr.StatusCode, respErr) + return + } + + c.JSON(http.StatusCreated, dto.ResponseSuccess{ + StatusCode: http.StatusCreated, + Message: imageConst.UploadImageSuccessMessage, + Data: response, + }) + return } func (h *Handler) Delete(c *router.FiberCtx) { + 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: imageConst.DelteImageSuccessMessage, + Data: res, + }) + return } diff --git a/src/app/handler/like/like.handler.go b/src/app/handler/like/like.handler.go index ab57fd8..799fc10 100644 --- a/src/app/handler/like/like.handler.go +++ b/src/app/handler/like/like.handler.go @@ -22,7 +22,7 @@ func NewHandler(service likeSvc.Service, validate validator.IDtoValidator) *Hand } func (h *Handler) FindByUserId(c router.IContext) { - id, err := c.Param("id") + id, err := c.ID() if err != nil { c.JSON(http.StatusBadRequest, dto.ResponseErr{ StatusCode: http.StatusInternalServerError, @@ -86,7 +86,7 @@ func (h *Handler) Create(c router.IContext) { } func (h *Handler) Delete(c router.IContext) { - id, err := c.Param("id") + id, err := c.ID() if err != nil { c.JSON(http.StatusBadRequest, dto.ResponseErr{ StatusCode: http.StatusBadRequest, diff --git a/src/app/handler/pet/pet.handler.go b/src/app/handler/pet/pet.handler.go index 86bc102..9f9c503 100644 --- a/src/app/handler/pet/pet.handler.go +++ b/src/app/handler/pet/pet.handler.go @@ -84,7 +84,7 @@ func (h *Handler) FindAll(c router.IContext) { // @Failure 503 {object} dto.ResponseServiceDownErr "Service is down" // @Router /v1/pets/{id} [get] func (h *Handler) FindOne(c router.IContext) { - id, err := c.Param("id") + id, err := c.ID() isAuth := c.IsAuth() if err != nil { c.JSON(http.StatusInternalServerError, dto.ResponseErr{ From 87da57f8c67aabcf00f6f087d0bcaccfe778ed39 Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:50:49 +0700 Subject: [PATCH 21/30] feat: GET image endpoint --- src/app/router/image.router.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/app/router/image.router.go b/src/app/router/image.router.go index e696190..f064d06 100644 --- a/src/app/router/image.router.go +++ b/src/app/router/image.router.go @@ -15,3 +15,10 @@ func (r *FiberRouter) DeleteImage(path string, h func(ctx *FiberCtx)) { return nil }) } + +func (r *FiberRouter) GetImages(path string, h func(ctx *FiberCtx)) { + r.image.Get(path, func(c *fiber.Ctx) error { + h(NewFiberCtx(c)) + return nil + }) +} From c6cf7e00501002c1b2c580af82f3c7f3e0329bb1 Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:50:59 +0700 Subject: [PATCH 22/30] feat: image utils --- src/app/utils/image/image.utils.go | 54 ++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/app/utils/image/image.utils.go diff --git a/src/app/utils/image/image.utils.go b/src/app/utils/image/image.utils.go new file mode 100644 index 0000000..705c34f --- /dev/null +++ b/src/app/utils/image/image.utils.go @@ -0,0 +1,54 @@ +package image + +import ( + "fmt" + + "github.com/isd-sgcu/johnjud-gateway/src/app/dto" + imageProto "github.com/isd-sgcu/johnjud-go-proto/johnjud/file/image/v1" +) + +func ProtoToDto(in *imageProto.Image) *dto.ImageResponse { + return &dto.ImageResponse{ + Id: in.Id, + Url: in.ImageUrl, + ObjectKey: in.ObjectKey, + } +} + +func ProtoToDtoList(in []*imageProto.Image) []*dto.ImageResponse { + var res []*dto.ImageResponse + for _, i := range in { + res = append(res, &dto.ImageResponse{ + Id: i.Id, + Url: i.ImageUrl, + ObjectKey: i.ObjectKey, + }) + } + return res +} + +func CreateDtoToProto(in *dto.UploadImageRequest) *imageProto.UploadImageRequest { + return &imageProto.UploadImageRequest{ + Filename: in.Filename, + Data: in.Data, + PetId: in.PetId, + } +} + +func MockImageList(n int) [][]*imageProto.Image { + var imagesList [][]*imageProto.Image + for i := 0; i <= n; i++ { + var images []*imageProto.Image + for j := 0; j <= 3; j++ { + images = append(images, &imageProto.Image{ + Id: fmt.Sprintf("%v%v", i, j), + PetId: fmt.Sprintf("%v%v", i, j), + ImageUrl: fmt.Sprintf("%v%v", i, j), + ObjectKey: fmt.Sprintf("%v%v", i, j), + }) + } + imagesList = append(imagesList, images) + } + + return imagesList +} From e5a40f30f74b4f01976d7ee8ad324e6d2e28f93d Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:51:06 +0700 Subject: [PATCH 23/30] chore --- src/constant/image/image.constant.go | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/constant/image/image.constant.go diff --git a/src/constant/image/image.constant.go b/src/constant/image/image.constant.go new file mode 100644 index 0000000..d20da60 --- /dev/null +++ b/src/constant/image/image.constant.go @@ -0,0 +1,5 @@ +package image + +const FindImageSuccessMessage = "find images success" +const UploadImageSuccessMessage = "upload image success" +const DelteImageSuccessMessage = "delete image success" From d3c7cc726652a6a0fba974b86d9a86dcc93b6d05 Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:51:18 +0700 Subject: [PATCH 24/30] chore: image mock --- src/mocks/client/image/image.mock.go | 38 ++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/mocks/client/image/image.mock.go diff --git a/src/mocks/client/image/image.mock.go b/src/mocks/client/image/image.mock.go new file mode 100644 index 0000000..677fd91 --- /dev/null +++ b/src/mocks/client/image/image.mock.go @@ -0,0 +1,38 @@ +package like + +import ( + "context" + + imageProto "github.com/isd-sgcu/johnjud-go-proto/johnjud/file/image/v1" + "github.com/stretchr/testify/mock" + "google.golang.org/grpc" +) + +type LikeClientMock struct { + mock.Mock +} + +func (c *LikeClientMock) FindByPetId(_ context.Context, in *imageProto.FindImageByPetIdRequest, _ ...grpc.CallOption) (res *imageProto.FindImageByPetIdResponse, err error) { + args := c.Called(in) + + if args.Get(0) != nil { + res = args.Get(0).(*imageProto.FindImageByPetIdResponse) + } + return res, args.Error(1) +} +func (c *LikeClientMock) Create(_ context.Context, in *imageProto.UploadImageRequest, _ ...grpc.CallOption) (res *imageProto.UploadImageResponse, err error) { + args := c.Called(in) + + if args.Get(0) != nil { + res = args.Get(0).(*imageProto.UploadImageResponse) + } + return res, args.Error(1) +} +func (c *LikeClientMock) Delete(_ context.Context, in *imageProto.DeleteImageRequest, _ ...grpc.CallOption) (res *imageProto.DeleteImageResponse, err error) { + args := c.Called(in) + + if args.Get(0) != nil { + res = args.Get(0).(*imageProto.DeleteImageResponse) + } + return res, args.Error(1) +} From 50bc17c273ba6b8372bfe655b71005a4afcca2fc Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:51:29 +0700 Subject: [PATCH 25/30] feat: image endpoint --- src/main.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main.go b/src/main.go index a9dc228..128adc5 100644 --- a/src/main.go +++ b/src/main.go @@ -12,6 +12,7 @@ import ( authHdr "github.com/isd-sgcu/johnjud-gateway/src/app/handler/auth" healthcheck "github.com/isd-sgcu/johnjud-gateway/src/app/handler/healthcheck" + imageHdr "github.com/isd-sgcu/johnjud-gateway/src/app/handler/image" likeHdr "github.com/isd-sgcu/johnjud-gateway/src/app/handler/like" petHdr "github.com/isd-sgcu/johnjud-gateway/src/app/handler/pet" userHdr "github.com/isd-sgcu/johnjud-gateway/src/app/handler/user" @@ -107,6 +108,7 @@ func main() { imageClient := imageProto.NewImageServiceClient(fileConn) imageService := imageSvc.NewService(imageClient) + imageHandler := imageHdr.NewHandler(imageService, v) likeClient := likeProto.NewLikeServiceClient(backendConn) likeService := likeSvc.NewService(likeClient) @@ -114,8 +116,7 @@ func main() { petClient := petProto.NewPetServiceClient(backendConn) petService := petSvc.NewService(petClient) - petHandler := petHdr.NewHandler(petService, imageService, likeService, v) - + petHandler := petHdr.NewHandler(petService, imageService, likeService, v) r := router.NewFiberRouter(&authGuard, conf.App) @@ -142,6 +143,10 @@ func main() { r.PostLike("/", likeHandler.Create) r.DeleteLike("/:id", likeHandler.Delete) + r.PostImage("/create", imageHandler.Upload) + r.GetImages("/:id", imageHandler.FindByPetId) + r.DeleteImage("/:id", imageHandler.Delete) + v1 := router.NewAPIv1(r, conf.App) go func() { From dec3428e3853769fc8c6aea398b60b35bbfb4232 Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:51:36 +0700 Subject: [PATCH 26/30] fix: image service interface --- src/pkg/service/image/image.service.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/pkg/service/image/image.service.go b/src/pkg/service/image/image.service.go index 4b68d29..836ae59 100644 --- a/src/pkg/service/image/image.service.go +++ b/src/pkg/service/image/image.service.go @@ -2,11 +2,10 @@ package image import ( "github.com/isd-sgcu/johnjud-gateway/src/app/dto" - proto "github.com/isd-sgcu/johnjud-go-proto/johnjud/file/image/v1" ) type Service interface { - FindByPetId(string) ([]*proto.Image, *dto.ResponseErr) - Upload(*dto.ImageDto) (*proto.Image, *dto.ResponseErr) - Delete(string) (bool, *dto.ResponseErr) + FindByPetId(string) ([]*dto.ImageResponse, *dto.ResponseErr) + Upload(*dto.UploadImageRequest) (*dto.ImageResponse, *dto.ResponseErr) + Delete(string) (*dto.DeleteImageResponse, *dto.ResponseErr) } From 730a318467ccbbda2a1fd02e76fa8e598f30fabf Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:51:42 +0700 Subject: [PATCH 27/30] gen mock --- src/mocks/service/image/image.mock.go | 38 +++++++++++++++------------ 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/mocks/service/image/image.mock.go b/src/mocks/service/image/image.mock.go index 09a1ae0..d629982 100644 --- a/src/mocks/service/image/image.mock.go +++ b/src/mocks/service/image/image.mock.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: ./src/pkg/service/image/image.service.go +// +// Generated by this command: +// +// mockgen -source ./src/pkg/service/image/image.service.go -destination ./src/mocks/service/image/image.mock.go +// // Package mock_image is a generated GoMock package. package mock_image @@ -7,9 +12,8 @@ package mock_image import ( reflect "reflect" - 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/file/image/v1" + gomock "github.com/golang/mock/gomock" ) // MockService is a mock of Service interface. @@ -36,46 +40,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) (*dto.DeleteImageResponse, *dto.ResponseErr) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Delete", id) - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "Delete", arg0) + ret0, _ := ret[0].(*dto.DeleteImageResponse) 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 any) *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) ([]*dto.ImageResponse, *dto.ResponseErr) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FindByPetId", id) - ret0, _ := ret[0].([]*v1.Image) + ret := m.ctrl.Call(m, "FindByPetId", arg0) + ret0, _ := ret[0].([]*dto.ImageResponse) 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 any) *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.UploadImageRequest) (*dto.ImageResponse, *dto.ResponseErr) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Upload", in) - ret0, _ := ret[0].(*v1.Image) + ret := m.ctrl.Call(m, "Upload", arg0) + ret0, _ := ret[0].(*dto.ImageResponse) 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 any) *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) } From ea2a73676ea218ec3c71f2e5dd369a6f554893a7 Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:51:50 +0700 Subject: [PATCH 28/30] test: setup etst --- src/app/service/image/image.service_test.go | 80 +++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 src/app/service/image/image.service_test.go diff --git a/src/app/service/image/image.service_test.go b/src/app/service/image/image.service_test.go new file mode 100644 index 0000000..843d5de --- /dev/null +++ b/src/app/service/image/image.service_test.go @@ -0,0 +1,80 @@ +package image + +import ( + "net/http" + "testing" + + "github.com/bxcodec/faker/v4" + "github.com/isd-sgcu/johnjud-gateway/src/app/constant" + "github.com/isd-sgcu/johnjud-gateway/src/app/dto" + imageUtils "github.com/isd-sgcu/johnjud-gateway/src/app/utils/image" + imageProto "github.com/isd-sgcu/johnjud-go-proto/johnjud/file/image/v1" + "github.com/stretchr/testify/suite" +) + +type ImageServiceTest struct { + suite.Suite + ImagesList [][]*imageProto.Image + Images []*imageProto.Image + ImagesListResponse [][]*dto.ImageResponse + ImagesResponse []*dto.ImageResponse + UploadImageProtoReq *imageProto.UploadImageRequest + UploadImageDtoReq *dto.UploadImageRequest + DeleteImageProtoReq *imageProto.DeleteImageRequest + + NotFoundErr *dto.ResponseErr + UnavailableServiceErr *dto.ResponseErr + InvalidArgumentErr *dto.ResponseErr + InternalErr *dto.ResponseErr +} + +func TestImageService(t *testing.T) { + suite.Run(t, new(ImageServiceTest)) +} + +func (t *ImageServiceTest) SetupTest() { + imagesList := imageUtils.MockImageList(3) + t.ImagesList = imagesList + t.Images = imagesList[0] + + t.UploadImageProtoReq = &imageProto.UploadImageRequest{ + Filename: faker.FirstName(), + Data: []byte(faker.Word()), + PetId: faker.UUIDDigit(), + } + + t.UploadImageDtoReq = &dto.UploadImageRequest{ + Filename: faker.FirstName(), + Data: []byte(faker.Word()), + PetId: faker.UUIDDigit(), + } + + t.DeleteImageProtoReq = &imageProto.DeleteImageRequest{ + Id: faker.UUIDDigit(), + ObjectKey: faker.Word(), + } + + 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.InternalErr = &dto.ResponseErr{ + StatusCode: http.StatusInternalServerError, + Message: constant.InternalErrorMessage, + Data: nil, + } + + t.InvalidArgumentErr = &dto.ResponseErr{ + StatusCode: http.StatusBadRequest, + Message: constant.InvalidArgumentMessage, + Data: nil, + } +} From edf676518c2a68769a06e914f358585fbd325964 Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:52:00 +0700 Subject: [PATCH 29/30] feat: iamge service --- src/app/service/image/image.service.go | 122 +++++++++++++++++++++++-- 1 file changed, 116 insertions(+), 6 deletions(-) diff --git a/src/app/service/image/image.service.go b/src/app/service/image/image.service.go index 6ff8668..05c1bc4 100644 --- a/src/app/service/image/image.service.go +++ b/src/app/service/image/image.service.go @@ -1,8 +1,17 @@ package image import ( + "context" + "net/http" + "time" + + "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/image" proto "github.com/isd-sgcu/johnjud-go-proto/johnjud/file/image/v1" + "github.com/rs/zerolog/log" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) type Service struct { @@ -15,14 +24,115 @@ func NewService(client proto.ImageServiceClient) *Service { } } -func (s *Service) FindByPetId(string) ([]*proto.Image, *dto.ResponseErr) { - return nil, nil +func (s *Service) FindByPetId(petId string) ([]*dto.ImageResponse, *dto.ResponseErr) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + res, errRes := s.client.FindByPetId(ctx, &proto.FindImageByPetIdRequest{PetId: petId}) + if errRes != nil { + st, _ := status.FromError(errRes) + log.Error(). + Str("service", "image"). + Str("module", "find by pet id"). + Msg(st.Message()) + switch st.Code() { + case codes.NotFound: + return nil, &dto.ResponseErr{ + StatusCode: http.StatusNotFound, + Message: constant.PetNotFoundMessage, + 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 utils.ProtoToDtoList(res.Images), nil } -func (s *Service) Upload(in *dto.ImageDto) (*proto.Image, *dto.ResponseErr) { - return nil, nil +func (s *Service) Upload(in *dto.UploadImageRequest) (*dto.ImageResponse, *dto.ResponseErr) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + request := utils.CreateDtoToProto(in) + res, errRes := s.client.Upload(ctx, request) + if errRes != nil { + st, _ := status.FromError(errRes) + log.Error(). + Err(errRes). + Str("service", "image"). + Str("module", "upload"). + Msg(st.Message()) + switch st.Code() { + case codes.InvalidArgument: + return nil, &dto.ResponseErr{ + StatusCode: http.StatusBadRequest, + Message: constant.InvalidArgumentMessage, + 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 utils.ProtoToDto(res.Image), nil } -func (s *Service) Delete(id string) (bool, *dto.ResponseErr) { - return false, nil +func (s *Service) Delete(id string) (*dto.DeleteImageResponse, *dto.ResponseErr) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + request := &proto.DeleteImageRequest{ + Id: id, + } + + res, errRes := s.client.Delete(ctx, request) + if errRes != nil { + st, _ := status.FromError(errRes) + log.Error(). + Err(errRes). + Str("service", "image"). + Str("module", "delete"). + Msg(st.Message()) + switch st.Code() { + case codes.NotFound: + return nil, &dto.ResponseErr{ + StatusCode: http.StatusNotFound, + Message: constant.ImageNotFoundMessage, + 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.DeleteImageResponse{ + Success: res.Success, + }, nil } From dceec6a5d8bb43def7076642955a723bd0b1be17 Mon Sep 17 00:00:00 2001 From: Gear <84141000+macgeargear@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:52:03 +0700 Subject: [PATCH 30/30] chore --- src/app/router/router.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/router/router.go b/src/app/router/router.go index 2a2bb91..0f55c33 100644 --- a/src/app/router/router.go +++ b/src/app/router/router.go @@ -51,7 +51,7 @@ func NewFiberRouter(authGuard IGuard, conf config.App) *FiberRouter { user := GroupWithAuthMiddleware(r, "/user", authGuard.Use) pet := GroupWithAuthMiddleware(r, "/pets", authGuard.Use) - image := GroupWithAuthMiddleware(r, "/image", authGuard.Use) + image := GroupWithAuthMiddleware(r, "/images", authGuard.Use) like := GroupWithAuthMiddleware(r, "/likes", authGuard.Use) return &FiberRouter{r, auth, user, pet, image, like}