use super::roles::TeamRole;
use super::settings::{OrganizationSettings, TeamSettings};
use super::types::{Organization, Team, TeamMember};
use crate::storage::database::Database;
use crate::utils::error::gateway_error::{GatewayError, Result};
use chrono::Utc;
use std::collections::HashMap;
use std::sync::Arc;
use tracing::info;
use uuid::Uuid;
pub struct TeamOperations {
database: Arc<Database>,
}
impl TeamOperations {
pub fn new(database: Arc<Database>) -> Self {
Self { database }
}
pub async fn create_team(
&self,
team_name: String,
description: Option<String>,
organization_id: Option<String>,
creator_id: String,
) -> Result<Team> {
info!("Creating team: {}", team_name);
let team = Team {
team_id: Uuid::new_v4().to_string(),
team_name,
description,
organization_id,
members: vec![TeamMember {
user_id: creator_id,
role: TeamRole::Owner,
joined_at: Utc::now(),
is_active: true,
}],
permissions: vec![],
models: vec![],
max_budget: Some(1000.0), spend: 0.0,
budget_duration: Some("1m".to_string()),
budget_reset_at: Some(Utc::now() + chrono::Duration::days(30)),
metadata: HashMap::new(),
is_active: true,
created_at: Utc::now(),
settings: TeamSettings::default(),
};
self.database.create_team(&team).await?;
info!("Team created successfully: {}", team.team_id);
Ok(team)
}
pub async fn get_team(&self, team_id: &str) -> Result<Option<Team>> {
self.database.get_team(team_id).await
}
pub async fn add_user_to_team(
&self,
team_id: &str,
user_id: &str,
role: TeamRole,
) -> Result<()> {
info!(
"Adding user {} to team {} with role {:?}",
user_id, team_id, role
);
let mut team = self
.database
.get_team(team_id)
.await?
.ok_or_else(|| GatewayError::NotFound("Team not found".to_string()))?;
if team.members.iter().any(|m| m.user_id == user_id) {
return Err(GatewayError::Conflict(
"User is already a team member".to_string(),
));
}
team.members.push(TeamMember {
user_id: user_id.to_string(),
role,
joined_at: Utc::now(),
is_active: true,
});
self.database.update_team(&team).await?;
if let Some(mut user) = self.database.get_user(user_id).await? {
user.teams.push(team_id.to_string());
self.database.update_user(&user).await?;
}
Ok(())
}
pub async fn remove_user_from_team(&self, team_id: &str, user_id: &str) -> Result<()> {
info!("Removing user {} from team {}", user_id, team_id);
let mut team = self
.database
.get_team(team_id)
.await?
.ok_or_else(|| GatewayError::NotFound("Team not found".to_string()))?;
team.members.retain(|m| m.user_id != user_id);
self.database.update_team(&team).await?;
if let Some(mut user) = self.database.get_user(user_id).await? {
user.teams.retain(|t| t != team_id);
self.database.update_user(&user).await?;
}
Ok(())
}
pub async fn update_team_spend(&self, team_id: &str, cost: f64) -> Result<()> {
self.database.update_team_spend(team_id, cost).await
}
pub async fn list_teams(&self, offset: u32, limit: u32) -> Result<Vec<Team>> {
self.database.list_teams(offset, limit).await
}
pub async fn create_organization(
&self,
organization_name: String,
description: Option<String>,
creator_id: String,
) -> Result<Organization> {
info!("Creating organization: {}", organization_name);
let organization = Organization {
organization_id: Uuid::new_v4().to_string(),
organization_name,
description,
domain: None,
teams: vec![],
admins: vec![creator_id],
max_budget: Some(10000.0), spend: 0.0,
budget_duration: Some("1m".to_string()),
budget_reset_at: Some(Utc::now() + chrono::Duration::days(30)),
metadata: HashMap::new(),
is_active: true,
created_at: Utc::now(),
settings: OrganizationSettings::default(),
};
self.database.create_organization(&organization).await?;
info!(
"Organization created successfully: {}",
organization.organization_id
);
Ok(organization)
}
pub async fn get_organization(&self, organization_id: &str) -> Result<Option<Organization>> {
self.database.get_organization(organization_id).await
}
}