1#![allow(unused_variables)]
2
3use crate::{State, permissions::PermissionGroup};
7use indexmap::IndexMap;
8use serde::Serialize;
9use std::{ops::Deref, sync::Arc};
10use utoipa::ToSchema;
11use utoipa_axum::router::OpenApiRouter;
12
13pub mod background_tasks;
14pub mod commands;
15pub mod distr;
16pub mod email_templates;
17pub mod manager;
18pub mod settings;
19pub mod shutdown_handlers;
20
21pub struct ExtensionRouteBuilder {
22 state: State,
23 pub global: Option<Box<OpenApiRouter<State>>>,
24 pub api_admin: Option<Box<OpenApiRouter<State>>>,
25 pub api_auth: Option<Box<OpenApiRouter<State>>>,
26 pub api_client: Option<Box<OpenApiRouter<State>>>,
27 pub api_client_servers_server: Option<Box<OpenApiRouter<State>>>,
28 pub api_remote: Option<Box<OpenApiRouter<State>>>,
29 pub api_remote_servers_server: Option<Box<OpenApiRouter<State>>>,
30}
31
32impl ExtensionRouteBuilder {
33 pub fn new(state: State) -> Self {
34 Self {
35 state,
36 global: None,
37 api_admin: None,
38 api_auth: None,
39 api_client: None,
40 api_client_servers_server: None,
41 api_remote: None,
42 api_remote_servers_server: None,
43 }
44 }
45
46 pub fn add_global_router(
48 mut self,
49 router: impl FnOnce(OpenApiRouter<State>) -> OpenApiRouter<State>,
50 ) -> Self {
51 self.global = Some(Box::new(router(self.global.map_or_else(
52 || OpenApiRouter::new().with_state(self.state.clone()),
53 |b| *b,
54 ))));
55
56 self
57 }
58
59 pub fn add_admin_api_router(
62 mut self,
63 router: impl FnOnce(OpenApiRouter<State>) -> OpenApiRouter<State>,
64 ) -> Self {
65 self.api_admin = Some(Box::new(router(self.api_admin.map_or_else(
66 || OpenApiRouter::new().with_state(self.state.clone()),
67 |b| *b,
68 ))));
69
70 self
71 }
72
73 pub fn add_auth_api_router(
75 mut self,
76 router: impl FnOnce(OpenApiRouter<State>) -> OpenApiRouter<State>,
77 ) -> Self {
78 self.api_auth = Some(Box::new(router(self.api_auth.map_or_else(
79 || OpenApiRouter::new().with_state(self.state.clone()),
80 |b| *b,
81 ))));
82
83 self
84 }
85
86 pub fn add_client_api_router(
89 mut self,
90 router: impl FnOnce(OpenApiRouter<State>) -> OpenApiRouter<State>,
91 ) -> Self {
92 self.api_client = Some(Box::new(router(self.api_client.map_or_else(
93 || OpenApiRouter::new().with_state(self.state.clone()),
94 |b| *b,
95 ))));
96
97 self
98 }
99
100 pub fn add_client_server_api_router(
103 mut self,
104 router: impl FnOnce(OpenApiRouter<State>) -> OpenApiRouter<State>,
105 ) -> Self {
106 self.api_client_servers_server = Some(Box::new(router(
107 self.api_client_servers_server.map_or_else(
108 || OpenApiRouter::new().with_state(self.state.clone()),
109 |b| *b,
110 ),
111 )));
112
113 self
114 }
115
116 pub fn add_remote_api_router(
119 mut self,
120 router: impl FnOnce(OpenApiRouter<State>) -> OpenApiRouter<State>,
121 ) -> Self {
122 self.api_remote = Some(Box::new(router(self.api_remote.map_or_else(
123 || OpenApiRouter::new().with_state(self.state.clone()),
124 |b| *b,
125 ))));
126
127 self
128 }
129
130 pub fn add_remote_server_api_router(
133 mut self,
134 router: impl FnOnce(OpenApiRouter<State>) -> OpenApiRouter<State>,
135 ) -> Self {
136 self.api_remote_servers_server = Some(Box::new(router(
137 self.api_remote_servers_server.map_or_else(
138 || OpenApiRouter::new().with_state(self.state.clone()),
139 |b| *b,
140 ),
141 )));
142
143 self
144 }
145}
146
147type RawPermissionMap = IndexMap<&'static str, PermissionGroup>;
148pub struct ExtensionPermissionsBuilder {
149 pub user_permissions: RawPermissionMap,
150 pub admin_permissions: RawPermissionMap,
151 pub server_permissions: RawPermissionMap,
152}
153
154impl ExtensionPermissionsBuilder {
155 pub fn new(
156 user_permissions: RawPermissionMap,
157 admin_permissions: RawPermissionMap,
158 server_permissions: RawPermissionMap,
159 ) -> Self {
160 Self {
161 user_permissions,
162 admin_permissions,
163 server_permissions,
164 }
165 }
166
167 pub fn add_user_permission_group(
169 mut self,
170 group_name: &'static str,
171 group: PermissionGroup,
172 ) -> Self {
173 self.user_permissions.insert(group_name, group);
174
175 self
176 }
177
178 pub fn mutate_user_permission_group(
180 mut self,
181 group_name: &'static str,
182 mutation: impl FnOnce(&mut PermissionGroup),
183 ) -> Self {
184 if let Some(group) = self.user_permissions.get_mut(group_name) {
185 mutation(group);
186 }
187
188 self
189 }
190
191 pub fn add_admin_permission_group(
193 mut self,
194 group_name: &'static str,
195 group: PermissionGroup,
196 ) -> Self {
197 self.admin_permissions.insert(group_name, group);
198
199 self
200 }
201
202 pub fn mutate_admin_permission_group(
204 mut self,
205 group_name: &'static str,
206 mutation: impl FnOnce(&mut PermissionGroup),
207 ) -> Self {
208 if let Some(group) = self.admin_permissions.get_mut(group_name) {
209 mutation(group);
210 }
211
212 self
213 }
214
215 pub fn add_server_permission_group(
217 mut self,
218 group_name: &'static str,
219 group: PermissionGroup,
220 ) -> Self {
221 self.server_permissions.insert(group_name, group);
222
223 self
224 }
225
226 pub fn mutate_server_permission_group(
228 mut self,
229 group_name: &'static str,
230 mutation: impl FnOnce(&mut PermissionGroup),
231 ) -> Self {
232 if let Some(group) = self.server_permissions.get_mut(group_name) {
233 mutation(group);
234 }
235
236 self
237 }
238}
239
240pub struct ExtensionUpdateInfo {
241 pub version: semver::Version,
242 pub changes: Vec<compact_str::CompactString>,
243}
244
245pub type ExtensionCallValue = Box<dyn std::any::Any + Send + Sync>;
246
247#[async_trait::async_trait]
248pub trait Extension: Send + Sync {
249 async fn initialize(&mut self, state: State) {}
251
252 async fn initialize_cli(
254 &mut self,
255 env: Option<&Arc<crate::env::Env>>,
256 builder: commands::CliCommandGroupBuilder,
257 ) -> commands::CliCommandGroupBuilder {
258 builder
259 }
260
261 async fn initialize_router(
263 &mut self,
264 state: State,
265 builder: ExtensionRouteBuilder,
266 ) -> ExtensionRouteBuilder {
267 builder
268 }
269
270 async fn initialize_email_templates(
272 &mut self,
273 state: State,
274 builder: email_templates::ExtensionEmailTemplateBuilder,
275 ) -> email_templates::ExtensionEmailTemplateBuilder {
276 builder
277 }
278
279 async fn initialize_background_tasks(
281 &mut self,
282 state: State,
283 builder: background_tasks::BackgroundTaskBuilder,
284 ) -> background_tasks::BackgroundTaskBuilder {
285 builder
286 }
287
288 async fn initialize_shutdown_handlers(
290 &mut self,
291 state: State,
292 builder: shutdown_handlers::ShutdownHandlerBuilder,
293 ) -> shutdown_handlers::ShutdownHandlerBuilder {
294 builder
295 }
296
297 async fn initialize_permissions(
299 &mut self,
300 state: State,
301 builder: ExtensionPermissionsBuilder,
302 ) -> ExtensionPermissionsBuilder {
303 builder
304 }
305
306 async fn settings_deserializer(&self, state: State) -> settings::ExtensionSettingsDeserializer {
310 Arc::new(settings::EmptySettings)
311 }
312
313 async fn check_for_updates(
317 &self,
318 state: State,
319 current_version: &semver::Version,
320 ) -> Result<Option<ExtensionUpdateInfo>, anyhow::Error> {
321 Ok(None)
322 }
323
324 async fn process_call(
329 &self,
330 name: &str,
331 args: &[ExtensionCallValue],
332 ) -> Option<ExtensionCallValue> {
333 None
334 }
335
336 async fn process_call_owned(
343 &self,
344 name: &str,
345 args: Vec<ExtensionCallValue>,
346 ) -> Option<ExtensionCallValue> {
347 self.process_call(name, &args).await
348 }
349}
350
351#[derive(ToSchema, Serialize, Clone)]
352pub struct ConstructedExtension {
353 pub metadata_toml: distr::MetadataToml,
354 pub package_name: &'static str,
355 pub description: &'static str,
356 pub authors: &'static [&'static str],
357 #[schema(value_type = String)]
358 pub version: semver::Version,
359
360 #[serde(skip)]
361 #[schema(ignore)]
362 pub extension: Arc<dyn Extension>,
363}
364
365impl Deref for ConstructedExtension {
366 type Target = Arc<dyn Extension>;
367
368 fn deref(&self) -> &Self::Target {
369 &self.extension
370 }
371}
372
373#[derive(ToSchema, Serialize, Clone)]
374pub struct PendingExtension {
375 pub metadata_toml: distr::MetadataToml,
376 pub package_name: compact_str::CompactString,
377 pub description: compact_str::CompactString,
378 pub authors: Vec<compact_str::CompactString>,
379 #[schema(value_type = String)]
380 pub version: semver::Version,
381}