Exemple #1
0
def compile_all(exam, subtitle, out, do_twice, email, exam_type, semester,
                deadline):
    """
    Compile individualized PDFs for the specified exam.
    Exam must have been deployed first.
    """
    if not out:
        out = "out/latex/" + exam

    pathlib.Path(out).mkdir(parents=True, exist_ok=True)

    exam_data = get_exam(exam=exam)
    password = exam_data.pop("secret")[:-1]
    print(password)
    exam_str = json.dumps(exam_data)

    roster = get_roster(exam=exam)

    if email:
        roster = [line_info for line_info in roster if line_info[0] == email]
        if len(roster) == 0:
            if deadline:
                roster = [(email, deadline)]
            else:
                raise ValueError("Email does not exist in the roster!")

    for email, deadline in roster:
        if not deadline:
            continue
        exam_data = json.loads(exam_str)
        scramble(email, exam_data)
        deadline_utc = datetime.utcfromtimestamp(int(deadline))
        deadline_pst = pytz.utc.localize(deadline_utc).astimezone(
            pytz.timezone("America/Los_Angeles"))
        deadline_string = deadline_pst.strftime("%I:%M%p")

        with render_latex(
                exam_data,
            {
                "emailaddress": sanitize_email(email),
                "deadline": deadline_string,
                "coursecode": prettify(exam.split("-")[0]),
                "description": subtitle,
                "examtype": exam_type,
                "semester": semester,
            },
                do_twice=do_twice,
        ) as pdf:
            pdf = Pdf.open(BytesIO(pdf))
            pdf.save(
                os.path.join(
                    out, "exam_" + email.replace("@", "_").replace(".", "_") +
                    ".pdf"),
                encryption=Encryption(owner=password, user=password),
            )
            pdf.close()
Exemple #2
0
def compile(exam, json, md, seed, json_out, out):
    """
    Compile one PDF or JSON (from Markdown), unencrypted.
    The exam may be deployed or local (in Markdown or JSON).
    If a seed is specified, it will scramble the exam.
    """
    if not out:
        out = ""

    pathlib.Path(out).mkdir(parents=True, exist_ok=True)

    if json:
        print("Loading exam...")
        exam_data = load(json)
    elif md:
        print("Compiling exam...")
        exam_text_data = md.read()
        exam_data = convert(exam_text_data)
    else:
        print("Fetching exam...")
        exam_data = get_exam(exam=exam)

    if seed:
        print("Scrambling exam...")
        exam_data = scramble(
            seed,
            exam_data,
        )

    if json_out:
        print("Dumping json...")
        dump(exam_data, json_out)
        return

    print("Rendering exam...")
    with render_latex(exam_data, {
            "coursecode": prettify(exam.split("-")[0]),
            "description": "Sample Exam."
    }) as pdf:
        pdf = Pdf.open(BytesIO(pdf))
        pdf.save(os.path.join(out, exam + ".pdf"))
        pdf.close()
Exemple #3
0
def send(exam, target, email, subject, filename):
    """
    Email an encrypted PDF to all students taking an exam. Specify `email` to email only a particular student.
    """
    if not target:
        target = "out/latex/" + exam

    course = prettify(exam.split("-")[0])

    filename = filename.format(course=course)
    subject = subject.format(course=course)
    body = (
        "Hello!\n\n"
        "You have an upcoming exam taking place on exam.cs61a.org. "
        "You should complete your exam on that website.\n\n"
        "Course: {course}\n"
        "Exam: {exam}\n\n"
        "However, if you encounter technical difficulties and are unable to do so, "
        "we have attached an encrypted PDF containing the same exam. "
        "You can then email your exam solutions to course staff before the deadline "
        "rather than submitting using exam.cs61a.org. "
        "To unlock the PDF, its password will be revealed on Piazza when the exam starts.\n\n"
        "Good luck, and remember to have fun!").format(course=course,
                                                       exam=exam)

    roster = []
    if email:
        roster = [email]
    else:
        for email, deadline in get_roster(exam=exam):
            if deadline:
                roster.append(email)

    key = get_api_key(exam=exam)

    print(("Subject: {subject}\n"
           "PDF filename: {filename}\n"
           "Body: {body}\n\n").format(body=body,
                                      filename=filename,
                                      subject=subject))
    if (input("Sending email to {} people - confirm? (y/N) ".format(
            len(roster))).lower() != "y"):
        exit(1)

    for email in roster:
        with open(
                os.path.join(
                    target, "exam_" +
                    email.replace("@", "_").replace(".", "_") + ".pdf"),
                "rb",
        ) as f:
            pdf = base64.b64encode(f.read()).decode("ascii")
        data = {
            "from": {
                "email": "*****@*****.**",
                "name": "CS 61A Exam Platform"
            },
            "personalizations": [{
                "to": [{
                    "email": email
                }],
                "substitutions": {}
            }],
            "subject":
            subject,
            "content": [{
                "type": "text/plain",
                "value": body
            }],
            "attachments": [{
                "content": pdf,
                "type": "application/pdf",
                "filename": filename,
                "disposition": "attachment",
            }],
        }

        send_email_local(key, data)
Exemple #4
0
def compile(
    exam,
    json,
    md,
    seed,
    subtitle,
    with_solutions,
    exam_type,
    semester,
    json_out,
    merged_md,
    draft,
    out,
):
    """
    Compile one PDF or JSON (from Markdown), unencrypted.
    The exam may be deployed or local (in Markdown or JSON).
    If a seed is specified, it will scramble the exam.
    """
    if not out:
        out = ""

    pathlib.Path(out).mkdir(parents=True, exist_ok=True)

    if json:
        print("Loading exam...")
        exam_data = load(json)
    elif md:
        exam_text_data = md.read()
        if merged_md:
            buff = LineBuffer(exam_text_data)
            handle_imports(buff, path=os.path.dirname(md.name))
            merged_md.write("\n".join(buff.lines))
            return
        print("Compiling exam...")
        exam_data = convert(exam_text_data, path=os.path.dirname(md.name), draft=draft)
    else:
        print("Fetching exam...")
        exam_data = get_exam(exam=exam)

    if seed:
        print("Scrambling exam...")
        exam_data = scramble(seed, exam_data, keep_data=with_solutions)

    def remove_solutions_from_groups(groups):
        for group in groups:
            # if isinstance(group, dict):
            group.pop("solution", None)
            if group.get("type") == "group":
                remove_solutions_from_groups(group.get("elements", []))

    if not seed and not with_solutions:
        print("Removing solutions...")
        groups = exam_data.get("groups", [])
        remove_solutions_from_groups(groups)

    if json_out:
        print("Dumping json...")
        dump(exam_data, json_out, indent=4, sort_keys=True)
        return

    print("Rendering exam...")
    settings = {
        "coursecode": prettify(exam.split("-")[0]),
        "description": subtitle,
        "examtype": exam_type,
        "semester": semester,
    }
    if seed:
        settings["emailaddress"] = sanitize_email(seed)
    with render_latex(exam_data, settings) as pdf:
        pdf = Pdf.open(BytesIO(pdf))
        pdf.save(os.path.join(out, exam + ".pdf"))
        pdf.close()