Skip to content

Commit

Permalink
Merge 1.x into main (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
fritzmg authored Jul 6, 2024
1 parent a6ed880 commit 88e2f88
Show file tree
Hide file tree
Showing 24 changed files with 305 additions and 25 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ After installation you will have the possibility to enable registration for indi
- **End of registraton**: You can define an optional date after which registration will not be possible anymore.
- **End of cancellation**: You cand efine an optional date after which cancellation will not be possible anymore.
- **Require confirmation**: When enabled, only confirmed registrations count towards the total number of registrations.
- **Enable waiting list**: Keeps the registration open after the maximum amount of participants is reached. All registrations will be put on a waiting list and will automatically be advanced, if prior registrations are cancelled.
- **Advancement from waiting list notification**: This notification will be sent when a participant is advanced from the waiting list.


### Modules
Expand Down Expand Up @@ -63,6 +65,7 @@ The following template variables are available in event templates as well as the
- `$this->canRegister`: Whether registration is possible for this event.
- `$this->registrationForm`: Contains the registration form.
- `$this->isFull`: Whether the maximum amount of registrations have been reached for this event.
- `$this->isWaitingList`: Whether the maximum amount of registrations have been reached for this event and waiting list is enabled.
- `$this->registrationCount`: The current registration count for this event.
- `$this->reg_min`: The minimum amount of registrations for this event.
- `$this->reg_max`: The maximum amount of registrations for this event.
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"symfony/dependency-injection": "^5.4 || ^6.4 || ^7.1",
"symfony/http-foundation": "^5.4 || ^6.4 || ^7.1",
"symfony/http-kernel": "^5.4 || ^6.4 || ^7.1",
"symfony/lock": "^5.4 || ^6.4 || ^7.1",
"symfony/routing": "^5.4 || ^6.4 || ^7.1",
"symfony/security-core": "^5.4 || ^6.4 || ^7.1",
"symfony/translation": "^5.4 || ^6.4 || ^7.1",
Expand Down
1 change: 1 addition & 0 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ parameters:
- !php/const Terminal42\NotificationCenterBundle\NotificationType\FormGeneratorNotificationType::NAME
- !php/const InspiredMinds\ContaoEventRegistration\NotificationTypes::CONFIRM
- !php/const InspiredMinds\ContaoEventRegistration\NotificationTypes::CANCEL
- !php/const InspiredMinds\ContaoEventRegistration\NotificationTypes::WAITING_LIST_ADVANCEMENT

services:
_defaults:
Expand Down
19 changes: 18 additions & 1 deletion contao/dca/tl_calendar_events.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,25 @@
'sql' => ['type' => 'boolean', 'default' => false],
];

$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['reg_enableWaitingList'] = [
'inputType' => 'checkbox',
'exclude' => true,
'eval' => ['tl_class' => 'clr w50', 'submitOnChange' => true],
'sql' => ['type' => 'boolean', 'default' => false],
];

$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['reg_waitingListAdvancementNotification'] = [
'exclude' => true,
'inputType' => 'select',
'eval' => ['includeBlankOption' => true, 'chosen' => true, 'tl_class' => 'w50'],
'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0],
'relation' => ['type' => 'hasOne', 'load' => 'lazy', 'table' => 'tl_nc_notification'],
];

$GLOBALS['TL_DCA']['tl_calendar_events']['palettes']['__selector__'][] = 'reg_enable';
$GLOBALS['TL_DCA']['tl_calendar_events']['subpalettes']['reg_enable'] = 'reg_form,reg_min,reg_max,reg_regEnd,reg_cancelEnd,reg_requireConfirm';
$GLOBALS['TL_DCA']['tl_calendar_events']['palettes']['__selector__'][] = 'reg_enableWaitingList';
$GLOBALS['TL_DCA']['tl_calendar_events']['subpalettes']['reg_enable'] = 'reg_form,reg_min,reg_max,reg_regEnd,reg_cancelEnd,reg_requireConfirm,reg_enableWaitingList';
$GLOBALS['TL_DCA']['tl_calendar_events']['subpalettes']['reg_enableWaitingList'] = 'reg_waitingListAdvancementNotification';

