page edition done

This commit is contained in:
Artemis 2025-01-25 22:46:54 +01:00
parent 6652a35ae9
commit 4a72745ab4
6 changed files with 238 additions and 7 deletions

View file

@ -87,6 +87,48 @@ pub async fn create(db: &mut DbHook, doll: CreateDollProfile<'_>) -> sqlx::Resul
Ok(())
}
pub async fn edit(db: &mut DbHook, doll: CreateDollProfile<'_>) -> sqlx::Result<()> {
sqlx::query!(
r#"
update doll_profiles
set microchip_id = $1,
name = $2,
pronoun_subject = $3,
pronoun_object = $4,
pronoun_possessive = $5,
handler_name = $6,
handler_link = $7,
kind = $8,
breed = $9,
behaviour = $10,
description = $11,
chassis_type = $12,
chassis_id = $13,
chassis_color = $14
where id = $15
"#,
doll.microchip_id,
doll.name,
doll.pronoun_subject,
doll.pronoun_object,
doll.pronoun_possessive,
doll.handler_name,
doll.handler_link,
doll.kind,
doll.breed,
doll.behaviour,
doll.description,
doll.chassis_type,
doll.chassis_id,
doll.chassis_color,
doll.id,
)
.execute(&mut **db)
.await?;
Ok(())
}
/// deleting a doll profile only wipes the data associated to it but retains two bits of info:
/// - the tag's ID
/// - the account which created this tag

View file

@ -36,6 +36,8 @@ fn rocket() -> _ {
account::change_password,
form::register_tag::show_register,
form::register_tag::handle_register,
form::register_tag::show_edit_tag,
form::register_tag::handle_edit_tag,
account::ask_delete,
account::confirm_delete,
account::ask_terminate_account,

View file

@ -49,3 +49,17 @@ impl<'r> FromRequest<'r> for CommonTemplateState {
})
}
}
/// FakeContext exists to be used as a replacement for Context when reusing a form for creation and edition, to avoid repeating lots of code.
///
/// Note: i made this custom context thingy because i couldn't find a way to create a real context with the right populated data.
#[derive(Debug, Serialize)]
#[serde(crate = "rocket::serde")]
pub struct FakeContext {
/// Values are made to simulate the same structure as the real Context
pub values: HashMap<&'static str, Vec<String>>,
/// NOP, used to placehold field errors
pub errors: HashMap<String, ()>,
/// NOP, used to placehold global errors
pub form_errors: Vec<()>,
}

View file

