Esempio n. 1
0
def delete_seminar(shortname):
    try:
        seminar = WebSeminar(shortname)
    except ValueError as err:
        flash_error(str(err))
        return redirect(url_for(".index"), 302)
    manage = "Manage" if current_user.is_organizer else "Create"
    lock = get_lock(shortname, request.args.get("lock"))

    def failure():
        return render_template(
            "edit_seminar.html",
            seminar=seminar,
            title="Edit properties",
            section=manage,
            subsection="editsem",
            institutions=institutions(),
            weekdays=weekdays,
            timezones=timezones,
            lock=lock,
        )

    if not seminar or not seminar.user_can_delete():
        flash_error("Only the owner of the seminar can delete it")
        return failure()
    else:
        if seminar.delete():
            flash("Series deleted")
            return redirect(url_for(".deleted_seminar", shortname=shortname),
                            302)
        else:
            flash_error("Only the owner of the seminar can delete it")
            return failure()
Esempio n. 2
0
 def __init__(self, semid=None, semctr=None, data=None, seminar=None, editing=False, showing=False, saving=False):
     if data is None and not editing:
         data = talks_lookup(semid, semctr)
         if data is None:
             raise ValueError("Talk %s/%s does not exist" % (semid, semctr))
         data = dict(data.__dict__)
     if seminar is None:
         seminar = WebSeminar(semid)
     self.seminar = seminar
     self.new = (data is None)
     if self.new:
         self.seminar_id = semid
         self.seminar_ctr = None
         self.token = '%016x' % random.randrange(16**16)
         self.display = current_user.is_creator()
         self.online = getattr(seminar, 'online', bool(getattr(seminar, 'live_link')))
         self.deleted=False
         for key, typ in db.talks.col_type.items():
             if key == 'id' or hasattr(self, key):
                 continue
             elif db.seminars.col_type.get(key) == typ and getattr(seminar, key, None) and key != "description":
                 # carry over from seminar
                 setattr(self, key, getattr(seminar, key))
             elif typ == 'text':
                 setattr(self, key, '')
             elif typ == 'text[]':
                 setattr(self, key, [])
             elif typ == 'timestamp with time zone':
                 setattr(self, key, None)
             else:
                 raise ValueError("Need to update talk code to account for schema change")
     else:
         self.__dict__.update(data)
Esempio n. 3
0
 def __init__(
     self,
     seminar_id=None,
     seminar_ctr=None,
     data=None,
     seminar=None,
     editing=False,
     include_deleted=False,
     include_pending=False,
 ):
     if data is None and not editing:
         data = talks_lookup(seminar_id, seminar_ctr, include_deleted=include_deleted, include_pending=include_pending)
         if data is None:
             raise ValueError("Talk %s/%s does not exist" % (seminar_id, seminar_ctr))
         data = dict(data.__dict__)
     elif data is not None:
         data = dict(data)
         # avoid Nones
         if data.get("topics") is None:
             data["topics"] = []
     if data and data.get("deleted"):
         include_deleted = True
     if seminar is None:
         seminar = WebSeminar(seminar_id, include_deleted=include_deleted)
     self.seminar = seminar
     self.new = data is None
     if self.new:
         self.seminar_id = seminar_id
         self.seminar_ctr = None
         self.token = secrets.token_hex(8)
         self.by_api = False # reset by API code if needed
         self.timezone = seminar.timezone
         self.deleted = False
         self.deleted_with_seminar = False
         self.hidden = False
         for key, typ in db.talks.col_type.items():
             if key == "id" or hasattr(self, key):
                 continue
             if key in inherited_talk_columns:
                 setattr(self, key, getattr(seminar, key))
             elif typ == "text":
                 setattr(self, key, "")
             elif typ == "text[]":
                 setattr(self, key, [])
             else:
                 # don't complain about columns we know are going to be set later
                 if not key in ["edited_by", "edited_at", "start_time", "end_time"]:
                     critical("Need to update talk code to account for schema change key=%s" % key)
                 setattr(self, key, None)
     else:
         # The output from psycopg2 seems to always be given in the server's time zone
         if data.get("timezone"):
             tz = pytz.timezone(data["timezone"])
             if data.get("start_time"):
                 data["start_time"] = adapt_datetime(data["start_time"], tz)
             if data.get("end_time"):
                 data["end_time"] = adapt_datetime(data["end_time"], tz)
         self.__dict__.update(data)
         self.cleanse()
