forked from ebhomengo/niki
feat(service): add admin kind_box_req assign sender agent endpoint.
This commit is contained in:
parent
0d54a3765b
commit
17b7c4beb2
|
@ -1 +0,0 @@
|
||||||
package adminkindboxhandler
|
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxhandler
|
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxhandler
|
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxhandler
|
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxreqhandler
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
package adminkindboxreqhandler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
param "git.gocasts.ir/ebhomengo/niki/param/admin/kind_box_req"
|
||||||
|
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
||||||
|
httpmsg "git.gocasts.ir/ebhomengo/niki/pkg/http_msg"
|
||||||
|
echo "github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h Handler) AssignSenderAgent(c echo.Context) error {
|
||||||
|
var req param.AssignSenderRequest
|
||||||
|
|
||||||
|
if bErr := c.Bind(&req); bErr != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
id, cErr := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||||
|
|
||||||
|
if cErr != nil {
|
||||||
|
return c.JSON(http.StatusBadRequest, errmsg.ErrorMsgInvalidInput)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.KindBoxReqID = uint(id)
|
||||||
|
|
||||||
|
if fieldErrors, err := h.adminKindBoxReqVld.ValidateAssignSenderAgent(req); err != nil {
|
||||||
|
msg, code := httpmsg.Error(err)
|
||||||
|
|
||||||
|
return c.JSON(code, echo.Map{
|
||||||
|
"message": msg,
|
||||||
|
"errors": fieldErrors,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, sErr := h.adminKindBoxReqSvc.AssignSenderAgent(c.Request().Context(), req)
|
||||||
|
|
||||||
|
if sErr != nil {
|
||||||
|
msg, code := httpmsg.Error(sErr)
|
||||||
|
|
||||||
|
return echo.NewHTTPError(code, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(http.StatusOK, resp)
|
||||||
|
}
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxreqhandler
|
|
|
@ -12,5 +12,6 @@ func (h Handler) SetRoutes(e *echo.Echo) {
|
||||||
r.PATCH("/accept-kind-box-req/:id", h.Accept)
|
r.PATCH("/accept-kind-box-req/:id", h.Accept)
|
||||||
r.PATCH("/reject-kind-box-req/:id", h.Reject)
|
r.PATCH("/reject-kind-box-req/:id", h.Reject)
|
||||||
r.PATCH("/deliver-kind-box-req/:id", h.Deliver)
|
r.PATCH("/deliver-kind-box-req/:id", h.Deliver)
|
||||||
|
r.PATCH("/assign-sender-agent/:id", h.AssignSenderAgent)
|
||||||
r.GET("/", h.GetAll, middleware.Auth(h.authSvc, h.authConfig))
|
r.GET("/", h.GetAll, middleware.Auth(h.authSvc, h.authConfig))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxreqhandler
|
|
|
@ -1 +0,0 @@
|
||||||
package benefactorkindboxreqhandler
|
|
|
@ -1 +0,0 @@
|
||||||
package benefactorkindboxreqhandler
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package adminserviceparam
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AdminExistByIDRequest struct {
|
||||||
|
AdminID uint
|
||||||
|
}
|
||||||
|
|
||||||
|
type AdminExistByIDResponse struct {
|
||||||
|
Admin entity.Admin
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package adminkindboxreqparam
|
||||||
|
|
||||||
|
type AssignSenderRequest struct {
|
||||||
|
KindBoxReqID uint `json:"kind_box_req_id"`
|
||||||
|
SenderAgentID uint `json:"sender_agent_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AssignSenderResponse struct{}
|
|
@ -17,5 +17,7 @@ const (
|
||||||
ErrBadRequest = "Bad request"
|
ErrBadRequest = "Bad request"
|
||||||
ErrorMsgAcceptKindBoxReqStatus = "only pending requests will have the ability to be confirmed"
|
ErrorMsgAcceptKindBoxReqStatus = "only pending requests will have the ability to be confirmed"
|
||||||
ErrorMsgRejectKindBoxReqStatus = "only pending requests will have the ability to be rejected"
|
ErrorMsgRejectKindBoxReqStatus = "only pending requests will have the ability to be rejected"
|
||||||
|
ErrorMsgAssignSenderAgentKindBoxReqStatus = "only accepted kind_box_reqs will have the ability to be assign sender agent"
|
||||||
ErrorMsgDeliverKindBoxReqStatus = "only assigned requests will have the ability to be delivered"
|
ErrorMsgDeliverKindBoxReqStatus = "only assigned requests will have the ability to be delivered"
|
||||||
|
ErrorMsgAdminIsNotAgent = "admin is not agent"
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
entity "git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
||||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||||
)
|
)
|
||||||
|
@ -52,3 +53,25 @@ func (d DB) AdminExistByEmail(ctx context.Context, email string) (bool, error) {
|
||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d DB) GetAdminByID(ctx context.Context, adminID uint) (entity.Admin, error) {
|
||||||
|
const op = "mysqladmin.GetAdminByID"
|
||||||
|
|
||||||
|
row := d.conn.Conn().QueryRowContext(ctx, `select * from admins where id = ?`, adminID)
|
||||||
|
|
||||||
|
admin, err := scanAdmin(row)
|
||||||
|
if err != nil {
|
||||||
|
sErr := sql.ErrNoRows
|
||||||
|
//TODO-errorsas: second argument to errors.As should not be *error
|
||||||
|
//nolint
|
||||||
|
if errors.As(err, &sErr) {
|
||||||
|
return entity.Admin{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO - log unexpected error for better observability
|
||||||
|
return entity.Admin{}, richerror.New(op).WithErr(err).
|
||||||
|
WithMessage(errmsg.ErrorMsgCantScanQueryResult).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
|
||||||
|
return admin, nil
|
||||||
|
}
|
||||||
|
|
|
@ -91,18 +91,14 @@ func mapNotNullToBenefactor(data nullableFields, benefactor *entity.Benefactor)
|
||||||
if data.lastName.Valid {
|
if data.lastName.Valid {
|
||||||
benefactor.LastName = data.lastName.String
|
benefactor.LastName = data.lastName.String
|
||||||
}
|
}
|
||||||
//if data.address.Valid {
|
|
||||||
// benefactor.Address = data.address.String
|
|
||||||
//}
|
|
||||||
if data.description.Valid {
|
if data.description.Valid {
|
||||||
benefactor.Description = data.description.String
|
benefactor.Description = data.description.String
|
||||||
}
|
}
|
||||||
if data.email.Valid {
|
if data.email.Valid {
|
||||||
benefactor.Email = data.email.String
|
benefactor.Email = data.email.String
|
||||||
}
|
}
|
||||||
//if data.city.Valid {
|
|
||||||
// benefactor.City = data.city.String
|
|
||||||
//}
|
|
||||||
if data.genderStr.Valid {
|
if data.genderStr.Valid {
|
||||||
benefactor.Gender = entity.MapToGender(data.genderStr.String)
|
benefactor.Gender = entity.MapToGender(data.genderStr.String)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package mysqlkindboxreq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
entity "git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
|
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
||||||
|
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (d DB) AssignSenderAgentToKindBoxReq(ctx context.Context, kindBoxReqID, senderAgentID uint) error {
|
||||||
|
const op = "mysqlkindboxreq.AssignSenderAgentToKindBoxReq"
|
||||||
|
|
||||||
|
_, err := d.conn.Conn().ExecContext(ctx, `update kind_box_reqs set sender_agent_id = ?, status = ?, updated_at= ? where id = ?`,
|
||||||
|
senderAgentID, entity.KindBoxReqAssignedSenderAgentStatus.String(), time.Now(), kindBoxReqID)
|
||||||
|
if err != nil {
|
||||||
|
return richerror.New(op).WithErr(err).
|
||||||
|
WithMessage(errmsg.ErrorMsgSomethingWentWrong).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
-- +migrate Up
|
-- +migrate Up
|
||||||
-- what can we do for password?
|
-- what can we do for password?
|
||||||
INSERT INTO `admins` (`id`, `phone_number`, `email`,`password`,`role`,`status`)
|
INSERT INTO `admins` (`id`, `phone_number`, `email`,`password`,`role`,`status`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, '09122702856', 'keshvari@gmail.com','Abc123456','super-admin','active');
|
(1, '09122702856', 'keshvari@gmail.com','Abc123456','super-admin','active');
|
||||||
|
|
||||||
-- +migrate Down
|
-- +migrate Down
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package adminservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
param "git.gocasts.ir/ebhomengo/niki/param/admin/admin"
|
||||||
|
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s Service) AdminExistByID(ctx context.Context, req param.AdminExistByIDRequest) (param.AdminExistByIDResponse, error) {
|
||||||
|
const op = "adminservice.AdminExistByID"
|
||||||
|
|
||||||
|
admin, err := s.repo.GetAdminByID(ctx, req.AdminID)
|
||||||
|
if err != nil {
|
||||||
|
return param.AdminExistByIDResponse{}, richerror.New(op).WithErr(err).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
|
||||||
|
return param.AdminExistByIDResponse{Admin: admin}, nil
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ type AuthGenerator interface {
|
||||||
type Repository interface {
|
type Repository interface {
|
||||||
AddAdmin(ctx context.Context, admin entity.Admin) (entity.Admin, error)
|
AddAdmin(ctx context.Context, admin entity.Admin) (entity.Admin, error)
|
||||||
GetAdminByPhoneNumber(ctx context.Context, phoneNumber string) (entity.Admin, error)
|
GetAdminByPhoneNumber(ctx context.Context, phoneNumber string) (entity.Admin, error)
|
||||||
|
GetAdminByID(ctx context.Context, adminID uint) (entity.Admin, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxservice
|
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxservice
|
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxservice
|
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxservice
|
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxreqservice
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
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) AssignSenderAgent(ctx context.Context, req param.AssignSenderRequest) (param.AssignSenderResponse, error) {
|
||||||
|
const op = "adminkindboxreqservice.AssignSenderAgent"
|
||||||
|
|
||||||
|
err := s.repo.AssignSenderAgentToKindBoxReq(ctx, req.KindBoxReqID, req.SenderAgentID)
|
||||||
|
if err != nil {
|
||||||
|
return param.AssignSenderResponse{}, richerror.New(op).WithErr(err).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
|
||||||
|
return param.AssignSenderResponse{}, nil
|
||||||
|
}
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxreqservice
|
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxreqservice
|
|
|
@ -3,7 +3,7 @@ package adminkindboxreqservice
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
entity "git.gocasts.ir/ebhomengo/niki/entity"
|
"git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
paginationparam "git.gocasts.ir/ebhomengo/niki/param"
|
paginationparam "git.gocasts.ir/ebhomengo/niki/param"
|
||||||
param "git.gocasts.ir/ebhomengo/niki/param/admin/kind_box"
|
param "git.gocasts.ir/ebhomengo/niki/param/admin/kind_box"
|
||||||
)
|
)
|
||||||
|
@ -14,6 +14,7 @@ type Repository interface {
|
||||||
RejectKindBoxReq(ctx context.Context, kindBoxReqID uint, description string) error
|
RejectKindBoxReq(ctx context.Context, kindBoxReqID uint, description string) error
|
||||||
RollbackKindBoxRequestStatus(ctx context.Context, id uint) error
|
RollbackKindBoxRequestStatus(ctx context.Context, id uint) error
|
||||||
GetAllKindBoxReq(ctx context.Context, pagination paginationparam.PaginationRequest) ([]entity.KindBoxReq, paginationparam.PaginationResponse, error)
|
GetAllKindBoxReq(ctx context.Context, pagination paginationparam.PaginationRequest) ([]entity.KindBoxReq, paginationparam.PaginationResponse, error)
|
||||||
|
AssignSenderAgentToKindBoxReq(ctx context.Context, kindBoxReqID uint, senderAgentID uint) error
|
||||||
DeliverKindBoxReq(ctx context.Context, kindBoxReqID uint) error
|
DeliverKindBoxReq(ctx context.Context, kindBoxReqID uint) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxreqservice
|
|
|
@ -2,6 +2,7 @@ package benefactorkindboxreqservice
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/entity"
|
"git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
param "git.gocasts.ir/ebhomengo/niki/param/benefactor/kind_box_req"
|
param "git.gocasts.ir/ebhomengo/niki/param/benefactor/kind_box_req"
|
||||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
package benefactorkindboxreqservice
|
|
|
@ -1 +0,0 @@
|
||||||
package benefactorkindboxreqservice
|
|
|
@ -1 +0,0 @@
|
||||||
package benefactorkindboxreqservice
|
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxvalidator
|
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxvalidator
|
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxvalidator
|
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxvalidator
|
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxreqvalidator
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
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) ValidateAssignSenderAgent(req param.AssignSenderRequest) (map[string]string, error) {
|
||||||
|
const op = "adminkindboxreqvalidator.ValidateAssignSenderAgent"
|
||||||
|
|
||||||
|
if err := validation.ValidateStruct(&req,
|
||||||
|
|
||||||
|
validation.Field(&req.KindBoxReqID, validation.Required, validation.By(v.doesKindBoxRequestExist), validation.By(v.checkKindBoxReqStatusForAssigningSenderAgent)),
|
||||||
|
|
||||||
|
validation.Field(&req.SenderAgentID, validation.Required, validation.By(v.doesAgentAdminExist))); 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
|
||||||
|
}
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxreqvalidator
|
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxreqvalidator
|
|
|
@ -1 +0,0 @@
|
||||||
package adminkindboxreqvalidator
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/entity"
|
"git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
|
param "git.gocasts.ir/ebhomengo/niki/param/admin/admin"
|
||||||
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -19,8 +20,13 @@ type Repository interface {
|
||||||
GetByID(ctx context.Context, id uint) (entity.KindBoxReq, error)
|
GetByID(ctx context.Context, id uint) (entity.KindBoxReq, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AdminSvc interface {
|
||||||
|
AdminExistByID(ctx context.Context, req param.AdminExistByIDRequest) (param.AdminExistByIDResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
type Validator struct {
|
type Validator struct {
|
||||||
repo Repository
|
repo Repository
|
||||||
|
adminSvc AdminSvc
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(repo Repository) Validator {
|
func New(repo Repository) Validator {
|
||||||
|
@ -76,6 +82,38 @@ func (v Validator) CheckKindBoxReqStatusForRejecting(value interface{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v Validator) checkKindBoxReqStatusForAssigningSenderAgent(value interface{}) error {
|
||||||
|
kindboxreqID, ok := value.(uint)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong)
|
||||||
|
}
|
||||||
|
kindBoxReq, err := v.repo.GetByID(context.Background(), kindboxreqID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if kindBoxReq.Status != entity.KindBoxReqAcceptedStatus {
|
||||||
|
return fmt.Errorf(errmsg.ErrorMsgAssignSenderAgentKindBoxReqStatus)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Validator) doesAgentAdminExist(value interface{}) error {
|
||||||
|
adminID, ok := value.(uint)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong)
|
||||||
|
}
|
||||||
|
resp, err := v.adminSvc.AdminExistByID(context.Background(), param.AdminExistByIDRequest{AdminID: adminID})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.Admin.Role != entity.AdminAgentRole {
|
||||||
|
return fmt.Errorf(errmsg.ErrorMsgAdminIsNotAgent)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (v Validator) checkKindBoxReqStatusForDelivering(value interface{}) error {
|
func (v Validator) checkKindBoxReqStatusForDelivering(value interface{}) error {
|
||||||
kindboxreqID, ok := value.(uint)
|
kindboxreqID, ok := value.(uint)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
Loading…
Reference in New Issue