Beispiel #1
0
def sendFileToServer(name, sock):
    """Copy code file to server side"""
    send_message("OK", sock)
    module_code = recv_message(sock)
    assignment_name = recv_message(sock)
    student_id = recv_message(sock)
    filepath = recv_message(sock)
    filename = os.path.basename(filepath)
    path = const.get_program_file_path(module_code, assignment_name,
                                       student_id, filename)
    path_directory = os.path.dirname(path)
    if not os.path.isdir(path_directory):
        os.makedirs(path_directory)

    delete_all_output_files(path_directory)

    send_message("Start sending", sock)
    with open(path, 'wb') as f:
        while True:
            data = recv_message(sock)
            if data.endswith("DONE"):
                content, done_str = data.split("DONE")
                f.write(str(content).encode())
                break
            f.write(data)
    send_message("End sending", sock)
    RetrCommand(name, sock)
Beispiel #2
0
def createVarsFile(name, sock):
    """Create vars file for a specific student"""
    send_message("OK", sock)
    module_code = recv_message(sock)
    student_id = recv_message(sock)
    assignment_name = recv_message(sock)
    vars_filepath = const.get_vars_file_path(module_code, assignment_name,
                                             student_id)
    vars_directory = os.path.dirname(vars_filepath)
    if not os.path.isdir(vars_directory):
        os.makedirs(vars_directory)

    submissions_archive.archive(student_id, module_code, const.whatAY(),
                                assignment_name)

    date_file = vars_directory + "/submission-date.txt"
    current_date = datetime.now()
    current_date = current_date.strftime(SUBMISSION_DATE_FORMAT)

    with open(date_file, 'w+') as file:
        file.write(current_date)

    if not os.path.exists(vars_filepath):
        with open(vars_filepath, 'w'):
            pass
        send_message("Success", sock)
    elif os.path.isfile(vars_directory + "/reinit.attempts"):
        send_message("Reinit", sock)
    else:
        send_message("Failed", sock)
    RetrCommand(name, sock)
Beispiel #3
0
def checkAttemptsLeft(name, sock):
    """check number of attempts left"""
    send_message("OK", sock)
    module_code = recv_message(sock)
    student_id = recv_message(sock)
    assignment_name = recv_message(sock)

    send_message(_checkAttemptsLeft(module_code, assignment_name, student_id),
                 sock)

    RetrCommand(name, sock)
Beispiel #4
0
def checkIfAssignmentName(name, sock):
    """check if an assignment exists"""
    send_message("OK", sock)
    module_code = recv_message(sock)
    assignment_name = recv_message(sock)
    path = const.ROOTDIR + "/" + module_code + "/curr/assignments/"
    if os.path.exists(path):
        assignments = [name for name in os.listdir(path)]
        if assignment_name in assignments:
            send_message("True", sock)
        else:
            send_message("False", sock)
    else:
        send_message("False", sock)
    RetrCommand(name, sock)
Beispiel #5
0
def checkLatePenalty(name, sock):
    """Get late penalty"""
    send_message("OK", sock)
    module_code = recv_message(sock)
    assignment_name = recv_message(sock)
    student_id = recv_message(sock)

    dates = getDates(module_code, assignment_name)

    if dates is None:
        send_message(
            "assignment parameters are poorly defined or module definitions do not exist! Contact the lecturer",
            sock)
    else:
        start_day = dates[0]
        end_day = dates[1]
        cutoff_day = dates[2]
        now: datetime = datetime.now()

        student_exceptions = getStudentExceptions(module_code, assignment_name,
                                                  student_id)

        if end_day <= start_day or cutoff_day < end_day:
            send_message(
                "Invalid dates defined for this assignment: Start day < end day and end day must be <= cutoff day. Contact the lecturer",
                sock)
        else:
            if now < start_day:
                send_message("Submission too early!", sock)
            elif now > cutoff_day:
                _late_cutoff(now, student_exceptions, sock)
            elif start_day < now < end_day:
                # no late penalty applied
                send_message("0", sock)
            elif end_day < now < cutoff_day:
                if student_exceptions is None:
                    penalty_per_day: str = getPenaltyPerDay(
                        module_code, assignment_name, end_day, now)
                    if penalty_per_day == "False":
                        send_message("ERROR: penaltyPerDay doesn't exist!!!",
                                     sock)
                else:
                    penalty_per_day = getExceptionsPenalty(
                        student_exceptions, now)

                send_message(str(penalty_per_day), sock)
    RetrCommand(name, sock)