Esempio n. 4
0
 def __init__(
     self,
     semid=None,
     semctr=None,
     data=None,
     seminar=None,
     editing=False,
     showing=False,
     saving=False,
     deleted=False,
 ):
     if data is None and not editing:
         data = talks_lookup(semid, semctr, include_deleted=deleted)
         if data is None:
             raise ValueError("Talk %s/%s does not exist" % (semid, semctr))
         data = dict(data.__dict__)
     elif data is not None:
         data = dict(data)
         # avoid Nones
         if data.get("topics") is None:
             data["topics"] = []
     if seminar is None:
         seminar = WebSeminar(semid, deleted=deleted)
     self.seminar = seminar
     self.new = data is None
     self.deleted=False
     if self.new:
         self.seminar_id = semid
         self.seminar_ctr = None
         self.token = "%016x" % random.randrange(16 ** 16)
         self.display = seminar.display
         self.online = getattr(seminar, "online", bool(seminar.live_link))
         self.timezone = seminar.timezone
         for key, typ in db.talks.col_type.items():
             if key == "id" or hasattr(self, key):
                 continue
             elif db.seminars.col_type.get(key) == typ and getattr(seminar, key, None):
                 # carry over from seminar, but not comments
                 setattr(self, key, getattr(seminar, key) if key != "comments" else "")
             elif typ == "text":
                 setattr(self, key, "")
             elif typ == "text[]":
                 setattr(self, key, [])
             else:
                 critical("Need to update talk code to account for schema change key=%s" % key)
                 setattr(self, key, None)
     else:
         # The output from psycopg2 seems to always be given in the server's time zone
         if data.get("timezone"):
             tz = pytz.timezone(data["timezone"])
             if data.get("start_time"):
                 data["start_time"] = adapt_datetime(data["start_time"], tz)
             if data.get("end_time"):
                 data["end_time"] = adapt_datetime(data["end_time"], tz)
         # transition to topics including the subject
         if data.get("topics"):
             data["topics"] = [(topic if "_" in topic else "math_" + topic) for topic in data["topics"]]
         self.__dict__.update(data)
Esempio n. 5
0
def deleted_seminar(shortname):
    try:
        seminar = WebSeminar(shortname, deleted=True)
    except ValueError as err:
        flash_error(str(err))
        return redirect(url_for(".index"), 302)
    return render_template("deleted_seminar.html",
                           seminar=seminar,
                           title="Deleted")
Esempio n. 6
0
 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)
Esempio n. 7
0
 def seminars(self):
     ans = []
     for elt in self.seminar_subscriptions:
         try:
             ans.append(WebSeminar(elt))
         except ValueError:
             self._data["seminar_subscriptions"].remove(elt)
             self._dirty = True
     if self._dirty:
         self.save()
     return ans
Esempio n. 8
0
 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,
     )
Esempio n. 9
0
def index():
    # TODO: use a join for the following query
    seminars = []
    conferences = []
    for semid in db.seminar_organizers.search({'email': current_user.email},
                                              'seminar_id'):
        seminar = WebSeminar(semid)
        if seminar.is_conference:
            conferences.append(seminar)
        else:
            seminars.append(seminar)
    menu = basic_top_menu()
    menu.pop(-3)
    return render_template("create_index.html",
                           seminars=seminars,
                           conferences=conferences,
                           top_menu=menu,
                           title="Create",
                           user_is_creator=current_user.is_creator())
