From 05b7b7fbbf7f720b37410b5004ed394376adbbff Mon Sep 17 00:00:00 2001 From: philipp Date: Mon, 4 Mar 2024 16:59:44 +0100 Subject: [PATCH] Create admin function to use copy-pasted users from ekey, return the ones which don't match to "Donau Linz" rowt user, Fixes #204 (#230) Reviewed-on: https://git.hofer.link/Ruderverein-Donau-Linz/rowt/pulls/230 --- Cargo.lock | 22 ++++++++++++ Cargo.toml | 1 + src/model/role.rs | 13 +++++++ src/model/user.rs | 2 +- src/tera/admin/mod.rs | 52 +++++++++++++++++++++++++-- templates/admin/list/index.html.tera | 12 +++++++ templates/admin/list/result.html.tera | 13 +++++++ 7 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 templates/admin/list/index.html.tera create mode 100644 templates/admin/list/result.html.tera diff --git a/Cargo.lock b/Cargo.lock index d425d3c..1e52887 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -521,6 +521,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 = "ctr" version = "0.9.2" @@ -2195,6 +2216,7 @@ dependencies = [ "argon2", "chrono", "chrono-tz", + "csv", "env_logger", "futures", "ics", diff --git a/Cargo.toml b/Cargo.toml index 259dd1c..7cd7572 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ tera = { version = "1.18", features = ["date-locale"], optional = true} ics = "0.5" futures = "0.3" lettre = "0.11" +csv = "1.3" [target.'cfg(not(windows))'.dependencies] openssl = { version = "0.10", features = [ "vendored" ] } diff --git a/src/model/role.rs b/src/model/role.rs index f66120c..c1a51ee 100644 --- a/src/model/role.rs +++ b/src/model/role.rs @@ -45,6 +45,19 @@ WHERE name like ? .ok() } + pub async fn names_from_role(&self, db: &SqlitePool) -> Vec { + let query = format!( + "SELECT u.name + FROM user u + JOIN user_role ur ON u.id = ur.user_id + JOIN role r ON ur.role_id = r.id + WHERE r.id = {} AND deleted=0;", + self.id + ); + + sqlx::query_scalar(&query).fetch_all(db).await.unwrap() + } + pub async fn mails_from_role(&self, db: &SqlitePool) -> Vec { let query = format!( "SELECT u.mail diff --git a/src/model/user.rs b/src/model/user.rs index 8dc5fcc..ba7a4b7 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -266,7 +266,7 @@ impl User { pub async fn roles(&self, db: &SqlitePool) -> Vec { sqlx::query!( - "SELECT r.name FROM role r JOIN user_role ur ON r.id = ur.role_id WHERE ur.user_id = ?;", + "SELECT r.name FROM role r JOIN user_role ur ON r.id = ur.role_id JOIN user u ON u.id = ur.user_id WHERE ur.user_id = ? AND u.deleted = 0;", self.id ) .fetch_all(db) diff --git a/src/tera/admin/mod.rs b/src/tera/admin/mod.rs index cb4e24d..27b24b8 100644 --- a/src/tera/admin/mod.rs +++ b/src/tera/admin/mod.rs @@ -1,8 +1,10 @@ -use rocket::{get, routes, Route, State}; +use csv::ReaderBuilder; +use rocket::{form::Form, get, post, routes, FromForm, Route, State}; +use rocket_dyn_templates::{context, Template}; use sqlx::SqlitePool; use crate::{ - model::{log::Log, user::AdminUser}, + model::{log::Log, role::Role, user::AdminUser}, tera::Config, }; @@ -25,12 +27,56 @@ async fn show_rss(db: &State, _admin: AdminUser) -> String { Log::show(db).await } +#[get("/list")] +async fn show_list(_admin: AdminUser) -> Template { + Template::render("admin/list/index", context!()) +} + +#[derive(FromForm)] +struct ListForm { + list: String, +} + +#[post("/list", data = "")] +async fn list(db: &State, _admin: AdminUser, list_form: Form) -> Template { + let role = Role::find_by_name(db, "Donau Linz").await.unwrap(); + let acceptable_users = role.names_from_role(db).await; + + let mut rdr = ReaderBuilder::new() + .has_headers(true) + .delimiter(b';') + .from_reader(list_form.list.trim().as_bytes()); + + let mut names_not_in_acceptable_users = Vec::new(); + + for result in rdr.records() { + println!("{result:?}"); + let record = result.unwrap(); + + // Concatenate Vorname and Nachname + let vorname = record.get(2).unwrap_or_default().trim(); + let nachname = record.get(3).unwrap_or_default().trim(); + let full_name = format!("{} {}", vorname, nachname); + + // Check if the concatenated name is not in the acceptable_users vector + if !acceptable_users.contains(&full_name) { + names_not_in_acceptable_users.push(full_name); + } + } + + let context = context! { + result: names_not_in_acceptable_users + }; + + Template::render("admin/list/result", &context) +} + pub fn routes() -> Vec { let mut ret = Vec::new(); ret.append(&mut user::routes()); ret.append(&mut boat::routes()); ret.append(&mut mail::routes()); ret.append(&mut planned_event::routes()); - ret.append(&mut routes![rss, show_rss]); + ret.append(&mut routes![rss, show_rss, show_list, list]); ret } diff --git a/templates/admin/list/index.html.tera b/templates/admin/list/index.html.tera new file mode 100644 index 0000000..6fe0e31 --- /dev/null +++ b/templates/admin/list/index.html.tera @@ -0,0 +1,12 @@ +{% import "includes/macros" as macros %} +{% extends "base" %} +{% block content %} + {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %} +
+

List

+
+ + +
+
+{% endblock content %} diff --git a/templates/admin/list/result.html.tera b/templates/admin/list/result.html.tera new file mode 100644 index 0000000..bc4c6b3 --- /dev/null +++ b/templates/admin/list/result.html.tera @@ -0,0 +1,13 @@ +{% import "includes/macros" as macros %} +{% extends "base" %} +{% block content %} + {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %} +
+

List - Result

+
    + {% for person in result%} +
  1. {{person}}
  2. + {% endfor %} +
+
+{% endblock content %}