def is_enrolled(course, *, roles=None):
    """Check whether the current user is enrolled as any of the ``roles`` for
    ``course``.

    :param course: the course code to check
    :type course: str

    :param roles: the roles to check for the user
    :type roles: list-like

    :return: ``True`` if the user is any of ``roles``, ``False`` otherwise
    """
    try:
        endpoint = get_endpoint(course=course)
        for participation in get_user()["participations"]:
            if roles and participation["role"] not in roles:
                continue
            if participation["course"]["offering"] != endpoint:
                continue
            return True
        return False
    except Exception as e:
        # fail safe!
        print(e)
        return False
Exemple #2
0
    def get_assignments(course):
        endpoint = get_endpoint(course=course)
        assignments: List[Assignment] = Assignment.query.filter(
            Assignment.endpoint == endpoint).all()

        return render_template(
            "assignments.html",
            course=course,
            assignments=sorted(assignments, key=lambda a: -a.last_modified),
        )
Exemple #3
0
def update():
    if not os.path.exists("data"):
        try:
            os.makedirs("data")
        except FileExistsError as e:
            print("Data folder exists, false alarm!")

    sections = "sp21" in get_endpoint(course="cs61a")

    with connect_db() as db:
        gscope: List[Tuple[str, str]] = db(
            "SELECT name, gs_code FROM gscope",
            [],
        ).fetchall()
        adjustments: List[Tuple[str, str]] = db(
            "SELECT url, sheet FROM adjustments",
            [],
        ).fetchall()

    print("=================================================")
    roster_export.export()

    print("=================================================")
    okpy_export.export()

    gs_assignments = {}

    if not gscope:
        print("No Gradescope assignments found!", file=sys.stderr)

    for name, gs_code in gscope:
        print("=================================================")
        full_name = gs_export.export(name, gs_code)
        if full_name:
            gs_assignments[name] = full_name
        else:
            print(f"Gradescope export for '{name} ({gs_code})' failed.",
                  file=sys.stderr)

    if sections:
        print("=================================================")
        sections_export.export()

    print("=================================================")
    assemble.assemble(gscope=gs_assignments,
                      recovery=True,
                      sections=sections,
                      adjustments=adjustments)

    print("=================================================")
Exemple #4
0
    def register_course(course):
        if get_endpoint(course=course) not in get_staff_endpoints():
            abort(403)

        with connect_db() as db:
            ret = db("SELECT * FROM bot_data WHERE course = (%s)",
                     [course]).fetchone()

        if ret:
            # course already setup
            return redirect(
                get_add_to_slack_link(slack_workspace_name(course=course)))
        else:
            return redirect(url_for("course_config", course=course))
Exemple #5
0
    def create_assignment_rpc(course, name, file, command, batch_size,
                              grading_base):
        assignment: Assignment = Assignment.query.filter_by(
            name=name, course=course,
            endpoint=get_endpoint(course=course)).one_or_none()

        if not assignment:
            assignment = Assignment(
                name=name,
                assignment_secret=new_secret(),
                course=course,
                endpoint=get_endpoint(course=course),
            )
            db.session.add(assignment)

        assignment.file = file
        assignment.command = command
        assignment.last_modified = int(time.time())
        assignment.batch_size = batch_size
        assignment.grading_base = grading_base
        db.session.commit()

        return assignment.assignment_secret
Exemple #6
0
def is_staff(course):
    try:
        endpoint = get_endpoint(course=course)
        for participation in get_user()["participations"]:
            if participation["role"] not in AUTHORIZED_ROLES:
                continue
            if participation["course"][
                    "offering"] != endpoint and endpoint is not None:
                continue
            return True
        return False
    except Exception as e:
        # fail safe!
        print(e)
        return False
Exemple #7
0
def get_endpoint(course=None):
    """Gets a course's most recent Okpy endpoint, typically the current
    semester's, using :meth:`~common.rpc.auth.get_endpoint`.

    :param course: the course code, such as "cs61a", inferred using
        :meth:`~common.course_config.get_course` if omitted
    :type course: str

    :return: the Okpy endpoint, such as "cal/cs61a/sp21"
    """
    if getenv("ENV") != "prod":
        return "cal/cs61a/sp21"
    if not course:
        course = get_course()
    if course not in COURSE_ENDPOINTS:
        COURSE_ENDPOINTS[course] = auth.get_endpoint(course=course)
    return COURSE_ENDPOINTS[course]
Exemple #8
0
    def set_course_config(course):
        if get_endpoint(course=course) not in get_staff_endpoints():
            abort(403)

        with connect_db() as db:
            for service in CONFIG["services"]:
                db(
                    "DELETE FROM activated_services WHERE course=(%s) AND service=(%s)",
                    [course, service],
                )
                if service in request.form:
                    db(
                        "INSERT INTO activated_services VALUES (%s, %s)",
                        [course, service],
                    )

        return redirect(url_for("course_config", course=course))
Exemple #9
0
    def fail_unfinished_jobs(course, assignment):
        endpoint = get_endpoint(course=course)
        jobs = (Job.query.join(Assignment).filter(
            Assignment.endpoint == endpoint).filter(
                Assignment.name == assignment).filter(
                    Job.status.in_(("queued", "running"))).all())
        count = Job.query.filter(
            Job.job_secret.in_([job.job_secret for job in jobs])).update(
                {
                    Job.status: "failed",
                    Job.finished_at: int(time.time()),
                    Job.result: f"Marked as failed by {get_user()['email']}.",
                },
                synchronize_session="fetch",
            )
        db.session.commit()

        return dict(modified=count)
