Initial commit.

This commit is contained in:
Ed 2023-07-11 21:32:10 +02:00
commit 4ed3ecef04
25 changed files with 593 additions and 0 deletions

BIN
avatar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
badge_azzurro.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 KiB

BIN
badge_giallo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 KiB

BIN
badge_rosso.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 KiB

BIN
badge_verde.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 KiB

BIN
badge_viola.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 KiB

224
ext.py Normal file
View File

@ -0,0 +1,224 @@
from dataclasses import dataclass
from sanic import Request, exceptions
import httpx
import re
from os.path import join
import json
from time import time
@dataclass
class Order:
def __init__(self, data):
self.time = time()
self.data = data
self.status = {'n': 'pending', 'p': 'paid', 'e': 'expired', 'c': 'canceled'}[self.data['status']]
if not len(self.data['positions']):
self.status = 'canceled'
self.code = data['code']
self.pending_update = False
self.has_card = False
self.sponsorship = None
self.has_early = False
self.has_late = False
for p in self.data['positions']:
if p['item'] in [16, 38]:
self.position_id = p['id']
self.position_positionid = p['positionid']
self.answers = p['answers']
self.barcode = p['secret']
if p['item'] == 17:
self.has_card = True
if p['item'] == 19:
self.sponsorship = 'normal' if p['variation'] == 13 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']
if p['item'] == 20:
self.has_early = True
if p['item'] == 21:
self.has_late = True
self.total = float(data['total'])
self.fees = 0
for fee in data['fees']:
self.fees += float(fee['value'])
answers = ['payment_provider', 'shirt_size', 'birth_date', 'fursona_name', 'room_confirmed', 'room_id']
self.payment_provider = data['payment_provider']
self.shirt_size = self.ans('shirt_size')
self.is_artist = True if self.ans('is_artist') != 'No' else False
self.is_fursuiter = True if self.ans('is_fursuiter') != 'No' else False
self.is_allergic = True if self.ans('is_allergic') != 'No' else False
self.propic_locked = self.ans('propic_locked')
self.propic = self.ans('propic')
self.birth_date = self.ans('birth_date')
self.name = self.ans('fursona_name')
self.room_id = self.ans('room_id')
self.room_confirmed = self.ans('room_confirmed')
self.room_name = self.ans('room_name')
self.pending_room = self.ans('pending_room')
self.pending_roommates = self.ans('pending_roommates').split(',') if self.ans('pending_roommates') else []
self.room_members = self.ans('room_members').split(',') if self.ans('room_members') else []
self.room_owner = (self.code == self.room_id)
self.room_secret = self.ans('room_secret')
def __getitem__(self, var):
return self.data[var]
def ans(self, name):
for p in self.data['positions']:
for a in p['answers']:
if a['question_identifier'] == name:
if a['answer'] in ['True', 'False']:
return bool(a['answer'] == 'True')
return a['answer']
return None
async def edit_answer(self, name, new_answer):
found = False
self.pending_update = True
for key in range(len(self.answers)):
if self.answers[key]['question_identifier'] == name:
if new_answer != None:
print('EXISTING ANSWER UPDATE', name, '=>', new_answer)
self.answers[key]['answer'] = new_answer
found = True
else:
print('DEL ANSWER', name, '=>', new_answer)
del self.answers[key]
break
if (not found) and (new_answer is not None):
async with httpx.AsyncClient() as client:
res = await client.get(join(base_url, 'questions/'), headers=headers)
res = res.json()
for r in res['results']:
if r['identifier'] != name: continue
print('ANSWER UPDATE', name, '=>', new_answer)
self.answers.append({
'question': r['id'],
'answer': new_answer,
'question_identifier': r['identifier'],
'options': r['options']
})
async def send_answers(self):
async with httpx.AsyncClient() as client:
res = await client.patch(join(base_url, f'orderpositions/{self.position_id}/'), headers=headers, json={'answers': self.answers})
self.pending_update = False
self.time = -1
@dataclass
class Quotas:
def __init__(self, data):
self.data = data
self.capacity_mapping = {
1: 16,
2: 17,
3: 18,
4: 19,
5: 20
}
def get_left(self, capacity):
for quota in self.data['results']:
if quota['id'] == self.capacity_mapping[capacity]:
return quota['available_number']
async def get_quotas(request: Request=None):
async with httpx.AsyncClient() as client:
res = await client.get(join(base_url, 'quotas/?order=id&with_availability=true'), headers=headers)
res = res.json()
return Quotas(res)
async def get_order(request: Request=None):
await request.receive_body()
return await request.app.ctx.om.get_order(request=request)
class OrderManager:
def __init__(self):
self.cache = {}
self.order_list = []
def add_cache(self, order):
self.cache[order.code] = order
if not order.code in self.order_list:
self.order_list.append(order.code)
def remove_cache(self, code):
if code in self.cache:
del self.cache[code]
self.order_list.remove(code)
async def get_order(self, request=None, code=None, secret=None, cached=False):
# Fill the cache on first load
if not self.cache:
p = 0
async with httpx.AsyncClient() as client:
while 1:
p += 1
res = await client.get(join(base_url, f"orders/?page={p}"), headers=headers)
if res.status_code == 404: break
data = res.json()
for o in data['results']:
o = Order(o)
if o.status in ['canceled', 'expired']: continue
self.add_cache(Order(o))
# If a cached order is needed, just get it if available
if code and cached and code in self.cache and time()-self.cache[code].time < 3600:
return self.cache[code]
# If it's a request, ignore all the other parameters and just get the order of the requestor
if request:
code = request.cookies.get("foxo_code")
secret = request.cookies.get("foxo_secret")
if re.match('^[A-Z0-9]{5}$', code or '') and (secret is None or re.match('^[a-z0-9]{16,}$', secret)):
print('Fetching', code, 'with secret', secret)
async with httpx.AsyncClient() as client:
res = await client.get(join(base_url, f"orders/{code}/"), headers=headers)
if res.status_code != 200:
if request:
raise exceptions.Forbidden("Your session has expired due to order deletion or change! Please check your E-Mail for more info.")
else:
self.remove_cache(code)
return None
res = res.json()
order = Order(res)
if order.status in ['canceled', 'expired']:
if request:
raise exceptions.Forbidden(f"Your order has been deleted. Contact support with your order identifier ({res['code']}) for further info.")
self.add_cache(order)
if request and secret != res['secret']:
raise exceptions.Forbidden("Your session has expired due to a token change. Please check your E-Mail for an updated link!")
return order

