Compare commits

...

2 Commits

Author SHA1 Message Date
Amir Tavakolian 951ec222d6 add update role feature 2026-05-19 14:01:38 +03:30
Amir Tavakolian 6ecf4f5209 refactor 2026-05-19 13:15:55 +03:30
8 changed files with 143 additions and 26 deletions

View File

@ -18,7 +18,7 @@ type Config struct {
MySQLDB mySql.Config `koanf:"mariadb"` MySQLDB mySql.Config `koanf:"mariadb"`
} }
type Application struct { type Application struct {
RoleRepo *repository.DB RoleRepo *repository.RoleRepo
AuthorizationService service.Authorization AuthorizationService service.Authorization
RoleHandler http.RoleHandler RoleHandler http.RoleHandler
RoleServer http.RoleServer RoleServer http.RoleServer
@ -40,6 +40,10 @@ func (a Application) Setup() Application {
} }
} }
func (a Application) Start() {
// todo implement role service start
}
func (a Application) getYamlConfigPath() Config { func (a Application) getYamlConfigPath() Config {
var appConfig Config var appConfig Config

View File

@ -31,5 +31,20 @@ func (r RoleHandler) Store(c *gin.Context) {
} }
c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("role %s created successfully", role.Title_fa)}) c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("role %s created successfully", role.Title_fa)})
return }
func (r RoleHandler) Update(c *gin.Context) {
var request service.UpdateRoleRequest
if err := c.ShouldBindJSON(&request); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
role, err := r.service.Update(c, request)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("role %s updated successfully", role.Title_fa)})
} }

View File

