Example #1
0
def show_seminar(shortname):
    seminar = seminars_lucky({"shortname": shortname})
    if seminar is None:
        return render_template("404.html", title="Seminar not found")
    organizers = list(db.seminar_organizers.search({"seminar_id": shortname}))
    talks = talks_search({"display": True, "seminar_id": shortname}, projection=3)
    now = get_now()
    future = []
    past = []
    for talk in talks:
        if talk.end_time >= now:
            future.append(talk)
        else:
            past.append(talk)
    future.sort(key=lambda talk: talk.start_time)
    past.sort(key=lambda talk: talk.start_time, reverse=True)
    return render_template(
        "seminar.html",
        title="View seminar",
        future=future,
        past=past,
        seminar=seminar,
        top_menu=basic_top_menu(),
        bread=None,
    )
Example #2
0
def talks_search_api(shortname, projection=1):
    query = {
        "seminar_id": shortname,
        "seminar_ctr": {
            "$gt": 0
        },
        "display": True,
        "hidden": {
            "$or": [False, {
                "$exists": False
            }]
        }
    }
    reverse_sort = False
    if 'daterange' in request.args:
        if request.args.get('daterange') == 'past':
            query["start_time"] = {'$lte': get_now()}
        elif request.args.get('daterange') == 'future':
            query["end_time"] = {'$gte': get_now()}
        else:
            parse_daterange(request.args, query, time=True)
    elif 'past' in request.args and 'future' in request.args:
        # no restriction on date
        pass
    elif 'past' in request.args:
        query["start_time"] = {'$lte': get_now()}
        reverse_sort = True
    elif 'future' in request.args:
        query["end_time"] = {'$gte': get_now()}
    talks = list(talks_search(query, projection=3))
    talks.sort(key=lambda talk: talk.start_time, reverse=reverse_sort)
    return talks
Example #3
0
    def talks(self, projection=1):
        from seminars.talk import talks_search  # avoid import loop

        query = {"seminar_id": self.shortname, "display": True}
        if self.user_can_edit():
            query.pop("display")
        return talks_search(query, projection=projection)
Example #4
0
 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
Example #5
0
def lookup_series(version=0, user=None):
    if version != 0:
        raise version_error(version)
    if request.method == "POST":
        raw_data = get_request_json()
    else:
        raw_data = get_request_args_json()
    series_id = _get_col("series_id", raw_data, "looking up a series")

    try:
        if user is None:
            sanitized = True
        else:
            sem = seminars_lookup(series_id)
            sanitized = not sem.user_can_edit(user=user)
        result = seminars_lookup(series_id, objects=False, sanitized=sanitized)
    except Exception as err:
        raise APIError({
            "code": "lookup_error",
            "description": "an error occurred looking up the series",
            "error": str(err)
        })
    talks = list(
        talks_search({"seminar_id": series_id},
                     sort=["start_time"],
                     sanitized=sanitized,
                     objects=False))
    # tz = pytz.timezone(raw_data.get("timezone", result.get("timezone", "UTC")))
    # TODO: adapt the times, support daterange, sort
    ans = {"code": "success", "properties": result, "talks": talks}
    callback = raw_data.get("callback", False)
    return str_jsonify(ans, callback)
