├── test.html ├── classes ├── renderers │ ├── coursework_renderer.php │ ├── submission_renderer.php │ └── personal_deadline_renderer.php ├── controllers │ └── allocations_controller.php ├── allocation │ ├── moderatable.php │ ├── table │ │ └── row │ │ │ └── processor.php │ ├── allocatable.php │ ├── widget.php │ └── strategy │ │ └── group_assessor.php ├── models │ ├── reminder.php │ ├── null_feedback.php │ ├── assessment_set_membership.php │ ├── null_user.php │ └── plagiarism_flag.php ├── render_helpers │ └── grading_report │ │ ├── cells │ │ ├── allocatable_cell.php │ │ ├── cell_interface.php │ │ ├── status_cell.php │ │ ├── plagiarism_cell.php │ │ └── grade_for_gradebook_cell.php │ │ ├── base_renderer.php │ │ ├── multi_renderer.php │ │ ├── single_renderer.php │ │ ├── sub_rows │ │ ├── no_sub_rows.php │ │ └── sub_rows_interface.php │ │ └── component_factory_interface.php ├── auto_grader │ ├── auto_grader.php │ └── none.php ├── framework │ ├── test │ │ └── classes │ │ │ └── user_table.php │ └── decorator.php ├── decorators │ ├── coursework_groups_decorator.php │ └── submission_groups_decorator.php ├── export │ └── csv │ │ └── cells │ │ ├── group_cell.php │ │ ├── submissiontime_cell.php │ │ ├── submissiondate_cell.php │ │ ├── cell_interface.php │ │ ├── personaldeadline_cell.php │ │ ├── extensionreason_cell.php │ │ ├── finalgrade_cell.php │ │ ├── extensiondeadline_cell.php │ │ ├── name_cell.php │ │ ├── plagiarismflagstatus_cell.php │ │ ├── username_cell.php │ │ ├── plagiarismflagcomment_cell.php │ │ ├── extensionextrainfo_cell.php │ │ ├── submissionid_cell.php │ │ ├── assessor_cell.php │ │ └── submissionfileid_cell.php ├── event │ ├── course_module_viewed.php │ ├── feedback_changed.php │ ├── course_module_instance_list_viewed.php │ ├── coursework_deadline_changed.php │ ├── assessable_submitted.php │ └── coursework_plagiarism_flag_updated.php ├── stages │ ├── moderator.php │ └── final_agreed.php ├── plagiarism_helpers │ ├── base.php │ └── turnitin.php ├── grading_table_row_single.php ├── exceptions │ ├── access_denied.php │ └── late_submission.php ├── grading_table_row_multi.php ├── task │ ├── cron_task.php │ ├── unenrol_task.php │ └── enrol_task.php ├── user_row.php ├── personal_deadline │ └── allocatable.php ├── forms │ ├── upload_grading_sheet_form.php │ ├── view_all_students_mform.php │ └── personal_deadline_form.php ├── feedback_files.php └── files.php ├── .gitignore ├── pix ├── add.png ├── ln.gif ├── delete.png ├── edit.png ├── hide.png ├── show.png ├── submit.png ├── view.png ├── add-item.png ├── moderate.png ├── arrow-down.png ├── collapsed.png ├── connector.jpg ├── connector.png ├── disability.png ├── mitigation.png ├── add-feedback.png └── new-deadline.png ├── tests ├── files_for_uploading │ ├── Test_image.png │ ├── Test_document.docx │ └── Test_document_two.docx ├── cron_tester.php ├── behat │ ├── feedback_restrict_feedback_editing.feature │ ├── allocation_visibility_of_allocated_teachers.feature │ ├── allocation_automatic_allocations_disabled.feature │ ├── pages │ │ ├── student_submission_form.php │ │ ├── gradebook_page.php │ │ ├── new_extension_page.php │ │ ├── login_page.php │ │ ├── show_feedback_page.php │ │ └── edit_extension_page.php │ ├── submissions_file_upload_limit.feature │ ├── submissions_auto_finalisation.feature │ ├── feedback_zero_grades.feature │ ├── submissions_submit_onbehalf_student.feature │ ├── submissions_start_date.feature │ ├── feedback_auto_release_without_cron.feature │ ├── submissions_late_submissions.feature │ ├── allocation_visibility_of_allocated_students.feature │ ├── warnings.feature │ ├── enrolment_triggers.feature │ ├── installation_and_set_up.feature │ ├── feedback_group_marking.feature │ ├── allocation_automatic_equal_assessor_allocations.feature │ ├── submissions_student_submission.feature │ ├── blind_marking_visibiilty_for_agreed_graders_with_blind_marking.feature │ ├── submissions_deadlines.feature │ ├── blind_marking_visibiilty_for_agreed_graders_without_blind_marking.feature │ ├── feedback_files.feature │ ├── blind_marking_visibility_for_teachers_without_blind_marking.feature │ ├── blind_marking_visibility_for_teachers_with_blind_marking.feature │ ├── allocation_automatic_interacting_with_manual_allocations.feature │ ├── deadline_extension_reason_dropdown_list.feature │ ├── allocation_visibility_of_all_students_capability.feature │ ├── submissions_file_upload_types.feature │ ├── allocation_automatic_percentage_assessor_allocations.feature │ ├── deadline_extension.feature │ ├── feedback_group_feedback_for_students.feature │ ├── automatic_agreement.feature │ ├── feedback_publishing_grades.feature │ ├── feedback_single_marking.feature │ ├── submissions_group_submissions.feature │ ├── sampling_manual_sampling.feature │ └── feedback_rubrics.feature ├── classes │ ├── controllers │ │ └── deadline_extensions_controller_test.php │ ├── models │ │ ├── group_test.php │ │ └── moderation_set_membership_test.php │ ├── ability_test.php │ ├── grade_judge_test.php │ ├── router_test.php │ └── stages │ │ └── assessor_test.php └── renderer_test.php ├── db ├── caches.php ├── install.php ├── tasks.php ├── messages.php ├── log.php └── events.php ├── actions ├── deadline_extensions │ ├── edit.php │ ├── show.php │ ├── update.php │ ├── new.php │ └── create.php ├── submissions │ ├── edit.php │ ├── finalise.php │ ├── update.php │ ├── new.php │ └── create.php ├── moderations │ ├── update.php │ ├── create.php │ ├── edit.php │ ├── show.php │ └── new.php ├── plagiarism_flagging │ ├── update.php │ ├── create.php │ ├── edit.php │ └── new.php ├── feedbacks │ ├── update.php │ ├── create.php │ ├── show.php │ ├── edit.php │ └── new.php ├── personal_deadline.php ├── processallocation.php ├── selectallallocatables.php ├── allocationsession.php └── revert.php ├── backup └── moodle2 │ ├── backup_coursework_activity_task.class.php │ └── restore_coursework_activity_task.class.php ├── version.php └── renderer.php /test.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /classes/renderers/coursework_renderer.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /classes/renderers/submission_renderer.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | phpunit.xml 2 | *~ 3 | .idea/ 4 | #* 5 | -------------------------------------------------------------------------------- /pix/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/pix/add.png -------------------------------------------------------------------------------- /pix/ln.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/pix/ln.gif -------------------------------------------------------------------------------- /pix/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/pix/delete.png -------------------------------------------------------------------------------- /pix/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/pix/edit.png -------------------------------------------------------------------------------- /pix/hide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/pix/hide.png -------------------------------------------------------------------------------- /pix/show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/pix/show.png -------------------------------------------------------------------------------- /pix/submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/pix/submit.png -------------------------------------------------------------------------------- /pix/view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/pix/view.png -------------------------------------------------------------------------------- /pix/add-item.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/pix/add-item.png -------------------------------------------------------------------------------- /pix/moderate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/pix/moderate.png -------------------------------------------------------------------------------- /pix/arrow-down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/pix/arrow-down.png -------------------------------------------------------------------------------- /pix/collapsed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/pix/collapsed.png -------------------------------------------------------------------------------- /pix/connector.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/pix/connector.jpg -------------------------------------------------------------------------------- /pix/connector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/pix/connector.png -------------------------------------------------------------------------------- /pix/disability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/pix/disability.png -------------------------------------------------------------------------------- /pix/mitigation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/pix/mitigation.png -------------------------------------------------------------------------------- /pix/add-feedback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/pix/add-feedback.png -------------------------------------------------------------------------------- /pix/new-deadline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/pix/new-deadline.png -------------------------------------------------------------------------------- /tests/files_for_uploading/Test_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/tests/files_for_uploading/Test_image.png -------------------------------------------------------------------------------- /tests/files_for_uploading/Test_document.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/tests/files_for_uploading/Test_document.docx -------------------------------------------------------------------------------- /db/caches.php: -------------------------------------------------------------------------------- 1 | array( 5 | 'mode' => cache_store::MODE_APPLICATION 6 | ) 7 | ); -------------------------------------------------------------------------------- /tests/files_for_uploading/Test_document_two.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ULCC/open-mod_coursework/HEAD/tests/files_for_uploading/Test_document_two.docx -------------------------------------------------------------------------------- /tests/cron_tester.php: -------------------------------------------------------------------------------- 1 | dirroot.'/mod/coursework/lib.php'); 10 | 11 | coursework_cron(); -------------------------------------------------------------------------------- /classes/controllers/allocations_controller.php: -------------------------------------------------------------------------------- 1 | $id, 11 | ); 12 | $controller = new mod_coursework\controllers\deadline_extensions_controller($params); 13 | $controller->edit_deadline_extension(); -------------------------------------------------------------------------------- /actions/deadline_extensions/show.php: -------------------------------------------------------------------------------- 1 | $id, 11 | ); 12 | $controller = new mod_coursework\controllers\deadline_extensions_controller($params); 13 | $controller->show_deadline_extension(); -------------------------------------------------------------------------------- /classes/auto_grader/auto_grader.php: -------------------------------------------------------------------------------- 1 | $submissionid, 13 | ); 14 | $controller = new mod_coursework\controllers\submissions_controller($params); 15 | $controller->edit_submission(); -------------------------------------------------------------------------------- /actions/submissions/finalise.php: -------------------------------------------------------------------------------- 1 | $submissionid, 13 | ); 14 | $controller = new mod_coursework\controllers\submissions_controller($params); 15 | $controller->finalise_submission(); -------------------------------------------------------------------------------- /classes/models/null_feedback.php: -------------------------------------------------------------------------------- 1 | $moderationid, 16 | ); 17 | $controller = new mod_coursework\controllers\moderations_controller($params); 18 | $controller->update_moderation(); -------------------------------------------------------------------------------- /actions/plagiarism_flagging/update.php: -------------------------------------------------------------------------------- 1 | $flagid 15 | ); 16 | 17 | $controller = new mod_coursework\controllers\plagiarism_flagging_controller($params); 18 | $controller->update_plagiarism_flag(); -------------------------------------------------------------------------------- /actions/plagiarism_flagging/create.php: -------------------------------------------------------------------------------- 1 | $submissionid 15 | ); 16 | 17 | $controller = new mod_coursework\controllers\plagiarism_flagging_controller($params); 18 | $controller->create_plagiarism_flag(); -------------------------------------------------------------------------------- /classes/render_helpers/grading_report/sub_rows/no_sub_rows.php: -------------------------------------------------------------------------------- 1 | $id, 11 | ); 12 | $url = '/mod/coursework/actions/deadline_extensions/create.php'; 13 | $link = new \moodle_url($url, $params); 14 | $PAGE->set_url($link); 15 | 16 | $controller = new mod_coursework\controllers\deadline_extensions_controller($params); 17 | $controller->update_deadline_extension(); -------------------------------------------------------------------------------- /classes/render_helpers/grading_report/sub_rows/sub_rows_interface.php: -------------------------------------------------------------------------------- 1 | $submissionid, 14 | 'finalised' => $finalised, 15 | ); 16 | $controller = new mod_coursework\controllers\submissions_controller($params); 17 | $controller->update_submission(); -------------------------------------------------------------------------------- /tests/classes/controllers/deadline_extensions_controller_test.php: -------------------------------------------------------------------------------- 1 | assertEquals('deadline_extension', $controller->model_name()); 13 | } 14 | 15 | 16 | } -------------------------------------------------------------------------------- /actions/feedbacks/update.php: -------------------------------------------------------------------------------- 1 | $feedbackid, 17 | 'finalised' => $finalised, 18 | ); 19 | $controller = new mod_coursework\controllers\feedback_controller($params); 20 | $controller->update_feedback(); -------------------------------------------------------------------------------- /classes/auto_grader/none.php: -------------------------------------------------------------------------------- 1 | id, PARAM_INT); 9 | $allocatabletype = optional_param('allocatabletype', $USER->id, PARAM_ALPHANUMEXT); 10 | 11 | $params = array( 12 | 'courseworkid' => $courseworkid, 13 | 'allocatableid' => $allocatableid, 14 | 'allocatabletype' => $allocatabletype, 15 | ); 16 | $controller = new mod_coursework\controllers\deadline_extensions_controller($params); 17 | $controller->new_deadline_extension(); -------------------------------------------------------------------------------- /classes/export/csv/cells/group_cell.php: -------------------------------------------------------------------------------- 1 | name; 18 | } 19 | 20 | /** 21 | * @param $stage 22 | * @return string 23 | * @throws \coding_exception 24 | */ 25 | public function get_header($stage){ 26 | return get_string('group', 'coursework'); 27 | } 28 | } -------------------------------------------------------------------------------- /db/install.php: -------------------------------------------------------------------------------- 1 | rulename = $p; 24 | $dbrecord->pluginorder = $i; 25 | 26 | $DB->insert_record('coursework_sample_set_plugin',$dbrecord); 27 | $i++; 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /actions/submissions/new.php: -------------------------------------------------------------------------------- 1 | id, PARAM_INT); 13 | $allocatabletype = optional_param('allocatabletype', 'user', PARAM_ALPHANUMEXT); 14 | 15 | $params = array( 16 | 'courseworkid' => $courseworkid, 17 | 'allocatableid' => $allocatableid, 18 | 'allocatabletype' => $allocatabletype, 19 | ); 20 | $controller = new mod_coursework\controllers\submissions_controller($params); 21 | $controller->new_submission(); -------------------------------------------------------------------------------- /tests/classes/models/group_test.php: -------------------------------------------------------------------------------- 1 | resetAfterTest(); 12 | } 13 | 14 | public function test_find() { 15 | 16 | $generator = $this->getDataGenerator(); 17 | $course = $generator->create_course(); 18 | 19 | $group = new stdClass(); 20 | $group->courseid = $course->id; 21 | $group = $generator->create_group($group); 22 | 23 | $this->assertNotEmpty($group->name); 24 | $this->assertEquals($group->name, group::find($group->id)->name); 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /classes/export/csv/cells/submissiontime_cell.php: -------------------------------------------------------------------------------- 1 | submission_time($submission); 19 | } 20 | 21 | /** 22 | * @param $stage 23 | * @return string 24 | * @throws \coding_exception 25 | */ 26 | public function get_header($stage){ 27 | return get_string('submissiontime', 'coursework'); 28 | 29 | } 30 | 31 | 32 | } -------------------------------------------------------------------------------- /tests/classes/models/moderation_set_membership_test.php: -------------------------------------------------------------------------------- 1 | resetAfterTest(); 11 | } 12 | 13 | public function test_find() { 14 | global $DB; 15 | 16 | $record = new stdClass(); 17 | $record->allocatableid = 22; 18 | $record->allocatabletype = 'user'; 19 | $record->courseworkid = 44; 20 | $record->id = $DB->insert_record('coursework_sample_set_mbrs', $record); 21 | 22 | $this->assertEquals(22, \mod_coursework\models\assessment_set_membership::find($record->id)->allocatableid); 23 | } 24 | } -------------------------------------------------------------------------------- /actions/deadline_extensions/create.php: -------------------------------------------------------------------------------- 1 | id, PARAM_INT); 9 | $allocatabletype = optional_param('allocatabletype', $USER->id, PARAM_ALPHANUMEXT); 10 | 11 | $params = array( 12 | 'courseworkid' => $courseworkid, 13 | 'allocatableid' => $allocatableid, 14 | 'allocatabletype' => $allocatabletype, 15 | ); 16 | $url = '/mod/coursework/actions/deadline_extensions/create.php'; 17 | $link = new \moodle_url($url, $params); 18 | $PAGE->set_url($link); 19 | 20 | $controller = new mod_coursework\controllers\deadline_extensions_controller($params); 21 | $controller->create_deadline_extension(); -------------------------------------------------------------------------------- /classes/export/csv/cells/submissiondate_cell.php: -------------------------------------------------------------------------------- 1 | time_submitted(), $this->dateformat); 20 | } 21 | 22 | /** 23 | * @param $stage 24 | * @return string 25 | * @throws \coding_exception 26 | */ 27 | public function get_header($stage){ 28 | return get_string('submissiondate', 'coursework'); 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /actions/moderations/create.php: -------------------------------------------------------------------------------- 1 | id, PARAM_INT); 15 | $stage_identifier = optional_param('stage_identifier', '', PARAM_ALPHANUMEXT); 16 | 17 | $params = array( 18 | 'submissionid' => $submissionid, 19 | 'feedbackid' => $feedbackid, 20 | 'moderatorid' => $moderatorid, 21 | 'stage_identifier' => $stage_identifier, 22 | ); 23 | $controller = new mod_coursework\controllers\moderations_controller($params); 24 | $controller->create_moderation(); -------------------------------------------------------------------------------- /classes/export/csv/cells/cell_interface.php: -------------------------------------------------------------------------------- 1 | data['objecttable'] = 'coursework'; 15 | parent::init(); 16 | } 17 | 18 | /** 19 | * @return \moodle_url 20 | */ 21 | public function get_url() { 22 | return new \moodle_url("/mod/$this->objecttable/view.php", array('id' => $this->contextinstanceid)); 23 | } 24 | // You might need to override get_url() and get_legacy_log_data() if view mode needs to be stored as well. 25 | } 26 | 27 | 28 | -------------------------------------------------------------------------------- /classes/models/assessment_set_membership.php: -------------------------------------------------------------------------------- 1 | submission_personal_deadline(); 19 | 20 | return userdate($personal_deadline, $this->dateformat); 21 | } 22 | 23 | /** 24 | * @param $stage 25 | * @return string 26 | * @throws \coding_exception 27 | */ 28 | public function get_header($stage){ 29 | return get_string('personal_deadline', 'coursework'); 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /classes/export/csv/cells/extensionreason_cell.php: -------------------------------------------------------------------------------- 1 | extension_exists($student)) { 19 | $reason = $this->get_extension_reason_for_csv($student); 20 | } else { 21 | $reason = ''; 22 | } 23 | return $reason; 24 | } 25 | 26 | /** 27 | * @param $stage 28 | * @return string 29 | * @throws \coding_exception 30 | */ 31 | public function get_header($stage){ 32 | return get_string('extensionreason', 'coursework'); 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /classes/export/csv/cells/finalgrade_cell.php: -------------------------------------------------------------------------------- 1 | get_final_grade() == false || $submission->editable_final_feedback_exist()? '' : $this->get_actual_grade($submission->get_final_grade()); 20 | 21 | } 22 | 23 | /** 24 | * @param $stage 25 | * @return string 26 | * @throws \coding_exception 27 | */ 28 | public function get_header($stage){ 29 | return get_string('provisionalgrade', 'coursework'); 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /actions/feedbacks/create.php: -------------------------------------------------------------------------------- 1 | id, PARAM_INT); 15 | $stage_identifier = optional_param('stage_identifier', '', PARAM_ALPHANUMEXT); 16 | $finalised = !!optional_param('submitbutton', 0, PARAM_TEXT); 17 | 18 | $params = array( 19 | 'submissionid' => $submissionid, 20 | 'isfinalgrade' => $isfinalgrade, 21 | 'assessorid' => $assessorid, 22 | 'stage_identifier' => $stage_identifier, 23 | 'finalised' => $finalised, 24 | ); 25 | $controller = new mod_coursework\controllers\feedback_controller($params); 26 | $controller->create_feedback(); -------------------------------------------------------------------------------- /classes/export/csv/cells/extensiondeadline_cell.php: -------------------------------------------------------------------------------- 1 | extension_exists($student)) { 19 | $deadline = $this->get_extension_date_for_csv($student); 20 | } else { 21 | $deadline = ''; 22 | } 23 | return $deadline; 24 | } 25 | 26 | /** 27 | * @param $stage 28 | * @return string 29 | * @throws \coding_exception 30 | */ 31 | public function get_header($stage){ 32 | return get_string('extensiondeadline', 'coursework'); 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /classes/export/csv/cells/name_cell.php: -------------------------------------------------------------------------------- 1 | can_view_hidden()){ 20 | $name = $student->lastname . ' ' . $student->firstname; 21 | } else { 22 | $name = get_string('hidden', 'coursework'); 23 | } 24 | 25 | return $name; 26 | } 27 | 28 | /** 29 | * @param $stage 30 | * @return string 31 | * @throws \coding_exception 32 | */ 33 | public function get_header($stage){ 34 | return get_string('studentname', 'coursework'); 35 | } 36 | } -------------------------------------------------------------------------------- /classes/export/csv/cells/plagiarismflagstatus_cell.php: -------------------------------------------------------------------------------- 1 | plagiarism_flagged($submission)) { 19 | $flag = $this->get_plagiarism_flag_status_for_csv($submission); 20 | } else { 21 | $flag = ''; 22 | } 23 | return $flag; 24 | } 25 | 26 | /** 27 | * @param $stage 28 | * @return string 29 | * @throws \coding_exception 30 | */ 31 | public function get_header($stage){ 32 | return get_string('plagiarismstatus', 'coursework'); 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /classes/export/csv/cells/username_cell.php: -------------------------------------------------------------------------------- 1 | can_view_hidden()){ 20 | $username = $student->username; 21 | } else { 22 | $username = get_string('hidden', 'coursework'); 23 | } 24 | 25 | return $username; 26 | } 27 | 28 | /** 29 | * @param $stage 30 | * @return string 31 | * @throws \coding_exception 32 | */ 33 | public function get_header($stage){ 34 | return get_string('studentusername', 'coursework'); 35 | 36 | } 37 | } -------------------------------------------------------------------------------- /classes/export/csv/cells/plagiarismflagcomment_cell.php: -------------------------------------------------------------------------------- 1 | plagiarism_flagged($submission)) { 19 | $flag = $this->get_plagiarism_flag_comment_for_csv($submission); 20 | } else { 21 | $flag = ''; 22 | } 23 | return $flag; 24 | } 25 | 26 | /** 27 | * @param $stage 28 | * @return string 29 | * @throws \coding_exception 30 | */ 31 | public function get_header($stage){ 32 | return get_string('plagiarismcomment', 'coursework'); 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /classes/export/csv/cells/extensionextrainfo_cell.php: -------------------------------------------------------------------------------- 1 | extension_exists($student)) { 20 | $extra_info = $this->get_extension_extra_info_for_csv($student); 21 | } else { 22 | $extra_info = ''; 23 | } 24 | return $extra_info; 25 | } 26 | 27 | /** 28 | * @param $stage 29 | * @return string 30 | * @throws \coding_exception 31 | */ 32 | public function get_header($stage){ 33 | return get_string('extensionextrainfo', 'coursework'); 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /classes/stages/moderator.php: -------------------------------------------------------------------------------- 1 | dirroot . '/mod/coursework/tests/behat/pages/page_base.php'); 8 | 9 | 10 | /** 11 | * Holds the functions that know about the HTML structure of the student page. 12 | * 13 | * 14 | */ 15 | class mod_coursework_behat_student_submission_form extends mod_coursework_behat_page_base { 16 | 17 | public function click_on_the_save_submission_button() { 18 | $this->getPage()->find('xpath', "//input[@id='id_submitbutton']")->press(); 19 | } 20 | 21 | public function click_on_the_save_and_finalise_submission_button() { 22 | $this->getPage()->find('css', "#id_finalisebutton")->press(); 23 | } 24 | 25 | public function should_not_have_the_save_and_finalise_button() { 26 | $buttons = $this->getPage()->findAll('css', '#id_finalisebutton'); 27 | assertEmpty($buttons); 28 | } 29 | } -------------------------------------------------------------------------------- /tests/classes/ability_test.php: -------------------------------------------------------------------------------- 1 | setAdminUser(); 16 | $this->resetAfterTest(); 17 | } 18 | 19 | public function test_allow_saves_rules() { 20 | $ability = new ability($this->create_a_teacher(), $this->create_a_coursework()); 21 | $this->assertTrue($ability->can('show', $this->get_coursework())); 22 | } 23 | 24 | public function test_ridiculous_things_are_banned_by_default_if_not_mentioned() { 25 | $ability = new ability($this->create_a_teacher(), $this->create_a_coursework()); 26 | $this->assertFalse($ability->can('set_fire_to', $this->get_coursework())); 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /tests/behat/submissions_file_upload_limit.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: File upload limits 3 | 4 | As a course leader 5 | I want to be able to limit the number of files that a student can upload 6 | So that they must submit a specific number 7 | 8 | Background: 9 | Given there is a course 10 | And there is a coursework 11 | And I am logged in as a student 12 | 13 | @javascript 14 | Scenario: I am prevented from uploading more files than specified 15 | Given the coursework "maxfiles" setting is "2" in the database 16 | 17 | When I visit the coursework page 18 | And I click on the new submission button 19 | And I upload "mod/coursework/tests/files_for_uploading/Test_document.docx" file to "Upload a file" filemanager 20 | And I upload "mod/coursework/tests/files_for_uploading/Test_document_two.docx" file to "Upload a file" filemanager 21 | Then the file upload button should not be visible 22 | 23 | -------------------------------------------------------------------------------- /classes/plagiarism_helpers/base.php: -------------------------------------------------------------------------------- 1 | coursework = $coursework; 22 | } 23 | 24 | /** 25 | * @return coursework 26 | */ 27 | protected function get_coursework() { 28 | return $this->coursework; 29 | } 30 | 31 | /** 32 | * @return string 33 | */ 34 | abstract public function file_submission_instructions(); 35 | 36 | /** 37 | * @return bool 38 | */ 39 | abstract public function enabled(); 40 | 41 | /** 42 | * @return string 43 | */ 44 | abstract public function human_readable_name(); 45 | 46 | } -------------------------------------------------------------------------------- /tests/behat/submissions_auto_finalisation.feature: -------------------------------------------------------------------------------- 1 | Feature: Auto finalising before cron runs 2 | 3 | As a teacher 4 | I want to see all work finalised as soon as the deadline passes, without having to 5 | wait for the cron to run 6 | So that I can start marking immediately 7 | 8 | Background: 9 | Given there is a course 10 | And there is a coursework 11 | And there is a student 12 | And the student has a submission 13 | 14 | Scenario: Teacher visits the page and sees the submission is finalised when the deadline has passed 15 | Given I am logged in as a teacher 16 | And the coursework deadline has passed 17 | When I visit the coursework page 18 | Then I should see "Ready to grade" 19 | 20 | Scenario: Teacher visits the page and sees the submission is not finalised when the deadline has not passed 21 | Given I am logged in as a teacher 22 | When I visit the coursework page 23 | Then I should not see "Ready to grade" 24 | -------------------------------------------------------------------------------- /classes/export/csv/cells/submissionid_cell.php: -------------------------------------------------------------------------------- 1 | id; 18 | } 19 | 20 | /** 21 | * @param $stage 22 | * @return string 23 | * @throws \coding_exception 24 | */ 25 | public function get_header($stage){ 26 | return get_string('submissionid', 'coursework'); 27 | } 28 | 29 | public function validate_cell($value,$submissionid,$stage_dentifier='',$uploadedgradecells = array()) { 30 | global $DB; 31 | return ($DB->record_exists('coursework_submissions',array('id'=>$submissionid,'courseworkid'=>$this->coursework->id()))) ? true: get_string('submissionnotfoundincoursework','coursework'); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /classes/grading_table_row_single.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | namespace mod_coursework; 18 | 19 | use coding_exception; 20 | 21 | defined('MOODLE_INTERNAL') || die(); 22 | 23 | 24 | /** 25 | * Single row of the grading table for when there is just one marker 26 | */ 27 | class grading_table_row_single extends grading_table_row_base { 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /backup/moodle2/backup_coursework_activity_task.class.php: -------------------------------------------------------------------------------- 1 | dirroot . '/mod/coursework/backup/moodle2/backup_coursework_stepslib.php'); 4 | 5 | class backup_coursework_activity_task extends backup_activity_task 6 | { 7 | static public function encode_content_links($content) 8 | { 9 | global $CFG; 10 | 11 | $base = preg_quote($CFG->wwwroot, "/"); 12 | 13 | //These have to be picked up by the restore code COURSEWORK... are arbitrary 14 | $search="/(".$base."\/mod\/coursework\/index.php\?id\=)([0-9]+)/"; 15 | $content= preg_replace($search, '$@COURSEWORKINDEX*$2@$', $content); 16 | 17 | $search="/(".$base."\/mod\/coursework\/view.php\?id\=)([0-9]+)/"; 18 | $content= preg_replace($search, '$@COURSEWORKBYID*$2@$', $content); 19 | 20 | return $content; 21 | } 22 | 23 | protected function define_my_settings() 24 | { 25 | } 26 | 27 | protected function define_my_steps() 28 | { 29 | $this->add_step(new backup_coursework_activity_structure_step('coursework_structure', 'coursework.xml')); 30 | } 31 | } -------------------------------------------------------------------------------- /classes/event/feedback_changed.php: -------------------------------------------------------------------------------- 1 | data['crud'] = 'c'; 31 | $this->data['edulevel'] = self::LEVEL_TEACHING; 32 | $this->data['objecttable'] = 'coursework_feedbacks'; 33 | } 34 | 35 | 36 | 37 | 38 | } -------------------------------------------------------------------------------- /tests/behat/feedback_zero_grades.feature: -------------------------------------------------------------------------------- 1 | Feature: Zero grades should show up just like the others 2 | 3 | As a teacher 4 | I want to be abel to award a grade of zero 5 | So that in case there is no work submitted or the work is truly and irredeemably useless, 6 | the student will know 7 | 8 | Background: 9 | Given there is a course 10 | And there is a coursework 11 | And there is a student 12 | And the student has a submission 13 | And the submission is finalised 14 | 15 | Scenario: Single maker final feedback 16 | Given the coursework "grade" setting is "9" in the database 17 | Given I am logged in as a teacher 18 | And the coursework "numberofmarkers" setting is "1" in the database 19 | When I visit the coursework page 20 | And I click the new single final feedback button for the student 21 | And I grade the submission as 0 using the simple form 22 | Then I should be on the coursework page 23 | And I should see the final grade as 0 on the single marker page 24 | 25 | -------------------------------------------------------------------------------- /classes/exceptions/access_denied.php: -------------------------------------------------------------------------------- 1 | get_path('coursework', array('coursework' => $coursework)); 26 | 27 | parent::__construct('access_denied', 'mod_coursework', $link, null, $message); 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /tests/behat/submissions_submit_onbehalf_student.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework @RVC_PT_83107284 2 | Feature: User can submit on behalf of a student 3 | 4 | As a user with the capability ‘coursework:submitonbehalfofstudent’ 5 | I can submit a file on behalf of a student. 6 | so that the work can be graded by the grader. 7 | 8 | Background: 9 | Given there is a course 10 | And there is a coursework 11 | And there is a student 12 | And I am logged in as a manager 13 | 14 | @javascript 15 | Scenario: As a teacher, I upload a file and see it on the coursework page as read only 16 | When I visit the coursework page 17 | And I click on the new submission button for the student 18 | And I upload "mod/coursework/tests/files_for_uploading/Test_document.docx" file to "Upload a file" filemanager 19 | And I save the submission 20 | Then I should be on the coursework page 21 | And I should see the file on the page 22 | 23 | When I click on the edit submission button for the student 24 | 25 | Then I should see "1" elements in "Upload a file" filemanager 26 | -------------------------------------------------------------------------------- /classes/exceptions/late_submission.php: -------------------------------------------------------------------------------- 1 | get_path('coursework', array('coursework' => $coursework)); 26 | 27 | parent::__construct('latesubmissionsnotallowed', 'mod_coursework', $link, null, $message); 28 | } 29 | } -------------------------------------------------------------------------------- /classes/export/csv/cells/assessor_cell.php: -------------------------------------------------------------------------------- 1 | coursework->get_assessor_allocation($submission, $stage_identifier ); 23 | if ($allocation) { 24 | $assessor = $this->get_assessor_name($allocation->assessorid); 25 | } else if($this->coursework->sampling_enabled()){ 26 | $assessor = 'Not in sample'; 27 | } 28 | return $assessor; 29 | } 30 | 31 | /** 32 | * @param $stage 33 | * @return string 34 | * @throws \coding_exception 35 | */ 36 | public function get_header($stage){ 37 | return get_string('assessorcsv', 'coursework', $stage); 38 | } 39 | 40 | 41 | 42 | } -------------------------------------------------------------------------------- /actions/personal_deadline.php: -------------------------------------------------------------------------------- 1 | id, PARAM_RAW); 10 | $allocatabletype = optional_param('allocatabletype', $USER->id, PARAM_ALPHANUMEXT); 11 | $setpersonaldeadlinespage = optional_param('setpersonaldeadlinespage', 0, PARAM_INT); 12 | $multipleuserdeadlines = optional_param('multipleuserdeadlines', 0, PARAM_INT); 13 | 14 | 15 | $allocatableid = (!empty($allocatableid_arr)) ? $allocatableid_arr : $allocatableid ; 16 | 17 | $params = array( 18 | 'courseworkid' => $courseworkid, 19 | 'allocatableid' => $allocatableid, 20 | 'allocatabletype' => $allocatabletype, 21 | 'setpersonaldeadlinespage' => $setpersonaldeadlinespage, 22 | 'multipleuserdeadlines' => $multipleuserdeadlines 23 | ); 24 | $controller = new mod_coursework\controllers\personal_deadlines_controller($params); 25 | $controller->new_personal_deadline(); 26 | -------------------------------------------------------------------------------- /tests/behat/submissions_start_date.feature: -------------------------------------------------------------------------------- 1 | Feature: Start date 2 | 3 | As a teacher 4 | I want to be able to restrict the start date of the coursework 5 | So that students will not begin to work on it until the right time 6 | 7 | Background: 8 | Given there is a course 9 | And there is a coursework 10 | 11 | Scenario: The student can submit when the start date is disabled 12 | Given the coursework start date is disabled 13 | When I log in as a student 14 | And I visit the coursework page 15 | Then I should see the new submission button 16 | 17 | Scenario: The student can not submit when the start date is in the future 18 | Given the coursework start date is in the future 19 | When I log in as a student 20 | And I visit the coursework page 21 | Then I should not see the new submission button 22 | 23 | Scenario: The student can submit when the start date is in the past 24 | Given the coursework start date is in the past 25 | When I log in as a student 26 | And I visit the coursework page 27 | Then I should see the new submission button -------------------------------------------------------------------------------- /classes/render_helpers/grading_report/cells/cell_interface.php: -------------------------------------------------------------------------------- 1 | wrapped_object->get_coursework()->is_configured_to_have_group_submissions()) { 27 | throw new \coding_exception('Asking for groups membership of a submissions when we are not using groups'); 28 | } 29 | 30 | $group = $this->wrapped_object->get_allocatable(); 31 | 32 | return groups_is_member($group->id, $user->id); 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /actions/submissions/create.php: -------------------------------------------------------------------------------- 1 | $courseworkid, 25 | 'finalised' => $finalised, 26 | 'allocatableid' => $allocatableid, 27 | 'allocatabletype' => $allocatabletype, 28 | ); 29 | if ($submissionid) { 30 | $params['submissionid'] = $submissionid; 31 | } 32 | $controller = new mod_coursework\controllers\submissions_controller($params); 33 | $controller->create_submission(); -------------------------------------------------------------------------------- /classes/stages/final_agreed.php: -------------------------------------------------------------------------------- 1 | . 17 | 18 | 19 | namespace mod_coursework\event; 20 | 21 | defined('MOODLE_INTERNAL') || die(); 22 | 23 | /** 24 | * Class course_module_instance_list_viewed is responsible for logging the fact that a user has looked at the list 25 | * of available coursework modules. 26 | * 27 | * @package mod_coursework\event 28 | */ 29 | class course_module_instance_list_viewed extends \core\event\course_module_instance_list_viewed { 30 | } -------------------------------------------------------------------------------- /classes/render_helpers/grading_report/cells/status_cell.php: -------------------------------------------------------------------------------- 1 | get_submission(); 20 | if ($submission) { 21 | $content = $submission->get_status_text(); 22 | } 23 | return $this->get_new_cell_with_class($content); 24 | } 25 | 26 | /** 27 | * @param array $options 28 | * @return string 29 | */ 30 | public function get_table_header($options = array()) { 31 | return get_string('tableheadstatus', 'coursework'); 32 | } 33 | 34 | /** 35 | * @return string 36 | */ 37 | public function get_table_header_class(){ 38 | return 'tableheadstatus'; 39 | } 40 | 41 | /** 42 | * @return string 43 | */ 44 | public function header_group() { 45 | return 'empty'; 46 | } 47 | } -------------------------------------------------------------------------------- /tests/behat/feedback_auto_release_without_cron.feature: -------------------------------------------------------------------------------- 1 | Feature: Auto releasing the student feedback without cron 2 | 3 | As a student 4 | I want to be able to see my grades and feedback as soon as the deadline 5 | for automatic release passes 6 | So that I get the feedback I need and don't think the system is broken 7 | 8 | Background: 9 | Given there is a course 10 | And there is a coursework 11 | And the coursework is set to single marker 12 | And there is a student 13 | And the student has a submission 14 | And there is a teacher 15 | And there is feedback for the submission from the teacher 16 | 17 | Scenario: auto release happens after the deadline without the cron running 18 | Given the coursework individual feedback release date has passed 19 | When I log in as a student 20 | And I visit the coursework page 21 | Then I should see "Released to students" 22 | 23 | Scenario: auto release does not happen before the deadline without the cron running 24 | Given the coursework individual feedback release date has not passed 25 | When I log in as a student 26 | And I visit the coursework page 27 | Then I should not see "Released to students" -------------------------------------------------------------------------------- /tests/behat/pages/gradebook_page.php: -------------------------------------------------------------------------------- 1 | dirroot . '/mod/coursework/tests/behat/pages/page_base.php'); 8 | 9 | 10 | /** 11 | * Holds the functions that know about the HTML structure of the student page. 12 | * 13 | * 14 | */ 15 | class mod_coursework_behat_gradebook_page extends mod_coursework_behat_page_base { 16 | 17 | /** 18 | * @param $coursework 19 | * @param $student 20 | * @param $grade 21 | */ 22 | public function should_have_coursework_grade_for_student($coursework, $student, $grade) { 23 | global $CFG; 24 | 25 | // This changed in 2.8, so we need a different selector 26 | if ((float)substr($CFG->release, 0, 5) > 2.6) { // 2.8 > 2.6 27 | $locator = '//th[a[contains(text(), "' . $coursework->name . '")]]/following-sibling::td[2]'; 28 | } else { 29 | $locator = '//th[a[contains(text(), "' . $coursework->name . '")]]/following-sibling::td[1]'; 30 | } 31 | $grade_cell = $this->getPage()->find('xpath', $locator); 32 | $cell_contents = $grade_cell->getText(); 33 | assertEquals($grade, $cell_contents, "Expected the gradebook grade to be '{$grade}', but got '{$cell_contents}'"); 34 | } 35 | } -------------------------------------------------------------------------------- /tests/behat/submissions_late_submissions.feature: -------------------------------------------------------------------------------- 1 | Feature: Late submissions 2 | 3 | As a teacher 4 | I want to be able to allow stuents to submit work past the deadline 5 | So that they can still get some credit even if their grades get capped 6 | 7 | Background: 8 | Given there is a course 9 | And there is a coursework 10 | And I am logged in as a student 11 | 12 | Scenario: not allowed to submit late if the setting does not allow it 13 | Given the coursework "allowlatesubmissions" setting is "0" in the database 14 | And the submission deadline has passed 15 | When I visit the coursework page 16 | Then I should not see the new submission button 17 | 18 | @javascript 19 | Scenario: allowed to submit late if the setting allows it 20 | Given the coursework "allowlatesubmissions" setting is "1" in the database 21 | And the submission deadline has passed 22 | When I visit the coursework page 23 | Then I should see the new submission button 24 | When I visit the new submission page 25 | And I upload "mod/coursework/tests/files_for_uploading/Test_document.docx" file to "Upload a file" filemanager 26 | And I press "Submit" 27 | Then I should be on the coursework page 28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/behat/allocation_visibility_of_allocated_students.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: Visibility of allocated students 3 | 4 | In order to make sure that the right assessors grade the right students 5 | As a course leader 6 | I want teachers to only see the students who have been allocated to them 7 | 8 | Background: 9 | Given there is a course 10 | And there is a coursework 11 | And the coursework "allocationenabled" setting is "1" in the database 12 | And the coursework "assessorallocationstrategy" setting is "none" in the database 13 | And there is a student 14 | And there is a teacher 15 | 16 | Scenario: Teachers do not see students who are unallocated 17 | Given I log in as the teacher 18 | And I visit the coursework page 19 | Then I should not see the student's name on the page 20 | 21 | Scenario: I can allocate a student manually and the teacher will see them 22 | Given I am logged in as a manager 23 | When I visit the allocations page 24 | And I manually allocate the student to the teacher 25 | And I save everything 26 | And I log out 27 | And I log in as the teacher 28 | And I visit the coursework page 29 | Then I should see the student's name on the page -------------------------------------------------------------------------------- /actions/feedbacks/show.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * @package mod 19 | * @subpackage coursework 20 | * @copyright 2011 University of London Computer Centre {@link ulcc.ac.uk} 21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 | */ 23 | 24 | require_once(dirname(__FILE__) . '/../../../../config.php'); 25 | 26 | global $CFG, $USER; 27 | 28 | $feedbackid = optional_param('feedbackid', 0, PARAM_INT); 29 | 30 | $params = array( 31 | 'feedbackid' => $feedbackid, 32 | ); 33 | $controller = new mod_coursework\controllers\feedback_controller($params); 34 | $controller->show_feedback(); -------------------------------------------------------------------------------- /tests/renderer_test.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * 19 | * @packagev mod 20 | * @subpackage coursework 21 | * @copyright 2012 ULCC {@link http://ulcc.ac.uk} 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die(); 26 | 27 | /** 28 | * Checks that parts of the renderer are doing what they should. Mostly for helper functions as 29 | * we will use Selenium for most of it. 30 | */ 31 | class renderer_test extends basic_testcase { 32 | 33 | public function test_equals() { 34 | $this->assertEquals(1, 1); 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /actions/feedbacks/edit.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * @package mod 19 | * @subpackage coursework 20 | * @copyright 2014 University of London Computer Centre {@link ulcc.ac.uk} 21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 | */ 23 | 24 | require_once(dirname(__FILE__) . '/../../../../config.php'); 25 | 26 | global $CFG, $USER; 27 | 28 | 29 | $feedbackid = optional_param('feedbackid', 0, PARAM_INT); 30 | 31 | $params = array( 32 | 'feedbackid' => $feedbackid, 33 | ); 34 | $controller = new mod_coursework\controllers\feedback_controller($params); 35 | $controller->edit_feedback(); -------------------------------------------------------------------------------- /classes/allocation/table/row/processor.php: -------------------------------------------------------------------------------- 1 | coursework = $coursework; 33 | $this->allocatable = $allocatable; 34 | } 35 | 36 | /** 37 | * Processes all the data in order to save it. 38 | * @param array $data 39 | */ 40 | public function process($data) { 41 | $stages = $this->coursework->marking_stages(); 42 | 43 | foreach ($stages as $stage) { 44 | if ($data) { 45 | $stage->process_allocation_form_row_data($this->allocatable, $data); 46 | } 47 | } 48 | } 49 | 50 | 51 | } -------------------------------------------------------------------------------- /tests/behat/warnings.feature: -------------------------------------------------------------------------------- 1 | Feature: warnings when settings are not right 2 | 3 | As a manager 4 | I want to know when there are issues with the setup of the coursework instance 5 | So that I can take corrective action before stuff goes wrong 6 | 7 | Background: 8 | Given there is a course 9 | And there is a coursework 10 | 11 | Scenario: managers see a warning about there being too few teachers 12 | Given there is a teacher 13 | And the coursework "numberofmarkers" setting is "3" in the database 14 | And I am logged in as a manager 15 | When I visit the coursework page 16 | Then I should see "There are only" 17 | 18 | Scenario: Teachers do not see the warnign about too few teachers 19 | Given there is a teacher 20 | And the coursework "numberofmarkers" setting is "3" in the database 21 | And I am logged in as a teacher 22 | When I visit the coursework page 23 | Then I should not see "There are only" 24 | 25 | Scenario: There is no warning when there are enough teachers 26 | Given there is a teacher 27 | And the coursework "numberofmarkers" setting is "1" in the database 28 | And I am logged in as a manager 29 | When I visit the coursework page 30 | Then I should not see "There are only" 31 | -------------------------------------------------------------------------------- /actions/moderations/edit.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * @package mod 19 | * @subpackage coursework 20 | * @copyright 2017 University of London Computer Centre {@link ulcc.ac.uk} 21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 | */ 23 | 24 | require_once(dirname(__FILE__) . '/../../../../config.php'); 25 | 26 | global $CFG, $USER; 27 | 28 | $moderationid = optional_param('moderationid', 0, PARAM_INT); 29 | 30 | $params = array( 31 | 'moderationid' => $moderationid, 32 | ); 33 | $controller = new mod_coursework\controllers\moderations_controller($params); 34 | $controller->edit_moderation(); -------------------------------------------------------------------------------- /actions/moderations/show.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * @package mod 19 | * @subpackage coursework 20 | * @copyright 2018 University of London Computer Centre {@link ulcc.ac.uk} 21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 | */ 23 | 24 | require_once(dirname(__FILE__) . '/../../../../config.php'); 25 | 26 | global $CFG, $USER; 27 | 28 | $moderationid = optional_param('moderationid', 0, PARAM_INT); 29 | 30 | $params = array( 31 | 'moderationid' => $moderationid, 32 | ); 33 | $controller = new mod_coursework\controllers\moderations_controller($params); 34 | $controller->show_moderation(); -------------------------------------------------------------------------------- /actions/plagiarism_flagging/edit.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * @package mod 19 | * @subpackage coursework 20 | * @copyright 2018 University of London Computer Centre {@link ulcc.ac.uk} 21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 | */ 23 | 24 | require_once(dirname(__FILE__) . '/../../../../config.php'); 25 | 26 | global $CFG, $USER; 27 | 28 | $flagid = optional_param('flagid', 0, PARAM_INT); 29 | 30 | $params = array( 31 | 'flagid' => $flagid 32 | ); 33 | 34 | $controller = new mod_coursework\controllers\plagiarism_flagging_controller($params); 35 | $controller->edit_plagiarism_flag(); -------------------------------------------------------------------------------- /actions/plagiarism_flagging/new.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * @package mod 19 | * @subpackage coursework 20 | * @copyright 2018 University of London Computer Centre {@link ulcc.ac.uk} 21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 | */ 23 | 24 | require_once(dirname(__FILE__) . '/../../../../config.php'); 25 | 26 | global $CFG, $USER; 27 | 28 | $submissionid = required_param('submissionid', PARAM_INT); 29 | 30 | $params = array( 31 | 'submissionid' => $submissionid 32 | ); 33 | 34 | $controller = new mod_coursework\controllers\plagiarism_flagging_controller($params); 35 | $controller->new_plagiarism_flag(); -------------------------------------------------------------------------------- /tests/behat/enrolment_triggers.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: the students should be auto allocated on enrolment 3 | 4 | As a manager 5 | I want the students to be reallocated when they or their assessors are added or removed from the course 6 | So that they always have a configured allocation for an appropriate assessor 7 | 8 | Background: 9 | Given there is a course 10 | And there is a coursework 11 | And there is a teacher 12 | And the coursework "allocationenabled" setting is "1" in the database 13 | And there are no allocations in the db 14 | 15 | Scenario: new students should be allocated when they join 16 | pending 17 | 18 | Scenario: exisitng manual allocations should not be reallocated when a tutor joins 19 | pending 20 | 21 | Scenario: existing auto allocations should not be reallocated when a tutor joins 22 | pending 23 | 24 | Scenario: exisitng graded allocations should not be reallocated when a tutor joins 25 | pending 26 | 27 | Scenario: exisitng manual allocations should not be reallocated when a tutor leaves 28 | pending 29 | 30 | Scenario: existing auto allocations should not be reallocated when a tutor leaves 31 | pending 32 | 33 | Scenario: exisitng graded allocations should not be reallocated when a tutor leaves 34 | pending 35 | 36 | -------------------------------------------------------------------------------- /tests/behat/pages/new_extension_page.php: -------------------------------------------------------------------------------- 1 | fill_in_date_field('extended_deadline', $time); 20 | 21 | // Choose an extension reason from the dropdown if it's there 22 | if (!empty($CFG->coursework_extension_reasons_list)) { 23 | $this->getPage()->fillField('pre_defined_reason', 0); 24 | } 25 | 26 | $fieldnode = $this->getPage()->findField('Extra information'); 27 | 28 | $field = behat_field_manager::get_form_field($fieldnode, $this->getSession()); 29 | // Delegates to the field class. 30 | $field->set_value('Extra info here'); 31 | 32 | 33 | $this->submit_form(); 34 | } 35 | 36 | public function submit_form() { 37 | $this->getPage()->find('css', '#id_submitbutton')->click(); 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /version.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * @package mod 19 | * @subpackage coursework 20 | * @copyright 2011 University of London Computer Centre {@link ulcc.ac.uk} 21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 | */ 23 | 24 | defined('MOODLE_INTERNAL') || die(); 25 | 26 | 27 | $plugin->component = 'mod_coursework'; 28 | 29 | $plugin->version = 2018060406; // If version == 0 then module will not be installed 30 | $plugin->requires = 2017111300; // Requires this Moodle version 3.4 31 | 32 | $plugin->cron = 300; // Period for cron to check this module (secs). 33 | 34 | $plugin->release = "3.6"; 35 | $plugin->maturity = MATURITY_STABLE; 36 | -------------------------------------------------------------------------------- /classes/grading_table_row_multi.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | namespace mod_coursework; 18 | 19 | defined('MOODLE_INTERNAL') || die(); 20 | 21 | 22 | /** 23 | * Single row of the grading table for when there are multiple markers. 24 | */ 25 | class grading_table_row_multi extends grading_table_row_base { 26 | 27 | 28 | /** 29 | * Returns a new table object using the attached submission as a constructor. 30 | * 31 | * @return assessor_feedback_table 32 | */ 33 | public function get_assessor_feedback_table() { 34 | $table = new assessor_feedback_table($this->coursework, $this->get_allocatable(), $this->get_submission()); 35 | return $table; 36 | } 37 | 38 | 39 | } -------------------------------------------------------------------------------- /tests/behat/installation_and_set_up.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: Installing the coursework module and making sure it works 3 | 4 | In order to start using the Coursework module 5 | As an admin 6 | I need to be able to successfully install the module in a course and add an instance 7 | 8 | @javascript 9 | Scenario: I can add a new instance of the coursework module to a course 10 | Given there is a course 11 | And I am logged in as an editing teacher 12 | And I visit the course page 13 | And I turn editing mode on 14 | When I add a "Coursework" to section "3" and I fill the form with: 15 | | name | Test coursework | 16 | | Description | Test coursework description | 17 | Then I should be on the course page 18 | 19 | Scenario: The module can be used with course completion enabled 20 | Given there is a course 21 | And I am logged in as an editing teacher 22 | And the course has completion enabled 23 | When I visit the course page 24 | And I turn editing mode on 25 | When I add a "Coursework" to section "3" and I fill the form with: 26 | | name | Test coursework | 27 | | Description | Test coursework description | 28 | Then I should be on the course page 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /classes/export/csv/cells/submissionfileid_cell.php: -------------------------------------------------------------------------------- 1 | coursework->get_username_hash($submission->allocatableid); 18 | } 19 | 20 | /** 21 | * @param $stage 22 | * @return string 23 | * @throws \coding_exception 24 | */ 25 | public function get_header($stage){ 26 | return get_string('submissionfileid', 'coursework'); 27 | } 28 | 29 | public function validate_cell($value,$submissionid,$stage_dentifier='',$uploadedgradecells = array()) { 30 | global $DB; 31 | 32 | if (empty($value)) { 33 | return 'No submission hash value entered'; 34 | } 35 | 36 | $subdbrecord = $DB->get_record('coursework_submissions',array('id'=>$submissionid)); 37 | 38 | $submission = \mod_coursework\models\submission::find($subdbrecord); 39 | 40 | $hash = $this->coursework->get_username_hash($submission->allocatableid); 41 | 42 | return ($value == $hash) ? true : get_string('submissionnotfound','coursework'); 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /classes/task/cron_task.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | namespace mod_coursework\task; 18 | 19 | /** 20 | * A scheduled task for the coursework module cron. 21 | * 22 | * @package mod_coursework 23 | * @copyright 2014 ULCC 24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 | */ 26 | 27 | class cron_task extends \core\task\scheduled_task { 28 | 29 | /** 30 | * Get a descriptive name for this task (shown to admins). 31 | * 32 | * @return string 33 | */ 34 | public function get_name() { 35 | return get_string('crontask', 'mod_coursework'); 36 | } 37 | 38 | /** 39 | * Run coursework cron. 40 | */ 41 | public function execute() { 42 | return \mod_coursework\cron::run(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tests/behat/feedback_group_marking.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: Marking the group submissions applies the grades to the whole group 3 | 4 | As a teacher 5 | I want to be able to grade the submission that the group have provided 6 | So that the marks are awarded to all of the group members and they can 7 | see their feedback and grades 8 | 9 | Background: 10 | Given there is a course 11 | And there is a coursework 12 | And there is a teacher 13 | And there is another teacher 14 | And the coursework "numberofmarkers" setting is "2" in the database 15 | And the coursework "use_groups" setting is "1" in the database 16 | And there is a student 17 | And the student is a member of a group 18 | And there is another student 19 | And the other student is a member of the group 20 | And the group has a submission 21 | And the submission is finalised 22 | And there are feedbacks from both teachers 23 | And I am logged in as a manager 24 | 25 | Scenario: grading the submission makes the grades show up for both students in the interface 26 | Given I am on the coursework page 27 | When I click the new final feedback button for the group 28 | And show me the page 29 | And I grade the submission using the simple form 30 | Then I should be on the coursework page 31 | And I should see the final grade for the group in the grading interface 32 | -------------------------------------------------------------------------------- /classes/event/coursework_deadline_changed.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * coursework_deadline_changed 19 | * 20 | * @package mod 21 | * @subpackage coursework 22 | * @copyright 2016 University of London Computer Centre {@link ulcc.ac.uk} 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | namespace mod_coursework\event; 27 | 28 | defined('MOODLE_INTERNAL') || die(); 29 | 30 | 31 | class coursework_deadline_changed extends \core\event\base { 32 | 33 | 34 | /** 35 | * Init method. 36 | * 37 | * @return void 38 | */ 39 | protected function init() { 40 | 41 | $this->data['crud'] = 'c'; 42 | $this->data['edulevel'] = self::LEVEL_TEACHING; 43 | $this->data['objecttable'] = 'coursework'; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /classes/plagiarism_helpers/turnitin.php: -------------------------------------------------------------------------------- 1 | enableplagiarism) { 28 | $plagiarismsettings = (array)get_config('plagiarism'); 29 | if (!empty($plagiarismsettings['turnitin_use'])) { 30 | $params = array( 31 | 'cm' => $this->get_coursework()->get_course_module()->id, 32 | 'name' => 'use_turnitin', 33 | 'value' => 1 34 | ); 35 | if ($DB->record_exists('plagiarism_turnitin_config', $params)) { 36 | return true; 37 | } 38 | } 39 | } 40 | 41 | return false; 42 | } 43 | 44 | /** 45 | * @return string 46 | * @throws \coding_exception 47 | */ 48 | public function human_readable_name() { 49 | return get_string('turnitin', 'plagiarism_turnitin'); 50 | } 51 | } -------------------------------------------------------------------------------- /classes/event/assessable_submitted.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * 19 | * @package coursework_submitted 20 | * @copyright 2013 Frédéric Massart 21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 | */ 23 | 24 | namespace mod_coursework\event; 25 | 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | /** 29 | 30 | * @package coursework_submitted 31 | * @copyright 2013 Frédéric Massart 32 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 33 | */ 34 | class assessable_submitted extends \core\event\assessable_submitted { 35 | 36 | 37 | /** 38 | * Init method. 39 | * 40 | * @return void 41 | */ 42 | protected function init() { 43 | parent::init(); 44 | $this->data['objecttable'] = 'coursework_submissions'; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /classes/user_row.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | namespace mod_coursework; 18 | 19 | /** 20 | * Class file for the renderable object that makes a single row int he marker allocation table. 21 | * 22 | * @package mod 23 | * @subpackage coursework 24 | * @copyright 2012 University of London Computer Centre {@link ulcc.ac.uk} 25 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 26 | */ 27 | use mod_coursework\allocation\allocatable; 28 | 29 | /** 30 | * Makes sure the renderer can use the row to get user details. 31 | */ 32 | interface user_row { 33 | 34 | public function get_allocatable_id(); 35 | 36 | public function get_user_name(); 37 | 38 | public function can_view_username(); 39 | 40 | /** 41 | * @return allocatable 42 | */ 43 | public function get_allocatable(); 44 | 45 | } 46 | -------------------------------------------------------------------------------- /tests/behat/allocation_automatic_equal_assessor_allocations.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: Automatic equal assessor allocations 3 | 4 | As a manager 5 | I want to be able to allocate assesors to students 6 | So that the marking is fairly distributed and the interface is less cluttered for teachers, 7 | and they don't mark to many or too few. 8 | 9 | Background: 10 | Given the managers are not allowed to grade 11 | And there is a course 12 | And there is a coursework 13 | And the coursework "allocationenabled" setting is "1" in the database 14 | And the coursework "numberofmarkers" setting is "1" in the database 15 | And there is a student 16 | And there is a teacher 17 | And teachers hava a capability to administer grades 18 | And I am logged in as a manager 19 | And there are no allocations in the db 20 | 21 | Scenario: Automatic allocations should work 22 | When I visit the allocations page 23 | And I save everything 24 | And I log out 25 | And I log in as the teacher 26 | And I visit the coursework page 27 | Then I should see the student's name on the page 28 | 29 | Scenario: Automatic allocations of non-manually allocated should work 30 | When I visit the allocations page 31 | And I save everything 32 | And I log out 33 | And I log in as the teacher 34 | And I visit the coursework page 35 | Then I should see the student's name on the page 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /tests/behat/submissions_student_submission.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: Students can submit files 3 | 4 | In order to submit work to my tutor for grading 5 | As a student who has completed some work 6 | I want to be able to upload it as a file to the coursework instance 7 | 8 | Background: 9 | Given there is a course 10 | And there is a coursework 11 | And I am logged in as a student 12 | 13 | @javascript 14 | Scenario: I upload a file and see it on the coursework page as read only 15 | When I visit the coursework page 16 | And I click on the new submission button 17 | And I upload "mod/coursework/tests/files_for_uploading/Test_document.docx" file to "Upload a file" filemanager 18 | And I save the submission 19 | Then I should be on the coursework page 20 | And I should see the file on the page 21 | And I should see the edit submission button 22 | 23 | @javascript 24 | Scenario: I upload a file and save it and I see it when I come back 25 | When I visit the coursework page 26 | And I click on the new submission button 27 | And I upload "mod/coursework/tests/files_for_uploading/Test_document.docx" file to "Upload a file" filemanager 28 | And I save the submission 29 | Then I should be on the coursework page 30 | When I visit the course page 31 | And I visit the coursework page 32 | And I click on the edit submission button 33 | Then I should see "1" elements in "Upload a file" filemanager 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /tests/behat/blind_marking_visibiilty_for_agreed_graders_with_blind_marking.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: visibility of agreed graders with blind marking 3 | 4 | As an agreed grader 5 | I want to be certain that teachers (and me) are unable to see the grades of other 6 | teachers before the agreement phase 7 | So that we are not influenced by one another or confused over what to do 8 | 9 | Background: 10 | Given there is a course 11 | And there is a coursework 12 | And blind marking is enabled 13 | And teachers have the add agreed grade capability 14 | And there is a teacher 15 | And there is another teacher 16 | And the coursework "numberofmarkers" setting is "2" in the database 17 | And there is a student 18 | And the student has a submission 19 | And the submission is finalised 20 | 21 | Scenario: agreed graders cannot see other feedbacks before they have done their own 22 | Given I am logged in as the other teacher 23 | And there is feedback for the submission from the teacher 24 | When I visit the coursework page 25 | Then I should not see the grade from the teacher in the assessor table 26 | 27 | Scenario: agreed graders can view the feedback of the other assessors when all done 28 | Given there are feedbacks from both teachers 29 | And I am logged in as the other teacher 30 | And I visit the coursework page 31 | When I click on the view icon for the first initial assessor's grade 32 | Then I should see the first initial assessors grade and comment 33 | 34 | -------------------------------------------------------------------------------- /renderer.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Renderer for the coursework module. 19 | * 20 | * @package mod 21 | * @subpackage coursework 22 | * @copyright 2011 University of London Computer Centre {@link ulcc.ac.uk} 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | /** 29 | * @var $OUTPUT core_renderer 30 | */ 31 | global $CFG, $OUTPUT; 32 | 33 | /** 34 | * Moodle has some weird rule for putting renderers in subdirectories (which we are not using). This seems like 35 | * a cleaner approach. 36 | */ 37 | foreach (scandir($CFG->dirroot . '/mod/coursework/renderers') as $filename) { 38 | $path = $CFG->dirroot . '/mod/coursework/renderers' . '/' . $filename; 39 | if (is_file($path)) { 40 | require $path; 41 | } 42 | } 43 | 44 | // Now moving them to the classes directory. 45 | 46 | require_once($CFG->dirroot . '/lib/filelib.php'); 47 | -------------------------------------------------------------------------------- /classes/event/coursework_plagiarism_flag_updated.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * ccoursework_plagiarism_flag_updated 19 | * 20 | * @package mod 21 | * @subpackage coursework 22 | * @copyright 2016 University of London Computer Centre {@link ulcc.ac.uk} 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | namespace mod_coursework\event; 27 | 28 | defined('MOODLE_INTERNAL') || die(); 29 | 30 | 31 | class coursework_plagiarism_flag_updated extends \core\event\base { 32 | 33 | /** 34 | * Init method. 35 | * 36 | * @return void 37 | */ 38 | protected function init() { 39 | 40 | $this->data['crud'] = 'u'; //One of [crud] letters - indicating 'c'reate, 'r'ead, 'u'pdate or 'd'elete operation. Statically declared in the event class method init(). 41 | $this->data['edulevel'] = self::LEVEL_TEACHING; 42 | $this->data['objecttable'] = 'coursework'; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /tests/behat/pages/login_page.php: -------------------------------------------------------------------------------- 1 | dirroot . '/mod/coursework/tests/behat/pages/page_base.php'); 10 | 11 | 12 | /** 13 | * Holds the functions that know about the HTML structure of the student page. 14 | * 15 | * 16 | */ 17 | class mod_coursework_behat_login_page extends mod_coursework_behat_page_base { 18 | 19 | public function load() { 20 | $this->getContext()->visit_page('login'); 21 | } 22 | 23 | /** 24 | * @param stdClass $user 25 | * @throws Behat\Mink\Exception\ElementNotFoundException 26 | * @throws Behat\Mink\Exception\ExpectationException 27 | */ 28 | public function login($user) { 29 | 30 | $this->getContext()->wait_till_element_exists('input#username'); 31 | 32 | if ($this->getContext()->running_javascript()) { 33 | $this->getSession()->wait(1000); 34 | } 35 | 36 | $this->getPage()->fillField('username', $user->username); 37 | $this->getPage()->fillField('password', $user->password); 38 | $this->getContext()->find_button('Log in')->press(); 39 | 40 | try { 41 | if ($this->getContext()->running_javascript()) { 42 | $this->getSession()->wait(10 * 1000); 43 | } 44 | $this->should_have_text('Log out'); 45 | 46 | } catch(ExpectationException $e) { 47 | $this->getContext()->show_me_the_page(); 48 | throw new ExpectationException('User '.$user->username.' could not be logged in', $this->getSession()); 49 | } 50 | 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /tests/behat/submissions_deadlines.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: Deadlines for submissions 3 | 4 | As a teacher 5 | I want to set deadlines that are viible to the student 6 | So that they know when they are expected to submut, and can be sent automatic reminders 7 | 8 | Background: 9 | Given there is a course 10 | And I am logged in as a teacher 11 | And there is a coursework 12 | 13 | Scenario: the general feedback deadline should be visible if enabled and set 14 | Given the coursework "generalfeedback" setting is "777777" in the database 15 | And the coursework general feedback is enabled 16 | When I visit the coursework page 17 | Then I should see the date when the general feedback will be released 18 | 19 | Scenario: the individual feedback deadline should not be visible if not enabled 20 | Given the coursework "individualfeedback" setting is "0" in the database 21 | When I visit the coursework page 22 | Then I should not see the date when the individual feedback will be released 23 | 24 | Scenario: the individual feedback deadline should be visible if enabled 25 | Given the coursework "individualfeedback" setting is "777777" in the database 26 | When I visit the coursework page 27 | Then I should see the date when the individual feedback will be released 28 | 29 | Scenario: the general feedback deadline should be visible if not enabled 30 | Given the coursework "individualfeedback" setting is "7777777" in the database 31 | When I visit the coursework page 32 | Then I should see the date when the individual feedback will be released -------------------------------------------------------------------------------- /classes/framework/decorator.php: -------------------------------------------------------------------------------- 1 | wrapped_object = $wrapped_object; 24 | } 25 | 26 | /** 27 | * Delegate everything to the wrapped object by default. 28 | * 29 | * @param $method 30 | * @param $args 31 | * @return mixed 32 | */ 33 | public function __call($method, $args) { 34 | return call_user_func_array(array($this->wrapped_object, 35 | $method), 36 | $args); 37 | } 38 | 39 | /** 40 | * Delegate everything to the wrapped object by default. 41 | * 42 | * @param $name 43 | * @return mixed 44 | */ 45 | public function __get($name) { 46 | return $this->wrapped_object->$name; 47 | } 48 | 49 | /** 50 | * Delegate everything to the wrapped object by default. 51 | * 52 | * @param $name 53 | * @param $value 54 | * @return mixed 55 | */ 56 | public function __set($name, $value) { 57 | return $this->wrapped_object->$name = $value; 58 | } 59 | 60 | /** 61 | * @return mixed 62 | */ 63 | public function wrapped_object() { 64 | return $this->wrapped_object(); 65 | } 66 | } -------------------------------------------------------------------------------- /actions/processallocation.php: -------------------------------------------------------------------------------- 1 | dirroot.'/mod/coursework/lib.php'); 19 | 20 | $coursemoduleid = required_param('coursemoduleid', PARAM_INT); 21 | $coursemodule = get_coursemodule_from_id('coursework', $coursemoduleid, 0, false, MUST_EXIST); 22 | $course = $DB->get_record('course', array('id' => $coursemodule->course), '*', MUST_EXIST); 23 | $coursework = $DB->get_record('coursework', array('id' => $coursemodule->instance), '*', MUST_EXIST); 24 | $coursework = coursework::find($coursework); 25 | $assessorallocationstrategy = optional_param('assessorallocationstrategy', false, PARAM_TEXT); 26 | 27 | 28 | require_login($course, true, $coursemodule); 29 | 30 | require_capability('mod/coursework:allocate', $PAGE->context, null, true, "Can't allocate here - permission denied."); 31 | 32 | if ($assessorallocationstrategy) { 33 | if ($assessorallocationstrategy != $coursework->assessorallocationstrategy) { 34 | $coursework->set_assessor_allocation_strategy($assessorallocationstrategy); 35 | } 36 | $coursework->save_allocation_strategy_options($assessorallocationstrategy); 37 | } 38 | 39 | $coursework->save(); 40 | 41 | $allocator = new \mod_coursework\allocation\auto_allocator($coursework); 42 | $allocator->process_allocations(); 43 | 44 | 45 | echo $coursework->name. "re-allocated"; -------------------------------------------------------------------------------- /tests/classes/grade_judge_test.php: -------------------------------------------------------------------------------- 1 | setAdminUser(); 17 | $this->resetAfterTest(); 18 | } 19 | 20 | 21 | public function test_get_feedbck_that_is_promoted_to_gradebook_returns_initial_feedback() { 22 | $coursework = $this->create_a_coursework(); 23 | $grade_judge = new grade_judge($coursework); 24 | 25 | $coursework->update_attribute('samplingenabled', 1); 26 | 27 | $submission = $this->create_a_submission_for_the_student(); 28 | $assessor = $this->create_a_teacher(); 29 | $feedback = $this->create_an_assessor_feedback_for_the_submisison($assessor); 30 | 31 | $this->assertEquals($feedback->id, $grade_judge->get_feedback_that_is_promoted_to_gradebook($submission)->id); 32 | } 33 | 34 | 35 | public function test_sampling_disabled_one_marker() { 36 | $coursework = $this->create_a_coursework(); 37 | $grade_judge = new grade_judge($coursework); 38 | 39 | $coursework->update_attribute('samplingenabled', 0); 40 | $coursework->update_attribute('numberofmarkers', 1); 41 | 42 | $submission = $this->create_a_submission_for_the_student(); 43 | $assessor = $this->create_a_teacher(); 44 | $feedback = $this->create_an_assessor_feedback_for_the_submisison($assessor); 45 | 46 | $this->assertEquals($feedback->id, $grade_judge->get_feedback_that_is_promoted_to_gradebook($submission)->id); 47 | } 48 | } -------------------------------------------------------------------------------- /tests/behat/blind_marking_visibiilty_for_agreed_graders_without_blind_marking.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: visibility of agreed graders without blind marking 3 | 4 | As an agreed grader 5 | I want to be certain that teachers (and me) are unable to see the grades of other 6 | teachers before the agreement phase 7 | So that we are not influenced by one another or confused over what to do 8 | 9 | Background: 10 | Given there is a course 11 | And there is a coursework 12 | And there is a teacher 13 | And there is another teacher 14 | And the coursework "numberofmarkers" setting is "2" in the database 15 | And there is a student 16 | And the student has a submission 17 | And the submission is finalised 18 | 19 | Scenario: agreed graders can see other feedbacks before they have done their own 20 | Given teachers have the add agreed grade capability 21 | And the coursework "viewinitialgradeenabled" setting is "1" in the database 22 | And I am logged in as the other teacher 23 | And there is feedback for the submission from the teacher 24 | When I visit the coursework page 25 | Then I should see the grade from the teacher in the assessor table 26 | 27 | Scenario: agreed graders can view the feedback of the other assessors when all done 28 | Given there are feedbacks from both teachers 29 | And teachers have the add agreed grade capability 30 | And I am logged in as the other teacher 31 | And I visit the coursework page 32 | When I click on the view icon for the first initial assessor's grade 33 | Then I should see the first initial assessors grade and comment -------------------------------------------------------------------------------- /actions/feedbacks/new.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * @package mod 19 | * @subpackage coursework 20 | * @copyright 2011 University of London Computer Centre {@link ulcc.ac.uk} 21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 | */ 23 | 24 | require_once(dirname(__FILE__) . '/../../../../config.php'); 25 | 26 | global $CFG, $USER; 27 | 28 | $submissionid = required_param('submissionid', PARAM_INT); 29 | $cmid = optional_param('cmid', 0, PARAM_INT); 30 | $feedbackid = optional_param('feedbackid', 0, PARAM_INT); 31 | $assessorid = optional_param('assessorid', $USER->id, PARAM_INT); 32 | $stage_identifier = optional_param('stage_identifier', 'uh-oh', PARAM_RAW); 33 | 34 | $params = array( 35 | 'submissionid' => $submissionid, 36 | 'cmid' => $cmid, 37 | 'feedbackid' => $feedbackid, 38 | 'assessorid' => $assessorid, 39 | 'stage_identifier' => $stage_identifier, 40 | ); 41 | $controller = new mod_coursework\controllers\feedback_controller($params); 42 | $controller->new_feedback(); -------------------------------------------------------------------------------- /actions/moderations/new.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * @package mod 19 | * @subpackage coursework 20 | * @copyright 2017 University of London Computer Centre {@link ulcc.ac.uk} 21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 | */ 23 | 24 | require_once(dirname(__FILE__) . '/../../../../config.php'); 25 | 26 | global $CFG, $USER; 27 | 28 | $submissionid = required_param('submissionid', PARAM_INT); 29 | $cmid = optional_param('cmid', 0, PARAM_INT); 30 | $feedbackid = required_param('feedbackid', PARAM_INT); 31 | $moderatorid = optional_param('moderatorid', $USER->id, PARAM_INT); 32 | $stage_identifier = optional_param('stage_identifier', 'uh-oh', PARAM_RAW); 33 | 34 | $params = array( 35 | 'submissionid' => $submissionid, 36 | 'cmid' => $cmid, 37 | 'feedbackid' => $feedbackid, 38 | 'moderatorid' => $moderatorid, 39 | 'stage_identifier' => $stage_identifier, 40 | ); 41 | $controller = new mod_coursework\controllers\moderations_controller($params); 42 | $controller->new_moderation(); -------------------------------------------------------------------------------- /actions/selectallallocatables.php: -------------------------------------------------------------------------------- 1 | dirroot.'/mod/coursework/lib.php'); 14 | 15 | $coursemoduleid = required_param('coursemoduleid', PARAM_INT); 16 | $stagenumber = required_param('stage', PARAM_INT); 17 | $coursemodule = get_coursemodule_from_id('coursework', $coursemoduleid, 0, false, MUST_EXIST); 18 | $course = $DB->get_record('course', array('id' => $coursemodule->course), '*', MUST_EXIST); 19 | $coursework = $DB->get_record('coursework', array('id' => $coursemodule->instance), '*', MUST_EXIST); 20 | $coursework = coursework::find($coursework); 21 | $assessorallocationstrategy = optional_param('assessorallocationstrategy', false, PARAM_TEXT); 22 | 23 | 24 | 25 | 26 | if ($stagenumber > 0) { 27 | 28 | if (!isset($SESSION->allocate_page_selectentirestage[$coursework->id()]['assessor_'.$stagenumber])) { 29 | $SESSION->allocate_page_selectentirestage[$coursework->id()]['assessor_'.$stagenumber] = 0; 30 | 31 | } 32 | 33 | $SESSION->allocate_page_selectentirestage[$coursework->id()]['assessor_'.$stagenumber] = !$SESSION->allocate_page_selectentirestage[$coursework->id()]['assessor_'.$stagenumber]; 34 | 35 | } else { 36 | if (!isset($SESSION->allocate_page_selectentirestage[$coursework->id()]['moderator'])) { 37 | $SESSION->allocate_page_selectentirestage[$coursework->id()]['moderator'] = 0; 38 | 39 | } 40 | 41 | $SESSION->allocate_page_selectentirestage[$coursework->id()]['moderator'] = !$SESSION->allocate_page_selectentirestage[$coursework->id()]['moderator']; 42 | } 43 | 44 | 45 | -------------------------------------------------------------------------------- /tests/behat/feedback_files.feature: -------------------------------------------------------------------------------- 1 | Feature: Adding feedback files 2 | 3 | As a teacher 4 | I want to be able to add feedback files 5 | So that I can provide users with rich, detailed feedback 6 | 7 | Background: 8 | Given there is a course 9 | And there is a coursework 10 | And the coursework "numberofmarkers" setting is "1" in the database 11 | And there is a student 12 | And the student has a submission 13 | And the submission is finalised 14 | 15 | @javascript 16 | Scenario: I can upload any file type, regardless of the coursework file types 17 | Given the coursework "filetypes" setting is "pdf" in the database 18 | And I am logged in as a teacher 19 | When I visit the coursework page 20 | And I click the new single final feedback button for the student 21 | And I upload "mod/coursework/tests/files_for_uploading/Test_image.png" file to "Upload a file" filemanager 22 | Then I should see "1" elements in "Upload a file" filemanager 23 | 24 | @javascript 25 | Scenario: Students see all the feedback files 26 | Given I am logged in as a manager 27 | When I visit the coursework page 28 | And I click the new single final feedback button for the student 29 | And I upload "mod/coursework/tests/files_for_uploading/Test_image.png" file to "Upload a file" filemanager 30 | When I upload "mod/coursework/tests/files_for_uploading/Test_document_two.docx" file to "Upload a file" filemanager 31 | And I press "Save changes" 32 | And I publish the grades 33 | And I log out 34 | And I log in as a student 35 | And I visit the coursework page 36 | Then I should see two feedback files on the page 37 | 38 | 39 | -------------------------------------------------------------------------------- /tests/behat/pages/show_feedback_page.php: -------------------------------------------------------------------------------- 1 | dirroot . '/mod/coursework/tests/behat/pages/page_base.php'); 8 | 9 | use Behat\Mink\Exception\ExpectationException; 10 | use mod_coursework\models\feedback; 11 | 12 | /** 13 | * Holds the functions that know about the HTML structure of the student page. 14 | * 15 | * 16 | */ 17 | class mod_coursework_behat_show_feedback_page extends mod_coursework_behat_page_base { 18 | 19 | /** 20 | * @var feedback 21 | */ 22 | protected $feedback; 23 | 24 | /** 25 | * @param string $grade 26 | */ 27 | public function should_have_grade($grade) { 28 | assertContains($grade, $this->get_feedback_table()->getText()); 29 | } 30 | 31 | /** 32 | * @param string $comment 33 | */ 34 | public function should_have_comment($comment) { 35 | assertContains($comment, $this->get_feedback_table()->getText()); 36 | } 37 | 38 | /** 39 | * @param feedback $feedback 40 | */ 41 | public function set_feedback($feedback) { 42 | $this->feedback = $feedback; 43 | } 44 | 45 | /** 46 | * @return \Behat\Mink\Element\NodeElement|null 47 | * @throws coding_exception 48 | */ 49 | private function get_feedback_table() { 50 | return $this->getPage()->find('css', '#feedback_'.$this->get_feedback()->id); 51 | } 52 | 53 | /** 54 | * @return feedback 55 | * @throws coding_exception 56 | */ 57 | private function get_feedback() { 58 | if (empty($this->feedback)) { 59 | throw new coding_exception('Must set the feedback on the show feedback page before using it!'); 60 | } 61 | return $this->feedback; 62 | } 63 | } -------------------------------------------------------------------------------- /tests/behat/blind_marking_visibility_for_teachers_without_blind_marking.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: visibility for teachers without blind marking 3 | 4 | As a manager 5 | I want to be able to prevent teachers from seeing each others' marks 6 | So that I can be sure that they are not influenced by each other and the marking is fair 7 | 8 | Background: 9 | Given there is a course 10 | And there is a coursework 11 | 12 | Scenario: The student names are normally visible to teachers in the user cells 13 | Given I am logged in as a teacher 14 | And there is a student 15 | When I visit the coursework page 16 | Then I should see the student's name in the user cell 17 | 18 | Scenario: The user names are visible from teachers in the group cells 19 | Given I am logged in as a teacher 20 | And there is a student 21 | And group submissions are enabled 22 | And the student is a member of a group 23 | And the group is part of a grouping for the coursework 24 | When I visit the coursework page 25 | Then I should see the student's name in the group cell 26 | 27 | Scenario: Teachers can see other grades 28 | Given the coursework "numberofmarkers" setting is "2" in the database 29 | And the coursework "viewinitialgradeenabled" setting is "1" in the database 30 | And there is a teacher 31 | And there is another teacher 32 | And there is a student 33 | And the student has a submission 34 | And the submission is finalised 35 | And there are feedbacks from both teachers 36 | And I am logged in as the other teacher 37 | When I visit the coursework page 38 | Then I should see the grade from the teacher in the assessor table 39 | 40 | -------------------------------------------------------------------------------- /tests/behat/blind_marking_visibility_for_teachers_with_blind_marking.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: Visibility for teachers with blind marking 3 | 4 | As a manager 5 | I want to be able to prevent teachers from seeing each others' marks 6 | So that I can be sure that they are not influenced by each other and the marking is fair 7 | 8 | Background: 9 | Given there is a course 10 | And there is a coursework 11 | And blind marking is enabled 12 | 13 | Scenario: The student names are hidden from teachers in the user cells 14 | Given I am logged in as a teacher 15 | And there is a student 16 | When I visit the coursework page 17 | Then I should not see the student's name in the user cell 18 | 19 | Scenario: The user names are hidden from teachers in the group cells 20 | Given I am logged in as a teacher 21 | And there is a student 22 | And group submissions are enabled 23 | And the student is a member of a group 24 | And the group is part of a grouping for the coursework 25 | When I visit the coursework page 26 | Then I should not see the student's name in the group cell 27 | 28 | Scenario: Teachers cannot see other initial grades before final grading happens 29 | Given the coursework "numberofmarkers" setting is "2" in the database 30 | And there is a teacher 31 | And there is another teacher 32 | And there is a student 33 | And the student has a submission 34 | And the submission is finalised 35 | And there are feedbacks from both teachers 36 | And I am logged in as the other teacher 37 | When I visit the coursework page 38 | Then I should not see the grade from the teacher in the assessor table 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /db/tasks.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Definition of Coursework module scheduled tasks. 19 | * 20 | * @package mod_coursework 21 | * @category task 22 | * @copyright 2014 ULCC 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | $tasks = array( 29 | array( 30 | 'classname' => 'mod_coursework\task\cron_task', 31 | 'blocking' => 0, 32 | 'minute' => '0', 33 | 'hour' => '0', 34 | 'day' => '*', 35 | 'month' => '*', 36 | 'dayofweek' => '*' 37 | ), 38 | array( 39 | 'classname' => 'mod_coursework\task\enrol_task', 40 | 'blocking' => 0, 41 | 'minute' => '0', 42 | 'hour' => '*', 43 | 'day' => '*', 44 | 'month' => '*', 45 | 'dayofweek' => '*' 46 | ), 47 | array( 48 | 'classname' => 'mod_coursework\task\unenrol_task', 49 | 'blocking' => 0, 50 | 'minute' => '0', 51 | 'hour' => '*', 52 | 'day' => '*', 53 | 'month' => '*', 54 | 'dayofweek' => '*' 55 | ) 56 | ); 57 | -------------------------------------------------------------------------------- /tests/behat/allocation_automatic_interacting_with_manual_allocations.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: Automatically allocations interacting with manually allocated students 3 | 4 | As a manager 5 | I want to be able to reallocate all of the non manual students 6 | So that if the number of students or teachers has changed, I can make sure everything remains balanced 7 | 8 | Background: 9 | Given there is a course 10 | And there is a coursework 11 | And the coursework "allocationenabled" setting is "1" in the database 12 | And the coursework "numberofmarkers" setting is "1" in the database 13 | And the managers are not allowed to grade 14 | And there is a student 15 | And there is a teacher 16 | And I am logged in as a manager 17 | 18 | Scenario: Automatic allocations should not alter the manual allocations 19 | Given there is another teacher 20 | And there are no allocations in the db 21 | When I visit the allocations page 22 | And I manually allocate the student to the teacher 23 | And I set the allocation strategy to 100 percent for the other teacher 24 | And I save everything 25 | When I visit the allocations page 26 | Then I should see the student allocated to the teacher for the first assessor 27 | 28 | @javascript 29 | Scenario: Automatic allocations should wipe the older automatic allocations 30 | Given the student is allocated to the teacher 31 | And there is another teacher 32 | When I visit the allocations page 33 | And I set the allocation strategy to 100 percent for the other teacher 34 | And I press "Apply" 35 | When I visit the allocations page 36 | Then I should see the student allocated to the other teacher for the first assessor 37 | 38 | -------------------------------------------------------------------------------- /classes/render_helpers/grading_report/cells/plagiarism_cell.php: -------------------------------------------------------------------------------- 1 | get_coursework()); 28 | 29 | if ($rowobject->has_submission() && $ability->can('show', $rowobject->get_submission())) { 30 | // The files and the form to resubmit them. 31 | $submission_files = $rowobject->get_submission_files(); 32 | if ($submission_files) { 33 | $content .= $this->get_renderer()->render_plagiarism_links(new mod_coursework_submission_files($submission_files)); 34 | } 35 | } 36 | 37 | return $this->get_new_cell_with_class($content); 38 | } 39 | 40 | /** 41 | * @param array $options 42 | * @return string 43 | */ 44 | public function get_table_header($options = array()) { 45 | return get_string('plagiarism', 'mod_coursework'); 46 | } 47 | 48 | /** 49 | * @return string 50 | */ 51 | public function get_table_header_class(){ 52 | return 'plagiarism'; 53 | } 54 | 55 | /** 56 | * @return string 57 | */ 58 | public function header_group() { 59 | return 'submission'; 60 | } 61 | } -------------------------------------------------------------------------------- /tests/behat/deadline_extension_reason_dropdown_list.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework @RVC_PT_83738596 2 | Feature: Deadline extension reasons dropdown list 3 | 4 | As an OCM admin 5 | I can create deadline extension reasons in a text box, 6 | so that the specific reason can be selected for the new cut off date. 7 | 8 | Background: 9 | Given there is a course 10 | And there is a coursework 11 | And there is a student 12 | And the coursework individual extension option is enabled 13 | 14 | Scenario: The teacher can add a reason for the deadline extension to an individual submission 15 | Given the coursework deadline has passed 16 | And there are some extension reasons configured at site level 17 | And I log in as a manager 18 | And I am on the coursework page 19 | When I add a new extension for the student 20 | Then I should be on the coursework page 21 | When I click on the edit extension icon for the student 22 | Then I should see the deadline reason in the deadline extension form 23 | And I should see the extra information in the deadline extension form 24 | 25 | Scenario: The teacher can edit a deadline extension and its reason to an individual submission 26 | Given the coursework deadline has passed 27 | And there are some extension reasons configured at site level 28 | And there is an extension for the student which has expired 29 | And I log in as a manager 30 | And I am on the coursework page 31 | When I edit the extension for the student 32 | Then I should be on the coursework page 33 | And I should see the new extended deadline in the student row 34 | When I click on the edit extension icon for the student 35 | Then I should see the new deadline reason in the dropdown 36 | And I should see the new extra deadline information in the deadline extension form 37 | 38 | -------------------------------------------------------------------------------- /tests/behat/allocation_visibility_of_all_students_capability.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: View of all students: allocated and non allocated students 3 | 4 | As a user with allocated and non allocated students 5 | I want to see the students who have been allocated at the top 6 | so that the rest of the enrolled students are toggled below the allocated students 7 | 8 | Background: 9 | Given there is a course 10 | And there is a coursework 11 | And the coursework "allocationenabled" setting is "1" in the database 12 | And the coursework "assessorallocationstrategy" setting is "0" in the database 13 | And the coursework "numberofmarkers" setting is "1" in the database 14 | And there is a student 15 | And there is a teacher 16 | And there is another student 17 | And there is another teacher 18 | And I am logged in as a manager 19 | And I visit the allocations page 20 | And I manually allocate the student to the teacher 21 | And I save everything 22 | And I manually allocate another student to another teacher 23 | And I log out 24 | 25 | Scenario: Teachers see students who are allocated 26 | Given I log in as the teacher 27 | And I visit the coursework page 28 | Then I should see the student's name on the page 29 | 30 | Scenario: Teachers do not see students who are unallocated 31 | Given I log in as the teacher 32 | And I visit the coursework page 33 | Then I should not see another student's name on the page 34 | 35 | Scenario: Teachers see all unallocated students pressing the toggle button 36 | Given I log in as the teacher 37 | And I am allowed to view all students 38 | And I visit the coursework page 39 | And I click show all students button 40 | Then I should see another student's name on the page 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /db/messages.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * @package mod 19 | * @subpackage coursework 20 | * @copyright 2012 University of London Computer Centre {@link ulcc.ac.uk} 21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 | */ 23 | 24 | defined('MOODLE_INTERNAL') || die(); 25 | 26 | global $CFG; 27 | 28 | $messageproviders = array( 29 | 'deadlinechanged' => array( 30 | ), 31 | 'submission_receipt' => array( 32 | 'defaults' => array( 33 | 'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF, 34 | 'email' => MESSAGE_FORCED, 35 | ), 36 | ), 37 | 'coursework_submission' => array( 38 | 'defaults' => array( 39 | 'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF, 40 | 'email' => MESSAGE_FORCED, 41 | ), 42 | ), 43 | 'feedback_released' => array( 44 | 'defaults' => array( 45 | 'popup' => MESSAGE_DISALLOWED, 46 | 'email' => MESSAGE_FORCED, 47 | ), 48 | ), 49 | 'student_deadline_reminder' => array( 50 | ), 51 | ); -------------------------------------------------------------------------------- /classes/allocation/allocatable.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * @package mod 19 | * @subpackage coursework 20 | * @copyright 2011 University of London Computer Centre {@link ulcc.ac.uk} 21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 | */ 23 | 24 | /** 25 | * Definition of log events 26 | * NOTE: this is an example how to insert log event during installation/update. 27 | * It is not really essential to know about it, but these logs were created as example 28 | * in the previous 1.9 coursework. 29 | * 30 | * @package mod_coursework 31 | * @copyright 2010 Your Name 32 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 33 | */ 34 | 35 | defined('MOODLE_INTERNAL') || die(); 36 | 37 | global $DB; 38 | 39 | $logs = array( 40 | array('module'=>'coursework', 'action'=>'add', 'mtable'=>'coursework', 'field'=>'name'), 41 | array('module'=>'coursework', 'action'=>'update', 'mtable'=>'coursework', 'field'=>'name'), 42 | array('module'=>'coursework', 'action'=>'view', 'mtable'=>'coursework', 'field'=>'name'), 43 | array('module'=>'coursework', 'action'=>'view all', 'mtable'=>'coursework', 'field'=>'name') 44 | ); 45 | -------------------------------------------------------------------------------- /actions/allocationsession.php: -------------------------------------------------------------------------------- 1 | coursework_allocationsessions)) { 18 | $SESSION->coursework_allocationsessions = array(); 19 | } 20 | 21 | if (!isset($SESSION->coursework_allocationsessions[$coursemoduleid])) { 22 | $SESSION->coursework_allocationsessions[$coursemoduleid] = array(); 23 | } 24 | 25 | 26 | 27 | for($i = 0; $i < count($assesorselect); $i++) { 28 | $SESSION->coursework_allocationsessions[$coursemoduleid][$assesorselect[$i]] = $assesorselectvalue[$i]; 29 | } 30 | 31 | for($i = 0; $i < count($pinnedchk); $i++) { 32 | $SESSION->coursework_allocationsessions[$coursemoduleid][$pinnedchk[$i]] = $pinnedchkval[$i]; 33 | } 34 | 35 | for($i = 0; $i < count($moderatorselect); $i++) { 36 | $SESSION->coursework_allocationsessions[$coursemoduleid][$moderatorselect[$i]] = $moderatorselectvalue[$i]; 37 | } 38 | 39 | for($i = 0; $i < count($samplechk); $i++) { 40 | $SESSION->coursework_allocationsessions[$coursemoduleid][$samplechk[$i]] = $samplechkvalue[$i]; 41 | } 42 | 43 | -------------------------------------------------------------------------------- /classes/personal_deadline/allocatable.php: -------------------------------------------------------------------------------- 1 | libdir.'/formslib.php'); 12 | 13 | 14 | 15 | class upload_grading_sheet_form extends moodleform { 16 | 17 | private $cmid; 18 | 19 | function __construct($cmid) { 20 | $this->cmid = $cmid; 21 | 22 | parent::__construct(); 23 | } 24 | 25 | function definition() { 26 | $mform =& $this->_form; 27 | 28 | $mform->addElement('filepicker', 'gradingdata', get_string('gradingsheetfile','coursework'), null, array( 'accepted_types' => '*.csv')); 29 | $mform->addRule('gradingdata', null, 'required'); 30 | 31 | $mform->addElement('checkbox','overwrite','',get_string('overwritegrades','coursework')); 32 | $mform->addElement('hidden','cmid',$this->cmid); 33 | 34 | $mform->setType('cmid',PARAM_RAW); 35 | 36 | $choices = csv_import_reader::get_delimiter_list(); 37 | $mform->addElement('select', 'delimiter_name', get_string('csvdelimiter', 'tool_uploaduser'), $choices); 38 | if (array_key_exists('cfg', $choices)) { 39 | $mform->setDefault('delimiter_name', 'cfg'); 40 | } else if (get_string('listsep', 'langconfig') == ';') { 41 | $mform->setDefault('delimiter_name', 'semicolon'); 42 | } else { 43 | $mform->setDefault('delimiter_name', 'comma'); 44 | } 45 | 46 | $choices = core_text::get_encodings(); 47 | $mform->addElement('select', 'encoding', get_string('encoding', 'tool_uploaduser'), $choices); 48 | $mform->setDefault('encoding', 'UTF-8'); 49 | 50 | 51 | $this->add_action_buttons(true,get_string('uploadgradingworksheet','coursework')); 52 | } 53 | 54 | function display() { 55 | return $this->_form->toHtml(); 56 | } 57 | 58 | 59 | 60 | 61 | } -------------------------------------------------------------------------------- /tests/behat/deadline_extension.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework @RVC_PT_83106618 2 | Feature: Deadlines extensions for submissions 3 | 4 | As an OCM admin 5 | I can add allow students to submit after the deadline 6 | So that late work can still be given a grade 7 | 8 | Background: 9 | Given there is a course 10 | And there is a coursework 11 | And the coursework individual extension option is enabled 12 | And there is a student 13 | 14 | Scenario: The student can submit after the deadline when the start date is disabled 15 | Given the coursework deadline has passed 16 | And there is an extension for the student that allows them to submit 17 | When I log in as a student 18 | And I visit the coursework page 19 | Then I should see the new submission button 20 | 21 | Scenario: The student can not submit when the start date is in the future 22 | Given the coursework deadline has passed 23 | And there is an extension for the student which has expired 24 | When I log in as a student 25 | And I visit the coursework page 26 | Then I should not see the new submission button 27 | 28 | Scenario: The teacher can add a deadline extension to an individual submission 29 | Given the coursework deadline has passed 30 | And I log in as a manager 31 | And I am on the coursework page 32 | When I add a new extension for the student 33 | Then I should be on the coursework page 34 | And I should see the extended deadline in the student row 35 | 36 | Scenario: The teacher can edit a deadline extension to an individual submission 37 | Given the coursework deadline has passed 38 | And there is an extension for the student which has expired 39 | And I log in as a manager 40 | And I am on the coursework page 41 | When I edit the extension for the student 42 | Then I should be on the coursework page 43 | And I should see the extended deadline in the student row 44 | -------------------------------------------------------------------------------- /tests/behat/pages/edit_extension_page.php: -------------------------------------------------------------------------------- 1 | fill_in_date_field('extended_deadline', $time); 21 | 22 | // Choose an extension reason from the dropdown if it's there 23 | if (!empty($CFG->coursework_extension_reasons_list)) { 24 | $this->getPage()->fillField('pre_defined_reason', 1); 25 | } 26 | 27 | $fieldnode = $this->getPage()->findField('Extra information'); 28 | 29 | $field = behat_field_manager::get_form_field($fieldnode, $this->getSession()); 30 | // Delegates to the field class. 31 | $field->set_value('New info here'); 32 | 33 | // Click the submit button 34 | $this->getPage()->find('css', '#id_submitbutton')->click(); 35 | 36 | } 37 | 38 | /** 39 | * @param string $reason 40 | */ 41 | public function should_show_extension_reason_for_allocatable($reason) { 42 | $field = $this->getPage()->findField('pre_defined_reason'); 43 | assertEquals($reason, $field->getValue()); 44 | } 45 | 46 | /** 47 | * @param string $string 48 | */ 49 | public function should_show_extra_information_for_allocatable($string) { 50 | $field = $this->getPage()->findField('extra_information[text]'); 51 | assertContains($string, $field->getValue()); 52 | } 53 | } -------------------------------------------------------------------------------- /tests/classes/router_test.php: -------------------------------------------------------------------------------- 1 | router = router::instance(); 28 | $this->setAdminUser(); 29 | $this->resetAfterTest(); 30 | } 31 | 32 | public function test_new_submission_path() { 33 | 34 | $submission = submission::build(array('allocatableid' => 4, 'allocatabletype' => 'user', 'courseworkid' => 5)); 35 | 36 | $path = $this->router->get_path('new submission', array('submission' => $submission)); 37 | $this->assertEquals($this->moodle_location.'/mod/coursework/actions/submissions/new.php?allocatableid=4&allocatabletype=user&courseworkid=5', $path); 38 | } 39 | 40 | /** 41 | * @return mod_coursework_generator 42 | * @throws coding_exception 43 | */ 44 | protected function get_generator() { 45 | return $this->getDataGenerator()->get_plugin_generator('mod_coursework'); 46 | } 47 | 48 | /** 49 | * @return \mod_coursework\models\coursework 50 | * @throws coding_exception 51 | */ 52 | protected function get_coursework() { 53 | $coursework = new stdClass(); 54 | $coursework->course = $this->get_course(); 55 | return $this->get_generator()->create_instance($coursework); 56 | } 57 | 58 | /** 59 | * @return stdClass 60 | */ 61 | private function get_course() { 62 | $this->course = $this->getDataGenerator()->create_course(); 63 | return $this->course; 64 | } 65 | } -------------------------------------------------------------------------------- /backup/moodle2/restore_coursework_activity_task.class.php: -------------------------------------------------------------------------------- 1 | dirroot . '/mod/coursework/backup/moodle2/restore_coursework_stepslib.php'); 6 | 7 | class restore_coursework_activity_task extends restore_activity_task 8 | { 9 | /** 10 | * Define the decoding rules for links belonging 11 | * to the activity to be executed by the link decoder. 12 | * 13 | * @return array of restore_decode_rule 14 | */ 15 | static public function define_decode_rules() 16 | { 17 | $rules = array(); 18 | 19 | $rules[] = new restore_decode_rule('COURSEWORKBYID', 20 | '/mod/coursework/view.php?id=$1', 21 | 'course_module'); 22 | $rules[] = new restore_decode_rule('CORSEWORKINDEX', 23 | '/mod/corsework/index.php?id=$1', 24 | 'course_module'); 25 | 26 | return $rules; 27 | 28 | } 29 | 30 | /** 31 | * Define the contents in the activity that must be 32 | * processed by the link decoder. 33 | * 34 | * @return array 35 | */ 36 | static public function define_decode_contents() { 37 | $contents = array(); 38 | 39 | $contents[] = new restore_decode_content('coursework', array('intro'), 'assign'); 40 | 41 | return $contents; 42 | } 43 | 44 | /** 45 | * Define (add) particular settings this activity can have. 46 | */ 47 | protected function define_my_settings() 48 | { 49 | // No particular settings for this activity. 50 | } 51 | 52 | /** 53 | * Define (add) particular steps this activity can have. 54 | */ 55 | protected function define_my_steps() 56 | { 57 | // Only has one structure step. 58 | $this->add_step(new restore_coursework_activity_structure_step('coursework_structure', 'coursework.xml')); 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /classes/models/null_user.php: -------------------------------------------------------------------------------- 1 | get_coursework()); 25 | $judge = new grade_judge($this->coursework); 26 | if ($ability->can('show', $judge->get_feedback_that_is_promoted_to_gradebook($row_object->get_submission())) && !$row_object->get_submission()->editable_final_feedback_exist()) { 27 | $grade = $judge->get_grade_capped_by_submission_time($row_object->get_submission()); 28 | $content .= $judge->grade_to_display($grade); 29 | } 30 | return $this->get_new_cell_with_class($content); 31 | } 32 | 33 | /** 34 | * @param array $options 35 | * @throws coding_exception 36 | * @return string 37 | */ 38 | public function get_table_header($options = array()) { 39 | return get_string('provisionalgrade', 'mod_coursework'); 40 | } 41 | 42 | /** 43 | * @return string 44 | */ 45 | public function get_table_header_class(){ 46 | return 'provisionalgrade'; 47 | } 48 | 49 | /** 50 | * @return string 51 | */ 52 | public function header_group() { 53 | return 'grades'; 54 | } 55 | 56 | /** 57 | * @return string 58 | */ 59 | public function get_table_header_help_icon(){ 60 | global $OUTPUT; 61 | return ($OUTPUT->help_icon('provisionalgrade', 'mod_coursework')); 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /classes/allocation/widget.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | namespace mod_coursework\allocation; 18 | 19 | /** 20 | * Rendererable object to make the widget to choose allocation strategy. 21 | * 22 | * @package mod 23 | * @subpackage coursework 24 | * @copyright 2012 University of London Computer Centre {@link ulcc.ac.uk} 25 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 26 | */ 27 | 28 | use mod_coursework\models\coursework; 29 | 30 | defined('MOODLE_INTERNAL') || die(); 31 | 32 | 33 | /** 34 | * Just a placeholder for the renderer really. 35 | */ 36 | class widget { 37 | 38 | /** 39 | * @var coursework 40 | */ 41 | private $coursework; 42 | 43 | /** 44 | * Constructor 45 | * 46 | * @param coursework $coursework 47 | */ 48 | public function __construct($coursework) { 49 | $this->coursework = $coursework; 50 | } 51 | 52 | /** 53 | * @return coursework 54 | */ 55 | public function get_coursework() { 56 | return $this->coursework; 57 | } 58 | 59 | /** 60 | * Gets the name of the strategy used by this coursework to auto allocate students to assessors. 61 | * 62 | * @return string 63 | */ 64 | public function get_assessor_allocation_strategy() { 65 | return $this->coursework->assessorallocationstrategy; 66 | 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /tests/behat/feedback_group_feedback_for_students.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: Students see feedback on group assignments 3 | 4 | As a student 5 | I want to be able to see the feedaback for the group assignment even if I did not submit it 6 | So that I know what my marks are and can improve my work 7 | 8 | Background: 9 | Given there is a course 10 | And there is a coursework 11 | And the coursework "use_groups" setting is "1" in the database 12 | And the coursework is set to double marker 13 | And there is a manager 14 | And there is a student 15 | And the student is a member of a group 16 | And there is another student 17 | And the other student is a member of the group 18 | And the group has a submission 19 | And the submission is finalised 20 | And there is final feedback 21 | And the grades have been published 22 | 23 | Scenario: I can see the published grade when someone else submitted 24 | Given I am logged in as the other student 25 | When I visit the coursework page 26 | Then I should see the grade for the group submission 27 | And I should see the feedback for the group submission 28 | 29 | Scenario: I can see the published grade when I submitted 30 | Given I am logged in as the student 31 | When I visit the coursework page 32 | Then I should see the grade for the group submission 33 | And I should see the feedback for the group submission 34 | 35 | @broken 36 | Scenario: I can see the published grade in the gradebook when someone else submitted 37 | Given I am logged in as the other student 38 | And I visit the coursework page 39 | When I visit the gradebook page 40 | Then I should see the grade in the gradebook 41 | 42 | @broken 43 | Scenario: I can see the published grade in the gradebook when I submitted 44 | Given I am logged in as the student 45 | When I visit the gradebook page 46 | Then I should see the grade in the gradebook 47 | -------------------------------------------------------------------------------- /classes/forms/view_all_students_mform.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /* 18 | * this is a mform designed to allow the toggling of the displaying of students not allocated to the current user 19 | * 20 | */ 21 | 22 | namespace mod_coursework\forms; 23 | 24 | use moodleform; 25 | 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | global $CFG; 29 | 30 | require_once($CFG->dirroot.'/lib/formslib.php'); 31 | 32 | class view_all_students_mform extends moodleform { 33 | 34 | function definition() { 35 | 36 | $this->_form->addElement('hidden', 'id', $this->_customdata['cmid']); 37 | $this->_form->setType('id', PARAM_INT); 38 | 39 | 40 | $buttontext = (empty($this->_customdata['displayallstudents'])) ? get_string('viewallstudents', 'coursework') : get_string('hideallstudents','coursework'); 41 | $hiddenvalue = (empty($this->_customdata['displayallstudents'])) ? 1 : 0; 42 | $this->_form->addElement('submit', 'displayallstudentbutton', $buttontext); 43 | $this->_form->addElement('hidden', 'displayallstudents', $hiddenvalue); 44 | $this->_form->setType('displayallstudents', PARAM_INT); 45 | 46 | 47 | } 48 | 49 | /** 50 | * Bypasses the bit that echos the HTML so we can join it to a string. 51 | * 52 | * @return string 53 | */ 54 | public function display() { 55 | return $this->_form->toHtml(); 56 | } 57 | 58 | 59 | } -------------------------------------------------------------------------------- /tests/behat/automatic_agreement.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: Automatic agreement for simple grades 3 | 4 | As an user with add/edit coursework capability 5 | I can add an automatic agreement for double marking when both simple grades are adjacent within a specified range, 6 | so that the highest grade is chosen for all cases apart from the fail grades. 7 | 8 | Background: 9 | Given there is a course 10 | And there is a coursework 11 | And the coursework "numberofmarkers" setting is "2" in the database 12 | And there is a teacher 13 | And there is another teacher 14 | And there is a student 15 | And the student has a submission 16 | And the submission is finalised 17 | And the coursework deadline has passed 18 | 19 | Scenario: Only one grade in the submissions 20 | And the coursework "automaticagreementstrategy" setting is "none" in the database 21 | Given I am logged in as a teacher 22 | And I visit the coursework page 23 | And I click on the new feedback button for assessor 1 24 | When I grade the submission as 56 using the simple form 25 | Then I should not see the final grade on the multiple marker page 26 | 27 | Scenario: Simple grades within 10% boundaries takes higher mark as a final grade 28 | Given the coursework "automaticagreementstrategy" setting is "percentage_distance" in the database 29 | Given the coursework "automaticagreementrange" setting is "10" in the database 30 | And I am logged in as a teacher 31 | And I visit the coursework page 32 | And I click on the new feedback button for assessor 1 33 | And I grade the submission as 67 using the simple form 34 | And I log out 35 | And I log in as the other teacher 36 | And I visit the coursework page 37 | And I click on the new feedback button for assessor 2 38 | And I grade the submission as 63 using the simple form 39 | Then I should see the final grade as 67 on the multiple marker page 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /tests/classes/stages/assessor_test.php: -------------------------------------------------------------------------------- 1 | resetAfterTest(); 12 | $this->setAdminUser(); 13 | $this->create_a_course(); 14 | $this->create_a_coursework(); 15 | } 16 | 17 | public function test_prerequisite_stages_is_ok_with_no_feedbacks() { 18 | $this->coursework->update_attribute('numberofmarkers', 2); 19 | $this->coursework->update_attribute('moderationenabled', 1); 20 | $this->coursework->update_attribute('moderatorallocationstrategy', 'none'); 21 | 22 | $stages = $this->coursework->get_assessor_marking_stages(); 23 | $first_stage = reset($stages); 24 | 25 | $student = $this->create_a_student(); 26 | $this->create_a_submission_for_the_student(); 27 | 28 | $this->assertTrue($first_stage->prerequisite_stages_have_feedback($student)); 29 | 30 | } 31 | 32 | public function test_prerequisite_stages_is_ok_with_one_assessor_feedback() { 33 | $this->coursework->update_attribute('numberofmarkers', 2); 34 | $this->coursework->update_attribute('moderationenabled', 1); 35 | $this->coursework->update_attribute('moderatorallocationstrategy', 'none'); 36 | 37 | $stages = $this->coursework->get_assessor_marking_stages(); 38 | array_shift($stages); 39 | $second_stage = reset($stages); 40 | $this->assertEquals('assessor_2', $second_stage->identifier()); 41 | 42 | $student = $this->create_a_student(); 43 | $this->create_a_submission_for_the_student(); 44 | $this->create_a_teacher(); 45 | $this->create_an_assessor_feedback_for_the_submisison($this->teacher); 46 | 47 | $this->assertTrue($second_stage->prerequisite_stages_have_feedback($student)); 48 | } 49 | 50 | public function test_type() { 51 | $stage = new \mod_coursework\stages\assessor($this->coursework, 'assessor_1'); 52 | $this->assertEquals('assessor', $stage->type()); 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /classes/feedback_files.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | namespace mod_coursework; 18 | 19 | /** 20 | * Displays the information a student sees when they submit or have submitted work 21 | * 22 | * @package mod 23 | * @subpackage coursework 24 | * @copyright 2012 University of London Computer Centre {@link ulcc.ac.uk} 25 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 26 | */ 27 | 28 | use mod_coursework\models\feedback; 29 | 30 | defined('MOODLE_INTERNAL') || die(); 31 | 32 | 33 | /** 34 | * Represents the files a student has submitted. 35 | */ 36 | class feedback_files extends files { 37 | 38 | /** 39 | * @var feedback 40 | */ 41 | protected $feedback; 42 | 43 | /** 44 | * Constructor 45 | * 46 | * @param array $files 47 | * @param feedback $feedback 48 | */ 49 | public function __construct($files, $feedback) { 50 | $this->feedback = $feedback; 51 | parent::__construct($files); 52 | } 53 | 54 | /** 55 | * Getter for type so we can access the file area. 56 | * 57 | * @return string 58 | */ 59 | public function get_file_area_name() { 60 | return 'feedback'; 61 | } 62 | 63 | /** 64 | * Tells us whether to show plagiarism links for this file. Feedback files are not sent for plagiarism checking 65 | * so always false. 66 | * 67 | * @return bool 68 | */ 69 | public function show_plagiarism_links() { 70 | return false; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /classes/task/unenrol_task.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | namespace mod_coursework\models; 18 | namespace mod_coursework\task; 19 | 20 | 21 | /** 22 | * A scheduled task for the coursework module cron. 23 | * 24 | * @package mod_coursework 25 | * @copyright 2014 ULCC 26 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 27 | */ 28 | 29 | class unenrol_task extends \core\task\scheduled_task { 30 | 31 | /** 32 | * Get a descriptive name for this task (shown to admins). 33 | * 34 | * @return string 35 | */ 36 | public function get_name() { 37 | return get_string('unenroltask', 'mod_coursework'); 38 | } 39 | 40 | /** 41 | * Run coursework cron. 42 | */ 43 | public function execute() { 44 | 45 | global $DB; 46 | 47 | $courseworkids = $DB->get_records('coursework',array('processunenrol'=>1)); 48 | 49 | if (!empty($courseworkids)) { 50 | foreach ($courseworkids as $courseworkid) { 51 | $coursework = \mod_coursework\models\coursework::find($courseworkid); 52 | if (empty($coursework)) { 53 | continue; 54 | } 55 | 56 | $allocator = new \mod_coursework\allocation\auto_allocator($coursework); 57 | $allocator->process_allocations(); 58 | 59 | $DB->set_field('coursework','processunenrol',0,array('id'=>$coursework->id())); 60 | } 61 | } 62 | 63 | return true; 64 | } 65 | } -------------------------------------------------------------------------------- /classes/forms/personal_deadline_form.php: -------------------------------------------------------------------------------- 1 | _form->addElement('hidden', 'allocatabletype'); 19 | $this->_form->settype('allocatabletype', PARAM_ALPHANUMEXT); 20 | $this->_form->addElement('hidden', 'allocatableid'); 21 | $this->_form->settype('allocatableid', PARAM_RAW); 22 | $this->_form->addElement('hidden', 'courseworkid'); 23 | $this->_form->settype('courseworkid', PARAM_INT); 24 | $this->_form->addElement('hidden', 'id'); 25 | $this->_form->settype('id', PARAM_INT); 26 | $this->_form->addElement('hidden', 'setpersonaldeadlinespage'); 27 | $this->_form->settype('setpersonaldeadlinespage', PARAM_INT); 28 | $this->_form->addElement('hidden', 'multipleuserdeadlines'); 29 | $this->_form->settype('multipleuserdeadlines', PARAM_INT); 30 | 31 | 32 | // Current deadline for comparison 33 | $this->_form->addElement('html', '
Default deadline: '. userdate($this->get_coursework()->deadline).'
'); 34 | 35 | // Date and time picker 36 | $this->_form->addElement('date_time_selector', 'personal_deadline', get_string('personal_deadline', 'mod_coursework')); 37 | 38 | 39 | // Submit button 40 | $this->add_action_buttons(); 41 | } 42 | 43 | private function get_coursework() { 44 | return $this->_customdata['coursework']; 45 | } 46 | 47 | 48 | /** 49 | * @param array $data 50 | * @param array $files 51 | * @return array 52 | */ 53 | public function validation($data, $files) { 54 | $errors = array(); 55 | if ($data['personal_deadline'] <= time()) { 56 | $errors['personal_deadline'] = 'The new deadline you chose has already passed. Please select appropriate deadline'; 57 | } 58 | 59 | return $errors; 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /classes/renderers/personal_deadline_renderer.php: -------------------------------------------------------------------------------- 1 | set_pagelayout('standard'); 22 | $PAGE->navbar->add('Personal deadline'); 23 | $PAGE->set_title($SITE->fullname); 24 | $PAGE->set_heading($SITE->fullname); 25 | 26 | $html = ''; 27 | 28 | //if page has been accessed via the set personal deadline page then we dont want to say who set the last personal 29 | //deadline 30 | if (empty($vars['params']['multipleuserdeadlines'])) { 31 | $allocatable = $vars['personal_deadline']->get_allocatable(); 32 | $createdby = $DB->get_record('user', array('id' => $vars['personal_deadline']->createdbyid)); 33 | $lasteditedby = $DB->get_record('user', array('id' => $vars['personal_deadline']->lastmodifiedbyid)); 34 | 35 | $html = '

Edit personal deadline for ' . $allocatable->name() . '

'; 36 | 37 | if ($createdby) { 38 | $html .= ''; 39 | $html .= ''; 40 | if ($lasteditedby) { 41 | $html .= ''; 43 | } 44 | $html .= '
' . get_string('createdby', 'coursework') . '' . fullname($createdby) . '
' . get_string('lasteditedby', 'coursework') . '' . fullname($lasteditedby) . ' on ' . 42 | userdate($vars['personal_deadline']->timemodified) . '
'; 45 | } 46 | } else { 47 | $html = '

Edit personal deadline for ' . get_string('multipleusers','mod_coursework') . '

'; 48 | } 49 | 50 | 51 | echo $OUTPUT->header(); 52 | echo $html; 53 | $vars['form']->display(); 54 | echo $OUTPUT->footer(); 55 | 56 | } 57 | } -------------------------------------------------------------------------------- /actions/revert.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This file will revert the finalised state for one student's submission so that they can alter 19 | * files again. Not allowed if they already have feedbacks 20 | * 21 | * @package mod 22 | * @subpackage coursework 23 | * @copyright 2011 University of London Computer Centre {@link ulcc.ac.uk} 24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 | */ 26 | 27 | use mod_coursework\models\coursework; 28 | use mod_coursework\models\submission; 29 | 30 | require_once(dirname(__FILE__).'/../../../config.php'); 31 | 32 | global $DB, $PAGE, $CFG; 33 | 34 | 35 | $cmid = required_param('cmid', PARAM_INT); 36 | $submission_id = required_param('submissionid', PARAM_INT); 37 | 38 | $cm = $DB->get_record('course_modules', array('id' => $cmid)); 39 | $coursework = coursework::find($cm->instance); 40 | $course = $DB->get_record('course', array('id' => $cm->course)); 41 | $submission_db = $DB->get_record('coursework_submissions', array('id' => $submission_id)); 42 | $submission = submission::find($submission_db); 43 | 44 | require_login($course, false, $cm); 45 | $url = new moodle_url('/mod/coursework/view.php', array('id' => $cm->id)); 46 | 47 | // Bounce anyone who shouldn't be here. 48 | if (!has_capability('mod/coursework:revertfinalised', $PAGE->context)) { 49 | $message = 'You do not have permission to revert submissions'; 50 | redirect($url, $message); 51 | } 52 | 53 | $submission->finalised = 0; 54 | $submission->save(); 55 | 56 | $message = get_string('changessaved'); 57 | redirect($url, $message); 58 | -------------------------------------------------------------------------------- /classes/files.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | namespace mod_coursework; 18 | 19 | use Countable; 20 | 21 | defined('MOODLE_INTERNAL') || die(); 22 | 23 | /** 24 | * Renderable files list object. 25 | */ 26 | abstract class files implements countable { 27 | 28 | /** 29 | * @var \stored_file[] 30 | */ 31 | protected $files; 32 | 33 | /** 34 | * Can be either submission or feedbackfiles. 35 | * @var string 36 | */ 37 | 38 | /** 39 | * @param array $files 40 | */ 41 | public function __construct($files = array()) { 42 | $this->files = $files; 43 | } 44 | 45 | /** 46 | * Getter for the files. 47 | * 48 | * @return array 49 | */ 50 | public function get_files() { 51 | return $this->files; 52 | } 53 | 54 | /** 55 | * Do we have any actual files attached? 56 | * 57 | * @return bool 58 | */ 59 | public function has_files() { 60 | return $this->files && count($this->files) > 0; 61 | } 62 | 63 | /** 64 | * Getter for type. 65 | * 66 | * @return string 67 | */ 68 | abstract public function get_file_area_name(); 69 | 70 | /** 71 | * So we know what lang strings to use, we need to know if the files are plural, so this tells us. 72 | * 73 | * @return bool 74 | */ 75 | public function has_multiple_files() { 76 | return (count($this->files) > 1); 77 | } 78 | 79 | /** 80 | * @return int 81 | */ 82 | public function count() { 83 | return count($this->files); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /tests/behat/feedback_publishing_grades.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: publishing grades to the students 3 | 4 | In order that the students receive their final grades 5 | As a manager 6 | I want to be able to publish the grades when I am ready to 7 | 8 | Background: 9 | Given there is a course 10 | And there is a coursework 11 | And the coursework "numberofmarkers" setting is "1" in the database 12 | And the coursework "blindmarking" setting is "0" in the database 13 | And the coursework "moderationenabled" setting is "0" in the database 14 | And there is a student 15 | And the student has a submission 16 | And the submission is finalised 17 | 18 | Scenario: Not publishing with double marking hides feedback from the student 19 | Given there is a teacher 20 | And there is another teacher 21 | And the coursework "numberofmarkers" setting is "2" in the database 22 | And there are feedbacks from both teachers 23 | And I am logged in as a manager 24 | When I visit the coursework page 25 | And I click the new multiple final feedback button for the student 26 | And I grade the submission using the simple form 27 | And I log out 28 | And I log in as the student 29 | And I visit the coursework page 30 | Then I should not see the final grade on the student page 31 | And I should not see the grade comment on the student page 32 | 33 | Scenario: Deliberate publishing with double marking shows feedback to the student 34 | Given there is a teacher 35 | And there is another teacher 36 | And the coursework "numberofmarkers" setting is "2" in the database 37 | And there are feedbacks from both teachers 38 | And I am logged in as a manager 39 | 40 | When I visit the coursework page 41 | And I click the new multiple final feedback button for the student 42 | And I grade the submission using the simple form 43 | And I press the publish button 44 | And I log out 45 | And I log in as the student 46 | And I visit the coursework page 47 | Then I should see the final grade on the student page 48 | And I should see the grade comment on the student page -------------------------------------------------------------------------------- /tests/behat/feedback_single_marking.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: Adding and editing single feedback 3 | 4 | In order to provide students with a fair final grade that combines the component grades 5 | As a course leader 6 | I want to be able to edit the final grade via a form 7 | 8 | Background: 9 | Given there is a course 10 | And there is a coursework 11 | And the coursework "numberofmarkers" setting is "1" in the database 12 | And there is a student 13 | And there is a teacher 14 | And the student has a submission 15 | And the teacher has a capability to edit their own initial feedbacks 16 | And I log in as the teacher 17 | 18 | Scenario: Setting the final feedback grade 19 | Given the submission is finalised 20 | And the coursework deadline has passed 21 | And I visit the coursework page 22 | When I click the new single final feedback button for the student 23 | When I grade the submission using the simple form 24 | Then I should be on the coursework page 25 | And I should see the final grade on the single marker page 26 | 27 | Scenario: Setting the final feedback comment 28 | Given the submission is finalised 29 | And I visit the coursework page 30 | When I click the new single final feedback button for the student 31 | When I grade the submission using the simple form 32 | Then I should be on the coursework page 33 | When I click the edit final feedback button 34 | Then I should see the grade comment in the form on the page 35 | And I should see the grade in the form on the page 36 | 37 | Scenario: I should not see the feedback icon when the submisison has not been finalised 38 | And I visit the coursework page 39 | Then I should not see a link to add feedback 40 | 41 | Scenario: Editing someone elses grade 42 | Given the submission is finalised 43 | And there is feedback for the submission from the teacher 44 | And I visit the coursework page 45 | When I click the edit final feedback button 46 | Then I should see the grade comment as "Blah" in the form on the page 47 | And I should see the other teacher's grade in the form on the page 48 | 49 | -------------------------------------------------------------------------------- /classes/models/plagiarism_flag.php: -------------------------------------------------------------------------------- 1 | coursework)) { 42 | $this->coursework = coursework::find($this->courseworkid); 43 | } 44 | 45 | return $this->coursework; 46 | } 47 | 48 | /** 49 | * Memoized getter 50 | * 51 | * @return bool|submission 52 | */ 53 | public function get_submission() { 54 | if (!isset($this->submission) && !empty($this->submissionid)) { 55 | $this->submission = submission::find($this->submissionid); 56 | } 57 | 58 | return $this->submission; 59 | } 60 | 61 | /** 62 | * @param $submission 63 | * @return static 64 | */ 65 | public static function get_plagiarism_flag($submission){ 66 | return static::find(array('submissionid' => $submission->id)); 67 | } 68 | 69 | 70 | /** 71 | * @return bool 72 | */ 73 | public function can_release_grades(){ 74 | 75 | switch ($this->status){ 76 | 77 | case self::INVESTIGATION: 78 | case self::NOTCLEARED: 79 | return false; 80 | break; 81 | case self::RELEASED: 82 | case self::CLEARED: 83 | return true; 84 | break; 85 | 86 | } 87 | } 88 | 89 | 90 | } -------------------------------------------------------------------------------- /tests/behat/submissions_group_submissions.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: Students are able to submit one piece of work on behalf of the group 3 | 4 | As a student 5 | I want to be able to submit a single piece of work on behalf of the other people in my group 6 | So that they and the tutor can see it and mark it 7 | 8 | Background: 9 | Given there is a course 10 | And there is a coursework 11 | And the coursework "use_groups" setting is "1" in the database 12 | And I am logged in as a student 13 | And the student is a member of a group 14 | And there is another student 15 | And the other student is a member of the group 16 | 17 | @javascript 18 | Scenario: I can submit a file and it appears for the others to see 19 | When I visit the coursework page 20 | And I click on the new submission button 21 | And I upload "mod/coursework/tests/files_for_uploading/Test_document.docx" file to "Upload a file" filemanager 22 | And I press "Submit" 23 | And I log out 24 | And I log in as the other student 25 | And I visit the coursework page 26 | Then I should see the file on the page 27 | 28 | @javascript 29 | Scenario: I can resubmit the work when someone else has submitted it 30 | Given the coursework "maxfiles" setting is "2" in the database 31 | And I visit the coursework page 32 | And I click on the new submission button 33 | And I upload "mod/coursework/tests/files_for_uploading/Test_document.docx" file to "Upload a file" filemanager 34 | And I press "Submit" 35 | And I log out 36 | And I log in as the other student 37 | And I visit the coursework page 38 | Then I should see that the submission was made by the student 39 | 40 | When I click on the edit submission button 41 | Then I should see "1" elements in "Upload a file" filemanager 42 | 43 | When I upload "mod/coursework/tests/files_for_uploading/Test_document_two.docx" file to "Upload a file" filemanager 44 | 45 | And I press "Submit" 46 | Then I should be on the coursework page 47 | And I should see both the submission files on the page 48 | And I should see that the submission was made by the other student 49 | -------------------------------------------------------------------------------- /classes/task/enrol_task.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | namespace mod_coursework; 18 | namespace mod_coursework\task; 19 | 20 | 21 | /** 22 | * A scheduled task for the coursework module cron. 23 | * 24 | * @package mod_coursework 25 | * @copyright 2014 ULCC 26 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 27 | */ 28 | 29 | class enrol_task extends \core\task\scheduled_task { 30 | 31 | /** 32 | * Get a descriptive name for this task (shown to admins). 33 | * 34 | * @return string 35 | */ 36 | public function get_name() { 37 | return get_string('enroltask', 'mod_coursework'); 38 | } 39 | 40 | /** 41 | * Run coursework cron. 42 | */ 43 | public function execute() { 44 | 45 | global $DB; 46 | 47 | $courseworkids = $DB->get_records('coursework',array('processenrol'=>1)); 48 | 49 | if (!empty($courseworkids)) { 50 | foreach ($courseworkids as $courseworkid) { 51 | $coursework = \mod_coursework\models\coursework::find($courseworkid); 52 | if (empty($coursework)) { 53 | continue; 54 | } 55 | 56 | $cache = \cache::make('mod_coursework', 'courseworkdata'); 57 | $cache->set($coursework->id()."_teachers", ''); 58 | $allocator = new \mod_coursework\allocation\auto_allocator($coursework); 59 | $allocator->process_allocations(); 60 | 61 | $DB->set_field('coursework','processenrol',0,array('id'=>$coursework->id())); 62 | } 63 | } 64 | 65 | return true; 66 | } 67 | } -------------------------------------------------------------------------------- /tests/behat/sampling_manual_sampling.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: Manual sampling 3 | 4 | As a teacher 5 | I can manually select the submissions to be included in the sample for a single feedback stage 6 | So I can select correct sample of students for double marking 7 | 8 | Background: 9 | Given there is a course 10 | And I am logged in as a manager 11 | And the manager has a capability to allocate students in samplings 12 | And there is a coursework 13 | And the coursework allocation option is disabled 14 | And the coursework has sampling enabled 15 | And the coursework is set to double marker 16 | And there is a student 17 | And there is a teacher 18 | And the teacher has a capability to mark submissions 19 | And there is another teacher 20 | And the student has a submission 21 | And there is feedback for the submission from the other teacher 22 | And the submission deadline has passed 23 | And the submission is finalised 24 | 25 | 26 | Scenario: Manual sampling should include student when selected 27 | When I visit the allocations page 28 | And I select a student as a part of the sample for the second stage 29 | And I save everything 30 | And I log out 31 | And I log in as the teacher 32 | And I visit the coursework page 33 | Then I should be able to add the second grade for this student 34 | 35 | 36 | Scenario: Manual sampling should not include student when not selected 37 | When I visit the allocations page 38 | And I deselect a student as a part of the sample for the second stage 39 | And I save everything 40 | And I log out 41 | And I log in as the teacher 42 | And I visit the coursework page 43 | Then I should not be able to add the second grade for this student 44 | 45 | 46 | Scenario: Single grade should go to the gradebook column when only first stage is in sample 47 | When I visit the allocations page 48 | And I deselect a student as a part of the sample for the second stage 49 | And I save everything 50 | And I log out 51 | And I log in as the teacher 52 | And I visit the coursework page 53 | Then I should see the grade given by the initial teacher in the provisional grade column 54 | -------------------------------------------------------------------------------- /db/events.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Event handlers. Mostly for dealing with auto allocation of markers. 19 | * 20 | * @package mod 21 | * @subpackage coursework 22 | * @copyright 2012 University of London Computer Centre {@link ulcc.ac.uk} 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | 27 | 28 | $observers = array( 29 | 30 | array( 31 | 'eventname' => '\core\event\role_assigned', 32 | 'callback' => 'mod_coursework_observer::autoallocate_when_user_added', 33 | ), 34 | array( 35 | 'eventname' => '\core\event\role_unassigned', 36 | 'callback' => 'mod_coursework_observer::autoallocate_when_user_removed', 37 | ), 38 | array( 39 | 'eventname' => '\mod_coursework\event\coursework_deadline_changed', 40 | 'callback' => 'mod_coursework_observer::coursework_deadline_changed', 41 | 'schedule' => 'cron' 42 | ), 43 | array( 44 | 'eventname' => '\core\event\course_module_updated', 45 | 'callback' => 'mod_coursework_observer::process_allocation_after_update', 46 | ), 47 | array( 48 | 'eventname' => '\core\event\course_module_created', 49 | 'callback' => 'mod_coursework_observer::process_allocation_after_creation', 50 | ), 51 | array( 52 | 'eventname' => '\core\event\group_member_added', 53 | 'callback' => 'mod_coursework_observer::process_allocations_when_group_member_added', 54 | ), 55 | array( 56 | 'eventname' => '\core\event\group_member_removed', 57 | 'callback' => 'mod_coursework_observer::process_allocations_when_group_member_removed', 58 | ), 59 | ); 60 | 61 | 62 | -------------------------------------------------------------------------------- /tests/behat/feedback_rubrics.feature: -------------------------------------------------------------------------------- 1 | @mod @mod_coursework 2 | Feature: Adding feedback using the built in Moodle rubrics 3 | 4 | As a teacher 5 | I want to be able to give detailed feedback about specific parts of the students work 6 | in a standardised way 7 | So that I can grade the work faster, give more consistent responses and make the process more fair 8 | 9 | Background: 10 | Given there is a course 11 | And there is a coursework 12 | And the coursework "numberofmarkers" setting is "1" in the database 13 | And there is a student 14 | And the student has a submission 15 | And the submission is finalised 16 | And I am logged in as a teacher 17 | 18 | Scenario: I should be able to add feedback using a simple rubric 19 | Given there is a rubric defined for the coursework 20 | Given I visit the coursework page 21 | When I click the new single final feedback button for the student 22 | And I grade by filling the rubric with: 23 | | first criterion | 1 | Very good | 24 | And I fill in the rest of the form after the rubric and submit it 25 | And I log out 26 | And I log in as a manager 27 | And I visit the coursework page 28 | And I publish the grades 29 | And I log out 30 | And I log in as a student 31 | And I visit the coursework page 32 | Then I should see the rubric grade on the page 33 | And I should see the grade comment on the student page 34 | 35 | @broken 36 | Scenario: I should see the rubric grade show up in the gradebook 37 | Given there is a rubric defined for the coursework 38 | Given I visit the coursework page 39 | When I click the new single final feedback button for the student 40 | And I grade by filling the rubric with: 41 | | first criterion | 1 | Very good | 42 | And I fill in the rest of the form after the rubric and submit it 43 | And I log out 44 | And I log in as a manager 45 | And I visit the coursework page 46 | And I publish the grades 47 | And I log out 48 | And I log in as a student 49 | When I visit the gradebook page 50 | Then I should see the rubric grade in the gradebook 51 | When I visit the coursework page 52 | And I should see the grade comment on the student page 53 | 54 | -------------------------------------------------------------------------------- /classes/allocation/strategy/group_assessor.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | namespace mod_coursework\allocation\strategy; 18 | 19 | /** 20 | * Class file for the Group assessor allocation strategy. 21 | * 22 | * @package mod 23 | * @subpackage coursework 24 | * @copyright 2018 University of London Computer Centre {@link ulcc.ac.uk} 25 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 26 | */ 27 | 28 | use html_writer;; 29 | /** 30 | * Assessor from the Moodle group assigned as 1st stage assessor to allocatables from their group 31 | */ 32 | class group_assessor extends base { 33 | 34 | /** 35 | * Flag that saves us from doing all the allocations and then getting a false response for all the 36 | * teacher ids. 37 | * 38 | * @return bool 39 | */ 40 | public function autoallocation_enabled() { 41 | return false; 42 | } 43 | 44 | /** 45 | * Some strategies need to be configured. This function will get the HTML for the form that will configure them. 46 | * 47 | * @param string $strategypurpose 48 | * @return string 49 | */ 50 | public function add_form_elements($strategypurpose = 'assessor') { 51 | return ''; 52 | } 53 | 54 | /** 55 | * Saves the form data associated with the instance of this strategy. 56 | * 57 | * @param $type 58 | * @return mixed 59 | */ 60 | public function save_allocation_strategy_options() { 61 | // Nothing to do here as there are no form elements. 62 | } 63 | 64 | /** 65 | * @param $teachers 66 | * @param $student 67 | * @return mixed 68 | */ 69 | protected function list_of_allocatable_teachers_and_their_current_number_of_allocations($teachers, $student) { 70 | return array(); 71 | } 72 | } 73 | --------------------------------------------------------------------------------