Skip to content

Commit ac93519

Browse files
committed
Implementing endpoints for exercise file links manipulation.
1 parent 2615ce5 commit ac93519

5 files changed

Lines changed: 374 additions & 29 deletions

File tree

app/V1Module/presenters/ExerciseFilesPresenter.php

Lines changed: 196 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,18 @@
1616
use App\Helpers\ExercisesConfig;
1717
use App\Helpers\FileStorageManager;
1818
use App\Model\Entity\Assignment;
19+
use App\Model\Entity\AttachmentFile;
20+
use App\Model\Entity\Exercise;
1921
use App\Model\Entity\ExerciseFile;
22+
use App\Model\Entity\ExerciseFileLink;
2023
use App\Model\Entity\UploadedFile;
21-
use App\Model\Entity\AttachmentFile;
2224
use App\Model\Repository\Assignments;
2325
use App\Model\Repository\AttachmentFiles;
2426
use App\Model\Repository\Exercises;
25-
use App\Model\Entity\Exercise;
27+
use App\Model\Repository\ExerciseFileLinks;
2628
use App\Model\Repository\ExerciseFiles;
2729
use App\Model\Repository\UploadedFiles;
30+
use App\Security\Roles;
2831
use App\Security\ACL\IExercisePermissions;
2932
use Exception;
3033

@@ -58,6 +61,12 @@ class ExerciseFilesPresenter extends BasePresenter
5861
*/
5962
public $exerciseFiles;
6063

64+
/**
65+
* @var ExerciseFileLinks
66+
* @inject
67+
*/
68+
public $fileLinks;
69+
6170
/**
6271
* @var AttachmentFiles
6372
* @inject
@@ -88,6 +97,12 @@ class ExerciseFilesPresenter extends BasePresenter
8897
*/
8998
public $configChecker;
9099

