Skip to content

Commit 399cf3b

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 8330284 commit 399cf3b

File tree

2 files changed

+146
-0
lines changed

2 files changed

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