chore: checkpoint 第一版
ci / verify (push) Canceled after 0s

This commit is contained in:
Codex Local
2026-09-06 17:04:11 +08:00
parent a8cdec98d1
commit 0c2151ace9
659 changed files with 185855 additions and 554 deletions
+28 -3
View File
@@ -10,6 +10,7 @@ import (
"data-terminal-cloud/internal/audit"
"data-terminal-cloud/internal/database"
"data-terminal-cloud/internal/deviceactivation"
"data-terminal-cloud/internal/identity"
"github.com/jackc/pgx/v5"
@@ -43,15 +44,15 @@ func (s *Service) ClaimDevice(ctx context.Context, principal identity.Principal,
return fmt.Errorf("resolve claim subject: %w", err)
}
var claimID, deviceID, devicePublicID string
var claimID, deviceID, devicePublicID, activationState string
var expiresAt time.Time
var revokedAt, usedAt *time.Time
var usedBindingID *string
if err := tx.QueryRow(ctx, `
SELECT dc.id::text,dc.device_id::text,d.public_id::text,dc.expires_at,dc.revoked_at,dc.used_at,dc.used_binding_id::text
SELECT dc.id::text,dc.device_id::text,d.public_id::text,d.activation_state,dc.expires_at,dc.revoked_at,dc.used_at,dc.used_binding_id::text
FROM device_claim dc JOIN device d ON d.id=dc.device_id AND d.tenant_id=dc.tenant_id
WHERE dc.token_digest=$1 AND dc.tenant_id=$2::uuid AND d.status='registered'
FOR UPDATE OF dc`, digest, access.tenantID).Scan(&claimID, &deviceID, &devicePublicID, &expiresAt, &revokedAt, &usedAt, &usedBindingID); errors.Is(err, pgx.ErrNoRows) {
FOR UPDATE OF d,dc`, digest, access.tenantID).Scan(&claimID, &deviceID, &devicePublicID, &activationState, &expiresAt, &revokedAt, &usedAt, &usedBindingID); errors.Is(err, pgx.ErrNoRows) {
return ErrDeviceClaimInvalid
} else if err != nil {
return fmt.Errorf("resolve device claim: %w", err)
@@ -78,6 +79,9 @@ func (s *Service) ClaimDevice(ctx context.Context, principal identity.Principal,
replayed = true
return nil
}
if activationState != string(deviceactivation.Claimable) {
return ErrDeviceClaimInvalid
}
var activeBinding bool
if err := tx.QueryRow(ctx, `SELECT EXISTS(SELECT 1 FROM device_binding WHERE device_id=$1::uuid AND unbound_at IS NULL)`, deviceID).Scan(&activeBinding); err != nil {
return fmt.Errorf("check active device binding: %w", err)
@@ -97,6 +101,27 @@ func (s *Service) ClaimDevice(ctx context.Context, principal identity.Principal,
if _, err := tx.Exec(ctx, `UPDATE device_claim SET used_at=now(),used_binding_id=$1::uuid WHERE id=$2::uuid`, bindingInternalID, claimID); err != nil {
return fmt.Errorf("mark device claim used: %w", err)
}
if _, err := deviceactivation.Apply(ctx, tx, deviceactivation.Input{DeviceID: deviceID, TenantID: access.tenantID,
Target: deviceactivation.Bound, Reason: "用户通过一次性绑定码认领设备", Source: "device-claim", ActorType: "user",
ActorPublicID: strPtr(access.userPublicID), RequestID: requestID}); err != nil {
return fmt.Errorf("activate claimed device binding: %w", err)
}
var runtime string
if err := tx.QueryRow(ctx, `SELECT COALESCE(desired_config->>'voice_runtime','legacy_voicechat') FROM device_twin WHERE device_id=$1::uuid`, deviceID).Scan(&runtime); err != nil {
return fmt.Errorf("read claimed device runtime: %w", err)
}
if runtime == "legacy_voicechat" {
if _, err := deviceactivation.Apply(ctx, tx, deviceactivation.Input{DeviceID: deviceID, TenantID: access.tenantID,
Target: deviceactivation.Provisioning, Reason: "旧版语音运行时平台凭据预配", Source: "platform-provisioning", ActorType: "user",
ActorPublicID: strPtr(access.userPublicID), RequestID: requestID}); err != nil {
return fmt.Errorf("provision claimed legacy device: %w", err)
}
if _, err := deviceactivation.Apply(ctx, tx, deviceactivation.Input{DeviceID: deviceID, TenantID: access.tenantID,
Target: deviceactivation.Active, Reason: "旧版语音运行时已具备绑定与平台凭据", Source: "platform-provisioning", ActorType: "user",
ActorPublicID: strPtr(access.userPublicID), RequestID: requestID}); err != nil {
return fmt.Errorf("activate claimed legacy device: %w", err)
}
}
return s.audit.Record(ctx, tx, audit.Event{
TenantID: strPtr(access.tenantID), ActorType: "user", ActorPublicID: strPtr(access.userPublicID),
Action: "device.claim", ResourceType: "device_binding", ResourceID: strPtr(result.BindingID),