foreach ($GLOBALS['TL_DCA']['tl_calendar_events']['palettes'] as $name => $palette) {
if (!is_string($palette)) {
Expand Down
8 changes: 7 additions & 1 deletion contao/dca/tl_event_registration.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@
'eval' => ['tl_class' => 'w50'],
'sql' => ['type' => 'boolean', 'default' => false],
],
'waiting' => [
'inputType' => 'checkbox',
'exclude' => true,
'eval' => ['tl_class' => 'w50', 'disabled' => true],
'sql' => ['type' => 'boolean', 'default' => false],
],
'form_data' => [
'inputType' => 'textarea',
'eval' => ['readonly' => true],
Expand All @@ -86,7 +92,7 @@
'sorting' => [
'mode' => 4,
'fields' => ['id'],
'headerFields' => ['title', 'reg_max'],
'headerFields' => ['title', 'reg_max', 'reg_waiting'],
'disableGrouping' => true,
'panelLayout' => 'limit',
],
Expand Down
5 changes: 3 additions & 2 deletions contao/languages/de/tl_nc_notification.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
use InspiredMinds\ContaoEventRegistration\NotificationTypes;

$GLOBALS['TL_LANG']['tl_nc_notification']['type']['event_registration'] = 'Event Registrierung';
$GLOBALS['TL_LANG']['tl_nc_notification']['type'][NotificationTypes::CONFIRM] = ['Event Registration: Registrierung bestätigt', 'Diese Benachrichtigung wird gesendet, wenn eine Registrierung für ein Event bestätigt wurde.'];
$GLOBALS['TL_LANG']['tl_nc_notification']['type'][NotificationTypes::CANCEL] = ['Event Registration: Registrierung storniert', 'Diese Benachrichtigung wird gesendet, wenn eine Registrierung für ein Event storniert wurde.'];
$GLOBALS['TL_LANG']['tl_nc_notification']['type'][NotificationTypes::CONFIRM] = ['Registrierung bestätigen', 'Diese Benachrichtigung wird gesendet, wenn eine Registrierung für ein Event bestätigt wurde.'];
$GLOBALS['TL_LANG']['tl_nc_notification']['type'][NotificationTypes::CANCEL] = ['Registrierung stornieren', 'Diese Benachrichtigung wird gesendet, wenn eine Registrierung für ein Event storniert wurde.'];
$GLOBALS['TL_LANG']['tl_nc_notification']['type'][NotificationTypes::WAITING_LIST_ADVANCEMENT] = ['Aufstieg von Warteliste', 'Diese Benachrichtigung wird gesendet, wenn eine Registrierung von der Warteliste auf die normale Liste kommt.'];
2 changes: 2 additions & 0 deletions contao/languages/en/tl_calendar_events.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@
$GLOBALS['TL_LANG']['tl_calendar_events']['reg_regEnd'] = ['End of registration', 'Specify an optional date for the end of the registration.'];
$GLOBALS['TL_LANG']['tl_calendar_events']['reg_cancelEnd'] = ['End of cancellation', 'Specify an optional date for the end of being able to cancel.'];
$GLOBALS['TL_LANG']['tl_calendar_events']['reg_requireConfirm'] = ['Require confirmation', 'Only confirmed registrations are counted.'];
$GLOBALS['TL_LANG']['tl_calendar_events']['reg_enableWaitingList'] = ['Enable waiting list', 'Enables registrations past the maximum amount of participants.'];
$GLOBALS['TL_LANG']['tl_calendar_events']['reg_waitingListAdvancementNotification'] = ['Advancement from waiting list notification', 'This notification will be sent when a participant is moved from the waiting list to the regular list of active registrations.'];
$GLOBALS['TL_LANG']['tl_calendar_events']['registrations'] = 'Registrations';
1 change: 1 addition & 0 deletions contao/languages/en/tl_event_registration.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@
$GLOBALS['TL_LANG']['tl_event_registration']['amount'] = ['Amount', 'Amount of people for this registration.'];
$GLOBALS['TL_LANG']['tl_event_registration']['confirmed'] = ['Confirmed', 'Whether this registration has been confirmed.'];
$GLOBALS['TL_LANG']['tl_event_registration']['cancelled'] = ['Cancelled', 'Whether this registration has been cancelled.'];
$GLOBALS['TL_LANG']['tl_event_registration']['waiting'] = ['Waiting list', 'Whether this registration is on the waiting list.'];
$GLOBALS['TL_LANG']['tl_event_registration']['form_data'] = ['Form data', 'The form data for this registration.'];
5 changes: 3 additions & 2 deletions contao/languages/en/tl_nc_notification.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
use InspiredMinds\ContaoEventRegistration\NotificationTypes;

$GLOBALS['TL_LANG']['tl_nc_notification']['type']['event_registration'] = 'Event registration';
$GLOBALS['TL_LANG']['tl_nc_notification']['type'][NotificationTypes::CONFIRM] = ['Event Registration: registration confirmed', 'This notification type is sent when an event registration was confirmed.'];
$GLOBALS['TL_LANG']['tl_nc_notification']['type'][NotificationTypes::CANCEL] = ['Event Registration: registration cancelled', 'This notification type is sent when an event registration was cancelled.'];
$GLOBALS['TL_LANG']['tl_nc_notification']['type'][NotificationTypes::CONFIRM] = ['Confirm registration', 'This notification type can be sent when an event registration is confirmed.'];
$GLOBALS['TL_LANG']['tl_nc_notification']['type'][NotificationTypes::CANCEL] = ['Cancel registration', 'This notification type can be sent when an event registration is cancelled.'];
$GLOBALS['TL_LANG']['tl_nc_notification']['type'][NotificationTypes::WAITING_LIST_ADVANCEMENT] = ['Advancement from waiting list', 'This notification type can be sent when an event registration is cancelled.'];
3 changes: 3 additions & 0 deletions contao/templates/mod_event_registration_form.html5
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
<?php if (!$this->canRegister): ?>
<p class="cannot-register"><?= $this->trans('cannot_register', [], 'im_contao_event_registration') ?></p>
<?php else: ?>
<?php if ($this->isWaitingList): ?>
<p class="waiting-list"><?= $this->trans('is_waiting_list', [], 'im_contao_event_registration') ?></p>
<?php endif; ?>
<?= $this->registrationForm ?>
<?php endif; ?>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use Contao\Template;
use InspiredMinds\ContaoEventRegistration\EventRegistration;
use InspiredMinds\ContaoEventRegistration\Model\EventRegistrationModel;
use InspiredMinds\ContaoEventRegistration\WaitingListChecker;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\Translation\TranslatorInterface;
Expand All @@ -43,6 +44,7 @@ public function __construct(
private readonly TranslatorInterface $translator,
private readonly SimpleTokenParser $simpleTokenParser,
private readonly NotificationCenter $notificationCenter,
private readonly WaitingListChecker $waitingListChecker,
) {
}

Expand Down Expand Up @@ -110,5 +112,8 @@ private function processCancel(Template $template, ModuleModel $model, CalendarE
if ($model->nc_notification) {
$this->notificationCenter->sendNotification($model->nc_notification, $tokens);
}

// Process waiting lists
($this->waitingListChecker)($event);
}
}
29 changes: 29 additions & 0 deletions src/Cron/WaitingListsCronJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Contao Event Registration extension.
*
* (c) INSPIRED MINDS
*
* @license LGPL-3.0-or-later
*/

namespace InspiredMinds\ContaoEventRegistration\Cron;

use Contao\CoreBundle\DependencyInjection\Attribute\AsCronJob;
use InspiredMinds\ContaoEventRegistration\WaitingListChecker;

#[AsCronJob('hourly')]
class WaitingListsCronJob
{
public function __construct(private readonly WaitingListChecker $waitingListChecker)
{
}

public function __invoke(): void
{
($this->waitingListChecker)();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public function __invoke(DataContainer $dc): void
->removeField('reg_regEnd')
->removeField('reg_cancelEnd')
->removeField('reg_requireConfirm')
->removeField('reg_enableWaitingList')
->applyToSubPalette('reg_enable', 'tl_calendar_events')
;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Contao Event Registration extension.
*
* (c) INSPIRED MINDS
*
* @license LGPL-3.0-or-later
*/

namespace InspiredMinds\ContaoEventRegistration\EventListener\DataContainer\CalendarEvents;

use Contao\CoreBundle\DependencyInjection\Attribute\AsCallback;
use Doctrine\DBAL\Connection;
use InspiredMinds\ContaoEventRegistration\NotificationTypes;

#[AsCallback('tl_calendar_events', 'fields.reg_waitingListAdvancementNotification.options')]
class WaitingListAdvancementNotificationOptionsCallbackListener
{
public function __construct(private readonly Connection $db)
{
}

public function __invoke(): array
{
return $this->db->fetchAllKeyValue('SELECT id, title FROM tl_nc_notification WHERE type = ? ORDER BY title', [NotificationTypes::WAITING_LIST_ADVANCEMENT]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@
use Contao\Image;
use Contao\StringUtil;
use InspiredMinds\ContaoEventRegistration\EventRegistration\LabelBuilder;
use Symfony\Contracts\Translation\TranslatorInterface;

/**
* @Callback(table="tl_event_registration", target="list.sorting.child_record")
*/
class ChildRecordCallbackListener
{
public function __construct(private readonly LabelBuilder $labelBuilder)
{
public function __construct(
private readonly LabelBuilder $labelBuilder,
private readonly TranslatorInterface $translator,
) {
}

public function __invoke(array $row): string
Expand All @@ -42,14 +45,25 @@ public function __invoke(array $row): string
}

$icon = 'visible_.svg';
$alt = '';
$attributes = ' style="float:left; margin-right:0.3em;"';

if ($row['cancelled']) {
$icon = 'unpublished.svg';
$alt = $this->translator->trans('tl_event_registration.cancelled.0', [], 'contao_tl_event_registration');
} elseif ($row['waiting']) {
$icon = 'news.svg';
$alt = $this->translator->trans('tl_event_registration.waiting.0', [], 'contao_tl_event_registration');
} elseif ($row['confirmed']) {
$icon = 'visible.svg';
$alt = $this->translator->trans('tl_event_registration.confirmed.0', [], 'contao_tl_event_registration');
}

if ($alt) {
$attributes .= ' title="'.$alt.'"';
}

$label = Image::getHtml($icon, '', ' style="float:left; margin-right:0.3em;"').' '.$label;
$label = Image::getHtml($icon, '', $attributes).' '.$label;

return '<div class="tl_content_left">'.$label.'</div>';
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Contao Event Registration extension.
*
* (c) INSPIRED MINDS
*
* @license LGPL-3.0-or-later
*/

namespace InspiredMinds\ContaoEventRegistration\EventListener\DataContainer\EventRegistration;

use Contao\CalendarEventsModel;
use Contao\CoreBundle\DependencyInjection\Attribute\AsCallback;
use Contao\DataContainer;
use InspiredMinds\ContaoEventRegistration\WaitingListChecker;

#[AsCallback('tl_event_registration', 'config.onsubmit')]
class ConfigOnSubmitCallbackListener
{
public function __construct(private readonly WaitingListChecker $waitingListChecker)
{
}

public function __invoke(DataContainer $dc): void
{
if ($event = CalendarEventsModel::findById($dc->activeRecord?->pid)) {
($this->waitingListChecker)($event);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@ public function __construct(
public function __invoke(array $labels, DataContainer $dc): array
{
$event = $this->helper->getMainEvent(CalendarEventsModel::findById($dc->id));
$label = $this->helper->getRegistrationCount($event);
$count = $this->helper->getRegistrationCount($event, true);
$waiting = $this->helper->getRegistrationCount($event) - $count;

$labels[$this->trans->trans('header_count_title', [], 'im_contao_event_registration')] = $label;
$labels[$this->trans->trans('header_count_title', [], 'im_contao_event_registration')] = $count;
$labels[$this->trans->trans('header_waiting_title', [], 'im_contao_event_registration')] = $waiting;

return $labels;
}
Expand Down
36 changes: 25 additions & 11 deletions src/EventListener/EventRegistrationFormListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
use Contao\FrontendUser;
use InspiredMinds\ContaoEventRegistration\EventRegistration;
use InspiredMinds\ContaoEventRegistration\Model\EventRegistrationModel;
use InspiredMinds\ContaoEventRegistration\WaitingListChecker;
use Ramsey\Uuid\Uuid;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Lock\LockFactory;
use Symfony\Contracts\Translation\TranslatorInterface;

/**
Expand All @@ -34,6 +36,7 @@ public function __construct(
private readonly EventRegistration $eventRegistration,
private readonly TokenStorageInterface $tokenStorage,
private readonly TranslatorInterface $translator,
private readonly LockFactory $lockFactory,
) {
}

Expand All @@ -49,17 +52,28 @@ public function __invoke(array &$submittedData, array $formData, array|null $fil
return;
}

$registration = new EventRegistrationModel();
$registration->pid = (int) $event->id;
$registration->created = time();
$registration->tstamp = time();
$registration->uuid = Uuid::uuid4()->toString();
$registration->form = (int) $form->id;
$registration->member = (int) $this->getMember()?->id ?? 0;
$registration->amount = max(1, (int) ($submittedData['amount'] ?? 1));
$registration->form_data = json_encode($submittedData, JSON_THROW_ON_ERROR);

$registration->save();
$lock = $this->lockFactory->createLock(WaitingListChecker::class);
$lock->acquire(true);

try {
$amount = max(1, (int) ($submittedData['amount'] ?? 1));
$waiting = $this->eventRegistration->getRegistrationCount($event, true) + $amount > $event->reg_max;

$registration = new EventRegistrationModel();
$registration->pid = (int) $event->id;
$registration->created = time();
$registration->tstamp = time();
$registration->uuid = Uuid::uuid4()->toString();
$registration->form = (int) $form->id;
$registration->member = (int) $this->getMember()?->id ?? 0;
$registration->amount = $amount;
$registration->waiting = $waiting;
$registration->form_data = json_encode($submittedData, JSON_THROW_ON_ERROR);

$registration->save();
} finally {
$lock->release();
}

// Inject event registration UUID
$t = EventRegistrationModel::getTable();
Expand Down
Loading

0 comments on commit 88e2f88

Please sign in to comment.