mirror of
https://github.com/absmach/magistrala.git
synced 2026-06-23 04:10:28 +00:00
SMQ-2924 - Allow bulk deleting of invitations from repository (#2942)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
This commit is contained in:
+2
-2
@@ -263,8 +263,8 @@ type Repository interface {
|
||||
// UpdateRejection updates an invitation by setting the rejection time.
|
||||
UpdateRejection(ctx context.Context, invitation Invitation) (err error)
|
||||
|
||||
// Delete deletes an invitation.
|
||||
DeleteInvitation(ctx context.Context, userID, domainID string) (err error)
|
||||
// DeleteUsersInvitations deletes invitation to a provided domain for users with provided user IDs.
|
||||
DeleteUsersInvitations(ctx context.Context, domainID string, userID ...string) (err error)
|
||||
|
||||
roles.Repository
|
||||
}
|
||||
|
||||
+28
-19
@@ -167,37 +167,44 @@ func (_c *Repository_DeleteDomain_Call) RunAndReturn(run func(ctx context.Contex
|
||||
return _c
|
||||
}
|
||||
|
||||
// DeleteInvitation provides a mock function for the type Repository
|
||||
func (_mock *Repository) DeleteInvitation(ctx context.Context, userID string, domainID string) error {
|
||||
ret := _mock.Called(ctx, userID, domainID)
|
||||
// DeleteUsersInvitations provides a mock function for the type Repository
|
||||
func (_mock *Repository) DeleteUsersInvitations(ctx context.Context, domainID string, userID ...string) error {
|
||||
var tmpRet mock.Arguments
|
||||
if len(userID) > 0 {
|
||||
tmpRet = _mock.Called(ctx, domainID, userID)
|
||||
} else {
|
||||
tmpRet = _mock.Called(ctx, domainID)
|
||||
}
|
||||
ret := tmpRet
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeleteInvitation")
|
||||
panic("no return value specified for DeleteUsersInvitations")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
|
||||
r0 = returnFunc(ctx, userID, domainID)
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context, string, ...string) error); ok {
|
||||
r0 = returnFunc(ctx, domainID, userID...)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
return r0
|
||||
}
|
||||
|
||||
// Repository_DeleteInvitation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteInvitation'
|
||||
type Repository_DeleteInvitation_Call struct {
|
||||
// Repository_DeleteUsersInvitations_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteUsersInvitations'
|
||||
type Repository_DeleteUsersInvitations_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// DeleteInvitation is a helper method to define mock.On call
|
||||
// DeleteUsersInvitations is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - userID string
|
||||
// - domainID string
|
||||
func (_e *Repository_Expecter) DeleteInvitation(ctx interface{}, userID interface{}, domainID interface{}) *Repository_DeleteInvitation_Call {
|
||||
return &Repository_DeleteInvitation_Call{Call: _e.mock.On("DeleteInvitation", ctx, userID, domainID)}
|
||||
// - userID ...string
|
||||
func (_e *Repository_Expecter) DeleteUsersInvitations(ctx interface{}, domainID interface{}, userID ...interface{}) *Repository_DeleteUsersInvitations_Call {
|
||||
return &Repository_DeleteUsersInvitations_Call{Call: _e.mock.On("DeleteUsersInvitations",
|
||||
append([]interface{}{ctx, domainID}, userID...)...)}
|
||||
}
|
||||
|
||||
func (_c *Repository_DeleteInvitation_Call) Run(run func(ctx context.Context, userID string, domainID string)) *Repository_DeleteInvitation_Call {
|
||||
func (_c *Repository_DeleteUsersInvitations_Call) Run(run func(ctx context.Context, domainID string, userID ...string)) *Repository_DeleteUsersInvitations_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
var arg0 context.Context
|
||||
if args[0] != nil {
|
||||
@@ -207,25 +214,27 @@ func (_c *Repository_DeleteInvitation_Call) Run(run func(ctx context.Context, us
|
||||
if args[1] != nil {
|
||||
arg1 = args[1].(string)
|
||||
}
|
||||
var arg2 string
|
||||
if args[2] != nil {
|
||||
arg2 = args[2].(string)
|
||||
var arg2 []string
|
||||
var variadicArgs []string
|
||||
if len(args) > 2 {
|
||||
variadicArgs = args[2].([]string)
|
||||
}
|
||||
arg2 = variadicArgs
|
||||
run(
|
||||
arg0,
|
||||
arg1,
|
||||
arg2,
|
||||
arg2...,
|
||||
)
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Repository_DeleteInvitation_Call) Return(err error) *Repository_DeleteInvitation_Call {
|
||||
func (_c *Repository_DeleteUsersInvitations_Call) Return(err error) *Repository_DeleteUsersInvitations_Call {
|
||||
_c.Call.Return(err)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Repository_DeleteInvitation_Call) RunAndReturn(run func(ctx context.Context, userID string, domainID string) error) *Repository_DeleteInvitation_Call {
|
||||
func (_c *Repository_DeleteUsersInvitations_Call) RunAndReturn(run func(ctx context.Context, domainID string, userID ...string) error) *Repository_DeleteUsersInvitations_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
@@ -150,10 +150,18 @@ func (repo domainRepo) UpdateRejection(ctx context.Context, invitation domains.I
|
||||
return nil
|
||||
}
|
||||
|
||||
func (repo domainRepo) DeleteInvitation(ctx context.Context, inviteeUserID, domain string) (err error) {
|
||||
q := `DELETE FROM invitations WHERE invitee_user_id = $1 AND domain_id = $2`
|
||||
func (repo domainRepo) DeleteUsersInvitations(ctx context.Context, domain string, inviteeUserIDs ...string) (err error) {
|
||||
if len(inviteeUserIDs) == 0 {
|
||||
return repoerr.ErrNotFound
|
||||
}
|
||||
|
||||
result, err := repo.db.ExecContext(ctx, q, inviteeUserID, domain)
|
||||
q := `DELETE FROM invitations WHERE domain_id = :domain_id AND invitee_user_id = ANY(:invitee_user_ids);`
|
||||
|
||||
params := map[string]any{
|
||||
"invitee_user_ids": inviteeUserIDs,
|
||||
"domain_id": domain,
|
||||
}
|
||||
result, err := repo.db.NamedExecContext(ctx, q, params)
|
||||
if err != nil {
|
||||
return postgres.HandleError(repoerr.ErrRemoveEntity, err)
|
||||
}
|
||||
|
||||
@@ -761,7 +761,7 @@ func TestUpdateRejection(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteInvitation(t *testing.T) {
|
||||
func TestDeleteUsersInvitations(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
_, err := db.Exec("DELETE FROM invitations")
|
||||
require.Nil(t, err, fmt.Sprintf("clean invitations unexpected error: %s", err))
|
||||
@@ -772,48 +772,58 @@ func TestDeleteInvitation(t *testing.T) {
|
||||
|
||||
dom := saveDomain(t, repo)
|
||||
|
||||
invitation := domains.Invitation{
|
||||
InvitedBy: testsutil.GenerateUUID(t),
|
||||
InviteeUserID: testsutil.GenerateUUID(t),
|
||||
DomainID: dom.ID,
|
||||
DomainName: dom.Name,
|
||||
RoleID: testsutil.GenerateUUID(t),
|
||||
RoleName: roleName,
|
||||
CreatedAt: time.Now(),
|
||||
num := 10
|
||||
items := make([]domains.Invitation, 0, num)
|
||||
|
||||
for i := 0; i < num; i++ {
|
||||
invitation := domains.Invitation{
|
||||
InvitedBy: testsutil.GenerateUUID(t),
|
||||
InviteeUserID: testsutil.GenerateUUID(t),
|
||||
DomainID: dom.ID,
|
||||
DomainName: dom.Name,
|
||||
RoleID: testsutil.GenerateUUID(t),
|
||||
RoleName: roleName,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
err := repo.SaveInvitation(context.Background(), invitation)
|
||||
require.Nil(t, err, fmt.Sprintf("create invitation unexpected error: %s", err))
|
||||
items = append(items, invitation)
|
||||
}
|
||||
err := repo.SaveInvitation(context.Background(), invitation)
|
||||
require.Nil(t, err, fmt.Sprintf("create invitation unexpected error: %s", err))
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
invitation domains.Invitation
|
||||
err error
|
||||
desc string
|
||||
domainID string
|
||||
userIDs []string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "delete invitation successfully",
|
||||
invitation: domains.Invitation{
|
||||
InviteeUserID: invitation.InviteeUserID,
|
||||
DomainID: invitation.DomainID,
|
||||
},
|
||||
err: nil,
|
||||
desc: "delete one invitation successfully",
|
||||
domainID: dom.ID,
|
||||
userIDs: []string{items[0].InviteeUserID},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "delete invitation with invalid invitation id",
|
||||
invitation: domains.Invitation{
|
||||
InviteeUserID: testsutil.GenerateUUID(t),
|
||||
DomainID: testsutil.GenerateUUID(t),
|
||||
},
|
||||
err: repoerr.ErrNotFound,
|
||||
desc: "delete multiple invitations successfully",
|
||||
domainID: dom.ID,
|
||||
userIDs: []string{items[1].InviteeUserID, items[2].InviteeUserID, items[3].InviteeUserID},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "delete invitation with empty invitation id",
|
||||
invitation: domains.Invitation{},
|
||||
err: repoerr.ErrNotFound,
|
||||
desc: "delete invitation with invalid invitation id",
|
||||
domainID: dom.ID,
|
||||
userIDs: []string{testsutil.GenerateUUID(t)},
|
||||
err: repoerr.ErrNotFound,
|
||||
},
|
||||
{
|
||||
desc: "delete invitation with empty user id",
|
||||
domainID: dom.ID,
|
||||
userIDs: []string{},
|
||||
err: repoerr.ErrNotFound,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
err := repo.DeleteInvitation(context.Background(), tc.invitation.InviteeUserID, tc.invitation.DomainID)
|
||||
err := repo.DeleteUsersInvitations(context.Background(), tc.domainID, tc.userIDs...)
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
})
|
||||
}
|
||||
|
||||
+7
-10
@@ -306,7 +306,7 @@ func (svc *service) RejectInvitation(ctx context.Context, session authn.Session,
|
||||
|
||||
func (svc *service) DeleteInvitation(ctx context.Context, session authn.Session, inviteeUserID, domainID string) error {
|
||||
if session.UserID == inviteeUserID {
|
||||
if err := svc.repo.DeleteInvitation(ctx, inviteeUserID, domainID); err != nil {
|
||||
if err := svc.repo.DeleteUsersInvitations(ctx, domainID, inviteeUserID); err != nil {
|
||||
return errors.Wrap(svcerr.ErrRemoveEntity, err)
|
||||
}
|
||||
return nil
|
||||
@@ -325,7 +325,7 @@ func (svc *service) DeleteInvitation(ctx context.Context, session authn.Session,
|
||||
return errors.Wrap(svcerr.ErrRemoveEntity, svcerr.ErrInvitationAlreadyRejected)
|
||||
}
|
||||
|
||||
if err := svc.repo.DeleteInvitation(ctx, inviteeUserID, domainID); err != nil {
|
||||
if err := svc.repo.DeleteUsersInvitations(ctx, domainID, inviteeUserID); err != nil {
|
||||
return errors.Wrap(svcerr.ErrRemoveEntity, err)
|
||||
}
|
||||
|
||||
@@ -334,11 +334,10 @@ func (svc *service) DeleteInvitation(ctx context.Context, session authn.Session,
|
||||
|
||||
// Add addition removal of user from invitations.
|
||||
func (svc *service) RemoveEntityMembers(ctx context.Context, session authn.Session, entityID string, members []string) error {
|
||||
for _, member := range members {
|
||||
if err := svc.repo.DeleteInvitation(ctx, member, entityID); err != nil && err != repoerr.ErrNotFound {
|
||||
return err
|
||||
}
|
||||
if err := svc.repo.DeleteUsersInvitations(ctx, entityID, members...); err != nil && err != repoerr.ErrNotFound {
|
||||
return err
|
||||
}
|
||||
|
||||
return svc.ProvisionManageService.RemoveEntityMembers(ctx, session, entityID, members)
|
||||
}
|
||||
|
||||
@@ -358,10 +357,8 @@ func (svc *service) RoleRemoveMembers(ctx context.Context, session authn.Session
|
||||
}
|
||||
}
|
||||
|
||||
for _, memberID := range members {
|
||||
if err := svc.repo.DeleteInvitation(ctx, memberID, entityID); err != nil && err != repoerr.ErrNotFound {
|
||||
return err
|
||||
}
|
||||
if err := svc.repo.DeleteUsersInvitations(ctx, entityID, members...); err != nil && err != repoerr.ErrNotFound {
|
||||
return err
|
||||
}
|
||||
|
||||
return svc.ProvisionManageService.RoleRemoveMembers(ctx, session, entityID, roleID, members)
|
||||
|
||||
@@ -1114,7 +1114,7 @@ func TestDeleteInvitation(t *testing.T) {
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
repoCall := drepo.On("RetrieveInvitation", context.Background(), mock.Anything, mock.Anything).Return(tc.resp, tc.retrieveInvitationErr)
|
||||
repoCall1 := drepo.On("DeleteInvitation", context.Background(), mock.Anything, mock.Anything).Return(tc.deleteInvitationErr)
|
||||
repoCall1 := drepo.On("DeleteUsersInvitations", context.Background(), mock.Anything, mock.Anything).Return(tc.deleteInvitationErr)
|
||||
err := svc.DeleteInvitation(context.Background(), tc.session, tc.userID, tc.domainID)
|
||||
assert.True(t, errors.Contains(err, tc.err))
|
||||
repoCall.Unset()
|
||||
|
||||
Reference in New Issue
Block a user