feat: location overview and creation

This commit is contained in:
Max Hohlfeld 2024-03-13 23:50:46 +01:00
parent b4baa6ac9e
commit 28c562d82f
7 changed files with 170 additions and 12 deletions

View File

@ -0,0 +1,38 @@
use actix_identity::Identity;
use actix_web::{web, HttpResponse, Responder};
use askama::Template;
use askama_actix::TemplateToResponse;
use sqlx::PgPool;
use crate::models::{Area, Role, User};
#[derive(Template)]
#[template(path = "location/new.html")]
pub struct NewLocationTemplate {
user: User,
areas: Option<Vec<Area>>,
}
#[actix_web::get("/locations/new")]
pub async fn get(user: Identity, pool: web::Data<PgPool>) -> impl Responder {
let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap())
.await
.unwrap();
if current_user.role == Role::AreaManager || current_user.role == Role::Admin {
let mut areas = None;
if current_user.role == Role::Admin {
areas = Some(Area::read_all(pool.get_ref()).await.unwrap());
}
let template = NewLocationTemplate {
user: current_user,
areas,
};
return template.to_response();
}
return HttpResponse::Unauthorized().finish();
}

View File

@ -10,8 +10,7 @@ use crate::models::{Area, Location, Role, User};
#[template(path = "location/overview.html")] #[template(path = "location/overview.html")]
pub struct LocationsTemplate { pub struct LocationsTemplate {
user: User, user: User,
area: Option<Area>, grouped_locations: Vec<(Area, Vec<Location>)>
locations: Vec<Location>
} }
#[actix_web::get("/locations")] #[actix_web::get("/locations")]
@ -19,20 +18,29 @@ pub async fn get(user: Identity, pool: web::Data<PgPool>) -> impl Responder {
let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap()).await.unwrap(); let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap()).await.unwrap();
if current_user.role == Role::AreaManager || current_user.role == Role::Admin { if current_user.role == Role::AreaManager || current_user.role == Role::Admin {
let mut area = None; let mut locations;
let locations;
if current_user.role == Role::Admin { if current_user.role == Role::Admin {
locations = Location::read_all_including_area(pool.get_ref()).await.unwrap(); locations = Location::read_all_including_area(pool.get_ref()).await.unwrap();
} else { } else {
locations = Location::read_by_area(pool.get_ref(), current_user.area_id).await.unwrap(); locations = Location::read_by_area(pool.get_ref(), current_user.area_id).await.unwrap();
area = Some(Area::read_by_id(pool.get_ref(), current_user.area_id).await.unwrap());
} }
let template = LocationsTemplate { user: current_user, area, locations}; let mut grouped_locations = Vec::new();
let areas: Vec<Area> = locations.iter().map(|l| l.area.clone().unwrap()).collect();
for area in areas {
let (locations_in_this_area, rest): (Vec<_>, Vec<_>) = locations.into_iter().partition(|l| l.area_id == area.id);
locations = rest;
grouped_locations.push((area, locations_in_this_area))
}
let template = LocationsTemplate { user: current_user, grouped_locations };
return template.to_response() return template.to_response()
} }
return HttpResponse::BadRequest().body("Fehler beim Zugriff auf die Veranstaltungsorte!"); return HttpResponse::Unauthorized().finish();
} }

View File

@ -1 +1,3 @@
pub mod get_overview; pub mod get_overview;
pub mod get_new;
pub mod post_new;

View File

@ -0,0 +1,34 @@
use actix_identity::Identity;
use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
use serde::Deserialize;
use sqlx::PgPool;
use crate::models::{Location, Role, User};
#[derive(Deserialize)]
pub struct NewLocationForm {
name: String,
area: Option<i32>,
}
#[actix_web::post("/locations/new")]
pub async fn post(user: Identity, pool: web::Data<PgPool>, form: web::Form<NewLocationForm>) -> impl Responder {
let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap())
.await
.unwrap();
if current_user.role == Role::AreaManager || current_user.role == Role::Admin {
let mut area_id = current_user.area_id;
if current_user.role == Role::Admin && form.area.is_some() {
area_id = form.area.unwrap();
}
match Location::create(pool.get_ref(), &form.name, area_id).await {
Ok(_) => return HttpResponse::Found().insert_header((LOCATION, "/locations")).finish(),
Err(err) => println!("{}", err)
}
}
return HttpResponse::Unauthorized().finish();
}

View File

@ -11,6 +11,8 @@ pub struct IdPath {
pub fn init(cfg: &mut ServiceConfig) { pub fn init(cfg: &mut ServiceConfig) {
cfg.service(location::get_overview::get); cfg.service(location::get_overview::get);
cfg.service(location::get_new::get);
cfg.service(location::post_new::post);
cfg.service(user::get_overview::get_overview); cfg.service(user::get_overview::get_overview);
cfg.service(user::get_new::get_new); cfg.service(user::get_new::get_new);

View File

@ -0,0 +1,63 @@
{% extends "nav.html" %}
{% block content %}
<section class="section">
<div class="container">
<form method="post" action="/locations/new">
<h1 class="title">Neuen Ort anlegen</h1>
<div class="field is-horizontal">
<div class="field-label">
<label class="label">Name</label>
</div>
<div class="field-body">
<div class="field">
<div class="control">
<input class="input" type="text" name="name" placeholder="Zentralstadion"/>
</div>
</div>
</div>
</div>
{% if user.role == Role::Admin %}
<div class="field is-horizontal">
<div class="field-label">
<label class="label">Bereich</label>
</div>
<div class="field-body">
<div class="field is-narrow">
<div class="control">
<div class="select is-fullwidth">
<select name="area">
{% for area in areas.as_ref().unwrap() %}
<option value="{{ area.id }}">{{ area.name }}</option>
{% endfor %}
</select>
</div>
</div>
</div>
</div>
</div>
{% endif %}
<div class="field is-horizontal">
<div class="field-label"></div>
<div class="field-body">
<div class="field is-grouped">
<div class="control">
<input class="button is-link" type="submit" value="Erstellen">
</div>
<div class="control">
<a class="button is-link is-light" href="/locations">Zurück</a>
</div>
</div>
</div>
</div>
</form>
</div>
</section>
<script>
</script>
{% endblock %}

View File

@ -6,22 +6,33 @@
<div class="level"> <div class="level">
<div class="level-left"> <div class="level-left">
<h3 class="title is-3"> <h3 class="title is-3">
Veranstaltungsorte im Bereich Veranstaltungsorte
</h3> </h3>
</div> </div>
<div class="level-right"> <div class="level-right">
<a class="button" href="/event/new">Neues Event für diesen Tag</a> <a class="button" href="/locations/new">Neuen Ort anlegen</a>
</div> </div>
</div> </div>
{% if locations.len() == 0 %} {% if grouped_locations.len() == 0 %}
<div class="box"> <div class="box">
<h5 class="title is-5">keine Orte vorhanden</h5> <h5 class="title is-5">keine Orte vorhanden</h5>
</div> </div>
{% else %} {% else %}
{% for location in locations %} {% for gl in grouped_locations %}
<div class="box"> <div class="box">
<h5 class="title is-5">{{ location.name }}</h5> <h5 class="title is-5">{{ gl.0.name }}</h5>
{% for l in gl.1 %}
<div class="level">
<div clas="level-left">
<em>{{ l.name }}</em>
</div>
<div clas="level-right">
<a class="button">Bearbeiten</a>
<a class="button">Löschen</a>
</div>
</div>
{% endfor %}
</div> </div>
{% endfor %} {% endfor %}
{% endif %} {% endif %}