Esempio n. 10
0
def index():
    # TODO: use a join for the following query
    seminars = []
    conferences = []
    for semid in db.seminar_organizers.search({"email": current_user.email},
                                              "seminar_id"):
        seminar = WebSeminar(semid)
        if seminar.is_conference:
            conferences.append(seminar)
        else:
            seminars.append(seminar)
    manage = "Manage" if current_user.is_organizer else "Create"
    return render_template(
        "create_index.html",
        seminars=seminars,
        conferences=conferences,
        institution_known=institution_known,
        institutions=institutions(),
        section=manage,
        subsection="home",
        title=manage,
        user_is_creator=current_user.is_creator,
    )
Esempio n. 11
0
 def __init__(
     self,
     seminar_id=None,
     seminar_ctr=None,
     data=None,
     seminar=None,
     editing=False,
     showing=False,
     saving=False,
     deleted=False,
 ):
     if data is None and not editing:
         data = talks_lookup(seminar_id,
                             seminar_ctr,
                             include_deleted=deleted)
         if data is None:
             raise ValueError("Talk %s/%s does not exist" %
                              (seminar_id, seminar_ctr))
         data = dict(data.__dict__)
     elif data is not None:
         data = dict(data)
         # avoid Nones
         if data.get("topics") is None:
             data["topics"] = []
     if data and data.get("deleted"):
         deleted = True
     if seminar is None:
         seminar = WebSeminar(seminar_id, deleted=deleted)
     self.seminar = seminar
     self.new = data is None
     self.deleted = False
     if self.new:
         self.seminar_id = seminar_id
         self.seminar_ctr = None
         self.token = secrets.token_hex(8)
         self.display = seminar.display
         self.online = getattr(seminar, "online", bool(seminar.live_link))
         self.by_api = False  # reset by API code if needed
         self.timezone = seminar.timezone
         for key, typ in db.talks.col_type.items():
             if key == "id" or hasattr(self, key):
                 continue
             elif db.seminars.col_type.get(key) == typ and getattr(
                     seminar, key, None):
                 # carry over from seminar, but not comments
                 setattr(self, key,
                         getattr(seminar, key) if key != "comments" else "")
                 print("talk inherited %s = %s from seminar" %
                       (key, getattr(self, key)))
             elif typ == "text":
                 setattr(self, key, "")
             elif typ == "text[]":
                 setattr(self, key, [])
             else:
                 critical(
                     "Need to update talk code to account for schema change key=%s"
                     % key)
                 setattr(self, key, None)
     else:
         # The output from psycopg2 seems to always be given in the server's time zone
         if data.get("timezone"):
             tz = pytz.timezone(data["timezone"])
             if data.get("start_time"):
                 data["start_time"] = adapt_datetime(data["start_time"], tz)
             if data.get("end_time"):
                 data["end_time"] = adapt_datetime(data["end_time"], tz)
         self.__dict__.update(data)
     self.cleanse()
