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::DelegatedTokenIssuer => RoleCapability::DelegatedTokenIssuer,
52 RoleCapabilityKey::DelegatedTokenVerifier => RoleCapability::DelegatedTokenVerifier,
53 RoleCapabilityKey::FleetAdmissionProjection => RoleCapability::FleetAdmissionProjection,
54 RoleCapabilityKey::FleetCoordinator => RoleCapability::FleetCoordinator,
55 RoleCapabilityKey::Index => RoleCapability::Index,
56 RoleCapabilityKey::Icrc21 => RoleCapability::Icrc21,
57 RoleCapabilityKey::LocalApplicationAuthorization => return None,
58 RoleCapabilityKey::RoleAttestationSigner => RoleCapability::RoleAttestationSigner,
59 RoleCapabilityKey::RoleAttestationVerifier => RoleCapability::RoleAttestationVerifier,
60 RoleCapabilityKey::Root => RoleCapability::Root,
61 RoleCapabilityKey::RootControlPlane => RoleCapability::RootControlPlane,
62 RoleCapabilityKey::Runtime => RoleCapability::Runtime,
63 RoleCapabilityKey::Scaling => RoleCapability::Scaling,
64 RoleCapabilityKey::Sharding => RoleCapability::Sharding,
65 RoleCapabilityKey::WasmStore => RoleCapability::WasmStore,
66 })
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn overview_projects_public_capabilities_in_lexical_order() {
75 let capabilities = BTreeSet::from([
76 RoleCapabilityKey::AutomaticTopup,
77 RoleCapabilityKey::DelegatedTokenIssuer,
78 RoleCapabilityKey::DelegatedTokenVerifier,
79 RoleCapabilityKey::FleetAdmissionProjection,
80 RoleCapabilityKey::FleetCoordinator,
81 RoleCapabilityKey::Index,
82 RoleCapabilityKey::Icrc21,
83 RoleCapabilityKey::LocalApplicationAuthorization,
84 RoleCapabilityKey::RoleAttestationSigner,
85 RoleCapabilityKey::RoleAttestationVerifier,
86 RoleCapabilityKey::Root,
87 RoleCapabilityKey::RootControlPlane,
88 RoleCapabilityKey::Runtime,
89 RoleCapabilityKey::Scaling,
90 RoleCapabilityKey::Sharding,
91 RoleCapabilityKey::WasmStore,
92 ]);
93 let overview = RoleOverviewApi::overview(
94 CanisterRole::new("app"),
95 &capabilities,
96 [9; 32],
97 CanicMetadataResponse {
98 package_name: "app".to_string(),
99 package_version: "0.1.0".to_string(),
100 package_description: "test".to_string(),
101 canic_version: "0.103.0".to_string(),
102 canister_version: 4,
103 },
104 BootstrapStatusResponse {
105 ready: true,
106 phase: "ready".to_string(),
107 last_error: None,
108 },
109 );
110
111 assert_eq!(
112 overview.capabilities,
113 vec![
114 RoleCapability::AutomaticTopup,
115 RoleCapability::DelegatedTokenIssuer,
116 RoleCapability::DelegatedTokenVerifier,
117 RoleCapability::FleetAdmissionProjection,
118 RoleCapability::FleetCoordinator,
119 RoleCapability::Icrc21,
120 RoleCapability::Index,
121 RoleCapability::RoleAttestationSigner,
122 RoleCapability::RoleAttestationVerifier,
123 RoleCapability::Root,
124 RoleCapability::RootControlPlane,
125 RoleCapability::Runtime,
126 RoleCapability::Scaling,
127 RoleCapability::Sharding,
128 RoleCapability::WasmStore,
129 ]
130 );
131 assert_eq!(overview.protocol_profile_digest, [9; 32]);
132 }
133}