Compare commits

..

No commits in common. "58812c787f38257d8fca238b51ed4fd12d237361" and "d53ee2eaf097e14a4fec1aebd3037948296dff39" have entirely different histories.

17 changed files with 126 additions and 112 deletions

19
api.py
View File

@ -1,5 +1,5 @@
from sanic import response
from sanic import Blueprint
from sanic import Blueprint, exceptions
from ext import *
from config import *
import sqlite3
@ -59,8 +59,8 @@ async def api_leaderboard(request):
async def send_feedback(request):
try:
async with httpx.AsyncClient() as client:
r = await client.post(f"https://api.telegram.org/bot{TG_BOT_API}/sendMessage",
json = {'chat_id': TG_CHAT_ID, 'text': str(request.json)}
r = await client.post("https://api.telegram.org/bot5648800229:AAGr5EJdyo4obXB7pftIcQGjYLAlQdpu1Iw/sendMessage",
json = {'chat_id': -946677603, 'text': str(request.json)}
)
except:
return response.json({'ok': False, 'error': 'There has been an issue sending your feedback.'})
@ -85,6 +85,19 @@ async def show_events(request):
return r
@bp.route("/achievements.json")
async def show_achievements(request):
if request.token:
user = await request.app.ctx.om.get_order(code=request.token[:5])
if not user or user.app_token != request.token[5:]:
return response.json({'ok': False, 'error': 'The token you have provided is not valid.'}, status=401)
with sqlite3.connect('data/boop.db') as db:
db.row_factory = sqlite3.Row
events = db.execute('SELECT * FROM achievement ORDER BY points DESC')
return response.json([{'won_at': '2023-05-05T21:00Z' if request.token and random.random() < 0.2 else None, **dict(x), 'about': 'This is instructions on how to win the field.'} for x in events])
@bp.get("/logout")
async def logout(request):
if not request.token:

View File

@ -1,6 +1,8 @@
from sanic.response import html
from sanic.response import html, redirect, text
from sanic import Blueprint, exceptions
from random import choice
from ext import *
from config import headers
import json
bp = Blueprint("carpooling", url_prefix="/manage/carpooling")

View File

@ -1,41 +1,11 @@
ORGANIZER = 'furizon'
EVENT_NAME = 'river-side-2023'
API_TOKEN = 'xxxxxxxxxxxxxxxxxxxxxx'
HOSTNAME = 'your-pretix-hostname'
headers = {'Host': HOSTNAME, 'Authorization': f'Token {API_TOKEN}'}
base_url = f"https://{HOSTNAME}/api/v1/organizers/{ORGANIZER}/events/{EVENT_NAME}/"
headers = {'Host': 'your-pretix-hostname', 'Authorization': 'Token XXXXXXXXXXXXXXXXXXXXXXXX'}
base_url = "https://your-pretix-hostname/api/v1/organizers/organizer-name/events/your-event/"
PROPIC_DEADLINE = 1683575684
FILL_CACHE = True
DEV_MODE = True
ITEM_IDS = {
'ticket': [90,],
'membership_card': [91,],
'sponsorship': [], # first one = normal, second = super
'early_arrival': [],
'late_departure': [],
'room': 98
}
# Create a bunch of "room" items which will get added to the order once somebody gets a room.
ROOM_MAP = {
1: 16,
2: 17,
3: 18,
4: 19,
5: 20
}
# This is used for feedback sending inside of the app. Feedbacks will be sent to the specified chat using the bot api id.
TG_BOT_API = '123456789:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
TG_CHAT_ID = -1234567
# These order codes have additional functions.
ADMINS = ['XXXXX', 'YYYYY']
SMTP_HOST = 'your-smtp-host.com'
SMTP_USER = 'username'
SMTP_PASSWORD = 'password'

View File

@ -1,14 +1,14 @@
from sanic.response import text
from sanic import Blueprint, exceptions
from ext import *
from config import headers, ADMINS, ORGANIZER, EVENT_NAME
from config import headers
bp = Blueprint("export", url_prefix="/manage/export")
@bp.route("/export.csv")
async def export_csv(request, order: Order):
if not order: raise exceptions.Forbidden("You have been logged out. Please access the link in your E-Mail to login again!")
if order.code not in ADMINS: raise exceptions.Forbidden("Birichino :)")
if order.code not in ['HWUC9','9YKGJ']: raise exceptions.Forbidden("Birichino :)")
page = 0
orders = {}
@ -18,7 +18,7 @@ async def export_csv(request, order: Order):
while 1:
page += 1
r = httpx.get(f'https://reg.furizon.net/api/v1/organizers/{ORGANIZER}/events/{EVENT_NAME}/orders/?page={page}', headers=headers)
r = httpx.get(f'https://reg.furizon.net/api/v1/organizers/furizon/events/beyond/orders/?page={page}', headers=headers)
if r.status_code == 404: break
for r in r.json()['results']:
@ -64,7 +64,7 @@ async def export_hotel_csv(request, order: Order):
while 1:
page += 1
r = httpx.get(f'https://reg.furizon.net/api/v1/organizers/{ORGANIZER}/events/{EVENT_NAME}/orders/?page={page}', headers=headers)
r = httpx.get(f'https://reg.furizon.net/api/v1/organizers/furizon/events/beyond/orders/?page={page}', headers=headers)
if r.status_code == 404: break
for r in r.json()['results']:

11
ext.py
View File

@ -29,21 +29,17 @@ class Order:
self.has_late = False
self.first_name = None
self.last_name = None
self.country = 'xx'
self.country = None
self.address = None
self.checked_in = False
idata = data['invoice_address']
if idata:
self.address = f"{idata['street']} - {idata['zipcode']} {idata['city']} - {idata['country']}"
self.country = idata['country']
for p in self.data['positions']:
if p['item'] in ITEM_IDS['ticket']:
self.position_id = p['id']
self.position_positionid = p['positionid']
self.answers = p['answers']
self.barcode = p['secret']
self.address = f"{p['street']} - {p['zipcode']} {p['city']} - {p['country']}"
self.checked_in = bool(p['checkins'])
if p['item'] in ITEM_IDS['membership_card']:
@ -52,6 +48,9 @@ class Order:
if p['item'] in ITEM_IDS['sponsorship']:
self.sponsorship = 'normal' if p['variation'] == ITEMS_IDS['sponsorship'][0] else 'super'
if p['country']:
self.country = p['country']
if p['attendee_name']:
self.first_name = p['attendee_name_parts']['given_name']
self.last_name = p['attendee_name_parts']['family_name']

View File

@ -1,8 +1,15 @@
from sanic.response import html, redirect, text
from sanic import Blueprint, exceptions, response
from random import choice
from ext import *
from config import headers, PROPIC_DEADLINE
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
from config import ADMINS
import json
bp = Blueprint("karaoke", url_prefix="/manage/karaoke")
@ -10,7 +17,7 @@ bp = Blueprint("karaoke", url_prefix="/manage/karaoke")
@bp.get("/admin")
async def show_songs(request, order: Order):
if order.code not in ADMINS:
if order.code not in ['9YKGJ', 'CMPQG']:
raise exceptions.Forbidden("Birichino")
orders = [x for x in request.app.ctx.om.cache.values() if x.karaoke_songs]
@ -28,7 +35,7 @@ async def show_songs(request, order: Order):
@bp.post("/approve")
async def approve_songs(request, order: Order):
if order.code not in ADMINS:
if order.code not in ['9YKGJ', 'CMPQG']:
raise exceptions.Forbidden("Birichino")
for song in request.form:
@ -44,7 +51,7 @@ async def sing_song(request, order: Order, songname):
if not order: raise exceptions.Forbidden("You have been logged out. Please access the link in your E-Mail to login again!")
if order.code not in ADMINS:
if order.code not in ['9YKGJ', 'CMPQG']:
raise exceptions.Forbidden("Birichino")
songname = unquote(songname)

View File

@ -1,8 +1,11 @@
from sanic.response import html, redirect
from sanic.response import html, redirect, text
from sanic import Blueprint, exceptions
from random import choice
from ext import *
from config import PROPIC_DEADLINE
from config import headers, PROPIC_DEADLINE
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

View File

@ -1,44 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
id="flag-icons-us"
viewBox="0 0 640 480"
version="1.1"
sodipodi:docname="??.svg"
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs4" />
<sodipodi:namedview
id="namedview4"
pagecolor="#ffffff"
bordercolor="#999999"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="1.8295363"
inkscape:cx="391.356"
inkscape:cy="277.93928"
inkscape:window-width="2560"
inkscape:window-height="1035"
inkscape:window-x="0"
inkscape:window-y="21"
inkscape:window-maximized="1"
inkscape:current-layer="flag-icons-us" />
<rect
style="fill:#003399;fill-rule:evenodd;stroke-width:2.59276;stroke-linecap:square;stroke-linejoin:round;paint-order:markers stroke fill"
id="rect4"
width="640"
height="480"
x="0"
y="0" />
<path
style="font-size:377.089px;line-height:1.25;font-family:OfficinaSanITCBoo;-inkscape-font-specification:OfficinaSanITCBoo;text-align:center;word-spacing:0px;text-anchor:middle;fill:#ffffff;stroke-width:1.964"
d="m 122.59391,314.85217 q 6.41051,0 12.06684,2.63962 5.65634,2.26253 9.80432,6.7876 4.52507,4.14798 6.7876,10.1814 2.63962,5.65634 2.63962,12.44394 0,13.19812 -9.42722,22.24825 -9.05014,9.42723 -22.24825,9.42723 -13.19812,0 -22.625341,-9.42723 -9.427225,-9.42722 -9.427225,-22.62534 0,-13.19811 9.427225,-22.24825 9.427221,-9.42722 23.002431,-9.42722 z m 18.85445,-48.26739 q 0,5.27924 -1.50836,6.7876 -1.13127,1.13127 -6.03342,1.13127 h -26.77332 q -5.27925,0 -6.7876,-1.13127 -1.13127,-1.50836 -1.13127,-6.7876 v -47.13613 q 0,-4.14798 1.50836,-5.65633 1.50835,-1.50836 7.16469,-3.01671 49.02157,-10.5585 49.02157,-39.21726 0,-13.19811 -9.42723,-19.98572 -9.05014,-7.16469 -26.01914,-7.16469 -9.80431,0 -18.85445,2.26254 -8.673046,2.26253 -22.625339,8.29596 -3.3938,1.50835 -4.525067,1.88544 -1.131267,0.37709 -1.885445,0.37709 -2.639623,0 -3.77089,-3.77089 l -9.804314,-25.64205 q -0.754178,-2.26254 -0.754178,-4.14798 0,-3.3938 6.787602,-7.16469 6.787602,-4.14798 17.346093,-7.16469 10.558492,-3.3938 22.625338,-5.65634 12.06685,-2.26253 23.00243,-2.26253 16.969,0 30.54421,5.27925 13.95229,4.90215 23.7566,14.32938 9.80432,9.05013 15.08356,22.24825 5.27925,12.82102 5.27925,28.65876 0,35.82345 -29.03585,54.6779 -6.03343,4.14798 -13.57521,7.16469 -7.16469,3.01672 -19.60862,7.1647 z m 169.69004,48.26739 q 6.41051,0 12.06685,2.63962 5.65633,2.26253 9.80431,6.7876 4.52507,4.14798 6.78761,10.1814 2.63962,5.65634 2.63962,12.44394 0,13.19812 -9.42723,22.24825 -9.05013,9.42723 -22.24825,9.42723 -13.19811,0 -22.62534,-9.42723 -9.42722,-9.42722 -9.42722,-22.62534 0,-13.19811 9.42722,-22.24825 9.42723,-9.42722 23.00243,-9.42722 z m 18.85445,-48.26739 q 0,5.27924 -1.50835,6.7876 -1.13127,1.13127 -6.03343,1.13127 h -26.77332 q -5.27924,0 -6.7876,-1.13127 -1.13127,-1.50836 -1.13127,-6.7876 v -47.13613 q 0,-4.14798 1.50836,-5.65633 1.50836,-1.50836 7.16469,-3.01671 49.02157,-10.5585 49.02157,-39.21726 0,-13.19811 -9.42722,-19.98572 -9.05014,-7.16469 -26.01915,-7.16469 -9.80431,0 -18.85444,2.26254 -8.67305,2.26253 -22.62534,8.29596 -3.3938,1.50835 -4.52507,1.88544 -1.13127,0.37709 -1.88545,0.37709 -2.63962,0 -3.77089,-3.77089 l -9.80431,-25.64205 q -0.75418,-2.26254 -0.75418,-4.14798 0,-3.3938 6.7876,-7.16469 6.78761,-4.14798 17.3461,-7.16469 10.55849,-3.3938 22.62534,-5.65634 12.06684,-2.26253 23.00242,-2.26253 16.96901,0 30.54421,5.27925 13.9523,4.90215 23.75661,14.32938 9.80431,9.05013 15.08356,22.24825 5.27924,12.82102 5.27924,28.65876 0,35.82345 -29.03585,54.6779 -6.03342,4.14798 -13.5752,7.16469 -7.16469,3.01672 -19.60863,7.1647 z m 169.69005,48.26739 q 6.41051,0 12.06684,2.63962 5.65634,2.26253 9.80432,6.7876 4.52507,4.14798 6.7876,10.1814 2.63962,5.65634 2.63962,12.44394 0,13.19812 -9.42722,22.24825 -9.05014,9.42723 -22.24825,9.42723 -13.19812,0 -22.62534,-9.42723 -9.42723,-9.42722 -9.42723,-22.62534 0,-13.19811 9.42723,-22.24825 9.42722,-9.42722 23.00243,-9.42722 z m 18.85445,-48.26739 q 0,5.27924 -1.50836,6.7876 -1.13127,1.13127 -6.03342,1.13127 h -26.77332 q -5.27925,0 -6.7876,-1.13127 -1.13127,-1.50836 -1.13127,-6.7876 v -47.13613 q 0,-4.14798 1.50836,-5.65633 1.50835,-1.50836 7.16469,-3.01671 49.02156,-10.5585 49.02156,-39.21726 0,-13.19811 -9.42722,-19.98572 -9.05014,-7.16469 -26.01914,-7.16469 -9.80431,0 -18.85445,2.26254 -8.67305,2.26253 -22.62534,8.29596 -3.3938,1.50835 -4.52507,1.88544 -1.13126,0.37709 -1.88544,0.37709 -2.63963,0 -3.77089,-3.77089 l -9.80432,-25.64205 q -0.75417,-2.26254 -0.75417,-4.14798 0,-3.3938 6.7876,-7.16469 6.7876,-4.14798 17.34609,-7.16469 10.55849,-3.3938 22.62534,-5.65634 12.06685,-2.26253 23.00243,-2.26253 16.969,0 30.54421,5.27925 13.95229,4.90215 23.7566,14.32938 9.80432,9.05013 15.08356,22.24825 5.27925,12.82102 5.27925,28.65876 0,35.82345 -29.03585,54.6779 -6.03343,4.14798 -13.57521,7.16469 -7.16469,3.01672 -19.60862,7.1647 z"
id="text4"
aria-label="???" />
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-xx" viewBox="0 0 640 480">
<path fill="#fff" fill-rule="evenodd" stroke="#adb5bd" stroke-width="1.1" d="M.5.5h638.9v478.9H.5z"/>
<path fill="none" stroke="#adb5bd" stroke-width="1.1" d="m.5.5 639 479M639.5.5l-639 479"/>
</svg>

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -1,6 +1,9 @@
from sanic.response import html
from sanic import Blueprint
from sanic import Blueprint, exceptions
from ext import *
from config import headers
from time import time
import asyncio
bp = Blueprint("stats", url_prefix="/manage")

View File

@ -88,6 +88,9 @@
<a href="/manage/nosecount">Nose Count</a>
{% if order %}
<a href="/manage/carpooling">Carpooling</a>
{% if not order.room_confirmed %}
<a href="/manage/roommate_search">Roommate Search</a>
{% endif %}
<a style="float:right;" href="/manage/logout">Logout</a>
{% endif %}
<br clear="both" />
@ -106,7 +109,7 @@
});
</script>
<footer>
Made in 🇮🇹 by <img src="/res/icons/silhouette.svg" class="icon" /> · <a href="/manage/privacy">Privacy</a>
Made in 🇮🇹 by <img src="/res/icons/silhouette.svg" class="icon" title="ACCBCAC" /> · <a href="/manage/privacy">Privacy</a>
</footer>
</body>
</html>

