diff --git a/pkg/probo/document_approval_service.go b/pkg/probo/document_approval_service.go index f3786ff7a..5a608138b 100644 --- a/pkg/probo/document_approval_service.go +++ b/pkg/probo/document_approval_service.go @@ -705,6 +705,36 @@ func (s *DocumentApprovalService) voidApprovalInTx( return nil } +func (s *DocumentApprovalService) voidPendingApprovalForLatestVersionInTx( + ctx context.Context, scope coredata.Scoper, + tx pg.Tx, + document *coredata.Document, + documentVersion *coredata.DocumentVersion, +) error { + if documentVersion.Status != coredata.DocumentVersionStatusPendingApproval { + return nil + } + + quorum := &coredata.DocumentVersionApprovalQuorum{} + if err := quorum.LoadLastByDocumentVersionID(ctx, tx, scope, documentVersion.ID); err != nil { + if errors.Is(err, coredata.ErrResourceNotFound) { + return nil + } + + return fmt.Errorf("cannot load approval quorum: %w", err) + } + + if quorum.Status != coredata.DocumentVersionApprovalQuorumStatusPending { + return nil + } + + if err := s.voidApprovalInTx(ctx, scope, tx, document, documentVersion, quorum); err != nil { + return fmt.Errorf("cannot void pending approval: %w", err) + } + + return nil +} + func (s *DocumentApprovalService) GetQuorum( ctx context.Context, scope coredata.Scoper, quorumID gid.GID, diff --git a/pkg/probo/document_service.go b/pkg/probo/document_service.go index 273062ade..49ad8dc83 100644 --- a/pkg/probo/document_service.go +++ b/pkg/probo/document_service.go @@ -1753,102 +1753,6 @@ func (s *DocumentService) clearDocumentReferences( return nil } -func (s *DocumentService) teardownDocumentWorkflowsInTx( - ctx context.Context, scope coredata.Scoper, - tx pg.Tx, - documentID gid.GID, -) error { - document := &coredata.Document{} - if err := document.LoadByID(ctx, tx, scope, documentID); err != nil { - return fmt.Errorf("cannot load document %q: %w", documentID, err) - } - - documentVersion := &coredata.DocumentVersion{} - if err := documentVersion.LoadLatestVersion(ctx, tx, scope, documentID); err != nil { - return fmt.Errorf("cannot load latest document version: %w", err) - } - - if documentVersion.Status == coredata.DocumentVersionStatusPendingApproval { - quorum := &coredata.DocumentVersionApprovalQuorum{} - if err := quorum.LoadLastByDocumentVersionID(ctx, tx, scope, documentVersion.ID); err != nil { - if !errors.Is(err, coredata.ErrResourceNotFound) { - return fmt.Errorf("cannot load approval quorum: %w", err) - } - } else if quorum.Status == coredata.DocumentVersionApprovalQuorumStatusPending { - if err := s.svc.DocumentApprovals.voidApprovalInTx(ctx, scope, tx, document, documentVersion, quorum); err != nil { - return err - } - } - } - - signatures := &coredata.DocumentVersionSignatures{} - if err := signatures.LoadRequestedByDocumentID(ctx, tx, scope, documentID); err != nil { - return fmt.Errorf("cannot load requested document version signatures: %w", err) - } - - for _, signature := range *signatures { - version := &coredata.DocumentVersion{} - if err := version.LoadByID(ctx, tx, scope, signature.DocumentVersionID); err != nil { - return fmt.Errorf("cannot load document version: %w", err) - } - - if err := signature.Delete(ctx, tx, scope, signature.ID); err != nil { - return fmt.Errorf("cannot delete document version signature: %w", err) - } - - if err := s.emitDocumentEvent( - ctx, - scope, - tx, - documentID, - coredata.WebhookEventTypeDocumentVersionSignatureCancelled, - version, - signature, - nil, - nil, - ); err != nil { - return fmt.Errorf("cannot emit document version signature cancelled webhook: %w", err) - } - } - - return nil -} - -func (s *DocumentService) ensureDraftReadyOnUnarchiveInTx( - ctx context.Context, scope coredata.Scoper, - tx pg.Tx, - documentID gid.GID, -) error { - document := &coredata.Document{} - if err := document.LoadByID(ctx, tx, scope, documentID); err != nil { - return fmt.Errorf("cannot load document %q: %w", documentID, err) - } - - documentVersion := &coredata.DocumentVersion{} - if err := documentVersion.LoadLatestVersion(ctx, tx, scope, documentID); err != nil { - return fmt.Errorf("cannot load latest document version: %w", err) - } - - if documentVersion.Status != coredata.DocumentVersionStatusPendingApproval { - return nil - } - - quorum := &coredata.DocumentVersionApprovalQuorum{} - if err := quorum.LoadLastByDocumentVersionID(ctx, tx, scope, documentVersion.ID); err != nil { - if errors.Is(err, coredata.ErrResourceNotFound) { - return nil - } - - return fmt.Errorf("cannot load approval quorum: %w", err) - } - - if quorum.Status != coredata.DocumentVersionApprovalQuorumStatusPending { - return nil - } - - return s.svc.DocumentApprovals.voidApprovalInTx(ctx, scope, tx, document, documentVersion, quorum) -} - func (s *DocumentService) RequestExport( ctx context.Context, scope coredata.Scoper, documentIDs []gid.GID, @@ -2498,6 +2402,58 @@ func (s *DocumentService) DeleteDraft( return document, nil } +func (s *DocumentService) teardownDocumentWorkflowsInTx( + ctx context.Context, scope coredata.Scoper, + tx pg.Tx, + documentID gid.GID, +) error { + document := &coredata.Document{} + if err := document.LoadByID(ctx, tx, scope, documentID); err != nil { + return fmt.Errorf("cannot load document %q: %w", documentID, err) + } + + documentVersion := &coredata.DocumentVersion{} + if err := documentVersion.LoadLatestVersion(ctx, tx, scope, documentID); err != nil { + return fmt.Errorf("cannot load latest document version: %w", err) + } + + if err := s.svc.DocumentApprovals.voidPendingApprovalForLatestVersionInTx( + ctx, + scope, + tx, + document, + documentVersion, + ); err != nil { + return err + } + + return s.cancelRequestedSignaturesForDocumentInTx(ctx, scope, tx, documentID) +} + +func (s *DocumentService) ensureDraftReadyOnUnarchiveInTx( + ctx context.Context, scope coredata.Scoper, + tx pg.Tx, + documentID gid.GID, +) error { + document := &coredata.Document{} + if err := document.LoadByID(ctx, tx, scope, documentID); err != nil { + return fmt.Errorf("cannot load document %q: %w", documentID, err) + } + + documentVersion := &coredata.DocumentVersion{} + if err := documentVersion.LoadLatestVersion(ctx, tx, scope, documentID); err != nil { + return fmt.Errorf("cannot load latest document version: %w", err) + } + + return s.svc.DocumentApprovals.voidPendingApprovalForLatestVersionInTx( + ctx, + scope, + tx, + document, + documentVersion, + ) +} + func (s *DocumentService) Archive( ctx context.Context, scope coredata.Scoper, documentID gid.GID, @@ -3432,6 +3388,44 @@ func (s *DocumentService) publishMajor( // major supersedes the signing obligations of older majors, so their // REQUESTED signatures must not linger. SIGNED signatures are left untouched // to preserve the audit trail. +func (s *DocumentService) cancelRequestedSignaturesForDocumentInTx( + ctx context.Context, scope coredata.Scoper, + tx pg.Tx, + documentID gid.GID, +) error { + signatures := &coredata.DocumentVersionSignatures{} + if err := signatures.LoadRequestedByDocumentID(ctx, tx, scope, documentID); err != nil { + return fmt.Errorf("cannot load requested document version signatures: %w", err) + } + + for _, signature := range *signatures { + version := &coredata.DocumentVersion{} + if err := version.LoadByID(ctx, tx, scope, signature.DocumentVersionID); err != nil { + return fmt.Errorf("cannot load document version: %w", err) + } + + if err := signature.Delete(ctx, tx, scope, signature.ID); err != nil { + return fmt.Errorf("cannot delete document version signature: %w", err) + } + + if err := s.emitDocumentEvent( + ctx, + scope, + tx, + documentID, + coredata.WebhookEventTypeDocumentVersionSignatureCancelled, + version, + signature, + nil, + nil, + ); err != nil { + return fmt.Errorf("cannot emit document version signature cancelled webhook: %w", err) + } + } + + return nil +} + func (s *DocumentService) cancelPreviousMajorSignatureRequestsInTx( ctx context.Context, scope coredata.Scoper, tx pg.Tx,