feat: wip edit of area

This commit is contained in:
Max Hohlfeld 2024-10-24 15:54:51 +02:00
parent bbc23c39a8
commit e515057e14
11 changed files with 133 additions and 76 deletions

View File

@ -0,0 +1,31 @@
use actix_web::{web, HttpResponse, Responder};
use askama_actix::TemplateToResponse;
use sqlx::PgPool;
use crate::{
endpoints::{area::NewOrEditAreaTemplate, IdPath},
models::{Area, Role, User},
utils::ApplicationError,
};
#[actix_web::get("/area/edit/{id}")]
async fn get(
user: web::ReqData<User>,
pool: web::Data<PgPool>,
path: web::Path<IdPath>,
) -> Result<impl Responder, ApplicationError> {
if user.role != Role::Admin {
return Err(ApplicationError::Unauthorized);
}
if let Some(area_in_db) = Area::read_by_id(pool.get_ref(), path.id).await? {
let template = NewOrEditAreaTemplate {
user: user.into_inner(),
area: Some(area_in_db),
};
return Ok(template.to_response());
} else {
return Ok(HttpResponse::NotFound().finish());
}
}

View File

@ -1,14 +1,7 @@
use actix_web::{web, HttpResponse, Responder};
use askama::Template;
use askama_actix::TemplateToResponse;
use crate::models::{Role, User};
#[derive(Template)]
#[template(path = "area/new.html")]
struct NewAreaTemplate {
user: User,
}
use crate::{endpoints::area::NewOrEditAreaTemplate, models::{Role, User}};
#[actix_web::get("/area/new")]
async fn get(user: web::ReqData<User>) -> impl Responder {
@ -16,8 +9,9 @@ async fn get(user: web::ReqData<User>) -> impl Responder {
return HttpResponse::Unauthorized().finish();
}
let template = NewAreaTemplate {
let template = NewOrEditAreaTemplate {
user: user.into_inner(),
area: None
};
template.to_response()

View File

@ -1,2 +1,14 @@
pub mod get_new;
pub mod post_new;
pub mod get_edit;
use askama::Template;
use crate::models::{Area, Role, User};
#[derive(Template)]
#[template(path = "area/new_or_edit.html")]
struct NewOrEditAreaTemplate {
user: User,
area: Option<Area>,
}

View File

@ -32,7 +32,7 @@ pub async fn get(user: web::ReqData<User>, pool: web::Data<PgPool>) -> impl Resp
.unwrap();
let area = Area::read_by_id(pool.get_ref(), user.area_id)
.await
.unwrap();
.unwrap().unwrap();
grouped_locations = vec![(area, Vec::new())];
}

View File

@ -59,6 +59,7 @@ pub fn init(cfg: &mut ServiceConfig) {
cfg.service(area::get_new::get);
cfg.service(area::post_new::post);
cfg.service(area::get_edit::get);
cfg.service(export::get_availability::get);
cfg.service(export::get_availability_data::get);

View File

@ -27,7 +27,7 @@ pub async fn get_overview(user: Identity, pool: web::Data<PgPool>) -> impl Respo
area = Some(
Area::read_by_id(pool.get_ref(), current_user.area_id)
.await
.unwrap(),
.unwrap().unwrap(),
);
users = User::read_all_by_area(pool.get_ref(), current_user.area_id)
.await

View File

@ -16,7 +16,7 @@ pub async fn get(user: web::ReqData<User>, pool: web::Data<PgPool>) -> impl Resp
let area = Area::read_by_id(pool.get_ref(), user.area_id).await.unwrap();
let mut user = user.into_inner();
user.area = Some(area);
user.area = area;
let template = ProfileTemplate { user };

View File

@ -1,26 +1,33 @@
use super::Result;
use sqlx::{query, query_as, PgPool};
#[derive(Clone, Debug)]
pub struct Area {
pub id: i32,
pub name: String
pub name: String,
}
impl Area {
pub async fn create(pool: &PgPool, name: &str) -> anyhow::Result<i32> {
let result = query!("INSERT INTO area (name) VALUES ($1) RETURNING id;", name).fetch_one(pool).await?;
pub async fn create(pool: &PgPool, name: &str) -> Result<i32> {
let result = query!("INSERT INTO area (name) VALUES ($1) RETURNING id;", name)
.fetch_one(pool)
.await?;
Ok(result.id)
}
pub async fn read_by_id(pool: &PgPool, id: i32) -> anyhow::Result<Area> {
let record = query_as!(Area, "SELECT * FROM area WHERE id = $1", id).fetch_one(pool).await?;
pub async fn read_by_id(pool: &PgPool, id: i32) -> Result<Option<Area>> {
let record = query_as!(Area, "SELECT * FROM area WHERE id = $1", id)
.fetch_optional(pool)
.await?;
Ok(record)
}
pub async fn read_all(pool: &PgPool) -> anyhow::Result<Vec<Area>> {
let records = query_as!(Area, "SELECT * FROM area").fetch_all(pool).await?;
pub async fn read_all(pool: &PgPool) -> Result<Vec<Area>> {
let records = query_as!(Area, "SELECT * FROM area")
.fetch_all(pool)
.await?;
Ok(records)
}

View File

@ -10,7 +10,7 @@ pub trait Token {
pub struct NoneToken {}
impl Token for NoneToken {
async fn delete(&self, pool: &PgPool) -> Result<()> {
async fn delete(&self, _pool: &PgPool) -> Result<()> {
unimplemented!()
}
}

View File

@ -1,56 +0,0 @@
{% extends "nav.html" %}
{% block content %}
<section class="section">
<div class="container">
<form method="post" action="/area/new">
<h1 class="title">Neuen Bereich 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" required placeholder="Leipzig Ost" />
</div>
</div>
</div>
</div>
<div class="field is-horizontal">
<div class="field-label"></div>
<div class="field-body">
<div class="field is-grouped">
<div class="control">
<button class="button is-success">
<span class="icon">
<svg class="feather">
<use href="/static/feather-sprite.svg#check-circle" />
</svg>
</span>
<span>Speichern</span>
</button>
</div>
<div class="control">
<a class="button is-link is-light" hx-boost="true" href="/locations">
<span class="icon">
<svg class="feather">
<use href="/static/feather-sprite.svg#arrow-left" />
</svg>
</span>
<span>Zurück</span>
</a>
</div>
</div>
</div>
</div>
</form>
</div>
</section>
<script>
</script>
{% endblock %}

View File

@ -0,0 +1,68 @@
{% extends "nav.html" %}
{% block content %}
<section class="section">
<div class="container">
{% if area.is_some() %}
<form method="post" action="/area/edit/{{ area.as_ref().unwrap().id }}">
<h1 class="title">Bereich '{{ area.as_ref().unwrap().name }}' anlegen</h1>
{% else %}
<form method="post" action="/area/new">
<h1 class="title">Neuen Bereich anlegen</h1>
{% endif %}
<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" required placeholder="Leipzig Ost" {% if area.is_some() -%}
value="{{ area.as_ref().unwrap().name }}" {% endif -%} />
</div>
</div>
</div>
</div>
<div class="field is-horizontal">
<div class="field-label"></div>
<div class="field-body">
<div class="field is-grouped">
<div class="control">
<button class="button is-success">
<span class="icon">
<svg class="feather">
<use href="/static/feather-sprite.svg#check-circle" />
</svg>
</span>
<span>
{% if area.is_some() %}
Speichern
{% else %}
Erstellen
{% endif %}
</span>
</button>
</div>
<div class="control">
<a class="button is-link is-light" hx-boost="true" href="/locations">
<span class="icon">
<svg class="feather">
<use href="/static/feather-sprite.svg#arrow-left" />
</svg>
</span>
<span>Zurück</span>
</a>
</div>
</div>
</div>
</div>
</form>
</div>
</section>
<script>
</script>
{% endblock %}