Compare commits

...

4 Commits

Author SHA1 Message Date
Ed 58812c787f Update default propic for Riverside 2023-08-06 12:47:32 +02:00
Ed 294d30a464 Translated ita -> eng and tidied for public release 2023-08-06 12:47:07 +02:00
Ed fc864fce57 Updated json schema for latest pretix version 2023-08-06 12:46:09 +02:00
Ed cb89641d05 Added flag for unknown countries 2023-08-06 12:45:40 +02:00
17 changed files with 112 additions and 126 deletions

19
api.py
View File

@ -1,5 +1,5 @@
from sanic import response
from sanic import Blueprint, exceptions
from sanic import Blueprint
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("https://api.telegram.org/bot5648800229:AAGr5EJdyo4obXB7pftIcQGjYLAlQdpu1Iw/sendMessage",
json = {'chat_id': -946677603, 'text': str(request.json)}
r = await client.post(f"https://api.telegram.org/bot{TG_BOT_API}/sendMessage",
json = {'chat_id': TG_CHAT_ID, 'text': str(request.json)}
)
except:
return response.json({'ok': False, 'error': 'There has been an issue sending your feedback.'})
@ -85,19 +85,6 @@ 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,8 +1,6 @@
from sanic.response import html, redirect, text
from sanic.response import html
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,11 +1,41 @@
headers = {'Host': 'your-pretix-hostname', 'Authorization': 'Token XXXXXXXXXXXXXXXXXXXXXXXX'}
base_url = "https://your-pretix-hostname/api/v1/organizers/organizer-name/events/your-event/"
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}/"
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
from config import headers, ADMINS, ORGANIZER, EVENT_NAME
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 ['HWUC9','9YKGJ']: raise exceptions.Forbidden("Birichino :)")
if order.code not in ADMINS: 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/furizon/events/beyond/orders/?page={page}', headers=headers)
r = httpx.get(f'https://reg.furizon.net/api/v1/organizers/{ORGANIZER}/events/{EVENT_NAME}/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/furizon/events/beyond/orders/?page={page}', headers=headers)
r = httpx.get(f'https://reg.furizon.net/api/v1/organizers/{ORGANIZER}/events/{EVENT_NAME}/orders/?page={page}', headers=headers)
if r.status_code == 404: break
for r in r.json()['results']:

11
ext.py
View File

@ -29,17 +29,21 @@ class Order:
self.has_late = False
self.first_name = None
self.last_name = None
self.country = None
self.country = 'xx'
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']:
@ -48,9 +52,6 @@ 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,15 +1,8 @@
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")
@ -17,7 +10,7 @@ bp = Blueprint("karaoke", url_prefix="/manage/karaoke")
@bp.get("/admin")
async def show_songs(request, order: Order):
if order.code not in ['9YKGJ', 'CMPQG']:
if order.code not in ADMINS:
raise exceptions.Forbidden("Birichino")
orders = [x for x in request.app.ctx.om.cache.values() if x.karaoke_songs]
@ -35,7 +28,7 @@ async def show_songs(request, order: Order):
@bp.post("/approve")
async def approve_songs(request, order: Order):
if order.code not in ['9YKGJ', 'CMPQG']:
if order.code not in ADMINS:
raise exceptions.Forbidden("Birichino")
for song in request.form:
@ -51,7 +44,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 ['9YKGJ', 'CMPQG']:
if order.code not in ADMINS:
raise exceptions.Forbidden("Birichino")
songname = unquote(songname)

View File

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

Before

Width:  |  Height:  |  Size: 286 B

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

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

View File

@ -88,9 +88,6 @@
<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" />
@ -109,7 +106,7 @@
});
</script>
<footer>
Made in 🇮🇹 by <img src="/res/icons/silhouette.svg" class="icon" title="ACCBCAC" /> · <a href="/manage/privacy">Privacy</a>
Made in 🇮🇹 by <img src="/res/icons/silhouette.svg" class="icon" /> · <a href="/manage/privacy">Privacy</a>
</footer>
</body>
</html>

View File

@ -1,7 +1,7 @@
{% extends "base.html" %}
{% block main %}
<main class="container">
<h1>Cerca ordine</h1>
<h1>Search order</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>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 />
<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 />
<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>
<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>
<form method="post" id="actionform" action="checkin">
<input type="hidden" value="{{order.code}}" name="code" />
<label for="actual_room">Numero Stanza Reale</label>
<label for="actual_room">Real Room Number</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 effettuato!</h1>
<p><strong>Ricorda di apporre il numero sul badge! Numero: {{order.badge_id}}</strong></p>
<h1>✅ Checkin done!</h1>
<p><strong>Remember to stick the REG number to the badge! Number: {{order.badge_id}}</strong></p>
<h2>Altri membri della stessa stanza ({{room_owner.actual_room}})</h2>
<h2>Other members of the same room ({{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>
<td><a href="order?order={{o.code}}">{{'Checkin' if not o.checked_in else '✅'}}</a></td>
</tr>
{% endfor %}
</table>
<h3><a href="start">Effettua un altro checkin ➡️</a></h3>
<h3><a href="start">Checkin somebody else ➡️</a></h3>
</main>
{% endblock %}

View File

@ -4,7 +4,7 @@
<main class="container">
<h1>Karaoke Admin</h1>
<h2>Canzoni da cantare</h2>
<h2>Songs to sing</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 %}>

View File

@ -1,54 +0,0 @@
{% 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>30 May → 3 June 2023</td></td>
<td>13 October → 15 October 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=BEYOND-{{order.code}}.pdf" target="_blank">Download ticket PDF</a>
<a href="/manage/download_ticket?name=RIVERSIDE-{{order.code}}.pdf" target="_blank">Download ticket PDF</a>
{% endif %}
</td>
</tr>