Esempio n. 12
0
def save_series(version=0, user=None):
    if version != 0:
        raise version_error(version)
    try:
        raw_data = get_request_json()
    except Exception:
        raw_data = None
    if not isinstance(raw_data, dict):
        raise APIError({
            "code": "invalid_json",
            "description": "request must contain a json dictionary"
        })
    # Temporary measure while we rename shortname
    series_id = raw_data.pop("series_id", None)
    raw_data["shortname"] = series_id
    if series_id is None:
        raise APIError({
            "code":
            "unspecified_series_id",
            "description":
            "You must specify series_id when saving a series"
        })
    series = seminars_lookup(series_id, include_deleted=True)
    if series is None:
        # Creating new series
        if not allowed_shortname(
                series_id) or len(series_id) < 3 or len(series_id) > 32:
            raise APIError({
                "code":
                "invalid_series_id",
                "description":
                "The identifier must be 3 to 32 characters in length and can include only letters, numbers, hyphens and underscores."
            })
        if "organizers" not in raw_data:
            raise APIError({
                "code":
                "organizers_required",
                "description":
                "You must specify organizers when creating new series"
            })
        update_organizers = True
        series = WebSeminar(series_id, data=None, editing=True, user=user)
    else:
        # Make sure user has permission to edit
        if not series.user_can_edit(user):
            raise APIError(
                {
                    "code":
                    "unauthorized_user",
                    "description":
                    "You do not have permission to edit %s." % series_id
                }, 401)
        if series.deleted:
            raise APIError({
                "code":
                "norevive",
                "description":
                "You cannot revive a series through the API"
            })
        if "organizers" in raw_data:
            raise APIError({
                "code":
                "organizers_prohibited",
                "description":
                "You may not specify organizers when editing series"
            })
        update_organizers = False
    # Check that there aren't extraneous keys (which might be misspelled)
    extra_keys = [
        key for key in raw_data
        if key not in db.seminars.search_cols + ["slots", "organizers"]
    ]
    if extra_keys:
        raise APIError({
            "code": "extra_keys",
            "description": "Unrecognized keys",
            "errors": extra_keys
        })
    # Time slots/weekdays and organizers are handled differently by the processing code
    # We want to allow them to be unspecified (in which case we fall back on the current value)
    # and for an API call it's also more convenient to specify them using a list
    if "slots" in raw_data:
        slots = raw_data["slots"]
    else:
        slots = [
            short_weekdays[day] + " " + slot
            for (day, slot) in zip(series.weekdays, series.time_slots)
        ]
    if not isinstance(slots, list) or len(slots) > MAX_SLOTS or not all(
            isinstance(slot, str) for slot in slots):
        raise APIError({
            "code":
            "processing_error",
            "description":
            "Error in processing slots",
            "errors": [
                "slots must be a list of strings of length at most %s" %
                MAX_SLOTS
            ]
        })
    for i, slot in enumerate(slots):
        try:
            day, time = slot.split(None, 1)
            day = short_weekdays.index(day)
        except ValueError:
            raise APIError({
                "code":
                "processing_error",
                "description":
                "Error in processing slots",
                "errors": [
                    "slots must be a three letter day-of-week followed by a time range after a space"
                ]
            })
        raw_data["weekday%s" % i] = str(day)
        raw_data["time_slot%s" % i] = time
    for i in range(len(slots), MAX_SLOTS):
        raw_data["weekday%s" % i] = raw_data["time_slot%s" % i] = ""
    raw_data["num_slots"] = len(slots)

    if update_organizers:
        # We require specifying the organizers of a new seminar and don't allow updates,
        # so we don't need to get anything from the seminar object
        organizers = raw_data.get("organizers", [])
        fixed_cols = list(db.seminar_organizers.search_cols)
        i = fixed_cols.index("curator")
        fixed_cols[i] = "organizer"
        if not (isinstance(organizers, list)
                and len(organizers) <= MAX_ORGANIZERS and all(
                    isinstance(OD, dict) and all(key in fixed_cols
                                                 for key in OD)
                    for OD in organizers)):
            raise APIError({
                "code":
                "processing_error",
                "description":
                "Error in processing organizers",
                "errors": [
                    "organizers must be a list of dictionaries (max length %s) with keys %s"
                    % (MAX_ORGANIZERS, ", ".join(fixed_cols))
                ]
            })
        for i, OD in enumerate(organizers):
            for col in db.seminar_organizers.search_cols:
                default = True if col == "display" else ""
                raw_data["org_%s%s" % (col, i)] = OD.get(col, default)
            # We store curator in the database but ask for organizer from the API
            raw_data["org_curator%s" % i] = not OD.get("organizer", True)

    warnings = []

    def warn(msg, *args):
        warnings.append(msg % args)

    new_version, errmsgs = process_save_seminar(series,
                                                raw_data,
                                                warn,
                                                format_error,
                                                format_input_error,
                                                update_organizers,
                                                incremental_update=True,
                                                user=user)
    if new_version is None:
        raise APIError({
            "code": "processing_error",
            "description": "Error in processing input",
            "errors": errmsgs
        })
    if series.new or new_version != series:
        # Series saved by the API are not displayed until user approves
        new_version.display = False
        new_version.by_api = True
        new_version.save(user)
    else:
        raise APIError({
            "code": "no_changes",
            "description": "No changes detected"
        })
    if series.new:
        new_version.save_organizers()
    edittype = "created" if series.new else "edited"
    if warnings:
        response = jsonify({
            "code": "warning",
            "description": "series successfully %s, but..." % edittype,
            "warnings": warnings
        })
    else:
        response = jsonify({
            "code": "success",
            "description": "series successfully %s" % edittype
        })
    return response
