Add coins to a ticket
continuous-integration/drone/push Build is passing Details

main
Julius 2022-11-12 22:19:27 +01:00
parent 0e5f70e7a4
commit 8d97c34fbe
Signed by: j00lz
GPG Key ID: AF241B0AA237BBA2
4 changed files with 59 additions and 9 deletions

View File

@ -19,6 +19,11 @@ pub async fn setup_db(pool: &Pool<sqlx::Postgres>) {
.await .await
.unwrap(); .unwrap();
query("alter table tickets add column if not exists coins bool default false")
.execute(pool)
.await
.unwrap();
query("create table if not exists users (id serial primary key, username text, password text)") query("create table if not exists users (id serial primary key, username text, password text)")
.execute(pool) .execute(pool)
.await .await
@ -42,6 +47,7 @@ pub struct Ticket {
party_id: i32, party_id: i32,
pub student: String, pub student: String,
pub inside: bool, pub inside: bool,
pub coins: bool,
} }
#[derive(sqlx::FromRow, Debug, Deserialize, Serialize)] #[derive(sqlx::FromRow, Debug, Deserialize, Serialize)]
@ -161,11 +167,12 @@ impl Db {
.unwrap(); .unwrap();
} }
pub async fn add_ticket(&self, party_id: i32, student: &str) -> Ticket { pub async fn add_ticket(&self, party_id: i32, student: &str, coins: bool) -> Ticket {
query_as("insert into tickets (party_id, student, inside) values ($1, $2, $3) returning *") query_as("insert into tickets (party_id, student, inside, coins) values ($1, $2, $3, $4) returning *")
.bind(party_id) .bind(party_id)
.bind(student) .bind(student)
.bind(false) .bind(false)
.bind(coins)
.fetch_one(&self.0) .fetch_one(&self.0)
.await .await
.unwrap() .unwrap()

View File

@ -120,6 +120,7 @@ async fn login(
struct ScanRequest { struct ScanRequest {
code: String, code: String,
check: bool, check: bool,
coins: bool,
party: i32, party: i32,
} }
@ -129,6 +130,7 @@ enum ScanState {
Found, Found,
Added, Added,
AlreadyScanned, AlreadyScanned,
Coins,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -155,7 +157,11 @@ async fn scan_card(
pool.update_ticket(&ticket).await; pool.update_ticket(&ticket).await;
Json(ScanResponse { Json(ScanResponse {
code: scan.code, code: scan.code,
state: ScanState::Found, state: if ticket.coins {
ScanState::Coins
} else {
ScanState::Found
},
}) })
} }
} else { } else {
@ -171,7 +177,7 @@ async fn scan_card(
state: ScanState::AlreadyScanned, state: ScanState::AlreadyScanned,
}) })
} else { } else {
pool.add_ticket(scan.party, &scan.code).await; pool.add_ticket(scan.party, &scan.code, scan.coins).await;
Json(ScanResponse { Json(ScanResponse {
code: scan.code, code: scan.code,
state: ScanState::Added, state: ScanState::Added,
@ -253,9 +259,14 @@ async fn export_party(
) -> impl IntoResponse { ) -> impl IntoResponse {
let tickets = pool.get_all_tickets_for_party(party).await; let tickets = pool.get_all_tickets_for_party(party).await;
let mut csv = String::new(); let mut csv = String::new();
csv.push_str("leerlingnummer,binnen\n"); csv.push_str("leerlingnummer,binnen,muntjes\n");
for ticket in tickets { for ticket in tickets {
csv.push_str(&format!("{},{}\n", ticket.student, ticket.inside)); csv.push_str(&format!(
"{},{},{}\n",
ticket.student,
ticket.inside,
if ticket.coins { "COINS" } else { "" }
));
} }
let mut resp = Response::new(Body::from(csv)); let mut resp = Response::new(Body::from(csv));
resp.headers_mut().insert( resp.headers_mut().insert(

View File

@ -22,6 +22,11 @@
<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>
<h3>Binnen/Betaald: <span id="stats">Laden...</span></h3> <h3>Binnen/Betaald: <span id="stats">Laden...</span></h3>
<h3>
<label class="form-checkbox form-inline">
<input type="checkbox" id="muntjes" ><i class="form-icon"></i> Muntjes kopen
</label>
</h3>
</div> </div>
<div class="columns"> <div class="columns">
<div class="column col-md-12 col-6"> <div class="column col-md-12 col-6">
@ -53,6 +58,11 @@
setTimeout(function () { setTimeout(function () {
document.body.classList.remove("bg-success"); document.body.classList.remove("bg-success");
}, 1000); }, 1000);
} else if (state == "COINS") {
document.body.classList.add("bg-primary");
setTimeout(function () {
document.body.classList.remove("bg-primary");
}, 1000);
} else if (state == "WARN") { } else if (state == "WARN") {
document.body.classList.add("bg-warning"); document.body.classList.add("bg-warning");
setTimeout(function () { setTimeout(function () {
@ -86,6 +96,11 @@
// alert("Leerlingnummer gevonden"); // alert("Leerlingnummer gevonden");
set_scan_status("Mag naar binnen"); set_scan_status("Mag naar binnen");
set_colour("OK"); set_colour("OK");
} else if (state === "Coins") {
// leerlingnummer is gevonden en mag naar binnen
// alert("Leerlingnummer gevonden");
set_scan_status("Mag naar binnen, heeft muntjes gekocht!");
set_colour("COINS");
} else if (state === "Added") { } else if (state === "Added") {
// leerlingummer is toegevoegd aan de gastenlijst // leerlingummer is toegevoegd aan de gastenlijst
// alert("Leerlingnummer toegevoegd"); // alert("Leerlingnummer toegevoegd");
@ -119,8 +134,13 @@
} }
function scan_ticket(code) { function scan_ticket(code) {
if (code === "COINS" || code === "000000") {
document.getElementById("muntjes").checked = true;
return;
}
let check = document.querySelector('input[name="mode"]:checked').value === "true"; let check = document.querySelector('input[name="mode"]:checked').value === "true";
let party_id = +document.getElementById("party_id").value; let party_id = +document.getElementById("party_id").value;
fetch("/api/ticket", { fetch("/api/ticket", {
method: "POST", method: "POST",
headers: { headers: {
@ -130,18 +150,19 @@
party: party_id, party: party_id,
code: code, code: code,
check: check, check: check,
coins: document.getElementById("muntjes").checked,
}) })
}).then(function (response) { }).then(function (response) {
return response.json(); return response.json();
}).then(function (data) { }).then(function (data) {
console.log(data) console.log(data)
document.getElementById("muntjes").checked = false;
return data; return data;
}).then(set_state); }).then(set_state);
} }
function return_handler(e) { function return_handler(e) {
e.preventDefault(); e.preventDefault();
console.log("wario");
let code = document.getElementById("student_number").value; let code = document.getElementById("student_number").value;
console.log(code); console.log(code);
scan_ticket(code); scan_ticket(code);
@ -249,11 +270,20 @@
let result = evt.target.result; let result = evt.target.result;
result = result.replace("\r\n", "\n").replace("\r", "\n"); result = result.replace("\r\n", "\n").replace("\r", "\n");
for (let line of result.split("\n")) { for (let line of result.split("\n")) {
let llnr_a = "";
let coins = false;
for (let llnr of line.split(",")) { for (let llnr of line.split(",")) {
if (llnr.length === 6 && !isNaN(llnr)) { if (llnr.length === 6 && !isNaN(llnr)) {
scan_ticket(llnr); llnr_a = llnr;
num += 1;
} }
if (llnr === "COINS") {
coins = true;
}
}
if (llnr_a !== "") {
num++;
scan_ticket("COINS");
scan_ticket(llnr_a);
} }
} }
document.getElementById("import-result").innerHTML = `${num} leerlingen geïmporteerd!` document.getElementById("import-result").innerHTML = `${num} leerlingen geïmporteerd!`

View File

@ -11,6 +11,7 @@
<th class="hide-md">Ticket Nummer</th> <th class="hide-md">Ticket Nummer</th>
<th>Leerling Nummer</th> <th>Leerling Nummer</th>
<th>Is binnen?</th> <th>Is binnen?</th>
<th>Heeft Muntjes</th>
<th class="hide-md""></th> <th class="hide-md""></th>
</tr> </tr>
</thead> </thead>
@ -20,6 +21,7 @@
<td class=" hide-md">{{guest.id}}</td> <td class=" hide-md">{{guest.id}}</td>
<td>{{guest.student}}</td> <td>{{guest.student}}</td>
<td>{{guest.inside}}</td> <td>{{guest.inside}}</td>
<td>{{guest.coins}}</td>
<td class="hide-md"><button class="delete-button btn btn-warning" <td class="hide-md"><button class="delete-button btn btn-warning"
data-id="{{guest.id}}">Verwijder</button></td> data-id="{{guest.id}}">Verwijder</button></td>
</tr> </tr>