Ejemplo n.º 1
0
def edit_talk():
    if request.method == "POST":
        data = request.form
    else:
        data = request.args
    token = data.get("token", "")
    resp, talk = can_edit_talk(data.get("seminar_id", ""),
                               data.get("seminar_ctr", ""), token)
    if resp is not None:
        return resp
    if token:
        # Also want to override top menu
        from seminars.utils import top_menu

        menu = top_menu()
        menu[2] = (url_for("create.index"), "", "Manage")
        extras = {"top_menu": menu}
    else:
        extras = {}
    # The seminar schedule page adds in a date and times
    if data.get("date", "").strip():
        tz = talk.seminar.tz
        date = process_user_input(data["date"], "date", "date", tz)
        try:
            # TODO: clean this up
            start_time = process_user_input(data.get("start_time"),
                                            "start_time", "time", tz)
            end_time = process_user_input(data.get("end_time"), "end_time",
                                          "time", tz)
            start_time = localize_time(datetime.combine(date, start_time), tz)
            end_time = localize_time(datetime.combine(date, end_time), tz)
        except ValueError:
            return redirect(
                url_for(".edit_seminar_schedule", shortname=talk.seminar_id),
                302)
        talk.start_time = start_time
        talk.end_time = end_time
    # lock = get_lock(seminar_id, data.get("lock"))
    title = "Create talk" if talk.new else "Edit talk"
    return render_template("edit_talk.html",
                           talk=talk,
                           seminar=talk.seminar,
                           title=title,
                           section="Manage",
                           subsection="edittalk",
                           institutions=institutions(),
                           timezones=timezones,
                           token=token,
                           **extras)
Ejemplo n.º 2
0
 def parse_date(key):
     date = data.get(key)
     if date:
         try:
             return process_user_input(date, "date", tz)
         except ValueError:
             pass
Ejemplo n.º 3
0
def set_info():
    errmsgs = []
    data = {}
    previous_email = current_user.email
    for col, val in request.form.items():
        try:
            typ = db.users.col_type[col]
            data[col] = process_user_input(val, col, typ)
        except Exception as err:  # should only be ValueError's but let's be cautious
            errmsgs.append(format_input_errmsg(err, val, col))
    if not data.get("name"):
        errmsgs.append(
            format_errmsg(
                'Name cannot be left blank.  See the user behavior section of our <a href="'
                + url_for('policies') +
                '" target="_blank">policies</a> page for details.'))
    if errmsgs:
        return show_input_errors(errmsgs)
    for k in data.keys():
        setattr(current_user, k, data[k])
    if current_user.save():
        flask.flash(Markup("Thank you for updating your details!"))
    if previous_email != current_user.email:
        if send_confirmation_email(current_user.email):
            flask.flash(Markup("New confirmation email has been sent!"))
    return redirect(url_for(".info"))
Ejemplo n.º 4
0
def search_series(version=0):
    if version != 0:
        raise version_error(version)
    if request.method == "POST":
        raw_data = get_request_json()
        query = raw_data.pop("query", {})
        # FIXME
        # projection = raw_data.pop("projection", 1)
        tz = raw_data.pop("timezone", "UTC")
    else:
        query = get_request_args_json()
        tz = current_user.tz # Is this the right choice?
        for col, val in query.items():
            if col in db.seminars.col_type:
                query[col] = process_user_input(val, col, db.seminars.col_type[col], tz)
            else:
                raise APIError({"code": "unknown_column",
                                "col": col,
                                "description": "%s not a column of seminars" % col})
        raw_data = {}
    query["visibility"] = 2
    # TODO: encode the times....
    try:
        results = list(seminars_search(query, objects=False, sanitized=True, **raw_data))
    except Exception as err:
        raise APIError({"code": "search_error",
                        "description": "error in executing search",
                        "error": str(err)})
    ans = {"code": "success", "results": results}
    callback = raw_data.get("callback", False)
    return str_jsonify(ans, callback)
Ejemplo n.º 5
0
 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)
Ejemplo n.º 6
0
def save_talk():
    raw_data = request.form
    resp, seminar, talk = can_edit_talk(raw_data.get("seminar_id", ""),
                                        raw_data.get("seminar_ctr", ""),
                                        raw_data.get("token", ""))
    if resp is not None:
        return resp

    data = {
        'seminar_id': talk.seminar_id,
        'token': talk.token,
        'display': talk.display,  # could be being edited by anonymous user
    }
    if talk.new:
        curmax = talks_max('seminar_ctr', {'seminar_id': talk.seminar_id})
        if curmax is None:
            curmax = 0
        data['seminar_ctr'] = curmax + 1
    else:
        data['seminar_ctr'] = talk.seminar_ctr
    for col in db.talks.search_cols:
        if col in data: continue
        try:
            val = raw_data.get(col)
            if not val:
                data[col] = None
            else:
                data[col] = process_user_input(val, db.talks.col_type[col])
            if col == 'speaker_homepage' and val and not val.startswith(
                    "http"):
                data[col] = "http://" + data[col]
            if col == "access" and val not in ["open", "users", "endorsed"]:
                raise ValueError("Invalid access type")
        except Exception as err:
            flash_error("Error processing %s: %s", [col, err])
            talk = WebTalk(talk.seminar_id, talk.seminar_ctr, data=raw_data)
            title = "Create talk" if talk.new else "Edit talk"
            return render_template("edit_talk.html",
                                   talk=talk,
                                   seminar=seminar,
                                   title=title,
                                   top_menu=basic_top_menu(),
                                   categories=categories(),
                                   institutions=institutions(),
                                   timezones=timezones)
    new_version = WebTalk(talk.seminar_id, data['seminar_ctr'], data=data)
    if new_version == talk:
        flash("No changes made to talk.")
    else:
        new_version.save()
        edittype = "created" if talk.new else "edited"
        flash("Talk successfully %s!" % edittype)
    return redirect(
        url_for("show_talk",
                semid=new_version.seminar_id,
                talkid=new_version.seminar_ctr), 301)
