( ctx context.Context, id string, target ApprovalState, eventType string, actor ActorContext, )
| 900 | } |
| 901 | |
| 902 | func (m *Service) transitionTaskApproval( |
| 903 | ctx context.Context, |
| 904 | id string, |
| 905 | target ApprovalState, |
| 906 | eventType string, |
| 907 | actor ActorContext, |
| 908 | ) (*Task, error) { |
| 909 | if err := requireWriteAuthority(actor); err != nil { |
| 910 | return nil, err |
| 911 | } |
| 912 | |
| 913 | trimmedID := strings.TrimSpace(id) |
| 914 | if trimmedID == "" { |
| 915 | return nil, fmt.Errorf("%w: task id is required", ErrValidation) |
| 916 | } |
| 917 | |
| 918 | record, err := m.store.GetTask(ctx, trimmedID) |
| 919 | if err != nil { |
| 920 | return nil, err |
| 921 | } |
| 922 | |
| 923 | previousApprovalState := normalizeApprovalStateOrDefault(record.ApprovalPolicy, record.ApprovalState) |
| 924 | if !taskApprovalDecisionAllowed(record, target) { |
| 925 | return nil, fmt.Errorf( |
| 926 | "%w: task %q cannot transition approval from %q to %q", |
| 927 | ErrInvalidStatusTransition, |
| 928 | record.ID, |
| 929 | previousApprovalState, |
| 930 | target.Normalize(), |
| 931 | ) |
| 932 | } |
| 933 | |
| 934 | record.ApprovalState = target.Normalize() |
| 935 | record.UpdatedAt = m.now().UTC() |
| 936 | record.ClosedAt = time.Time{} |
| 937 | if err := m.store.UpdateTask(ctx, record); err != nil { |
| 938 | return nil, err |
| 939 | } |
| 940 | |
| 941 | reconciled, err := m.reconcileTaskCascade(ctx, record.ID) |
| 942 | if err != nil { |
| 943 | return nil, err |
| 944 | } |
| 945 | if err := m.recordTaskEvent(ctx, reconciled.ID, "", eventType, actor, approvalDecisionTaskPayload{ |
| 946 | PreviousApprovalState: previousApprovalState, |
| 947 | ApprovalState: reconciled.ApprovalState, |
| 948 | Status: reconciled.Status, |
| 949 | }); err != nil { |
| 950 | return nil, err |
| 951 | } |
| 952 | |
| 953 | return &reconciled, nil |
| 954 | } |
| 955 | |
| 956 | func taskApprovalDecisionAllowed(record Task, target ApprovalState) bool { |
| 957 | normalizedPolicy := normalizeApprovalPolicyOrDefault(record.ApprovalPolicy) |
no test coverage detected