def config(): auth_result = authenticate(app) if not (isinstance(auth_result, str) and auth_result == "Authorized!"): return auth_result with connect_db() as db: gscope: List[Tuple[str, str]] = db( "SELECT name, gs_code FROM gscope", [], ).fetchall() adjustments: List[Tuple[str, str, str]] = db( "SELECT hashed, url, sheet FROM adjustments", [], ).fetchall() return html( """ <h1>Grade Display Config</h1> <p> Add a Gradescope assignment: """ + make_row( """<input name="name" placeholder="Shortname (no spaces!)" /> <input name="gs_code" placeholder="Gradescope code" /> """, url_for("create_assign"), "Submit", ) + """ </p> <p> Add an adjustments sheet: """ + make_row( """<input name="url" placeholder="Full URL" /> <input name="sheet" placeholder="Sheet Name" /> """, url_for("add_adjustments"), "Submit", ) + """ </p> """ + "".join( "<p>" + make_row(f"{name} ({gs_code})", url_for("delete_assign", name=name)) for name, gs_code in gscope ) + "".join( "<p>" + make_row( f"Adjustments: {url} ({sheet})", url_for("delete_adjustments", hashed=hashed), ) for hashed, url, sheet in adjustments ) )
def super_clients(): if not is_staff(MASTER_COURSE): return "" with connect_db() as db: ret = db("SELECT client_name, creator, unused FROM super_auth_keys" ).fetchall() super_client_names = [ make_row( f'{client_name}, created by {creator} {"(unused)" if unused else ""} ', url_for("revoke_super_key", client_name=client_name), ) for client_name, creator, unused in ret ] return f""" <h3>Super-Clients</h3> <p> Warning - the API keys for these clients are extremely sensitive, as they can access <i>any</i> course's data. Only use them for 61A-hosted apps, and reset them whenever a head TA leaves course staff. </p> Create new super-client and obtain secret key: <form action="{url_for("create_super_key")}" method="post"> <input name="client_name" type="text" placeholder="client_name"> <input type="submit"> </form> """ + "<p>".join(super_client_names)
def admin_data(course): with connect_db() as db: ret = db( "SELECT email, name, course, creator FROM course_admins WHERE course=(%s)", [course], ).fetchall() admin_names = [ make_row( f'{name} (<a href="mailto:{email}">{email}</a>), added by {creator} ', url_for("remove_admin", course=course, email=email), ) for email, name, course, creator in ret ] add_admin = f""" Add new course administrator: <form action="{url_for("add_admin", course=course)}" method="post"> <input name="email" type="email" placeholder="Email address"> <input type="submit"> </form> """ with connect_db() as db: ret = db( "SELECT url, sheet FROM course_permissions WHERE course=(%s)", [course]).fetchall() perms_sheet = [ make_row( f'<a href="{url}">{sheet} ({url})</a>', url_for("unset_granular_spreadsheet", course=course), ) for url, sheet in ret ] # there should only be 0-1 perms sheets add_perms_sheet = f""" Add granular permissions sheet (first column should be email, the rest should be permission names): <form action="{url_for("set_granular_spreadsheet", course=course)}" method="post"> <input name="url" placeholder="URL"> <input name="sheet" placeholder="Sheet Name"> <input type="submit"> </form> """ return ("<h3>Admins</h3>" + add_admin + "<p>".join(admin_names) + "<br>" + "<h3>Granular Permissions</h3>" + add_perms_sheet + "<p>".join(perms_sheet))
def slack_help(course): with connect_db() as db: workspace = db( "SELECT workspace FROM slack_config WHERE course=(%s)", [course]).fetchone() workspace = workspace[0] if workspace else "" registered_channels = db( "SELECT purpose, channel, channel_id FROM slack_channels WHERE course=(%s)", [course], ).fetchall() try: channels = list_channels(course=course) except: registration = """ To register Slack channels, first go to <a href="https://slack.cs61a.org">slack.cs61a.org</a> to add the bot to your workspace. """ else: channels = [ f"<option value=\"{channel['name']}\">{channel['name']}</option>" for channel in channels ] registration = f""" Register a new Slack channel. <form action="/slack/{course}/register_channel" method="post"> <input name="purpose" type="text" placeholder="Purpose"> <select name="channel"> {channels} </select> <input type="submit"> </form> """ registered_channels_list = "<p>".join( make_row( f"{purpose} associated with #{channel} (id: {channel_id})", url_for("remove_channel", course=course, purpose=purpose), ) for purpose, channel, channel_id in registered_channels) return f"""
def index(): if not is_staff(get_course()): return login() with connect_db() as db: sources = db( "SELECT url, sheet, secure FROM sources WHERE course=%s", [get_course()] ).fetchall() insert_fields = """<input placeholder="Spreadsheet URL" name="url"></input> <input placeholder="Sheet Name" name="sheet"></input> <label> <input type="checkbox" name="secure"></input> Require Authentication </label>""" sources = "<br/>".join( make_row( f'<a href="{url}">{url}</a> {sheet} (Secure: {secure})' f'<input name="url" type="hidden" value="{url}"></input>' f'<input name="sheet" type="hidden" value="{sheet}"></input>', url_for("remove_source"), ) for url, sheet, secure in sources ) return html( f""" <h2>Course: <code>{get_course()}</code></h2> Each spreadsheet should be shared with the 61A service account <a href="mailto:[email protected]"> [email protected]</a>. They should have three columns with the headers: "URL", "Shortlink", and "Creator". <p> Visit <a href="{url_for("refresh")}">{url_for("refresh")}</a> (no auth required) after adding a link to synchronize with the spreadsheets. <h3>Sources</h3> {sources} <h3>Add Sources</h3> {make_row(insert_fields, url_for("add_source"), "Add")} """ )
def client_data(course): with connect_db() as db: ret = db( "SELECT email, name, course, creator FROM course_admins WHERE course=(%s)", [course], ).fetchall() admin_names = [ make_row( f'{name} (<a href="mailto:{email}">{email}</a>), added by {creator} ', url_for("remove_admin", course=course, email=email), ) for email, name, course, creator in ret ] create_client = f""" Add new course administrator: <form action="{url_for("add_admin", course=course)}" method="post"> <input name="email" type="email" placeholder="Email address"> <input type="submit"> </form> """ return "<h3>Admins</h3>" + create_client + "<p>".join(admin_names)
def client_data(course): with connect_db() as db: ret = db( "SELECT client_name, creator, unused FROM auth_keys WHERE course=(%s)", [course], ).fetchall() client_names = [ make_row( f'{client_name}, created by {creator} {"(unused)" if unused else ""} ', url_for("revoke_key", course=course, client_name=client_name), ) for client_name, creator, unused in ret ] create_client = f""" Create new client and obtain secret key: <form action="{url_for("create_key", course=course)}" method="post"> <input name="client_name" type="text" placeholder="client_name"> <input type="submit"> </form> """ return "<h3>Clients</h3>" + create_client + "<p>".join(client_names)
def domains_help(course): with connect_db() as db: ret = db("SELECT domain FROM domains_config WHERE course=(%s)", [course]).fetchall() client_names = [ make_row(domain, url_for("remove_domain", domain=domain, course=course)) for domain, in ret ] register_domain = f""" Register new domain: <form action="/domains/{course}/register_domain" method="post"> <input name="domain_name" type="text" placeholder="seating.cs61a.org"> <input type="submit"> </form> View the status of your domain setup at <a href="https://domains.cs61a.org/">domains.cs61a.org</a> <br /> """ return "<h3>Domains</h3>" + register_domain + "<p>".join(client_names)
def add_course(): if not is_staff(MASTER_COURSE): return "" with connect_db() as db: courses = db("SELECT course, endpoint FROM courses").fetchall() courses = [ make_row( "{} ({}), at endpoint {}".format(prettify(course), course, endpoint), url_for("remove_course", course=course), ) for course, endpoint in courses ] return """ <h2>Admin</h2> <h3>Courses</h3> Activate Auth for a new course (method only available to 61A admins): <form action="/api/add_course" method="post"> <input name="course" type="text" placeholder="course name"> <input name="endpoint" type="text" placeholder="OKPy endpoint"> <input type="submit"> </form> """ + "<p>".join(courses)