37 lines
1.5 KiB
TypeScript
37 lines
1.5 KiB
TypeScript
// The proposal target of this module: the code that writes an approved line.
|
|
//
|
|
// kit-proposals runs `apply` inside the approving transaction, on the approver's own repositories,
|
|
// so the line and the proposal's new status commit together or not at all. That is the only way a
|
|
// row reaches `documents_line`, which is why the export, which reads that table alone, cannot
|
|
// contain a line nobody approved.
|
|
|
|
import { notFound } from "@conusai-kit/core"
|
|
import type { ProposalTarget } from "@conusai-kit/proposals"
|
|
import { documents, LINE_TARGET_KEY, lineChangeSchema, lines } from "../contract/index.js"
|
|
|
|
export const lineTarget: ProposalTarget = {
|
|
key: LINE_TARGET_KEY,
|
|
change: lineChangeSchema,
|
|
// Checked before `apply` runs, so approving a proposal is never a way around this module's own
|
|
// write permission (decision AT-D29).
|
|
permission: "documents.line.approve",
|
|
async apply(tx, scope, write) {
|
|
if (write.targetRecordId === null) throw notFound("no such document")
|
|
const change = lineChangeSchema.parse(write.change)
|
|
const document = await tx.of(documents).get(write.targetRecordId)
|
|
if (!document) throw notFound("no such document")
|
|
const line = await tx.of(lines).insert({
|
|
documentId: document.id,
|
|
proposalId: write.proposalId,
|
|
label: change.label,
|
|
value: change.value,
|
|
page: change.page,
|
|
position: change.position,
|
|
quote: change.quote,
|
|
edited: change.edited,
|
|
approvedBy: scope.actor.userId,
|
|
})
|
|
return { recordId: line.id }
|
|
},
|
|
}
|