shared

package
v0.28.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 5, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ErrCodeFlowNotFound              = 40001
	ErrCodeFlowNotActive             = 40002
	ErrCodeNoPublishedVersion        = 40003
	ErrCodeVersionNotDraft           = 40004
	ErrCodeInvalidFlowDesign         = 40005
	ErrCodeFlowCodeExists            = 40006
	ErrCodeVersionNotFound           = 40007
	ErrCodeInvalidBusinessIdentifier = 40008

	ErrCodeInstanceNotFound          = 40101
	ErrCodeInstanceCompleted         = 40102
	ErrCodeNotAllowedInitiate        = 40103
	ErrCodeWithdrawNotAllowed        = 40104
	ErrCodeResubmitNotAllowed        = 40105
	ErrCodeInvalidInstanceTransition = 40106

	ErrCodeTaskNotFound             = 40201
	ErrCodeTaskNotPending           = 40202
	ErrCodeNotAssignee              = 40203
	ErrCodeInvalidTaskTransition    = 40204
	ErrCodeRollbackNotAllowed       = 40205
	ErrCodeAddAssigneeNotAllowed    = 40206
	ErrCodeTransferNotAllowed       = 40207
	ErrCodeOpinionRequired          = 40208
	ErrCodeManualCcNotAllowed       = 40209
	ErrCodeRemoveAssigneeNotAllowed = 40210
	ErrCodeInvalidAddAssigneeType   = 40211
	ErrCodeNotApplicant             = 40212
	ErrCodeInvalidRollbackTarget    = 40213
	ErrCodeLastAssigneeRemoval      = 40214
	ErrCodeInvalidTransferTarget    = 40215

	ErrCodeNoAssignee            = 40301
	ErrCodeAssigneeResolveFailed = 40302

	ErrCodeFormValidationFailed = 40401
	ErrCodeFieldNotEditable     = 40402

	ErrCodeDelegationNotFound = 40501
	ErrCodeDelegationConflict = 40502

	ErrCodeUrgeCooldown = 40601

	ErrCodeAccessDenied       = 40701
	ErrCodeInstanceNotRunning = 40702
)

Error codes for the approval module (40xxx range).

View Source
const (
	// Urge errors. Template parameters:
	//   {{.minutes}} — cooldown window in minutes
	ErrMessageUrgeTooFrequent = "approval_urge_too_frequent"

	// Form field validation errors. Template parameters:
	//   {{.field}} — field label or key
	//   {{.min}}   — minimum length / value
	//   {{.max}}   — maximum length / value
	ErrMessageFormFieldNotDefined        = "approval_form_field_not_defined"
	ErrMessageFormFieldRequired          = "approval_form_field_required"
	ErrMessageFormFieldMustBeString      = "approval_form_field_must_be_string"
	ErrMessageFormFieldMustBeNumber      = "approval_form_field_must_be_number"
	ErrMessageFormFieldMinLength         = "approval_form_field_min_length"
	ErrMessageFormFieldMaxLength         = "approval_form_field_max_length"
	ErrMessageFormFieldInvalidValidation = "approval_form_field_invalid_validation"
	ErrMessageFormFieldPatternMismatch   = "approval_form_field_pattern_mismatch"
	ErrMessageFormFieldMinValue          = "approval_form_field_min_value"
	ErrMessageFormFieldMaxValue          = "approval_form_field_max_value"
	ErrMessageFormFieldEmpty             = "approval_form_field_empty"
	ErrMessageFormFieldInvalidFileItem   = "approval_form_field_invalid_file_item"
	ErrMessageFormFieldMustBeFile        = "approval_form_field_must_be_file"
	ErrMessageFormFieldInvalidValue      = "approval_form_field_invalid_value"
)

Message IDs for the approval module's i18n keys. Only constants referenced cross-file (template params, factory errors, or mapping tables) are defined here. Single-use sentinel keys are inlined directly at their result.Err definition in api_errors.go.

