shared

package
v0.26.0 Latest Latest
Warning

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

Go to latest
Published: May 25, 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 (
	// Flow definition errors.
	ErrMessageFlowNotFound              = "approval_flow_not_found"
	ErrMessageFlowNotActive             = "approval_flow_not_active"
	ErrMessageNoPublishedVersion        = "approval_no_published_version"
	ErrMessageVersionNotDraft           = "approval_version_not_draft"
	ErrMessageInvalidFlowDesign         = "approval_invalid_flow_design"
	ErrMessageFlowCodeExists            = "approval_flow_code_exists"
	ErrMessageVersionNotFound           = "approval_version_not_found"
	ErrMessageInvalidBusinessIdentifier = "approval_invalid_business_identifier"

	// Instance errors.
	ErrMessageInstanceNotFound          = "approval_instance_not_found"
	ErrMessageInstanceCompleted         = "approval_instance_completed"
	ErrMessageNotAllowedInitiate        = "approval_not_allowed_initiate"
	ErrMessageWithdrawNotAllowed        = "approval_withdraw_not_allowed"
	ErrMessageResubmitNotAllowed        = "approval_resubmit_not_allowed"
	ErrMessageInvalidInstanceTransition = "approval_invalid_instance_transition"

	// Task errors.
	ErrMessageTaskNotFound             = "approval_task_not_found"
	ErrMessageTaskNotPending           = "approval_task_not_pending"
	ErrMessageNotAssignee              = "approval_not_assignee"
	ErrMessageInvalidTaskTransition    = "approval_invalid_task_transition"
	ErrMessageRollbackNotAllowed       = "approval_rollback_not_allowed"
	ErrMessageAddAssigneeNotAllowed    = "approval_add_assignee_not_allowed"
	ErrMessageTransferNotAllowed       = "approval_transfer_not_allowed"
	ErrMessageOpinionRequired          = "approval_opinion_required"
	ErrMessageManualCcNotAllowed       = "approval_manual_cc_not_allowed"
	ErrMessageRemoveAssigneeNotAllowed = "approval_remove_assignee_not_allowed"
	ErrMessageInvalidAddAssigneeType   = "approval_invalid_add_assignee_type"
	ErrMessageNotApplicant             = "approval_not_applicant"
	ErrMessageInvalidRollbackTarget    = "approval_invalid_rollback_target"
	ErrMessageLastAssigneeRemoval      = "approval_last_assignee_removal"
	ErrMessageInvalidTransferTarget    = "approval_invalid_transfer_target"

	// Assignee resolution errors.
	ErrMessageNoAssignee            = "approval_no_assignee"
	ErrMessageAssigneeResolveFailed = "approval_assignee_resolve_failed"

	// Form aggregate errors.
	ErrMessageFormValidationFailed = "approval_form_validation_failed"
	ErrMessageFieldNotEditable     = "approval_field_not_editable"
	ErrMessageFormDataTooLarge     = "approval_form_data_too_large"

	// Delegation errors.
	ErrMessageDelegationNotFound = "approval_delegation_not_found"
	ErrMessageDelegationConflict = "approval_delegation_conflict"

	// Urge errors.
	ErrMessageUrgeTooFrequent = "approval_urge_too_frequent"

	// Access errors.
	ErrMessageAccessDenied       = "approval_access_denied"
	ErrMessageInstanceNotRunning = "approval_instance_not_running"

	// 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. Use with i18n.T() to resolve to the active language.

Variables

View Source
var (
	ErrFlowNotFound       = result.Err(i18n.T(ErrMessageFlowNotFound), result.WithCode(ErrCodeFlowNotFound))
	ErrFlowNotActive      = result.Err(i18n.T(ErrMessageFlowNotActive), result.WithCode(ErrCodeFlowNotActive))
	ErrNoPublishedVersion = result.Err(i18n.T(ErrMessageNoPublishedVersion), result.WithCode(ErrCodeNoPublishedVersion))
	ErrVersionNotDraft    = result.Err(i18n.T(ErrMessageVersionNotDraft), result.WithCode(ErrCodeVersionNotDraft))
	ErrInvalidFlowDesign  = result.Err(i18n.T(ErrMessageInvalidFlowDesign), result.WithCode(ErrCodeInvalidFlowDesign))
	ErrFlowCodeExists     = result.Err(i18n.T(ErrMessageFlowCodeExists), result.WithCode(ErrCodeFlowCodeExists))
	ErrVersionNotFound    = result.Err(i18n.T(ErrMessageVersionNotFound), 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(ErrMessageInvalidBusinessIdentifier),
		result.WithCode(ErrCodeInvalidBusinessIdentifier),
	)

	ErrInstanceNotFound          = result.Err(i18n.T(ErrMessageInstanceNotFound), result.WithCode(ErrCodeInstanceNotFound))
	ErrInstanceCompleted         = result.Err(i18n.T(ErrMessageInstanceCompleted), result.WithCode(ErrCodeInstanceCompleted))
	ErrNotAllowedInitiate        = result.Err(i18n.T(ErrMessageNotAllowedInitiate), result.WithCode(ErrCodeNotAllowedInitiate))
	ErrWithdrawNotAllowed        = result.Err(i18n.T(ErrMessageWithdrawNotAllowed), result.WithCode(ErrCodeWithdrawNotAllowed))
	ErrResubmitNotAllowed        = result.Err(i18n.T(ErrMessageResubmitNotAllowed), result.WithCode(ErrCodeResubmitNotAllowed))
	ErrInvalidInstanceTransition = result.Err(i18n.T(ErrMessageInvalidInstanceTransition), result.WithCode(ErrCodeInvalidInstanceTransition))

	ErrTaskNotFound             = result.Err(i18n.T(ErrMessageTaskNotFound), result.WithCode(ErrCodeTaskNotFound))
	ErrTaskNotPending           = result.Err(i18n.T(ErrMessageTaskNotPending), result.WithCode(ErrCodeTaskNotPending))
	ErrNotAssignee              = result.Err(i18n.T(ErrMessageNotAssignee), result.WithCode(ErrCodeNotAssignee))
	ErrInvalidTaskTransition    = result.Err(i18n.T(ErrMessageInvalidTaskTransition), result.WithCode(ErrCodeInvalidTaskTransition))
	ErrRollbackNotAllowed       = result.Err(i18n.T(ErrMessageRollbackNotAllowed), result.WithCode(ErrCodeRollbackNotAllowed))
	ErrAddAssigneeNotAllowed    = result.Err(i18n.T(ErrMessageAddAssigneeNotAllowed), result.WithCode(ErrCodeAddAssigneeNotAllowed))
	ErrTransferNotAllowed       = result.Err(i18n.T(ErrMessageTransferNotAllowed), result.WithCode(ErrCodeTransferNotAllowed))
	ErrOpinionRequired          = result.Err(i18n.T(ErrMessageOpinionRequired), result.WithCode(ErrCodeOpinionRequired))
	ErrManualCcNotAllowed       = result.Err(i18n.T(ErrMessageManualCcNotAllowed), result.WithCode(ErrCodeManualCcNotAllowed))
	ErrRemoveAssigneeNotAllowed = result.Err(i18n.T(ErrMessageRemoveAssigneeNotAllowed), result.WithCode(ErrCodeRemoveAssigneeNotAllowed))
	ErrInvalidAddAssigneeType   = result.Err(i18n.T(ErrMessageInvalidAddAssigneeType), result.WithCode(ErrCodeInvalidAddAssigneeType))
	ErrNotApplicant             = result.Err(i18n.T(ErrMessageNotApplicant), result.WithCode(ErrCodeNotApplicant))
	ErrInvalidRollbackTarget    = result.Err(i18n.T(ErrMessageInvalidRollbackTarget), result.WithCode(ErrCodeInvalidRollbackTarget))
	ErrLastAssigneeRemoval      = result.Err(i18n.T(ErrMessageLastAssigneeRemoval), result.WithCode(ErrCodeLastAssigneeRemoval))
	ErrInvalidTransferTarget    = result.Err(i18n.T(ErrMessageInvalidTransferTarget), result.WithCode(ErrCodeInvalidTransferTarget))

	ErrNoAssignee            = result.Err(i18n.T(ErrMessageNoAssignee), result.WithCode(ErrCodeNoAssignee))
	ErrAssigneeResolveFailed = result.Err(i18n.T(ErrMessageAssigneeResolveFailed), result.WithCode(ErrCodeAssigneeResolveFailed))

	ErrFormValidationFailed = result.Err(i18n.T(ErrMessageFormValidationFailed), result.WithCode(ErrCodeFormValidationFailed))
	ErrFieldNotEditable     = result.Err(i18n.T(ErrMessageFieldNotEditable), 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(ErrMessageFormDataTooLarge),
		result.WithCode(ErrCodeFormValidationFailed),
	)

	ErrDelegationNotFound = result.Err(i18n.T(ErrMessageDelegationNotFound), result.WithCode(ErrCodeDelegationNotFound))
	ErrDelegationConflict = result.Err(i18n.T(ErrMessageDelegationConflict), result.WithCode(ErrCodeDelegationConflict))

	ErrAccessDenied       = result.Err(i18n.T(ErrMessageAccessDenied), result.WithCode(ErrCodeAccessDenied))
	ErrInstanceNotRunning = result.Err(i18n.T(ErrMessageInstanceNotRunning), 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