mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 17:30:23 +08:00
Merge branch 'pr-478'
# Conflicts: # apps/aether-gateway/src/data/state/mod.rs # apps/aether-gateway/src/handlers/admin/mod.rs # apps/aether-gateway/src/handlers/admin/routes.rs # crates/aether-data/src/lifecycle/bootstrap/postgres.rs # crates/aether-data/src/lifecycle/migrate/tests.rs # crates/aether-data/src/repository/announcements/postgres.rs # frontend/src/features/auth/components/RegisterDialog.vue
This commit is contained in:
@@ -1954,14 +1954,38 @@ fn resolve_effective_list_policy(
|
||||
&aether_data::repository::users::StoredUserGroup,
|
||||
) -> (&str, Option<Vec<String>>),
|
||||
) -> Option<Vec<String>> {
|
||||
let group_policy = groups.iter().fold(None, |effective, group| {
|
||||
let (mode, values) = group_field(group);
|
||||
intersect_list_policies(effective, list_restriction_from_mode(mode, values))
|
||||
});
|
||||
let group_policy = union_group_list_policies(groups, group_field);
|
||||
let user_policy = list_restriction_from_mode(user_mode, user_values);
|
||||
intersect_list_policies(group_policy, user_policy)
|
||||
}
|
||||
|
||||
fn union_group_list_policies(
|
||||
groups: &[aether_data::repository::users::StoredUserGroup],
|
||||
group_field: impl Fn(
|
||||
&aether_data::repository::users::StoredUserGroup,
|
||||
) -> (&str, Option<Vec<String>>),
|
||||
) -> Option<Vec<String>> {
|
||||
let mut saw_restrictive_group = false;
|
||||
let mut values = std::collections::BTreeSet::new();
|
||||
|
||||
for group in groups {
|
||||
let (mode, group_values) = group_field(group);
|
||||
match mode {
|
||||
"unrestricted" => return None,
|
||||
"specific" => {
|
||||
saw_restrictive_group = true;
|
||||
values.extend(group_values.unwrap_or_default());
|
||||
}
|
||||
"deny_all" => {
|
||||
saw_restrictive_group = true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
saw_restrictive_group.then(|| values.into_iter().collect())
|
||||
}
|
||||
|
||||
fn list_restriction_from_mode(mode: &str, values: Option<Vec<String>>) -> Option<Vec<String>> {
|
||||
match mode {
|
||||
"specific" => Some(values.unwrap_or_default()),
|
||||
@@ -2177,7 +2201,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn list_policy_intersects_group_and_user_restrictions() {
|
||||
fn list_policy_intersects_unrestricted_group_union_with_user_restriction() {
|
||||
let groups = vec![
|
||||
sample_group("default", 0, None, "unrestricted", None, "system"),
|
||||
sample_group(
|
||||
@@ -2197,11 +2221,14 @@ mod tests {
|
||||
|group| (&group.allowed_models_mode, group.allowed_models.clone()),
|
||||
);
|
||||
|
||||
assert_eq!(policy, Some(vec!["gpt-4.1".to_string()]));
|
||||
assert_eq!(
|
||||
policy,
|
||||
Some(vec!["gpt-4.1".to_string(), "gemini-2.5-pro".to_string()])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn list_policy_intersects_multiple_group_restrictions() {
|
||||
fn list_policy_unions_multiple_group_restrictions_legacy_case() {
|
||||
let groups = vec![
|
||||
sample_group(
|
||||
"team-a",
|
||||
@@ -2225,7 +2252,91 @@ mod tests {
|
||||
(&group.allowed_models_mode, group.allowed_models.clone())
|
||||
});
|
||||
|
||||
assert_eq!(policy, Some(vec!["gpt-4.1".to_string()]));
|
||||
assert_eq!(
|
||||
policy,
|
||||
Some(vec![
|
||||
"gemini-2.5-pro".to_string(),
|
||||
"gpt-4.1".to_string(),
|
||||
"gpt-5".to_string()
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn list_policy_unions_multiple_group_restrictions() {
|
||||
let groups = vec![
|
||||
sample_group(
|
||||
"team-a",
|
||||
10,
|
||||
Some(vec!["gpt-5", "gpt-4.1"]),
|
||||
"specific",
|
||||
None,
|
||||
"system",
|
||||
),
|
||||
sample_group(
|
||||
"team-b",
|
||||
20,
|
||||
Some(vec!["gpt-4.1", "gemini-2.5-pro"]),
|
||||
"specific",
|
||||
None,
|
||||
"system",
|
||||
),
|
||||
];
|
||||
|
||||
let policy = resolve_effective_list_policy(None, "unrestricted", &groups, |group| {
|
||||
(&group.allowed_models_mode, group.allowed_models.clone())
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
policy,
|
||||
Some(vec![
|
||||
"gemini-2.5-pro".to_string(),
|
||||
"gpt-4.1".to_string(),
|
||||
"gpt-5".to_string()
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unrestricted_group_makes_group_policy_unrestricted() {
|
||||
let groups = vec![
|
||||
sample_group(
|
||||
"restricted",
|
||||
10,
|
||||
Some(vec!["gpt-5"]),
|
||||
"specific",
|
||||
None,
|
||||
"system",
|
||||
),
|
||||
sample_group("unrestricted", 20, None, "unrestricted", None, "system"),
|
||||
];
|
||||
|
||||
let policy = resolve_effective_list_policy(None, "unrestricted", &groups, |group| {
|
||||
(&group.allowed_models_mode, group.allowed_models.clone())
|
||||
});
|
||||
|
||||
assert_eq!(policy, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deny_all_group_does_not_remove_other_group_grants() {
|
||||
let groups = vec![
|
||||
sample_group("deny", 10, None, "deny_all", None, "system"),
|
||||
sample_group(
|
||||
"restricted",
|
||||
20,
|
||||
Some(vec!["gpt-5"]),
|
||||
"specific",
|
||||
None,
|
||||
"system",
|
||||
),
|
||||
];
|
||||
|
||||
let policy = resolve_effective_list_policy(None, "unrestricted", &groups, |group| {
|
||||
(&group.allowed_models_mode, group.allowed_models.clone())
|
||||
});
|
||||
|
||||
assert_eq!(policy, Some(vec!["gpt-5".to_string()]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -142,6 +142,12 @@ use aether_data_contracts::repository::video_tasks::{
|
||||
};
|
||||
use aether_runtime_state::RuntimeQueueStore;
|
||||
|
||||
pub(crate) use self::referrals::{
|
||||
ReferralAdminStats, ReferralMutationStatus, ReferralRelationshipListQuery,
|
||||
ReferralRelationshipRecord, ReferralRewardConfig, ReferralRewardListQuery,
|
||||
ReferralRewardRecord, ReferralUserDashboard,
|
||||
};
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub(crate) struct GatewayDataState {
|
||||
config: GatewayDataConfig,
|
||||
@@ -317,6 +323,7 @@ mod core;
|
||||
mod integrations;
|
||||
mod models;
|
||||
mod pool_scores;
|
||||
mod referrals;
|
||||
mod routing_profiles;
|
||||
mod runtime;
|
||||
#[cfg(test)]
|
||||
|
||||
2652
apps/aether-gateway/src/data/state/referrals.rs
Normal file
2652
apps/aether-gateway/src/data/state/referrals.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -262,6 +262,22 @@ impl GatewayDataState {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn list_required_unread_active_announcements(
|
||||
&self,
|
||||
user_id: &str,
|
||||
now_unix_secs: u64,
|
||||
limit: usize,
|
||||
) -> Result<Vec<StoredAnnouncement>, DataLayerError> {
|
||||
match &self.announcement_reader {
|
||||
Some(repository) => {
|
||||
repository
|
||||
.list_required_unread_active_announcements(user_id, now_unix_secs, limit)
|
||||
.await
|
||||
}
|
||||
None => Ok(Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn create_announcement(
|
||||
&self,
|
||||
record: CreateAnnouncementRecord,
|
||||
|
||||
Reference in New Issue
Block a user