Beispiel #6
0
def checkCollectionFilename(name, sock):
    """check if the submitted filename matches the required filename"""
    send_message("OK", sock)
    filename = recv_message(sock)
    module_code = recv_message(sock)
    assignment_name = recv_message(sock)

    params_filepath = const.get_params_file_path(module_code, assignment_name)
    with open(params_filepath, 'r') as stream:
        data = yaml.safe_load(stream)
    if data.get("collectionFilename") and str(
            data.get("collectionFilename")) == filename:
        send_message("True", sock)
    else:
        send_message(
            str(data.get("collectionFilename")) + " is required!", sock)
    RetrCommand(name, sock)
Beispiel #7
0
def authentication_of_student(name, sock):
    """check if student_id exist in the class list"""
    send_message("OK", sock)
    # get current module code
    module_code = recv_message(sock)
    # get student id
    student_id = recv_message(sock)
    class_list_file_path = const.get_class_list_file_path(
        module_code=module_code.lower())
    if os.path.exists(class_list_file_path):
        with open(class_list_file_path, 'r') as f:
            for line in f:
                if student_id in line:
                    send_message("True", sock)
                    print(student_id + " has been authenticated ...")
                    RetrCommand(name, sock)
                    return
    send_message("False", sock)
    RetrCommand(name, sock)
Beispiel #8
0
def checkIfModuleExists(name, sock):
    """check if the moduleCode exists"""
    send_message("OK", sock)
    module_code = recv_message(sock)
    path = const.ROOTDIR
    if os.path.exists(path):
        modules = [name.lower() for name in os.listdir(path)]
        if module_code.lower() in modules:
            send_message("True", sock)
        else:
            send_message("False", sock)
    else:
        send_message("False", sock)
    RetrCommand(name, sock)
Beispiel #9
0
def initVarsFile(name, sock):
    """init vars.yaml file"""
    send_message("OK", sock)
    module_code = recv_message(sock)
    student_id = recv_message(sock)
    assignment_name = recv_message(sock)
    vars_filepath = const.get_vars_file_path(module_code, assignment_name,
                                             student_id)
    params_filepath = const.get_params_file_path(module_code, assignment_name)
    vars_directory = os.path.dirname(vars_filepath)

    if os.path.isfile(vars_directory + "/reinit.attempts"):
        print("Re-initialising attempts to excepted attempts")
        os.remove(vars_directory + "/reinit.attempts")
        re_initialise_attempts(vars_filepath, module_code, assignment_name,
                               student_id)
    else:
        with open(params_filepath, 'r') as stream:
            params: dict = yaml.safe_load(stream)

        data = {
            "attemptsLeft":
            get_total_attempts(module_code, assignment_name, student_id),
            "marks":
            0,
        }

        if 'attendance' in params:
            data['attendance'] = 0

        if 'compilation' in params:
            data['compilation'] = 0

        with open(vars_filepath, 'w') as f:
            yaml.dump(data, f, default_flow_style=False)

    RetrCommand(name, sock)
Beispiel #10
0
def RetrCommand(name, sock: socket.socket):
    msg = recv_message(sock)
    print("Received command \"%s\"" % msg)

    if msg == "Authentication":
        time.sleep(.1)
        authentication_of_student(name, sock)
    elif msg == "Check attempts left":
        time.sleep(.1)
        checkAttemptsLeft(name, sock)
    elif msg == "Checking Assignment Name":
        time.sleep(.1)
        checkIfAssignmentName(name, sock)
    elif msg == "Check module exists":
        time.sleep(.1)
        checkIfModuleExists(name, sock)
    elif msg == "Create vars file":
        time.sleep(.1)
        createVarsFile(name, sock)
    elif msg == "Init vars file":
        time.sleep(.1)
        initVarsFile(name, sock)
    elif msg == "Check late penalty":
        time.sleep(.1)
        checkLatePenalty(name, sock)
    elif msg == "Check collection filename":
        time.sleep(.1)
        checkCollectionFilename(name, sock)
    elif msg == "Send file to server":
        time.sleep(.1)
        sendFileToServer(name, sock)
    elif msg == "Get exec result":
        time.sleep(.1)
        getExecResult(name, sock)
    else:
        print(f"Unknown Message: {msg}")
