def ans(rmk): format = "%a %b %-d, %H:%M" if adapt_datetime(self.start_time, newtz=tz).year == datetime.now(tz).year else "%d-%b-%Y, %H:%M" return "%s-%s (%s)" % ( adapt_datetime(start, newtz=newtz).strftime(format), adapt_datetime(end, newtz=newtz).strftime("%H:%M"), rmk, )
def oneline(self, include_seminar=True, include_slides=False, include_video=False, include_subscribe=True, tz=None, _external=False): t, now, e = adapt_datetime(self.start_time, newtz=tz), adapt_datetime( datetime.now(), newtz=tz), adapt_datetime(self.end_time, newtz=tz) if t < now < e: datetime_tds = t.strftime( '<td class="weekday">%a</td><td class="monthdate">%b %d</td><td class="time"><b>%H:%M</b></td>' ) else: datetime_tds = t.strftime( '<td class="weekday">%a</td><td class="monthdate">%b %d</td><td class="time">%H:%M</td>' ) cols = [] if include_seminar: cols.append(('class="seriesname"', self.show_seminar())) cols.append(('class="speaker"', self.show_speaker(affiliation=False))) cols.append( ('class="talktitle"', self.show_knowl_title(_external=_external))) if include_slides: cols.append(('', self.show_slides_link())) if include_video: cols.append(('', self.show_video_link())) if include_subscribe: cols.append(('class="subscribe"', self.show_subscribe())) #cols.append(('style="display: none;"', self.show_link_title())) return datetime_tds + "".join("<td %s>%s</td>" % c for c in cols)
def oneline(self, include_seminar=True, include_content=False, include_subscribe=True, tz=None, _external=False): rescheduled = self.rescheduled() t, now, e = adapt_datetime(self.start_time, newtz=tz), adapt_datetime(datetime.now(), newtz=tz), adapt_datetime(self.end_time, newtz=tz) if rescheduled: datetime_tds = t.strftime('<td class="weekday rescheduled">%a</i></td><td class="monthdate rescheduled">%b %d</td><td class="time rescheduled"><i>%H:%M</i></td>') else: if t < now < e: datetime_tds = t.strftime('<td class="weekday">%a</td><td class="monthdate">%b %d</td><td class="time"><b>%H:%M</b></td>') else: datetime_tds = t.strftime('<td class="weekday">%a</td><td class="monthdate">%b %d</td><td class="time">%H:%M</td>') cols = [] rclass = " rescheduled" if rescheduled else "" if include_seminar: cols.append(('class="seriesname%s"'%rclass, self.show_seminar())) cols.append(('class="speaker%s"'%rclass, self.show_speaker(affiliation=False))) new_talk = talks_lookup(self.seminar_id, -self.seminar_ctr) if rescheduled else self cols.append(('class="talktitle"', new_talk.show_knowl_title(_external=_external, rescheduled=rescheduled, blackout=self.blackout_date(), tz=tz))) if include_content: cols.append(('', self.show_slides_link())) cols.append(('', self.show_video_link())) cols.append(('', self.show_paper_link())) if include_subscribe: if rescheduled: cols.append(("", "")) else: cols.append(('class="subscribe"', self.show_subscribe())) return datetime_tds + ''.join('<td %s>%s</td>' % c for c in cols)
def ans(rmk): return "%s-%s (%s)" % ( adapt_datetime(start, newtz=newtz).strftime("%a %b %-d, %H:%M"), adapt_datetime(end, newtz=newtz).strftime("%H:%M"), rmk, )
def __init__( self, seminar_id=None, seminar_ctr=None, data=None, seminar=None, editing=False, include_deleted=False, include_pending=False, ): if data is None and not editing: data = talks_lookup(seminar_id, seminar_ctr, include_deleted=include_deleted, include_pending=include_pending) if data is None: raise ValueError("Talk %s/%s does not exist" % (seminar_id, seminar_ctr)) data = dict(data.__dict__) elif data is not None: data = dict(data) # avoid Nones if data.get("topics") is None: data["topics"] = [] if data and data.get("deleted"): include_deleted = True if seminar is None: seminar = WebSeminar(seminar_id, include_deleted=include_deleted) self.seminar = seminar self.new = data is None if self.new: self.seminar_id = seminar_id self.seminar_ctr = None self.token = secrets.token_hex(8) self.by_api = False # reset by API code if needed self.timezone = seminar.timezone self.deleted = False self.deleted_with_seminar = False self.hidden = False for key, typ in db.talks.col_type.items(): if key == "id" or hasattr(self, key): continue if key in inherited_talk_columns: setattr(self, key, getattr(seminar, key)) elif typ == "text": setattr(self, key, "") elif typ == "text[]": setattr(self, key, []) else: # don't complain about columns we know are going to be set later if not key in ["edited_by", "edited_at", "start_time", "end_time"]: critical("Need to update talk code to account for schema change key=%s" % key) setattr(self, key, None) else: # The output from psycopg2 seems to always be given in the server's time zone if data.get("timezone"): tz = pytz.timezone(data["timezone"]) if data.get("start_time"): data["start_time"] = adapt_datetime(data["start_time"], tz) if data.get("end_time"): data["end_time"] = adapt_datetime(data["end_time"], tz) self.__dict__.update(data) self.cleanse()
def show_date(self, tz=None): if self.start_time is None: return "" else: format = "%a %b %-d" if adapt_datetime( self.start_time, newtz=tz).year == datetime.now(tz).year else "%d-%b-%Y" return adapt_datetime(self.start_time, newtz=tz).strftime(format)
def event(self, user): link = url_for("show_talk", seminar_id=self.seminar_id, talkid=self.seminar_ctr, _external=True, _scheme='https') event = Event() #FIXME: code to remove hrefs from speaker name is a temporary hack to be # removed once we support multiple speakers if "href=" in self.speaker: tokens = re.split(r'>([a-zA-Z ]*)', self.speaker) speaker = ', '.join([ tokens[i] for i in range(1, len(tokens), 2) if tokens[i].strip() ]) else: speaker = self.show_speaker(raw=True) event.add("summary", speaker) event.add("dtstart", adapt_datetime(self.start_time, pytz.UTC)) event.add("dtend", adapt_datetime(self.end_time, pytz.UTC)) desc = "" # Title if self.title: desc += 'Title: <a href="%s">%s</a>\n' % ( link, self.title, ) # Speaker and seminar desc += "by %s" % (speaker) if self.seminar.name: desc += " as part of %s" % (self.seminar.name) desc += "\n\n" if self.live_link: link = self.show_live_link(user=user, raw=True) if link.startswith("http"): desc += "Interactive livestream: %s\n" % link if self.access_control == 2 and self.access_hint: desc += "Password hint: %s\n" % self.access_hint event.add("url", link) if self.stream_link: link = self.show_stream_link(user=user, raw=True) if link.startswith("http"): desc += "View-only livestream: %s\n" % link event.add("url", link) if self.room: desc += "Lecture held in %s.\n" % self.room if self.abstract: desc += "\nAbstract\n%s\n" % self.abstract else: desc += "Abstract: TBA\n" if self.comments: desc += "\n%s\n" % self.comments event.add("description", desc) event.add("location", link) event.add("DTSTAMP", datetime.now(tz=pytz.UTC)) event.add("UID", "%s/%s" % (self.seminar_id, self.seminar_ctr)) return event
def __init__( self, semid=None, semctr=None, data=None, seminar=None, editing=False, showing=False, saving=False, deleted=False, ): if data is None and not editing: data = talks_lookup(semid, semctr, include_deleted=deleted) if data is None: raise ValueError("Talk %s/%s does not exist" % (semid, semctr)) data = dict(data.__dict__) elif data is not None: data = dict(data) # avoid Nones if data.get("topics") is None: data["topics"] = [] if seminar is None: seminar = WebSeminar(semid, deleted=deleted) self.seminar = seminar self.new = data is None self.deleted=False if self.new: self.seminar_id = semid self.seminar_ctr = None self.token = "%016x" % random.randrange(16 ** 16) self.display = seminar.display self.online = getattr(seminar, "online", bool(seminar.live_link)) self.timezone = seminar.timezone for key, typ in db.talks.col_type.items(): if key == "id" or hasattr(self, key): continue elif db.seminars.col_type.get(key) == typ and getattr(seminar, key, None): # carry over from seminar, but not comments setattr(self, key, getattr(seminar, key) if key != "comments" else "") elif typ == "text": setattr(self, key, "") elif typ == "text[]": setattr(self, key, []) else: critical("Need to update talk code to account for schema change key=%s" % key) setattr(self, key, None) else: # The output from psycopg2 seems to always be given in the server's time zone if data.get("timezone"): tz = pytz.timezone(data["timezone"]) if data.get("start_time"): data["start_time"] = adapt_datetime(data["start_time"], tz) if data.get("end_time"): data["end_time"] = adapt_datetime(data["end_time"], tz) # transition to topics including the subject if data.get("topics"): data["topics"] = [(topic if "_" in topic else "math_" + topic) for topic in data["topics"]] self.__dict__.update(data)
def show_end_time(self, tz=None): """ INPUT: - ``tz`` -- a timezone object or None (use the current user's time zone) OUTPUT: If ``tz`` is given, the time in that time zone (no date). Otherwise, show the date only if different from the date of the start time in that time zone. """ # This is used in show_time_and_duration, and needs to include the ending date if different (might not be the same in current user's time zone) t = adapt_datetime(self.end_time, newtz=tz) if tz is not None: return t.strftime("%H:%M") t0 = adapt_datetime(self.start_time, newtz=tz) if t0.date() == t.date(): return t.strftime("%H:%M") else: return t.strftime("%a %b %-d, %H:%M")
def event(self, user): event = Event() event.add("summary", self.speaker) event.add("dtstart", adapt_datetime(self.start_time, pytz.UTC)) event.add("dtend", adapt_datetime(self.end_time, pytz.UTC)) desc = "" # Title if self.title: desc += "Title: %s\n" % (self.title) # Speaker and seminar desc += "by %s" % (self.speaker) if self.speaker_affiliation: desc += " (%s)" % (self.speaker_affiliation) if self.seminar.name: desc += " as part of %s" % (self.seminar.name) desc += "\n\n" if self.live_link: link = self.show_live_link(user=user, raw=True) if link.startswith("http"): desc += "Access: %s\n" % (link) event.add("url", link) if self.room: desc += "Lecture held in %s.\n" % self.room if self.abstract: desc += "\nAbstract\n%s\n" % self.abstract else: desc += "Abstract: TBA\n" if self.comments: desc += "\n%s\n" % (self.comments) event.add("description", desc) if self.room: event.add("location", "Lecture held in {}".format(self.room)) event.add("DTSTAMP", datetime.datetime.now(tz=pytz.UTC)) event.add("UID", "%s/%s" % (self.seminar_id, self.seminar_ctr)) return event
def oneline( self, conference=False, include_institutions=True, include_datetime=True, include_topics=False, include_audience=False, include_subscribe=True, show_attributes=False, ): datetime_tds = "" if include_datetime: if conference: # include start and end date instead if self.is_conference and self.start_date and self.end_date: if self.start_date == self.end_date: datetime_tds = '<td colspan="2" class="onedate">' + self._show_date( self.start_date) + '</td>' else: datetime_tds = '<td class="startdate">' + self._show_date( self.start_date ) + '</td><td class="enddate">' + self._show_date( self.end_date) + '</td>' else: datetime_tds = '<td class="startdate"></td><td class="enddate"></td>' else: # could include both conferences and seminar series t = adapt_datetime(self.next_talk_time) if t is None: datetime_tds = '<td></td><td></td><td></td>' else: datetime_tds = t.strftime( '<td class="weekday">%a</td><td class="monthdate">%b %d</td><td class="time">%H:%M</td>' ) cols = [] cols.append( ('class="seriesname"', self.show_name(show_attributes=show_attributes, homepage_link=True if self.deleted else False))) if include_institutions: cols.append(('class="institutions"', self.show_institutions())) if include_audience: cols.append(('class="audience"', self.show_audience())) if include_topics: cols.append(('class="topics"', self.show_topics())) if include_subscribe: cols.append(('class="subscribe"', self.show_subscribe())) return datetime_tds + "".join("<td %s>%s</td>" % c for c in cols)
def oneline( self, conference=False, include_institutions=True, include_datetime=True, include_description=True, include_topics=False, include_subscribe=True, show_attributes=False, ): cols = [] if include_datetime: if conference: # include start and end date instead if self.start_date is None: cols.append(('class="date"', "")) else: cols.append(('class="date"', self.start_date.strftime("%a %b %-d"))) if self.end_date is None: cols.append(('class="date"', "")) else: cols.append( ('class="date"', self.end_date.strftime("%a %b %-d"))) else: # could include both conferences and seminar series t = adapt_datetime(self.next_talk_time) if t is None: cols.append(('class="date"', "")) cols.append(('class="time"', "")) else: cols.append(('class="date"', t.strftime("%a %b %-d"))) cols.append(('class="time"', t.strftime("%H:%M"))) cols.append( ('class="name"', self.show_name(show_attributes=show_attributes))) if include_institutions: cols.append(('class="institution"', self.show_institutions())) if include_description: cols.append(('class="description"', self.show_description())) if include_topics: cols.append(('class="topics"', self.show_topics())) if include_subscribe: cols.append(('class="subscribe"', self.show_subscribe())) return "".join("<td %s>%s</td>" % c for c in cols)
def __init__( self, shortname, data=None, organizers=None, editing=False, showing=False, saving=False, deleted=False, user=None, ): if user is None: user = current_user if data is None and not editing: data = seminars_lookup(shortname, include_deleted=deleted) if data is None: raise ValueError("Seminar %s does not exist" % shortname) data = dict(data.__dict__) elif data is not None: data = dict(data) if data.get("topics") is None: data["topics"] = [] if data.get("institutions") is None: data["institutions"] = [] if data.get("timezone") is None: data["timesone"] = str(user.tz) self.new = data is None self.deleted = False if self.new: self.shortname = shortname self.display = user.is_creator self.online = True # default self.by_api = False # reset by API code if needed self.access = "open" # default FIXME: remove once we switch to access_control self.access_control = 4 # default is instant registration self.access_time = None self.edited_by = user.id self.visibility = 2 # public by default, once display is set to True self.level = 0 # default is research seminar self.is_conference = False # seminar by default self.frequency = 7 self.per_day = 1 self.weekday = self.start_time = self.end_time = None self.timezone = str(user.tz) for key, typ in db.seminars.col_type.items(): if key == "id" or hasattr(self, key): continue elif typ == "text": setattr(self, key, "") elif typ == "text[]": setattr(self, key, []) elif typ == "smallint[]": setattr(self, key, []) elif typ == "timestamp with time zone": setattr(self, key, None) elif typ == "timestamp with time zone[]": setattr(self, key, []) elif typ == "date": setattr(self, key, None) else: critical( "Need to update seminar code to account for schema change key=%s" % key ) setattr(self, key, None) if organizers is None: organizers = [ { "seminar_id": self.shortname, "email": user.email, "homepage": user.homepage, "name": user.name, "order": 0, "curator": False, "display": True, "contact": True, } ] else: # The output from psycopg2 seems to always be given in the server's time zone if data.get("timezone"): tz = pytz.timezone(data["timezone"]) if data.get("start_time"): data["start_time"] = adapt_datetime(data["start_time"], tz) if data.get("end_time"): data["end_time"] = adapt_datetime(data["end_time"], tz) self.__dict__.update(data) if organizers is None: organizers = list( db.seminar_organizers.search({"seminar_id": self.shortname}, sort=["order"]) ) self.organizers = organizers self.cleanse()
def __init__(self, shortname, data=None, organizer_data=None, editing=False, showing=False, saving=False, deleted=False): if data is None and not editing: data = seminars_lookup(shortname, include_deleted=deleted) if data is None: raise ValueError("Seminar %s does not exist" % shortname) data = dict(data.__dict__) elif data is not None: data = dict(data) if data.get("topics") is None: data["topics"] = [] if data.get("institutions") is None: data["institutions"] = [] if data.get("timezone") is None: data["timesone"] = str(current_user.tz) self.new = data is None self.deleted = False if self.new: self.shortname = shortname self.display = current_user.is_creator self.online = True # default self.access = "open" # default self.visibility = 2 # public by default, once display is set to True self.is_conference = False # seminar by default self.frequency = 7 self.per_day = 1 self.weekday = self.start_time = self.end_time = None self.timezone = str(current_user.tz) for key, typ in db.seminars.col_type.items(): if key == "id" or hasattr(self, key): continue elif typ == "text": setattr(self, key, "") elif typ == "text[]": setattr(self, key, []) elif typ == "smallint[]": setattr(self, key, []) elif typ == "timestamp with time zone": setattr(self, key, None) elif typ == "timestamp with time zone[]": setattr(self, key, []) elif typ == "date": setattr(self, key, None) elif typ == "bigint": setattr(self, key, None) else: critical( "Need to update seminar code to account for schema change key=%s" % key) setattr(self, key, None) if organizer_data is None: organizer_data = [{ "seminar_id": self.shortname, "email": current_user.email, "homepage": current_user.homepage, "full_name": current_user.name, "order": 0, "curator": False, "display": True, "contact": True, }] else: # The output from psycopg2 seems to always be given in the server's time zone if data.get("timezone"): tz = pytz.timezone(data["timezone"]) if data.get("start_time"): data["start_time"] = adapt_datetime(data["start_time"], tz) if data.get("end_time"): data["end_time"] = adapt_datetime(data["end_time"], tz) # transition to topics including the subject if data.get("topics"): data["topics"] = [(topic if "_" in topic else "math_" + topic) for topic in data["topics"]] self.__dict__.update(data) if organizer_data is None: organizer_data = list( db.seminar_organizers.search({"seminar_id": self.shortname}, sort=["order"])) self.organizer_data = organizer_data self.convert_time_to_times()
def blackout_date(self): return adapt_datetime(self.start_time, newtz=self.tz).strftime("%Y-%m-%d") in blackout_dates
def show_daytimes(self, tz=None): return adapt_datetime(self.start_time, tz).strftime("%H:%M") + "-" + adapt_datetime(self.end_time, tz).strftime("%H:%M")
def show_start_time(self, tz=None): return adapt_datetime(self.start_time, tz).strftime("%H:%M")
def _talks_index(query={}, sort=None, subsection=None, past=False): # Eventually want some kind of cutoff on which talks are included. search_array = TalkSearchArray(past=past) info = to_dict(read_search_cookie(search_array), search_array=search_array) info.update(request.args) query = dict(query) parse_substring(info, query, "keywords", ["title", "abstract", "speaker", "speaker_affiliation", "seminar_id", "comments", "speaker_homepage", "paper_link"]) more = {} # we will be selecting talks satsifying the query and recording whether they satisfy the "more" query # Note that talks_parser ignores the "time" field at the moment; see below for workaround talks_parser(info, more) if topdomain() == "mathseminars.org": query["topics"] = {"$contains": "math"} query["hidden"] = {"$or": [False, {"$exists": False}]} if past: query["end_time"] = {"$lt": datetime.now()} if sort is None: sort = [("start_time", -1), "seminar_id"] else: query["end_time"] = {"$gte": datetime.now()} if sort is None: sort = ["start_time", "seminar_id"] talks = list(talks_search(query, sort=sort, seminar_dict=all_seminars(), more=more)) # Filtering on display and hidden isn't sufficient since the seminar could be private talks = [talk for talk in talks if talk.searchable()] # While we may be able to write a query specifying inequalities on the timestamp in the user's timezone, it's not easily supported by talks_search. So we filter afterward timerange = info.get("timerange", "").strip() if timerange: tz = current_user.tz try: timerange = process_user_input(timerange, col="search", typ="daytimes") except ValueError: try: onetime = process_user_input(timerange, col="search", typ="daytime") except ValueError: flash_error("Invalid time range input: %s", timerange) else: for talk in talks: if talk.more: talkstart = adapt_datetime(talk.start_time, tz) t = date_and_daytime_to_time(talkstart.date(), onetime, tz) talk.more = (t == talkstart) else: for talk in talks: if talk.more: talkstart = adapt_datetime(talk.start_time, tz) talkend = adapt_datetime(talk.end_time, tz) t0, t1 = date_and_daytimes_to_times(talkstart.date(), timerange, tz) talk.more = (t0 <= talkstart) and (talkend <= t1) counters = _get_counters(talks) row_attributes = _get_row_attributes(talks) response = make_response(render_template( "browse_talks.html", title="Browse talks", section="Browse", info=info, subsection=subsection, talk_row_attributes=zip(talks, row_attributes), past=past, **counters )) if request.cookies.get("topics", ""): # TODO: when we move cookie data to server with ajax calls, this will need to get updated again # For now we set the max_age to 30 years response.set_cookie("topics_dict", topic_dag.port_cookie(), max_age=60*60*24*365*30) response.set_cookie("topics", "", max_age=0) return response
def layout_schedule(seminar, data): """ Returns a list of schedule slots in specified date range (date, daytime-interval, talk) where talk is a WebTalk or none. Picks default dates if none specified """ tz = seminar.tz def parse_date(key): date = data.get(key) if date: try: return process_user_input(date, "date", "date", tz) except ValueError: flash_warning( "Invalid date %s ignored, please use a format like mmm dd, yyyy or dd-mmm-yyyy or mm/dd/yyyy", date) def slot_start_time(s): # put slots with no time specified at the end of the day return date_and_daytimes_to_times(parse_time(s[0]), s[1] if s[1] else "23:59-23:59", tz)[0] begin = parse_date("begin") end = parse_date("end") shortname = seminar.shortname now = datetime.now(tz=tz) today = now.date() day = timedelta(days=1) if seminar.is_conference and (seminar.start_date is None or seminar.end_date is None): flash_warning( "You have not specified the start and end dates of your conference (we chose a date range to layout your schedule)." ) begin = seminar.start_date if begin is None and seminar.is_conference else begin begin = today if begin is None else begin end = seminar.end_date if end is None and seminar.is_conference else end if end is None: if seminar.is_conference: if seminar.per_day: end = begin + day * ceil(SCHEDULE_LEN / seminar.per_day) else: end = begin + 7 * day else: if seminar.frequency: end = begin + day * ceil( SCHEDULE_LEN * seminar.frequency / len(seminar.time_slots)) else: end = begin + 14 * day if end < begin: end = begin data["begin"] = seminar.show_input_date(begin) data["end"] = seminar.show_input_date(end) midnight_begin = midnight(begin, tz) midnight_end = midnight(end, tz) query = {"$gte": midnight_begin, "$lt": midnight_end + day} talks = list( talks_search({ "seminar_id": shortname, "start_time": query }, sort=["start_time"])) slots = [(t.show_date(tz), t.show_daytimes(tz), t) for t in talks] if seminar.is_conference: newslots = [] d = midnight_begin while d < midnight_end + day: newslots += [(seminar.show_schedule_date(d), "", None) for i in range(seminar.per_day)] d += day for t in slots: if (t[0], "", None) in newslots: newslots.remove((t[0], "", None)) slots = sorted(slots + newslots, key=lambda t: slot_start_time(t)) return slots if not seminar.frequency: for i in range(max(SCHEDULE_LEN - len(slots), 3)): slots.append(("", "", None)) else: # figure out week to start in. # use the week of the first seminar after begin if any, otherwise last seminar before begin, if any # otherwise just use the week containing begin t = talks_lucky( { "seminar_id": shortname, "start_time": { "$gte": midnight_begin } }, sort=[("start_time", 1)]) if not t: t = talks_lucky( { "seminar_id": shortname, "start_time": { "$lt": midnight_begin } }, sort=[("start_time", -1)]) if t: t = adapt_datetime(t.start_time, newtz=tz) w = t - t.weekday() * day while w > midnight_begin: w -= day * seminar.frequency while w + day * seminar.frequency < midnight_begin: w += day * seminar.frequency else: w = midnight_begin - midnight_begin.weekday() * day # make a list of all seminar time slots in [begin,end) newslots = [] while w < midnight_end: for i in range(len(seminar.weekdays)): d = w + day * seminar.weekdays[i] if d >= midnight_begin and d < midnight_end + day: newslots.append((seminar.show_schedule_date(d), seminar.time_slots[i], None)) w = w + day * seminar.frequency # remove slots that are (exactly) matched by an existing talk # this should handle slots that occur with multiplicity for t in slots: if (t[0], t[1], None) in newslots: newslots.remove((t[0], t[1], None)) slots = sorted(slots + newslots, key=lambda t: slot_start_time(t)) return slots
def __init__( self, seminar_id=None, seminar_ctr=None, data=None, seminar=None, editing=False, showing=False, saving=False, deleted=False, ): if data is None and not editing: data = talks_lookup(seminar_id, seminar_ctr, include_deleted=deleted) if data is None: raise ValueError("Talk %s/%s does not exist" % (seminar_id, seminar_ctr)) data = dict(data.__dict__) elif data is not None: data = dict(data) # avoid Nones if data.get("topics") is None: data["topics"] = [] if data and data.get("deleted"): deleted = True if seminar is None: seminar = WebSeminar(seminar_id, deleted=deleted) self.seminar = seminar self.new = data is None self.deleted = False if self.new: self.seminar_id = seminar_id self.seminar_ctr = None self.token = secrets.token_hex(8) self.display = seminar.display self.online = getattr(seminar, "online", bool(seminar.live_link)) self.by_api = False # reset by API code if needed self.timezone = seminar.timezone for key, typ in db.talks.col_type.items(): if key == "id" or hasattr(self, key): continue elif db.seminars.col_type.get(key) == typ and getattr( seminar, key, None): # carry over from seminar, but not comments setattr(self, key, getattr(seminar, key) if key != "comments" else "") print("talk inherited %s = %s from seminar" % (key, getattr(self, key))) elif typ == "text": setattr(self, key, "") elif typ == "text[]": setattr(self, key, []) else: critical( "Need to update talk code to account for schema change key=%s" % key) setattr(self, key, None) else: # The output from psycopg2 seems to always be given in the server's time zone if data.get("timezone"): tz = pytz.timezone(data["timezone"]) if data.get("start_time"): data["start_time"] = adapt_datetime(data["start_time"], tz) if data.get("end_time"): data["end_time"] = adapt_datetime(data["end_time"], tz) self.__dict__.update(data) self.cleanse()
def __init__(self, shortname, data=None, organizer_data=None, editing=False, showing=False, saving=False): if data is None and not editing: data = seminars_lookup(shortname) if data is None: raise ValueError("Seminar %s does not exist" % shortname) data = dict(data.__dict__) elif data is not None: data = dict(data) if data.get("topics") is None: data["topics"] = [] if data.get("instructions") is None: data["instructions"] = [] self.new = data is None if self.new: self.shortname = shortname self.display = current_user.is_creator self.online = True # default self.access = "open" # default self.archived = False # don't start out archived self.is_conference = False # seminar by default self.frequency = 7 self.per_day = 1 self.weekday = self.start_time = self.end_time = None self.timezone = str(current_user.tz) self.start_date = None self.end_date = None for key, typ in db.seminars.col_type.items(): if key == "id" or hasattr(self, key): continue elif typ == "text": setattr(self, key, "") elif typ == "text[]": setattr(self, key, []) else: raise ValueError( "Need to update seminar code to account for schema change" ) if organizer_data is None: organizer_data = [{ "seminar_id": self.shortname, "email": current_user.email, "full_name": current_user.name, "order": 0, "curator": False, "display": True, "contact": True, }] else: # The output from psycopg2 seems to always be given in the server's time zone if data.get("timezone"): tz = pytz.timezone(data["timezone"]) if data.get("start_time"): data["start_time"] = adapt_datetime(data["start_time"], tz) if data.get("end_time"): data["end_time"] = adapt_datetime(data["end_time"], tz) self.__dict__.update(data) if organizer_data is None: organizer_data = list( db.seminar_organizers.search({"seminar_id": self.shortname}, sort=["order"])) self.organizer_data = organizer_data
def show_date(self): if self.start_time is None: return "" else: return adapt_datetime(self.start_time).strftime("%a %b %-d")
def show_schedule_date(self, date): if not date: return "" format = "%a %b %-d" if adapt_datetime( date, self.tz).year == datetime.now(self.tz).year else "%d-%b-%Y" return adapt_datetime(date, self.tz).strftime(format)
def _talks_index( query={}, sort=None, subsection=None, past=False, keywords="", limit=None, # this is an upper bound on desired number of talks, we might filter some extra out limitbuffer=1000, # the number of extra talks that we give ourselves to try to get the limit right asblock=False, # the number of talks returned is based on star time blocks getcounters=True, # doesn't limit the SQL search to get the full counters visible_counter=0, fully_filtered=True, ): # Eventually want some kind of cutoff on which talks are included. search_array = TalkSearchArray(past=past) info = to_dict(read_search_cookie(search_array), search_array=search_array) info.update(request.args) if keywords: info["keywords"] = keywords keywords = info.get("keywords", "") query = dict(query) parse_substring(info, query, "keywords", [ "title", "abstract", "speaker", "speaker_affiliation", "seminar_id", "comments", "speaker_homepage", "paper_link" ]) more = { } # we will be selecting talks satsifying the query and recording whether they satisfy the "more" query # Note that talks_parser ignores the "time" field at the moment; see below for workaround talks_parser(info, more) if topdomain() == "mathseminars.org": query["topics"] = {"$contains": "math"} query["display"] = True query["hidden"] = {"$or": [False, {"$exists": False}]} query["audience"] = {"$lte": DEFAULT_AUDIENCE} now = datetime.now(pytz.UTC) if past: query["end_time"] = {"$lt": now} query["seminar_ctr"] = {"$gt": 0} # don't show rescheduled talks if sort is None: sort = [("start_time", -1), "seminar_id"] else: query["end_time"] = {"$gte": now} if sort is None: sort = ["start_time", "seminar_id"] def dosearch(limit=limit, limitbuffer=limitbuffer): if limit and not getcounters: # we fetch extra talks to account for filtering talks = talks_search(query, sort=sort, seminar_dict=all_seminars(), more=more, limit=limit + limitbuffer) else: talks = talks_search(query, sort=sort, seminar_dict=all_seminars(), more=more) # Filtering on display and hidden isn't sufficient since the seminar could be private talks = [talk for talk in talks if talk.searchable()] return talks def truncateasblock(talks, retry=True): if not talks: return talks last_time = None # find enough talks such that the next talk has a different starting time for i, t in enumerate(talks): if last_time is None: last_time = t.start_time continue if t.start_time != last_time: if i > limit: return talks[:i - 1] else: last_time = t.start_time else: if retry and limit and not getcounters: # redo the search without limits talks = dosearch(limit=None) return truncateasblock(talks, retry=False) return talks def truncate(talks): if asblock and limit: return truncateasblock(talks) elif limit: return talks[:limit] else: return talks talks = dosearch() if getcounters: counters = _get_counters(talks) else: counters = _get_counters([]) if getcounters and fully_filtered: # the initial query was not limited as getcounters = True # we will first filter after figuring out the more attribute # and then truncate pass else: # we are not going to filter or the query was already limited, so we can truncate talks = truncate(talks) # While we may be able to write a query specifying inequalities on the timestamp in the user's timezone, it's not easily supported by talks_search. So we filter afterward timerange = info.get("timerange", "").strip() if timerange: tz = current_user.tz try: timerange = process_user_input(timerange, col="search", typ="daytimes") except ValueError: try: onetime = process_user_input(timerange, col="search", typ="daytime") except ValueError: flash_error("Invalid time range input: %s", timerange) else: for talk in talks: if talk.more: talkstart = adapt_datetime(talk.start_time, tz) t = date_and_daytime_to_time(talkstart.date(), onetime, tz) talk.more = (t == talkstart) else: for talk in talks: if talk.more: talkstart = adapt_datetime(talk.start_time, tz) talkend = adapt_datetime(talk.end_time, tz) t0, t1 = date_and_daytimes_to_times( talkstart.date(), timerange, tz) talk.more = (t0 <= talkstart) and (talkend <= t1) # get last_time before potential filtering last_time = int(talks[-1].start_time.timestamp()) if talks else None if fully_filtered: # first filter then truncate row_attributes, talks = _get_row_attributes(talks, visible_counter, fully_filtered) if getcounters: # we have not yet truncated the results if limit and len(talks) > limit: talks = truncate(talks) row_attributes = row_attributes[:len(talks)] last_time = int( talks[-1].start_time.timestamp()) if talks else None else: row_attributes = _get_row_attributes(talks, visible_counter) response = make_response( render_template("browse_talks.html", title="Browse past talks" if past else "Browse talks", section="Browse", info=info, subsection=subsection, talk_row_attributes=zip(talks, row_attributes), past=past, last_time=last_time, extraargs=urlencode({'keywords': keywords}), **counters)) if request.cookies.get("topics", ""): # TODO: when we move cookie data to server with ajax calls, this will need to get updated again # For now we set the max_age to 30 years response.set_cookie("topics_dict", topic_dag.port_cookie(), max_age=60 * 60 * 24 * 365 * 30) response.set_cookie("topics", "", max_age=0) # disable cache response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate' response.headers['Pragma'] = 'no-cache' return response
def make_date_data(seminar, data): tz = seminar.tz def parse_date(key): date = data.get(key) if date: try: return process_user_input(date, "date", tz) except ValueError: pass begin = parse_date("begin") end = parse_date("end") frequency = data.get("frequency") try: frequency = int(frequency) except Exception: frequency = None if not frequency or frequency < 0: frequency = seminar.frequency if not frequency or frequency < 0: frequency = 1 if seminar.is_conference else 7 try: weekday = short_weekdays.index(data.get("weekday", "")[:3]) except ValueError: weekday = None if weekday is None: weekday = seminar.weekday shortname = seminar.shortname day = datetime.timedelta(days=1) now = datetime.datetime.now(tz=tz) today = now.date() midnight_today = now.replace(hour=0, minute=0, second=0, microsecond=0) if begin is None or seminar.start_time is None or seminar.end_time is None: future_talk = talks_lucky( { "seminar_id": shortname, "start_time": { "$exists": True, "$gte": midnight_today } }, sort=["start_time"]) last_talk = talks_lucky( { "seminar_id": shortname, "start_time": { "$exists": True, "$lt": midnight_today } }, sort=[("start_time", -1)], ) if begin is None: if seminar.is_conference: if seminar.start_date: begin = seminar.start_date else: begin = today else: if weekday is not None and frequency == 7: begin = today # Will set to next weekday below else: # Try to figure out a plan from future and past talks if future_talk is None: if last_talk is None: # Give up begin = today else: begin = last_talk.start_time.date() while begin < today: begin += frequency * day else: begin = future_talk.start_time.date() while begin >= today: begin -= frequency * day begin += frequency * day if not seminar.is_conference and seminar.weekday is not None: # Weekly meetings: take the next one while begin.weekday() != weekday: begin += day if end is None: if seminar.is_conference: if seminar.end_date: end = seminar.end_date schedule_len = int((end - begin) / (frequency * day)) + 1 else: end = begin + 6 * day schedule_len = 7 else: end = begin + (SCHEDULE_LEN - 1) * frequency * day schedule_len = SCHEDULE_LEN else: schedule_len = abs(int((end - begin) / (frequency * day))) + 1 seminar.frequency = frequency data["begin"] = seminar.show_input_date(begin) data["end"] = seminar.show_input_date(end) midnight_begin = localize_time( datetime.datetime.combine(begin, datetime.time()), tz) midnight_end = localize_time( datetime.datetime.combine(end, datetime.time()), tz) # add a day since we want to allow talks on the final day if end < begin: # Only possible by user input frequency = -frequency query = {"$gte": midnight_end, "$lt": midnight_begin + day} else: query = {"$gte": midnight_begin, "$lt": midnight_end + day} schedule_days = [begin + i * frequency * day for i in range(schedule_len)] scheduled_talks = list( talks_search({ "seminar_id": shortname, "start_time": query })) by_date = defaultdict(list) for T in scheduled_talks: by_date[adapt_datetime(T.start_time, tz).date()].append(T) all_dates = sorted(set(schedule_days + list(by_date)), reverse=(end < begin)) # Fill in by_date with Nones up to the per_day value for date in all_dates: by_date[date].extend([None] * (seminar.per_day - len(by_date[date]))) if seminar.start_time is None: if future_talk is not None and future_talk.start_time: seminar.start_time = future_talk.start_time.time() elif last_talk is not None and last_talk.start_time: seminar.start_time = last_talk.start_time.time() if seminar.end_time is None: if future_talk is not None and future_talk.start_time: seminar.end_time = future_talk.end_time.time() elif last_talk is not None and last_talk.start_time: seminar.end_time = last_talk.end_time.time() return seminar, all_dates, by_date