固化七月迭代审计治理进展以隔离线上热修
Constraint: 切换 main 前必须保存当前七月分支全部项目进展,套餐生效提案仅属于 Iteration/7-11。 Rejected: 将七月套餐修复直接移植到 main | 两个分支的可靠投递架构不同。 Confidence: medium Scope-risk: broad Directive: 不得将本提交整体 cherry-pick 到 main;main 套餐热修必须基于其纯 Asynq 代码独立实施。 Tested: git diff --check;openspec validate fix-package-activation-starvation --strict。 Not-tested: 按用户要求未运行自动化测试;go build ./... 因当前审计改造中的 Enterprise 模型字面量和 role.recordFailure 参数类型错误未通过。
This commit is contained in:
@@ -92,10 +92,13 @@ func (u *ApprovalAttachmentUploader) Upload(ctx context.Context, applicationID,
|
||||
return "", err
|
||||
}
|
||||
resourceID := strconv.FormatUint(uint64(instanceID), 10)
|
||||
integrationID, triggerSeries, correlationID := singleIntegrationLinkage(nil)
|
||||
attempt, err := u.integration.Start(ctx, integrationlog.Attempt{
|
||||
Provider: constants.IntegrationProviderWeCom, Direction: constants.IntegrationDirectionOutbound,
|
||||
IntegrationID: integrationID,
|
||||
Provider: constants.IntegrationProviderWeCom, Direction: constants.IntegrationDirectionOutbound,
|
||||
Operation: constants.IntegrationOperationWeComAttachmentUpload, ResourceType: constants.WeComApprovalInstanceResourceType,
|
||||
ResourceID: &resourceID, RequestSummary: map[string]any{
|
||||
ResourceID: &resourceID, TriggerSeries: triggerSeries, CorrelationID: correlationID,
|
||||
RequestSummary: map[string]any{
|
||||
"application_id": applicationID, "file_name": fileName, "file_bytes": info.Size(),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -42,7 +42,7 @@ func NewApprovalDetailClient(tokens DirectoryTokenProvider, integration TokenInt
|
||||
}
|
||||
|
||||
// Get 获取审批详情并记录一次真实外呼。
|
||||
func (c *ApprovalDetailClient) Get(ctx context.Context, applicationID uint, spNo string) (ApprovalDetail, error) {
|
||||
func (c *ApprovalDetailClient) Get(ctx context.Context, applicationID uint, spNo string, resourceID *string, correlationID string) (ApprovalDetail, error) {
|
||||
token, err := c.tokens.GetAccessToken(ctx, applicationID)
|
||||
if err != nil {
|
||||
return ApprovalDetail{}, err
|
||||
@@ -51,11 +51,14 @@ func (c *ApprovalDetailClient) Get(ctx context.Context, applicationID uint, spNo
|
||||
if err != nil {
|
||||
return ApprovalDetail{}, err
|
||||
}
|
||||
resourceID := strconv.FormatUint(uint64(applicationID), 10)
|
||||
resourceKey := strings.TrimSpace(spNo)
|
||||
triggerSeries := "wecom-approval-detail:" + resourceKey
|
||||
attempt, err := c.integration.Start(ctx, integrationlog.Attempt{
|
||||
Provider: constants.IntegrationProviderWeCom, Direction: constants.IntegrationDirectionOutbound,
|
||||
Operation: constants.IntegrationOperationWeComApprovalDetail, ResourceType: constants.WeComApprovalInstanceResourceType,
|
||||
ResourceID: &resourceID, ExternalID: &spNo, RequestSummary: map[string]any{"application_id": applicationID, "sp_no": spNo},
|
||||
ResourceID: resourceID, ResourceKey: &resourceKey, ExternalID: &spNo,
|
||||
TriggerSeries: &triggerSeries, CorrelationID: optionalIntegrationString(correlationID),
|
||||
RequestSummary: map[string]any{"application_id": applicationID, "sp_no": spNo},
|
||||
})
|
||||
if err != nil {
|
||||
return ApprovalDetail{}, err
|
||||
|
||||
@@ -2,6 +2,7 @@ package wecom
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -39,11 +40,18 @@ func (h *ApprovalDetailTaskHandler) Handle(ctx context.Context, task *asynq.Task
|
||||
if !validApprovalSyncSource(payload.Source) {
|
||||
return errors.New(errors.CodeInvalidParam, "企业微信审批详情同步来源无效")
|
||||
}
|
||||
detail, err := h.details.Get(ctx, payload.ApplicationID, payload.SPNo)
|
||||
record, err := h.contexts.FindBySPNo(ctx, payload.ApplicationID, payload.SPNo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
record, err := h.contexts.FindBySPNo(ctx, payload.ApplicationID, payload.SPNo)
|
||||
correlationID := payload.SPNo
|
||||
var resourceID *string
|
||||
if record != nil {
|
||||
value := strconv.FormatUint(uint64(record.Instance.ID), 10)
|
||||
resourceID = &value
|
||||
correlationID = record.Instance.CorrelationID
|
||||
}
|
||||
detail, err := h.details.Get(ctx, payload.ApplicationID, payload.SPNo, resourceID, correlationID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -68,11 +76,14 @@ func (h *ApprovalDetailTaskHandler) Handle(ctx context.Context, task *asynq.Task
|
||||
}
|
||||
}
|
||||
if strings.TrimSpace(payload.IntegrationID) != "" {
|
||||
resolvedResourceID := strconv.FormatUint(uint64(record.Instance.ID), 10)
|
||||
resolvedResourceKey := strings.TrimSpace(payload.SPNo)
|
||||
_, err = h.integration.Complete(ctx, payload.IntegrationID, integrationlog.Completion{
|
||||
Result: constants.IntegrationResultCompleted, ProviderCode: "processed",
|
||||
ProviderMessage: "企业微信审批回调已完成权威详情同步",
|
||||
ResponseSummary: map[string]any{"sp_no": payload.SPNo, "sp_status": detail.SPStatus, "decisions": decisions},
|
||||
DurationMS: 0, StateChanged: len(decisions) > 0,
|
||||
ResourceID: &resolvedResourceID, ResourceKey: &resolvedResourceKey,
|
||||
})
|
||||
}
|
||||
return err
|
||||
|
||||
@@ -71,14 +71,16 @@ func (c *ApprovalInfoClient) List(ctx context.Context, input ApprovalInfoQuery)
|
||||
return ApprovalInfoPage{}, err
|
||||
}
|
||||
resourceID := strconv.FormatUint(uint64(input.ApplicationID), 10)
|
||||
integrationID, triggerSeries, correlationID := singleIntegrationLinkage(nil)
|
||||
attempt, err := c.integration.Start(ctx, integrationlog.Attempt{
|
||||
Provider: constants.IntegrationProviderWeCom, Direction: constants.IntegrationDirectionOutbound,
|
||||
Operation: constants.IntegrationOperationWeComApprovalInfo, ResourceType: constants.WeComApprovalInstanceResourceType,
|
||||
IntegrationID: integrationID,
|
||||
Provider: constants.IntegrationProviderWeCom, Direction: constants.IntegrationDirectionOutbound,
|
||||
Operation: constants.IntegrationOperationWeComApprovalInfo, ResourceType: constants.WeComApplicationResourceType,
|
||||
ResourceID: &resourceID, RequestSummary: map[string]any{
|
||||
"application_id": input.ApplicationID, "starttime": input.StartTime.Unix(), "endtime": input.EndTime.Unix(),
|
||||
"template_id": input.TemplateID, "creator_userid": input.CreatorUserID, "size": input.Size,
|
||||
"cursor_present": strings.TrimSpace(input.Cursor) != "",
|
||||
},
|
||||
}, TriggerSeries: triggerSeries, CorrelationID: correlationID,
|
||||
})
|
||||
if err != nil {
|
||||
return ApprovalInfoPage{}, err
|
||||
|
||||
@@ -76,13 +76,14 @@ func (c *ApprovalSubmissionClient) Submit(ctx context.Context, input ApprovalSub
|
||||
}
|
||||
resourceID := strconv.FormatUint(uint64(input.InstanceID), 10)
|
||||
correlationID := strings.TrimSpace(input.CorrelationID)
|
||||
triggerSeries := "wecom-approval-submit:" + resourceID
|
||||
attempt, err := c.integration.Start(ctx, integrationlog.Attempt{
|
||||
Provider: constants.IntegrationProviderWeCom, Direction: constants.IntegrationDirectionOutbound,
|
||||
Operation: constants.IntegrationOperationWeComApprovalSubmit, ResourceType: constants.WeComApprovalInstanceResourceType,
|
||||
ResourceID: &resourceID, RequestSummary: map[string]any{
|
||||
"application_id": input.ApplicationID, "template_id": input.TemplateID,
|
||||
"creator_source_configured": input.CreatorUserID != "", "control_count": len(input.Contents),
|
||||
}, CorrelationID: optionalIntegrationString(correlationID),
|
||||
}, CorrelationID: optionalIntegrationString(correlationID), TriggerSeries: &triggerSeries,
|
||||
})
|
||||
if err != nil {
|
||||
return ApprovalSubmitResult{Outcome: submissionOutcomeFailed, Message: "写入企业微信审批提交日志失败", SafeToRetry: true}, err
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/middleware"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/queue"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -84,12 +85,13 @@ func (s *CallbackService) Receive(ctx context.Context, applicationID uint, signa
|
||||
if err := xml.Unmarshal(plaintext, &event); err != nil || event.Event != "sys_approval_change" || strings.TrimSpace(event.SPNo) == "" {
|
||||
return errors.New(errors.CodeInvalidParam, "企业微信审批回调事件无效")
|
||||
}
|
||||
resourceID := strconv.FormatUint(uint64(applicationID), 10)
|
||||
resourceKey := strings.TrimSpace(event.SPNo)
|
||||
requestID := middleware.GetRequestIDFromContext(ctx)
|
||||
log, created, err := s.integration.RecordInbound(ctx, integrationlog.InboundAttempt{
|
||||
IdempotencyKey: applicationCallbackIdempotencyKey(applicationID, signature),
|
||||
Provider: constants.IntegrationProviderWeCom, Operation: constants.IntegrationOperationWeComApprovalCallback,
|
||||
ExternalID: event.SPNo, ResourceType: constants.WeComApprovalInstanceResourceType, ResourceID: &resourceID,
|
||||
RawPayload: body, ContentType: "application/xml",
|
||||
ExternalID: event.SPNo, ResourceType: constants.WeComApprovalInstanceResourceType, ResourceKey: &resourceKey,
|
||||
RawPayload: body, ContentType: "application/xml", RequestID: requestID, CorrelationID: &resourceKey,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -75,11 +75,13 @@ func (c *DirectoryClient) listVisibleDepartments(ctx context.Context, applicatio
|
||||
}
|
||||
resourceID := strconv.FormatUint(uint64(applicationID), 10)
|
||||
requestID := middleware.GetRequestIDFromContext(ctx)
|
||||
integrationID, triggerSeries, correlationID := singleIntegrationLinkage(requestID)
|
||||
attempt, err := c.integration.Start(ctx, integrationlog.Attempt{
|
||||
Provider: constants.IntegrationProviderWeCom, Direction: constants.IntegrationDirectionOutbound,
|
||||
IntegrationID: integrationID,
|
||||
Provider: constants.IntegrationProviderWeCom, Direction: constants.IntegrationDirectionOutbound,
|
||||
Operation: constants.IntegrationOperationWeComVisibleDepartments, ResourceType: constants.WeComApplicationResourceType,
|
||||
ResourceID: &resourceID, RequestSummary: map[string]any{"application_id": applicationID},
|
||||
RequestID: requestID, CorrelationID: requestID,
|
||||
RequestID: requestID, CorrelationID: correlationID, TriggerSeries: triggerSeries,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -115,12 +117,14 @@ func (c *DirectoryClient) listDepartmentMembers(ctx context.Context, application
|
||||
}
|
||||
resourceID := strconv.FormatUint(uint64(applicationID), 10)
|
||||
requestID := middleware.GetRequestIDFromContext(ctx)
|
||||
integrationID, triggerSeries, correlationID := singleIntegrationLinkage(requestID)
|
||||
attempt, err := c.integration.Start(ctx, integrationlog.Attempt{
|
||||
Provider: constants.IntegrationProviderWeCom, Direction: constants.IntegrationDirectionOutbound,
|
||||
IntegrationID: integrationID,
|
||||
Provider: constants.IntegrationProviderWeCom, Direction: constants.IntegrationDirectionOutbound,
|
||||
Operation: constants.IntegrationOperationWeComVisibleMembers, ResourceType: constants.WeComApplicationResourceType,
|
||||
ResourceID: &resourceID, RequestSummary: map[string]any{
|
||||
"application_id": applicationID, "department_id": departmentID, "fetch_child": true,
|
||||
}, RequestID: requestID, CorrelationID: requestID,
|
||||
}, RequestID: requestID, CorrelationID: correlationID, TriggerSeries: triggerSeries,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
11
internal/infrastructure/wecom/integration_linkage.go
Normal file
11
internal/infrastructure/wecom/integration_linkage.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package wecom
|
||||
|
||||
import "github.com/google/uuid"
|
||||
|
||||
func singleIntegrationLinkage(correlationID *string) (string, *string, *string) {
|
||||
integrationID := uuid.NewString()
|
||||
if correlationID == nil {
|
||||
correlationID = &integrationID
|
||||
}
|
||||
return integrationID, &integrationID, correlationID
|
||||
}
|
||||
@@ -54,12 +54,14 @@ func (c *TemplateClient) GetTemplateDetail(ctx context.Context, applicationID ui
|
||||
}
|
||||
resourceID := strconv.FormatUint(uint64(applicationID), 10)
|
||||
requestID := middleware.GetRequestIDFromContext(ctx)
|
||||
integrationID, triggerSeries, correlationID := singleIntegrationLinkage(requestID)
|
||||
attempt, err := c.integration.Start(ctx, integrationlog.Attempt{
|
||||
Provider: constants.IntegrationProviderWeCom, Direction: constants.IntegrationDirectionOutbound,
|
||||
IntegrationID: integrationID,
|
||||
Provider: constants.IntegrationProviderWeCom, Direction: constants.IntegrationDirectionOutbound,
|
||||
Operation: constants.IntegrationOperationWeComTemplateDetail, ResourceType: constants.WeComApprovalSceneResourceType,
|
||||
ResourceID: &resourceID, RequestSummary: map[string]any{
|
||||
"application_id": applicationID, "template_id": templateID,
|
||||
}, RequestID: requestID, CorrelationID: requestID,
|
||||
}, RequestID: requestID, CorrelationID: correlationID, TriggerSeries: triggerSeries,
|
||||
})
|
||||
if err != nil {
|
||||
return wecomapp.TemplateDefinition{}, err
|
||||
|
||||
@@ -161,12 +161,14 @@ func (p *TokenProvider) fetchAndCache(ctx context.Context, applicationID uint, c
|
||||
}
|
||||
resourceID := strconv.FormatUint(uint64(applicationID), 10)
|
||||
requestID := middleware.GetRequestIDFromContext(ctx)
|
||||
integrationID, triggerSeries, correlationID := singleIntegrationLinkage(requestID)
|
||||
attempt, err := p.integration.Start(ctx, integrationlog.Attempt{
|
||||
Provider: constants.IntegrationProviderWeCom, Direction: constants.IntegrationDirectionOutbound,
|
||||
IntegrationID: integrationID,
|
||||
Provider: constants.IntegrationProviderWeCom, Direction: constants.IntegrationDirectionOutbound,
|
||||
Operation: constants.IntegrationOperationWeComAccessToken, ResourceType: constants.WeComApplicationResourceType,
|
||||
ResourceID: &resourceID, RequestSummary: map[string]any{
|
||||
"application_id": applicationID, "corp_id": application.CorpID, "agent_id": application.AgentID,
|
||||
}, RequestID: requestID, CorrelationID: requestID,
|
||||
}, RequestID: requestID, CorrelationID: correlationID, TriggerSeries: triggerSeries,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
Reference in New Issue
Block a user