aboutsummaryrefslogtreecommitdiff
path: root/lib/classes/JsonApi
diff options
context:
space:
mode:
authorMarcus Eibrink-Lunzenauer <lunzenauer@elan-ev.de>2024-01-23 07:41:52 +0000
committerMarcus Eibrink-Lunzenauer <lunzenauer@elan-ev.de>2024-01-23 07:41:52 +0000
commit1728bc517691b3d0dde5ccdf0c0631ff1b855b6d (patch)
treef3ad972dc584dc70c4817405d616558cc1a55061 /lib/classes/JsonApi
parent9750421a650a4e4980a1286212661a87eb92905b (diff)
Courseware Aufgaben erweitern (StEP3286)
Merge request studip/studip!2445
Diffstat (limited to 'lib/classes/JsonApi')
-rw-r--r--lib/classes/JsonApi/RouteMap.php7
-rw-r--r--lib/classes/JsonApi/Routes/Courseware/Authority.php33
-rw-r--r--lib/classes/JsonApi/Routes/Courseware/Rel/SolversOfTaskGroup.php207
-rw-r--r--lib/classes/JsonApi/Routes/Courseware/TaskGroupsCreate.php25
-rw-r--r--lib/classes/JsonApi/Routes/Courseware/TaskGroupsDelete.php38
-rw-r--r--lib/classes/JsonApi/Routes/Courseware/TaskGroupsUpdate.php99
-rw-r--r--lib/classes/JsonApi/Routes/Courseware/TasksIndex.php7
-rw-r--r--lib/classes/JsonApi/Routes/Courseware/TasksUpdate.php65
-rw-r--r--lib/classes/JsonApi/SchemaMap.php10
-rw-r--r--lib/classes/JsonApi/Schemas/Courseware/Task.php2
-rw-r--r--lib/classes/JsonApi/Schemas/Courseware/TaskGroup.php3
11 files changed, 432 insertions, 64 deletions
diff --git a/lib/classes/JsonApi/RouteMap.php b/lib/classes/JsonApi/RouteMap.php
index d4d5bbb..4f44165 100644
--- a/lib/classes/JsonApi/RouteMap.php
+++ b/lib/classes/JsonApi/RouteMap.php
@@ -501,6 +501,13 @@ class RouteMap
$group->get('/courseware-task-groups/{id}', Routes\Courseware\TaskGroupsShow::class);
$group->post('/courseware-task-groups', Routes\Courseware\TaskGroupsCreate::class);
+ $group->patch('/courseware-task-groups/{id}', Routes\Courseware\TaskGroupsUpdate::class);
+ $group->delete('/courseware-task-groups/{id}', Routes\Courseware\TaskGroupsDelete::class);
+ $this->addRelationship(
+ $group,
+ '/courseware-task-groups/{id}/relationships/solvers',
+ Routes\Courseware\Rel\SolversOfTaskGroup::class
+ );
$group->get('/courseware-task-feedback/{id}', Routes\Courseware\TaskFeedbackShow::class);
$group->post('/courseware-task-feedback', Routes\Courseware\TaskFeedbackCreate::class);
diff --git a/lib/classes/JsonApi/Routes/Courseware/Authority.php b/lib/classes/JsonApi/Routes/Courseware/Authority.php
index 88eb3df..2acf83e 100644
--- a/lib/classes/JsonApi/Routes/Courseware/Authority.php
+++ b/lib/classes/JsonApi/Routes/Courseware/Authority.php
@@ -23,7 +23,13 @@ use User;
use Course;
/**
+ * @SuppressWarnings(PHPMD.CamelCaseParameterName)
+ * @SuppressWarnings(PHPMD.CamelCaseVariableName)
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
+ * @SuppressWarnings(PHPMD.ExcessivePublicCount)
+ * @SuppressWarnings(PHPMD.StaticAccess)
+ * @SuppressWarnings(PHPMD.Superglobals)
* @SuppressWarnings(PHPMD.TooManyMethods)
* @SuppressWarnings(PHPMD.TooManyPublicMethods)
*/
@@ -306,6 +312,16 @@ class Authority
return $resource['lecturer_id'] === $user->id;
}
+ public static function canUpdateTaskGroup(User $user, TaskGroup $resource): bool
+ {
+ return self::canCreateTasks($user, $resource->target);
+ }
+
+ public static function canDeleteTaskGroup(User $user, TaskGroup $resource): bool
+ {
+ return self::canUpdateTaskGroup($user, $resource);
+ }
+
public static function canShowTask(User $user, Task $resource): bool
{
return self::canUpdateTask($user, $resource);
@@ -332,6 +348,11 @@ class Authority
return self::canCreateTasks($user, $resource->structural_element) && !$resource->userIsASolver($user);
}
+ public static function canRenewTask(User $user, Task $resource): bool
+ {
+ return self::canDeleteTask($user, $resource);
+ }
+
public static function canCreateTaskFeedback(User $user, Task $resource): bool
{
return self::canCreateTasks($user, $resource->structural_element);
@@ -352,7 +373,6 @@ class Authority
return self::canCreateTaskFeedback($user, $resource);
}
-
public static function canIndexStructuralElementComments(User $user, StructuralElement $resource)
{
return self::canShowStructuralElement($user, $resource);
@@ -407,7 +427,8 @@ class Authority
public static function canShowStructuralElementFeedback(User $user, StructuralElementFeedback $resource)
{
- return $resource->user_id === $user->id || self::canUpdateStructuralElement($user, $resource->structural_element);
+ return $resource->user_id === $user->id ||
+ self::canUpdateStructuralElement($user, $resource->structural_element);
}
public static function canDeleteStructuralElementFeedback(User $user, StructuralElementFeedback $resource)
@@ -415,7 +436,6 @@ class Authority
return self::canUpdateStructuralElementFeedback($user, $resource);
}
-
public static function canShowTemplate(User $user, Template $resource)
{
// templates are for everybody, aren't they?
@@ -430,7 +450,7 @@ class Authority
public static function canCreateTemplate(User $user)
{
- return $GLOBALS['perm']->have_perm('admin');
+ return $GLOBALS['perm']->have_perm('admin', $user->id);
}
public static function canUpdateTemplate(User $user, Template $resource)
@@ -490,7 +510,7 @@ class Authority
if ($user->id === $range->id) {
return true;
}
- return $GLOBALS['perm']->have_studip_perm('tutor', $range->id ,$user->id);
+ return $GLOBALS['perm']->have_studip_perm('tutor', $range->id, $user->id);
}
public static function canSortUnit(User $user, \Range $range): bool
@@ -518,7 +538,6 @@ class Authority
return $request_user->id === $user->id;
}
-
public static function canShowClipboard(User $user, Clipboard $resource): bool
{
return $resource->user_id === $user->id;
@@ -541,7 +560,7 @@ class Authority
} else {
$structural_element = $resource->getStructuralElement();
}
-
+
return $structural_element->canEdit($user);
}
diff --git a/lib/classes/JsonApi/Routes/Courseware/Rel/SolversOfTaskGroup.php b/lib/classes/JsonApi/Routes/Courseware/Rel/SolversOfTaskGroup.php
new file mode 100644
index 0000000..2ab5ffa
--- /dev/null
+++ b/lib/classes/JsonApi/Routes/Courseware/Rel/SolversOfTaskGroup.php
@@ -0,0 +1,207 @@
+<?php
+
+namespace JsonApi\Routes\Courseware\Rel;
+
+use Courseware\StructuralElement;
+use Courseware\Task;
+use Courseware\TaskGroup;
+use JsonApi\Errors\RecordNotFoundException;
+use JsonApi\Errors\UnprocessableEntityException;
+use JsonApi\Routes\Courseware\Authority;
+use JsonApi\Routes\RelationshipsController;
+use JsonApi\Schemas\Courseware\TaskGroup as TaskGroupSchema;
+use JsonApi\Schemas\StatusGroup as StatusGroupSchema;
+use JsonApi\Schemas\User as UserSchema;
+use Psr\Http\Message\ServerRequestInterface as Request;
+use Statusgruppen;
+use User;
+
+/**
+ * @SuppressWarnings(PHPMD.LongVariable)
+ * @SuppressWarnings(PHPMD.StaticAccess)
+ */
+class SolversOfTaskGroup extends RelationshipsController
+{
+ protected $allowedPagingParameters = ['offset', 'limit'];
+
+ /**
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ protected function fetchRelationship(Request $request, $related)
+ {
+ $solvers = $related->getSolvers();
+ $total = count($solvers);
+
+ return $this->getPaginatedIdentifiersResponse(array_slice($solvers, ...$this->getOffsetAndLimit()), $total);
+ }
+
+ /**
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ protected function addToRelationship(Request $request, $related)
+ {
+ $this->createTaskFor(
+ $related,
+ array_filter($this->validateSolvers($related, $this->validate($request)), function ($solver) use (
+ $related
+ ) {
+ return !$related->findTaskBySolver($solver);
+ })
+ );
+
+ return $this->getCodeResponse(204);
+ }
+
+ protected function findRelated(array $args)
+ {
+ $related = TaskGroup::find($args['id']);
+ if (!$related) {
+ throw new RecordNotFoundException();
+ }
+
+ return $related;
+ }
+
+ protected function authorize(Request $request, $resource)
+ {
+ switch ($request->getMethod()) {
+ case 'GET':
+ return Authority::canShowTaskGroup($this->getUser($request), $resource);
+ case 'POST':
+ return Authority::canUpdateTaskGroup($this->getUser($request), $resource);
+
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ protected function getRelationshipSelfLink($resource, $schema, $userData)
+ {
+ return $schema->getRelationshipSelfLink($resource, TaskGroupSchema::REL_SOLVERS);
+ }
+
+ /**
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ protected function getRelationshipRelatedLink($resource, $schema, $userData)
+ {
+ return $schema->getRelationshipRelatedLink($resource, TaskGroupSchema::REL_SOLVERS);
+ }
+
+ protected function validateResourceDocument($json, $data)
+ {
+ if (!self::arrayHas($json, 'data')) {
+ return 'Missing `data` member at document´s top level.';
+ }
+
+ $data = self::arrayGet($json, 'data');
+
+ if (!is_array($data)) {
+ return 'Document´s `data` must be an array.';
+ }
+
+ foreach ($data as $item) {
+ if (!in_array(self::arrayGet($item, 'type'), [UserSchema::TYPE, StatusGroupSchema::TYPE])) {
+ return 'Wrong `type` in document´s `data`.';
+ }
+
+ if (!self::arrayGet($item, 'id')) {
+ return 'Missing `id` of document´s `data`.';
+ }
+ }
+ }
+
+ private function validateSolvers(TaskGroup $taskGroup, iterable $json): iterable
+ {
+ if (!$taskGroup->course) {
+ return [];
+ }
+ $solvers = [];
+ foreach ($json['data'] as $item) {
+ $solver = $this->findSolver($item);
+ if (!$solver) {
+ throw new RecordNotFoundException();
+ }
+ if (!$this->validateSolver($taskGroup, $solver)) {
+ throw new UnprocessableEntityException();
+ }
+ $solvers[] = $solver;
+ }
+ return $solvers;
+ }
+
+ /**
+ * @return Statusgruppen|User|null
+ */
+ private function findSolver($json)
+ {
+ switch ($json['type']) {
+ case 'status-groups':
+ return Statusgruppen::find($json['id']);
+ case 'users':
+ return User::find($json['id']);
+ }
+ return null;
+ }
+
+ /**
+ * @param Statusgruppen|User $solver
+ *
+ * @SuppressWarnings(PHPMD.Superglobals)
+ */
+ private function validateSolver(TaskGroup $taskGroup, $solver): bool
+ {
+ if ($solver instanceof User) {
+ return $GLOBALS['perm']->have_studip_perm('autor', $taskGroup->course->id, $solver->id);
+ }
+ if ($solver instanceof Statusgruppen) {
+ return $taskGroup->course->id === $solver->range_id;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param array<User|Statusgruppen> $solvers
+ */
+ private function createTaskFor(TaskGroup $taskGroup, $solvers): void
+ {
+ $template = $this->getTaskTemplate($taskGroup);
+ if (!$template) {
+ throw new RuntimeException();
+ }
+
+ foreach ($solvers as $solver) {
+ $task = Task::build([
+ 'task_group_id' => $taskGroup->id,
+ 'solver_id' => $solver->id,
+ 'solver_type' => $this->getSolverType($solver),
+ ]);
+
+ $taskElement = $template->copy($taskGroup->lecturer, $taskGroup->target, 'task');
+ $taskElement->title = $taskGroup->title;
+ $taskElement->store();
+
+ $task['structural_element_id'] = $taskElement->id;
+ $task->store();
+ }
+ }
+
+ private function getTaskTemplate(TaskGroup $taskGroup): StructuralElement
+ {
+ return StructuralElement::find($taskGroup->task_template_id);
+ }
+
+ /**
+ * @param User|Statusgruppen $solver
+ */
+ private function getSolverType($solver): string
+ {
+ $solverTypes = [\User::class => 'autor', \Statusgruppen::class => 'group'];
+
+ return $solverTypes[get_class($solver)];
+ }
+}
diff --git a/lib/classes/JsonApi/Routes/Courseware/TaskGroupsCreate.php b/lib/classes/JsonApi/Routes/Courseware/TaskGroupsCreate.php
index 28c4e9c..f7357a4 100644
--- a/lib/classes/JsonApi/Routes/Courseware/TaskGroupsCreate.php
+++ b/lib/classes/JsonApi/Routes/Courseware/TaskGroupsCreate.php
@@ -65,14 +65,20 @@ class TaskGroupsCreate extends JsonApiController
if (!self::arrayHas($json, 'data.attributes.title')) {
return 'Missing `title` attribute.';
}
- if (!self::arrayHas($json, 'data.attributes.submission-date')) {
- return 'Missing `submission-date` attribute.';
+ if (!self::arrayHas($json, 'data.attributes.start-date')) {
+ return 'Missing `start-date` attribute.';
}
- $submissionDate = self::arrayGet($json, 'data.attributes.submission-date');
- if (!self::isValidTimestamp($submissionDate)) {
- return '`submission-date` is not an ISO 8601 timestamp.';
+ $startDate = self::arrayGet($json, 'data.attributes.start-date');
+ if (!self::isValidTimestamp($startDate)) {
+ return '`start-date` is not an ISO 8601 timestamp.';
+ }
+ if (!self::arrayHas($json, 'data.attributes.end-date')) {
+ return 'Missing `end-date` attribute.';
+ }
+ $endDate = self::arrayGet($json, 'data.attributes.end-date');
+ if (!self::isValidTimestamp($endDate)) {
+ return '`end-date` is not an ISO 8601 timestamp.';
}
-
if (!self::arrayHas($json, 'data.relationships.target')) {
return 'Missing `target` relationship.';
}
@@ -165,8 +171,8 @@ class TaskGroupsCreate extends JsonApiController
$target = $this->getTargetFromJson($json);
$solverMayAddBlocks = self::arrayGet($json, 'data.attributes.solver-may-add-blocks', '');
- $submissionDate = self::arrayGet($json, 'data.attributes.submission-date', '');
- $submissionDate = self::fromISO8601($submissionDate);
+ $startDate = self::fromISO8601(self::arrayGet($json, 'data.attributes.start-date', ''));
+ $endDate = self::fromISO8601(self::arrayGet($json, 'data.attributes.end-date', ''));
$title = self::arrayGet($json, 'data.attributes.title', '');
/** @var TaskGroup $taskGroup */
@@ -177,6 +183,8 @@ class TaskGroupsCreate extends JsonApiController
'task_template_id' => $taskTemplate->getId(),
'solver_may_add_blocks' => $solverMayAddBlocks,
'title' => $title,
+ 'start_date' => $startDate->getTimestamp(),
+ 'end_date' => $endDate->getTimestamp(),
]);
foreach ($solvers as $solver) {
@@ -184,7 +192,6 @@ class TaskGroupsCreate extends JsonApiController
'task_group_id' => $taskGroup->getId(),
'solver_id' => $solver->getId(),
'solver_type' => $this->getSolverType($solver),
- 'submission_date' => $submissionDate->getTimestamp(),
]);
// copy task template
diff --git a/lib/classes/JsonApi/Routes/Courseware/TaskGroupsDelete.php b/lib/classes/JsonApi/Routes/Courseware/TaskGroupsDelete.php
new file mode 100644
index 0000000..2faf778
--- /dev/null
+++ b/lib/classes/JsonApi/Routes/Courseware/TaskGroupsDelete.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace JsonApi\Routes\Courseware;
+
+use Courseware\TaskGroup;
+use JsonApi\Errors\AuthorizationFailedException;
+use JsonApi\Errors\RecordNotFoundException;
+use JsonApi\JsonApiController;
+use Psr\Http\Message\ResponseInterface as Response;
+use Psr\Http\Message\ServerRequestInterface as Request;
+
+/**
+ * Delete one TaskGroup.
+ */
+class TaskGroupsDelete extends JsonApiController
+{
+ /**
+ * @param array $args
+ * @return Response
+ *
+ * @SuppressWarnings(PHPMD.StaticAccess)
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function __invoke(Request $request, Response $response, $args)
+ {
+ /** @var ?TaskGroup $resource */
+ $resource = TaskGroup::find($args['id']);
+ if (!$resource) {
+ throw new RecordNotFoundException();
+ }
+ if (!Authority::canDeleteTaskGroup($this->getUser($request), $resource)) {
+ throw new AuthorizationFailedException();
+ }
+ $resource->delete();
+
+ return $this->getCodeResponse(204);
+ }
+}
diff --git a/lib/classes/JsonApi/Routes/Courseware/TaskGroupsUpdate.php b/lib/classes/JsonApi/Routes/Courseware/TaskGroupsUpdate.php
new file mode 100644
index 0000000..8662b71
--- /dev/null
+++ b/lib/classes/JsonApi/Routes/Courseware/TaskGroupsUpdate.php
@@ -0,0 +1,99 @@
+<?php
+
+namespace JsonApi\Routes\Courseware;
+
+use Courseware\TaskGroup;
+use JsonApi\Errors\AuthorizationFailedException;
+use JsonApi\Errors\RecordNotFoundException;
+use JsonApi\JsonApiController;
+use JsonApi\Routes\TimestampTrait;
+use JsonApi\Routes\ValidationTrait;
+use JsonApi\Schemas\Courseware\TaskGroup as TaskGroupSchema;
+use Psr\Http\Message\ResponseInterface as Response;
+use Psr\Http\Message\ServerRequestInterface as Request;
+use User;
+
+/**
+ * Updates one TaskGroup.
+ *
+ * @SuppressWarnings(PHPMD.StaticAccess)
+ */
+class TaskGroupsUpdate extends JsonApiController
+{
+ use TimestampTrait;
+ use ValidationTrait;
+
+ /**
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ * @param array $args
+ * @return Response
+ */
+ public function __invoke(Request $request, Response $response, $args)
+ {
+ /** @var ?\Courseware\TaskGroup $resource */
+ $resource = TaskGroup::find($args['id']);
+ if (!$resource) {
+ throw new RecordNotFoundException();
+ }
+ $json = $this->validate($request, $resource);
+ $user = $this->getUser($request);
+ if (!Authority::canUpdateTaskGroup($user, $resource)) {
+ throw new AuthorizationFailedException();
+ }
+
+ $process = $this->update($resource, $json);
+
+ return $this->getContentResponse($process);
+ }
+
+ /**
+ * @SuppressWarnings(PHPMD.UnusedFormalParameters)
+ *
+ * @param array $json
+ * @param mixed $data
+ *
+ * @return string|void
+ */
+ protected function validateResourceDocument($json, $data)
+ {
+ if (!self::arrayHas($json, 'data')) {
+ return 'Missing `data` member at document´s top level.';
+ }
+ if (TaskGroupSchema::TYPE !== self::arrayGet($json, 'data.type')) {
+ return 'Invalid `type` of document´s `data`.';
+ }
+
+ if (!self::arrayHas($json, 'data.attributes.start-date')) {
+ return 'Missing `start-date` attribute.';
+ }
+ $startDate = self::arrayGet($json, 'data.attributes.start-date');
+ if (!self::isValidTimestamp($startDate)) {
+ return '`start-date` is not an ISO 8601 timestamp.';
+ }
+
+ if (!self::arrayHas($json, 'data.attributes.end-date')) {
+ return 'Missing `end-date` attribute.';
+ }
+ $endDate = self::arrayGet($json, 'data.attributes.end-date');
+ if (!self::isValidTimestamp($endDate)) {
+ return '`end-date` is not an ISO 8601 timestamp.';
+ }
+
+ if (self::fromISO8601($startDate) > self::fromISO8601($endDate)) {
+ return '`start-date` is later than `end-date`';
+ }
+ }
+
+ private function update(TaskGroup $taskGroup, array $json): TaskGroup
+ {
+ $startDate = self::fromISO8601(self::arrayGet($json, 'data.attributes.start-date'));
+ $endDate = self::fromISO8601(self::arrayGet($json, 'data.attributes.end-date'));
+
+ $taskGroup->start_date = $startDate->getTimestamp();
+ $taskGroup->end_date = $endDate->getTimestamp();
+
+ $taskGroup->store();
+
+ return $taskGroup;
+ }
+}
diff --git a/lib/classes/JsonApi/Routes/Courseware/TasksIndex.php b/lib/classes/JsonApi/Routes/Courseware/TasksIndex.php
index f0b2ce9..26a021c 100644
--- a/lib/classes/JsonApi/Routes/Courseware/TasksIndex.php
+++ b/lib/classes/JsonApi/Routes/Courseware/TasksIndex.php
@@ -77,9 +77,10 @@ class TasksIndex extends JsonApiController
}
}
- private function findTasksByCourse(\Course $course): \SimpleCollection
+ private function findTasksByCourse(\Course $course, bool $showNotYetActive = true): \SimpleCollection
{
- $taskGroups = TaskGroup::findBySQL('seminar_id = ?', [$course->getId()]);
+ $whereClause = $showNotYetActive ? 'seminar_id = ?' : 'start_date <= UNIX_TIMESTAMP() AND seminar_id = ?';
+ $taskGroups = TaskGroup::findBySQL($whereClause, [$course->getId()]);
$tasks = [];
foreach ($taskGroups as $taskGroup) {
@@ -98,7 +99,7 @@ class TasksIndex extends JsonApiController
})
->pluck('id');
- return $this->findTasksByCourse($course)->filter(function ($task) use ($user, $groupIds) {
+ return $this->findTasksByCourse($course, false)->filter(function ($task) use ($user, $groupIds) {
return ('autor' === $task['solver_type'] && $task['solver_id'] === $user->getId()) ||
('group' === $task['solver_type'] && in_array($task['solver_id'], $groupIds));
});
diff --git a/lib/classes/JsonApi/Routes/Courseware/TasksUpdate.php b/lib/classes/JsonApi/Routes/Courseware/TasksUpdate.php
index 3728dba..33b51ad 100644
--- a/lib/classes/JsonApi/Routes/Courseware/TasksUpdate.php
+++ b/lib/classes/JsonApi/Routes/Courseware/TasksUpdate.php
@@ -13,6 +13,8 @@ use Psr\Http\Message\ServerRequestInterface as Request;
/**
* Update one Task.
+ *
+ * @SuppressWarnings(PHPMD.StaticAccess)
*/
class TasksUpdate extends JsonApiController
{
@@ -32,7 +34,8 @@ class TasksUpdate extends JsonApiController
throw new RecordNotFoundException();
}
$json = $this->validate($request, $resource);
- if (!Authority::canUpdateTask($user = $this->getUser($request), $resource)) {
+ $user = $this->getUser($request);
+ if (!Authority::canUpdateTask($user, $resource)) {
throw new AuthorizationFailedException();
}
$resource = $this->updateTask($user, $resource, $json);
@@ -66,53 +69,35 @@ class TasksUpdate extends JsonApiController
private function updateTask(\User $user, Task $resource, array $json): Task
{
- if (Authority::canDeleteTask($user, $resource)) {
- if (self::arrayHas($json, 'data.attributes.renewal')) {
- $newRenewalState = self::arrayGet($json, 'data.attributes.renewal');
- if ('declined' === $newRenewalState) {
- $resource->renewal = $newRenewalState;
- }
- if ('granted' === $newRenewalState && self::arrayHas($json, 'data.attributes.renewal-date')) {
- $renewalDate = self::arrayGet($json, 'data.attributes.renewal-date', '');
- $renewalDate = self::fromISO8601($renewalDate);
+ if (Authority::canRenewTask($user, $resource)) {
+ return $this->renewTask($resource, $json);
+ }
- $resource->renewal = $newRenewalState;
- $resource->renewal_date = $renewalDate->getTimestamp();
- }
- }
- } else {
- if (self::arrayHas($json, 'data.attributes.submitted')) {
- $newSubmittedState = self::arrayGet($json, 'data.attributes.submitted');
- if ($this->canSubmit($resource, $newSubmittedState)) {
- $resource->submitted = $newSubmittedState;
- if ('pending' === $resource->renewal) {
- $resource->renewal = '';
- }
- }
- }
- if (self::arrayHas($json, 'data.attributes.renewal')) {
- $newRenewalState = self::arrayGet($json, 'data.attributes.renewal');
- if ('pending' === $newRenewalState) {
- $resource->renewal = $newRenewalState;
- }
- }
+ if (self::arrayGet($json, 'data.attributes.submitted') === true && $resource->canSubmit()) {
+ $resource->submitTask();
}
- $resource->store();
+ if (self::arrayGet($json, 'data.attributes.renewal') === 'pending') {
+ $resource->requestRenewal();
+ }
return $resource;
}
- private function canSubmit(Task $resource, string $newSubmittedState): bool
+ private function renewTask(Task $resource, array $json): Task
{
- $now = time();
- if (1 === (int) $resource->submitted || !$newSubmittedState) {
- return false;
- }
- if ('granted' === $resource->renewal) {
- return $now <= $resource->renewal_date;
- } else {
- return $now <= $resource->submission_date;
+ switch (self::arrayGet($json, 'data.attributes.renewal')) {
+ case 'declined':
+ $resource->declineRenewalRequest();
+ break;
+
+ case 'granted':
+ $resource->grantRenewalRequest(
+ self::fromISO8601(self::arrayGet($json, 'data.attributes.renewal-date'))
+ );
+ break;
}
+
+ return $resource;
}
}
diff --git a/lib/classes/JsonApi/SchemaMap.php b/lib/classes/JsonApi/SchemaMap.php
index dd74bc9..71aadf7 100644
--- a/lib/classes/JsonApi/SchemaMap.php
+++ b/lib/classes/JsonApi/SchemaMap.php
@@ -59,17 +59,17 @@ class SchemaMap
\Courseware\Clipboard::class => Schemas\Courseware\Clipboard::class,
\Courseware\Container::class => Schemas\Courseware\Container::class,
\Courseware\Instance::class => Schemas\Courseware\Instance::class,
+ \Courseware\PublicLink::class => Schemas\Courseware\PublicLink::class,
\Courseware\StructuralElement::class => Schemas\Courseware\StructuralElement::class,
\Courseware\StructuralElementComment::class => Schemas\Courseware\StructuralElementComment::class,
\Courseware\StructuralElementFeedback::class => Schemas\Courseware\StructuralElementFeedback::class,
- \Courseware\Unit::class => Schemas\Courseware\Unit::class,
- \Courseware\UserDataField::class => Schemas\Courseware\UserDataField::class,
- \Courseware\UserProgress::class => Schemas\Courseware\UserProgress::class,
\Courseware\Task::class => Schemas\Courseware\Task::class,
- \Courseware\TaskGroup::class => Schemas\Courseware\TaskGroup::class,
\Courseware\TaskFeedback::class => Schemas\Courseware\TaskFeedback::class,
+ \Courseware\TaskGroup::class => Schemas\Courseware\TaskGroup::class,
\Courseware\Template::class => Schemas\Courseware\Template::class,
- \Courseware\PublicLink::class => Schemas\Courseware\PublicLink::class,
+ \Courseware\Unit::class => Schemas\Courseware\Unit::class,
+ \Courseware\UserDataField::class => Schemas\Courseware\UserDataField::class,
+ \Courseware\UserProgress::class => Schemas\Courseware\UserProgress::class,
];
}
}
diff --git a/lib/classes/JsonApi/Schemas/Courseware/Task.php b/lib/classes/JsonApi/Schemas/Courseware/Task.php
index a0605e6..81c7a0d 100644
--- a/lib/classes/JsonApi/Schemas/Courseware/Task.php
+++ b/lib/classes/JsonApi/Schemas/Courseware/Task.php
@@ -2,6 +2,8 @@
namespace JsonApi\Schemas\Courseware;
+use Courseware\Task as TaskModel;
+use JsonApi\Routes\Courseware\Authority as CoursewareAuthority;
use JsonApi\Schemas\SchemaProvider;
use Neomerx\JsonApi\Contracts\Schema\ContextInterface;
use Neomerx\JsonApi\Schema\Link;
diff --git a/lib/classes/JsonApi/Schemas/Courseware/TaskGroup.php b/lib/classes/JsonApi/Schemas/Courseware/TaskGroup.php
index 12dbc6c..c950671 100644
--- a/lib/classes/JsonApi/Schemas/Courseware/TaskGroup.php
+++ b/lib/classes/JsonApi/Schemas/Courseware/TaskGroup.php
@@ -3,6 +3,7 @@
namespace JsonApi\Schemas\Courseware;
use Courseware\StructuralElement;
+use Courseware\TaskGroup as TaskGroupModel;
use JsonApi\Schemas\SchemaProvider;
use Neomerx\JsonApi\Contracts\Schema\ContextInterface;
use Neomerx\JsonApi\Schema\Identifier;
@@ -35,6 +36,8 @@ class TaskGroup extends SchemaProvider
return [
'solver-may-add-blocks' => (bool) $resource['solver_may_add_blocks'],
'title' => (string) $resource->title,
+ 'start-date' => date('c', $resource['start_date']),
+ 'end-date' => date('c', $resource['end_date']),
'mkdate' => date('c', $resource['mkdate']),
'chdate' => date('c', $resource['chdate']),
];