Use electronic signature for compliage page NDA

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2026-02-20 09:22:37 +01:00
parent c191d25e9a
commit 16503a7df4
25 changed files with 849 additions and 1125 deletions

View File

@@ -216,58 +216,6 @@ LIMIT 1
return nil
}
func (es *ElectronicSignature) LoadByOrgEmailAndDocType(
ctx context.Context,
conn pg.Conn,
scope Scoper,
orgID gid.GID,
email string,
docType ElectronicSignatureDocumentType,
fileID gid.GID,
) error {
q := `
SELECT
id, tenant_id, organization_id, status, document_type, file_id,
signer_email, consent_text, signer_full_name, signer_ip_address,
signer_user_agent, file_hash, seal, seal_version, tsa_token, signed_at,
certificate_file_id, certificate_processing_started_at,
attempt_count, max_attempts, last_attempted_at, last_error,
processing_started_at, created_at, updated_at
FROM electronic_signatures
WHERE %s
AND organization_id = @organization_id
AND signer_email = @signer_email
AND document_type = @document_type
AND file_id = @file_id
LIMIT 1
`
q = fmt.Sprintf(q, scope.SQLFragment())
args := pgx.StrictNamedArgs{
"organization_id": orgID,
"signer_email": email,
"document_type": docType,
"file_id": fileID,
}
maps.Copy(args, scope.SQLArguments())
rows, err := conn.Query(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot query electronic signature: %w", err)
}
sig, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[ElectronicSignature])
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return ErrResourceNotFound
}
return fmt.Errorf("cannot collect electronic signature: %w", err)
}
*es = sig
return nil
}
func (es *ElectronicSignature) LoadNextAcceptedForUpdateSkipLocked(
ctx context.Context,
conn pg.Conn,

View File

@@ -0,0 +1,2 @@
ALTER TABLE trust_center_accesses
ADD COLUMN electronic_signature_id TEXT REFERENCES electronic_signatures(id);

View File

@@ -42,6 +42,7 @@ type (
HasAcceptedNonDisclosureAgreement bool `db:"has_accepted_non_disclosure_agreement"`
HasAcceptedNonDisclosureAgreementMetadata json.RawMessage `db:"has_accepted_non_disclosure_agreement_metadata"`
NDAFileID *gid.GID `db:"nda_file_id"`
ElectronicSignatureID *gid.GID `db:"electronic_signature_id"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
@@ -90,6 +91,7 @@ SELECT
has_accepted_non_disclosure_agreement,
has_accepted_non_disclosure_agreement_metadata,
nda_file_id,
electronic_signature_id,
created_at,
updated_at
FROM
@@ -143,6 +145,7 @@ SELECT
has_accepted_non_disclosure_agreement,
has_accepted_non_disclosure_agreement_metadata,
nda_file_id,
electronic_signature_id,
created_at,
updated_at
FROM
@@ -196,6 +199,7 @@ INSERT INTO trust_center_accesses (
name,
state,
has_accepted_non_disclosure_agreement,
electronic_signature_id,
created_at,
updated_at
) VALUES (
@@ -207,6 +211,7 @@ INSERT INTO trust_center_accesses (
@name,
@state,
@has_accepted_non_disclosure_agreement,
@electronic_signature_id,
@created_at,
@updated_at
)
@@ -221,6 +226,7 @@ INSERT INTO trust_center_accesses (
"name": tca.Name,
"state": tca.State,
"has_accepted_non_disclosure_agreement": tca.HasAcceptedNonDisclosureAgreement,
"electronic_signature_id": tca.ElectronicSignatureID,
"created_at": tca.CreatedAt,
"updated_at": tca.UpdatedAt,
}
@@ -251,7 +257,8 @@ UPDATE trust_center_accesses SET
updated_at = @updated_at,
has_accepted_non_disclosure_agreement = @has_accepted_non_disclosure_agreement,
has_accepted_non_disclosure_agreement_metadata = @has_accepted_non_disclosure_agreement_metadata,
nda_file_id = @nda_file_id
nda_file_id = @nda_file_id,
electronic_signature_id = @electronic_signature_id
WHERE
%s
AND id = @id
@@ -266,7 +273,8 @@ WHERE
"updated_at": tca.UpdatedAt,
"has_accepted_non_disclosure_agreement": tca.HasAcceptedNonDisclosureAgreement,
"has_accepted_non_disclosure_agreement_metadata": tca.HasAcceptedNonDisclosureAgreementMetadata,
"nda_file_id": tca.NDAFileID,
"nda_file_id": tca.NDAFileID,
"electronic_signature_id": tca.ElectronicSignatureID,
}
maps.Copy(args, scope.SQLArguments())
@@ -324,6 +332,7 @@ SELECT
has_accepted_non_disclosure_agreement,
has_accepted_non_disclosure_agreement_metadata,
nda_file_id,
electronic_signature_id,
created_at,
updated_at
FROM

View File

@@ -174,16 +174,16 @@ func (s *Service) CreateSignature(
return sig, nil
}
func (s *Service) AcceptSignature(ctx context.Context, req *AcceptSignatureRequest) error {
func (s *Service) AcceptSignature(ctx context.Context, req *AcceptSignatureRequest) (*coredata.ElectronicSignature, error) {
var (
scope = coredata.NewScopeFromObjectID(req.SignatureID)
now = time.Now()
scope = coredata.NewScopeFromObjectID(req.SignatureID)
now = time.Now()
signature = coredata.ElectronicSignature{}
)
return s.pg.WithTx(
err := s.pg.WithTx(
ctx,
func(tx pg.Conn) error {
var signature coredata.ElectronicSignature
if err := signature.LoadByID(ctx, tx, scope, req.SignatureID); err != nil {
return fmt.Errorf("cannot load electronic signature: %w", err)
}
@@ -193,7 +193,6 @@ func (s *Service) AcceptSignature(ctx context.Context, req *AcceptSignatureReque
return fmt.Errorf("cannot accept electronic signature in status %s", signature.Status)
}
// If retrying from FAILED, reset attempt tracking.
if signature.Status == coredata.ElectronicSignatureStatusFailed {
signature.AttemptCount = 0
signature.LastError = nil
@@ -210,7 +209,7 @@ func (s *Service) AcceptSignature(ctx context.Context, req *AcceptSignatureReque
return fmt.Errorf("cannot update signature: %w", err)
}
s.recordEvent(
if err := s.recordEvent(
ctx,
tx,
&RecordEventRequest{
@@ -221,11 +220,18 @@ func (s *Service) AcceptSignature(ctx context.Context, req *AcceptSignatureReque
ActorIPAddr: req.SignerIPAddr,
ActorUA: req.SignerUA,
},
)
); err != nil {
return fmt.Errorf("cannot record event: %w", err)
}
return nil
},
)
if err != nil {
return nil, err
}
return &signature, nil
}
func (s *Service) RecordEvent(ctx context.Context, req *RecordEventRequest) error {
@@ -262,7 +268,7 @@ func (s *Service) recordEvent(ctx context.Context, tx pg.Conn, req *RecordEventR
return nil
}
func (s *Service) LoadSignatureByID(ctx context.Context, id gid.GID) (*coredata.ElectronicSignature, error) {
func (s *Service) GetSignatureByID(ctx context.Context, id gid.GID) (*coredata.ElectronicSignature, error) {
var (
scope = coredata.NewScopeFromObjectID(id)
signature = coredata.ElectronicSignature{}
@@ -285,36 +291,28 @@ func (s *Service) LoadSignatureByID(ctx context.Context, id gid.GID) (*coredata.
return &signature, nil
}
func (s *Service) LoadSignatureByOrgEmailAndDocType(
ctx context.Context,
orgID gid.GID,
email string,
docType coredata.ElectronicSignatureDocumentType,
fileID gid.GID,
) (*coredata.ElectronicSignature, error) {
scope := coredata.NewScopeFromObjectID(orgID)
var sig coredata.ElectronicSignature
err := s.pg.WithConn(ctx, func(conn pg.Conn) error {
return sig.LoadByOrgEmailAndDocType(ctx, conn, scope, orgID, email, docType, fileID)
})
if err != nil {
return nil, err
}
return &sig, nil
}
func (s *Service) GenerateCertificateFileURL(
ctx context.Context,
certificateFileID gid.GID,
expiresIn time.Duration,
) (string, error) {
scope := coredata.NewScopeFromObjectID(certificateFileID)
var file coredata.File
err := s.pg.WithConn(ctx, func(conn pg.Conn) error {
return file.LoadByID(ctx, conn, scope, certificateFileID)
})
var (
scope = coredata.NewScopeFromObjectID(certificateFileID)
file = coredata.File{}
)
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
if err := file.LoadByID(ctx, conn, scope, certificateFileID); err != nil {
return fmt.Errorf("cannot load certificate file: %w", err)
}
return nil
},
)
if err != nil {
return "", fmt.Errorf("cannot load certificate file: %w", err)
return "", err
}
url, err := s.fileManager.GenerateFileUrl(ctx, &file, expiresIn)
@@ -325,7 +323,7 @@ func (s *Service) GenerateCertificateFileURL(
return url, nil
}
func (s *Service) LoadEventsBySignatureID(
func (s *Service) GetEventsBySignatureID(
ctx context.Context,
signatureID gid.GID,
) (coredata.ElectronicSignatureEvents, error) {

View File

@@ -63,7 +63,7 @@ func (c *TSAClient) Timestamp(ctx context.Context, data []byte) ([]byte, error)
if err != nil {
return nil, fmt.Errorf("esign: TSA request failed: %w", err)
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("esign: TSA returned HTTP %d", resp.StatusCode)

View File

@@ -250,12 +250,8 @@ func (s TrustCenterAccessService) Create(
UpdatedAt: now,
}
if err := access.Insert(ctx, tx, s.svc.scope); err != nil {
return fmt.Errorf("cannot insert trust center access: %w", err)
}
if trustCenter.NonDisclosureAgreementFileID != nil && s.svc.esign != nil {
_, err := s.svc.esign.CreateSignature(
sig, err := s.svc.esign.CreateSignature(
ctx,
tx,
&esign.CreateSignatureRequest{
@@ -265,10 +261,14 @@ func (s TrustCenterAccessService) Create(
SignerEmail: access.Email,
},
)
if err != nil {
return fmt.Errorf("cannot create pending signature: %w", err)
}
access.ElectronicSignatureID = &sig.ID
}
if err := access.Insert(ctx, tx, s.svc.scope); err != nil {
return fmt.Errorf("cannot insert trust center access: %w", err)
}
return nil

View File

@@ -107,9 +107,8 @@ func (req *UpdateTrustCenterBrandRequest) Validate() error {
func (s TrustCenterService) Get(
ctx context.Context,
trustCenterID gid.GID,
) (*coredata.TrustCenter, *coredata.File, error) {
) (*coredata.TrustCenter, error) {
var trustCenter *coredata.TrustCenter
var file *coredata.File
err := s.svc.pg.WithConn(
ctx,
@@ -119,30 +118,22 @@ func (s TrustCenterService) Get(
return fmt.Errorf("cannot load trust center: %w", err)
}
if trustCenter.NonDisclosureAgreementFileID != nil {
file = &coredata.File{}
if err := file.LoadByID(ctx, conn, s.svc.scope, *trustCenter.NonDisclosureAgreementFileID); err != nil {
return fmt.Errorf("cannot load file: %w", err)
}
}
return nil
},
)
if err != nil {
return nil, nil, fmt.Errorf("cannot load trust center: %w", err)
return nil, fmt.Errorf("cannot load trust center: %w", err)
}
return trustCenter, file, nil
return trustCenter, nil
}
func (s TrustCenterService) GetByOrganizationID(
ctx context.Context,
organizationID gid.GID,
) (*coredata.TrustCenter, *coredata.File, error) {
) (*coredata.TrustCenter, error) {
var trustCenter *coredata.TrustCenter
var file *coredata.File
err := s.svc.pg.WithConn(
ctx,
@@ -152,22 +143,15 @@ func (s TrustCenterService) GetByOrganizationID(
return fmt.Errorf("cannot load trust center: %w", err)
}
if trustCenter.NonDisclosureAgreementFileID != nil {
file = &coredata.File{}
if err := file.LoadByID(ctx, conn, s.svc.scope, *trustCenter.NonDisclosureAgreementFileID); err != nil {
return fmt.Errorf("cannot load file: %w", err)
}
}
return nil
},
)
if err != nil {
return nil, nil, err
return nil, err
}
return trustCenter, file, nil
return trustCenter, nil
}
func (s TrustCenterService) Update(

View File

@@ -1243,7 +1243,7 @@ func (r *documentVersionSignatureConnectionResolver) TotalCount(ctx context.Cont
// CertificateFileURL is the resolver for the certificateFileUrl field.
func (r *electronicSignatureResolver) CertificateFileURL(ctx context.Context, obj *types.ElectronicSignature) (*string, error) {
sig, err := r.esign.LoadSignatureByID(ctx, obj.ID)
sig, err := r.esign.GetSignatureByID(ctx, obj.ID)
if err != nil {
return nil, fmt.Errorf("cannot load signature: %w", err)
}
@@ -1262,7 +1262,7 @@ func (r *electronicSignatureResolver) CertificateFileURL(ctx context.Context, ob
// Events is the resolver for the events field.
func (r *electronicSignatureResolver) Events(ctx context.Context, obj *types.ElectronicSignature) ([]*types.ElectronicSignatureEvent, error) {
events, err := r.esign.LoadEventsBySignatureID(ctx, obj.ID)
events, err := r.esign.GetEventsBySignatureID(ctx, obj.ID)
if err != nil {
return nil, fmt.Errorf("cannot load signature events: %w", err)
}
@@ -6394,13 +6394,13 @@ func (r *organizationResolver) TrustCenter(ctx context.Context, obj *types.Organ
prb := r.ProboService(ctx, obj.ID.TenantID())
trustCenter, file, err := prb.TrustCenters.GetByOrganizationID(ctx, obj.ID)
trustCenter, err := prb.TrustCenters.GetByOrganizationID(ctx, obj.ID)
if err != nil {
// TODO no panic use gqlutils.InternalError
panic(fmt.Errorf("cannot get trust center: %w", err))
}
return types.NewTrustCenter(trustCenter, file), nil
return types.NewTrustCenter(trustCenter, nil), nil
}
// CustomDomain is the resolver for the customDomain field.
@@ -6874,11 +6874,11 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error
case coredata.TrustCenterEntityType:
action = probo.ActionTrustCenterGet
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
trustCenter, file, err := prb.TrustCenters.Get(ctx, id)
trustCenter, err := prb.TrustCenters.Get(ctx, id)
if err != nil {
return nil, err
}
return types.NewTrustCenter(trustCenter, file), nil
return types.NewTrustCenter(trustCenter, nil), nil
}
case coredata.TrustCenterAccessEntityType:
action = probo.ActionTrustCenterAccessGet
@@ -7739,7 +7739,7 @@ func (r *trustCenterResolver) Organization(ctx context.Context, obj *types.Trust
prb := r.ProboService(ctx, obj.ID.TenantID())
trustCenter, _, err := prb.TrustCenters.Get(ctx, obj.ID)
trustCenter, err := prb.TrustCenters.Get(ctx, obj.ID)
if err != nil {
panic(fmt.Errorf("cannot get trust center: %w", err))
}
@@ -7832,24 +7832,13 @@ func (r *trustCenterAccessResolver) NdaSignature(ctx context.Context, obj *types
return nil, fmt.Errorf("cannot load trust center access: %w", err)
}
trustCenter, _, err := prb.TrustCenters.Get(ctx, access.TrustCenterID)
if err != nil {
return nil, fmt.Errorf("cannot load trust center: %w", err)
}
if trustCenter.NonDisclosureAgreementFileID == nil {
if access.ElectronicSignatureID == nil {
return nil, nil
}
sig, err := r.esign.LoadSignatureByOrgEmailAndDocType(
ctx,
access.OrganizationID,
string(access.Email),
coredata.ElectronicSignatureDocumentTypeNDA,
*trustCenter.NonDisclosureAgreementFileID,
)
sig, err := r.esign.GetSignatureByID(ctx, *access.ElectronicSignatureID)
if err != nil {
return nil, nil // No signature row — pre-existing access
return nil, nil
}
return types.NewElectronicSignature(sig), nil

View File

@@ -488,18 +488,23 @@ type TrustCenterFileEdge {
node: TrustCenterFile!
}
type NonDisclosureAgreement {
fileName: String!
fileUrl: String! @goField(forceResolver: true)
viewerSignature: ElectronicSignature @goField(forceResolver: true)
}
type TrustCenter implements Node {
id: ID!
active: Boolean!
slug: String!
logoFileUrl: String @goField(forceResolver: true)
darkLogoFileUrl: String @goField(forceResolver: true)
ndaFileName: String
ndaFileUrl: String @goField(forceResolver: true)
ndaSignature: ElectronicSignature @goField(forceResolver: true)
organization: Organization! @goField(forceResolver: true)
nonDisclosureAgreement: NonDisclosureAgreement @goField(forceResolver: true)
isViewerMember: Boolean! @goField(forceResolver: true)
hasAcceptedNonDisclosureAgreement: Boolean! @goField(forceResolver: true)
organization: Organization! @goField(forceResolver: true)
documents(
first: Int
@@ -601,14 +606,6 @@ type ExportTrustCenterFilePayload {
data: String!
}
input AcceptNonDisclosureAgreementInput {
fullName: String!
}
type AcceptNonDisclosureAgreementPayload {
success: Boolean!
}
# Electronic Signature
enum ElectronicSignatureStatus
@@ -770,11 +767,7 @@ type Mutation {
input: ExportTrustCenterFileInput!
): ExportTrustCenterFilePayload! @session(required: OPTIONAL)
acceptNonDisclosureAgreement(
input: AcceptNonDisclosureAgreementInput!
): AcceptNonDisclosureAgreementPayload @session(required: PRESENT)
requestDocumentAccess(
requestDocumentAccess(
input: RequestDocumentAccessInput!
): RequestAccessesPayload! @session(required: PRESENT)

File diff suppressed because it is too large Load Diff

View File

@@ -18,16 +18,16 @@ import (
"go.probo.inc/probo/pkg/coredata"
)
func NewTrustCenter(tc *coredata.TrustCenter, file *coredata.File) *TrustCenter {
var ndaFileName *string
if file != nil {
ndaFileName = &file.FileName
}
func NewTrustCenter(tc *coredata.TrustCenter) *TrustCenter {
return &TrustCenter{
ID: tc.ID,
Active: tc.Active,
Slug: tc.Slug,
NdaFileName: ndaFileName,
ID: tc.ID,
Active: tc.Active,
Slug: tc.Slug,
}
}
func NewNonDisclosureAgreement(file *coredata.File) *NonDisclosureAgreement {
return &NonDisclosureAgreement{
FileName: file.FileName,
}
}

View File

@@ -25,14 +25,6 @@ type AcceptElectronicSignaturePayload struct {
Signature *ElectronicSignature `json:"signature"`
}
type AcceptNonDisclosureAgreementInput struct {
FullName string `json:"fullName"`
}
type AcceptNonDisclosureAgreementPayload struct {
Success bool `json:"success"`
}
type Audit struct {
ID gid.GID `json:"id"`
Framework *Framework `json:"framework"`
@@ -136,6 +128,12 @@ func (this Identity) GetID() gid.GID { return this.ID }
type Mutation struct {
}
type NonDisclosureAgreement struct {
FileName string `json:"fileName"`
FileURL string `json:"fileUrl"`
ViewerSignature *ElectronicSignature `json:"viewerSignature,omitempty"`
}
type Organization struct {
ID gid.GID `json:"id"`
Name string `json:"name"`
@@ -203,22 +201,19 @@ type SendMagicLinkPayload struct {
}
type TrustCenter struct {
ID gid.GID `json:"id"`
Active bool `json:"active"`
Slug string `json:"slug"`
LogoFileURL *string `json:"logoFileUrl,omitempty"`
DarkLogoFileURL *string `json:"darkLogoFileUrl,omitempty"`
NdaFileName *string `json:"ndaFileName,omitempty"`
NdaFileURL *string `json:"ndaFileUrl,omitempty"`
NdaSignature *ElectronicSignature `json:"ndaSignature,omitempty"`
Organization *Organization `json:"organization"`
IsViewerMember bool `json:"isViewerMember"`
HasAcceptedNonDisclosureAgreement bool `json:"hasAcceptedNonDisclosureAgreement"`
Documents *DocumentConnection `json:"documents"`
Audits *AuditConnection `json:"audits"`
Vendors *VendorConnection `json:"vendors"`
References *TrustCenterReferenceConnection `json:"references"`
TrustCenterFiles *TrustCenterFileConnection `json:"trustCenterFiles"`
ID gid.GID `json:"id"`
Active bool `json:"active"`
Slug string `json:"slug"`
LogoFileURL *string `json:"logoFileUrl,omitempty"`
DarkLogoFileURL *string `json:"darkLogoFileUrl,omitempty"`
NonDisclosureAgreement *NonDisclosureAgreement `json:"nonDisclosureAgreement,omitempty"`
IsViewerMember bool `json:"isViewerMember"`
Organization *Organization `json:"organization"`
Documents *DocumentConnection `json:"documents"`
Audits *AuditConnection `json:"audits"`
Vendors *VendorConnection `json:"vendors"`
References *TrustCenterReferenceConnection `json:"references"`
TrustCenterFiles *TrustCenterFileConnection `json:"trustCenterFiles"`
}
func (TrustCenter) IsNode() {}

View File

@@ -88,7 +88,7 @@ func (r *documentResolver) IsUserAuthorized(ctx context.Context, obj *types.Docu
return false, nil
}
documentAccess, err := trustService.TrustCenterAccesses.LoadDocumentAccess(
documentAccess, err := trustService.TrustCenterAccesses.GetDocumentAccess(
ctx,
trustCenter.ID,
identity.EmailAddress,
@@ -123,7 +123,7 @@ func (r *documentResolver) HasUserRequestedAccess(ctx context.Context, obj *type
}
// Try to load document access - if it exists (regardless of active status), user has requested it
_, err := trustService.TrustCenterAccesses.LoadDocumentAccess(
_, err := trustService.TrustCenterAccesses.GetDocumentAccess(
ctx,
trustCenter.ID,
identity.EmailAddress,
@@ -228,6 +228,41 @@ func (r *mutationResolver) RequestAllAccesses(ctx context.Context) (*types.Reque
}, nil
}
func (r *mutationResolver) checkNDASignature(
ctx context.Context,
trustCenter *coredata.TrustCenter,
identity *coredata.Identity,
) error {
if trustCenter.NonDisclosureAgreementFileID == nil {
return nil
}
trustService := r.TrustService(ctx, trustCenter.ID.TenantID())
access, err := trustService.TrustCenterAccesses.GetAccess(ctx, trustCenter.ID, identity.EmailAddress)
if err != nil {
return gqlutils.Forbiddenf(ctx, "user has not signed the NDA")
}
if access.ElectronicSignatureID == nil {
return gqlutils.Forbiddenf(ctx, "user has not signed the NDA")
}
sig, err := r.esign.GetSignatureByID(ctx, *access.ElectronicSignatureID)
if err != nil {
return gqlutils.Forbiddenf(ctx, "user has not signed the NDA")
}
switch sig.Status {
case coredata.ElectronicSignatureStatusAccepted,
coredata.ElectronicSignatureStatusProcessing,
coredata.ElectronicSignatureStatusCompleted:
return nil
default:
return gqlutils.Forbiddenf(ctx, "user has not signed the NDA")
}
}
// ExportDocumentPDF is the resolver for the exportDocumentPDF field.
func (r *mutationResolver) ExportDocumentPDF(ctx context.Context, input types.ExportDocumentPDFInput) (*types.ExportDocumentPDFPayload, error) {
trustService := r.TrustService(ctx, input.DocumentID.TenantID())
@@ -256,35 +291,13 @@ func (r *mutationResolver) ExportDocumentPDF(ctx context.Context, input types.Ex
return nil, gqlutils.Unauthenticated(ctx, errors.New("unauthenticated"))
}
ndaExists := true
hasAcceptedNDA := false
if trustCenter.NonDisclosureAgreementFileID == nil {
ndaExists = false
}
if ndaExists {
hasAcceptedNDA, err = trustService.TrustCenterAccesses.HasAcceptedNonDisclosureAgreement(
ctx,
trustCenter.ID,
identity.EmailAddress,
)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot check if user has accepted NDA", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
}
documentAccess, err := trustService.TrustCenterAccesses.LoadDocumentAccess(
documentAccess, err := trustService.TrustCenterAccesses.GetDocumentAccess(
ctx,
trustCenter.ID,
identity.EmailAddress,
input.DocumentID,
)
if err != nil {
// FIXME check for not found and return without error in this case
// r.logger.ErrorCtx(ctx, "cannot check document access", log.Error(err))
// return false, gqlutils.Internal(ctx)
return nil, nil
}
@@ -292,8 +305,8 @@ func (r *mutationResolver) ExportDocumentPDF(ctx context.Context, input types.Ex
return nil, gqlutils.Forbiddenf(ctx, "access denied: no permission to access this document")
}
if ndaExists && !hasAcceptedNDA {
return nil, gqlutils.Forbiddenf(ctx, "user has not accepted NDA")
if err := r.checkNDASignature(ctx, trustCenter, identity); err != nil {
return nil, err
}
pdf, err := trustService.Documents.ExportPDF(ctx, input.DocumentID, identity.EmailAddress)
@@ -336,35 +349,13 @@ func (r *mutationResolver) ExportReportPDF(ctx context.Context, input types.Expo
return nil, gqlutils.Unauthenticatedf(ctx, "unauthenticated")
}
ndaExists := true
hasAcceptedNDA := false
if trustCenter.NonDisclosureAgreementFileID == nil {
ndaExists = false
}
if ndaExists {
hasAcceptedNDA, err = trustService.TrustCenterAccesses.HasAcceptedNonDisclosureAgreement(
ctx,
trustCenter.ID,
identity.EmailAddress,
)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot check if user has accepted NDA", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
}
reportAccess, err := trustService.TrustCenterAccesses.LoadReportAccess(
reportAccess, err := trustService.TrustCenterAccesses.GetReportAccess(
ctx,
trustCenter.ID,
identity.EmailAddress,
input.ReportID,
)
if err != nil {
// FIXME check for not found and return without error in this case
// r.logger.ErrorCtx(ctx, "cannot check report access", log.Error(err))
// return false, gqlutils.Internal(ctx)
return nil, nil
}
@@ -372,8 +363,8 @@ func (r *mutationResolver) ExportReportPDF(ctx context.Context, input types.Expo
return nil, gqlutils.Forbiddenf(ctx, "access denied: no permission to access this report")
}
if ndaExists && !hasAcceptedNDA {
return nil, gqlutils.Forbiddenf(ctx, "user has not accepted NDA")
if err := r.checkNDASignature(ctx, trustCenter, identity); err != nil {
return nil, err
}
pdf, err := trustService.Reports.ExportPDF(ctx, input.ReportID, identity.EmailAddress)
@@ -415,33 +406,12 @@ func (r *mutationResolver) ExportTrustCenterFile(ctx context.Context, input type
return nil, gqlutils.Unauthenticatedf(ctx, "unauthenticated")
}
ndaExists := true
hasAcceptedNDA := false
if trustCenter.NonDisclosureAgreementFileID == nil {
ndaExists = false
}
if ndaExists {
hasAcceptedNDA, err = trustService.TrustCenterAccesses.HasAcceptedNonDisclosureAgreement(ctx,
trustCenter.ID,
identity.EmailAddress,
)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot check if user has accepted NDA", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
}
fileAccess, err := trustService.TrustCenterAccesses.LoadTrustCenterFileAccess(ctx,
fileAccess, err := trustService.TrustCenterAccesses.GetTrustCenterFileAccess(ctx,
trustCenter.ID,
identity.EmailAddress,
input.TrustCenterFileID,
)
if err != nil {
// FIXME check for not found and return without error in this case
// r.logger.ErrorCtx(ctx, "cannot check trust center file access", log.Error(err))
// return false, gqlutils.Internal(ctx)
return nil, nil
}
@@ -449,8 +419,8 @@ func (r *mutationResolver) ExportTrustCenterFile(ctx context.Context, input type
return nil, gqlutils.Forbiddenf(ctx, "access denied: no permission to access this file")
}
if ndaExists && !hasAcceptedNDA {
return nil, gqlutils.Forbiddenf(ctx, "user has not accepted NDA")
if err := r.checkNDASignature(ctx, trustCenter, identity); err != nil {
return nil, err
}
fileData, err := trustService.TrustCenterFiles.ExportFile(ctx, input.TrustCenterFileID, identity.EmailAddress)
@@ -464,42 +434,6 @@ func (r *mutationResolver) ExportTrustCenterFile(ctx context.Context, input type
}, nil
}
// AcceptNonDisclosureAgreement is the resolver for the acceptNonDisclosureAgreement field.
func (r *mutationResolver) AcceptNonDisclosureAgreement(ctx context.Context, input types.AcceptNonDisclosureAgreementInput) (*types.AcceptNonDisclosureAgreementPayload, error) {
identity := authn.IdentityFromContext(ctx)
if identity == nil {
return nil, gqlutils.Unauthenticatedf(ctx, "unauthenticated")
}
trustCenter := compliancepage.CompliancePageFromContext(ctx)
trustService := r.TrustService(ctx, trustCenter.ID.TenantID())
httpReq := gqlutils.HTTPRequestFromContext(ctx)
if _, err := r.iam.AuthService.UpdateIdentity(ctx, identity.ID, input.FullName); err != nil {
var errNotFound *iam.ErrIdentityNotFound
if errors.As(err, &errNotFound) {
return nil, gqlutils.NotFound(ctx, err)
}
r.logger.ErrorCtx(ctx, "cannot update identity", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
if err := trustService.TrustCenterAccesses.AcceptNonDisclosureAgreement(
ctx,
&trust.AcceptNDARequest{
TrustCenterID: trustCenter.ID,
Email: identity.EmailAddress,
IPAddr: httpReq.RemoteAddr,
},
); err != nil {
r.logger.ErrorCtx(ctx, "cannot accept NDA", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.AcceptNonDisclosureAgreementPayload{Success: true}, nil
}
// RequestDocumentAccess is the resolver for the requestDocumentAccess field.
func (r *mutationResolver) RequestDocumentAccess(ctx context.Context, input types.RequestDocumentAccessInput) (*types.RequestAccessesPayload, error) {
trustCenter := compliancepage.CompliancePageFromContext(ctx)
@@ -651,12 +585,10 @@ func (r *mutationResolver) RequestTrustCenterFileAccess(ctx context.Context, inp
// AcceptElectronicSignature is the resolver for the acceptElectronicSignature field.
func (r *mutationResolver) AcceptElectronicSignature(ctx context.Context, input types.AcceptElectronicSignatureInput) (*types.AcceptElectronicSignaturePayload, error) {
identity := authn.IdentityFromContext(ctx)
if identity == nil {
return nil, gqlutils.Unauthenticatedf(ctx, "unauthenticated")
}
httpReq := gqlutils.HTTPRequestFromContext(ctx)
var (
identity = authn.IdentityFromContext(ctx)
httpReq = gqlutils.HTTPRequestFromContext(ctx)
)
if _, err := r.iam.AuthService.UpdateIdentity(ctx, identity.ID, input.FullName); err != nil {
var errNotFound *iam.ErrIdentityNotFound
@@ -668,45 +600,44 @@ func (r *mutationResolver) AcceptElectronicSignature(ctx context.Context, input
return nil, gqlutils.Internal(ctx)
}
if err := r.esign.AcceptSignature(ctx, &esign.AcceptSignatureRequest{
SignatureID: input.SignatureID,
SignerFullName: input.FullName,
SignerEmail: identity.EmailAddress,
SignerIPAddr: httpReq.RemoteAddr,
SignerUA: httpReq.UserAgent(),
}); err != nil {
signature, err := r.esign.AcceptSignature(
ctx,
&esign.AcceptSignatureRequest{
SignatureID: input.SignatureID,
SignerFullName: input.FullName,
SignerEmail: identity.EmailAddress,
SignerIPAddr: httpReq.RemoteAddr,
SignerUA: httpReq.UserAgent(),
},
)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot accept electronic signature", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
sig, err := r.esign.LoadSignatureByID(ctx, input.SignatureID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot load electronic signature", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.AcceptElectronicSignaturePayload{
Signature: types.NewElectronicSignature(sig),
Signature: types.NewElectronicSignature(signature),
}, nil
}
// RecordSigningEvent is the resolver for the recordSigningEvent field.
func (r *mutationResolver) RecordSigningEvent(ctx context.Context, input types.RecordSigningEventInput) (*types.RecordSigningEventPayload, error) {
identity := authn.IdentityFromContext(ctx)
if identity == nil {
return nil, gqlutils.Unauthenticatedf(ctx, "unauthenticated")
}
var (
identity = authn.IdentityFromContext(ctx)
httpReq = gqlutils.HTTPRequestFromContext(ctx)
)
httpReq := gqlutils.HTTPRequestFromContext(ctx)
if err := r.esign.RecordEvent(ctx, &esign.RecordEventRequest{
SignatureID: input.SignatureID,
EventType: input.EventType,
EventSource: coredata.ElectronicSignatureEventSourceClient,
ActorEmail: identity.EmailAddress,
ActorIPAddr: httpReq.RemoteAddr,
ActorUA: httpReq.UserAgent(),
}); err != nil {
if err := r.esign.RecordEvent(
ctx,
&esign.RecordEventRequest{
SignatureID: input.SignatureID,
EventType: input.EventType,
EventSource: coredata.ElectronicSignatureEventSourceClient,
ActorEmail: identity.EmailAddress,
ActorIPAddr: httpReq.RemoteAddr,
ActorUA: httpReq.UserAgent(),
},
); err != nil {
r.logger.ErrorCtx(ctx, "cannot record signing event", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
@@ -714,6 +645,46 @@ func (r *mutationResolver) RecordSigningEvent(ctx context.Context, input types.R
return &types.RecordSigningEventPayload{Success: true}, nil
}
// FileURL is the resolver for the fileUrl field.
func (r *nonDisclosureAgreementResolver) FileURL(ctx context.Context, obj *types.NonDisclosureAgreement) (string, error) {
trustCenter := compliancepage.CompliancePageFromContext(ctx)
trustService := r.TrustService(ctx, trustCenter.ID.TenantID())
fileURL, err := trustService.TrustCenters.GenerateNDAFileURL(ctx, trustCenter.ID, 15*time.Minute)
if err != nil {
return "", gqlutils.Internal(ctx)
}
return fileURL, nil
}
// ViewerSignature is the resolver for the viewerSignature field.
func (r *nonDisclosureAgreementResolver) ViewerSignature(ctx context.Context, obj *types.NonDisclosureAgreement) (*types.ElectronicSignature, error) {
identity := authn.IdentityFromContext(ctx)
if identity == nil {
return nil, nil
}
trustCenter := compliancepage.CompliancePageFromContext(ctx)
trustService := r.TrustService(ctx, trustCenter.ID.TenantID())
access, err := trustService.TrustCenterAccesses.GetAccess(ctx, trustCenter.ID, identity.EmailAddress)
if err != nil {
return nil, nil
}
if access.ElectronicSignatureID == nil {
return nil, nil
}
sig, err := r.esign.GetSignatureByID(ctx, *access.ElectronicSignatureID)
if err != nil {
return nil, nil
}
return types.NewElectronicSignature(sig), nil
}
// LogoURL is the resolver for the logoUrl field.
func (r *organizationResolver) LogoURL(ctx context.Context, obj *types.Organization) (*string, error) {
trustService := r.TrustService(ctx, obj.ID.TenantID())
@@ -793,12 +764,12 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error
return types.NewVendor(vendor), nil
case coredata.TrustCenterEntityType:
trustCenter, file, err := trustService.TrustCenters.Get(ctx, id)
trustCenter, err := trustService.TrustCenters.Get(ctx, id)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot get trust center", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return types.NewTrustCenter(trustCenter, file), nil
return types.NewTrustCenter(trustCenter), nil
case coredata.TrustCenterReferenceEntityType:
reference, err := trustService.TrustCenterReferences.Get(ctx, id)
@@ -824,12 +795,12 @@ func (r *queryResolver) CurrentTrustCenter(ctx context.Context) (*types.TrustCen
panic(fmt.Errorf("cannot get organization: %w", err))
}
trustCenter, file, err := trustService.TrustCenters.Get(ctx, trustCenter.ID)
trustCenter, err = trustService.TrustCenters.Get(ctx, trustCenter.ID)
if err != nil {
panic(fmt.Errorf("cannot get trust center: %w", err))
}
response := types.NewTrustCenter(trustCenter, file)
response := types.NewTrustCenter(trustCenter)
response.Organization = types.NewOrganization(org)
return response, nil
@@ -856,7 +827,7 @@ func (r *reportResolver) IsUserAuthorized(ctx context.Context, obj *types.Report
return false, nil
}
reportAccess, err := trustService.TrustCenterAccesses.LoadReportAccess(ctx,
reportAccess, err := trustService.TrustCenterAccesses.GetReportAccess(ctx,
trustCenter.ID,
identity.EmailAddress,
obj.ID,
@@ -890,7 +861,7 @@ func (r *reportResolver) HasUserRequestedAccess(ctx context.Context, obj *types.
return false, nil // User is not authenticated, so no access requested
}
_, err := trustService.TrustCenterAccesses.LoadReportAccess(ctx,
_, err := trustService.TrustCenterAccesses.GetReportAccess(ctx,
trustCenter.ID,
identity.EmailAddress,
obj.ID,
@@ -919,50 +890,25 @@ func (r *trustCenterResolver) DarkLogoFileURL(ctx context.Context, obj *types.Tr
return trustService.TrustCenters.GenerateDarkLogoURL(ctx, obj.ID, 1*time.Hour)
}
// NdaFileURL is the resolver for the ndaFileUrl field.
func (r *trustCenterResolver) NdaFileURL(ctx context.Context, obj *types.TrustCenter) (*string, error) {
// NonDisclosureAgreement is the resolver for the nonDisclosureAgreement field.
func (r *trustCenterResolver) NonDisclosureAgreement(ctx context.Context, obj *types.TrustCenter) (*types.NonDisclosureAgreement, error) {
trustCenter := compliancepage.CompliancePageFromContext(ctx)
if trustCenter.NonDisclosureAgreementFileID == nil {
return nil, nil
}
trustService := r.TrustService(ctx, obj.ID.TenantID())
fileURL, err := trustService.TrustCenters.GenerateNDAFileURL(ctx, obj.ID, 15*time.Minute)
file, err := trustService.TrustCenters.GetNDAFile(ctx, obj.ID)
if err != nil {
// FIXME: add error not found check etc
// r.logger.ErrorCtx(ctx, "cannot generate NDA file URL", log.Error(err))
// return nil, gqlutils.Internal(ctx)
r.logger.ErrorCtx(ctx, "cannot load NDA file", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
if file == nil {
return nil, nil
}
return &fileURL, nil
}
// NdaSignature is the resolver for the ndaSignature field.
func (r *trustCenterResolver) NdaSignature(ctx context.Context, obj *types.TrustCenter) (*types.ElectronicSignature, error) {
identity := authn.IdentityFromContext(ctx)
if identity == nil {
return nil, nil
}
trustCenter := compliancepage.CompliancePageFromContext(ctx)
if trustCenter == nil || trustCenter.NonDisclosureAgreementFileID == nil {
return nil, nil
}
sig, err := r.esign.LoadSignatureByOrgEmailAndDocType(
ctx,
trustCenter.OrganizationID,
identity.EmailAddress.String(),
coredata.ElectronicSignatureDocumentTypeNDA,
*trustCenter.NonDisclosureAgreementFileID,
)
if err != nil {
return nil, nil
}
return types.NewElectronicSignature(sig), nil
}
// Organization is the resolver for the organization field.
func (r *trustCenterResolver) Organization(ctx context.Context, obj *types.TrustCenter) (*types.Organization, error) {
return obj.Organization, nil
return types.NewNonDisclosureAgreement(file), nil
}
// IsViewerMember is the resolver for the isViewerMember field.
@@ -972,22 +918,9 @@ func (r *trustCenterResolver) IsViewerMember(ctx context.Context, obj *types.Tru
return membership != nil, nil
}
// HasAcceptedNonDisclosureAgreement is the resolver for the hasAcceptedNonDisclosureAgreement field.
func (r *trustCenterResolver) HasAcceptedNonDisclosureAgreement(ctx context.Context, obj *types.TrustCenter) (bool, error) {
trustService := r.TrustService(ctx, obj.ID.TenantID())
identity := authn.IdentityFromContext(ctx)
if identity == nil {
return false, nil // User is not authenticated, so no NDA accepted
}
hasAcceptedNDA, err := trustService.TrustCenterAccesses.HasAcceptedNonDisclosureAgreement(ctx, obj.ID, identity.EmailAddress)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot check if user has accepted NDA", log.Error(err))
return false, gqlutils.Internal(ctx)
}
return hasAcceptedNDA, nil
// Organization is the resolver for the organization field.
func (r *trustCenterResolver) Organization(ctx context.Context, obj *types.TrustCenter) (*types.Organization, error) {
return obj.Organization, nil
}
// Documents is the resolver for the documents field.
@@ -1112,7 +1045,7 @@ func (r *trustCenterFileResolver) IsUserAuthorized(ctx context.Context, obj *typ
return false, nil
}
fileAccess, err := trustService.TrustCenterAccesses.LoadTrustCenterFileAccess(ctx,
fileAccess, err := trustService.TrustCenterAccesses.GetTrustCenterFileAccess(ctx,
trustCenter.ID,
identity.EmailAddress,
obj.ID,
@@ -1146,7 +1079,7 @@ func (r *trustCenterFileResolver) HasUserRequestedAccess(ctx context.Context, ob
return false, nil // User is not authenticated, so no access requested
}
_, err := trustService.TrustCenterAccesses.LoadTrustCenterFileAccess(ctx,
_, err := trustService.TrustCenterAccesses.GetTrustCenterFileAccess(ctx,
trustCenter.ID,
identity.EmailAddress,
obj.ID,
@@ -1201,6 +1134,11 @@ func (r *Resolver) Framework() schema.FrameworkResolver { return &frameworkResol
// Mutation returns schema.MutationResolver implementation.
func (r *Resolver) Mutation() schema.MutationResolver { return &mutationResolver{r} }
// NonDisclosureAgreement returns schema.NonDisclosureAgreementResolver implementation.
func (r *Resolver) NonDisclosureAgreement() schema.NonDisclosureAgreementResolver {
return &nonDisclosureAgreementResolver{r}
}
// Organization returns schema.OrganizationResolver implementation.
func (r *Resolver) Organization() schema.OrganizationResolver { return &organizationResolver{r} }
@@ -1232,6 +1170,7 @@ type auditResolver struct{ *Resolver }
type documentResolver struct{ *Resolver }
type frameworkResolver struct{ *Resolver }
type mutationResolver struct{ *Resolver }
type nonDisclosureAgreementResolver struct{ *Resolver }
type organizationResolver struct{ *Resolver }
type queryResolver struct{ *Resolver }
type reportResolver struct{ *Resolver }

View File

@@ -16,7 +16,6 @@ package trust
import (
"context"
"encoding/json"
"errors"
"fmt"
"time"
@@ -155,13 +154,8 @@ func (s TrustCenterAccessService) Request(
UpdatedAt: now,
}
if err := access.Insert(ctx, tx, s.svc.scope); err != nil {
return fmt.Errorf("cannot insert trust center access: %w", err)
}
// Create PENDING electronic signature when NDA is configured.
if trustCenter.NonDisclosureAgreementFileID != nil && s.svc.esign != nil {
_, err := s.svc.esign.CreateSignature(
sig, err := s.svc.esign.CreateSignature(
ctx,
tx,
&esign.CreateSignatureRequest{
@@ -174,6 +168,11 @@ func (s TrustCenterAccessService) Request(
if err != nil {
return fmt.Errorf("cannot create pending signature: %w", err)
}
access.ElectronicSignatureID = &sig.ID
}
if err := access.Insert(ctx, tx, s.svc.scope); err != nil {
return fmt.Errorf("cannot insert trust center access: %w", err)
}
}
@@ -243,93 +242,21 @@ func (s TrustCenterAccessService) Request(
return access, nil
}
func (s TrustCenterAccessService) HasAcceptedNonDisclosureAgreement(ctx context.Context, trustCenterID gid.GID, email mail.Addr) (bool, error) {
func (s TrustCenterAccessService) GetAccess(
ctx context.Context,
trustCenterID gid.GID,
email mail.Addr,
) (coredata.TrustCenterAccess, error) {
var access coredata.TrustCenterAccess
err := s.svc.pg.WithConn(ctx, func(conn pg.Conn) error {
return access.LoadByTrustCenterIDAndEmail(ctx, conn, s.svc.scope, trustCenterID, email)
})
if err != nil {
return false, nil
}
// Legacy path: check the old boolean field.
if access.HasAcceptedNonDisclosureAgreement {
return true, nil
}
// New path: check for an electronic signature in ACCEPTED or later status.
if s.svc.esign != nil {
trustCenter := &coredata.TrustCenter{}
err := s.svc.pg.WithConn(ctx, func(conn pg.Conn) error {
return trustCenter.LoadByID(ctx, conn, s.svc.scope, trustCenterID)
})
if err != nil {
return false, nil
}
if trustCenter.NonDisclosureAgreementFileID != nil {
sig, err := s.svc.esign.LoadSignatureByOrgEmailAndDocType(
ctx,
trustCenter.OrganizationID,
email.String(),
coredata.ElectronicSignatureDocumentTypeNDA,
*trustCenter.NonDisclosureAgreementFileID,
)
if err == nil {
switch sig.Status {
case coredata.ElectronicSignatureStatusAccepted,
coredata.ElectronicSignatureStatusProcessing,
coredata.ElectronicSignatureStatusCompleted:
return true, nil
}
}
}
}
return false, nil
return access, err
}
type AcceptNDARequest struct {
TrustCenterID gid.GID
Email mail.Addr
IPAddr string
}
func (s TrustCenterAccessService) AcceptNonDisclosureAgreement(ctx context.Context, req *AcceptNDARequest) error {
return s.svc.pg.WithTx(ctx, func(tx pg.Conn) error {
access := &coredata.TrustCenterAccess{}
if err := access.LoadByTrustCenterIDAndEmail(ctx, tx, s.svc.scope, req.TrustCenterID, req.Email); err != nil {
return fmt.Errorf("cannot load trust center access: %w", err)
}
trustCenter := &coredata.TrustCenter{}
if err := trustCenter.LoadByID(ctx, tx, s.svc.scope, req.TrustCenterID); err != nil {
return fmt.Errorf("cannot load trust center: %w", err)
}
acceptationLogs, err := json.Marshal(map[string]string{
"email": req.Email.String(),
"timestamp": time.Now().Format(time.RFC3339),
"ip": req.IPAddr,
})
if err != nil {
return fmt.Errorf("cannot marshal non disclosure agreement acceptation logs: %w", err)
}
access.HasAcceptedNonDisclosureAgreement = true
access.UpdatedAt = time.Now()
access.HasAcceptedNonDisclosureAgreementMetadata = acceptationLogs
access.NDAFileID = trustCenter.NonDisclosureAgreementFileID
if err := access.Update(ctx, tx, s.svc.scope); err != nil {
return fmt.Errorf("cannot update trust center access: %w", err)
}
return nil
})
}
func (s TrustCenterAccessService) LoadDocumentAccess(
func (s TrustCenterAccessService) GetDocumentAccess(
ctx context.Context,
trustCenterID gid.GID,
email mail.Addr,
@@ -372,7 +299,7 @@ func (s TrustCenterAccessService) LoadDocumentAccess(
return documentAccess, nil
}
func (s TrustCenterAccessService) LoadReportAccess(
func (s TrustCenterAccessService) GetReportAccess(
ctx context.Context,
trustCenterID gid.GID,
email mail.Addr,
@@ -415,7 +342,7 @@ func (s TrustCenterAccessService) LoadReportAccess(
return reportAccess, nil
}
func (s TrustCenterAccessService) LoadTrustCenterFileAccess(
func (s TrustCenterAccessService) GetTrustCenterFileAccess(
ctx context.Context,
trustCenterID gid.GID,
email mail.Addr,

View File

@@ -34,9 +34,8 @@ type TrustCenterService struct {
func (s TrustCenterService) Get(
ctx context.Context,
trustCenterID gid.GID,
) (*coredata.TrustCenter, *coredata.File, error) {
) (*coredata.TrustCenter, error) {
var trustCenter *coredata.TrustCenter
var file *coredata.File
err := s.svc.pg.WithConn(
ctx,
@@ -46,22 +45,15 @@ func (s TrustCenterService) Get(
return fmt.Errorf("cannot load trust center: %w", err)
}
if trustCenter.NonDisclosureAgreementFileID != nil {
file = &coredata.File{}
if err := file.LoadByID(ctx, conn, s.svc.scope, *trustCenter.NonDisclosureAgreementFileID); err != nil {
return fmt.Errorf("cannot load file: %w", err)
}
}
return nil
},
)
if err != nil {
return nil, nil, fmt.Errorf("cannot load trust center: %w", err)
return nil, fmt.Errorf("cannot load trust center: %w", err)
}
return trustCenter, file, nil
return trustCenter, nil
}
func (s TrustCenterService) GetByOrganizationID(
@@ -89,6 +81,39 @@ func (s TrustCenterService) GetByOrganizationID(
return trustCenter, nil
}
func (s TrustCenterService) GetNDAFile(
ctx context.Context,
trustCenterID gid.GID,
) (*coredata.File, error) {
var file *coredata.File
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
trustCenter := &coredata.TrustCenter{}
if err := trustCenter.LoadByID(ctx, conn, s.svc.scope, trustCenterID); err != nil {
return fmt.Errorf("cannot load trust center: %w", err)
}
if trustCenter.NonDisclosureAgreementFileID == nil {
return nil
}
file = &coredata.File{}
if err := file.LoadByID(ctx, conn, s.svc.scope, *trustCenter.NonDisclosureAgreementFileID); err != nil {
return fmt.Errorf("cannot load file: %w", err)
}
return nil
},
)
if err != nil {
return nil, err
}
return file, nil
}
func (s TrustCenterService) GenerateNDAFileURL(
ctx context.Context,
trustCenterID gid.GID,

View File

@@ -92,7 +92,7 @@ func (s VendorService) CountForTrustCenterId(
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) (err error) {
trustCenter, _, err := s.svc.TrustCenters.Get(ctx, trustCenterID)
trustCenter, err := s.svc.TrustCenters.Get(ctx, trustCenterID)
if err != nil {
return fmt.Errorf("cannot load trust center: %w", err)
}