diff --git a/README.md b/README.md index 0699ceb77..b2c925f59 100755 --- a/README.md +++ b/README.md @@ -200,4 +200,6 @@ IDP_CLIENT_SECRET=client-secret *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 + * 803: User could not leave the event +*MealGuestController 9xx* + * 901: Could not find the Invitation for the given hash \ No newline at end of file diff --git a/config/packages/security.yaml b/config/packages/security.yaml index c720a45e0..c7e149e78 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -80,9 +80,9 @@ security: - { path: ^/api/guest-invitation, roles: [IS_AUTHENTICATED_ANONYMOUSLY] } - { path: ^/api/environmentals, roles: [IS_AUTHENTICATED_ANONYMOUSLY] } - { path: ^/api/user, roles: [IS_AUTHENTICATED_ANONYMOUSLY] } + - { path: ^/api/event/invitation/\S*, roles: [IS_AUTHENTICATED_ANONYMOUSLY] } - { path: '^/participation/slots-status/\d{4}-\d{2}-\d{2}$', roles: [IS_AUTHENTICATED_ANONYMOUSLY] } - { path: '^/participation/count-status/\d{4}-\d{2}-\d{2}$', roles: [IS_AUTHENTICATED_ANONYMOUSLY] } - - { path: ^/language-switch, roles: [IS_AUTHENTICATED_ANONYMOUSLY] } - { path: ^/css, roles: [IS_AUTHENTICATED_ANONYMOUSLY] } - { path: ^/js, roles: [IS_AUTHENTICATED_ANONYMOUSLY] } - { path: ^/images, roles: [IS_AUTHENTICATED_ANONYMOUSLY] } diff --git a/config/services.yaml b/config/services.yaml index 537036ebc..af84cbfee 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -47,11 +47,10 @@ parameters: app.secret: '%env(APP_SECRET)%' mealz.lock_toggle_participation_at: '-1 day 16:00' - mealz.meal.price: 3.60 + mealz.meal.price: 4.13 mealz.meal.search_timestamp: '2000-01-01' mealz.meal.new_flag_counter: 2 - mealz.meal.combined.price: 5.60 - + mealz.meal.combined.price: 6.13 # PDO Session Handler options # Define table and column names to store session data app.session.handler.pdo.options: diff --git a/src/Mealz/MealBundle/Controller/LanguageController.php b/src/Mealz/MealBundle/Controller/LanguageController.php deleted file mode 100644 index 8ad38bf93..000000000 --- a/src/Mealz/MealBundle/Controller/LanguageController.php +++ /dev/null @@ -1,26 +0,0 @@ -headers->get('referer'); - $response = new RedirectResponse($referrer); - - $preferredLanguage = ('en' === $request->getLocale()) ? 'de' : 'en'; - - $cookie = Cookie::create('locale', $preferredLanguage, time() + 60 * 60 * 24 * 365); - $response->headers->setCookie($cookie); - - return $response; - } -} diff --git a/src/Mealz/MealBundle/Controller/MealGuestController.php b/src/Mealz/MealBundle/Controller/MealGuestController.php index 7372eef97..d90de9b77 100644 --- a/src/Mealz/MealBundle/Controller/MealGuestController.php +++ b/src/Mealz/MealBundle/Controller/MealGuestController.php @@ -5,6 +5,7 @@ namespace App\Mealz\MealBundle\Controller; use App\Mealz\MealBundle\Entity\Day; +use App\Mealz\MealBundle\Entity\GuestInvitation; use App\Mealz\MealBundle\Entity\Participant; use App\Mealz\MealBundle\Event\ParticipationUpdateEvent; use App\Mealz\MealBundle\Event\SlotAllocationUpdateEvent; @@ -62,14 +63,38 @@ public function newGuestInvitation( ): JsonResponse { $guestInvitation = $guestInvitationRepo->findOrCreateInvitation($this->getUser()->getProfile(), $mealDay); - return new JsonResponse( - [ - 'url' => $this->generateUrl( - 'MealzMealBundle_Meal_guest', - ['hash' => $guestInvitation->getId()], - UrlGeneratorInterface::ABSOLUTE_URL), - ], 200 - ); + return new JsonResponse(['url' => $this->generateInvitationUrl($guestInvitation)], 200); + } + + /** + * @Security("is_granted('ROLE_USER')") + */ + public function newGuestEventInvitation( + Day $dayId, + GuestInvitationRepositoryInterface $guestInvitationRepo + ): JsonResponse { + $eventInvitation = $guestInvitationRepo->findOrCreateInvitation($this->getUser()->getProfile(), $dayId); + + return new JsonResponse(['url' => $this->generateInvitationUrl($eventInvitation, false)], 200); + } + + public function getEventInvitationData( + string $invitationId, + GuestInvitationRepositoryInterface $guestInvitationRepo + ): JsonResponse { + /** @var GuestInvitation $invitation */ + $invitation = $guestInvitationRepo->find($invitationId); + if (null === $invitation) { + return new JsonResponse(['message' => '901: Could not find invitation for the given hash', 403]); + } + + $guestData = [ + 'date' => $invitation->getDay()->getDateTime(), + 'lockDate' => $invitation->getDay()->getLockParticipationDateTime(), + 'event' => $invitation->getDay()->getEvent()->getEvent()->getTitle(), + ]; + + return new JsonResponse($guestData, 200); } /** @@ -91,4 +116,13 @@ private function triggerJoinEvents(array $participants): void $this->eventDispatcher->dispatch(new SlotAllocationUpdateEvent($participant->getMeal()->getDay(), $slot)); } } + + private function generateInvitationUrl(GuestInvitation $invitation, bool $isMeal = true): string + { + return $this->generateUrl( + true === $isMeal ? 'MealzMealBundle_Meal_guest' : 'MealzMealBundle_Meal_guest_event', + ['hash' => $invitation->getId()], + UrlGeneratorInterface::ABSOLUTE_URL + ); + } } diff --git a/src/Mealz/MealBundle/DataFixtures/ORM/LoadDishVariations.php b/src/Mealz/MealBundle/DataFixtures/ORM/LoadDishVariations.php index 6921ea485..bea3eddc6 100644 --- a/src/Mealz/MealBundle/DataFixtures/ORM/LoadDishVariations.php +++ b/src/Mealz/MealBundle/DataFixtures/ORM/LoadDishVariations.php @@ -74,7 +74,7 @@ private function getDishVariation(Dish $dish): DishVariation $dishVariation->setTitleDe($dish->getTitleDe() . $dummyPrefix); $dishVariation->setTitleEn($dish->getTitleEn() . $dummyPrefix); $dishVariation->setParent($dish); - $dishVariation->setPrice(3.60); + $dishVariation->setPrice(4.13); $variations = $dish->getVariations(); $variations->add($dishVariation); diff --git a/src/Mealz/MealBundle/DataFixtures/ORM/LoadDishes.php b/src/Mealz/MealBundle/DataFixtures/ORM/LoadDishes.php index bd772e3f8..5f2a5ca05 100644 --- a/src/Mealz/MealBundle/DataFixtures/ORM/LoadDishes.php +++ b/src/Mealz/MealBundle/DataFixtures/ORM/LoadDishes.php @@ -72,7 +72,7 @@ public function getOrder(): int protected function addDish(string $titleEN, string $titleDE, string $descEN = null, string $descDE = null, bool $oneSize = false): void { $dish = new Dish(); - $dish->setPrice(3.60); + $dish->setPrice(4.13); $dish->setTitleEn($titleEN); $dish->setTitleDe($titleDE); $dish->setDescriptionEn('Description - ' . $titleEN); diff --git a/src/Mealz/MealBundle/Resources/config/routing.yml b/src/Mealz/MealBundle/Resources/config/routing.yml index 40effdc8c..242ca65ee 100644 --- a/src/Mealz/MealBundle/Resources/config/routing.yml +++ b/src/Mealz/MealBundle/Resources/config/routing.yml @@ -1,7 +1,3 @@ -MealzMealBundle_language_switch: - path: /language-switch - defaults: { _controller: App\Mealz\MealBundle\Controller\LanguageController::switch } - MealzMealBundle_api_dashboard: path: /api/dashboard defaults: { _controller: App\Mealz\MealBundle\Controller\ApiController::getDashboardData } @@ -87,6 +83,11 @@ MealzMealBundle_Meal_guest: defaults: { _controller: App\Mealz\MealBundle\Controller\FrontendController::renderIndex } methods: [ GET, POST ] +MealzMealBundle_Meal_guest_event: + path: /guest/event/{hash} + defaults: { _controller: App\Mealz\MealBundle\Controller\FrontendController::renderIndex } + methods: [ GET, POST ] + MealzMealBundle_balance: path: /balance defaults: { _controller: App\Mealz\MealBundle\Controller\FrontendController::renderIndex } @@ -167,6 +168,11 @@ MealzMealBundle_api_invitationdata: defaults: { _controller: App\Mealz\MealBundle\Controller\ApiController::getGuestData } methods: [ GET ] +MealzMealBundle_api_event_invitation_data: + path: /api/event/invitation/{invitationId} + defaults: { _controller: App\Mealz\MealBundle\Controller\MealGuestController::getEventInvitationData } + methods: [ GET ] + MealzMealBundle_api_events: path: /api/events defaults: { _controller: App\Mealz\MealBundle\Controller\EventController::getEventList } @@ -197,6 +203,12 @@ MealzMealBundle_api_events_leave: defaults: { _controller: App\Mealz\MealBundle\Controller\EventController::leave } methods: [ DELETE ] +MealzMealBundle_Meal_api_guest_event_invitation: + path: /event/invitation/{dayId} + defaults: { _controller: App\Mealz\MealBundle\Controller\MealGuestController::newGuestEventInvitation } + requirements: + dayId: '[1-9][0-9]*' + MealzMealBundle_Meal_offers: path: /menu/{date}/{dish}/offers defaults: { _controller: App\Mealz\MealBundle\Controller\MealController::getOffers } diff --git a/src/Mealz/MealBundle/Service/EventParticipationService.php b/src/Mealz/MealBundle/Service/EventParticipationService.php index f4996575d..2491faa25 100644 --- a/src/Mealz/MealBundle/Service/EventParticipationService.php +++ b/src/Mealz/MealBundle/Service/EventParticipationService.php @@ -56,6 +56,7 @@ public function getEventParticipationData(Day $day, Profile $profile = null): ?a 'eventId' => $eventParticipation->getEvent()->getId(), 'participationId' => $eventParticipation->getId(), 'participations' => count($eventParticipation->getParticipants()), + 'isPublic' => $eventParticipation->getEvent()->isPublic(), ]; if (null !== $profile) { diff --git a/src/Resources/src/api/getDashboardData.ts b/src/Resources/src/api/getDashboardData.ts index 45dbbae03..e5b9a5e4e 100644 --- a/src/Resources/src/api/getDashboardData.ts +++ b/src/Resources/src/api/getDashboardData.ts @@ -40,7 +40,8 @@ export type EventParticipation = { eventId: number, participationId: number, participations: number, - isParticipating: boolean + isParticipating: boolean, + isPublic: boolean } export type Day = { diff --git a/src/Resources/src/api/getEventGuestLink.ts b/src/Resources/src/api/getEventGuestLink.ts new file mode 100644 index 000000000..057b75acc --- /dev/null +++ b/src/Resources/src/api/getEventGuestLink.ts @@ -0,0 +1,13 @@ +import useApi from "./api"; +import { Link } from "./getGuestLink"; + +export default async function getEventGuestLink(dayId: string) { + const { error, response: link, request } = useApi( + 'GET', + `/event/invitation/${dayId}` + ); + + await request(); + + return { link, error }; +} \ No newline at end of file diff --git a/src/Resources/src/api/getEventInvitionData.ts b/src/Resources/src/api/getEventInvitionData.ts new file mode 100644 index 000000000..5d640589d --- /dev/null +++ b/src/Resources/src/api/getEventInvitionData.ts @@ -0,0 +1,20 @@ +import { IMessage } from "@/interfaces/IMessage"; +import useApi from "./api"; +import { DateTime } from "./getDashboardData"; + +export interface EventInvitationData { + date: DateTime, + lockDate: DateTime, + event: string +} + +export default async function getEventInvitationData(invitationHash: string) { + const { error, request, response } = useApi( + 'GET', + `/api/event/invitation/${invitationHash}` + ); + + await request(); + + return { error, response }; +} \ No newline at end of file diff --git a/src/Resources/src/api/getGuestLink.ts b/src/Resources/src/api/getGuestLink.ts index 1c795e1e4..b341588bc 100644 --- a/src/Resources/src/api/getGuestLink.ts +++ b/src/Resources/src/api/getGuestLink.ts @@ -1,7 +1,7 @@ import useApi from '@/api/api'; import { ref } from 'vue'; -type Link = { +export type Link = { url: string } diff --git a/src/Resources/src/components/dashboard/Day.vue b/src/Resources/src/components/dashboard/Day.vue index 26dc1315d..901164b50 100644 --- a/src/Resources/src/components/dashboard/Day.vue +++ b/src/Resources/src/components/dashboard/Day.vue @@ -15,6 +15,8 @@ v-if="!day.isLocked && !emptyDay && !guestData && day.isEnabled" :dayID="dayID" :index="index" + :invitation="Invitation.MEAL" + :icon-white="true" class="row-start-2 w-[24px] pl-[3px] text-center" /> @@ -38,7 +40,7 @@ v-for="(meal, mealID) in day.meals" :key="mealID" class="mx-[15px] border-b-[0.7px] last:border-b-0" - :class="isEventDay ? 'pt-[13px] pb-[13px] last:pb-0 last:pt-[21px]' : 'py-[13px]'" + :class="isEventDay && !guestData ? 'pt-[13px] pb-[13px] last:pb-0 last:pt-[21px]' : 'py-[13px]'" > @@ -86,6 +89,7 @@ import GuestButton from '@/components/dashboard/GuestButton.vue'; import { translateWeekday } from 'tools/localeHelper'; import { GuestDay } from '@/api/getInvitationData'; import EventData from './EventData.vue'; +import { Invitation } from '@/enums/Invitation'; const { t, locale } = useI18n() diff --git a/src/Resources/src/components/dashboard/EventData.vue b/src/Resources/src/components/dashboard/EventData.vue index b9baf3097..9f3437080 100644 --- a/src/Resources/src/components/dashboard/EventData.vue +++ b/src/Resources/src/components/dashboard/EventData.vue @@ -23,6 +23,14 @@ {{ getEventById(day.event.eventId)?.title }} + (); const { t } = useI18n(); diff --git a/src/Resources/src/components/dashboard/GuestButton.vue b/src/Resources/src/components/dashboard/GuestButton.vue index e465ab492..657b36ac4 100644 --- a/src/Resources/src/components/dashboard/GuestButton.vue +++ b/src/Resources/src/components/dashboard/GuestButton.vue @@ -4,12 +4,16 @@ - + @@ -18,9 +22,12 @@ import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'; import Icons from '@/components/misc/Icons.vue'; import GuestLink from '@/components/dashboard/GuestLink.vue'; +import { Invitation } from '@/enums/Invitation'; defineProps<{ dayID: number | string, - index: number + index: number, + invitation: Invitation, + iconWhite: boolean }>(); \ No newline at end of file diff --git a/src/Resources/src/components/dashboard/GuestLink.vue b/src/Resources/src/components/dashboard/GuestLink.vue index b03bd52dc..28fe86726 100644 --- a/src/Resources/src/components/dashboard/GuestLink.vue +++ b/src/Resources/src/components/dashboard/GuestLink.vue @@ -10,19 +10,22 @@ \ No newline at end of file diff --git a/tests/e2e/cypress/e2e/Dashboard.cy.ts b/tests/e2e/cypress/e2e/Dashboard.cy.ts index 1d5a91e52..21294450f 100644 --- a/tests/e2e/cypress/e2e/Dashboard.cy.ts +++ b/tests/e2e/cypress/e2e/Dashboard.cy.ts @@ -240,7 +240,7 @@ describe('Test Dashboard View', () => { .contains('Afterwork') .parent() .find('div') - .eq(3) + .eq(4) .children() .should('have.length', 0); @@ -257,7 +257,7 @@ describe('Test Dashboard View', () => { .contains('Afterwork') .parent() .find('div') - .eq(3) + .eq(4) .click(); // confirm event has been joined @@ -273,7 +273,7 @@ describe('Test Dashboard View', () => { .contains('Afterwork') .parent() .find('div') - .eq(3) + .eq(4) .children() .should('have.length', 1); @@ -290,7 +290,7 @@ describe('Test Dashboard View', () => { .contains('Afterwork') .parent() .find('div') - .eq(3) + .eq(4) .click(); // confirm event has been left @@ -306,7 +306,7 @@ describe('Test Dashboard View', () => { .contains('Afterwork') .parent() .find('div') - .eq(3) + .eq(4) .children() .should('have.length', 0); }); @@ -366,7 +366,7 @@ describe('Test Dashboard View', () => { .contains('Afterwork') .parent() .find('div') - .eq(3) + .eq(4) .click(); // click on the info-icon @@ -381,7 +381,7 @@ describe('Test Dashboard View', () => { .contains('Afterwork') .parent() .find('svg') - .eq(0) + .eq(1) .click(); cy.wait('@getParticipants'); @@ -415,7 +415,7 @@ describe('Test Dashboard View', () => { .contains('Afterwork') .parent() .find('div') - .eq(3) + .eq(4) .click(); // click on the info-icon @@ -430,7 +430,7 @@ describe('Test Dashboard View', () => { .contains('Afterwork') .parent() .find('svg') - .eq(0) + .eq(1) .click(); cy.wait('@getParticipants');