From e4005e0f740d7ecf0b5c09dc1546499adba1ee85 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 12 May 2026 06:46:27 +0000 Subject: [PATCH] Filter inactive people from signature request recipients MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The signature request recipient lists (both the multi-select dialog and the document signatures page) included people who were inactive via SCIM deactivation. The existing filter only excluded people with ended contracts but not those with an INACTIVE state. This adds state: ACTIVE to the ProfileFilter in both frontend queries and introduces a server-side ErrProfileInactive validation in the RequestSignature and BulkRequestSignatures service methods to reject inactive profiles even if called directly via API. Co-authored-by: Émile Ré Signed-off-by: Émile Ré Signed-off-by: Émile Ré --- .../_components/SignatureDocumentsDialog.tsx | 2 +- .../signatures/DocumentSignaturesPage.tsx | 2 +- pkg/probo/document_service.go | 15 +++++++++++++++ pkg/server/api/console/v1/document_resolvers.go | 8 ++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/apps/console/src/pages/organizations/documents/_components/SignatureDocumentsDialog.tsx b/apps/console/src/pages/organizations/documents/_components/SignatureDocumentsDialog.tsx index dabf2cffa..b7e833581 100644 --- a/apps/console/src/pages/organizations/documents/_components/SignatureDocumentsDialog.tsx +++ b/apps/console/src/pages/organizations/documents/_components/SignatureDocumentsDialog.tsx @@ -196,7 +196,7 @@ function PeopleList({ signatureDocumentsDialogPeopleQuery, { organizationId, - filter: { contractEnded: false }, + filter: { contractEnded: false, state: "ACTIVE" }, }, ); const { diff --git a/apps/console/src/pages/organizations/documents/signatures/DocumentSignaturesPage.tsx b/apps/console/src/pages/organizations/documents/signatures/DocumentSignaturesPage.tsx index 993476b32..052f8c165 100644 --- a/apps/console/src/pages/organizations/documents/signatures/DocumentSignaturesPage.tsx +++ b/apps/console/src/pages/organizations/documents/signatures/DocumentSignaturesPage.tsx @@ -27,7 +27,7 @@ export const documentSignaturesPageQuery = graphql` query DocumentSignaturesPageQuery($documentId: ID! $organizationId: ID! $versionId: ID! $versionSpecified: Boolean!) { organization: node(id: $organizationId) { __typename - ...DocumentSignatureList_peopleFragment @arguments(filter: { contractEnded: false }) + ...DocumentSignatureList_peopleFragment @arguments(filter: { contractEnded: false, state: ACTIVE }) } # We use this on /documents/:documentId document: node(id: $documentId) @skip(if: $versionSpecified) { diff --git a/pkg/probo/document_service.go b/pkg/probo/document_service.go index 5e11cac51..7de295e86 100644 --- a/pkg/probo/document_service.go +++ b/pkg/probo/document_service.go @@ -97,6 +97,10 @@ type ( ProfileID gid.GID } + ErrProfileInactive struct { + ProfileID gid.GID + } + CreateDocumentRequest struct { OrganizationID gid.GID Title string @@ -278,6 +282,10 @@ func (e ErrProfileContractEnded) Error() string { return fmt.Sprintf("cannot use profile %q: contract has ended", e.ProfileID) } +func (e ErrProfileInactive) Error() string { + return fmt.Sprintf("cannot use profile %q: profile is inactive", e.ProfileID) +} + func (s *DocumentService) Get( ctx context.Context, documentID gid.GID, @@ -971,6 +979,9 @@ func (s *DocumentService) BulkRequestSignatures( now := time.Now() for _, p := range *profiles { + if p.State == coredata.ProfileStateInactive { + return &ErrProfileInactive{ProfileID: p.ID} + } if p.ContractEndDate != nil && p.ContractEndDate.Before(now) { return &ErrProfileContractEnded{ProfileID: p.ID} } @@ -1082,6 +1093,10 @@ func (s *DocumentService) RequestSignature( return fmt.Errorf("cannot load signatory profile: %w", err) } + if profile.State == coredata.ProfileStateInactive { + return &ErrProfileInactive{ProfileID: profile.ID} + } + if profile.ContractEndDate != nil && profile.ContractEndDate.Before(time.Now()) { return &ErrProfileContractEnded{ProfileID: profile.ID} } diff --git a/pkg/server/api/console/v1/document_resolvers.go b/pkg/server/api/console/v1/document_resolvers.go index 467d3d3bf..e33bf6bba 100644 --- a/pkg/server/api/console/v1/document_resolvers.go +++ b/pkg/server/api/console/v1/document_resolvers.go @@ -1296,6 +1296,10 @@ func (r *mutationResolver) RequestSignature(ctx context.Context, input types.Req return nil, gqlutils.Conflict(ctx, errContractEnded) } + if errInactive, ok := errors.AsType[*probo.ErrProfileInactive](err); ok { + return nil, gqlutils.Conflict(ctx, errInactive) + } + r.logger.ErrorCtx(ctx, "cannot request signature", log.Error(err)) return nil, gqlutils.Internal(ctx) } @@ -1341,6 +1345,10 @@ func (r *mutationResolver) BulkRequestSignatures(ctx context.Context, input type return nil, gqlutils.Conflict(ctx, errContractEnded) } + if errInactive, ok := errors.AsType[*probo.ErrProfileInactive](err); ok { + return nil, gqlutils.Conflict(ctx, errInactive) + } + r.logger.ErrorCtx(ctx, "cannot bulk request signatures", log.Error(err)) return nil, gqlutils.Internal(ctx) }