diff --git a/src/docs/docs.go b/src/docs/docs.go index 2349a98..7a6f31e 100644 --- a/src/docs/docs.go +++ b/src/docs/docs.go @@ -886,6 +886,34 @@ const docTemplate = `{ } } }, + "/v0.1/system/foods/report": { + "post": { + "description": "■ errCode with 400\nPARAM_BAD : 파라미터 오류\nUSER_NOT_EXIST : 유저가 존재하지 않음\nUSER_ALREADY_EXISTED : 유저가 이미 존재\n\n■ errCode with 500\nINTERNAL_SERVER : 내부 로직 처리 실패\nINTERNAL_DB : DB 처리 실패\nPLAYER_STATE_CHANGE_FAILED : 플레이어 상태 변경 실패", + "produces": [ + "application/json" + ], + "tags": [ + "system" + ], + "summary": "음식 이미지, 영양 성분 없는 음식 리포트", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "boolean" + } + }, + "400": { + "description": "Bad Request", + "schema": {} + }, + "500": { + "description": "Internal Server Error", + "schema": {} + } + } + } + }, "/v0.1/system/report": { "post": { "description": "■ errCode with 400\nPARAM_BAD : 파라미터 오류\nUSER_NOT_EXIST : 유저가 존재하지 않음\nUSER_ALREADY_EXISTED : 유저가 이미 존재\n\n■ errCode with 500\nINTERNAL_SERVER : 내부 로직 처리 실패\nINTERNAL_DB : DB 처리 실패\nPLAYER_STATE_CHANGE_FAILED : 플레이어 상태 변경 실패", diff --git a/src/docs/swagger.json b/src/docs/swagger.json index e1bd3f9..b137a9e 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -875,6 +875,34 @@ } } }, + "/v0.1/system/foods/report": { + "post": { + "description": "■ errCode with 400\nPARAM_BAD : 파라미터 오류\nUSER_NOT_EXIST : 유저가 존재하지 않음\nUSER_ALREADY_EXISTED : 유저가 이미 존재\n\n■ errCode with 500\nINTERNAL_SERVER : 내부 로직 처리 실패\nINTERNAL_DB : DB 처리 실패\nPLAYER_STATE_CHANGE_FAILED : 플레이어 상태 변경 실패", + "produces": [ + "application/json" + ], + "tags": [ + "system" + ], + "summary": "음식 이미지, 영양 성분 없는 음식 리포트", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "boolean" + } + }, + "400": { + "description": "Bad Request", + "schema": {} + }, + "500": { + "description": "Internal Server Error", + "schema": {} + } + } + } + }, "/v0.1/system/report": { "post": { "description": "■ errCode with 400\nPARAM_BAD : 파라미터 오류\nUSER_NOT_EXIST : 유저가 존재하지 않음\nUSER_ALREADY_EXISTED : 유저가 이미 존재\n\n■ errCode with 500\nINTERNAL_SERVER : 내부 로직 처리 실패\nINTERNAL_DB : DB 처리 실패\nPLAYER_STATE_CHANGE_FAILED : 플레이어 상태 변경 실패", diff --git a/src/docs/swagger.yaml b/src/docs/swagger.yaml index 5a129b7..ca21be9 100644 --- a/src/docs/swagger.yaml +++ b/src/docs/swagger.yaml @@ -1378,6 +1378,34 @@ paths: summary: 음식 선택하기 tags: - food + /v0.1/system/foods/report: + post: + description: |- + ■ errCode with 400 + PARAM_BAD : 파라미터 오류 + USER_NOT_EXIST : 유저가 존재하지 않음 + USER_ALREADY_EXISTED : 유저가 이미 존재 + + ■ errCode with 500 + INTERNAL_SERVER : 내부 로직 처리 실패 + INTERNAL_DB : DB 처리 실패 + PLAYER_STATE_CHANGE_FAILED : 플레이어 상태 변경 실패 + produces: + - application/json + responses: + "200": + description: OK + schema: + type: boolean + "400": + description: Bad Request + schema: {} + "500": + description: Internal Server Error + schema: {} + summary: 음식 이미지, 영양 성분 없는 음식 리포트 + tags: + - system /v0.1/system/report: post: description: |- diff --git a/src/features/system/handler/foodReportSystemHandler.go b/src/features/system/handler/foodReportSystemHandler.go new file mode 100644 index 0000000..918ecac --- /dev/null +++ b/src/features/system/handler/foodReportSystemHandler.go @@ -0,0 +1,49 @@ +package handler + +import ( + "context" + _interface "main/features/system/model/interface" + "net/http" + + "github.com/labstack/echo/v4" +) + +type FoodReportSystemHandler struct { + UseCase _interface.IFoodReportSystemUseCase +} + +func NewFoodReportSystemHandler(c *echo.Echo, useCase _interface.IFoodReportSystemUseCase) _interface.IFoodReportSystemHandler { + handler := &FoodReportSystemHandler{ + UseCase: useCase, + } + c.POST("/v0.1/system/foods/report", handler.FoodReport) + return handler +} + +// 음식 이미지, 영양 성분 없는 음식 리포트 +// @Router /v0.1/system/foods/report [post] +// @Summary 음식 이미지, 영양 성분 없는 음식 리포트 +// @Description +// @Description ■ errCode with 400 +// @Description PARAM_BAD : 파라미터 오류 +// @Description USER_NOT_EXIST : 유저가 존재하지 않음 +// @Description USER_ALREADY_EXISTED : 유저가 이미 존재 +// @Description +// @Description ■ errCode with 500 +// @Description INTERNAL_SERVER : 내부 로직 처리 실패 +// @Description INTERNAL_DB : DB 처리 실패 +// @Description PLAYER_STATE_CHANGE_FAILED : 플레이어 상태 변경 실패 +// @Produce json +// @Success 200 {object} bool +// @Failure 400 {object} error +// @Failure 500 {object} error +// @Tags system +func (d *FoodReportSystemHandler) FoodReport(c echo.Context) error { + ctx := context.Background() + err := d.UseCase.FoodReport(ctx) + if err != nil { + return err + } + + return c.JSON(http.StatusOK, true) +} diff --git a/src/features/system/handler/index.go b/src/features/system/handler/index.go index a1d880e..8675ebe 100644 --- a/src/features/system/handler/index.go +++ b/src/features/system/handler/index.go @@ -10,4 +10,5 @@ import ( func NewSystemHandler(c *echo.Echo) { NewReportSystemHandler(c, usecase.NewReportSystemUseCase(repository.NewReportSystemRepository(mysql.GormMysqlDB), mysql.DBTimeOut)) + NewFoodReportSystemHandler(c, usecase.NewFoodReportSystemUseCase(repository.NewFoodReportSystemRepository(mysql.GormMysqlDB), mysql.DBTimeOut)) } diff --git a/src/features/system/model/interface/ISystemHandler.go b/src/features/system/model/interface/ISystemHandler.go index 054128b..9235217 100644 --- a/src/features/system/model/interface/ISystemHandler.go +++ b/src/features/system/model/interface/ISystemHandler.go @@ -5,3 +5,7 @@ import "github.com/labstack/echo/v4" type IReportSystemHandler interface { Report(c echo.Context) error } + +type IFoodReportSystemHandler interface { + FoodReport(c echo.Context) error +} \ No newline at end of file diff --git a/src/features/system/model/interface/ISystemRepository.go b/src/features/system/model/interface/ISystemRepository.go index d561c48..15254bf 100644 --- a/src/features/system/model/interface/ISystemRepository.go +++ b/src/features/system/model/interface/ISystemRepository.go @@ -8,3 +8,8 @@ import ( type IReportSystemRepository interface { SaveReport(ctx context.Context, reportDTO *mysql.Reports) error } + +type IFoodReportSystemRepository interface { + FindFoodWithoutImage(ctx context.Context) ([]*mysql.FoodImages, error) + FindFoodWithoutNutrient(ctx context.Context) ([]*mysql.Foods, error) +} diff --git a/src/features/system/model/interface/ISystemUseCase.go b/src/features/system/model/interface/ISystemUseCase.go index 5550aec..a08f5e3 100644 --- a/src/features/system/model/interface/ISystemUseCase.go +++ b/src/features/system/model/interface/ISystemUseCase.go @@ -8,3 +8,7 @@ import ( type IReportSystemUseCase interface { Report(c context.Context, uID uint, req *request.ReqReport) error } + +type IFoodReportSystemUseCase interface { + FoodReport(c context.Context) error +} diff --git a/src/features/system/repository/foodReportSystemRepository.go b/src/features/system/repository/foodReportSystemRepository.go new file mode 100644 index 0000000..fb2686d --- /dev/null +++ b/src/features/system/repository/foodReportSystemRepository.go @@ -0,0 +1,42 @@ +package repository + +import ( + "context" + _interface "main/features/system/model/interface" + "main/utils" + "main/utils/db/mysql" + + "gorm.io/gorm" +) + +func NewFoodReportSystemRepository(gormDB *gorm.DB) _interface.IFoodReportSystemRepository { + return &FoodReportSystemRepository{GormDB: gormDB} +} + +func (d *FoodReportSystemRepository) FindFoodWithoutImage(ctx context.Context) ([]*mysql.FoodImages, error) { + var foodImages []*mysql.FoodImages + result := d.GormDB.Where("image = ?", "food_default.png").Find(&foodImages) + if result.Error != nil { + return nil, utils.ErrorMsg(ctx, utils.ErrInternalDB, utils.Trace(), utils.HandleError(result.Error.Error(), foodImages), utils.ErrFromMysqlDB) + } + return foodImages, nil +} + +func (d *FoodReportSystemRepository) FindFoodWithoutNutrient(ctx context.Context) ([]*mysql.Foods, error) { + + var foodsWithoutNutrients []*mysql.Foods + + query := ` + SELECT f.* + FROM foods f + LEFT JOIN nutrients n ON f.name = n.food_name + WHERE n.food_name IS NULL AND f.deleted_at IS NULL + ` + + if err := d.GormDB.WithContext(ctx).Raw(query).Scan(&foodsWithoutNutrients).Error; err != nil { + return nil, utils.ErrorMsg(ctx, utils.ErrInternalDB, utils.Trace(), utils.HandleError(err.Error(), foodsWithoutNutrients), utils.ErrFromMysqlDB) + } + + return foodsWithoutNutrients, nil + +} diff --git a/src/features/system/repository/repository.go b/src/features/system/repository/repository.go index 965a962..faf2b68 100644 --- a/src/features/system/repository/repository.go +++ b/src/features/system/repository/repository.go @@ -5,3 +5,7 @@ import "gorm.io/gorm" type ReportSystemRepository struct { GormDB *gorm.DB } + +type FoodReportSystemRepository struct { + GormDB *gorm.DB +} \ No newline at end of file diff --git a/src/features/system/usecase/foodReportSystemUseCase.go b/src/features/system/usecase/foodReportSystemUseCase.go new file mode 100644 index 0000000..7baf4b9 --- /dev/null +++ b/src/features/system/usecase/foodReportSystemUseCase.go @@ -0,0 +1,46 @@ +package usecase + +import ( + "context" + _interface "main/features/system/model/interface" + "main/utils/aws" + "time" +) + +type FoodReportSystemUseCase struct { + Repository _interface.IFoodReportSystemRepository + ContextTimeout time.Duration +} + +func NewFoodReportSystemUseCase(repo _interface.IFoodReportSystemRepository, timeout time.Duration) _interface.IFoodReportSystemUseCase { + return &FoodReportSystemUseCase{Repository: repo, ContextTimeout: timeout} +} + +func (d *FoodReportSystemUseCase) FoodReport(c context.Context) error { + ctx, cancel := context.WithTimeout(c, d.ContextTimeout) + defer cancel() + + //음식 이미지가 없는 음식 리스트 조회 + images, err := d.Repository.FindFoodWithoutImage(ctx) + if err != nil { + return err + } + + //음식 영양성분이 없는 음식 리스트 조회 + nutrients, err := d.Repository.FindFoodWithoutNutrient(ctx) + if err != nil { + return err + } + imageList := make([]string, 0) + nutrientList := make([]string, 0) + for _, image := range images { + imageList = append(imageList, image.Name) + } + for _, nutrient := range nutrients { + nutrientList = append(nutrientList, nutrient.Name) + } + + go aws.EmailSendFoodInfoEmptyReport(imageList, nutrientList) + + return nil +} diff --git a/src/features/system/usecase/reportSystemUseCase.go b/src/features/system/usecase/reportSystemUseCase.go index 7c65941..53cc19d 100644 --- a/src/features/system/usecase/reportSystemUseCase.go +++ b/src/features/system/usecase/reportSystemUseCase.go @@ -33,7 +33,7 @@ func (d *ReportSystemUseCase) Report(c context.Context, uID uint, req *request.R UserID: strconv.Itoa(int(uID)), Reason: string(req.Reason), } - go aws.EmailSendReport([]string{"pkjhj485@gmail.com", "dtw7225@naver.com"}, reqReport) + go aws.EmailSendReport([]string{"pkjhj485@gmail.com", "dtw7225@naver.com", "ohhyejin1213@naver.com"}, reqReport) return nil } diff --git a/src/utils/aws/ses.go b/src/utils/aws/ses.go index ee996ef..ac5c718 100644 --- a/src/utils/aws/ses.go +++ b/src/utils/aws/ses.go @@ -36,6 +36,20 @@ type ReqReportSES struct { Reason string } + +func EmailSendFoodInfoEmptyReport(imageEmpty, nutrientEmpty []string) { + templateDataMap := map[string][]string{ + "imageMissingFoods": imageEmpty, + "nutrientMissingFoods": nutrientEmpty, + } + templateDataJson, err := json.Marshal(templateDataMap) + if err != nil { + fmt.Println("Error marshaling template data:", err) + return + } + + emailSend([]string{"pkjhj485@gmail.com", "dtw7225@naver.com", "ohhyejin1213@naver.com"}, emailTypeFoodNameReport, string(templateDataJson), "foodInfoEmptyReport") +} func EmailSendFoodUploadReport(successFoodList, failedFoodList []string) { templateDataMap := map[string]string{ "successFoodList": strings.Join(successFoodList, ", "), diff --git a/src/utils/aws/template/foodEmptyReport.html b/src/utils/aws/template/foodEmptyReport.html new file mode 100644 index 0000000..162bc34 --- /dev/null +++ b/src/utils/aws/template/foodEmptyReport.html @@ -0,0 +1,134 @@ + + + + + + + Food Information Update + + + + +
+
+ 음식 정보 업데이트 요청 +
+
+

안녕하세요,

+

현재 아래 음식 리스트들의 이미지와 영양 성분 정보가 비어 있습니다. 정보를 업데이트해 주세요.

+
+

음식 이미지가 없는 리스트

+
    + {{#each imageMissingFoods}} +
  • {{this}}
  • + {{/each}} +
+
+
+

음식 영양성분이 없는 리스트

+
    + {{#each nutrientMissingFoods}} +
  • {{this}}
  • + {{/each}} +
+
+

감사합니다.

+
+ +
+ + + \ No newline at end of file diff --git a/src/utils/aws/template/foodEmptyReport.json b/src/utils/aws/template/foodEmptyReport.json new file mode 100644 index 0000000..3e562e4 --- /dev/null +++ b/src/utils/aws/template/foodEmptyReport.json @@ -0,0 +1,8 @@ +{ + "Template": { + "TemplateName": "foodInfoEmptyReport", + "SubjectPart": "음식 정보 없는 리포트", + "TextPart": "안녕하세요,\n\n현재 아래 음식 리스트들의 이미지와 영양 성분 정보가 비어 있습니다. 정보를 업데이트해 주세요.\n\n음식 이미지가 없는 리스트:\n{{#each imageMissingFoods}}\n- {{this}}\n{{/each}}\n\n음식 영양성분이 없는 리스트:\n{{#each nutrientMissingFoods}}\n- {{this}}\n{{/each}}\n\n감사합니다.\n\n-- YourCompany", + "HtmlPart": "\n\n\n \n \n Food Information Update\n \n\n\n
\n
\n 음식 정보 업데이트 요청\n
\n
\n

안녕하세요,

\n

현재 아래 음식 리스트들의 이미지와 영양 성분 정보가 비어 있습니다. 정보를 업데이트해 주세요.

\n
\n

음식 이미지가 없는 리스트

\n
    \n {{#each imageMissingFoods}}\n
  • {{this}}
  • \n {{/each}}\n
\n
\n
\n

음식 영양성분이 없는 리스트

\n
    \n {{#each nutrientMissingFoods}}\n
  • {{this}}
  • \n {{/each}}\n
\n
\n

감사합니다.

\n
\n
\n © 2024 YourCompany. All rights reserved.\n
\n
\n\n" + } +} \ No newline at end of file