From 6014179e6ff799fd1adb07db27c9f5c371ec8431 Mon Sep 17 00:00:00 2001 From: Pavlo Voroniak Date: Fri, 11 Apr 2025 00:15:23 +0300 Subject: [PATCH 1/2] [DEV-5227] check if member is in use --- store/sqlstore/cc_member_store.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/store/sqlstore/cc_member_store.go b/store/sqlstore/cc_member_store.go index 01a051a6..bb310e56 100644 --- a/store/sqlstore/cc_member_store.go +++ b/store/sqlstore/cc_member_store.go @@ -392,7 +392,21 @@ from m // TODO add force func (s SqlMemberStore) Delete(ctx context.Context, queueId, id int64) model.AppError { - var cnt int64 + var cntCheck, cnt int64 + + check, err := s.GetMaster().WithContext(ctx).Exec(`select 1 from call_center.cc_member_attempt a where a.member_id = :Id and a.state != 'leaving' for update`, + map[string]interface{}{"Id": id}) + if err != nil { + return model.NewCustomCodeError("store.sql_member.delete.app_error", fmt.Sprintf("Id=%v, %s", id, err.Error()), extractCodeFromErr(err)) + } + cntCheck, err = check.RowsAffected() + if err != nil { + return model.NewCustomCodeError("store.sql_member.delete.app_error", fmt.Sprintf("Id=%v, %s", id, err.Error()), extractCodeFromErr(err)) + } + + if cntCheck == 0 { + return model.NewCustomCodeError("store.sql_member.delete.app_error", fmt.Sprintf("Id=%v, member reserved", id), http.StatusForbidden) + } res, err := s.GetMaster().WithContext(ctx).Exec(`delete from call_center.cc_member c where c.id = :Id From da44d9fd77c2df2bcf8bcfdd1bcd2aa6c57e4239 Mon Sep 17 00:00:00 2001 From: "i.navrotskyj" Date: Fri, 11 Apr 2025 09:03:09 +0300 Subject: [PATCH 2/2] [DEV-5227] check if member is in queue --- app/cc_member.go | 8 ++++++-- grpc_api/cc_member.go | 4 +++- store/sqlstore/cc_member_store.go | 27 ++++++++------------------- store/store.go | 2 +- 4 files changed, 18 insertions(+), 23 deletions(-) diff --git a/app/cc_member.go b/app/cc_member.go index 4a23a618..66f6429d 100644 --- a/app/cc_member.go +++ b/app/cc_member.go @@ -137,14 +137,18 @@ func (app *App) PatchMember(ctx context.Context, domainId, queueId, id int64, pa return oldMember, nil } -func (app *App) RemoveMember(ctx context.Context, domainId, queueId, id int64) (*model.Member, model.AppError) { +func (app *App) RemoveMember(ctx context.Context, domainId, queueId, id int64, force bool) (*model.Member, model.AppError) { member, err := app.GetMember(ctx, domainId, queueId, id) if err != nil { return nil, err } - err = app.Store.Member().Delete(ctx, queueId, id) + if !force && member.Reserved { + return nil, model.NewBadRequestError("member.reserved", "Member is reserved") + } + + err = app.Store.Member().Delete(ctx, queueId, id, force) if err != nil { return nil, err } diff --git a/grpc_api/cc_member.go b/grpc_api/cc_member.go index 9a023d9e..0471509e 100644 --- a/grpc_api/cc_member.go +++ b/grpc_api/cc_member.go @@ -521,8 +521,10 @@ func (api *member) DeleteMember(ctx context.Context, in *engine.DeleteMemberRequ } } + const force = false + var m *model.Member - m, err = api.app.RemoveMember(ctx, session.Domain(in.GetDomainId()), in.GetQueueId(), in.GetId()) + m, err = api.app.RemoveMember(ctx, session.Domain(in.GetDomainId()), in.GetQueueId(), in.GetId(), force) if err != nil { return nil, err } diff --git a/store/sqlstore/cc_member_store.go b/store/sqlstore/cc_member_store.go index bb310e56..f36c4b2a 100644 --- a/store/sqlstore/cc_member_store.go +++ b/store/sqlstore/cc_member_store.go @@ -390,29 +390,18 @@ from m return member, nil } -// TODO add force -func (s SqlMemberStore) Delete(ctx context.Context, queueId, id int64) model.AppError { - var cntCheck, cnt int64 - - check, err := s.GetMaster().WithContext(ctx).Exec(`select 1 from call_center.cc_member_attempt a where a.member_id = :Id and a.state != 'leaving' for update`, - map[string]interface{}{"Id": id}) - if err != nil { - return model.NewCustomCodeError("store.sql_member.delete.app_error", fmt.Sprintf("Id=%v, %s", id, err.Error()), extractCodeFromErr(err)) - } - cntCheck, err = check.RowsAffected() - if err != nil { - return model.NewCustomCodeError("store.sql_member.delete.app_error", fmt.Sprintf("Id=%v, %s", id, err.Error()), extractCodeFromErr(err)) - } - - if cntCheck == 0 { - return model.NewCustomCodeError("store.sql_member.delete.app_error", fmt.Sprintf("Id=%v, member reserved", id), http.StatusForbidden) - } +func (s SqlMemberStore) Delete(ctx context.Context, queueId, id int64, force bool) model.AppError { + var cnt int64 res, err := s.GetMaster().WithContext(ctx).Exec(`delete from call_center.cc_member c where c.id = :Id and c.queue_id = :QueueId - and not exists(select 1 from call_center.cc_member_attempt a where a.member_id = c.id and a.state != 'leaving' for update)`, - map[string]interface{}{"Id": id, "QueueId": queueId}) + and not exists(select 1 from call_center.cc_member_attempt a where not :Force::bool and a.member_id = c.id and a.state != 'leaving' for update)`, + map[string]interface{}{ + "Id": id, + "QueueId": queueId, + "Force": force, + }) if err != nil { return model.NewCustomCodeError("store.sql_member.delete.app_error", fmt.Sprintf("Id=%v, %s", id, err.Error()), extractCodeFromErr(err)) diff --git a/store/store.go b/store/store.go index f0c71f17..95038e12 100644 --- a/store/store.go +++ b/store/store.go @@ -312,7 +312,7 @@ type MemberStore interface { SearchMembers(ctx context.Context, domainId int64, search *model.SearchMemberRequest) ([]*model.Member, model.AppError) Get(ctx context.Context, domainId, queueId, id int64) (*model.Member, model.AppError) Update(ctx context.Context, domainId int64, member *model.Member) (*model.Member, model.AppError) - Delete(ctx context.Context, queueId, id int64) model.AppError + Delete(ctx context.Context, queueId, id int64, force bool) model.AppError MultiDelete(ctx context.Context, domainId int64, del *model.MultiDeleteMembers, withoutMembers bool) ([]*model.Member, model.AppError) ResetMembers(ctx context.Context, domainId int64, req *model.ResetMembers) (int64, model.AppError)