diff --git a/docs/docs.go b/docs/docs.go index b97688b..b668308 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -106,9 +106,6 @@ const docTemplate = `{ } ], "description": "Обновить информацию про мерч по его uuid в json-е", - "consumes": [ - "application/json" - ], "tags": [ "Merch" ], @@ -334,9 +331,6 @@ const docTemplate = `{ } ], "description": "Создать новую метку для товара", - "consumes": [ - "application/json" - ], "tags": [ "Merch labels" ], @@ -379,9 +373,6 @@ const docTemplate = `{ } ], "description": "Прикрепить метку к товару", - "consumes": [ - "application/json" - ], "tags": [ "Merch labels" ], @@ -424,9 +415,6 @@ const docTemplate = `{ } ], "description": "Удалить привязку метки к товару", - "consumes": [ - "application/json" - ], "tags": [ "Merch labels" ], @@ -510,9 +498,6 @@ const docTemplate = `{ } ], "description": "Изменить метку", - "consumes": [ - "application/json" - ], "tags": [ "Merch labels" ], @@ -638,9 +623,6 @@ const docTemplate = `{ } ], "description": "Пометить нулевые цены как удаленные", - "consumes": [ - "application/json" - ], "tags": [ "Merch zero prices" ], @@ -1178,11 +1160,11 @@ const docTemplate = `{ "merch.DeleteZeroPrices": { "type": "object", "properties": { - "id": { - "type": "integer" - }, - "merch_uuid": { - "type": "string" + "merch_uuids": { + "type": "array", + "items": { + "type": "string" + } } } }, @@ -1360,9 +1342,6 @@ const docTemplate = `{ "created_at": { "type": "string" }, - "id": { - "type": "integer" - }, "merch_uuid": { "type": "string" }, diff --git a/docs/swagger.json b/docs/swagger.json index f746266..0df1704 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -98,9 +98,6 @@ } ], "description": "Обновить информацию про мерч по его uuid в json-е", - "consumes": [ - "application/json" - ], "tags": [ "Merch" ], @@ -326,9 +323,6 @@ } ], "description": "Создать новую метку для товара", - "consumes": [ - "application/json" - ], "tags": [ "Merch labels" ], @@ -371,9 +365,6 @@ } ], "description": "Прикрепить метку к товару", - "consumes": [ - "application/json" - ], "tags": [ "Merch labels" ], @@ -416,9 +407,6 @@ } ], "description": "Удалить привязку метки к товару", - "consumes": [ - "application/json" - ], "tags": [ "Merch labels" ], @@ -502,9 +490,6 @@ } ], "description": "Изменить метку", - "consumes": [ - "application/json" - ], "tags": [ "Merch labels" ], @@ -630,9 +615,6 @@ } ], "description": "Пометить нулевые цены как удаленные", - "consumes": [ - "application/json" - ], "tags": [ "Merch zero prices" ], @@ -1170,11 +1152,11 @@ "merch.DeleteZeroPrices": { "type": "object", "properties": { - "id": { - "type": "integer" - }, - "merch_uuid": { - "type": "string" + "merch_uuids": { + "type": "array", + "items": { + "type": "string" + } } } }, @@ -1352,9 +1334,6 @@ "created_at": { "type": "string" }, - "id": { - "type": "integer" - }, "merch_uuid": { "type": "string" }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 883b177..fd4e41b 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -9,10 +9,10 @@ definitions: type: object merch.DeleteZeroPrices: properties: - id: - type: integer - merch_uuid: - type: string + merch_uuids: + items: + type: string + type: array type: object merch.ImageLink: properties: @@ -126,8 +126,6 @@ definitions: properties: created_at: type: string - id: - type: integer merch_uuid: type: string name: @@ -256,8 +254,6 @@ paths: tags: - Merch put: - consumes: - - application/json description: Обновить информацию про мерч по его uuid в json-е parameters: - description: merch_uuid @@ -457,8 +453,6 @@ paths: tags: - Merch labels post: - consumes: - - application/json description: Создать новую метку для товара parameters: - description: payload @@ -535,8 +529,6 @@ paths: tags: - Merch labels put: - consumes: - - application/json description: Изменить метку parameters: - description: label uuid @@ -568,8 +560,6 @@ paths: - Merch labels /merch/labels/attach: post: - consumes: - - application/json description: Прикрепить метку к товару parameters: - description: payload @@ -596,8 +586,6 @@ paths: - Merch labels /merch/labels/detach: post: - consumes: - - application/json description: Удалить привязку метки к товару parameters: - description: payload @@ -624,8 +612,6 @@ paths: - Merch labels /merch/zeroprices: delete: - consumes: - - application/json description: Пометить нулевые цены как удаленные parameters: - description: payload diff --git a/internal/api/merch/controller.go b/internal/api/merch/controller.go index 7ea9636..63b28f2 100644 --- a/internal/api/merch/controller.go +++ b/internal/api/merch/controller.go @@ -95,7 +95,7 @@ func (co *controller) addMerch(c *gin.Context) { // @Description Получить всю информацию про мерч по его uuid // @Tags Merch // @Security BearerAuth -// @Produce json +// @Produce json // @Param uuid path string true "merch_uuid" // @Success 200 {object} MerchDTO // @Failure 400 {object} responses.ErrorResponse400 @@ -129,7 +129,7 @@ func (co *controller) getSingleMerch(c *gin.Context) { // @Description Получить все записи мерча // @Tags Merch // @Security BearerAuth -// @Produce json +// @Produce json // @Success 200 {array} ListResponse // @Failure 400 {object} responses.ErrorResponse400 // @Failure 500 {object} responses.ErrorResponse500 @@ -156,7 +156,7 @@ func (co *controller) getAllMerch(c *gin.Context) { // @Description Обновить информацию про мерч по его uuid в json-е // @Tags Merch // @Security BearerAuth -// @Accept json +// Accept json // @Param body body UpdateMerchDTO true "merch_uuid" // @Success 200 // @Failure 400 {object} responses.ErrorResponse400 @@ -182,7 +182,6 @@ func (co *controller) updateMerch(c *gin.Context) { log.WithError(err).Error("Merch | Failed to get single merch") return } - c.Status(http.StatusOK) } // @Summary Пометить мерч как удаленный @@ -193,8 +192,7 @@ func (co *controller) updateMerch(c *gin.Context) { // @Success 200 {object} MerchDTO // @Failure 400 {object} responses.ErrorResponse400 // @Failure 500 {object} responses.ErrorResponse500 -// -// @Router /merch/{uuid} [delete] +// @Router /merch/{uuid} [delete] func (co *controller) deleteMerch(c *gin.Context) { merchUuid := c.Param("uuid") if merchUuid == "" { @@ -222,16 +220,12 @@ func (co *controller) deleteMerch(c *gin.Context) { // @Description Получить цены мерча за период // @Tags Merch // @Security BearerAuth -// @Produce json +// @Produce json // @Param days query string false "period in days" // @Success 200 {array} PricesResponse // @Failure 400 {object} responses.ErrorResponse400 // @Failure 500 {object} responses.ErrorResponse500 // @Router /prices [get] -// -// @Failure 400 {object} responses.ErrorResponse400 -// @Failure 500 {object} responses.ErrorResponse500 -// @Router /prices [get] func (co *controller) getChartsPrices(c *gin.Context) { daysQuery := strings.ToLower(c.DefaultQuery("days", "")) @@ -256,7 +250,7 @@ func (co *controller) getChartsPrices(c *gin.Context) { // @Description Получить перепады цен мерча за период по его merch_uuid // @Tags Merch // @Security BearerAuth -// @Produce json +// @Produce json // @Param uuid path string true "merch_uuid" // @Param days query string false "period in days" // @Success 200 {object} PricesResponse @@ -344,6 +338,7 @@ func (co *controller) uploadMerchImage(c *gin.Context) { return } + //c.Status(http.StatusOK) c.JSON(http.StatusOK, response) } @@ -351,7 +346,7 @@ func (co *controller) uploadMerchImage(c *gin.Context) { // @Description Получить картинки по merch_uuid и query параметрам // @Tags Merch images // @Security BearerAuth -// @Produce json +// @Produce json // @Param uuid path string true "merch_uuid" // @Param type query string true "image type" // @Success 200 {object} ImageLink @@ -398,6 +393,7 @@ func (co *controller) getMerchImage(c *gin.Context) { //} // //c.JSON(http.StatusOK, link) + c.JSON(http.StatusNotImplemented, gin.H{"msg": "Method deprecated. Request images from image storage."}) } // @Summary Удалить (безвозвратно) картинки по merch_uuid @@ -442,7 +438,7 @@ func (co *controller) deleteMerchImage(c *gin.Context) { // @Description Создать новую метку для товара // @Tags Merch labels // @Security BearerAuth -// @Accept json +// Accept json // @Param payload body LabelDTO true "payload" // @Success 200 // @Failure 400 {object} responses.ErrorResponse400 @@ -478,7 +474,7 @@ func (co *controller) createLabel(c *gin.Context) { // @Description Получить все метки товаров // @Tags Merch labels // @Security BearerAuth -// @Produce json +// @Produce json // @Success 200 {array} LabelsList // @Failure 400 {object} responses.ErrorResponse400 // @Failure 500 {object} responses.ErrorResponse500 @@ -507,7 +503,7 @@ func (co *controller) getLabels(c *gin.Context) { // @Description Изменить метку // @Tags Merch labels // @Security BearerAuth -// @Accept json +// Accept json // @Param uuid path string true "label uuid" // @Param payload body LabelDTO true "payload" // @Success 200 @@ -580,16 +576,16 @@ func (co *controller) deleteLabel(c *gin.Context) { c.Status(http.StatusOK) } -// @Summary Прикрепить метку к товару -// @Description Прикрепить метку к товару -// @Tags Merch labels -// @Security BearerAuth -// @Accept json -// @Param payload body LabelLink true "payload" -// @Success 200 -// @Failure 400 {object} responses.ErrorResponse400 -// @Failure 500 {object} responses.ErrorResponse500 -// @Router /merch/labels/attach [post] +// @Summary Прикрепить метку к товару +// @Description Прикрепить метку к товару +// @Tags Merch labels +// @Security BearerAuth +// Accept json +// @Param payload body LabelLink true "payload" +// @Success 200 +// @Failure 400 {object} responses.ErrorResponse400 +// @Failure 500 {object} responses.ErrorResponse500 +// @Router /merch/labels/attach [post] func (co *controller) attachLabel(c *gin.Context) { const logMsg = "Merch | Attach label" @@ -615,16 +611,16 @@ func (co *controller) attachLabel(c *gin.Context) { c.Status(http.StatusOK) } -// @Summary Удалить привязку метки к товару -// @Description Удалить привязку метки к товару -// @Tags Merch labels -// @Security BearerAuth -// @Accept json -// @Param payload body LabelLink true "payload" -// @Success 200 -// @Failure 400 {object} responses.ErrorResponse400 -// @Failure 500 {object} responses.ErrorResponse500 -// @Router /merch/labels/detach [post] +// @Summary Удалить привязку метки к товару +// @Description Удалить привязку метки к товару +// @Tags Merch labels +// @Security BearerAuth +// Accept json +// @Param payload body LabelLink true "payload" +// @Success 200 +// @Failure 400 {object} responses.ErrorResponse400 +// @Failure 500 {object} responses.ErrorResponse500 +// @Router /merch/labels/detach [post] func (co *controller) detachLabel(c *gin.Context) { const logMsg = "Merch | Detach label" @@ -654,7 +650,7 @@ func (co *controller) detachLabel(c *gin.Context) { // @Description Получить метки товара по его uuid // @Tags Merch labels // @Security BearerAuth -// @Produce json +// @Produce json // @Param uuid path string true "label uuid" // @Success 200 // @Failure 400 {object} responses.ErrorResponse400 @@ -690,10 +686,10 @@ func (co *controller) getMerchLabels(c *gin.Context) { // @Description Получить нулевые цены // @Tags Merch zero prices // @Security BearerAuth -// @Produce json -// @Success 200 {array} ZeroPrice -// @Failure 400 {object} responses.ErrorResponse400 -// @Failure 500 {object} responses.ErrorResponse500 +// @Produce json +// @Success 200 {array} ZeroPrice +// @Failure 400 {object} responses.ErrorResponse400 +// @Failure 500 {object} responses.ErrorResponse500 // @Router /merch/zeroprices [get] func (co *controller) getZeroPrices(c *gin.Context) { const logMsg = "Merch | Get zero prices" @@ -719,11 +715,11 @@ func (co *controller) getZeroPrices(c *gin.Context) { // @Description Пометить нулевые цены как удаленные // @Tags Merch zero prices // @Security BearerAuth -// @Accept json +// Accept json // @Param payload body DeleteZeroPrices true "payload" // @Success 200 -// @Failure 400 {object} responses.ErrorResponse400 -// @Failure 500 {object} responses.ErrorResponse500 +// @Failure 400 {object} responses.ErrorResponse400 +// @Failure 500 {object} responses.ErrorResponse500 // @Router /merch/zeroprices [delete] func (co *controller) deleteZeroPrices(c *gin.Context) { const logMsg = "Merch | Delete zero prices" @@ -735,7 +731,7 @@ func (co *controller) deleteZeroPrices(c *gin.Context) { return } - var payload []DeleteZeroPrices + var payload DeleteZeroPrices if err = c.ShouldBindJSON(&payload); err != nil { c.JSON(http.StatusBadRequest, responses.ErrorResponse400{Error: err.Error()}) log.WithError(err).Error(logMsg) diff --git a/internal/api/merch/dto.go b/internal/api/merch/dto.go index 7ee7281..b10aa6b 100644 --- a/internal/api/merch/dto.go +++ b/internal/api/merch/dto.go @@ -82,7 +82,6 @@ type LabelLink struct { } type ZeroPrice struct { - Id int `json:"id"` CreatedAt time.Time `json:"created_at"` MerchUuid string `json:"merch_uuid"` Name string `json:"name"` @@ -90,6 +89,5 @@ type ZeroPrice struct { } type DeleteZeroPrices struct { - Id uint `json:"id"` - MerchUuid string `json:"merch_uuid"` + MerchUuids []string `json:"merch_uuids"` } diff --git a/internal/api/merch/repository.go b/internal/api/merch/repository.go index 711b731..1af8df0 100644 --- a/internal/api/merch/repository.go +++ b/internal/api/merch/repository.go @@ -3,7 +3,6 @@ package merch import ( "database/sql" "errors" - "fmt" "gorm.io/gorm" "gorm.io/gorm/clause" "time" @@ -23,7 +22,6 @@ type repository interface { addMerch(bundle merchBundle) error merchRecordExists(userUuid, merchUuid string) (bool, error) - userOwnsMerchUuids(userUuid string, merchUuids []string) (bool, error) getSingleMerch(userUuid, merchUuid string) (merchBundle, error) getAllMerch(userUuid string) ([]ListResponse, error) @@ -42,7 +40,7 @@ type prices interface { getDistinctPrices(userUuid, merchUuid string, period time.Time) (prices []Price, err error) getZeroPrices(userUuid string) ([]ZeroPrice, error) - deleteZeroPrices(list []DeleteZeroPrices) error + deleteZeroPrices(userUuid string, list []string) error } type labels interface { @@ -86,22 +84,6 @@ func (r *Repo) merchRecordExists(userUuid, merchUuid string) (bool, error) { return exists, err } -func (r *Repo) userOwnsMerchUuids(userUuid string, merchUuids []string) (bool, error) { - var count int64 - - err := r.db.Model(&Merch{}). - Where("user_uuid = ?", userUuid). - Where("merch_uuid IN ?", merchUuids). - Where("deleted_at IS NULL"). - Count(&count).Error - fmt.Println("!!!!!!", count) - if err != nil { - return false, err - } - fmt.Println("!!!!!!", len(merchUuids)) - return count == int64(len(merchUuids)), nil -} - func (r *Repo) getSingleMerch(userUuid, merchUuid string) (merchBundle, error) { var merch Merch if err := r.db. @@ -338,17 +320,16 @@ func (r *Repo) getZeroPrices(userUuid string) ([]ZeroPrice, error) { if err := r.db.Raw(` WITH price_with_neighbors AS ( SELECT - p.id, p.created_at, p.merch_uuid, p.price, p.origin, m.name, + p.created_at, p.merch_uuid, p.price, p.origin, m.name, LAG(price) OVER (PARTITION BY p.merch_uuid ORDER BY p.created_at, p.id) AS prev_price, LEAD(price) OVER (PARTITION BY p.merch_uuid ORDER BY p.created_at, p.id) AS next_price FROM prices AS p JOIN merch as m ON m.merch_uuid = p.merch_uuid WHERE p.deleted_at IS NULL - AND m.deleted_at IS NULL AND m.user_uuid = ?) SELECT - id, created_at, merch_uuid, origin, name + created_at, merch_uuid, origin, name FROM price_with_neighbors WHERE price = 0 @@ -362,13 +343,14 @@ func (r *Repo) getZeroPrices(userUuid string) ([]ZeroPrice, error) { return priceList, nil } -func (r *Repo) deleteZeroPrices(list []DeleteZeroPrices) error { - for _, item := range list { - if err := r.db.Model(&Price{}). - Where("id = ? AND merch_uuid = ?", item.Id, item.MerchUuid). - Update("deleted_at", time.Now().UTC()).Error; err != nil { - return err - } - } - return nil +func (r *Repo) deleteZeroPrices(userUuid string, list []string) error { + subQuery := r.db.Table("merch"). + Select("merch_uuid"). + Where("user_uuid = ?", userUuid) + + return r.db.Model(&Price{}). + Where("merch_uuid IN ?", list). + Where("merch_uuid IN (?)", subQuery). + Update("deleted_at", time.Now().UTC()). + Error } diff --git a/internal/api/merch/service.go b/internal/api/merch/service.go index 4d06a37..259563d 100644 --- a/internal/api/merch/service.go +++ b/internal/api/merch/service.go @@ -16,7 +16,6 @@ import ( is "merch-parser-api/proto/imageStorage" "mime/multipart" "path/filepath" - "slices" "strings" "time" ) @@ -618,26 +617,6 @@ func (s *service) getZeroPrices(userUuid string) ([]ZeroPrice, error) { return s.repo.getZeroPrices(userUuid) } -func (s *service) deleteZeroPrices(userUuid string, list []DeleteZeroPrices) error { - if len(list) == 0 { - return nil - } - - ids := make([]string, 0, len(list)) - for _, item := range list { - ids = append(ids, item.MerchUuid) - fmt.Println(item.MerchUuid, ids) - } - slices.Compact(ids) - - owns, err := s.repo.userOwnsMerchUuids(userUuid, ids) - if err != nil { - return err - } - - if !owns { - return errors.New("wrong ids") - } - - return s.repo.deleteZeroPrices(list) +func (s *service) deleteZeroPrices(userUuid string, list DeleteZeroPrices) error { + return s.repo.deleteZeroPrices(userUuid, list.MerchUuids) }