Skip to content
Snippets Groups Projects
Commit 332f5ef2 authored by Viktoria Wiebe's avatar Viktoria Wiebe Committed by Ron Lucke
Browse files

Tic 2807 - add toggling task visibility functionality to student task dashboard

Closes #2807

Merge request studip/studip!3096
parent 7a924cef
No related branches found
No related tags found
No related merge requests found
<?php
class Tic2807AddCWTaskVisibility extends Migration
{
public function description()
{
return 'Adds a visibility column to courseware tasks.';
}
protected function up()
{
DBManager::get()->exec(
"ALTER TABLE `cw_tasks`
ADD COLUMN `visible` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0 AFTER `renewal_date`"
);
}
protected function down()
{
DBManager::get()->exec(
"ALTER TABLE `cw_tasks`
DROP COLUMN `visible`"
);
}
}
...@@ -324,7 +324,7 @@ class Authority ...@@ -324,7 +324,7 @@ class Authority
public static function canShowTask(User $user, Task $resource): bool public static function canShowTask(User $user, Task $resource): bool
{ {
return self::canUpdateTask($user, $resource); return self::canUpdateTask($user, $resource) || $resource->visible;
} }
public static function canIndexTasks(User $user): bool public static function canIndexTasks(User $user): bool
......
...@@ -81,6 +81,10 @@ class TasksUpdate extends JsonApiController ...@@ -81,6 +81,10 @@ class TasksUpdate extends JsonApiController
$resource->requestRenewal(); $resource->requestRenewal();
} }
if (self::arrayHas($json, 'data.attributes.visible')) {
$resource->setVisibility(self::arrayGet($json, 'data.attributes.visible'));
}
return $resource; return $resource;
} }
......
...@@ -36,6 +36,7 @@ class Task extends SchemaProvider ...@@ -36,6 +36,7 @@ class Task extends SchemaProvider
'submitted' => (bool) $resource['submitted'], 'submitted' => (bool) $resource['submitted'],
'renewal' => empty($resource['renewal']) ? null : (string) $resource['renewal'], 'renewal' => empty($resource['renewal']) ? null : (string) $resource['renewal'],
'renewal-date' => date('c', $resource['renewal_date']), 'renewal-date' => date('c', $resource['renewal_date']),
'visible' => (bool) $resource['visible'],
'mkdate' => date('c', $resource['mkdate']), 'mkdate' => date('c', $resource['mkdate']),
'chdate' => date('c', $resource['chdate']), 'chdate' => date('c', $resource['chdate']),
]; ];
......
...@@ -391,6 +391,19 @@ class StructuralElement extends \SimpleORMap implements \PrivacyObject, \Feedbac ...@@ -391,6 +391,19 @@ class StructuralElement extends \SimpleORMap implements \PrivacyObject, \Feedbac
return true; return true;
} }
if ($task->isSubmitted()) {
if ($task->visible) {
return true;
}
$solvers = $task->getTaskGroup()->getSolvers();
foreach ($solvers as $solver) {
if ($solver->id === $user->id) {
return true;
}
}
return false;
}
return $task->userIsASolver($user); return $task->userIsASolver($user);
} }
...@@ -1240,4 +1253,9 @@ SQL; ...@@ -1240,4 +1253,9 @@ SQL;
[$this->id, self::class] [$this->id, self::class]
); );
} }
public function isTaskVisible(): bool
{
return $this->payload['task-visibility'];
}
} }
...@@ -21,6 +21,7 @@ use User; ...@@ -21,6 +21,7 @@ use User;
* @property int $submitted database column * @property int $submitted database column
* @property string|null $renewal database column * @property string|null $renewal database column
* @property int $renewal_date database column * @property int $renewal_date database column
* @property int $visible database column
* @property int|null $feedback_id database column * @property int|null $feedback_id database column
* @property int $mkdate database column * @property int $mkdate database column
* @property int $chdate database column * @property int $chdate database column
...@@ -90,6 +91,11 @@ class Task extends \SimpleORMap ...@@ -90,6 +91,11 @@ class Task extends \SimpleORMap
parent::configure($config); parent::configure($config);
} }
public function getTaskGroup(): TaskGroup
{
return $this->task_group;
}
/** /**
* Returns the structural element of this task. * Returns the structural element of this task.
* This structural element and all its children are part of the task. * This structural element and all its children are part of the task.
...@@ -130,6 +136,16 @@ class Task extends \SimpleORMap ...@@ -130,6 +136,16 @@ class Task extends \SimpleORMap
if ($this->solver_id === $user->id) { if ($this->solver_id === $user->id) {
return true; return true;
} }
if ($this->visible) {
$solvers = $this->getTaskGroup()->getSolvers();
foreach ($solvers as $solver) {
if ($solver->id === $user->id) {
return true;
}
}
}
break; break;
case 'group': case 'group':
...@@ -235,6 +251,12 @@ class Task extends \SimpleORMap ...@@ -235,6 +251,12 @@ class Task extends \SimpleORMap
$this->store(); $this->store();
} }
public function setVisibility(bool $visibility): void
{
$this->visible = (int) $visibility;
$this->store();
}
private function getStructuralElementProgress(StructuralElement $structural_element): float private function getStructuralElementProgress(StructuralElement $structural_element): float
{ {
$containers = Container::findBySQL('structural_element_id = ?', [intval($structural_element->id)]); $containers = Container::findBySQL('structural_element_id = ?', [intval($structural_element->id)]);
......
...@@ -2,7 +2,15 @@ ...@@ -2,7 +2,15 @@
<div class="cw-dashboard-tasks-wrapper"> <div class="cw-dashboard-tasks-wrapper">
<table v-if="tasks.length > 0" class="default"> <table v-if="tasks.length > 0" class="default">
<colgroup> <colgroup>
<col /> <col style="width: 5%" />
<col style="width: 20%" />
<col style="width: 10%" />
<col style="width: 10%" />
<col style="width: 5%" />
<col style="width: 15%" />
<col style="width: 15%" />
<col style="width: 15%" />
<col style="width: 5%" />
</colgroup> </colgroup>
<thead> <thead>
<tr> <tr>
...@@ -12,6 +20,7 @@ ...@@ -12,6 +20,7 @@
<th>{{ $gettext('Abgabefrist') }}</th> <th>{{ $gettext('Abgabefrist') }}</th>
<th>{{ $gettext('Abgabe') }}</th> <th>{{ $gettext('Abgabe') }}</th>
<th class="responsive-hidden">{{ $gettext('Verlängerungsanfrage') }}</th> <th class="responsive-hidden">{{ $gettext('Verlängerungsanfrage') }}</th>
<th class="responsive-hidden">{{ $gettext('Für Teilnehmende freigeben') }}</th>
<th class="responsive-hidden">{{ $gettext('Anmerkung') }}</th> <th class="responsive-hidden">{{ $gettext('Anmerkung') }}</th>
<th class="actions">{{ $gettext('Aktionen') }}</th> <th class="actions">{{ $gettext('Aktionen') }}</th>
</tr> </tr>
...@@ -54,6 +63,23 @@ ...@@ -54,6 +63,23 @@
{{ $gettext('verlängert bis') }}: {{ getReadableDate(task.attributes['renewal-date']) }} {{ $gettext('verlängert bis') }}: {{ getReadableDate(task.attributes['renewal-date']) }}
</span> </span>
</td> </td>
<td class="responsive-hidden">
<span v-if="task.attributes.submitted">
<button
class="button"
v-if="!task.attributes.visible"
@click="toggleVisibilityOn(task)"
>
{{ $gettext('Freigeben') }}
</button>
<button
class="button"
v-if="task.attributes.visible"
@click="toggleVisibilityOff(task)">
{{ $gettext('Freigabe widerrufen') }}
</button>
</span>
</td>
<td class="responsive-hidden"> <td class="responsive-hidden">
<studip-icon <studip-icon
v-if="feedback" v-if="feedback"
...@@ -166,6 +192,13 @@ export default { ...@@ -166,6 +192,13 @@ export default {
return result; return result;
}); });
}, },
taskVisibilities() {
let visibilities = [];
for (const task of this.tasks) {
visibilities[`${task.task.id}`] = task.element.attributes.payload['task-visibility'];
}
return visibilities;
}
}, },
methods: { methods: {
...mapActions({ ...mapActions({
...@@ -175,6 +208,7 @@ export default { ...@@ -175,6 +208,7 @@ export default {
companionSuccess: 'companionSuccess', companionSuccess: 'companionSuccess',
companionError: 'companionError', companionError: 'companionError',
createCoursewareUnit: 'courseware-units/create', createCoursewareUnit: 'courseware-units/create',
loadStructuralElement: 'courseware-structural-elements/loadById'
}), }),
getTaskMenuItems(task, status, element) { getTaskMenuItems(task, status, element) {
let menuItems = []; let menuItems = [];
...@@ -277,6 +311,37 @@ export default { ...@@ -277,6 +311,37 @@ export default {
this.showFeedbackDialog = true; this.showFeedbackDialog = true;
this.currentTaskFeedback = feedback.attributes.content; this.currentTaskFeedback = feedback.attributes.content;
}, },
toggleVisibilityOn(task) {
let attributes = task.attributes;
attributes['visible'] = true;
this.toggleVisibility(task, attributes);
},
toggleVisibilityOff(task) {
let attributes = task.attributes;
attributes['visible'] = false;
this.toggleVisibility(task, attributes);
},
async toggleVisibility(task, attributes) {
await this.updateTask({
attributes: attributes,
taskId: task.id,
});
const taskGroup = this.getTaskGroupById({ id: task.relationships['task-group'].data.id });
const taskTitle = taskGroup.attributes.title;
if (attributes.visible) {
this.companionSuccess({
info: this.$gettextInterpolate(this.$gettext('"%{ title }" wurde freigegeben.'),
{ title: taskTitle }),
});
} else {
this.companionSuccess({
info: this.$gettextInterpolate(this.$gettext('Die Freigabe für %{ "title }" wurde zurückgenommen.'),
{ title: taskTitle }),
});
}
}
}, },
}; };
</script> </script>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment