def price_notice(label, takedown, amount_extra=0, discount=0): if not takedown: takedown = c.ESCHATON prereg_pages = ['/preregistration/form', '/preregistration/post_form', '/preregistration/register_group_member'] if c.PAGE_PATH not in prereg_pages: return '' # we only display notices for new attendees else: badge_price = c.BADGE_PRICE # optimization. this call is VERY EXPENSIVE. on_or_by = "no later than" if c.PRICE_LIMITS else "on" for day, price in sorted(c.PRICE_BUMPS.items()): if day < takedown and localized_now() < day and price > badge_price: new_price = price - int(discount) + int(amount_extra) new_price_date = day - timedelta(days=1) return safe_string( '<div class="prereg-price-notice">Price goes up to ${} {} 11:59pm {} on {}</div>'.format( new_price, on_or_by, new_price_date.strftime('%Z'), new_price_date.strftime('%A, %b %e'))) elif localized_now() < day and takedown == c.PREREG_TAKEDOWN and takedown < c.EPOCH and price > badge_price: new_price = price + amount_extra return safe_string(( '<div class="prereg-type-closing">' '{} closes at 11:59pm {} on {}. Price goes up to ${} at-door.' '</div>').format( label, takedown.strftime('%Z'), takedown.strftime('%A, %b %e'), new_price)) if takedown < c.EPOCH: return safe_string( '<div class="prereg-type-closing">{} closes at 11:59pm {} on {}</div>'.format( jinja2.escape(label), takedown.strftime('%Z'), takedown.strftime('%A, %b %e'))) else: return ''
def now(self, session, when=None): if when: now = c.EVENT_TIMEZONE.localize( datetime(*map(int, when.split(',')))) else: now = c.EVENT_TIMEZONE.localize( datetime.combine(localized_now().date(), time(localized_now().hour))) current, upcoming = [], [] for loc, desc in c.EVENT_LOCATION_OPTS: approx = session.query(Event).filter( Event.location == loc, Event.start_time >= now - timedelta(hours=6), Event.start_time <= now).all() for event in approx: if now in event.half_hours: current.append(event) next_events = session.query(Event).filter( Event.location == loc, Event.start_time >= now + timedelta(minutes=30), Event.start_time <= now + timedelta(hours=4)).order_by('start_time').all() if next_events: upcoming.extend( event for event in next_events if event.start_time == next_events[0].start_time) return { 'now': now if when else localized_now(), 'current': current, 'upcoming': upcoming }
def now(self, session, when=None): if when: now = c.EVENT_TIMEZONE.localize(datetime(*map(int, when.split(',')))) else: now = c.EVENT_TIMEZONE.localize(datetime.combine(localized_now().date(), time(localized_now().hour))) current, upcoming = [], [] for loc, desc in c.EVENT_LOCATION_OPTS: approx = session.query(Event).filter(Event.location == loc, Event.start_time >= now - timedelta(hours=6), Event.start_time <= now).all() for event in approx: if now in event.half_hours: current.append(event) next_events = session.query(Event).filter( Event.location == loc, Event.start_time >= now + timedelta(minutes=30), Event.start_time <= now + timedelta(hours=4)).order_by('start_time').all() if next_events: upcoming.extend(event for event in next_events if event.start_time == next_events[0].start_time) return { 'now': now if when else localized_now(), 'current': current, 'upcoming': upcoming }
def form(self, session, message='', return_to='', omit_badge='', check_in='', **params): attendee = session.attendee( params, checkgroups=Attendee.all_checkgroups, bools=Attendee.all_bools, allow_invalid=True) if 'first_name' in params: attendee.group_id = params['group_opt'] or None if (c.AT_THE_CON and omit_badge) or not attendee.badge_num: attendee.badge_num = None if 'no_override' in params: attendee.overridden_price = None message = '' if c.BADGE_PROMO_CODES_ENABLED and 'promo_code' in params: message = session.add_promo_code_to_attendee( attendee, params.get('promo_code')) if not message: message = check(attendee) if not message: # Free group badges are only considered 'registered' when they are actually claimed. if attendee.paid == c.PAID_BY_GROUP and attendee.group_id and attendee.group.cost == 0: attendee.registered = localized_now() if check_in: attendee.checked_in = localized_now() session.add(attendee) if attendee.is_new and \ session.attendees_with_badges().filter_by(first_name=attendee.first_name, last_name=attendee.last_name, email=attendee.email).count(): raise HTTPRedirect('duplicate?id={}&return_to={}', attendee.id, return_to or 'index') msg_text = '{} has been saved'.format(attendee.full_name) if params.get('save') == 'save_return_to_search': if return_to: raise HTTPRedirect(return_to + '&message={}', 'Attendee data saved') else: raise HTTPRedirect( 'index?uploaded_id={}&message={}&search_text={}', attendee.id, msg_text, '{} {}'.format(attendee.first_name, attendee.last_name) if c.AT_THE_CON else '') else: raise HTTPRedirect('form?id={}&message={}&return_to={}', attendee.id, msg_text, return_to) return { 'message': message, 'attendee': attendee, 'check_in': check_in, 'return_to': return_to, 'omit_badge': omit_badge, 'admin_can_change_status': session.admin_attendee().is_dept_head_of(c.DEFAULT_REGDESK_INT), 'group_opts': [(g.id, g.name) for g in session.query(Group).order_by(Group.name).all()], 'unassigned': { group_id: unassigned for group_id, unassigned in session.query(Attendee.group_id, func.count('*')).filter( Attendee.group_id != None, Attendee.first_name == '').group_by(Attendee.group_id).all()} } # noqa: E711
def form(self, session, message='', return_to='', omit_badge='', check_in='', **params): attendee = session.attendee( params, checkgroups=Attendee.all_checkgroups, bools=Attendee.all_bools, allow_invalid=True) if 'first_name' in params: attendee.group_id = params['group_opt'] or None if (c.AT_THE_CON and omit_badge) or not attendee.badge_num: attendee.badge_num = None if 'no_override' in params: attendee.overridden_price = None message = '' if c.BADGE_PROMO_CODES_ENABLED and 'promo_code' in params: message = session.add_promo_code_to_attendee(attendee, params.get('promo_code')) if not message: message = check(attendee) if not message: # Free group badges are only considered 'registered' when they are actually claimed. if attendee.paid == c.PAID_BY_GROUP and attendee.group_id and attendee.group.cost == 0: attendee.registered = localized_now() if check_in: attendee.checked_in = localized_now() session.add(attendee) if attendee.is_new and \ session.attendees_with_badges().filter_by(first_name=attendee.first_name, last_name=attendee.last_name, email=attendee.email).count(): raise HTTPRedirect('duplicate?id={}&return_to={}', attendee.id, return_to or 'index') msg_text = '{} has been saved'.format(attendee.full_name) if params.get('save') == 'save_return_to_search': if return_to: raise HTTPRedirect(return_to + '&message={}', 'Attendee data saved') else: raise HTTPRedirect( 'index?uploaded_id={}&message={}&search_text={}', attendee.id, msg_text, '{} {}'.format(attendee.first_name, attendee.last_name) if c.AT_THE_CON else '') else: raise HTTPRedirect('form?id={}&message={}&return_to={}', attendee.id, msg_text, return_to) return { 'message': message, 'attendee': attendee, 'check_in': check_in, 'return_to': return_to, 'omit_badge': omit_badge, 'admin_can_change_status': session.admin_attendee().is_dept_head_of(c.DEFAULT_REGDESK_INT), 'group_opts': [(g.id, g.name) for g in session.query(Group).order_by(Group.name).all()], 'unassigned': { group_id: unassigned for group_id, unassigned in session.query(Attendee.group_id, func.count('*')).filter( Attendee.group_id != None, Attendee.first_name == '').group_by(Attendee.group_id).all()} } # noqa: E711
def should_send_reminder(self): stagger = timedelta(minutes=c.TABLETOP_SMS_STAGGER_MINUTES) reminder = timedelta(minutes=c.TABLETOP_SMS_REMINDER_MINUTES) return not self.confirmed \ and not self.reminder \ and localized_now() < self.tournament.event.start_time \ and localized_now() > self.signed_up + stagger \ and localized_now() > self.tournament.event.start_time - reminder
def test_dealer_reg_open(self, monkeypatch): monkeypatch.setattr(c, 'DEALER_REG_START', localized_now() - timedelta(days=1)) monkeypatch.setattr(c, 'DEALER_REG_SHUTDOWN', localized_now() + timedelta(days=1)) monkeypatch.setattr(uber.config.Config, 'DEALER_REG_SOFT_CLOSED', property(lambda s: False)) assert c.DEALER_REG_OPEN
def test_at_door_badge_opts_presold_one_days(self, monkeypatch): monkeypatch.setattr(c, 'PRESELL_ONE_DAYS', True) monday_after_now = localized_now() + timedelta( days=(7 - localized_now().weekday())) monkeypatch.setattr(c, 'EPOCH', monday_after_now + timedelta(days=4)) monkeypatch.setattr(c, 'ESCHATON', monday_after_now + timedelta(days=6)) assert dict(c.AT_THE_DOOR_BADGE_OPTS).keys() == { c.ATTENDEE_BADGE, c.FRIDAY, c.SATURDAY, c.SUNDAY }
def reprint_fee(self, session, attendee_id=None, message='', fee_amount=0, reprint_reason='', refund=''): attendee = session.attendee(attendee_id) fee_amount = int(fee_amount) if not fee_amount and not reprint_reason: message = "You must charge a fee " \ "or enter a reason for a free reprint!" if not fee_amount and refund: message = "You can't refund a fee of $0!" if not message: if not fee_amount: attendee.for_review += \ "Automated message: " \ "Badge marked for free reprint by {} on {}. Reason: {}"\ .format(session.admin_attendee().full_name, localized_now().strftime('%m/%d, %H:%M'), reprint_reason) message = 'Free reprint recorded and badge sent to printer.' attendee.print_pending = True elif refund: attendee.paid = c.REFUNDED attendee.amount_refunded += fee_amount attendee.for_review += \ "Automated message: " \ "Reprint fee of ${} refunded by {} on {}. Reason: {}"\ .format(fee_amount, session.admin_attendee().full_name, localized_now().strftime('%m/%d, %H:%M'), reprint_reason) message = 'Reprint fee of ${} refunded.'.format(fee_amount) else: attendee.amount_paid += fee_amount attendee.for_review += \ "Automated message: " \ "Reprint fee of ${} charged by {} on {}. Reason: {}"\ .format(fee_amount, session.admin_attendee().full_name, localized_now().strftime('%m/%d, %H:%M'), reprint_reason) message = 'Reprint fee of ${} charged. Badge sent to printer.'\ .format(fee_amount) attendee.print_pending = True raise HTTPRedirect('../registration/form?id={}&message={}', attendee_id, message)
def checklist_items_due_soon_grouped(self): two_days = [] one_day = [] overdue = [] for key, val in c.MIVS_CHECKLIST.items(): if localized_now() >= self.checklist_deadline(key): overdue.append([val['name'], "mivs_" + key]) elif (localized_now() - timedelta(days=1)) >= self.checklist_deadline(key): one_day.append([val['name'], "mivs_" + key]) elif (localized_now() - timedelta(days=2)) >= self.checklist_deadline(key): two_days.append([val['name'], "mivs_" + key]) return two_days, one_day, overdue
def reg_take_report(self, session, **params): if params: start = c.EVENT_TIMEZONE.localize( datetime.strptime( '{startday} {starthour}:{startminute}'.format(**params), '%Y-%m-%d %H:%M')) end = c.EVENT_TIMEZONE.localize( datetime.strptime( '{endday} {endhour}:{endminute}'.format(**params), '%Y-%m-%d %H:%M')) sales = session.query(Sale).filter( Sale.reg_station == params['reg_station'], Sale.when > start, Sale.when <= end).all() attendees = session.query(Attendee).filter( Attendee.reg_station == params['reg_station'], Attendee.amount_paid > 0, Attendee.registered > start, Attendee.registered <= end).all() params['sales'] = sales params['attendees'] = attendees params['total_cash'] = \ sum((a.amount_paid / 100) for a in attendees if a.payment_method == c.CASH) \ + sum(s.cash for s in sales if s.payment_method == c.CASH) params['total_credit'] = \ sum((a.amount_paid / 100) for a in attendees if a.payment_method in [c.STRIPE, c.SQUARE, c.MANUAL]) \ + sum(s.cash for s in sales if s.payment_method == c.CREDIT) else: params['endday'] = localized_now().strftime('%Y-%m-%d') params['endhour'] = localized_now().strftime('%H') params['endminute'] = localized_now().strftime('%M') # list all reg stations associated with attendees and sales stations_attendees = session.query(Attendee.reg_station).filter( Attendee.reg_station != None, Attendee.reg_station > 0) # noqa: E711 stations_sales = session.query(Sale.reg_station).filter( Sale.reg_station != None, Sale.reg_station > 0) # noqa: E711 stations = [ r for (r, ) in stations_attendees.union( stations_sales).distinct().order_by(Attendee.reg_station) ] params['reg_stations'] = stations params.setdefault('reg_station', stations[0] if stations else 0) return params
def price_notice(label, takedown, amount_extra=0, discount=0): if c.HARDCORE_OPTIMIZATIONS_ENABLED: # CPU optimizaiton: the calculations done in this function are somewhat expensive and even with caching, # still do some expensive DB queries. if hardcore optimizations mode is enabled, we display a # simpler message. This is intended to be enabled during the heaviest loads at the beginning of an event # in order to reduce server load so the system stays up. After the rush, it should be safe to turn this # back off return '' if not takedown: takedown = c.ESCHATON prereg_pages = [ '/preregistration/form', '/preregistration/post_form', '/preregistration/register_group_member' ] if c.PAGE_PATH not in prereg_pages: return '' # we only display notices for new attendees else: badge_price = c.BADGE_PRICE # optimization. this call is VERY EXPENSIVE. on_or_by = "no later than" if c.PRICE_LIMITS else "on" for day, price in sorted(c.PRICE_BUMPS.items()): if day < takedown and localized_now( ) < day and price > badge_price: new_price = price - int(discount) + int(amount_extra) new_price_date = day - timedelta(days=1) return safe_string( '<div class="prereg-price-notice">Price goes up to ${} {} 11:59pm {} on {}</div>' .format(new_price, on_or_by, new_price_date.strftime('%Z'), new_price_date.strftime('%A, %b %e'))) elif localized_now( ) < day and takedown == c.PREREG_TAKEDOWN and takedown < c.EPOCH and price > badge_price: new_price = price + amount_extra return safe_string(( '<div class="prereg-type-closing">' '{} closes at 11:59pm {} on {}. Price goes up to ${} at-door.' '</div>').format(label, takedown.strftime('%Z'), takedown.strftime('%A, %b %e'), new_price)) if takedown < c.EPOCH: return safe_string( '<div class="prereg-type-closing">{} closes at 11:59pm {} on {}</div>' .format(jinja2.escape(label), takedown.strftime('%Z'), takedown.strftime('%A, %b %e'))) else: return ''
def check_in(self, session, message='', group_id='', **params): bools = ['got_merch'] if c.MERCH_AT_CHECKIN else [] attendee = session.attendee(params, allow_invalid=True, bools=bools) group = attendee.group or (session.group(group_id) if group_id else None) pre_badge = attendee.badge_num success, increment = False, False message = pre_checkin_check(attendee, group) if not message and group_id: message = session.match_to_group(attendee, group) if not message and attendee.paid == c.PAID_BY_GROUP and not attendee.group_id: message = 'You must select a group for this attendee.' if not message: message = '' success = True attendee.checked_in = localized_now() session.commit() increment = True message += '{} checked in as {}{}'.format(attendee.full_name, attendee.badge, attendee.accoutrements) return { 'success': success, 'message': message, 'increment': increment, 'badge': attendee.badge, 'paid': attendee.paid_label, 'age_group': attendee.age_group_conf['desc'], 'pre_badge': pre_badge, 'checked_in': attendee.checked_in and hour_day_format(attendee.checked_in) }
def check_duplicate_registrations(): """ This function looks through registered attendees for attendees with the same names and email addresses. It first deletes any unpaid duplicates, then sets paid duplicates from "Completed" to "New" and sends an email to the registration email address. This allows us to see new duplicate attendees without repetitive emails. """ if c.PRE_CON and (c.DEV_BOX or c.SEND_EMAILS): subject = c.EVENT_NAME + ' Duplicates Report for ' + localized_now().strftime('%Y-%m-%d') with Session() as session: if session.no_email(subject): grouped = defaultdict(list) for a in session.query(Attendee).filter(Attendee.first_name != '') \ .filter(Attendee.badge_status == c.COMPLETED_STATUS).options(joinedload(Attendee.group)) \ .order_by(Attendee.registered): if not a.group or a.group.status not in [c.WAITLISTED, c.UNAPPROVED]: grouped[a.full_name, a.email.lower()].append(a) dupes = {k: v for k, v in grouped.items() if len(v) > 1} for who, attendees in dupes.items(): paid = [a for a in attendees if a.paid == c.HAS_PAID] unpaid = [a for a in attendees if a.paid == c.NOT_PAID] if len(paid) == 1 and len(attendees) == 1 + len(unpaid): for a in unpaid: session.delete(a) del dupes[who] for a in paid: a.badge_status = c.NEW_STATUS if dupes: body = render('emails/daily_checks/duplicates.html', {'dupes': sorted(dupes.items())}) send_email(c.ADMIN_EMAIL, c.REGDESK_EMAIL, subject, body, format='html', model='n/a')
def schedule_tsv(self, session): cherrypy.response.headers['Content-Type'] = 'text/tsv' cherrypy.response.headers[ 'Content-Disposition'] = 'attachment;filename=Schedule-{}.tsv'.format( int(localized_now().timestamp())) schedule = defaultdict(list) for event in session.query(Event).order_by('start_time').all(): schedule[event.location_label].append( dict( event.to_dict(), **{ 'date': event.start_time_local.strftime('%m/%d/%Y'), 'start_time': event.start_time_local.strftime('%I:%M:%S %p'), 'end_time': (event.start_time_local + timedelta( minutes=event.minutes)).strftime('%I:%M:%S %p'), 'description': normalize_newlines(event.description).replace( '\n', ' ') })) return render( 'schedule/schedule.tsv', { 'schedule': sorted(schedule.items(), key=lambda tup: c.ORDERED_EVENT_LOCS.index(tup[1][0][ 'location'])) })
def check_pending_badges(): if c.PRE_CON and (c.DEV_BOX or c.SEND_EMAILS): emails = [[ 'Staff', c.STAFF_EMAIL, Attendee.badge_type == c.STAFF_BADGE, 'staffing_admin' ], [ 'Attendee', c.REGDESK_EMAIL, Attendee.badge_type != c.STAFF_BADGE, 'registration' ]] subject = c.EVENT_NAME + ' Pending {} Badge Report for ' + localized_now( ).strftime('%Y-%m-%d') with Session() as session: for badge_type, to, per_email_filter, site_section in emails: pending = session.query(Attendee).filter_by( badge_status=c.PENDING_STATUS).filter( per_email_filter).all() if pending and session.no_email(subject.format(badge_type)): body = render('emails/daily_checks/pending.html', { 'pending': pending, 'site_section': site_section }) send_email(c.ADMIN_EMAIL, to, subject.format(badge_type), body, format='html', model='n/a')
def test_dealer_reg_not_soft_closed_optimizations(self, monkeypatch): monkeypatch.setattr(c, 'DEALER_REG_DEADLINE', localized_now() + timedelta(days=1)) monkeypatch.setattr(uber.config.Config, 'DEALER_APPS', 10) monkeypatch.setattr(c, 'MAX_DEALER_APPS', 1) monkeypatch.setattr(c, 'HARDCORE_OPTIMIZATIONS_ENABLED', True) assert not c.DEALER_REG_SOFT_CLOSED
def check_in(self, session, message='', group_id='', **params): attendee = session.attendee(params, allow_invalid=True) group = attendee.group or (session.group(group_id) if group_id else None) pre_badge = attendee.badge_num success, increment = False, False message = pre_checkin_check(attendee, group) if not message and group_id: message = session.match_to_group(attendee, group) if not message and attendee.paid == c.PAID_BY_GROUP and not attendee.group_id: message = 'You must select a group for this attendee.' if not message: message = '' success = True attendee.checked_in = localized_now() session.commit() increment = True message += '{} checked in as {}{}'.format(attendee.full_name, attendee.badge, attendee.accoutrements) return { 'success': success, 'message': message, 'increment': increment, 'badge': attendee.badge, 'paid': attendee.paid_label, 'age_group': attendee.age_group_conf['desc'], 'pre_badge': pre_badge, 'checked_in': attendee.checked_in and hour_day_format(attendee.checked_in) }
def notify_admins_of_pending_emails(): """ Generate and email a report which alerts admins that there are automated emails which are ready to send, but can't be sent until they are approved by an admin. This is important so we don't forget to let certain automated emails send. """ if not c.ENABLE_PENDING_EMAILS_REPORT or not c.PRE_CON or not (c.DEV_BOX or c.SEND_EMAILS): return None with Session() as session: pending_emails = session.query(AutomatedEmail).filter(*AutomatedEmail.filters_for_pending).all() pending_emails_by_sender = groupify(pending_emails, ['sender', 'ident']) for sender, emails_by_ident in pending_emails_by_sender.items(): if sender == c.STAFF_EMAIL: # STOPS receives a report on ALL the pending emails. emails_by_sender = pending_emails_by_sender else: emails_by_sender = {sender: emails_by_ident} subject = '{} Pending Emails Report for {}'.format(c.EVENT_NAME, utils.localized_now().strftime('%Y-%m-%d')) body = render('emails/daily_checks/pending_emails.html', { 'pending_emails_by_sender': emails_by_sender, 'primary_sender': sender, }) send_email(c.STAFF_EMAIL, sender, subject, body, format='html', model='n/a', session=session) return groupify(pending_emails, 'sender', 'ident')
def printed_badge_change(attendee): if attendee.badge_printed_name != attendee.orig_value_of('badge_printed_name') \ and not AdminAccount.admin_name() \ and localized_now() > c.get_printed_badge_deadline_by_type(attendee.badge_type_real): return '{} badges have already been ordered, so you cannot change the badge printed name.'.format( attendee.badge_type_label if attendee.badge_type in c.PREASSIGNED_BADGE_TYPES else "Supporter")
def pre_print_check(session, attendee, printer_id, dry_run=False, **params): fee_amount = params.get('fee_amount', 0) reprint_reason = params.get('reprint_reason') try: fee_amount = int(fee_amount) except Exception: return False, "What you entered for Reprint Fee ({}) isn't even a number".format( fee_amount) if not fee_amount and not reprint_reason and c.BADGE_REPRINT_FEE and attendee.times_printed > 0: return False, "You must set a fee or enter a reason for a free reprint!" print_id, errors = session.add_to_print_queue( attendee, printer_id, params.get('reg_station', cherrypy.session.get('reg_station')), fee_amount, dry_run) if errors: return False, "<br>".join(errors) if not fee_amount: if c.BADGE_REPRINT_FEE and attendee.times_printed > 0: attendee.for_review += \ "Automated message: " \ "Badge marked for free reprint by {} on {}.{}"\ .format(session.admin_attendee().full_name, localized_now().strftime('%m/%d, %H:%M'), " Reason: " + reprint_reason if reprint_reason else '') return True, '{}adge sent to printer.'.format( "B" if not c.BADGE_REPRINT_FEE or attendee.times_printed == 0 else "Free reprint recorded and b") else: return True, 'Badge sent to printer with reprint fee of ${}.'.format( fee_amount) return True, 'Badge sent to printer.'
def test_assign_extra_create_arguments(session): group = Group() registered = localized_now() session.assign_badges(group, 2, registered=registered) assert 2 == group.badges == len(group.attendees) for attendee in group.attendees: assert attendee.registered == registered
def waiver(self, session, message='', **params): if params.get('id'): session.log_in_as_mits_team(params['id'], redirect_to='waiver') else: team = session.logged_in_mits_team() if cherrypy.request.method == 'POST': if not params['waiver_signature']: message = "Please enter your full name to sign the waiver." else: for applicant in team.applicants: if getattr( applicant.attendee, 'full_name', applicant.full_name) == params['waiver_signature']: team.waiver_signature = params['waiver_signature'] team.waiver_signed = localized_now() break else: message = "The name you entered did not match any of this team's members." if not message: raise HTTPRedirect('index?message={}', 'Thank you for signing the waiver!') return { 'team': team, 'message': message, }
def test_match_to_group(match_to_group_preconditions): with Session() as session: console = session.query(Department).filter_by(name='Console_01').one() late_comer = Attendee( first_name='Late', last_name='Comer', email='*****@*****.**', zip_code='21211', ec_name='Nana Fearless', ec_phone='555-555-1234', cellphone='555-555-2345', birthdate=date(1964, 12, 30), registered=localized_now(), paid=c.NEED_NOT_PAY, badge_type=c.STAFF_BADGE, badge_num=99, badge_printed_name='Lateness', ribbon='', staffing=True, assigned_depts=[console]) group = session.query(Group).get(match_to_group_preconditions) assert [6, 7, 8, 9] == sorted([a.badge_num for a in group.attendees]) session.match_to_group(late_comer, group) assert [6, 7, 8, 99] == sorted([a.badge_num for a in group.attendees])
def waiver(self, session, message='', **params): if params.get('id'): session.log_in_as_mits_team(params['id'], redirect_to='waiver') else: team = session.logged_in_mits_team() if cherrypy.request.method == 'POST': if not params['waiver_signature']: message = "Please enter your full name to sign the waiver." else: for applicant in team.applicants: if getattr(applicant.attendee, 'full_name', applicant.full_name) == params['waiver_signature']: team.waiver_signature = params['waiver_signature'] team.waiver_signed = localized_now() break else: message = "The name you entered did not match any of this team's members." if not message: raise HTTPRedirect('index?message={}', 'Thank you for signing the waiver!') return { 'team': team, 'message': message, }
def check_if_preregistered(self, session, message='', **params): if 'email' in params: attendee = session.query(Attendee).filter( func.lower(Attendee.email) == func.lower( params['email'])).first() message = 'Thank you! You will receive a confirmation email if ' \ 'you are registered for {}.'.format(c.EVENT_NAME_AND_YEAR) subject = c.EVENT_NAME_AND_YEAR + ' Registration Confirmation' if attendee: last_email = (session.query(Email).filter_by( to=attendee.email, subject=subject).order_by(Email.when.desc()).first()) if not last_email or last_email.when < (localized_now() - timedelta(days=7)): send_email.delay( c.REGDESK_EMAIL, attendee.email, subject, render('emails/reg_workflow/prereg_check.txt', {'attendee': attendee}, encoding=None), model=attendee.to_dict('id')) return {'message': message}
def register_group_member(self, session, group_id, message='', **params): # Safe to ignore csrf tokens here, because an attacker would need to know the group id a priori group = session.group(group_id, ignore_csrf=True) attendee = session.attendee(params, restricted=True, ignore_csrf=True) must_be_staffing = False if group.unassigned[0].staffing: must_be_staffing = True attendee.staffing = True params['staffing'] = True message = check_pii_consent(params, attendee) or message if not message and 'first_name' in params: message = check(attendee, prereg=True) if not message and not params['first_name']: message = 'First and Last Name are required fields' if not message: if not group.unassigned: raise HTTPRedirect( 'register_group_member?group_id={}&message={}', group_id, 'No more unassigned badges exist in this group') attrs_to_preserve_from_unassigned_group_member = [ 'id', 'group_id', 'badge_type', 'badge_num', 'base_badge_price', 'ribbon', 'paid', 'overridden_price', 'requested_hotel_info'] attendee = group.unassigned[0] for attr in attrs_to_preserve_from_unassigned_group_member: if attr in params: del params[attr] attendee.apply(params, restricted=True) # Free group badges are considered registered' when they are actually claimed. if group.cost == 0: attendee.registered = localized_now() if attendee.amount_unpaid: raise HTTPRedirect('attendee_donation_form?id={}', attendee.id) else: raise HTTPRedirect('badge_updated?id={}&message={}', attendee.id, 'Badge registered successfully') return { 'message': message, 'group_id': group_id, 'group': group, 'attendee': attendee, 'affiliates': session.affiliates(), 'badge_cost': 0, 'must_be_staffing': must_be_staffing, }
def test_localized_now(fixed_localized_now): """ Asserts that our localized_now monkeypatch is working as expected. """ assert fixed_localized_now == utils.localized_now() assert not before(fixed_localized_now)() assert before(fixed_localized_now + timedelta(microseconds=1))() assert not before(fixed_localized_now - timedelta(microseconds=1))()
def returned(self, session, game_id): try: session.tabletop_game( game_id).checked_out.returned = localized_now() session.commit() except Exception: pass return {'message': 'Success!', 'games': _games(session)}
def test_hotel_shifts_required(monkeypatch): monkeypatch.setattr(c, 'SHIFTS_CREATED', localized_now()) assert not Attendee().hotel_shifts_required monkeypatch.setattr(Attendee, 'takes_shifts', True) monkeypatch.setattr(Attendee, 'hotel_nights', [c.THURSDAY, c.FRIDAY]) assert Attendee().hotel_shifts_required monkeypatch.setattr(Attendee, 'is_dept_head', True) assert not Attendee().hotel_shifts_required
def onsite_jobs(self, session, message=''): attendee = session.logged_in_volunteer() return { 'message': message, 'attendee': attendee, 'jobs': [job for job in attendee.possible_and_current if getattr(job, 'taken', False) or job.start_time > localized_now()] }
def lost_badge(self, session, id): a = session.attendee(id, allow_invalid=True) a.for_review += "Automated message: Badge reported lost on {}. Previous payment type: {}.".format( localized_now().strftime('%m/%d, %H:%M'), a.paid_label) a.paid = c.LOST_BADGE session.add(a) session.commit() raise HTTPRedirect('index?message={}', 'Badge has been recorded as lost.')
def confirm(self, session, message='', return_to='confirm', undoing_extra='', **params): attendee = session.attendee(params, restricted=True) if attendee.badge_status == c.REFUNDED_STATUS: raise HTTPRedirect('repurchase?id={}', attendee.id) placeholder = attendee.placeholder if 'email' in params and not message: attendee.placeholder = False message = check(attendee, prereg=True) if not message: if placeholder: attendee.confirmed = localized_now() message = 'Your registration has been confirmed' else: message = 'Your information has been updated' page = ('badge_updated?id=' + attendee.id + '&') if return_to == 'confirm' else (return_to + '?') if attendee.amount_unpaid: raise HTTPRedirect('attendee_donation_form?id={}', attendee.id) else: raise HTTPRedirect(page + 'message=' + message) elif attendee.amount_unpaid and attendee.zip_code and not undoing_extra: # Don't skip to payment until the form is filled out raise HTTPRedirect('attendee_donation_form?id={}&message={}', attendee.id, message) attendee.placeholder = placeholder if not message and attendee.placeholder: attendee.can_spam = True message = 'You are not yet registered! You must fill out this form to complete your registration.' elif not message: message = 'You are already registered but you may update your information with this form.' return { 'undoing_extra': undoing_extra, 'return_to': return_to, 'attendee': attendee, 'message': message, 'affiliates': session.affiliates(), 'badge_cost': attendee.badge_cost if attendee.paid != c.PAID_BY_GROUP else 0, }
def returned(self, session, game_id): try: session.tabletop_game(game_id).checked_out.returned = localized_now() session.commit() except Exception: pass return { 'message': 'Success!', 'games': _games(session) }
def check_unassigned_volunteers(): if c.PRE_CON and (c.DEV_BOX or c.SEND_EMAILS): with Session() as session: unassigned = session.query(Attendee).filter( Attendee.staffing == True, not_(Attendee.dept_memberships.any())).order_by(Attendee.full_name).all() # noqa: E712 subject = c.EVENT_NAME + ' Unassigned Volunteer Report for ' + localized_now().strftime('%Y-%m-%d') if unassigned and session.no_email(subject): body = render('emails/daily_checks/unassigned.html', {'unassigned': unassigned}) send_email(c.STAFF_EMAIL, c.STAFF_EMAIL, subject, body, format='html', model='n/a')
def past_checklist_deadline(self, slug): """ Args: slug: A standardized name, which should match the checklist's section name in config. E.g., the properties above ending in _status Returns: A timedelta object representing how far from the deadline this team is for a particular checklist item """ return localized_now() - self.checklist_deadline(slug)
def register_group_member(self, session, group_id, message='', **params): # Safe to ignore csrf tokens here, because an attacker would need to know the group id a priori group = session.group(group_id, ignore_csrf=True) attendee = session.attendee(params, restricted=True, ignore_csrf=True) message = check_pii_consent(params, attendee) or message if not message and 'first_name' in params: message = check(attendee, prereg=True) if not message and not params['first_name']: message = 'First and Last Name are required fields' if not message: if not group.unassigned: raise HTTPRedirect( 'register_group_member?group_id={}&message={}', group_id, 'No more unassigned badges exist in this group') attrs_to_preserve_from_unassigned_group_member = [ 'id', 'group_id', 'badge_type', 'badge_num', 'base_badge_price', 'ribbon', 'paid', 'overridden_price', 'requested_hotel_info'] attendee = group.unassigned[0] for attr in attrs_to_preserve_from_unassigned_group_member: if attr in params: del params[attr] attendee.apply(params, restricted=True) # Free group badges are considered registered' when they are actually claimed. if group.cost == 0: attendee.registered = localized_now() if attendee.amount_unpaid: raise HTTPRedirect('attendee_donation_form?id={}', attendee.id) else: raise HTTPRedirect('badge_updated?id={}&message={}', attendee.id, 'Badge registered successfully') return { 'message': message, 'group_id': group_id, 'group': group, 'attendee': attendee, 'affiliates': session.affiliates(), 'badge_cost': 0 }
def shifts(self, session, id, shift_id='', message=''): attendee = session.attendee(id, allow_invalid=True) attrs = Shift.to_dict_default_attrs + ['worked_label'] return { 'message': message, 'shift_id': shift_id, 'attendee': attendee, 'shifts': {s.id: s.to_dict(attrs) for s in attendee.shifts}, 'jobs': [ (job.id, '({}) [{}] {}'.format(job.timespan(), job.department_name, job.name)) for job in attendee.available_jobs if job.start_time + timedelta(hours=job.duration + 2) > localized_now()] }
def reg_take_report(self, session, **params): if params: start = c.EVENT_TIMEZONE.localize( datetime.strptime('{startday} {starthour}:{startminute}'.format(**params), '%Y-%m-%d %H:%M')) end = c.EVENT_TIMEZONE.localize( datetime.strptime('{endday} {endhour}:{endminute}'.format(**params), '%Y-%m-%d %H:%M')) sales = session.query(Sale).filter( Sale.reg_station == params['reg_station'], Sale.when > start, Sale.when <= end).all() attendees = session.query(Attendee).filter( Attendee.reg_station == params['reg_station'], Attendee.amount_paid > 0, Attendee.registered > start, Attendee.registered <= end).all() params['sales'] = sales params['attendees'] = attendees params['total_cash'] = \ sum(a.amount_paid for a in attendees if a.payment_method == c.CASH) \ + sum(s.cash for s in sales if s.payment_method == c.CASH) params['total_credit'] = \ sum(a.amount_paid for a in attendees if a.payment_method in [c.STRIPE, c.SQUARE, c.MANUAL]) \ + sum(s.cash for s in sales if s.payment_method == c.CREDIT) else: params['endday'] = localized_now().strftime('%Y-%m-%d') params['endhour'] = localized_now().strftime('%H') params['endminute'] = localized_now().strftime('%M') # list all reg stations associated with attendees and sales stations_attendees = session.query(Attendee.reg_station).filter( Attendee.reg_station != None, Attendee.reg_station > 0) # noqa: E711 stations_sales = session.query(Sale.reg_station).filter( Sale.reg_station != None, Sale.reg_station > 0) # noqa: E711 stations = [r for (r,) in stations_attendees.union(stations_sales).distinct().order_by(Attendee.reg_station)] params['reg_stations'] = stations params.setdefault('reg_station', stations[0] if stations else 0) return params
def update_promo_code(self, session, message='', **params): if 'id' in params: promo_code = session.promo_code(params) message = check(promo_code) if message: session.rollback() else: if 'expire' in params: promo_code.expiration_date = localized_now() - timedelta(days=1) message = 'Promo code updated' session.commit() raise HTTPRedirect('view_promo_codes?message={}', message)
def checklist_completion(self, out, session): header_row = ['Studio'] for key, val in c.MIVS_CHECKLIST.items(): header_row.append(val['name']) header_row.append('Past Due?') out.writerow(header_row) for studio in session.query(IndieStudio).join(IndieStudio.group).join(Group.guest): row = [studio.name] for key, val in c.MIVS_CHECKLIST.items(): row.extend([ 'Not Completed' if getattr(studio, key + "_status", None) is None else getattr(studio, key + "_status"), 'No' if localized_now() <= studio.checklist_deadline(key) else humanize_timedelta(studio.past_checklist_deadline(key), granularity='hours'), ]) out.writerow(row)
def schedule_tsv(self, session): cherrypy.response.headers['Content-Type'] = 'text/tsv' cherrypy.response.headers['Content-Disposition'] = 'attachment;filename=Schedule-{}.tsv'.format( int(localized_now().timestamp())) schedule = defaultdict(list) for event in session.query(Event).order_by('start_time').all(): schedule[event.location_label].append(dict(event.to_dict(), **{ 'date': event.start_time_local.strftime('%m/%d/%Y'), 'start_time': event.start_time_local.strftime('%I:%M:%S %p'), 'end_time': (event.start_time_local + timedelta(minutes=event.minutes)).strftime('%I:%M:%S %p'), 'description': normalize_newlines(event.description).replace('\n', ' ') })) return render('schedule/schedule.tsv', { 'schedule': sorted(schedule.items(), key=lambda tup: c.ORDERED_EVENT_LOCS.index(tup[1][0]['location'])) })
def setup_cherrypy_fake_env(self, monkeypatch): monkeypatch.setattr(AdminAccount, 'admin_name', Mock(return_value='Bruce')) monkeypatch.setattr(cherrypy.request, 'request_line', "/uber/location3/hello") monkeypatch.setattr(cherrypy.request, 'params', { 'id': '32', 'action': 'reload', 'thing': 3, # use a non-string 'attachment': MockPart(), # add fake attachment based on cherrypy's Part() class, make sure we handle OK }) monkeypatch.setattr(cherrypy, 'session', {'session_id': '762876'}) headers = [ ('Content-Type', 'text/html'), ('Server', 'Null CherryPy'), ('Date', localized_now()), ('Content-Length', '80'), ] monkeypatch.setattr(cherrypy.request, 'header_list', headers)
def everywhere(self, session, message='', show_restricted='', show_nonpublic=''): job_filters = [Job.start_time > localized_now() - timedelta(hours=2)] if not show_restricted: job_filters.append(Job.restricted == False) # noqa: E712 if not show_nonpublic: job_filters.append(Job.department_id.in_( select([Department.id]).where( Department.solicits_volunteers == True))) # noqa: E712 jobs = session.jobs().filter(*job_filters) return { 'message': message, 'show_restricted': show_restricted, 'show_nonpublic': show_nonpublic, 'attendees': session.staffers_for_dropdown(), 'jobs': [job_dict(job) for job in jobs] }
def match_to_group_preconditions(): group_id = None # leader_id = None with Session() as session: console = Department(name='Console_01', description='Console_01') leader = Attendee( first_name='Fearless', last_name='Leader', email='*****@*****.**', zip_code='21211', ec_name='Nana Fearless', ec_phone='555-555-1234', cellphone='555-555-2345', birthdate=date(1964, 12, 30), registered=localized_now(), paid=c.PAID_BY_GROUP, badge_type=c.STAFF_BADGE, badge_printed_name='Fearmore', ribbon='', staffing=True, assigned_depts=[console]) group = Group(name='Too Many Badges!') group.auto_recalc = False group.attendees = [leader] group.leader = leader session.add(leader) session.add(group) assert session.assign_badges( group, 4, new_badge_type=c.STAFF_BADGE, new_ribbon_type='', paid=c.PAID_BY_GROUP) is None session.flush() group_id = group.id # leader_id = leader.id yield group_id with Session() as session: session.query(Group).filter(Group.id == group_id).delete( synchronize_session=False)
def confirm(self, session, message='', return_to='confirm', undoing_extra='', **params): # Safe to ignore csrf tokens here, because an attacker would need to know the attendee id a priori attendee = session.attendee(params, restricted=True, ignore_csrf=True) if attendee.badge_status == c.REFUNDED_STATUS: raise HTTPRedirect('repurchase?id={}', attendee.id) placeholder = attendee.placeholder if 'email' in params and not message: attendee.placeholder = False message = check(attendee, prereg=True) if not message: if placeholder: attendee.confirmed = localized_now() message = 'Your registration has been confirmed' else: message = 'Your information has been updated' page = ('badge_updated?id=' + attendee.id + '&') if return_to == 'confirm' else (return_to + '?') if attendee.amount_unpaid: raise HTTPRedirect('attendee_donation_form?id={}', attendee.id) else: raise HTTPRedirect(page + 'message=' + message) elif attendee.amount_unpaid and attendee.zip_code and not undoing_extra and cherrypy.request.method == 'POST': # Don't skip to payment until the form is filled out raise HTTPRedirect('attendee_donation_form?id={}&message={}', attendee.id, message) attendee.placeholder = placeholder if not message and attendee.placeholder: message = 'You are not yet registered! You must fill out this form to complete your registration.' elif not message: message = 'You are already registered but you may update your information with this form.' return { 'undoing_extra': undoing_extra, 'return_to': return_to, 'attendee': attendee, 'message': message, 'affiliates': session.affiliates(), 'attractions': session.query(Attraction).filter_by(is_public=True).all(), 'badge_cost': attendee.badge_cost if attendee.paid != c.PAID_BY_GROUP else 0, }
def check_if_applied(self, session, message='', **params): if cherrypy.request.method == 'POST': subject = c.EVENT_NAME_AND_YEAR + ' MITS Team Confirmation' if 'email' not in params: message = "Please enter an email address." if not message: last_email = (session.query(Email) .filter(Email.to.ilike(params['email'])) .filter_by(subject=subject) .order_by(Email.when.desc()).first()) if not last_email or last_email.when < ( localized_now() - timedelta(days=7)): can_send_email = True else: can_send_email = False mits_teams = session.query(MITSTeam).all() match_counter = 0 for team in mits_teams: if params['email'] in team.email: match_counter += 1 if can_send_email: send_email.delay( c.MITS_EMAIL, params['email'], subject, render('emails/mits/mits_check.txt', {'team': team}, encoding=None), cc=team.email, model=team.to_dict('id')) if match_counter: message = 'We found {} team{}.{}'\ .format(match_counter, 's' if match_counter > 1 else '', ' Please check your email for a link to your application.' if can_send_email else ' Please check your spam or junk folder.') return {'message': message}
def check_if_preregistered(self, session, message='', **params): if 'email' in params: attendee = session.query(Attendee).filter(func.lower(Attendee.email) == func.lower(params['email'])).first() message = 'Thank you! You will receive a confirmation email if ' \ 'you are registered for {}.'.format(c.EVENT_NAME_AND_YEAR) subject = c.EVENT_NAME_AND_YEAR + ' Registration Confirmation' if attendee: last_email = (session.query(Email) .filter_by(to=attendee.email, subject=subject) .order_by(Email.when.desc()).first()) if not last_email or last_email.when < (localized_now() - timedelta(days=7)): send_email.delay( c.REGDESK_EMAIL, attendee.email, subject, render('emails/reg_workflow/prereg_check.txt', {'attendee': attendee}, encoding=None), model=attendee.to_dict('id')) return {'message': message}
def new_checkin(self, session, message='', **params): attendee = session.attendee(params, allow_invalid=True) group = session.group(attendee.group_id) if attendee.group_id else None checked_in = '' if 'reg_station' not in cherrypy.session: raise HTTPRedirect('new_reg_station') message = pre_checkin_check(attendee, group) if message: session.rollback() else: if group: session.match_to_group(attendee, group) attendee.checked_in = localized_now() attendee.reg_station = cherrypy.session['reg_station'] message = '{a.full_name} checked in as {a.badge}{a.accoutrements}'.format(a=attendee) checked_in = attendee.id session.commit() raise HTTPRedirect('new?message={}&checked_in={}', message, checked_in)
def test_datetime_val(job): format = '%Y-%m-%d %H:%M:%S' assert job.start_time is None now = localized_now() job.apply({'start_time': now.strftime(format)}, restricted=False) assert job.start_time.strftime(format) == now.strftime(format)
def now_localized(): return localized_now()
def duplicate_badge_num_preconditions(): group_id = None leader_id = None with Session() as session: leader = Attendee( first_name='Fearless', last_name='Leader', email='*****@*****.**', zip_code='21211', ec_name='Nana Fearless', ec_phone='555-555-1234', cellphone='555-555-2345', birthdate=date(1964, 12, 30), registered=localized_now(), paid=c.PAID_BY_GROUP, ribbon='', staffing=True, badge_type=c.PSEUDO_GROUP_BADGE) group = Group(name='Too Many Badges!') group.attendees = [leader] group.leader = leader session.add(leader) session.add(group) assert session.assign_badges( group, 15, new_badge_type=c.STAFF_BADGE, new_ribbon_type='', paid=c.NEED_NOT_PAY) is None session.flush() group_id = group.id leader_id = leader.id with Session() as session: console = Department(name='DEPT_01', description='DEPT_01') leader = session.query(Attendee).get(leader_id) leader.paid = c.NEED_NOT_PAY leader.badge_printed_name = 'Fearmore' leader.badge_type = c.STAFF_BADGE leader.assigned_depts = [console] group = session.query(Group).get(group_id) group.auto_recalc = False for i in range(10): with Session() as session: console = session.query(Department).filter_by(name='DEPT_01').one() group = session.query(Group).get(group_id) is_staff = (i < 9) params = { 'first_name': 'Doubtful', 'last_name': 'Follower{}'.format(i), 'email': 'fearsome{}@example.com'.format(i), 'zip_code': '21211', 'ec_name': 'Nana Fearless', 'ec_phone': '555-555-1234', 'cellphone': '555-555-321{}'.format(i), 'birthdate': date(1964, 12, 30), 'registered': localized_now(), 'staffing': is_staff, 'badge_status': str(c.COMPLETED_STATUS), 'badge_printed_name': 'Fears{}'.format(i) if is_staff else '', 'assigned_depts': [console] if is_staff else ''} attendee = group.unassigned[0] attendee.apply(params, restricted=False) with Session() as session: group = session.query(Group).get(group_id) badge_nums = [a.badge_num for a in group.attendees] # SQLite doesn't support deferred constraints, so our test database # doesn't actually have a unique constraint on the badge_num # column. So we have to manually check for duplicate badge numbers. assert_unique(badge_nums) yield group_id with Session() as session: session.query(Group).filter(Group.id == group_id).delete( synchronize_session=False)
MIVSEmailFixture( IndieGame, 'Your MIVS application has been waitlisted', 'mivs/game_waitlisted.txt', lambda game: game.status == c.WAITLISTED, ident='mivs_game_waitlisted') MIVSEmailFixture( IndieGame, 'Last chance to accept your MIVS booth', 'mivs/game_accept_reminder.txt', lambda game: ( game.status == c.ACCEPTED and not game.confirmed and (localized_now() - timedelta(days=2)) > game.studio.confirm_deadline), ident='mivs_accept_booth_reminder') MIVSEmailFixture( IndieGame, 'MIVS December Updates: Hotels and Magfest Versus!', 'mivs/december_updates.txt', lambda game: game.confirmed, ident='mivs_december_updates') MIVSEmailFixture( IndieGame, 'REQUIRED: Pre-flight for MIVS due by midnight, January 2nd', 'mivs/game_preflight.txt', lambda game: game.confirmed, ident='mivs_game_preflight_reminder')