This commit is contained in:
Oliver Walter
2026-06-06 15:37:42 +02:00
commit 5f43c19878
26 changed files with 2881 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
pub mod tool;
+235
View File
@@ -0,0 +1,235 @@
use serde::{Deserialize, Serialize};
use std::fmt;
// ---------------------------------------------------------------------------
// Tool Hauptstruktur
// ---------------------------------------------------------------------------
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Tool {
pub id: String,
pub name: String,
pub anzahl: Anzahl,
pub beschaffung: Beschaffung,
pub verwendung: Vec<String>,
pub tags: Vec<String>,
pub status: Status,
pub prioritaet: Prioritaet,
pub notizen: Option<String>,
pub verantwortlich: Option<String>,
pub erstellt_am: String, // ISO-8601, wird nur serverseitig gesetzt
}
#[cfg(feature = "ssr")]
impl Tool {
pub fn neu(input: NewTool) -> Self {
Tool {
id: uuid::Uuid::new_v4().to_string(),
erstellt_am: chrono::Utc::now().to_rfc3339(),
name: input.name,
anzahl: input.anzahl,
beschaffung: input.beschaffung,
verwendung: input.verwendung,
tags: input.tags,
status: input.status,
prioritaet: input.prioritaet,
notizen: input.notizen,
verantwortlich: input.verantwortlich,
}
}
}
// ---------------------------------------------------------------------------
// Anzahl
// ---------------------------------------------------------------------------
/// Entweder eine konkrete Zahl oder "Mehrere" (unbestimmt).
/// Flache Struct-Darstellung für problemlose TOML-Serialisierung.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Anzahl {
/// None bedeutet "Mehrere"
pub zahl: Option<u32>,
}
impl Anzahl {
pub fn zahl(n: u32) -> Self {
Self { zahl: Some(n) }
}
pub fn mehrere() -> Self {
Self { zahl: None }
}
pub fn ist_mehrere(&self) -> bool {
self.zahl.is_none()
}
}
impl Default for Anzahl {
fn default() -> Self {
Self::zahl(1)
}
}
impl fmt::Display for Anzahl {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.zahl {
Some(n) => write!(f, "{}", n),
None => write!(f, "Mehrere"),
}
}
}
// ---------------------------------------------------------------------------
// Beschaffung
// ---------------------------------------------------------------------------
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub enum BeschaffungsArt {
#[default]
Unbekannt,
InBesitz,
Leihen,
Mieten,
Kaufen,
}
impl fmt::Display for BeschaffungsArt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BeschaffungsArt::Unbekannt => write!(f, "Unbekannt"),
BeschaffungsArt::InBesitz => write!(f, "In Besitz"),
BeschaffungsArt::Leihen => write!(f, "Leihen"),
BeschaffungsArt::Mieten => write!(f, "Mieten"),
BeschaffungsArt::Kaufen => write!(f, "Kaufen"),
}
}
}
/// Flache Struct-Darstellung damit TOML-Serialisierung einfach bleibt.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct Beschaffung {
pub art: BeschaffungsArt,
/// Für Leihen: von wem
pub von: Option<String>,
/// Für Mieten/Kaufen: wo
pub wo: Option<String>,
/// Für Mieten/Kaufen: Preis in €
pub preis: Option<f64>,
}
impl fmt::Display for Beschaffung {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.art {
BeschaffungsArt::Unbekannt => write!(f, "Unbekannt"),
BeschaffungsArt::InBesitz => write!(f, "In Besitz"),
BeschaffungsArt::Leihen => {
if let Some(von) = &self.von {
write!(f, "Leihen (von {})", von)
} else {
write!(f, "Leihen")
}
}
BeschaffungsArt::Mieten => {
let wo = self.wo.as_deref().unwrap_or("?");
if let Some(p) = self.preis {
write!(f, "Mieten bei {} ({:.2} €)", wo, p)
} else {
write!(f, "Mieten bei {}", wo)
}
}
BeschaffungsArt::Kaufen => {
let wo = self.wo.as_deref().unwrap_or("?");
if let Some(p) = self.preis {
write!(f, "Kaufen bei {} ({:.2} €)", wo, p)
} else {
write!(f, "Kaufen bei {}", wo)
}
}
}
}
}
// ---------------------------------------------------------------------------
// Status
// ---------------------------------------------------------------------------
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub enum Status {
#[default]
Offen,
Organisiert,
VorOrt,
}
impl fmt::Display for Status {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Status::Offen => write!(f, "Offen"),
Status::Organisiert => write!(f, "Organisiert"),
Status::VorOrt => write!(f, "Vor Ort"),
}
}
}
// ---------------------------------------------------------------------------
// Prioritaet
// ---------------------------------------------------------------------------
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub enum Prioritaet {
Hoch,
#[default]
Mittel,
Niedrig,
}
impl fmt::Display for Prioritaet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Prioritaet::Hoch => write!(f, "Hoch"),
Prioritaet::Mittel => write!(f, "Mittel"),
Prioritaet::Niedrig => write!(f, "Niedrig"),
}
}
}
// ---------------------------------------------------------------------------
// NewTool Eingabe-Struct für Erstellen und Bearbeiten
// ---------------------------------------------------------------------------
// Wird als serde-Default für NewTool::anzahl verwendet, damit ein leeres
// Anzahl-Objekt (Mehrere = zahl: None, keine URL-Keys) korrekt deserialisiert.
fn default_anzahl_mehrere() -> Anzahl {
Anzahl::mehrere()
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct NewTool {
pub name: String,
#[serde(default = "default_anzahl_mehrere")]
pub anzahl: Anzahl,
pub beschaffung: Beschaffung,
#[serde(default)]
pub verwendung: Vec<String>,
#[serde(default)]
pub tags: Vec<String>,
pub status: Status,
pub prioritaet: Prioritaet,
pub notizen: Option<String>,
pub verantwortlich: Option<String>,
}
impl From<&Tool> for NewTool {
fn from(t: &Tool) -> Self {
NewTool {
name: t.name.clone(),
anzahl: t.anzahl.clone(),
beschaffung: t.beschaffung.clone(),
verwendung: t.verwendung.clone(),
tags: t.tags.clone(),
status: t.status.clone(),
prioritaet: t.prioritaet.clone(),
notizen: t.notizen.clone(),
verantwortlich: t.verantwortlich.clone(),
}
}
}