aboutsummaryrefslogtreecommitdiff
path: root/server/src/ui/account/mod.rs
blob: 448f91ea4aa6ea3b011887c8e623c7e18ad19c08 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/*
    This file is part of jellything (https://codeberg.org/metamuffin/jellything)
    which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
    Copyright (C) 2026 metamuffin <metamuffin.org>
*/
// pub mod settings;

pub mod settings;

use super::error::MyError;
use crate::{
    auth::login, request_info::RequestInfo, ui::error::MyResult, ui_responder::UiResponse,
};
use anyhow::anyhow;
use jellycommon::{VIEW_ACCOUNT_LOGIN, VIEW_ACCOUNT_LOGOUT, jellyobject::Object, routes::u_home};
use rocket::{
    FromForm,
    form::{Contextual, Form},
    get,
    http::{Cookie, CookieJar},
    post,
    response::{Flash, Redirect},
};
use serde::{Deserialize, Serialize};

#[get("/account/login")]
pub async fn r_account_login(ri: RequestInfo<'_>) -> UiResponse {
    ri.respond_ui(Object::EMPTY.insert(VIEW_ACCOUNT_LOGIN, ()))
}

#[get("/account/logout")]
pub fn r_account_logout(ri: RequestInfo<'_>) -> UiResponse {
    ri.respond_ui(Object::EMPTY.insert(VIEW_ACCOUNT_LOGOUT, ()))
}

#[derive(FromForm, Serialize, Deserialize)]
pub struct LoginForm {
    #[field(validate = len(4..32))]
    pub username: String,
    #[field(validate = len(..64))]
    pub password: String,
    #[field(default = 604800)] // one week
    pub expire: u64,
}

#[post("/account/login", data = "<form>")]
pub fn r_account_login_post(
    ri: RequestInfo<'_>,
    jar: &CookieJar,
    form: Form<Contextual<LoginForm>>,
) -> MyResult<Redirect> {
    let form = match &form.value {
        Some(v) => v,
        None => return Err(MyError(anyhow!(format_form_error(form)))),
    };
    let session = login(&ri.state, &form.username, &form.password, None)?;
    jar.add(Cookie::build(("session", session)).permanent().build());

    Ok(Redirect::found(u_home()))
}

#[post("/account/logout")]
pub fn r_account_logout_post(jar: &CookieJar) -> MyResult<Flash<Redirect>> {
    jar.remove(Cookie::build("session"));
    Ok(Flash::new(
        Redirect::found(u_home()),
        "success",
        "Logged out!",
    ))
}

pub fn format_form_error<T>(form: Form<Contextual<T>>) -> String {
    let mut k = String::from("form validation failed:");
    for e in form.context.errors() {
        k += &format!(
            "\n\t{}: {e}",
            e.name
                .as_ref()
                .map(|e| e.to_string())
                .unwrap_or("<unknown>".to_string())
        )
    }
    k
}