merge upstream
All checks were successful
mnemo-build-and-publish / gractwo-mnemo-build (push) Successful in 45s

This commit is contained in:
2026-04-09 17:29:37 +00:00
4 changed files with 61 additions and 3 deletions

View File

@@ -97,6 +97,12 @@ pub enum LogAction {
pn: String, // primary name pn: String, // primary name
nn: String, // new name nn: String, // new name
}, },
DeletePersonName {
pid: Uuid,
nid: Uuid,
pn: String,
n: String,
},
SetPersonPrimaryName { SetPersonPrimaryName {
pid: Uuid, // person id pid: Uuid, // person id
nid: Uuid, // name id nid: Uuid, // name id
@@ -123,7 +129,9 @@ impl LogAction {
| Self::RenameTag { id, .. } | Self::RenameTag { id, .. }
| Self::DeleteTag { id, .. } | Self::DeleteTag { id, .. }
| Self::ManuallyChangeUsersPassword { id } => Some(*id), | Self::ManuallyChangeUsersPassword { id } => Some(*id),
Self::AddPersonName { pid, .. } | Self::SetPersonPrimaryName { pid, .. } => Some(*pid), Self::AddPersonName { pid, .. }
| Self::DeletePersonName { pid, .. }
| Self::SetPersonPrimaryName { pid, .. } => Some(*pid),
} }
} }
pub fn get_humanreadable_payload(&self) -> String { pub fn get_humanreadable_payload(&self) -> String {
@@ -154,6 +162,9 @@ impl LogAction {
LogAction::AddPersonName { pid, nid, pn, nn } => { LogAction::AddPersonName { pid, nid, pn, nn } => {
format!("Added name \"{nn}\" to ~{pn} (pid: {pid}; nid: {nid})") format!("Added name \"{nn}\" to ~{pn} (pid: {pid}; nid: {nid})")
} }
LogAction::DeletePersonName { pid, nid, pn, n } => {
format!("Deleted name \"{n}\" from ~{pn} (pid: {pid}; nid: {nid})")
}
LogAction::SetPersonPrimaryName { pid, nid, on, nn } => { LogAction::SetPersonPrimaryName { pid, nid, on, nn } => {
format!("~{on} now has primary name \"{nn}\" (pid: {pid}; nid: {nid})") format!("~{on} now has primary name \"{nn}\" (pid: {pid}; nid: {nid})")
} }

View File

@@ -171,6 +171,16 @@ impl Name {
})? })?
.collect::<Result<Vec<Name>, _>>()?) .collect::<Result<Vec<Name>, _>>()?)
} }
pub fn times_attributed(&self, conn: &Connection) -> Result<i64, PersonError> {
Ok(conn
.prepare("SELECT COUNT(*) FROM lines WHERE name_id = ?1")?
.query_row((&self.id,), |r| r.get(0))?)
}
pub fn delete(self, conn: &Connection) -> Result<(), PersonError> {
conn.prepare("DELETE FROM names WHERE id = ?1")?
.execute((&self.id,))?;
Ok(())
}
pub fn set_primary(&mut self, conn: &Connection) -> Result<(), PersonError> { pub fn set_primary(&mut self, conn: &Connection) -> Result<(), PersonError> {
if self.is_primary { if self.is_primary {
return Err(PersonError::AlreadyPrimary); return Err(PersonError::AlreadyPrimary);

View File

@@ -34,6 +34,7 @@ pub fn pages() -> Router {
.route("/persons/create", post(persons::create)) .route("/persons/create", post(persons::create))
.route("/persons/{id}", get(persons::profile::page)) .route("/persons/{id}", get(persons::profile::page))
.route("/persons/{id}/add-name", post(persons::profile::add_name)) .route("/persons/{id}/add-name", post(persons::profile::add_name))
.route("/names/{id}/delete", post(persons::profile::delete_name))
// //
.route("/logs", get(logs::page)) .route("/logs", get(logs::page))
// //

View File

@@ -12,7 +12,7 @@ use crate::{
database, database,
error::CompositeError, error::CompositeError,
logs::{LogAction, LogEntry}, logs::{LogAction, LogEntry},
persons::Person, persons::{Name, Person},
users::{ users::{
User, User,
auth::{AuthError, UserAuthRequired, UserAuthenticate}, auth::{AuthError, UserAuthRequired, UserAuthenticate},
@@ -29,7 +29,7 @@ pub async fn page(Path(id): Path<Uuid>, req: Request) -> Result<Response, AuthEr
let p = Person::get_by_id(&conn, id); let p = Person::get_by_id(&conn, id);
let title = match &p { let title = match &p {
Ok(p) => format!("~{} | Mnemosyne", p.primary_name), Ok(p) => format!("~{} | Mnemosyne", p.primary_name),
Err(_) => "Error!".into(), Err(_) => "Error! | Mnemosyne".into(),
}; };
Ok(base( Ok(base(
@@ -53,6 +53,13 @@ pub async fn page(Path(id): Path<Uuid>, req: Request) -> Result<Response, AuthEr
@if name.is_primary { @if name.is_primary {
span class="text-xs text-neutral-500" {"(primary)"} span class="text-xs text-neutral-500" {"(primary)"}
} }
@if let Ok(0) = name.times_attributed(&conn) {
form action=(format!("/names/{}/delete", name.id)) method="post" class="flex items-center ml-1" {
button type="submit" class="text-neutral-500 hover:text-red-400 flex items-center justify-center cursor-pointer" title="Delete" {
""
}
}
}
} }
} }
} @else { } @else {
@@ -109,3 +116,32 @@ pub async fn add_name(
Ok(Redirect::to(&format!("/persons/{}", p.id)).into_response()) Ok(Redirect::to(&format!("/persons/{}", p.id)).into_response())
} }
pub async fn delete_name(
Path(id): Path<Uuid>,
headers: HeaderMap,
) -> Result<Response, CompositeError> {
let u = User::authenticate(&headers)?.required()?;
let mut conn = database::conn()?;
let tx = conn.transaction()?;
let n = Name::get_by_id(&tx, id)?;
let p = Person::get_by_id(&tx, n.person_id)?;
let nn = n.name.clone();
n.delete(&tx)?;
LogEntry::new(
&tx,
u,
LogAction::DeletePersonName {
pid: p.id,
nid: id,
pn: p.primary_name,
n: nn,
},
)?;
tx.commit()?;
Ok(Redirect::to(&format!("/persons/{}", p.id)).into_response())
}