@ -1,3 +1,5 @@
use std::collections::HashMap;
use rocket::{
form::{self, Contextual, Form},
response::Redirect,
@ -7,11 +9,11 @@ use rocket_dyn_templates::{context, Template};
use crate::{
db::{
doll,
schema::{CreateDollProfile, DollTagsDb, User},
schema::{CreateDollProfile, DollProfile, DollTagsDb, User},
},
ids::{id_public_to_db, pick_ids},
pages::CommonTemplateState,
routes::{error_handlers::PageResult, public},
pages::{CommonTemplateState, FakeContext},
routes::{account, error_handlers::PageResult, public},
};
#[get("/new_tag")]
@ -21,6 +23,7 @@ pub async fn show_register(db: DollTagsDb, _user: User, meta: CommonTemplateStat
Ok(Template::render(
"register_tag",
context! {
mode: "register",
ids,
previous: form::Context::default(),
meta,
@ -29,6 +32,78 @@ pub async fn show_register(db: DollTagsDb, _user: User, meta: CommonTemplateStat
.into())
}
impl From<DollProfile> for FakeContext {
fn from(tag: DollProfile) -> Self {
FakeContext {
values: HashMap::from([
("id", vec![format!("{:0>6}", tag.id)]),
(
"microchip_id",
vec![tag.microchip_id.unwrap_or(String::from(""))],
),
("name", vec![tag.name]),
("pronoun_subject", vec![tag.pronoun_subject]),
("pronoun_object", vec![tag.pronoun_object]),
("pronoun_possessive", vec![tag.pronoun_possessive]),
("handler_name", vec![tag.handler_name]),
(
"handler_link",
vec![tag.handler_link.unwrap_or(String::from(""))],
),
("kind", vec![tag.kind.unwrap_or(String::from(""))]),
("breed", vec![tag.breed.unwrap_or(String::from(""))]),
("behaviour", vec![tag.behaviour.unwrap_or(String::from(""))]),
(
"description",
vec![tag.description.unwrap_or(String::from(""))],
),
(
"chassis_type",
vec![tag.chassis_type.unwrap_or(String::from(""))],
),
(
"chassis_id",
vec![tag.chassis_id.unwrap_or(String::from(""))],
),
(
"chassis_color",
vec![tag.chassis_color.unwrap_or(String::from(""))],
),
]),
errors: HashMap::new(),
form_errors: vec![],
}
}
}
#[get("/edit_tag/<id>")]
pub async fn show_edit_tag(
mut db: DollTagsDb,
id: &str,
_user: User,
meta: CommonTemplateState,
) -> PageResult {
let normalized_id = match id_public_to_db(id) {
Some(v) => v,
None => return Ok(Redirect::to(uri!("/account", account::index)).into()),
};
let tag = match doll::get(&mut *db, normalized_id, "").await? {
Some(v) => v,
None => return Ok(Redirect::to(uri!("/account", account::index)).into()),
};
Ok(Template::render(
"register_tag",
context! {
mode: "edit",
id,
previous: FakeContext::from(tag),
meta,
},
)
.into())
}
#[derive(Debug, FromForm)]
pub struct TagForm<'a> {
#[field(validate=validate_id())]
@ -109,6 +184,7 @@ pub async fn handle_register(
return Ok(Template::render(
"register_tag",
context! {
mode: "register",
ids,
previous: &tag.context,
meta,
@ -160,3 +236,71 @@ pub async fn handle_register(
Ok(Redirect::to(uri!(public::show_profile(Some(tag.ident), microchip_id))).into())
}
#[post("/edit_tag/<id>", data = "<tag>")]
pub async fn handle_edit_tag(
mut db: DollTagsDb,
id: &str,
tag: Form<Contextual<'_, TagForm<'_>>>,
user: User,
meta: CommonTemplateState,
) -> PageResult {
let id = match id_public_to_db(id) {
None => return Ok(Redirect::to(uri!("/account", crate::routes::account::index)).into()),
Some(v) => v,
};
let tag = match tag.value {
Some(ref values) => values,
None => {
debug!("tag edition form invalid, context: {:?}", &tag.context);
return Ok(Template::render(
"register_tag",
context! {
mode: "edit",
id,
previous: &tag.context,
meta,
},
)
.into());
}
};
debug!("editing tag: {:?}", tag);
fn normalize_opt(opt: &str) -> Option<&str> {
if opt.len() != 0 {
Some(opt)
} else {
None
}
}
let normalized_microchip_id = tag.microchip_id.to_lowercase();
let microchip_id = normalize_opt(&normalized_microchip_id);
doll::edit(
&mut *db,
CreateDollProfile {
id,
microchip_id,
name: tag.name,
pronoun_subject: tag.pronoun_subject,
pronoun_object: tag.pronoun_object,
pronoun_possessive: tag.pronoun_possessive,
handler_name: tag.handler_name,
handler_link: normalize_opt(tag.handler_link),
kind: normalize_opt(tag.kind),
breed: normalize_opt(tag.breed),
behaviour: normalize_opt(tag.behaviour),
description: normalize_opt(tag.description),
chassis_type: normalize_opt(tag.chassis_type),
chassis_id: normalize_opt(tag.chassis_id),
chassis_color: normalize_opt(tag.chassis_color),
bound_to_id: &user.id,
},
)
.await?;
Ok(Redirect::to(uri!(public::show_profile(Some(tag.ident), microchip_id))).into())
}

View file

@ -32,7 +32,7 @@
<h3>{{profile.name}}</h3>
<div class="subnav">
<a href="/profile/{{profile.id}}">Public page</a>
<a href="/account/edit/{{profile.id}}">Edit</a>
<a href="/account/edit_tag/{{profile.id}}">Edit</a>
<a href="/account/delete/{{profile.id}}">Delete</a>
</div>
</article>

View file

@ -1,8 +1,10 @@
{% extends "base" %}
{% import "macros/form" as form %}
{% block title %}Register a new tag - {% endblock title %}
{% block title %}{% if mode == "register" %}Register a new tag{% else %}Edit {{id}}{% endif %} - {% endblock title
%}
{% block main %}
<h2>Register a new tag</h2>
<h2>{% if mode == "register" %}Register a new tag{% else %}Edit {{id}}{% endif %}</h2>
<aside>
<h3>A foreword</h3>
@ -15,7 +17,11 @@
</aside>
<section>
{% if mode == "register" %}
<h3>Now, to the registration!</h3>
{% else %}
<h3>Now, to the editing!</h3>
{% endif %}
{% if previous.form_errors | length > 0 %}
<div class="form-error">
@ -30,14 +36,24 @@
{% endif %}
<form method="POST">
{% if mode != "register" %}
<!-- No, changing this value in the HTML won't edit the tag, sorry :c it won't do anything but risk failing the edition -->
<input type="hidden" name="ident" value="{{id}}">
{% endif %}
<section>
<h4>Firstly, the tag's ID</h4>
{% if mode == "register" %}
<p>
You may enter your own, but in case of collision it will not be usable.<br />
To that end, here's a few free ones you may also pick from.
</p>
{% else %}
<p>You can't change a tag's ID for now. If it's something you'd like to do, contact me directly.</p>
{% endif %}
<div class="dual-fields bordered raised">
{% if mode == "register" %}
<div>
<p class="heading"><label for="ident">Enter its ID</label></p>
<input type="text" inputmode="numeric" pattern="\d{6}" id="ident" name="ident" required size="6"
@ -60,6 +76,13 @@
placeholder="A hexadecimal ID" {{form::value(ctx=previous, name="microchip_id" )}}>
{{form::error(ctx=previous, name="microchip_id")}}
</div>
{% else %}
<p class="heading"><label for="microchip_id">If it's microchipped,<br />you may enter the chip's
ID</label></p>
<input type="text" pattern="(0x)?[a-fA-F0-9]+" id="microchip_id" name="microchip_id"
placeholder="A hexadecimal ID" {{form::value(ctx=previous, name="microchip_id" )}}>
{{form::error(ctx=previous, name="microchip_id")}}
{% endif %}
</div>
</section>
@ -182,7 +205,13 @@
</div>
</section>
<button class="submit" type="submit">Register this tag!</button>
<button class="submit" type="submit">
{% if mode == "register" %}
Register this tag!
{% else %}
Save your changes
{% endif %}
</button>
</form>
</section>