7
flag.svg Normal file
View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-it" viewBox="0 0 640 480">
<g fill-rule="evenodd" stroke-width="1pt">
<path fill="#fff" d="M0 0h640v480H0z"/>
<path fill="#009246" d="M0 0h213.3v480H0z"/>
<path fill="#ce2b37" d="M426.7 0H640v480H426.7z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 289 B

6
flags/at.svg Normal file
View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-at" viewBox="0 0 640 480">
<g fill-rule="evenodd">
<path fill="#fff" d="M640 480H0V0h640z"/>
<path fill="#c8102e" d="M640 480H0V320h640zm0-319.9H0V.1h640z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 237 B

4
flags/ca.svg Normal file
View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-ca" viewBox="0 0 640 480">
<path fill="#fff" d="M150.1 0h339.7v480H150z"/>
<path fill="#d52b1e" d="M-19.7 0h169.8v480H-19.7zm509.5 0h169.8v480H489.9zM201 232l-13.3 4.4 61.4 54c4.7 13.7-1.6 17.8-5.6 25l66.6-8.4-1.6 67 13.9-.3-3.1-66.6 66.7 8c-4.1-8.7-7.8-13.3-4-27.2l61.3-51-10.7-4c-8.8-6.8 3.8-32.6 5.6-48.9 0 0-35.7 12.3-38 5.8l-9.2-17.5-32.6 35.8c-3.5.9-5-.5-5.9-3.5l15-74.8-23.8 13.4c-2 .9-4 .1-5.2-2.2l-23-46-23.6 47.8c-1.8 1.7-3.6 1.9-5 .7L264 130.8l13.7 74.1c-1.1 3-3.7 3.8-6.7 2.2l-31.2-35.3c-4 6.5-6.8 17.1-12.2 19.5-5.4 2.3-23.5-4.5-35.6-7 4.2 14.8 17 39.6 9 47.7z"/>
</svg>