100+
/**
101+
* @var Roles
102+
* @inject
103+
*/
104+
public $roles;
105+
91106
public function checkUploadExerciseFiles(string $id)
92107
{
93108
$exercise = $this->exercises->findOrThrow($id);
@@ -352,7 +367,7 @@ public function checkDeleteAttachmentFile(string $id, string $fileId)
352367
* @throws NotFoundException
353368
*/
354369
#[Path("id", new VUuid(), "identification of exercise", required: true)]
355-
#[Path("fileId", new VString(), "identification of file", required: true)]
370+
#[Path("fileId", new VUuid(), "identification of file", required: true)]
356371
public function actionDeleteAttachmentFile(string $id, string $fileId)
357372
{
358373
$exercise = $this->exercises->findOrThrow($id);
@@ -428,4 +443,182 @@ public function actionDownloadAttachmentFilesArchive(string $id)
428443
}
429444
$this->sendZipFilesResponse($files, "exercise-attachment-{$id}.zip");
430445
}
446+
447+
/*
448+
* Exercise file links management
449+
*/
450+
451+
public function checkGetFileLinks(string $id)
452+
{
453+
$exercise = $this->exercises->findOrThrow($id);
454+
if (!$this->exerciseAcl->canUpdate($exercise)) {
455+
throw new ForbiddenRequestException("You cannot view exercise file links for this exercise.");
456+
}
457+
}
458+
459+
/**
460+
* Retrieve a list of all exercise-file links for given exercise.
461+
* @GET
462+
*/
463+
#[Path("id", new VUuid(), "of exercise", required: true)]
464+
public function actionGetFileLinks(string $id)
465+
{
466+
$exercise = $this->exercises->findOrThrow($id);
467+
$this->sendSuccessResponse($exercise->getFileLinks()->getValues());
468+
}
469+
470+
public function checkCreateFileLink(string $id)
471+
{
472+
$exercise = $this->exercises->findOrThrow($id);
473+
if (!$this->exerciseAcl->canUpdate($exercise)) {
474+
throw new ForbiddenRequestException("You cannot create exercise file links for this exercise.");
475+
}
476+
}
477+
/**
478+
* Create a new exercise-file link for given exercise.
479+
* @POST
480+
*/
481+
#[Path("id", new VUuid(), "of exercise", required: true)]
482+
#[Post(
483+
"exerciseFileId",
484+
new VUuid(),
485+
"Target file the link will point to",
486+
required: true
487+
)]
488+
#[Post(
489+
"key",
490+
new VString(1, 16),
491+
"Internal user-selected identifier of the exercise file link within the exercise",
492+
required: true
493+
)]
494+
#[Post(
495+
"requiredRole",
496+
new VString(1, 255),
497+
"Minimal required user role to access the file (null = non-logged-in users)",
498+
nullable: true,
499+
required: false
500+
)]
501+
#[Post(
502+
"saveName",
503+
new VString(1, 255),
504+
"File name override (the file will be downloaded under this name instead of the original name)",
505+
nullable: true,
506+
required: false
507+
)]
508+
public function actionCreateFileLink(string $id)
509+
{
510+
$exercise = $this->exercises->findOrThrow($id);
511+
$req = $this->getRequest();
512+
$exerciseFile = $this->exerciseFiles->findOrThrow($req->getPost("exerciseFileId"));
513+
$key = $req->getPost("key");
514+
$requiredRole = $req->getPost("requiredRole");
515+
$saveName = $req->getPost("saveName");
516+
517+
if (!$this->roles->validateRole($requiredRole)) {
518+
throw new InvalidApiArgumentException('requiredRole', "Unknown user role '$requiredRole'");
519+
}
520+
521+
$link = ExerciseFileLink::createForExercise(
522+
$key,
523+
$exerciseFile,
524+
$exercise,
525+
$requiredRole,
526+
$saveName
527+
);
528+
529+
$this->fileLinks->persist($link);
530+
$this->sendSuccessResponse($link);
531+
}
532+
533+
public function checkUpdateFileLink(string $id, string $linkId)
534+
{
535+
$exercise = $this->exercises->findOrThrow($id);
536+
$link = $this->fileLinks->findOrThrow($linkId);
537+
538+
if ($link->getExercise()?->getId() !== $id) {
539+
throw new BadRequestException("The exercise file link is not associated with the given exercise.");
540+
}
541+
542+
if (!$this->exerciseAcl->canUpdate($exercise)) {
543+
throw new ForbiddenRequestException("You cannot update exercise file links for this exercise.");
544+
}
545+
}
546+
/**
547+
* Update a specific exercise-file link.
548+
* @POST
549+
*/
550+
#[Path("id", new VUuid(), "of exercise", required: true)]
551+
#[Path("linkId", new VUuid(), "of the exercise file link", required: true)]
552+
#[Post(
553+
"key",
554+
new VString(1, 16),
555+
"Internal user-selected identifier of the exercise file link within the exercise",
556+
required: true
557+
)]
558+
#[Post(
559+
"requiredRole",
560+
new VString(1, 255),
561+
"Minimal required user role to access the file (null = non-logged-in users)",
562+
nullable: true,
563+
required: false
564+
)]
565+
#[Post(
566+
"saveName",
567+
new VString(1, 255),
568+
"File name override (the file will be downloaded under this name instead of the original name)",
569+
nullable: true,
570+
required: false
571+
)]
572+
public function actionUpdateFileLink(string $id, string $linkId)
573+
{
574+
$link = $this->fileLinks->findOrThrow($linkId);
575+
$req = $this->getRequest();
576+
$post = $req->getPost();
577+
578+
if (array_key_exists("requiredRole", $post)) {
579+
// array_key_exists checks whether the key is present (even if null)
580+
$requiredRole = $post["requiredRole"];
581+
if (!$this->roles->validateRole($requiredRole)) {
582+
throw new InvalidApiArgumentException('requiredRole', "Unknown user role '$requiredRole'");
583+
}
584+
$link->setRequiredRole($requiredRole);
585+
}
586+
587+
if (array_key_exists("saveName", $post)) {
588+
// array_key_exists checks whether the key is present (even if null)
589+
$link->setSaveName($post["saveName"]);
590+
}
591+
592+
$link->setKey($req->getPost("key"));
593+
594+
$this->fileLinks->persist($link);
595+
$this->sendSuccessResponse($link);
596+
}
597+
598+
public function checkDeleteFileLink(string $id, string $linkId)
599+
{
600+
$exercise = $this->exercises->findOrThrow($id);
601+
$link = $this->fileLinks->findOrThrow($linkId);
602+
603+
if ($link->getExercise()?->getId() !== $id) {
604+
throw new BadRequestException("The exercise file link is not associated with the given exercise.");
605+
}
606+
607+
if (!$this->exerciseAcl->canUpdate($exercise)) {
608+
throw new ForbiddenRequestException("You cannot delete exercise file links for this exercise.");
609+
}
610+
}
611+
612+
/**
613+
* Delete a specific exercise-file link.
614+
* @DELETE
615+
*/
616+
#[Path("id", new VUuid(), "of exercise", required: true)]
617+
#[Path("linkId", new VUuid(), "of the exercise file link", required: true)]
618+
public function actionDeleteFileLink(string $id, string $linkId)
619+
{
620+
$link = $this->fileLinks->findOrThrow($linkId);
621+
$this->fileLinks->remove($link);
622+
$this->sendSuccessResponse("OK");
623+
}
431624
}

0 commit comments

Comments
 (0)