Skip to content

Commit

Permalink
Better time management for assignments
Browse files Browse the repository at this point in the history
  • Loading branch information
kreut committed Jun 30, 2022
1 parent f9a8307 commit ef1edba
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 58 deletions.
4 changes: 2 additions & 2 deletions app/Helpers/Helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
23 changes: 20 additions & 3 deletions app/Http/Controllers/AssignmentController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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}';
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}



}
23 changes: 19 additions & 4 deletions app/Http/Requests/StoreAssignmentProperties.php
Original file line number Diff line number Diff line change
Expand Up @@ -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';
}
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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.";
}
}
12 changes: 6 additions & 6 deletions app/Traits/Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,26 @@ 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;
foreach ( $assignment_info['assign_tos'][0]['groups'] as $key => $group) {
$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;
}
Expand Down
84 changes: 58 additions & 26 deletions resources/js/components/AssignmentProperties.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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)"
/>
<has-error :form="form" :field="`groups_${index}`"/>
</b-col>
Expand Down Expand Up @@ -1294,18 +1294,25 @@
required
tabindex="0"
:min="min"
class="datepicker"
:class="{ 'is-invalid': form.errors.has(`available_from_date_${index}`) }"
/>
<has-error :form="form" :field="`available_from_date_${index}`"/>
</b-col>
<b-col>
<b-form-timepicker :id="`available_from_time_${index}`"
v-model="assignTo.available_from_time"
tabindex="0"
locale="en"
:class="{ 'is-invalid': form.errors.has(`available_from_time_${index}`) }"
<b-input-group class="time-input-group">
<b-form-input :id="`available_from_time_${index}`"
v-model="assignTo.available_from_time"
:class="{ 'is-invalid': form.errors.has(`available_from_time_${index}`) }"
class="time-input"
@input="form.errors.clear(`available_from_time_${index}`)"
@shown="form.errors.clear(`available_from_time_${index}`)"
/>
<b-input-group-append>
<span class="input-group-text"><b-icon-clock/></span>
</b-input-group-append>
<has-error :form="form" :field="`available_from_time_${index}`"/>
</b-input-group>
</b-col>
</b-form-row>
</b-form-group>
Expand All @@ -1327,20 +1334,26 @@
tabindex="0"
:min="min"
:class="{ 'is-invalid': form.errors.has(`due_${index}`) }"
class="datepicker"
@shown="form.errors.clear(`due_${index}`)"
/>
<has-error :form="form" :field="`due_${index}`"/>
</b-col>
<b-col>
<b-form-timepicker :id="`due_time_${index}`"
v-model="assignTo.due_time"
tabindex="0"
locale="en"
required
:class="{ 'is-invalid': form.errors.has(`due_time_${index}`) }"
@shown="form.errors.clear(`due_time_${index}`)"
<b-input-group class="time-input-group">
<b-form-input :id="`due_time_${index}`"
v-model="assignTo.due_time"
required
:class="{ 'is-invalid': form.errors.has(`due_time_${index}`) }"
class="time-input"
@input="form.errors.clear(`due_time_${index}`)"
@shown="form.errors.clear(`due_time_${index}`)"
/>
<has-error :form="form" :field="`due_time_${index}`"/>
<b-input-group-append>
<span class="input-group-text"><b-icon-clock/></span>
</b-input-group-append>
<has-error :form="form" :field="`due_time_${index}`"/>
</b-input-group>
</b-col>
</b-form-row>
</b-form-group>
Expand Down Expand Up @@ -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}`)"
/>
<has-error :form="form" :field="`final_submission_deadline_${index}`"/>
</b-col>
<b-col>
<b-form-timepicker :id="`final_submission_deadline_time_${index}`"
v-model="assignTo.final_submission_deadline_time"
tabindex="0"
locale="en"
required
:class="{ 'is-invalid': form.errors.has(`final_submission_deadline_time_${index}`) }"
:disabled="Boolean(solutionsReleased) && assessmentType !== 'real time'"
@shown="form.errors.clear(`final_submission_deadline_time_${index}`)"
<b-input-group class="time-input-group">
<b-form-input :id="`final_submission_deadline_time_${index}`"
v-model="assignTo.final_submission_deadline_time"
required
:class="{ 'is-invalid': form.errors.has(`final_submission_deadline_time_${index}`) }"
class="time-input"
:disabled="Boolean(solutionsReleased) && assessmentType !== 'real time'"
@input="form.errors.clear(`final_submission_deadline_time_${index}`)"
@shown="form.errors.clear(`final_submission_deadline_time_${index}`)"
/>
<has-error :form="form" :field="`final_submission_deadline_time_${index}`"/>
<b-input-group-append>
<span class="input-group-text"><b-icon-clock/></span>
</b-input-group-append>
<has-error :form="form" :field="`final_submission_deadline_time_${index}`"/>
</b-input-group>
</b-col>
</b-form-row>
</b-form-group>
Expand Down Expand Up @@ -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 () {
Expand Down Expand Up @@ -1910,3 +1926,19 @@ export default {
}
}
</script>
<style scoped>
.datepicker {
border-color: #8a8f90;
}
.time-input-group .input-group-text {
width: 40px;
border-left: none;
background-color: #ffffff;
border-color: #8a8f90;
}
.time-input-group .time-input {
border-right: none;
}
</style>
23 changes: 18 additions & 5 deletions resources/js/helpers/AssignmentProperties.js
Original file line number Diff line number Diff line change
@@ -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: [],
Expand Down Expand Up @@ -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'
}
}

Expand All @@ -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'
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit ef1edba

Please sign in to comment.