Variables

View Source
var (
	ErrFlowNotFound       = result.Err(i18n.T("approval_flow_not_found"), result.WithCode(ErrCodeFlowNotFound))
	ErrFlowNotActive      = result.Err(i18n.T("approval_flow_not_active"), result.WithCode(ErrCodeFlowNotActive))
	ErrNoPublishedVersion = result.Err(i18n.T("approval_no_published_version"), result.WithCode(ErrCodeNoPublishedVersion))
	ErrVersionNotDraft    = result.Err(i18n.T("approval_version_not_draft"), result.WithCode(ErrCodeVersionNotDraft))
	ErrInvalidFlowDesign  = result.Err(i18n.T("approval_invalid_flow_design"), result.WithCode(ErrCodeInvalidFlowDesign))
	ErrFlowCodeExists     = result.Err(i18n.T("approval_flow_code_exists"), result.WithCode(ErrCodeFlowCodeExists))
	ErrVersionNotFound    = result.Err(i18n.T("approval_version_not_found"), result.WithCode(ErrCodeVersionNotFound))
	// ErrInvalidBusinessIdentifier rejects business_table / pk / status /
	// title field values that do not match a strict SQL-identifier regex.
	// Flow definitions interpolate these into UPDATE statements at runtime
	// so accepting arbitrary user input would open a SQL injection vector.
	ErrInvalidBusinessIdentifier = result.Err(
		i18n.T("approval_invalid_business_identifier"),
		result.WithCode(ErrCodeInvalidBusinessIdentifier),
	)

	ErrInstanceNotFound          = result.Err(i18n.T("approval_instance_not_found"), result.WithCode(ErrCodeInstanceNotFound))
	ErrInstanceCompleted         = result.Err(i18n.T("approval_instance_completed"), result.WithCode(ErrCodeInstanceCompleted))
	ErrNotAllowedInitiate        = result.Err(i18n.T("approval_not_allowed_initiate"), result.WithCode(ErrCodeNotAllowedInitiate))
	ErrWithdrawNotAllowed        = result.Err(i18n.T("approval_withdraw_not_allowed"), result.WithCode(ErrCodeWithdrawNotAllowed))
	ErrResubmitNotAllowed        = result.Err(i18n.T("approval_resubmit_not_allowed"), result.WithCode(ErrCodeResubmitNotAllowed))
	ErrInvalidInstanceTransition = result.Err(i18n.T("approval_invalid_instance_transition"), result.WithCode(ErrCodeInvalidInstanceTransition))

	ErrTaskNotFound             = result.Err(i18n.T("approval_task_not_found"), result.WithCode(ErrCodeTaskNotFound))
	ErrTaskNotPending           = result.Err(i18n.T("approval_task_not_pending"), result.WithCode(ErrCodeTaskNotPending))
	ErrNotAssignee              = result.Err(i18n.T("approval_not_assignee"), result.WithCode(ErrCodeNotAssignee))
	ErrInvalidTaskTransition    = result.Err(i18n.T("approval_invalid_task_transition"), result.WithCode(ErrCodeInvalidTaskTransition))
	ErrRollbackNotAllowed       = result.Err(i18n.T("approval_rollback_not_allowed"), result.WithCode(ErrCodeRollbackNotAllowed))
	ErrAddAssigneeNotAllowed    = result.Err(i18n.T("approval_add_assignee_not_allowed"), result.WithCode(ErrCodeAddAssigneeNotAllowed))
	ErrTransferNotAllowed       = result.Err(i18n.T("approval_transfer_not_allowed"), result.WithCode(ErrCodeTransferNotAllowed))
	ErrOpinionRequired          = result.Err(i18n.T("approval_opinion_required"), result.WithCode(ErrCodeOpinionRequired))
	ErrManualCcNotAllowed       = result.Err(i18n.T("approval_manual_cc_not_allowed"), result.WithCode(ErrCodeManualCcNotAllowed))
	ErrRemoveAssigneeNotAllowed = result.Err(i18n.T("approval_remove_assignee_not_allowed"), result.WithCode(ErrCodeRemoveAssigneeNotAllowed))
	ErrInvalidAddAssigneeType   = result.Err(i18n.T("approval_invalid_add_assignee_type"), result.WithCode(ErrCodeInvalidAddAssigneeType))
	ErrNotApplicant             = result.Err(i18n.T("approval_not_applicant"), result.WithCode(ErrCodeNotApplicant))
	ErrInvalidRollbackTarget    = result.Err(i18n.T("approval_invalid_rollback_target"), result.WithCode(ErrCodeInvalidRollbackTarget))
	ErrLastAssigneeRemoval      = result.Err(i18n.T("approval_last_assignee_removal"), result.WithCode(ErrCodeLastAssigneeRemoval))
	ErrInvalidTransferTarget    = result.Err(i18n.T("approval_invalid_transfer_target"), result.WithCode(ErrCodeInvalidTransferTarget))

	ErrNoAssignee            = result.Err(i18n.T("approval_no_assignee"), result.WithCode(ErrCodeNoAssignee))
	ErrAssigneeResolveFailed = result.Err(i18n.T("approval_assignee_resolve_failed"), result.WithCode(ErrCodeAssigneeResolveFailed))

	ErrFormValidationFailed = result.Err(i18n.T("approval_form_validation_failed"), result.WithCode(ErrCodeFormValidationFailed))
	ErrFieldNotEditable     = result.Err(i18n.T("approval_field_not_editable"), result.WithCode(ErrCodeFieldNotEditable))
	// ErrFormDataTooLarge rejects submissions whose JSON-encoded form data
	// would exceed FormDataMaxBytes. Stops malicious clients from blowing
	// up the JSONB column or driving the runtime into OOM via deeply
	// nested or massive maps.
	ErrFormDataTooLarge = result.Err(
		i18n.T("approval_form_data_too_large"),
		result.WithCode(ErrCodeFormValidationFailed),
	)

	ErrDelegationNotFound = result.Err(i18n.T("approval_delegation_not_found"), result.WithCode(ErrCodeDelegationNotFound))
	ErrDelegationConflict = result.Err(i18n.T("approval_delegation_conflict"), result.WithCode(ErrCodeDelegationConflict))

	ErrAccessDenied       = result.Err(i18n.T("approval_access_denied"), result.WithCode(ErrCodeAccessDenied))
	ErrInstanceNotRunning = result.Err(i18n.T("approval_instance_not_running"), result.WithCode(ErrCodeInstanceNotRunning))
)

