Added function for csv to members
This commit is contained in:
parent
e418456a82
commit
32d03540fd
22
Cargo.lock
generated
22
Cargo.lock
generated
@ -926,6 +926,27 @@ dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe"
|
||||
dependencies = [
|
||||
"csv-core",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv-core"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.10"
|
||||
@ -5831,6 +5852,7 @@ name = "wrbapp"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"csv",
|
||||
"dioxus",
|
||||
"dioxus-logger",
|
||||
"manganis",
|
||||
|
@ -16,6 +16,8 @@ axum = { version = "0.7.5", optional = true }
|
||||
once_cell = { version = "1.19.0", optional = true }
|
||||
surrealdb = { version = "1.5.4", features = ["kv-speedb"], optional = true }
|
||||
|
||||
csv = { version = "1.3.0", optional = true }
|
||||
|
||||
# Debug
|
||||
tracing = "0.1.40"
|
||||
dioxus-logger = "0.5.0"
|
||||
@ -23,5 +25,5 @@ manganis = "0.2.2"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
server = [ "dioxus/axum", "tokio", "axum", "once_cell", "surrealdb" ]
|
||||
server = [ "dioxus/axum", "tokio", "axum", "once_cell", "surrealdb", "csv" ]
|
||||
web = ["dioxus/web"]
|
||||
|
@ -818,7 +818,48 @@ html {
|
||||
content: var(--tw-content);
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.dropdown > *:not(summary):focus {
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.dropdown .dropdown-content {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.dropdown:is(:not(details)) .dropdown-content {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transform-origin: top;
|
||||
--tw-scale-x: .95;
|
||||
--tw-scale-y: .95;
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter;
|
||||
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
|
||||
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
||||
transition-duration: 200ms;
|
||||
}
|
||||
|
||||
.dropdown.dropdown-open .dropdown-content,
|
||||
.dropdown:not(.dropdown-hover):focus .dropdown-content,
|
||||
.dropdown:focus-within .dropdown-content {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.dropdown.dropdown-hover:hover .dropdown-content {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: var(--fallback-b3,oklch(var(--b3)/var(--tw-border-opacity)));
|
||||
@ -879,6 +920,16 @@ html {
|
||||
border-color: color-mix(in oklab, var(--fallback-p,oklch(var(--p)/1)) 90%, black);
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown.dropdown-hover:hover .dropdown-content {
|
||||
--tw-scale-x: 1;
|
||||
--tw-scale-y: 1;
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown:is(details) summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.input {
|
||||
@ -906,6 +957,12 @@ html {
|
||||
margin-inline-end: -1rem;
|
||||
}
|
||||
|
||||
.join .dropdown .join-item:first-child:not(:last-child),
|
||||
.join *:first-child:not(:last-child) .dropdown .join-item {
|
||||
border-start-end-radius: inherit;
|
||||
border-end-end-radius: inherit;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -1024,6 +1081,14 @@ html {
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown.dropdown-open .dropdown-content,
|
||||
.dropdown:focus .dropdown-content,
|
||||
.dropdown:focus-within .dropdown-content {
|
||||
--tw-scale-x: 1;
|
||||
--tw-scale-y: 1;
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
.input input {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity)));
|
||||
|
@ -1 +1,2 @@
|
||||
#[cfg(feature = "server")]
|
||||
pub mod member;
|
||||
|
@ -1,15 +1,19 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
mod migration;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct Member {
|
||||
id: String,
|
||||
name: Name,
|
||||
hours: Vec<String>,
|
||||
groups: Vec<String>,
|
||||
hours: BTreeSet<String>,
|
||||
groups: BTreeSet<String>,
|
||||
diploma: Option<String>,
|
||||
registration_token: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct Name {
|
||||
first: String,
|
||||
last: String,
|
||||
full: String,
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use super::Member;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{BTreeSet, HashMap, HashSet};
|
||||
|
||||
// Create a store for saving information when migrating to a new members list
|
||||
static MEMBERS_STORE: Lazy<MembersStore> = Lazy::new(|| MembersStore::new());
|
||||
@ -33,10 +34,146 @@ impl MembersStore {
|
||||
}
|
||||
}
|
||||
|
||||
impl Member {
|
||||
async fn migrate() {}
|
||||
// Create a row for the csv file
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
struct Row {
|
||||
#[serde(rename = "Relatiecode")]
|
||||
id: String,
|
||||
#[serde(rename = "Roepnaam")]
|
||||
first_name: String,
|
||||
#[serde(rename = "Tussenvoegsel(s)")]
|
||||
middle_name: String,
|
||||
#[serde(rename = "Achternaam")]
|
||||
last_name: String,
|
||||
#[serde(rename = "E-mail")]
|
||||
email: String,
|
||||
#[serde(rename = "Verenigingssporten")]
|
||||
hours: String,
|
||||
#[serde(rename = "Diploma dropdown 1")]
|
||||
diploma: Option<String>,
|
||||
}
|
||||
|
||||
fn csv_to_vec(input: String) -> Result<Vec<Member>, ()> {
|
||||
Ok(vec![])
|
||||
impl Row {
|
||||
fn to_member(&self) -> Member {
|
||||
Member {
|
||||
id: self.id.trim().to_string(),
|
||||
name: super::Name {
|
||||
first: self.first_name.clone(),
|
||||
full: self.generate_full_name(),
|
||||
},
|
||||
hours: self.generate_hours(),
|
||||
groups: BTreeSet::new(),
|
||||
diploma: self.diploma.clone(),
|
||||
registration_token: None,
|
||||
}
|
||||
}
|
||||
|
||||
// Get the hour data from the raw string
|
||||
fn generate_hours(&self) -> BTreeSet<String> {
|
||||
let mut hours: BTreeSet<String> = BTreeSet::new();
|
||||
|
||||
let group_parts: Vec<&str> = self.hours.split(", ").collect();
|
||||
|
||||
for group in group_parts {
|
||||
let hour_parts: Vec<&str> = group.split(" - ").collect();
|
||||
|
||||
for part in hour_parts {
|
||||
if &*part != "Groep" {
|
||||
hours.insert(part.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hours
|
||||
}
|
||||
|
||||
// Generate the full name from 3 parts
|
||||
fn generate_full_name(&self) -> String {
|
||||
let mut parts: Vec<&str> = vec![];
|
||||
|
||||
parts.push(&self.first_name);
|
||||
parts.push(&self.middle_name);
|
||||
parts.push(&self.last_name);
|
||||
|
||||
let filtered_strings: Vec<&str> = parts.into_iter().filter(|s| !s.is_empty()).collect();
|
||||
|
||||
filtered_strings.join(" ")
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the raw csv file to rust objects
|
||||
fn csv_to_rows(input: String) -> Result<Vec<Row>, Box<dyn std::error::Error>> {
|
||||
let mut members: Vec<Row> = vec![];
|
||||
|
||||
let mut rdr = csv::Reader::from_reader(input.as_bytes());
|
||||
|
||||
for result in rdr.deserialize() {
|
||||
let row: Row = result?;
|
||||
members.push(row);
|
||||
}
|
||||
|
||||
Ok(members)
|
||||
}
|
||||
|
||||
// Covert the rows to formatted members
|
||||
fn rows_to_members(rows: Vec<Row>) -> Vec<Member> {
|
||||
let mut members: Vec<Member> = vec![];
|
||||
|
||||
for row in rows {
|
||||
members.push(row.to_member());
|
||||
}
|
||||
|
||||
members
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn csv_to_members_test() -> Result<(), String> {
|
||||
let data = "Relatiecode,Volledige naam (1),Roepnaam,Tussenvoegsel(s),Achternaam,E-mail,2e E-mail,Verenigingssporten,Diploma dropdown 1
|
||||
D000001,\"Last, First\",First,,Last,first.last@example.com,first.last@example.nl,\"Groep - Wedstrijd - Zaterdag, Groep - Z5 - Zaterdag\",LS1
|
||||
D000002,\"Last2, First2\",First2,,Last2,first1.last@example.nl,,Groep - Z5 - Zaterdag,ZR4".to_string();
|
||||
|
||||
let expected = vec![
|
||||
Member {
|
||||
id: "D000001".to_string(),
|
||||
name: super::super::Name {
|
||||
first: "First".to_string(),
|
||||
full: "First Last".to_string(),
|
||||
},
|
||||
hours: BTreeSet::from([
|
||||
"Wedstrijd".to_string(),
|
||||
"Z5".to_string(),
|
||||
"Zaterdag".to_string(),
|
||||
]),
|
||||
groups: BTreeSet::new(),
|
||||
diploma: Some("LS1".to_string()),
|
||||
registration_token: None,
|
||||
},
|
||||
Member {
|
||||
id: "D000002".to_string(),
|
||||
name: super::super::Name {
|
||||
first: "First2".to_string(),
|
||||
full: "First2 Last2".to_string(),
|
||||
},
|
||||
hours: BTreeSet::from(["Z5".to_string(), "Zaterdag".to_string()]),
|
||||
groups: BTreeSet::new(),
|
||||
diploma: Some("ZR4".to_string()),
|
||||
registration_token: None,
|
||||
},
|
||||
];
|
||||
|
||||
let rows = match csv_to_rows(data) {
|
||||
Ok(r) => r,
|
||||
Err(err) => return Err(err.to_string()),
|
||||
};
|
||||
|
||||
let members = rows_to_members(rows);
|
||||
|
||||
assert_eq!(expected, members);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user