diff --git a/apps/console/src/pages/organizations/compliance-page/documents/_components/CompliancePageDocumentList.tsx b/apps/console/src/pages/organizations/compliance-page/documents/_components/CompliancePageDocumentList.tsx index 25c98d56a..21f50ab20 100644 --- a/apps/console/src/pages/organizations/compliance-page/documents/_components/CompliancePageDocumentList.tsx +++ b/apps/console/src/pages/organizations/compliance-page/documents/_components/CompliancePageDocumentList.tsx @@ -16,7 +16,7 @@ const fragment = graphql` edges { node { id - currentPublishedVersion + currentPublishedMajor ...CompliancePageDocumentListItem_documentFragment } } @@ -30,7 +30,7 @@ export function CompliancePageDocumentList(props: { fragmentRef: CompliancePageD const { __ } = useTranslate(); const { compliancePage, documents } = useFragment(fragment, fragmentRef); - const publishedDocuments = documents.edges.filter(({ node }) => node.currentPublishedVersion != null); + const publishedDocuments = documents.edges.filter(({ node }) => node.currentPublishedMajor != null); return (
diff --git a/apps/console/src/pages/organizations/documents/_components/DocumentActionsDropdown.tsx b/apps/console/src/pages/organizations/documents/_components/DocumentActionsDropdown.tsx index edcbb23db..62e1a8627 100644 --- a/apps/console/src/pages/organizations/documents/_components/DocumentActionsDropdown.tsx +++ b/apps/console/src/pages/organizations/documents/_components/DocumentActionsDropdown.tsx @@ -75,7 +75,8 @@ const unarchiveDocumentMutation = graphql` const versionFragment = graphql` fragment DocumentActionsDropdown_versionFragment on DocumentVersion { id - version + major + minor status canDeleteDraft: permission(action: "core:document-version:delete-draft") } @@ -229,7 +230,7 @@ export function DocumentActionsDropdownn(props: { __( "This will permanently delete the draft version %s of \"%s\". This action cannot be undone.", ), - version.version, + `${version.major}.${version.minor}`, document.title, ), }, @@ -259,7 +260,7 @@ export function DocumentActionsDropdownn(props: { if (data.exportDocumentVersionPDF) { const link = window.document.createElement("a"); link.href = data.exportDocumentVersionPDF.data; - link.download = `${document.title}-v${version.version}.pdf`; + link.download = `${document.title}-v${version.major}.${version.minor}.pdf`; window.document.body.appendChild(link); link.click(); window.document.body.removeChild(link); diff --git a/apps/console/src/pages/organizations/documents/_components/DocumentLayoutDrawer.tsx b/apps/console/src/pages/organizations/documents/_components/DocumentLayoutDrawer.tsx index a43efb02f..d7eb2462f 100644 --- a/apps/console/src/pages/organizations/documents/_components/DocumentLayoutDrawer.tsx +++ b/apps/console/src/pages/organizations/documents/_components/DocumentLayoutDrawer.tsx @@ -29,7 +29,8 @@ const versionFragment = graphql` fragment DocumentLayoutDrawer_versionFragment on DocumentVersion { id classification - version + major + minor status updatedAt publishedAt @@ -202,7 +203,9 @@ export function DocumentLayoutDrawer(props: {
- {version.version} + {version.major} + . + {version.minor}
diff --git a/apps/console/src/pages/organizations/documents/_components/DocumentListItem.tsx b/apps/console/src/pages/organizations/documents/_components/DocumentListItem.tsx index e22c72549..8e0b5b5d7 100644 --- a/apps/console/src/pages/organizations/documents/_components/DocumentListItem.tsx +++ b/apps/console/src/pages/organizations/documents/_components/DocumentListItem.tsx @@ -22,7 +22,8 @@ const fragment = graphql` node { id status - version + major + minor approvalQuorums(first: 1, orderBy: { field: CREATED_AT, direction: DESC }) { edges { node { @@ -148,7 +149,9 @@ export function DocumentListItem(props: { v - {lastVersion.version} + {lastVersion.major} + . + {lastVersion.minor} {getDocumentTypeLabel(__, document.documentType)} diff --git a/apps/console/src/pages/organizations/documents/_components/DocumentVersionsDropdownItem.tsx b/apps/console/src/pages/organizations/documents/_components/DocumentVersionsDropdownItem.tsx index 9fea76124..e03a6db27 100644 --- a/apps/console/src/pages/organizations/documents/_components/DocumentVersionsDropdownItem.tsx +++ b/apps/console/src/pages/organizations/documents/_components/DocumentVersionsDropdownItem.tsx @@ -13,7 +13,8 @@ import { useOrganizationId } from "#/hooks/useOrganizationId"; const fragment = graphql` fragment DocumentVersionsDropdownItemFragment on DocumentVersion { id - version + major + minor status publishedAt updatedAt @@ -51,7 +52,9 @@ export function DocumentVersionsDropdownItem(props: { )} >
- {version.version} + {version.major} + . + {version.minor}
diff --git a/apps/console/src/pages/organizations/documents/_components/PublishDialog.tsx b/apps/console/src/pages/organizations/documents/_components/PublishDialog.tsx index 711693795..f0bcf7537 100644 --- a/apps/console/src/pages/organizations/documents/_components/PublishDialog.tsx +++ b/apps/console/src/pages/organizations/documents/_components/PublishDialog.tsx @@ -18,7 +18,8 @@ import { graphql } from "relay-runtime"; import { z } from "zod"; import type { PublishDialog_documentFragment$key } from "#/__generated__/core/PublishDialog_documentFragment.graphql"; -import type { PublishDialog_publishMutation } from "#/__generated__/core/PublishDialog_publishMutation.graphql"; +import type { PublishDialog_publishMajorMutation } from "#/__generated__/core/PublishDialog_publishMajorMutation.graphql"; +import type { PublishDialog_publishMinorMutation } from "#/__generated__/core/PublishDialog_publishMinorMutation.graphql"; import type { PublishDialog_requestApprovalMutation } from "#/__generated__/core/PublishDialog_requestApprovalMutation.graphql"; import { PeopleMultiSelectField } from "#/components/form/PeopleMultiSelectField"; import { useFormWithSchema } from "#/hooks/useFormWithSchema"; @@ -62,9 +63,24 @@ const documentFragment = graphql` } `; -const publishMutation = graphql` - mutation PublishDialog_publishMutation($input: PublishDocumentVersionInput!) { - publishDocumentVersion(input: $input) { +const publishMajorMutation = graphql` + mutation PublishDialog_publishMajorMutation($input: PublishMajorDocumentVersionInput!) { + publishMajorDocumentVersion(input: $input) { + document { + id + status + } + documentVersion { + id + status + } + } + } +`; + +const publishMinorMutation = graphql` + mutation PublishDialog_publishMinorMutation($input: PublishMinorDocumentVersionInput!) { + publishMinorDocumentVersion(input: $input) { document { id status @@ -160,36 +176,52 @@ export function PublishDialog({ }, })); - const [publishVersion, isPublishing] = useMutation(publishMutation); - const [requestApproval, isRequesting] = useMutation(requestApprovalMutation); + const [publishMajor, isPublishingMajor] + = useMutation(publishMajorMutation); + const [publishMinor, isPublishingMinor] + = useMutation(publishMinorMutation); + const [requestApproval, isRequesting] + = useMutation(requestApprovalMutation); - const isBusy = isPublishing || isRequesting; + const isBusy = isPublishingMajor || isPublishingMinor || isRequesting; const approverIds = watch("approverIds"); - const actionRef = useRef<"publish" | "request-approval">("publish"); + const actionRef = useRef<"publish" | "publish-minor" | "request-approval">("publish"); - const handlePublish = (data: z.infer) => { - publishVersion({ + const onPublishCompleted = (_: unknown, errors: ReadonlyArray<{ message: string }> | null) => { + if (errors?.length) { + toast({ + title: __("Error"), + description: formatError(__("Failed to publish document"), [...errors]), + variant: "error", + }); + } else { + toast({ + title: __("Success"), + description: __("Document published successfully."), + variant: "success", + }); + dialogRef.current?.close(); + onSuccess(); + } + }; + + const onPublishError = (error: Error) => { + toast({ title: __("Error"), description: error.message, variant: "error" }); + }; + + const handlePublishMajor = (data: z.infer) => { + publishMajor({ variables: { input: { documentId, changelog: data.changelog } }, - onCompleted(_, errors) { - if (errors?.length) { - toast({ - title: __("Error"), - description: formatError(__("Failed to publish document"), errors), - variant: "error", - }); - } else { - toast({ - title: __("Success"), - description: __("Document published successfully."), - variant: "success", - }); - dialogRef.current?.close(); - onSuccess(); - } - }, - onError(error) { - toast({ title: __("Error"), description: error.message, variant: "error" }); - }, + onCompleted: onPublishCompleted, + onError: onPublishError, + }); + }; + + const handlePublishMinor = (data: z.infer) => { + publishMinor({ + variables: { input: { documentId, changelog: data.changelog } }, + onCompleted: onPublishCompleted, + onError: onPublishError, }); }; @@ -231,7 +263,9 @@ export function PublishDialog({
void handleSubmit((data) => { if (actionRef.current === "publish") { - handlePublish(data); + handlePublishMajor(data); + } else if (actionRef.current === "publish-minor") { + handlePublishMinor(data); } else { onRequestApproval(data); } @@ -284,38 +318,34 @@ export function PublishDialog({
- {hasPendingApproval - ? ( - - ) - : ( - <> - - - - )} + + + {!hasPendingApproval && ( + + )} diff --git a/apps/console/src/pages/organizations/documents/_components/PublishDocumentsDialog.tsx b/apps/console/src/pages/organizations/documents/_components/PublishDocumentsDialog.tsx index 1e722ca27..15589b4b0 100644 --- a/apps/console/src/pages/organizations/documents/_components/PublishDocumentsDialog.tsx +++ b/apps/console/src/pages/organizations/documents/_components/PublishDocumentsDialog.tsx @@ -5,17 +5,19 @@ import { Dialog, DialogContent, DialogFooter, + IconUpload, IconWarning, Textarea, useDialogRef, useToast, } from "@probo/ui"; -import { type ReactNode } from "react"; +import { type ReactNode, useRef } from "react"; import { useMutation } from "react-relay"; import { graphql } from "relay-runtime"; import { z } from "zod"; -import type { PublishDocumentsDialogMutation } from "#/__generated__/core/PublishDocumentsDialogMutation.graphql"; +import type { PublishDocumentsDialog_majorMutation } from "#/__generated__/core/PublishDocumentsDialog_majorMutation.graphql"; +import type { PublishDocumentsDialog_minorMutation } from "#/__generated__/core/PublishDocumentsDialog_minorMutation.graphql"; import { useFormWithSchema } from "#/hooks/useFormWithSchema"; type Props = { @@ -24,11 +26,27 @@ type Props = { onSave: () => void; }; -const documentsPublishMutation = graphql` - mutation PublishDocumentsDialogMutation( +const publishMajorMutation = graphql` + mutation PublishDocumentsDialog_majorMutation( $input: BulkPublishDocumentVersionsInput! ) { - bulkPublishDocumentVersions(input: $input) { + bulkPublishMajorDocumentVersions(input: $input) { + documentVersions { + id + } + documents { + id + ...DocumentListItemFragment + } + } + } +`; + +const publishMinorMutation = graphql` + mutation PublishDocumentsDialog_minorMutation( + $input: BulkPublishDocumentVersionsInput! + ) { + bulkPublishMinorDocumentVersions(input: $input) { documentVersions { id } @@ -48,12 +66,18 @@ export function PublishDocumentsDialog({ const { __ } = useTranslate(); const { toast } = useToast(); const dialogRef = useDialogRef(); + const actionRef = useRef<"major" | "minor">("major"); const schema = z.object({ changelog: z.string().min(1, __("Changelog is required")), }); - const [publishMutation, isPublishing] = useMutation(documentsPublishMutation); + const [publishMajor, isPublishingMajor] + = useMutation(publishMajorMutation); + const [publishMinor, isPublishingMinor] + = useMutation(publishMinorMutation); + + const isBusy = isPublishingMajor || isPublishingMinor; const { handleSubmit, @@ -65,41 +89,47 @@ export function PublishDocumentsDialog({ }, }); - const onSubmit = (data: z.infer) => { - publishMutation({ - variables: { - input: { - documentIds, - changelog: data.changelog, - }, - }, - onCompleted(_, errors) { - if (errors?.length) { - toast({ - title: __("Error"), - description: formatError(__("Failed to publish documents"), errors), - variant: "error", - }); - } else { - toast({ - title: __("Success"), - description: sprintf(__("%s documents published"), documentIds.length), - variant: "success", - }); - dialogRef.current?.close(); - onSave(); - } - }, - onError(error) { - toast({ - title: __("Error"), - description: error.message, - variant: "error", - }); - }, + const onCompleted = (_: unknown, errors: ReadonlyArray<{ message: string }> | null) => { + if (errors?.length) { + toast({ + title: __("Error"), + description: formatError(__("Failed to publish documents"), [...errors]), + variant: "error", + }); + } else { + toast({ + title: __("Success"), + description: sprintf(__("%s documents published"), documentIds.length), + variant: "success", + }); + dialogRef.current?.close(); + onSave(); + } + }; + + const onError = (error: Error) => { + toast({ + title: __("Error"), + description: error.message, + variant: "error", }); }; + const onSubmit = (data: z.infer) => { + const variables = { + input: { + documentIds, + changelog: data.changelog, + }, + }; + + if (actionRef.current === "minor") { + publishMinor({ variables, onCompleted, onError }); + } else { + publishMajor({ variables, onCompleted, onError }); + } + }; + return ( - + diff --git a/apps/console/src/pages/organizations/documents/_components/UpdateVersionDialog.tsx b/apps/console/src/pages/organizations/documents/_components/UpdateVersionDialog.tsx index 6dcf7a335..7db71d0d8 100644 --- a/apps/console/src/pages/organizations/documents/_components/UpdateVersionDialog.tsx +++ b/apps/console/src/pages/organizations/documents/_components/UpdateVersionDialog.tsx @@ -51,7 +51,8 @@ const createDraftDocument = graphql` content status publishedAt - version + major + minor updatedAt signatures(first: 100) { edges { diff --git a/apps/console/src/pages/organizations/documents/approve/DocumentApprovePage.tsx b/apps/console/src/pages/organizations/documents/approve/DocumentApprovePage.tsx index 32f02258c..669c6d686 100644 --- a/apps/console/src/pages/organizations/documents/approve/DocumentApprovePage.tsx +++ b/apps/console/src/pages/organizations/documents/approve/DocumentApprovePage.tsx @@ -70,9 +70,11 @@ const documentFragment = graphql` const versionRowFragment = graphql` fragment DocumentApprovePageVersionRowFragment on EmployeeDocumentVersion { id - version + major + minor publishedAt approvalDecision { + id state } } @@ -96,10 +98,7 @@ const approveDocumentVersionMutation = graphql` ) { approveDocumentVersion(input: $input) { approvalDecision { - id - state - decidedAt - comment + ...DocumentApprovePageDecisionFragment } } } @@ -111,10 +110,7 @@ const rejectDocumentVersionMutation = graphql` ) { rejectDocumentVersion(input: $input) { approvalDecision { - id - state - decidedAt - comment + ...DocumentApprovePageDecisionFragment } } } @@ -192,14 +188,14 @@ function VersionRow({ )} > {versionData.publishedAt - ? `v${versionData.version} - ${(() => { + ? `v${versionData.major}.${versionData.minor} - ${(() => { const date = new Date(versionData.publishedAt); const day = String(date.getDate()).padStart(2, "0"); const month = String(date.getMonth() + 1).padStart(2, "0"); const year = date.getFullYear(); return `${day}/${month}/${year}`; })()}` - : `v${versionData.version}`} + : `v${versionData.major}.${versionData.minor}`}

diff --git a/apps/console/src/pages/organizations/employee/_components/VersionRow.tsx b/apps/console/src/pages/organizations/employee/_components/VersionRow.tsx index 3d9b01845..98408b8ae 100644 --- a/apps/console/src/pages/organizations/employee/_components/VersionRow.tsx +++ b/apps/console/src/pages/organizations/employee/_components/VersionRow.tsx @@ -9,7 +9,8 @@ const fragment = graphql` fragment VersionRowFragment on EmployeeDocumentVersion { # eslint-disable-next-line relay/unused-fields id - version + major + minor signed publishedAt } @@ -55,14 +56,14 @@ export function VersionRow({ )} > {versionData.publishedAt - ? `v${versionData.version} - ${(() => { + ? `v${versionData.major}.${versionData.minor} - ${(() => { const date = new Date(versionData.publishedAt); const day = String(date.getDate()).padStart(2, "0"); const month = String(date.getMonth() + 1).padStart(2, "0"); const year = date.getFullYear(); return `${day}/${month}/${year}`; })()}` - : `v${versionData.version}`} + : `v${versionData.major}.${versionData.minor}`}

diff --git a/e2e/console/document_version_test.go b/e2e/console/document_version_test.go index 5860481e8..9c8f07bc3 100644 --- a/e2e/console/document_version_test.go +++ b/e2e/console/document_version_test.go @@ -223,7 +223,8 @@ func TestDocumentVersion_PublishVersion(t *testing.T) { node { id status - version + major + minor } } } @@ -237,9 +238,10 @@ func TestDocumentVersion_PublishVersion(t *testing.T) { Versions struct { Edges []struct { Node struct { - ID string `json:"id"` - Status string `json:"status"` - Version int `json:"version"` + ID string `json:"id"` + Status string `json:"status"` + Major int `json:"major"` + Minor int `json:"minor"` } `json:"node"` } `json:"edges"` } `json:"versions"` @@ -251,7 +253,8 @@ func TestDocumentVersion_PublishVersion(t *testing.T) { require.NotEmpty(t, result.Node.Versions.Edges) assert.Equal(t, "PUBLISHED", result.Node.Versions.Edges[0].Node.Status) - assert.Equal(t, 1, result.Node.Versions.Edges[0].Node.Version) + assert.Equal(t, 1, result.Node.Versions.Edges[0].Node.Major) + assert.Equal(t, 0, result.Node.Versions.Edges[0].Node.Minor) } func TestDocumentVersion_CreateDraft(t *testing.T) { @@ -435,8 +438,8 @@ func TestDocumentVersion_BulkPublish(t *testing.T) { approveTestDocument(t, owner, docID2) query := ` - mutation BulkPublishDocumentVersions($input: BulkPublishDocumentVersionsInput!) { - bulkPublishDocumentVersions(input: $input) { + mutation BulkPublishMajorDocumentVersions($input: BulkPublishDocumentVersionsInput!) { + bulkPublishMajorDocumentVersions(input: $input) { documentVersions { id status @@ -446,12 +449,12 @@ func TestDocumentVersion_BulkPublish(t *testing.T) { ` var result struct { - BulkPublishDocumentVersions struct { + BulkPublishMajorDocumentVersions struct { DocumentVersions []struct { ID string `json:"id"` Status string `json:"status"` } `json:"documentVersions"` - } `json:"bulkPublishDocumentVersions"` + } `json:"bulkPublishMajorDocumentVersions"` } err := owner.Execute(query, map[string]any{ @@ -462,8 +465,8 @@ func TestDocumentVersion_BulkPublish(t *testing.T) { }, &result) require.NoError(t, err) - assert.Equal(t, 2, len(result.BulkPublishDocumentVersions.DocumentVersions)) - for _, dv := range result.BulkPublishDocumentVersions.DocumentVersions { + assert.Equal(t, 2, len(result.BulkPublishMajorDocumentVersions.DocumentVersions)) + for _, dv := range result.BulkPublishMajorDocumentVersions.DocumentVersions { assert.Equal(t, "PUBLISHED", dv.Status) } } diff --git a/pkg/coredata/document.go b/pkg/coredata/document.go index 17a978937..e7d2509d0 100644 --- a/pkg/coredata/document.go +++ b/pkg/coredata/document.go @@ -30,17 +30,18 @@ import ( type ( Document struct { - ID gid.GID `db:"id"` - OrganizationID gid.GID `db:"organization_id"` - Title string `db:"title"` - DocumentType DocumentType `db:"document_type"` - Classification DocumentClassification `db:"classification"` - CurrentPublishedVersion *int `db:"current_published_version"` - TrustCenterVisibility TrustCenterVisibility `db:"trust_center_visibility"` - Status DocumentStatus `db:"status"` - ArchivedAt *time.Time `db:"archived_at"` - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` + ID gid.GID `db:"id"` + OrganizationID gid.GID `db:"organization_id"` + Title string `db:"title"` + DocumentType DocumentType `db:"document_type"` + Classification DocumentClassification `db:"classification"` + CurrentPublishedMajor *int `db:"current_published_major"` + CurrentPublishedMinor *int `db:"current_published_minor"` + TrustCenterVisibility TrustCenterVisibility `db:"trust_center_visibility"` + Status DocumentStatus `db:"status"` + ArchivedAt *time.Time `db:"archived_at"` + CreatedAt time.Time `db:"created_at"` + UpdatedAt time.Time `db:"updated_at"` } Documents []*Document @@ -128,7 +129,8 @@ SELECT title, document_type, classification, - current_published_version, + current_published_major, + current_published_minor, trust_center_visibility, status, archived_at, @@ -181,7 +183,8 @@ SELECT title, document_type, classification, - current_published_version, + current_published_major, + current_published_minor, trust_center_visibility, status, archived_at, @@ -235,7 +238,8 @@ SELECT title, document_type, classification, - current_published_version, + current_published_major, + current_published_minor, trust_center_visibility, status, archived_at, @@ -318,7 +322,8 @@ SELECT title, document_type, classification, - current_published_version, + current_published_major, + current_published_minor, trust_center_visibility, status, archived_at, @@ -370,7 +375,8 @@ SELECT title, document_type, classification, - current_published_version, + current_published_major, + current_published_minor, trust_center_visibility, status, archived_at, @@ -424,7 +430,8 @@ WITH published_documents AS ( documents d LEFT JOIN document_versions dv ON dv.document_id = d.id - AND dv.version_number = d.current_published_version + AND dv.major = d.current_published_major + AND dv.minor = d.current_published_minor WHERE d.deleted_at IS NULL AND d.organization_id = @organization_id @@ -435,7 +442,8 @@ SELECT COALESCE(published_title, title) AS title, document_type, classification, - current_published_version, + current_published_major, + current_published_minor, trust_center_visibility, status, archived_at, @@ -484,7 +492,8 @@ INSERT INTO title, document_type, classification, - current_published_version, + current_published_major, + current_published_minor, trust_center_visibility, status, archived_at, @@ -498,7 +507,8 @@ VALUES ( @title, @document_type, @classification, - @current_published_version, + @current_published_major, + @current_published_minor, @trust_center_visibility, @status, @archived_at, @@ -508,18 +518,19 @@ VALUES ( ` args := pgx.StrictNamedArgs{ - "tenant_id": scope.GetTenantID(), - "document_id": p.ID, - "organization_id": p.OrganizationID, - "title": p.Title, - "document_type": p.DocumentType, - "classification": p.Classification, - "current_published_version": p.CurrentPublishedVersion, - "trust_center_visibility": p.TrustCenterVisibility, - "status": p.Status, - "archived_at": p.ArchivedAt, - "created_at": p.CreatedAt, - "updated_at": p.UpdatedAt, + "tenant_id": scope.GetTenantID(), + "document_id": p.ID, + "organization_id": p.OrganizationID, + "title": p.Title, + "document_type": p.DocumentType, + "classification": p.Classification, + "current_published_major": p.CurrentPublishedMajor, + "current_published_minor": p.CurrentPublishedMinor, + "trust_center_visibility": p.TrustCenterVisibility, + "status": p.Status, + "archived_at": p.ArchivedAt, + "created_at": p.CreatedAt, + "updated_at": p.UpdatedAt, } _, err := conn.Exec(ctx, q, args) return err @@ -572,7 +583,8 @@ UPDATE documents SET title = @title, - current_published_version = @current_published_version, + current_published_major = @current_published_major, + current_published_minor = @current_published_minor, document_type = @document_type, classification = @classification, trust_center_visibility = @trust_center_visibility, @@ -587,15 +599,16 @@ WHERE q = fmt.Sprintf(q, scope.SQLFragment()) args := pgx.StrictNamedArgs{ - "document_id": p.ID, - "updated_at": time.Now(), - "title": p.Title, - "current_published_version": p.CurrentPublishedVersion, - "document_type": p.DocumentType, - "classification": p.Classification, - "trust_center_visibility": p.TrustCenterVisibility, - "status": p.Status, - "archived_at": p.ArchivedAt, + "document_id": p.ID, + "updated_at": time.Now(), + "title": p.Title, + "current_published_major": p.CurrentPublishedMajor, + "current_published_minor": p.CurrentPublishedMinor, + "document_type": p.DocumentType, + "classification": p.Classification, + "trust_center_visibility": p.TrustCenterVisibility, + "status": p.Status, + "archived_at": p.ArchivedAt, } maps.Copy(args, scope.SQLArguments()) @@ -666,7 +679,8 @@ SELECT scoped_documents.title, scoped_documents.document_type, scoped_documents.classification, - scoped_documents.current_published_version, + scoped_documents.current_published_major, + scoped_documents.current_published_minor, scoped_documents.trust_center_visibility, scoped_documents.status, scoped_documents.archived_at, @@ -757,7 +771,8 @@ SELECT scoped_documents.title, scoped_documents.document_type, scoped_documents.classification, - scoped_documents.current_published_version, + scoped_documents.current_published_major, + scoped_documents.current_published_minor, scoped_documents.trust_center_visibility, scoped_documents.status, scoped_documents.archived_at, @@ -874,28 +889,29 @@ func (p *Document) IsLastSignableVersionSignedByUserEmail( userEmail mail.Addr, ) (bool, error) { q := ` -WITH last_signable_version AS ( +WITH max_signable_major AS ( + SELECT MAX(dv.major) AS major + FROM document_versions dv + INNER JOIN document_version_signatures dvs ON dvs.document_version_id = dv.id + INNER JOIN iam_membership_profiles p ON dvs.signed_by_profile_id = p.id + INNER JOIN identities i ON p.identity_id = i.id + WHERE dv.document_id = @document_id + AND i.email_address = @user_email::CITEXT +), +last_signable_version AS ( SELECT d.id AS document_id, d.tenant_id, - dv.version_number, + dv.major, dvs.state FROM documents d INNER JOIN document_versions dv ON dv.document_id = d.id + INNER JOIN max_signable_major msm ON dv.major = msm.major INNER JOIN document_version_signatures dvs ON dvs.document_version_id = dv.id INNER JOIN iam_membership_profiles p ON dvs.signed_by_profile_id = p.id INNER JOIN identities i ON p.identity_id = i.id WHERE d.id = @document_id AND i.email_address = @user_email::CITEXT - AND dv.version_number = ( - SELECT MAX(dv2.version_number) - FROM document_versions dv2 - INNER JOIN document_version_signatures dvs2 ON dvs2.document_version_id = dv2.id - INNER JOIN iam_membership_profiles p2 ON dvs2.signed_by_profile_id = p2.id - INNER JOIN identities i2 ON p2.identity_id = i2.id - WHERE dv2.document_id = d.id - AND i2.email_address = @user_email::CITEXT - ) ) SELECT EXISTS ( SELECT 1 @@ -938,7 +954,7 @@ WITH viewer_decision AS ( SELECT dvad.tenant_id, dvad.state, - dv.version_number, + dv.major, dvaq.created_at AS quorum_created_at FROM documents d INNER JOIN document_versions dv ON dv.document_id = d.id @@ -951,7 +967,7 @@ WITH viewer_decision AS ( SELECT state FROM viewer_decision WHERE %s -ORDER BY version_number DESC, quorum_created_at DESC +ORDER BY major DESC, quorum_created_at DESC LIMIT 1 ` diff --git a/pkg/coredata/document_filter.go b/pkg/coredata/document_filter.go index 9f29ea2de..0a6781769 100644 --- a/pkg/coredata/document_filter.go +++ b/pkg/coredata/document_filter.go @@ -131,8 +131,8 @@ func (f *DocumentFilter) SQLFragment() string { AND CASE WHEN @published::boolean IS NULL THEN TRUE - WHEN @published::boolean IS TRUE THEN current_published_version IS NOT NULL - WHEN @published::boolean IS FALSE THEN current_published_version IS NULL + WHEN @published::boolean IS TRUE THEN current_published_major IS NOT NULL + WHEN @published::boolean IS FALSE THEN current_published_major IS NULL END AND CASE diff --git a/pkg/coredata/document_version.go b/pkg/coredata/document_version.go index 1bba3d44f..f3a573ae6 100644 --- a/pkg/coredata/document_version.go +++ b/pkg/coredata/document_version.go @@ -34,7 +34,8 @@ type ( OrganizationID gid.GID `db:"organization_id"` DocumentID gid.GID `db:"document_id"` Title string `db:"title"` - VersionNumber int `db:"version_number"` + Major int `db:"major"` + Minor int `db:"minor"` Classification DocumentClassification `db:"classification"` Content string `db:"content"` Changelog string `db:"changelog"` @@ -116,7 +117,8 @@ SELECT organization_id, document_id, title, - version_number, + major, + minor, classification, content, changelog, @@ -177,7 +179,8 @@ SELECT organization_id, document_id, title, - version_number, + major, + minor, classification, content, changelog, @@ -227,7 +230,8 @@ INSERT INTO document_versions ( organization_id, document_id, title, - version_number, + major, + minor, classification, content, changelog, @@ -241,7 +245,8 @@ VALUES ( @organization_id, @document_id, @title, - @version_number, + @major, + @minor, @classification, @content, @changelog, @@ -256,7 +261,8 @@ VALUES ( "organization_id": dv.OrganizationID, "document_id": dv.DocumentID, "title": dv.Title, - "version_number": dv.VersionNumber, + "major": dv.Major, + "minor": dv.Minor, "classification": dv.Classification, "content": dv.Content, "changelog": dv.Changelog, @@ -270,7 +276,7 @@ VALUES ( var pgErr *pgconn.PgError if errors.As(err, &pgErr) { if pgErr.Code == "23505" { - if pgErr.ConstraintName == "document_versions_document_id_version_number_key" || pgErr.ConstraintName == "document_one_draft_version_idx" { + if pgErr.ConstraintName == "document_versions_document_id_major_minor_key" || pgErr.ConstraintName == "document_one_draft_version_idx" { return ErrResourceAlreadyExists } } @@ -281,12 +287,13 @@ VALUES ( return nil } -func (dv *DocumentVersion) LoadByDocumentIDAndVersionNumber( +func (dv *DocumentVersion) LoadByDocumentIDAndVersion( ctx context.Context, conn pg.Conn, scope Scoper, documentID gid.GID, - versionNumber int, + major int, + minor int, ) error { q := ` SELECT @@ -294,7 +301,8 @@ SELECT organization_id, document_id, title, - version_number, + major, + minor, classification, content, changelog, @@ -307,15 +315,17 @@ FROM WHERE %s AND document_id = @document_id - AND version_number = @version_number + AND major = @major + AND minor = @minor LIMIT 1; ` q = fmt.Sprintf(q, scope.SQLFragment()) args := pgx.StrictNamedArgs{ - "document_id": documentID, - "version_number": versionNumber, + "document_id": documentID, + "major": major, + "minor": minor, } maps.Copy(args, scope.SQLArguments()) @@ -346,7 +356,8 @@ SELECT organization_id, document_id, title, - version_number, + major, + minor, classification, content, changelog, @@ -396,7 +407,8 @@ SELECT organization_id, document_id, title, - version_number, + major, + minor, classification, content, changelog, @@ -444,6 +456,8 @@ func (dv DocumentVersion) Update( q := ` UPDATE document_versions SET title = @title, + major = @major, + minor = @minor, changelog = @changelog, status = @status, content = @content, @@ -459,6 +473,8 @@ WHERE %s args := pgx.StrictNamedArgs{ "document_version_id": dv.ID, "title": dv.Title, + "major": dv.Major, + "minor": dv.Minor, "changelog": dv.Changelog, "status": dv.Status, "content": dv.Content, diff --git a/pkg/coredata/document_version_approval_quorum.go b/pkg/coredata/document_version_approval_quorum.go index 65e0d7f67..1bbe15b00 100644 --- a/pkg/coredata/document_version_approval_quorum.go +++ b/pkg/coredata/document_version_approval_quorum.go @@ -115,19 +115,26 @@ func (q *DocumentVersionApprovalQuorum) LoadLastByDocumentVersionID( documentVersionID gid.GID, ) error { query := ` +WITH source_version AS ( + SELECT document_id, major FROM document_versions WHERE id = @version_id +), +major_versions AS ( + SELECT dv.id FROM document_versions dv + INNER JOIN source_version sv ON dv.document_id = sv.document_id AND dv.major = sv.major +) SELECT - id, - organization_id, - version_id, - status, - created_at, - updated_at + document_version_approval_quorums.id, + document_version_approval_quorums.organization_id, + document_version_approval_quorums.version_id, + document_version_approval_quorums.status, + document_version_approval_quorums.created_at, + document_version_approval_quorums.updated_at FROM document_version_approval_quorums +INNER JOIN major_versions mv ON document_version_approval_quorums.version_id = mv.id WHERE %s - AND version_id = @version_id -ORDER BY created_at DESC +ORDER BY document_version_approval_quorums.created_at DESC LIMIT 1 ` @@ -162,18 +169,25 @@ func (q *DocumentVersionApprovalQuorums) LoadAllByDocumentVersionID( cursor *page.Cursor[DocumentVersionApprovalQuorumOrderField], ) error { query := ` +WITH source_version AS ( + SELECT document_id, major FROM document_versions WHERE id = @version_id +), +major_versions AS ( + SELECT dv.id FROM document_versions dv + INNER JOIN source_version sv ON dv.document_id = sv.document_id AND dv.major = sv.major +) SELECT - id, - organization_id, - version_id, - status, - created_at, - updated_at + document_version_approval_quorums.id, + document_version_approval_quorums.organization_id, + document_version_approval_quorums.version_id, + document_version_approval_quorums.status, + document_version_approval_quorums.created_at, + document_version_approval_quorums.updated_at FROM document_version_approval_quorums +INNER JOIN major_versions mv ON document_version_approval_quorums.version_id = mv.id WHERE %s - AND version_id = @version_id AND %s ` @@ -205,13 +219,20 @@ func (q *DocumentVersionApprovalQuorums) CountByDocumentVersionID( documentVersionID gid.GID, ) (int, error) { query := ` +WITH source_version AS ( + SELECT document_id, major FROM document_versions WHERE id = @version_id +), +major_versions AS ( + SELECT dv.id FROM document_versions dv + INNER JOIN source_version sv ON dv.document_id = sv.document_id AND dv.major = sv.major +) SELECT - COUNT(id) + COUNT(document_version_approval_quorums.id) FROM document_version_approval_quorums +INNER JOIN major_versions mv ON document_version_approval_quorums.version_id = mv.id WHERE %s - AND version_id = @version_id ` query = fmt.Sprintf(query, scope.SQLFragment()) diff --git a/pkg/coredata/document_version_signature.go b/pkg/coredata/document_version_signature.go index 00a48cdbf..3122d3155 100644 --- a/pkg/coredata/document_version_signature.go +++ b/pkg/coredata/document_version_signature.go @@ -236,21 +236,28 @@ func (pvss *DocumentVersionSignatures) LoadByDocumentVersionID( filter *DocumentVersionSignatureFilter, ) error { q := ` +WITH source_version AS ( + SELECT document_id, major FROM document_versions WHERE id = @document_version_id +), +major_versions AS ( + SELECT dv.id FROM document_versions dv + INNER JOIN source_version sv ON dv.document_id = sv.document_id AND dv.major = sv.major +) SELECT - id, - organization_id, - document_version_id, - state, - signed_by_profile_id, - signed_at, - requested_at, - created_at, - updated_at + document_version_signatures.id, + document_version_signatures.organization_id, + document_version_signatures.document_version_id, + document_version_signatures.state, + document_version_signatures.signed_by_profile_id, + document_version_signatures.signed_at, + document_version_signatures.requested_at, + document_version_signatures.created_at, + document_version_signatures.updated_at FROM document_version_signatures +INNER JOIN major_versions mv ON document_version_signatures.document_version_id = mv.id WHERE %s - AND document_version_id = @document_version_id AND %s AND %s ` @@ -348,7 +355,14 @@ func (pvss *DocumentVersionSignaturesWithPeople) LoadByDocumentVersionIDWithPeop limit int, ) error { q := ` -WITH sigs AS ( +WITH source_version AS ( + SELECT document_id, major FROM document_versions WHERE id = @document_version_id +), +major_versions AS ( + SELECT dv.id FROM document_versions dv + INNER JOIN source_version sv ON dv.document_id = sv.document_id AND dv.major = sv.major +), +signatures_with_people AS ( SELECT dvs.id, dvs.organization_id, @@ -360,16 +374,10 @@ WITH sigs AS ( dvs.requested_at, dvs.created_at, dvs.updated_at, - p.full_name as signed_by_full_name - FROM - document_version_signatures dvs - INNER JOIN - iam_membership_profiles p ON dvs.signed_by_profile_id = p.id - WHERE - dvs.document_version_id = @document_version_id - ORDER BY - p.full_name ASC - LIMIT @limit + p.full_name AS signed_by_full_name + FROM document_version_signatures dvs + INNER JOIN major_versions mv ON dvs.document_version_id = mv.id + INNER JOIN iam_membership_profiles p ON dvs.signed_by_profile_id = p.id ) SELECT id, @@ -383,9 +391,12 @@ SELECT updated_at, signed_by_full_name FROM - sigs + signatures_with_people WHERE %s +ORDER BY + signed_by_full_name ASC +LIMIT @limit ` q = fmt.Sprintf(q, scope.SQLFragment()) @@ -419,18 +430,31 @@ func (pvs *DocumentVersionSignature) IsSignedByUserEmail( userEmail mail.Addr, ) (bool, error) { q := ` -SELECT EXISTS ( - SELECT 1 +WITH source_version AS ( + SELECT document_id, major FROM document_versions WHERE id = @document_version_id +), +major_versions AS ( + SELECT dv.id FROM document_versions dv + INNER JOIN source_version sv ON dv.document_id = sv.document_id AND dv.major = sv.major +), +signed_emails AS ( + SELECT dvs.id, dvs.tenant_id FROM document_version_signatures dvs + INNER JOIN major_versions mv ON dvs.document_version_id = mv.id INNER JOIN iam_membership_profiles p ON dvs.signed_by_profile_id = p.id INNER JOIN identities i ON p.identity_id = i.id - WHERE dvs.document_version_id = @document_version_id - AND i.email_address = @user_email::CITEXT + WHERE i.email_address = @user_email::CITEXT AND dvs.state = 'SIGNED' - AND dvs.tenant_id = @tenant_id +) +SELECT EXISTS ( + SELECT 1 + FROM signed_emails + WHERE %s ) AS signed ` + q = fmt.Sprintf(q, scope.SQLFragment()) + args := pgx.StrictNamedArgs{ "document_version_id": documentVersionID, "user_email": userEmail, @@ -458,13 +482,20 @@ func (dvs *DocumentVersionSignatures) CountByDocumentVersionID( filter *DocumentVersionSignatureFilter, ) (int, error) { q := ` +WITH source_version AS ( + SELECT document_id, major FROM document_versions WHERE id = @document_version_id +), +major_versions AS ( + SELECT dv.id FROM document_versions dv + INNER JOIN source_version sv ON dv.document_id = sv.document_id AND dv.major = sv.major +) SELECT - COUNT(id) + COUNT(document_version_signatures.id) FROM document_version_signatures +INNER JOIN major_versions mv ON document_version_signatures.document_version_id = mv.id WHERE %s - AND document_version_id = @document_version_id AND %s ` diff --git a/pkg/coredata/migrations/20260326T120000Z.sql b/pkg/coredata/migrations/20260326T120000Z.sql new file mode 100644 index 000000000..60b3e551c --- /dev/null +++ b/pkg/coredata/migrations/20260326T120000Z.sql @@ -0,0 +1,11 @@ +ALTER TABLE document_versions DROP CONSTRAINT document_versions_document_id_version_number_key; + +ALTER TABLE document_versions RENAME COLUMN version_number TO major; +ALTER TABLE document_versions ADD COLUMN minor INTEGER NOT NULL DEFAULT 0; +ALTER TABLE document_versions ALTER COLUMN minor DROP DEFAULT; + +ALTER TABLE document_versions ADD CONSTRAINT document_versions_document_id_major_minor_key UNIQUE (document_id, major, minor); + +ALTER TABLE documents RENAME COLUMN current_published_version TO current_published_major; +ALTER TABLE documents ADD COLUMN current_published_minor INTEGER; +UPDATE documents SET current_published_minor = 0 WHERE current_published_major IS NOT NULL; diff --git a/pkg/docgen/generator.go b/pkg/docgen/generator.go index f8a5d1eac..c2e5516c1 100644 --- a/pkg/docgen/generator.go +++ b/pkg/docgen/generator.go @@ -218,7 +218,8 @@ type ( DocumentData struct { Title string Content string - Version int + Major int + Minor int Classification Classification Approvers []string Description string diff --git a/pkg/docgen/generator_test.go b/pkg/docgen/generator_test.go index 0d3363fa8..c029829b9 100644 --- a/pkg/docgen/generator_test.go +++ b/pkg/docgen/generator_test.go @@ -39,7 +39,7 @@ func TestRenderHTML(t *testing.T) { data: DocumentData{ Title: "Test Document", Content: "# Main Title\n\nThis is **bold** text with *italic* formatting.", - Version: 1, + Major: 1, Classification: ClassificationPublic, Approvers: []string{"John Doe"}, PublishedAt: &now, @@ -57,7 +57,7 @@ func TestRenderHTML(t *testing.T) { "

Main Title

", "bold", "italic", - "1", + "1.0", "PUBLIC", "John Doe", "Alice Smith", @@ -383,7 +383,7 @@ func BenchmarkGenerateHTML(b *testing.B) { data := DocumentData{ Title: "Benchmark Document", Content: "# Title\n\nThis is **bold** text with *italic* formatting.\n\n- Item 1\n- Item 2", - Version: 1, + Major: 1, Classification: ClassificationPublic, Approvers: []string{"John Doe"}, PublishedAt: &now, diff --git a/pkg/docgen/template.html b/pkg/docgen/template.html index 34fe31621..3aef8cfac 100644 --- a/pkg/docgen/template.html +++ b/pkg/docgen/template.html @@ -404,7 +404,7 @@ {{- end}} Version: - {{.Version}} + {{.Major}}.{{.Minor}} {{- if .PublishedAt}} diff --git a/pkg/probo/document_approval_service.go b/pkg/probo/document_approval_service.go index a9a1c9536..49e3d3029 100644 --- a/pkg/probo/document_approval_service.go +++ b/pkg/probo/document_approval_service.go @@ -960,26 +960,13 @@ func (s *DocumentApprovalService) publishVersion( return fmt.Errorf("cannot load document version: %w", err) } - document := &coredata.Document{} - if err := document.LoadByID(ctx, tx, s.svc.scope, version.DocumentID); err != nil { - return fmt.Errorf("cannot load document: %w", err) - } + _, _, err := s.svc.Documents.publishMajorVersionInTx( + ctx, + tx, + version.DocumentID, + nil, + false, + ) - now := time.Now() - document.CurrentPublishedVersion = &version.VersionNumber - document.UpdatedAt = now - - version.Status = coredata.DocumentVersionStatusPublished - version.PublishedAt = &now - version.UpdatedAt = now - - if err := document.Update(ctx, tx, s.svc.scope); err != nil { - return fmt.Errorf("cannot update document: %w", err) - } - - if err := version.Update(ctx, tx, s.svc.scope); err != nil { - return fmt.Errorf("cannot update document version: %w", err) - } - - return nil + return err } diff --git a/pkg/probo/document_service.go b/pkg/probo/document_service.go index 271d9d171..97b5349bd 100644 --- a/pkg/probo/document_service.go +++ b/pkg/probo/document_service.go @@ -107,7 +107,6 @@ type ( BulkPublishVersionsRequest struct { DocumentIDs []gid.GID - PublishedBy gid.GID Changelog string } ) @@ -337,11 +336,11 @@ func (s DocumentService) GenerateChangelog( return fmt.Errorf("cannot load document: %w", err) } - if document.CurrentPublishedVersion == nil { + if document.CurrentPublishedMajor == nil { initialVersionChangelog := "Initial version" changelog = &initialVersionChangelog } else { - if err := publishedVersion.LoadByDocumentIDAndVersionNumber(ctx, conn, s.svc.scope, documentID, *document.CurrentPublishedVersion); err != nil { + if err := publishedVersion.LoadByDocumentIDAndVersion(ctx, conn, s.svc.scope, documentID, *document.CurrentPublishedMajor, *document.CurrentPublishedMinor); err != nil { return fmt.Errorf("cannot load published version: %w", err) } } @@ -369,7 +368,7 @@ func (s DocumentService) GenerateChangelog( return changelog, nil } -func (s *DocumentService) BulkPublishVersions( +func (s *DocumentService) BulkPublishMajorVersions( ctx context.Context, req BulkPublishVersionsRequest, ) ([]*coredata.DocumentVersion, []*coredata.Document, error) { @@ -380,7 +379,7 @@ func (s *DocumentService) BulkPublishVersions( ctx, func(tx pg.Conn) error { for _, documentID := range req.DocumentIDs { - document, version, err := s.publishVersionInTx(ctx, tx, documentID, req.PublishedBy, &req.Changelog, true) + document, version, err := s.publishMajorVersionInTx(ctx, tx, documentID, &req.Changelog, true) if err != nil { return fmt.Errorf("cannot publish document %q: %w", documentID, err) } @@ -400,7 +399,38 @@ func (s *DocumentService) BulkPublishVersions( return publishedVersions, updatedDocuments, nil } -func (s *DocumentService) PublishVersion( +func (s *DocumentService) BulkPublishMinorVersions( + ctx context.Context, + req BulkPublishVersionsRequest, +) ([]*coredata.DocumentVersion, []*coredata.Document, error) { + var publishedVersions []*coredata.DocumentVersion + var updatedDocuments []*coredata.Document + + err := s.svc.pg.WithTx( + ctx, + func(tx pg.Conn) error { + for _, documentID := range req.DocumentIDs { + document, version, err := s.publishMinorVersionInTx(ctx, tx, documentID, &req.Changelog, true) + if err != nil { + return fmt.Errorf("cannot publish document %q: %w", documentID, err) + } + + publishedVersions = append(publishedVersions, version) + updatedDocuments = append(updatedDocuments, document) + } + + return nil + }, + ) + + if err != nil { + return nil, nil, err + } + + return publishedVersions, updatedDocuments, nil +} + +func (s *DocumentService) PublishMajorVersion( ctx context.Context, documentID gid.GID, publishedBy gid.GID, @@ -414,9 +444,9 @@ func (s *DocumentService) PublishVersion( func(tx pg.Conn) error { var err error - document, documentVersion, err = s.publishVersionInTx(ctx, tx, documentID, publishedBy, changelog, false) + document, documentVersion, err = s.publishMajorVersionInTx(ctx, tx, documentID, changelog, false) if err != nil { - return fmt.Errorf("cannot publish version: %w", err) + return fmt.Errorf("cannot publish major version: %w", err) } return nil @@ -430,66 +460,31 @@ func (s *DocumentService) PublishVersion( return document, documentVersion, nil } -func (s *DocumentService) publishVersionInTx( +func (s *DocumentService) PublishMinorVersion( ctx context.Context, - tx pg.Conn, documentID gid.GID, publishedBy gid.GID, changelog *string, - ignoreExisting bool, ) (*coredata.Document, *coredata.DocumentVersion, error) { - document := &coredata.Document{} - documentVersion := &coredata.DocumentVersion{} - publishedVersion := &coredata.DocumentVersion{} - now := time.Now() + var document *coredata.Document + var documentVersion *coredata.DocumentVersion - if err := document.LoadByID(ctx, tx, s.svc.scope, documentID); err != nil { - return nil, nil, fmt.Errorf("cannot load document %q: %w", documentID, err) - } + err := s.svc.pg.WithTx( + ctx, + func(tx pg.Conn) error { + var err error - if document.ArchivedAt != nil { - return nil, nil, &ErrDocumentArchived{} - } + document, documentVersion, err = s.publishMinorVersionInTx(ctx, tx, documentID, changelog, false) + if err != nil { + return fmt.Errorf("cannot publish minor version: %w", err) + } - if err := documentVersion.LoadLatestVersion(ctx, tx, s.svc.scope, documentID); err != nil { - return nil, nil, fmt.Errorf("cannot load current draft: %w", err) - } + return nil + }, + ) - if ignoreExisting && documentVersion.Status == coredata.DocumentVersionStatusPublished { - return document, documentVersion, nil - } - - if documentVersion.Status != coredata.DocumentVersionStatusDraft { - return nil, nil, fmt.Errorf("cannot publish version") - } - - if document.CurrentPublishedVersion != nil { - if err := publishedVersion.LoadByDocumentIDAndVersionNumber(ctx, tx, s.svc.scope, documentID, *document.CurrentPublishedVersion); err != nil { - return nil, nil, fmt.Errorf("cannot load published version: %w", err) - } - if publishedVersion.Content == documentVersion.Content && - publishedVersion.Title == documentVersion.Title { - return nil, nil, &ErrDocumentVersionNoChanges{} - } - } - - if changelog != nil { - documentVersion.Changelog = *changelog - } - - document.CurrentPublishedVersion = &documentVersion.VersionNumber - document.UpdatedAt = now - - documentVersion.Status = coredata.DocumentVersionStatusPublished - documentVersion.PublishedAt = &now - documentVersion.UpdatedAt = now - - if err := document.Update(ctx, tx, s.svc.scope); err != nil { - return nil, nil, fmt.Errorf("cannot update document: %w", err) - } - - if err := documentVersion.Update(ctx, tx, s.svc.scope); err != nil { - return nil, nil, fmt.Errorf("cannot update document version: %w", err) + if err != nil { + return nil, nil, err } return document, documentVersion, nil @@ -528,7 +523,8 @@ func (s *DocumentService) Create( ID: documentVersionID, DocumentID: documentID, Title: req.Title, - VersionNumber: 1, + Major: 0, + Minor: 1, Content: req.Content, Status: coredata.DocumentVersionStatusDraft, Classification: req.Classification, @@ -1004,7 +1000,8 @@ func (s *DocumentService) CreateDraft( draftVersion.OrganizationID = document.OrganizationID draftVersion.DocumentID = documentID draftVersion.Title = document.Title - draftVersion.VersionNumber = latestVersion.VersionNumber + 1 + draftVersion.Major = latestVersion.Major + draftVersion.Minor = latestVersion.Minor + 1 draftVersion.Classification = document.Classification draftVersion.Content = latestVersion.Content draftVersion.Status = coredata.DocumentVersionStatusDraft @@ -1043,7 +1040,7 @@ func (s *DocumentService) DeleteDraft( return fmt.Errorf("cannot delete published document version") } - if documentVersion.VersionNumber == 1 { + if documentVersion.Major == 0 && documentVersion.Minor == 1 { return fmt.Errorf("cannot delete the first version of a document") } @@ -1961,7 +1958,8 @@ func exportDocumentPDF( docData := docgen.DocumentData{ Title: version.Title, Content: version.Content, - Version: version.VersionNumber, + Major: version.Major, + Minor: version.Minor, Classification: classification, Approvers: approverNames, PublishedAt: version.PublishedAt, @@ -2168,3 +2166,133 @@ func sanitizeFilename(title string) string { return sanitized } + +func (s *DocumentService) loadDraftForPublish( + ctx context.Context, + tx pg.Conn, + documentID gid.GID, + ignoreExisting bool, +) (*coredata.Document, *coredata.DocumentVersion, error) { + document := &coredata.Document{} + documentVersion := &coredata.DocumentVersion{} + + if err := document.LoadByID(ctx, tx, s.svc.scope, documentID); err != nil { + return nil, nil, fmt.Errorf("cannot load document %q: %w", documentID, err) + } + + if document.ArchivedAt != nil { + return nil, nil, &ErrDocumentArchived{} + } + + if err := documentVersion.LoadLatestVersion(ctx, tx, s.svc.scope, documentID); err != nil { + return nil, nil, fmt.Errorf("cannot load current draft: %w", err) + } + + if ignoreExisting && documentVersion.Status == coredata.DocumentVersionStatusPublished { + return document, documentVersion, nil + } + + if documentVersion.Status != coredata.DocumentVersionStatusDraft { + return nil, nil, &ErrDocumentVersionNotDraft{} + } + + return document, documentVersion, nil +} + +func (s *DocumentService) finalizePublish( + ctx context.Context, + tx pg.Conn, + document *coredata.Document, + documentVersion *coredata.DocumentVersion, + changelog *string, +) error { + now := time.Now() + + if changelog != nil { + documentVersion.Changelog = *changelog + } + + document.UpdatedAt = now + documentVersion.Status = coredata.DocumentVersionStatusPublished + documentVersion.PublishedAt = &now + documentVersion.UpdatedAt = now + + if err := document.Update(ctx, tx, s.svc.scope); err != nil { + return fmt.Errorf("cannot update document: %w", err) + } + + if err := documentVersion.Update(ctx, tx, s.svc.scope); err != nil { + return fmt.Errorf("cannot update document version: %w", err) + } + + return nil +} + +func (s *DocumentService) publishMajorVersionInTx( + ctx context.Context, + tx pg.Conn, + documentID gid.GID, + changelog *string, + ignoreExisting bool, +) (*coredata.Document, *coredata.DocumentVersion, error) { + document, documentVersion, err := s.loadDraftForPublish(ctx, tx, documentID, ignoreExisting) + if err != nil { + return nil, nil, err + } + + if ignoreExisting && documentVersion.Status == coredata.DocumentVersionStatusPublished { + return document, documentVersion, nil + } + + if document.CurrentPublishedMajor != nil { + publishedVersion := &coredata.DocumentVersion{} + if err := publishedVersion.LoadByDocumentIDAndVersion(ctx, tx, s.svc.scope, documentID, *document.CurrentPublishedMajor, *document.CurrentPublishedMinor); err != nil { + return nil, nil, fmt.Errorf("cannot load published version: %w", err) + } + + if publishedVersion.Content == documentVersion.Content && + publishedVersion.Title == documentVersion.Title { + return nil, nil, &ErrDocumentVersionNoChanges{} + } + + documentVersion.Major = *document.CurrentPublishedMajor + 1 + } else { + documentVersion.Major = 1 + } + + documentVersion.Minor = 0 + document.CurrentPublishedMajor = &documentVersion.Major + document.CurrentPublishedMinor = &documentVersion.Minor + + if err := s.finalizePublish(ctx, tx, document, documentVersion, changelog); err != nil { + return nil, nil, err + } + + return document, documentVersion, nil +} + +func (s *DocumentService) publishMinorVersionInTx( + ctx context.Context, + tx pg.Conn, + documentID gid.GID, + changelog *string, + ignoreExisting bool, +) (*coredata.Document, *coredata.DocumentVersion, error) { + document, documentVersion, err := s.loadDraftForPublish(ctx, tx, documentID, ignoreExisting) + if err != nil { + return nil, nil, err + } + + if ignoreExisting && documentVersion.Status == coredata.DocumentVersionStatusPublished { + return document, documentVersion, nil + } + + document.CurrentPublishedMajor = &documentVersion.Major + document.CurrentPublishedMinor = &documentVersion.Minor + + if err := s.finalizePublish(ctx, tx, document, documentVersion, changelog); err != nil { + return nil, nil, err + } + + return document, documentVersion, nil +} diff --git a/pkg/server/api/console/v1/schema.graphql b/pkg/server/api/console/v1/schema.graphql index ff87919f7..afe01c8d8 100644 --- a/pkg/server/api/console/v1/schema.graphql +++ b/pkg/server/api/console/v1/schema.graphql @@ -2441,7 +2441,8 @@ type Document implements Node { description: String documentType: DocumentType! classification: DocumentClassification! - currentPublishedVersion: Int + currentPublishedMajor: Int + currentPublishedMinor: Int trustCenterVisibility: TrustCenterVisibility! organization: Organization! @goField(forceResolver: true) @@ -2501,7 +2502,8 @@ type EmployeeDocumentVersion model: "go.probo.inc/probo/pkg/server/api/console/v1/types.EmployeeDocumentVersion" ) { id: ID! - version: Int! + major: Int! + minor: Int! status: DocumentVersionStatus! signed: Boolean! @goField(forceResolver: true) approvalDecision: DocumentVersionApprovalDecision @goField(forceResolver: true) @@ -3792,10 +3794,16 @@ type Mutation { exportStateOfApplicabilityPDF( input: ExportStateOfApplicabilityPDFInput! ): ExportStateOfApplicabilityPDFPayload! - publishDocumentVersion( - input: PublishDocumentVersionInput! + publishMajorDocumentVersion( + input: PublishMajorDocumentVersionInput! ): PublishDocumentVersionPayload! - bulkPublishDocumentVersions( + publishMinorDocumentVersion( + input: PublishMinorDocumentVersionInput! + ): PublishDocumentVersionPayload! + bulkPublishMajorDocumentVersions( + input: BulkPublishDocumentVersionsInput! + ): BulkPublishDocumentVersionsPayload! + bulkPublishMinorDocumentVersions( input: BulkPublishDocumentVersionsInput! ): BulkPublishDocumentVersionsPayload! requestDocumentVersionApproval( @@ -5355,7 +5363,8 @@ type DocumentVersion implements Node { id: ID! document: Document! @goField(forceResolver: true) status: DocumentVersionStatus! - version: Int! + major: Int! + minor: Int! content: String! changelog: String! title: String! @@ -5686,7 +5695,12 @@ type RequestDocumentVersionApprovalPayload { approvalQuorum: DocumentVersionApprovalQuorum! } -input PublishDocumentVersionInput { +input PublishMajorDocumentVersionInput { + documentId: ID! + changelog: String +} + +input PublishMinorDocumentVersionInput { documentId: ID! changelog: String } diff --git a/pkg/server/api/console/v1/types/document.go b/pkg/server/api/console/v1/types/document.go index 4e349f51a..30ca61e70 100644 --- a/pkg/server/api/console/v1/types/document.go +++ b/pkg/server/api/console/v1/types/document.go @@ -80,13 +80,14 @@ func NewDocument(document *coredata.Document) *Document { Organization: &Organization{ ID: document.OrganizationID, }, - DocumentType: document.DocumentType, - Classification: document.Classification, - CurrentPublishedVersion: document.CurrentPublishedVersion, - TrustCenterVisibility: document.TrustCenterVisibility, - Status: document.Status, - ArchivedAt: document.ArchivedAt, - CreatedAt: document.CreatedAt, - UpdatedAt: document.UpdatedAt, + DocumentType: document.DocumentType, + Classification: document.Classification, + CurrentPublishedMajor: document.CurrentPublishedMajor, + CurrentPublishedMinor: document.CurrentPublishedMinor, + TrustCenterVisibility: document.TrustCenterVisibility, + Status: document.Status, + ArchivedAt: document.ArchivedAt, + CreatedAt: document.CreatedAt, + UpdatedAt: document.UpdatedAt, } } diff --git a/pkg/server/api/console/v1/types/document_version.go b/pkg/server/api/console/v1/types/document_version.go index 5825dc504..c00cdd28e 100644 --- a/pkg/server/api/console/v1/types/document_version.go +++ b/pkg/server/api/console/v1/types/document_version.go @@ -76,7 +76,8 @@ func NewDocumentVersion(documentVersion *coredata.DocumentVersion) *DocumentVers Document: &Document{ ID: documentVersion.DocumentID, }, - Version: documentVersion.VersionNumber, + Major: documentVersion.Major, + Minor: documentVersion.Minor, Title: documentVersion.Title, Content: documentVersion.Content, Status: documentVersion.Status, diff --git a/pkg/server/api/console/v1/types/employee_document.go b/pkg/server/api/console/v1/types/employee_document.go index 1ba5da99e..72d25b811 100644 --- a/pkg/server/api/console/v1/types/employee_document.go +++ b/pkg/server/api/console/v1/types/employee_document.go @@ -66,7 +66,8 @@ type ( EmployeeDocumentVersion struct { ID gid.GID OrganizationID gid.GID - Version int + Major int + Minor int Status coredata.DocumentVersionStatus PublishedAt *time.Time CreatedAt time.Time diff --git a/pkg/server/api/console/v1/v1_resolver.go b/pkg/server/api/console/v1/v1_resolver.go index 58f00d16e..92ac96b54 100644 --- a/pkg/server/api/console/v1/v1_resolver.go +++ b/pkg/server/api/console/v1/v1_resolver.go @@ -1647,7 +1647,8 @@ func (r *employeeDocumentResolver) Versions(ctx context.Context, obj *types.Empl employeeVersions[i] = &types.EmployeeDocumentVersion{ ID: v.ID, OrganizationID: v.OrganizationID, - Version: v.VersionNumber, + Major: v.Major, + Minor: v.Minor, Status: v.Status, PublishedAt: v.PublishedAt, CreatedAt: v.CreatedAt, @@ -5012,16 +5013,20 @@ func (r *mutationResolver) ExportStateOfApplicabilityPDF(ctx context.Context, in }, nil } -// PublishDocumentVersion is the resolver for the publishDocumentVersion field. -func (r *mutationResolver) PublishDocumentVersion(ctx context.Context, input types.PublishDocumentVersionInput) (*types.PublishDocumentVersionPayload, error) { +// PublishMajorDocumentVersion is the resolver for the publishMajorDocumentVersion field. +func (r *mutationResolver) PublishMajorDocumentVersion(ctx context.Context, input types.PublishMajorDocumentVersionInput) (*types.PublishDocumentVersionPayload, error) { if err := r.authorize(ctx, input.DocumentID, probo.ActionDocumentVersionPublish); err != nil { return nil, err } - identity := authn.IdentityFromContext(ctx) prb := r.ProboService(ctx, input.DocumentID.TenantID()) - document, documentVersion, err := prb.Documents.PublishVersion(ctx, input.DocumentID, identity.ID, input.Changelog) + document, documentVersion, err := prb.Documents.PublishMajorVersion( + ctx, + input.DocumentID, + authn.IdentityFromContext(ctx).ID, + input.Changelog, + ) if err != nil { if errArchived, ok := errors.AsType[*probo.ErrDocumentArchived](err); ok { return nil, gqlutils.Conflict(ctx, errArchived) @@ -5031,7 +5036,11 @@ func (r *mutationResolver) PublishDocumentVersion(ctx context.Context, input typ return nil, gqlutils.Invalid(ctx, errNotDraft) } - r.logger.ErrorCtx(ctx, "cannot publish document version", log.Error(err)) + if errNoChanges, ok := errors.AsType[*probo.ErrDocumentVersionNoChanges](err); ok { + return nil, gqlutils.Invalid(ctx, errNoChanges) + } + + r.logger.ErrorCtx(ctx, "cannot publish major document version", log.Error(err)) return nil, gqlutils.Internal(ctx) } @@ -5041,8 +5050,41 @@ func (r *mutationResolver) PublishDocumentVersion(ctx context.Context, input typ }, nil } -// BulkPublishDocumentVersions is the resolver for the bulkPublishDocumentVersions field. -func (r *mutationResolver) BulkPublishDocumentVersions(ctx context.Context, input types.BulkPublishDocumentVersionsInput) (*types.BulkPublishDocumentVersionsPayload, error) { +// PublishMinorDocumentVersion is the resolver for the publishMinorDocumentVersion field. +func (r *mutationResolver) PublishMinorDocumentVersion(ctx context.Context, input types.PublishMinorDocumentVersionInput) (*types.PublishDocumentVersionPayload, error) { + if err := r.authorize(ctx, input.DocumentID, probo.ActionDocumentVersionPublish); err != nil { + return nil, err + } + + prb := r.ProboService(ctx, input.DocumentID.TenantID()) + + document, documentVersion, err := prb.Documents.PublishMinorVersion( + ctx, + input.DocumentID, + authn.IdentityFromContext(ctx).ID, + input.Changelog, + ) + if err != nil { + if errArchived, ok := errors.AsType[*probo.ErrDocumentArchived](err); ok { + return nil, gqlutils.Conflict(ctx, errArchived) + } + + if errNotDraft, ok := errors.AsType[*probo.ErrDocumentVersionNotDraft](err); ok { + return nil, gqlutils.Invalid(ctx, errNotDraft) + } + + r.logger.ErrorCtx(ctx, "cannot publish minor document version", log.Error(err)) + return nil, gqlutils.Internal(ctx) + } + + return &types.PublishDocumentVersionPayload{ + Document: types.NewDocument(document), + DocumentVersion: types.NewDocumentVersion(documentVersion), + }, nil +} + +// BulkPublishMajorDocumentVersions is the resolver for the bulkPublishMajorDocumentVersions field. +func (r *mutationResolver) BulkPublishMajorDocumentVersions(ctx context.Context, input types.BulkPublishDocumentVersionsInput) (*types.BulkPublishDocumentVersionsPayload, error) { if len(input.DocumentIds) == 0 { return &types.BulkPublishDocumentVersionsPayload{ DocumentVersions: []*types.DocumentVersion{}, @@ -5056,12 +5098,10 @@ func (r *mutationResolver) BulkPublishDocumentVersions(ctx context.Context, inpu } } - identity := authn.IdentityFromContext(ctx) prb := r.ProboService(ctx, input.DocumentIds[0].TenantID()) - versions, documents, err := prb.Documents.BulkPublishVersions(ctx, probo.BulkPublishVersionsRequest{ + versions, documents, err := prb.Documents.BulkPublishMajorVersions(ctx, probo.BulkPublishVersionsRequest{ DocumentIDs: input.DocumentIds, - PublishedBy: identity.ID, Changelog: input.Changelog, }) if err != nil { @@ -5073,7 +5113,57 @@ func (r *mutationResolver) BulkPublishDocumentVersions(ctx context.Context, inpu return nil, gqlutils.Invalid(ctx, errNotDraft) } - r.logger.ErrorCtx(ctx, "cannot bulk publish document versions", log.Error(err)) + r.logger.ErrorCtx(ctx, "cannot bulk publish major document versions", log.Error(err)) + return nil, gqlutils.Internal(ctx) + } + + typesVersions := make([]*types.DocumentVersion, len(versions)) + for i, v := range versions { + typesVersions[i] = types.NewDocumentVersion(v) + } + + typesDocuments := make([]*types.Document, len(documents)) + for i, d := range documents { + typesDocuments[i] = types.NewDocument(d) + } + + return &types.BulkPublishDocumentVersionsPayload{ + DocumentVersions: typesVersions, + Documents: typesDocuments, + }, nil +} + +// BulkPublishMinorDocumentVersions is the resolver for the bulkPublishMinorDocumentVersions field. +func (r *mutationResolver) BulkPublishMinorDocumentVersions(ctx context.Context, input types.BulkPublishDocumentVersionsInput) (*types.BulkPublishDocumentVersionsPayload, error) { + if len(input.DocumentIds) == 0 { + return &types.BulkPublishDocumentVersionsPayload{ + DocumentVersions: []*types.DocumentVersion{}, + Documents: []*types.Document{}, + }, nil + } + + for _, documentID := range input.DocumentIds { + if err := r.authorize(ctx, documentID, probo.ActionDocumentVersionPublish); err != nil { + return nil, err + } + } + + prb := r.ProboService(ctx, input.DocumentIds[0].TenantID()) + + versions, documents, err := prb.Documents.BulkPublishMinorVersions(ctx, probo.BulkPublishVersionsRequest{ + DocumentIDs: input.DocumentIds, + Changelog: input.Changelog, + }) + if err != nil { + if errArchived, ok := errors.AsType[*probo.ErrDocumentArchived](err); ok { + return nil, gqlutils.Conflict(ctx, errArchived) + } + + if errNotDraft, ok := errors.AsType[*probo.ErrDocumentVersionNotDraft](err); ok { + return nil, gqlutils.Invalid(ctx, errNotDraft) + } + + r.logger.ErrorCtx(ctx, "cannot bulk publish minor document versions", log.Error(err)) return nil, gqlutils.Internal(ctx) } diff --git a/pkg/server/api/mcp/v1/schema.resolvers.go b/pkg/server/api/mcp/v1/schema.resolvers.go index 542ed0588..6b8749bdc 100644 --- a/pkg/server/api/mcp/v1/schema.resolvers.go +++ b/pkg/server/api/mcp/v1/schema.resolvers.go @@ -2196,24 +2196,6 @@ func (r *Resolver) UpdateDocumentVersionTool(ctx context.Context, req *mcp.CallT }, nil } -func (r *Resolver) PublishDocumentVersionTool(ctx context.Context, req *mcp.CallToolRequest, input *types.PublishDocumentVersionInput) (*mcp.CallToolResult, types.PublishDocumentVersionOutput, error) { - r.MustAuthorize(ctx, input.DocumentID, probo.ActionDocumentVersionPublish) - - svc := r.ProboService(ctx, input.DocumentID) - - user := authn.IdentityFromContext(ctx) - - document, documentVersion, err := svc.Documents.PublishVersion(ctx, input.DocumentID, user.ID, input.Changelog) - if err != nil { - panic(fmt.Errorf("cannot publish document version: %w", err)) - } - - return nil, types.PublishDocumentVersionOutput{ - Document: types.NewDocument(document), - DocumentVersion: types.NewDocumentVersion(documentVersion), - }, nil -} - func (r *Resolver) ListDocumentVersionSignaturesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListDocumentVersionSignaturesInput) (*mcp.CallToolResult, types.ListDocumentVersionSignaturesOutput, error) { r.MustAuthorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionSignatureList) @@ -3324,3 +3306,47 @@ func (r *Resolver) RequestDocumentVersionApprovalTool(ctx context.Context, req * DocumentVersion: types.NewDocumentVersion(documentVersion), }, nil } + +func (r *Resolver) PublishMajorDocumentVersionTool(ctx context.Context, req *mcp.CallToolRequest, input *types.PublishMajorDocumentVersionInput) (*mcp.CallToolResult, types.PublishMajorDocumentVersionOutput, error) { + r.MustAuthorize(ctx, input.DocumentID, probo.ActionDocumentVersionPublish) + + svc := r.ProboService(ctx, input.DocumentID) + user := authn.IdentityFromContext(ctx) + + document, documentVersion, err := svc.Documents.PublishMajorVersion( + ctx, + input.DocumentID, + user.ID, + input.Changelog, + ) + if err != nil { + panic(fmt.Errorf("cannot publish major document version: %w", err)) + } + + return nil, types.PublishMajorDocumentVersionOutput{ + Document: types.NewDocument(document), + DocumentVersion: types.NewDocumentVersion(documentVersion), + }, nil +} + +func (r *Resolver) PublishMinorDocumentVersionTool(ctx context.Context, req *mcp.CallToolRequest, input *types.PublishMinorDocumentVersionInput) (*mcp.CallToolResult, types.PublishMinorDocumentVersionOutput, error) { + r.MustAuthorize(ctx, input.DocumentID, probo.ActionDocumentVersionPublish) + + svc := r.ProboService(ctx, input.DocumentID) + user := authn.IdentityFromContext(ctx) + + document, documentVersion, err := svc.Documents.PublishMinorVersion( + ctx, + input.DocumentID, + user.ID, + input.Changelog, + ) + if err != nil { + panic(fmt.Errorf("cannot publish minor document version: %w", err)) + } + + return nil, types.PublishMinorDocumentVersionOutput{ + Document: types.NewDocument(document), + DocumentVersion: types.NewDocumentVersion(documentVersion), + }, nil +} diff --git a/pkg/server/api/mcp/v1/specification.yaml b/pkg/server/api/mcp/v1/specification.yaml index f6c9fabca..e8ce19ee1 100644 --- a/pkg/server/api/mcp/v1/specification.yaml +++ b/pkg/server/api/mcp/v1/specification.yaml @@ -5207,11 +5207,16 @@ components: classification: $ref: "#/components/schemas/DocumentClassification" description: Document classification - current_published_version: + current_published_major: type: - integer - "null" - description: Current published version number + description: Current published major version number + current_published_minor: + type: + - integer + - "null" + description: Current published minor version number trust_center_visibility: $ref: "#/components/schemas/TrustCenterVisibility" description: Trust center visibility @@ -5240,7 +5245,8 @@ components: - organization_id - document_id - title - - version_number + - major + - minor - classification - content - changelog @@ -5260,9 +5266,12 @@ components: title: type: string description: Document version title - version_number: + major: type: integer - description: Version number + description: Major version number + minor: + type: integer + description: Minor version number classification: $ref: "#/components/schemas/DocumentClassification" description: Document classification @@ -5606,7 +5615,19 @@ components: $ref: "#/components/schemas/GID" description: Deleted document version ID - PublishDocumentVersionInput: + PublishMajorDocumentVersionInput: + type: object + required: + - document_id + properties: + document_id: + $ref: "#/components/schemas/GID" + description: Document ID + changelog: + type: string + description: Changelog for this version + + PublishMinorDocumentVersionInput: type: object required: - document_id @@ -7471,12 +7492,20 @@ tools: $ref: "#/components/schemas/DeleteDraftDocumentVersionInput" outputSchema: $ref: "#/components/schemas/DeleteDraftDocumentVersionOutput" - - name: publishDocumentVersion - description: Publish a draft document version + - name: publishMajorDocumentVersion + description: Publish a draft document version as a new major version hints: readonly: false inputSchema: - $ref: "#/components/schemas/PublishDocumentVersionInput" + $ref: "#/components/schemas/PublishMajorDocumentVersionInput" + outputSchema: + $ref: "#/components/schemas/PublishDocumentVersionOutput" + - name: publishMinorDocumentVersion + description: Publish a draft document version as a minor version + hints: + readonly: false + inputSchema: + $ref: "#/components/schemas/PublishMinorDocumentVersionInput" outputSchema: $ref: "#/components/schemas/PublishDocumentVersionOutput" - name: requestDocumentVersionApproval diff --git a/pkg/server/api/mcp/v1/types/document.go b/pkg/server/api/mcp/v1/types/document.go index b3066bd55..8e29bbcac 100644 --- a/pkg/server/api/mcp/v1/types/document.go +++ b/pkg/server/api/mcp/v1/types/document.go @@ -21,17 +21,18 @@ import ( func NewDocument(d *coredata.Document) *Document { return &Document{ - ID: d.ID, - OrganizationID: d.OrganizationID, - Title: d.Title, - DocumentType: d.DocumentType, - Classification: d.Classification, - CurrentPublishedVersion: d.CurrentPublishedVersion, - TrustCenterVisibility: d.TrustCenterVisibility, - Status: d.Status, - ArchivedAt: d.ArchivedAt, - CreatedAt: d.CreatedAt, - UpdatedAt: d.UpdatedAt, + ID: d.ID, + OrganizationID: d.OrganizationID, + Title: d.Title, + DocumentType: d.DocumentType, + Classification: d.Classification, + CurrentPublishedMajor: d.CurrentPublishedMajor, + CurrentPublishedMinor: d.CurrentPublishedMinor, + TrustCenterVisibility: d.TrustCenterVisibility, + Status: d.Status, + ArchivedAt: d.ArchivedAt, + CreatedAt: d.CreatedAt, + UpdatedAt: d.UpdatedAt, } } @@ -84,7 +85,8 @@ func NewDocumentVersion(dv *coredata.DocumentVersion) *DocumentVersion { OrganizationID: dv.OrganizationID, DocumentID: dv.DocumentID, Title: dv.Title, - VersionNumber: dv.VersionNumber, + Major: dv.Major, + Minor: dv.Minor, Classification: dv.Classification, Content: dv.Content, Changelog: dv.Changelog, diff --git a/pkg/trust/document_service.go b/pkg/trust/document_service.go index f949b1264..e874a094c 100644 --- a/pkg/trust/document_service.go +++ b/pkg/trust/document_service.go @@ -244,7 +244,8 @@ func (s *DocumentService) exportPDFData( docData := docgen.DocumentData{ Title: version.Title, Content: version.Content, - Version: version.VersionNumber, + Major: version.Major, + Minor: version.Minor, Classification: classification, Approvers: approverNames, PublishedAt: version.PublishedAt,