diff --git a/README.md b/README.md index 0a29c9a0b..0699ceb77 100755 --- a/README.md +++ b/README.md @@ -197,3 +197,7 @@ IDP_CLIENT_SECRET=client-secret * 601: The amount of cash that will be added, has to be more than zero *EventController 7xx* * 701: Event creation parameters are missing +*EventParticipationController 8xx* + * 801: User has no permission to enter or leave + * 802: User could not join the event + * 803: User could not leave the event \ No newline at end of file diff --git a/src/Mealz/MealBundle/Controller/EventParticipationController.php b/src/Mealz/MealBundle/Controller/EventParticipationController.php new file mode 100644 index 000000000..8aecb279e --- /dev/null +++ b/src/Mealz/MealBundle/Controller/EventParticipationController.php @@ -0,0 +1,61 @@ +eventDispatcher = $eventDispatcher; + $this->eventParticipationService = $eventParticipationService; + } + + public function join(Day $day): JsonResponse + { + $profile = $this->getProfile(); + if (null === $profile) { + return new JsonResponse(['messasge' => '801: User is not allowed to join'], 403); + } + + $eventParticipation = $this->eventParticipationService->join($profile, $day); + if (null === $eventParticipation) { + return new JsonResponse(['messasge' => '802: User could not join the event'], 500); + } + + $this->eventDispatcher->dispatch(new EventParticipationUpdateEvent($eventParticipation)); + return new JsonResponse(['isParticipating' => true], 200); + } + + public function leave(Day $day): JsonResponse + { + $profile = $this->getProfile(); + if (null === $profile) { + return new JsonResponse(['messasge' => '801: User is not allowed to leave'], 403); + } + + $eventParticipation = $this->eventParticipationService->leave($profile, $day); + if (null === $eventParticipation) { + return new JsonResponse(['messasge' => '802: User could not leave the event'], 500); + } + + $this->eventDispatcher->dispatch(new EventParticipationUpdateEvent($eventParticipation)); + return new JsonResponse(['isParticipating' => false], 200); + } +} \ No newline at end of file diff --git a/src/Mealz/MealBundle/Entity/EventParticipation.php b/src/Mealz/MealBundle/Entity/EventParticipation.php index 4926d9aef..977d42e5a 100644 --- a/src/Mealz/MealBundle/Entity/EventParticipation.php +++ b/src/Mealz/MealBundle/Entity/EventParticipation.php @@ -96,4 +96,14 @@ public function getParticipants(): ArrayCollection return new ArrayCollection($this->participants->toArray()); } + + public function addParticipant(Participant $participant): void + { + $this->participants->add($participant); + } + + public function removeParticipant(Participant $participant): bool + { + return $this->participants->removeElement($participant); + } } diff --git a/src/Mealz/MealBundle/Entity/Participant.php b/src/Mealz/MealBundle/Entity/Participant.php index 4fee8a2c9..b2f2fed04 100644 --- a/src/Mealz/MealBundle/Entity/Participant.php +++ b/src/Mealz/MealBundle/Entity/Participant.php @@ -32,9 +32,9 @@ class Participant * @Assert\NotNull() * @Assert\Type(type="App\Mealz\MealBundle\Entity\Meal") * @ORM\ManyToOne(targetEntity="Meal",inversedBy="participants") - * @ORM\JoinColumn(name="meal_id", referencedColumnName="id") + * @ORM\JoinColumn(name="meal_id", referencedColumnName="id", nullable=true) */ - private Meal $meal; + private ?Meal $meal; /** * @Assert\NotNull() @@ -85,10 +85,11 @@ class Participant */ private bool $confirmed = false; - public function __construct(Profile $profile, ?Meal $meal) + public function __construct(Profile $profile, ?Meal $meal, ?EventParticipation $eventParticipation) { $this->profile = $profile; $this->meal = $meal; + $this->event = $eventParticipation; $this->combinedDishes = new DishCollection(); } diff --git a/src/Mealz/MealBundle/Resources/config/routing.yml b/src/Mealz/MealBundle/Resources/config/routing.yml index cdf10aae6..98979bf61 100644 --- a/src/Mealz/MealBundle/Resources/config/routing.yml +++ b/src/Mealz/MealBundle/Resources/config/routing.yml @@ -187,6 +187,16 @@ MealzMealBundle_api_events_delete: defaults: { _controller: App\Mealz\MealBundle\Controller\EventController::delete } methods: [ DELETE ] +MealzMealBundle_api_events_join: + path: /api/events/participation + defaults: { _controller: App\Mealz\MealBundle\Controller\EventParticipationController::join } + methods: [ POST ] + +MealzMealBundle_api_events_join: + path: /api/events/participation + defaults: { _controller: App\Mealz\MealBundle\Controller\EventParticipationController::leave } + methods: [ DELETE ] + MealzMealBundle_Meal_offers: path: /menu/{date}/{dish}/offers defaults: { _controller: App\Mealz\MealBundle\Controller\MealController::getOffers } diff --git a/src/Mealz/MealBundle/Service/Doorman.php b/src/Mealz/MealBundle/Service/Doorman.php index f1ef7c2c2..5c77570e9 100644 --- a/src/Mealz/MealBundle/Service/Doorman.php +++ b/src/Mealz/MealBundle/Service/Doorman.php @@ -2,6 +2,7 @@ namespace App\Mealz\MealBundle\Service; +use App\Mealz\MealBundle\Entity\EventParticipation; use App\Mealz\MealBundle\Entity\Meal; use App\Mealz\MealBundle\Entity\Participant; use App\Mealz\UserBundle\Entity\Profile; @@ -66,6 +67,15 @@ public function isUserAllowedToJoin(Meal $meal, array $dishSlugs = []): bool && $this->hasAccessTo(self::AT_MEAL_PARTICIPATION, ['meal' => $meal]); } + public function isUserAllowedToJoinEvent(EventParticipation $eventParticipation): bool + { + if (false === $this->security->getUser()->getProfile() instanceof Profile) { + return false; + } + + return $this->isToggleParticipationAllowed($eventParticipation->getDay()->getLockParticipationDateTime()); + } + public function isOfferAvailable(Meal $meal): bool { if (false === $this->security->getUser()->getProfile() instanceof Profile) { diff --git a/src/Mealz/MealBundle/Service/EventParticipationService.php b/src/Mealz/MealBundle/Service/EventParticipationService.php index 6af20fbe5..cfc85a8dc 100644 --- a/src/Mealz/MealBundle/Service/EventParticipationService.php +++ b/src/Mealz/MealBundle/Service/EventParticipationService.php @@ -5,6 +5,7 @@ use App\Mealz\MealBundle\Entity\Day; use App\Mealz\MealBundle\Entity\Event; use App\Mealz\MealBundle\Entity\EventParticipation; +use App\Mealz\MealBundle\Entity\Participant; use App\Mealz\MealBundle\Repository\EventParticipationRepositoryInterface; use App\Mealz\MealBundle\Repository\EventRepositoryInterface; use App\Mealz\UserBundle\Entity\Profile; @@ -12,15 +13,18 @@ class EventParticipationService { + private Doorman $doorman; private EntityManagerInterface $em; private EventParticipationRepositoryInterface $eventPartRepo; private EventRepositoryInterface $eventRepo; public function __construct( + Doorman $doorman, EntityManagerInterface $em, EventRepositoryInterface $eventRepo, EventParticipationRepositoryInterface $eventPartRepo ) { + $this->doorman = $doorman; $this->em = $em; $this->eventPartRepo = $eventPartRepo; $this->eventRepo = $eventRepo; @@ -55,6 +59,39 @@ public function getEventParticipationData(Day $day, Profile $profile): ?array ]; } + public function join(Profile $profile, Day $day): ?EventParticipation + { + $eventParticipation = $day->getEvent(); + if (null !== $eventParticipation && true === $this->doorman->isUserAllowedToJoinEvent($eventParticipation)) { + $participation = $this->createEventParticipation($profile, $eventParticipation); + if (null !== $participation) { + $this->em->persist($participation); + $this->em->flush(); + + $eventParticipation->addParticipant($participation); + return $eventParticipation; + } + } + + return null; + } + + public function leave(Profile $profile, Day $day): ?EventParticipation + { + $eventParticipation = $day->getEvent(); + $participation = $eventParticipation->getParticipant($profile); + + if (null !== $eventParticipation) { + $eventParticipation->removeParticipant($participation); + $this->em->remove($participation); + $this->em->flush(); + + return $eventParticipation; + } + + return null; + } + private function addEventToDay(Day $day, ?Event $event) { // new eventparticipation @@ -74,4 +111,9 @@ private function removeEventFromDay(Day $day) $day->setEvent(null); } } + + private function createEventParticipation(Profile $profile, EventParticipation $eventParticiation): ?Participant + { + return new Participant($profile, null, $eventParticiation); + } }