def manage(uid): has_directory_page = current_app.config["HAS_DIRECTORY_PAGE"] society = Society.query.filter_by(uid=uid).first() if not society: abort(404) crsid = auth_decorator.principal user = User.query.filter_by(crsid=crsid).first() if society not in user.societies: abort(403) sessions_data = {"days": current_app.config["NUMBER_OF_DAYS"]} if request.method == "POST": is_new_owner = False is_new_session = False # Input validation from https://github.com/SRCF/control-panel/blob/master/control/webapp/signup.py#L37 values = {} for key in ( "soc_name", "website", "description", "short_description", "welcome_text", "logo", "banner_text", "banner_color", "new_owner_crsid", "new_session_day", "new_session_start", "new_session_end", ): values[key] = request.form.get(key, "").strip() for key in ("mute_on_start", "disable_private_chat"): values[key] = bool(request.form.get(key, False)) errors = {} if len(values["soc_name"]) <= 1: errors["soc_name"] = _("Society name is too short.") if len(values["short_description"]) > 200: errors["short_description"] = _("This description is too long.") if "logo" in request.files: logo = request.files["logo"] bbb_logo = request.files["bbb_logo"] logo_filename, logo_extension = os.path.splitext(logo.filename) bbb_logo_filename, bbb_logo_extension = os.path.splitext(bbb_logo.filename) images_dir = current_app.config["IMAGES_DIR"] if logo and logo_filename != "": if logo_extension in current_app.config["LOGO_ALLOWED_EXTENSIONS"]: # Delete the old logo if it's not the default delete_society_logo(uid) static_filename = ( society.uid + "_" + gen_unique_string() + logo_extension ) path = os.path.join(images_dir, static_filename) current_app.logger.info( f"For user { crsid }, society uid='{ society.uid }': changing logo..." ) if not os.path.isdir(images_dir): current_app.logger.error( f"'{ images_dir }': no such directory." ) abort(500) maxwidth, maxheight = current_app.config["MAX_LOGO_SIZE"] logo_img = Image.open(logo) ratio = min(maxwidth / logo_img.width, maxheight / logo_img.height) # possible optimization with reduce here? logo_resized = logo_img.resize( (round(logo_img.width * ratio), round(logo_img.height * ratio)) ) logo_resized.save(path) current_app.logger.info( f"For uid='{ society.uid }': saved new logo '{ path }'" ) society.logo = static_filename db.session.commit() current_app.logger.info(f"For uid='{ society.uid }': updated logo.") else: errors["logo"] = "Invalid file." if bbb_logo and bbb_logo_filename != "": if bbb_logo_extension in current_app.config["LOGO_ALLOWED_EXTENSIONS"]: # Delete the old logo if it's not the default delete_society_bbb_logo(uid) static_filename = ( society.uid + "_bbb_" + gen_unique_string() + bbb_logo_extension ) path = os.path.join(images_dir, static_filename) current_app.logger.info( f"For user { crsid }, society uid='{ society.uid }': changing bbb_logo..." ) if not os.path.isdir(images_dir): current_app.logger.error( f"'{ images_dir }': no such directory." ) abort(500) bbb_logo_img = Image.open(bbb_logo) bbb_logo_resized = bbb_logo_img.resize((100, 30)) bbb_logo_resized.save(path) current_app.logger.info( f"For uid='{ society.uid }': saved new bbb_logo to '{ path }'" ) society.bbb_logo = static_filename db.session.commit() current_app.logger.info( f"For uid='{ society.uid }': updated bbb_logo." ) else: errors["bbb_logo"] = "Invalid file." # TODO: tweak these values when their ideal maximum lengths become apparent if len(values["welcome_text"]) > 100: errors["welcome_text"] = "Welcome text is too long." if len(values["banner_text"]) > 100: errors["banner_text"] = "Banner text is too long." # Adding a new owner if values["new_owner_crsid"] != "": current_app.logger.info( f"For uid='{ society.uid }': { crsid } is adding new owner { values['new_owner_crsid'] }..." ) new_owner = User.query.filter_by(crsid=values["new_owner_crsid"]).first() if not new_owner: errors[ "new_owner_crsid" ] = "That user is not registered yet. Users must register before being added as administrators." is_new_owner = True # Add a new session if values["new_session_start"] and values["new_session_end"]: start_time = [int(nstr) for nstr in values["new_session_start"].split(":")] end_time = [int(nstr) for nstr in values["new_session_end"].split(":")] # Check that start is before end t1 = time(hour=start_time[0], minute=start_time[1]) t2 = time(hour=end_time[0], minute=end_time[1]) if t1 > t2: errors[ "new_session_start" ] = "Unfortunately, time travel is not possible." is_new_session = True elif values["new_session_start"]: errors["new_session_end"] = "No end time specified." elif values["new_session_end"]: errors["new_session_start"] = "No start time specified." if errors: flash("There are errors with the information you provided.") return render_template( "rooms/manage.html", page_title=f"Stall administration for { society.name }", society=society, crsid=crsid, errors=errors, sessions_data=sessions_data, page_parent=url_for("home.home"), has_directory_page=has_directory_page, **values, ) else: society.name = values["soc_name"] society.website = values["website"] if values["website"] != "" else None # fetch all social fields from values, as we generate the uid in jinja social_forms = {k: v for (k, v) in request.form.items() if ("social-" in k)} for id, value in social_forms.items(): index, found_social = get_social_by_id(id, society.socials) # do we have this social already? if found_social: if found_social["url"] != value: if value == "": del society.socials[index] else: found_social["url"] = value found_social["type"] = match_social(value) flag_modified(society, "socials") else: # create a new social field # and check if its empty if value: social_type = match_social(value) social_data = {"id": id, "url": value, "type": social_type} society.socials.append(social_data) flag_modified(society, "socials") society.description = values["description"] if values["description"] != "" else None society.short_description = values["short_description"] if values["short_description"] != "" else None society.welcome_text = values["welcome_text"] if values["welcome_text"] != "" else None society.banner_text = values["banner_text"] if values["banner_text"] != "" else None society.banner_color = values["banner_color"] society.mute_on_start = values["mute_on_start"] society.disable_private_chat = values["disable_private_chat"] if is_new_owner: society.owners.append(new_owner) if is_new_session: society.sessions.append( { "id": gen_unique_string(), "day": values["new_session_day"], "start": values["new_session_start"], "end": values["new_session_end"], } ) # we need this to ensure that sqlalchemy updates the val flag_modified(society, "sessions") db.session.commit() if is_new_owner: current_app.logger.info( f"For uid='{ society.uid }': added new owner { new_owner }." ) if is_new_session: current_app.logger.info( f"For uid='{ society.uid }': { crsid } added new session [ day: { values['new_session_day'] }, start: { values['new_session_start'] }, end: { values['new_session_end'] } ]" ) flash("Settings saved.") return redirect(url_for("rooms.manage", uid=society.uid)) else: # defaults values = { "soc_name": society.name, "website": society.website, "description": society.description, "short_description": society.short_description, "welcome_text": society.welcome_text, "banner_text": society.banner_text, "banner_color": society.banner_color, "logo": society.logo, "mute_on_start": society.mute_on_start, "disable_private_chat": society.disable_private_chat, } return render_template( "rooms/manage.html", page_title=f"Stall administration for { society.name }", society=society, crsid=crsid, errors={}, sessions_data=sessions_data, page_parent=url_for("home.home"), has_directory_page=has_directory_page, **values, )
def register_soc(): crsid = auth_decorator.principal user = User.query.filter_by(crsid=crsid).first() # Check the user is registered with us, if not redirect to the user reg page if not user: return redirect(url_for("home.register")) if request.method == "POST": values = {} for key in ("soc_name", "soc_short_name"): values[key] = request.form.get(key, "").strip() errors = {} values["uid"] = values["soc_short_name"].lower() values["bbb_id"] = gen_unique_string() values["moderator_pw"] = gen_unique_string()[0:12] values["attendee_pw"] = gen_unique_string()[0:12] # TODO: What's the best way of handling the (unlikely) event # that the passwords are: # a) non-unique across registered societies # b) the same # Currently we abort(500) if values["moderator_pw"] == values["attendee_pw"]: abort(500) elif (Society.query.filter_by( attendee_pw=values["attendee_pw"]).first() or Society.query.filter_by( moderator_pw=values["moderator_pw"]).first() or Society.query.filter_by(bbb_id=values["bbb_id"]).first()): abort(500) if Society.query.filter_by(uid=values["uid"]).first(): errors[ "soc_short_name"] = "That society short name is already in use." if " " in values["soc_short_name"]: errors[ "soc_short_name"] = "Your society short name must not contain spaces." if errors: return render_template("home/register_soc.html", page_title="Register a society", crsid=crsid, errors=errors, **values) else: society = Society(short_name=values["soc_short_name"], name=values["soc_name"], attendee_pw=values["attendee_pw"], moderator_pw=values["moderator_pw"], uid=values["uid"], bbb_id=values["bbb_id"]) db.session.add(society) db.session.commit() user.societies.append(society) db.session.commit() current_app.logger.info(f"Registered society {values['uid']}") return redirect(url_for("home.register_soc_success")) else: return render_template("home/register_soc.html", page_title="Register a society", crsid=crsid, errors={})
def register(): if request.method == "POST": name = request.form["name"] email_address = request.form["email_address"] soc_name = request.form["soc_name"] soc_short_name = request.form["soc_short_name"] uid = soc_short_name.lower() bbb_id = gen_unique_string() moderator_pw = gen_unique_string()[0:12] attendee_pw = gen_unique_string()[0:12] errors = [] if not name: errors.append("A name is required.") if not email_address: errors.append("An email address is required.") if not "@" in email_address: errors.append("Enter a valid email address.") elif not "." in email_address: errors.append("Enter a valid email address.") if not soc_name: errors.append("A society name is required.") if not soc_short_name: errors.append("A short society name is required.") # TODO: What's the best way of handling the (unlikely) event # that the passwords are: # a) non-unique across registered societies # b) the same # Currently we flash the error: # "An error occured. Please try again." if moderator_pw == attendee_pw: errors.append("An error occured. Please try again.") if User.query.filter_by(email=email_address): errors.append("That email address is already registered.") if Society.query.filter_by(uid=uid): errors.append("That society short name is already in use.") elif (Society.query.filter_by(attendee_pw=attendee_pw) or Society.query.filter_by(moderator_pw=moderator_pw) or Society.query.filter_by(bbb_id=bbb_id)): errors.append("An error occured. Please try again.") if not errors: # TODO: BBB create() API call goes here? admin = User(email=email_address, name=name, society_id=society.id, crsid=auth_decorator.principal) society = Society(short_name=soc_short_name, name=name, attendee_pw=attendee_pw, moderator_pw=moderator_pw, uid=uid, bbb_id=bbb_id, admins=admin) db.session.add(society) db.session.add(admin) db.session.commit() else: for message in errors: flash(message) print(f"{auth_decorator.principal}") return render_template("home/register.html", page_title="Register a Society", crsid=auth_decorator.principal)