Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
93.88% |
46 / 49 |
|
0.00% |
0 / 1 |
CRAP | |
0.00% |
0 / 1 |
| ToggleTerminReactionEndpoint | |
93.88% |
46 / 49 |
|
0.00% |
0 / 1 |
19.08 | |
0.00% |
0 / 1 |
| handle | |
93.88% |
46 / 49 |
|
0.00% |
0 / 1 |
19.08 | |||
| 1 | <?php |
| 2 | |
| 3 | namespace Olz\Termine\Endpoints; |
| 4 | |
| 5 | use Olz\Api\OlzTypedEndpoint; |
| 6 | use Olz\Entity\Termine\Termin; |
| 7 | use Olz\Entity\Termine\TerminReaction; |
| 8 | use Olz\Entity\Users\User; |
| 9 | use PhpTypeScriptApi\HttpError; |
| 10 | |
| 11 | /** |
| 12 | * @phpstan-import-type OlzReaction from ListTerminReactionsEndpoint |
| 13 | * |
| 14 | * @extends OlzTypedEndpoint< |
| 15 | * array{ |
| 16 | * userId?: ?int<1, max>, |
| 17 | * terminId: int<1, max>, |
| 18 | * emoji: non-empty-string, |
| 19 | * action: 'on'|'off'|'toggle', |
| 20 | * }, |
| 21 | * array{ |
| 22 | * result: ?OlzReaction, |
| 23 | * } |
| 24 | * > |
| 25 | */ |
| 26 | class ToggleTerminReactionEndpoint extends OlzTypedEndpoint { |
| 27 | protected function handle(mixed $input): mixed { |
| 28 | $has_access = $this->authUtils()->hasPermission('any'); |
| 29 | $user = $this->authUtils()->getCurrentUser(); |
| 30 | if (($input['userId'] ?? null) !== null) { |
| 31 | $user_repo = $this->entityManager()->getRepository(User::class); |
| 32 | $user = $user_repo->findOneBy(['id' => $input['userId']]); |
| 33 | } |
| 34 | if (!$has_access || !$user) { |
| 35 | throw new HttpError(403, 'Kein Zugriff!'); |
| 36 | } |
| 37 | $auth_user_id = $this->session()->get('auth_user_id'); |
| 38 | $is_parent = $auth_user_id && intval($user->getParentUserId()) === intval($auth_user_id); |
| 39 | $is_self = $auth_user_id && intval($user->getId()) === intval($auth_user_id); |
| 40 | if (!$is_self && !$is_parent) { |
| 41 | throw new HttpError(403, "Kein Zugriff!"); |
| 42 | } |
| 43 | if (!$this->generalUtils()->isOneEmoji($input['emoji'])) { |
| 44 | $enc_emoji = urlencode($input['emoji']); |
| 45 | throw new HttpError(400, "Ungültiges Emoji: {$input['emoji']} ({$enc_emoji})"); |
| 46 | } |
| 47 | |
| 48 | $termin_reaction_repo = $this->entityManager()->getRepository(TerminReaction::class); |
| 49 | $reactions = $termin_reaction_repo->findBy([ |
| 50 | 'termin' => $input['terminId'], |
| 51 | 'emoji' => $input['emoji'], |
| 52 | 'user' => $user, |
| 53 | ]); |
| 54 | // Hack for prod not applying the emoji filter correctly. |
| 55 | $reactions = array_filter( |
| 56 | $reactions, |
| 57 | fn ($reaction) => $input['emoji'] === $reaction->getEmoji(), |
| 58 | ); |
| 59 | $has_reactions = count($reactions) > 0; |
| 60 | $want_reaction = $input['action'] === 'on' || ($input['action'] === 'toggle' && !$has_reactions); |
| 61 | $result = null; |
| 62 | |
| 63 | if (!$has_reactions && $want_reaction) { |
| 64 | $termin_repo = $this->entityManager()->getRepository(Termin::class); |
| 65 | $termin = $termin_repo->findOneBy(['id' => $input['terminId']]); |
| 66 | if (!$termin) { |
| 67 | throw new HttpError(400, "Kein solcher Termin"); |
| 68 | } |
| 69 | $reaction = new TerminReaction(); |
| 70 | $reaction->setTermin($termin); |
| 71 | $reaction->setUser($user); |
| 72 | $reaction->setEmoji($input['emoji']); |
| 73 | $this->entityManager()->persist($reaction); |
| 74 | $this->entityManager()->flush(); |
| 75 | $result = [ |
| 76 | 'userId' => $reaction->getUser()->getId() ?? 0, |
| 77 | 'name' => $reaction->getUser()->getFullName() ?: '?', |
| 78 | 'emoji' => $reaction->getEmoji() ?: '?', |
| 79 | ]; |
| 80 | } |
| 81 | if ($has_reactions && !$want_reaction) { |
| 82 | foreach ($reactions as $reaction) { |
| 83 | $this->entityManager()->remove($reaction); |
| 84 | } |
| 85 | $this->entityManager()->flush(); |
| 86 | } |
| 87 | |
| 88 | return ['result' => $result]; |
| 89 | } |
| 90 | } |