Exemple #10
0
    def job_details(course, id):
        endpoint = get_endpoint(course=course)
        job: Job = (Job.query.join(Assignment).filter(
            Assignment.endpoint == endpoint).filter(
                Job.external_job_id == id).one_or_none())

        if not job:
            abort(404, "Job not found.")

        return render_template(
            "job.html",
            course=course,
            backup=job.backup,
            status=job.status,
            result=job.result,
            start=job.started_at,
            finish=job.finished_at,
        )
Exemple #11
0
    def okpy_batch_grade_impl():
        data = request.json
        subm_ids = data["subm_ids"]
        assignment = data["assignment"]
        access_token = data["access_token"]

        if assignment == "test":
            return "OK"

        assignment: Optional[Assignment] = Assignment.query.get(assignment)
        if not assignment or assignment.endpoint != get_endpoint(
            course=assignment.course
        ):
            abort(404, "Unknown Assignment")

        if len(subm_ids) / assignment.batch_size > 50:
            abort(
                405,
                "Too many batches! Please set the batch_size so that there are <= 50 batches.",
            )

        job_secrets = [new_secret() for _ in subm_ids]
        queue_time = int(time.time())

        jobs = [
            Job(
                assignment_secret=assignment.assignment_secret,
                backup=backup_id,
                status="queued",
                job_secret=job_secret,
                external_job_id=new_secret(),
                access_token=access_token,
                queued_at=queue_time,
            )
            for backup_id, job_secret in zip(subm_ids, job_secrets)
        ]
        db.session.bulk_save_objects(jobs)
        db.session.commit()

        trigger_jobs(
            assignment_id=assignment.assignment_secret, jobs=job_secrets, noreply=True
        )

        return dict(jobs=[job.external_job_id for job in jobs])
Exemple #12
0
    def retrigger_unsuccessful_jobs(course, assignment):
        endpoint = get_endpoint(course=course)
        assignment = Assignment.query.filter_by(name=assignment,
                                                endpoint=endpoint).one()
        jobs = (Job.query.join(Assignment).filter(
            Assignment.endpoint == endpoint).filter(
                Assignment.name == assignment.name).filter(
                    Job.status != "finished").all())

        for job in jobs:
            job.status = "queued"
        db.session.commit()

        trigger_jobs(
            assignment_id=assignment.assignment_secret,
            jobs=[job.job_secret for job in jobs if job.status == "queued"],
        )

        return dict(modified=len(jobs))
Exemple #13
0
    def course_config(course):
        if get_endpoint(course=course) not in get_staff_endpoints():
            abort(403)

        with connect_db() as db:
            ret = db(
                "SELECT service FROM activated_services WHERE course = (%s)",
                [course])
            active_services = set(x[0] for x in ret)

        service_list = "<br />".join(f"""
            <label>
                <input 
                    type="checkbox" 
                    name="{service}" 
                    {"checked" if service in active_services else ""}
                >
                {service.title()}: {description}
            </label>
        """ for service, description in CONFIG["services"].items())

        return f"""
Exemple #14
0
import os, roster_export, okpy_export, sys
import gs_export, sections_export, assemble

from typing import List, Tuple

from common.rpc.auth import get_endpoint
from common.db import connect_db

if not os.path.exists("data"):
    try:
        os.makedirs("data")
    except FileExistsError as e:
        print("Data folder exists, false alarm!")

sections = "fa20" in get_endpoint(course="cs61a")

with connect_db() as db:
    gscope: List[Tuple[str, str]] = db(
        "SELECT name, gs_code FROM gscope",
        [],
    ).fetchall()
    acadh: List[Tuple[str, str]] = db(
        "SELECT url, sheet FROM acadh",
        [],
    ).fetchall()


def update():
    print("=================================================")
    roster_export.export()
Exemple #15
0
    def get_jobs(course, assign):
        endpoint = get_endpoint(course=course)
        jobs: List[Job] = (Job.query.join(Assignment).filter(
            Assignment.endpoint == endpoint).filter(Assignment.name == assign))
        assign = (Assignment.query.filter(Assignment.name == assign).filter(
            Assignment.endpoint == endpoint).one_or_none())

        if not assign:
            abort(404, "Assignment not found.")

        queued_at = request.args.get("queued_at", 0)
        if queued_at:
            jobs = jobs.filter(Job.queued_at == queued_at)

        status = request.args.get("status", "all")
        if status != "all":
            jobs = jobs.filter(Job.status == status)
        jobs = jobs.all()

        batches = {}
        for job in jobs:
            if str(job.queued_at) not in batches:
                batches[str(job.queued_at)] = {
                    "jobs": [],
                    "finished": 0,
                    "failed": 0,
                    "running": 0,
                    "queued": 0,
                    "completed": 0,
                    "total": 0,
                }
            batch = batches[str(job.queued_at)]

            details = {
                "started_at": job.started_at,
                "finished_at": job.finished_at,
                "backup": job.backup,
                "status": job.status,
                "result": job.result,
                "id": job.external_job_id,
            }

            if details["finished_at"]:
                if details["status"] == "finished":
                    batch["finished"] += 1
                    details["duration"] = details["finished_at"] - details[
                        "started_at"]
                else:
                    batch["failed"] += 1
                batch["completed"] += 1
            elif details["started_at"]:
                batch["running"] += 1
            else:
                batch["queued"] += 1

            batch["total"] += 1
            batch["progress"] = batch["completed"] / batch["total"]
            batch["jobs"].append(details)

        return render_template(
            "assignment.html",
            course=course,
            assign=assign,
            batches={k: batches[k]
                     for k in sorted(batches, reverse=True)},
            queued_at=str(queued_at),
            status=status,
        )