engelsystem/src/Controllers/RegistrationController.php

199 lines
7.3 KiB
PHP

<?php
declare(strict_types=1);
namespace Engelsystem\Controllers;
use Engelsystem\Config\Config;
use Engelsystem\Config\GoodieType;
use Engelsystem\Events\Listener\OAuth2;
use Engelsystem\Factories\User;
use Engelsystem\Helpers\Authenticator;
use Engelsystem\Http\Redirector;
use Engelsystem\Http\Request;
use Engelsystem\Http\Response;
use Engelsystem\Models\AngelType;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
class RegistrationController extends BaseController
{
use HasUserNotifications;
public function __construct(
private Config $config,
private Response $response,
private Redirector $redirect,
private SessionInterface $session,
private Authenticator $auth,
private OAuth2 $oAuth,
private User $userFactory
) {
}
public function view(): Response
{
if ($this->determineRegistrationDisabled()) {
return $this->notifySignUpDisabledAndRedirectToHome();
}
return $this->renderSignUpPage();
}
public function save(Request $request): Response
{
if ($this->determineRegistrationDisabled()) {
return $this->notifySignUpDisabledAndRedirectToHome();
}
$rawData = $request->getParsedBody();
$user = $this->userFactory->createFromData($rawData);
$this->addNotification('registration.successful');
if ($this->config->get('welcome_msg')) {
// Set a session marker to display the welcome message on the next page
$this->session->set('show_welcome', true);
}
if ($user->oauth?->count() > 0) {
// User has OAuth configured. Log in directly.
$provider = $user->oauth->first();
return $this->redirect->to('/oauth/' . $provider->provider);
}
if ($this->auth->user()) {
// User is already logged in - that means a supporter has registered an angel. Return to register page.
return $this->redirect->to('/register');
}
return $this->redirect->to('/');
}
private function notifySignUpDisabledAndRedirectToHome(): Response
{
$this->addNotification('registration.disabled', NotificationType::INFORMATION);
return $this->redirect->to('/');
}
private function renderSignUpPage(): Response
{
$goodieType = GoodieType::from($this->config->get('goodie_type'));
$preselectedAngelTypes = $this->determinePreselectedAngelTypes();
$requiredFields = $this->config->get('required_user_fields');
// form-data-register-submit is a marker, that the form was submitted.
// It will be used for instance to use the default angel types or the user selected ones.
// Clear it before render to reset the marker state.
$this->session->remove('form-data-register-submit');
return $this->response->withView(
'pages/registration',
[
'minPasswordLength' => $this->config->get('min_password_length'),
'tShirtSizes' => $this->config->get('tshirt_sizes'),
'angelTypes' => AngelType::whereHideRegister(false)->get(),
'preselectedAngelTypes' => $preselectedAngelTypes,
'buildUpStartDate' => $this->userFactory->determineBuildUpStartDate()->format('Y-m-d'),
'tearDownEndDate' => $this->config->get('teardown_end')?->format('Y-m-d'),
'isPasswordEnabled' => $this->userFactory->determineIsPasswordEnabled(),
'isDECTEnabled' => $this->config->get('enable_dect'),
'isShowMobileEnabled' => $this->config->get('enable_mobile_show'),
'isGoodieEnabled' => $goodieType !== GoodieType::None,
'isGoodieTShirt' => $goodieType === GoodieType::Tshirt,
'isPronounEnabled' => $this->config->get('enable_pronoun'),
'isFullNameEnabled' => $this->config->get('enable_user_name'),
'isPlannedArrivalDateEnabled' => $this->config->get('enable_planned_arrival'),
'isPronounRequired' => $requiredFields['pronoun'],
'isFirstnameRequired' => $requiredFields['firstname'],
'isLastnameRequired' => $requiredFields['lastname'],
'isTShirtSizeRequired' => $requiredFields['tshirt_size'],
'isMobileRequired' => $requiredFields['mobile'],
'isDectRequired' => $requiredFields['dect'],
],
);
}
/**
* @return Array<string, 1> Checkbox field name/Id → 1
*/
private function determinePreselectedAngelTypes(): array
{
if ($this->session->has('form-data-register-submit')) {
// form-data-register-submit means a user just submitted the page.
// Preselect the angel types from the persisted session form data.
return $this->loadAngelTypesFromSessionFormData();
}
$preselectedAngelTypes = [];
if ($this->session->has('oauth2_connect_provider')) {
$preselectedAngelTypes = $this->loadAngelTypesFromSessionOAuthGroups();
}
foreach (AngelType::whereRestricted(false)->whereHideRegister(false)->get() as $angelType) {
// preselect every angel type without restriction
$preselectedAngelTypes['angel_types_' . $angelType->id] = 1;
}
return $preselectedAngelTypes;
}
/**
* @return Array<string, 1>
*/
private function loadAngelTypesFromSessionOAuthGroups(): array
{
$oAuthAngelTypes = [];
$ssoTeams = $this->oAuth->getSsoTeams($this->session->get('oauth2_connect_provider'));
$oAuth2Groups = $this->session->get('oauth2_groups');
foreach ($ssoTeams as $name => $team) {
if (in_array($name, $oAuth2Groups)) {
// preselect angel type from oauth
$oAuthAngelTypes['angel_types_' . $team['id']] = 1;
}
}
return $oAuthAngelTypes;
}
/**
* @return Array<string, 1>
*/
private function loadAngelTypesFromSessionFormData(): array
{
$angelTypes = AngelType::whereHideRegister(false)->get();
$selectedAngelTypes = [];
foreach ($angelTypes as $angelType) {
$sessionKey = 'form-data-angel_types_' . $angelType->id;
if ($this->session->has($sessionKey)) {
$selectedAngelTypes['angel_types_' . $angelType->id] = 1;
// remove from session so that it doesn't stay there forever
$this->session->remove($sessionKey);
}
}
return $selectedAngelTypes;
}
private function determineRegistrationDisabled(): bool
{
$authUser = $this->auth->user();
$isOAuth = $this->session->get('oauth2_connect_provider');
$isPasswordEnabled = $this->userFactory->determineIsPasswordEnabled();
return !auth()->can('register') // No registration permission
// Not authenticated and
// Registration disabled
|| (
!$authUser
&& !$this->config->get('registration_enabled')
&& !$this->session->get('oauth2_allow_registration')
)
// Password disabled and not oauth
|| (!$authUser && !$isPasswordEnabled && !$isOAuth);
}
}