From af106c1ffce57762ddc51408e9bd33cf7e1adaf9 Mon Sep 17 00:00:00 2001 From: Denis Arh Date: Tue, 27 Aug 2019 02:12:59 +0200 Subject: [PATCH] User & role unique name check --- system/internal/repository/role.go | 16 +++++++++++ system/internal/repository/user.go | 5 ++++ system/internal/service/role.go | 44 ++++++++++++++++++++++++++++-- system/internal/service/user.go | 40 +++++++++++++++++++++++++++ 4 files changed, 103 insertions(+), 2 deletions(-) diff --git a/system/internal/repository/role.go b/system/internal/repository/role.go index 93e2474a1..0dc45839b 100644 --- a/system/internal/repository/role.go +++ b/system/internal/repository/role.go @@ -14,6 +14,8 @@ type ( With(ctx context.Context, db *factory.DB) RoleRepository FindByID(id uint64) (*types.Role, error) + FindByName(name string) (*types.Role, error) + FindByHandle(handle string) (*types.Role, error) FindByMemberID(userID uint64) (types.RoleSet, error) Find(filter *types.RoleFilter) (types.RoleSet, error) @@ -68,6 +70,20 @@ func (r *role) FindByID(id uint64) (*types.Role, error) { return mod, isFound(r.db().Get(mod, sql, id), mod.ID > 0, ErrRoleNotFound) } +func (r role) FindByHandle(handle string) (*types.Role, error) { + sql := "SELECT * FROM " + r.roles + " WHERE handle = ? AND " + sqlRoleScope + mod := &types.Role{} + + return mod, isFound(r.db().Get(mod, sql, handle), mod.ID > 0, ErrRoleNotFound) +} + +func (r role) FindByName(name string) (*types.Role, error) { + sql := "SELECT * FROM " + r.roles + " WHERE name = ? AND " + sqlRoleScope + mod := &types.Role{} + + return mod, isFound(r.db().Get(mod, sql, name), mod.ID > 0, ErrRoleNotFound) +} + func (r *role) FindByMemberID(userID uint64) (types.RoleSet, error) { sql := "SELECT * FROM " + r.roles + " where id in (select rel_role from " + r.members + " where rel_user=?) and " + sqlRoleScope rval := make([]*types.Role, 0) diff --git a/system/internal/repository/user.go b/system/internal/repository/user.go index 261a6c8a5..7691d968d 100644 --- a/system/internal/repository/user.go +++ b/system/internal/repository/user.go @@ -17,6 +17,7 @@ type ( FindByEmail(email string) (*types.User, error) FindByUsername(username string) (*types.User, error) + FindByHandle(handle string) (*types.User, error) FindByID(id uint64) (*types.User, error) FindByIDs(id ...uint64) (types.UserSet, error) Find(filter types.UserFilter) (set types.UserSet, f types.UserFilter, err error) @@ -97,6 +98,10 @@ func (r user) FindByUsername(username string) (*types.User, error) { return r.findBy("username", username) } +func (r user) FindByHandle(handle string) (*types.User, error) { + return r.findBy("handle", handle) +} + func (r user) FindByEmail(email string) (*types.User, error) { return r.findBy("email", email) } diff --git a/system/internal/service/role.go b/system/internal/service/role.go index d637c1f7d..616a93888 100644 --- a/system/internal/service/role.go +++ b/system/internal/service/role.go @@ -34,6 +34,8 @@ type ( With(ctx context.Context) RoleService FindByID(roleID uint64) (*types.Role, error) + FindByName(name string) (*types.Role, error) + FindByHandle(handle string) (*types.Role, error) Find(filter *types.RoleFilter) ([]*types.Role, error) Create(role *types.Role) (*types.Role, error) @@ -111,11 +113,27 @@ func (svc role) Find(filter *types.RoleFilter) ([]*types.Role, error) { return ret, nil } -func (svc role) Create(mod *types.Role) (*types.Role, error) { +func (svc role) FindByName(rolename string) (*types.Role, error) { + return svc.role.FindByName(rolename) +} + +func (svc role) FindByHandle(handle string) (*types.Role, error) { + return svc.role.FindByHandle(handle) +} + +func (svc role) Create(mod *types.Role) (t *types.Role, err error) { if !svc.ac.CanCreateRole(svc.ctx) { return nil, ErrNoPermissions.withStack() } - return svc.role.Create(mod) + + return t, svc.db.Transaction(func() (err error) { + if err = svc.UniqueCheck(mod); err != nil { + return + } + + t, err = svc.role.Create(mod) + return + }) } func (svc role) Update(mod *types.Role) (t *types.Role, err error) { @@ -134,6 +152,10 @@ func (svc role) Update(mod *types.Role) (t *types.Role, err error) { return } + if err = svc.UniqueCheck(mod); err != nil { + return + } + // Assign changed values t.Name = mod.Name t.Handle = mod.Handle @@ -146,6 +168,24 @@ func (svc role) Update(mod *types.Role) (t *types.Role, err error) { }) } +func (svc role) UniqueCheck(r *types.Role) (err error) { + var ( + e *types.Role + ) + + if e, _ = svc.FindByName(r.Name); e != nil && e.ID != r.ID { + return ErrUserUsernameNotUnque + } + + if r.Handle != "" { + if e, _ = svc.FindByHandle(r.Handle); e != nil && e.ID != r.ID { + err = ErrUserHandleNotUnique + } + } + + return +} + func (svc role) Delete(roleID uint64) error { role, err := svc.findByID(roleID) if err != nil { diff --git a/system/internal/service/user.go b/system/internal/service/user.go index d1b47a124..994383041 100644 --- a/system/internal/service/user.go +++ b/system/internal/service/user.go @@ -17,6 +17,9 @@ import ( const ( ErrUserInvalidCredentials = serviceError("UserInvalidCredentials") + ErrUserHandleNotUnique = serviceError("HandleNotUnique") + ErrUserUsernameNotUnque = serviceError("UsernameNotUnque") + ErrUserEmailNotUnique = serviceError("EmailNotUnique") ErrUserLocked = serviceError("UserLocked") ) @@ -54,6 +57,7 @@ type ( FindByUsername(username string) (*types.User, error) FindByEmail(email string) (*types.User, error) + FindByHandle(handle string) (*types.User, error) FindByID(id uint64) (*types.User, error) FindByIDs(id ...uint64) (types.UserSet, error) Find(types.UserFilter) (types.UserSet, types.UserFilter, error) @@ -125,6 +129,10 @@ func (svc user) FindByUsername(username string) (*types.User, error) { return svc.user.FindByUsername(username) } +func (svc user) FindByHandle(handle string) (*types.User, error) { + return svc.user.FindByHandle(handle) +} + func (svc user) Find(f types.UserFilter) (types.UserSet, types.UserFilter, error) { if f.IncDeleted || f.IncSuspended { if !svc.ac.CanAccess(svc.ctx) { @@ -141,6 +149,10 @@ func (svc user) Create(input *types.User) (out *types.User, err error) { } return out, svc.db.Transaction(func() (err error) { + if err = svc.UniqueCheck(input); err != nil { + return + } + out, err = svc.user.Create(input) return }) @@ -172,11 +184,39 @@ func (svc user) Update(mod *types.User) (u *types.User, err error) { u.Kind = mod.Kind return u, svc.db.Transaction(func() (err error) { + if err = svc.UniqueCheck(u); err != nil { + return + } + u, err = svc.user.Update(u) return }) } +func (svc user) UniqueCheck(u *types.User) (err error) { + var ( + e *types.User + ) + + if e, _ = svc.FindByEmail(u.Email); e != nil && e.ID != u.ID { + err = ErrUserEmailNotUnique + } + + if u.Username != "" { + if e, _ = svc.FindByUsername(u.Username); e != nil && e.ID != u.ID { + return ErrUserUsernameNotUnque + } + } + + if u.Handle != "" { + if e, _ = svc.FindByHandle(u.Handle); e != nil && e.ID != u.ID { + err = ErrUserHandleNotUnique + } + } + + return +} + func (svc user) UpdateWithAvatar(mod *types.User, avatar io.Reader) (out *types.User, err error) { // @todo: avatar return svc.Create(mod)