Пример #1
0
 def login():
     if app.debug:
         response = remote.authorize(
             callback=url_for("authorized", _external=True))
     else:
         response = remote.authorize(
             url_for("authorized", _external=True, _scheme="https"))
     return response
Пример #2
0
def toggle_recovery():
    if not is_staff("cs61a"):
        return redirect(url_for("config"))
    with connect_db() as db:
        was_enabled = is_recovery_enabled()
        db('DELETE FROM config WHERE conf_key="recovery"')
        if not was_enabled:
            db('INSERT INTO config VALUES ("recovery", "true")')
    return redirect(url_for("config"))
Пример #3
0
def sudo(username):
    if not is_software_ta(get_user()["email"]):
        return redirect(url_for("index"))

    out = "<h1>61A Sandbox IDE</h1>\n"
    out += f"Hi {get_user()['name'].split()[0]}! {username}'s IDE is "

    session[SK_RETURN_TO] = url_for("sudo", username=username)
    return gen_index_html(out, username, True)
Пример #4
0
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
        )
    )
Пример #5
0
def add_adjustments():
    if not is_staff("cs61a"):
        return redirect(url_for("config"))

    url = request.form["url"]
    sheet = request.form["sheet"]
    hashed = hashlib.sha512(url.encode("utf-8") + sheet.encode("utf-8")).hexdigest()
    with connect_db() as db:
        db(
            "INSERT INTO adjustments (hashed, url, sheet) VALUES (%s, %s, %s)",
            [hashed, url, sheet],
        )
    return redirect(url_for("config"))
Пример #6
0
def set_acadh():
    if not is_staff("cs61a"):
        return redirect(url_for("config"))

    url = request.form["url"]
    sheet = request.form["sheet"]
    with connect_db() as db:
        db("DELETE FROM acadh")
        db(
            "INSERT INTO acadh (url, sheet) VALUES (%s, %s)",
            [url, sheet],
        )
    return redirect(url_for("config"))
Пример #7
0
def authorized():
    from common.course_config import get_endpoint

    message = request.args.get("error")
    if message:
        message = "Ok OAuth error: %s" % (message)
        return redirect(url_for("error", message=message))
    try:
        auth_resp = auth.ok_auth.authorized_response()
        if auth_resp is None:
            message = "Invalid Ok response: %s" % (message)
            return redirect(url_for("error", message=message))
    except OAuthException as ex:
        message = str(ex)
        return redirect(url_for("error", message=message))
    token = auth_resp["access_token"]
    session["access_token"] = (token, "")  # (access_token, secret)
    info = auth.ok_auth.get("user").data["data"]
    email = info["email"]
    name = info["name"]
    if not name:
        name = email
    if ", " in name:
        last, first = name.split(", ")
        name = first + " " + last
    is_staff = False
    offering = get_endpoint()
    for p in info["participations"]:
        if p["course"]["offering"] == offering:
            if p["role"] != "student":
                is_staff = True
            else:
                is_staff = False
            break
    else:
        if (
            ConfigEntry.query.filter_by(
                course=get_course(), key="only_registered_students"
            )
            .one()
            .value
            == "true"
        ):
            return redirect(
                url_for(
                    "error",
                    message="Only registered students can log in",
                )
            )
    user = user_from_email(name, email, is_staff)
    return authorize_user(user)
Пример #8
0
def create_assign():
    if not is_staff("cs61a"):
        return redirect(url_for("config"))

    name = request.form["name"]
    gs_code = request.form["gs_code"]
    with connect_db() as db:
        existing = db("SELECT * FROM gscope WHERE name=%s", [name]).fetchall()
        if existing:
            abort(409)
        db(
            "INSERT INTO gscope (name, gs_code) VALUES (%s, %s)",
            [name, gs_code],
        )
    return redirect(url_for("config"))
Пример #9
0
    def load_file(path):
        try:
            out = send_from_directory(STATIC_FOLDER, path.replace("//", "/"))
        except NotFound:
            pass
        else:
            return out

        raw = load_shortlink_file(path)

        if raw is NOT_LOGGED_IN:
            response = redirect(url_for("login"))
            response.set_cookie(COOKIE_SHORTLINK_REDIRECT, value=path)
            return response
        elif raw is NOT_AUTHORIZED:
            return "This file is only visible to staff."

        if raw is NOT_FOUND:
            return "File not found", 404

        data = {
            "fileName": raw["full_name"],
            "data": raw["data"],
            "shareRef": raw["share_ref"],
        }

        return render_template("index.html", initData={"loadFile": data})
Пример #10
0
    def add_admin(course):
        email = request.form["email"]
        with connect_db() as db:
            check = db(
                "SELECT * FROM course_admins WHERE email=(%s) AND course=(%s)",
                [email, course],
            ).fetchone()
        if check:
            return error("User is already an admin"), 409
        with connect_db() as db:
            db(
                "INSERT INTO course_admins VALUES (%s, %s, %s, %s)",
                [email, "Unknown", course,
                 get_name()],
            )

        # make sure that you can't accidentally lock yourself out
        with connect_db() as db:
            check = db(
                "SELECT * FROM course_admins WHERE email=(%s) AND course=(%s)",
                [get_email(), course],
            ).fetchone()
            if not check:
                db(
                    "INSERT INTO course_admins VALUES (%s, %s, %s, %s)",
                    [get_email(), get_name(), course,
                     get_name()],
                )

        return redirect(url_for("index"))