Esempio n. 13
0
def index():
    # TODO: use a join for the following query
    seminars = {}
    conferences = {}
    deleted_seminars = []
    deleted_talks = []

    def key(elt):
        role_key = {"organizer": 0, "curator": 1, "creator": 3}
        return (role_key[elt[1]], elt[0].name)

    for rec in db.seminar_organizers.search(
        {"email": ilike_query(current_user.email)}, ["seminar_id", "curator"]):
        semid = rec["seminar_id"]
        role = "curator" if rec["curator"] else "organizer"
        seminar = WebSeminar(semid)
        pair = (seminar, role)
        if seminar.is_conference:
            conferences[semid] = pair
        else:
            seminars[semid] = pair
    role = "creator"
    for semid in seminars_search({"owner": ilike_query(current_user.email)},
                                 "shortname",
                                 include_deleted=True):
        if semid not in seminars and semid not in conferences:
            seminar = WebSeminar(semid, deleted=True)  # allow deleted
            pair = (seminar, role)
            if seminar.deleted:
                deleted_seminars.append(seminar)
            elif seminar.is_conference:
                conferences[semid] = pair
            else:
                seminars[semid] = pair
    seminars = sorted(seminars.values(), key=key)
    conferences = sorted(conferences.values(), key=key)
    deleted_seminars.sort(key=lambda sem: sem.name)
    for semid, semctr in db._execute(
            # ~~* is case insensitive amtch
            SQL("""
SELECT DISTINCT ON ({Ttalks}.{Csemid}, {Ttalks}.{Csemctr}) {Ttalks}.{Csemid}, {Ttalks}.{Csemctr}
FROM {Ttalks} INNER JOIN {Tsems} ON {Ttalks}.{Csemid} = {Tsems}.{Csname}
WHERE {Tsems}.{Cowner} ~~* %s AND {Ttalks}.{Cdel} = %s AND {Tsems}.{Cdel} = %s
            """).format(
                Ttalks=IdentifierWrapper("talks"),
                Tsems=IdentifierWrapper("seminars"),
                Csemid=IdentifierWrapper("seminar_id"),
                Csemctr=IdentifierWrapper("seminar_ctr"),
                Csname=IdentifierWrapper("shortname"),
                Cowner=IdentifierWrapper("owner"),
                Cdel=IdentifierWrapper("deleted"),
            ),
        [ilike_escape(current_user.email), True, False],
    ):
        talk = WebTalk(semid, semctr, deleted=True)
        deleted_talks.append(talk)
    deleted_talks.sort(key=lambda talk: (talk.seminar.name, talk.start_time))

    manage = "Manage" if current_user.is_organizer else "Create"
    return render_template(
        "create_index.html",
        seminars=seminars,
        conferences=conferences,
        deleted_seminars=deleted_seminars,
        deleted_talks=deleted_talks,
        institution_known=institution_known,
        institutions=institutions(),
        section=manage,
        subsection="home",
        title=manage,
        user_is_creator=current_user.is_creator,
    )
Esempio n. 14
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)
Esempio 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(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)
Esempio n. 16
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)