package merch import ( "errors" "github.com/gin-gonic/gin" "github.com/google/uuid" log "github.com/sirupsen/logrus" "merch-api/pkg/responses" "merch-api/pkg/router" "merch-api/pkg/utils" "net/http" ) const controllerLogHeader string = "[Controller]" type controller struct { service *service utils utils.Utils } func newController(s *service, u utils.Utils) *controller { return &controller{ service: s, utils: u, } } func (h *Handler) RegisterRoutes(r *gin.RouterGroup, mw *router.Middlewares) { merchGroup := r.Group("/merch") merchGroup.Use(mw.AuthMW) merchGroup.POST("/create", h.controller.create) merchGroup.GET("/:uuid", h.controller.getOne) merchGroup.GET("/list", h.controller.getMany) merchGroup.PUT("/:uuid", h.controller.updateMerch) merchGroup.PUT("/extra/:uuid", h.controller.updateExtraData) merchGroup.DELETE("/:uuid", h.controller.deleteMerch) originsGroup := merchGroup.Group("/origins") originsGroup.Use(mw.AuthMW) originsGroup.POST("", h.controller.createOrigin) originsGroup.GET("", h.controller.getOrigins) originsGroup.DELETE("", h.controller.deleteOrigin) chartsGroup := r.Group("/prices") chartsGroup.Use(mw.AuthMW) chartsGroup.GET("", h.controller.getChartsPrices) chartsGroup.GET("/:uuid", h.controller.getDistinctPrices) zeroPricesGroup := merchGroup.Group("/zeroprices") zeroPricesGroup.Use(mw.AuthMW) zeroPricesGroup.GET("", h.controller.getZeroPrices) zeroPricesGroup.DELETE("", h.controller.deleteZeroPrices) zeroPricesGroup.DELETE("/period", h.controller.deleteZeroPricesPeriod) labelsGroup := merchGroup.Group("/labels") labelsGroup.Use(mw.AuthMW) labelsGroup.POST("", h.controller.createLabel) labelsGroup.GET("", h.controller.getLabels) labelsGroup.PUT("/:uuid", h.controller.updateLabel) labelsGroup.DELETE("/:uuid", h.controller.deleteLabel) labelsGroup.POST("/attach", h.controller.attachLabel) labelsGroup.POST("/detach", h.controller.detachLabel) labelsGroup.GET("/:uuid", h.controller.getMerchLabels) } // create godoc // // @Summary Create new merch // @Description Create new merch // @Tags Merch // @Accept json // @Param merch body newMerchDTO true "merch body" // @Success 201 // @Failure 400 {object} responses.BadRequest // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // @Router /merch/create [POST] func (co *controller) create(c *gin.Context) { var newMerch newMerchDTO if err := c.ShouldBindJSON(&newMerch); err != nil { c.JSON(http.StatusBadRequest, responses.BadRequest{Error: err.Error()}) logErr(controllerLogHeader, err) return } if err := co.service.createMerch(c, getUserId(c), &newMerch); err != nil { c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) logErr(controllerLogHeader, err) return } c.Status(http.StatusCreated) } // getOne godoc // // @Summary Получить всю информацию про мерч // @Description Получить всю информацию про мерч по его uuid // @Tags Merch // @Security BearerAuth // @Produce json // @Param uuid path string true "merch_uuid" // @Success 200 {object} singleMerchResponse // // @Failure 400 {object} responses.BadRequest // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // // @Router /merch/{uuid} [get] func (co *controller) getOne(c *gin.Context) { merchUuid := c.Param("uuid") if merchUuid == "" { c.JSON(http.StatusBadRequest, responses.BadRequest{Error: "MerchUuid is empty"}) return } response, err := co.service.getSingleMerch(c, getUserId(c), merchUuid) if err != nil { c.JSON(http.StatusBadRequest, responses.InternalServerError{Error: err.Error()}) log.WithError(err).Error("Merch | Failed to get single merch") return } c.JSON(http.StatusOK, response) } // getMany godoc // // @Summary Get all merch // @Description Get all merch without origins // @Tags Merch // @Produce json // @Success 200 {array} listResponse // @Success 204 // @Failure 400 {object} responses.BadRequest // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // @Router /merch/list [GET] func (co *controller) getMany(c *gin.Context) { response, err := co.service.getMany(c, getUserId(c)) if err != nil { c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) logErr(controllerLogHeader, err) return } if len(response) == 0 { c.Status(http.StatusNoContent) return } c.JSON(http.StatusOK, response) } // updateMerch godoc // // @Summary Update merch // @Description Update merch general info (except extra data) // @Tags Merch // @Accept json // @Param uuid path string true "merch uuid" // @Param payload body updateMerchDTO true "payload" // @Produce json // @Success 200 {object} merchDTO // @Failure 400 {object} responses.BadRequest // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // @Router /merch/{uuid} [PUT] func (co *controller) updateMerch(c *gin.Context) { merchUuid := c.Param("uuid") if err := uuid.Validate(merchUuid); err != nil { c.JSON(http.StatusBadRequest, responses.BadRequest{Error: err.Error()}) logErr(controllerLogHeader, err) return } var payload updateMerchDTO if err := c.ShouldBindJSON(&payload); err != nil { c.JSON(http.StatusBadRequest, responses.BadRequest{Error: err.Error()}) logErr(controllerLogHeader, err) return } if merchUuid != payload.MerchUuid { c.JSON(http.StatusBadRequest, responses.BadRequest{Error: "MerchUuid does not match"}) logErr(controllerLogHeader, errors.New("MerchUuid does not match")) return } response, err := co.service.updateMerch(c, getUserId(c), &payload) if err != nil { c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) logErr(controllerLogHeader, err) return } c.JSON(http.StatusOK, response) } // updateMerch godoc // // @Summary Update merch extra data // @Description Update ONLY merch extra data // @Tags Merch // @Accept json // @Param uuid path string true "merch uuid" // @Param payload body extraDataDTO true "payload" // @Produce json // @Success 200 {object} extraDataDTO // @Failure 400 {object} responses.BadRequest // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // @Router /merch/extra/{uuid} [PUT] func (co *controller) updateExtraData(c *gin.Context) { merchUuid := c.Param("uuid") if err := uuid.Validate(merchUuid); err != nil { c.JSON(http.StatusBadRequest, responses.BadRequest{Error: err.Error()}) logErr(controllerLogHeader, err) return } var payload extraDataDTO if err := c.ShouldBindJSON(&payload); err != nil { c.JSON(http.StatusBadRequest, responses.BadRequest{Error: err.Error()}) logErr(controllerLogHeader, err) return } if merchUuid != payload.MerchUuid { c.JSON(http.StatusBadRequest, responses.BadRequest{Error: "MerchUuid does not match"}) logErr(controllerLogHeader, errors.New("MerchUuid does not match")) return } response, err := co.service.updateExtraData(c, getUserId(c), &payload) if err != nil { c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) logErr(controllerLogHeader, err) return } c.JSON(http.StatusOK, response) } // deleteMerch godoc // // @Summary Delete merch // @Description Marks merch and all its extra data as deleted by uuid. // @Tags Merch // @Param uuid path string true "merch uuid" // @Success 204 // @Failure 400 {object} responses.BadRequest // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // @Router /merch/{uuid} [DELETE] func (co *controller) deleteMerch(c *gin.Context) { merchUuid := c.Param("uuid") if err := uuid.Validate(merchUuid); err != nil { c.JSON(http.StatusBadRequest, responses.BadRequest{Error: err.Error()}) logErr(controllerLogHeader, err) return } if err := co.service.deleteOneMerchRecord(c, getUserId(c), merchUuid); err != nil { c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) logErr(controllerLogHeader, err) return } c.Status(http.StatusNoContent) } // createOrigin godoc // // @Summary Create new origin // @Description Create new origin with name // @Tags Origins // @Accept json // @Param origin body newOriginDTO true "origin body" // @Success 201 // @Failure 400 {object} responses.BadRequest // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // @Router /merch/origins [POST] func (co *controller) createOrigin(c *gin.Context) { var origin *newOriginDTO if err := c.ShouldBindJSON(&origin); err != nil { c.JSON(http.StatusBadRequest, responses.BadRequest{Error: err.Error()}) logErr(controllerLogHeader, err) return } if err := co.service.createOrigin(c, origin); err != nil { c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) logErr(controllerLogHeader, err) return } logDebug(controllerLogHeader, "create origin success") c.Status(http.StatusCreated) } // getOrigins godoc // // @Summary Get all origins // @Description Get all origins // @Tags Origins // @Produce json // @Success 200 {object} originsDTO // @Success 204 // @Failure 400 {object} responses.BadRequest // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // @Router /merch/origins [GET] func (co *controller) getOrigins(c *gin.Context) { response, err := co.service.getOrigins(c) if err != nil { c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) logErr(controllerLogHeader, err) return } logDebug(controllerLogHeader, "get origins success") c.JSON(http.StatusOK, response) } // deleteOrigin godoc // // @Summary Delete origin // @Description Marks origin as deleted by name. // @Tags Origins // @Accept json // @Param origin body deleteOriginDTO true "origin body" // @Success 204 // @Failure 400 {object} responses.BadRequest // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // @Router /merch/origins [DELETE] func (co *controller) deleteOrigin(c *gin.Context) { var origin *deleteOriginDTO if err := c.ShouldBindJSON(&origin); err != nil { c.JSON(http.StatusBadRequest, responses.BadRequest{Error: err.Error()}) logErr(controllerLogHeader, err) return } if err := co.service.deleteOrigin(c, origin); err != nil { c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) logErr(controllerLogHeader, err) return } logDebug(controllerLogHeader, "delete origin success") c.Status(http.StatusNoContent) } // getChartsPrices godoc // // @Summary Получить цены мерча за период // @Description Получить цены мерча за период // @Tags Merch // @Produce json // @Param days query string false "period in days" // @Success 200 {array} PricesResponse // @Failure 400 {object} responses.BadRequest // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // @Router /prices [get] func (co *controller) getChartsPrices(c *gin.Context) { response, err := co.service.getPrices(c, getUserId(c), getDays(c)) if err != nil { c.JSON(http.StatusBadRequest, responses.InternalServerError{Error: err.Error()}) logErr(controllerLogHeader, err) return } log.WithField("response", response).Debugf("%v %v get chart prices success", pkgLogHeader, controllerLogHeader) c.JSON(http.StatusOK, response) } // getDistinctPrices godoc // // @Summary Получить перепады цен мерча за период по его merch_uuid // @Description Получить перепады цен мерча за период по его merch_uuid // @Tags Merch // @Produce json // @Param uuid path string true "merch_uuid" // @Param days query string false "period in days" // @Success 200 {object} PricesResponse // @Success 204 // @Failure 400 {object} responses.BadRequest // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // @Router /prices/{uuid} [get] func (co *controller) getDistinctPrices(c *gin.Context) { merchUuid := c.Param("uuid") if merchUuid == "" { err := errors.New("MerchUuid is empty") c.JSON(http.StatusBadRequest, responses.BadRequest{Error: err.Error()}) logErr(controllerLogHeader, err) return } response, err := co.service.getDistinctPrices(c, getUserId(c), merchUuid, getDays(c)) if err != nil { c.JSON(http.StatusBadRequest, responses.InternalServerError{Error: err.Error()}) logErr(controllerLogHeader, err) return } if response == nil { c.Status(http.StatusNoContent) return } log.WithField("response", response).Debugf("%v %v get distinct prices success", pkgLogHeader, controllerLogHeader) c.JSON(http.StatusOK, response) } // getZeroPrices godoc // // @Summary Получить нулевые цены // @Description Получить нулевые цены // @Tags Merch zero prices // @Produce json // @Success 200 {array} ZeroPrice // @Success 204 // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // @Router /merch/zeroprices [get] func (co *controller) getZeroPrices(c *gin.Context) { response, err := co.service.getZeroPrices(c, getUserId(c)) if err != nil { c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) logErr(controllerLogHeader, err) return } if response == nil { c.Status(http.StatusNoContent) } c.JSON(http.StatusOK, response) } // deleteZeroPrices godoc // // @Summary Пометить нулевые цены как удаленные // @Description Пометить нулевые цены как удаленные // @Tags Merch zero prices // @Security BearerAuth // @Accept json // @Param payload body DeleteZeroPrices true "payload" // @Success 204 // @Failure 400 {object} responses.BadRequest // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // @Router /merch/zeroprices [delete] func (co *controller) deleteZeroPrices(c *gin.Context) { var payload []DeleteZeroPrices if err := c.ShouldBindJSON(&payload); err != nil { c.JSON(http.StatusBadRequest, responses.BadRequest{Error: err.Error()}) logErr(controllerLogHeader, err) return } if len(payload) < 1 || payload == nil { c.Status(http.StatusNoContent) return } if err := co.service.deleteZeroPrices(c, getUserId(c), payload); err != nil { c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) logErr(controllerLogHeader, err) return } c.Status(http.StatusNoContent) } // deleteZeroPricesPeriod godoc // // @Summary Пометить нулевые цены как удаленные за указанный период // @Description Пометить нулевые цены как удаленные за указанный период // @Tags Merch zero prices // @Security BearerAuth // @Param start query string true "start" // @Param end query string true "end" // @Success 204 // @Failure 400 {object} responses.BadRequest // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // @Router /merch/zeroprices/period [delete] func (co *controller) deleteZeroPricesPeriod(c *gin.Context) { start, err := co.utils.ParseTime(c.Query("start")) if err != nil { c.JSON(http.StatusBadRequest, responses.BadRequest{Error: err.Error()}) logErr(controllerLogHeader, err) return } end, err := co.utils.ParseTime(c.Query("end")) if err != nil { c.JSON(http.StatusBadRequest, responses.BadRequest{Error: err.Error()}) logErr(controllerLogHeader, err) return } if err = co.service.deleteZeroPricesPeriod(c, getUserId(c), start, end); err != nil { c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) logErr(controllerLogHeader, err) return } c.Status(http.StatusOK) } // createLabel godoc // // @Summary Создать новую метку для товара // @Description Создать новую метку для товара // @Tags Merch labels // @Security BearerAuth // @Accept json // @Param payload body LabelDTO true "payload" // @Success 200 // @Failure 400 {object} responses.BadRequest // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // @Router /merch/labels [post] func (co *controller) createLabel(c *gin.Context) { var payload LabelDTO if err := c.ShouldBindJSON(&payload); err != nil { c.JSON(http.StatusBadRequest, responses.BadRequest{Error: err.Error()}) logErr(controllerLogHeader, err) return } if err := co.service.createLabel(c, getUserId(c), &payload); err != nil { c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) logErr(controllerLogHeader, err) return } c.Status(http.StatusOK) } // getLabels godoc // // @Summary Получить все метки товаров // @Description Получить все метки товаров // @Tags Merch labels // @Security BearerAuth // @Produce json // @Success 200 {array} LabelsList // @Failure 400 {object} responses.BadRequest // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // @Router /merch/labels [get] func (co *controller) getLabels(c *gin.Context) { response, err := co.service.getLabels(c, getUserId(c)) if err != nil { c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) logErr(controllerLogHeader, err) return } c.JSON(http.StatusOK, response) } // updateLabel godoc // // @Summary Изменить метку // @Description Изменить метку // @Tags Merch labels // @Security BearerAuth // @Accept json // @Param uuid path string true "label uuid" // @Param payload body LabelDTO true "payload" // @Success 200 // @Failure 400 {object} responses.BadRequest // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // @Router /merch/labels/{uuid} [put] func (co *controller) updateLabel(c *gin.Context) { labelUuid := c.Param("uuid") if labelUuid == "" { e := errors.New("LabelUuid is empty") c.JSON(http.StatusBadRequest, responses.BadRequest{Error: e.Error()}) logErr(controllerLogHeader, e) return } var payload LabelDTO if err := c.ShouldBindJSON(&payload); err != nil { c.JSON(http.StatusBadRequest, responses.BadRequest{Error: err.Error()}) logErr(controllerLogHeader, err) return } if err := co.service.updateLabel(c, getUserId(c), labelUuid, &payload); err != nil { c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) logErr(controllerLogHeader, err) return } c.Status(http.StatusOK) } // deleteLabel godoc // // @Summary Пометить метку как удаленную // @Description Пометить метку как удаленную // @Tags Merch labels // @Security BearerAuth // @Param uuid path string true "label uuid" // @Success 200 // @Failure 400 {object} responses.BadRequest // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // @Router /merch/labels/{uuid} [delete] func (co *controller) deleteLabel(c *gin.Context) { labelUuid := c.Param("uuid") if labelUuid == "" { e := errors.New("LabelUuid is empty") c.JSON(http.StatusBadRequest, responses.BadRequest{Error: e.Error()}) logErr(controllerLogHeader, e) return } if err := co.service.deleteLabel(c, getUserId(c), labelUuid); err != nil { c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) logErr(controllerLogHeader, err) return } c.Status(http.StatusOK) } // attachLabel godoc // // @Summary Прикрепить метку к товару // @Description Прикрепить метку к товару // @Tags Merch labels // @Security BearerAuth // @Accept json // @Param payload body LabelLink true "payload" // @Success 200 // @Failure 400 {object} responses.BadRequest // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // @Router /merch/labels/attach [post] func (co *controller) attachLabel(c *gin.Context) { var payload LabelLink if err := c.ShouldBindJSON(&payload); err != nil { c.JSON(http.StatusBadRequest, responses.BadRequest{Error: err.Error()}) logErr(controllerLogHeader, err) return } if err := co.service.attachLabel(c, getUserId(c), &payload); err != nil { c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) logErr(controllerLogHeader, err) return } c.Status(http.StatusOK) } // detachLabel godoc // // @Summary Удалить привязку метки к товару // @Description Удалить привязку метки к товару // @Tags Merch labels // @Security BearerAuth // @Accept json // @Param payload body LabelLink true "payload" // @Success 200 // @Failure 400 {object} responses.BadRequest // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // @Router /merch/labels/detach [post] func (co *controller) detachLabel(c *gin.Context) { var payload LabelLink if err := c.ShouldBindJSON(&payload); err != nil { c.JSON(http.StatusBadRequest, responses.BadRequest{Error: err.Error()}) logErr(controllerLogHeader, err) return } if err := co.service.detachLabel(c, getUserId(c), &payload); err != nil { c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) logErr(controllerLogHeader, err) return } c.Status(http.StatusOK) } // getMerchLabels godoc // // @Summary Получить метки товара по его uuid // @Description Получить метки товара по его uuid // @Tags Merch labels // @Security BearerAuth // @Produce json // @Param uuid path string true "label uuid" // @Success 200 // @Failure 400 {object} responses.BadRequest // @Failure 401 {object} responses.Unauthorized // @Failure 500 {object} responses.InternalServerError // @Router /merch/labels/{uuid} [get] func (co *controller) getMerchLabels(c *gin.Context) { merchUuid := c.Param("uuid") if merchUuid == "" { e := errors.New("MerchUuid is empty") c.JSON(http.StatusBadRequest, responses.BadRequest{Error: e.Error()}) logErr(controllerLogHeader, e) return } response, err := co.service.getMerchLabels(c, getUserId(c), merchUuid) if err != nil { c.JSON(http.StatusInternalServerError, responses.InternalServerError{Error: err.Error()}) logErr(controllerLogHeader, err) return } c.JSON(http.StatusOK, response) }