1#![allow(clippy::needless_for_each)]
4
5use actix_web::web;
6use utoipa::{
7 openapi::security::{AuthorizationCode, Flow, OAuth2, Scopes, SecurityScheme},
8 Modify, OpenApi,
9};
10use utoipa_swagger_ui::SwaggerUi;
11
12use crate::{
13 config::auth::Config,
14 controller::{
15 areas, base_layer_image, blossoms, config, drawings, guided_tours, layers, map,
16 map_collaborators, plant_layer, plantings, plants, seed, timeline, users,
17 },
18 keycloak_api,
19 model::{
20 dto::{
21 areas::{
22 AreaDto, AreaKind, NewAreaDto, UpdateAddDateAreaDto, UpdateAreaDto,
23 UpdateRemoveDateAreaDto,
24 },
25 base_layer_images::{BaseLayerImageDto, UpdateBaseLayerImageDto},
26 core::{
27 ActionDtoWrapperDeleteDrawings, ActionDtoWrapperDeleteLayer,
28 ActionDtoWrapperDeletePlantings, ActionDtoWrapperNewDrawings,
29 ActionDtoWrapperNewLayer, ActionDtoWrapperNewPlantings,
30 ActionDtoWrapperUpdateDrawings, ActionDtoWrapperUpdateLayer,
31 ActionDtoWrapperUpdatePlantings, TimelinePagePlantingsDto,
32 },
33 drawings::{
34 DrawingDto, EllipseProperties, FreeLineProperties, ImageProperties,
35 LabelTextProperties, PolygonProperties, RectangleProperties,
36 UpdateAddDateDrawingDto, UpdateNotesDrawingDto, UpdateRemoveDateDrawingDto,
37 },
38 layers::LayerDto,
39 plantings::{
40 MovePlantingDto, PlantingDto, TransformPlantingDto, UpdateAddDatePlantingDto,
41 UpdatePlantingDto, UpdatePlantingNoteDto, UpdateRemoveDatePlantingDto,
42 },
43 timeline::{TimelineDto, TimelineEntryDto},
44 ConfigDto, Coordinates, DeleteMapCollaboratorDto, GainedBlossomsDto, GuidedToursDto,
45 MapCollaboratorDto, MapDto, NewMapCollaboratorDto, NewMapDto, NewSeedDto, PageLayerDto,
46 PageMapDto, PagePlantsSummaryDto, PageSeedDto, PlantsSummaryDto, RelationDto,
47 RelationsDto, SeedDto, UpdateGuidedToursDto, UpdateMapDto, UsersDto,
48 },
49 r#enum::{
50 experience::Experience, membership::Membership, privacy_option::PrivacyOption,
51 quality::Quality, quantity::Quantity, salutation::Salutation, shade::Shade,
52 spatial_relation_type::SpatialRelationType,
53 },
54 },
55};
56
57#[derive(OpenApi)]
59#[openapi(paths(config::get), components(schemas(ConfigDto)))]
60struct ConfigApiDoc;
61
62#[derive(OpenApi)]
64#[openapi(
65 paths(
66 seed::find,
67 seed::find_by_id,
68 seed::create,
69 seed::delete_by_id
70 ),
71 components(
72 schemas(
73 PageSeedDto,
74 SeedDto,
75 NewSeedDto,
76 Quality,
77 Quantity
78 )
79 ),
80 modifiers(&SecurityAddon)
81)]
82struct SeedApiDoc;
83
84#[derive(OpenApi)]
86#[openapi(
87 paths(
88 plants::find,
89 plants::find_by_id
90 ),
91 components(
92 schemas(
93 PagePlantsSummaryDto,
94 PlantsSummaryDto
95 )
96 ),
97 modifiers(&SecurityAddon)
98)]
99struct PlantsApiDoc;
100
101#[derive(OpenApi)]
103#[openapi(
104 paths(
105 map::find,
106 map::find_by_id,
107 map::create,
108 map::update
109 ),
110 components(
111 schemas(
112 PageMapDto,
113 MapDto,
114 NewMapDto,
115 UpdateMapDto,
116 PrivacyOption,
117 Coordinates
118 )
119 ),
120 modifiers(&SecurityAddon)
121)]
122struct MapApiDoc;
123
124#[derive(OpenApi)]
126#[openapi(
127 paths(
128 layers::find,
129 layers::find_by_id,
130 layers::create,
131 layers::delete
132 ),
133 components(
134 schemas(
135 LayerDto,
136 PageLayerDto,
137 ActionDtoWrapperNewLayer,
138 ActionDtoWrapperUpdateLayer,
139 ActionDtoWrapperDeleteLayer,
140 )
141 ),
142 modifiers(&SecurityAddon)
143)]
144struct LayerApiDoc;
145
146#[derive(OpenApi)]
148#[openapi(
149 paths(
150 plant_layer::heatmap,
151 plant_layer::find_relations
152 ),
153 components(
154 schemas(
155 RelationsDto,
156 RelationDto,
157 SpatialRelationType
158 )
159 ),
160 modifiers(&SecurityAddon)
161)]
162struct PlantLayerApiDoc;
163
164#[derive(OpenApi)]
166#[openapi(
167 paths(
168 base_layer_image::find,
169 base_layer_image::create,
170 base_layer_image::update,
171 base_layer_image::delete
172 ),
173 components(
174 schemas(
175 BaseLayerImageDto,
176 UpdateBaseLayerImageDto,
177 )
178 ),
179 modifiers(&SecurityAddon)
180)]
181struct BaseLayerImagesApiDoc;
182
183#[derive(OpenApi)]
185#[openapi(
186 paths(
187 plantings::find,
188 plantings::create,
189 plantings::update,
190 plantings::delete
191 ),
192 components(
193 schemas(
194 PlantingDto,
195 TimelinePagePlantingsDto,
196 UpdatePlantingDto,
197 TransformPlantingDto,
198 MovePlantingDto,
199 UpdateAddDatePlantingDto,
200 UpdateRemoveDatePlantingDto,
201 UpdatePlantingNoteDto,
202 ActionDtoWrapperNewPlantings,
203 ActionDtoWrapperUpdatePlantings,
204 ActionDtoWrapperDeletePlantings,
205 ActionDtoWrapperDeleteDrawings,
206 )
207 ),
208 modifiers(&SecurityAddon)
209)]
210struct PlantingsApiDoc;
211
212#[derive(OpenApi)]
214#[openapi(
215 paths(
216 areas::find,
217 areas::create,
218 areas::update,
219 areas::delete
220 ),
221 components(
222 schemas(
223 AreaKind,
224 AreaDto,
225 NewAreaDto,
226 UpdateAreaDto,
227 UpdateAddDateAreaDto,
228 UpdateRemoveDateAreaDto,
229 Shade
230 )
231 ),
232 modifiers(&SecurityAddon)
233)]
234struct AreasApiDoc;
235
236#[derive(OpenApi)]
238#[openapi(
239 paths(
240 users::create,
241 users::find
242 ),
243 components(
244 schemas(
245 keycloak_api::UserDto,
246 UsersDto,
247 Experience,
248 Membership,
249 Salutation
250 )
251 ),
252 modifiers(&SecurityAddon)
253)]
254struct UsersApiDoc;
255
256#[derive(OpenApi)]
258#[openapi(
259 paths(
260 guided_tours::setup,
261 guided_tours::find_by_user,
262 guided_tours::update
263 ),
264 components(
265 schemas(
266 GuidedToursDto,
267 UpdateGuidedToursDto
268 )
269 ),
270 modifiers(&SecurityAddon)
271)]
272struct GuidedToursApiDoc;
273
274#[derive(OpenApi)]
276#[openapi(
277 paths(
278 blossoms::gain,
279 ),
280 components(
281 schemas(
282 GainedBlossomsDto
283 )
284 ),
285 modifiers(&SecurityAddon)
286)]
287struct BlossomsApiDoc;
288
289#[derive(OpenApi)]
291#[openapi(
292 paths(
293 timeline::get_timeline,
294 ),
295 components(
296 schemas(
297 TimelineEntryDto,
298 TimelineDto
299 )
300 ),
301 modifiers(&SecurityAddon)
302)]
303struct TimelineApiDoc;
304
305#[derive(OpenApi)]
307#[openapi(
308 paths(
309 drawings::find,
310 drawings::create,
311 drawings::update,
312 drawings::delete,
313 ),
314 components(
315 schemas(
316 DrawingDto,
317 RectangleProperties,
318 EllipseProperties,
319 FreeLineProperties,
320 PolygonProperties,
321 LabelTextProperties,
322 ImageProperties,
323 UpdateAddDateDrawingDto,
324 UpdateRemoveDateDrawingDto,
325 UpdateNotesDrawingDto,
326 ActionDtoWrapperNewDrawings,
327 ActionDtoWrapperUpdateDrawings,
328 ActionDtoWrapperDeleteDrawings,
329 )
330 ),
331 modifiers(&SecurityAddon)
332)]
333struct DrawingsApiDoc;
334
335#[derive(OpenApi)]
337#[openapi(
338 paths(
339 map_collaborators::create,
340 map_collaborators::find,
341 map_collaborators::delete,
342 ),
343 components(
344 schemas(
345 NewMapCollaboratorDto,
346 MapCollaboratorDto,
347 DeleteMapCollaboratorDto,
348 )
349 ),
350 modifiers(&SecurityAddon)
351)]
352struct MapCollaboratorsApiDoc;
353
354pub fn config(cfg: &mut web::ServiceConfig) {
356 let mut openapi = ConfigApiDoc::openapi();
357 openapi.merge(SeedApiDoc::openapi());
358 openapi.merge(PlantsApiDoc::openapi());
359 openapi.merge(MapApiDoc::openapi());
360 openapi.merge(LayerApiDoc::openapi());
361 openapi.merge(PlantLayerApiDoc::openapi());
362 openapi.merge(BaseLayerImagesApiDoc::openapi());
363 openapi.merge(PlantingsApiDoc::openapi());
364 openapi.merge(AreasApiDoc::openapi());
365 openapi.merge(UsersApiDoc::openapi());
366 openapi.merge(TimelineApiDoc::openapi());
367 openapi.merge(DrawingsApiDoc::openapi());
368 openapi.merge(GuidedToursApiDoc::openapi());
369 openapi.merge(BlossomsApiDoc::openapi());
370 openapi.merge(MapCollaboratorsApiDoc::openapi());
371
372 cfg.service(SwaggerUi::new("/doc/api/swagger/ui/{_:.*}").url("/doc/api/openapi.json", openapi));
373}
374
375struct SecurityAddon;
377
378impl Modify for SecurityAddon {
379 fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
380 #[allow(clippy::unwrap_used)]
382 let components = openapi.components.as_mut().unwrap();
383
384 let config = &Config::get().openid_configuration;
385 let oauth2 = OAuth2::new([Flow::AuthorizationCode(AuthorizationCode::new(
386 config.authorization_endpoint.clone(),
387 config.token_endpoint.clone(),
388 Scopes::new(),
389 ))]);
390 components.add_security_scheme("oauth2", SecurityScheme::OAuth2(oauth2));
391 }
392}