Пример #11
0
 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)
Пример #12
0
def delete_unused_services_handler():
    if not is_staff("cs61a"):
        return login()
    email = get_user()["email"]
    if not is_admin(course="cs61a", email=email):
        return login()
    delete_unused_services()
    return redirect(url_for("index"))
Пример #13
0
def kill():
    username = request.form.get("username")
    pid = get_server_pid(username)

    if pid:
        sh("kill", pid.decode("utf-8")[:-1])
        sh("sleep", "2")  # give the server a couple of seconds to shutdown
    return redirect(session.pop(SK_RETURN_TO, url_for("index")))
Пример #14
0
def index():
    username = get_username()

    out = "<h1>61A Sandbox IDE</h1>\n"
    out += f"Hi {get_user()['name'].split()[0]}! Your IDE is "

    session[SK_RETURN_TO] = url_for("index")
    return gen_index_html(out, username, is_software_ta(get_user()["email"]))
Пример #15
0
 def remove_admin(course):
     email = request.args["email"]
     with connect_db() as db:
         db(
             "DELETE FROM course_admins WHERE email=(%s) AND course=(%s)",
             [email, course],
         )
     return redirect(url_for("index"))
Пример #16
0
def login():
    """Store the current URL as the redirect target on success, then redirect
    to the login endpoint for the current app.

    :return: a :func:`~flask.redirect` to the login endpoint for the current
      :class:`~flask.Flask` app.
    """
    session[REDIRECT_KEY] = urlparse(request.url)._replace(netloc=get_host()).geturl()
    return redirect(url_for("login"))
Пример #17
0
 def set_granular_spreadsheet(course):
     url = request.form["url"]
     sheet = request.form["sheet"]
     with connect_db() as db:
         db("DELETE FROM course_permissions WHERE course=(%s)", [course])
         db(
             "INSERT INTO course_permissions (course, url, sheet) VALUES (%s, %s, %s)",
             [course, url, sheet],
         )
     return redirect(url_for("index"))
Пример #18
0
 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))
Пример #19
0
def remove_source():
    if not is_staff(get_course()):
        return login()

    url = request.form["url"]
    sheet = request.form["sheet"]

    with connect_db() as db:
        db(
            "DELETE FROM sources WHERE url=%s AND sheet=%s AND course=%s",
            [url, sheet, get_course()],
        )

    return redirect(url_for("index"))
Пример #20
0
def add_source():
    if not is_staff(get_course()):
        return login()

    url = request.form["url"]
    sheet = request.form["sheet"]
    secure = True if request.form.get("secure", False) else False

    with connect_db() as db:
        db(
            "INSERT INTO sources VALUES (%s, %s, %s, %s)",
            [url, sheet, secure, get_course()],
        )

    return redirect(url_for("index"))
Пример #21
0
def authenticate(app):
    """Returns an OAuth token that can be passed to the server for
    identification. If FORCE is False, it will attempt to use a cached token
    or refresh the OAuth token. If NOINTERACT is true, it will return None
    rather than prompting the user.
    """
    try:
        access_token = refresh_local_token()
    except Exception:
        print("Performing authentication.")

    if not is_staff("cs61a"):
        return redirect(url_for("login"))

    return "Authorized!"
Пример #22
0
    def authorized():
        resp = remote.authorized_response()
        if resp is None:
            return "Access denied: error=%s" % (request.args["error"])
        if isinstance(resp, dict) and "access_token" in resp:
            session["access_token"] = (resp["access_token"], "")
            if return_response:
                return_response(resp)

        if success_callback:
            success_callback()

        target = session.get(REDIRECT_KEY)
        if target:
            session.pop(REDIRECT_KEY)
            return redirect(target)
        return redirect(url_for("index"))
Пример #23
0
    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"""
Пример #24
0
def view_course(course=None):
    if not course:
        course = request.form["course"]
        return redirect(url_for("canonical_view_course", course=course))
    if not is_logged_in():
        return login()
    email = get_user()["email"]
    if not is_admin(email, course):
        abort(403)

    with connect_db() as db:
        apps = db(
            "SELECT domain, app, status FROM hosted_apps WHERE course=(%s)",
            [course]).fetchall()

    return html(f"""
        <h2>Hosted Apps for {format_coursecode(course)}</h2>
        {"<p>".join(f"<code>{domain}</code> ({app}) - {status}" for domain, app, status in apps)}
    """)
Пример #25
0
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")}
    """
    )
Пример #26
0
 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)
Пример #27
0
 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)
Пример #28
0
    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)
Пример #29
0
    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)
Пример #30
0
def submit():
    if not is_staff("cs61a"):
        return login()
    data = request.form["data"]
    return redirect(url_for("load_formatted", name=paste_worker(data)))