Ejemplo n.º 7
0
def save_institution():
    raw_data = request.form
    shortname = raw_data["shortname"]
    new = raw_data.get("new") == "yes"
    resp, institution = can_edit_institution(shortname, new)
    if resp is not None:
        return resp

    data = {}
    data["timezone"] = tz = raw_data.get("timezone", "UTC")
    tz = pytz.timezone(tz)
    for col in db.institutions.search_cols:
        if col in data:
            continue
        try:
            val = raw_data.get(col)
            if not val:
                data[col] = None
            else:
                data[col] = process_user_input(val,
                                               db.institutions.col_type[col],
                                               tz=tz)
            if col == "admin":
                userdata = db.users.lookup(val)
                if userdata is None:
                    raise ValueError("%s must have account on this site" % val)
            if col == "homepage" and val and not val.startswith("http"):
                data[col] = "http://" + data[col]
            if col == "access" and val not in ["open", "users", "endorsed"]:
                raise ValueError("Invalid access type")
        except Exception as err:
            # TODO: this probably needs to be a redirect to change the URL?  We want to save the data the user entered.
            flash_error("Error processing %s: %s" % (col, err))
            institution = WebInstitution(shortname, data=raw_data)
            return render_template(
                "edit_institution.html",
                institution=institution,
                institution_types=institution_types,
                timezones=timezones,
                title="Edit institution error",
                section="Manage",
                subsection="editinst",
            )
    new_version = WebInstitution(shortname, data=data)
    if new_version == institution:
        flash("No changes made to institution.")
    else:
        new_version.save()
        edittype = "created" if new else "edited"
        flash("Institution %s successfully!" % edittype)
    return redirect(url_for(".edit_institution", shortname=shortname), 301)
Ejemplo n.º 8
0
def set_info():
    errmsgs = []
    data = {}
    previous_email = current_user.email
    external_ids = []
    for col, val in request.form.items():
        if col == "ids":
            continue
        try:
            # handle external id values separately, these are not named columns, they all go in external_ids
            if col.endswith("_value"):
                name = col.split("_")[0]
                value = val.strip()
                # external id values are validated against regex by the form, but the user can still click update
                if value:
                    if not re.match(db.author_ids.lookup(name, "regex"),
                                    value):
                        errmsgs.append(
                            format_input_errmsg(
                                "Invalid %s format" %
                                (db.author_ids.lookup(name, "display_name")),
                                val, name))
                    else:
                        external_ids.append(name + ":" + value)
                continue
            typ = db.users.col_type[col]
            data[col] = process_user_input(val, col, typ)
        except Exception as err:  # should only be ValueError's but let's be cautious
            errmsgs.append(format_input_errmsg(err, val, col))
    if not data.get("name"):
        errmsgs.append(
            format_errmsg(
                'Name cannot be left blank.  See the user behavior section of our <a href="'
                + url_for('policies') +
                '" target="_blank">policies</a> page for details.'))
    if errmsgs:
        return show_input_errors(errmsgs)
    data["external_ids"] = external_ids
    for k in data.keys():
        setattr(current_user, k, data[k])
    if current_user.save():
        flask.flash(Markup("Thank you for updating your details!"))
    if previous_email != current_user.email:
        if send_confirmation_email(current_user.email):
            flask.flash(Markup("New confirmation email has been sent!"))
    return redirect(url_for(".info"))
Ejemplo n.º 9
0
def save_institution():
    raw_data = request.form
    shortname = raw_data["shortname"]
    new = (raw_data.get("new") == "yes")
    resp, institution = can_edit_institution(shortname, new)
    if resp is not None:
        return resp

    data = {}
    for col in db.institutions.search_cols:
        if col in data: continue
        try:
            val = raw_data.get(col)
            if not val:
                data[col] = None
            else:
                data[col] = process_user_input(val,
                                               db.institutions.col_type[col])
            if col == 'admin':
                userdata = db.users.lookup(val)
                if userdata is None:
                    raise ValueError("%s must have account on this site" % val)
                if not userdata['phd']:
                    raise ValueError(
                        "%s must have a PhD to administer an institution" %
                        val)
            if col == 'homepage' and val and not val.startswith("http"):
                data[col] = "http://" + data[col]
            if col == "access" and val not in ["open", "users", "endorsed"]:
                raise ValueError("Invalid access type")
        except Exception as err:
            # TODO: this probably needs to be a redirect to change the URL?  We want to save the data the user entered.
            flash_error("Error processing %s: %s" % (col, err))
            institution = WebInstitution(shortname, data=raw_data)
            return render_template("edit_institution.html",
                                   institution=institution,
                                   institution_types=institution_types,
                                   timezones=timezones,
                                   title="Edit institution error",
                                   top_menu=basic_top_menu())
    new_version = WebInstitution(shortname, data=data)
    new_version.save()
    edittype = "created" if new else "edited"
    flash("Institution successfully %s!" % edittype)
    return redirect(url_for("show_institution", shortname=shortname), 301)
