diff --git a/system/internal/repository/util.go b/system/internal/repository/util.go index 320f0f153..0b7f4cd8b 100644 --- a/system/internal/repository/util.go +++ b/system/internal/repository/util.go @@ -3,6 +3,8 @@ package repository import ( "fmt" "time" + + "github.com/pkg/errors" ) func (r repository) updateColumnByID(tableName, columnName string, value interface{}, id uint64) (err error) { @@ -13,15 +15,15 @@ func (r repository) updateColumnByID(tableName, columnName string, value interfa } func exec(_ interface{}, err error) error { - return err + return errors.WithStack(err) } // Returns err if set otherwise it returns nerr if not valid func isFound(err error, valid bool, nerr error) error { if err != nil { - return err + return errors.WithStack(err) } else if !valid { - return nerr + return errors.WithStack(nerr) } return nil diff --git a/system/internal/service/error.go b/system/internal/service/error.go index 9f45193a8..437459435 100644 --- a/system/internal/service/error.go +++ b/system/internal/service/error.go @@ -1,5 +1,9 @@ package service +import ( + "github.com/pkg/errors" +) + type ( serviceError string readableError string @@ -13,6 +17,11 @@ func (e readableError) Error() string { return string(e) } +func (e readableError) new() error { + return errors.WithStack(e) +} + const ( + ErrNoPermissions readableError = "You don't have permissions for this operation" ErrAvatarOnlyHTTPS readableError = "Avatar URL only supports HTTPS" ) diff --git a/system/internal/service/user.go b/system/internal/service/user.go index c1b8351b9..e92259798 100644 --- a/system/internal/service/user.go +++ b/system/internal/service/user.go @@ -2,8 +2,8 @@ package service import ( "context" + "io" - "github.com/pkg/errors" "github.com/titpetric/factory" internalAuth "github.com/crusttech/crust/internal/auth" @@ -40,6 +40,9 @@ type ( Create(input *types.User) (*types.User, error) Update(mod *types.User) (*types.User, error) + CreateWithAvatar(input *types.User, avatar io.Reader) (*types.User, error) + UpdateWithAvatar(mod *types.User, avatar io.Reader) (*types.User, error) + Delete(id uint64) error Suspend(id uint64) error Unsuspend(id uint64) error @@ -84,85 +87,89 @@ func (svc *user) Find(filter *types.UserFilter) (types.UserSet, error) { } func (svc *user) Create(input *types.User) (out *types.User, err error) { - return out, svc.db.Transaction(func() error { - if !svc.prm.CanCreateUser() { - return errors.New("not allowed to create users") - } + if !svc.prm.CanCreateUser() { + return nil, ErrNoPermissions.new() + } - if out, err = svc.user.Create(input); err != nil { - return err - } - - return nil + return out, svc.db.Transaction(func() (err error) { + out, err = svc.user.Create(input) + return }) } +func (svc *user) CreateWithAvatar(input *types.User, avatar io.Reader) (out *types.User, err error) { + // @todo: avatar + return svc.Create(input) +} + func (svc *user) Update(mod *types.User) (u *types.User, err error) { + if u, err = svc.user.FindByID(mod.ID); err != nil { + return + } + + if mod.ID != internalAuth.GetIdentityFromContext(svc.ctx).Identity() && !svc.prm.CanUpdateUser(u) { + return nil, ErrNoPermissions.new() + } + + // Assign changed values + u.Email = mod.Email + u.Username = mod.Username + u.Name = mod.Name + u.Handle = mod.Handle + u.Kind = mod.Kind + return u, svc.db.Transaction(func() (err error) { - if u, err = svc.user.FindByID(mod.ID); err != nil { - return - } - - if mod.ID != internalAuth.GetIdentityFromContext(svc.ctx).Identity() && !svc.prm.CanUpdateUser(u) { - return errors.New("not allowed to update this user") - } - - // Assign changed values - u.Email = mod.Email - u.Username = mod.Username - u.Name = mod.Name - u.Handle = mod.Handle - u.Kind = mod.Kind - - if u, err = svc.user.Update(u); err != nil { - return err - } - - return nil + u, err = svc.user.Update(u) + return }) } -func (svc *user) Delete(id uint64) error { +func (svc *user) UpdateWithAvatar(mod *types.User, avatar io.Reader) (out *types.User, err error) { + // @todo: avatar + return svc.Create(mod) +} + +func (svc *user) Delete(id uint64) (err error) { + var u *types.User + if u, err = svc.user.FindByID(id); err != nil { + return + } + + if !svc.prm.CanDeleteUser(u) { + return ErrNoPermissions.new() + } + return svc.db.Transaction(func() (err error) { - var u *types.User - if u, err = svc.user.FindByID(id); err != nil { - return - } - - if !svc.prm.CanDeleteUser(u) { - return errors.New("not allowed to update this user") - } - return svc.user.DeleteByID(id) }) } -func (svc *user) Suspend(id uint64) error { +func (svc *user) Suspend(id uint64) (err error) { + var u *types.User + if u, err = svc.user.FindByID(id); err != nil { + return + } + + if !svc.prm.CanSuspendUser(u) { + return ErrNoPermissions.new() + } + return svc.db.Transaction(func() (err error) { - var u *types.User - if u, err = svc.user.FindByID(id); err != nil { - return - } - - if !svc.prm.CanSuspendUser(u) { - return errors.New("not allowed to update this user") - } - return svc.user.SuspendByID(id) }) } -func (svc *user) Unsuspend(id uint64) error { +func (svc *user) Unsuspend(id uint64) (err error) { + var u *types.User + if u, err = svc.user.FindByID(id); err != nil { + return + } + + if !svc.prm.CanUnsuspendUser(u) { + return ErrNoPermissions.new() + } + return svc.db.Transaction(func() (err error) { - var u *types.User - if u, err = svc.user.FindByID(id); err != nil { - return - } - - if !svc.prm.CanUnsuspendUser(u) { - return errors.New("not allowed to update this user") - } - return svc.user.UnsuspendByID(id) }) } diff --git a/system/service/user.go b/system/service/user.go index b7ddebd75..f47145ebc 100644 --- a/system/service/user.go +++ b/system/service/user.go @@ -2,6 +2,7 @@ package service import ( "context" + "io" "testing" "github.com/crusttech/crust/system/internal/service" @@ -10,6 +11,14 @@ import ( type ( UserService interface { + Create(input *types.User) (*types.User, error) + Update(mod *types.User) (*types.User, error) + + CreateWithAvatar(input *types.User, avatar io.Reader) (*types.User, error) + UpdateWithAvatar(mod *types.User, avatar io.Reader) (*types.User, error) + + Delete(id uint64) error + FindByUsername(username string) (*types.User, error) FindByEmail(email string) (*types.User, error) FindByID(id uint64) (*types.User, error)