use scim_server::{
RequestContext, ResourceProvider, providers::StandardResourceProvider,
resource_handlers::create_group_resource_handler, schema::SchemaRegistry,
scim_server::ScimServer, storage::InMemoryStorage,
};
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("🚀 SCIM Server Group Example");
println!("=============================\n");
let storage = InMemoryStorage::new();
let provider = StandardResourceProvider::new(storage);
let mut server = ScimServer::new(provider)?;
let registry = SchemaRegistry::new()?;
let group_schema = registry.get_group_schema().clone();
let group_handler = create_group_resource_handler(group_schema);
server.register_resource_type(
"Group",
group_handler,
vec![
scim_server::multi_tenant::ScimOperation::Create,
scim_server::multi_tenant::ScimOperation::Read,
scim_server::multi_tenant::ScimOperation::Update,
scim_server::multi_tenant::ScimOperation::Delete,
scim_server::multi_tenant::ScimOperation::List,
scim_server::multi_tenant::ScimOperation::Search,
],
)?;
println!("✅ Group resource type registered successfully");
let context = RequestContext::new("group-example".to_string());
println!("\n📝 Creating Groups...");
let engineering_group = json!({
"displayName": "Engineering Team",
"members": [
{
"value": "user-alice",
"$ref": "https://example.com/v2/Users/user-alice",
"type": "User"
},
{
"value": "user-bob",
"$ref": "https://example.com/v2/Users/user-bob",
"type": "User"
}
]
});
let created_engineering = server
.create_resource("Group", engineering_group, &context)
.await?;
println!(
"✅ Created Engineering Team: {}",
created_engineering.get_id().unwrap_or("unknown")
);
let marketing_group = json!({
"displayName": "Marketing Team",
"members": [
{
"value": "user-charlie",
"$ref": "https://example.com/v2/Users/user-charlie",
"type": "User"
}
]
});
let created_marketing = server
.create_resource("Group", marketing_group, &context)
.await?;
println!(
"✅ Created Marketing Team: {}",
created_marketing.get_id().unwrap_or("unknown")
);
println!("\n🔍 Retrieving Groups...");
let engineering_id = created_engineering.get_id().unwrap();
let retrieved_group = server
.get_resource("Group", &engineering_id, &context)
.await?;
if let Some(group) = retrieved_group {
let display_name = group
.get_attribute("displayName")
.and_then(|v| v.as_str())
.unwrap_or("Unknown");
let member_count = group
.get_attribute("members")
.and_then(|v| v.as_array())
.map(|arr| arr.len())
.unwrap_or(0);
println!(
"✅ Retrieved group: {} with {} members",
display_name, member_count
);
}
println!("\n📋 Listing all Groups...");
let all_groups = server.list_resources("Group", &context).await?;
println!("✅ Found {} groups:", all_groups.len());
for group in &all_groups {
let display_name = group
.get_attribute("displayName")
.and_then(|v| v.as_str())
.unwrap_or("Unknown");
let id = group.get_id().unwrap_or("unknown");
println!(" 📁 {}: {}", display_name, id);
}
println!("\n👥 Updating Group membership...");
let engineering_id = created_engineering.get_id().unwrap();
let updated_engineering_data = json!({
"id": engineering_id,
"displayName": "Engineering Team (Updated)",
"members": [
{
"value": "user-alice",
"$ref": "https://example.com/v2/Users/user-alice",
"type": "User"
},
{
"value": "user-bob",
"$ref": "https://example.com/v2/Users/user-bob",
"type": "User"
},
{
"value": "user-david",
"$ref": "https://example.com/v2/Users/user-david",
"type": "User"
}
]
});
let updated_group = server
.update_resource("Group", &engineering_id, updated_engineering_data, &context)
.await?;
let updated_display_name = updated_group
.get_attribute("displayName")
.and_then(|v| v.as_str())
.unwrap_or("Unknown");
let updated_member_count = updated_group
.get_attribute("members")
.and_then(|v| v.as_array())
.map(|arr| arr.len())
.unwrap_or(0);
println!(
"✅ Updated group: {} now has {} members",
updated_display_name, updated_member_count
);
println!("\n👤 Group members details...");
if let Some(members) = updated_group
.get_attribute("members")
.and_then(|v| v.as_array())
{
println!("📋 Members of {}:", updated_display_name);
for member in members {
if let Some(member_obj) = member.as_object() {
let user_id = member_obj
.get("value")
.and_then(|v| v.as_str())
.unwrap_or("unknown");
let user_type = member_obj
.get("type")
.and_then(|v| v.as_str())
.unwrap_or("unknown");
let user_ref = member_obj
.get("$ref")
.and_then(|v| v.as_str())
.unwrap_or("no reference");
println!(" 👤 {} ({}): {}", user_id, user_type, user_ref);
}
}
}
println!("\n🔍 Searching Groups by display name...");
let found_groups = server
.provider()
.find_resources_by_attribute("Group", "displayName", "Marketing Team", &context)
.await?;
if !found_groups.is_empty() {
let group = &found_groups[0];
let display_name = group
.get_attribute("displayName")
.and_then(|v| v.as_str())
.unwrap_or("Unknown");
let id = group.get_id().unwrap_or("unknown");
println!(
"✅ Found group by display name: {} (ID: {})",
display_name, id
);
} else {
println!("❌ Group not found by display name");
}
println!("\n🔍 Group schema validation...");
let invalid_group = json!({
"displayName": "", "members": "not-an-array" });
match server
.create_resource("Group", invalid_group, &context)
.await
{
Ok(_) => println!("⚠️ Validation should have failed"),
Err(e) => println!("✅ Validation correctly failed: {}", e),
}
println!("\n🔍 Testing resource existence...");
let marketing_id = created_marketing.get_id().unwrap();
let exists = server
.provider()
.resource_exists("Group", &marketing_id, &context)
.await?;
println!("✅ Marketing group exists: {}", exists);
println!("\n🗑️ Deleting Groups...");
server
.delete_resource("Group", &marketing_id, &context)
.await?;
println!("✅ Deleted Marketing Team");
let exists_after = server
.provider()
.resource_exists("Group", &marketing_id, &context)
.await?;
println!("✅ Marketing group exists after deletion: {}", exists_after);
let remaining_groups = server.list_resources("Group", &context).await?;
println!("📊 Groups remaining: {}", remaining_groups.len());
println!("\n📊 Provider Statistics...");
let stats = server.provider().get_stats().await;
println!("📈 Provider Statistics:");
println!(" • Total tenants: {}", stats.tenant_count);
println!(" • Total resources: {}", stats.total_resources);
println!(" • Resource types: {:?}", stats.resource_types);
println!(" • Resource type count: {}", stats.resource_type_count);
println!("\n✅ Group Example Complete!");
println!("🎉 Successfully demonstrated:");
println!(" • Group creation with StandardResourceProvider and InMemoryStorage");
println!(" • Group retrieval and listing");
println!(" • Group membership management");
println!(" • Group search and validation");
println!(" • Group deletion and resource existence checks");
println!(" • Provider statistics");
Ok(())
}