feat: creation and display of availabillies work
This commit is contained in:
parent
497e6fbf6c
commit
8840f0ab48
30
Cargo.lock
generated
30
Cargo.lock
generated
@ -648,6 +648,7 @@ dependencies = [
|
|||||||
"askama_actix",
|
"askama_actix",
|
||||||
"chrono",
|
"chrono",
|
||||||
"dotenv",
|
"dotenv",
|
||||||
|
"futures-util",
|
||||||
"serde",
|
"serde",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
]
|
]
|
||||||
@ -995,9 +996,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-core"
|
name = "futures-core"
|
||||||
version = "0.3.28"
|
version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
|
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-intrusive"
|
name = "futures-intrusive"
|
||||||
@ -1031,6 +1032,17 @@ dependencies = [
|
|||||||
"waker-fn",
|
"waker-fn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-macro"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.18",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-rustls"
|
name = "futures-rustls"
|
||||||
version = "0.22.2"
|
version = "0.22.2"
|
||||||
@ -1044,27 +1056,29 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-sink"
|
name = "futures-sink"
|
||||||
version = "0.3.28"
|
version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
|
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-task"
|
name = "futures-task"
|
||||||
version = "0.3.28"
|
version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
|
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-util"
|
name = "futures-util"
|
||||||
version = "0.3.28"
|
version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
|
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"futures-macro",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"futures-task",
|
"futures-task",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"pin-utils",
|
"pin-utils",
|
||||||
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -18,3 +18,4 @@ actix-identity = "0.5.2"
|
|||||||
chrono = { version = "0.4.33", features = ["serde"] }
|
chrono = { version = "0.4.33", features = ["serde"] }
|
||||||
actix-files = "0.6.5"
|
actix-files = "0.6.5"
|
||||||
askama_actix = "0.14.0"
|
askama_actix = "0.14.0"
|
||||||
|
futures-util = "0.3.30"
|
||||||
|
@ -37,7 +37,8 @@ CREATE TABLE availabillity
|
|||||||
userId INTEGER NOT NULL REFERENCES user_ (id),
|
userId INTEGER NOT NULL REFERENCES user_ (id),
|
||||||
date DATE NOT NULL,
|
date DATE NOT NULL,
|
||||||
startTime TIME,
|
startTime TIME,
|
||||||
endTime TIME
|
endTime TIME,
|
||||||
|
comment TEXT
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE event
|
CREATE TABLE event
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
pub mod routes;
|
pub mod routes;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
pub mod redirect;
|
||||||
|
|
||||||
pub use routes::init;
|
pub use routes::init;
|
||||||
|
70
src/auth/redirect.rs
Normal file
70
src/auth/redirect.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
use std::future::{ready, Ready};
|
||||||
|
|
||||||
|
use actix_identity::IdentityExt;
|
||||||
|
use actix_web::{
|
||||||
|
body::EitherBody,
|
||||||
|
dev::{self, Service, ServiceRequest, ServiceResponse, Transform},
|
||||||
|
http, Error, HttpResponse,
|
||||||
|
};
|
||||||
|
use futures_util::future::LocalBoxFuture;
|
||||||
|
|
||||||
|
pub struct CheckLogin;
|
||||||
|
|
||||||
|
impl<S, B> Transform<S, ServiceRequest> for CheckLogin
|
||||||
|
where
|
||||||
|
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||||
|
S::Future: 'static,
|
||||||
|
B: 'static,
|
||||||
|
{
|
||||||
|
type Response = ServiceResponse<EitherBody<B>>;
|
||||||
|
type Error = Error;
|
||||||
|
type InitError = ();
|
||||||
|
type Transform = CheckLoginMiddleware<S>;
|
||||||
|
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
||||||
|
|
||||||
|
fn new_transform(&self, service: S) -> Self::Future {
|
||||||
|
ready(Ok(CheckLoginMiddleware { service }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub struct CheckLoginMiddleware<S> {
|
||||||
|
service: S,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, B> Service<ServiceRequest> for CheckLoginMiddleware<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>>;
|
||||||
|
|
||||||
|
dev::forward_ready!(service);
|
||||||
|
|
||||||
|
fn call(&self, request: ServiceRequest) -> Self::Future {
|
||||||
|
// Change this to see the change in outcome in the browser.
|
||||||
|
// Usually this boolean would be acquired from a password check or other auth verification.
|
||||||
|
let is_logged_in = request.get_identity().is_ok();
|
||||||
|
|
||||||
|
// Don't forward to `/login` if we are already on `/login`.
|
||||||
|
if !is_logged_in && request.path() != "/login" && !request.path().starts_with("/static") {
|
||||||
|
let (request, _pl) = request.into_parts();
|
||||||
|
|
||||||
|
let response = HttpResponse::Found()
|
||||||
|
.insert_header((http::header::LOCATION, "/login"))
|
||||||
|
.finish()
|
||||||
|
// constructed responses map to "right" body
|
||||||
|
.map_into_right_body();
|
||||||
|
|
||||||
|
return Box::pin(async { Ok(ServiceResponse::new(request, response)) });
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = self.service.call(request);
|
||||||
|
|
||||||
|
Box::pin(async move {
|
||||||
|
// forwarded responses map to "left" body
|
||||||
|
res.await.map(ServiceResponse::map_into_left_body)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
pub mod routes;
|
pub mod routes;
|
||||||
mod get_availabillity_new;
|
mod get_availabillity_new;
|
||||||
|
mod post_availabillity;
|
||||||
|
|
||||||
pub use routes::init;
|
pub use routes::init;
|
||||||
|
34
src/calendar/post_availabillity.rs
Normal file
34
src/calendar/post_availabillity.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use actix_identity::Identity;
|
||||||
|
use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
|
||||||
|
use chrono::{NaiveDate, NaiveTime};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use sqlx::PgPool;
|
||||||
|
|
||||||
|
use crate::models::{availabillity::Availabillity, user::User};
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct AvailabillityForm {
|
||||||
|
date: NaiveDate,
|
||||||
|
start_time: Option<NaiveTime>,
|
||||||
|
end_time: Option<NaiveTime>,
|
||||||
|
comment: Option<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_web::post("/availabillity/new")]
|
||||||
|
pub async fn post_availabillity(
|
||||||
|
user: Identity,
|
||||||
|
pool: web::Data<PgPool>,
|
||||||
|
form: web::Form<AvailabillityForm>,
|
||||||
|
) -> impl Responder {
|
||||||
|
let current_user = User::read_by_id(pool.as_ref(), user.id().unwrap().parse().unwrap())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if let Ok(_) = Availabillity::create(pool.get_ref(), current_user.id, form.date, form.start_time, form.end_time, form.comment.clone()).await {
|
||||||
|
HttpResponse::Found()
|
||||||
|
.insert_header((LOCATION, "/"))
|
||||||
|
.finish()
|
||||||
|
} else {
|
||||||
|
HttpResponse::BadRequest().body("Fehler beim erstellen")
|
||||||
|
}
|
||||||
|
}
|
@ -9,12 +9,12 @@ use crate::models::{
|
|||||||
area::Area, availabillity::Availabillity, event::Event, role::Role, user::User,
|
area::Area, availabillity::Availabillity, event::Event, role::Role, user::User,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::get_availabillity_new::get_availabillity_new;
|
use super::{get_availabillity_new::get_availabillity_new, post_availabillity::post_availabillity};
|
||||||
|
|
||||||
|
|
||||||
pub fn init(cfg: &mut web::ServiceConfig) {
|
pub fn init(cfg: &mut web::ServiceConfig) {
|
||||||
cfg.service(get_index);
|
cfg.service(get_index);
|
||||||
cfg.service(get_availabillity_new);
|
cfg.service(get_availabillity_new);
|
||||||
|
cfg.service(post_availabillity);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
@ -34,38 +34,36 @@ struct CalendarTemplate {
|
|||||||
|
|
||||||
#[actix_web::get("/")]
|
#[actix_web::get("/")]
|
||||||
async fn get_index(
|
async fn get_index(
|
||||||
user: Option<Identity>,
|
user: Identity,
|
||||||
pool: web::Data<PgPool>,
|
pool: web::Data<PgPool>,
|
||||||
query: web::Query<CalendarQuery>,
|
query: web::Query<CalendarQuery>,
|
||||||
) -> impl Responder {
|
) -> impl Responder {
|
||||||
if let Some(user) = user {
|
let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap())
|
||||||
let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap())
|
.await
|
||||||
.await
|
.unwrap();
|
||||||
.unwrap();
|
let date = match query.date {
|
||||||
let date = match query.date {
|
Some(given_date) => given_date,
|
||||||
Some(given_date) => given_date,
|
None => Utc::now().date_naive(),
|
||||||
None => Utc::now().date_naive(),
|
};
|
||||||
};
|
let area = Area::read_by_id(pool.get_ref(), current_user.area_id)
|
||||||
let area = Area::read_by_id(pool.get_ref(), current_user.area_id)
|
.await
|
||||||
.await
|
.unwrap();
|
||||||
.unwrap();
|
let events = Event::read_by_date(pool.get_ref(), date).await.unwrap();
|
||||||
let events = Event::read_by_date(pool.get_ref(), date).await.unwrap();
|
let mut availabillities = Availabillity::read_by_date(pool.get_ref(), date)
|
||||||
let availabillities = Availabillity::read_by_date(pool.get_ref(), date)
|
.await
|
||||||
.await
|
.unwrap();
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let template = CalendarTemplate {
|
for avl in availabillities.iter_mut() {
|
||||||
user_role: current_user.role,
|
avl.load_user(pool.get_ref()).await.unwrap()
|
||||||
date,
|
|
||||||
area,
|
|
||||||
events,
|
|
||||||
availabillities,
|
|
||||||
};
|
|
||||||
|
|
||||||
HttpResponse::Ok().body(template.render().unwrap())
|
|
||||||
} else {
|
|
||||||
HttpResponse::PermanentRedirect()
|
|
||||||
.insert_header((LOCATION, "/login"))
|
|
||||||
.finish()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let template = CalendarTemplate {
|
||||||
|
user_role: current_user.role,
|
||||||
|
date,
|
||||||
|
area,
|
||||||
|
events,
|
||||||
|
availabillities,
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpResponse::Ok().body(template.render().unwrap())
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ use actix_web::{web, App, HttpServer};
|
|||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
use sqlx::postgres::PgPool;
|
use sqlx::postgres::PgPool;
|
||||||
|
|
||||||
|
use crate::auth::redirect;
|
||||||
mod auth;
|
mod auth;
|
||||||
mod calendar;
|
mod calendar;
|
||||||
mod models;
|
mod models;
|
||||||
@ -24,12 +25,13 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
.app_data(web::Data::new(pool.clone()))
|
.app_data(web::Data::new(pool.clone()))
|
||||||
.configure(auth::init)
|
.configure(auth::init)
|
||||||
.configure(calendar::init)
|
.configure(calendar::init)
|
||||||
|
.wrap(redirect::CheckLogin)
|
||||||
.wrap(IdentityMiddleware::default())
|
.wrap(IdentityMiddleware::default())
|
||||||
.wrap(SessionMiddleware::new(
|
.wrap(SessionMiddleware::new(
|
||||||
CookieSessionStore::default(),
|
CookieSessionStore::default(),
|
||||||
secret_key.clone(),
|
secret_key.clone(),
|
||||||
))
|
))
|
||||||
.service(actix_files::Files::new("", "./static").show_files_listing())
|
.service(actix_files::Files::new("/static", "./static").show_files_listing())
|
||||||
})
|
})
|
||||||
.bind(("127.0.0.1", 8080))?
|
.bind(("127.0.0.1", 8080))?
|
||||||
.run()
|
.run()
|
||||||
|
@ -1,25 +1,41 @@
|
|||||||
use chrono::{NaiveDate, NaiveTime};
|
use chrono::{NaiveDate, NaiveTime};
|
||||||
use sqlx::{query, PgPool};
|
use sqlx::{query, PgPool};
|
||||||
|
|
||||||
|
use super::user::User;
|
||||||
|
|
||||||
pub struct Availabillity {
|
pub struct Availabillity {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub user_id: i32,
|
pub user_id: i32,
|
||||||
|
pub user: Option<User>,
|
||||||
pub date: NaiveDate,
|
pub date: NaiveDate,
|
||||||
pub start_time: Option<NaiveTime>,
|
pub start_time: Option<NaiveTime>,
|
||||||
pub end_time: Option<NaiveTime>
|
pub end_time: Option<NaiveTime>,
|
||||||
|
pub comment: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Availabillity {
|
impl Availabillity {
|
||||||
pub async fn create(pool: &PgPool, user_id: i32, date: NaiveDate, start_time: Option<NaiveTime>, end_time: Option<NaiveTime>) -> anyhow::Result<i32> {
|
pub async fn create(
|
||||||
let mut result = match (start_time, end_time) {
|
pool: &PgPool,
|
||||||
(Some(start_time), Some(end_time)) => query!("INSERT INTO availabillity (userId, date, startTime, endTime) VALUES ($1, $2, $3, $4) RETURNING id;", user_id, date, start_time, end_time).fetch_one(pool).await?.id,
|
user_id: i32,
|
||||||
(_, _) => query!("INSERT INTO availabillity (userId, date) VALUES ($1, $2) RETURNING id;", user_id, date).fetch_one(pool).await?.id
|
date: NaiveDate,
|
||||||
|
start_time: Option<NaiveTime>,
|
||||||
|
end_time: Option<NaiveTime>,
|
||||||
|
comment: Option<String>,
|
||||||
|
) -> anyhow::Result<i32> {
|
||||||
|
let result = match (start_time, end_time, comment) {
|
||||||
|
(Some(start_time), Some(end_time), Some(comment)) => query!("INSERT INTO availabillity (userId, date, startTime, endTime, comment) VALUES ($1, $2, $3, $4, $5) RETURNING id;", user_id, date, start_time, end_time, comment).fetch_one(pool).await?.id,
|
||||||
|
(Some(start_time), Some(end_time), None) => query!("INSERT INTO availabillity (userId, date, startTime, endTime) VALUES ($1, $2, $3, $4) RETURNING id;", user_id, date, start_time, end_time).fetch_one(pool).await?.id,
|
||||||
|
(None, None, Some(comment)) => query!("INSERT INTO availabillity (userId, date, comment) VALUES ($1, $2, $3) RETURNING id;", user_id, date, comment).fetch_one(pool).await?.id,
|
||||||
|
(_, _, _) => query!("INSERT INTO availabillity (userId, date) VALUES ($1, $2) RETURNING id;", user_id, date).fetch_one(pool).await?.id
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn read_by_date(pool: &PgPool, date: NaiveDate) -> anyhow::Result<Vec<Availabillity>> {
|
pub async fn read_by_date(
|
||||||
|
pool: &PgPool,
|
||||||
|
date: NaiveDate,
|
||||||
|
) -> anyhow::Result<Vec<Availabillity>> {
|
||||||
let records = query!("SELECT * FROM availabillity WHERE date = $1", date)
|
let records = query!("SELECT * FROM availabillity WHERE date = $1", date)
|
||||||
.fetch_all(pool)
|
.fetch_all(pool)
|
||||||
.await?;
|
.await?;
|
||||||
@ -29,12 +45,21 @@ impl Availabillity {
|
|||||||
.map(|a| Availabillity {
|
.map(|a| Availabillity {
|
||||||
id: a.id,
|
id: a.id,
|
||||||
user_id: a.userid,
|
user_id: a.userid,
|
||||||
|
user: None,
|
||||||
date: a.date,
|
date: a.date,
|
||||||
start_time: a.starttime,
|
start_time: a.starttime,
|
||||||
end_time: a.endtime
|
end_time: a.endtime,
|
||||||
|
comment: a.comment.clone(),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(availabillities)
|
Ok(availabillities)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn load_user(&mut self, pool: &PgPool) -> anyhow::Result<()> {
|
||||||
|
let user = User::read_by_id(pool, self.user_id).await?;
|
||||||
|
self.user = Some(user);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,21 @@
|
|||||||
#[derive(sqlx::Type, Debug)]
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
#[derive(sqlx::Type, Debug, Clone)]
|
||||||
#[sqlx(type_name = "function", rename_all = "lowercase")]
|
#[sqlx(type_name = "function", rename_all = "lowercase")]
|
||||||
pub enum Function {
|
pub enum Function {
|
||||||
Posten = 1,
|
Posten = 1,
|
||||||
Wachhabender = 10,
|
Wachhabender = 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Function {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Function::Posten => write!(f, "Posten"),
|
||||||
|
Function::Wachhabender => write!(f, "Wachhabender")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<u8> for Function {
|
impl TryFrom<u8> for Function {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#[derive(sqlx::Type, Debug)]
|
#[derive(sqlx::Type, Debug, Clone)]
|
||||||
#[sqlx(type_name = "role", rename_all = "lowercase")]
|
#[sqlx(type_name = "role", rename_all = "lowercase")]
|
||||||
pub enum Role {
|
pub enum Role {
|
||||||
Staff = 1,
|
Staff = 1,
|
||||||
|
@ -3,6 +3,7 @@ use sqlx::PgPool;
|
|||||||
|
|
||||||
use super::{function::Function, role::Role};
|
use super::{function::Function, role::Role};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@ -51,7 +52,7 @@ impl User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn read_by_id(pool: &PgPool, id: i32) -> Option<User> {
|
pub async fn read_by_id(pool: &PgPool, id: i32) -> anyhow::Result<User> {
|
||||||
let record = sqlx::query!(
|
let record = sqlx::query!(
|
||||||
r#"
|
r#"
|
||||||
SELECT id,
|
SELECT id,
|
||||||
@ -71,10 +72,9 @@ impl User {
|
|||||||
id,
|
id,
|
||||||
)
|
)
|
||||||
.fetch_one(pool)
|
.fetch_one(pool)
|
||||||
.await;
|
.await?;
|
||||||
|
|
||||||
match record {
|
let user = User {
|
||||||
Ok(record) => Some(User {
|
|
||||||
id: record.id,
|
id: record.id,
|
||||||
name: record.name,
|
name: record.name,
|
||||||
email: record.email,
|
email: record.email,
|
||||||
@ -86,12 +86,9 @@ impl User {
|
|||||||
locked: record.locked,
|
locked: record.locked,
|
||||||
last_login: record.lastlogin,
|
last_login: record.lastlogin,
|
||||||
receive_notifications: record.receivenotifications,
|
receive_notifications: record.receivenotifications,
|
||||||
}),
|
};
|
||||||
Err(err) => {
|
|
||||||
println!("User.read({id}): {err}");
|
Ok(user)
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn read_for_login(pool: &PgPool, email: &str) -> anyhow::Result<Option<User>> {
|
pub async fn read_for_login(pool: &PgPool, email: &str) -> anyhow::Result<Option<User>> {
|
||||||
|
@ -3,29 +3,14 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="section">
|
<section class="section">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<form>
|
<form method="post" action="/availabillity/new">
|
||||||
<h1 class="title">Neue Vefügbarkeit für den {{ date.format("%d.%m.%Y") }}</h1>
|
<h1 class="title">Neue Vefügbarkeit für den {{ date.format("%d.%m.%Y") }}</h1>
|
||||||
<div class="field is-horizontal">
|
|
||||||
<div class="field-label">
|
<input type="hidden" name="date" value="{{ date }}">
|
||||||
<label class="label">Funktion</label>
|
|
||||||
</div>
|
|
||||||
<div class="field-body">
|
|
||||||
<div class="field">
|
|
||||||
<div class="control">
|
|
||||||
<div class="select">
|
|
||||||
<select name="function">
|
|
||||||
<option value="1">Posten</option>
|
|
||||||
<option value="10">Wachhabender</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="field is-horizontal">
|
<div class="field is-horizontal">
|
||||||
<div class="field-label">
|
<div class="field-label">
|
||||||
<label class="label">Zeitangabe</label>
|
<label class="label">Dauer</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="field-body">
|
<div class="field-body">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
@ -56,6 +41,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="field is-horizontal">
|
||||||
|
<div class="field-label">
|
||||||
|
<label class="label">Kommentar</label>
|
||||||
|
</div>
|
||||||
|
<div class="field-body">
|
||||||
|
<div class="field">
|
||||||
|
<div class="control">
|
||||||
|
<textarea class="textarea" placeholder="nur Posten, nur Wachhabender, etc.."></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="field is-horizontal">
|
<div class="field is-horizontal">
|
||||||
<div class="field-label"></div>
|
<div class="field-label"></div>
|
||||||
<div class="field-body">
|
<div class="field-body">
|
||||||
@ -69,6 +67,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>Brass - Brasiwa Leipzig</title>
|
<title>Brass - Brasiwa Leipzig</title>
|
||||||
<link rel="stylesheet" href="/bulma.css">
|
<link rel="stylesheet" href="/static/bulma.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
@ -57,14 +57,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if events.len() == 0 %}
|
{% if availabillities.len() == 0 %}
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<h5 class="title is-5">keine Verfügbarkeiten eingetragen</h5>
|
<h5 class="title is-5">keine Verfügbarkeiten eingetragen</h5>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% for availabillity in availabillities %}
|
{% for availabillity in availabillities %}
|
||||||
|
{% let user = availabillity.user.as_ref().unwrap() %}
|
||||||
|
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<h5 class="title is-5">{{ availabillity.user_id }}</h5>
|
<p>{{ user.name }}</p>
|
||||||
|
<p>{{ user.function }}</p>
|
||||||
|
{% if availabillity.start_time.is_some() && availabillity.end_time.is_some() %}
|
||||||
|
<p>{{ availabillity.start_time.as_ref().unwrap() }}</p>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user