Ejemplo n.º 10
0
def edit_seminar():
    if request.method == "POST":
        data = request.form
    else:
        data = request.args
    shortname = data.get("shortname", "")
    new = data.get("new") == "yes"
    resp, seminar = can_edit_seminar(shortname, new)
    if resp is not None:
        return resp
    if new:
        subjects = clean_subjects(data.get("subjects"))
        if not subjects:
            return show_input_errors(
                [format_errmsg("Please select at least one subject.")])
        else:
            seminar.subjects = subjects

        seminar.is_conference = process_user_input(data.get("is_conference"),
                                                   "is_conference", "boolean",
                                                   None)
        if seminar.is_conference:
            seminar.frequency = 1
            seminar.per_day = 4
        seminar.name = data.get("name", "")
        seminar.institutions = clean_institutions(data.get("institutions"))
        if seminar.institutions:
            seminar.timezone = db.institutions.lookup(seminar.institutions[0],
                                                      "timezone")
    lock = get_lock(shortname, data.get("lock"))
    title = "Create series" if new else "Edit series"
    manage = "Manage" if current_user.is_organizer else "Create"
    return render_template(
        "edit_seminar.html",
        seminar=seminar,
        title=title,
        section=manage,
        subsection="editsem",
        institutions=institutions(),
        short_weekdays=short_weekdays,
        timezones=timezones,
        max_slots=MAX_SLOTS,
        lock=lock,
    )
Ejemplo n.º 11
0
def edit_seminar():
    if request.method == "POST":
        data = request.form
    else:
        data = request.args
    shortname = data.get("shortname", "")
    new = data.get("new") == "yes"
    resp, seminar = can_edit_seminar(shortname, new)
    if resp is not None:
        return resp
    if new:
        seminar.is_conference = process_user_input(data.get("is_conference"),
                                                   "boolean", None)
        if seminar.is_conference:
            seminar.frequency = 1
            seminar.per_day = 4
        seminar.name = data.get("name", "")
        seminar.institutions = clean_institutions(data.get("institutions"))
        if seminar.institutions:
            seminar.timezone = db.institutions.lookup(seminar.institutions[0],
                                                      "timezone")
    lock = get_lock(shortname, data.get("lock"))
    title = "conference" if seminar.is_conference else "seminar"
    title = "Create " + title if new else "Edit " + title + " properties"
    manage = "Manage" if current_user.is_organizer else "Create"
    return render_template(
        "edit_seminar.html",
        seminar=seminar,
        title=title,
        section=manage,
        subsection="editsem",
        institutions=institutions(),
        weekdays=weekdays,
        timezones=timezones,
        lock=lock,
    )
Ejemplo n.º 12
0
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
Ejemplo n.º 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
Ejemplo n.º 14
0
def save_seminar_schedule():
    raw_data = request.form
    shortname = raw_data["shortname"]
    resp, seminar = can_edit_seminar(shortname, new=False)
    if resp is not None:
        return resp
    schedule_count = int(raw_data["schedule_count"])
    update_times = bool(raw_data.get("update_times"))
    curmax = talks_max('seminar_ctr', {'seminar_id': shortname})
    if curmax is None:
        curmax = 0
    ctr = curmax + 1
    try:
        start_time = datetime.time.fromisoformat(raw_data["start_time"])
        end_time = datetime.time.fromisoformat(raw_data["end_time"])
    except ValueError as err:
        flash_error("Invalid time: %s", err)
        return redirect(url_for(".edit_seminar_schedule", shortname=shortname),
                        301)
    for i in range(schedule_count):
        seminar_ctr = raw_data.get("seminar_ctr%s" % i)
        date = datetime.date.fromisoformat(raw_data["date%s" % i])
        if seminar_ctr:
            # existing talk
            seminar_ctr = int(seminar_ctr)
            talk = WebTalk(shortname, seminar_ctr, seminar=seminar)
            data = dict(talk.__dict__)
            for col in [
                    "speaker", "speaker_affiliation", "speaker_email", "title"
            ]:
                data[col] = process_user_input(raw_data["%s%s" % (col, i)],
                                               'text')
            if update_times:
                data["start_time"] = datetime.datetime.combine(
                    date, start_time)
                data["end_time"] = datetime.datetime.combine(date, end_time)
            new_version = WebTalk(talk.seminar_id,
                                  data['seminar_ctr'],
                                  data=data)
            if new_version != talk:
                print(data)
                new_version.save()
        elif raw_data["speaker%s" % i].strip():
            # new talk
            talk = WebTalk(shortname, seminar=seminar, editing=True)
            data = dict(talk.__dict__)
            for col in [
                    "speaker", "speaker_affiliation", "speaker_email", "title"
            ]:
                data[col] = process_user_input(raw_data["%s%s" % (col, i)],
                                               'text')
            data["start_time"] = datetime.datetime.combine(date, start_time)
            data["end_time"] = datetime.datetime.combine(date, end_time)
            data["seminar_ctr"] = ctr
            ctr += 1
            new_version = WebTalk(talk.seminar_id, ctr, data=data)
            print(data)
            new_version.save()

    return redirect(url_for(".edit_seminar_schedule", shortname=shortname),
                    301)
Ejemplo n.º 15
0
def save_seminar():
    raw_data = request.form
    shortname = raw_data["shortname"]
    new = (raw_data.get("new") == "yes")
    resp, seminar = can_edit_seminar(shortname, new)
    if resp is not None:
        return resp

    def make_error(err):
        flash_error("Error processing %s: %s" % (col, err))
        seminar = WebSeminar(shortname, data=raw_data)
        return render_template("edit_seminar.html",
                               seminar=seminar,
                               title="Edit seminar error",
                               top_menu=basic_top_menu(),
                               categories=categories(),
                               institutions=institutions(),
                               lock=None)

    if seminar.new:
        data = {
            'shortname': shortname,
            'display': current_user.is_creator(),
            'owner': current_user.email,
            'archived': False
        }
    else:
        data = {
            'shortname': shortname,
            'display': seminar.display or current_user.is_creator(),
            'owner': seminar.owner
        }
    for col in db.seminars.search_cols:
        if col in data: continue
        try:
            val = raw_data.get(col)
            if not val:
                data[col] = None
            else:
                data[col] = process_user_input(val, db.seminars.col_type[col])
        except Exception as err:
            return make_error(err)
    if not data['timezone'] and data['institutions']:
        # Set time zone from institution
        data['timezone'] = WebInstitution(data['institutions'][0]).timezone
    organizer_data = []
    for i in range(6):
        D = {'seminar_id': seminar.shortname}
        for col in db.seminar_organizers.search_cols:
            if col in D: continue
            name = "org_%s%s" % (col, i)
            try:
                val = raw_data.get(name)
                if val == '':
                    D[col] = None
                elif val is None:
                    D[col] = False  # checkboxes
                else:
                    D[col] = process_user_input(
                        val, db.seminar_organizers.col_type[col])
                if col == 'homepage' and val and not val.startswith("http"):
                    data[col] = "http://" + data[col]
            except Exception as err:
                return make_error(err)
        if D.get('email') or D.get('full_name'):
            D['order'] = len(organizer_data)
            organizer_data.append(D)
    new_version = WebSeminar(shortname,
                             data=data,
                             organizer_data=organizer_data)
    if seminar.new or new_version != seminar:
        new_version.save()
    if seminar.organizer_data != new_version.organizer_data:
        new_version.save_organizers()
    edittype = "created" if new else "edited"
    flash("Seminar successfully %s!" % edittype)
    return redirect(url_for("show_seminar", shortname=shortname), 301)