After

Width:  |  Height:  |  Size: 643 B

9
flags/ch.svg Normal file
View File

@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-ch" viewBox="0 0 640 480">
<g fill-rule="evenodd" stroke-width="1pt">
<path fill="red" d="M0 0h640v480H0z"/>
<g fill="#fff">
<path d="M170 195h300v90H170z"/>
<path d="M275 90h90v300h-90z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 290 B

5
flags/cz.svg Normal file
View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-cz" viewBox="0 0 640 480">
<path fill="#fff" d="M0 0h640v240H0z"/>
<path fill="#d7141a" d="M0 240h640v240H0z"/>
<path fill="#11457e" d="M360 240 0 0v480z"/>
</svg>

After

Width:  |  Height:  |  Size: 225 B

5
flags/de.svg Normal file
View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-de" viewBox="0 0 640 480">
<path fill="#ffce00" d="M0 320h640v160H0z"/>
<path d="M0 0h640v160H0z"/>
<path fill="#d00" d="M0 160h640v160H0z"/>
</svg>

After

Width:  |  Height:  |  Size: 210 B

5
flags/fi.svg Normal file
View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-fi" viewBox="0 0 640 480">
<path fill="#fff" d="M0 0h640v480H0z"/>
<path fill="#002f6c" d="M0 174.5h640v131H0z"/>
<path fill="#002f6c" d="M175.5 0h130.9v480h-131z"/>
</svg>

After

Width:  |  Height:  |  Size: 234 B

7
flags/fr.svg Normal file
View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-fr" viewBox="0 0 640 480">
<g fill-rule="evenodd" stroke-width="1pt">
<path fill="#fff" d="M0 0h640v480H0z"/>
<path fill="#002654" d="M0 0h213.3v480H0z"/>
<path fill="#ce1126" d="M426.7 0H640v480H426.7z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 289 B

7
flags/gb.svg Normal file
View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-gb" viewBox="0 0 640 480">
<path fill="#012169" d="M0 0h640v480H0z"/>
<path fill="#FFF" d="m75 0 244 181L562 0h78v62L400 241l240 178v61h-80L320 301 81 480H0v-60l239-178L0 64V0h75z"/>
<path fill="#C8102E" d="m424 281 216 159v40L369 281h55zm-184 20 6 35L54 480H0l240-179zM640 0v3L391 191l2-44L590 0h50zM0 0l239 176h-60L0 42V0z"/>
<path fill="#FFF" d="M241 0v480h160V0H241zM0 160v160h640V160H0z"/>
<path fill="#C8102E" d="M0 193v96h640v-96H0zM273 0v480h96V0h-96z"/>
</svg>

After

Width:  |  Height:  |  Size: 535 B

58
flags/hr.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 41 KiB

7
flags/hu.svg Normal file
View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-hu" viewBox="0 0 640 480">
<g fill-rule="evenodd">
<path fill="#fff" d="M640 480H0V0h640z"/>
<path fill="#388d00" d="M640 480H0V320h640z"/>
<path fill="#d43516" d="M640 160.1H0V.1h640z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 271 B

7
flags/it.svg Normal file
View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-it" viewBox="0 0 640 480">
<g fill-rule="evenodd" stroke-width="1pt">
<path fill="#fff" d="M0 0h640v480H0z"/>
<path fill="#009246" d="M0 0h213.3v480H0z"/>
<path fill="#ce2b37" d="M426.7 0H640v480H426.7z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 289 B

5
flags/nl.svg Normal file
View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-nl" viewBox="0 0 640 480">
<path fill="#21468b" d="M0 0h640v480H0z"/>
<path fill="#fff" d="M0 0h640v320H0z"/>
<path fill="#ae1c28" d="M0 0h640v160H0z"/>
</svg>

After

Width:  |  Height:  |  Size: 221 B

6
flags/pl.svg Normal file
View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-pl" viewBox="0 0 640 480">
<g fill-rule="evenodd">
<path fill="#fff" d="M640 480H0V0h640z"/>
<path fill="#dc143c" d="M640 480H0V240h640z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 219 B

