Add major.minor document versioning
Introduce a two-part version scheme (major.minor) for documents. Drafts start at 0.1 and increment minor on each new draft. Publishing as minor keeps the current version, publishing as major bumps to the next major.0. Both current_published_major and current_published_minor are tracked on the document for exact version lookups. Signatures and approval quorums aggregate across all versions sharing the same major number using CTE joins. Approval page mutations spread the decision fragment so Relay updates the version row state without requiring a page refresh. GraphQL, MCP, and service layer expose separate publishMajor and publishMinor mutations instead of a single mutation with a type enum. Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
@@ -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
|
||||
`
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
|
||||
`
|
||||
|
||||
|
||||
11
pkg/coredata/migrations/20260326T120000Z.sql
Normal file
11
pkg/coredata/migrations/20260326T120000Z.sql
Normal file
@@ -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;
|
||||
Reference in New Issue
Block a user