Files
member-console/internal/forms/shared.go
T
cgalo5758 88db730fcc Add dual licensing and SPDX headers
Introduce a commercial license option alongside AGPL-3.0-only, require a
CLA for contributors, and document the terms in COMMERCIAL.md and
NOTICE. Add a script to stamp SPDX headers on Go files and apply it
across the tree.
2026-09-06 02:29:42 -05:00

88 lines
3.4 KiB
Go

// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Commercial
// SPDX-FileCopyrightText: 2025-2026 Christian Galo
package forms
// Shared field values (design D3; spec form-library "Two forms that write
// one column share one field"). A Field written by more than one form to
// the same column is declared once here and included by reference, so its
// name, label, hint and rules are identical wherever it appears. A variant
// is a new value with a new name, never a copy with loosened rules
// (lesson L§45).
//
// This is what ends the "reason" collision the audit found (findings
// FA-28, FA-29): Issue grant keeps "reason" for the grant-reason enum and
// Extend writes its note through GrantNote, so one column has one field,
// one label, one hint and one 500-character cap on both paths.
// maxGrantText caps the free-text fields that feed grants.description and
// pool_provision_transitions.reason. Those columns are TEXT with no
// database bound; the cap is the console's own guard, applied by the
// declaration so the control and the handler cannot disagree.
const maxGrantText = 500
// GrantNote is the note written with a grant, by Issue grant and by Extend
// alike; the text is the grant's note, the column upstream is called
// description. Both are dense rows, where a line under one control lifts
// its label above its neighbours', so the explanation rides the help icon
// after the label rather than a hint (form-conventions "Dense form rows
// keep explanations behind a help icon"; the invariants refuse a hint in a
// dense form). Optional because grants.description is a nullable column
// (00001_init.sql) and pre-existing deliveries carry no description at all;
// an extension with no note and no expiry is a legitimate, complete
// submission, not a refused one (a lesson the DB-backed suite caught before
// this was corrected: TestExtendGrant_SucceedsForSinglePoolOrg and
// TestGrantsListDeliveryStateAgreesWithGoDerivation both submit with the
// field absent and expect success).
func GrantNote() Field {
return Field{
Name: "description",
Label: "Note",
Control: Text,
Optional: true,
Help: Help("Note", "Why this grant is issued. Shown with the grant in its history."),
MaxLen: maxGrantText,
Autocomplete: "off",
}
}
// GrantValidUntil is the optional end of a grant, on both grant forms.
// One label, because the two forms wrote one column under two names
// ("Valid until" and "Expires at") before this change.
func GrantValidUntil() Field {
return Field{
Name: "valid_until",
Label: "Valid until",
Control: DateTime,
Optional: true,
Help: Help("Valid until", "Leave blank for a grant with no end date."),
}
}
// RecordName is the name of a catalog record: a product, an entitlement
// set, a plan ladder. Required on every one of them, with no marker,
// because required is the default and only optional is marked.
func RecordName() Field {
return Field{
Name: "name",
Label: "Name",
Control: Text,
MaxLen: 200,
Autocomplete: "off",
}
}
// RecordDescription is the optional prose under a catalog record's name.
// The same column on three records carried three markings before this
// change (finding FA-4); it carries one now.
func RecordDescription() Field {
return Field{
Name: "description",
Label: "Description",
Control: Text,
Optional: true,
MaxLen: 500,
Autocomplete: "off",
}
}