1use crate::{
8 dto::{
9 metadata::CanicMetadataResponse,
10 role::{RoleCapability, RoleOverviewResponse},
11 state::BootstrapStatusResponse,
12 },
13 ids::CanisterRole,
14 role_contract::RoleCapabilityKey,
15};
16use std::collections::BTreeSet;
17
18pub struct RoleOverviewApi;
20
21impl RoleOverviewApi {
22 #[must_use]
24 pub fn overview(
25 role: CanisterRole,
26 capabilities: &BTreeSet<RoleCapabilityKey>,
27 protocol_profile_digest: [u8; 32],
28 metadata: CanicMetadataResponse,
29 bootstrap: BootstrapStatusResponse,
30 ) -> RoleOverviewResponse {
31 let mut capabilities = capabilities
32 .iter()
33 .copied()
34 .filter_map(capability_view)
35 .collect::<Vec<_>>();
36 capabilities.sort_unstable();
37
38 RoleOverviewResponse {
39 role,
40 capabilities,
41 protocol_profile_digest,
42 metadata,
43 bootstrap,
44 }
45 }
46}
47
48const fn capability_view(capability: RoleCapabilityKey) -> Option<RoleCapability> {
49 Some(match capability {
50 RoleCapabilityKey::AutomaticTopup => RoleCapability::AutomaticTopup,
51 RoleCapabilityKey::ChildProvisioning => RoleCapability::ChildProvisioning,
52 RoleCapabilityKey::DelegatedTokenIssuer => RoleCapability::DelegatedTokenIssuer,
53 RoleCapabilityKey::DelegatedTokenVerifier => RoleCapability::DelegatedTokenVerifier,
54 RoleCapabilityKey::FleetAdmissionProjection => RoleCapability::FleetAdmissionProjection,
55 RoleCapabilityKey::FleetCoordinator => RoleCapability::FleetCoordinator,
56 RoleCapabilityKey::Index => RoleCapability::Index,
57 RoleCapabilityKey::Icrc21 => RoleCapability::Icrc21,
58 RoleCapabilityKey::LocalApplicationAuthorization => return None,
59 RoleCapabilityKey::RoleAttestationSigner => RoleCapability::RoleAttestationSigner,
60 RoleCapabilityKey::RoleAttestationVerifier => RoleCapability::RoleAttestationVerifier,
61 RoleCapabilityKey::Root => RoleCapability::Root,
62 RoleCapabilityKey::RootControlPlane => RoleCapability::RootControlPlane,
63 RoleCapabilityKey::Runtime => RoleCapability::Runtime,
64 RoleCapabilityKey::Scaling => RoleCapability::Scaling,
65 RoleCapabilityKey::Sharding => RoleCapability::Sharding,
66 RoleCapabilityKey::WasmStore => RoleCapability::WasmStore,
67 })
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn overview_projects_public_capabilities_in_lexical_order() {
76 let capabilities = BTreeSet::from([
77 RoleCapabilityKey::AutomaticTopup,
78 RoleCapabilityKey::ChildProvisioning,
79 RoleCapabilityKey::DelegatedTokenIssuer,
80 RoleCapabilityKey::DelegatedTokenVerifier,
81 RoleCapabilityKey::FleetAdmissionProjection,
82 RoleCapabilityKey::FleetCoordinator,
83 RoleCapabilityKey::Index,
84 RoleCapabilityKey::Icrc21,
85 RoleCapabilityKey::LocalApplicationAuthorization,
86 RoleCapabilityKey::RoleAttestationSigner,
87 RoleCapabilityKey::RoleAttestationVerifier,
88 RoleCapabilityKey::Root,
89 RoleCapabilityKey::RootControlPlane,
90 RoleCapabilityKey::Runtime,
91 RoleCapabilityKey::Scaling,
92 RoleCapabilityKey::Sharding,
93 RoleCapabilityKey::WasmStore,
94 ]);
95 let overview = RoleOverviewApi::overview(
96 CanisterRole::new("app"),
97 &capabilities,
98 [9; 32],
99 CanicMetadataResponse {
100 package_name: "app".to_string(),
101 package_version: "0.1.0".to_string(),
102 package_description: "test".to_string(),
103 canic_version: "0.103.0".to_string(),
104 canister_version: 4,
105 },
106 BootstrapStatusResponse {
107 ready: true,
108 phase: "ready".to_string(),
109 last_error: None,
110 },
111 );
112
113 assert_eq!(
114 overview.capabilities,
115 vec![
116 RoleCapability::AutomaticTopup,
117 RoleCapability::ChildProvisioning,
118 RoleCapability::DelegatedTokenIssuer,
119 RoleCapability::DelegatedTokenVerifier,
120 RoleCapability::FleetAdmissionProjection,
121 RoleCapability::FleetCoordinator,
122 RoleCapability::Icrc21,
123 RoleCapability::Index,
124 RoleCapability::RoleAttestationSigner,
125 RoleCapability::RoleAttestationVerifier,
126 RoleCapability::Root,
127 RoleCapability::RootControlPlane,
128 RoleCapability::Runtime,
129 RoleCapability::Scaling,
130 RoleCapability::Sharding,
131 RoleCapability::WasmStore,
132 ]
133 );
134 assert_eq!(overview.protocol_profile_digest, [9; 32]);
135 }
136}