View File

@ -1,7 +1,7 @@
{% extends "base.html" %}
{% block main %}
<main class="container">
<h1>Search order</h1>
<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>

View File

@ -2,15 +2,15 @@
{% block main %}
<main class="container">
<h1><kbd>{{order.code}}</kbd> {{order.name}} ({{order.first_name}} {{order.last_name}})</h1>
<p><strong>Comment:</strong> {{order.comment or '--'}}<br />
<strong>Order notes:</strong> {{order.notes or '--'}}<br />
<strong>Status: <span style="color: {{'#900' if order.status == 'unpaid' else '#090'}}">{{order.status}}</span></strong><br />
<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>Roommates:</strong> {% for code in room_owner.room_members %}<kbd><a href="order?order={{code}}">{{code}}</a></kbd> {% endfor %}<br />
<a target="_blank" href="https://{config.HOSTNAME}/control/event/{config.ORGANIZER}/{config.EVENT_NAME}/orders/{{order.code}}/">Open on pretix</a><br /></p>
<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">Real Room Number</label>
<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 />

View File

@ -1,19 +1,19 @@
{% extends "base.html" %}
{% block main %}
<main class="container">
<h1>✅ Checkin done!</h1>
<p><strong>Remember to stick the REG number to the badge! Number: {{order.badge_id}}</strong></p>
<h1>✅ Checkin effettuato!</h1>
<p><strong>Ricorda di apporre il numero sul badge! Numero: {{order.badge_id}}</strong></p>
<h2>Other members of the same room ({{room_owner.actual_room}})</h2>
<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}}">{{'Checkin' if not o.checked_in else '✅'}}</a></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">Checkin somebody else ➡️</a></h3>
<h3><a href="start">Effettua un altro checkin ➡️</a></h3>
</main>
{% endblock %}

