Skip to content

Commit

Permalink
feat: delete by pet id
Browse files Browse the repository at this point in the history
  • Loading branch information
bookpanda committed Feb 13, 2024
1 parent d4e982f commit 39627f7
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 1 deletion.
24 changes: 24 additions & 0 deletions client/bucket/bucket.client.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,30 @@ func (c *Client) Delete(objectKey string) error {
return nil
}

func (c *Client) DeleteMany(objectKeys []string) error {
ctx := context.Background()
ctx, cancel := context.WithTimeout(ctx, 50*time.Second)
defer cancel()

opts := minio.RemoveObjectOptions{
GovernanceBypass: true,
}
for _, objectKey := range objectKeys {
err := c.minio.RemoveObject(context.Background(), c.conf.BucketName, objectKey, opts)
if err != nil {
log.Error().
Err(err).
Str("service", "file").
Str("module", "bucket client").
Msgf("Couldn't delete object from bucket %v:%v.", c.conf.BucketName, objectKey)

return errors.Wrap(err, "Error while deleting the object")
}
}

return nil
}

func (c *Client) getURL(objectKey string) string {
return "https://" + c.conf.Endpoint + "/" + c.conf.BucketName + "/" + objectKey
}
62 changes: 62 additions & 0 deletions internal/service/image/image.service.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,50 @@ func (s *serviceImpl) Delete(_ context.Context, req *proto.DeleteImageRequest) (
return &proto.DeleteImageResponse{Success: true}, nil
}

func (s *serviceImpl) DeleteByPetId(_ context.Context, req *proto.DeleteByPetIdRequest) (res *proto.DeleteByPetIdResponse, err error) {
var images []*model.Image

err = s.repository.FindByPetId(req.PetId, &images)
if err != nil {
log.Error().Err(err).
Str("service", "image").
Str("module", "delete by pet id").
Str("pet id", req.PetId).
Msg("Error finding image from repo")
if err == gorm.ErrRecordNotFound {
return nil, status.Error(codes.NotFound, constant.ImageNotFoundErrorMessage)
}

return nil, status.Error(codes.Internal, constant.InternalServerErrorMessage)
}

imageObjectKeys := ExtractImageObjectKeys(images)
err = s.client.DeleteMany(imageObjectKeys)
if err != nil {
log.Error().Err(err).
Str("service", "image").
Str("module", "delete by pet id").
Interface("image object keys", imageObjectKeys).
Msg(constant.DeleteFromBucketErrorMessage)

return nil, status.Error(codes.Internal, constant.DeleteFromBucketErrorMessage)
}

imageIds := ExtractImageIds(images)
err = s.repository.DeleteMany(imageIds)
if err != nil {
log.Error().Err(err).
Str("service", "image").
Str("module", "delete by pet id").
Interface("image ids", imageIds).
Msg(constant.DeleteImageErrorMessage)

return nil, status.Error(codes.Internal, constant.DeleteImageErrorMessage)
}

return &proto.DeleteByPetIdResponse{Success: true}, nil
}