Ejemplo n.º 16
0
def save_seminar_schedule():
    raw_data = request.form
    shortname = raw_data["shortname"]
    resp, seminar = can_edit_seminar(shortname, new=False)
    if resp is not None:
        return resp
    frequency = raw_data.get("frequency")
    try:
        frequency = int(frequency)
    except Exception:
        pass
    slots = int(raw_data["slots"])
    curmax = talks_max("seminar_ctr", {"seminar_id": shortname})
    if curmax is None:
        curmax = 0
    ctr = curmax + 1
    updated = 0
    warned = False
    errmsgs = []
    tz = seminar.tz
    to_save = []
    for i in list(range(slots)):
        seminar_ctr = raw_data.get("seminar_ctr%s" % i)
        speaker = process_user_input(raw_data.get("speaker%s" % i, ""),
                                     "speaker", "text", tz)
        if not speaker:
            if not warned and any(
                    raw_data.get("%s%s" % (col, i), "").strip()
                    for col in optional_cols):
                warned = True
                flash_warning("Talks are only saved if you specify a speaker")
            elif (not warned and seminar_ctr and not any(
                    raw_data.get("%s%s" % (col, i), "").strip()
                    for col in optional_cols)):
                warned = True
                flash_warning(
                    "To delete an existing talk, click Details and then click delete on the Edit talk page"
                )
            continue
        date = start_time = end_time = None
        dateval = raw_data.get("date%s" % i).strip()
        timeval = raw_data.get("time%s" % i).strip()
        if dateval and timeval:
            try:
                date = process_user_input(dateval, "date", "date", tz)
            except Exception as err:  # should only be ValueError's but let's be cautious
                errmsgs.append(format_input_errmsg(err, dateval, "date"))
            if date:
                try:
                    interval = process_user_input(timeval, "time", "daytimes",
                                                  tz)
                    start_time, end_time = date_and_daytimes_to_times(
                        date, interval, tz)
                except Exception as err:  # should only be ValueError's but let's be cautious
                    errmsgs.append(format_input_errmsg(err, timeval, "time"))
        if not date or not start_time or not end_time:
            errmsgs.append(
                format_errmsg(
                    "You must specify a date and time for the talk by %s",
                    speaker))

        # we need to flag date and time errors before we go any further
        if errmsgs:
            return show_input_errors(errmsgs)

        if daytimes_early(interval):
            flash_warning(
                "Talk for speaker %s includes early AM hours, please correct if this is not intended (use 24-hour time format).",
                speaker,
            )
        elif daytimes_long(interval) > 8 * 60:
            flash_warning(
                "Time s %s is longer than 8 hours, please correct if this is not intended.",
                speaker),

        if seminar_ctr:
            # existing talk
            seminar_ctr = int(seminar_ctr)
            talk = WebTalk(shortname, seminar_ctr, seminar=seminar)
        else:
            # new talk
            talk = WebTalk(shortname, seminar=seminar, editing=True)

        data = dict(talk.__dict__)
        data["speaker"] = speaker
        data["start_time"] = start_time
        data["end_time"] = end_time

        for col in optional_cols:
            typ = db.talks.col_type[col]
            try:
                val = raw_data.get("%s%s" % (col, i), "")
                data[
                    col] = None  # make sure col is present even if process_user_input fails
                data[col] = process_user_input(val, col, typ, tz)
            except Exception as err:
                errmsgs.append(format_input_errmsg(err, val, col))

        # Don't try to create new_version using invalid input
        if errmsgs:
            return show_input_errors(errmsgs)

        if seminar_ctr:
            new_version = WebTalk(talk.seminar_id, data=data)
            if new_version != talk:
                updated += 1
                to_save.append(
                    new_version)  # defer save in case of errors on other talks
        else:
            data["seminar_ctr"] = ctr
            ctr += 1
            new_version = WebTalk(talk.seminar_id, data=data)
            to_save.append(
                new_version)  # defer save in case of errors on other talks

    for newver in to_save:
        newver.save()

    if raw_data.get("detailctr"):
        return redirect(
            url_for(
                ".edit_talk",
                seminar_id=shortname,
                seminar_ctr=int(raw_data.get("detailctr")),
            ),
            302,
        )
    else:
        flash("%s talks updated, %s talks created" %
              (updated, ctr - curmax - 1))
        if warned:
            return redirect(url_for(".edit_seminar_schedule", **raw_data), 302)
        else:
            return redirect(
                url_for(
                    ".edit_seminar_schedule",
                    shortname=shortname,
                    begin=raw_data.get("begin"),
                    end=raw_data.get("end"),
                    frequency=raw_data.get("frequency"),
                    weekday=raw_data.get("weekday"),
                ),
                302,
            )
