feat(t215): add admin order authorization
This commit is contained in:
@@ -24,13 +24,15 @@ const (
|
||||
)
|
||||
|
||||
type AdminServices struct {
|
||||
Assets *usecase.AssetService
|
||||
Tasks *usecase.TaskService
|
||||
Results *usecase.ExecutionResultService
|
||||
Assets *usecase.AssetService
|
||||
Tasks *usecase.TaskService
|
||||
Results *usecase.ExecutionResultService
|
||||
Authorizations *usecase.OrderAuthorizationService
|
||||
}
|
||||
|
||||
func (s AdminServices) validate() error {
|
||||
if s.Assets == nil || s.Tasks == nil || s.Results == nil {
|
||||
if s.Assets == nil || s.Tasks == nil || s.Results == nil ||
|
||||
s.Authorizations == nil {
|
||||
return errors.New("admin services are required")
|
||||
}
|
||||
return nil
|
||||
@@ -55,6 +57,10 @@ func registerAdminAPI(routes gin.IRoutes, services AdminServices) error {
|
||||
handler.evidenceContent,
|
||||
)
|
||||
routes.POST("/api/v1/tasks/:id/cancel", handler.cancelTask)
|
||||
routes.POST(
|
||||
"/api/v1/tasks/:id/order-authorizations",
|
||||
handler.createOrderAuthorization,
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -371,13 +377,116 @@ func (h *adminHandlers) taskDetail(ctx *gin.Context) {
|
||||
"claim": claim,
|
||||
"execution": execution,
|
||||
"execution_report": executionReport,
|
||||
"events": events,
|
||||
"order_authorizations": orderAuthorizationResponses(
|
||||
detail.OrderAuthorizations,
|
||||
),
|
||||
"events": events,
|
||||
"assets": []gin.H{
|
||||
assetResponse(detail.Asset),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (h *adminHandlers) createOrderAuthorization(ctx *gin.Context) {
|
||||
var request struct {
|
||||
ExecutionID string `json:"execution_id"`
|
||||
TaskContentSHA256 string `json:"task_content_sha256"`
|
||||
ExpectedTaskVersion int64 `json:"expected_task_version"`
|
||||
CandidateKey string `json:"candidate_key"`
|
||||
ReasonSchemaVersion int `json:"reason_schema_version"`
|
||||
PrimaryReasonCode string `json:"primary_reason_code"`
|
||||
Note string `json:"note"`
|
||||
SupersedesAuthorizationID *string `json:"supersedes_authorization_id"`
|
||||
Items []usecase.OrderAuthorizationItemInput `json:"items"`
|
||||
}
|
||||
if err := decodeJSON(ctx, &request); err != nil {
|
||||
writePublicError(
|
||||
ctx,
|
||||
http.StatusBadRequest,
|
||||
"INVALID_JSON",
|
||||
"request body must be valid JSON",
|
||||
false,
|
||||
gin.H{},
|
||||
)
|
||||
return
|
||||
}
|
||||
result, err := h.services.Authorizations.Create(
|
||||
ctx.Request.Context(),
|
||||
usecase.CreateOrderAuthorizationCommand{
|
||||
ActorUserID: adminActorUserID(ctx),
|
||||
TaskID: ctx.Param("id"),
|
||||
IdempotencyKey: ctx.GetHeader("Idempotency-Key"),
|
||||
ExecutionID: request.ExecutionID,
|
||||
TaskContentSHA256: request.TaskContentSHA256,
|
||||
ExpectedTaskVersion: request.ExpectedTaskVersion,
|
||||
CandidateKey: request.CandidateKey,
|
||||
ReasonSchemaVersion: request.ReasonSchemaVersion,
|
||||
PrimaryReasonCode: request.PrimaryReasonCode,
|
||||
Note: request.Note,
|
||||
SupersedesAuthorizationID: request.SupersedesAuthorizationID,
|
||||
Items: request.Items,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
writeUsecaseError(ctx, err)
|
||||
return
|
||||
}
|
||||
ctx.Header("Cache-Control", "no-store")
|
||||
ctx.JSON(http.StatusCreated, gin.H{
|
||||
"authorization": orderAuthorizationResponse(result.Authorization),
|
||||
"replayed": result.Replayed,
|
||||
})
|
||||
}
|
||||
|
||||
func orderAuthorizationResponses(
|
||||
authorizations []domain.OrderAuthorization,
|
||||
) []gin.H {
|
||||
result := make([]gin.H, 0, len(authorizations))
|
||||
for _, authorization := range authorizations {
|
||||
result = append(result, orderAuthorizationResponse(authorization))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func orderAuthorizationResponse(
|
||||
authorization domain.OrderAuthorization,
|
||||
) gin.H {
|
||||
return gin.H{
|
||||
"id": authorization.ID,
|
||||
"task_id": authorization.TaskID,
|
||||
"execution_id": authorization.ExecutionID,
|
||||
"authorization_version": authorization.AuthorizationVersion,
|
||||
"candidate_key": authorization.CandidateKey,
|
||||
"task_content_sha256": authorization.TaskContentSHA256,
|
||||
"task_version": authorization.TaskVersion,
|
||||
"review_id": authorization.ReviewID,
|
||||
"review_version": authorization.ReviewVersion,
|
||||
"user_id": authorization.UserID,
|
||||
"device_id": authorization.DeviceID,
|
||||
"claim_generation": authorization.ClaimGeneration,
|
||||
"original_sku": authorization.OriginalSKU,
|
||||
"quantity": authorization.Quantity,
|
||||
"candidate_sku_text": authorization.CandidateSKUText,
|
||||
"candidate_price_text": authorization.CandidatePriceText,
|
||||
"card_signature": authorization.CardSignature,
|
||||
"detail_signature": authorization.DetailSignature,
|
||||
"detail_evidence_sha256": authorization.DetailEvidenceSHA256,
|
||||
"specification_evidence_sha256": authorization.SpecificationEvidenceSHA256,
|
||||
"status": authorization.Status,
|
||||
"supersedes_authorization_id": authorization.SupersedesAuthorizationID,
|
||||
"created_by_user_id": authorization.CreatedByUserID,
|
||||
"created_at": formatTime(authorization.CreatedAt),
|
||||
"delivered_at": formatOptionalTime(authorization.DeliveredAt),
|
||||
"acknowledged_at": formatOptionalTime(authorization.AcknowledgedAt),
|
||||
"execution_started_at": formatOptionalTime(authorization.ExecutionStartedAt),
|
||||
"consumed_at": formatOptionalTime(authorization.ConsumedAt),
|
||||
"failed_at": formatOptionalTime(authorization.FailedAt),
|
||||
"revoked_at": formatOptionalTime(authorization.RevokedAt),
|
||||
"failure_code": authorization.FailureCode,
|
||||
"failure_message": authorization.FailureMessage,
|
||||
}
|
||||
}
|
||||
|
||||
func executionReportResponse(report *domain.ExecutionReport) gin.H {
|
||||
events := make([]gin.H, 0, len(report.Events))
|
||||
for _, event := range report.Events {
|
||||
|
||||
Reference in New Issue
Block a user