This commit is contained in:
parent
a38b47c223
commit
5303be8aca
653
Cargo.lock
generated
653
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -13,7 +13,8 @@ sqlx = { version = "0.5.13", features = ["runtime-tokio-rustls", "postgres", "ch
|
||||||
tokio = { version = "1.19.2", features = ["full"] }
|
tokio = { version = "1.19.2", features = ["full"] }
|
||||||
uuid = { version = "0.8", features = ["serde", "v4"] }
|
uuid = { version = "0.8", features = ["serde", "v4"] }
|
||||||
tower-http = { version = "0.3.4", features = ["fs", "trace"] }
|
tower-http = { version = "0.3.4", features = ["fs", "trace"] }
|
||||||
serde = { version = "1.0.137", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
argon2 = "0.4.0"
|
argon2 = "0.4.0"
|
||||||
axum-extra = { version = "0.3.4", features = ["cookie"] }
|
axum-extra = { version = "0.3.4", features = ["cookie"] }
|
||||||
|
regex = "1.7.0"
|
||||||
|
|
|
@ -14,5 +14,3 @@ services:
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "4567:8080"
|
- "4567:8080"
|
||||||
links:
|
|
||||||
- db
|
|
||||||
|
|
46
src/main.rs
46
src/main.rs
|
@ -13,6 +13,7 @@ use axum::{
|
||||||
use axum_extra::extract::{cookie::Cookie, CookieJar};
|
use axum_extra::extract::{cookie::Cookie, CookieJar};
|
||||||
use db::{Database, Db, Party, Ticket, User};
|
use db::{Database, Db, Party, Ticket, User};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
use regex::Regex;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::postgres::PgPoolOptions;
|
use sqlx::postgres::PgPoolOptions;
|
||||||
use tower_http::services::ServeDir;
|
use tower_http::services::ServeDir;
|
||||||
|
@ -405,6 +406,50 @@ async fn stats(
|
||||||
Json(StatResponse { total, inside })
|
Json(StatResponse { total, inside })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
struct CSVScan {
|
||||||
|
party: i32,
|
||||||
|
csv: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
struct CSVScanResponse {
|
||||||
|
scanned: i32,
|
||||||
|
with_coins: i32,
|
||||||
|
total: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn tickets_csv(
|
||||||
|
_: User,
|
||||||
|
Extension(pool): Extension<Database>,
|
||||||
|
Json(csv_scan): Json<CSVScan>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let llnr_regex = Regex::new(r".*(\d{6}).*").unwrap();
|
||||||
|
let coins_regex = Regex::new(r".*COINS.*").unwrap();
|
||||||
|
let party = csv_scan.party;
|
||||||
|
let mut total = 0;
|
||||||
|
let mut with_coins = 0;
|
||||||
|
let mut scanned = 0;
|
||||||
|
for l in csv_scan.csv.lines() {
|
||||||
|
total += 1;
|
||||||
|
if let Some(captures) = llnr_regex.captures(l) {
|
||||||
|
if let Some(llnr) = captures.get(1) {
|
||||||
|
let has_coins = coins_regex.is_match(l);
|
||||||
|
pool.add_ticket(party, llnr.as_str(), has_coins).await;
|
||||||
|
scanned += 1;
|
||||||
|
if has_coins {
|
||||||
|
with_coins += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Json(CSVScanResponse {
|
||||||
|
scanned,
|
||||||
|
with_coins,
|
||||||
|
total,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let url = if let Some(url) = std::env::var("DATABASE_URL").ok() {
|
let url = if let Some(url) = std::env::var("DATABASE_URL").ok() {
|
||||||
|
@ -438,6 +483,7 @@ async fn main() {
|
||||||
.route("/party/:id/export", get(export_party))
|
.route("/party/:id/export", get(export_party))
|
||||||
.route("/party/:id/lijst", get(party_goers))
|
.route("/party/:id/lijst", get(party_goers))
|
||||||
.route("/api/ticket", get(get_tickets).post(scan_card))
|
.route("/api/ticket", get(get_tickets).post(scan_card))
|
||||||
|
.route("/api/csv", post(tickets_csv))
|
||||||
.route("/api/ticket/delete", post(remove_ticket))
|
.route("/api/ticket/delete", post(remove_ticket))
|
||||||
.route("/api/party", get(get_party_by_name).post(create_party))
|
.route("/api/party", get(get_party_by_name).post(create_party))
|
||||||
.route("/api/party/list", get(get_parties))
|
.route("/api/party/list", get(get_parties))
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
onclick="reselect()">Start
|
onclick="reselect()">Start
|
||||||
Scannen</button> </p>
|
Scannen</button> </p>
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
<video autoplay playsinline controls="false" class="column col-12"></video>
|
<video autoplay playsinline controls="false" class="column col-12" id="webcam_holder" hidden></video>
|
||||||
</div>
|
</div>
|
||||||
<h4><span id="last-scanned">Nog geen gescand</span></h4>
|
<h4><span id="last-scanned">Nog geen gescand</span></h4>
|
||||||
<h3><span id="scan-status">Nog geen gescand</span></h3>
|
<h3><span id="scan-status">Nog geen gescand</span></h3>
|
||||||
|
@ -184,6 +184,7 @@
|
||||||
const videoSelect = document.querySelector("select#videoSource");
|
const videoSelect = document.querySelector("select#videoSource");
|
||||||
|
|
||||||
function start_scanning() {
|
function start_scanning() {
|
||||||
|
document.getElementById("webcam_holder").hidden = false;
|
||||||
navigator.mediaDevices
|
navigator.mediaDevices
|
||||||
.enumerateDevices()
|
.enumerateDevices()
|
||||||
.then(gotDevices)
|
.then(gotDevices)
|
||||||
|
@ -272,30 +273,28 @@
|
||||||
function upload_csv() {
|
function upload_csv() {
|
||||||
let file = document.getElementById("file-selector").files[0];
|
let file = document.getElementById("file-selector").files[0];
|
||||||
if (file) {
|
if (file) {
|
||||||
const reader = new FileReader();
|
set_scan_status("CSV uploaden...");
|
||||||
let num = 0;
|
// upload file contents to server
|
||||||
reader.onload = (evt) => {
|
let reader = new FileReader();
|
||||||
let result = evt.target.result;
|
reader.onload = function (e) {
|
||||||
result = result.replace("\r\n", "\n").replace("\r", "\n");
|
let contents = e.target.result;
|
||||||
for (let line of result.split("\n")) {
|
let party_id = +document.getElementById("party_id").value;
|
||||||
let llnr_a = "";
|
fetch("/api/csv", {
|
||||||
let coins = false;
|
method: "POST",
|
||||||
for (let llnr of line.split(",")) {
|
headers: {
|
||||||
if (llnr.length === 6 && !isNaN(llnr)) {
|
"Content-Type": "application/json"
|
||||||
llnr_a = llnr;
|
},
|
||||||
}
|
body: JSON.stringify({
|
||||||
if (llnr === "COINS") {
|
party: party_id,
|
||||||
coins = true;
|
csv: contents,
|
||||||
}
|
})
|
||||||
}
|
}).then(function (response) {
|
||||||
console.log(llnr_a, coins);
|
return response.json();
|
||||||
if (llnr_a !== "") {
|
}).then(function (data) {
|
||||||
num++;
|
console.log(data)
|
||||||
scan_ticket(llnr_a, coins);
|
set_scan_status(`CSV geupload: ${data.total} regels, waarvan ${data.scanned} leerlingen, ${data.with_coins} met muntjes`);
|
||||||
}
|
});
|
||||||
}
|
};
|
||||||
document.getElementById("import-result").innerHTML = `${num} leerlingen geïmporteerd!`
|
|
||||||
}
|
|
||||||
reader.readAsText(file);
|
reader.readAsText(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue