Implemented user authentication.
							parent
							
								
									0bac17f2eb
								
							
						
					
					
						commit
						17f628739f
					
				@ -0,0 +1,71 @@
 | 
			
		||||
use cfg_if::cfg_if;
 | 
			
		||||
cfg_if! { if #[cfg(feature = "ssr")] {
 | 
			
		||||
 | 
			
		||||
    use std::future::{Ready, ready};
 | 
			
		||||
    use actix_session::SessionExt;
 | 
			
		||||
    use actix_web::dev::{Service, ServiceRequest, ServiceResponse, Transform, forward_ready};
 | 
			
		||||
    use actix_web::Error;
 | 
			
		||||
    use actix_web::HttpResponse;
 | 
			
		||||
    use actix_web::body::EitherBody;
 | 
			
		||||
    use futures_util::future::LocalBoxFuture;
 | 
			
		||||
    use actix_web::http::header::LOCATION;
 | 
			
		||||
    use crate::backend::data::User;
 | 
			
		||||
 | 
			
		||||
    pub struct Authentication;
 | 
			
		||||
 | 
			
		||||
    impl<S, B> Transform<S, ServiceRequest> for Authentication
 | 
			
		||||
        where
 | 
			
		||||
            S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
 | 
			
		||||
            S::Future: 'static,
 | 
			
		||||
            B: 'static,
 | 
			
		||||
    {
 | 
			
		||||
        type Response = ServiceResponse<EitherBody<B>>;
 | 
			
		||||
        type Error = Error;
 | 
			
		||||
        type Transform = AuthenticationMiddleware<S>;
 | 
			
		||||
        type InitError = ();
 | 
			
		||||
        type Future = Ready<Result<Self::Transform, Self::InitError>>;
 | 
			
		||||
 | 
			
		||||
        fn new_transform(&self, service: S) -> Self::Future {
 | 
			
		||||
            ready(Ok(AuthenticationMiddleware { service }))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pub struct AuthenticationMiddleware<S> {
 | 
			
		||||
        service: S,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl<S, B> Service<ServiceRequest> for AuthenticationMiddleware<S>
 | 
			
		||||
        where
 | 
			
		||||
            S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
 | 
			
		||||
            S::Future: 'static,
 | 
			
		||||
            B: 'static,
 | 
			
		||||
    {
 | 
			
		||||
        type Response = ServiceResponse<EitherBody<B>>;
 | 
			
		||||
        type Error = Error;
 | 
			
		||||
        type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
 | 
			
		||||
 | 
			
		||||
        forward_ready!(service);
 | 
			
		||||
 | 
			
		||||
        fn call(&self, req: ServiceRequest) -> Self::Future {
 | 
			
		||||
            let session = req.get_session();
 | 
			
		||||
            let authenticate_pass = !req.path().starts_with("/admin") ||
 | 
			
		||||
                session.get::<User>("user").unwrap_or(None).is_some();
 | 
			
		||||
 | 
			
		||||
            if authenticate_pass {
 | 
			
		||||
                let res = self.service.call(req);
 | 
			
		||||
 | 
			
		||||
                Box::pin(async move {
 | 
			
		||||
                    res.await.map(ServiceResponse::map_into_left_body)
 | 
			
		||||
                })
 | 
			
		||||
            } else {
 | 
			
		||||
                let (request, _pl) = req.into_parts();
 | 
			
		||||
 | 
			
		||||
                let response = HttpResponse::Found()
 | 
			
		||||
                    .insert_header((LOCATION, "/login"))
 | 
			
		||||
                    .finish()
 | 
			
		||||
                    .map_into_right_body();
 | 
			
		||||
 | 
			
		||||
                Box::pin(async { Ok(ServiceResponse::new(request, response)) })
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}}
 | 
			
		||||
@ -0,0 +1,102 @@
 | 
			
		||||
use cfg_if::cfg_if;
 | 
			
		||||
use leptos::*;
 | 
			
		||||
 | 
			
		||||
cfg_if! { if #[cfg(feature = "ssr")] {
 | 
			
		||||
    use sqlx::{query_as, Error, PgPool, query};
 | 
			
		||||
    use actix_session::*;
 | 
			
		||||
    use leptos_actix::{extract, redirect};
 | 
			
		||||
    use crate::backend::data::User;
 | 
			
		||||
 | 
			
		||||
    pub async fn has_admin_user(pool: &PgPool) -> Result<bool, Error> {
 | 
			
		||||
        let count: (i64,) = query_as(r#"SELECT COUNT(id) FROM "user" WHERE admin = $1"#)
 | 
			
		||||
            .bind(true)
 | 
			
		||||
            .fetch_one(pool)
 | 
			
		||||
            .await?;
 | 
			
		||||
 | 
			
		||||
        Ok(count.0 > 0)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn create_admin(pool: &PgPool) -> Result<(), Error> {
 | 
			
		||||
        if !has_admin_user(pool).await? {
 | 
			
		||||
            let pwd = pwhash::bcrypt::hash("admin");
 | 
			
		||||
            query(r#"INSERT INTO "user"(login, password, full_name, admin) VALUES($1, $2, $3, $4)"#)
 | 
			
		||||
                .bind("admin")
 | 
			
		||||
                .bind(pwd.unwrap())
 | 
			
		||||
                .bind("Admin User")
 | 
			
		||||
                .bind(true)
 | 
			
		||||
                .execute(pool).await?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn user_from_login(pool: &PgPool, login: &str) -> Result<User, Error> {
 | 
			
		||||
        let usr = query_as::<_, User>(r#"SELECT * FROM "user" WHERE login=$1"#)
 | 
			
		||||
            .bind(login)
 | 
			
		||||
            .fetch_one(pool).await?;
 | 
			
		||||
        Ok(usr)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn logged_in_user() -> Option<User> {
 | 
			
		||||
        extract(|session: Session| async move {
 | 
			
		||||
            session.get::<User>("user").unwrap_or(None)
 | 
			
		||||
        }).await.unwrap_or(None)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn is_logged_in() -> bool {
 | 
			
		||||
        logged_in_user().await.is_some()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn is_admin() -> bool {
 | 
			
		||||
        if let Some(user) = logged_in_user().await {
 | 
			
		||||
            user.admin
 | 
			
		||||
        } else {
 | 
			
		||||
            false
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}}
 | 
			
		||||
 | 
			
		||||
#[server(Login, "/api")]
 | 
			
		||||
pub async fn login(username: String, password: String) -> Result<(), ServerFnError> {
 | 
			
		||||
    use crate::backend::AppData;
 | 
			
		||||
    use actix_session::*;
 | 
			
		||||
    use actix_web::web::Data;
 | 
			
		||||
    use leptos_actix::extract;
 | 
			
		||||
 | 
			
		||||
    let pool = extract(|data: Data<AppData>| async move { data.db_pool().clone() }).await?;
 | 
			
		||||
 | 
			
		||||
    let user = user_from_login(&pool, &username).await?;
 | 
			
		||||
 | 
			
		||||
    if pwhash::bcrypt::verify(password, &user.password) {
 | 
			
		||||
        extract(|session: Session| async move {
 | 
			
		||||
            let _ = session.insert("user", user);
 | 
			
		||||
        })
 | 
			
		||||
            .await?;
 | 
			
		||||
 | 
			
		||||
        redirect("/admin");
 | 
			
		||||
        return Ok(());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Err(ServerFnError::ServerError("Bad login".to_string()))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[server]
 | 
			
		||||
pub async fn logout() -> Result<(), ServerFnError> {
 | 
			
		||||
    extract(|session: Session| async move {
 | 
			
		||||
        session.clear();
 | 
			
		||||
    }).await?;
 | 
			
		||||
 | 
			
		||||
    redirect("/login");
 | 
			
		||||
    
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[server]
 | 
			
		||||
pub async fn auth_check() -> Result<bool, ServerFnError> {
 | 
			
		||||
    Ok(is_logged_in().await)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[server]
 | 
			
		||||
pub async fn admin_check() -> Result<bool, ServerFnError> {
 | 
			
		||||
    Ok(is_admin().await)
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,140 @@
 | 
			
		||||
use leptos::*;
 | 
			
		||||
use crate::locales::trl;
 | 
			
		||||
 | 
			
		||||
#[component]
 | 
			
		||||
pub fn AdminPortal(children: Children) -> impl IntoView {
 | 
			
		||||
    view! {
 | 
			
		||||
        <div class="layout-wrapper layout-content-navbar">
 | 
			
		||||
            <div class="layout-container">
 | 
			
		||||
        //<!-- Menu -->
 | 
			
		||||
 | 
			
		||||
                <aside id="layout-menu" class="layout-menu menu-vertical menu bg-menu-theme">
 | 
			
		||||
                    <div class="app-brand demo">
 | 
			
		||||
                        <a href="javascript:void(0);" class="layout-menu-toggle menu-link text-large ms-auto d-block d-xl-none">
 | 
			
		||||
                            <i class="bx bx-chevron-left bx-sm align-middle"></i>
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="menu-inner-shadow"></div>
 | 
			
		||||
 | 
			
		||||
                    <ul class="menu-inner py-1">
 | 
			
		||||
                        //<!-- Dashboard -->
 | 
			
		||||
                        <li class="menu-item">
 | 
			
		||||
                            <a href="/admin" class="menu-link">
 | 
			
		||||
                                <i class="menu-icon tf-icons bx bx-home-circle"></i>
 | 
			
		||||
                                <div data-i18n="Analytics">{trl("Dashboard")}</div>
 | 
			
		||||
                            </a>
 | 
			
		||||
                        </li>
 | 
			
		||||
                        <li class="menu-item">
 | 
			
		||||
                            <a href="/" class="menu-link">
 | 
			
		||||
                                <i class="menu-icon tf-icons bx bx-time"></i>
 | 
			
		||||
                                <div data-i18n="Analytics">"Opening hours"</div>
 | 
			
		||||
                            </a>
 | 
			
		||||
                        </li>
 | 
			
		||||
                        <li class="menu-item">
 | 
			
		||||
                            <a href="/" class="menu-link">
 | 
			
		||||
                                <i class="menu-icon tf-icons bx bx-layer"></i>
 | 
			
		||||
                                <div data-i18n="Analytics">"Places"</div>
 | 
			
		||||
                            </a>
 | 
			
		||||
                        </li>
 | 
			
		||||
                        <li class="menu-item">
 | 
			
		||||
                            <a href="/" class="menu-link">
 | 
			
		||||
                                <i class="menu-icon tf-icons bx bx-info-circle"></i>
 | 
			
		||||
                                <div data-i18n="Analytics">"About"</div>
 | 
			
		||||
                            </a>
 | 
			
		||||
                        </li>
 | 
			
		||||
                    </ul>
 | 
			
		||||
                </aside>
 | 
			
		||||
                //<!-- Layout container -->
 | 
			
		||||
                <div class="layout-page">
 | 
			
		||||
                    //<!-- Navbar -->
 | 
			
		||||
 | 
			
		||||
                      <nav
 | 
			
		||||
                        class="layout-navbar container-xxl navbar navbar-expand-xl navbar-detached align-items-center bg-navbar-theme"
 | 
			
		||||
                        id="layout-navbar">
 | 
			
		||||
                        <div class="layout-menu-toggle navbar-nav align-items-xl-center me-3 me-xl-0 d-xl-none">
 | 
			
		||||
                          <a class="nav-item nav-link px-0 me-xl-4" href="javascript:void(0)">
 | 
			
		||||
                            <i class="bx bx-menu bx-sm"></i>
 | 
			
		||||
                          </a>
 | 
			
		||||
                        </div>
 | 
			
		||||
 | 
			
		||||
                        <div class="navbar-nav-right d-flex align-items-center" id="navbar-collapse">
 | 
			
		||||
                          //<!-- Search -->
 | 
			
		||||
                          <div class="navbar-nav align-items-center ms-auto mt-auto">
 | 
			
		||||
                            <div class="nav-item d-flex align-items-center mt-auto">
 | 
			
		||||
                              <h4 class="mt-3"><i class="bx bx-desktop fs-4 lh-0"></i>" Admin portal"</h4>
 | 
			
		||||
                            </div>
 | 
			
		||||
                          </div>
 | 
			
		||||
                          //<!-- /Search -->
 | 
			
		||||
                          <ul class="navbar-nav flex-row align-items-center ms-auto">
 | 
			
		||||
                            <li class="nav-item navbar-dropdown dropdown-user dropdown">
 | 
			
		||||
                              <a class="nav-link dropdown-toggle hide-arrow" href="/admin/settings" data-bs-toggle="dropdown">
 | 
			
		||||
                              <i class="bx bx-cog fs-3 lh-0"></i>
 | 
			
		||||
                                </a>
 | 
			
		||||
                            </li>
 | 
			
		||||
                            //<!-- User -->
 | 
			
		||||
                            <li class="nav-item navbar-dropdown dropdown-user dropdown">
 | 
			
		||||
                              <a class="nav-link dropdown-toggle hide-arrow" href="#" data-bs-toggle="dropdown">
 | 
			
		||||
                                //<div class="avatar avatar-online">
 | 
			
		||||
                                //  <img src="/img/avatars/1.png" alt class="w-px-40 h-auto rounded-circle" />
 | 
			
		||||
                                //</div>
 | 
			
		||||
                                <i class="bx bx-user fs-3 lh-0"></i>
 | 
			
		||||
                              </a>
 | 
			
		||||
                              <ul class="dropdown-menu dropdown-menu-end">
 | 
			
		||||
                                <li>
 | 
			
		||||
                                  <a class="dropdown-item" href="#">
 | 
			
		||||
                                    <div class="d-flex">
 | 
			
		||||
                                      <div class="flex-shrink-0 me-3">
 | 
			
		||||
                                        <div class="avatar avatar-online">
 | 
			
		||||
                                          <img src="/img/avatars/1.png" alt class="w-px-40 h-auto rounded-circle" />
 | 
			
		||||
                                        </div>
 | 
			
		||||
                                      </div>
 | 
			
		||||
                                      <div class="flex-grow-1">
 | 
			
		||||
                                        <span class="fw-semibold d-block">"John Doe"</span>
 | 
			
		||||
                                        <small class="text-muted">"Admin"</small>
 | 
			
		||||
                                      </div>
 | 
			
		||||
                                    </div>
 | 
			
		||||
                                  </a>
 | 
			
		||||
                                </li>
 | 
			
		||||
                                <li>
 | 
			
		||||
                                  <div class="dropdown-divider"></div>
 | 
			
		||||
                                </li>
 | 
			
		||||
                                <li>
 | 
			
		||||
                                  <a class="dropdown-item" href="#">
 | 
			
		||||
                                    <i class="bx bx-user me-2"></i>
 | 
			
		||||
                                    <span class="align-middle">"My Profile"</span>
 | 
			
		||||
                                  </a>
 | 
			
		||||
                                </li>
 | 
			
		||||
                                <li>
 | 
			
		||||
                                  <a class="dropdown-item" href="#">
 | 
			
		||||
                                    <i class="bx bx-cog me-2"></i>
 | 
			
		||||
                                    <span class="align-middle">"Settings"</span>
 | 
			
		||||
                                  </a>
 | 
			
		||||
                                </li>
 | 
			
		||||
                                <li>
 | 
			
		||||
                                  <div class="dropdown-divider"></div>
 | 
			
		||||
                                </li>
 | 
			
		||||
                                <li>
 | 
			
		||||
                                  <a class="dropdown-item" href="auth-login-basic.html">
 | 
			
		||||
                                    <i class="bx bx-power-off me-2"></i>
 | 
			
		||||
                                    <span class="align-middle">"Log Out"</span>
 | 
			
		||||
                                  </a>
 | 
			
		||||
                                </li>
 | 
			
		||||
                              </ul>
 | 
			
		||||
                            </li>
 | 
			
		||||
                            //<!--/ User -->
 | 
			
		||||
                          </ul>
 | 
			
		||||
                        </div>
 | 
			
		||||
                      </nav>
 | 
			
		||||
 | 
			
		||||
                //<!-- Content wrapper -->
 | 
			
		||||
                <div class="content-wrapper">
 | 
			
		||||
                    //<!-- Content -->
 | 
			
		||||
                    <div class="container-xxl flex-grow-1 container-p-y">
 | 
			
		||||
                    {children()}
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,38 @@
 | 
			
		||||
use leptos::*;
 | 
			
		||||
use leptos_meta::*;
 | 
			
		||||
 | 
			
		||||
#[component]
 | 
			
		||||
pub fn Header() -> impl IntoView {
 | 
			
		||||
    view! {
 | 
			
		||||
        <Html
 | 
			
		||||
            lang="cz"
 | 
			
		||||
            dir="ltr"
 | 
			
		||||
            attributes=AdditionalAttributes::from(vec![
 | 
			
		||||
                ("data-theme", "theme-default"),
 | 
			
		||||
                ("class", "light-style layout-menu-fixed"),
 | 
			
		||||
                ("data-template", "vertical-menu-template-free"),
 | 
			
		||||
                ("data-assets-path", "/")])
 | 
			
		||||
        />
 | 
			
		||||
        <Meta charset="utf-8"/>
 | 
			
		||||
        <Meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"/>
 | 
			
		||||
 | 
			
		||||
        //<!-- Fonts -->
 | 
			
		||||
        <Link rel="preconnect" href="https://fonts.googleapis.com" />
 | 
			
		||||
        <Link rel="preconnect" href="https://fonts.gstatic.com" />
 | 
			
		||||
        <Link
 | 
			
		||||
            href="https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap"
 | 
			
		||||
            rel="stylesheet"
 | 
			
		||||
        />
 | 
			
		||||
 | 
			
		||||
        //<!-- Icons. Uncomment required icon fonts -->
 | 
			
		||||
        <Link rel="stylesheet" href="/vendor/fonts/boxicons.css" />
 | 
			
		||||
 | 
			
		||||
        //<!-- Core CSS -->
 | 
			
		||||
        <Link rel="stylesheet" href="/vendor/css/core.css" />
 | 
			
		||||
        <Link rel="stylesheet" href="/vendor/css/theme-default.css" />
 | 
			
		||||
        <Link rel="stylesheet" href="/css/demo.css" />
 | 
			
		||||
 | 
			
		||||
        //<!-- Vendors CSS -->
 | 
			
		||||
        <Link rel="stylesheet" href="/vendor/libs/perfect-scrollbar/perfect-scrollbar.css" />
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,4 +1,6 @@
 | 
			
		||||
pub mod modal_box;
 | 
			
		||||
pub mod server_err;
 | 
			
		||||
pub mod validation_err;
 | 
			
		||||
pub mod header;
 | 
			
		||||
pub mod admin_portal;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,74 @@
 | 
			
		||||
use leptos::*;
 | 
			
		||||
use leptos_meta::*;
 | 
			
		||||
use leptos_router::ActionForm;
 | 
			
		||||
use crate::backend::user::Login;
 | 
			
		||||
 | 
			
		||||
#[component]
 | 
			
		||||
pub fn Login() -> impl IntoView {
 | 
			
		||||
    let login = create_server_action::<Login>();
 | 
			
		||||
 | 
			
		||||
    view! {
 | 
			
		||||
      <Link rel="stylesheet" href="/vendor/css/pages/page-auth.css" />
 | 
			
		||||
      <div class="authentication-wrapper authentication-basic container-p-y">
 | 
			
		||||
        <div class="authentication-inner">
 | 
			
		||||
 | 
			
		||||
          <div class="card">
 | 
			
		||||
            <div class="card-body">
 | 
			
		||||
              //<!-- Logo -->
 | 
			
		||||
              <div class="app-brand justify-content-center">
 | 
			
		||||
                <a href="index.html" class="app-brand-link gap-2">
 | 
			
		||||
                  <span class="app-brand-logo demo">
 | 
			
		||||
 | 
			
		||||
                  </span>
 | 
			
		||||
                  //<span class="app-brand-text demo text-body fw-bolder">Sneat</span>
 | 
			
		||||
                </a>
 | 
			
		||||
              </div>
 | 
			
		||||
              //<!-- /Logo -->
 | 
			
		||||
              <h4 class="mb-2">"Welcome to Rezervator 👋"</h4>
 | 
			
		||||
              <p class="mb-4">"Please sign-in to your account and start the adventure"</p>
 | 
			
		||||
 | 
			
		||||
              <ActionForm action=login>
 | 
			
		||||
                <div class="mb-3">
 | 
			
		||||
                  <label for="username" class="form-label">"Username"</label>
 | 
			
		||||
                  <input
 | 
			
		||||
                    type="text"
 | 
			
		||||
                    class="form-control"
 | 
			
		||||
                    id="username"
 | 
			
		||||
                    name="username"
 | 
			
		||||
                    placeholder="Enter your username"
 | 
			
		||||
                    autofocus
 | 
			
		||||
                  />
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="mb-3 form-password-toggle">
 | 
			
		||||
                  <div class="d-flex justify-content-between">
 | 
			
		||||
                    <label class="form-label" for="password">"Password"</label>
 | 
			
		||||
                    <a href="auth-forgot-password-basic.html">
 | 
			
		||||
                      <small>"Forgot Password?"</small>
 | 
			
		||||
                    </a>
 | 
			
		||||
                  </div>
 | 
			
		||||
                  <div class="input-group input-group-merge">
 | 
			
		||||
                    <input
 | 
			
		||||
                      type="password"
 | 
			
		||||
                      id="password"
 | 
			
		||||
                      class="form-control"
 | 
			
		||||
                      name="password"
 | 
			
		||||
                      aria-describedby="password"
 | 
			
		||||
                    />
 | 
			
		||||
                    <span class="input-group-text cursor-pointer"><i class="bx bx-hide"></i></span>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="mb-3">
 | 
			
		||||
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="mb-3">
 | 
			
		||||
                  <button class="btn btn-primary d-grid w-100" type="submit">"Sign in"</button>
 | 
			
		||||
                </div>
 | 
			
		||||
              </ActionForm>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,8 @@
 | 
			
		||||
use leptos::*;
 | 
			
		||||
 | 
			
		||||
#[component]
 | 
			
		||||
pub fn Public() -> impl IntoView {
 | 
			
		||||
    view! {
 | 
			
		||||
        <div>"public"</div>
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,33 +0,0 @@
 | 
			
		||||
use leptos::*;
 | 
			
		||||
 | 
			
		||||
#[server(SetSession, "/api", "Url", "set_session")]
 | 
			
		||||
pub async fn set_session() -> Result<(), ServerFnError> {
 | 
			
		||||
    use leptos_actix::extract;
 | 
			
		||||
    use actix_session::*;
 | 
			
		||||
    use actix_web::web::Data;
 | 
			
		||||
    use leptos::logging::log;
 | 
			
		||||
    //use crate::DataPok;
 | 
			
		||||
 | 
			
		||||
    extract(|session: Session| async move {
 | 
			
		||||
        log!("extract");
 | 
			
		||||
        let pok = session.insert("user", "uzivatel");
 | 
			
		||||
        log!("{pok:?}");
 | 
			
		||||
    }).await
 | 
			
		||||
 | 
			
		||||
    //Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[server(GetSession, "/api")]
 | 
			
		||||
pub async fn get_session() -> Result<(), ServerFnError> {
 | 
			
		||||
    use leptos_actix::extract;
 | 
			
		||||
    use actix_session::*;
 | 
			
		||||
    use leptos::logging::log;
 | 
			
		||||
 | 
			
		||||
    extract(|session: Session| async move {
 | 
			
		||||
        log!("extract");
 | 
			
		||||
        let pok = session.get::<String>("user");
 | 
			
		||||
        log!("{pok:?}");
 | 
			
		||||
    }).await
 | 
			
		||||
 | 
			
		||||
    //Ok(())
 | 
			
		||||
}
 | 
			
		||||
					Loading…
					
					
				
		Reference in New Issue