Skip to content

Commit 088c538

Browse files
fix(api): seperate and fix user add and update endpoint logic
1 parent 47efe69 commit 088c538

File tree

3 files changed

+106
-37
lines changed

3 files changed

+106
-37
lines changed

webapp/src/Controller/API/UserController.php

Lines changed: 81 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -291,12 +291,12 @@ public function singleAction(Request $request, string $id): Response
291291
* Add a new user.
292292
*/
293293
#[IsGranted('ROLE_API_WRITER')]
294-
#[Rest\Post]
294+
#[Rest\Put("")]
295295
#[OA\RequestBody(
296296
required: true,
297297
content: [
298298
new OA\MediaType(
299-
mediaType: 'multipart/form-data',
299+
mediaType: 'application/json',
300300
schema: new OA\Schema(ref: new Model(type: AddUser::class))
301301
),
302302
]
@@ -311,19 +311,19 @@ public function addAction(
311311
AddUser $addUser,
312312
Request $request
313313
): Response {
314-
return $this->addOrUpdateUser($addUser, $request);
314+
return $this->addUser($addUser, $request);
315315
}
316316

317317
/**
318-
* Update an existing User or create one with the given ID
318+
* Update an existing User
319319
*/
320320
#[IsGranted('ROLE_API_WRITER')]
321-
#[Rest\Put('/{id}')]
321+
#[Rest\Patch('/{id}')]
322322
#[OA\RequestBody(
323323
required: true,
324324
content: [
325325
new OA\MediaType(
326-
mediaType: 'multipart/form-data',
326+
mediaType: 'application/json',
327327
schema: new OA\Schema(ref: new Model(type: UpdateUser::class))
328328
),
329329
]
@@ -336,28 +336,19 @@ public function addAction(
336336
public function updateAction(
337337
#[MapRequestPayload(validationFailedStatusCode: Response::HTTP_BAD_REQUEST)]
338338
UpdateUser $updateUser,
339+
string $id,
339340
Request $request
340341
): Response {
341-
return $this->addOrUpdateUser($updateUser, $request);
342+
return $this->updateUser($updateUser, $id, $request);
342343
}
343344

344-
protected function addOrUpdateUser(AddUser $addUser, Request $request): Response
345+
protected function addUser(AddUser $addUser, Request $request): Response
345346
{
346-
if ($addUser instanceof UpdateUser && !$addUser->id) {
347-
throw new BadRequestHttpException('`id` field is required');
348-
}
349-
350347
if ($this->em->getRepository(User::class)->findOneBy(['username' => $addUser->username])) {
351348
throw new BadRequestHttpException(sprintf("User %s already exists", $addUser->username));
352349
}
353350

354351
$user = new User();
355-
if ($addUser instanceof UpdateUser) {
356-
$existingUser = $this->em->getRepository(User::class)->findOneBy(['externalid' => $addUser->id]);
357-
if ($existingUser) {
358-
$user = $existingUser;
359-
}
360-
}
361352
$user
362353
->setUsername($addUser->username)
363354
->setName($addUser->name)
@@ -366,7 +357,8 @@ protected function addOrUpdateUser(AddUser $addUser, Request $request): Response
366357
->setPlainPassword($addUser->password)
367358
->setEnabled($addUser->enabled ?? true);
368359

369-
if ($addUser instanceof UpdateUser) {
360+
// if not set let it autogenerate
361+
if ($addUser->id) {
370362
$user->setExternalid($addUser->id);
371363
}
372364

@@ -415,6 +407,76 @@ protected function addOrUpdateUser(AddUser $addUser, Request $request): Response
415407
return $this->renderCreateData($request, $user, 'user', $user->getUserid());
416408
}
417409

410+
411+
protected function updateUser(UpdateUser $updateUser, string $id, Request $request): Response
412+
{
413+
$user = $this->em->getRepository(User::class)->findOneBy(['externalid' => $id]);
414+
if (!$user) {
415+
throw new BadRequestHttpException(sprintf("User does not exist", $id));
416+
}
417+
if ($updateUser->username !== null) {
418+
$user->setUsername($updateUser->username);
419+
}
420+
if ($updateUser->name !== null) {
421+
$user->setName($updateUser->name);
422+
}
423+
if ($updateUser->email !== null) {
424+
$user->setEmail($updateUser->email);
425+
}
426+
if ($updateUser->ip !== null) {
427+
$user->setIpAddress($updateUser->ip);
428+
}
429+
if ($updateUser->password !== null) {
430+
$user->setPlainPassword($updateUser->password);
431+
}
432+
if ($updateUser->enabled !== null) {
433+
$user->setEnabled($updateUser->enabled);
434+
}
435+
if ($updateUser->teamId) {
436+
/** @var Team|null $team */
437+
$team = $this->em->createQueryBuilder()
438+
->from(Team::class, 't')
439+
->select('t')
440+
->andWhere('t.externalid = :team')
441+
->setParameter('team', $updateUser->teamId)
442+
->getQuery()
443+
->getOneOrNullResult();
444+
445+
if ($team === null) {
446+
throw new BadRequestHttpException(sprintf("Team %s not found", $updateUser->teamId));
447+
}
448+
$user->setTeam($team);
449+
}
450+
451+
$roles = $updateUser->roles;
452+
// For the file import we change a CDS user to the roles needed for ICPC CDS.
453+
if ($user->getUsername() === 'cds') {
454+
$roles = ['cds'];
455+
}
456+
if (in_array('cds', $roles)) {
457+
$roles = ['api_source_reader', 'api_writer', 'api_reader', ...array_diff($roles, ['cds'])];
458+
}
459+
foreach ($roles as $djRole) {
460+
if ($djRole === '') {
461+
continue;
462+
}
463+
if ($djRole === 'judge') {
464+
$djRole = 'jury';
465+
}
466+
$role = $this->em->getRepository(Role::class)->findOneBy(['dj_role' => $djRole]);
467+
if ($role === null) {
468+
throw new BadRequestHttpException(sprintf("Role %s not found", $djRole));
469+
}
470+
$user->addUserRole($role);
471+
}
472+
473+
$this->em->persist($user);
474+
$this->em->flush();
475+
$this->dj->auditlog('user', $user->getUserid(), 'updated');
476+
477+
return $this->renderCreateData($request, $user, 'user', $user->getUserid());
478+
}
479+
418480
protected function getQueryBuilder(Request $request): QueryBuilder
419481
{
420482
$queryBuilder = $this->em->createQueryBuilder()

webapp/src/DataTransferObject/AddUser.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,9 @@
88
#[OA\Schema(required: ['username', 'name', 'roles'])]
99
class AddUser
1010
{
11-
/**
12-
* @param array<string> $roles
13-
*/
1411
public function __construct(
12+
#[OA\Property(nullable: true)]
13+
public readonly ?string $id,
1514
public readonly string $username,
1615
public readonly string $name,
1716
#[OA\Property(format: 'email', nullable: true)]
@@ -25,6 +24,6 @@ public function __construct(
2524
#[OA\Property(nullable: true)]
2625
public readonly ?string $teamId,
2726
#[Serializer\Type('array<string>')]
28-
public readonly array $roles,
27+
public readonly array $roles = [],
2928
) {}
3029
}

webapp/src/DataTransferObject/UpdateUser.php

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,30 @@
22

33
namespace App\DataTransferObject;
44

5+
use JMS\Serializer\Annotation as Serializer;
56
use OpenApi\Attributes as OA;
67

7-
#[OA\Schema(required: ['id', 'username', 'name', 'roles'])]
8-
class UpdateUser extends AddUser
8+
#[OA\Schema(required: ['roles'])]
9+
class UpdateUser
910
{
1011
public function __construct(
11-
public readonly string $id,
12-
string $username,
13-
string $name,
14-
?string $email,
15-
?string $ip,
16-
?string $password,
17-
?bool $enabled,
18-
?string $teamId,
19-
array $roles
20-
) {
21-
parent::__construct($username, $name, $email, $ip, $password, $enabled, $teamId, $roles);
22-
}
12+
public readonly ?string $id = null,
13+
#[OA\Property(nullable: true)]
14+
public readonly ?string $username = null,
15+
#[OA\Property(nullable: true)]
16+
public readonly ?string $name = null,
17+
#[OA\Property(format: 'email', nullable: true)]
18+
public readonly ?string $email = null,
19+
#[OA\Property(nullable: true)]
20+
public readonly ?string $ip = null,
21+
#[OA\Property(format: 'password', nullable: true)]
22+
public readonly ?string $password = null,
23+
#[OA\Property(nullable: true)]
24+
public readonly ?bool $enabled = null,
25+
#[OA\Property(nullable: true)]
26+
public readonly ?string $teamId = null,
27+
#[OA\Property(nullable: true)]
28+
#[Serializer\Type('array<string>')]
29+
public readonly array $roles = []
30+
) {}
2331
}

0 commit comments

Comments
 (0)