Example #6
0
def search_talks():
    info = to_dict(
        request.args, search_array=TalkSearchArray()
    )
    if "search_type" not in info:
        info["talk_online"] = True
        info["daterange"] = info.get("daterange", datetime.now(current_user.tz).strftime("%B %d, %Y -")
        )
    try:
        talk_count = int(info["talk_count"])
        talk_start = int(info["talk_start"])
        if talk_start < 0:
            talk_start += (1 - (talk_start + 1) // talk_count) * talk_count
    except (KeyError, ValueError):
        talk_count = info["talk_count"] = 50
        talk_start = info["talk_start"] = 0
    talk_query = {}
    talks_parser(info, talk_query)
    talks = talks_search(
        talk_query, sort=["start_time", "speaker"], seminar_dict=all_seminars()
    )  # limit=talk_count, offset=talk_start
    # The talk query isn't sufficient since we don't do a join so don't have access to whether the seminar is private
    talks = [talk for talk in talks if talk.searchable()]
    info["results"] = talks
    return render_template(
        "search_talks.html", title="Search talks", info=info, section="Search", subsection="talks", bread=None,
    )
Example #7
0
def search_talks(version=0):
    if version != 0:
        raise version_error(version)
    if request.method == "POST":
        raw_data = get_request_json()
        query = raw_data.pop("query", {})
        projection = raw_data.pop("projection", 1)
        # FIXME
        # tz = raw_data.pop("timezone", "UTC")
    else:
        query = get_request_args_json()
        projection = 1
        raw_data = {}
    query["hidden"] = False
    visible_series = set(seminars_search({"visibility": 2}, "shortname"))
    # TODO: Need to check visibility on the seminar
    try:
        results = talks_search(query, projection, objects=False, **raw_data)
    except Exception as err:
        raise APIError({
            "code": "search_error",
            "description": "error in executing search",
            "error": str(err)
        })
    results = [rec for rec in results if rec["seminar_id"] in visible_series]
    ans = {"code": "success", "results": results}
    callback = raw_data.get("callback", False)
    return str_jsonify(ans, callback)
Example #8
0
    def talks(self, projection=1):
        from seminars.talk import talks_search  # avoid import loop

        query = {"seminar_id": self.shortname, "display": True, "hidden": {"$or": [False, {"$exists": False}]}}
        if self.user_can_edit():
            query.pop("display")
        return talks_search(query, projection=projection)
    def talks(self):
        if not self.talks_query:  # searching on the empty gives us everything
            return []
        query = {
            '$or': self.talks_query,
            'hidden': {
                "$or": [False, {
                    "$exists": False
                }]
            }
        }
        res = [
            t for t in talks_search(
                query, sort=["start_time"], seminar_dict=all_seminars())
            if t.searchable() or t.user_can_edit(user=self)
        ]
        talk_subscriptions = defaultdict(list)

        for t in res:
            bisect.insort(talk_subscriptions[t.seminar_id], t.seminar_ctr)

        if talk_subscriptions != self.talk_subscriptions:
            self._data["talk_subscriptions"] = talk_subscriptions
            self.save()

        return res
Example #10
0
def index():
    # Eventually want some kind of cutoff on which talks are included.
    # Deal with time zone right
    talks = talks_search(
        {"display": True, "end_time": {"$gte": datetime.datetime.now()}},
        sort=["start_time"],
    )
    menu = basic_top_menu()
    menu[0] = ("#", "$('#filter-menu').slideToggle(400); return false;", "Filter")
    return render_template(
        "browse.html",
        title="Math Seminars",
        info={},
        talks=talks,
        top_menu=menu,
        bread=None,
    )
Example #11
0
 def ics_talks(self):
     query = self.talks_query[:]
     for shortname in self.seminar_subscriptions:
         query.append({'seminar_id': shortname})
     query = {'$or': query, 'hidden': {"$or": [False, {"$exists": False}]}}
     query_st = {}
     now = datetime.now(tz=UTC)
     if self.ics_limit_past:
         query_st['$gte'] = now - timedelta(days=14)
     if self.ics_limit_future:
         query_st['$lte'] = now + timedelta(days=31)
     if query_st:
         query['start_time'] = query_st
     res = [t for t in talks_search(query,
                                    seminar_dict=all_seminars())
            if t.searchable() or t.user_can_edit(user=self)]
     res.sort(key=lambda elt:
              now - elt.start_time if now > elt.start_time else elt.start_time - now)
     return res
Example #12
0
def _talks_index(query={}, sort=None, subsection=None, past=False):
    # Eventually want some kind of cutoff on which talks are included.
    query = dict(query)
    subs = subject_pairs()
    hide_filters = []
    if "subjects" in query:
        subject = query["subjects"]["$contains"]
        hide_filters = ["subject"]
        subs = ((subject, subject.capitalize()), )
    elif "topics" in query:
        hide_filters = ["subject", "topic"]
    elif topdomain() == "mathseminars.org":
        query["subjects"] = ["math"]
    query["display"] = True
    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()))
    # Filtering on display and hidden isn't sufficient since the seminar could be private
    talks = [talk for talk in talks if talk.searchable()]
    counters = _get_counters(talks)
    row_attributes = _get_row_attributes(talks)
    return render_template("browse_talks.html",
                           title="Browse talks",
                           hide_filters=hide_filters,
                           subjects=subs,
                           section="Browse",
                           subsection=subsection,
                           talk_row_attributes=zip(talks, row_attributes),
                           past=past,
                           **counters)
Example #13
0
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
Example #14
0
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
Example #15
0
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
Example #16
0
def make_date_data(seminar):
    shortname = seminar.shortname
    if not seminar.frequency or seminar.frequency < 0 or not seminar.schedule_len or seminar.schedule_len < 0 or seminar.schedule_len > 400:
        print(seminar.frequency, seminar.schedule_len)
        flash_error(
            "You must specify a meeting frequence to use the scheduler")
        return redirect(url_for("show_seminar", shortname=shortname),
                        301), None, None, None
    now = datetime.datetime.now(tz=pytz.utc)
    today = now.date()
    day = datetime.timedelta(days=1)
    last_talk = talks_lucky(
        {
            'seminar_id': shortname,
            'start_time': {
                '$lte': now
            }
        },
        sort=[('start_time', -1)])
    future_talks = list(
        talks_search({
            'seminar_id': shortname,
            'start_time': {
                '$gte': now
            }
        },
                     sort=['start_time']))
    by_date = {T.start_time.date(): T for T in future_talks}
    if len(by_date) != len(future_talks):
        flash_error(
            "Cannot use scheduler when there are multiple talks on the same day"
        )
        return redirect(url_for("show_seminar", shortname=shortname),
                        301), None, None, None
    if last_talk is None:
        if seminar.weekday is None:
            if not future_talks:
                flash_error(
                    "You must specify a weekday or add a talk to the seminar")
                return redirect(url_for("show_seminar", shortname=shortname),
                                301), None, None, None
            seminar.weekday = future_talks[0].start_time.date().weekday()
        next_date = today
        while next_date.weekday() != seminar.weekday:
            next_date += day
    else:
        next_date = last_talk.start_time.date()
        today = now.date()
        while next_date < today:
            next_date += seminar.frequency * day
    all_dates = sorted(
        set([
            next_date + i * seminar.frequency * day
            for i in range(seminar.schedule_len)
        ] + list(by_date)))
    if seminar.start_time is None:
        if future_talks:
            seminar.start_time = future_talks[0].start_time.time()
        elif last_talk is not None:
            seminar.start_time = last_talk.start_time.time()
    if seminar.end_time is None:
        if future_talks:
            seminar.end_time = future_talks[0].end_time.time()
        elif last_talk is not None:
            seminar.end_time = last_talk.end_time.time()
    return None, seminar, all_dates, by_date