Added helper functions to checkin (admin only)

This commit is contained in:
Ed 2023-07-04 23:06:48 +02:00
parent a811965504
commit 3c4d31e1b9
4 changed files with 196 additions and 0 deletions

72
checkin.py Normal file
View File

@ -0,0 +1,72 @@
from sanic.response import html, redirect, text
from sanic import Blueprint, exceptions, response
from random import choice
from ext import *
from config import headers, base_url
from PIL import Image
from os.path import isfile
from os import unlink
from io import BytesIO
from hashlib import sha224
from time import time
from urllib.parse import unquote
import json
bp = Blueprint("checkin", url_prefix="/checkin")
@bp.get("/")
async def redirect_start(request):
return response.redirect("start")
@bp.get("/start")
async def start_checkin(request):
orders = request.app.ctx.om.cache.values()
tpl = request.app.ctx.tpl.get_template('checkin_1.html')
return html(tpl.render(orders=orders))
@bp.get("/order")
async def show_order(request):
max_id = 0
for o in request.app.ctx.om.cache.values():
if not o.badge_id: continue
max_id = max(o.badge_id, max_id)
order = await request.app.ctx.om.get_order(code=request.args.get('order'))
if order.room_id == order.code:
room_owner = order
else:
room_owner = await request.app.ctx.om.get_order(code=order.room_id)
tpl = request.app.ctx.tpl.get_template('checkin_2.html')
return html(tpl.render(order=order, room_owner=room_owner, max_id=max_id))
@bp.post("/checkin")
async def do_checkin(request):
# Update room info
order = await request.app.ctx.om.get_order(code=request.form.get('code'))
if order.room_id == order.code:
room_owner = order
await order.edit_answer('actual_room', request.form.get('actual_room'))
else:
room_owner = await request.app.ctx.om.get_order(code=order.room_id)
await room_owner.edit_answer('actual_room', request.form.get('actual_room'))
await room_owner.send_answers()
roommates = [await request.app.ctx.om.get_order(code=code, cached=True) for code in room_owner.room_members]
# Update nfc and badge id
await order.edit_answer('nfc_id', request.form.get('nfc_id'))
await order.edit_answer('badge_id', request.form.get('badge_id'))
await order.send_answers()
if not order.checked_in:
async with httpx.AsyncClient() as client:
res = await client.post(base_url.replace('events/beyond/', 'checkinrpc/redeem/'), json={'secret': order.barcode, 'source_type': 'barcode', 'type': 'entry', 'lists': [3,]}, headers=headers)
tpl = request.app.ctx.tpl.get_template('checkin_3.html')
return html(tpl.render(order=order, room_owner=room_owner, roommates=roommates))

49
tpl/checkin_1.html Normal file
View File

@ -0,0 +1,49 @@
{% extends "base.html" %}
{% block main %}
<main class="container">
<h1>Cerca ordine</h1>
<input id="search" type="text" onchange="updateSearch();" onclick="this.value = '';" />
<form method="get" id="actionform" style="font-family:monospace;" action="order">
<select id="badgelist" name="order" id="order" multiple>
{% for o in orders %}
<option value="{{o.code}}" data-nfc="{{o.nfc_id}}" data-secret="{{o.secret}}" style="">{{o.code}} · {{o.nfc_id or ('&nbsp;'*14)|safe}} · {{o.name}} ({{o.first_name}} {{o.last_name}})</option>
{% endfor %}
</select>
<input type="submit" value="Search" />
</form>
<script type="text/javascript">
function filterOptions(textInputId, optionInputId) {
const textInput = document.getElementById(textInputId);
const optionInput = document.getElementById(optionInputId);
textInput.addEventListener('input', () => {
const searchText = textInput.value.toLowerCase();
const options = optionInput.getElementsByTagName('option');
let visible = 0;
let last_visible;
for (let i = 0; i < options.length; i++) {
const optionText = options[i].textContent.toLowerCase();
if (!searchText||optionText.includes(searchText)||options[i].getAttribute('data-secret').includes(searchText)) {
options[i].style.display = '';
last_visible = options[i]
visible++;
} else {
options[i].style.display = 'none';
}
}
if(visible == 1) {
last_visible.selected = 'selected';
}
});
}
document.addEventListener('DOMContentLoaded', () => {
filterOptions('search', 'badgelist');
});
</script>
</main>
{% endblock %}