Ejemplo n.º 17
0
def save_seminar():
    raw_data = request.form
    shortname = raw_data["shortname"]
    new = raw_data.get("new") == "yes"
    resp, seminar = can_edit_seminar(shortname, new)
    if resp is not None:
        return resp

    def make_error(shortname, col=None, err=None):
        if err is not None:
            flash_error("Error processing %s: {0}".format(err), col)
        seminar = WebSeminar(shortname, data=raw_data)
        manage = "Manage" if current_user.is_organizer else "Create"
        return render_template(
            "edit_seminar.html",
            seminar=seminar,
            title="Edit seminar error",
            section=manage,
            institutions=institutions(),
            lock=None,
        )

    if seminar.new:
        data = {
            "shortname": shortname,
            "display": current_user.is_creator,
            "owner": current_user.email,
            "archived": False,
        }
    else:
        data = {
            "shortname": shortname,
            "display": seminar.display,
            "owner": seminar.owner,
        }
    # Have to get time zone first
    data["timezone"] = tz = raw_data.get("timezone")
    tz = pytz.timezone(tz)

    def replace(a):
        if a == "timestamp with time zone":
            return "time"
        return a

    for col in db.seminars.search_cols:
        if col in data:
            continue
        try:
            val = raw_data.get(col)
            if not val:
                data[col] = None
            else:
                data[col] = process_user_input(val,
                                               replace(
                                                   db.seminars.col_type[col]),
                                               tz=tz)
        except Exception as err:
            return make_error(shortname, col, err)
    data["institutions"] = clean_institutions(data.get("institutions"))
    data["topics"] = clean_topics(data.get("topics"))
    data["language"] = clean_language(data.get("language"))
    if not data["timezone"] and data["institutions"]:
        # Set time zone from institution
        data["timezone"] = WebInstitution(data["institutions"][0]).timezone
    organizer_data = []
    for i in range(10):
        D = {"seminar_id": seminar.shortname}
        for col in db.seminar_organizers.search_cols:
            if col in D:
                continue
            name = "org_%s%s" % (col, i)
            try:
                val = raw_data.get(name)
                if val == "":
                    D[col] = None
                elif val is None:
                    D[col] = False  # checkboxes
                else:
                    D[col] = process_user_input(
                        val, db.seminar_organizers.col_type[col], tz=tz)
                # if col == 'homepage' and val and not val.startswith("http"):
                #     D[col] = "http://" + data[col]
            except Exception as err:
                return make_error(shortname, col, err)
        if D.get("email") or D.get("full_name"):
            D["order"] = len(organizer_data)
            ####### HOT FIX ####################
            # WARNING the header on the template
            # says organizer and we have agreed
            # that one is either an organizer or
            # a curator
            D["curator"] = not D["curator"]
            organizer_data.append(D)
    new_version = WebSeminar(shortname,
                             data=data,
                             organizer_data=organizer_data)
    if check_time(new_version.start_time, new_version.end_time):
        return make_error(shortname)
    if seminar.new or new_version != seminar:
        new_version.save()
        edittype = "created" if new else "edited"
        flash("Seminar %s successfully!" % edittype)
    elif seminar.organizer_data == new_version.organizer_data:
        flash("No changes made to seminar.")
    if seminar.new or seminar.organizer_data != new_version.organizer_data:
        new_version.save_organizers()
        if not seminar.new:
            flash("Seminar organizers updated!")
    return redirect(url_for(".edit_seminar", shortname=shortname), 301)
Ejemplo n.º 18
0
def save_talk():
    raw_data = request.form
    token = raw_data.get("token", "")
    resp, talk = can_edit_talk(raw_data.get("seminar_id", ""),
                               raw_data.get("seminar_ctr", ""), token)
    if resp is not None:
        return resp
    errmsgs = []

    data = {
        "seminar_id": talk.seminar_id,
        "token": talk.token,
        "display": talk.display,  # could be being edited by anonymous user
    }
    if talk.new:
        curmax = talks_max("seminar_ctr", {"seminar_id": talk.seminar_id},
                           include_deleted=True)
        if curmax is None:
            curmax = 0
        data["seminar_ctr"] = curmax + 1
    else:
        data["seminar_ctr"] = talk.seminar_ctr
    default_tz = talk.seminar.timezone
    if not default_tz:
        default_tz = "UTC"
    data["timezone"] = tz = raw_data.get("timezone", default_tz)
    tz = pytz.timezone(tz)
    for col in db.talks.search_cols:
        if col in data:
            continue
        typ = db.talks.col_type[col]
        try:
            val = raw_data.get(col, "")
            data[
                col] = None  # make sure col is present even if process_user_input fails
            data[col] = process_user_input(val, col, typ, tz)
            if col == "access" and data[col] not in [
                    "open", "users", "endorsed"
            ]:
                errmsgs.append(
                    format_errmsg("Access type %s invalid", data[col]))
        except Exception as err:  # should only be ValueError's but let's be cautious
            errmsgs.append(format_input_errmsg(err, val, col))
    if not data["speaker"]:
        errmsgs.append(
            "Speaker name cannot be blank -- use TBA if speaker not chosen.")
    if data["start_time"] is None or data["end_time"] is None:
        errmsgs.append("Talks must have both a start and end time.")
    data["topics"] = clean_topics(data.get("topics"))
    data["language"] = clean_language(data.get("language"))
    data["subjects"] = clean_subjects(data.get("subjects"))
    if not data["subjects"]:
        errmsgs.append("Please select at least one subject")

    # Don't try to create new_version using invalid input
    if errmsgs:
        return show_input_errors(errmsgs)
    else:  # to make it obvious that these two statements should be together
        new_version = WebTalk(talk.seminar_id, data=data)

    # Warnings
    sanity_check_times(new_version.start_time, new_version.end_time)
    if "zoom" in data["video_link"] and not "rec" in data["video_link"]:
        flash_warning(
            "Recorded video link should not be used for Zoom meeting links; be sure to use Livestream link for meeting links."
        )
    if not data["topics"]:
        flash_warning(
            "This talk has no topics, and thus will only be visible to users when they disable their topics filter."
        )
    if new_version == talk:
        flash("No changes made to talk.")
    else:
        new_version.save()
        edittype = "created" if talk.new else "edited"
        flash("Talk successfully %s!" % edittype)
    edit_kwds = dict(seminar_id=new_version.seminar_id,
                     seminar_ctr=new_version.seminar_ctr)
    if token:
        edit_kwds["token"] = token
    else:
        edit_kwds.pop("token", None)
    return redirect(url_for(".edit_talk", **edit_kwds), 302)
