diff --git a/public/static/style.css b/public/static/style.css index 6064a86..ba29d51 100644 --- a/public/static/style.css +++ b/public/static/style.css @@ -123,6 +123,11 @@ button { color: gray; } +.margin_vertical_1rem { + margin-top: 1rem; + margin-bottom: 1rem; +} + /* -- Tables -- */ table td, table th { diff --git a/src/Common/FormData.php b/src/Common/FormData.php index 24eaf68..2756aba 100644 --- a/src/Common/FormData.php +++ b/src/Common/FormData.php @@ -34,22 +34,27 @@ abstract class FormData // Input validation - Application specific validators - protected static function validateUsername(string $username, bool $required = true): ?string + protected static function validateUsername(string $username, bool $required = true, string $fieldName = 'Username'): ?string { if (!$required && $username === '') { return null; } $username = strtolower( - self::validateString($username, 3, 100, 'Username') + self::validateString($username, 3, 100, $fieldName) ); if (!preg_match('/^[a-z0-9._+-]+@[a-z0-9.-]+$/', $username) || preg_match('/^\\.|\\.\\.|\\.@|@\\.|\\.$/', $username)) { - throw new InputValidationError('Username is not valid (must be a valid mail address).'); + throw new InputValidationError("$fieldName is not valid (must be a valid mail address)."); } return $username; } + protected static function validateAliasAddress(string $aliasAddress): string + { + return self::validateUsername($aliasAddress, true, 'Alias address'); + } + protected static function validatePassword(string $password, string $passwordRepeat, bool $required = true): ?string { if (!$required && $password === '' && $passwordRepeat === '') { diff --git a/src/Frontend/Accounts/AccountAddAliasData.php b/src/Frontend/Accounts/AccountAddAliasData.php new file mode 100644 index 0000000..306ca90 --- /dev/null +++ b/src/Frontend/Accounts/AccountAddAliasData.php @@ -0,0 +1,28 @@ +aliasAddress = $aliasAddress; + } + + public static function createFromArray($raw): self + { + return new self( + self::validateAliasAddress(trim($raw['alias_address'] ?? '')), + ); + } + + public function getAliasAddress(): string + { + return $this->aliasAddress; + } +} diff --git a/src/Frontend/Accounts/AccountController.php b/src/Frontend/Accounts/AccountController.php index 4a6e268..1f9d6ac 100644 --- a/src/Frontend/Accounts/AccountController.php +++ b/src/Frontend/Accounts/AccountController.php @@ -64,6 +64,9 @@ class AccountController extends BaseController return $this->showAccount404($response, $accountId); } + // If the "add alias" form has been submitted, add the result message to the render data array + $renderData = $this->addLastActionResultToRenderData($renderData); + return $this->view->render($response, 'account_details.html.twig', $renderData); } @@ -210,4 +213,30 @@ class AccountController extends BaseController // Redirect to edit form page via GET (PRG) return $response->withHeader('Location', $redirectTarget)->withStatus(303); } + + + // -- /accounts/{id}/addalias - Create a new alias for the account + + public function addAliasToAccount(Request $request, Response $response, array $args): Response + { + // Parse URL arguments and form data + $accountId = (int)$args['id']; + $addAliasData = $request->getParsedBody(); + + try { + // Validate input + $validatedAddAliasData = AccountAddAliasData::createFromArray($addAliasData); + $this->accountHandler->addAliasToAccount($accountId, $validatedAddAliasData); + + // Save success result + $successMessage = "Alias {$validatedAddAliasData->getAliasAddress()} was added."; + $this->sessionHelper->setLastActionResult(ActionResult::createSuccessResult($successMessage)); + } catch (InputValidationError $e) { + // Save error result + $this->sessionHelper->setLastActionResult(ActionResult::createErrorResult($e->getMessage(), $addAliasData)); + } + + // Redirect to edit form page via GET (PRG) + return $response->withHeader('Location', '/accounts/' . $accountId)->withStatus(303); + } } diff --git a/src/Frontend/Accounts/AccountHandler.php b/src/Frontend/Accounts/AccountHandler.php index 0556e6a..32dce32 100644 --- a/src/Frontend/Accounts/AccountHandler.php +++ b/src/Frontend/Accounts/AccountHandler.php @@ -265,4 +265,26 @@ class AccountHandler 'deleted_alias_count' => $deleteAliasCount, ]; } + + + // -- /accounts/{id}/addalias - Create a new alias for the account + + public function addAliasToAccount(int $accountId, AccountAddAliasData $aliasAddData): void + { + // Check if account exists + try { + $this->accountRepository->fetchAccountById($accountId); + } catch (AccountNotFoundException $e) { + throw new InputValidationError('Account with ID ' . $accountId . ' does not exist!'); + } + + // Check if alias address is still available + $address = $aliasAddData->getAliasAddress(); + if (!$this->accountRepository->checkUsernameAvailable($address) || !$this->aliasRepository->checkAliasAvailable($address)) { + throw new InputValidationError("Alias address \"$address\" is not available."); + } + + // Create alias in database + $this->aliasRepository->createNewAlias($accountId, $address); + } } diff --git a/src/Routes.php b/src/Routes.php index 62faebd..00611ab 100644 --- a/src/Routes.php +++ b/src/Routes.php @@ -33,5 +33,6 @@ class Routes $app->post('/accounts/{id:[1-9][0-9]*}/edit', AccountController::class . ':editAccount'); $app->get('/accounts/{id:[1-9][0-9]*}/delete', AccountController::class . ':showAccountDelete'); $app->post('/accounts/{id:[1-9][0-9]*}/delete', AccountController::class . ':deleteAccount'); + $app->post('/accounts/{id:[1-9][0-9]*}/addalias', AccountController::class . ':addAliasToAccount'); } } diff --git a/templates/account_details.html.twig b/templates/account_details.html.twig index 5021452..4e00c14 100644 --- a/templates/account_details.html.twig +++ b/templates/account_details.html.twig @@ -82,4 +82,20 @@ {% else %}

No aliases.

{% endif %} + +
+ {{ include('includes/form_result_box.html.twig') }} + + + + + + + + + +
+ +
+
{% endblock %}