18
flags/si.svg Normal file
View File

@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-si" viewBox="0 0 640 480">
<defs>
<clipPath id="a">
<path fill-opacity=".7" d="M-15 0h682.6v512H-15.1z"/>
</clipPath>
</defs>
<g fill-rule="evenodd" stroke-width="1pt" clip-path="url(#a)" transform="translate(14.1) scale(.9375)">
<path fill="#fff" d="M-62 0H962v512H-62z"/>
<path fill="#d50000" d="M-62 341.3H962V512H-62z"/>
<path fill="#0000bf" d="M-62 170.7H962v170.6H-62z"/>
<path fill="#d50000" d="M228.4 93c-4 61.6-6.4 95.4-15.7 111-10.2 16.8-20 29.1-59.7 44-39.6-14.9-49.4-27.2-59.6-44-9.4-15.6-11.7-49.4-15.7-111l5.8-2c11.8-3.6 20.6-6.5 27.1-7.8 9.3-2 17.3-4.2 42.3-4.7 25 .4 33 2.8 42.3 4.8 6.4 1.4 15.6 4 27.3 7.7l5.9 2z"/>
<path fill="#0000bf" d="M222.6 91c-3.8 61.5-7 89.7-12 103.2-9.6 23.2-24.8 35.9-57.6 48-32.8-12.1-48-24.8-57.7-48-5-13.6-8-41.7-11.8-103.3 11.6-3.6 20.6-6.4 27.1-7.7 9.3-2 17.3-4.3 42.3-4.7 25 .4 33 2.7 42.3 4.7a284 284 0 0 1 27.4 7.7z"/>
<path fill="#ffdf00" d="m153 109.8 1.5 3.7 7 1-4.5 2.7 4.3 2.9-6.3 1-2 3.4-2-3.5-6-.8 4-3-4.2-2.7 6.7-1 1.5-3.7z"/>
<path fill="#fff" d="m208.3 179.6-3.9-3-2.7-4.6-5.4-4.7-2.9-4.7-5.4-4.9-2.6-4.7-3-2.3-1.8-1.9-5 4.3-2.6 4.7-3.3 3-3.7-2.9-2.7-4.8-10.3-18.3-10.3 18.3-2.7 4.8-3.7 2.9-3.3-3-2.7-4.7-4.9-4.3-1.9 1.8-2.9 2.4-2.6 4.7-5.4 4.9-2.9 4.7-5.4 4.7-2.7 4.6-3.9 3a65.8 65.8 0 0 0 18.6 36.3 107 107 0 0 0 36.6 20.5 104.1 104.1 0 0 0 36.8-20.5c5.8-6 16.6-19.3 18.6-36.3z"/>
<path fill="#ffdf00" d="m169.4 83.9 1.6 3.7 7 1-4.6 2.7 4.4 2.9-6.3 1-2 3.4-2-3.5-6-.8 4-3-4.2-2.7 6.6-1 1.6-3.7zm-33 0 1.6 3.7 7 .9-4.5 2.7 4.3 2.9-6.3 1-2 3.4-2-3.4-6-.9 4-3-4.2-2.7 6.7-1 1.5-3.7z"/>
<path fill="#0000bf" d="M199.7 203h-7.4l-7-.5-8.3-4h-9.4l-8.1 4-6.5.6-6.4-.6-8.1-4H129l-8.4 4-6.9.6-7.6-.1-3.6-6.2.1-.2 11.2 1.9 6.9-.5 8.3-4.1h9.4l8.2 4 6.4.6 6.5-.6 8.1-4h9.4l8.4 4 6.9.6 10.8-2 .2.4-3.7 6.1zm-86.4 9.5 7.4-.5 8.3-4h9.4l8.2 4 6.4.5 6.4-.5 8.2-4h9.4l8.3 4 7.5.5 4.8-6h-.1l-5.2 1.4-6.9-.5-8.3-4h-9.4l-8.2 4-6.4.6-6.5-.6-8.1-4H129l-8.4 4-6.9.6-5-1.3v.2l4.5 5.6z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

10
flags/us.svg Normal file
View File