func DtoToRaw(in *proto.Image) (result *model.Image, err error) {
var id uuid.UUID
if in.Id != "" {
Expand Down Expand Up @@ -269,3 +313,21 @@ func RawToDto(in *model.Image) *proto.Image {
ObjectKey: in.ObjectKey,
}
}

func ExtractImageIds(in []*model.Image) []string {
var imageIds []string
for _, image := range in {
imageIds = append(imageIds, image.ID.String())
}

return imageIds
}

func ExtractImageObjectKeys(in []*model.Image) []string {
var imageObjectKeys []string
for _, image := range in {
imageObjectKeys = append(imageObjectKeys, image.ObjectKey)
}

return imageObjectKeys
}
97 changes: 97 additions & 0 deletions internal/service/image/image.service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type ImageServiceTest struct {
id uuid.UUID
petId uuid.UUID
objectKey string
objectKeys []string
imageUrl string
randomString string
objectKeyWithRandom string
Expand All @@ -36,6 +37,8 @@ type ImageServiceTest struct {
uploadReq *proto.UploadImageRequest
assignReq *proto.AssignPetRequest
deleteReq *proto.DeleteImageRequest
deleteByPetIdReq *proto.DeleteByPetIdRequest
imageIds []string
imageProto *proto.Image
image *model.Image
images []*model.Image
Expand Down Expand Up @@ -70,6 +73,9 @@ func (t *ImageServiceTest) SetupTest() {
t.deleteReq = &proto.DeleteImageRequest{
Id: t.id.String(),
}
t.deleteByPetIdReq = &proto.DeleteByPetIdRequest{
PetId: t.petId.String(),
}
t.imageProto = &proto.Image{
Id: t.id.String(),
PetId: t.petId.String(),
Expand Down Expand Up @@ -108,6 +114,8 @@ func (t *ImageServiceTest) SetupTest() {
ObjectKey: faker.Name(),
},
}
t.objectKeys = []string{t.images[0].ObjectKey, t.images[1].ObjectKey}
t.imageIds = []string{t.images[0].ID.String(), t.images[1].ID.String()}
}

func (t *ImageServiceTest) TestFindAllSuccess() {
Expand Down Expand Up @@ -649,3 +657,92 @@ func (t *ImageServiceTest) TestDeleteInternalErr() {
assert.Equal(t.T(), codes.Internal, status.Code())
assert.Equal(t.T(), expected.Error(), err.Error())
}

func (t *ImageServiceTest) TestDeleteByPetIdSuccess() {
expected := &proto.DeleteByPetIdResponse{
Success: true,
}
var images []*model.Image

controller := gomock.NewController(t.T())

imageRepo := &mock_image.ImageRepositoryMock{}
bucketClient := mock_bucket.NewMockClient(controller)
randomUtils := &mock_random.RandomUtilMock{}
imageRepo.On("FindByPetId", t.petId.String(), &images).Return(&t.images, nil)
imageRepo.On("DeleteMany", t.imageIds).Return(nil)
bucketClient.EXPECT().DeleteMany(t.objectKeys).Return(nil)

imageService := NewService(bucketClient, imageRepo, randomUtils)
actual, err := imageService.DeleteByPetId(context.Background(), t.deleteByPetIdReq)

assert.Nil(t.T(), err)
assert.Equal(t.T(), expected, actual)
}

func (t *ImageServiceTest) TestDeleteByPetIdBucketFailed() {
expected := status.Error(codes.Internal, constant.DeleteFromBucketErrorMessage)
var images []*model.Image

controller := gomock.NewController(t.T())

imageRepo := &mock_image.ImageRepositoryMock{}
bucketClient := mock_bucket.NewMockClient(controller)
randomUtils := &mock_random.RandomUtilMock{}
imageRepo.On("FindByPetId", t.petId.String(), &images).Return(&t.images, nil)
imageRepo.On("DeleteMany", t.imageIds).Return(nil)
bucketClient.EXPECT().DeleteMany(t.objectKeys).Return(errors.New("Error deleting from bucket client"))

imageService := NewService(bucketClient, imageRepo, randomUtils)
actual, err := imageService.DeleteByPetId(context.Background(), t.deleteByPetIdReq)

status, ok := status.FromError(err)
assert.True(t.T(), ok)
assert.Nil(t.T(), actual)
assert.Equal(t.T(), codes.Internal, status.Code())
assert.Equal(t.T(), expected.Error(), err.Error())
}

func (t *ImageServiceTest) TestDeleteByPetIdNotFound() {
expected := status.Error(codes.NotFound, constant.ImageNotFoundErrorMessage)
var images []*model.Image

controller := gomock.NewController(t.T())

imageRepo := &mock_image.ImageRepositoryMock{}
bucketClient := mock_bucket.NewMockClient(controller)
randomUtils := &mock_random.RandomUtilMock{}
imageRepo.On("FindByPetId", t.petId.String(), &images).Return(nil, gorm.ErrRecordNotFound)

imageService := NewService(bucketClient, imageRepo, randomUtils)
actual, err := imageService.DeleteByPetId(context.Background(), t.deleteByPetIdReq)

status, ok := status.FromError(err)
assert.True(t.T(), ok)
assert.Nil(t.T(), actual)
assert.Equal(t.T(), codes.NotFound, status.Code())
assert.Equal(t.T(), expected.Error(), err.Error())
}

func (t *ImageServiceTest) TestDeleteByPetIdInternalErr() {
expected := status.Error(codes.Internal, constant.DeleteImageErrorMessage)
var images []*model.Image

controller := gomock.NewController(t.T())

imageRepo := &mock_image.ImageRepositoryMock{}
bucketClient := mock_bucket.NewMockClient(controller)
randomUtils := &mock_random.RandomUtilMock{}
imageRepo.On("FindByPetId", t.petId.String(), &images).Return(&t.images, nil)
imageRepo.On("DeleteMany", t.imageIds).Return(errors.New(constant.DeleteImageErrorMessage))
bucketClient.EXPECT().DeleteMany(t.objectKeys).Return(nil)

imageService := NewService(bucketClient, imageRepo, randomUtils)
actual, err := imageService.DeleteByPetId(context.Background(), t.deleteByPetIdReq)

status, ok := status.FromError(err)
assert.True(t.T(), ok)
assert.Nil(t.T(), actual)
assert.Equal(t.T(), codes.Internal, status.Code())
assert.Equal(t.T(), expected.Error(), err.Error())
}
14 changes: 14 additions & 0 deletions mocks/client/bucket/bucket.mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pkg/client/bucket/bucket.client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import (
type Client interface {
Upload([]byte, string) (string, string, error)
Delete(string) error
DeleteMany([]string) error
}

// func NewClient(config cfgldr.Bucket, awsClient *s3.Client) Client {
func NewClient(config cfgldr.Bucket, minioClient *minio.Client) Client {
return bucket.NewClient(config, minioClient)
}

0 comments on commit 39627f7

Please sign in to comment.