use actix_web::web;
use utoipa::{
openapi::security::{AuthorizationCode, Flow, OAuth2, Scopes, SecurityScheme},
Modify, OpenApi,
};
use utoipa_swagger_ui::SwaggerUi;
use crate::{
config::auth::Config,
controller::{
areas, base_layer_image, blossoms, config, drawings, guided_tours, layers, map,
map_collaborators, plant_layer, plantings, plants, seed, timeline, users,
},
keycloak_api,
model::{
dto::{
areas::{
AreaDto, AreaKind, NewAreaDto, UpdateAddDateAreaDto, UpdateAreaDto,
UpdateRemoveDateAreaDto,
},
base_layer_images::{BaseLayerImageDto, UpdateBaseLayerImageDto},
core::{
ActionDtoWrapperDeleteDrawings, ActionDtoWrapperDeleteLayer,
ActionDtoWrapperDeletePlantings, ActionDtoWrapperNewDrawings,
ActionDtoWrapperNewLayer, ActionDtoWrapperNewPlantings,
ActionDtoWrapperUpdateDrawings, ActionDtoWrapperUpdateLayer,
ActionDtoWrapperUpdatePlantings, TimelinePagePlantingsDto,
},
drawings::{
DrawingDto, EllipseProperties, FreeLineProperties, ImageProperties,
LabelTextProperties, PolygonProperties, RectangleProperties,
UpdateAddDateDrawingDto, UpdateNotesDrawingDto, UpdateRemoveDateDrawingDto,
},
layers::LayerDto,
plantings::{
MovePlantingDto, PlantingDto, TransformPlantingDto, UpdateAddDatePlantingDto,
UpdatePlantingDto, UpdatePlantingNoteDto, UpdateRemoveDatePlantingDto,
},
timeline::{TimelineDto, TimelineEntryDto},
ConfigDto, Coordinates, DeleteMapCollaboratorDto, GainedBlossomsDto, GuidedToursDto,
MapCollaboratorDto, MapDto, NewMapCollaboratorDto, NewMapDto, NewSeedDto, PageLayerDto,
PageMapDto, PagePlantsSummaryDto, PageSeedDto, PlantsSummaryDto, RelationDto,
RelationsDto, SeedDto, UpdateGuidedToursDto, UpdateMapDto, UsersDto,
},
r#enum::{
experience::Experience, membership::Membership, privacy_option::PrivacyOption,
quality::Quality, quantity::Quantity, salutation::Salutation, shade::Shade,
spatial_relation_type::SpatialRelationType,
},
},
};
#[derive(OpenApi)]
#[openapi(paths(config::get), components(schemas(ConfigDto)))]
struct ConfigApiDoc;
#[derive(OpenApi)]
#[openapi(
paths(
seed::find,
seed::find_by_id,
seed::create,
seed::delete_by_id
),
components(
schemas(
PageSeedDto,
SeedDto,
NewSeedDto,
Quality,
Quantity
)
),
modifiers(&SecurityAddon)
)]
struct SeedApiDoc;
#[derive(OpenApi)]
#[openapi(
paths(
plants::find,
plants::find_by_id
),
components(
schemas(
PagePlantsSummaryDto,
PlantsSummaryDto
)
),
modifiers(&SecurityAddon)
)]
struct PlantsApiDoc;
#[derive(OpenApi)]
#[openapi(
paths(
map::find,
map::find_by_id,
map::create,
map::update
),
components(
schemas(
PageMapDto,
MapDto,
NewMapDto,
UpdateMapDto,
PrivacyOption,
Coordinates
)
),
modifiers(&SecurityAddon)
)]
struct MapApiDoc;
#[derive(OpenApi)]
#[openapi(
paths(
layers::find,
layers::find_by_id,
layers::create,
layers::delete
),
components(
schemas(
LayerDto,
PageLayerDto,
ActionDtoWrapperNewLayer,
ActionDtoWrapperUpdateLayer,
ActionDtoWrapperDeleteLayer,
)
),
modifiers(&SecurityAddon)
)]
struct LayerApiDoc;
#[derive(OpenApi)]
#[openapi(
paths(
plant_layer::heatmap,
plant_layer::find_relations
),
components(
schemas(
RelationsDto,
RelationDto,
SpatialRelationType
)
),
modifiers(&SecurityAddon)
)]
struct PlantLayerApiDoc;
#[derive(OpenApi)]
#[openapi(
paths(
base_layer_image::find,
base_layer_image::create,
base_layer_image::update,
base_layer_image::delete
),
components(
schemas(
BaseLayerImageDto,
UpdateBaseLayerImageDto,
)
),
modifiers(&SecurityAddon)
)]
struct BaseLayerImagesApiDoc;
#[derive(OpenApi)]
#[openapi(
paths(
plantings::find,
plantings::create,
plantings::update,
plantings::delete
),
components(
schemas(
PlantingDto,
TimelinePagePlantingsDto,
UpdatePlantingDto,
TransformPlantingDto,
MovePlantingDto,
UpdateAddDatePlantingDto,
UpdateRemoveDatePlantingDto,
UpdatePlantingNoteDto,
ActionDtoWrapperNewPlantings,
ActionDtoWrapperUpdatePlantings,
ActionDtoWrapperDeletePlantings,
ActionDtoWrapperDeleteDrawings,
)
),
modifiers(&SecurityAddon)
)]
struct PlantingsApiDoc;
#[derive(OpenApi)]
#[openapi(
paths(
areas::find,
areas::create,
areas::update,
areas::delete
),
components(
schemas(
AreaKind,
AreaDto,
NewAreaDto,
UpdateAreaDto,
UpdateAddDateAreaDto,
UpdateRemoveDateAreaDto,
Shade
)
),
modifiers(&SecurityAddon)
)]
struct AreasApiDoc;
#[derive(OpenApi)]
#[openapi(
paths(
users::create,
users::find
),
components(
schemas(
keycloak_api::UserDto,
UsersDto,
Experience,
Membership,
Salutation
)
),
modifiers(&SecurityAddon)
)]
struct UsersApiDoc;
#[derive(OpenApi)]
#[openapi(
paths(
guided_tours::setup,
guided_tours::find_by_user,
guided_tours::update
),
components(
schemas(
GuidedToursDto,
UpdateGuidedToursDto
)
),
modifiers(&SecurityAddon)
)]
struct GuidedToursApiDoc;
#[derive(OpenApi)]
#[openapi(
paths(
blossoms::gain,
),
components(
schemas(
GainedBlossomsDto
)
),
modifiers(&SecurityAddon)
)]
struct BlossomsApiDoc;
#[derive(OpenApi)]
#[openapi(
paths(
timeline::get_timeline,
),
components(
schemas(
TimelineEntryDto,
TimelineDto
)
),
modifiers(&SecurityAddon)
)]
struct TimelineApiDoc;
#[derive(OpenApi)]
#[openapi(
paths(
drawings::find,
drawings::create,
drawings::update,
drawings::delete,
),
components(
schemas(
DrawingDto,
RectangleProperties,
EllipseProperties,
FreeLineProperties,
PolygonProperties,
LabelTextProperties,
ImageProperties,
UpdateAddDateDrawingDto,
UpdateRemoveDateDrawingDto,
UpdateNotesDrawingDto,
ActionDtoWrapperNewDrawings,
ActionDtoWrapperUpdateDrawings,
ActionDtoWrapperDeleteDrawings,
)
),
modifiers(&SecurityAddon)
)]
struct DrawingsApiDoc;
#[derive(OpenApi)]
#[openapi(
paths(
map_collaborators::create,
map_collaborators::find,
map_collaborators::delete,
),
components(
schemas(
NewMapCollaboratorDto,
MapCollaboratorDto,
DeleteMapCollaboratorDto,
)
),
modifiers(&SecurityAddon)
)]
struct MapCollaboratorsApiDoc;
pub fn config(cfg: &mut web::ServiceConfig) {
let mut openapi = ConfigApiDoc::openapi();
openapi.merge(SeedApiDoc::openapi());
openapi.merge(PlantsApiDoc::openapi());
openapi.merge(MapApiDoc::openapi());
openapi.merge(LayerApiDoc::openapi());
openapi.merge(PlantLayerApiDoc::openapi());
openapi.merge(BaseLayerImagesApiDoc::openapi());
openapi.merge(PlantingsApiDoc::openapi());
openapi.merge(AreasApiDoc::openapi());
openapi.merge(UsersApiDoc::openapi());
openapi.merge(TimelineApiDoc::openapi());
openapi.merge(DrawingsApiDoc::openapi());
openapi.merge(GuidedToursApiDoc::openapi());
openapi.merge(BlossomsApiDoc::openapi());
openapi.merge(MapCollaboratorsApiDoc::openapi());
cfg.service(SwaggerUi::new("/doc/api/swagger/ui/{_:.*}").url("/doc/api/openapi.json", openapi));
}
struct SecurityAddon;
impl Modify for SecurityAddon {
fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
#[allow(clippy::unwrap_used)]
let components = openapi.components.as_mut().unwrap();
let config = &Config::get().openid_configuration;
let oauth2 = OAuth2::new([Flow::AuthorizationCode(AuthorizationCode::new(
config.authorization_endpoint.clone(),
config.token_endpoint.clone(),
Scopes::new(),
))]);
components.add_security_scheme("oauth2", SecurityScheme::OAuth2(oauth2));
}
}