diff --git a/assets/js/party.manage.js b/assets/js/party.manage.js index 9d133657..d75aba81 100644 --- a/assets/js/party.manage.js +++ b/assets/js/party.manage.js @@ -44,6 +44,11 @@ $(document).ready(function () { $('.link_remove_participant').attr('disabled', false); }); + $('#btn_join').click(function (e) { + $('#join-mode').show(); + $('#btn_join').attr('disabled', true); + }); + if (Modernizr.inputtypes.date == true) { $("#intracto_secretsantabundle_updatepartydetailstype_eventdate").click(function (e) { $(this).datepicker({dateFormat: 'dd-mm-yy'}); diff --git a/src/Controller/Participant/JoinController.php b/src/Controller/Participant/JoinController.php new file mode 100644 index 00000000..1171b3b4 --- /dev/null +++ b/src/Controller/Participant/JoinController.php @@ -0,0 +1,64 @@ +findOneBy(['joinurl' => $joinurl, 'joinmode' => 1, 'created' => 0]); + + if (null !== $party) { + $addParticipantForm = $this->createForm(AddParticipantType::class, new Participant(), [ + 'action' => $this->generateUrl('join_party', ['joinurl' => $party->getJoinurl()]), + ]); + $addParticipantForm->handleRequest($request); + + if ($addParticipantForm->isSubmitted() && $addParticipantForm->isValid()) { + /** @var Participant $newParticipant */ + $newParticipant = $addParticipantForm->getData(); + $newParticipant->setParty($party); + $this->getDoctrine()->getManager()->persist($newParticipant); + $this->getDoctrine()->getManager()->flush(); + + return $this->redirectToRoute('join_party_joined', ['joinurl' => $party->getJoinurl()]); + } + } + + return [ + 'party' => $party, + 'form' => isset($addParticipantForm) ? $addParticipantForm->createView() : null, + ]; + } + + /** + * @Route("/joined/{joinurl}", name="join_party_joined") + * @Template("Participant/show/join.html.twig") + */ + public function joinedAction(string $joinurl, PartyRepository $partyRepository) + { + /** @var Party $party */ + $party = $partyRepository->findOneBy(['joinurl' => $joinurl, 'joinmode' => 1, 'created' => 0]); + + return [ + 'party' => $party, + 'form' => null, + ]; + } +} diff --git a/src/Controller/Party/ManagementController.php b/src/Controller/Party/ManagementController.php index b9cad72e..574082be 100644 --- a/src/Controller/Party/ManagementController.php +++ b/src/Controller/Party/ManagementController.php @@ -6,6 +6,7 @@ use App\Entity\Party; use App\Form\Handler\AddParticipantFormHandler; +use App\Form\Type\SetJoinModeType; use App\Mailer\MailerService; use App\Service\PartyService; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; @@ -50,6 +51,9 @@ public function validAction(Party $party, Form $excludeForm = null) $updatePartyDetailsForm = $this->createForm(UpdatePartyDetailsType::class, $party, [ 'action' => $this->generateUrl('party_manage_update', ['listurl' => $party->getListurl()]), ]); + $setJoinModeForm = $this->createForm(SetJoinModeType::class, $party, [ + 'action' => $this->generateUrl('party_manage_joinmode', ['listurl' => $party->getListurl()]), + ]); if ($excludeForm === null) { $excludeForm = $this->createForm(PartyExcludeParticipantType::class, $party, [ @@ -64,6 +68,7 @@ public function validAction(Party $party, Form $excludeForm = null) 'delete_party_csrf_token' => $this->get('security.csrf.token_manager')->getToken('delete_party'), 'delete_participant_csrf_token' => $this->get('security.csrf.token_manager')->getToken('delete_participant'), 'excludeForm' => $excludeForm->createView(), + 'setJoinModeForm' => $setJoinModeForm->createView(), ]; } @@ -144,4 +149,30 @@ public function excludeAction(Request $request, Party $party) return $this->redirectToRoute('party_manage', ['listurl' => $party->getListurl()]); } + + /** + * @Route("/manage/joinmode/{listurl}", name="party_manage_joinmode", methods={"POST"}) + */ + public function joinModeAction(Request $request, Party $party) + { + $party->setConfirmed(true); + $setJoinModeForm = $this->createForm(SetJoinModeType::class, $party, []); + $setJoinModeForm->handleRequest($request); + + if ($setJoinModeForm->isSubmitted() && $setJoinModeForm->isValid()) { + if (($party->getJoinmode() == 1 && $party->getJoinurl() === null) || $request->request->get('reset', 0) == '1') { + // generate join URL + $party->setJoinurl(base_convert(sha1(uniqid((string) mt_rand(), true)), 16, 36)); + } + + $this->getDoctrine()->getManager()->persist($party); + $this->getDoctrine()->getManager()->flush(); + + $this->addFlash('success', $this->translator->trans('flashes.management.join_mode.success')); + } else { + $this->addFlash('danger', $this->translator->trans('flashes.management.join_mode.danger')); + } + + return $this->redirectToRoute('party_manage', ['listurl' => $party->getListurl()]); + } } diff --git a/src/Entity/Party.php b/src/Entity/Party.php index daaf9711..0a4f5cff 100644 --- a/src/Entity/Party.php +++ b/src/Entity/Party.php @@ -68,6 +68,12 @@ class Party */ private $confirmed; + /** @var ?string */ + private $joinurl; + + /** @var int */ + private $joinmode = 0; + public function __construct($createDefaults = true) { $this->participants = new ArrayCollection(); @@ -81,6 +87,7 @@ public function __construct($createDefaults = true) $this->creationdate = new \DateTime(); $this->message = ''; $this->location = ''; + $this->joinurl = base_convert(sha1(uniqid((string) mt_rand(), true)), 16, 36); } /** @@ -292,6 +299,26 @@ public function setConfirmed(bool $confirmed) $this->confirmed = (string) $confirmed; } + public function getJoinurl(): ?string + { + return $this->joinurl; + } + + public function setJoinurl(?string $joinurl): void + { + $this->joinurl = $joinurl; + } + + public function getJoinmode(): int + { + return $this->joinmode; + } + + public function setJoinmode(int $joinmode): void + { + $this->joinmode = $joinmode; + } + /** * @return array */ diff --git a/src/Form/Handler/JoinParticipantFormHandler.php b/src/Form/Handler/JoinParticipantFormHandler.php new file mode 100644 index 00000000..662bdd27 --- /dev/null +++ b/src/Form/Handler/JoinParticipantFormHandler.php @@ -0,0 +1,50 @@ +translator = $translator; + $this->session = $session; + $this->em = $em; + } + + public function handle(FormInterface $form, Request $request, Party $party): void + { + /** @var Participant $newParticipant */ + $newParticipant = $form->getData(); + + if (!$request->isMethod('POST')) { + return; + } + + if (!$form->handleRequest($request)->isValid()) { + $this->session->getFlashBag()->add('danger', $this->translator->trans('flashes.management.add_participant.danger')); + + return; + } + + $newParticipant->setParty($party); + + $this->em->persist($newParticipant); + $this->em->flush(); + + $this->session->getFlashBag()->add('success', $this->translator->trans('flashes.management.add_participant.success')); + } +} diff --git a/src/Form/Type/SetJoinModeType.php b/src/Form/Type/SetJoinModeType.php new file mode 100644 index 00000000..def6136d --- /dev/null +++ b/src/Form/Type/SetJoinModeType.php @@ -0,0 +1,35 @@ +add( + 'join_mode', + ChoiceType::class, + [ + 'attr' => ['data-hj-masked' => ''], + 'choices' => ['party_manage_valid.join_mode.mode.no' => '0', 'party_manage_valid.join_mode.mode.yes' => '1'], + 'expanded' => true, + 'multiple' => false, + ] + ) + ; + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => Party::class, + ]); + } +} diff --git a/src/ORM/Mapping/Party.orm.xml b/src/ORM/Mapping/Party.orm.xml index f50bf4de..c5068cf4 100644 --- a/src/ORM/Mapping/Party.orm.xml +++ b/src/ORM/Mapping/Party.orm.xml @@ -34,6 +34,9 @@ + + + diff --git a/templates/Participant/show/join.html.twig b/templates/Participant/show/join.html.twig new file mode 100644 index 00000000..a43957e1 --- /dev/null +++ b/templates/Participant/show/join.html.twig @@ -0,0 +1,66 @@ +{% extends "Participant/show/base.html.twig" %} + +{% block main %} +
+
+
+

{{ 'party_join.title'|trans }}

+ + {% if party is not null %} + + {{ 'party_join.description'|trans|raw }} + + {% if form is null %} +
+ {{ 'party_join.joined'|trans|raw }} +
+ {% endif %} + +
+

{{ 'participant_show_base.headers.title'|trans|raw }}

+
+
    +
  • {{ 'participant_show_base.headers.date'|trans }}: {{ party.eventdate|format_datetime('medium', 'none') }}
  • +
  • {{ 'participant_show_base.headers.location'|trans }}: {{ party.location }}
  • +
  • {{ 'participant_show_base.headers.amount'|trans }}: {{ party.amount }}
  • +
  • {{ 'participant_show_base.headers.person_created_list'|trans }}: {{ party.participants|first.name }} ({{ party.participants|first.email }}) +
+
+
+ + {% if form is not null %} + {{ form_start(form) }} + {{ form_row(form._token) }} +
+ {{ 'party_manage_valid.label.name'|trans }} {{ form_widget(form.name ,{'attr':{'class':'form-control'}}) }} + {% if form_errors(form.name) %} + {% for error in form.name.vars.errors %} + {{ error.message }}
+ {% endfor %} + {% endif %} +
+
+ {{ 'party_manage_valid.label.email'|trans }} {{ form_widget(form.email ,{'attr':{'class':'form-control'}}) }} + {% if form_errors(form.email) %} + {% for error in form.email.vars.errors %} + {{ error.message }}
+ {% endfor %} + {% endif %} +
+ + + {{ form_end(form) }} + {% endif %} + {% else %} +
+ {{ 'party_join.invalid'|trans|raw }} +
+ {% endif %} + +
+
+ +
+ +{% endblock %} diff --git a/templates/Party/manage/valid.html.twig b/templates/Party/manage/valid.html.twig index 2cb032c6..1527d8c7 100644 --- a/templates/Party/manage/valid.html.twig +++ b/templates/Party/manage/valid.html.twig @@ -109,6 +109,9 @@ {% if (form_errors(addParticipantForm.name)) or (form_errors(addParticipantForm.email)) %}disabled{% endif %}> {{ 'party_manage_valid.btn.add_participant'|trans|raw }} +
{{ 'party_manage_valid.label.name'|trans }} {{ form_widget(addParticipantForm.name ,{'attr':{'class':'form-control'}}) }} - {% if form_errors(addParticipantForm.name) %}addParticipantForm + {% if form_errors(addParticipantForm.name) %} {% for error in addParticipantForm.name.vars.errors %} {{ error.message }}
{% endfor %} @@ -160,6 +163,36 @@
+
+ {% if party.created %}
diff --git a/translations/messages.en.yml b/translations/messages.en.yml index 7a6904a3..86623601 100644 --- a/translations/messages.en.yml +++ b/translations/messages.en.yml @@ -416,6 +416,21 @@ party_manage_valid: Your participants will be notified of these changes immediately.

+ join_mode: + title: Join by link settings + body: > +

+ Instead of manually adding people, you can allow people to join your party by sharing a link. +
When you start the party, people aren't able to join anymore (but you can still add them manually). +

+ mode: + no: No, do not allow people to join by link + yes: Yes, allow anyone with the link to join my party + reset_body: > + By checking this checkbox, a new link will be generated. People will not be able to join with the old link anymore. + Use this when the current link has been shared with people that are not supposed to be able to join. + reset_unset: Enable join by link to generate a link. + btn: add_participant: Add participant to party add_participant_confirm: Add this participant @@ -428,6 +443,8 @@ party_manage_valid: remove_participant_confirm: Remove this participant updated_party: Update your party details start_party: Start your party + join_mode: Join by link + join_mode_confirm: Set join mode label: name: Name @@ -435,6 +452,9 @@ party_manage_valid: confirmed: Email status wishlist_filled: Wish List Entered actions: Actions + join_mode: Allow join by link + join_url: Share this URL with your friends + reset: Reset join URL excludes: title: Exclude certain combinations @@ -447,6 +467,34 @@ party_manage_valid: name: Name exclude: Exclude +party_join: + title: Join the party! + description: > +

+ With the link you were given, you can add yourself to this Secret Santa party! + Please review the party details below, and fill out the form if you want to participate. + If you have questions regarding the party, please contact the person who created this party. +

+ joined: > +

+ We have added you to the party! +
Note that you will not receive your match until the party is started. + If you have any questions regarding the party or want to change your info, you must contact the person who created this party! +

+ invalid: > +

+ The link you have used is not valid. There could be several reasons for this +

    +
  • The party does not exists, or has been deleted.
  • +
  • The creator of the party has disabled or reset the link.
  • +
  • The party has already been started.
  • +
+ Please contact the person that sent you the link. He or she might still be able to add you to the party manually! +

+ + btn: + join_confirm: Join party + # Emails/baseEmail.html.twig emails-base_email: sender: Santa Claus @@ -686,6 +734,9 @@ flashes: add_participant: success:

Added!

Participant successfully added to your party. danger:

Oops

An error occurred while adding the participant. Please try again. + join_mode: + success:

Updated!

The join by link settings have been successfully updated. + danger:

Oops

An error has occurred while updating the join by link settings. Please try again. updated_party: success:

Updated!

Your party details have been successfully updated. danger:

Oops

An error has occurred while updating your party. Please try again.