From b6ed899b894d447514312edf0d33c38debcc54d5 Mon Sep 17 00:00:00 2001 From: javadifa Date: Tue, 23 Jul 2024 22:51:02 +0330 Subject: [PATCH] feat(kindboxreq): added edit kindboxreq by benefactor --- .../benefactor/kind_box_req/route.go | 1 + .../benefactor/kind_box_req/update.go | 53 +++++++++ docs/docs.go | 103 +++++++++++++++++ docs/swagger.json | 103 +++++++++++++++++ docs/swagger.yaml | 67 +++++++++++ param/benefactor/kind_box_req/update.go | 21 +++- repository/mysql/db.go | 108 ++++++++++-------- service/benefactor/kind_box_req/service.go | 1 + service/benefactor/kind_box_req/update.go | 31 +++++ validator/benefactor/kind_box_req/update.go | 39 ++++--- .../benefactor/kind_box_req/validator.go | 46 ++++++++ 11 files changed, 504 insertions(+), 69 deletions(-) create mode 100644 delivery/http_server/benefactor/kind_box_req/update.go create mode 100644 service/benefactor/kind_box_req/update.go diff --git a/delivery/http_server/benefactor/kind_box_req/route.go b/delivery/http_server/benefactor/kind_box_req/route.go index b7b93fb..b821d37 100644 --- a/delivery/http_server/benefactor/kind_box_req/route.go +++ b/delivery/http_server/benefactor/kind_box_req/route.go @@ -18,4 +18,5 @@ func (h Handler) SetRoutes(e *echo.Echo) { r.GET("/:id", h.Get) r.DELETE("/:id", h.Delete) r.GET("/", h.GetAll) + r.PUT("/:id", h.Update) } diff --git a/delivery/http_server/benefactor/kind_box_req/update.go b/delivery/http_server/benefactor/kind_box_req/update.go new file mode 100644 index 0000000..65cec5f --- /dev/null +++ b/delivery/http_server/benefactor/kind_box_req/update.go @@ -0,0 +1,53 @@ +package benefactorkindboxreqhandler + +import ( + param "git.gocasts.ir/ebhomengo/niki/param/benefactor/kind_box_req" + httpmsg "git.gocasts.ir/ebhomengo/niki/pkg/http_msg" + "git.gocasts.ir/ebhomengo/niki/pkg/claim" + "github.com/labstack/echo/v4" + "net/http" +) + +// Update godoc +// @Summary Update kind box request by benefactor +// @Tags KindBoxReq +// @Accept json +// @Produce json +// @Param id path int true "KindBoxReq ID" +// @Param Request body param.KindBoxReqUpdateRequest true "Update KindBoxReq Request Body" +// @Success 204 +// @Failure 400 {string} "Bad Request" +// @Failure 401 {string} "invalid or expired jwt" +// @Failure 403 {string} "user not allowed" +// @Failure 422 {object} httpmsg.ErrorResponse +// @Failure 500 {string} "something went wrong" +// @Security AuthBearerBenefactor +// @Router /benefactor/kindboxreqs/{id} [put] +func (h Handler) Update(c echo.Context) error { + + var req param.KindBoxReqUpdateRequest + if bErr := c.Bind(&req); bErr != nil { + return echo.NewHTTPError(http.StatusBadRequest) + } + + claims := claim.GetClaimsFromEchoContext(c) + req.BenefactorID = claims.UserID + + if fieldErrors, err := h.benefactorKindBoxReqVld.ValidateUpdateRequest(req); err != nil { + msg, code := httpmsg.Error(err) + + return c.JSON(code, echo.Map{ + "message": msg, + "errors": fieldErrors, + }) + } + + sErr := h.benefactorKindBoxReqSvc.Update(c.Request().Context(), req) + if sErr != nil { + msg, code := httpmsg.Error(sErr) + + return echo.NewHTTPError(code, msg) + } + + return c.JSON(http.StatusNoContent, nil) +} diff --git a/docs/docs.go b/docs/docs.go index 8d91496..ee63407 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -2195,6 +2195,76 @@ const docTemplate = `{ } } }, + "put": { + "security": [ + { + "AuthBearerBenefactor": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "KindBoxReq" + ], + "summary": "Update kind box request by benefactor", + "parameters": [ + { + "type": "integer", + "description": "KindBoxReq ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Update KindBoxReq Request Body", + "name": "Request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/benefactorkindboxreqparam.KindBoxReqUpdateRequest" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "string" + } + }, + "401": { + "description": "invalid or expired jwt", + "schema": { + "type": "string" + } + }, + "403": { + "description": "user not allowed", + "schema": { + "type": "string" + } + }, + "422": { + "description": "Unprocessable Entity", + "schema": { + "$ref": "#/definitions/httpmsg.ErrorResponse" + } + }, + "500": { + "description": "something went wrong", + "schema": { + "type": "string" + } + } + } + }, "delete": { "security": [ { @@ -3297,6 +3367,39 @@ const docTemplate = `{ } } }, + "benefactorkindboxreqparam.KindBoxReqUpdateRequest": { + "type": "object", + "properties": { + "count_requested": { + "type": "integer", + "example": 5 + }, + "deliver_address_id": { + "type": "integer", + "example": 1 + }, + "deliver_refer_date": { + "type": "string", + "example": "2025-01-02T15:04:05Z" + }, + "deliver_refer_time_id": { + "type": "integer", + "example": 1 + }, + "description": { + "type": "string", + "example": "description" + }, + "kind_box_type": { + "allOf": [ + { + "$ref": "#/definitions/entity.KindBoxType" + } + ], + "example": 2 + } + } + }, "entity.Address": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 3ae5d09..b3ac5b0 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -2184,6 +2184,76 @@ } } }, + "put": { + "security": [ + { + "AuthBearerBenefactor": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "KindBoxReq" + ], + "summary": "Update kind box request by benefactor", + "parameters": [ + { + "type": "integer", + "description": "KindBoxReq ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Update KindBoxReq Request Body", + "name": "Request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/benefactorkindboxreqparam.KindBoxReqUpdateRequest" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "string" + } + }, + "401": { + "description": "invalid or expired jwt", + "schema": { + "type": "string" + } + }, + "403": { + "description": "user not allowed", + "schema": { + "type": "string" + } + }, + "422": { + "description": "Unprocessable Entity", + "schema": { + "$ref": "#/definitions/httpmsg.ErrorResponse" + } + }, + "500": { + "description": "something went wrong", + "schema": { + "type": "string" + } + } + } + }, "delete": { "security": [ { @@ -3286,6 +3356,39 @@ } } }, + "benefactorkindboxreqparam.KindBoxReqUpdateRequest": { + "type": "object", + "properties": { + "count_requested": { + "type": "integer", + "example": 5 + }, + "deliver_address_id": { + "type": "integer", + "example": 1 + }, + "deliver_refer_date": { + "type": "string", + "example": "2025-01-02T15:04:05Z" + }, + "deliver_refer_time_id": { + "type": "integer", + "example": 1 + }, + "description": { + "type": "string", + "example": "description" + }, + "kind_box_type": { + "allOf": [ + { + "$ref": "#/definitions/entity.KindBoxType" + } + ], + "example": 2 + } + } + }, "entity.Address": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index dd5c482..37a4e32 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -643,6 +643,28 @@ definitions: kind_box_req: $ref: '#/definitions/entity.KindBoxReq' type: object + benefactorkindboxreqparam.KindBoxReqUpdateRequest: + properties: + count_requested: + example: 5 + type: integer + deliver_address_id: + example: 1 + type: integer + deliver_refer_date: + example: "2025-01-02T15:04:05Z" + type: string + deliver_refer_time_id: + example: 1 + type: integer + description: + example: description + type: string + kind_box_type: + allOf: + - $ref: '#/definitions/entity.KindBoxType' + example: 2 + type: object entity.Address: properties: address: @@ -2323,6 +2345,51 @@ paths: summary: Get a kind box request for a benefactor tags: - KindBoxReq + put: + consumes: + - application/json + parameters: + - description: KindBoxReq ID + in: path + name: id + required: true + type: integer + - description: Update KindBoxReq Request Body + in: body + name: Request + required: true + schema: + $ref: '#/definitions/benefactorkindboxreqparam.KindBoxReqUpdateRequest' + produces: + - application/json + responses: + "204": + description: No Content + "400": + description: Bad Request + schema: + type: string + "401": + description: invalid or expired jwt + schema: + type: string + "403": + description: user not allowed + schema: + type: string + "422": + description: Unprocessable Entity + schema: + $ref: '#/definitions/httpmsg.ErrorResponse' + "500": + description: something went wrong + schema: + type: string + security: + - AuthBearerBenefactor: [] + summary: Update kind box request by benefactor + tags: + - KindBoxReq /benefactor/login-register: post: consumes: diff --git a/param/benefactor/kind_box_req/update.go b/param/benefactor/kind_box_req/update.go index 3f46c7f..33a6d89 100644 --- a/param/benefactor/kind_box_req/update.go +++ b/param/benefactor/kind_box_req/update.go @@ -1,14 +1,23 @@ package benefactorkindboxreqparam -import entity "git.gocasts.ir/ebhomengo/niki/entity" +import ( + "time" + + "git.gocasts.ir/ebhomengo/niki/entity" +) type KindBoxReqUpdateRequest struct { - BenefactorID uint - KindBoxReqID uint - KindBoxType entity.KindBoxType - CountRequested uint + KindBoxReqID uint `json:"-" param:"id" example:"1"` + BenefactorID uint `json:"-" example: "1"` + KindBoxType entity.KindBoxType `json:"kind_box_type" example:"2"` + CountRequested uint `json:"count_requested" example:"5"` + Description string `json:"description" example:"description"` + DeliverReferTimeID uint `json:"deliver_refer_time_id" example:"1"` + DeliverReferDate time.Time `json:"deliver_refer_date" example:"2025-01-02T15:04:05Z"` + DeliverAddressID uint `json:"deliver_address_id" example:"1"` } + type KindBoxReqUpdateResponse struct { - KindBoxReq entity.KindBoxReq + } diff --git a/repository/mysql/db.go b/repository/mysql/db.go index af326f1..20d6cfc 100644 --- a/repository/mysql/db.go +++ b/repository/mysql/db.go @@ -1,81 +1,89 @@ package mysql import ( - "database/sql" - "fmt" - querier "git.gocasts.ir/ebhomengo/niki/pkg/query_transaction/sql" - "sync" - "time" + "database/sql" + "fmt" + querier "git.gocasts.ir/ebhomengo/niki/pkg/query_transaction/sql" + "sync" + "time" ) type Config struct { - Username string `koanf:"username"` - Password string `koanf:"password"` - Port int `koanf:"port"` - Host string `koanf:"host"` - DBName string `koanf:"db_name"` + Username string `koanf:"username"` + Password string `koanf:"password"` + Port int `koanf:"port"` + Host string `koanf:"host"` + DBName string `koanf:"db_name"` } type DB struct { - config Config - db *querier.SqlDB - mu sync.Mutex - statements map[string]*sql.Stmt + config Config + db *querier.SqlDB + mu sync.Mutex + statements map[string]*sql.Stmt } func (db *DB) Conn() *querier.SqlDB { - return db.db + return db.db } -// TODO: this temperary to ignore linter error (magic number). +// TODO: this temporary to ignore linter error (magic number). const ( - dbMaxConnLifetime = time.Minute * 3 - dbMaxOpenConns = 10 - dbMaxIdleConns = 10 + dbMaxConnLifetime = time.Minute * 3 + dbMaxOpenConns = 10 + dbMaxIdleConns = 10 ) func New(config Config) *DB { - // parseTime=true changes the output type of DATE and DATETIME values to time.Time - // instead of []byte / string - // The date or datetime like 0000-00-00 00:00:00 is converted into zero value of time.Time - db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@(%s:%d)/%s?parseTime=true", - config.Username, config.Password, config.Host, config.Port, config.DBName)) - if err != nil { - panic(fmt.Errorf("can't open mysql db: %w", err)) - } + // parseTime=true changes the output type of DATE and DATETIME values to time.Time + // instead of []byte / string + // The date or datetime like 0000-00-00 00:00:00 is converted into zero value of time.Time + db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@(%s:%d)/%s?parseTime=true", + config.Username, config.Password, config.Host, config.Port, config.DBName)) + if err != nil { + panic(fmt.Errorf("can't open mysql db: %w", err)) + } - // See "Important settings" section. - db.SetConnMaxLifetime(dbMaxConnLifetime) - db.SetMaxOpenConns(dbMaxOpenConns) - db.SetMaxIdleConns(dbMaxIdleConns) + // See "Important settings" section. + db.SetConnMaxLifetime(dbMaxConnLifetime) + db.SetMaxOpenConns(dbMaxOpenConns) + db.SetMaxIdleConns(dbMaxIdleConns) - return &DB{config: config, db: &querier.SqlDB{db}} + return &DB{ + config: config, + db: &querier.SqlDB{DB: db}, + statements: make(map[string]*sql.Stmt), + } } func (p *DB) PrepareStatement(key string, query string) (*sql.Stmt, error) { - p.mu.Lock() - defer p.mu.Unlock() + p.mu.Lock() + defer p.mu.Unlock() - if stmt, ok := p.statements[key]; ok { - return stmt, nil - } + if stmt, ok := p.statements[key]; ok { + return stmt, nil + } - stmt, err := p.db.Prepare(query) - if err != nil { - return nil, err - } - p.statements[key] = stmt + stmt, err := p.db.Prepare(query) + if err != nil { + return nil, err + } + p.statements[key] = stmt - return stmt, nil + return stmt, nil } func (p *DB) CloseStatements() error { - for _, stmt := range p.statements { - err := stmt.Close() - if err != nil { - return err - } - } + p.mu.Lock() + defer p.mu.Unlock() - return nil + for _, stmt := range p.statements { + err := stmt.Close() + if err != nil { + return err + } + } + + p.statements = make(map[string]*sql.Stmt) + return nil } diff --git a/service/benefactor/kind_box_req/service.go b/service/benefactor/kind_box_req/service.go index a7a3fdc..548d850 100644 --- a/service/benefactor/kind_box_req/service.go +++ b/service/benefactor/kind_box_req/service.go @@ -12,6 +12,7 @@ type Repository interface { GetKindBoxReqByID(ctx context.Context, kindBoxReqID uint) (entity.KindBoxReq, error) DeleteKindBoxReqByID(ctx context.Context, kindBoxReqID uint) error GetAllKindBoxReq(ctx context.Context, filter params.FilterRequest, pagination params.PaginationRequest, sort params.SortRequest) ([]entity.KindBoxReq, uint, error) + UpdateKindBoxReq(ctx context.Context, kindBoxReq entity.KindBoxReq) error } type Service struct { diff --git a/service/benefactor/kind_box_req/update.go b/service/benefactor/kind_box_req/update.go new file mode 100644 index 0000000..104001a --- /dev/null +++ b/service/benefactor/kind_box_req/update.go @@ -0,0 +1,31 @@ +package benefactorkindboxreqservice + +import ( + "context" + + param "git.gocasts.ir/ebhomengo/niki/param/benefactor/kind_box_req" + richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error" +) + +func (s Service) Update(ctx context.Context, req param.KindBoxReqUpdateRequest) error { + const op = "benefactorkindboxreqservice.Update" + + kindBoxReq, err := s.repo.GetKindBoxReqByID(ctx, req.KindBoxReqID) + if err != nil { + return richerror.New(op).WithErr(err) + } + + kindBoxReq.KindBoxType = req.KindBoxType + kindBoxReq.CountRequested = req.CountRequested + kindBoxReq.Description = req.Description + kindBoxReq.DeliverReferTimeID = req.DeliverReferTimeID + kindBoxReq.DeliverReferDate = req.DeliverReferDate + kindBoxReq.DeliverAddressID = req.DeliverAddressID + + uErr := s.repo.UpdateKindBoxReq(ctx, kindBoxReq) + if uErr != nil { + return richerror.New(op).WithErr(err) + } + + return nil +} diff --git a/validator/benefactor/kind_box_req/update.go b/validator/benefactor/kind_box_req/update.go index 11b8b61..0bd0c07 100644 --- a/validator/benefactor/kind_box_req/update.go +++ b/validator/benefactor/kind_box_req/update.go @@ -10,24 +10,37 @@ import ( ) func (v Validator) ValidateUpdateRequest(req param.KindBoxReqUpdateRequest) (map[string]string, error) { - const op = "userkindboxreqvalidator.ValidateUpdateRequest" + const op = "benefactorkindboxreqvalidator.ValidateUpdateRequest" if err := validation.ValidateStruct(&req, - validation.Field(&req.CountRequested, validation.Required, validation.Min(MinKindBoxReq), validation.Max(MaxKindBoxReq)), - - validation.Field(&req.BenefactorID, + validation.Field(&req.KindBoxReqID, validation.Required, - validation.By(v.doesBenefactorExist)), - - // validation.Field(&req.KindBoxReqID, - // validation.Required, - // validation.By(v.doesKindBoxRequestExist), - // validation.By(v.hasPendingStatus), - // validation.By(v.doesKindBoxBelongToBenefactor(req.BenefactorID))), - + validation.By(v.doesKindBoxRequestExist), + validation.By(v.doesKindBoxRequestHavePendingStatus), + validation.By(v.doesKindBoxBelongToBenefactor(req.BenefactorID)), + ), + validation.Field(&req.CountRequested, + validation.Required, + validation.Min(uint(MinKindBoxReq)), + validation.Max(uint(MaxKindBoxReq)), + ), validation.Field(&req.KindBoxType, validation.Required, - validation.By(v.doesTypeExist)), + validation.By(v.doesTypeExist), + ), + validation.Field(&req.DeliverAddressID, + validation.Required, + validation.By(v.doesBenefactorAddressExist(req.KindBoxReqID)), + ), + validation.Field(&req.DeliverReferDate, + validation.Required, + validation.By(v.isDateValid), + ), + validation.Field(&req.DeliverReferTimeID, + validation.Required, + validation.By(v.isReferTimeIDValid), + ), + ); err != nil { fieldErrors := make(map[string]string) diff --git a/validator/benefactor/kind_box_req/validator.go b/validator/benefactor/kind_box_req/validator.go index 08a8537..31dd3b7 100644 --- a/validator/benefactor/kind_box_req/validator.go +++ b/validator/benefactor/kind_box_req/validator.go @@ -6,6 +6,7 @@ import ( params "git.gocasts.ir/ebhomengo/niki/param" "slices" "time" + "errors" "git.gocasts.ir/ebhomengo/niki/entity" refertimeparam "git.gocasts.ir/ebhomengo/niki/param/admin/refer_time" @@ -33,6 +34,7 @@ type ReferTimeSvc interface { } type Repository interface { + KindBoxRequestExist(id uint) (bool, error) GetKindBoxReqByID(ctx context.Context, kindBoxReqID uint) (entity.KindBoxReq, error) } @@ -202,3 +204,47 @@ func (v Validator) areSortFieldsValid(validSortFields []string) validation.RuleF return nil } } + +func (v Validator) doesKindBoxRequestExist(value interface{}) error { + kindboxreqID, ok := value.(uint) + if !ok { + return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong) + } + if isExist, err := v.repo.KindBoxRequestExist(kindboxreqID); !isExist || err != nil { + if err != nil { + return err + } + if !isExist { + return errors.New("kind box request is not exist") + } + } + + return nil +} + +func (v Validator) doesBenefactorAddressExist(kindBoxReqID uint) validation.RuleFunc { + return func(value interface{}) error { + addressID, ok := value.(uint) + if !ok { + return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong) + } + + kindBoxReq, err := v.repo.GetKindBoxReqByID(context.Background(), kindBoxReqID) + if err != nil { + return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong) + } + + address, aErr := v.addressSvc.AddressExistByID(context.Background(), addressparam.GetAddressByIDRequest{ID: addressID}) + if aErr != nil { + return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong) + } + if address.Address == nil { + return fmt.Errorf(errmsg.ErrorMsgNotFound) + } + if address.Address.BenefactorID != kindBoxReq.BenefactorID { + return fmt.Errorf(errmsg.ErrorMsgNotFound) + } + + return nil + } +}