Error definitions. Messages are resolved through i18n at package init time using the language selected by VEF_I18N_LANGUAGE.

These are sentinel values — callers use errors.Is to recognize them, so the Error value must remain stable. Switching i18n language at runtime (e.g. via i18n.SetLanguage in tests) will not update these frozen messages; new translations only take effect on process restart.

Functions

func CollectUniqueCCUserIDs

func CollectUniqueCCUserIDs(
	configs []approval.FlowNodeCC,
	formData approval.FormData,
	resolver CCUserResolver,
	selector CCConfigSelector,
) ([]string, error)

CollectUniqueCCUserIDs resolves and deduplicates CC user IDs while preserving first-seen order.

func ComputeTaskDeadline

func ComputeTaskDeadline(timeoutHours int) *timex.DateTime

ComputeTaskDeadline calculates a task deadline from timeout hours. Returns nil when timeout is disabled.

func InsertAutoCCRecords

func InsertAutoCCRecords(ctx context.Context, db orm.DB, instanceID, nodeID string, userIDs []string, userNames map[string]string) ([]string, error)

InsertAutoCCRecords inserts non-manual CC records and returns newly inserted IDs.

func InsertCCRecords

func InsertCCRecords(
	ctx context.Context,
	db orm.DB,
	instanceID string,
	nodeID *string,
	userIDs []string,
	userNames map[string]string,
	isManual bool,
) ([]string, error)

