-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hotel Lottery Forms #4360
base: main
Are you sure you want to change the base?
Hotel Lottery Forms #4360
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
[hotel_lottery] | ||
[[hotels]] | ||
[[[gaylord]]] | ||
name = "Gaylord National Harbor" | ||
description = "The drive can't be that bad, can it?" | ||
|
||
[[[roof]]] | ||
name = "Rooftop Room" | ||
description = "Camping out on the roof of the Donald E. Stephens Convention Center" | ||
|
||
[[[cardboard]]] | ||
name = "Cardboard Box" | ||
description = "Literally a big box. Do you fits?" | ||
|
||
[[[mark_center]]] | ||
name = "Hilton Mark Center" | ||
description = "The tall one" | ||
|
||
[[room_types]] | ||
[[[king]]] | ||
name = "King Room" | ||
description = "One really big bed" | ||
|
||
[[[double]]] | ||
name = "Double Room" | ||
description = "Two beds" | ||
|
||
[[suite_room_types]] | ||
[[[super]]] | ||
name = "Super Suite" | ||
description = "This is the one everyone wants" | ||
|
||
[[[meh]]] | ||
name = "Meh Suite" | ||
description = "I guess" | ||
|
||
[[[overpriced]]] | ||
name = "Overpriced Suite" | ||
description = "This one is just crazy expensive. Otherwise a normal room." | ||
|
||
[[hotel_priorities]] | ||
[[[hotel]]] | ||
name = "Hotel" | ||
description = "Which hotel matters to me." | ||
|
||
[[[dates]]] | ||
name = "Dates" | ||
description = "Check-In and Check-Out dates matter to me." | ||
|
||
[[[room]]] | ||
name = "Room Type" | ||
description = "The type of room I get matters." |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,7 @@ | |
|
||
from uber.config import c | ||
from uber.forms import (AddressForm, MultiCheckbox, MagForm, SelectAvailableField, SwitchInput, NumberInputGroup, | ||
HiddenBoolField, HiddenIntField, CustomValidation) | ||
HiddenBoolField, HiddenIntField, CustomValidation, Ranking) | ||
from uber.custom_tags import popup_link | ||
from uber.badge_funcs import get_real_badge_type | ||
from uber.models import Attendee, Session, PromoCodeGroup | ||
|
@@ -18,7 +18,8 @@ | |
|
||
|
||
__all__ = ['AdminBadgeExtras', 'AdminBadgeFlags', 'AdminConsents', 'AdminStaffingInfo', 'BadgeExtras', | ||
'BadgeFlags', 'BadgeAdminNotes', 'PersonalInfo', 'PreregOtherInfo', 'OtherInfo', 'StaffingInfo', 'Consents'] | ||
'BadgeFlags', 'BadgeAdminNotes', 'PersonalInfo', 'PreregOtherInfo', 'OtherInfo', 'StaffingInfo', | ||
'LotteryApplication', 'Consents'] | ||
|
||
|
||
# TODO: turn this into a proper validation class | ||
|
@@ -28,6 +29,26 @@ def valid_cellphone(form, field): | |
'include a country code (e.g. +44) for international numbers.') | ||
|
||
|
||
class LotteryApplication(MagForm): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's move this into its own forms/hotel.py file, to more closely reflect where it is in models/. I'm sure we'll have plenty of lottery-related forms as we progress so it won't be a file with just one class in it. Also, just wondering, why is this a StringField and not a SelectMultipleField or similar? Is it because the choices have to be ordered? |
||
wants_room = BooleanField('I would like to enter the hotel room lottery.', default=False) | ||
earliest_room_checkin_date = DateField('Earliest acceptable Check-In Date', validators=[validators.DataRequired("Please enter your earliest check-in date.")]) | ||
latest_room_checkin_date = DateField('Latest acceptable Check-In Date', validators=[validators.DataRequired("Please enter your latest check-in date.")]) | ||
earliest_room_checkout_date = DateField('Earliest acceptable Check-Out Date', validators=[validators.DataRequired("Please enter your earliest check-out date.")]) | ||
latest_room_checkout_date = DateField('Latest acceptable Check-Out Date', validators=[validators.DataRequired("Please enter your latest check-out date.")]) | ||
hotel_preference = StringField('Hotel Preference', widget=Ranking(c.HOTEL_LOTTERY_HOTELS_OPTS, id="hotel_preference")) | ||
room_type_preference = StringField('Room Type Preference', widget=Ranking(c.HOTEL_LOTTERY_ROOM_TYPES_OPTS, id="room_type_preference")) | ||
selection_priorities = StringField('Room Priorities', widget=Ranking(c.HOTEL_LOTTERY_HOTEL_PRIORITIES_OPTS, id="selection_priorities")) | ||
accessibility_contact = BooleanField('Please contact me in regards to an accessibility requirement.', default=False) | ||
|
||
wants_suite = BooleanField('I would like to enter the suite lottery.', default=False) | ||
earliest_suite_checkin_date = DateField('Earliest acceptable Check-In Date', validators=[validators.DataRequired("Please enter your earliest check-in date.")]) | ||
latest_suite_checkin_date = DateField('Latest acceptable Check-In Date', validators=[validators.DataRequired("Please enter your latest check-in date.")]) | ||
earliest_suite_checkout_date = DateField('Earliest acceptable Check-Out Date', validators=[validators.DataRequired("Please enter your earliest check-out date.")]) | ||
latest_suite_checkout_date = DateField('Latest acceptable Check-Out Date', validators=[validators.DataRequired("Please enter your latest check-out date.")]) | ||
suite_type_preference = StringField('Hotel Preference', widget=Ranking(c.HOTEL_LOTTERY_SUITE_ROOM_TYPES_OPTS, id="suite_type_preference")) | ||
|
||
terms_accepted = BooleanField('I accept the terms of service of the hotel lottery.', default=False) | ||
|
||
class PersonalInfo(AddressForm, MagForm): | ||
field_validation, new_or_changed_validation = CustomValidation(), CustomValidation() | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,12 +5,16 @@ | |
from wtforms.validators import ValidationError | ||
|
||
from uber.config import c | ||
from uber.forms import AddressForm, CustomValidation, MultiCheckbox, MagForm, IntSelect, NumberInputGroup | ||
from uber.forms import AddressForm, CustomValidation, MultiCheckbox, MagForm, IntSelect, NumberInputGroup, Ranking | ||
from uber.forms.attendee import valid_cellphone | ||
from uber.custom_tags import format_currency, pluralize | ||
from uber.model_checks import invalid_phone_number | ||
|
||
__all__ = ['GroupInfo', 'ContactInfo', 'TableInfo', 'AdminGroupInfo', 'AdminTableInfo'] | ||
__all__ = ['HotelLotteryApplication', 'GroupInfo', 'ContactInfo', 'TableInfo', 'AdminGroupInfo', 'AdminTableInfo'] | ||
|
||
|
||
class HotelLotteryApplication(MagForm): | ||
ranked_hotels = Ranking(c.HOTEL_LOTTERY.keys()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is Ranking() a widget or a field class? I see this form isn't being used, is it just left over from something else you were trying? |
||
|
||
|
||
class GroupInfo(MagForm): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -102,3 +102,59 @@ def render_option(cls, value, label, selected, **kwargs): | |
return Markup( | ||
"<option {}>{}</option>".format(html_params(**options), escape(label)) | ||
) | ||
|
||
class Ranking(): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to double-check, should this be subclassing an existing WTForms widget? |
||
def __init__(self, choices=None, id=None, **kwargs): | ||
self.choices = choices | ||
self.id = id | ||
|
||
def __call__(self, field, choices=None, id=None, **kwargs): | ||
choices = choices or self.choices or [('', {"name": "Error", "description": "No choices are configured"})] | ||
id = id or self.id or "ranking" | ||
selected_choices = field.data.split(",") | ||
|
||
deselected_html = [] | ||
selected_html = [] | ||
choice_dict = {key: val for key, val in choices} | ||
for choice_id in selected_choices: | ||
try: | ||
choice_item = choice_dict[choice_id] | ||
el = f""" | ||
<li class="choice" value="{choice_id}"> | ||
<div class="choice-name"> | ||
{choice_item["name"]} | ||
</div> | ||
<div class="choice-description"> | ||
{choice_item["description"]} | ||
</div> | ||
</li>""" | ||
selected_html.append(el) | ||
except KeyError: | ||
continue | ||
for choice_id, choice_item in choices: | ||
if not choice_id in selected_choices: | ||
el = f""" | ||
<li class="choice" value="{choice_id}"> | ||
<div class="choice-name"> | ||
{choice_item["name"]} | ||
</div> | ||
<div class="choice-description"> | ||
{choice_item["description"]} | ||
</div> | ||
</li>""" | ||
deselected_html.append(el) | ||
|
||
html = [ | ||
'<div class="row">', | ||
'<div class="col-md-6">', | ||
'Available', | ||
f'<ul class="choice-list" id="deselected_{id}">', | ||
*deselected_html, | ||
'</ul></div><div class="col-md-6">', | ||
'Selected', | ||
f'<ul class="choice-list" id="selected_{id}">', | ||
*selected_html, | ||
f'</ul></div></div><input type="hidden" id="{id}" name="{id}" value="None" />' | ||
] | ||
|
||
return Markup(''.join(html)) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
from datetime import datetime | ||
|
||
from uber.config import c | ||
from uber.decorators import ajax, all_renderable | ||
from uber.errors import HTTPRedirect | ||
from uber.models import Attendee, Room, RoomAssignment, Shift, LotteryApplication | ||
from uber.forms import load_forms | ||
from uber.utils import validate_model | ||
|
||
|
||
@all_renderable() | ||
class Root: | ||
def index(self, session, **params): | ||
lottery_application = LotteryApplication() | ||
params['id'] = 'None' | ||
forms = load_forms(params, lottery_application, ['LotteryApplication']) | ||
return { | ||
"checkin_start": c.HOTEL_LOTTERY_CHECKIN_START, | ||
"checkin_end": c.HOTEL_LOTTERY_CHECKIN_END, | ||
"checkout_start": c.HOTEL_LOTTERY_CHECKOUT_START, | ||
"checkout_end": c.HOTEL_LOTTERY_CHECKOUT_END, | ||
"hotels": c.HOTEL_LOTTERY, | ||
"forms": forms | ||
} | ||
|
||
@ajax | ||
def validate_hotel_lottery(self, session, form_list=[], **params): | ||
if params.get('id') in [None, '', 'None']: | ||
application = LotteryApplication() | ||
else: | ||
application = LotteryApplication.get(id=params.get('id')) | ||
|
||
if not form_list: | ||
form_list = ["LotteryApplication"] | ||
elif isinstance(form_list, str): | ||
form_list = [form_list] | ||
forms = load_forms(params, application, form_list, get_optional=False) | ||
|
||
all_errors = validate_model(forms, application, LotteryApplication(**application.to_dict())) | ||
if all_errors: | ||
return {"error": all_errors} | ||
|
||
return {"success": True} | ||
|
||
def form(self, session, message="", **params): | ||
application = LotteryApplication() | ||
forms_list = ["LotteryApplication"] | ||
forms = load_forms(params, application, forms_list) | ||
for form in forms.values(): | ||
form.populate_obj(application) | ||
return { | ||
'forms': forms, | ||
'message': message, | ||
'application': application | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to double-check, is/was this a temporary statement for debugging?