flams_router_login/
server_fns.rs

1use flams_database::{LoginError, UserData};
2use flams_router_base::LoginState;
3use leptos::prelude::*;
4
5#[server(prefix = "/api", endpoint = "login")]
6pub async fn login(
7    admin_pwd: Option<String>,
8) -> Result<Option<LoginState>, ServerFnError<LoginError>> {
9    ssr::login(admin_pwd).await
10}
11
12#[server(prefix = "/api", endpoint = "logout")]
13pub async fn logout() -> Result<(), ServerFnError<LoginError>> {
14    ssr::logout().await
15}
16
17#[server(LoginStateFn, prefix = "/api", endpoint = "login_state")]
18#[allow(clippy::unused_async)]
19pub async fn login_state() -> Result<LoginState, ServerFnError<String>> {
20    Ok(LoginState::get_server())
21}
22
23#[server(prefix = "/api", endpoint = "get_users")]
24pub async fn get_users() -> Result<Vec<UserData>, ServerFnError<LoginError>> {
25    ssr::get_users().await
26}
27
28#[server(prefix = "/api", endpoint = "set_admin")]
29pub async fn set_admin(user_id: i64, is_admin: bool) -> Result<(), ServerFnError<LoginError>> {
30    ssr::set_admin(user_id, is_admin).await
31}
32
33#[cfg(feature = "ssr")]
34mod ssr {
35    use flams_database::{DBBackend, LoginError, UserData};
36    use flams_git::gl::auth::GitLabOAuth;
37    use flams_router_base::LoginState;
38    use leptos::prelude::*;
39
40    pub(super) async fn login(
41        admin_pwd: Option<String>,
42    ) -> Result<Option<LoginState>, ServerFnError<LoginError>> {
43        let Some(session) = use_context::<axum_login::AuthSession<DBBackend>>() else {
44            return Ok(Some(LoginState::None));
45        };
46        if session.backend.admin.is_none() {
47            return Ok(Some(LoginState::NoAccounts));
48        }
49        if let Some(password) = admin_pwd {
50            return if DBBackend::login_as_admin(&password, session).await.is_ok() {
51                Ok(Some(LoginState::Admin))
52            } else {
53                Err(LoginError::WrongUsernameOrPassword.into())
54            };
55        }
56        let oauth: Option<GitLabOAuth> = expect_context();
57        if let Some(oauth) = oauth.as_ref() {
58            leptos_axum::redirect(oauth.login_url().as_str());
59        } else {
60            leptos_axum::redirect("/dashboard");
61        }
62        Ok(None)
63    }
64
65    pub async fn logout() -> Result<(), ServerFnError<LoginError>> {
66        let Some(mut session) = use_context::<axum_login::AuthSession<DBBackend>>() else {
67            return Ok(());
68        };
69        let _ = session.logout().await;
70        leptos_axum::redirect("/dashboard");
71        Ok(())
72    }
73
74    pub(super) async fn get_users() -> Result<Vec<UserData>, ServerFnError<LoginError>> {
75        match LoginState::get_server() {
76            LoginState::Admin | LoginState::NoAccounts => (),
77            _ => return Err(ServerFnError::WrappedServerError(LoginError::NotLoggedIn)),
78        }
79        let Some(session) = use_context::<axum_login::AuthSession<DBBackend>>() else {
80            return Ok(Vec::new());
81        };
82        let users = session
83            .backend
84            .all_users()
85            .await
86            .map_err(|_| ServerFnError::WrappedServerError(LoginError::NotLoggedIn))?;
87        let mut users: Vec<_> = users.into_iter().map(UserData::from).collect();
88        users.sort_by_key(|e| e.id);
89        Ok(users)
90    }
91
92    pub async fn set_admin(user_id: i64, is_admin: bool) -> Result<(), ServerFnError<LoginError>> {
93        match LoginState::get_server() {
94            LoginState::Admin | LoginState::NoAccounts => (),
95            _ => return Err(ServerFnError::WrappedServerError(LoginError::NotLoggedIn)),
96        }
97        let Some(session) = use_context::<axum_login::AuthSession<DBBackend>>() else {
98            return Ok(());
99        };
100        session
101            .backend
102            .set_admin(user_id, is_admin)
103            .await
104            .map_err(|_| ServerFnError::WrappedServerError(LoginError::NotLoggedIn))?;
105        Ok(())
106    }
107}