Initial commit.
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 296 KiB |
After Width: | Height: | Size: 295 KiB |
After Width: | Height: | Size: 297 KiB |
After Width: | Height: | Size: 299 KiB |
After Width: | Height: | Size: 299 KiB |
|
@ -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
|
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
After Width: | Height: | Size: 41 KiB |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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')
|
|
@ -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 |