@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-us" viewBox="0 0 640 480">
<g fill-rule="evenodd">
<g stroke-width="1pt">
<path fill="#bd3d44" d="M0 0h912v37H0zm0 73.9h912v37H0zm0 73.8h912v37H0zm0 73.8h912v37H0zm0 74h912v36.8H0zm0 73.7h912v37H0zM0 443h912V480H0z"/>
<path fill="#fff" d="M0 37h912v36.9H0zm0 73.8h912v36.9H0zm0 73.8h912v37H0zm0 73.9h912v37H0zm0 73.8h912v37H0zm0 73.8h912v37H0z"/>
</g>
<path fill="#192f5d" d="M0 0h364.8v258.5H0z"/>
<path fill="#fff" d="m30.4 11 3.4 10.3h10.6l-8.6 6.3 3.3 10.3-8.7-6.4-8.6 6.3L25 27.6l-8.7-6.3h10.9zm60.8 0 3.3 10.3h10.8l-8.7 6.3 3.2 10.3-8.6-6.4-8.7 6.3 3.3-10.2-8.6-6.3h10.6zm60.8 0 3.3 10.3H166l-8.6 6.3 3.3 10.3-8.7-6.4-8.7 6.3 3.3-10.2-8.7-6.3h10.8zm60.8 0 3.3 10.3h10.8l-8.7 6.3 3.3 10.3-8.7-6.4-8.7 6.3 3.4-10.2-8.8-6.3h10.7zm60.8 0 3.3 10.3h10.7l-8.6 6.3 3.3 10.3-8.7-6.4-8.7 6.3 3.3-10.2-8.6-6.3h10.7zm60.8 0 3.3 10.3h10.8l-8.8 6.3 3.4 10.3-8.7-6.4-8.7 6.3 3.4-10.2-8.8-6.3h10.8zM60.8 37l3.3 10.2H75l-8.7 6.2 3.2 10.3-8.5-6.3-8.7 6.3 3.1-10.3-8.4-6.2h10.7zm60.8 0 3.4 10.2h10.7l-8.8 6.2 3.4 10.3-8.7-6.3-8.7 6.3 3.3-10.3-8.7-6.2h10.8zm60.8 0 3.3 10.2h10.8l-8.7 6.2 3.3 10.3-8.7-6.3-8.7 6.3 3.3-10.3-8.6-6.2H179zm60.8 0 3.4 10.2h10.7l-8.8 6.2 3.4 10.3-8.7-6.3-8.6 6.3 3.2-10.3-8.7-6.2H240zm60.8 0 3.3 10.2h10.8l-8.7 6.2 3.3 10.3-8.7-6.3-8.7 6.3 3.3-10.3-8.6-6.2h10.7zM30.4 62.6l3.4 10.4h10.6l-8.6 6.3 3.3 10.2-8.7-6.3-8.6 6.3L25 79.3 16.3 73h10.9zm60.8 0L94.5 73h10.8l-8.7 6.3 3.2 10.2-8.6-6.3-8.7 6.3 3.3-10.3-8.6-6.3h10.6zm60.8 0 3.3 10.3H166l-8.6 6.3 3.3 10.2-8.7-6.3-8.7 6.3 3.3-10.3-8.7-6.3h10.8zm60.8 0 3.3 10.3h10.8l-8.7 6.3 3.3 10.2-8.7-6.3-8.7 6.3 3.4-10.3-8.8-6.3h10.7zm60.8 0 3.3 10.3h10.7l-8.6 6.3 3.3 10.2-8.7-6.3-8.7 6.3 3.3-10.3-8.6-6.3h10.7zm60.8 0 3.3 10.3h10.8l-8.8 6.3 3.4 10.2-8.7-6.3-8.7 6.3 3.4-10.3-8.8-6.3h10.8zM60.8 88.6l3.3 10.2H75l-8.7 6.3 3.3 10.3-8.7-6.4-8.7 6.3 3.3-10.2-8.6-6.3h10.7zm60.8 0 3.4 10.2h10.7l-8.8 6.3 3.4 10.3-8.7-6.4-8.7 6.3 3.3-10.2-8.7-6.3h10.8zm60.8 0 3.3 10.2h10.8l-8.7 6.3 3.3 10.3-8.7-6.4-8.7 6.3 3.3-10.2-8.6-6.3H179zm60.8 0 3.4 10.2h10.7l-8.7 6.3 3.3 10.3-8.7-6.4-8.6 6.3 3.2-10.2-8.7-6.3H240zm60.8 0 3.3 10.2h10.8l-8.7 6.3 3.3 10.3-8.7-6.4-8.7 6.3 3.3-10.2-8.6-6.3h10.7zM30.4 114.5l3.4 10.2h10.6l-8.6 6.3 3.3 10.3-8.7-6.4-8.6 6.3L25 131l-8.7-6.3h10.9zm60.8 0 3.3 10.2h10.8l-8.7 6.3 3.2 10.2-8.6-6.3-8.7 6.3 3.3-10.2-8.6-6.3h10.6zm60.8 0 3.3 10.2H166l-8.6 6.3 3.3 10.3-8.7-6.4-8.7 6.3 3.3-10.2-8.7-6.3h10.8zm60.8 0 3.3 10.2h10.8l-8.7 6.3 3.3 10.3-8.7-6.4-8.7 6.3 3.4-10.2-8.8-6.3h10.7zm60.8 0 3.3 10.2h10.7L279 131l3.3 10.3-8.7-6.4-8.7 6.3 3.3-10.2-8.6-6.3h10.7zm60.8 0 3.3 10.2h10.8l-8.8 6.3 3.4 10.3-8.7-6.4-8.7 6.3L329 131l-8.8-6.3h10.8zM60.8 140.3l3.3 10.3H75l-8.7 6.2 3.3 10.3-8.7-6.4-8.7 6.4 3.3-10.3-8.6-6.3h10.7zm60.8 0 3.4 10.3h10.7l-8.8 6.2 3.4 10.3-8.7-6.4-8.7 6.4 3.3-10.3-8.7-6.3h10.8zm60.8 0 3.3 10.3h10.8l-8.7 6.2 3.3 10.3-8.7-6.4-8.7 6.4 3.3-10.3-8.6-6.3H179zm60.8 0 3.4 10.3h10.7l-8.7 6.2 3.3 10.3-8.7-6.4-8.6 6.4 3.2-10.3-8.7-6.3H240zm60.8 0 3.3 10.3h10.8l-8.7 6.2 3.3 10.3-8.7-6.4-8.7 6.4 3.3-10.3-8.6-6.3h10.7zM30.4 166.1l3.4 10.3h10.6l-8.6 6.3 3.3 10.1-8.7-6.2-8.6 6.2 3.2-10.2-8.7-6.3h10.9zm60.8 0 3.3 10.3h10.8l-8.7 6.3 3.3 10.1-8.7-6.2-8.7 6.2 3.4-10.2-8.7-6.3h10.6zm60.8 0 3.3 10.3H166l-8.6 6.3 3.3 10.1-8.7-6.2-8.7 6.2 3.3-10.2-8.7-6.3h10.8zm60.8 0 3.3 10.3h10.8l-8.7 6.3 3.3 10.1-8.7-6.2-8.7 6.2 3.4-10.2-8.8-6.3h10.7zm60.8 0 3.3 10.3h10.7l-8.6 6.3 3.3 10.1-8.7-6.2-8.7 6.2 3.3-10.2-8.6-6.3h10.7zm60.8 0 3.3 10.3h10.8l-8.8 6.3 3.4 10.1-8.7-6.2-8.7 6.2 3.4-10.2-8.8-6.3h10.8zM60.8 192l3.3 10.2H75l-8.7 6.3 3.3 10.3-8.7-6.4-8.7 6.3 3.3-10.2-8.6-6.3h10.7zm60.8 0 3.4 10.2h10.7l-8.8 6.3 3.4 10.3-8.7-6.4-8.7 6.3 3.3-10.2-8.7-6.3h10.8zm60.8 0 3.3 10.2h10.8l-8.7 6.3 3.3 10.3-8.7-6.4-8.7 6.3 3.3-10.2-8.6-6.3H179zm60.8 0 3.4 10.2h10.7l-8.7 6.3 3.3 10.3-8.7-6.4-8.6 6.3 3.2-10.2-8.7-6.3H240zm60.8 0 3.3 10.2h10.8l-8.7 6.3 3.3 10.3-8.7-6.4-8.7 6.3 3.3-10.2-8.6-6.3h10.7zM30.4 217.9l3.4 10.2h10.6l-8.6 6.3 3.3 10.2-8.7-6.3-8.6 6.3 3.2-10.3-8.7-6.3h10.9zm60.8 0 3.3 10.2h10.8l-8.7 6.3 3.3 10.2-8.7-6.3-8.7 6.3 3.4-10.3-8.7-6.3h10.6zm60.8 0 3.3 10.2H166l-8.4 6.3 3.3 10.2-8.7-6.3-8.7 6.3 3.3-10.3-8.7-6.3h10.8zm60.8 0 3.3 10.2h10.8l-8.7 6.3 3.3 10.2-8.7-6.3-8.7 6.3 3.4-10.3-8.8-6.3h10.7zm60.8 0 3.3 10.2h10.7l-8.6 6.3 3.3 10.2-8.7-6.3-8.7 6.3 3.3-10.3-8.6-6.3h10.7zm60.8 0 3.3 10.2h10.8l-8.8 6.3 3.4 10.2-8.7-6.3-8.7 6.3 3.4-10.3-8.8-6.3h10.8z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

