feat: delete event and list assignments in overview
This commit is contained in:
parent
0bb5f54f16
commit
ee9c4b1ac1
14
.sqlx/query-4bfce344fc6f0bfbb2b460677ce3eba3793ecf697355e81012e721357ba351b9.json
generated
Normal file
14
.sqlx/query-4bfce344fc6f0bfbb2b460677ce3eba3793ecf697355e81012e721357ba351b9.json
generated
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"db_name": "PostgreSQL",
|
||||||
|
"query": "DELETE FROM event WHERE id = $1;",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Int4"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "4bfce344fc6f0bfbb2b460677ce3eba3793ecf697355e81012e721357ba351b9"
|
||||||
|
}
|
@ -1,4 +1,8 @@
|
|||||||
use crate::{filters, utils::ApplicationError};
|
use crate::{
|
||||||
|
filters,
|
||||||
|
models::{Assignment, Function},
|
||||||
|
utils::ApplicationError,
|
||||||
|
};
|
||||||
use actix_web::{web, HttpResponse, Responder};
|
use actix_web::{web, HttpResponse, Responder};
|
||||||
use chrono::{NaiveDate, Utc};
|
use chrono::{NaiveDate, Utc};
|
||||||
use rinja::Template;
|
use rinja::Template;
|
||||||
@ -20,7 +24,7 @@ struct CalendarTemplate {
|
|||||||
date: NaiveDate,
|
date: NaiveDate,
|
||||||
selected_area: Option<i32>,
|
selected_area: Option<i32>,
|
||||||
areas: Vec<Area>,
|
areas: Vec<Area>,
|
||||||
events: Vec<Event>,
|
events_and_assignments: Vec<(Event, Vec<String>, Option<String>, Option<String>)>,
|
||||||
availabillities: Vec<Availabillity>,
|
availabillities: Vec<Availabillity>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,13 +52,6 @@ async fn get(
|
|||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let events = Event::read_all_by_date_and_area_including_location(
|
|
||||||
pool.get_ref(),
|
|
||||||
date,
|
|
||||||
query.area.unwrap_or(user.area_id),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let availabillities = Availabillity::read_by_date_and_area_including_user(
|
let availabillities = Availabillity::read_by_date_and_area_including_user(
|
||||||
pool.get_ref(),
|
pool.get_ref(),
|
||||||
date,
|
date,
|
||||||
@ -62,12 +59,74 @@ async fn get(
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let mut events_and_assignments = Vec::new();
|
||||||
|
for e in Event::read_all_by_date_and_area_including_location(
|
||||||
|
pool.get_ref(),
|
||||||
|
date,
|
||||||
|
query.area.unwrap_or(user.area_id),
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
{
|
||||||
|
let assignments = Assignment::read_all_by_event(pool.get_ref(), e.id).await?;
|
||||||
|
let (posten, rest): (Vec<Assignment>, Vec<Assignment>) = assignments
|
||||||
|
.into_iter()
|
||||||
|
.partition(|a| a.function == Function::Posten);
|
||||||
|
let (wachhabender, fuehrungsassistent): (Vec<Assignment>, Vec<Assignment>) = rest
|
||||||
|
.into_iter()
|
||||||
|
.partition(|a| a.function == Function::Wachhabender);
|
||||||
|
|
||||||
|
events_and_assignments.push((
|
||||||
|
e,
|
||||||
|
posten
|
||||||
|
.into_iter()
|
||||||
|
.map(|p| {
|
||||||
|
availabillities
|
||||||
|
.iter()
|
||||||
|
.find(|a| a.id == p.availabillity_id)
|
||||||
|
.unwrap()
|
||||||
|
.user
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.name
|
||||||
|
.clone()
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
fuehrungsassistent.first().and_then(|fa| {
|
||||||
|
Some(
|
||||||
|
availabillities
|
||||||
|
.iter()
|
||||||
|
.find(|a| a.id == fa.availabillity_id)
|
||||||
|
.unwrap()
|
||||||
|
.user
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.name
|
||||||
|
.clone(),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
wachhabender.first().and_then(|wh| {
|
||||||
|
Some(
|
||||||
|
availabillities
|
||||||
|
.iter()
|
||||||
|
.find(|a| a.id == wh.availabillity_id)
|
||||||
|
.unwrap()
|
||||||
|
.user
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.name
|
||||||
|
.clone(),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
let template = CalendarTemplate {
|
let template = CalendarTemplate {
|
||||||
user: user.into_inner(),
|
user: user.into_inner(),
|
||||||
date,
|
date,
|
||||||
selected_area,
|
selected_area,
|
||||||
areas,
|
areas,
|
||||||
events,
|
events_and_assignments,
|
||||||
availabillities,
|
availabillities,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
40
web/src/endpoints/events/delete.rs
Normal file
40
web/src/endpoints/events/delete.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
use actix_web::{web, HttpResponse, Responder};
|
||||||
|
use sqlx::PgPool;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
endpoints::IdPath,
|
||||||
|
models::{Assignment, Event, Role, User},
|
||||||
|
utils::{self, ApplicationError},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[actix_web::delete("/events/{id}")]
|
||||||
|
pub async fn delete(
|
||||||
|
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 Ok(HttpResponse::BadRequest().body("Can't use location outside of your area"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let assignments_for_event = Assignment::read_all_by_event(pool.get_ref(), event.id).await?;
|
||||||
|
|
||||||
|
if assignments_for_event.len() > 0 {
|
||||||
|
return Ok(HttpResponse::BadRequest().body("Can't delete event when people are assigned"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Event::delete(pool.get_ref(), event.id).await?;
|
||||||
|
|
||||||
|
let url = utils::get_return_url_for_date(&event.date);
|
||||||
|
Ok(HttpResponse::Ok()
|
||||||
|
.insert_header(("HX-LOCATION", url))
|
||||||
|
.finish())
|
||||||
|
}
|
@ -4,11 +4,12 @@ use rinja::Template;
|
|||||||
|
|
||||||
use crate::models::{Event, Location, Role, User};
|
use crate::models::{Event, Location, Role, User};
|
||||||
|
|
||||||
|
pub mod delete;
|
||||||
pub mod get_edit;
|
pub mod get_edit;
|
||||||
pub mod get_new;
|
pub mod get_new;
|
||||||
pub mod get_plan;
|
pub mod get_plan;
|
||||||
pub mod post_new;
|
|
||||||
pub mod post_edit;
|
pub mod post_edit;
|
||||||
|
pub mod post_new;
|
||||||
pub mod put_cancelation;
|
pub mod put_cancelation;
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use actix_http::header::LOCATION;
|
|
||||||
use actix_web::{web, HttpResponse, Responder};
|
use actix_web::{web, HttpResponse, Responder};
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
|
|
||||||
@ -49,7 +48,6 @@ async fn handle_set_event_cancelation_to(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let url = utils::get_return_url_for_date(&event.date);
|
let url = utils::get_return_url_for_date(&event.date);
|
||||||
println!("redirecto to {url}");
|
|
||||||
Ok(HttpResponse::Ok()
|
Ok(HttpResponse::Ok()
|
||||||
.insert_header(("HX-LOCATION", url))
|
.insert_header(("HX-LOCATION", url))
|
||||||
.finish())
|
.finish())
|
||||||
|
@ -63,6 +63,7 @@ pub fn init(cfg: &mut ServiceConfig) {
|
|||||||
cfg.service(events::get_plan::get);
|
cfg.service(events::get_plan::get);
|
||||||
cfg.service(events::get_edit::get);
|
cfg.service(events::get_edit::get);
|
||||||
cfg.service(events::post_edit::post);
|
cfg.service(events::post_edit::post);
|
||||||
|
cfg.service(events::delete::delete);
|
||||||
|
|
||||||
cfg.service(assignment::post_new::post);
|
cfg.service(assignment::post_new::post);
|
||||||
cfg.service(assignment::delete::delete);
|
cfg.service(assignment::delete::delete);
|
||||||
|
@ -16,7 +16,7 @@ impl Assignment {
|
|||||||
pool: &PgPool,
|
pool: &PgPool,
|
||||||
event_id: i32,
|
event_id: i32,
|
||||||
availabillity_id: i32,
|
availabillity_id: i32,
|
||||||
changeset: AssignmentChangeset
|
changeset: AssignmentChangeset,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
query!(
|
query!(
|
||||||
r##"
|
r##"
|
||||||
|
@ -160,7 +160,21 @@ impl Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_cancelation(pool: &PgPool, id: i32, canceled: bool) -> Result<()> {
|
pub async fn update_cancelation(pool: &PgPool, id: i32, canceled: bool) -> Result<()> {
|
||||||
query!("UPDATE event SET canceled = $1 WHERE id = $2;", canceled, id).execute(pool).await?;
|
query!(
|
||||||
|
"UPDATE event SET canceled = $1 WHERE id = $2;",
|
||||||
|
canceled,
|
||||||
|
id
|
||||||
|
)
|
||||||
|
.execute(pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn delete(pool: &PgPool, id: i32) -> Result<()> {
|
||||||
|
query!("DELETE FROM event WHERE id = $1;", id)
|
||||||
|
.execute(pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -30,13 +30,21 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<button class="button is-danger" type="button">
|
{% let delete_disabled = amount_of_planned_posten > 0 || is_wachhabender_planned ||
|
||||||
|
is_fuehrungsassistent_planned %}
|
||||||
|
<button class="button is-danger" type="button" hx-delete="/events/{{ event.id }}" {{
|
||||||
|
delete_disabled|cond_show("disabled") }} hx-trigger="confirmed">
|
||||||
<svg class="icon">
|
<svg class="icon">
|
||||||
<use href="/static/feather-sprite.svg#x-circle" />
|
<use href="/static/feather-sprite.svg#x-circle" />
|
||||||
</svg>
|
</svg>
|
||||||
<span>Löschen</span>
|
<span>Löschen</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
{% if delete_disabled %}
|
||||||
|
<p class="help is-align-content-center">
|
||||||
|
Löschen nicht möglich, da bereits eine Planung existiert.
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -69,12 +69,12 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if events.len() == 0 %}
|
{% if events_and_assignments.len() == 0 %}
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<h5 class="subtitle is-5">keine Events geplant</h5>
|
<h5 class="subtitle is-5">keine Events geplant</h5>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% for event in events %}
|
{% for (event, posten, fuehrungsassistent, wachhabender) in events_and_assignments %}
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="fixed-grid has-1-cols-mobile">
|
<div class="fixed-grid has-1-cols-mobile">
|
||||||
<div class="grid content">
|
<div class="grid content">
|
||||||
@ -135,6 +135,28 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="cell is-col-span-2">
|
||||||
|
<hr class="my-1">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if let Some(wh) = wachhabender %}
|
||||||
|
<div class="cell">
|
||||||
|
<p><b>Wachhabender geplant:</b> {{ wh }}</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if let Some(fa) = fuehrungsassistent %}
|
||||||
|
<div class="cell">
|
||||||
|
<p><b>fuehrungsassistent geplant:</b> {{ fa }}</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if posten.len() > 0 %}
|
||||||
|
<div class="cell is-col-span-2">
|
||||||
|
<p><b>Posten:</b> {{ posten.join(", ")}}</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user