Ejemplo n.º 19
0
def save_talk():
    raw_data = request.form
    token = raw_data.get("token", "")
    resp, talk = can_edit_talk(raw_data.get("seminar_id", ""),
                               raw_data.get("seminar_ctr", ""), token)
    if resp is not None:
        return resp

    def make_error(talk, col=None, err=None):
        if err is not None:
            flash_error("Error processing %s: {0}".format(err), col)
        talk = WebTalk(talk.seminar_id, talk.seminar_ctr, data=raw_data)
        title = "Create talk error" if talk.new else "Edit talk error"
        return render_template(
            "edit_talk.html",
            talk=talk,
            seminar=talk.seminar,
            title=title,
            section="Manage",
            subsection="edittalk",
            institutions=institutions(),
            timezones=timezones,
        )

    data = {
        "seminar_id": talk.seminar_id,
        "token": talk.token,
        "display": talk.display,  # could be being edited by anonymous user
    }
    if talk.new:
        curmax = talks_max("seminar_ctr", {"seminar_id": talk.seminar_id})
        if curmax is None:
            curmax = 0
        data["seminar_ctr"] = curmax + 1
    else:
        data["seminar_ctr"] = talk.seminar_ctr
    default_tz = talk.seminar.timezone
    if not default_tz:
        default_tz = "UTC"
    data["timezone"] = tz = raw_data.get("timezone", default_tz)
    tz = pytz.timezone(tz)
    for col in db.talks.search_cols:
        if col in data:
            continue
        try:
            val = raw_data.get(col, "").strip()
            if not val:
                data[col] = None
            else:
                data[col] = process_user_input(val,
                                               db.talks.col_type[col],
                                               tz=tz)
            if col == "speaker_homepage" and val and not val.startswith(
                    "http"):
                data[col] = "http://" + data[col]
            if col == "access" and val not in ["open", "users", "endorsed"]:
                raise ValueError("Invalid access type")
        except Exception as err:
            return make_error(talk, col, err)
    data["topics"] = clean_topics(data.get("topics"))
    data["language"] = clean_language(data.get("language"))
    new_version = WebTalk(talk.seminar_id, data["seminar_ctr"], data=data)
    if check_time(new_version.start_time,
                  new_version.end_time,
                  check_past=True):
        return make_error(talk)
    if new_version == talk:
        flash("No changes made to talk.")
    else:
        new_version.save()
        edittype = "created" if talk.new else "edited"
        flash("Talk successfully %s!" % edittype)
    edit_kwds = dict(seminar_id=new_version.seminar_id,
                     seminar_ctr=new_version.seminar_ctr)
    if token:
        edit_kwds["token"] = token
    else:
        edit_kwds.pop("token", None)
    return redirect(url_for(".edit_talk", **edit_kwds), 301)
Ejemplo n.º 20
0
def save_institution():
    raw_data = request.form
    shortname = raw_data["shortname"]
    new = raw_data.get("new") == "yes"
    resp, institution = can_edit_institution(shortname, new)
    if resp is not None:
        return resp

    data = {}
    data["timezone"] = tz = raw_data.get("timezone", "UTC")
    tz = pytz.timezone(tz)
    errmsgs = []
    for col in db.institutions.search_cols:
        if col in data:
            continue
        typ = db.institutions.col_type[col]
        try:
            val = raw_data.get(col, "")
            data[
                col] = None  # make sure col is present even if process_user_input fails
            data[col] = process_user_input(val, col, typ, tz)
            if col == "admin":
                userdata = userdb.lookup(data[col])
                if userdata is None:
                    if not data[col]:
                        errmsgs.append(
                            "You must specify the email address of the maintainer."
                        )
                        continue
                    else:
                        errmsgs.append(
                            format_errmsg(
                                "User %s does not have an account on this site",
                                data[col]))
                        continue
                elif not userdata["creator"]:
                    errmsgs.append(
                        format_errmsg("User %s has not been endorsed",
                                      data[col]))
                    continue
                if not userdata["homepage"]:
                    if current_user.email == userdata["email"]:
                        flash_warning(
                            "Your email address will become public if you do not set your homepage in your user profile."
                        )
                    else:
                        flash_warning(
                            "The email address %s of maintainer %s will be publicly visible.<br>%s",
                            userdata["email"],
                            userdata["name"],
                            "The homepage on the maintainer's user account should be set prevent this.",
                        )
        except Exception as err:  # should only be ValueError's but let's be cautious
            errmsgs.append(format_input_errmsg(err, val, col))
    if not data["name"]:
        errmsgs.append("Institution name cannot be blank.")
    if not errmsgs and not data["homepage"]:
        errmsgs.append("Institution homepage cannot be blank.")
    # Don't try to create new_version using invalid input
    if errmsgs:
        return show_input_errors(errmsgs)
    new_version = WebInstitution(shortname, data=data)
    if new_version == institution:
        flash("No changes made to institution.")
    else:
        new_version.save()
        edittype = "created" if new else "edited"
        flash("Institution %s successfully!" % edittype)
    return redirect(url_for(".edit_institution", shortname=shortname), 302)
