Added order caching
This commit is contained in:
parent
435beecb7c
commit
70f5aaa362
42
app.py
42
app.py
|
@ -19,8 +19,9 @@ app.ext.add_dependency(Quotas, get_quotas)
|
||||||
|
|
||||||
from room import bp as room_bp
|
from room import bp as room_bp
|
||||||
from propic import bp as propic_bp
|
from propic import bp as propic_bp
|
||||||
|
from export import bp as export_bp
|
||||||
|
|
||||||
app.blueprint([room_bp,propic_bp])
|
app.blueprint([room_bp,propic_bp,export_bp])
|
||||||
|
|
||||||
@app.exception(exceptions.SanicException)
|
@app.exception(exceptions.SanicException)
|
||||||
async def clear_session(request, exception):
|
async def clear_session(request, exception):
|
||||||
|
@ -35,13 +36,13 @@ async def clear_session(request, exception):
|
||||||
@app.before_server_start
|
@app.before_server_start
|
||||||
async def main_start(*_):
|
async def main_start(*_):
|
||||||
print(">>>>>> main_start <<<<<<")
|
print(">>>>>> main_start <<<<<<")
|
||||||
|
|
||||||
|
app.ctx.om = OrderManager()
|
||||||
app.ctx.tpl = Environment(loader=FileSystemLoader("tpl"), autoescape=True)
|
app.ctx.tpl = Environment(loader=FileSystemLoader("tpl"), autoescape=True)
|
||||||
app.ctx.tpl.globals.update(time=time)
|
app.ctx.tpl.globals.update(time=time)
|
||||||
app.ctx.tpl.globals.update(int=int)
|
app.ctx.tpl.globals.update(int=int)
|
||||||
app.ctx.tpl.globals.update(len=len)
|
app.ctx.tpl.globals.update(len=len)
|
||||||
|
|
||||||
app.ctx.order_cache = {}
|
|
||||||
|
|
||||||
@app.route("/manage/barcode/<code>")
|
@app.route("/manage/barcode/<code>")
|
||||||
async def gen_barcode(request, code):
|
async def gen_barcode(request, code):
|
||||||
aa = AztecCode(code).image(module_size=8, border=2)
|
aa = AztecCode(code).image(module_size=8, border=2)
|
||||||
|
@ -50,22 +51,23 @@ async def gen_barcode(request, code):
|
||||||
|
|
||||||
return raw(img.getvalue(), content_type="image/png")
|
return raw(img.getvalue(), content_type="image/png")
|
||||||
|
|
||||||
|
@app.route("/manage/cache")
|
||||||
|
async def cache_status(request):
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/manage/stats")
|
||||||
|
async def stats(request, order: Order):
|
||||||
|
|
||||||
|
with open('res/stats.json') as f:
|
||||||
|
stats = json.load(f)
|
||||||
|
|
||||||
|
tpl = app.ctx.tpl.get_template('stats.html')
|
||||||
|
return html(tpl.render(order=order, stats=stats))
|
||||||
|
|
||||||
@app.route("/manage/nosecount")
|
@app.route("/manage/nosecount")
|
||||||
async def nose_count(request, order: Order):
|
async def nose_count(request, order: Order):
|
||||||
p = 0
|
orders = {key:value for key,value in sorted(app.ctx.om.cache.items(), key=lambda x: len(x[1].room_members), reverse=True) if value.status not in ['c', 'e']}
|
||||||
orders = {}
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
while 1:
|
|
||||||
p += 1
|
|
||||||
res = await client.get(join(base_url, f"orders/?include_canceled_positions=false&page={p}"), headers=headers)
|
|
||||||
|
|
||||||
if res.status_code == 404: break
|
|
||||||
|
|
||||||
data = res.json()
|
|
||||||
for o in data['results']:
|
|
||||||
orders[o['code']] = Order(o)
|
|
||||||
|
|
||||||
orders = {key:value for key,value in sorted(orders.items(), key=lambda x: len(x[1].room_members), reverse=True)}
|
|
||||||
|
|
||||||
tpl = app.ctx.tpl.get_template('nosecount.html')
|
tpl = app.ctx.tpl.get_template('nosecount.html')
|
||||||
return html(tpl.render(orders=orders, order=order))
|
return html(tpl.render(orders=orders, order=order))
|
||||||
|
@ -99,12 +101,12 @@ async def welcome(request, order: Order, quota: Quotas):
|
||||||
if order.pending_roommates:
|
if order.pending_roommates:
|
||||||
for pr in order.pending_roommates:
|
for pr in order.pending_roommates:
|
||||||
if not pr: continue
|
if not pr: continue
|
||||||
pending_roommates.append(await get_order(code=pr, insecure=True))
|
pending_roommates.append(await app.ctx.om.get_order(code=pr, cached=True))
|
||||||
|
|
||||||
room_members = []
|
room_members = []
|
||||||
if order.room_id:
|
if order.room_id:
|
||||||
if order.room_id != order.code:
|
if order.room_id != order.code:
|
||||||
room_owner = await get_order(code=order.room_id, insecure=True)
|
room_owner = await app.ctx.om.get_order(code=order.room_id, cached=True)
|
||||||
else:
|
else:
|
||||||
room_owner = order
|
room_owner = order
|
||||||
|
|
||||||
|
@ -115,7 +117,7 @@ async def welcome(request, order: Order, quota: Quotas):
|
||||||
if member_id == order.code:
|
if member_id == order.code:
|
||||||
room_members.append(order)
|
room_members.append(order)
|
||||||
else:
|
else:
|
||||||
room_members.append(await get_order(code=member_id, insecure=True))
|
room_members.append(await app.ctx.om.get_order(code=member_id, cached=True))
|
||||||
|
|
||||||
tpl = app.ctx.tpl.get_template('welcome.html')
|
tpl = app.ctx.tpl.get_template('welcome.html')
|
||||||
return html(tpl.render(order=order, quota=quota, room_members=room_members, pending_roommates=pending_roommates))
|
return html(tpl.render(order=order, quota=quota, room_members=room_members, pending_roommates=pending_roommates))
|
||||||
|
|
114
ext.py
114
ext.py
|
@ -5,15 +5,22 @@ import re
|
||||||
from config import *
|
from config import *
|
||||||
from os.path import join
|
from os.path import join
|
||||||
import json
|
import json
|
||||||
|
from time import time
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Order:
|
class Order:
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
|
|
||||||
|
self.time = time
|
||||||
self.data = data
|
self.data = data
|
||||||
self.status = {'n': 'pending', 'p': 'paid', 'e': 'expired', 'c': 'canceled'}[self.data['status']]
|
self.status = {'n': 'pending', 'p': 'paid', 'e': 'expired', 'c': 'canceled'}[self.data['status']]
|
||||||
self.code = data['code']
|
self.code = data['code']
|
||||||
|
self.pending_update = False
|
||||||
|
|
||||||
self.has_card = False
|
self.has_card = False
|
||||||
self.sponsorship = None
|
self.sponsorship = None
|
||||||
|
self.has_early = False
|
||||||
|
self.has_late = False
|
||||||
|
|
||||||
for p in self.data['positions']:
|
for p in self.data['positions']:
|
||||||
if p['item'] in [16, 38]:
|
if p['item'] in [16, 38]:
|
||||||
|
@ -31,8 +38,25 @@ class Order:
|
||||||
if p['country']:
|
if p['country']:
|
||||||
self.country = 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.shirt_size = self.ans('shirt_size')
|
||||||
self.birth_date = self.ans('birth_date')
|
|
||||||
self.is_artist = True if self.ans('is_artist') != 'No' else False
|
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_fursuiter = True if self.ans('is_fursuiter') != 'No' else False
|
||||||
self.is_allergic = True if self.ans('is_allergic') != 'No' else False
|
self.is_allergic = True if self.ans('is_allergic') != 'No' else False
|
||||||
|
@ -47,6 +71,7 @@ class Order:
|
||||||
self.room_owner = (self.code == self.room_id)
|
self.room_owner = (self.code == self.room_id)
|
||||||
self.room_secret = self.ans('room_secret')
|
self.room_secret = self.ans('room_secret')
|
||||||
|
|
||||||
|
|
||||||
def __getitem__(self, var):
|
def __getitem__(self, var):
|
||||||
return self.data[var]
|
return self.data[var]
|
||||||
|
|
||||||
|
@ -61,6 +86,7 @@ class Order:
|
||||||
|
|
||||||
async def edit_answer(self, name, new_answer):
|
async def edit_answer(self, name, new_answer):
|
||||||
found = False
|
found = False
|
||||||
|
self.pending_update = True
|
||||||
for key in range(len(self.answers)):
|
for key in range(len(self.answers)):
|
||||||
if self.answers[key]['question_identifier'] == name:
|
if self.answers[key]['question_identifier'] == name:
|
||||||
if new_answer != None:
|
if new_answer != None:
|
||||||
|
@ -93,6 +119,7 @@ class Order:
|
||||||
async def send_answers(self):
|
async def send_answers(self):
|
||||||
async with httpx.AsyncClient() as client:
|
async with httpx.AsyncClient() as client:
|
||||||
res = await client.patch(join(base_url, f'orderpositions/{self.position_id}/'), headers=headers, json={'answers': self.answers})
|
res = await client.patch(join(base_url, f'orderpositions/{self.position_id}/'), headers=headers, json={'answers': self.answers})
|
||||||
|
self.pending_update = False
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Quotas:
|
class Quotas:
|
||||||
|
@ -118,33 +145,72 @@ async def get_quotas(request: Request=None):
|
||||||
|
|
||||||
return Quotas(res)
|
return Quotas(res)
|
||||||
|
|
||||||
async def get_order(request: Request=None, code=None, secret=None, insecure=False):
|
async def get_order(request: Request=None):
|
||||||
if request:
|
await request.receive_body()
|
||||||
await request.receive_body()
|
return await request.app.ctx.om.get_order(request=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)):
|
class OrderManager:
|
||||||
print('Fetching', code, 'with secret', secret)
|
def __init__(self):
|
||||||
|
self.cache = {}
|
||||||
|
self.order_list = []
|
||||||
|
|
||||||
async with httpx.AsyncClient() as client:
|
def add_cache(self, order):
|
||||||
res = await client.get(join(base_url, f"orders/{code}/"), headers=headers)
|
self.cache[order.code] = order
|
||||||
if res.status_code != 200:
|
if not order.code in self.order_list:
|
||||||
if request:
|
self.order_list.append(order.code)
|
||||||
raise exceptions.Forbidden("Your session has expired due to order deletion or change! Please check your E-Mail for more info.")
|
|
||||||
|
|
||||||
res = res.json()
|
def remove_cache(self, code):
|
||||||
|
if code in self.cache:
|
||||||
|
del self.cache[code]
|
||||||
|
self.order_list.remove(code)
|
||||||
|
|
||||||
if request and res:
|
async def get_order(self, request=None, code=None, secret=None, cached=False):
|
||||||
request.app.ctx.order_cache = {}
|
|
||||||
|
|
||||||
if res['status'] in ['c', 'e']:
|
# Fill the cache on first load
|
||||||
if request:
|
if not self.cache:
|
||||||
raise exceptions.Forbidden(f"Your order has been deleted. Contact support with your order identifier ({res['code']}) for further info.")
|
p = 0
|
||||||
|
|
||||||
if secret == res['secret'] or insecure:
|
async with httpx.AsyncClient() as client:
|
||||||
return Order(res)
|
while 1:
|
||||||
else:
|
p += 1
|
||||||
if request:
|
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']:
|
||||||
|
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 < 1800:
|
||||||
|
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()
|
||||||
|
|
||||||
|
if res['status'] in ['c', 'e']:
|
||||||
|
if request:
|
||||||
|
raise exceptions.Forbidden(f"Your order has been deleted. Contact support with your order identifier ({res['code']}) for further info.")
|
||||||
|
|
||||||
|
order = Order(res)
|
||||||
|
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!")
|
raise exceptions.Forbidden("Your session has expired due to a token change. Please check your E-Mail for an updated link!")
|
||||||
return None
|
return order
|
||||||
|
|
Loading…
Reference in New Issue