feat: WIP implement event planning
This commit is contained in:
parent
91046d0e1c
commit
95ca418875
@ -34,3 +34,6 @@ thiserror = "1.0.63"
|
||||
[build-dependencies]
|
||||
built = "0.7.4"
|
||||
static-files = "0.2.1"
|
||||
|
||||
[profile.dev.package.askama_derive]
|
||||
opt-level = 3
|
||||
|
6
build.rs
6
build.rs
@ -20,10 +20,6 @@ fn main() -> std::io::Result<()> {
|
||||
nm_path.join("feather-icons/dist/feather-sprite.svg"),
|
||||
dist_path.join("feather-sprite.svg"),
|
||||
)?;
|
||||
//copy(
|
||||
// nm_path.join("bulma/css/bulma.min.css"),
|
||||
// dist_path.join("bulma.min.css"),
|
||||
//)?;
|
||||
copy(
|
||||
nm_path.join("htmx.org/dist/htmx.min.js"),
|
||||
dist_path.join("htmx.min.js"),
|
||||
@ -33,7 +29,7 @@ fn main() -> std::io::Result<()> {
|
||||
dist_path.join("response-targets.js"),
|
||||
)?;
|
||||
copy(
|
||||
nm_path.join("sweetalert2/dist/sweetalert2.min.js"),
|
||||
nm_path.join("sweetalert2-neutral/dist/sweetalert2.min.js"),
|
||||
dist_path.join("sweetalert2.min.js"),
|
||||
)?;
|
||||
copy(
|
||||
|
@ -24,23 +24,23 @@ pub struct NewAssignmentTemplate {
|
||||
|
||||
#[actix_web::get("/assignments/new")]
|
||||
pub async fn get(user: Identity, pool: web::Data<PgPool>, query: web::Query<EventQuery>) -> impl Responder {
|
||||
let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
if let Ok(event) = Event::read_by_id_including_location(pool.get_ref(), query.event).await {
|
||||
if current_user.role == Role::Admin || current_user.role == Role::AreaManager && event.location.as_ref().unwrap().area_id == current_user.area_id {
|
||||
let all = Availabillity::read_not_assigned_by_date_including_user(pool.get_ref(), event.date).await.unwrap();
|
||||
let available_posten = Availabillity::read_not_assigned_by_date_including_user(pool.get_ref(), event.date).await.unwrap();
|
||||
let available_wachhabende = available_posten.iter().filter(|a| a.user.as_ref().unwrap().function == Function::Wachhabender).map(|avl| avl.clone()).collect();
|
||||
|
||||
let template = NewAssignmentTemplate { user: current_user, event, available_wachhabende, available_posten, all };
|
||||
|
||||
return template.to_response();
|
||||
}
|
||||
|
||||
return HttpResponse::Unauthorized().finish();
|
||||
}
|
||||
//let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap())
|
||||
// .await
|
||||
// .unwrap();
|
||||
//
|
||||
//if let Ok(event) = Event::read_by_id_including_location(pool.get_ref(), query.event).await {
|
||||
// if current_user.role == Role::Admin || current_user.role == Role::AreaManager && event.location.as_ref().unwrap().area_id == current_user.area_id {
|
||||
// let all = Availabillity::read_not_assigned_by_date_including_user(pool.get_ref(), event.date).await.unwrap();
|
||||
// let available_posten = Availabillity::read_not_assigned_by_date_including_user(pool.get_ref(), event.date).await.unwrap();
|
||||
// let available_wachhabende = available_posten.iter().filter(|a| a.user.as_ref().unwrap().function == Function::Wachhabender).map(|avl| avl.clone()).collect();
|
||||
//
|
||||
// let template = NewAssignmentTemplate { user: current_user, event, available_wachhabende, available_posten, all };
|
||||
//
|
||||
// return template.to_response();
|
||||
// }
|
||||
//
|
||||
// return HttpResponse::Unauthorized().finish();
|
||||
//}
|
||||
|
||||
HttpResponse::BadRequest().body("Fehler beim Laden für Assignment")
|
||||
}
|
||||
|
@ -13,47 +13,47 @@ pub struct NewAssignmentsForm {
|
||||
|
||||
#[actix_web::post("/assignments/new")]
|
||||
pub async fn post(pool: web::Data<PgPool>, form: web::Form<Vec<(String, String)>>) -> impl Responder {
|
||||
let event_id = form.iter().find(|x| x.0 == "event").unwrap().1.parse().unwrap();
|
||||
let wachhabender = form.iter().find(|x| x.0 == "wachhabender");
|
||||
let posten: Vec<i32> = form.iter().filter(|x| x.0 == "posten").map(|x| x.1.parse().unwrap()).collect();
|
||||
|
||||
let event = Event::read_by_id_including_location(&pool, event_id).await.unwrap(); // TODO: Check if location is needed
|
||||
|
||||
if event.voluntary_wachhabender && wachhabender.is_some() && posten.contains(&wachhabender.unwrap().1.parse().unwrap()) {
|
||||
return HttpResponse::BadRequest().body("Wachhabender kann nicht zugleich Posten sein!");
|
||||
}
|
||||
|
||||
let mut joined_ids = posten.clone();
|
||||
if let Some((_,id)) = wachhabender {
|
||||
joined_ids.push(id.parse().unwrap());
|
||||
}
|
||||
|
||||
for availabillity_id in joined_ids {
|
||||
let assignments = Assignment::read_by_availabillity(pool.get_ref(), availabillity_id).await.unwrap();
|
||||
|
||||
let mut can_be_used = true;
|
||||
|
||||
|
||||
for assignment in assignments {
|
||||
if event.start_time >= assignment.start_time && event.start_time <= assignment.end_time {
|
||||
} else {
|
||||
can_be_used = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !can_be_used {
|
||||
return HttpResponse::BadRequest().body("availabillity time slot bereits genutzt!");
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((_,id)) = wachhabender {
|
||||
Assignment::create(pool.get_ref(), event.id, id.parse().unwrap(), Function::Wachhabender, event.start_time, event.end_time).await.unwrap();
|
||||
}
|
||||
|
||||
for id in posten {
|
||||
Assignment::create(pool.get_ref(), event.id, id, Function::Posten, event.start_time, event.end_time).await.unwrap();
|
||||
}
|
||||
|
||||
//let event_id = form.iter().find(|x| x.0 == "event").unwrap().1.parse().unwrap();
|
||||
//let wachhabender = form.iter().find(|x| x.0 == "wachhabender");
|
||||
//let posten: Vec<i32> = form.iter().filter(|x| x.0 == "posten").map(|x| x.1.parse().unwrap()).collect();
|
||||
//
|
||||
//let event = Event::read_by_id_including_location(&pool, event_id).await.unwrap(); // TODO: Check if location is needed
|
||||
//
|
||||
//if event.voluntary_wachhabender && wachhabender.is_some() && posten.contains(&wachhabender.unwrap().1.parse().unwrap()) {
|
||||
// return HttpResponse::BadRequest().body("Wachhabender kann nicht zugleich Posten sein!");
|
||||
//}
|
||||
//
|
||||
//let mut joined_ids = posten.clone();
|
||||
//if let Some((_,id)) = wachhabender {
|
||||
// joined_ids.push(id.parse().unwrap());
|
||||
//}
|
||||
//
|
||||
//for availabillity_id in joined_ids {
|
||||
// let assignments = Assignment::read_by_availabillity(pool.get_ref(), availabillity_id).await.unwrap();
|
||||
//
|
||||
// let mut can_be_used = true;
|
||||
//
|
||||
//
|
||||
// for assignment in assignments {
|
||||
// if event.start_time >= assignment.start_time && event.start_time <= assignment.end_time {
|
||||
// } else {
|
||||
// can_be_used = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if !can_be_used {
|
||||
// return HttpResponse::BadRequest().body("availabillity time slot bereits genutzt!");
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//if let Some((_,id)) = wachhabender {
|
||||
// Assignment::create(pool.get_ref(), event.id, id.parse().unwrap(), Function::Wachhabender, event.start_time, event.end_time).await.unwrap();
|
||||
//}
|
||||
//
|
||||
//for id in posten {
|
||||
// Assignment::create(pool.get_ref(), event.id, id, Function::Posten, event.start_time, event.end_time).await.unwrap();
|
||||
//}
|
||||
//
|
||||
HttpResponse::Ok().finish()
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use sqlx::PgPool;
|
||||
|
||||
use crate::{
|
||||
endpoints::IdPath,
|
||||
models::{Availabillity, User},
|
||||
models::{Availabillity, User}, utils::ApplicationError,
|
||||
};
|
||||
|
||||
#[actix_web::delete("/availabillity/delete/{id}")]
|
||||
@ -11,14 +11,16 @@ pub async fn delete(
|
||||
user: web::ReqData<User>,
|
||||
pool: web::Data<PgPool>,
|
||||
path: web::Path<IdPath>,
|
||||
) -> impl Responder {
|
||||
if let Ok(availabillity_in_db) = Availabillity::read_by_id(pool.get_ref(), path.id).await {
|
||||
if availabillity_in_db.user_id == user.id {
|
||||
if let Ok(_) = Availabillity::delete(pool.get_ref(), availabillity_in_db.id).await {
|
||||
return HttpResponse::Ok().finish();
|
||||
}
|
||||
}
|
||||
) -> Result<impl Responder, ApplicationError> {
|
||||
let Some(availabillity) = Availabillity::read_by_id(pool.get_ref(), path.id).await? else {
|
||||
return Ok(HttpResponse::NotFound().finish());
|
||||
};
|
||||
|
||||
if availabillity.user_id == user.id {
|
||||
return Err(ApplicationError::Unauthorized);
|
||||
}
|
||||
|
||||
return HttpResponse::BadRequest().finish();
|
||||
Availabillity::delete(pool.get_ref(), availabillity.id).await?;
|
||||
|
||||
Ok(HttpResponse::Ok().finish())
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ async fn get(
|
||||
None => None,
|
||||
};
|
||||
|
||||
let events = Event::read_by_date_and_area_including_location(
|
||||
let events = Event::read_all_by_date_and_area_including_location(
|
||||
pool.get_ref(),
|
||||
date,
|
||||
query.area.unwrap_or(user.area_id),
|
||||
|
@ -6,6 +6,7 @@ use sqlx::PgPool;
|
||||
use crate::{
|
||||
endpoints::{availability::NewOrEditAvailabilityTemplate, IdPath},
|
||||
models::{Availabillity, User},
|
||||
utils::ApplicationError,
|
||||
};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@ -20,32 +21,34 @@ pub async fn get(
|
||||
pool: web::Data<PgPool>,
|
||||
path: web::Path<IdPath>,
|
||||
query: web::Query<EditAvailabilityQuery>,
|
||||
) -> impl Responder {
|
||||
if let Ok(availabillity) = Availabillity::read_by_id(pool.get_ref(), path.id).await {
|
||||
if availabillity.user_id == user.id {
|
||||
let start_time = availabillity
|
||||
.start_time
|
||||
.and_then(|d| Some(d.format("%R").to_string()));
|
||||
) -> Result<impl Responder, ApplicationError> {
|
||||
let Some(availabillity) = Availabillity::read_by_id(pool.get_ref(), path.id).await? else {
|
||||
return Ok(HttpResponse::NotFound().finish());
|
||||
};
|
||||
|
||||
let end_time = availabillity
|
||||
.end_time
|
||||
.and_then(|d| Some(d.format("%R").to_string()));
|
||||
|
||||
let has_time = availabillity.start_time.is_some() && availabillity.end_time.is_some();
|
||||
|
||||
let template = NewOrEditAvailabilityTemplate {
|
||||
user: user.into_inner(),
|
||||
date: availabillity.date,
|
||||
whole_day: query.whole_day.unwrap_or(!has_time),
|
||||
id: Some(path.id),
|
||||
start_time: start_time.as_deref(),
|
||||
end_time: end_time.as_deref(),
|
||||
comment: availabillity.comment.as_deref(),
|
||||
};
|
||||
|
||||
return template.to_response();
|
||||
}
|
||||
if availabillity.user_id == user.id {
|
||||
return Err(ApplicationError::Unauthorized);
|
||||
}
|
||||
|
||||
HttpResponse::BadRequest().body("Availabillity with this id doesn't exist.")
|
||||
let start_time = availabillity
|
||||
.start_time
|
||||
.and_then(|d| Some(d.format("%R").to_string()));
|
||||
|
||||
let end_time = availabillity
|
||||
.end_time
|
||||
.and_then(|d| Some(d.format("%R").to_string()));
|
||||
|
||||
let has_time = availabillity.start_time.is_some() && availabillity.end_time.is_some();
|
||||
|
||||
let template = NewOrEditAvailabilityTemplate {
|
||||
user: user.into_inner(),
|
||||
date: availabillity.date,
|
||||
whole_day: query.whole_day.unwrap_or(!has_time),
|
||||
id: Some(path.id),
|
||||
start_time: start_time.as_deref(),
|
||||
end_time: end_time.as_deref(),
|
||||
comment: availabillity.comment.as_deref(),
|
||||
};
|
||||
|
||||
Ok(template.to_response())
|
||||
}
|
||||
|
@ -3,7 +3,10 @@ use chrono::{NaiveDate, NaiveTime};
|
||||
use serde::Deserialize;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::models::{Availabillity, User};
|
||||
use crate::{
|
||||
models::{Availabillity, User},
|
||||
utils::{self, ApplicationError},
|
||||
};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct AvailabillityForm {
|
||||
@ -18,8 +21,8 @@ pub async fn post(
|
||||
user: web::ReqData<User>,
|
||||
pool: web::Data<PgPool>,
|
||||
form: web::Form<AvailabillityForm>,
|
||||
) -> impl Responder {
|
||||
if let Ok(_) = Availabillity::create(
|
||||
) -> Result<impl Responder, ApplicationError> {
|
||||
Availabillity::create(
|
||||
pool.get_ref(),
|
||||
user.id,
|
||||
form.date,
|
||||
@ -27,12 +30,11 @@ pub async fn post(
|
||||
form.till,
|
||||
form.comment.clone(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
HttpResponse::Found()
|
||||
.insert_header((LOCATION, "/"))
|
||||
.finish()
|
||||
} else {
|
||||
HttpResponse::BadRequest().body("Fehler beim erstellen")
|
||||
}
|
||||
.await?;
|
||||
|
||||
let url = utils::get_return_url_for_date(&form.date);
|
||||
Ok(HttpResponse::Found()
|
||||
.insert_header((LOCATION, url.clone()))
|
||||
.insert_header(("HX-LOCATION", url))
|
||||
.finish())
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ use sqlx::PgPool;
|
||||
use crate::{
|
||||
endpoints::{availability::post_new::AvailabillityForm, IdPath},
|
||||
models::{Availabillity, User},
|
||||
utils::{self, ApplicationError},
|
||||
};
|
||||
|
||||
#[actix_web::post("/availabillity/edit/{id}")]
|
||||
@ -12,42 +13,32 @@ pub async fn post(
|
||||
pool: web::Data<PgPool>,
|
||||
path: web::Path<IdPath>,
|
||||
form: web::Form<AvailabillityForm>,
|
||||
) -> impl Responder {
|
||||
if let Ok(mut availabillity) = Availabillity::read_by_id(pool.get_ref(), path.id).await {
|
||||
if availabillity.user_id == user.id {
|
||||
let mut has_changed = false;
|
||||
) -> Result<impl Responder, ApplicationError> {
|
||||
let Some(availabillity) = Availabillity::read_by_id(pool.get_ref(), path.id).await? else {
|
||||
return Ok(HttpResponse::NotFound().finish());
|
||||
};
|
||||
|
||||
if availabillity.start_time != form.from {
|
||||
availabillity.start_time = form.from;
|
||||
has_changed = true;
|
||||
}
|
||||
|
||||
if availabillity.end_time != form.till {
|
||||
availabillity.end_time = form.till;
|
||||
has_changed = true;
|
||||
}
|
||||
|
||||
if availabillity.comment != form.comment {
|
||||
availabillity.comment = form.comment.clone();
|
||||
has_changed = true;
|
||||
}
|
||||
|
||||
if has_changed {
|
||||
if let Ok(_) = Availabillity::update(pool.get_ref(), path.id, &availabillity).await
|
||||
{
|
||||
return HttpResponse::Found()
|
||||
.insert_header((LOCATION, "/"))
|
||||
.finish();
|
||||
}
|
||||
}
|
||||
|
||||
if !has_changed {
|
||||
return HttpResponse::Found()
|
||||
.insert_header((LOCATION, "/"))
|
||||
.finish();
|
||||
}
|
||||
}
|
||||
if availabillity.user_id != user.id {
|
||||
return Err(ApplicationError::Unauthorized);
|
||||
}
|
||||
|
||||
HttpResponse::BadRequest().body("Fehler beim erstellen")
|
||||
if availabillity.start_time != form.from
|
||||
|| availabillity.end_time != form.till
|
||||
|| availabillity.comment != form.comment
|
||||
{
|
||||
Availabillity::update(
|
||||
pool.get_ref(),
|
||||
availabillity.id,
|
||||
form.from,
|
||||
form.till,
|
||||
form.comment.as_ref(),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
let url = utils::get_return_url_for_date(&form.date);
|
||||
Ok(HttpResponse::Found()
|
||||
.insert_header((LOCATION, url.clone()))
|
||||
.insert_header(("HX-LOCATION", url))
|
||||
.finish())
|
||||
}
|
||||
|
@ -1,38 +1,44 @@
|
||||
use actix_identity::Identity;
|
||||
use actix_web::{web, HttpResponse, Responder};
|
||||
use actix_web::{web, Responder};
|
||||
use askama::Template;
|
||||
use askama_actix::TemplateToResponse;
|
||||
use chrono::NaiveDate;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::{endpoints::NaiveDateQuery, models::{Role, User, Location}};
|
||||
use crate::{
|
||||
endpoints::NaiveDateQuery,
|
||||
models::{Location, Role, User},
|
||||
utils::ApplicationError,
|
||||
};
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "events/new.html")]
|
||||
pub struct NewEventTemplate {
|
||||
user: User,
|
||||
date: NaiveDate,
|
||||
locations: Vec<Location>
|
||||
locations: Vec<Location>,
|
||||
}
|
||||
|
||||
#[actix_web::get("/events/new")]
|
||||
pub async fn get(user: Identity, pool: web::Data<PgPool>, query: web::Query<NaiveDateQuery>) -> impl Responder {
|
||||
let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
if current_user.role != Role::Admin && current_user.role != Role::AreaManager {
|
||||
return HttpResponse::Unauthorized().finish();
|
||||
pub async fn get(
|
||||
user: web::ReqData<User>,
|
||||
pool: web::Data<PgPool>,
|
||||
query: web::Query<NaiveDateQuery>,
|
||||
) -> Result<impl Responder, ApplicationError> {
|
||||
if user.role != Role::Admin && user.role != Role::AreaManager {
|
||||
return Err(ApplicationError::Unauthorized);
|
||||
}
|
||||
|
||||
let locations;
|
||||
if current_user.role == Role::Admin {
|
||||
locations = Location::read_all_including_area(pool.get_ref()).await.unwrap();
|
||||
let locations = if user.role == Role::Admin {
|
||||
Location::read_all_including_area(pool.get_ref()).await?
|
||||
} else {
|
||||
locations = Location::read_by_area(pool.get_ref(), current_user.area_id).await.unwrap();
|
||||
}
|
||||
Location::read_by_area(pool.get_ref(), user.area_id).await?
|
||||
};
|
||||
|
||||
let template = NewEventTemplate { user: current_user, date: query.date, locations };
|
||||
let template = NewEventTemplate {
|
||||
user: user.into_inner(),
|
||||
date: query.date,
|
||||
locations,
|
||||
};
|
||||
|
||||
return template.to_response();
|
||||
Ok(template.to_response())
|
||||
}
|
||||
|
101
src/endpoints/events/get_plan.rs
Normal file
101
src/endpoints/events/get_plan.rs
Normal file
@ -0,0 +1,101 @@
|
||||
use actix_web::{web, HttpResponse, Responder};
|
||||
use askama::Template;
|
||||
use askama_actix::TemplateToResponse;
|
||||
use chrono::NaiveDate;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::{
|
||||
endpoints::{IdPath, NaiveDateQuery},
|
||||
models::{Assignment, Availabillity, Event, Function, Location, Role, User},
|
||||
utils::ApplicationError,
|
||||
};
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "events/plan.html")]
|
||||
pub struct PlanEventTemplate {
|
||||
user: User,
|
||||
event: Event,
|
||||
availabillities: Vec<(Availabillity, AssignmentState)>,
|
||||
}
|
||||
|
||||
enum AssignmentState {
|
||||
// availabillity is not assigned at all or at least not timely conflicting
|
||||
Unassigned,
|
||||
// availabillity is assigned for another event that is timely conflicting
|
||||
Conflicting,
|
||||
// availabillity is assigned to this event as Posten
|
||||
AssignedPosten,
|
||||
// availabillity is assigned to this event as Führungsassistent
|
||||
AssignedFührungsassistent,
|
||||
// availabillity is assigned to this event as Wachhabender
|
||||
AssignedWachahabender,
|
||||
}
|
||||
|
||||
#[actix_web::get("/events/{id}/plan")]
|
||||
pub async fn get(
|
||||
user: web::ReqData<User>,
|
||||
pool: web::Data<PgPool>,
|
||||
path: web::Path<IdPath>,
|
||||
) -> Result<impl Responder, ApplicationError> {
|
||||
if user.role != Role::Admin && user.role != Role::AreaManager {
|
||||
return Err(ApplicationError::Unauthorized);
|
||||
}
|
||||
|
||||
let Some(event) = Event::read_by_id_including_location(pool.get_ref(), path.id).await? else {
|
||||
return Ok(HttpResponse::NotFound().finish());
|
||||
};
|
||||
|
||||
if user.role != Role::Admin && user.area_id != event.location.as_ref().unwrap().area_id {
|
||||
return Err(ApplicationError::Unauthorized);
|
||||
}
|
||||
|
||||
let availabillities_in_db = Availabillity::read_by_date_and_area_including_user(
|
||||
pool.get_ref(),
|
||||
event.date,
|
||||
event.location.as_ref().unwrap().area_id,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let mut availabillities = Vec::new();
|
||||
for availabillity in availabillities_in_db {
|
||||
let assignments =
|
||||
Assignment::read_all_by_availabillity(pool.get_ref(), availabillity.id).await?;
|
||||
|
||||
if let Some(assignment) = assignments
|
||||
.iter()
|
||||
.find(|assignment| assignment.event_id == event.id)
|
||||
{
|
||||
let state = match assignment.function {
|
||||
Function::Posten => AssignmentState::AssignedPosten,
|
||||
Function::Fuehrungsassistent => AssignmentState::AssignedFührungsassistent,
|
||||
Function::Wachhabender => AssignmentState::AssignedWachahabender,
|
||||
};
|
||||
|
||||
availabillities.push((availabillity, state));
|
||||
continue;
|
||||
}
|
||||
|
||||
let has_start_time_during_event =
|
||||
|a: &Assignment| a.start_time >= event.start_time && a.start_time <= event.end_time;
|
||||
let has_end_time_during_event =
|
||||
|a: &Assignment| a.end_time >= event.start_time && a.end_time <= event.end_time;
|
||||
|
||||
if assignments
|
||||
.iter()
|
||||
.any(|a| has_start_time_during_event(a) || has_end_time_during_event(a))
|
||||
{
|
||||
availabillities.push((availabillity, AssignmentState::Conflicting));
|
||||
continue;
|
||||
}
|
||||
|
||||
availabillities.push((availabillity, AssignmentState::Unassigned));
|
||||
}
|
||||
|
||||
let template = PlanEventTemplate {
|
||||
user: user.into_inner(),
|
||||
event,
|
||||
availabillities,
|
||||
};
|
||||
|
||||
Ok(template.to_response())
|
||||
}
|
@ -1,2 +1,3 @@
|
||||
pub mod get_new;
|
||||
pub mod post_new;
|
||||
pub mod get_plan;
|
||||
|
@ -1,10 +1,9 @@
|
||||
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::{Event, Role, User};
|
||||
use crate::{models::{Event, Role, User}, utils::{self, ApplicationError}};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct NewEventForm {
|
||||
@ -16,25 +15,20 @@ pub struct NewEventForm {
|
||||
voluntarywachhabender: Option<bool>,
|
||||
amount: i16,
|
||||
clothing: String,
|
||||
note: Option<String>
|
||||
}
|
||||
|
||||
#[actix_web::post("/events/new")]
|
||||
pub async fn post(
|
||||
user: Identity,
|
||||
user: web::ReqData<User>,
|
||||
pool: web::Data<PgPool>,
|
||||
form: web::Form<NewEventForm>,
|
||||
) -> impl Responder {
|
||||
let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
if current_user.role != Role::Admin && current_user.role != Role::AreaManager {
|
||||
return HttpResponse::Unauthorized().finish();
|
||||
) -> Result<impl Responder, ApplicationError> {
|
||||
if user.role != Role::Admin && user.role != Role::AreaManager {
|
||||
return Err(ApplicationError::Unauthorized);
|
||||
}
|
||||
|
||||
let return_location = format!("/?data={}", form.date);
|
||||
|
||||
match Event::create(
|
||||
Event::create(
|
||||
pool.get_ref(),
|
||||
&form.date,
|
||||
&form.from,
|
||||
@ -44,9 +38,14 @@ pub async fn post(
|
||||
form.voluntarywachhabender.is_some() && form.voluntarywachhabender.unwrap(),
|
||||
form.amount,
|
||||
&form.clothing,
|
||||
form.note.as_ref()
|
||||
)
|
||||
.await {
|
||||
Ok(_) => HttpResponse::Found().insert_header((LOCATION, return_location)).finish(),
|
||||
Err(_) => HttpResponse::BadRequest().body("Fehler beim Erstellen")
|
||||
}
|
||||
.await?;
|
||||
|
||||
let url = utils::get_return_url_for_date(&form.date);
|
||||
println!("redirecto to {url}");
|
||||
Ok(HttpResponse::Found()
|
||||
.insert_header((LOCATION, url.clone()))
|
||||
.insert_header(("HX-LOCATION", url))
|
||||
.finish())
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ pub fn init(cfg: &mut ServiceConfig) {
|
||||
|
||||
cfg.service(events::get_new::get);
|
||||
cfg.service(events::post_new::post);
|
||||
cfg.service(events::get_plan::get);
|
||||
|
||||
cfg.service(assignment::get_new::get);
|
||||
cfg.service(assignment::post_new::post);
|
||||
|
@ -1,7 +1,7 @@
|
||||
use chrono::NaiveTime;
|
||||
use sqlx::{query, PgPool};
|
||||
|
||||
use super::Function;
|
||||
use super::{Function, Result};
|
||||
|
||||
pub struct Assignment {
|
||||
pub event_id: i32,
|
||||
@ -19,7 +19,7 @@ impl Assignment {
|
||||
function: Function,
|
||||
start_time: NaiveTime,
|
||||
end_time: NaiveTime,
|
||||
) -> anyhow::Result<()> {
|
||||
) -> Result<()> {
|
||||
query!(
|
||||
r##"
|
||||
INSERT INTO assignment (eventId, availabillityId, function, startTime, endTime)
|
||||
@ -37,13 +37,13 @@ impl Assignment {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn read_by_availabillity(
|
||||
pub async fn read_all_by_availabillity(
|
||||
pool: &PgPool,
|
||||
availabillity_id: i32,
|
||||
) -> anyhow::Result<Vec<Assignment>> {
|
||||
) -> Result<Vec<Assignment>> {
|
||||
let records = query!(
|
||||
r##"
|
||||
SELECT
|
||||
SELECT
|
||||
assignment.eventId,
|
||||
assignment.availabillityId,
|
||||
assignment.function AS "function: Function",
|
||||
|
@ -1,7 +1,7 @@
|
||||
use chrono::{NaiveDate, NaiveTime};
|
||||
use sqlx::{query, PgPool};
|
||||
|
||||
use super::{function::Function, role::Role, user::User, Area};
|
||||
use super::{Area, Function, Result, Role, User};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Availabillity {
|
||||
@ -22,22 +22,29 @@ impl Availabillity {
|
||||
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
|
||||
};
|
||||
) -> Result<()> {
|
||||
query!(
|
||||
r#"
|
||||
INSERT INTO availabillity (userId, date, startTime, endTime, comment)
|
||||
VALUES ($1, $2, $3, $4, $5);
|
||||
"#,
|
||||
user_id,
|
||||
date,
|
||||
start_time,
|
||||
end_time,
|
||||
comment
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
Ok(result)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn read_by_date_and_area_including_user(
|
||||
pool: &PgPool,
|
||||
date: NaiveDate,
|
||||
area_id: i32
|
||||
) -> anyhow::Result<Vec<Availabillity>> {
|
||||
area_id: i32,
|
||||
) -> Result<Vec<Availabillity>> {
|
||||
let records = query!(
|
||||
r##"
|
||||
SELECT
|
||||
@ -100,7 +107,7 @@ impl Availabillity {
|
||||
pub async fn read_not_assigned_by_date_including_user(
|
||||
pool: &PgPool,
|
||||
date: NaiveDate,
|
||||
) -> anyhow::Result<Vec<Availabillity>> {
|
||||
) -> Result<Vec<Availabillity>> {
|
||||
let records = query!(
|
||||
r##"
|
||||
SELECT
|
||||
@ -159,20 +166,22 @@ impl Availabillity {
|
||||
Ok(availabillities)
|
||||
}
|
||||
|
||||
pub async fn read_by_id(pool: &PgPool, id: i32) -> anyhow::Result<Availabillity> {
|
||||
pub async fn read_by_id(pool: &PgPool, id: i32) -> Result<Option<Availabillity>> {
|
||||
let record = query!("SELECT * FROM availabillity WHERE id = $1", id)
|
||||
.fetch_one(pool)
|
||||
.fetch_optional(pool)
|
||||
.await?;
|
||||
|
||||
let availabillity = Availabillity {
|
||||
id: record.id,
|
||||
user_id: record.userid,
|
||||
user: None,
|
||||
date: record.date,
|
||||
start_time: record.starttime,
|
||||
end_time: record.endtime,
|
||||
comment: record.comment.clone(),
|
||||
};
|
||||
let availabillity = record.and_then(|record| {
|
||||
Some(Availabillity {
|
||||
id: record.id,
|
||||
user_id: record.userid,
|
||||
user: None,
|
||||
date: record.date,
|
||||
start_time: record.starttime,
|
||||
end_time: record.endtime,
|
||||
comment: record.comment.clone(),
|
||||
})
|
||||
});
|
||||
|
||||
Ok(availabillity)
|
||||
}
|
||||
@ -181,7 +190,7 @@ impl Availabillity {
|
||||
pool: &PgPool,
|
||||
date_range: (NaiveDate, NaiveDate),
|
||||
area_id: i32,
|
||||
) -> anyhow::Result<Vec<Availabillity>> {
|
||||
) -> Result<Vec<Availabillity>> {
|
||||
let records = query!(
|
||||
r##"
|
||||
SELECT
|
||||
@ -251,13 +260,15 @@ impl Availabillity {
|
||||
pub async fn update(
|
||||
pool: &PgPool,
|
||||
id: i32,
|
||||
updated_availabillity: &Availabillity,
|
||||
) -> anyhow::Result<()> {
|
||||
start_time: Option<NaiveTime>,
|
||||
end_time: Option<NaiveTime>,
|
||||
comment: Option<&String>,
|
||||
) -> Result<()> {
|
||||
query!(
|
||||
"UPDATE availabillity SET startTime = $1, endTime = $2, comment = $3 WHERE id = $4",
|
||||
updated_availabillity.start_time,
|
||||
updated_availabillity.end_time,
|
||||
updated_availabillity.comment,
|
||||
start_time,
|
||||
end_time,
|
||||
comment,
|
||||
id
|
||||
)
|
||||
.execute(pool)
|
||||
@ -266,7 +277,7 @@ impl Availabillity {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete(pool: &PgPool, id: i32) -> anyhow::Result<()> {
|
||||
pub async fn delete(pool: &PgPool, id: i32) -> Result<()> {
|
||||
query!("DELETE FROM availabillity WHERE id = $1", id)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
@ -1,8 +1,9 @@
|
||||
use chrono::{NaiveDate, NaiveTime};
|
||||
use sqlx::{query, PgPool};
|
||||
|
||||
use super::Location;
|
||||
use super::{Location, Result};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Event {
|
||||
pub id: i32,
|
||||
pub date: NaiveDate,
|
||||
@ -15,6 +16,7 @@ pub struct Event {
|
||||
pub amount_of_posten: i16,
|
||||
pub clothing: String,
|
||||
pub canceled: bool,
|
||||
pub note: Option<String>,
|
||||
}
|
||||
|
||||
impl Event {
|
||||
@ -28,17 +30,22 @@ impl Event {
|
||||
voluntary_wachhabender: bool,
|
||||
amount_of_posten: i16,
|
||||
clothing: &String,
|
||||
) -> anyhow::Result<i32> {
|
||||
let result = query!("INSERT INTO event (date, startTime, endTime, name, locationId, voluntaryWachhabender, amountOfPosten, clothing) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING id;", date, start_time, end_time, name, location_id, voluntary_wachhabender, amount_of_posten, clothing).fetch_one(pool).await?;
|
||||
note: Option<&String>,
|
||||
) -> Result<()> {
|
||||
query!(r#"
|
||||
INSERT INTO event (date, startTime, endTime, name, locationId, voluntaryWachhabender, amountOfPosten, clothing, note)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9);
|
||||
"#,
|
||||
date, start_time, end_time, name, location_id, voluntary_wachhabender, amount_of_posten, clothing, note).execute(pool).await?;
|
||||
|
||||
Ok(result.id)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn read_by_date_and_area_including_location(
|
||||
pub async fn read_all_by_date_and_area_including_location(
|
||||
pool: &PgPool,
|
||||
date: NaiveDate,
|
||||
area_id: i32
|
||||
) -> anyhow::Result<Vec<Event>> {
|
||||
area_id: i32,
|
||||
) -> Result<Vec<Event>> {
|
||||
let records = query!(
|
||||
r#"
|
||||
SELECT
|
||||
@ -52,6 +59,7 @@ impl Event {
|
||||
event.amountOfPosten,
|
||||
event.clothing,
|
||||
event.canceled,
|
||||
event.note,
|
||||
location.id,
|
||||
location.name AS locationName,
|
||||
location.areaId AS locationAreaId
|
||||
@ -67,7 +75,7 @@ impl Event {
|
||||
.await?;
|
||||
|
||||
let events = records
|
||||
.iter()
|
||||
.into_iter()
|
||||
.map(|record| Event {
|
||||
id: record.eventid,
|
||||
date: record.date,
|
||||
@ -85,13 +93,14 @@ impl Event {
|
||||
amount_of_posten: record.amountofposten,
|
||||
clothing: record.clothing.to_string(),
|
||||
canceled: record.canceled,
|
||||
note: record.note,
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(events)
|
||||
}
|
||||
|
||||
pub async fn read_by_id_including_location(pool: &PgPool, id: i32) -> anyhow::Result<Event> {
|
||||
pub async fn read_by_id_including_location(pool: &PgPool, id: i32) -> Result<Option<Event>> {
|
||||
let record = query!(
|
||||
r#"
|
||||
SELECT
|
||||
@ -105,6 +114,7 @@ impl Event {
|
||||
event.amountOfPosten,
|
||||
event.clothing,
|
||||
event.canceled,
|
||||
event.note,
|
||||
location.id,
|
||||
location.name AS locationName,
|
||||
location.areaId AS locationAreaId
|
||||
@ -114,27 +124,30 @@ impl Event {
|
||||
"#,
|
||||
id
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.fetch_optional(pool)
|
||||
.await?;
|
||||
|
||||
let event = Event {
|
||||
id: record.eventid,
|
||||
date: record.date,
|
||||
start_time: record.starttime,
|
||||
end_time: record.endtime,
|
||||
name: record.name.to_string(),
|
||||
location_id: record.locationid,
|
||||
location: Some(Location {
|
||||
id: record.locationid,
|
||||
name: record.locationname.to_string(),
|
||||
area_id: record.locationareaid,
|
||||
area: None,
|
||||
}),
|
||||
voluntary_wachhabender: record.voluntarywachhabender,
|
||||
amount_of_posten: record.amountofposten,
|
||||
clothing: record.clothing.to_string(),
|
||||
canceled: record.canceled,
|
||||
};
|
||||
let event = record.and_then(|record| {
|
||||
Some(Event {
|
||||
id: record.eventid,
|
||||
date: record.date,
|
||||
start_time: record.starttime,
|
||||
end_time: record.endtime,
|
||||
name: record.name.to_string(),
|
||||
location_id: record.locationid,
|
||||
location: Some(Location {
|
||||
id: record.locationid,
|
||||
name: record.locationname.to_string(),
|
||||
area_id: record.locationareaid,
|
||||
area: None,
|
||||
}),
|
||||
voluntary_wachhabender: record.voluntarywachhabender,
|
||||
amount_of_posten: record.amountofposten,
|
||||
clothing: record.clothing.to_string(),
|
||||
canceled: record.canceled,
|
||||
note: record.note,
|
||||
})
|
||||
});
|
||||
|
||||
Ok(event)
|
||||
}
|
||||
|
@ -2,7 +2,10 @@ use sqlx::{query, PgPool};
|
||||
|
||||
use super::Area;
|
||||
|
||||
pub struct Location {
|
||||
use super::Result;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Location {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub area_id: i32,
|
||||
@ -10,19 +13,19 @@ pub struct Location {
|
||||
}
|
||||
|
||||
impl Location {
|
||||
pub async fn create(pool: &PgPool, name: &str, area_id: i32) -> anyhow::Result<i32> {
|
||||
let result = query!(
|
||||
"INSERT INTO location (name, areaId) VALUES ($1, $2) RETURNING id;",
|
||||
pub async fn create(pool: &PgPool, name: &str, area_id: i32) -> Result<()> {
|
||||
query!(
|
||||
"INSERT INTO location (name, areaId) VALUES ($1, $2);",
|
||||
name,
|
||||
area_id
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
|
||||
Ok(result.id)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn read_by_area(pool: &PgPool, area_id: i32) -> anyhow::Result<Vec<Location>> {
|
||||
pub async fn read_by_area(pool: &PgPool, area_id: i32) -> Result<Vec<Location>> {
|
||||
let records = query!("SELECT * FROM location WHERE areaId = $1;", area_id)
|
||||
.fetch_all(pool)
|
||||
.await?;
|
||||
@ -40,7 +43,7 @@ impl Location {
|
||||
Ok(locations)
|
||||
}
|
||||
|
||||
pub async fn read_all(pool: &PgPool) -> anyhow::Result<Vec<Location>> {
|
||||
pub async fn read_all(pool: &PgPool) -> Result<Vec<Location>> {
|
||||
let records = query!("SELECT * FROM location").fetch_all(pool).await?;
|
||||
|
||||
let locations = records
|
||||
@ -56,7 +59,7 @@ impl Location {
|
||||
Ok(locations)
|
||||
}
|
||||
|
||||
pub async fn read_all_including_area(pool: &PgPool) -> anyhow::Result<Vec<Location>> {
|
||||
pub async fn read_all_including_area(pool: &PgPool) -> Result<Vec<Location>> {
|
||||
let records = query!("SELECT location.id AS locationId, location.name, location.areaId, area.id, area.name AS areaName FROM location JOIN area ON location.areaId = area.id;")
|
||||
.fetch_all(pool)
|
||||
.await?;
|
||||
@ -77,7 +80,7 @@ impl Location {
|
||||
Ok(locations)
|
||||
}
|
||||
|
||||
pub async fn read_by_id(pool: &PgPool, id: i32) -> super::Result<Option<Location>> {
|
||||
pub async fn read_by_id(pool: &PgPool, id: i32) -> Result<Option<Location>> {
|
||||
let record = query!("SELECT * FROM location WHERE id = $1;", id)
|
||||
.fetch_optional(pool)
|
||||
.await?;
|
||||
@ -94,7 +97,7 @@ impl Location {
|
||||
Ok(location)
|
||||
}
|
||||
|
||||
pub async fn update(pool: &PgPool, id: i32, name: &str, area_id: i32) -> super::Result<()> {
|
||||
pub async fn update(pool: &PgPool, id: i32, name: &str, area_id: i32) -> Result<()> {
|
||||
query!(
|
||||
"UPDATE location SET name = $1, areaid = $2 WHERE id = $3;",
|
||||
name,
|
||||
@ -107,7 +110,7 @@ impl Location {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete(pool: &PgPool, id: i32) -> super::Result<()> {
|
||||
pub async fn delete(pool: &PgPool, id: i32) -> Result<()> {
|
||||
query!("DELETE FROM location WHERE id = $1;", id)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
@ -5,3 +5,13 @@ pub mod token_generation;
|
||||
mod application_error;
|
||||
|
||||
pub use application_error::ApplicationError;
|
||||
use chrono::{NaiveDate, Utc};
|
||||
|
||||
pub fn get_return_url_for_date(date: &NaiveDate) -> String {
|
||||
let today = Utc::now().date_naive();
|
||||
if date == &today {
|
||||
return String::from("/");
|
||||
}
|
||||
|
||||
format!("/?date={}", date)
|
||||
}
|
||||
|
1394
static/package-lock.json
generated
1394
static/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,10 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"bulma": "^1.0.1",
|
||||
"bulma": "^1.0.2",
|
||||
"feather-icons": "^4.29.2",
|
||||
"htmx.org": "^1.9.12",
|
||||
"sass": "^1.77.8",
|
||||
"sweetalert2": "^11.12.4"
|
||||
"sweetalert2-neutral": "^11.14.1-neutral-fix6"
|
||||
},
|
||||
"scripts": {
|
||||
"build-bulma": "sass --load-path=node_modules --no-source-map style.scss dist/style.css"
|
||||
|
@ -3,7 +3,7 @@ $crimson: #00d1b2; //#B80F0A;
|
||||
|
||||
// Override global Sass variables from the /utilities folder
|
||||
@use "bulma/sass/utilities" with ($family-primary: '"Nunito", sans-serif',
|
||||
$primary: $crimson,
|
||||
$primary: $crimson,
|
||||
);
|
||||
// $grey-dark: $brown,
|
||||
// $grey-light: $beige-light,
|
||||
@ -34,6 +34,8 @@ $crimson: #00d1b2; //#B80F0A;
|
||||
@forward "bulma/sass/layout/section";
|
||||
@forward "bulma/sass/layout/hero";
|
||||
|
||||
@forward "bulma/sass/grid";
|
||||
|
||||
@forward "bulma/sass/helpers/spacing";
|
||||
@forward "bulma/sass/helpers/flexbox";
|
||||
|
||||
@ -41,7 +43,7 @@ $crimson: #00d1b2; //#B80F0A;
|
||||
@forward "bulma/sass/themes";
|
||||
|
||||
// TODO: bulma theme for sweetalert looks and feels outdated
|
||||
@use "sweetalert2/src/sweetalert2.scss" with ($swal2-confirm-button-background-color: $crimson);
|
||||
@use "sweetalert2-neutral/src/sweetalert2.scss" with ($swal2-confirm-button-background-color: $crimson);
|
||||
|
||||
[class*=" icon"],
|
||||
[class^=icon] {
|
||||
|
@ -96,6 +96,19 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label">
|
||||
<label class="label">Anmerkung</label>
|
||||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input class="input" name="note" placeholder="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label"></div>
|
||||
<div class="field-body">
|
||||
|
64
templates/events/plan.html
Normal file
64
templates/events/plan.html
Normal file
@ -0,0 +1,64 @@
|
||||
{% extends "nav.html" %}
|
||||
|
||||
{% block content %}
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<h1 class="title">Eventplanung</h1>
|
||||
|
||||
<div class="box">
|
||||
<h5 class="title is-5">Allgemeines</h5>
|
||||
|
||||
<div class="fixed-grid has-1-cols-mobile">
|
||||
<div class="grid content">
|
||||
<div class="cell is-col-span-2">
|
||||
<p><b>Name:</b> {{ event.name }}</p>
|
||||
</div>
|
||||
|
||||
<div class="cell">
|
||||
<p><b>Datum:</b> {{ event.date.format("%d.%m.%Y") }}</p>
|
||||
</div>
|
||||
|
||||
<div class="cell">
|
||||
<p><b>Uhrzeit:</b> {{ event.start_time.format("%R") }} Uhr - {{ event.end_time.format("%R") }} Uhr</p>
|
||||
</div>
|
||||
|
||||
<div class="cell is-col-span-2">
|
||||
<p><b>Veranstaltungsort:</b> {{ event.location.as_ref().unwrap().name }}</p>
|
||||
</div>
|
||||
|
||||
<div class="cell">
|
||||
<p><b>Wachhabender:</b> {% if event.voluntary_wachhabender %}FF{% else %}BF{% endif %}</p>
|
||||
</div>
|
||||
|
||||
<div class="cell">
|
||||
<p><b>Führungsassistent:</b> {% if event.voluntary_wachhabender %}FF{% else %}BF{% endif %}</p>
|
||||
</div>
|
||||
|
||||
<div class="cell is-col-span-2">
|
||||
<p><b>Anzahl der Posten:</b> {{ event.amount_of_posten }}</p>
|
||||
</div>
|
||||
|
||||
<div class="cell is-col-span-2">
|
||||
<p><b>Anzugsordnung:</b> {{ event.clothing }}</p>
|
||||
</div>
|
||||
|
||||
<div class="cell is-col-span-2">
|
||||
<p><b>Anmerkungen:</b> {{ event.note.as_ref().unwrap_or(String::new()|as_ref) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box">
|
||||
<h5 class="title is-5">Einteilung Personal</h5>
|
||||
<!--TODO: next: Use availabillities-->
|
||||
|
||||
</div>
|
||||
|
||||
<div class="box">
|
||||
<h5 class="title is-5">Einteilung Fahrzeuge</h5>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
@ -56,7 +56,7 @@
|
||||
Events am {{ date.format("%d.%m.%Y") }}
|
||||
</h3>
|
||||
</div>
|
||||
{% if (user.role == Role::Admin || user.role == Role::AreaManager) && (selected_area.is_none() ||
|
||||
{% if user.role == Role::Admin || user.role == Role::AreaManager && (selected_area.is_none() ||
|
||||
selected_area.unwrap() == user.area_id) %}
|
||||
<div class="level-right">
|
||||
<a class="button is-link is-light" hx-boost="true" href="/events/new?date={{ date }}">
|
||||
@ -81,7 +81,7 @@
|
||||
<h5 class="title is-5 level-left">{{ event.name }}</h5>
|
||||
<span class="level-right">
|
||||
{% if user.role == Role::AreaManager || user.role == Role::Admin %}
|
||||
<a href="/assignments/new?event={{ event.id }}" hx-boost="true"
|
||||
<a href="/events/{{ event.id }}/plan" hx-boost="true"
|
||||
class="button is-primary level-item">Planen</a>
|
||||
<a href="" class="button is-primary-light level-item">bearbeiten</a>
|
||||
<a href="" class="button is-warning level-item">als abgesagt markieren</a>
|
||||
|
Loading…
x
Reference in New Issue
Block a user