diff --git a/controllers/solutions.php b/controllers/solutions.php index 9e03ced2474b16bfe5e69e3d9156e111f230f6ed..fa943dc3c766a0077229cd36f4a06fcdfbea5ae1 100644 --- a/controllers/solutions.php +++ b/controllers/solutions.php @@ -303,6 +303,16 @@ class SolutionsController extends StudipController $solvers[$solver_id]['extra_info'] = $extra_info; } + $confirm = []; + + if (!$released) { + $num_corrected = count($assignment->assignment_attempts->filter(function($a) { return $a->options['corrected']; })); + + if ($num_corrected > 0 && $num_corrected < count($assignment->assignment_attempts)) { + $confirm = ['data-confirm' => _vips('Es sind noch nicht alle Ergebnisse bestätigt. Wollen Sie trotzdem die Ergebnisse freigeben?')]; + } + } + $this->assignment = $assignment; $this->assignment_id = $assignment_id; $this->view = $view; @@ -420,16 +430,16 @@ class SolutionsController extends StudipController $released == 0); $widget->addRadioButton(_vips('vergebene Punkte'), $this->link_for('solutions/change_released', ['assignment_id' => $assignment_id, 'released' => 1]), - $released == 1); + $released == 1, $confirm); $widget->addRadioButton(_vips('Punkte und Kommentare'), $this->link_for('solutions/change_released', ['assignment_id' => $assignment_id, 'released' => 2]), - $released == 2); + $released == 2, $confirm); $widget->addRadioButton(_vips('… zusätzlich Aufgaben und Korrektur'), $this->link_for('solutions/change_released', ['assignment_id' => $assignment_id, 'released' => 3]), - $released == 3); + $released == 3, $confirm); $widget->addRadioButton(_vips('… zusätzlich Musterlösungen'), $this->link_for('solutions/change_released', ['assignment_id' => $assignment_id, 'released' => 4]), - $released == 4); + $released == 4, $confirm); Sidebar::get()->addWidget($widget); $widget = new SidebarWidget(); @@ -1147,6 +1157,97 @@ class SolutionsController extends StudipController $this->redirect($this->url_for('solutions/assignment_solutions', compact('assignment_id', 'view'))); } + /** + * Add assignment level feedback to an assignment attempt. + */ + public function edit_feedback_dialog_action() + { + $assignment_id = Request::int('assignment_id'); + $assignment = VipsAssignment::find($assignment_id); + $user_ids = Request::optionArray('user_ids'); + $view = Request::option('view'); + + vips_require_edit_permission($assignment); + + $this->assignment = $assignment; + $this->user_ids = $user_ids; + $this->view = $view; + $this->feedback = null; + $this->corrected = null; + + foreach ($user_ids as $user_id) { + $assignment_attempt = $assignment->getAssignmentAttempt($user_id); + $feedback = $assignment->getUserFeedback($user_id) ?? ''; + $corrected = $assignment_attempt->options['corrected'] ?? 0; + + if (!isset($this->feedback) || $this->feedback === $feedback) { + $this->feedback = $feedback; + } else { + $this->feedback = ''; + } + + if (!isset($this->corrected) || $this->corrected === $corrected) { + $this->corrected = $corrected; + } else { + $this->corrected = 0; + } + } + } + + /** + * Store feedback and status for an assignment attempt. + */ + public function edit_feedback_action() + { + CSRFProtection::verifyUnsafeRequest(); + + $assignment_id = Request::int('assignment_id'); + $assignment = VipsAssignment::find($assignment_id); + $user_ids = Request::optionArray('user_ids'); + $view = Request::option('view'); + + $feedback = trim(Request::get('feedback')); + $feedback = Studip\Markup::purifyHtml($feedback); + $corrected = Request::int('corrected'); + + vips_require_edit_permission($assignment); + + foreach ($user_ids as $user_id) { + $assignment_attempt = $assignment->getAssignmentAttempt($user_id); + + if ($assignment_attempt) { + $options = $assignment_attempt->options; + + unset($options['feedback']); + + if ($feedback !== '') { + $options['feedback'] = $feedback; + } + + if (!$corrected) { + unset($options['corrected']); + unset($options['corrector_id']); + unset($options['correction_time']); + } else if (!$options['corrected']) { + $options['corrected'] = $corrected; + $options['corrector_id'] = $GLOBALS['user']->id; + $options['correction_time'] = time(); + } + + $assignment_attempt->options = $options; + $assignment_attempt->store(); + } + } + + if ($feedback === '' && !$corrected) { + PageLayout::postSuccess(_vips('Der Kommentar zur Bewertung wurde entfernt.')); + } else { + PageLayout::postSuccess(_vips('Der Kommentar zur Bewertung wurde gespeichert.')); + } + + $this->redirect($this->url_for('solutions/assignment_solutions', compact('assignment_id', 'view'))); + } + /** * Write a message to selected members for an assignment. */ @@ -1376,6 +1477,7 @@ class SolutionsController extends StudipController $this->user_id = $GLOBALS['user']->id; $this->released = $assignment->releaseStatus($this->user_id); $this->feedback = $assignment->getUserFeedback($this->user_id); + $this->assignment_attempt = $assignment->getAssignmentAttempt($this->user_id); // Security check -- is assignment really accessible for students? if ($this->released == 0) { @@ -2228,7 +2330,8 @@ function get_solutions($assignment, $view) $solvers[$user_id] = [ 'type' => 'single', 'id' => $user_id, - 'user_id' => $user_id + 'user_id' => $user_id, + 'feedback' => $attempt->options['feedback'] ]; } diff --git a/lib/VipsAssignment.php b/lib/VipsAssignment.php index a91e17e0b76a1303e0ae754ffd4131ef4bc3f692..823946e29c6072c65c1130d18816ceaee171cc23 100644 --- a/lib/VipsAssignment.php +++ b/lib/VipsAssignment.php @@ -1133,6 +1133,12 @@ class VipsAssignment extends SimpleORMap */ public function getUserFeedback($user_id) { + $assignment_attempt = $this->getAssignmentAttempt($user_id); + + if ($assignment_attempt && isset($assignment_attempt->options['feedback'])) { + return $assignment_attempt->options['feedback']; + } + if (isset($this->options['feedback'])) { $user_points = $this->getUserPoints($user_id); $max_points = $this->test->getTotalPoints(); diff --git a/views/sheets/print_assignment.php b/views/sheets/print_assignment.php index 4fa307a79b1b6a2703eb5767cc57ea453df62aa7..e489e463b8aa99961d47e3a9718e1aaaf51e98be 100644 --- a/views/sheets/print_assignment.php +++ b/views/sheets/print_assignment.php @@ -69,6 +69,7 @@ <? $max_points = $assignment->test->getTotalPoints(); ?> <? $reached_points = $assignment->getUserPoints($user_id); ?> <? $feedback = $assignment->getUserFeedback($user_id); ?> + <? $assignment_attempt = $assignment->getAssignmentAttempt($user_id); ?> <div class="exercise"> <h2> <?= _vips('Gesamtpunktzahl') ?> @@ -89,6 +90,10 @@ <?= formatReady($feedback) ?> <? endif ?> + + <? if ($assignment_attempt->options['corrected']): ?> + <?= sprintf(_vips('Bewertung wurde am %s von %s bestätigt.'), date('d.m.Y', $assignment_attempt->options['correction_time']), htmlReady(get_fullname($assignment_attempt->options['corrector_id']))) ?> + <? endif ?> </div> <? setlocale(LC_NUMERIC, 'C') ?> <? endif ?> diff --git a/views/solutions/assignment_solutions.php b/views/solutions/assignment_solutions.php index beea89e0da97930dad118cf83b4ff6610f31b4b3..46bb89f90adb22e24d521bf07787d87da6228fd0 100644 --- a/views/solutions/assignment_solutions.php +++ b/views/solutions/assignment_solutions.php @@ -115,6 +115,9 @@ <?= Icon::create('arr_1right', 'clickable', ['class' => 'solution-open', 'title' => _vips('Aufgaben anzeigen')]) ?> <?= Icon::create('arr_1down', 'clickable', ['class' => 'solution-close', 'title' => _vips('Aufgaben verstecken')]) ?> <?= htmlReady($solver['name']) ?> + <? if ($solver['feedback']): ?> + <?= tooltipIcon(kill_format($solver['feedback'])) ?> + <? endif ?> </a> <? if ($solver['type'] == 'single') : ?> @@ -199,6 +202,9 @@ <? $menu->addLink($controller->url_for('solutions/show_assignment_log', ['assignment_id' => $assignment_id, 'solver_id' => $solver['user_id']]), _vips('Abgabeprotokoll anzeigen'), Icon::create('log'), ['data-dialog' => 'size=auto'] ) ?> + <? $menu->addLink($controller->url_for('solutions/edit_feedback_dialog', ['assignment_id' => $assignment_id, 'user_ids[]' => $solver['user_id'], 'view' => $view]), + _vips('Kommentar zur Bewertung'), Icon::create('feedback'), ['data-dialog' => 'size=800x440'] + ) ?> <? endif ?> <? if ($uploaded_files > 0): ?> <? $menu->addLink($controller->url_for('solutions/download_uploads', ['assignment_id' => $assignment_id, 'solver_id' => $solver['user_id']]), @@ -298,6 +304,12 @@ 'formmethod' => 'post', 'formtarget' => '_blank' ]) ?> + <?= Studip\Button::create(_vips('Kommentar zur Bewertung'), 'feedback', [ + 'class' => 'batch_action', + 'formaction' => $controller->url_for('solutions/edit_feedback_dialog'), + 'formmethod' => 'post', + 'data-dialog' => 'size=800x440' + ]) ?> <?= Studip\Button::create(_vips('Nachricht schreiben'), 'message', [ 'class' => 'batch_action', 'formaction' => $controller->url_for('solutions/write_message'), diff --git a/views/solutions/edit_feedback_dialog.php b/views/solutions/edit_feedback_dialog.php new file mode 100644 index 0000000000000000000000000000000000000000..e54cb3a09e34e599d91e0c83099712e86306d845 --- /dev/null +++ b/views/solutions/edit_feedback_dialog.php @@ -0,0 +1,22 @@ +<form class="default" action="<?= $controller->link_for('solutions/edit_feedback') ?>" method="POST"> + <?= CSRFProtection::tokenTag() ?> + <input type="hidden" name="assignment_id" value="<?= $assignment->id ?>"> + <? foreach ($user_ids as $user_id): ?> + <input type="hidden" name="user_ids[]" value="<?= $user_id ?>"> + <? endforeach ?> + <input type="hidden" name="view" value="<?= $view ?>"> + + <label> + <?= _vips('Kommentar zur Bewertung') ?> + <textarea name="feedback" class="size-l wysiwyg" data-editor="toolbar=small"><?= wysiwygReady($feedback) ?></textarea> + </label> + + <label> + <input type="checkbox" name="corrected" value="1" <?= $corrected ? 'checked' : '' ?>> + <?= _vips('Bestätigungsvermerk hinzufügen') ?> + </label> + + <footer data-dialog-button> + <?= Studip\Button::createAccept(_vips('Speichern'), 'save') ?> + </footer> +</form> diff --git a/views/solutions/student_assignment_solutions.php b/views/solutions/student_assignment_solutions.php index fe1ece0f973206c94f95382c9785868251f0fd1d..a746e34f1d499d14110ab25efadce24200ac6517 100644 --- a/views/solutions/student_assignment_solutions.php +++ b/views/solutions/student_assignment_solutions.php @@ -113,4 +113,8 @@ </div> <? endif ?> +<? if ($assignment_attempt->options['corrected']): ?> + <?= sprintf(_vips('Bewertung wurde am %s von %s bestätigt.'), date('d.m.Y', $assignment_attempt->options['correction_time']), htmlReady(get_fullname($assignment_attempt->options['corrector_id']))) ?> +<? endif ?> + <? setlocale(LC_NUMERIC, 'C') ?>