1use crate::{prelude::*, routes::{delete_file, display_card_grid, export_csv, search}, ActixAdminMenuElement};
2use actix_web::{web, Route };
3use std::collections::HashMap;
4use std::fs;
5use crate::routes::{
6 create_get, create_post, delete, delete_many, edit_get, edit_post, index, list, not_found, show, download
7};
8
9pub struct ActixAdminBuilder {
11 pub scopes: HashMap<String, actix_web::Scope>,
12 pub custom_routes: Vec<(String, Route)>,
13 pub actix_admin: ActixAdmin,
14 pub custom_index: Option<Route>,
15}
16
17pub trait ActixAdminBuilderTrait {
19 fn new(configuration: ActixAdminConfiguration) -> Self;
20 fn add_entity<E: ActixAdminViewModelTrait + 'static>(
21 &mut self,
22 view_model: &ActixAdminViewModel,
23 );
24 fn add_entity_to_category<
25 E: ActixAdminViewModelTrait + 'static,
26 >(
27 &mut self,
28 view_model: &ActixAdminViewModel,
29 category_name: &str,
30 );
31 fn add_custom_handler(
32 &mut self,
33 menu_element_name: &str,
34 path: &str,
35 route: Route,
36 add_to_menu: bool,
37 );
38 fn add_custom_handler_to_category(
39 &mut self,
40 menu_element_name: &str,
41 path: &str,
42 route: Route,
43 add_to_menu: bool,
44 category: &str
45 );
46 fn add_card_grid(
47 &mut self,
48 menu_element_name: &str,
49 path: &str,
50 elements: Vec<Vec<String>>,
51 add_to_menu: bool,
52 );
53 fn add_card_grid_to_category(
54 &mut self,
55 menu_element_name: &str,
56 path: &str,
57 elements: Vec<Vec<String>>,
58 add_to_menu: bool,
59 category: &str
60 );
61 fn add_custom_handler_for_entity<
62 E: ActixAdminViewModelTrait + 'static,
63 >(
64 &mut self,
65 menu_element_name: &str,
66 path: &str,
67 route: Route,
68 add_to_menu: bool
69 );
70 fn add_custom_handler_for_entity_in_category<
71 E: ActixAdminViewModelTrait + 'static,
72 >(
73 &mut self,
74 menu_element_name: &str,
75 path: &str,
76 route: Route,
77 category_name: &str,
78 add_to_menu: bool,
79 );
80 fn add_custom_handler_for_index(&mut self, route: Route);
81 fn get_scope(self) -> actix_web::Scope;
82 fn get_actix_admin(&self) -> ActixAdmin;
83 fn add_support_handler(&mut self, arg: &str, support: Route);
84}
85
86impl ActixAdminBuilderTrait for ActixAdminBuilder {
87 fn new(configuration: ActixAdminConfiguration) -> Self {
88 ActixAdminBuilder {
89 actix_admin: ActixAdmin {
90 entity_names: HashMap::new(),
91 view_models: HashMap::new(),
92 card_grids: HashMap::new(),
93 configuration: configuration,
94 tera: crate::tera_templates::get_tera(),
95 support_path: None
96 },
97 custom_routes: Vec::new(),
98 scopes: HashMap::new(),
99 custom_index: None,
100 }
101 }
102
103 fn add_entity<E: ActixAdminViewModelTrait + 'static>(
104 &mut self,
105 view_model: &ActixAdminViewModel,
106 ) {
107 let _ = &self.add_entity_to_category::<E>(view_model, "");
108 }
109
110 fn add_entity_to_category<
111 E: ActixAdminViewModelTrait + 'static,
112 >(
113 &mut self,
114 view_model: &ActixAdminViewModel,
115 category_name: &str,
116 ) {
117 self.scopes.insert(
118 E::get_entity_name(),
119 web::scope(&format!("/{}", E::get_entity_name()))
120 .route("/list", web::get().to(list::<E>))
121 .route("/export_csv", web::get().to(export_csv::<E>))
122 .route("/create", web::get().to(create_get::<E>))
123 .route("/search", web::get().to(search::<E>))
124 .route("/create", web::post().to(create_post::<E>))
125 .route("/edit/{id}", web::get().to(edit_get::<E>))
126 .route("/edit/{id}", web::post().to(edit_post::<E>))
127 .route("/delete", web::delete().to(delete_many::<E>))
128 .route("/delete/{id}", web::delete().to(delete::<E>))
129 .route("/show/{id}", web::get().to(show::<E>))
130 .route("/file/{id}/{column_name}", web::get().to(download::<E>))
131 .route("/file/{id}/{column_name}", web::delete().to(delete_file::<E>))
132 .default_service(web::to(not_found))
133 );
134
135 fs::create_dir_all(format!("{}/{}", &self.actix_admin.configuration.file_upload_directory, E::get_entity_name())).unwrap();
136
137 let category = self.actix_admin.entity_names.get_mut(category_name);
138 let menu_element = ActixAdminMenuElement {
139 name: E::get_entity_name(),
140 link: E::get_entity_name(),
141 is_custom_handler: false,
142 };
143 match category {
144 Some(entity_list) => entity_list.push(menu_element),
145 None => {
146 let mut entity_list = Vec::new();
147 entity_list.push(menu_element);
148 self.actix_admin
149 .entity_names
150 .insert(category_name.to_string(), entity_list);
151 }
152 }
153
154 let key = E::get_entity_name();
155 self.actix_admin.view_models.insert(key, view_model.clone());
156 }
157
158 fn add_custom_handler_for_index(&mut self, route: Route) {
159 self.custom_index = Some(route);
160 }
161
162 fn add_custom_handler_to_category(
163 &mut self,
164 menu_element_name: &str,
165 path: &str,
166 route: Route,
167 add_to_menu: bool,
168 category_name: &str
169 ) {
170 self.custom_routes.push((path.to_string(), route));
171
172 if add_to_menu {
173 let menu_element = ActixAdminMenuElement {
174 name: menu_element_name.to_string(),
175 link: path.replacen("/", "", 1),
176 is_custom_handler: true,
177 };
178 let category = self.actix_admin.entity_names.get_mut(category_name);
179 match category {
180 Some(entity_list) => {
181 if !entity_list.contains(&menu_element) {
182 entity_list.push(menu_element);
183 }
184 }
185 None => {
186 let mut entity_list = Vec::new();
187 entity_list.push(menu_element);
188 self.actix_admin
189 .entity_names
190 .insert(category_name.to_string(), entity_list);
191 },
192 }
193 }
194 }
195
196 fn add_card_grid(
197 &mut self,
198 menu_element_name: &str,
199 path: &str,
200 elements: Vec<Vec<String>>,
201 add_to_menu: bool,
202 ) {
203 self.add_card_grid_to_category(menu_element_name, path, elements, add_to_menu, "");
204 }
205
206 fn add_card_grid_to_category(
207 &mut self,
208 menu_element_name: &str,
209 path: &str,
210 elements: Vec<Vec<String>>,
211 add_to_menu: bool,
212 category_name: &str
213 ) {
214 self.custom_routes.push((path.to_string(), web::get().to(display_card_grid)));
215 self.actix_admin.card_grids.insert(path.to_string().replace("/", ""), elements);
216
217 if add_to_menu {
218 let menu_element = ActixAdminMenuElement {
219 name: menu_element_name.to_string(),
220 link: path.replacen("/", "", 1),
221 is_custom_handler: true,
222 };
223 let category = self.actix_admin.entity_names.get_mut(category_name);
224 match category {
225 Some(entity_list) => {
226 if !entity_list.contains(&menu_element) {
227 entity_list.push(menu_element);
228 }
229 }
230 None => {
231 let mut entity_list = Vec::new();
232 entity_list.push(menu_element);
233 self.actix_admin
234 .entity_names
235 .insert(category_name.to_string(), entity_list);
236 },
237 }
238 }
239 }
240
241 fn add_custom_handler(
242 &mut self,
243 menu_element_name: &str,
244 path: &str,
245 route: Route,
246 add_to_menu: bool
247 ) {
248 self.add_custom_handler_to_category(menu_element_name, path, route, add_to_menu, "");
249 }
250
251 fn add_support_handler(&mut self, arg: &str, support: Route) {
252 self.custom_routes.push((arg.to_string(), support));
253 self.actix_admin.support_path = Some(arg.to_string().replace("/", ""));
254 }
255
256 fn add_custom_handler_for_entity<
257 E: ActixAdminViewModelTrait + 'static,
258 >(
259 &mut self,
260 menu_element_name: &str,
261 path: &str,
262 route: Route,
263 add_to_menu: bool,
264 ) {
265 let _ = &self.add_custom_handler_for_entity_in_category::<E>(
266 menu_element_name,
267 path,
268 route,
269 "",
270 add_to_menu,
271 );
272 }
273
274 fn add_custom_handler_for_entity_in_category<
275 E: ActixAdminViewModelTrait + 'static,
276 >(
277 &mut self,
278 menu_element_name: &str,
279 path: &str,
280 route: Route,
281 category_name: &str,
282 add_to_menu: bool,
283 ) {
284 let menu_element = ActixAdminMenuElement {
285 name: menu_element_name.to_string(),
286 link: format!("{}{}", E::get_entity_name(), path),
287 is_custom_handler: true,
288 };
289
290 let existing_scope = self.scopes.remove(&E::get_entity_name());
291
292 match existing_scope {
293 Some(scope) => {
294 let existing_scope = scope.route(path, route);
295 self.scopes
296 .insert(E::get_entity_name(), existing_scope);
297 }
298 _ => {
299 let new_scope =
300 web::scope(&format!("/{}", E::get_entity_name())).route(path, route);
301 self.scopes.insert(E::get_entity_name(), new_scope);
302 }
303 }
304
305 if add_to_menu {
306 let category = self.actix_admin.entity_names.get_mut(category_name);
307 match category {
308 Some(entity_list) => {
309 if !entity_list.contains(&menu_element) {
310 entity_list.push(menu_element);
311 }
312 }
313 _ => (),
314 }
315 }
316 }
317
318 fn get_scope(self) -> actix_web::Scope {
319 let index_handler = match self.custom_index {
320 Some(handler) => handler,
321 _ => web::get().to(index),
322 };
323 let mut admin_scope = web::scope(&self.actix_admin.configuration.base_path)
324 .route("/", index_handler)
325 .default_service(web::to(not_found));
326
327 for (_entity, scope) in self.scopes {
328 admin_scope = admin_scope.service(scope);
329 }
330
331 for (path, route) in self.custom_routes {
332 admin_scope = admin_scope.route(&path, route);
333 }
334
335 admin_scope
336 }
337
338 fn get_actix_admin(&self) -> ActixAdmin {
339 self.actix_admin.clone()
340 }
341}