Ejemplo n.º 21
0
def save_seminar():
    raw_data = request.form
    shortname = raw_data["shortname"]
    new = raw_data.get("new") == "yes"
    resp, seminar = can_edit_seminar(shortname, new)
    if resp is not None:
        return resp
    errmsgs = []

    if seminar.new:
        data = {
            "shortname": shortname,
            "display": current_user.is_creator,
            "owner": current_user.email,
        }
    else:
        data = {
            "shortname": shortname,
            "display": seminar.display,
            "owner": seminar.owner,
        }
    # Have to get time zone first
    data["timezone"] = tz = raw_data.get("timezone")
    tz = pytz.timezone(tz)
    for col in db.seminars.search_cols:
        if col in data:
            continue
        typ = db.seminars.col_type[col]
        ### Hack to be removed ###
        if col.endswith("time") and typ == "timestamp with time zone":
            typ = "time"
        try:
            val = raw_data.get(col, "")
            data[
                col] = None  # make sure col is present even if process_user_input fails
            data[col] = process_user_input(val, col, typ, tz)
        except Exception as err:  # should only be ValueError's but let's be cautious
            errmsgs.append(format_input_errmsg(err, val, col))
    if not data["name"]:
        errmsgs.append("The name cannot be blank")
    if data["is_conference"] and data["start_date"] and data[
            "end_date"] and data["end_date"] < data["start_date"]:
        errmsgs.append("End date cannot precede start date")
    if data["per_day"] is not None and data["per_day"] < 1:
        errmsgs.append(
            format_input_errmsg("integer must be positive", data["per_day"],
                                "per_day"))
    if data["is_conference"] and (not data["start_date"]
                                  or not data["end_date"]):
        errmsgs.append(
            "Please specify the start and end dates of your conference (you can change these later if needed)."
        )

    if data["is_conference"] and not data["per_day"]:
        flash_warning(
            "It will be easier to edit the conference schedule if you specify talks per day (an upper bound is fine)."
        )

    data["institutions"] = clean_institutions(data.get("institutions"))
    data["topics"] = clean_topics(data.get("topics"))
    data["language"] = clean_language(data.get("language"))
    data["subjects"] = clean_subjects(data.get("subjects"))
    if not data["subjects"]:
        errmsgs.append(format_errmsg("Please select at least one subject."))
    if not data["timezone"] and data["institutions"]:
        # Set time zone from institution
        data["timezone"] = WebInstitution(data["institutions"][0]).timezone
    data["weekdays"] = []
    data["time_slots"] = []
    for i in range(MAX_SLOTS):
        weekday = daytimes = None
        try:
            col = "weekday" + str(i)
            val = raw_data.get(col, "")
            weekday = process_user_input(val, col, "weekday_number", tz)
            col = "time_slot" + str(i)
            val = raw_data.get(col, "")
            daytimes = process_user_input(val, col, "daytimes", tz)
        except Exception as err:  # should only be ValueError's but let's be cautious
            errmsgs.append(format_input_errmsg(err, val, col))
        if weekday is not None and daytimes is not None:
            data["weekdays"].append(weekday)
            data["time_slots"].append(daytimes)
            if daytimes_early(daytimes):
                flash_warning(
                    "Time slot %s includes early AM hours, please correct if this is not intended (use 24-hour time format).",
                    daytimes,
                )
            elif daytimes_long(daytimes):
                flash_warning(
                    "Time slot %s is longer than 8 hours, please correct if this is not intended.",
                    daytimes,
                )
    if data["frequency"] and not data["weekdays"]:
        errmsgs.append(
            'You must specify at least one time slot (or set periodicty to "no fixed schedule").'
        )
    if len(data["weekdays"]) > 1:
        x = sorted(
            list(zip(data["weekdays"], data["time_slots"])),
            key=lambda t: t[0] * 24 * 60 + daytime_minutes(t[1].split("-")[0]),
        )
        data["weekdays"], data["time_slots"] = [t[0]
                                                for t in x], [t[1] for t in x]
    organizer_data = []
    contact_count = 0
    for i in range(10):
        D = {"seminar_id": seminar.shortname}
        for col in db.seminar_organizers.search_cols:
            if col in D:
                continue
            name = "org_%s%s" % (col, i)
            typ = db.seminar_organizers.col_type[col]
            try:
                val = raw_data.get(name, "")
                D[col] = None  # make sure col is present even if process_user_input fails
                D[col] = process_user_input(val, col, typ, tz)
            except Exception as err:  # should only be ValueError's but let's be cautious
                errmsgs.append(format_input_errmsg(err, val, col))
        if D["homepage"] or D["email"] or D["full_name"]:
            if not D["full_name"]:
                errmsgs.append(
                    format_errmsg("Organizer name cannot be left blank"))
            D["order"] = len(organizer_data)
            # WARNING the header on the template says organizer
            # but it sets the database column curator, so the
            # boolean needs to be inverted
            D["curator"] = not D["curator"]
            if not errmsgs and D["display"] and D[
                    "email"] and not D["homepage"]:
                flash_warning(
                    "The email address %s of organizer %s will be publicly visible.<br>%s",
                    D["email"],
                    D["full_name"],
                    "Set homepage or disable display to prevent this.",
                ),
            if D["email"]:
                r = db.users.lookup(D["email"])
                if r and r["email_confirmed"]:
                    if D["full_name"] != r["name"]:
                        errmsgs.append(
                            format_errmsg(
                                "Organizer name %s does not match the name %s of the account with email address %s",
                                D["full_name"],
                                r["name"],
                                D["email"],
                            ))
                    else:
                        if D["homepage"] and r[
                                "homepage"] and D["homepage"] != r["homepage"]:
                            flash_warning(
                                "The homepage %s does not match the homepage %s of the account with email address %s, please correct if unintended.",
                                D["homepage"],
                                r["homepage"],
                                D["email"],
                            )
                        if D["display"]:
                            contact_count += 1

            organizer_data.append(D)
    if contact_count == 0:
        errmsgs.append(
            format_errmsg(
                "There must be at least one displayed organizer or curator with a %s so that there is a contact for this listing.<br>%s<br>%s",
                "confirmed email",
                "This email will not be visible if homepage is set or display is not checked, it is used only to identify the organizer's account.",
                "If none of the organizers has a confirmed account, add yourself and leave the organizer box unchecked.",
            ))
    # Don't try to create new_version using invalid input
    if errmsgs:
        return show_input_errors(errmsgs)
    else:  # to make it obvious that these two statements should be together
        new_version = WebSeminar(shortname,
                                 data=data,
                                 organizer_data=organizer_data)

    # Warnings
    sanity_check_times(new_version.start_time, new_version.end_time)
    if not data["topics"]:
        flash_warning(
            "This series has no topics selected; don't forget to set the topics for each new talk individually."
        )
    if seminar.new or new_version != seminar:
        new_version.save()
        edittype = "created" if new else "edited"
        flash("Series %s successfully!" % edittype)
    elif seminar.organizer_data == new_version.organizer_data:
        flash("No changes made to series.")
    if seminar.new or seminar.organizer_data != new_version.organizer_data:
        new_version.save_organizers()
        if not seminar.new:
            flash("Series organizers updated!")
    return redirect(url_for(".edit_seminar", shortname=shortname), 302)
