ezidam: apps: form, create new app
This commit is contained in:
parent
d2e1792f3c
commit
f911fc665c
6 changed files with 175 additions and 14 deletions
|
|
@ -38,7 +38,7 @@ impl AdminMenu {
|
|||
MainItem {
|
||||
id: AdminMenu::Apps.id(),
|
||||
label: "Applications",
|
||||
link: uri!(routes::admin::apps::admin_apps).to_string(),
|
||||
link: uri!(routes::admin::apps::admin_apps_list).to_string(),
|
||||
icon: Icon::Apps.svg,
|
||||
sub: None,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ pub enum Page {
|
|||
AdminDashboard(AdminDashboard),
|
||||
AdminSettingsBranding(AdminSettingsBranding),
|
||||
AdminSettingsSecurity(AdminSettingsSecurity),
|
||||
AdminApps(AdminApps),
|
||||
AdminAppsList(AdminAppsList),
|
||||
AdminAppsNew(AdminAppsNew),
|
||||
}
|
||||
|
||||
impl Page {
|
||||
|
|
@ -33,7 +34,8 @@ impl Page {
|
|||
Page::AdminDashboard(_) => "pages/admin/dashboard",
|
||||
Page::AdminSettingsBranding(_) => "pages/admin/settings/branding",
|
||||
Page::AdminSettingsSecurity(_) => "pages/admin/settings/security",
|
||||
Page::AdminApps(_) => "pages/admin/apps/list",
|
||||
Page::AdminAppsList(_) => "pages/admin/apps/list",
|
||||
Page::AdminAppsNew(_) => "pages/admin/apps/new",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +50,8 @@ impl Page {
|
|||
Page::AdminDashboard(_) => "Admin dashboard",
|
||||
Page::AdminSettingsBranding(_) => "Server branding",
|
||||
Page::AdminSettingsSecurity(_) => "Server security",
|
||||
Page::AdminApps(_) => "Applications",
|
||||
Page::AdminAppsList(_) => "Applications",
|
||||
Page::AdminAppsNew(_) => "New application",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,7 +68,8 @@ impl Page {
|
|||
Page::AdminDashboard(_) => Some(AdminMenu::Dashboard.into()),
|
||||
Page::AdminSettingsBranding(_) => Some(AdminMenu::Settings.into()),
|
||||
Page::AdminSettingsSecurity(_) => Some(AdminMenu::Settings.into()),
|
||||
Page::AdminApps(_) => Some(AdminMenu::Apps.into()),
|
||||
Page::AdminAppsList(_) => Some(AdminMenu::Apps.into()),
|
||||
Page::AdminAppsNew(_) => Some(AdminMenu::Apps.into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -80,7 +84,8 @@ impl Page {
|
|||
Page::AdminDashboard(dashboard) => Box::new(dashboard),
|
||||
Page::AdminSettingsBranding(branding) => Box::new(branding),
|
||||
Page::AdminSettingsSecurity(security) => Box::new(security),
|
||||
Page::AdminApps(apps) => Box::new(apps),
|
||||
Page::AdminAppsList(list) => Box::new(list),
|
||||
Page::AdminAppsNew(new) => Box::new(new),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@ pub fn routes() -> Vec<Route> {
|
|||
settings_update_branding,
|
||||
settings_security,
|
||||
settings_security_form,
|
||||
admin_apps,
|
||||
admin_apps_list,
|
||||
admin_apps_new,
|
||||
admin_apps_new_form,
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -49,8 +51,15 @@ pub mod content {
|
|||
#[derive(Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
#[derive(Clone)]
|
||||
pub struct AdminApps {
|
||||
pub struct AdminAppsList {
|
||||
pub user: JwtClaims,
|
||||
pub apps: Vec<App>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
#[derive(Clone)]
|
||||
pub struct AdminAppsNew {
|
||||
pub user: JwtClaims,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,75 @@
|
|||
use crate::routes::prelude::*;
|
||||
use apps::App;
|
||||
use rocket::get;
|
||||
use hash::{Secret, SecretString};
|
||||
use rocket::{get, post};
|
||||
use url::Url;
|
||||
|
||||
#[get("/admin/apps")]
|
||||
pub async fn admin_apps(mut db: Connection<Database>, admin: JwtAdmin) -> Result<Page> {
|
||||
pub async fn admin_apps_list(
|
||||
mut db: Connection<Database>,
|
||||
admin: JwtAdmin,
|
||||
flash: Option<FlashMessage<'_>>,
|
||||
) -> Result<Template> {
|
||||
let mut apps = App::get_all(&mut *db, None).await?;
|
||||
|
||||
// Remove ezidam from list
|
||||
apps.retain(|app| *app.id() != AppID("ezidam".into()));
|
||||
|
||||
Ok(Page::AdminApps(super::content::AdminApps {
|
||||
let page = Page::AdminAppsList(super::content::AdminAppsList {
|
||||
user: admin.0,
|
||||
apps,
|
||||
});
|
||||
|
||||
Ok(flash
|
||||
.map(|flash| Page::with_flash(page.clone(), flash))
|
||||
.unwrap_or_else(|| page.into()))
|
||||
}
|
||||
|
||||
#[get("/admin/apps/new")]
|
||||
pub async fn admin_apps_new(admin: JwtAdmin) -> Result<Page> {
|
||||
Ok(Page::AdminAppsNew(super::content::AdminAppsNew {
|
||||
user: admin.0,
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Debug, FromForm)]
|
||||
pub struct NewApp<'r> {
|
||||
pub label: &'r str,
|
||||
pub redirect_uri: &'r str,
|
||||
pub is_confidential: bool,
|
||||
}
|
||||
|
||||
#[post("/admin/apps/new", data = "<form>")]
|
||||
pub async fn admin_apps_new_form(
|
||||
mut db: Connection<Database>,
|
||||
_admin: JwtAdmin,
|
||||
form: Form<NewApp<'_>>,
|
||||
) -> Result<Flash<Redirect>> {
|
||||
// Generate app id
|
||||
let app_id = task::spawn_blocking(AppID::default).await?;
|
||||
|
||||
// Parse redirect uri
|
||||
let redirect_uri = Url::parse(form.redirect_uri)?;
|
||||
|
||||
// Generate secret
|
||||
let app_secret = task::spawn_blocking(SecretString::default).await?;
|
||||
// Hash secret
|
||||
let app_secret_hash = task::spawn_blocking(move || Secret::new(app_secret)).await??;
|
||||
|
||||
// Insert in database
|
||||
App::insert(
|
||||
&mut *db,
|
||||
&app_id,
|
||||
form.label,
|
||||
&redirect_uri,
|
||||
&app_secret_hash,
|
||||
form.is_confidential,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(Flash::new(
|
||||
Redirect::to(uri!(admin_apps_list)),
|
||||
FlashKind::Success,
|
||||
format!("Application \"{}\" has been created", form.label),
|
||||
))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
{% block content %}
|
||||
{% set new_app_label = "New application" %}
|
||||
{% set new_app_link = "./new" %}
|
||||
{% set new_app_link = "apps/new" %}
|
||||
<div class="page-header d-print-none">
|
||||
<div class="container-xl">
|
||||
<div class="row align-items-center">
|
||||
|
|
@ -34,6 +34,14 @@
|
|||
<!-- Page body -->
|
||||
<div class="page-body">
|
||||
<div class="container-xl">
|
||||
|
||||
{% if flash %}
|
||||
<div class="alert alert-{{flash.0}}" role="alert">
|
||||
<h4 class="alert-title">Success</h4>
|
||||
<div class="text-muted">{{ flash.1 }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if apps | length != 0 %}
|
||||
<div class="card">
|
||||
<div id="table-default" class="table-responsive">
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
Admin dashboard
|
||||
</div>
|
||||
<h2 class="page-title">
|
||||
New application
|
||||
Applications
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -17,7 +17,87 @@
|
|||
</div>
|
||||
<!-- Page body -->
|
||||
<div class="page-body">
|
||||
<div class="container-xl"></div>
|
||||
<div class="container-xl">
|
||||
<form action="" method="post" autocomplete="off" class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">New Application</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<!-- App name -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label required" for="label">Application name</label>
|
||||
<div>
|
||||
<input name="label" id="label" type="text" placeholder="Enter name" class="form-control"
|
||||
required>
|
||||
<small class="form-hint">
|
||||
The name of the application, it will be shown to users when authorizing access.
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Redirect URI -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label required" for="redirect_uri">Redirect URI</label>
|
||||
<div>
|
||||
<input name="redirect_uri" id="redirect_uri" type="url" placeholder="Enter redirect URI"
|
||||
class="form-control" required>
|
||||
<small class="form-hint">Make sure you have control over the provided Redirect URI.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Confidential app -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label required">Confidentiality</label>
|
||||
<div class="form-selectgroup-boxes row mb-3">
|
||||
|
||||
<!-- Private apps -->
|
||||
<div class="col-lg-6">
|
||||
<label class="form-selectgroup-item">
|
||||
<input name="is_confidential" type="radio" value="true" class="form-selectgroup-input"
|
||||
required>
|
||||
<span class="form-selectgroup-label d-flex align-items-center p-3">
|
||||
<span class="me-3">
|
||||
<span class="form-selectgroup-check"></span>
|
||||
</span>
|
||||
|
||||
<span class="form-selectgroup-label-content">
|
||||
<span class="form-selectgroup-title strong mb-1">Private application</span>
|
||||
<span class="d-block text-muted">
|
||||
For applications with a backend, where the application secret can be securely stored.
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Public apps -->
|
||||
<div class="col-lg-6">
|
||||
<label class="form-selectgroup-item">
|
||||
<input name="is_confidential" type="radio" value="false" class="form-selectgroup-input"
|
||||
required>
|
||||
<span class="form-selectgroup-label d-flex align-items-center p-3">
|
||||
<span class="me-3">
|
||||
<span class="form-selectgroup-check"></span>
|
||||
</span>
|
||||
|
||||
<span class="form-selectgroup-label-content">
|
||||
<span class="form-selectgroup-title strong mb-1">Public application</span>
|
||||
<span class="d-block text-muted">
|
||||
For public applications (PWAs, desktop, mobile). The application secret can not be securely stored.
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer text-end">
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue