Compare commits

..

4 Commits

6 changed files with 66 additions and 44 deletions

2
.gitignore vendored
View File

@ -165,3 +165,5 @@ res/rooms/*
config.py config.py
furizon_webinit_riverside2023.tar.gz furizon_webinit_riverside2023.tar.gz
diomerdas diomerdas
furizon.net/site/*
furizon.net.zip

View File

@ -8,37 +8,42 @@ from config import SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASSWORD
from jinja2 import Environment, FileSystemLoader from jinja2 import Environment, FileSystemLoader
async def send_unconfirm_message (room_order, orders): async def send_unconfirm_message (room_order, orders):
memberMessages = [] memberMessages = []
issues_plain = "" issues_plain = ""
issues_html = "<ul>" issues_html = "<ul>"
for err in room_order.room_errors: for err in room_order.room_errors:
if err in ROOM_ERROR_TYPES.keys(): errId = err[1]
issues_plain += f"{ROOM_ERROR_TYPES[err]}\n" order = err[0]
issues_html += f"<li>{ROOM_ERROR_TYPES[err]}</li>" orderStr = ""
issues_html += "</ul>" if order is not None:
orderStr = f"{order}: "
if errId in ROOM_ERROR_TYPES.keys():
issues_plain += f"{orderStr}{ROOM_ERROR_TYPES[errId]}\n"
issues_html += f"<li>{orderStr}{ROOM_ERROR_TYPES[errId]}</li>"
issues_html += "</ul>"
for member in orders: for member in orders:
plain_body = ROOM_UNCONFIRM_TEXT['plain'].format(member.name, room_order.room_name, issues_plain) plain_body = ROOM_UNCONFIRM_TEXT['plain'].format(member.name, room_order.room_name, issues_plain)
html_body = render_email_template(ROOM_UNCONFIRM_TITLE, ROOM_UNCONFIRM_TEXT['html'].format(member.name, room_order.room_name, issues_html)) html_body = render_email_template(ROOM_UNCONFIRM_TITLE, ROOM_UNCONFIRM_TEXT['html'].format(member.name, room_order.room_name, issues_html))
plain_text = MIMEText(plain_body, "plain") plain_text = MIMEText(plain_body, "plain")
html_text = MIMEText(html_body, "html") html_text = MIMEText(html_body, "html")
message = MIMEMultipart("alternative") message = MIMEMultipart("alternative")
message.attach(plain_text) message.attach(plain_text)
message.attach(html_text) message.attach(html_text)
message['Subject'] = '[Furizon] Your room cannot be confirmed' message['Subject'] = '[Furizon] Your room cannot be confirmed'
message['From'] = 'Furizon <no-reply@furizon.net>' message['From'] = 'Furizon <no-reply@furizon.net>'
message['To'] = f"{member.name} <{member.email}>" message['To'] = f"{member.name} <{member.email}>"
memberMessages.append(message) memberMessages.append(message)
if len(memberMessages) == 0: return if len(memberMessages) == 0: return
with smtplib.SMTP_SSL(SMTP_HOST, SMTP_PORT) as sender: with smtplib.SMTP_SSL(SMTP_HOST, SMTP_PORT) as sender:
sender.login(SMTP_USER, SMTP_PASSWORD) sender.login(SMTP_USER, SMTP_PASSWORD)
for message in memberMessages: for message in memberMessages:
sender.sendmail(message['From'], message['to'], message.as_string()) sender.sendmail(message['From'], message['to'], message.as_string())
def render_email_template(title = "", body = ""): def render_email_template(title = "", body = ""):
tpl = Environment(loader=FileSystemLoader("tpl"), autoescape=False).get_template('email/comunication.html') tpl = Environment(loader=FileSystemLoader("tpl"), autoescape=False).get_template('email/comunication.html')
return str(tpl.render(title=title, body=body)) return str(tpl.render(title=title, body=body))

View File

@ -18,7 +18,8 @@ def draw_profile (source, member, position, font, size=(170, 170), border_width=
# Draw border # Draw border
idraw.rounded_rectangle(border_loc, border_width, border_color) idraw.rounded_rectangle(border_loc, border_width, border_color)
# Draw profile picture # Draw profile picture
with Image.open(f'res/propic/{member['propic'] or 'default.png'}') as to_add: fileName = member['propic'] or 'default.png'
with Image.open(f'res/propic/{fileName}') as to_add:
source.paste(to_add.resize (size), profile_location) source.paste(to_add.resize (size), profile_location)
name_len = idraw.textlength(str(member['name']), font) name_len = idraw.textlength(str(member['name']), font)
calc_size = 0 calc_size = 0

View File

@ -20,7 +20,7 @@
h1 img {max-height:1.4em;} h1 img {max-height:1.4em;}
.notice {padding:0.8em;border-radius:3px;background:#e53935;color:#eee;} .notice {padding:0.8em;border-radius:3px;background:#e53935;color:#eee;}
.notice a {color:#eee;text-decoration:underline;} .notice a {color:#eee;text-decoration:underline;}
.container {max-width:40em;padding:1em;box-sizing:border-box;} .container {max-width:50em;padding:1em;box-sizing:border-box;}
td > a[role=button] {padding: 0.3em 0.7em;} td > a[role=button] {padding: 0.3em 0.7em;}
td {padding-left: 0.2em;padding-right: 0.2em;} td {padding-left: 0.2em;padding-right: 0.2em;}
td > input[type=file] {margin:0;padding:0;} td > input[type=file] {margin:0;padding:0;}

View File

@ -88,8 +88,8 @@
<details id="shuttle"> <details id="shuttle">
<summary role="button"><img src="/res/icons/bus.svg" class="icon" />Shuttle</summary> <summary role="button"><img src="/res/icons/bus.svg" class="icon" />Shuttle</summary>
<p>This year we teamed up with VisitFiemme to take our guests to the convention.</p> <p>This year, a shuttle service operated by the tourism company of Val di Fiemme will be available. The shuttle service will consist of a bus serving the convention, with scheduled stops at major airports and train stations. More informations <a href="https://furizon.net/furizon-overlord/furizon-overlord-shuttle-bus/">in the dedicated page.</a></p>
<p style="text-align:right;"><a href="{{LOCALES['shuttle_link_url'][locale]}}" target="_blank" role="button">Book now</a></p> <p style="text-align:right;"><a href="{{LOCALES['shuttle_link_url'][locale]}}" target="_blank" role="button">Book now!</a></p>
</details> </details>
<details id="barcard"> <details id="barcard">

View File

@ -154,26 +154,32 @@ async def validate_rooms(request, rooms, om):
logger.info('Validating rooms...') logger.info('Validating rooms...')
if not om: om = request.app.ctx.om if not om: om = request.app.ctx.om
failed_rooms = [] # rooms_to_unconfirm is the room that MUST be unconfirmed, room_with_errors is a less strict set containing all rooms with kind-ish errors
rooms_to_unconfirm = []
room_with_errors = []
# Validate rooms # Validate rooms
for order in rooms: for order in rooms:
# returns tuple (room owner order, check, room error list, room members orders)
result = await check_room(request, order, om) result = await check_room(request, order, om)
order = result[0] if(len(order.room_errors) > 0):
room_with_errors.append(result)
check = result[1] check = result[1]
if check != None and check == False: if check != None and check == False:
failed_rooms.append(result) rooms_to_unconfirm.append(result)
# End here if no room has failed check # End here if no room has failed check
if len(failed_rooms) == 0: if len(room_with_errors) == 0:
logger.info('[ROOM VALIDATION] Every room passed the check.') logger.info('[ROOM VALIDATION] Every room passed the check.')
return return
logger.warning(f'[ROOM VALIDATION] Room validation failed for orders: %s', list(map(lambda rf: rf[0].code, failed_rooms))) roomErrListSrts = []
for fr in room_with_errors:
for error in fr[0].room_errors:
roomErrListSrts.append(f"[ROOM VALIDATION] [ERR] Parent room: {fr[0].code} {'C' if fr[0].room_confirmed else 'N'} | Order {error[0] if error[0] else '-----'} with code {error[1]}")
logger.warning(f'[ROOM VALIDATION] Room validation failed for orders: \n%s', "\n".join(roomErrListSrts))
# Get confirmed rooms that fail validation # Get confirmed rooms that fail validation
failed_confirmed_rooms = list(filter(lambda fr: (fr[0].room_confirmed == True), failed_rooms)) failed_confirmed_rooms = list(filter(lambda fr: (fr[0].room_confirmed == True), rooms_to_unconfirm))
if len(failed_confirmed_rooms) == 0: if len(failed_confirmed_rooms) == 0:
logger.info('[ROOM VALIDATION] No rooms to unconfirm.') logger.info('[ROOM VALIDATION] No rooms to unconfirm.')
@ -213,6 +219,7 @@ async def check_room(request, order, om=None):
# This is not needed anymore you buy tickets already # This is not needed anymore you buy tickets already
#if quotas.get_left(len(order.room_members)) == 0: #if quotas.get_left(len(order.room_members)) == 0:
# raise exceptions.BadRequest("There are no more rooms of this size to reserve.") # raise exceptions.BadRequest("There are no more rooms of this size to reserve.")
allOk = True
bed_in_room = order.bed_in_room # Variation id of the ticket for that kind of room bed_in_room = order.bed_in_room # Variation id of the ticket for that kind of room
for m in order.room_members: for m in order.room_members:
@ -223,20 +230,27 @@ async def check_room(request, order, om=None):
# Room user in another room # Room user in another room
if res.room_id != order.code: if res.room_id != order.code:
room_errors.append('room_id_mismatch') room_errors.append((res.code, 'room_id_mismatch'))
allOk = False
if res.status != 'paid': if res.status != 'paid':
room_errors.append('unpaid') room_errors.append((res.code, 'unpaid'))
if res.bed_in_room != bed_in_room: if res.bed_in_room != bed_in_room:
room_errors.append('type_mismatch') room_errors.append((res.code, 'type_mismatch'))
if order.room_confirmed:
allOk = False
if res.daily: if res.daily:
room_errors.append('daily') room_errors.append((res.code, 'daily'))
if order.room_confirmed:
allOk = False
room_members.append(res) room_members.append(res)
if len(room_members) != order.room_person_no and order.room_person_no != None: if len(room_members) != order.room_person_no and order.room_person_no != None:
room_errors.append('capacity_mismatch') room_errors.append((None, 'capacity_mismatch'))
if order.room_confirmed:
allOk = False
order.set_room_errors(room_errors) order.set_room_errors(room_errors)
return (order, len(room_errors) == 0, room_members) return (order, allOk, room_members)