InsertCCRecords inserts CC records for the given users and returns only the newly inserted user IDs (existing records are ignored).

Callers must hold an instance-level FOR UPDATE lock to prevent concurrent inserts from racing on the existence check.

func InsertManualCCRecords

func InsertManualCCRecords(ctx context.Context, db orm.DB, instanceID, nodeID string, userIDs []string, userNames map[string]string) ([]string, error)

InsertManualCCRecords inserts manual CC records and returns newly inserted IDs.

func NormalizeUniqueIDs

func NormalizeUniqueIDs(ids []string) []string

NormalizeUniqueIDs trims, deduplicates, and filters empty IDs while preserving first-seen order.

func ResolveCCUserIDs

func ResolveCCUserIDs(cfg approval.FlowNodeCC, formData approval.FormData) ([]string, error)

ResolveCCUserIDs resolves CC recipients from static IDs or form-field values. CCRole and CCDepartment kinds require external user resolution and are not supported here.

func ResolveUserName

func ResolveUserName(ctx context.Context, resolver approval.UserInfoResolver, userID string) string

ResolveUserName resolves a single user ID to a display name. Returns empty string on failure (best-effort for display-only fields).

func ResolveUserNameMap

func ResolveUserNameMap(ctx context.Context, resolver approval.UserInfoResolver, ids []string) (map[string]string, error)

ResolveUserNameMap batch-resolves user IDs to a map of ID→Name. Returns an error if the resolver fails.

func ResolveUserNameMapSilent

func ResolveUserNameMapSilent(ctx context.Context, resolver approval.UserInfoResolver, ids []string) map[string]string

ResolveUserNameMapSilent batch-resolves user IDs to a map of ID→Name. Silently returns an empty map on resolver failure (best-effort for display-only fields).

Types

type CCConfigSelector

type CCConfigSelector func(cfg approval.FlowNodeCC) bool

CCConfigSelector decides whether a FlowNodeCC config should be included.

type CCUserResolver

type CCUserResolver func(cfg approval.FlowNodeCC, formData approval.FormData) ([]string, error)

CCUserResolver resolves CC user IDs from a single FlowNodeCC configuration.

type CreateFlowInitiatorCmd

type CreateFlowInitiatorCmd struct {
	Kind approval.InitiatorKind
	IDs  []string
}

CreateFlowInitiatorCmd contains the parameters for creating a flow initiator.

type FlowGraph

type FlowGraph struct {
	Flow    *approval.Flow        `json:"flow"`
	Version *approval.FlowVersion `json:"version"`
	Nodes   []approval.FlowNode   `json:"nodes"`
	Edges   []approval.FlowEdge   `json:"edges"`
}

FlowGraph contains the complete flow graph for a version.

type OrderedUnique

type OrderedUnique[T comparable] struct {
	// contains filtered or unexported fields
}

OrderedUnique stores unique values while preserving first-seen order.

func NewOrderedUnique

func NewOrderedUnique[T comparable](capacity int) *OrderedUnique[T]

NewOrderedUnique creates an ordered-unique container with optional capacity.

func (*OrderedUnique[T]) Add

func (o *OrderedUnique[T]) Add(value T) bool

Add inserts value only if it does not already exist, preserving insertion order.

func (*OrderedUnique[T]) AddAll

func (o *OrderedUnique[T]) AddAll(values ...T) int

AddAll inserts multiple values and returns how many were newly added.

func (*OrderedUnique[T]) Contains

func (o *OrderedUnique[T]) Contains(value T) bool

Contains reports whether value already exists in the set.

func (*OrderedUnique[T]) Len

func (o *OrderedUnique[T]) Len() int

Len returns the number of unique values.

func (*OrderedUnique[T]) ToSlice

func (o *OrderedUnique[T]) ToSlice() []T

ToSlice returns a copy of ordered unique values.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL