mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-12 14:10:19 +08:00
Merge remote-tracking branch 'zhefox/main' into zhefox-main
# Conflicts: # crates/aether-admin/src/provider/quota.rs # crates/aether-ai/formats/src/formats/openai/chat/stream.rs # crates/aether-ai/formats/src/formats/openai/responses/mod.rs # crates/aether-provider/pool/src/provider.rs # crates/aether-provider/pool/src/quota.rs
This commit is contained in:
+59
@@ -0,0 +1,59 @@
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'providers'
|
||||
AND column_name = 'enabled'
|
||||
) AND EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'providers'
|
||||
AND column_name = 'is_active'
|
||||
) THEN
|
||||
UPDATE public.providers
|
||||
SET enabled = is_active
|
||||
WHERE is_active IS NOT NULL
|
||||
AND enabled IS DISTINCT FROM is_active;
|
||||
END IF;
|
||||
|
||||
IF EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'provider_endpoints'
|
||||
AND column_name = 'enabled'
|
||||
) AND EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'provider_endpoints'
|
||||
AND column_name = 'is_active'
|
||||
) THEN
|
||||
UPDATE public.provider_endpoints
|
||||
SET enabled = is_active
|
||||
WHERE is_active IS NOT NULL
|
||||
AND enabled IS DISTINCT FROM is_active;
|
||||
END IF;
|
||||
|
||||
IF EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'models'
|
||||
AND column_name = 'enabled'
|
||||
) AND EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'models'
|
||||
AND column_name = 'is_active'
|
||||
) THEN
|
||||
UPDATE public.models
|
||||
SET enabled = is_active
|
||||
WHERE is_active IS NOT NULL
|
||||
AND enabled IS DISTINCT FROM is_active;
|
||||
END IF;
|
||||
END $$;
|
||||
@@ -47,7 +47,8 @@ fn pending_backfills_from_applied_returns_all_versions_when_none_applied() {
|
||||
20260504120000,
|
||||
20260505120000,
|
||||
20260517012000,
|
||||
20260716010000
|
||||
20260716010000,
|
||||
20260722140744
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -68,7 +69,8 @@ fn pending_backfills_from_applied_skips_versions_already_applied() {
|
||||
20260504120000,
|
||||
20260505120000,
|
||||
20260517012000,
|
||||
20260716010000
|
||||
20260716010000,
|
||||
20260722140744
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -965,13 +967,14 @@ async fn run_backfills_rebuilds_stats_and_records_execution() {
|
||||
let pending_before = pending_backfills(&pool)
|
||||
.await
|
||||
.expect("pending backfills should load");
|
||||
assert_eq!(pending_before.len(), 6);
|
||||
assert_eq!(pending_before.len(), 7);
|
||||
assert_eq!(pending_before[0].version, 20260422110000);
|
||||
assert_eq!(pending_before[1].version, 20260422120000);
|
||||
assert_eq!(pending_before[2].version, 20260504120000);
|
||||
assert_eq!(pending_before[3].version, 20260505120000);
|
||||
assert_eq!(pending_before[4].version, 20260517012000);
|
||||
assert_eq!(pending_before[5].version, 20260716010000);
|
||||
assert_eq!(pending_before[6].version, 20260722140744);
|
||||
|
||||
run_backfills(&pool)
|
||||
.await
|
||||
@@ -995,7 +998,8 @@ async fn run_backfills_rebuilds_stats_and_records_execution() {
|
||||
20260504120000,
|
||||
20260505120000,
|
||||
20260517012000,
|
||||
20260716010000
|
||||
20260716010000,
|
||||
20260722140744
|
||||
]
|
||||
);
|
||||
|
||||
@@ -1669,5 +1673,5 @@ ORDER BY total_tokens
|
||||
.fetch_one(&pool)
|
||||
.await
|
||||
.expect("backfill count should load");
|
||||
assert_eq!(applied_count, 6);
|
||||
assert_eq!(applied_count, 7);
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ fn billing_plan_from_input(
|
||||
|
||||
fn daily_quota_availability_from_entitlements(
|
||||
entitlements: impl IntoIterator<Item = UserPlanEntitlementRecord>,
|
||||
billing_plans: &BTreeMap<String, BillingPlanRecord>,
|
||||
now: u64,
|
||||
) -> UserDailyQuotaAvailabilityRecord {
|
||||
let mut has_active_daily_quota = false;
|
||||
@@ -92,6 +93,9 @@ fn daily_quota_availability_from_entitlements(
|
||||
let Some(items) = entitlement.entitlements_snapshot.as_array() else {
|
||||
continue;
|
||||
};
|
||||
let current_allow_wallet_overage = billing_plans
|
||||
.get(&entitlement.plan_id)
|
||||
.and_then(|plan| daily_quota_wallet_overage_policy(&plan.entitlements_json));
|
||||
for item in items {
|
||||
if item.get("type").and_then(serde_json::Value::as_str) != Some("daily_quota") {
|
||||
continue;
|
||||
@@ -106,10 +110,11 @@ fn daily_quota_availability_from_entitlements(
|
||||
has_active_daily_quota = true;
|
||||
total_quota_usd += daily_quota_usd;
|
||||
remaining_usd += daily_quota_usd;
|
||||
allow_wallet_overage &= item
|
||||
.get("allow_wallet_overage")
|
||||
.and_then(serde_json::Value::as_bool)
|
||||
.unwrap_or(false);
|
||||
allow_wallet_overage &= current_allow_wallet_overage.unwrap_or_else(|| {
|
||||
item.get("allow_wallet_overage")
|
||||
.and_then(serde_json::Value::as_bool)
|
||||
.unwrap_or(false)
|
||||
});
|
||||
}
|
||||
}
|
||||
UserDailyQuotaAvailabilityRecord {
|
||||
@@ -121,6 +126,17 @@ fn daily_quota_availability_from_entitlements(
|
||||
}
|
||||
}
|
||||
|
||||
fn daily_quota_wallet_overage_policy(entitlements: &serde_json::Value) -> Option<bool> {
|
||||
entitlements.as_array()?.iter().find_map(|item| {
|
||||
(item.get("type").and_then(serde_json::Value::as_str) == Some("daily_quota"))
|
||||
.then(|| {
|
||||
item.get("allow_wallet_overage")
|
||||
.and_then(serde_json::Value::as_bool)
|
||||
})
|
||||
.flatten()
|
||||
})
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl BillingReadRepository for InMemoryBillingReadRepository {
|
||||
async fn find_model_context(
|
||||
@@ -366,6 +382,31 @@ impl BillingReadRepository for InMemoryBillingReadRepository {
|
||||
Ok(Some(items))
|
||||
}
|
||||
|
||||
async fn revoke_user_plan_entitlement(
|
||||
&self,
|
||||
user_id: &str,
|
||||
entitlement_id: &str,
|
||||
) -> Result<AdminBillingMutationOutcome<()>, DataLayerError> {
|
||||
let now = current_unix_secs();
|
||||
let mut entitlements = self
|
||||
.entitlements_by_id
|
||||
.write()
|
||||
.expect("billing repository lock");
|
||||
let Some(entitlement) = entitlements.get_mut(entitlement_id) else {
|
||||
return Ok(AdminBillingMutationOutcome::NotFound);
|
||||
};
|
||||
if entitlement.user_id != user_id
|
||||
|| entitlement.status != "active"
|
||||
|| entitlement.expires_at_unix_secs <= now
|
||||
{
|
||||
return Ok(AdminBillingMutationOutcome::NotFound);
|
||||
}
|
||||
entitlement.status = "revoked".to_string();
|
||||
entitlement.expires_at_unix_secs = entitlement.expires_at_unix_secs.min(now);
|
||||
entitlement.updated_at_unix_secs = now;
|
||||
Ok(AdminBillingMutationOutcome::Applied(()))
|
||||
}
|
||||
|
||||
async fn find_user_daily_quota_availability(
|
||||
&self,
|
||||
user_id: &str,
|
||||
@@ -379,8 +420,13 @@ impl BillingReadRepository for InMemoryBillingReadRepository {
|
||||
.filter(|item| item.user_id == user_id)
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
let billing_plans = self
|
||||
.billing_plans_by_id
|
||||
.read()
|
||||
.expect("billing repository lock");
|
||||
Ok(Some(daily_quota_availability_from_entitlements(
|
||||
entitlements,
|
||||
&billing_plans,
|
||||
now,
|
||||
)))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user