brass/web/src/models/availabillity.rs

343 lines
12 KiB
Rust

use chrono::{NaiveDate, NaiveTime};
use sqlx::{query, PgPool};
use super::{Area, AvailabilityChangeset, Function, Result, Role, User};
#[derive(Clone, Debug)]
pub struct Availability {
pub id: i32,
pub user_id: i32,
pub user: Option<User>,
pub date: NaiveDate,
pub time: AvailabilityTime,
pub comment: Option<String>,
}
#[derive(Clone, Debug, PartialEq)]
pub enum AvailabilityTime {
WholeDay,
Temporarily(NaiveTime, NaiveTime),
}
impl Availability {
// TODO: fix db name
pub async fn create(
pool: &PgPool,
user_id: i32,
date: NaiveDate,
changeset: AvailabilityChangeset,
) -> Result<()> {
let (start, end) = if let AvailabilityTime::Temporarily(s, e) = changeset.time {
(Some(s), Some(e))
} else {
(None, None)
};
query!(
r#"
INSERT INTO availabillity (userId, date, startTime, endTime, comment)
VALUES ($1, $2, $3, $4, $5);
"#,
user_id,
date,
start,
end,
changeset.comment
)
.execute(pool)
.await?;
Ok(())
}
pub async fn read_by_date_and_area_including_user(
pool: &PgPool,
date: NaiveDate,
area_id: i32,
) -> Result<Vec<Availability>> {
let records = query!(
r##"
SELECT
availabillity.id,
availabillity.userId,
availabillity.date,
availabillity.startTime,
availabillity.endTime,
availabillity.comment,
user_.name,
user_.email,
user_.password,
user_.salt,
user_.role AS "role: Role",
user_.function AS "function: Function",
user_.areaId,
user_.locked,
user_.lastLogin,
user_.receiveNotifications
FROM availabillity
JOIN user_ ON availabillity.userId = user_.id
WHERE availabillity.date = $1
AND user_.areaId = $2;
"##,
date,
area_id
)
.fetch_all(pool)
.await?;
let availabillities = records
.iter()
.map(|r| Availability {
id: r.id,
user_id: r.userid,
user: Some(User {
id: r.userid,
name: r.name.clone(),
email: r.email.clone(),
password: r.password.clone(),
salt: r.salt.clone(),
role: r.role.clone(),
function: r.function.clone(),
area_id: r.areaid,
area: None,
locked: r.locked,
last_login: r.lastlogin,
receive_notifications: r.receivenotifications,
}),
date: r.date,
time: match (r.starttime, r.endtime) {
(Some(start), Some(end)) => AvailabilityTime::Temporarily(start, end),
(_, _) => AvailabilityTime::WholeDay,
},
comment: r.comment.clone(),
})
.collect();
Ok(availabillities)
}
pub async fn read_by_id_including_user(pool: &PgPool, id: i32) -> Result<Option<Availability>> {
let record = query!(
r##"
SELECT
availabillity.id,
availabillity.userId,
availabillity.date,
availabillity.startTime,
availabillity.endTime,
availabillity.comment,
user_.name,
user_.email,
user_.password,
user_.salt,
user_.role AS "role: Role",
user_.function AS "function: Function",
user_.areaId,
user_.locked,
user_.lastLogin,
user_.receiveNotifications
FROM availabillity
LEFT JOIN assignment ON availabillity.Id = assignment.availabillityId
JOIN user_ ON availabillity.userId = user_.id
WHERE availabillity.id = $1;
"##,
id
)
.fetch_optional(pool)
.await?;
let availabillity = record.and_then(|r| {
Some(Availability {
id: r.id,
user_id: r.userid,
user: Some(User {
id: r.userid,
name: r.name.clone(),
email: r.email.clone(),
password: r.password.clone(),
salt: r.salt.clone(),
role: r.role.clone(),
function: r.function.clone(),
area_id: r.areaid,
area: None,
locked: r.locked,
last_login: r.lastlogin,
receive_notifications: r.receivenotifications,
}),
date: r.date,
time: match (r.starttime, r.endtime) {
(Some(start), Some(end)) => AvailabilityTime::Temporarily(start, end),
(_, _) => AvailabilityTime::WholeDay,
},
comment: r.comment.clone(),
})
});
Ok(availabillity)
}
pub async fn read_by_id(pool: &PgPool, id: i32) -> Result<Option<Availability>> {
let record = query!("SELECT * FROM availabillity WHERE id = $1", id)
.fetch_optional(pool)
.await?;
let availabillity = record.and_then(|record| {
Some(Availability {
id: record.id,
user_id: record.userid,
user: None,
date: record.date,
time: match (record.starttime, record.endtime) {
(Some(start), Some(end)) => AvailabilityTime::Temporarily(start, end),
(_, _) => AvailabilityTime::WholeDay,
},
comment: record.comment.clone(),
})
});
Ok(availabillity)
}
pub async fn read_for_export(
pool: &PgPool,
date_range: (NaiveDate, NaiveDate),
area_id: i32,
) -> Result<Vec<Availability>> {
let records = query!(
r##"
SELECT
availabillity.id,
availabillity.userId,
availabillity.date,
availabillity.startTime,
availabillity.endTime,
availabillity.comment,
user_.name,
user_.email,
user_.password,
user_.salt,
user_.role AS "role: Role",
user_.function AS "function: Function",
user_.areaId,
user_.locked,
user_.lastLogin,
user_.receiveNotifications,
area.name AS areaName
FROM availabillity
JOIN user_ ON availabillity.userId = user_.id
JOIN area ON user_.areaId = area.id
WHERE user_.areaId = $1 AND
availabillity.date >= $2 AND
availabillity.date <= $3;
"##,
area_id,
date_range.0,
date_range.1
)
.fetch_all(pool)
.await?;
let availabillities = records
.iter()
.map(|r| Availability {
id: r.id,
user_id: r.userid,
user: Some(User {
id: r.userid,
name: r.name.clone(),
email: r.email.clone(),
password: r.password.clone(),
salt: r.salt.clone(),
role: r.role.clone(),
function: r.function.clone(),
area_id: r.areaid,
area: Some(Area {
id: r.areaid,
name: r.areaname.clone(),
}),
locked: r.locked,
last_login: r.lastlogin,
receive_notifications: r.receivenotifications,
}),
date: r.date,
time: match (r.starttime, r.endtime) {
(Some(start), Some(end)) => AvailabilityTime::Temporarily(start, end),
(_, _) => AvailabilityTime::WholeDay,
},
comment: r.comment.clone(),
})
.collect();
Ok(availabillities)
}
pub async fn read_by_user_and_date(
pool: &PgPool,
user_id: i32,
date: &NaiveDate,
) -> Result<Vec<Availability>> {
let records = query!(
r##"
SELECT
availabillity.id,
availabillity.userId,
availabillity.date,
availabillity.startTime,
availabillity.endTime,
availabillity.comment
FROM availabillity
WHERE availabillity.userId = $1
AND availabillity.date = $2;
"##,
user_id,
date
)
.fetch_all(pool)
.await?;
let availabillities = records
.iter()
.map(|r| Availability {
id: r.id,
user_id: r.userid,
user: None,
date: r.date,
time: match (r.starttime, r.endtime) {
(Some(start), Some(end)) => AvailabilityTime::Temporarily(start, end),
(_, _) => AvailabilityTime::WholeDay,
},
comment: r.comment.clone(),
})
.collect();
Ok(availabillities)
}
pub async fn update(pool: &PgPool, id: i32, changeset: AvailabilityChangeset) -> Result<()> {
let (start, end) = if let AvailabilityTime::Temporarily(s, e) = changeset.time {
(Some(s), Some(e))
} else {
(None, None)
};
query!(
"UPDATE availabillity SET startTime = $1, endTime = $2, comment = $3 WHERE id = $4",
start,
end,
changeset.comment,
id
)
.execute(pool)
.await?;
Ok(())
}
pub async fn delete(pool: &PgPool, id: i32) -> Result<()> {
query!("DELETE FROM availabillity WHERE id = $1", id)
.execute(pool)
.await?;
Ok(())
}
}