76
gen_badges.py Normal file
View File

@ -0,0 +1,76 @@
import httpx
import re
import json
import os
from ext import Order
headers = {'Host': 'reg.furizon.net', 'Authorization': 'Token [REDACTED]'}
output = {}
# uid starts from 2 because of the two hard-coded badge numbers
i = 2
# Furizon was 200 orders, plenty of pages to go through
for x in range(10):
r = httpx.get(f'https://reg.furizon.net/api/v1/organizers/furizon/events/beyond/orders/?page={x+1}', headers=headers)
if r.status_code == 404: break
data = r.json()
for r in data['results']:
badge = open('template.svg', 'r').read()
order = Order(r)
if not order: continue
if order.status != 'paid': continue
# These orders had an hard-coded UID of 1 and 2
if order.code == 'HWUC9':
uid = 2
elif order.code == 'ZUESS':
uid = 1
else:
i += 1
uid = i
output[uid] = (order.code, order.name)
# Replace the various texts and colors inside of the svg
badge = badge.replace('#deadbe', {None: '#546e7a', 'normal': '#8e24aa', 'super': '#fb8c00'}[order.sponsorship])
badge = badge.replace('#SPONSOR_STATUS', {None: 'Regular', 'normal': 'Sponsor', 'super': 'Supersponsor'}[order.sponsorship])
badge = badge.replace('#ATTEND_NAME', order.name)
badge = badge.replace('#CODE', order.code)
badge = badge.replace('#UID', f'{uid:03}')
badge = badge.replace('flag.svg', f"../flags/{order.country.lower()}.svg")
# Change the background of the badge depending on staff role
if order.ans('staff_role'):
if 'main staff' in order.ans('staff_role'):
badge = badge.replace('badge_viola.png', 'badge_rosso.png')
elif 'staff' in order.ans('staff_role'):
badge = badge.replace('badge_viola.png', 'badge_azzurro.png')
# Change the background also based on sponsorship
elif order.sponsorship == 'normal':
badge = badge.replace('badge_viola.png', 'badge_viola.png')
elif order.sponsorship == 'super':
badge = badge.replace('badge_viola.png', 'badge_giallo.png')
else:
badge = badge.replace('badge_viola.png', 'badge_verde.png')
# Fix paths so that they are correct
badge = badge.replace('badge_', '../badge_')
# Add the propics
if order.propic:
badge = badge.replace('avatar.png', f"../propic/{order.propic}")
else:
badge = badge.replace('avatar.png', f"../avatar.png")
# Save the badges
with open(f"output/{uid:03}_{order.code}.svg", 'w') as f:
f.write(badge)
# Use inkscape to convert all badges to pdf and then create a unique file
os.system('inkscape --actions="export-type:pdf;export-do;" output/*.svg')
os.system('rm output/*.svg')
os.system('pdfunite output/* combined.pdf')

