Added swagger ui support
This commit is contained in:
+9
-1
@@ -86,6 +86,7 @@ fn config_display_entries(config: &AppConfig, sources: &ConfigSources) -> Vec<Co
|
||||
entry!(auth_sso_enabled, config.auth_sso_enabled.to_string(), defaults.auth_sso_enabled.to_string()),
|
||||
entry!(oidc_button_text, config.oidc_button_text.clone(), defaults.oidc_button_text.clone()),
|
||||
entry!(oidc_admin_groups, config.oidc_admin_groups.clone(), defaults.oidc_admin_groups.clone()),
|
||||
entry!(swagger_enabled, config.swagger_enabled.to_string(), defaults.swagger_enabled.to_string()),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -155,6 +156,8 @@ struct SettingsTemplate {
|
||||
oidc_client_secret_source: &'static str,
|
||||
oidc_admin_groups: String,
|
||||
oidc_admin_groups_source: &'static str,
|
||||
swagger_enabled: bool,
|
||||
swagger_enabled_source: &'static str,
|
||||
}
|
||||
|
||||
pub async fn settings_handler(
|
||||
@@ -185,6 +188,8 @@ pub async fn settings_handler(
|
||||
oidc_client_secret_source: sources.oidc_client_secret.code(),
|
||||
oidc_admin_groups: config.oidc_admin_groups,
|
||||
oidc_admin_groups_source: sources.oidc_admin_groups.code(),
|
||||
swagger_enabled: config.swagger_enabled,
|
||||
swagger_enabled_source: sources.swagger_enabled.code(),
|
||||
};
|
||||
Ok(Html::new(template.render()?))
|
||||
}
|
||||
@@ -198,6 +203,7 @@ pub struct OidcSettingsForm {
|
||||
oidc_client_id: String,
|
||||
oidc_client_secret: String,
|
||||
oidc_admin_groups: String,
|
||||
swagger_enabled: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn settings_submit(
|
||||
@@ -212,7 +218,8 @@ pub async fn settings_submit(
|
||||
FormResult::Ok(data) => {
|
||||
let pw_enabled = if data.auth_password_enabled.is_some() { "true" } else { "false" };
|
||||
let sso_enabled = if data.auth_sso_enabled.is_some() { "true" } else { "false" };
|
||||
let fields: [(&str, &str); 7] = [
|
||||
let swagger = if data.swagger_enabled.is_some() { "true" } else { "false" };
|
||||
let fields: [(&str, &str); 8] = [
|
||||
("auth_password_enabled", pw_enabled),
|
||||
("auth_sso_enabled", sso_enabled),
|
||||
("oidc_button_text", &data.oidc_button_text),
|
||||
@@ -220,6 +227,7 @@ pub async fn settings_submit(
|
||||
("oidc_client_id", &data.oidc_client_id),
|
||||
("oidc_client_secret", &data.oidc_client_secret),
|
||||
("oidc_admin_groups", &data.oidc_admin_groups),
|
||||
("swagger_enabled", swagger),
|
||||
];
|
||||
for (key, value) in fields {
|
||||
let mut entry = ConfigEntry::new(key.to_owned(), value.to_owned());
|
||||
|
||||
+20
-16
@@ -1,23 +1,19 @@
|
||||
use cot::db::Database;
|
||||
use cot::router::method::get;
|
||||
use cot::json::Json;
|
||||
use cot::response::IntoResponse;
|
||||
use cot::router::method::openapi::api_get;
|
||||
use cot::router::{Route, Router};
|
||||
use cot::session::Session;
|
||||
use cot::{App, Body};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::auth;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// JSON response helpers
|
||||
// JSON error helper
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
fn json_ok(value: &serde_json::Value) -> cot::response::Response {
|
||||
cot::http::Response::builder()
|
||||
.status(cot::http::StatusCode::OK)
|
||||
.header(cot::http::header::CONTENT_TYPE, "application/json")
|
||||
.body(Body::fixed(value.to_string()))
|
||||
.expect("valid response")
|
||||
}
|
||||
|
||||
fn json_error(status: cot::http::StatusCode, message: &str) -> cot::response::Response {
|
||||
let body = serde_json::json!({ "error": message });
|
||||
cot::http::Response::builder()
|
||||
@@ -31,6 +27,13 @@ fn json_error(status: cot::http::StatusCode, message: &str) -> cot::response::Re
|
||||
// GET /api/me
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[derive(Debug, Serialize, JsonSchema)]
|
||||
struct MeResponse {
|
||||
id: i64,
|
||||
name: String,
|
||||
role: String,
|
||||
}
|
||||
|
||||
async fn me_handler(
|
||||
session: Session,
|
||||
db: Database,
|
||||
@@ -42,11 +45,12 @@ async fn me_handler(
|
||||
));
|
||||
};
|
||||
|
||||
Ok(json_ok(&serde_json::json!({
|
||||
"id": user.id,
|
||||
"name": user.name,
|
||||
"role": user.role.code(),
|
||||
})))
|
||||
Json(MeResponse {
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
role: user.role.code().to_owned(),
|
||||
})
|
||||
.into_response()
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -62,7 +66,7 @@ impl App for ApiApp {
|
||||
|
||||
fn router(&self) -> Router {
|
||||
Router::with_urls([
|
||||
Route::with_handler_and_name("/me", get(me_handler), "api_me"),
|
||||
Route::with_api_handler_and_name("/me", api_get(me_handler), "api_me"),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,6 +127,7 @@ pub struct ConfigSources {
|
||||
pub auth_sso_enabled: ConfigSource,
|
||||
pub oidc_button_text: ConfigSource,
|
||||
pub oidc_admin_groups: ConfigSource,
|
||||
pub swagger_enabled: ConfigSource,
|
||||
}
|
||||
|
||||
impl Default for ConfigSources {
|
||||
@@ -141,6 +142,7 @@ impl Default for ConfigSources {
|
||||
auth_sso_enabled: ConfigSource::Default,
|
||||
oidc_button_text: ConfigSource::Default,
|
||||
oidc_admin_groups: ConfigSource::Default,
|
||||
swagger_enabled: ConfigSource::Default,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,6 +225,8 @@ pub struct AppConfig {
|
||||
pub oidc_button_text: String,
|
||||
/// Comma-separated list of OIDC group names that grant admin role.
|
||||
pub oidc_admin_groups: String,
|
||||
/// Whether the Swagger UI is served at /swagger/.
|
||||
pub swagger_enabled: bool,
|
||||
}
|
||||
|
||||
impl Default for AppConfig {
|
||||
@@ -237,6 +241,7 @@ impl Default for AppConfig {
|
||||
auth_sso_enabled: false,
|
||||
oidc_button_text: "Sign in with SSO".into(),
|
||||
oidc_admin_groups: String::new(),
|
||||
swagger_enabled: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -252,6 +257,7 @@ impl_env_overrides!(
|
||||
auth_sso_enabled,
|
||||
oidc_button_text,
|
||||
oidc_admin_groups,
|
||||
swagger_enabled,
|
||||
);
|
||||
|
||||
impl AppConfig {
|
||||
@@ -317,6 +323,7 @@ impl AppConfig {
|
||||
apply_db_field!(auth_sso_enabled);
|
||||
apply_db_field!(oidc_button_text);
|
||||
apply_db_field!(oidc_admin_groups);
|
||||
apply_db_field!(swagger_enabled);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,6 +89,11 @@ translations! {
|
||||
users_password_hint: "Leave blank to keep current" , "Оставьте пустым, чтобы не менять";
|
||||
users_saved: "User saved." , "Пользователь сохранён.";
|
||||
|
||||
// API settings
|
||||
settings_api: "API" , "API";
|
||||
settings_swagger: "Swagger UI" , "Swagger UI";
|
||||
settings_swagger_help: "Serves interactive API docs at /swagger/ (requires restart)" , "Интерактивная документация API на /swagger/ (требуется перезапуск)";
|
||||
|
||||
// OIDC login errors
|
||||
login_oidc_error: "SSO login failed. Please try again." , "Ошибка входа через SSO. Попробуйте ещё раз.";
|
||||
login_sso_disabled: "SSO login is not configured." , "Вход через SSO не настроен.";
|
||||
|
||||
+16
@@ -19,6 +19,7 @@ use cot::db::Database;
|
||||
use cot::form::{Form, FormResult};
|
||||
use cot::html::Html;
|
||||
use cot::middleware::SessionMiddleware;
|
||||
use cot::static_files::StaticFilesMiddleware;
|
||||
use cot::project::RegisterAppsContext;
|
||||
use cot::request::extractors::{RequestForm, UrlQuery};
|
||||
use cot::response::IntoResponse;
|
||||
@@ -148,6 +149,11 @@ impl App for FuruApp {
|
||||
get(|| async { Ok::<_, cot::Error>(auth::redirect("/admin/")) }),
|
||||
"admin_redirect",
|
||||
),
|
||||
Route::with_handler_and_name(
|
||||
"/swagger",
|
||||
get(|| async { Ok::<_, cot::Error>(auth::redirect("/swagger/")) }),
|
||||
"swagger_redirect",
|
||||
),
|
||||
Route::with_handler_and_name("/", index, "index"),
|
||||
Route::with_handler_and_name(
|
||||
"/login",
|
||||
@@ -258,6 +264,9 @@ impl Project for FuruProject {
|
||||
" FURU_OIDC_BUTTON_TEXT SSO button label (default: Sign in with SSO)\n",
|
||||
" FURU_OIDC_ADMIN_GROUPS OIDC groups that grant admin role\n",
|
||||
"\n",
|
||||
" API:\n",
|
||||
" FURU_SWAGGER_ENABLED Enable Swagger UI at /swagger/ (default: false)\n",
|
||||
"\n",
|
||||
"QUICK START\n",
|
||||
" export FURU_DATABASE_URL=postgres://user:pass@localhost/furumusic\n",
|
||||
" furumusic run",
|
||||
@@ -300,6 +309,7 @@ impl Project for FuruProject {
|
||||
context: &cot::project::MiddlewareContext,
|
||||
) -> cot::project::RootHandler {
|
||||
handler
|
||||
.middleware(StaticFilesMiddleware::from_context(context))
|
||||
.middleware(
|
||||
SessionMiddleware::from_context(context)
|
||||
.same_site(cot::config::SameSite::Lax),
|
||||
@@ -320,6 +330,12 @@ impl Project for FuruProject {
|
||||
"/admin",
|
||||
);
|
||||
apps.register_with_views(api::ApiApp, "/api");
|
||||
if self.app_config.swagger_enabled {
|
||||
apps.register_with_views(
|
||||
cot::openapi::swagger_ui::SwaggerUi::new(),
|
||||
"/swagger",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user