aboutsummaryrefslogtreecommitdiff
path: root/server/src/routes/ui/account/settings.rs
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/routes/ui/account/settings.rs')
-rw-r--r--server/src/routes/ui/account/settings.rs103
1 files changed, 103 insertions, 0 deletions
diff --git a/server/src/routes/ui/account/settings.rs b/server/src/routes/ui/account/settings.rs
new file mode 100644
index 0000000..c95c4bb
--- /dev/null
+++ b/server/src/routes/ui/account/settings.rs
@@ -0,0 +1,103 @@
+use std::ops::Range;
+
+use rocket::{
+ form::{self, validate::len, Contextual, Form},
+ get, post, FromForm, State,
+};
+
+use super::{format_form_error, hash_password};
+use crate::{
+ database::Database,
+ routes::ui::{
+ account::session::Session,
+ error::MyResult,
+ layout::{DynLayoutPage, LayoutPage},
+ },
+ uri,
+};
+
+#[derive(FromForm)]
+pub struct SettingsForm {
+ #[field(validate = option_len(4..64))]
+ password: Option<String>,
+ #[field(validate = option_len(4..32))]
+ display_name: Option<String>,
+}
+
+fn option_len<'v>(value: &Option<String>, range: Range<usize>) -> form::Result<'v, ()> {
+ value.as_ref().map(|v| len(v, range)).unwrap_or(Ok(()))
+}
+
+fn settings_page(session: Session, flash: Option<MyResult<String>>) -> DynLayoutPage<'static> {
+ LayoutPage {
+ title: "Settings".to_string(),
+ content: markup::new! {
+ h1 { "Settings" }
+ @if let Some(flash) = &flash {
+ @match flash {
+ Ok(mesg) => { section.message { p.success { @mesg } } }
+ Err(err) => { section.message { p.error { @format!("{err}") } } }
+ }
+ }
+ h2 { "Account" }
+ form[method="POST", action=uri!(r_account_settings_post())] {
+ label[for="username"] { "Username" }
+ input[type="text", id="username", disabled, value=&session.user.name];
+ input[type="submit", disabled, value="Immutable"];
+ }
+ form[method="POST", action=uri!(r_account_settings_post())] {
+ label[for="display_name"] { "Display Name" }
+ input[type="text", id="display_name", name="display_name", value=&session.user.display_name];
+ input[type="submit", value="Update"];
+ }
+ form[method="POST", action=uri!(r_account_settings_post())] {
+ label[for="password"] { "Password" }
+ input[type="password", id="password", name="password"];
+ input[type="submit", value="Update"];
+ }
+ h2 { "Appearance" }
+ p.error { "TODO: theming" }
+ },
+ }
+}
+
+#[get("/account/settings")]
+pub fn r_account_settings(session: Session) -> DynLayoutPage<'static> {
+ settings_page(session, None)
+}
+
+#[post("/account/settings", data = "<form>")]
+pub fn r_account_settings_post(
+ session: Session,
+ database: &State<Database>,
+ form: Form<Contextual<SettingsForm>>,
+) -> MyResult<DynLayoutPage<'static>> {
+ let form = match &form.value {
+ Some(v) => v,
+ None => return Ok(settings_page(session, Some(Err(format_form_error(form))))),
+ };
+
+ let mut out = String::new();
+ database.users.fetch_and_update(&session.user.name, |k| {
+ k.map(|mut k| {
+ if let Some(password) = &form.password {
+ k.password = hash_password(&session.user.name, password);
+ out += "Password updated\n";
+ }
+ if let Some(display_name) = &form.display_name {
+ k.display_name = display_name.clone();
+ out += "Display name updated\n";
+ }
+ k
+ })
+ })?;
+
+ Ok(settings_page(
+ session,
+ Some(Ok(if out.is_empty() {
+ "Nothing changed :)".to_string()
+ } else {
+ out
+ })),
+ ))
+}