Skip to content

Commit

Permalink
Merge pull request #197 from JokerTrickster/feat/196/image_upload_che…
Browse files Browse the repository at this point in the history
…ck_api

{feat} - 음식 이미지 업로드 체크 api 구현 \n #196
  • Loading branch information
JokerTrickster authored Oct 25, 2024
2 parents 66c6817 + 981f9e8 commit 6f52d63
Show file tree
Hide file tree
Showing 15 changed files with 396 additions and 6 deletions.
56 changes: 56 additions & 0 deletions src/docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,45 @@ const docTemplate = `{
}
}
},
"/v0.1/foods/images/upload-check": {
"post": {
"description": "■ errCode with 400\nPARAM_BAD : 파라미터 오류\nUSER_NOT_FOUND : 유저가 존재하지 않음\n■ errCode with 401\nINVALID_AUTH_CODE : 인증 코드 검증 실패\nTOKEN_BAD : 잘못된 토큰\nINVALID_ACCESS_TOKEN : 잘못된 액세스 토큰\n\n■ errCode with 500\nINTERNAL_SERVER : 내부 로직 처리 실패\nINTERNAL_DB : DB 처리 실패\nGEMINI_INTERNAL_SERVER : Gemini 서버 내부 오류",
"produces": [
"application/json"
],
"tags": [
"food"
],
"summary": "음식 이미지 업로드 체크하기",
"parameters": [
{
"description": "type",
"name": "type",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.ReqCheckImageUploadFood"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "boolean"
}
},
"400": {
"description": "Bad Request",
"schema": {}
},
"500": {
"description": "Internal Server Error",
"schema": {}
}
}
}
},
"/v0.1/foods/meta": {
"get": {
"description": "■ errCode with 400\nPARAM_BAD : 파라미터 오류\nUSER_NOT_FOUND : 유저가 존재하지 않음\n■ errCode with 401\nINVALID_AUTH_CODE : 인증 코드 검증 실패\nTOKEN_BAD : 잘못된 토큰\nINVALID_ACCESS_TOKEN : 잘못된 액세스 토큰\n\n■ errCode with 500\nINTERNAL_SERVER : 내부 로직 처리 실패\nINTERNAL_DB : DB 처리 실패\nGEMINI_INTERNAL_SERVER : Gemini 서버 내부 오류",
Expand Down Expand Up @@ -1052,6 +1091,23 @@ const docTemplate = `{
}
},
"definitions": {
"request.ReqCheckImageUploadFood": {
"type": "object",
"properties": {
"failedFoodList": {
"type": "array",
"items": {
"type": "string"
}
},
"successFoodList": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"request.ReqKakaoOauth": {
"type": "object",
"properties": {
Expand Down
56 changes: 56 additions & 0 deletions src/docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,45 @@
}
}
},
"/v0.1/foods/images/upload-check": {
"post": {
"description": "■ errCode with 400\nPARAM_BAD : 파라미터 오류\nUSER_NOT_FOUND : 유저가 존재하지 않음\n■ errCode with 401\nINVALID_AUTH_CODE : 인증 코드 검증 실패\nTOKEN_BAD : 잘못된 토큰\nINVALID_ACCESS_TOKEN : 잘못된 액세스 토큰\n\n■ errCode with 500\nINTERNAL_SERVER : 내부 로직 처리 실패\nINTERNAL_DB : DB 처리 실패\nGEMINI_INTERNAL_SERVER : Gemini 서버 내부 오류",
"produces": [
"application/json"
],
"tags": [
"food"
],
"summary": "음식 이미지 업로드 체크하기",
"parameters": [
{
"description": "type",
"name": "type",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.ReqCheckImageUploadFood"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "boolean"
}
},
"400": {
"description": "Bad Request",
"schema": {}
},
"500": {
"description": "Internal Server Error",
"schema": {}
}
}
}
},
"/v0.1/foods/meta": {
"get": {
"description": "■ errCode with 400\nPARAM_BAD : 파라미터 오류\nUSER_NOT_FOUND : 유저가 존재하지 않음\n■ errCode with 401\nINVALID_AUTH_CODE : 인증 코드 검증 실패\nTOKEN_BAD : 잘못된 토큰\nINVALID_ACCESS_TOKEN : 잘못된 액세스 토큰\n\n■ errCode with 500\nINTERNAL_SERVER : 내부 로직 처리 실패\nINTERNAL_DB : DB 처리 실패\nGEMINI_INTERNAL_SERVER : Gemini 서버 내부 오류",
Expand Down Expand Up @@ -1041,6 +1080,23 @@
}
},
"definitions": {
"request.ReqCheckImageUploadFood": {
"type": "object",
"properties": {
"failedFoodList": {
"type": "array",
"items": {
"type": "string"
}
},
"successFoodList": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"request.ReqKakaoOauth": {
"type": "object",
"properties": {
Expand Down
49 changes: 49 additions & 0 deletions src/docs/swagger.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
definitions:
request.ReqCheckImageUploadFood:
properties:
failedFoodList:
items:
type: string
type: array
successFoodList:
items:
type: string
type: array
type: object
request.ReqKakaoOauth:
properties:
token:
Expand Down Expand Up @@ -1045,6 +1056,44 @@ paths:
summary: 음식 이미지 업로드하기
tags:
- food
/v0.1/foods/images/upload-check:
post:
description: |-
■ errCode with 400
PARAM_BAD : 파라미터 오류
USER_NOT_FOUND : 유저가 존재하지 않음
■ errCode with 401
INVALID_AUTH_CODE : 인증 코드 검증 실패
TOKEN_BAD : 잘못된 토큰
INVALID_ACCESS_TOKEN : 잘못된 액세스 토큰
■ errCode with 500
INTERNAL_SERVER : 내부 로직 처리 실패
INTERNAL_DB : DB 처리 실패
GEMINI_INTERNAL_SERVER : Gemini 서버 내부 오류
parameters:
- description: type
in: body
name: type
required: true
schema:
$ref: '#/definitions/request.ReqCheckImageUploadFood'
produces:
- application/json
responses:
"200":
description: OK
schema:
type: boolean
"400":
description: Bad Request
schema: {}
"500":
description: Internal Server Error
schema: {}
summary: 음식 이미지 업로드 체크하기
tags:
- food
/v0.1/foods/meta:
get:
description: |-
Expand Down
62 changes: 62 additions & 0 deletions src/features/food/handler/checkImageUploadFoodHandler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package handler

import (
"context"
_interface "main/features/food/model/interface"
"main/features/food/model/request"
"main/utils"

"net/http"

"github.com/labstack/echo/v4"
)

type CheckImageUploadFoodHandler struct {
UseCase _interface.ICheckImageUploadFoodUseCase
}

func NewCheckImageUploadFoodHandler(c *echo.Echo, useCase _interface.ICheckImageUploadFoodUseCase) _interface.ICheckImageUploadFoodHandler {
handler := &CheckImageUploadFoodHandler{
UseCase: useCase,
}
c.POST("/v0.1/foods/images/upload-check", handler.CheckImageUpload)
return handler
}

// 음식 이미지 업로드 체크하기
// @Router /v0.1/foods/images/upload-check [post]
// @Summary 음식 이미지 업로드 체크하기
// @Description
// @Description ■ errCode with 400
// @Description PARAM_BAD : 파라미터 오류
// @Description USER_NOT_FOUND : 유저가 존재하지 않음
// @Description ■ errCode with 401
// @Description INVALID_AUTH_CODE : 인증 코드 검증 실패
// @Description TOKEN_BAD : 잘못된 토큰
// @Description INVALID_ACCESS_TOKEN : 잘못된 액세스 토큰
// @Description
// @Description ■ errCode with 500
// @Description INTERNAL_SERVER : 내부 로직 처리 실패
// @Description INTERNAL_DB : DB 처리 실패
// @Description GEMINI_INTERNAL_SERVER : Gemini 서버 내부 오류
// @Param type body request.ReqCheckImageUploadFood true "type"
// @Produce json
// @Success 200 {object} bool
// @Failure 400 {object} error
// @Failure 500 {object} error
// @Tags food
func (d *CheckImageUploadFoodHandler) CheckImageUpload(c echo.Context) error {
ctx := context.Background()
req := &request.ReqCheckImageUploadFood{}
if err := utils.ValidateReq(c, req); err != nil {
return err
}

//business logic
err := d.UseCase.CheckImageUpload(ctx, req)
if err != nil {
return err
}

return c.JSON(http.StatusOK, true)
}
1 change: 1 addition & 0 deletions src/features/food/handler/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ func NewFoodHandler(c *echo.Echo) {
NewEmptyImageFoodHandler(c, usecase.NewEmptyImageFoodUseCase(repository.NewEmptyImageFoodRepository(mysql.GormMysqlDB), mysql.DBTimeOut))
NewDailyRecommendFoodHandler(c, usecase.NewDailyRecommendFoodUseCase(repository.NewDailyRecommendFoodRepository(mysql.GormMysqlDB), mysql.DBTimeOut))
NewSaveFoodHandler(c, usecase.NewSaveFoodUseCase(repository.NewSaveFoodRepository(mysql.GormMysqlDB), mysql.DBTimeOut))
NewCheckImageUploadFoodHandler(c, usecase.NewCheckImageUploadFoodUseCase(repository.NewCheckImageUploadFoodRepository(mysql.GormMysqlDB), mysql.DBTimeOut))
}
3 changes: 3 additions & 0 deletions src/features/food/model/interface/IFoodHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,6 @@ type IDailyRecommendFoodHandler interface {
type ISaveFoodHandler interface {
Save(c echo.Context) error
}
type ICheckImageUploadFoodHandler interface {
CheckImageUpload(c echo.Context) error
}
5 changes: 4 additions & 1 deletion src/features/food/model/interface/IFoodRepository.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type IRankingFoodRepository interface {
}

type IImageUploadFoodRepository interface {
FindOneAndUpdateFoodImages(ctx context.Context,foodName, fileName string) error
FindOneAndUpdateFoodImages(ctx context.Context, foodName, fileName string) error
}

type IEmptyImageFoodRepository interface {
Expand All @@ -52,3 +52,6 @@ type ISaveFoodRepository interface {
SaveFood(ctx context.Context, foodDTO *mysql.Foods) error
FindOneOrCreateFoodImage(ctx context.Context, foodImageDTO *mysql.FoodImages) (*mysql.FoodImages, error)
}

type ICheckImageUploadFoodRepository interface {
}
4 changes: 4 additions & 0 deletions src/features/food/model/interface/IFoodUseCase.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,7 @@ type IDailyRecommendFoodUseCase interface {
type ISaveFoodUseCase interface {
Save(c context.Context, req *request.ReqSaveFood) error
}

type ICheckImageUploadFoodUseCase interface {
CheckImageUpload(c context.Context, req *request.ReqCheckImageUploadFood) error
}
6 changes: 6 additions & 0 deletions src/features/food/model/request/checkImageUploadFood.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package request

type ReqCheckImageUploadFood struct {
FailedFoodList []string `json:"failedFoodList"`
SuccessFoodList []string `json:"successFoodList"`
}
11 changes: 11 additions & 0 deletions src/features/food/repository/checkImageUploadFoodRepository.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package repository

import (
_interface "main/features/food/model/interface"

"gorm.io/gorm"
)

func NewCheckImageUploadFoodRepository(gormDB *gorm.DB) _interface.ICheckImageUploadFoodRepository {
return &CheckImageUploadFoodRepository{GormDB: gormDB}
}
4 changes: 4 additions & 0 deletions src/features/food/repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,7 @@ type DailyRecommendFoodRepository struct {
type SaveFoodRepository struct {
GormDB *gorm.DB
}

type CheckImageUploadFoodRepository struct {
GormDB *gorm.DB
}
29 changes: 29 additions & 0 deletions src/features/food/usecase/checkImageUploadFoodUseCase.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package usecase

import (
"context"

_interface "main/features/food/model/interface"
"main/features/food/model/request"
"main/utils/aws"

"time"
)

type CheckImageUploadFoodUseCase struct {
Repository _interface.ICheckImageUploadFoodRepository
ContextTimeout time.Duration
}

func NewCheckImageUploadFoodUseCase(repo _interface.ICheckImageUploadFoodRepository, timeout time.Duration) _interface.ICheckImageUploadFoodUseCase {
return &CheckImageUploadFoodUseCase{Repository: repo, ContextTimeout: timeout}
}

func (d *CheckImageUploadFoodUseCase) CheckImageUpload(c context.Context, req *request.ReqCheckImageUploadFood) error {
_, cancel := context.WithTimeout(c, d.ContextTimeout)
defer cancel()

aws.EmailSendFoodUploadReport(req.SuccessFoodList, req.FailedFoodList)

return nil
}
24 changes: 19 additions & 5 deletions src/utils/aws/ses.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ import (
type emailType string

const (
emailTypePassword = emailType("password")
emailTypeAuth = emailType("authCode")
emailTypeReport = emailType("report")
emailTypeSignup = emailType("signup")
emailTypeFoodNameReport = emailType("foodNameReport")
emailTypePassword = emailType("password")
emailTypeAuth = emailType("authCode")
emailTypeReport = emailType("report")
emailTypeSignup = emailType("signup")
emailTypeFoodNameReport = emailType("foodNameReport")
emailTypeFoodUploadReport = emailType("foodUploadReport")
)

type sesMailData struct {
Expand All @@ -35,6 +36,19 @@ type ReqReportSES struct {
Reason string
}

func EmailSendFoodUploadReport(successFoodList, failedFoodList []string) {
templateDataMap := map[string]string{
"successFoodList": strings.Join(successFoodList, ", "),
"failedFoodList": strings.Join(failedFoodList, ", "),
}
templateDataJson, err := json.Marshal(templateDataMap)
if err != nil {
fmt.Println("Error marshaling template data:", err)
return
}
//"[email protected]"
emailSend([]string{"[email protected]"}, emailTypeFoodNameReport, string(templateDataJson), "foodUploadReport")
}
func EmailSendFoodNameReport(foodNames []string) {
currentDate := time.Now().Format("01-02")
templateDataMap := map[string]string{
Expand Down
Loading

0 comments on commit 6f52d63

Please sign in to comment.