View File

@ -4,7 +4,7 @@
<main class="container">
<h1>Karaoke Admin</h1>
<h2>Songs to sing</h2>
<h2>Canzoni da cantare</h2>
<table>
{% for s in songs if s.approved is not none and (not s.singed) %}
<tr {% if s.approved == false %}style="text-decoration: line-through"{% endif %}>

54
tpl/stats.html Normal file
View File

@ -0,0 +1,54 @@
{% extends "base.html" %}
{% block title %}Furizon 2023 Stats{% endblock %}
{% block main %}
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<main class="container">
<header>
<picture>
<source srcset="/res/furizon.png" media="(prefers-color-scheme:dark)">
<img src="/res/furizon-light.png" style="height:4rem;text-align:center;">
</picture>
</header>
<h2>Countries</h2>
<div style="margin: 0 auto;">
<canvas id="countries"></canvas>
</div>
<script>
const ctx = document.getElementById('countries');
new Chart(ctx, {
type: 'bar',
data: {
labels: {{stats['countries'].keys()|list|safe}},
datasets: [{
label: '# of Attendees',
data: {{stats['countries'].values()|list|safe}},
borderWidth: 0
}]
},
options: {
scales: {
y: {beginAtZero: true}
}
}
});
</script>
<h2>Sponsors</h2>
<div style="max-width:20em;margin: 0 auto;">
<canvas id="sponsors"></canvas>
</div>
<script>
const ctx2 = document.getElementById('sponsors');
new Chart(ctx2, {
type: 'pie',
data: {
labels: {{stats['sponsors'].keys()|list|safe}},
datasets: [{
label: '# of Attendees',
data: {{stats['sponsors'].values()|list|safe}},
borderWidth: 0
}]
}
});
</script>
</main>
{% endblock %}

View File

@ -24,7 +24,7 @@
</tr>
<tr>
<th>When{{' (convention)' if order.has_early or order.has_late else ''}}?</th>
<td>13 October → 15 October 2023</td></td>
<td>30 May → 3 June 2023</td></td>
</tr>
{% if order.has_early or order.has_late %}
<tr>
@ -53,7 +53,7 @@
{% if order.status == 'paid' and order.room_confirmed %}
<br />
<img src="/res/icons/pdf.svg" class="icon" />
<a href="/manage/download_ticket?name=RIVERSIDE-{{order.code}}.pdf" target="_blank">Download ticket PDF</a>
<a href="/manage/download_ticket?name=BEYOND-{{order.code}}.pdf" target="_blank">Download ticket PDF</a>
{% endif %}
</td>
</tr>