333 lines
10 KiB
Rust
333 lines
10 KiB
Rust
use chrono::{NaiveDate, NaiveDateTime};
|
|
use sqlx::{PgPool, query, query_file};
|
|
|
|
use super::{Area, AvailabilityChangeset, Result, Role, User, UserFunction};
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct Availability {
|
|
pub id: i32,
|
|
pub user_id: i32,
|
|
pub user: Option<User>,
|
|
pub start: NaiveDateTime,
|
|
pub end: NaiveDateTime,
|
|
pub comment: Option<String>,
|
|
}
|
|
|
|
impl Availability {
|
|
pub async fn create(
|
|
pool: &PgPool,
|
|
user_id: i32,
|
|
changeset: AvailabilityChangeset,
|
|
) -> Result<()> {
|
|
query_file!(
|
|
"sql/availability/create.sql",
|
|
user_id,
|
|
changeset.time.0.and_utc(),
|
|
changeset.time.1.and_utc(),
|
|
changeset.comment
|
|
)
|
|
.execute(pool)
|
|
.await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn read_all_by_date_and_area_including_user(
|
|
pool: &PgPool,
|
|
date: NaiveDate,
|
|
area_id: i32,
|
|
) -> Result<Vec<Availability>> {
|
|
let records = query_file!(
|
|
"sql/availability/read_all_by_date_and_area_including_user.sql",
|
|
date,
|
|
area_id
|
|
)
|
|
.fetch_all(pool)
|
|
.await?;
|
|
|
|
let availabilities = 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,
|
|
function: r.function.clone(),
|
|
area_id: r.areaid,
|
|
area: None,
|
|
locked: r.locked,
|
|
last_login: r.lastlogin,
|
|
receive_notifications: r.receivenotifications,
|
|
}),
|
|
start: r.starttimestamp.naive_utc(),
|
|
end: r.endtimestamp.naive_utc(),
|
|
comment: r.comment.clone(),
|
|
})
|
|
.collect();
|
|
|
|
Ok(availabilities)
|
|
}
|
|
|
|
/// loads availabilities for the area and the same day as the start date and which fully lie inside the daterange
|
|
pub async fn read_all_by_daterange_and_area_including_user_for_event_planning(
|
|
pool: &PgPool,
|
|
date_range: (NaiveDateTime, NaiveDateTime),
|
|
area_id: i32,
|
|
) -> Result<Vec<Availability>> {
|
|
let records = query_file!(
|
|
"sql/availability/read_all_by_daterange_and_area_including_user_for_event_planning.sql",
|
|
date_range.0.date(),
|
|
area_id,
|
|
date_range.0.and_utc(),
|
|
date_range.1.and_utc()
|
|
)
|
|
.fetch_all(pool)
|
|
.await?;
|
|
|
|
let availabilities = 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,
|
|
function: r.function.clone(),
|
|
area_id: r.areaid,
|
|
area: None,
|
|
locked: r.locked,
|
|
last_login: r.lastlogin,
|
|
receive_notifications: r.receivenotifications,
|
|
}),
|
|
start: r.starttimestamp.naive_utc(),
|
|
end: r.endtimestamp.naive_utc(),
|
|
comment: r.comment.clone(),
|
|
})
|
|
.collect();
|
|
|
|
Ok(availabilities)
|
|
}
|
|
|
|
pub async fn read_including_user(pool: &PgPool, id: i32) -> Result<Option<Availability>> {
|
|
let record = query_file!("sql/availability/read_including_user.sql", id)
|
|
.fetch_optional(pool)
|
|
.await?;
|
|
|
|
let availability = record.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,
|
|
function: r.function.clone(),
|
|
area_id: r.areaid,
|
|
area: None,
|
|
locked: r.locked,
|
|
last_login: r.lastlogin,
|
|
receive_notifications: r.receivenotifications,
|
|
}),
|
|
start: r.starttimestamp.naive_utc(),
|
|
end: r.endtimestamp.naive_utc(),
|
|
comment: r.comment.clone(),
|
|
});
|
|
|
|
Ok(availability)
|
|
}
|
|
|
|
pub async fn read(pool: &PgPool, id: i32) -> Result<Option<Availability>> {
|
|
let record = query!("SELECT * FROM availability WHERE id = $1", id)
|
|
.fetch_optional(pool)
|
|
.await?;
|
|
|
|
let availability = record.map(|record| Availability {
|
|
id: record.id,
|
|
user_id: record.userid,
|
|
user: None,
|
|
start: record.starttimestamp.naive_utc(),
|
|
end: record.endtimestamp.naive_utc(),
|
|
comment: record.comment.clone(),
|
|
});
|
|
|
|
Ok(availability)
|
|
}
|
|
|
|
pub async fn read_all_by_daterange_and_area_including_user_for_export(
|
|
pool: &PgPool,
|
|
date_range: (NaiveDate, NaiveDate),
|
|
area_id: i32,
|
|
) -> Result<Vec<Availability>> {
|
|
let records = query_file!(
|
|
"sql/availability/read_all_by_daterange_and_area_including_user_for_export.sql",
|
|
area_id,
|
|
date_range.0,
|
|
date_range.1
|
|
)
|
|
.fetch_all(pool)
|
|
.await?;
|
|
|
|
let availabilities = 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,
|
|
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,
|
|
}),
|
|
start: r.starttimestamp.naive_utc(),
|
|
end: r.endtimestamp.naive_utc(),
|
|
comment: r.comment.clone(),
|
|
})
|
|
.collect();
|
|
|
|
Ok(availabilities)
|
|
}
|
|
|
|
pub async fn read_all_by_user_and_date(
|
|
pool: &PgPool,
|
|
user_id: i32,
|
|
date: &NaiveDate,
|
|
) -> Result<Vec<Availability>> {
|
|
let records = query_file!(
|
|
"sql/availability/read_all_by_user_and_date.sql",
|
|
user_id,
|
|
date
|
|
)
|
|
.fetch_all(pool)
|
|
.await?;
|
|
|
|
let availabilities = records
|
|
.iter()
|
|
.map(|r| Availability {
|
|
id: r.id,
|
|
user_id: r.userid,
|
|
user: None,
|
|
start: r.starttimestamp.naive_utc(),
|
|
end: r.endtimestamp.naive_utc(),
|
|
comment: r.comment.clone(),
|
|
})
|
|
.collect();
|
|
|
|
Ok(availabilities)
|
|
}
|
|
|
|
pub async fn read_all_by_user_and_daterange(
|
|
pool: &PgPool,
|
|
user_id: i32,
|
|
date_range: (&NaiveDate, &NaiveDate),
|
|
) -> Result<Vec<Availability>> {
|
|
let records = query_file!(
|
|
"sql/availability/read_all_by_user_and_daterange.sql",
|
|
user_id,
|
|
date_range.0,
|
|
date_range.1
|
|
)
|
|
.fetch_all(pool)
|
|
.await?;
|
|
|
|
let availabilities = records
|
|
.iter()
|
|
.map(|r| Availability {
|
|
id: r.id,
|
|
user_id: r.userid,
|
|
user: None,
|
|
start: r.starttimestamp.naive_utc(),
|
|
end: r.endtimestamp.naive_utc(),
|
|
comment: r.comment.clone(),
|
|
})
|
|
.collect();
|
|
|
|
Ok(availabilities)
|
|
}
|
|
|
|
pub async fn find_adjacent_by_time_for_user(
|
|
pool: &PgPool,
|
|
start: &NaiveDateTime,
|
|
end: &NaiveDateTime,
|
|
user: i32,
|
|
availability_to_ignore: Option<i32>,
|
|
) -> Result<Option<Availability>> {
|
|
let records = query!(
|
|
r##"
|
|
SELECT
|
|
availability.id,
|
|
availability.userId,
|
|
availability.startTimestamp,
|
|
availability.endTimestamp,
|
|
availability.comment
|
|
FROM availability
|
|
WHERE availability.userId = $1
|
|
AND (availability.endtimestamp = $2
|
|
OR availability.starttimestamp = $3)
|
|
AND (availability.id <> $4 OR $4 IS NULL);
|
|
"##,
|
|
user,
|
|
start.and_utc(),
|
|
end.and_utc(),
|
|
availability_to_ignore
|
|
)
|
|
.fetch_all(pool) // possible to find up to two availabilities (upper and lower), for now we only pick one and extend it
|
|
.await?;
|
|
|
|
let adjacent_avaialability = records.first().and_then(|r| {
|
|
Some(Availability {
|
|
id: r.id,
|
|
user_id: r.userid,
|
|
user: None,
|
|
start: r.starttimestamp.naive_utc(),
|
|
end: r.endtimestamp.naive_utc(),
|
|
comment: r.comment.clone(),
|
|
})
|
|
});
|
|
|
|
Ok(adjacent_avaialability)
|
|
}
|
|
|
|
pub async fn update(pool: &PgPool, id: i32, changeset: AvailabilityChangeset) -> Result<()> {
|
|
query!(
|
|
"UPDATE availability SET startTimestamp = $1, endTimestamp = $2, comment = $3 WHERE id = $4",
|
|
changeset.time.0.and_utc(),
|
|
changeset.time.1.and_utc(),
|
|
changeset.comment,
|
|
id
|
|
)
|
|
.execute(pool)
|
|
.await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn delete(pool: &PgPool, id: i32) -> Result<()> {
|
|
query!("DELETE FROM availability WHERE id = $1", id)
|
|
.execute(pool)
|
|
.await?;
|
|
Ok(())
|
|
}
|
|
}
|