56
tpl/checkin_2.html Normal file
View File

@ -0,0 +1,56 @@
{% extends "base.html" %}
{% block main %}
<main class="container">
<h1><kbd>{{order.code}}</kbd> {{order.name}} ({{order.first_name}} {{order.last_name}})</h1>
<p><strong>Commento:</strong> {{order.comment or '--'}}<br />
<strong>Note ordine:</strong> {{order.notes or '--'}}<br />
<strong>Stato ordine: <span style="color: {{'#900' if order.status == 'unpaid' else '#090'}}">{{order.status}}</span></strong><br />
<strong>Sponsor: <span style="color: {{'#fa0' if order.sponsorship == 'super' else ('#e8e' if order.sponsorship else 'initial')}}">{{order.sponsorship}}</span></strong><br />
<strong>Compagni di stanza:</strong> {% for code in room_owner.room_members %}<kbd><a href="order?order={{code}}">{{code}}</a></kbd> {% endfor %}<br />
<a target="_blank" href="https://reg.furizon.net/control/event/furizon/beyond/orders/{{order.code}}/">Apri su pretix</a><br /></p>
<form method="post" id="actionform" action="checkin">
<input type="hidden" value="{{order.code}}" name="code" />
<label for="actual_room">Numero Stanza Reale</label>
<input type="text" value="{{room_owner.actual_room or ''}}" name="actual_room" required />
<label for="nfc_id">NFC Badge</label>
<input type="text" value="{{order.nfc_id or ''}}" name="nfc_id" pattern="[A-F0-9]{14}" title="NFC Tag id must be 14 chars" required />
<label for="badge_id">Badge ID</label>
<input type="text" value="{{order.badge_id or (max_id+1)}}" name="badge_id" required />
<input type="submit" value="Checkin!" />
</form>
<script type="text/javascript">
function filterOptions(textInputId, optionInputId) {
const textInput = document.getElementById(textInputId);
const optionInput = document.getElementById(optionInputId);
textInput.addEventListener('input', () => {
const searchText = textInput.value.toLowerCase();
const options = optionInput.getElementsByTagName('option');
let visible = 0;
let last_visible;
for (let i = 0; i < options.length; i++) {
const optionText = options[i].textContent.toLowerCase();
if (!searchText||optionText.includes(searchText)||options[i].getAttribute('data-secret').includes(searchText)) {
options[i].style.display = '';
last_visible = options[i]
visible++;
} else {
options[i].style.display = 'none';
}
}
if(visible == 1) {
last_visible.selected = 'selected';
}
});
}
document.addEventListener('DOMContentLoaded', () => {
filterOptions('search', 'badgelist');
});
</script>
</main>
{% endblock %}

19
tpl/checkin_3.html Normal file
View File

@ -0,0 +1,19 @@
{% extends "base.html" %}
{% block main %}
<main class="container">
<h1>✅ Checkin effettuato!</h1>
<p><strong>Ricorda di apporre il numero sul badge! Numero: {{order.badge_id}}</strong></p>
<h2>Altri membri della stessa stanza ({{room_owner.actual_room}})</h2>
<table>
{% for o in roommates %}
<tr>
<td><a href="order?order={{o.code}}">{{o.code}}</a></td>
<td>{{o.name}}</td>
<td><a href="order?order={{o.code}}">{{'Effettua Checkin' if not o.checked_in else '✅'}}</a></td>
</tr>
{% endfor %}
</table>
<h3><a href="start">Effettua un altro checkin ➡️</a></h3>
</main>
{% endblock %}