feat: styling of clothing input
This commit is contained in:
parent
8d4a981055
commit
045a509daf
@ -1,4 +1,5 @@
|
||||
use askama::Template;
|
||||
use garde::Validate;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::models::Clothing;
|
||||
@ -25,7 +26,16 @@ struct ReadClothingPartialTemplate {
|
||||
c: Clothing,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, Validate)]
|
||||
struct NewOrEditClothingForm {
|
||||
#[garde(length(min=3), custom(alphanumeric_or_space))]
|
||||
name: String,
|
||||
}
|
||||
|
||||
fn alphanumeric_or_space(value: &str, _context: &()) -> garde::Result {
|
||||
if value.chars().all(|c| c.is_alphanumeric() || c == ' ') {
|
||||
return Ok(())
|
||||
} else {
|
||||
return Err(garde::Error::new("Eingabe enthält unerlaubte Zeichen. Erlaubt sind Buchstaben, Zahlen und Leerzeichen."));
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use actix_web::{web, HttpResponse, Responder};
|
||||
use garde::Validate;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::{
|
||||
@ -17,7 +18,7 @@ pub async fn post(
|
||||
path: web::Path<IdPath>,
|
||||
form: web::Form<NewOrEditClothingForm>,
|
||||
) -> Result<impl Responder, ApplicationError> {
|
||||
if user.role == Role::Admin {
|
||||
if user.role != Role::Admin {
|
||||
return Err(ApplicationError::Unauthorized);
|
||||
}
|
||||
|
||||
@ -25,6 +26,10 @@ pub async fn post(
|
||||
return Ok(HttpResponse::NotFound().finish());
|
||||
};
|
||||
|
||||
if let Err(e) = form.validate() {
|
||||
return Ok(HttpResponse::UnprocessableEntity().body(e.to_string()));
|
||||
};
|
||||
|
||||
clothing.name = form.name.to_string();
|
||||
|
||||
Clothing::update(pool.get_ref(), clothing.id, &clothing.name).await?;
|
||||
|
@ -1,4 +1,5 @@
|
||||
use actix_web::{web, Responder};
|
||||
use actix_web::{web, HttpResponse, Responder};
|
||||
use garde::Validate;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::{
|
||||
@ -13,10 +14,14 @@ pub async fn post(
|
||||
pool: web::Data<PgPool>,
|
||||
form: web::Form<NewOrEditClothingForm>,
|
||||
) -> Result<impl Responder, ApplicationError> {
|
||||
if user.role == Role::Admin {
|
||||
if user.role != Role::Admin {
|
||||
return Err(ApplicationError::Unauthorized);
|
||||
}
|
||||
|
||||
if let Err(e) = form.validate() {
|
||||
return Ok(HttpResponse::UnprocessableEntity().body(e.to_string()));
|
||||
};
|
||||
|
||||
let clothing = Clothing::create(pool.get_ref(), &form.name).await?;
|
||||
|
||||
let template = ReadClothingPartialTemplate { c: clothing };
|
||||
|
@ -95,10 +95,10 @@ pub fn init(cfg: &mut ServiceConfig) {
|
||||
cfg.service(vehicle_assignment::delete::delete);
|
||||
|
||||
cfg.service(clothing::get_overview::get);
|
||||
cfg.service(clothing::get_edit::get);
|
||||
cfg.service(clothing::get_new::get);
|
||||
cfg.service(clothing::get_edit::get);
|
||||
cfg.service(clothing::get_read::get);
|
||||
cfg.service(clothing::delete::delete);
|
||||
cfg.service(clothing::post_new::post);
|
||||
cfg.service(clothing::post_edit::post);
|
||||
cfg.service(clothing::post_new::post);
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ impl Clothing {
|
||||
}
|
||||
|
||||
pub async fn read_all(pool: &PgPool) -> Result<Vec<Clothing>> {
|
||||
let records = query!("SELECT * FROM clothing;").fetch_all(pool).await?;
|
||||
let records = query!("SELECT * FROM clothing ORDER by id;").fetch_all(pool).await?;
|
||||
|
||||
let clothing_options = records
|
||||
.into_iter()
|
||||
|
@ -18,6 +18,7 @@ $primary: $crimson,
|
||||
@forward "bulma/sass/components/navbar";
|
||||
@forward "bulma/sass/components/message";
|
||||
@forward "bulma/sass/components/dropdown";
|
||||
@forward "bulma/sass/components/panel";
|
||||
|
||||
@forward "bulma/sass/elements/button";
|
||||
@forward "bulma/sass/elements/box";
|
||||
|
@ -1,26 +1,32 @@
|
||||
<li>
|
||||
<form method="post" action="/clothing/{% if let Some(id) = id %}{{ id }}{% else %}new{% endif %}">
|
||||
{% if id.is_none() %}<a class="panel-block is-active">{% endif %}
|
||||
<form hx-post="/clothing{% if let Some(id) = id %}/{{ id }}{% endif %}" hx-target="closest a" hx-target-422="find p">
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<input class="input" type="text" {{ name|insert_value }} />
|
||||
<div class="field">
|
||||
<label class="label"></label>
|
||||
<div class="control">
|
||||
<input class="input" name="name" type="text" {{ name|insert_value|safe }}
|
||||
_="on input put '' into the next <p/>" placeholder="Tuchuniform" minlength="3" />
|
||||
</div>
|
||||
<p class="help is-danger"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="level-item buttons are-small">
|
||||
<button class="button">
|
||||
<button class="button is-success">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#check-circle" />
|
||||
</svg>
|
||||
</button>
|
||||
{% if let Some(id) = id %}
|
||||
<button class="button" type="button" hx-get="/clothing/{{ id }}" hx-swap="outerHTML"
|
||||
hx-target="closest li">
|
||||
<button class="button is-warning is-light" type="button" hx-get="/clothing/{{ id }}" hx-target="closest a">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#x-circle" />
|
||||
</svg>
|
||||
</button>
|
||||
{% else %}
|
||||
<button class="button" type="button" _="on click remove the closest <li/>">
|
||||
<button class="button is-warning" type="button" _="on click remove the closest <a/>">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#x-circle" />
|
||||
</svg>
|
||||
@ -30,4 +36,5 @@
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</li>
|
||||
{% if id.is_none() %}
|
||||
</a>{% endif %}
|
||||
|
@ -1,23 +1,21 @@
|
||||
<li>
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
{{ c.name }}
|
||||
</div>
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
{{ c.name }}
|
||||
</div>
|
||||
|
||||
<div class="level-item buttons are-small">
|
||||
<button class="button" hx-get="/clothing/edit/{{ c.id }}" hx-swap="outerHTML" hx-target="closest li">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#edit" />
|
||||
</svg>
|
||||
</button>
|
||||
<button class="button" hx-delete="/clothing/{{ c.id }}" hx-swap="delete"
|
||||
hx-target="closest li" hx-trigger="confirmed">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#trash-2" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="level-item buttons are-small">
|
||||
<button class="button is-success is-light" hx-get="/clothing/edit/{{ c.id }}" hx-target="closest a">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#edit" />
|
||||
</svg>
|
||||
</button>
|
||||
<button class="button is-danger is-light" hx-delete="/clothing/{{ c.id }}" hx-swap="delete"
|
||||
hx-target="closest a" hx-trigger="confirmed">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#trash-2" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</div>
|
||||
|
@ -6,17 +6,22 @@
|
||||
<h3 class="title is-3">
|
||||
Anzugsordnungen
|
||||
</h3>
|
||||
<p class="content">zur Auswahl bei der Erstellung von Events</p>
|
||||
<p class="subtitle is-5">zur Auswahl bei der Erstellung von Events</p>
|
||||
|
||||
<div class="box">
|
||||
<ul>
|
||||
{% for c in clothings %}
|
||||
<div class="panel p-2">
|
||||
{% for c in clothings %}
|
||||
<a class="panel-block is-active">
|
||||
{% include "clothing_entry_read.html" %}
|
||||
{% endfor %}
|
||||
<li>
|
||||
<button hx-get="/clothing/new" hx-swap="beforebegin">neue Anzugsordnung +</button>
|
||||
</li>
|
||||
</ul>
|
||||
</a>
|
||||
{% endfor %}
|
||||
<div class="panel-block">
|
||||
<button class="button is-link is-light" hx-get="/clothing/new" hx-swap="beforebegin" hx-target="closest div">
|
||||
<svg class="icon">
|
||||
<use href="/static/feather-sprite.svg#plus-circle" />
|
||||
</svg>
|
||||
<span>neue Anzugsordnung</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user