From cd18bd2e717e6e95fbd89f727babdc149a14d1db Mon Sep 17 00:00:00 2001 From: Ruhollah Date: Sun, 21 Jul 2024 17:46:01 +0330 Subject: [PATCH] feat(niki): implement get kind box req by id for admin --- .../http_server/admin/kind_box_req/get.go | 48 ++++++++ .../http_server/admin/kind_box_req/route.go | 2 + docs/docs.go | 107 ++++++++++++++++++ docs/swagger.json | 107 ++++++++++++++++++ docs/swagger.yaml | 69 +++++++++++ entity/admin_permission.go | 1 + main.go | 1 + param/admin/kind_box_req/get.go | 9 +- pkg/err_msg/message.go | 1 + repository/mysql/db.go | 35 +++++- repository/mysql/kind_box_req/kind_box_req.go | 12 +- ...s_controls_table_permission_enum_field.sql | 3 +- ...565_insert_admin_access_controls_table.sql | 2 + service/admin/kind_box_req/get.go | 21 ++++ validator/admin/kind_box_req/get.go | 36 ++++++ 15 files changed, 444 insertions(+), 10 deletions(-) create mode 100644 delivery/http_server/admin/kind_box_req/get.go create mode 100644 service/admin/kind_box_req/get.go create mode 100644 validator/admin/kind_box_req/get.go diff --git a/delivery/http_server/admin/kind_box_req/get.go b/delivery/http_server/admin/kind_box_req/get.go new file mode 100644 index 0000000..9b707d9 --- /dev/null +++ b/delivery/http_server/admin/kind_box_req/get.go @@ -0,0 +1,48 @@ +package adminkindboxreqhandler + +import ( + "net/http" + + param "git.gocasts.ir/ebhomengo/niki/param/admin/kind_box_req" + httpmsg "git.gocasts.ir/ebhomengo/niki/pkg/http_msg" + "github.com/labstack/echo/v4" +) + +// Get godoc +// @Summary Get a specific kind box req by ID +// @Tags KindBoxReq +// @Accept json +// @Produce json +// @Param id path int true "KindBoxReq ID" +// @Success 200 {object} param.GetKindBoxReqResponse +// @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 AuthBearerAdmin +// @Router /admins/kindboxreqs/{id} [get] +func (h Handler) Get(c echo.Context) error { + var req param.GetKindBoxReqRequest + if err := c.Bind(&req); err != nil { + return echo.NewHTTPError(http.StatusBadRequest) + } + + if fieldErrors, err := h.adminKindBoxReqVld.ValidateGetRequest(req); err != nil { + msg, code := httpmsg.Error(err) + + return c.JSON(code, httpmsg.ErrorResponse{ + Message: msg, + Errors: fieldErrors, + }) + } + + resp, err := h.adminKindBoxReqSvc.Get(c.Request().Context(), req) + if err != nil { + msg, code := httpmsg.Error(err) + + return echo.NewHTTPError(code, msg) + } + + return c.JSON(http.StatusOK, resp) +} diff --git a/delivery/http_server/admin/kind_box_req/route.go b/delivery/http_server/admin/kind_box_req/route.go index c14a0df..8ecb4f9 100644 --- a/delivery/http_server/admin/kind_box_req/route.go +++ b/delivery/http_server/admin/kind_box_req/route.go @@ -19,4 +19,6 @@ func (h Handler) SetRoutes(e *echo.Echo) { r.GET("/awaiting-delivery/:id", h.GetAwaitingDelivery, middleware.AdminAuthorization(h.adminAuthorizeSvc, entity.AdminKindBoxReqGetAwaitingDeliveryPermission)) r.GET("/awaiting-delivery", h.GetAllAwaitingDelivery, middleware.AdminAuthorization(h.adminAuthorizeSvc, entity.AdminKindBoxReqGetAwaitingDeliveryPermission)) r.PUT("/:id", h.Update, middleware.AdminAuthorization(h.adminAuthorizeSvc, entity.AdminKindBoxReqUpdatePermission)) + r.GET("/:id", h.Get, middleware.AdminAuthorization(h.adminAuthorizeSvc, entity.AdminKindBoxReqGetPermission)) + } diff --git a/docs/docs.go b/docs/docs.go index 380c121..2a476df 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -1242,6 +1242,72 @@ const docTemplate = `{ } } }, + "/admins/kindboxreqs/{id}": { + "get": { + "security": [ + { + "AuthBearerAdmin": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "KindBoxReq" + ], + "summary": "Get a specific kind box req by ID", + "parameters": [ + { + "type": "integer", + "description": "KindBoxReq ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/adminkindboxreqparam.GetKindBoxReqResponse" + } + }, + "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" + } + } + } + } + }, "/admins/login-by-phone": { "post": { "consumes": [ @@ -2239,6 +2305,47 @@ const docTemplate = `{ } } }, + "adminkindboxreqparam.GetKindBoxReqResponse": { + "type": "object", + "properties": { + "benefactorID": { + "type": "integer" + }, + "countAccepted": { + "type": "integer" + }, + "countRequested": { + "type": "integer" + }, + "deliverAddressID": { + "type": "integer" + }, + "deliverReferDate": { + "type": "string" + }, + "deliverReferTimeID": { + "type": "integer" + }, + "deliveredAt": { + "type": "string" + }, + "description": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "kindBoxType": { + "$ref": "#/definitions/entity.KindBoxType" + }, + "senderAgentID": { + "type": "integer" + }, + "status": { + "$ref": "#/definitions/entity.KindBoxReqStatus" + } + } + }, "adminkindboxreqparam.KindBoxReqAcceptRequest": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 68397d4..a8da8bb 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -1231,6 +1231,72 @@ } } }, + "/admins/kindboxreqs/{id}": { + "get": { + "security": [ + { + "AuthBearerAdmin": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "KindBoxReq" + ], + "summary": "Get a specific kind box req by ID", + "parameters": [ + { + "type": "integer", + "description": "KindBoxReq ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/adminkindboxreqparam.GetKindBoxReqResponse" + } + }, + "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" + } + } + } + } + }, "/admins/login-by-phone": { "post": { "consumes": [ @@ -2228,6 +2294,47 @@ } } }, + "adminkindboxreqparam.GetKindBoxReqResponse": { + "type": "object", + "properties": { + "benefactorID": { + "type": "integer" + }, + "countAccepted": { + "type": "integer" + }, + "countRequested": { + "type": "integer" + }, + "deliverAddressID": { + "type": "integer" + }, + "deliverReferDate": { + "type": "string" + }, + "deliverReferTimeID": { + "type": "integer" + }, + "deliveredAt": { + "type": "string" + }, + "description": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "kindBoxType": { + "$ref": "#/definitions/entity.KindBoxType" + }, + "senderAgentID": { + "type": "integer" + }, + "status": { + "$ref": "#/definitions/entity.KindBoxReqStatus" + } + } + }, "adminkindboxreqparam.KindBoxReqAcceptRequest": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index ab87ebc..d86692f 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -179,6 +179,33 @@ definitions: status: $ref: '#/definitions/entity.KindBoxReqStatus' type: object + adminkindboxreqparam.GetKindBoxReqResponse: + properties: + benefactorID: + type: integer + countAccepted: + type: integer + countRequested: + type: integer + deliverAddressID: + type: integer + deliverReferDate: + type: string + deliverReferTimeID: + type: integer + deliveredAt: + type: string + description: + type: string + id: + type: integer + kindBoxType: + $ref: '#/definitions/entity.KindBoxType' + senderAgentID: + type: integer + status: + $ref: '#/definitions/entity.KindBoxReqStatus' + type: object adminkindboxreqparam.KindBoxReqAcceptRequest: properties: count_accepted: @@ -1583,6 +1610,48 @@ paths: summary: Admin get all kindboxreq tags: - KindBoxReq + /admins/kindboxreqs/{id}: + get: + consumes: + - application/json + parameters: + - description: KindBoxReq ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/adminkindboxreqparam.GetKindBoxReqResponse' + "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: + - AuthBearerAdmin: [] + summary: Get a specific kind box req by ID + tags: + - KindBoxReq /admins/login-by-phone: post: consumes: diff --git a/entity/admin_permission.go b/entity/admin_permission.go index 734dc29..0f22856 100644 --- a/entity/admin_permission.go +++ b/entity/admin_permission.go @@ -16,4 +16,5 @@ const ( AdminKindBoxAssignReceiverAgentPermission = AdminPermission("kindbox-assign_receiver_agent") AdminKindBoxGetAllPermission = AdminPermission("kindbox-getall") AdminKindBoxReqUpdatePermission = AdminPermission("kindboxreq-update") + AdminKindBoxReqGetPermission = AdminPermission("kindboxreq-get") ) diff --git a/main.go b/main.go index 6435755..2747403 100644 --- a/main.go +++ b/main.go @@ -39,6 +39,7 @@ func main() { cfg := config.C() db := initDatabase(cfg, migrate) + defer db.CloseStatements() redisAdapter := initRedis(cfg) dependencies := initDependencies(cfg, redisAdapter, db) diff --git a/param/admin/kind_box_req/get.go b/param/admin/kind_box_req/get.go index e64c73a..6a7acd2 100644 --- a/param/admin/kind_box_req/get.go +++ b/param/admin/kind_box_req/get.go @@ -1,12 +1,11 @@ package adminkindboxreqparam -import entity "git.gocasts.ir/ebhomengo/niki/entity" +import "git.gocasts.ir/ebhomengo/niki/entity" -type KindBoxReqGetRequest struct { - BenefactorID uint - KindBoxReqID uint +type GetKindBoxReqRequest struct { + KindBoxID uint `param:"id"` } -type KindBoxReqGetResponse struct { +type GetKindBoxReqResponse struct { entity.KindBoxReq } diff --git a/pkg/err_msg/message.go b/pkg/err_msg/message.go index eda2b5f..ced8d71 100644 --- a/pkg/err_msg/message.go +++ b/pkg/err_msg/message.go @@ -14,6 +14,7 @@ const ( ErrorMsgOtpCodeExist = "please wait a little bit" ErrorMsgOtpCodeIsNotValid = "verification code is not valid" ErrorMsgCantScanQueryResult = "can't scan query result" + ErrorMsgCantPrepareStatement = "can't prepare statement" ErrorMsgPhoneNumberOrPassIsIncorrect = "phone number or password is incorrect" ErrBadRequest = "Bad request" ErrorMsgAcceptKindBoxReqStatus = "only pending requests will have the ability to be confirmed" diff --git a/repository/mysql/db.go b/repository/mysql/db.go index e2ad514..af326f1 100644 --- a/repository/mysql/db.go +++ b/repository/mysql/db.go @@ -4,6 +4,7 @@ import ( "database/sql" "fmt" querier "git.gocasts.ir/ebhomengo/niki/pkg/query_transaction/sql" + "sync" "time" ) @@ -16,8 +17,10 @@ type Config struct { } type DB struct { - config Config - db *querier.SqlDB + config Config + db *querier.SqlDB + mu sync.Mutex + statements map[string]*sql.Stmt } func (db *DB) Conn() *querier.SqlDB { @@ -48,3 +51,31 @@ func New(config Config) *DB { return &DB{config: config, db: &querier.SqlDB{db}} } + +func (p *DB) PrepareStatement(key string, query string) (*sql.Stmt, error) { + p.mu.Lock() + defer p.mu.Unlock() + + 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 + + return stmt, nil +} + +func (p *DB) CloseStatements() error { + for _, stmt := range p.statements { + err := stmt.Close() + if err != nil { + return err + } + } + + return nil +} diff --git a/repository/mysql/kind_box_req/kind_box_req.go b/repository/mysql/kind_box_req/kind_box_req.go index c58d3d5..1833978 100644 --- a/repository/mysql/kind_box_req/kind_box_req.go +++ b/repository/mysql/kind_box_req/kind_box_req.go @@ -11,8 +11,16 @@ import ( ) func (d DB) KindBoxRequestExist(id uint) (bool, error) { - op := richerror.Op("mysqlkindboxreq.KindBoxRequestExist") - row := d.conn.Conn().QueryRow(`select * from kind_box_reqs where id = ?`, id) + const op = "mysqlkindboxreq.KindBoxRequestExist" + + query := `select * from kind_box_reqs where id = ?` + stmt, err := d.conn.PrepareStatement(op, query) + if err != nil { + return false, richerror.New(op).WithErr(err). + WithMessage(errmsg.ErrorMsgCantPrepareStatement).WithKind(richerror.KindUnexpected) + } + + row := stmt.QueryRow(id) _, sErr := scanKindBoxReq(row) if sErr != nil { if errors.Is(sErr, sql.ErrNoRows) { diff --git a/repository/mysql/migration/1708712564_alter_admin_access_controls_table_permission_enum_field.sql b/repository/mysql/migration/1708712564_alter_admin_access_controls_table_permission_enum_field.sql index 4b02654..835a1c5 100644 --- a/repository/mysql/migration/1708712564_alter_admin_access_controls_table_permission_enum_field.sql +++ b/repository/mysql/migration/1708712564_alter_admin_access_controls_table_permission_enum_field.sql @@ -13,7 +13,8 @@ ALTER TABLE `admin_access_controls` MODIFY COLUMN `permission` 'kindboxreq-add', 'kindbox-assign_receiver_agent', 'kindbox-getall', - 'kindboxreq-update' + 'kindboxreq-update', + 'kindboxreq-get' ) NOT NULL; -- +migrate Down \ No newline at end of file diff --git a/repository/mysql/migration/1708712565_insert_admin_access_controls_table.sql b/repository/mysql/migration/1708712565_insert_admin_access_controls_table.sql index 7e97529..5145b61 100644 --- a/repository/mysql/migration/1708712565_insert_admin_access_controls_table.sql +++ b/repository/mysql/migration/1708712565_insert_admin_access_controls_table.sql @@ -16,6 +16,8 @@ INSERT INTO `admin_access_controls` (`id`, `actor_id`, `actor_type`,`permission` (DEFAULT, 1 , 'role','kindboxreq-deliver'), (DEFAULT, 2 , 'role','kindboxreq-deliver'), (DEFAULT, 3 , 'role','kindboxreq-deliver'), + (DEFAULT, 1 , 'role','kindboxreq-get'), + (DEFAULT, 2 , 'role','kindboxreq-get'), (DEFAULT, 1 , 'role','kindboxreq-getall'), (DEFAULT, 2 , 'role','kindboxreq-getall'), (DEFAULT, 1 , 'role','kindboxreq-update'), diff --git a/service/admin/kind_box_req/get.go b/service/admin/kind_box_req/get.go new file mode 100644 index 0000000..baca02b --- /dev/null +++ b/service/admin/kind_box_req/get.go @@ -0,0 +1,21 @@ +package adminkindboxreqservice + +import ( + "context" + + param "git.gocasts.ir/ebhomengo/niki/param/admin/kind_box_req" + richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error" +) + +func (s Service) Get(ctx context.Context, request param.GetKindBoxReqRequest) (param.GetKindBoxReqResponse, error) { + const op = "adminkindboxreqservice.Get" + + kindBoxReq, err := s.repo.GetByID(ctx, request.KindBoxID) + if err != nil { + return param.GetKindBoxReqResponse{}, richerror.New(op).WithErr(err) + } + + return param.GetKindBoxReqResponse{ + KindBoxReq: kindBoxReq, + }, nil +} diff --git a/validator/admin/kind_box_req/get.go b/validator/admin/kind_box_req/get.go new file mode 100644 index 0000000..eeec291 --- /dev/null +++ b/validator/admin/kind_box_req/get.go @@ -0,0 +1,36 @@ +package adminkindboxreqvalidator + +import ( + "errors" + param "git.gocasts.ir/ebhomengo/niki/param/admin/kind_box_req" + errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg" + richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error" + validation "github.com/go-ozzo/ozzo-validation/v4" +) + +func (v Validator) ValidateGetRequest(req param.GetKindBoxReqRequest) (map[string]string, error) { + const op = "adminkindboxreqvalidator.ValidateGetRequest" + + if err := validation.ValidateStruct(&req, + validation.Field(&req.KindBoxID, validation.Required, validation.By(v.doesKindBoxRequestExist)), + ); err != nil { + fieldErrors := make(map[string]string) + + var errV validation.Errors + if errors.As(err, &errV) { + for key, value := range errV { + if value != nil { + fieldErrors[key] = value.Error() + } + } + } + + return fieldErrors, richerror.New(op). + WithMessage(errmsg.ErrorMsgInvalidInput). + WithKind(richerror.KindInvalid). + WithMeta(map[string]interface{}{"req": req}). + WithErr(err) + } + + return map[string]string{}, nil +}