Skip to content

Commit 68c297e

Browse files
committed
Define API endpoint for printing as a team
This endpoint can be used for `printfile` CLI submit tools, when printing via DOMjudge has been configured.
1 parent 58a630c commit 68c297e

File tree

2 files changed

+139
-0
lines changed

2 files changed

+139
-0
lines changed
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace App\Controller\API;
4+
5+
use App\DataTransferObject\PrintTeam;
6+
use App\Service\DOMJudgeService;
7+
use Doctrine\ORM\AbstractQuery;
8+
use Doctrine\ORM\EntityManagerInterface;
9+
use FOS\RestBundle\Controller\AbstractFOSRestController;
10+
use FOS\RestBundle\Controller\Annotations as Rest;
11+
use Nelmio\ApiDocBundle\Annotation\Model;
12+
use OpenApi\Attributes as OA;
13+
use Psr\Log\LoggerInterface;
14+
use Symfony\Component\HttpFoundation\JsonResponse;
15+
use Symfony\Component\HttpFoundation\Request;
16+
use Symfony\Component\HttpFoundation\Response;
17+
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
18+
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
19+
use Symfony\Component\Routing\Attribute\Route;
20+
use Symfony\Component\Security\Http\Attribute\IsGranted;
21+
use App\Entity\Language;
22+
23+
#[Route(path: "/printing")]
24+
#[OA\Tag(name: "Printing")]
25+
#[OA\Response(ref: "#/components/responses/Unauthenticated", response: 401)]
26+
#[OA\Response(ref: "#/components/responses/Unauthorized", response: 403)]
27+
class PrintController extends AbstractFOSRestController
28+
{
29+
public function __construct(
30+
protected readonly EntityManagerInterface $em,
31+
protected readonly DOMJudgeService $dj,
32+
protected readonly LoggerInterface $logger
33+
) {
34+
}
35+
36+
/**
37+
* Send a file to the system printer as a team.
38+
* @return JsonResponse
39+
*/
40+
#[IsGranted("ROLE_TEAM")]
41+
#[Rest\Post("/team")]
42+
#[OA\Tag(name: "Printing")]
43+
#[OA\RequestBody(
44+
required: true,
45+
content: new OA\JsonContent(ref: new Model(type: PrintTeam::class))
46+
)]
47+
#[OA\Response(
48+
response: 200,
49+
description: "Returns the ID of the imported problem and any messages produced",
50+
content: new OA\JsonContent(
51+
properties: [
52+
new OA\Property(
53+
property: "success",
54+
description: "Whether printing was successful",
55+
type: "boolean"
56+
),
57+
new OA\Property(
58+
property: "output",
59+
description: "The print command output",
60+
type: "string"
61+
),
62+
],
63+
type: "object"
64+
)
65+
)]
66+
#[OA\Response(
67+
response: 422,
68+
description: "An error occurred while processing the print job",
69+
content: new OA\JsonContent(
70+
properties: [
71+
new OA\Property(property: "errors", type: "object"),
72+
]
73+
)
74+
)]
75+
public function printAsTeam(
76+
#[MapRequestPayload(validationFailedStatusCode: Response::HTTP_BAD_REQUEST)]
77+
PrintTeam $print,
78+
Request $request
79+
): JsonResponse {
80+
$langid = null;
81+
if ($print->language !== null) {
82+
$langid = $this->em
83+
->createQueryBuilder()
84+
->from(Language::class, "l")
85+
->select("l.langid")
86+
->andWhere("l.allowSubmit = 1")
87+
->andWhere("l.name = :name")
88+
->setParameter("name", $print->language)
89+
->getQuery()
90+
->getOneOrNullResult(AbstractQuery::HYDRATE_SINGLE_SCALAR);
91+
if ($langid === null) {
92+
throw new BadRequestHttpException("Programming language not found.");
93+
}
94+
}
95+
96+
$decodedFile = base64_decode($print->fileContents, true);
97+
if ($decodedFile === false) {
98+
throw new BadRequestHttpException("The file contents is not base64 encoded.");
99+
}
100+
101+
if (!($tempFilename = tempnam($this->dj->getDomjudgeTmpDir(), "printfile-"))) {
102+
throw new ServiceUnavailableHttpException(null, "Could not create temporary file.");
103+
}
104+
105+
if (file_put_contents($tempFilename, $decodedFile) === false) {
106+
throw new ServiceUnavailableHttpException(
107+
null,
108+
sprintf("Could not write printfile to temporary file '%s'.", $tempFilename)
109+
);
110+
}
111+
112+
$ret = $this->dj->printUserFile($tempFilename, $print->originalName, $langid, true);
113+
unlink($tempFilename);
114+
115+
return new JsonResponse(
116+
["success" => $ret[0], "output" => $ret[1]],
117+
$ret[0] ? Response::HTTP_OK : Response::HTTP_SERVICE_UNAVAILABLE
118+
);
119+
}
120+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace App\DataTransferObject;
4+
5+
use JMS\Serializer\Annotation as Serializer;
6+
use OpenApi\Attributes as OA;
7+
8+
#[OA\Schema(required: ['name'])]
9+
class PrintTeam
10+
{
11+
public function __construct(
12+
#[OA\Property(description: 'The original name of the file')]
13+
public readonly string $originalName,
14+
#[OA\Property(description: 'The programming language of the file contents', nullable: true)]
15+
public readonly ?string $language,
16+
#[OA\Property(description: 'The (base64-encoded) contents of the source file', format: 'binary')]
17+
public readonly string $fileContents,
18+
) {}
19+
}

0 commit comments

Comments
 (0)