ezidam: branding page: logo update/delete, update business name
This commit is contained in:
parent
d8fe336b06
commit
3532f80882
10 changed files with 165 additions and 52 deletions
|
|
@ -20,6 +20,12 @@ impl From<url::ParseError> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<std::io::Error> for Error {
|
||||||
|
fn from(e: std::io::Error) -> Self {
|
||||||
|
Error::internal_server_error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Local crates
|
// Local crates
|
||||||
|
|
||||||
impl From<hash::Error> for Error {
|
impl From<hash::Error> for Error {
|
||||||
|
|
|
||||||
|
|
@ -35,11 +35,11 @@ impl AdminMenu {
|
||||||
MainItem {
|
MainItem {
|
||||||
id: AdminMenu::Settings.id(),
|
id: AdminMenu::Settings.id(),
|
||||||
label: "Server settings",
|
label: "Server settings",
|
||||||
link: uri!(routes::admin::settings::admin_settings).to_string(),
|
link: uri!(routes::admin::settings::settings_branding).to_string(),
|
||||||
icon: icons::SETTINGS,
|
icon: icons::SETTINGS,
|
||||||
sub: Some(vec![SubItem {
|
sub: Some(vec![SubItem {
|
||||||
label: "Branding",
|
label: "Branding",
|
||||||
link: uri!(routes::admin::settings::admin_settings).to_string(),
|
link: uri!(routes::admin::settings::settings_branding).to_string(),
|
||||||
}]),
|
}]),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ pub enum Page {
|
||||||
Authorize(Authorize),
|
Authorize(Authorize),
|
||||||
Redirect(Redirect),
|
Redirect(Redirect),
|
||||||
AdminDashboard(AdminDashboard),
|
AdminDashboard(AdminDashboard),
|
||||||
AdminSettings(AdminSettings),
|
AdminSettingsBranding(AdminSettingsBranding),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Page {
|
impl Page {
|
||||||
|
|
@ -28,7 +28,7 @@ impl Page {
|
||||||
Page::Authorize(_) => "pages/oauth/authorize",
|
Page::Authorize(_) => "pages/oauth/authorize",
|
||||||
Page::Redirect(_) => "pages/oauth/redirect",
|
Page::Redirect(_) => "pages/oauth/redirect",
|
||||||
Page::AdminDashboard(_) => "pages/admin/dashboard",
|
Page::AdminDashboard(_) => "pages/admin/dashboard",
|
||||||
Page::AdminSettings(_) => "pages/admin/settings",
|
Page::AdminSettingsBranding(_) => "pages/admin/settings_branding",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,7 +41,7 @@ impl Page {
|
||||||
Page::Authorize(_) => "Authorize app",
|
Page::Authorize(_) => "Authorize app",
|
||||||
Page::Redirect(_) => "Redirecting",
|
Page::Redirect(_) => "Redirecting",
|
||||||
Page::AdminDashboard(_) => "Admin dashboard",
|
Page::AdminDashboard(_) => "Admin dashboard",
|
||||||
Page::AdminSettings(_) => "Server settings",
|
Page::AdminSettingsBranding(_) => "Server branding",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,7 +56,7 @@ impl Page {
|
||||||
Page::Authorize(_) => None,
|
Page::Authorize(_) => None,
|
||||||
Page::Redirect(_) => None,
|
Page::Redirect(_) => None,
|
||||||
Page::AdminDashboard(_) => Some(AdminMenu::Dashboard.into()),
|
Page::AdminDashboard(_) => Some(AdminMenu::Dashboard.into()),
|
||||||
Page::AdminSettings(_) => Some(AdminMenu::Settings.into()),
|
Page::AdminSettingsBranding(_) => Some(AdminMenu::Settings.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,7 +69,7 @@ impl Page {
|
||||||
Page::Authorize(authorize) => Box::new(authorize),
|
Page::Authorize(authorize) => Box::new(authorize),
|
||||||
Page::Redirect(redirect) => Box::new(redirect),
|
Page::Redirect(redirect) => Box::new(redirect),
|
||||||
Page::AdminDashboard(dashboard) => Box::new(dashboard),
|
Page::AdminDashboard(dashboard) => Box::new(dashboard),
|
||||||
Page::AdminSettings(settings) => Box::new(settings),
|
Page::AdminSettingsBranding(branding) => Box::new(branding),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ pub mod dashboard;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
|
|
||||||
pub fn routes() -> Vec<Route> {
|
pub fn routes() -> Vec<Route> {
|
||||||
routes![admin_dashboard, admin_settings]
|
routes![admin_dashboard, settings_branding, settings_update_branding]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod content {
|
pub mod content {
|
||||||
|
|
@ -23,7 +23,8 @@ pub mod content {
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[serde(crate = "rocket::serde")]
|
#[serde(crate = "rocket::serde")]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AdminSettings {
|
pub struct AdminSettingsBranding {
|
||||||
pub user: JwtClaims,
|
pub user: JwtClaims,
|
||||||
|
pub business_name: String,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,61 @@
|
||||||
use crate::routes::prelude::*;
|
use crate::routes::prelude::*;
|
||||||
use rocket::get;
|
use rocket::fs::TempFile;
|
||||||
|
use rocket::{get, post};
|
||||||
|
use settings::Settings;
|
||||||
|
|
||||||
#[get("/admin/settings")]
|
#[get("/admin/settings/branding")]
|
||||||
pub async fn admin_settings(mut db: Connection<Database>, admin: JwtAdmin) -> Result<Page> {
|
pub async fn settings_branding(mut db: Connection<Database>, admin: JwtAdmin) -> Result<Page> {
|
||||||
Ok(Page::AdminSettings(super::content::AdminSettings {
|
let settings = Settings::get(&mut *db).await?;
|
||||||
user: admin.0,
|
|
||||||
}))
|
Ok(Page::AdminSettingsBranding(
|
||||||
|
super::content::AdminSettingsBranding {
|
||||||
|
user: admin.0,
|
||||||
|
business_name: settings.business_name().to_string(),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, FromForm)]
|
||||||
|
pub struct UpdateBranding<'r> {
|
||||||
|
pub file: TempFile<'r>,
|
||||||
|
pub business_name: Option<&'r str>,
|
||||||
|
pub delete_logo: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/admin/settings/branding", data = "<form>")]
|
||||||
|
pub async fn settings_update_branding(
|
||||||
|
mut db: Connection<Database>,
|
||||||
|
_admin: JwtAdmin,
|
||||||
|
form: Form<UpdateBranding<'_>>,
|
||||||
|
) -> Result<Redirect> {
|
||||||
|
let mut transaction = db.begin().await?;
|
||||||
|
|
||||||
|
match form.delete_logo {
|
||||||
|
Some(delete_logo) => {
|
||||||
|
if delete_logo {
|
||||||
|
Settings::delete_business_logo(&mut transaction).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if let Some(business_name) = form.business_name {
|
||||||
|
Settings::set_business_name(&mut transaction, business_name).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if form.file.len() != 0 {
|
||||||
|
let file_path = form.file.path().ok_or_else(|| {
|
||||||
|
Error::internal_server_error("Failed to get path of uploaded file")
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Read bytes from file
|
||||||
|
let file_bytes = rocket::tokio::fs::read(file_path).await?;
|
||||||
|
|
||||||
|
// Save in database
|
||||||
|
Settings::set_business_logo(&mut transaction, &file_bytes).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction.commit().await?;
|
||||||
|
|
||||||
|
Ok(Redirect::to(uri!(settings_branding)))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
{% extends "shell" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<!-- Page header -->
|
|
||||||
<div class="page-header d-print-none">
|
|
||||||
<div class="container-xl">
|
|
||||||
<div class="row g-2 align-items-center">
|
|
||||||
<div class="col">
|
|
||||||
<h2 class="page-title">
|
|
||||||
Server settings
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- Page body -->
|
|
||||||
<div class="page-body">
|
|
||||||
<div class="container-xl">
|
|
||||||
<div class="card">
|
|
||||||
<div class="row g-0">
|
|
||||||
<div class="col-3 d-none d-md-block border-end">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="list-group list-group-transparent">
|
|
||||||
<a href="." class="list-group-item list-group-item-action d-flex align-items-center active">Branding</a>
|
|
||||||
<a href="./security" class="list-group-item list-group-item-action d-flex align-items-center">Security</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col d-flex flex-column">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock content %}
|
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
{% extends "shell" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<!-- Page header -->
|
||||||
|
<div class="page-header d-print-none">
|
||||||
|
<div class="container-xl">
|
||||||
|
<div class="row g-2 align-items-center">
|
||||||
|
<div class="col">
|
||||||
|
<h2 class="page-title">
|
||||||
|
Server settings
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Page body -->
|
||||||
|
<div class="page-body">
|
||||||
|
<div class="container-xl">
|
||||||
|
<div class="card">
|
||||||
|
<div class="row g-0">
|
||||||
|
<div class="col-3 d-none d-md-block border-end">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="list-group list-group-transparent">
|
||||||
|
<a href="./branding"
|
||||||
|
class="list-group-item list-group-item-action d-flex align-items-center active">Branding</a>
|
||||||
|
<a href="./security"
|
||||||
|
class="list-group-item list-group-item-action d-flex align-items-center">Security</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col d-flex flex-column">
|
||||||
|
<form action="" method="post" enctype="multipart/form-data">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="mb-4">Branding</h2>
|
||||||
|
|
||||||
|
<h3 class="card-title">Company logo</h3>
|
||||||
|
<div class="row align-items-center">
|
||||||
|
|
||||||
|
<!-- Current logo -->
|
||||||
|
<div class="col-auto my-2">
|
||||||
|
<img src="/logo?time={{ now(timestamp=true) }}" alt="business logo" style="max-width: 13rem; padding: 1rem; background-color: white;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Update logo -->
|
||||||
|
<div class="col-auto">
|
||||||
|
<label for="file-input" class="btn">Choose File</label>
|
||||||
|
<input id="file-input" name="file" type="file" class="d-none">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Delete logo -->
|
||||||
|
<div class="col-auto">
|
||||||
|
<button class="btn btn-ghost-danger" type="submit" name="delete_logo" value="true">
|
||||||
|
Delete logo
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Business info -->
|
||||||
|
<h3 class="card-title mt-4">Business Profile</h3>
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-md">
|
||||||
|
<div class="form-label">Business Name</div>
|
||||||
|
<input type="text" class="form-control" name="business_name"
|
||||||
|
value="{{ business_name }}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Save -->
|
||||||
|
<div class="card-footer bg-transparent mt-auto">
|
||||||
|
<div class="btn-list justify-content-end">
|
||||||
|
<button class="btn" type="reset">Cancel</button>
|
||||||
|
<button class="btn btn-primary" type="submit">Submit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
<a href="/" class="navbar-brand navbar-brand-autodark">
|
<a href="/" class="navbar-brand navbar-brand-autodark">
|
||||||
<img src="/logo" alt="business logo" height="96">
|
<img src="/logo" alt="business logo" style="max-width: 13rem; padding: 1rem;">
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
<a href="/">
|
<a href="/">
|
||||||
<img src="/logo" alt="business logo" class="navbar-brand-image navbar-brand-autodark">
|
<img src="/logo" alt="business logo" style="width: 4rem;">
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,12 @@ impl Settings {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn delete_business_logo(conn: impl SqliteExecutor<'_>) -> Result<(), Error> {
|
||||||
|
DatabaseSettings::set_business_logo(conn, None).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn set_first_admin(conn: impl SqliteExecutor<'_>, id: &UserID) -> Result<(), Error> {
|
pub async fn set_first_admin(conn: impl SqliteExecutor<'_>, id: &UserID) -> Result<(), Error> {
|
||||||
DatabaseSettings::set_first_admin(conn, &id.0).await?;
|
DatabaseSettings::set_first_admin(conn, &id.0).await?;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue