diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index 24251c760..1a66c220d 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -37,9 +37,9 @@ public static function getDefaultAssignTos(int $course_id): array return [['groups' => [['value' => ['course_id' => $course_id], 'text' => 'Everybody']], 'selectedGroup' => '', 'available_from_date' => Carbon::now()->format('Y-m-d'), - 'available_from_time' => '09:00:00', + 'available_from_time' => '9:00 AM', 'due_date' => Carbon::now()->addDay()->format('Y-m-d'), - 'due_time' => '09:00:00']]; + 'due_time' => '9:00 AM']]; } public static function getQtiQuestionType(string $qti_json) diff --git a/app/Http/Controllers/AssignmentController.php b/app/Http/Controllers/AssignmentController.php index 5fb3e9bb0..3f5f57ece 100644 --- a/app/Http/Controllers/AssignmentController.php +++ b/app/Http/Controllers/AssignmentController.php @@ -755,6 +755,7 @@ function store(StoreAssignmentProperties $request, try { $data = $request->validated(); + $assign_tos = $this->reformatAssignToTimes($request->assign_tos); if ($request->user()->role === 5) { $assignment_json = '{"public_description":null,"private_description":null,"assessment_type":"real time","number_of_allowed_attempts":"1","number_of_allowed_attempts_penalty":null,"can_view_hint":0,"hint_penalty":null,"algorithmic":0,"learning_tree_success_level":null,"learning_tree_success_criteria":null,"number_of_successful_branches_for_a_reset":null,"number_of_resets":null,"min_time":null,"min_number_of_successful_assessments":null,"free_pass_for_satisfying_learning_tree_criteria":null,"min_time_needed_in_learning_tree":null,"percent_earned_for_exploring_learning_tree":null,"submission_count_percent_decrease":null,"assignment_group_id":1,"source":"a","instructions":"","number_of_randomized_assessments":null,"external_source_points":null,"scoring_type":"p","points_per_question":"number of points","default_completion_scoring_mode":null,"default_points_per_question":"10.00","total_points":null,"default_clicker_time_to_submit":null,"show_points_per_question":1,"file_upload_mode":null,"default_open_ended_submission_type":"0","default_open_ended_text_editor":null,"late_policy":"not accepted","late_deduction_percent":null,"late_deduction_application_period":"once","shown":1,"show_scores":1,"solutions_released":0,"solutions_availability":"automatic","graders_can_see_student_names":1,"students_can_view_assignment_statistics":0,"include_in_weighted_average":1,"notifications":1,"course_id":512,"lms_resource_link_id":null,"textbook_url":null}'; @@ -768,12 +769,11 @@ function store(StoreAssignmentProperties $request, $date = date("Y-m-d"); $datetime = new DateTime('tomorrow'); $tomorrow = $datetime->format('Y-m-d'); - $assign_tos = '[{"groups":[{"value":{"course_id":' . $course->id . '},"text":"Everybody"}],"selectedGroup":null,"available_from_date":"' . $date . '","available_from_time":"09:00:00","due_date":"' . $tomorrow . '","due_time":"09:00:00"}]'; + $assign_tos = '[{"groups":[{"value":{"course_id":' . $course->id . '},"text":"Everybody"}],"selectedGroup":null,"available_from_date":"' . $date . '","available_from_time":"9:00 AM","due_date":"' . $tomorrow . '","due_time":"9:00 AM"}]'; $assign_tos = json_decode($assign_tos, true); $this->addAssignTos($assignment, $assign_tos, $section, $request->user()); } else { - $assign_tos = $request->assign_tos; $repeated_groups = $this->groupsMustNotRepeat($assign_tos); if ($repeated_groups) { $response['message'] = $repeated_groups; @@ -1321,7 +1321,7 @@ function update(StoreAssignmentProperties $request, } - $assign_tos = $request->assign_tos; + $assign_tos = $this->reformatAssignToTimes($request->assign_tos); $repeated_groups = $this->groupsMustNotRepeat($assign_tos); if ($repeated_groups) { $response['message'] = $repeated_groups; @@ -1589,5 +1589,22 @@ public function validAssessmentTypeSwitch(Assignment $assignment, $new_assessmen } + /** + * @param $assign_tos + * @return array + */ + function reformatAssignToTimes($assign_tos): array + { + foreach ($assign_tos as $key => $assign_to) { + foreach (['available_from_time', 'due_time', 'final_submission_deadline_time'] as $time_key => $value) { + if (isset($assign_tos[$key][$value])) { + $assign_tos[$key][$value] = DateTime::createFromFormat('g:i A', $assign_to[$value])->format('H:i:00'); + } + } + } + return $assign_tos; + } + + } diff --git a/app/Http/Requests/StoreAssignmentProperties.php b/app/Http/Requests/StoreAssignmentProperties.php index 2b13f2e63..819386aa5 100644 --- a/app/Http/Requests/StoreAssignmentProperties.php +++ b/app/Http/Requests/StoreAssignmentProperties.php @@ -121,11 +121,12 @@ public function rules(): array $new_assign_tos[$key]['due'] = "{$assign_to['due_date']} {$assign_to['due_time']}"; if ($this->late_policy !== 'not accepted') { $rules['final_submission_deadline_' . $key] = new IsADateLaterThan($this->{'due_' . $key}, 'due', 'late policy deadline'); + $rules['final_submission_deadline_time_' . $key] = 'date_format:g:i A'; } $rules['due_' . $key] = new IsADateLaterThan($this->{'available_from_' . $key}, 'available on', 'due'); $rules['available_from_date_' . $key] = 'required|date'; - $rules['available_from_time_' . $key] = 'required|date_format:H:i:00'; - $rules['due_time_' . $key] = 'required|date_format:H:i:00'; + $rules['available_from_time_' . $key] = 'required|date_format:g:i A'; + $rules['due_time_' . $key] = 'required|date_format:g:i A'; $rules['groups_' . $key] = 'required'; } } @@ -197,10 +198,14 @@ public function messages() $messages = []; if (!$this->is_template) { foreach ($this->assign_tos as $key => $assign_to) { + $index = $key + 1; $messages["groups_{$key}.required"] = 'The assign to field is required.'; $messages["available_from_date_{$key}.required"] = 'This date is required.'; - $messages["available_from_time_{$key}.required"] = 'This time is required: H:i:00'; - $messages["due_time_{$key}.required"] = 'This time is required: H:i:00'; + $messages["available_from_time_{$key}.required"] = $this->getTimeFormatErrorMessage('available on', $index); + $messages["available_from_time_{$key}.date_format"] = $this->getTimeFormatErrorMessage('available on', $index); + $messages["due_time_{$key}.required"] = $this->getTimeFormatErrorMessage('due time', $index); + $messages["due_time_{$key}.date_format"] = $this->getTimeFormatErrorMessage('due time', $index); + $messages["final_submission_deadline_time_{$key}.date_format"] = $this->getTimeFormatErrorMessage('final submission deadline time', $index); } $messages['name.unique'] = "Assignment names must be unique with a course."; } else { @@ -209,4 +214,14 @@ public function messages() $messages['textbook_url.url'] = "The URL should be of the form https://my-textbook-url.com/some-page."; return $messages; } + + /** + * @param string $field + * @param int $index + * @return string + */ + public function getTimeFormatErrorMessage(string $field, int $index): string + { + return "Time for $field $index needs a valid time such as 9:00 AM."; + } } diff --git a/app/Traits/Test.php b/app/Traits/Test.php index e42ff8b2b..a1af8c90f 100644 --- a/app/Traits/Test.php +++ b/app/Traits/Test.php @@ -33,13 +33,13 @@ public function createAssignTosFromGroups($assignment_info, $groups){ 'groups' => $groups, 'available_from' => '2020-06-10 09:00:00', 'available_from_date' => '2020-06-10', - 'available_from_time' => '09:00:00', + 'available_from_time' => '9:00 AM', 'due' => '2020-06-12 09:00:00', 'due_date' => '2020-06-12', - 'due_time' => '09:00:00', + 'due_time' => '9:00 AM', 'final_submission_deadline' => '2021-06-12 09:00:00', 'final_submission_deadline_date' => '2021-06-12', - 'final_submission_deadline_time' => '09:00:00' + 'final_submission_deadline_time' => '9:00 AM', ] ]; $assignment_info['assign_tos'] = $assign_tos; @@ -47,12 +47,12 @@ public function createAssignTosFromGroups($assignment_info, $groups){ $group_info = ["groups_$key" => [$groups], "due_$key" => '2020-06-12 09:00:00', "due_date_$key" => '2020-06-12', - "due_time_$key" => '09:00:00', + "due_time_$key" => '9:00 AM', "available_from_$key" => '2020-06-10', "available_from_date_$key" => '2020-06-12', - "available_from_time_$key" => '09:00:00', + "available_from_time_$key" => '9:00 AM', "final_submission_deadline_date_$key" => '2021-06-12', - "final_submission_deadline_time_$key" => '09:00:00']; + "final_submission_deadline_time_$key" => '9:00 AM']; foreach ($group_info as $info_key => $info_value) { $assignment_info[$info_key] = $info_value; } diff --git a/resources/js/components/AssignmentProperties.vue b/resources/js/components/AssignmentProperties.vue index 35ba3975d..5648d3177 100644 --- a/resources/js/components/AssignmentProperties.vue +++ b/resources/js/components/AssignmentProperties.vue @@ -1255,7 +1255,7 @@ required :options="assignToGroups" :class="{ 'is-invalid': form.errors.has(`groups_${index}`) }" - @change="updateAssignTos(assignTo)" + @change="form.errors.clear(`groups_${index}`);updateAssignTos(assignTo)" /> @@ -1294,18 +1294,25 @@ required tabindex="0" :min="min" + class="datepicker" :class="{ 'is-invalid': form.errors.has(`available_from_date_${index}`) }" /> - + + + + + @@ -1327,20 +1334,26 @@ tabindex="0" :min="min" :class="{ 'is-invalid': form.errors.has(`due_${index}`) }" + class="datepicker" @shown="form.errors.clear(`due_${index}`)" /> - + - + + + + + @@ -1373,22 +1386,28 @@ tabindex="0" :min="min" :class="{ 'is-invalid': form.errors.has(`final_submission_deadline_${index}`) }" + class="datepicker" :disabled="Boolean(solutionsReleased) && assessmentType !== 'real time'" @shown="form.errors.clear(`final_submission_deadline_${index}`)" /> - + - + + + + + @@ -1595,11 +1614,8 @@ export default { fixDatePickerAccessibilitysForAssignTos () { for (let i = 0; i < this.form.assign_tos.length; i++) { fixDatePicker(`available_from_${i}`, `selected_available_from_${i}`) - fixDatePicker(`available_from_time_${i}`, `selected_available_from_time_${i}`) fixDatePicker(`due_date_${i}`, `selected_due_date_${i}`) - fixDatePicker(`due_time_${i}`, `selected_due_time_${i}`) fixDatePicker(`final_submission_deadline_${i}`, `selected_final_submission_deadline_${i}`) - fixDatePicker(`final_submission_deadline_time_${i}`, `selected_final_submission_deadline_time_${i}`) } }, checkDefaultOpenEndedSubmissionType () { @@ -1910,3 +1926,19 @@ export default { } } + diff --git a/resources/js/helpers/AssignmentProperties.js b/resources/js/helpers/AssignmentProperties.js index 0dde7dc1f..e70eb69b8 100644 --- a/resources/js/helpers/AssignmentProperties.js +++ b/resources/js/helpers/AssignmentProperties.js @@ -1,6 +1,10 @@ import axios from 'axios' import Form from 'vform' +function reformatTime (vm, time) { + return vm.$moment(time, 'HH:mm:ss').format('h:mm A') +} + export const assignmentForm = new Form({ name: '', assign_tos: [], @@ -90,11 +94,11 @@ export function defaultAssignTos (moment, courseStartDate, courseEndDate) { groups: [], selectedGroup: null, available_from_date: moment(courseStartDate).format('YYYY-MM-DD'), - available_from_time: '09:00:00', + available_from_time: '9:00 AM', due_date: moment(moment(), 'YYYY-MM-DD').format('YYYY-MM-DD'), - due_time: '09:00:00', + due_time: '9:00 AM', final_submission_deadline_date: moment(courseEndDate).format('YYYY-MM-DD'), - final_submission_deadline_time: '09:00:00' + final_submission_deadline_time: '9:00 AM' } } @@ -120,9 +124,9 @@ export function resetAssignmentForm (form, assignmentId) { form.public_description = '' form.private_description = '' form.available_from_date = '' - form.available_from_time = '09:00:00' + form.available_from_time = '9:00 AM' form.due_date = '' - form.due_time = '09:00:00' + form.due_time = '9:00 AM' form.type_of_submission = 'correct' form.num_submissions_needed = '2' form.default_open_ended_submission_type = 'file' @@ -213,6 +217,15 @@ export async function editAssignmentProperties (assignmentProperties, vm) { for (let i = 0; i < assignmentProperties.assign_tos.length; i++) { vm.form.assign_tos[i].groups = vm.form.assign_tos[i].formatted_groups vm.form.assign_tos[i].selectedGroup = null + if (vm.form.assign_tos[i].available_from_time) { + vm.form.assign_tos[i].available_from_time = reformatTime(vm, vm.form.assign_tos[i].available_from_time) + } + if (vm.form.assign_tos[i].due_time) { + vm.form.assign_tos[i].due_time = reformatTime(vm, vm.form.assign_tos[i].due_time) + } + if (vm.form.assign_tos[i].final_submission_deadline_time) { + vm.form.assign_tos[i].final_submission_deadline_time = reformatTime(vm, vm.form.assign_tos[i].final_submission_deadline_time) + } } } vm.form.algorithmic = assignmentProperties.algorithmic diff --git a/tests/Feature/Instructors/AssignmentsIndex2Test.php b/tests/Feature/Instructors/AssignmentsIndex2Test.php index 443e6c6bc..18745e461 100644 --- a/tests/Feature/Instructors/AssignmentsIndex2Test.php +++ b/tests/Feature/Instructors/AssignmentsIndex2Test.php @@ -95,13 +95,13 @@ public function setup(): void 'groups' => [['value' => ['course_id' => $this->course->id], 'text' => 'Everybody']], 'available_from' => '2020-06-10 09:00:00', 'available_from_date' => '2020-06-10', - 'available_from_time' => '09:00:00', + 'available_from_time' => '9:00 AM', 'due' => '2020-06-12 09:00:00', 'due_date' => '2020-06-12', - 'due_time' => '09:00:00', + 'due_time' => '9:00 AM', 'final_submission_deadline' => '2021-06-12 09:00:00', 'final_submission_deadline_date' => '2021-06-12', - 'final_submission_deadline_time' => '09:00:00' + 'final_submission_deadline_time' => '9:00 AM', ] ]; $this->assignment_info = ['course_id' => $this->course->id, @@ -127,12 +127,12 @@ public function setup(): void $group_info = ["groups_$key" => ['Everybody'], "due_$key" => '2020-06-12 09:00:00', "due_date_$key" => '2020-06-12', - "due_time_$key" => '09:00:00', + "due_time_$key" => '9:00 AM', "available_from_$key" => '2020-06-10', "available_from_date_$key" => '2020-06-12', - "available_from_time_$key" => '09:00:00', + "available_from_time_$key" => '9:00 AM', "final_submission_deadline_date_$key" => '2021-06-12', - "final_submission_deadline_time_$key" => '09:00:00']; + "final_submission_deadline_time_$key" => '9:00 AM']; foreach ($group_info as $info_key => $info_value) { $this->assignment_info[$info_key] = $info_value; } diff --git a/tests/Feature/Instructors/AssignmentsIndex3Test.php b/tests/Feature/Instructors/AssignmentsIndex3Test.php index e17bd5e9d..349f60f9f 100644 --- a/tests/Feature/Instructors/AssignmentsIndex3Test.php +++ b/tests/Feature/Instructors/AssignmentsIndex3Test.php @@ -52,13 +52,13 @@ public function setup(): void 'groups' => [['value' => ['course_id' => $this->course->id], 'text' => 'Everybody']], 'available_from' => '2020-06-10 09:00:00', 'available_from_date' => '2020-06-10', - 'available_from_time' => '09:00:00', + 'available_from_time' => '9:00 AM', 'due' => '2020-06-12 09:00:00', 'due_date' => '2020-06-12', - 'due_time' => '09:00:00', + 'due_time' => '9:00 AM', 'final_submission_deadline' => '2021-06-12 09:00:00', 'final_submission_deadline_date' => '2021-06-12', - 'final_submission_deadline_time' => '09:00:00' + 'final_submission_deadline_time' => '9:00 AM', ] ]; $this->assignment_info = ['course_id' => $this->course->id, @@ -85,12 +85,12 @@ public function setup(): void $group_info = ["groups_$key" => ['Everybody'], "due_$key" => '2020-06-12 09:00:00', "due_date_$key" => '2020-06-12', - "due_time_$key" => '09:00:00', + "due_time_$key" => '9:00 AM', "available_from_$key" => '2020-06-10', "available_from_date_$key" => '2020-06-12', - "available_from_time_$key" => '09:00:00', + "available_from_time_$key" => '9:00 AM', "final_submission_deadline_date_$key" => '2021-06-12', - "final_submission_deadline_time_$key" => '09:00:00']; + "final_submission_deadline_time_$key" => '9:00 AM']; foreach ($group_info as $info_key => $info_value) { $this->assignment_info[$info_key] = $info_value; }