127
template.svg Normal file
View File

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
sodipodi:docname="template.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xml:space="preserve"
id="svg5"
version="1.1"
viewBox="0 0 55 85"
height="85mm"
width="55mm"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#999999"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="3.1260366"
inkscape:cx="55.021748"
inkscape:cy="70.696548"
inkscape:window-width="2560"
inkscape:window-height="1035"
inkscape:window-x="0"
inkscape:window-y="21"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" /><defs
id="defs2"><rect
x="14.018331"
y="291.69302"
width="80.720735"
height="20.280508"
id="rect6591" /><rect
x="14.018331"
y="291.69302"
width="80.720734"
height="20.280508"
id="rect6591-9" /><mask
maskUnits="userSpaceOnUse"
id="mask1156"><rect
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke-width:0.964999;stroke-linecap:square;paint-order:markers stroke fill"
id="rect1158"
width="10.29269"
height="7.7195182"
x="39.545406"
y="52.386959"
ry="0.5348357" /></mask><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath1379"><path
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.404752px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 27.494104,-27.494104 22.793538,-2e-6 -11.396768,-11.396768 z"
id="path1381" /></clipPath></defs><g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"><image
width="55.000004"
height="87.897247"
preserveAspectRatio="none"
style="image-rendering:optimizeQuality"
xlink:href="badge_viola.png"
id="image487"
x="-1.4901161e-06"
y="-2.8972483" /><image
width="41.064999"
height="41.064999"
preserveAspectRatio="none"
style="image-rendering:auto"
xlink:href="avatar.png"
id="image17976"
x="6.9675007"
y="31.949114"
mask="none"
inkscape:label="image17976"
inkscape:svg-dpi="300" /><text
xml:space="preserve"
style="font-size:6.42516px;line-height:1.25;font-family:OfficinaSanITCBoo;-inkscape-font-specification:OfficinaSanITCBoo;text-align:center;word-spacing:0px;text-anchor:middle;fill:#000000;stroke-width:0.438077"
x="27.700787"
y="28.132782"
id="text487"
inkscape:label="attend_name"><tspan
sodipodi:role="line"
id="tspan485"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Modern DOS 8x14';-inkscape-font-specification:'Modern DOS 8x14';text-align:center;text-anchor:middle;fill:#000000;stroke-width:0.438077"
x="27.700787"
y="28.132782">#ATTEND_NAME</tspan></text><text
xml:space="preserve"
transform="matrix(0.40062452,0,0,0.40062452,11.538596,-102.11708)"
id="text6589"
style="font-size:14.6667px;line-height:1.25;font-family:OfficinaSanITCBoo;-inkscape-font-specification:OfficinaSanITCBoo;text-align:end;word-spacing:0px;white-space:pre;shape-inside:url(#rect6591);display:inline;fill:#000000"
x="29.450735"
y="0"
inkscape:label="uid"><tspan
x="64.040871"
y="304.88359"
id="tspan1542">#UID</tspan></text><text
xml:space="preserve"
transform="matrix(0.41758719,0,0,0.41758719,-17.932252,-107.16127)"
id="text6589-0"
style="font-size:14.6667px;line-height:1.25;font-family:OfficinaSanITCBoo;-inkscape-font-specification:OfficinaSanITCBoo;text-align:end;word-spacing:0px;white-space:pre;shape-inside:url(#rect6591-9);display:inline;fill:#000000"
x="29.450735"
y="0"
inkscape:label="code"><tspan
x="56.03286"
y="304.88359"
id="tspan1544">#CODE</tspan></text><image
preserveAspectRatio="none"
inkscape:svg-dpi="200"
width="22.45895"
height="16.852631"
style="image-rendering:auto"
xlink:href="flag.svg"
id="image2674"
x="27.956015"
y="-39.333645"
mask="none"
transform="matrix(0.64476446,0.64476446,-0.64476446,0.64476446,4.8930539,-0.0748076)"
clip-path="url(#clipPath1379)"
inkscape:label="flag" /></g></svg>

After

Width:  |  Height:  |  Size: 4.9 KiB