Beispiel #11
0
def getExecResult(name, sock):
    """Exec the program and get exec result"""
    send_message("OK", sock)
    module_code = recv_message(sock)
    assignment_name = recv_message(sock)
    student_id = recv_message(sock)
    file_suffix = recv_message(sock)
    penalty = recv_message(sock)
    curr_marks: int = 0
    result_msg: str = ""

    required_code_filename = get_required_code_filename(
        module_code, assignment_name)
    code_filepath = const.get_program_file_path(module_code, assignment_name,
                                                student_id,
                                                required_code_filename)
    params_filepath = const.get_params_file_path(module_code, assignment_name)
    vars_filepath = const.get_vars_file_path(module_code, assignment_name,
                                             student_id)
    vars_directory = os.path.dirname(vars_filepath)
    with open(params_filepath, 'r') as stream:
        data: dict = yaml.safe_load(stream)
    with open(vars_filepath, 'r') as stream:
        vars_data: dict = yaml.safe_load(stream)

    attempts_left = _checkAttemptsLeft(module_code, assignment_name,
                                       student_id)

    # check if attempts left
    if attempts_left != "False" and int(attempts_left) > 0:
        if "tests" in data and data["tests"]:
            tests = data["tests"]
            # if attendance exists, check attendance, assign marks
            if "attendance" in tests:
                attendance = tests["attendance"]
                attendance_marks = int(attendance["marks"])
                attendance_tag = attendance["tag"]
                curr_marks = curr_marks + attendance_marks
                result_msg += "%s: %d/%d\n" % (
                    attendance_tag, attendance_marks, attendance_marks)
                vars_data["attendance"] = attendance_marks
            """Execute the program specified by test"""
            # if compilation exists, check compilation, assign marks

            with handinexecutor.start() as executor:
                compilation_successful = True
                if "compilation" in tests:
                    compilation = tests["compilation"]
                    compilation_marks = int(compilation["marks"])
                    compilation_tag = compilation["tag"]
                    compilation_command = compilation["command"]

                    compile_proc = executor.compile(
                        path_to_file=code_filepath,
                        compile_command=compilation_command,
                        language=None)
                    compilation_successful = compile_proc.exit_code == 0

                    if compilation_successful:
                        vars_data["compilation"] = compilation_marks
                        result_msg += "%s: %d/%d\n" % (compilation_tag,
                                                       compilation_marks,
                                                       compilation_marks)
                        curr_marks += compilation_marks
                    else:
                        # compilation failed
                        result_msg += "%s: %d/%d\n" % (compilation_tag, 0,
                                                       compilation_marks)
                        vars_data["compilation"] = 0
                        test_output(vars_directory, "compilation",
                                    compile_proc.stderr, False)
                        with open(vars_filepath, 'w') as f:
                            yaml.dump(vars_data, f)

                if compilation_successful:
                    for key in tests.keys():
                        if key.startswith("test"):
                            test_marks = int(tests[key]["marks"])
                            test_tag = tests[key]["tag"]
                            test_command = tests[key]["command"]
                            input_data_file_path, answer_file_path, filter_file_path = get_file_paths(
                                tests[key])
                            filter_command = tests[key]["filterCommand"]

                            stdin_input = None
                            if input_data_file_path is not None and input_data_file_path != '':
                                input_data_file = open(input_data_file_path,
                                                       'r')
                                stdin_input = input_data_file.read()
                                input_data_file.close()

                            # change working directory
                            os.chdir(os.path.dirname(code_filepath))
                            exec1 = executor.run(path_to_file=code_filepath,
                                                 run_command=test_command,
                                                 language=None,
                                                 stdin=stdin_input)

                            if exec1.exit_code != 0:
                                # custom test failed
                                result_msg += "%s: %d/%d</br> " % (test_tag, 0,
                                                                   test_marks)
                                test_marks = 0
                                test_output(vars_directory, key,
                                            "Stderr: " + exec1.stderr, False)
                            else:
                                if exec1.timeout:
                                    # custom test failed
                                    result_msg += "%s: %d/%d</br> " % (
                                        test_tag, 0, test_marks)
                                    test_marks = 0
                                    test_output(vars_directory, key,
                                                "Test execution timed out",
                                                False)
                                else:
                                    if const.PROGRAM_SYSCALL_MONITORING and not executor.copy_syscall_log(
                                            vars_directory, key):
                                        print(
                                            "Warning: failed to copy syscall_monitor log"
                                        )

                                    output = exec1.stdout
                                    if answer_file_path is not None and answer_file_path != '':
                                        answer_file = open(
                                            answer_file_path, 'rb')
                                        answer = answer_file.read()

                                        # use stdout and answer as two argv of filter file, then perform filtering
                                        # TODO: may need to be changed ...
                                        if (filter_file_path is not None and filter_file_path != '') and \
                                                (filter_command is not None and filter_command != ''):
                                            try:
                                                # copy filter file to student dir
                                                filter_filename = os.path.basename(
                                                    filter_file_path)
                                                filter_file_path_dst = os.path.join(
                                                    os.path.dirname(
                                                        code_filepath),
                                                    filter_filename)
                                                with open(
                                                        filter_file_path_dst,
                                                        'w'):
                                                    pass
                                                shutil.copyfile(
                                                    filter_file_path,
                                                    filter_file_path_dst)

                                                os.chdir(
                                                    os.path.dirname(
                                                        filter_file_path_dst))
                                                output = replace_whitespace_with_underscore(
                                                    output.decode('utf-8')
                                                ).encode('utf-8')
                                                answer = replace_whitespace_with_underscore(
                                                    answer.decode('utf-8')
                                                ).encode('utf-8')
                                                command: str = (
                                                    filter_command + " %s %s"
                                                ) % (output.decode('utf-8'),
                                                     answer.decode('utf-8'))
                                                filter_proc = Popen(
                                                    command,
                                                    stdin=PIPE,
                                                    stdout=PIPE,
                                                    stderr=PIPE,
                                                    shell=True)
                                                stdout, stderr = filter_proc.communicate(
                                                )
                                                output, answer = stdout.decode(
                                                    'utf-8').split(' ')
                                            except Exception as e:
                                                print(e)
                                        else:
                                            answer = answer.decode()

                                        if compare_output_with_answer(
                                                output, answer):
                                            # custom test success
                                            curr_marks = curr_marks + test_marks
                                            result_msg += "%s: %d/%d</br> " % (
                                                test_tag, test_marks,
                                                test_marks)
                                            test_output(
                                                vars_directory, key, output,
                                                True)
                                        else:
                                            # custom test failed
                                            result_msg += "%s: %d/%d</br> " % (
                                                test_tag, 0, test_marks)
                                            test_marks = 0
                                            test_output(
                                                vars_directory, key, output,
                                                False)
                                            test_output(
                                                vars_directory, key, answer,
                                                None, "Answer File")
                                    else:
                                        # custom test success
                                        curr_marks = curr_marks + test_marks
                                        result_msg += "%s: %d/%d</br> " % (
                                            test_tag, test_marks, test_marks)
                                        test_output(vars_directory, key,
                                                    output, True)

                            vars_data[key] = test_marks

        # check assignment attempts left and update attempts left
        if "attemptsLeft" in vars_data and vars_data["attemptsLeft"]:
            attemptsLeft = vars_data["attemptsLeft"]
            vars_data["attemptsLeft"] = attemptsLeft - 1
            attemptsLeft -= 1
            if attemptsLeft <= 0:
                vars_data["attemptsLeft"] = 0
                attemptsLeft = 0
            with open(vars_filepath, 'w') as f:
                yaml.dump(vars_data, f)
            result_msg += "</br>You have %s attempts left</br> " % str(
                attemptsLeft)

            # apply penalty
            curr_marks = int(
                round(curr_marks - (curr_marks * (int(penalty) / 100))))
            result_msg += f"</br>Penalty: {penalty}%</br> "

            if curr_marks < 0:
                curr_marks = 0

            # update student marks
            with open(vars_filepath, 'r') as stream:
                vars_data2: dict = yaml.safe_load(stream)
            if "marks" in vars_data2.keys():
                vars_data2["marks"] = curr_marks
            with open(vars_filepath, 'w') as f:
                yaml.dump(vars_data2, f)
            result_msg += f"</br>Total marks: {curr_marks}</br> "
            submissions_archive.cull_old_archives(
            )  # this is a successful submission so, you are free to remove old ones
    else:
        result_msg = "Sorry, you have no attempts left for this assignment!"
        submissions_archive.undo_archive(
        )  # unsuccessful submission, remove newest archive and don't remove any old ones

    send_message(result_msg, sock)
    RetrCommand(name, sock)