def event_date_processor(): def suffix(d): return ("th" if 11 <= d <= 13 else { 1: "st", 2: "nd", 3: "rd" }.get(d % 10, "th")) s = event_start() e = event_end() assert s.year == e.year if s.month == e.month: fancy_dates = f"""{s.strftime('%B')}<span style="white-space: nowrap"> {s.day}<sup>{suffix(s.day)}</sup>–{e.day}<sup>{suffix(e.day)}</sup> {s.year} </span>""" simple_dates = f"{s.day}–{e.day} {s.strftime('%B')}" else: fancy_dates = f"""{s.strftime("%B")} {s.day}<sup>{suffix(s.day)}</sup>–{e.strftime("%B")} {e.day}<sup>{suffix(e.day)}</sup>""" simple_dates = ( f"""{s.day} {s.strftime("%B")}–{e.day} {e.strftime("%B")}""" ) return { "fancy_dates": Markup(fancy_dates), "simple_dates": Markup(simple_dates), "event_start": s, "event_end": e, "event_year": s.year, }
def get_days_with_slots(cls, now=None): remaining_slots = cls.get_remaining_lightning_slots() now = datetime.now() if now is None else now # If we're before the event start we don't need to worry if now < event_start(): return remaining_slots # If the day has passed (or is today) there're no more slots for it for (day_name, date) in get_days_map().items(): if date.date() <= now.date(): remaining_slots[day_name] = 0 return remaining_slots
def generate_departure_options(): choices = [] # Work out our last arrival based on config last_departure = event_end() + timedelta(app.config["DEPARTURE_DAYS"]) # Work out dates between start of the event and last departure choices = generate_day_options(event_start(), last_departure) # Replace last array element with the last date and 'or later' choices[len(choices) - 1] = ( last_departure.strftime("%F"), last_departure.strftime("%A %-d %B or later"), ) return choices
def generate_arrival_options(): choices = [] # Work out our first arrival based on config first_arrival = event_start() - timedelta(app.config["ARRIVAL_DAYS"]) # Work out dates between first arrival and end of the event choices = generate_day_options(first_arrival, event_end()) # Replace first array element with first date and 'or earlier' choices[0] = ( first_arrival.strftime("%F"), first_arrival.strftime("%A %-d %B or earlier"), ) return choices
def make_root(): root = etree.Element("schedule") _add_sub_with_text(root, "version", "1.0-public") conference = etree.SubElement(root, "conference") _add_sub_with_text(conference, "title", "Electromagnetic Field {}".format(event_year())) _add_sub_with_text(conference, "acronym", "emf{}".format(event_year())) _add_sub_with_text(conference, "start", event_start().strftime("%Y-%m-%d")) _add_sub_with_text(conference, "end", event_end().strftime("%Y-%m-%d")) _add_sub_with_text(conference, "days", "3") _add_sub_with_text(conference, "timeslot_duration", "00:10") return root
def sign_up(): form = VolunteerSignUpForm() form.arrival.choices = generate_arrival_options() form.departure.choices = generate_departure_options() if current_user.is_authenticated and VolunteerUser.get_for_user( current_user): return redirect(url_for(".account")) if request.method != "POST" and current_user.is_authenticated: form.volunteer_email.data = current_user.email form.nickname.data = current_user.name form.volunteer_phone.data = current_user.phone # Can't try to process age, as that's only submitted as part of the outreach questions if form.validate_on_submit(): if current_user.is_anonymous: create_current_user(form.volunteer_email.data, form.nickname.data) new_volunteer = VolunteerUser() new_volunteer.user_id = current_user.id new_volunteer = update_volunteer_from_form(new_volunteer, form) db.session.add(new_volunteer) # On sign up give user 'volunteer' permission (+ managers etc.) current_user.grant_permission("volunteer:user") db.session.commit() app.logger.info("Add volunteer: %s", new_volunteer) flash("Thank you for signing up!", "message") return redirect(url_for(".choose_role")) # Set form default arrival and departure dates to be start and end form.arrival.data = event_start().strftime("%F") form.departure.data = event_end().strftime("%F") return render_template("volunteer/sign-up.html", user=current_user, form=form)
def refresh(self): request = requests.get(self.url) cal = Calendar.from_ical(request.text) if self.name is None: self.name = cal.get("X-WR-CALNAME") for event in self.events: event.displayed = False local_tz = pendulum.timezone("Europe/London") alerts = [] uids_seen = set() out_of_range_event = False for component in cal.walk(): if component.name == "VEVENT": summary = component.get("Summary") # postgres converts to UTC if given an aware datetime, so strip it up front start_dt = pendulum.instance(component.get("dtstart").dt) start_dt = local_tz.convert(start_dt).naive() end_dt = pendulum.instance(component.get("dtend").dt) end_dt = local_tz.convert(end_dt).naive() name = summary if summary and start_dt: name = "'{}' at {}".format(summary, start_dt) elif summary: name = "'{}'".format(summary) elif start_dt: name = "Event at {}".format(start_dt) else: name = len(self.events) + 1 if not component.get("uid"): alerts.append(("danger", "{} has no UID".format(name))) continue uid = str(component["uid"]) if uid in uids_seen: alerts.append( ("danger", "{} has duplicate UID {}".format(name, uid)) ) continue uids_seen.add(uid) if "rrule" in component: alerts.append( ("warning", "{} has rrule, which is not processed".format(uid)) ) # Allow a bit of slop for build-up events if ( start_dt < event_start() - pendulum.duration(days=2) and not out_of_range_event ): alerts.append( ( "warning", "At least one event ({}) is before the start of the event".format( uid ), ) ) out_of_range_event = True if ( end_dt > event_end() + pendulum.duration(days=1) and not out_of_range_event ): alerts.append( ( "warning", "At least one event ({}) is after the end of the event".format( uid ), ) ) out_of_range_event = True if start_dt > end_dt: alerts.append( ( "danger", "Start time for {} is after its end time".format(uid), ) ) out_of_range_event = True try: event = CalendarEvent.query.filter_by( source_id=self.id, uid=uid ).one() except NoResultFound: event = CalendarEvent(uid=uid) self.events.append(event) if len(self.events) > 1000: raise Exception("Too many events in feed") event.start_dt = start_dt event.end_dt = end_dt event.summary = component.get("summary") event.description = component.get("description") event.location = component.get("location") event.displayed = True self.refreshed_at = pendulum.now() return alerts
def get_days_map(): event_days = [ datetime.combine(event_start() + timedelta(days=day_idx), time.min) for day_idx in range((event_end() - event_start()).days + 1) ] return {ed.strftime("%a").lower(): ed for ed in event_days}