@ -17,7 +17,10 @@ func NewRoleServer(cfg httpserver.Config, handler RoleHandler) RoleServer {
func (s RoleServer) Start() { func (s RoleServer) Start() {
r := gin.Default() r := gin.Default()
r.POST("/role/create", s.handler.Store) group := r.Group("/role")
group.POST("/create", s.handler.Store)
group.PUT("/update/:id", s.handler.Update)
err := r.Run(fmt.Sprintf("%s:%s", s.cfg.Host, s.cfg.Port)) err := r.Run(fmt.Sprintf("%s:%s", s.cfg.Host, s.cfg.Port))
if err != nil { if err != nil {

View File

@ -3,21 +3,20 @@ package repository
import ( import (
"context" "context"
"git.gocasts.ir/ebhomengo/niki/domain/authorization/service" "git.gocasts.ir/ebhomengo/niki/domain/authorization/service"
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
"git.gocasts.ir/ebhomengo/niki/pkg/database/mysql" "git.gocasts.ir/ebhomengo/niki/pkg/database/mysql"
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
"git.gocasts.ir/ebhomengo/niki/types" "git.gocasts.ir/ebhomengo/niki/types"
) )
type DB struct { type RoleRepo struct {
conn *mysql.DB conn *mysql.DB
} }
func New(conn *mysql.DB) *DB { func New(conn *mysql.DB) *RoleRepo {
return &DB{conn: conn} return &RoleRepo{conn: conn}
} }
func (m DB) Store(ctx context.Context, req service.StoreRoleRequest) (types.ID, error) { func (m RoleRepo) Store(ctx context.Context, req service.StoreRoleRequest) (types.ID, error) {
const op = "domain.authorization.repository.role.store" const op = "domain.authorization.repository.role.store"
result, err := m.conn.Conn().ExecContext(ctx, "INSERT INTO roles VALUES (`?,?`)", req.Title, req.TitleFa) result, err := m.conn.Conn().ExecContext(ctx, "INSERT INTO roles VALUES (`?,?`)", req.Title, req.TitleFa)
@ -32,3 +31,34 @@ func (m DB) Store(ctx context.Context, req service.StoreRoleRequest) (types.ID,
return types.ID(roleID), nil return types.ID(roleID), nil
} }
func (m RoleRepo) Update(ctx context.Context, req service.UpdateRoleRequest) (types.ID, error) {
const op = "domain.authorization.repository.role.update"
result, err := m.conn.Conn().ExecContext(ctx,
"UPDATE roles SET title = ?, title_fa = ? WHERE id = ?",
req.Title, req.TitleFa, req.ID)
if err != nil {
return 0, richerror.New(op).WithErr(err)
}
_, err = result.RowsAffected()
if err != nil {
return 0, richerror.New(op).WithErr(err)
}
return types.ID(req.ID), nil
}
func (m RoleRepo) IsRoleExistsByID(ctx context.Context, id types.ID) error {
const op = "domain.authorization.repository.role.is_exists_by_id"
var exists bool
err := m.conn.Conn().QueryRowContext(ctx, "SELECT EXISTS(SELECT 1 FROM roles WHERE id = ?)", id).Scan(&exists)
if err != nil {
return richerror.New(op).WithErr(err)
}
return nil
}

View File

@ -4,8 +4,6 @@ import (
"context" "context"
"git.gocasts.ir/ebhomengo/niki/domain/authorization/entity" "git.gocasts.ir/ebhomengo/niki/domain/authorization/entity"
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error" richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
"github.com/go-ozzo/ozzo-validation/v4"
"regexp"
) )
type Authorization struct { type Authorization struct {
@ -19,7 +17,7 @@ func NewAuthorization(roleRepo RoleRepo) Authorization {
func (a Authorization) Store(ctx context.Context, req StoreRoleRequest) (entity.Role, error) { func (a Authorization) Store(ctx context.Context, req StoreRoleRequest) (entity.Role, error) {
const op = "authorizationservice.Store" const op = "authorizationservice.Store"
if err := a.validateRole(req); err != nil { if err := a.validateStoreRole(req); err != nil {
return entity.Role{}, richerror.New(op).WithErr(err).WithKind(richerror.KindUnexpected) return entity.Role{}, richerror.New(op).WithErr(err).WithKind(richerror.KindUnexpected)
} }
@ -27,19 +25,28 @@ func (a Authorization) Store(ctx context.Context, req StoreRoleRequest) (entity.
if err != nil { if err != nil {
return entity.Role{}, richerror.New(op).WithErr(err).WithKind(richerror.KindUnexpected) return entity.Role{}, richerror.New(op).WithErr(err).WithKind(richerror.KindUnexpected)
} }
return role, nil return entity.Role{
ID: role,
Title_fa: req.TitleFa,
Title: req.Title,
}, nil
} }
func (s Authorization) validateRole(req StoreRoleRequest) error { func (a Authorization) Update(ctx context.Context, req UpdateRoleRequest) (entity.Role, error) {
return validation.ValidateStruct(&req, const op = "authorizationservice.Update"
validation.Field(&req.Title,
validation.Required,
validation.Length(4, 0),
validation.Match(regexp.MustCompile(`^[a-zA-Z\s]+$`))),
validation.Field(&req.TitleFa, if err := a.validateUpdateRole(ctx, req); err != nil {
validation.Required, return entity.Role{}, richerror.New(op).WithErr(err).WithKind(richerror.KindUnexpected)
validation.Length(4, 0), }
validation.Match(regexp.MustCompile(`^[\x{0600}-\x{06FF}\s]+$`))),
) role, err := a.roleRepo.Update(ctx, req)
if err != nil {
return entity.Role{}, richerror.New(op).WithErr(err).WithKind(richerror.KindUnexpected)
}
return entity.Role{
ID: role,
Title_fa: req.TitleFa,
Title: req.Title,
}, nil
} }

View File

@ -1,6 +1,17 @@
package service package service
type StoreRoleRequest struct { import "git.gocasts.ir/ebhomengo/niki/types"
type RoleRequest struct {
Title string `json:"title"` Title string `json:"title"`
TitleFa string `json:"title_fa"` TitleFa string `json:"title_fa"`
} }
type StoreRoleRequest struct {
RoleRequest
}
type UpdateRoleRequest struct {
ID types.ID `json:"id"`
RoleRequest
}

View File

@ -2,9 +2,11 @@ package service
import ( import (
"context" "context"
"git.gocasts.ir/ebhomengo/niki/types" "git.gocasts.ir/ebhomengo/niki/types"
) )
type RoleRepo interface { type RoleRepo interface {
Store(ctx context.Context, req StoreRoleRequest) (types.ID, error) Store(ctx context.Context, req StoreRoleRequest) (types.ID, error)
Update(ctx context.Context, req UpdateRoleRequest) (types.ID, error)
IsRoleExistsByID(ctx context.Context, id types.ID) error
} }

View File

@ -0,0 +1,45 @@
package service
import (
"context"
"github.com/go-ozzo/ozzo-validation/v4"
"regexp"
)
func (a Authorization) validateStoreRole(req StoreRoleRequest) error {
return validation.ValidateStruct(&req,
validation.Field(&req.Title,
validation.Required,
validation.Length(4, 0),
validation.Match(regexp.MustCompile(`^[a-zA-Z\s]+$`))),
validation.Field(&req.TitleFa,
validation.Required,
validation.Length(4, 0),
validation.Match(regexp.MustCompile(`^[\x{0600}-\x{06FF}\s]+$`))),
)
}
func (a Authorization) validateUpdateRole(ctx context.Context, req UpdateRoleRequest) error {
return validation.ValidateStruct(&req,
validation.Field(&req.ID,
validation.Required,
validation.By(func(value interface{}) error {
err := a.roleRepo.IsRoleExistsByID(ctx, req.ID)
if err != nil {
return err
}
return nil
}),
),
validation.Field(&req.Title,
validation.Required,
validation.Length(4, 0),
validation.Match(regexp.MustCompile(`^[a-zA-Z\s]+$`))),
validation.Field(&req.TitleFa,
validation.Required,
validation.Length(4, 0),
validation.Match(regexp.MustCompile(`^[\x{0600}-\x{06FF}\s]+$`))),
)
}