Ejemplo n.º 22
0
def save_seminar_schedule():
    raw_data = request.form
    shortname = raw_data["shortname"]
    resp, seminar = can_edit_seminar(shortname, new=False)
    if resp is not None:
        return resp
    frequency = raw_data.get("frequency")
    try:
        frequency = int(frequency)
    except Exception:
        pass
    schedule_count = int(raw_data["schedule_count"])
    # FIXME not being used
    # update_times = bool(raw_data.get("update_times"))
    curmax = talks_max("seminar_ctr", {"seminar_id": shortname})
    if curmax is None:
        curmax = 0
    ctr = curmax + 1
    updated = 0
    warned = False
    for i in list(range(schedule_count)):
        seminar_ctr = raw_data.get("seminar_ctr%s" % i)
        speaker = process_user_input(raw_data.get("speaker%s" % i, ""),
                                     "text",
                                     tz=seminar.timezone)
        if not speaker:
            if not warned and any(
                    raw_data.get("%s%s" % (col, i), "").strip()
                    for col in optional_cols):
                warned = True
                flash_warning("Talks are only saved if you specify a speaker")
            continue
        date = raw_data.get("date%s" % i).strip()
        if date:
            try:
                date = process_user_input(date, "date", tz=seminar.tz)
            except ValueError as err:
                flash_error("invalid date %s: {0}".format(err), date)
                redirect(
                    url_for(".edit_seminar_schedule",
                            shortname=shortname,
                            **raw_data), 301)
        else:
            date = None
        time_input = raw_data.get("time%s" % i, "").strip()
        if time_input:
            try:
                time_split = time_input.split("-")
                if len(time_split) == 1:
                    raise ValueError("Must specify both start and end times")
                elif len(time_split) > 2:
                    raise ValueError("More than one hyphen")
                # TODO: clean this up
                start_time = process_user_input(time_split[0], "time",
                                                seminar.tz).time()
                end_time = process_user_input(time_split[1], "time",
                                              seminar.tz).time()
                if check_time(start_time, end_time):
                    raise ValueError
            except ValueError as err:
                if str(err):
                    flash_error("invalid time range %s: {0}".format(err),
                                time_input)
                return redirect(url_for(".edit_seminar_schedule", **raw_data),
                                301)
        else:
            start_time = end_time = None
        if any(X is None for X in [start_time, end_time, date]):
            flash_error("You must give a date, start and end time for %s" %
                        speaker)
            return redirect(url_for(".edit_seminar_schedule", **raw_data), 301)
        if seminar_ctr:
            # existing talk
            seminar_ctr = int(seminar_ctr)
            talk = WebTalk(shortname, seminar_ctr, seminar=seminar)
        else:
            # new talk
            talk = WebTalk(shortname, seminar=seminar, editing=True)
        data = dict(talk.__dict__)
        data["speaker"] = speaker
        for col in optional_cols:
            data[col] = process_user_input(raw_data.get("%s%s" % (col, i), ""),
                                           "text",
                                           tz=seminar.timezone)
        data["start_time"] = localize_time(
            datetime.datetime.combine(date, start_time), seminar.tz)
        data["end_time"] = localize_time(
            datetime.datetime.combine(date, end_time), seminar.tz)
        if seminar_ctr:
            new_version = WebTalk(talk.seminar_id,
                                  data["seminar_ctr"],
                                  data=data)
            if new_version != talk:
                updated += 1
                new_version.save()
        else:
            data["seminar_ctr"] = ctr
            ctr += 1
            new_version = WebTalk(talk.seminar_id, ctr, data=data)
            new_version.save()

    if raw_data.get("detailctr"):
        return redirect(
            url_for(
                ".edit_talk",
                seminar_id=shortname,
                seminar_ctr=int(raw_data.get("detailctr")),
            ),
            301,
        )
    else:
        if updated or ctr > curmax + 1:
            flash("%s talks updated, %s talks created" %
                  (updated, ctr - curmax - 1))
        if warned:
            return redirect(url_for(".edit_seminar_schedule", **raw_data), 301)
        else:
            return redirect(
                url_for(".edit_seminar_schedule",
                        shortname=shortname,
                        begin=raw_data.get('begin'),
                        end=raw_data.get('end'),
                        frequency=raw_data.get('frequency'),
                        weekday=raw_data.get('weekday')), 301)