@@ -94,6 +94,7 @@ enum InvitationStatus
|
||||
enum MembershipRole @goModel(model: "go.probo.inc/probo/pkg/coredata.MembershipRole") {
|
||||
OWNER @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleOwner")
|
||||
ADMIN @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleAdmin")
|
||||
EMPLOYEE @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleEmployee")
|
||||
VIEWER @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleViewer")
|
||||
}
|
||||
|
||||
@@ -522,10 +523,6 @@ enum BusinessImpact
|
||||
|
||||
enum DocumentVersionOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.DocumentVersionOrderField") {
|
||||
VERSION
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionOrderFieldVersion"
|
||||
)
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionOrderFieldCreatedAt"
|
||||
@@ -2035,6 +2032,29 @@ type Document implements Node {
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type SignableDocument @goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.SignableDocument"
|
||||
){
|
||||
id: ID!
|
||||
title: String!
|
||||
description: String
|
||||
documentType: DocumentType!
|
||||
classification: DocumentClassification!
|
||||
signed: Boolean! @goField(forceResolver: true)
|
||||
|
||||
versions(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: DocumentVersionOrder
|
||||
filter: DocumentVersionFilter
|
||||
): DocumentVersionConnection! @goField(forceResolver: true)
|
||||
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type Meeting implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
@@ -2259,6 +2279,17 @@ type Viewer {
|
||||
before: CursorKey
|
||||
orderBy: OrganizationOrder
|
||||
): OrganizationConnection! @goField(forceResolver: true)
|
||||
|
||||
signableDocuments(
|
||||
organizationId: ID!
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: DocumentOrder
|
||||
): SignableDocumentConnection! @goField(forceResolver: true)
|
||||
|
||||
signableDocument(id: ID!): SignableDocument @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
# Connection Types
|
||||
@@ -2514,6 +2545,22 @@ type EvidenceEdge {
|
||||
node: Evidence!
|
||||
}
|
||||
|
||||
type SignableDocumentConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.SignableDocumentConnection"
|
||||
) {
|
||||
edges: [SignableDocumentEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type SignableDocumentEdge
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.SignableDocumentEdge"
|
||||
) {
|
||||
cursor: CursorKey!
|
||||
node: SignableDocument!
|
||||
}
|
||||
|
||||
type DocumentConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.DocumentConnection"
|
||||
@@ -2914,9 +2961,16 @@ type Mutation {
|
||||
input: SendSigningNotificationsInput!
|
||||
): SendSigningNotificationsPayload! cancelSignatureRequest(
|
||||
input: CancelSignatureRequestInput!
|
||||
): CancelSignatureRequestPayload! exportDocumentVersionPDF(
|
||||
): CancelSignatureRequestPayload!
|
||||
signDocument(
|
||||
input: SignDocumentInput!
|
||||
): SignDocumentPayload!
|
||||
exportDocumentVersionPDF(
|
||||
input: ExportDocumentVersionPDFInput!
|
||||
): ExportDocumentVersionPDFPayload!
|
||||
exportSignableVersionDocumentPDF(
|
||||
input: ExportSignableDocumentVersionPDFInput!
|
||||
): ExportSignableDocumentVersionPDFPayload!
|
||||
createVendorRiskAssessment(
|
||||
input: CreateVendorRiskAssessmentInput!
|
||||
): CreateVendorRiskAssessmentPayload!
|
||||
@@ -3488,6 +3542,10 @@ input ExportDocumentVersionPDFInput {
|
||||
withSignatures: Boolean!
|
||||
}
|
||||
|
||||
input ExportSignableDocumentVersionPDFInput {
|
||||
documentVersionId: ID!
|
||||
}
|
||||
|
||||
input DeleteDocumentInput {
|
||||
documentId: ID!
|
||||
}
|
||||
@@ -4072,6 +4130,10 @@ type ExportDocumentVersionPDFPayload {
|
||||
data: String!
|
||||
}
|
||||
|
||||
type ExportSignableDocumentVersionPDFPayload {
|
||||
data: String!
|
||||
}
|
||||
|
||||
type UpdateDocumentPayload {
|
||||
document: Document!
|
||||
}
|
||||
@@ -4186,6 +4248,8 @@ type DocumentVersion implements Node @goModel(model: "go.probo.inc/probo/pkg/ser
|
||||
filter: DocumentVersionSignatureFilter
|
||||
): DocumentVersionSignatureConnection! @goField(forceResolver: true)
|
||||
|
||||
signed: Boolean! @goField(forceResolver: true)
|
||||
|
||||
publishedAt: Datetime
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
@@ -4347,6 +4411,14 @@ type CancelSignatureRequestPayload {
|
||||
deletedDocumentVersionSignatureId: ID!
|
||||
}
|
||||
|
||||
input SignDocumentInput {
|
||||
documentVersionId: ID!
|
||||
}
|
||||
|
||||
type SignDocumentPayload {
|
||||
documentVersionSignature: DocumentVersionSignature!
|
||||
}
|
||||
|
||||
type UploadMeasureEvidencePayload {
|
||||
evidenceEdge: EvidenceEdge!
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
83
pkg/server/api/console/v1/types/signable_document.go
Normal file
83
pkg/server/api/console/v1/types/signable_document.go
Normal file
@@ -0,0 +1,83 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
)
|
||||
|
||||
type (
|
||||
SignableDocumentConnection struct {
|
||||
Edges []*SignableDocumentEdge
|
||||
PageInfo *PageInfo
|
||||
}
|
||||
|
||||
SignableDocumentEdge struct {
|
||||
Cursor page.CursorKey
|
||||
Node *SignableDocument
|
||||
}
|
||||
|
||||
SignableDocument struct {
|
||||
ID gid.GID
|
||||
Title string
|
||||
Description *string
|
||||
DocumentType coredata.DocumentType
|
||||
Classification coredata.DocumentClassification
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
)
|
||||
|
||||
func (SignableDocument) IsNode() {}
|
||||
func (this SignableDocument) GetID() gid.GID { return this.ID }
|
||||
|
||||
func NewSignableDocumentConnection(
|
||||
p *page.Page[*SignableDocument, coredata.DocumentOrderField],
|
||||
) *SignableDocumentConnection {
|
||||
var edges = make([]*SignableDocumentEdge, len(p.Data))
|
||||
|
||||
for i := range edges {
|
||||
edges[i] = NewSignableDocumentEdge(p.Data[i], p.Cursor.OrderBy.Field)
|
||||
}
|
||||
|
||||
return &SignableDocumentConnection{
|
||||
Edges: edges,
|
||||
PageInfo: NewPageInfo(p),
|
||||
}
|
||||
}
|
||||
|
||||
func NewSignableDocumentEdge(document *SignableDocument, orderBy coredata.DocumentOrderField) *SignableDocumentEdge {
|
||||
return &SignableDocumentEdge{
|
||||
Cursor: document.CursorKey(orderBy),
|
||||
Node: document,
|
||||
}
|
||||
}
|
||||
|
||||
func (d SignableDocument) CursorKey(orderBy coredata.DocumentOrderField) page.CursorKey {
|
||||
switch orderBy {
|
||||
case coredata.DocumentOrderFieldCreatedAt:
|
||||
return page.NewCursorKey(d.ID, d.CreatedAt)
|
||||
case coredata.DocumentOrderFieldTitle:
|
||||
return page.NewCursorKey(d.ID, d.Title)
|
||||
case coredata.DocumentOrderFieldDocumentType:
|
||||
return page.NewCursorKey(d.ID, d.DocumentType)
|
||||
}
|
||||
|
||||
panic("unsupported order by")
|
||||
}
|
||||
@@ -1153,6 +1153,14 @@ type ExportFrameworkPayload struct {
|
||||
ExportJobID gid.GID `json:"exportJobId"`
|
||||
}
|
||||
|
||||
type ExportSignableDocumentVersionPDFInput struct {
|
||||
DocumentVersionID gid.GID `json:"documentVersionId"`
|
||||
}
|
||||
|
||||
type ExportSignableDocumentVersionPDFPayload struct {
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
||||
type File struct {
|
||||
ID gid.GID `json:"id"`
|
||||
MimeType string `json:"mimeType"`
|
||||
@@ -1680,6 +1688,14 @@ type Session struct {
|
||||
ExpiresAt time.Time `json:"expiresAt"`
|
||||
}
|
||||
|
||||
type SignDocumentInput struct {
|
||||
DocumentVersionID gid.GID `json:"documentVersionId"`
|
||||
}
|
||||
|
||||
type SignDocumentPayload struct {
|
||||
DocumentVersionSignature *DocumentVersionSignature `json:"documentVersionSignature"`
|
||||
}
|
||||
|
||||
type SlackConnection struct {
|
||||
ID gid.GID `json:"id"`
|
||||
Channel *string `json:"channel,omitempty"`
|
||||
@@ -2506,9 +2522,11 @@ type VerifyDomainPayload struct {
|
||||
}
|
||||
|
||||
type Viewer struct {
|
||||
ID gid.GID `json:"id"`
|
||||
User *User `json:"user"`
|
||||
Organizations *OrganizationConnection `json:"organizations"`
|
||||
ID gid.GID `json:"id"`
|
||||
User *User `json:"user"`
|
||||
Organizations *OrganizationConnection `json:"organizations"`
|
||||
SignableDocuments *SignableDocumentConnection `json:"signableDocuments"`
|
||||
SignableDocument *SignableDocument `json:"signableDocument,omitempty"`
|
||||
}
|
||||
|
||||
type Role string
|
||||
|
||||
@@ -714,7 +714,9 @@ func (r *documentResolver) Versions(ctx context.Context, obj *types.Document, fi
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := prb.Documents.ListVersions(ctx, obj.ID, cursor)
|
||||
versionFilter := coredata.NewDocumentVersionFilter()
|
||||
|
||||
page, err := prb.Documents.ListVersions(ctx, obj.ID, cursor, versionFilter)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot list document versions: %w", err))
|
||||
}
|
||||
@@ -785,7 +787,7 @@ func (r *documentConnectionResolver) TotalCount(ctx context.Context, obj *types.
|
||||
|
||||
// Document is the resolver for the document field.
|
||||
func (r *documentVersionResolver) Document(ctx context.Context, obj *types.DocumentVersion) (*types.Document, error) {
|
||||
r.MustBeAuthorized(ctx, obj.ID, authz.ActionDocument)
|
||||
r.MustBeAuthorized(ctx, obj.ID, authz.ActionGetDocument)
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
@@ -862,6 +864,24 @@ func (r *documentVersionResolver) Signatures(ctx context.Context, obj *types.Doc
|
||||
return types.NewDocumentVersionSignatureConnection(page), nil
|
||||
}
|
||||
|
||||
// Signed is the resolver for the signed field.
|
||||
func (r *documentVersionResolver) Signed(ctx context.Context, obj *types.DocumentVersion) (bool, error) {
|
||||
r.MustBeAuthorized(ctx, obj.ID, authz.ActionGetSigned)
|
||||
|
||||
user := UserFromContext(ctx)
|
||||
if user == nil {
|
||||
panic(fmt.Errorf("user not found in context"))
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
signed, err := prb.Documents.IsVersionSignedByUserEmail(ctx, obj.ID, user.EmailAddress)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot check if document version is signed: %w", err))
|
||||
}
|
||||
|
||||
return signed, nil
|
||||
}
|
||||
|
||||
// DocumentVersion is the resolver for the documentVersion field.
|
||||
func (r *documentVersionSignatureResolver) DocumentVersion(ctx context.Context, obj *types.DocumentVersionSignature) (*types.DocumentVersion, error) {
|
||||
r.MustBeAuthorized(ctx, obj.ID, authz.ActionDocumentVersion)
|
||||
@@ -3551,6 +3571,31 @@ func (r *mutationResolver) CancelSignatureRequest(ctx context.Context, input typ
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SignDocument is the resolver for the signDocument field.
|
||||
func (r *mutationResolver) SignDocument(ctx context.Context, input types.SignDocumentInput) (*types.SignDocumentPayload, error) {
|
||||
r.MustBeAuthorized(ctx, input.DocumentVersionID, authz.ActionSignDocument)
|
||||
|
||||
user := UserFromContext(ctx)
|
||||
if user == nil {
|
||||
panic(fmt.Errorf("user not found in context"))
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.DocumentVersionID.TenantID())
|
||||
|
||||
documentVersionSignature, err := prb.Documents.SignDocumentVersionByEmail(ctx, input.DocumentVersionID, user.EmailAddress)
|
||||
if err != nil {
|
||||
var errAlreadySigned *coredata.ErrDocumentVersionSignatureAlreadySigned
|
||||
if errors.As(err, &errAlreadySigned) {
|
||||
return nil, gqlutils.Conflict(errAlreadySigned)
|
||||
}
|
||||
panic(fmt.Errorf("cannot sign document: %w", err))
|
||||
}
|
||||
|
||||
return &types.SignDocumentPayload{
|
||||
DocumentVersionSignature: types.NewDocumentVersionSignature(documentVersionSignature),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ExportDocumentVersionPDF is the resolver for the exportDocumentVersionPDF field.
|
||||
func (r *mutationResolver) ExportDocumentVersionPDF(ctx context.Context, input types.ExportDocumentVersionPDFInput) (*types.ExportDocumentVersionPDFPayload, error) {
|
||||
r.MustBeAuthorized(ctx, input.DocumentVersionID, authz.ActionExportDocumentVersionPDF)
|
||||
@@ -3573,6 +3618,49 @@ func (r *mutationResolver) ExportDocumentVersionPDF(ctx context.Context, input t
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ExportSignableVersionDocumentPDF is the resolver for the exportSignableVersionDocumentPDF field.
|
||||
func (r *mutationResolver) ExportSignableVersionDocumentPDF(ctx context.Context, input types.ExportSignableDocumentVersionPDFInput) (*types.ExportSignableDocumentVersionPDFPayload, error) {
|
||||
r.MustBeAuthorized(ctx, input.DocumentVersionID, authz.ActionExportSignableVersionDocumentPDF)
|
||||
|
||||
prb := r.ProboService(ctx, input.DocumentVersionID.TenantID())
|
||||
|
||||
documentVersion, err := prb.Documents.GetVersion(ctx, input.DocumentVersionID)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot get document version: %w", err))
|
||||
}
|
||||
|
||||
user := UserFromContext(ctx)
|
||||
if user == nil {
|
||||
panic(fmt.Errorf("user not found in context"))
|
||||
}
|
||||
|
||||
documentFilter := coredata.NewDocumentFilter(nil).WithUserEmail(&user.EmailAddress)
|
||||
|
||||
_, err = prb.Documents.GetWithFilter(ctx, documentVersion.DocumentID, documentFilter)
|
||||
if err != nil {
|
||||
var errNotFound *coredata.ErrDocumentNotFound
|
||||
if errors.As(err, &errNotFound) {
|
||||
return nil, gqlutils.NotFound(errNotFound)
|
||||
}
|
||||
panic(fmt.Errorf("cannot get signable document: %w", err))
|
||||
}
|
||||
|
||||
options := probo.ExportPDFOptions{
|
||||
WithSignatures: false,
|
||||
WithWatermark: true,
|
||||
WatermarkEmail: &user.EmailAddress,
|
||||
}
|
||||
|
||||
pdf, err := prb.Documents.ExportPDF(ctx, input.DocumentVersionID, options)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot export signable document PDF: %w", err))
|
||||
}
|
||||
|
||||
return &types.ExportSignableDocumentVersionPDFPayload{
|
||||
Data: fmt.Sprintf("data:application/pdf;base64,%s", base64.StdEncoding.EncodeToString(pdf)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateVendorRiskAssessment is the resolver for the createVendorRiskAssessment field.
|
||||
func (r *mutationResolver) CreateVendorRiskAssessment(ctx context.Context, input types.CreateVendorRiskAssessmentInput) (*types.CreateVendorRiskAssessmentPayload, error) {
|
||||
r.MustBeAuthorized(ctx, input.VendorID, authz.ActionCreateVendorRiskAssessment)
|
||||
@@ -5994,6 +6082,59 @@ func (r *sAMLConfigurationResolver) TestLoginURL(ctx context.Context, obj *types
|
||||
return fmt.Sprintf("%s/connect/saml/login/%s", parts[0], obj.ID), nil
|
||||
}
|
||||
|
||||
// Signed is the resolver for the signed field.
|
||||
func (r *signableDocumentResolver) Signed(ctx context.Context, obj *types.SignableDocument) (bool, error) {
|
||||
r.MustBeAuthorized(ctx, obj.ID, authz.ActionGetSigned)
|
||||
|
||||
user := UserFromContext(ctx)
|
||||
if user == nil {
|
||||
panic(fmt.Errorf("user not found in context"))
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
signed, err := prb.Documents.IsSigned(ctx, obj.ID, user.EmailAddress)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot check if document is signed: %w", err))
|
||||
}
|
||||
|
||||
return signed, nil
|
||||
}
|
||||
|
||||
// Versions is the resolver for the versions field.
|
||||
func (r *signableDocumentResolver) Versions(ctx context.Context, obj *types.SignableDocument, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentVersionOrderBy, filter *types.DocumentVersionFilter) (*types.DocumentVersionConnection, error) {
|
||||
r.MustBeAuthorized(ctx, obj.ID, authz.ActionListSignableDocumentVersion)
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.DocumentVersionOrderField]{
|
||||
Field: coredata.DocumentVersionOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.DocumentVersionOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
user := UserFromContext(ctx)
|
||||
if user == nil {
|
||||
panic(fmt.Errorf("user not found in context"))
|
||||
}
|
||||
|
||||
versionFilter := coredata.NewDocumentVersionFilter().WithUserEmail(&user.EmailAddress)
|
||||
|
||||
page, err := prb.Documents.ListVersions(ctx, obj.ID, cursor, versionFilter)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot list signable document versions: %w", err))
|
||||
}
|
||||
|
||||
return types.NewDocumentVersionConnection(page), nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *snapshotResolver) Organization(ctx context.Context, obj *types.Snapshot) (*types.Organization, error) {
|
||||
r.MustBeAuthorized(ctx, obj.ID, authz.ActionGetOrganization)
|
||||
@@ -6349,7 +6490,7 @@ func (r *trustCenterAccessResolver) AvailableDocumentAccesses(ctx context.Contex
|
||||
|
||||
// Document is the resolver for the document field.
|
||||
func (r *trustCenterDocumentAccessResolver) Document(ctx context.Context, obj *types.TrustCenterDocumentAccess) (*types.Document, error) {
|
||||
r.MustBeAuthorized(ctx, obj.TrustCenterAccessID, authz.ActionDocument)
|
||||
r.MustBeAuthorized(ctx, obj.ID, authz.ActionGet)
|
||||
|
||||
if obj.DocumentID == nil {
|
||||
return nil, nil
|
||||
@@ -6979,6 +7120,85 @@ func (r *viewerResolver) Organizations(ctx context.Context, obj *types.Viewer, f
|
||||
return types.NewOrganizationConnection(page), nil
|
||||
}
|
||||
|
||||
// SignableDocuments is the resolver for the signableDocuments field.
|
||||
func (r *viewerResolver) SignableDocuments(ctx context.Context, obj *types.Viewer, organizationID gid.GID, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy) (*types.SignableDocumentConnection, error) {
|
||||
r.MustBeAuthorized(ctx, organizationID, authz.ActionListSignableDocuments)
|
||||
|
||||
prb := r.ProboService(ctx, organizationID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.DocumentOrderField]{
|
||||
Field: coredata.DocumentOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.DocumentOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
user := UserFromContext(ctx)
|
||||
if user == nil {
|
||||
panic(fmt.Errorf("user not found in context"))
|
||||
}
|
||||
|
||||
documentFilter := coredata.NewDocumentFilter(nil).WithUserEmail(&user.EmailAddress)
|
||||
|
||||
documentsPage, err := prb.Documents.ListByOrganizationID(ctx, organizationID, cursor, documentFilter)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot list organization signable documents: %w", err))
|
||||
}
|
||||
|
||||
signableDocuments := make([]*types.SignableDocument, len(documentsPage.Data))
|
||||
for i, doc := range documentsPage.Data {
|
||||
signableDocuments[i] = &types.SignableDocument{
|
||||
ID: doc.ID,
|
||||
Title: doc.Title,
|
||||
DocumentType: doc.DocumentType,
|
||||
Classification: doc.Classification,
|
||||
CreatedAt: doc.CreatedAt,
|
||||
UpdatedAt: doc.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
page := page.NewPage(signableDocuments, documentsPage.Cursor)
|
||||
|
||||
return types.NewSignableDocumentConnection(page), nil
|
||||
}
|
||||
|
||||
// SignableDocument is the resolver for the signableDocument field.
|
||||
func (r *viewerResolver) SignableDocument(ctx context.Context, obj *types.Viewer, id gid.GID) (*types.SignableDocument, error) {
|
||||
r.MustBeAuthorized(ctx, id, authz.ActionGetSignableDocument)
|
||||
|
||||
prb := r.ProboService(ctx, id.TenantID())
|
||||
|
||||
user := UserFromContext(ctx)
|
||||
if user == nil {
|
||||
panic(fmt.Errorf("user not found in context"))
|
||||
}
|
||||
|
||||
documentFilter := coredata.NewDocumentFilter(nil).WithUserEmail(&user.EmailAddress)
|
||||
document, err := prb.Documents.GetWithFilter(ctx, id, documentFilter)
|
||||
if err != nil {
|
||||
var errNotFound *coredata.ErrDocumentNotFound
|
||||
if errors.As(err, &errNotFound) {
|
||||
return nil, gqlutils.NotFound(errNotFound)
|
||||
}
|
||||
panic(fmt.Errorf("cannot get signable document: %w", err))
|
||||
}
|
||||
|
||||
return &types.SignableDocument{
|
||||
ID: document.ID,
|
||||
Title: document.Title,
|
||||
DocumentType: document.DocumentType,
|
||||
Classification: document.Classification,
|
||||
CreatedAt: document.CreatedAt,
|
||||
UpdatedAt: document.UpdatedAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Asset returns schema.AssetResolver implementation.
|
||||
func (r *Resolver) Asset() schema.AssetResolver { return &assetResolver{r} }
|
||||
|
||||
@@ -7144,6 +7364,11 @@ func (r *Resolver) SAMLConfiguration() schema.SAMLConfigurationResolver {
|
||||
return &sAMLConfigurationResolver{r}
|
||||
}
|
||||
|
||||
// SignableDocument returns schema.SignableDocumentResolver implementation.
|
||||
func (r *Resolver) SignableDocument() schema.SignableDocumentResolver {
|
||||
return &signableDocumentResolver{r}
|
||||
}
|
||||
|
||||
// Snapshot returns schema.SnapshotResolver implementation.
|
||||
func (r *Resolver) Snapshot() schema.SnapshotResolver { return &snapshotResolver{r} }
|
||||
|
||||
@@ -7277,6 +7502,7 @@ type reportResolver struct{ *Resolver }
|
||||
type riskResolver struct{ *Resolver }
|
||||
type riskConnectionResolver struct{ *Resolver }
|
||||
type sAMLConfigurationResolver struct{ *Resolver }
|
||||
type signableDocumentResolver struct{ *Resolver }
|
||||
type snapshotResolver struct{ *Resolver }
|
||||
type snapshotConnectionResolver struct{ *Resolver }
|
||||
type taskResolver struct{ *Resolver }
|
||||
|
||||
Reference in New Issue
Block a user