forked from ebhomengo/niki
Merge pull request 'feat(niki): implement refresh access token for admins and benefactors (#156)' (#157) from stage/ruhollahh01/implement-refresh-access-token-endpoints into develop
Reviewed-on: ebhomengo/niki#157
This commit is contained in:
commit
c8c5ca808e
|
@ -0,0 +1,37 @@
|
||||||
|
package adminhandler
|
||||||
|
|
||||||
|
import (
|
||||||
|
adminserviceparam "git.gocasts.ir/ebhomengo/niki/param/admin/admin"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
httpmsg "git.gocasts.ir/ebhomengo/niki/pkg/http_msg"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RefreshAccess godoc
|
||||||
|
// @Summary Get a new access token by providing a refresh token
|
||||||
|
// @Tags Admins
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param Request body adminserviceparam.RefreshAccessRequest true "Refresh access request body"
|
||||||
|
// @Success 200 {object} adminserviceparam.RefreshAccessResponse
|
||||||
|
// @Failure 400 {string} "Bad Request"
|
||||||
|
// @Failure 422 {string} "invalid or expired jwt"
|
||||||
|
// @Failure 500 {string} "something went wrong"
|
||||||
|
// @Router /admins/refresh-access [post].
|
||||||
|
func (h Handler) RefreshAccess(c echo.Context) error {
|
||||||
|
var req adminserviceparam.RefreshAccessRequest
|
||||||
|
|
||||||
|
if err := c.Bind(&req); err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := h.adminSvc.RefreshAccess(c.Request().Context(), req)
|
||||||
|
if err != nil {
|
||||||
|
msg, code := httpmsg.Error(err)
|
||||||
|
|
||||||
|
return echo.NewHTTPError(code, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(http.StatusOK, resp)
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ func (h Handler) SetRoutes(e *echo.Echo) {
|
||||||
//r.POST("/", h.Add).Name = "admin-addkindboxreq"
|
//r.POST("/", h.Add).Name = "admin-addkindboxreq"
|
||||||
r.POST("/register", h.Register, middleware.Auth(h.authSvc), middleware.AdminAuthorization(h.adminAuthorizeSvc, entity.AdminAdminRegisterPermission))
|
r.POST("/register", h.Register, middleware.Auth(h.authSvc), middleware.AdminAuthorization(h.adminAuthorizeSvc, entity.AdminAdminRegisterPermission))
|
||||||
r.POST("/login-by-phone", h.LoginByPhoneNumber)
|
r.POST("/login-by-phone", h.LoginByPhoneNumber)
|
||||||
|
r.POST("/refresh-access", h.RefreshAccess)
|
||||||
//nolint:gocritic
|
//nolint:gocritic
|
||||||
//r.PATCH("/:id", h.Update).Name = "admin-updatekindboxreq"
|
//r.PATCH("/:id", h.Update).Name = "admin-updatekindboxreq"
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package benefactorhandler
|
||||||
|
|
||||||
|
import (
|
||||||
|
benefactorparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/benefactor"
|
||||||
|
httpmsg "git.gocasts.ir/ebhomengo/niki/pkg/http_msg"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RefreshAccess godoc
|
||||||
|
// @Summary Get a new access token by providing your refresh token
|
||||||
|
// @Tags Benefactors
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param Request body benefactorparam.RefreshAccessRequest true "Refresh access token request body"
|
||||||
|
// @Success 200 {object} benefactorparam.RefreshAccessResponse
|
||||||
|
// @Failure 400 {string} "Bad Request"
|
||||||
|
// @Failure 500 {string} "something went wrong"
|
||||||
|
// @Router /benefactors/refresh-access [post].
|
||||||
|
func (h Handler) RefreshAccess(c echo.Context) error {
|
||||||
|
var req benefactorparam.RefreshAccessRequest
|
||||||
|
|
||||||
|
if err := c.Bind(&req); err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := h.benefactorSvc.RefreshAccess(c.Request().Context(), req)
|
||||||
|
if err != nil {
|
||||||
|
msg, code := httpmsg.Error(err)
|
||||||
|
|
||||||
|
return echo.NewHTTPError(code, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(http.StatusOK, resp)
|
||||||
|
}
|
|
@ -9,4 +9,5 @@ func (h Handler) SetRoutes(e *echo.Echo) {
|
||||||
|
|
||||||
r.POST("/send-otp", h.SendOtp)
|
r.POST("/send-otp", h.SendOtp)
|
||||||
r.POST("/login-register", h.loginOrRegister)
|
r.POST("/login-register", h.loginOrRegister)
|
||||||
|
r.POST("/refresh-access", h.RefreshAccess)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ func Auth(service authservice.Service) echo.MiddlewareFunc {
|
||||||
// TODO - as sign method string to config
|
// TODO - as sign method string to config
|
||||||
SigningMethod: "HS256",
|
SigningMethod: "HS256",
|
||||||
ParseTokenFunc: func(c echo.Context, auth string) (interface{}, error) {
|
ParseTokenFunc: func(c echo.Context, auth string) (interface{}, error) {
|
||||||
claims, err := service.ParseToken(auth)
|
claims, err := service.ParseBearerToken(auth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
128
docs/docs.go
128
docs/docs.go
|
@ -1235,6 +1235,57 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/admins/refresh-access": {
|
||||||
|
"post": {
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Admins"
|
||||||
|
],
|
||||||
|
"summary": "Get a new access token by providing a refresh token",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Refresh access request body",
|
||||||
|
"name": "Request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/adminserviceparam.RefreshAccessRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/adminserviceparam.RefreshAccessResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"422": {
|
||||||
|
"description": "invalid or expired jwt",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "something went wrong",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/admins/register": {
|
"/admins/register": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
|
@ -2487,6 +2538,51 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/benefactors/refresh-access": {
|
||||||
|
"post": {
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Benefactors"
|
||||||
|
],
|
||||||
|
"summary": "Get a new access token by providing your refresh token",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Refresh access token request body",
|
||||||
|
"name": "Request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/benefactoreparam.RefreshAccessRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/benefactoreparam.RefreshAccessResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "something went wrong",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/benefactors/send-otp": {
|
"/benefactors/send-otp": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "This endpoint sends an OTP to the benefactor's phone number for verification purposes.",
|
"description": "This endpoint sends an OTP to the benefactor's phone number for verification purposes.",
|
||||||
|
@ -3218,6 +3314,22 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"adminserviceparam.RefreshAccessRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"refresh_token": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"adminserviceparam.RefreshAccessResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"access_token": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"adminserviceparam.RegisterRequest": {
|
"adminserviceparam.RegisterRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -3449,6 +3561,22 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"benefactoreparam.RefreshAccessRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"refresh_token": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"benefactoreparam.RefreshAccessResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"access_token": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"benefactoreparam.SendOtpRequest": {
|
"benefactoreparam.SendOtpRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
|
@ -1224,6 +1224,57 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/admins/refresh-access": {
|
||||||
|
"post": {
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Admins"
|
||||||
|
],
|
||||||
|
"summary": "Get a new access token by providing a refresh token",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Refresh access request body",
|
||||||
|
"name": "Request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/adminserviceparam.RefreshAccessRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/adminserviceparam.RefreshAccessResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"422": {
|
||||||
|
"description": "invalid or expired jwt",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "something went wrong",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/admins/register": {
|
"/admins/register": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
|
@ -2476,6 +2527,51 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/benefactors/refresh-access": {
|
||||||
|
"post": {
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Benefactors"
|
||||||
|
],
|
||||||
|
"summary": "Get a new access token by providing your refresh token",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Refresh access token request body",
|
||||||
|
"name": "Request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/benefactoreparam.RefreshAccessRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/benefactoreparam.RefreshAccessResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "something went wrong",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/benefactors/send-otp": {
|
"/benefactors/send-otp": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "This endpoint sends an OTP to the benefactor's phone number for verification purposes.",
|
"description": "This endpoint sends an OTP to the benefactor's phone number for verification purposes.",
|
||||||
|
@ -3207,6 +3303,22 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"adminserviceparam.RefreshAccessRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"refresh_token": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"adminserviceparam.RefreshAccessResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"access_token": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"adminserviceparam.RegisterRequest": {
|
"adminserviceparam.RegisterRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -3438,6 +3550,22 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"benefactoreparam.RefreshAccessRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"refresh_token": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"benefactoreparam.RefreshAccessResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"access_token": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"benefactoreparam.SendOtpRequest": {
|
"benefactoreparam.SendOtpRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
|
@ -455,6 +455,16 @@ definitions:
|
||||||
tokens:
|
tokens:
|
||||||
$ref: '#/definitions/adminserviceparam.Tokens'
|
$ref: '#/definitions/adminserviceparam.Tokens'
|
||||||
type: object
|
type: object
|
||||||
|
adminserviceparam.RefreshAccessRequest:
|
||||||
|
properties:
|
||||||
|
refresh_token:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
adminserviceparam.RefreshAccessResponse:
|
||||||
|
properties:
|
||||||
|
access_token:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
adminserviceparam.RegisterRequest:
|
adminserviceparam.RegisterRequest:
|
||||||
properties:
|
properties:
|
||||||
description:
|
description:
|
||||||
|
@ -604,6 +614,16 @@ definitions:
|
||||||
tokens:
|
tokens:
|
||||||
$ref: '#/definitions/benefactoreparam.Tokens'
|
$ref: '#/definitions/benefactoreparam.Tokens'
|
||||||
type: object
|
type: object
|
||||||
|
benefactoreparam.RefreshAccessRequest:
|
||||||
|
properties:
|
||||||
|
refresh_token:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
benefactoreparam.RefreshAccessResponse:
|
||||||
|
properties:
|
||||||
|
access_token:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
benefactoreparam.SendOtpRequest:
|
benefactoreparam.SendOtpRequest:
|
||||||
properties:
|
properties:
|
||||||
phone_number:
|
phone_number:
|
||||||
|
@ -1721,6 +1741,39 @@ paths:
|
||||||
summary: "Admin login by\tPhoneNumber"
|
summary: "Admin login by\tPhoneNumber"
|
||||||
tags:
|
tags:
|
||||||
- Admins
|
- Admins
|
||||||
|
/admins/refresh-access:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: Refresh access request body
|
||||||
|
in: body
|
||||||
|
name: Request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/adminserviceparam.RefreshAccessRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/adminserviceparam.RefreshAccessResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
"422":
|
||||||
|
description: invalid or expired jwt
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
"500":
|
||||||
|
description: something went wrong
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
summary: Get a new access token by providing a refresh token
|
||||||
|
tags:
|
||||||
|
- Admins
|
||||||
/admins/register:
|
/admins/register:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
|
@ -2547,6 +2600,35 @@ paths:
|
||||||
summary: Login or register a benefactor
|
summary: Login or register a benefactor
|
||||||
tags:
|
tags:
|
||||||
- Benefactors
|
- Benefactors
|
||||||
|
/benefactors/refresh-access:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
parameters:
|
||||||
|
- description: Refresh access token request body
|
||||||
|
in: body
|
||||||
|
name: Request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/benefactoreparam.RefreshAccessRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/benefactoreparam.RefreshAccessResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
"500":
|
||||||
|
description: something went wrong
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
summary: Get a new access token by providing your refresh token
|
||||||
|
tags:
|
||||||
|
- Benefactors
|
||||||
/benefactors/send-otp:
|
/benefactors/send-otp:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
|
@ -12,4 +12,5 @@ type Benefactor struct {
|
||||||
Gender Gender
|
Gender Gender
|
||||||
BirthDate time.Time
|
BirthDate time.Time
|
||||||
Role UserRole
|
Role UserRole
|
||||||
|
Status BenefactorStatus
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package entity
|
||||||
|
|
||||||
|
type BenefactorStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
BenefactorActiveStatus = BenefactorStatus("active")
|
||||||
|
BenefactorInactiveStatus = BenefactorStatus("inactive")
|
||||||
|
)
|
||||||
|
|
||||||
|
var BenefactorStatusStrings = map[BenefactorStatus]string{
|
||||||
|
BenefactorActiveStatus: "active",
|
||||||
|
BenefactorInactiveStatus: "inactive",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b BenefactorStatus) IsValid() bool {
|
||||||
|
_, ok := BenefactorStatusStrings[b]
|
||||||
|
|
||||||
|
return ok
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package adminserviceparam
|
||||||
|
|
||||||
|
type RefreshAccessRequest struct {
|
||||||
|
RefreshToken string `json:"refresh_token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RefreshAccessResponse struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package benefactoreparam
|
||||||
|
|
||||||
|
type RefreshAccessRequest struct {
|
||||||
|
RefreshToken string `json:"refresh_token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RefreshAccessResponse struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
}
|
|
@ -37,4 +37,6 @@ const (
|
||||||
ErrorMsgAssignReceiverAgentKindBoxStatus = "only ready to return kindboxes can be assigned to a receiver agent"
|
ErrorMsgAssignReceiverAgentKindBoxStatus = "only ready to return kindboxes can be assigned to a receiver agent"
|
||||||
ErrorMsgReturnKindBoxStatus = "only returned kindboxes can be enumerated"
|
ErrorMsgReturnKindBoxStatus = "only returned kindboxes can be enumerated"
|
||||||
ErrorMsgInvalidSerialNumberRange = "invalid serial number range"
|
ErrorMsgInvalidSerialNumberRange = "invalid serial number range"
|
||||||
|
ErrorMsgInvalidOrExpiredJwt = "invalid or expired jwt"
|
||||||
|
ErrorMsgInvalidRefreshToken = "invalid refresh token"
|
||||||
)
|
)
|
||||||
|
|
|
@ -83,14 +83,11 @@ func (d *DB) GetAdminByID(ctx context.Context, adminID uint) (entity.Admin, erro
|
||||||
row := stmt.QueryRowContext(ctx, adminID)
|
row := stmt.QueryRowContext(ctx, adminID)
|
||||||
admin, err := scanAdmin(row)
|
admin, err := scanAdmin(row)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sErr := sql.ErrNoRows
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
//TODO-errorsas: second argument to errors.As should not be *error
|
return entity.Admin{}, richerror.New(op).WithKind(richerror.KindNotFound).
|
||||||
//nolint
|
WithMessage(errmsg.ErrorMsgNotFound)
|
||||||
if errors.As(err, &sErr) {
|
|
||||||
return entity.Admin{}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO - log unexpected error for better observability
|
|
||||||
return entity.Admin{}, richerror.New(op).WithErr(err).
|
return entity.Admin{}, richerror.New(op).WithErr(err).
|
||||||
WithMessage(errmsg.ErrorMsgCantScanQueryResult).WithKind(richerror.KindUnexpected)
|
WithMessage(errmsg.ErrorMsgCantScanQueryResult).WithKind(richerror.KindUnexpected)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,15 +26,11 @@ func (d *DB) GetAdminByPhoneNumber(ctx context.Context, phoneNumber string) (ent
|
||||||
row := stmt.QueryRowContext(ctx, phoneNumber)
|
row := stmt.QueryRowContext(ctx, phoneNumber)
|
||||||
admin, err := scanAdmin(row)
|
admin, err := scanAdmin(row)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sErr := sql.ErrNoRows
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
//TODO-errorsas: second argument to errors.As should not be *error
|
return entity.Admin{}, richerror.New(op).
|
||||||
//nolint
|
|
||||||
if errors.As(err, &sErr) {
|
|
||||||
return entity.Admin{}, richerror.New(op).WithErr(sErr).
|
|
||||||
WithMessage(errmsg.ErrorMsgNotFound).WithKind(richerror.KindNotFound)
|
WithMessage(errmsg.ErrorMsgNotFound).WithKind(richerror.KindNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO - log unexpected error for better observability
|
|
||||||
return entity.Admin{}, richerror.New(op).WithErr(err).
|
return entity.Admin{}, richerror.New(op).WithErr(err).
|
||||||
WithMessage(errmsg.ErrorMsgCantScanQueryResult).WithKind(richerror.KindUnexpected)
|
WithMessage(errmsg.ErrorMsgCantScanQueryResult).WithKind(richerror.KindUnexpected)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,142 +2,39 @@ package mysqlbenefactor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"errors"
|
"errors"
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/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"
|
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||||
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (d *DB) IsExistBenefactorByPhoneNumber(ctx context.Context, phoneNumber string) (bool, entity.Benefactor, error) {
|
func (d *DB) IsExistBenefactorByPhoneNumber(ctx context.Context, phoneNumber string) (bool, entity.Benefactor, error) {
|
||||||
const op = "mysqlbenefactor.IsExistBenefactorByPhoneNumber"
|
const op = "mysqlbenefactor.IsExistBenefactorByPhoneNumber"
|
||||||
|
|
||||||
query := `select * from benefactors where phone_number = ?`
|
bnf, err := d.GetByPhoneNumber(ctx, phoneNumber)
|
||||||
//nolint
|
|
||||||
stmt, err := d.conn.PrepareStatement(ctx, mysql.StatementKeyBenefactorIsExistByPhoneNumber, query)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, entity.Benefactor{}, richerror.New(op).WithErr(err).
|
var richErr richerror.RichError
|
||||||
WithMessage(errmsg.ErrorMsgCantPrepareStatement).WithKind(richerror.KindUnexpected)
|
if errors.As(err, &richErr) && richErr.Kind() == richerror.KindNotFound {
|
||||||
}
|
|
||||||
|
|
||||||
row := stmt.QueryRowContext(ctx, phoneNumber)
|
|
||||||
Benefactor, err := scanBenefactor(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 false, entity.Benefactor{}, nil
|
return false, entity.Benefactor{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO - log unexpected error for better observability
|
return false, entity.Benefactor{}, richerror.New(op).WithErr(err)
|
||||||
return false, entity.Benefactor{}, richerror.New(op).WithErr(err).
|
|
||||||
WithMessage(errmsg.ErrorMsgCantScanQueryResult).WithKind(richerror.KindUnexpected)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, Benefactor, nil
|
return true, bnf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DB) IsExistBenefactorByID(ctx context.Context, id uint) (bool, error) {
|
func (d *DB) IsExistBenefactorByID(ctx context.Context, id uint) (bool, error) {
|
||||||
const op = "mysqlbenefactor.IsExistBenefactorByID"
|
const op = "mysqlbenefactor.IsExistBenefactorByID"
|
||||||
|
|
||||||
query := `select * from benefactors where id = ?`
|
_, err := d.GetByID(ctx, id)
|
||||||
//nolint
|
|
||||||
stmt, err := d.conn.PrepareStatement(ctx, mysql.StatementKeyBenefactorIsExistByID, query)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, richerror.New(op).WithErr(err).
|
var richErr richerror.RichError
|
||||||
WithMessage(errmsg.ErrorMsgCantPrepareStatement).WithKind(richerror.KindUnexpected)
|
if errors.As(err, &richErr) && richErr.Kind() == richerror.KindNotFound {
|
||||||
}
|
|
||||||
|
|
||||||
row := stmt.QueryRowContext(ctx, id)
|
|
||||||
_, err = scanBenefactor(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 false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO - log unexpected error for better observability
|
return false, richerror.New(op).WithErr(err)
|
||||||
return false, richerror.New(op).WithErr(err).
|
|
||||||
WithMessage(errmsg.ErrorMsgCantScanQueryResult).WithKind(richerror.KindUnexpected)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func scanBenefactor(scanner mysql.Scanner) (entity.Benefactor, error) {
|
|
||||||
var createdAt, updatedAt time.Time
|
|
||||||
var benefactor entity.Benefactor
|
|
||||||
// TODO - use db model and mapper between entity and db model OR use this approach
|
|
||||||
|
|
||||||
var benefactorNullableFields nullableFields
|
|
||||||
|
|
||||||
err := scanner.Scan(&benefactor.ID, &benefactorNullableFields.firstName,
|
|
||||||
&benefactorNullableFields.lastName, &benefactor.PhoneNumber, &benefactorNullableFields.description,
|
|
||||||
&benefactorNullableFields.email, &benefactorNullableFields.genderStr,
|
|
||||||
&benefactorNullableFields.birthdate, &createdAt, &updatedAt)
|
|
||||||
|
|
||||||
mapNotNullToBenefactor(benefactorNullableFields, &benefactor)
|
|
||||||
|
|
||||||
return benefactor, err
|
|
||||||
}
|
|
||||||
|
|
||||||
type nullableFields struct {
|
|
||||||
firstName sql.NullString
|
|
||||||
lastName sql.NullString
|
|
||||||
description sql.NullString
|
|
||||||
email sql.NullString
|
|
||||||
genderStr sql.NullString
|
|
||||||
birthdate sql.NullTime
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO - find the other solution.
|
|
||||||
func mapNotNullToBenefactor(data nullableFields, benefactor *entity.Benefactor) {
|
|
||||||
if data.firstName.Valid {
|
|
||||||
benefactor.FirstName = data.firstName.String
|
|
||||||
}
|
|
||||||
if data.lastName.Valid {
|
|
||||||
benefactor.LastName = data.lastName.String
|
|
||||||
}
|
|
||||||
|
|
||||||
if data.description.Valid {
|
|
||||||
benefactor.Description = data.description.String
|
|
||||||
}
|
|
||||||
if data.email.Valid {
|
|
||||||
benefactor.Email = data.email.String
|
|
||||||
}
|
|
||||||
|
|
||||||
if data.genderStr.Valid {
|
|
||||||
benefactor.Gender = entity.Gender(data.genderStr.String)
|
|
||||||
}
|
|
||||||
if data.birthdate.Valid {
|
|
||||||
benefactor.BirthDate = data.birthdate.Time
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DB) GetByID(ctx context.Context, benefactorID uint) (entity.Benefactor, error) {
|
|
||||||
const op = "mysqlbenefactor.IsExistBenefactorByID"
|
|
||||||
|
|
||||||
row := d.conn.Conn().QueryRowContext(ctx, `select * from benefactors where id = ?`, benefactorID)
|
|
||||||
|
|
||||||
bnf, err := scanBenefactor(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 bnf, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO - log unexpected error for better observability
|
|
||||||
return bnf, richerror.New(op).WithErr(err).
|
|
||||||
WithMessage(errmsg.ErrorMsgCantScanQueryResult).WithKind(richerror.KindUnexpected)
|
|
||||||
}
|
|
||||||
|
|
||||||
return bnf, nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package mysqlbenefactor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
|
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
||||||
|
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (d *DB) GetByID(ctx context.Context, id uint) (entity.Benefactor, error) {
|
||||||
|
const op = "mysqlbenefactor.GetByID"
|
||||||
|
|
||||||
|
query := `select * from benefactors where id = ?`
|
||||||
|
//nolint
|
||||||
|
stmt, err := d.conn.PrepareStatement(ctx, mysql.StatementKeyBenefactorGetByID, query)
|
||||||
|
if err != nil {
|
||||||
|
return entity.Benefactor{}, richerror.New(op).WithErr(err).
|
||||||
|
WithMessage(errmsg.ErrorMsgCantPrepareStatement).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
|
||||||
|
row := stmt.QueryRowContext(ctx, id)
|
||||||
|
bnf, err := scanBenefactor(row)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return entity.Benefactor{}, richerror.New(op).WithKind(richerror.KindNotFound).
|
||||||
|
WithMessage(errmsg.ErrorMsgNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
return entity.Benefactor{}, richerror.New(op).WithErr(err).
|
||||||
|
WithMessage(errmsg.ErrorMsgCantScanQueryResult).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
|
||||||
|
return bnf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DB) GetByPhoneNumber(ctx context.Context, phoneNumber string) (entity.Benefactor, error) {
|
||||||
|
const op = "mysqlbenefactor.GetByPhoneNumber"
|
||||||
|
|
||||||
|
query := `select * from benefactors where phone_number = ?`
|
||||||
|
//nolint
|
||||||
|
stmt, err := d.conn.PrepareStatement(ctx, mysql.StatementKeyBenefactorGetByPhoneNumber, query)
|
||||||
|
if err != nil {
|
||||||
|
return entity.Benefactor{}, richerror.New(op).WithErr(err).
|
||||||
|
WithMessage(errmsg.ErrorMsgCantPrepareStatement).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
|
||||||
|
row := stmt.QueryRowContext(ctx, phoneNumber)
|
||||||
|
bnf, err := scanBenefactor(row)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return entity.Benefactor{}, richerror.New(op).WithKind(richerror.KindNotFound).
|
||||||
|
WithMessage(errmsg.ErrorMsgNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
return entity.Benefactor{}, richerror.New(op).WithErr(err).
|
||||||
|
WithMessage(errmsg.ErrorMsgCantScanQueryResult).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
|
||||||
|
return bnf, nil
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package mysqlbenefactor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func scanBenefactor(scanner mysql.Scanner) (entity.Benefactor, error) {
|
||||||
|
var createdAt, updatedAt time.Time
|
||||||
|
var benefactor entity.Benefactor
|
||||||
|
// TODO - use db model and mapper between entity and db model OR use this approach
|
||||||
|
|
||||||
|
var benefactorNullableFields nullableFields
|
||||||
|
|
||||||
|
err := scanner.Scan(&benefactor.ID, &benefactorNullableFields.firstName,
|
||||||
|
&benefactorNullableFields.lastName, &benefactor.PhoneNumber, &benefactorNullableFields.description,
|
||||||
|
&benefactorNullableFields.email, &benefactorNullableFields.genderStr,
|
||||||
|
&benefactorNullableFields.birthdate, &createdAt, &updatedAt, &benefactor.Status)
|
||||||
|
|
||||||
|
mapNotNullToBenefactor(benefactorNullableFields, &benefactor)
|
||||||
|
|
||||||
|
return benefactor, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type nullableFields struct {
|
||||||
|
firstName sql.NullString
|
||||||
|
lastName sql.NullString
|
||||||
|
description sql.NullString
|
||||||
|
email sql.NullString
|
||||||
|
genderStr sql.NullString
|
||||||
|
birthdate sql.NullTime
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO - find the other solution.
|
||||||
|
func mapNotNullToBenefactor(data nullableFields, benefactor *entity.Benefactor) {
|
||||||
|
if data.firstName.Valid {
|
||||||
|
benefactor.FirstName = data.firstName.String
|
||||||
|
}
|
||||||
|
if data.lastName.Valid {
|
||||||
|
benefactor.LastName = data.lastName.String
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.description.Valid {
|
||||||
|
benefactor.Description = data.description.String
|
||||||
|
}
|
||||||
|
if data.email.Valid {
|
||||||
|
benefactor.Email = data.email.String
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.genderStr.Valid {
|
||||||
|
benefactor.Gender = entity.Gender(data.genderStr.String)
|
||||||
|
}
|
||||||
|
if data.birthdate.Valid {
|
||||||
|
benefactor.BirthDate = data.birthdate.Time
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
-- +migrate Up
|
||||||
|
ALTER TABLE `benefactors` ADD COLUMN `status` ENUM('active','inactive') NOT NULL DEFAULT 'active';
|
||||||
|
|
||||||
|
-- +migrate Down
|
||||||
|
ALTER TABLE `benefactors` DROP COLUMN `status`;
|
|
@ -22,8 +22,8 @@ const (
|
||||||
StatementKeyAdminGetByID
|
StatementKeyAdminGetByID
|
||||||
StatementKeyAdminGetByPhoneNumber
|
StatementKeyAdminGetByPhoneNumber
|
||||||
StatementKeyAdminAgentGetAll
|
StatementKeyAdminAgentGetAll
|
||||||
StatementKeyBenefactorIsExistByID
|
StatementKeyBenefactorGetByID
|
||||||
StatementKeyBenefactorIsExistByPhoneNumber
|
StatementKeyBenefactorGetByPhoneNumber
|
||||||
StatementKeyBenefactorCreate
|
StatementKeyBenefactorCreate
|
||||||
StatementKeyKindBoxAdd
|
StatementKeyKindBoxAdd
|
||||||
StatementKeyKindBoxAssignReceiverAgent
|
StatementKeyKindBoxAssignReceiverAgent
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
package adminservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
|
adminserviceparam "git.gocasts.ir/ebhomengo/niki/param/admin/admin"
|
||||||
|
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
||||||
|
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s Service) RefreshAccess(ctx context.Context, req adminserviceparam.RefreshAccessRequest) (adminserviceparam.RefreshAccessResponse, error) {
|
||||||
|
const op = "adminservice.RefreshAccess"
|
||||||
|
claims, err := s.auth.ParseRefreshToken(req.RefreshToken)
|
||||||
|
if err != nil {
|
||||||
|
return adminserviceparam.RefreshAccessResponse{}, richerror.New(op).WithKind(richerror.KindInvalid).WithMessage(errmsg.ErrorMsgInvalidOrExpiredJwt)
|
||||||
|
}
|
||||||
|
|
||||||
|
admin, err := s.repo.GetAdminByID(ctx, claims.UserID)
|
||||||
|
if err != nil {
|
||||||
|
return adminserviceparam.RefreshAccessResponse{}, richerror.New(op).WithKind(richerror.KindUnexpected).WithErr(err)
|
||||||
|
}
|
||||||
|
if admin.Status == entity.AdminInactiveStatus {
|
||||||
|
return adminserviceparam.RefreshAccessResponse{}, richerror.New(op).WithKind(richerror.KindForbidden).WithMessage(errmsg.ErrorMsgAdminNotAllowed)
|
||||||
|
}
|
||||||
|
|
||||||
|
accessToken, err := s.auth.CreateAccessToken(entity.Authenticable{
|
||||||
|
ID: claims.UserID,
|
||||||
|
Role: claims.Role,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return adminserviceparam.RefreshAccessResponse{}, richerror.New(op).WithKind(richerror.KindUnexpected).WithErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adminserviceparam.RefreshAccessResponse{AccessToken: accessToken}, nil
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ package adminservice
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/service/auth"
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/config"
|
"git.gocasts.ir/ebhomengo/niki/config"
|
||||||
"git.gocasts.ir/ebhomengo/niki/entity"
|
"git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
|
@ -10,9 +11,10 @@ import (
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AuthGenerator interface {
|
type AuthService interface {
|
||||||
CreateAccessToken(admin entity.Authenticable) (string, error)
|
CreateAccessToken(admin entity.Authenticable) (string, error)
|
||||||
CreateRefreshToken(admin entity.Authenticable) (string, error)
|
CreateRefreshToken(admin entity.Authenticable) (string, error)
|
||||||
|
ParseRefreshToken(refreshToken string) (*auth.Claims, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Repository interface {
|
type Repository interface {
|
||||||
|
@ -23,11 +25,11 @@ type Repository interface {
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
repo Repository
|
repo Repository
|
||||||
auth AuthGenerator
|
auth AuthService
|
||||||
vld validator.Validator
|
vld validator.Validator
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(repo Repository, auth AuthGenerator, vld validator.Validator) Service {
|
func New(repo Repository, auth AuthService, vld validator.Validator) Service {
|
||||||
return Service{
|
return Service{
|
||||||
repo: repo,
|
repo: repo,
|
||||||
auth: auth,
|
auth: auth,
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
|
"github.com/golang-jwt/jwt/v4"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s Service) CreateAccessToken(user entity.Authenticable) (string, error) {
|
||||||
|
return s.createToken(user.ID, user.Role, s.Config.AccessSubject, s.Config.AccessExpirationTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Service) CreateRefreshToken(user entity.Authenticable) (string, error) {
|
||||||
|
return s.createToken(user.ID, user.Role, s.Config.RefreshSubject, s.Config.RefreshExpirationTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Service) createToken(userID uint, role, subject string, expireDuration time.Duration) (string, error) {
|
||||||
|
// create a signer for rsa 256
|
||||||
|
// TODO - replace with rsa 256 RS256 - https://github.com/golang-jwt/jwt/blob/main/http_example_test.go
|
||||||
|
|
||||||
|
// set our claims
|
||||||
|
claims := Claims{
|
||||||
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
|
Subject: subject,
|
||||||
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(expireDuration)),
|
||||||
|
},
|
||||||
|
UserID: userID,
|
||||||
|
Role: role,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO - add sign method to config
|
||||||
|
accessToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
tokenString, err := accessToken.SignedString([]byte(s.Config.SignKey))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokenString, nil
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
||||||
|
"github.com/golang-jwt/jwt/v4"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s Service) ParseBearerToken(bearerToken string) (*Claims, error) {
|
||||||
|
tokenStr := strings.Replace(bearerToken, "Bearer ", "", 1)
|
||||||
|
|
||||||
|
return s.parseToken(tokenStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Service) ParseRefreshToken(refreshToken string) (*Claims, error) {
|
||||||
|
claims, err := s.parseToken(refreshToken)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if claims.Subject != s.Config.RefreshSubject {
|
||||||
|
return nil, fmt.Errorf(errmsg.ErrorMsgInvalidRefreshToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
return claims, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Service) parseToken(token string) (*Claims, error) {
|
||||||
|
// https://pkg.go.dev/github.com/golang-jwt/jwt/v5#example-ParseWithClaims-CustomClaimsType
|
||||||
|
t, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
|
||||||
|
return []byte(s.Config.SignKey), nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if claims, ok := t.Claims.(*Claims); ok && t.Valid {
|
||||||
|
return claims, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
}
|
|
@ -1,11 +1,7 @@
|
||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/entity"
|
|
||||||
"github.com/golang-jwt/jwt/v4"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
@ -25,54 +21,3 @@ func New(cfg Config) Service {
|
||||||
Config: cfg,
|
Config: cfg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Service) CreateAccessToken(user entity.Authenticable) (string, error) {
|
|
||||||
return s.createToken(user.ID, user.Role, s.Config.AccessSubject, s.Config.AccessExpirationTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Service) CreateRefreshToken(user entity.Authenticable) (string, error) {
|
|
||||||
return s.createToken(user.ID, user.Role, s.Config.RefreshSubject, s.Config.RefreshExpirationTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Service) ParseToken(bearerToken string) (*Claims, error) {
|
|
||||||
// https://pkg.go.dev/github.com/golang-jwt/jwt/v5#example-ParseWithClaims-CustomClaimsType
|
|
||||||
|
|
||||||
tokenStr := strings.Replace(bearerToken, "Bearer ", "", 1)
|
|
||||||
|
|
||||||
token, err := jwt.ParseWithClaims(tokenStr, &Claims{}, func(token *jwt.Token) (interface{}, error) {
|
|
||||||
return []byte(s.Config.SignKey), nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
|
|
||||||
return claims, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Service) createToken(userID uint, role, subject string, expireDuration time.Duration) (string, error) {
|
|
||||||
// create a signer for rsa 256
|
|
||||||
// TODO - replace with rsa 256 RS256 - https://github.com/golang-jwt/jwt/blob/main/http_example_test.go
|
|
||||||
|
|
||||||
// set our claims
|
|
||||||
claims := Claims{
|
|
||||||
RegisteredClaims: jwt.RegisteredClaims{
|
|
||||||
Subject: subject,
|
|
||||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(expireDuration)),
|
|
||||||
},
|
|
||||||
UserID: userID,
|
|
||||||
Role: role,
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO - add sign method to config
|
|
||||||
accessToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
|
||||||
tokenString, err := accessToken.SignedString([]byte(s.Config.SignKey))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return tokenString, nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
package benefactorservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
|
benefactorparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/benefactor"
|
||||||
|
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
||||||
|
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s Service) RefreshAccess(ctx context.Context, req benefactorparam.RefreshAccessRequest) (benefactorparam.RefreshAccessResponse, error) {
|
||||||
|
const op = "adminservice.RefreshAccess"
|
||||||
|
claims, err := s.auth.ParseRefreshToken(req.RefreshToken)
|
||||||
|
if err != nil {
|
||||||
|
return benefactorparam.RefreshAccessResponse{}, richerror.New(op).WithKind(richerror.KindInvalid).WithMessage(errmsg.ErrorMsgInvalidOrExpiredJwt)
|
||||||
|
}
|
||||||
|
|
||||||
|
benefactor, err := s.repo.GetByID(ctx, claims.UserID)
|
||||||
|
if err != nil {
|
||||||
|
return benefactorparam.RefreshAccessResponse{}, richerror.New(op).WithKind(richerror.KindUnexpected).WithErr(err)
|
||||||
|
}
|
||||||
|
if benefactor.Status == entity.BenefactorInactiveStatus {
|
||||||
|
return benefactorparam.RefreshAccessResponse{}, richerror.New(op).WithKind(richerror.KindForbidden).WithMessage(errmsg.ErrorMsgUserNotAllowed)
|
||||||
|
}
|
||||||
|
|
||||||
|
accessToken, err := s.auth.CreateAccessToken(entity.Authenticable{
|
||||||
|
ID: claims.UserID,
|
||||||
|
Role: claims.Role,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return benefactorparam.RefreshAccessResponse{}, richerror.New(op).WithKind(richerror.KindUnexpected).WithErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return benefactorparam.RefreshAccessResponse{AccessToken: accessToken}, nil
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ import (
|
||||||
|
|
||||||
func (s Service) SendOtp(ctx context.Context, req benefactoreparam.SendOtpRequest) (benefactoreparam.SendOtpResponse, error) {
|
func (s Service) SendOtp(ctx context.Context, req benefactoreparam.SendOtpRequest) (benefactoreparam.SendOtpResponse, error) {
|
||||||
const op = "benefactorservice.SendOtp"
|
const op = "benefactorservice.SendOtp"
|
||||||
if fieldErrors, vErr := s.vld.ValidateSendOtpRequest(req); vErr != nil {
|
if fieldErrors, vErr := s.vld.ValidateSendOtpRequest(ctx, req); vErr != nil {
|
||||||
return benefactoreparam.SendOtpResponse{FieldErrors: fieldErrors}, richerror.New(op).WithErr(vErr)
|
return benefactoreparam.SendOtpResponse{FieldErrors: fieldErrors}, richerror.New(op).WithErr(vErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package benefactorservice
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/service/auth"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
smscontract "git.gocasts.ir/ebhomengo/niki/contract/sms"
|
smscontract "git.gocasts.ir/ebhomengo/niki/contract/sms"
|
||||||
|
@ -22,9 +23,10 @@ type Repository interface {
|
||||||
GetByID(ctx context.Context, benefactorID uint) (entity.Benefactor, error)
|
GetByID(ctx context.Context, benefactorID uint) (entity.Benefactor, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthGenerator interface {
|
type AuthService interface {
|
||||||
CreateAccessToken(benefactor entity.Authenticable) (string, error)
|
CreateAccessToken(admin entity.Authenticable) (string, error)
|
||||||
CreateRefreshToken(benefactor entity.Authenticable) (string, error)
|
CreateRefreshToken(admin entity.Authenticable) (string, error)
|
||||||
|
ParseRefreshToken(refreshToken string) (*auth.Claims, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type RedisOtp interface {
|
type RedisOtp interface {
|
||||||
|
@ -38,13 +40,13 @@ type Service struct {
|
||||||
config Config
|
config Config
|
||||||
redisOtp RedisOtp
|
redisOtp RedisOtp
|
||||||
smsAdapter smscontract.SmsAdapter
|
smsAdapter smscontract.SmsAdapter
|
||||||
auth AuthGenerator
|
auth AuthService
|
||||||
repo Repository
|
repo Repository
|
||||||
vld benefactorvalidator.Validator
|
vld benefactorvalidator.Validator
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg Config, redisOtp RedisOtp, smsAdapter smscontract.SmsAdapter,
|
func New(cfg Config, redisOtp RedisOtp, smsAdapter smscontract.SmsAdapter,
|
||||||
auth AuthGenerator, repo Repository, vld benefactorvalidator.Validator,
|
auth AuthService, repo Repository, vld benefactorvalidator.Validator,
|
||||||
) Service {
|
) Service {
|
||||||
return Service{
|
return Service{
|
||||||
config: cfg,
|
config: cfg,
|
||||||
|
|
|
@ -89,7 +89,7 @@ func New(cfg config.Config, db *mysql.DB, rds *redis.Adapter, smsAdapter smscont
|
||||||
BenefactorAuthSvc = auth.New(cfg.BenefactorAuth)
|
BenefactorAuthSvc = auth.New(cfg.BenefactorAuth)
|
||||||
BenefactorReferTimeSvc = benefactorrefertimeservice.New(referTimeRepo)
|
BenefactorReferTimeSvc = benefactorrefertimeservice.New(referTimeRepo)
|
||||||
|
|
||||||
BenefactorVld = benefactorvalidator.New()
|
BenefactorVld = benefactorvalidator.New(benefactorRepo)
|
||||||
BenefactorSvc = benefactorservice.New(cfg.BenefactorSvc, redisOtp, smsAdapter, BenefactorAuthSvc, benefactorRepo, BenefactorVld)
|
BenefactorSvc = benefactorservice.New(cfg.BenefactorSvc, redisOtp, smsAdapter, BenefactorAuthSvc, benefactorRepo, BenefactorVld)
|
||||||
BenefactorAddressVld = benefactoraddressvalidator.New(BenefactorSvc, addressRepo)
|
BenefactorAddressVld = benefactoraddressvalidator.New(BenefactorSvc, addressRepo)
|
||||||
BenefactorAddressSvc = benefactoraddressservice.New(addressRepo, BenefactorAddressVld)
|
BenefactorAddressSvc = benefactoraddressservice.New(addressRepo, BenefactorAddressVld)
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (v Validator) ValidateLoginWithPhoneNumberRequest(ctx context.Context, req adminserviceparam.LoginWithPhoneNumberRequest) (map[string]string, error) {
|
func (v Validator) ValidateLoginWithPhoneNumberRequest(ctx context.Context, req adminserviceparam.LoginWithPhoneNumberRequest) (map[string]string, error) {
|
||||||
const op = "adminvalidator.ValidateRegisterRequest"
|
const op = "adminvalidator.ValidateLoginWithPhoneNumberRequest"
|
||||||
|
|
||||||
if err := validation.ValidateStruct(&req,
|
if err := validation.ValidateStruct(&req,
|
||||||
// TODO - add regex
|
// TODO - add regex
|
||||||
|
@ -22,7 +22,9 @@ func (v Validator) ValidateLoginWithPhoneNumberRequest(ctx context.Context, req
|
||||||
validation.Field(&req.PhoneNumber,
|
validation.Field(&req.PhoneNumber,
|
||||||
validation.Required,
|
validation.Required,
|
||||||
validation.Match(regexp.MustCompile(phoneNumberRegex)).Error(errmsg.ErrorMsgPhoneNumberIsNotValid),
|
validation.Match(regexp.MustCompile(phoneNumberRegex)).Error(errmsg.ErrorMsgPhoneNumberIsNotValid),
|
||||||
validation.By(v.doesAdminExistByPhoneNumber(ctx)))); err != nil {
|
validation.By(v.doesAdminExistByPhoneNumber(ctx)),
|
||||||
|
validation.By(v.isAdminAllowed(ctx)),
|
||||||
|
)); err != nil {
|
||||||
fieldErrors := make(map[string]string)
|
fieldErrors := make(map[string]string)
|
||||||
|
|
||||||
vErr := validation.Errors{}
|
vErr := validation.Errors{}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package adminvalidator
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
adminserviceparam "git.gocasts.ir/ebhomengo/niki/param/admin/admin"
|
adminserviceparam "git.gocasts.ir/ebhomengo/niki/param/admin/admin"
|
||||||
|
@ -23,7 +24,10 @@ func TestValidateLoginWithPhoneNumberRequest(t *testing.T) {
|
||||||
Password: validPassword,
|
Password: validPassword,
|
||||||
}
|
}
|
||||||
|
|
||||||
mockRepo.EXPECT().AdminExistByPhoneNumber(ctx, validPhoneNumber).Return(true, nil).Once()
|
mockRepo.EXPECT().AdminExistByPhoneNumber(ctx, req.PhoneNumber).Return(true, nil).Once()
|
||||||
|
mockRepo.EXPECT().GetAdminByPhoneNumber(ctx, req.PhoneNumber).Return(entity.Admin{
|
||||||
|
Status: entity.AdminActiveStatus,
|
||||||
|
}, nil).Once()
|
||||||
|
|
||||||
fieldErrors, err := validator.ValidateLoginWithPhoneNumberRequest(ctx, req)
|
fieldErrors, err := validator.ValidateLoginWithPhoneNumberRequest(ctx, req)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -48,7 +52,10 @@ func TestValidateLoginWithPhoneNumberRequest(t *testing.T) {
|
||||||
Password: "",
|
Password: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
mockRepo.EXPECT().AdminExistByPhoneNumber(ctx, validPhoneNumber).Return(true, nil).Once()
|
mockRepo.EXPECT().AdminExistByPhoneNumber(ctx, req.PhoneNumber).Return(true, nil).Once()
|
||||||
|
mockRepo.EXPECT().GetAdminByPhoneNumber(ctx, req.PhoneNumber).Return(entity.Admin{
|
||||||
|
Status: entity.AdminActiveStatus,
|
||||||
|
}, nil).Once()
|
||||||
|
|
||||||
fieldErrors, err := validator.ValidateLoginWithPhoneNumberRequest(ctx, req)
|
fieldErrors, err := validator.ValidateLoginWithPhoneNumberRequest(ctx, req)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
@ -74,7 +81,10 @@ func TestValidateLoginWithPhoneNumberRequest(t *testing.T) {
|
||||||
Password: "short",
|
Password: "short",
|
||||||
}
|
}
|
||||||
|
|
||||||
mockRepo.EXPECT().AdminExistByPhoneNumber(ctx, validPhoneNumber).Return(true, nil).Once()
|
mockRepo.EXPECT().AdminExistByPhoneNumber(ctx, req.PhoneNumber).Return(true, nil).Once()
|
||||||
|
mockRepo.EXPECT().GetAdminByPhoneNumber(ctx, req.PhoneNumber).Return(entity.Admin{
|
||||||
|
Status: entity.AdminActiveStatus,
|
||||||
|
}, nil).Once()
|
||||||
|
|
||||||
fieldErrors, err := validator.ValidateLoginWithPhoneNumberRequest(ctx, req)
|
fieldErrors, err := validator.ValidateLoginWithPhoneNumberRequest(ctx, req)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
@ -88,7 +98,7 @@ func TestValidateLoginWithPhoneNumberRequest(t *testing.T) {
|
||||||
Password: validPassword,
|
Password: validPassword,
|
||||||
}
|
}
|
||||||
|
|
||||||
mockRepo.EXPECT().AdminExistByPhoneNumber(ctx, validPhoneNumber).Return(false, nil).Once()
|
mockRepo.EXPECT().AdminExistByPhoneNumber(ctx, req.PhoneNumber).Return(false, nil).Once()
|
||||||
|
|
||||||
fieldErrors, err := validator.ValidateLoginWithPhoneNumberRequest(ctx, req)
|
fieldErrors, err := validator.ValidateLoginWithPhoneNumberRequest(ctx, req)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
@ -102,11 +112,28 @@ func TestValidateLoginWithPhoneNumberRequest(t *testing.T) {
|
||||||
Password: validPassword,
|
Password: validPassword,
|
||||||
}
|
}
|
||||||
|
|
||||||
mockRepo.EXPECT().AdminExistByPhoneNumber(ctx, validPhoneNumber).Return(false, errors.New("repo error")).Once()
|
mockRepo.EXPECT().AdminExistByPhoneNumber(ctx, req.PhoneNumber).Return(false, errors.New("repo error")).Once()
|
||||||
|
|
||||||
fieldErrors, err := validator.ValidateLoginWithPhoneNumberRequest(ctx, req)
|
fieldErrors, err := validator.ValidateLoginWithPhoneNumberRequest(ctx, req)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.NotNil(t, fieldErrors)
|
assert.NotNil(t, fieldErrors)
|
||||||
assert.Equal(t, errmsg.ErrorMsgSomethingWentWrong, fieldErrors["phone_number"])
|
assert.Equal(t, errmsg.ErrorMsgSomethingWentWrong, fieldErrors["phone_number"])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Inactive admin is not allowed", func(t *testing.T) {
|
||||||
|
req := adminserviceparam.LoginWithPhoneNumberRequest{
|
||||||
|
PhoneNumber: validPhoneNumber,
|
||||||
|
Password: validPassword,
|
||||||
|
}
|
||||||
|
|
||||||
|
mockRepo.EXPECT().AdminExistByPhoneNumber(ctx, req.PhoneNumber).Return(true, nil).Once()
|
||||||
|
mockRepo.EXPECT().GetAdminByPhoneNumber(ctx, req.PhoneNumber).Return(entity.Admin{
|
||||||
|
Status: entity.AdminInactiveStatus,
|
||||||
|
}, nil).Once()
|
||||||
|
|
||||||
|
fieldErrors, err := validator.ValidateLoginWithPhoneNumberRequest(ctx, req)
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.NotNil(t, fieldErrors)
|
||||||
|
assert.Equal(t, errmsg.ErrorMsgAdminNotAllowed, fieldErrors["phone_number"])
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
// Code generated by mockery v2.41.0. DO NOT EDIT.
|
// Code generated by mockery v2.45.1. DO NOT EDIT.
|
||||||
|
|
||||||
package adminvalidator
|
package adminvalidator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
context "context"
|
context "context"
|
||||||
|
|
||||||
|
entity "git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
mock "github.com/stretchr/testify/mock"
|
mock "github.com/stretchr/testify/mock"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -135,6 +136,63 @@ func (_c *MockRepository_AdminExistByPhoneNumber_Call) RunAndReturn(run func(con
|
||||||
return _c
|
return _c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAdminByPhoneNumber provides a mock function with given fields: ctx, phoneNumber
|
||||||
|
func (_m *MockRepository) GetAdminByPhoneNumber(ctx context.Context, phoneNumber string) (entity.Admin, error) {
|
||||||
|
ret := _m.Called(ctx, phoneNumber)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for GetAdminByPhoneNumber")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 entity.Admin
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(context.Context, string) (entity.Admin, error)); ok {
|
||||||
|
return rf(ctx, phoneNumber)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(context.Context, string) entity.Admin); ok {
|
||||||
|
r0 = rf(ctx, phoneNumber)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Get(0).(entity.Admin)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||||
|
r1 = rf(ctx, phoneNumber)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockRepository_GetAdminByPhoneNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAdminByPhoneNumber'
|
||||||
|
type MockRepository_GetAdminByPhoneNumber_Call struct {
|
||||||
|
*mock.Call
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAdminByPhoneNumber is a helper method to define mock.On call
|
||||||
|
// - ctx context.Context
|
||||||
|
// - phoneNumber string
|
||||||
|
func (_e *MockRepository_Expecter) GetAdminByPhoneNumber(ctx interface{}, phoneNumber interface{}) *MockRepository_GetAdminByPhoneNumber_Call {
|
||||||
|
return &MockRepository_GetAdminByPhoneNumber_Call{Call: _e.mock.On("GetAdminByPhoneNumber", ctx, phoneNumber)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockRepository_GetAdminByPhoneNumber_Call) Run(run func(ctx context.Context, phoneNumber string)) *MockRepository_GetAdminByPhoneNumber_Call {
|
||||||
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
|
run(args[0].(context.Context), args[1].(string))
|
||||||
|
})
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockRepository_GetAdminByPhoneNumber_Call) Return(_a0 entity.Admin, _a1 error) *MockRepository_GetAdminByPhoneNumber_Call {
|
||||||
|
_c.Call.Return(_a0, _a1)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockRepository_GetAdminByPhoneNumber_Call) RunAndReturn(run func(context.Context, string) (entity.Admin, error)) *MockRepository_GetAdminByPhoneNumber_Call {
|
||||||
|
_c.Call.Return(run)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
// NewMockRepository creates a new instance of MockRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
// NewMockRepository creates a new instance of MockRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||||
// The first argument is typically a *testing.T value.
|
// The first argument is typically a *testing.T value.
|
||||||
func NewMockRepository(t interface {
|
func NewMockRepository(t interface {
|
||||||
|
|
|
@ -3,7 +3,6 @@ package adminvalidator
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/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"
|
||||||
validation "github.com/go-ozzo/ozzo-validation/v4"
|
validation "github.com/go-ozzo/ozzo-validation/v4"
|
||||||
|
@ -23,6 +22,7 @@ const (
|
||||||
type Repository interface {
|
type Repository interface {
|
||||||
AdminExistByPhoneNumber(ctx context.Context, phoneNumber string) (bool, error)
|
AdminExistByPhoneNumber(ctx context.Context, phoneNumber string) (bool, error)
|
||||||
AdminExistByEmail(ctx context.Context, email string) (bool, error)
|
AdminExistByEmail(ctx context.Context, email string) (bool, error)
|
||||||
|
GetAdminByPhoneNumber(ctx context.Context, phoneNumber string) (entity.Admin, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Validator struct {
|
type Validator struct {
|
||||||
|
@ -33,6 +33,24 @@ func New(repo Repository) Validator {
|
||||||
return Validator{repo: repo}
|
return Validator{repo: repo}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v Validator) isAdminAllowed(ctx context.Context) func(interface{}) error {
|
||||||
|
return func(value interface{}) error {
|
||||||
|
phoneNumber, ok := value.(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong)
|
||||||
|
}
|
||||||
|
admin, err := v.repo.GetAdminByPhoneNumber(ctx, phoneNumber)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong)
|
||||||
|
}
|
||||||
|
if admin.Status == entity.AdminInactiveStatus {
|
||||||
|
return fmt.Errorf(errmsg.ErrorMsgAdminNotAllowed)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (v Validator) doesAdminExistByPhoneNumber(ctx context.Context) validation.RuleFunc {
|
func (v Validator) doesAdminExistByPhoneNumber(ctx context.Context) validation.RuleFunc {
|
||||||
return func(value interface{}) error {
|
return func(value interface{}) error {
|
||||||
phoneNumber, ok := value.(string)
|
phoneNumber, ok := value.(string)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by mockery v2.45.0. DO NOT EDIT.
|
// Code generated by mockery v2.45.1. DO NOT EDIT.
|
||||||
|
|
||||||
package adminkindboxvalidator
|
package adminkindboxvalidator
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by mockery v2.45.0. DO NOT EDIT.
|
// Code generated by mockery v2.45.1. DO NOT EDIT.
|
||||||
|
|
||||||
package adminkindboxvalidator
|
package adminkindboxvalidator
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by mockery v2.45.0. DO NOT EDIT.
|
// Code generated by mockery v2.45.1. DO NOT EDIT.
|
||||||
|
|
||||||
package adminkindboxvalidator
|
package adminkindboxvalidator
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by mockery v2.45.0. DO NOT EDIT.
|
// Code generated by mockery v2.45.1. DO NOT EDIT.
|
||||||
|
|
||||||
package adminkindboxvalidator
|
package adminkindboxvalidator
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by mockery v2.45.0. DO NOT EDIT.
|
// Code generated by mockery v2.45.1. DO NOT EDIT.
|
||||||
|
|
||||||
package adminkindboxvalidator
|
package adminkindboxvalidator
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by mockery v2.41.0. DO NOT EDIT.
|
// Code generated by mockery v2.45.1. DO NOT EDIT.
|
||||||
|
|
||||||
package benefactoraddressvalidator
|
package benefactoraddressvalidator
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import (
|
||||||
context "context"
|
context "context"
|
||||||
|
|
||||||
benefactoreparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/benefactor"
|
benefactoreparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/benefactor"
|
||||||
|
|
||||||
mock "github.com/stretchr/testify/mock"
|
mock "github.com/stretchr/testify/mock"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by mockery v2.41.0. DO NOT EDIT.
|
// Code generated by mockery v2.45.1. DO NOT EDIT.
|
||||||
|
|
||||||
package benefactoraddressvalidator
|
package benefactoraddressvalidator
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestValidator_ValidateLoginRegisterRequest(t *testing.T) {
|
func TestValidator_ValidateLoginRegisterRequest(t *testing.T) {
|
||||||
validator := New()
|
mockRepository := NewMockRepository(t)
|
||||||
|
validator := New(mockRepository)
|
||||||
validPhoneNumber := "09123456789"
|
validPhoneNumber := "09123456789"
|
||||||
|
|
||||||
t.Run("Valid request", func(t *testing.T) {
|
t.Run("Valid request", func(t *testing.T) {
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
// Code generated by mockery v2.45.1. DO NOT EDIT.
|
||||||
|
|
||||||
|
package benefactorvalidator
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
|
||||||
|
entity "git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
|
mock "github.com/stretchr/testify/mock"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockRepository is an autogenerated mock type for the Repository type
|
||||||
|
type MockRepository struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
type MockRepository_Expecter struct {
|
||||||
|
mock *mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_m *MockRepository) EXPECT() *MockRepository_Expecter {
|
||||||
|
return &MockRepository_Expecter{mock: &_m.Mock}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByPhoneNumber provides a mock function with given fields: ctx, phoneNumber
|
||||||
|
func (_m *MockRepository) GetByPhoneNumber(ctx context.Context, phoneNumber string) (entity.Benefactor, error) {
|
||||||
|
ret := _m.Called(ctx, phoneNumber)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for GetByPhoneNumber")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 entity.Benefactor
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(context.Context, string) (entity.Benefactor, error)); ok {
|
||||||
|
return rf(ctx, phoneNumber)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(context.Context, string) entity.Benefactor); ok {
|
||||||
|
r0 = rf(ctx, phoneNumber)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Get(0).(entity.Benefactor)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||||
|
r1 = rf(ctx, phoneNumber)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockRepository_GetByPhoneNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetByPhoneNumber'
|
||||||
|
type MockRepository_GetByPhoneNumber_Call struct {
|
||||||
|
*mock.Call
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByPhoneNumber is a helper method to define mock.On call
|
||||||
|
// - ctx context.Context
|
||||||
|
// - phoneNumber string
|
||||||
|
func (_e *MockRepository_Expecter) GetByPhoneNumber(ctx interface{}, phoneNumber interface{}) *MockRepository_GetByPhoneNumber_Call {
|
||||||
|
return &MockRepository_GetByPhoneNumber_Call{Call: _e.mock.On("GetByPhoneNumber", ctx, phoneNumber)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockRepository_GetByPhoneNumber_Call) Run(run func(ctx context.Context, phoneNumber string)) *MockRepository_GetByPhoneNumber_Call {
|
||||||
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
|
run(args[0].(context.Context), args[1].(string))
|
||||||
|
})
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockRepository_GetByPhoneNumber_Call) Return(_a0 entity.Benefactor, _a1 error) *MockRepository_GetByPhoneNumber_Call {
|
||||||
|
_c.Call.Return(_a0, _a1)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *MockRepository_GetByPhoneNumber_Call) RunAndReturn(run func(context.Context, string) (entity.Benefactor, error)) *MockRepository_GetByPhoneNumber_Call {
|
||||||
|
_c.Call.Return(run)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMockRepository creates a new instance of MockRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||||
|
// The first argument is typically a *testing.T value.
|
||||||
|
func NewMockRepository(t interface {
|
||||||
|
mock.TestingT
|
||||||
|
Cleanup(func())
|
||||||
|
}) *MockRepository {
|
||||||
|
mock := &MockRepository{}
|
||||||
|
mock.Mock.Test(t)
|
||||||
|
|
||||||
|
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||||
|
|
||||||
|
return mock
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package benefactorvalidator
|
package benefactorvalidator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
|
@ -10,13 +11,15 @@ import (
|
||||||
validation "github.com/go-ozzo/ozzo-validation/v4"
|
validation "github.com/go-ozzo/ozzo-validation/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (v Validator) ValidateSendOtpRequest(req benefactoreparam.SendOtpRequest) (map[string]string, error) {
|
func (v Validator) ValidateSendOtpRequest(ctx context.Context, req benefactoreparam.SendOtpRequest) (map[string]string, error) {
|
||||||
const op = "benefactorvalidator.ValidateSendOtpRequest"
|
const op = "benefactorvalidator.ValidateSendOtpRequest"
|
||||||
|
|
||||||
if err := validation.ValidateStruct(&req,
|
if err := validation.ValidateStruct(&req,
|
||||||
validation.Field(&req.PhoneNumber,
|
validation.Field(&req.PhoneNumber,
|
||||||
validation.Required,
|
validation.Required,
|
||||||
validation.Match(regexp.MustCompile(phoneNumberRegex)).Error(errmsg.ErrorMsgPhoneNumberIsNotValid))); err != nil {
|
validation.Match(regexp.MustCompile(phoneNumberRegex)).Error(errmsg.ErrorMsgPhoneNumberIsNotValid),
|
||||||
|
validation.By(v.isBenefactorAllowed(ctx)),
|
||||||
|
)); err != nil {
|
||||||
fieldErrors := make(map[string]string)
|
fieldErrors := make(map[string]string)
|
||||||
|
|
||||||
vErr := validation.Errors{}
|
vErr := validation.Errors{}
|
||||||
|
|
|
@ -1,23 +1,32 @@
|
||||||
package benefactorvalidator
|
package benefactorvalidator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"context"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
benefactoreparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/benefactor"
|
benefactoreparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/benefactor"
|
||||||
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"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestValidator_ValidateSendOtpRequest(t *testing.T) {
|
func TestValidator_ValidateSendOtpRequest(t *testing.T) {
|
||||||
validator := New()
|
mockRepository := NewMockRepository(t)
|
||||||
|
validator := New(mockRepository)
|
||||||
|
|
||||||
validPhoneNumber := "09123456789"
|
validPhoneNumber := "09123456789"
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
t.Run("Valid request", func(t *testing.T) {
|
t.Run("Valid request", func(t *testing.T) {
|
||||||
req := benefactoreparam.SendOtpRequest{
|
req := benefactoreparam.SendOtpRequest{
|
||||||
PhoneNumber: validPhoneNumber,
|
PhoneNumber: validPhoneNumber,
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldErrors, err := validator.ValidateSendOtpRequest(req)
|
mockRepository.EXPECT().GetByPhoneNumber(ctx, req.PhoneNumber).Return(entity.Benefactor{
|
||||||
|
Status: entity.BenefactorActiveStatus,
|
||||||
|
}, nil).Once()
|
||||||
|
|
||||||
|
fieldErrors, err := validator.ValidateSendOtpRequest(ctx, req)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Nil(t, fieldErrors)
|
assert.Nil(t, fieldErrors)
|
||||||
})
|
})
|
||||||
|
@ -27,7 +36,7 @@ func TestValidator_ValidateSendOtpRequest(t *testing.T) {
|
||||||
PhoneNumber: "",
|
PhoneNumber: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldErrors, err := validator.ValidateSendOtpRequest(req)
|
fieldErrors, err := validator.ValidateSendOtpRequest(ctx, req)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.NotNil(t, fieldErrors)
|
assert.NotNil(t, fieldErrors)
|
||||||
assert.Contains(t, fieldErrors, "phone_number")
|
assert.Contains(t, fieldErrors, "phone_number")
|
||||||
|
@ -38,9 +47,37 @@ func TestValidator_ValidateSendOtpRequest(t *testing.T) {
|
||||||
PhoneNumber: "12345",
|
PhoneNumber: "12345",
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldErrors, err := validator.ValidateSendOtpRequest(req)
|
fieldErrors, err := validator.ValidateSendOtpRequest(ctx, req)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.NotNil(t, fieldErrors)
|
assert.NotNil(t, fieldErrors)
|
||||||
assert.Equal(t, errmsg.ErrorMsgPhoneNumberIsNotValid, fieldErrors["phone_number"])
|
assert.Equal(t, errmsg.ErrorMsgPhoneNumberIsNotValid, fieldErrors["phone_number"])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Inactive user is not allowed", func(t *testing.T) {
|
||||||
|
req := benefactoreparam.SendOtpRequest{
|
||||||
|
PhoneNumber: validPhoneNumber,
|
||||||
|
}
|
||||||
|
|
||||||
|
mockRepository.EXPECT().GetByPhoneNumber(ctx, req.PhoneNumber).Return(entity.Benefactor{
|
||||||
|
Status: entity.BenefactorInactiveStatus,
|
||||||
|
}, nil).Once()
|
||||||
|
|
||||||
|
fieldErrors, err := validator.ValidateSendOtpRequest(ctx, req)
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.NotNil(t, fieldErrors)
|
||||||
|
assert.Equal(t, errmsg.ErrorMsgUserNotAllowed, fieldErrors["phone_number"])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("new users are allowed", func(t *testing.T) {
|
||||||
|
req := benefactoreparam.SendOtpRequest{
|
||||||
|
PhoneNumber: validPhoneNumber,
|
||||||
|
}
|
||||||
|
|
||||||
|
mockRepository.EXPECT().GetByPhoneNumber(ctx, req.PhoneNumber).Return(entity.Benefactor{}, richerror.New("test").
|
||||||
|
WithKind(richerror.KindNotFound)).Once()
|
||||||
|
|
||||||
|
fieldErrors, err := validator.ValidateSendOtpRequest(ctx, req)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Nil(t, fieldErrors)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,51 @@
|
||||||
package benefactorvalidator
|
package benefactorvalidator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
|
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
||||||
|
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
phoneNumberRegex = "^09\\d{9}$"
|
phoneNumberRegex = "^09\\d{9}$"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Validator struct{}
|
//go:generate mockery --name Repository
|
||||||
|
type Repository interface {
|
||||||
func New() Validator {
|
GetByPhoneNumber(ctx context.Context, phoneNumber string) (entity.Benefactor, error)
|
||||||
return Validator{}
|
}
|
||||||
|
|
||||||
|
type Validator struct {
|
||||||
|
repo Repository
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(repo Repository) Validator {
|
||||||
|
return Validator{repo: repo}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Validator) isBenefactorAllowed(ctx context.Context) func(interface{}) error {
|
||||||
|
return func(value interface{}) error {
|
||||||
|
phoneNumber, ok := value.(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong)
|
||||||
|
}
|
||||||
|
bnf, err := v.repo.GetByPhoneNumber(ctx, phoneNumber)
|
||||||
|
if err != nil {
|
||||||
|
// new users are always allowed
|
||||||
|
var richErr richerror.RichError
|
||||||
|
if errors.As(err, &richErr) && richErr.Kind() == richerror.KindNotFound {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong)
|
||||||
|
}
|
||||||
|
if bnf.Status == entity.BenefactorInactiveStatus {
|
||||||
|
return fmt.Errorf(errmsg.ErrorMsgUserNotAllowed)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by mockery v2.41.0. DO NOT EDIT.
|
// Code generated by mockery v2.45.1. DO NOT EDIT.
|
||||||
|
|
||||||
package benefactorkindboxvalidator
|
package benefactorkindboxvalidator
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import (
|
||||||
context "context"
|
context "context"
|
||||||
|
|
||||||
addressparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/address"
|
addressparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/address"
|
||||||
|
|
||||||
mock "github.com/stretchr/testify/mock"
|
mock "github.com/stretchr/testify/mock"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by mockery v2.41.0. DO NOT EDIT.
|
// Code generated by mockery v2.45.1. DO NOT EDIT.
|
||||||
|
|
||||||
package benefactorkindboxvalidator
|
package benefactorkindboxvalidator
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import (
|
||||||
context "context"
|
context "context"
|
||||||
|
|
||||||
benefactoreparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/benefactor"
|
benefactoreparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/benefactor"
|
||||||
|
|
||||||
mock "github.com/stretchr/testify/mock"
|
mock "github.com/stretchr/testify/mock"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by mockery v2.41.0. DO NOT EDIT.
|
// Code generated by mockery v2.45.1. DO NOT EDIT.
|
||||||
|
|
||||||
package benefactorkindboxvalidator
|
package benefactorkindboxvalidator
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by mockery v2.41.0. DO NOT EDIT.
|
// Code generated by mockery v2.45.1. DO NOT EDIT.
|
||||||
|
|
||||||
package benefactorkindboxvalidator
|
package benefactorkindboxvalidator
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by mockery v2.41.0. DO NOT EDIT.
|
// Code generated by mockery v2.45.1. DO NOT EDIT.
|
||||||
|
|
||||||
package benefactorkindboxreqvalidator
|
package benefactorkindboxreqvalidator
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import (
|
||||||
context "context"
|
context "context"
|
||||||
|
|
||||||
addressparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/address"
|
addressparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/address"
|
||||||
|
|
||||||
mock "github.com/stretchr/testify/mock"
|
mock "github.com/stretchr/testify/mock"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by mockery v2.41.0. DO NOT EDIT.
|
// Code generated by mockery v2.45.1. DO NOT EDIT.
|
||||||
|
|
||||||
package benefactorkindboxreqvalidator
|
package benefactorkindboxreqvalidator
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import (
|
||||||
context "context"
|
context "context"
|
||||||
|
|
||||||
benefactoreparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/benefactor"
|
benefactoreparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/benefactor"
|
||||||
|
|
||||||
mock "github.com/stretchr/testify/mock"
|
mock "github.com/stretchr/testify/mock"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by mockery v2.41.0. DO NOT EDIT.
|
// Code generated by mockery v2.45.1. DO NOT EDIT.
|
||||||
|
|
||||||
package benefactorkindboxreqvalidator
|
package benefactorkindboxreqvalidator
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by mockery v2.41.0. DO NOT EDIT.
|
// Code generated by mockery v2.45.1. DO NOT EDIT.
|
||||||
|
|
||||||
package benefactorkindboxreqvalidator
|
package benefactorkindboxreqvalidator
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue