mail-account-admin/src/Frontend/Accounts/AccountHandler.php

221 lines
7.6 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
namespace MailAccountAdmin\Frontend\Accounts;
use MailAccountAdmin\Common\PasswordHelper;
use MailAccountAdmin\Exceptions\AccountNotFoundException;
use MailAccountAdmin\Exceptions\InputValidationError;
use MailAccountAdmin\Repositories\AccountRepository;
use MailAccountAdmin\Repositories\AliasRepository;
use MailAccountAdmin\Repositories\DomainRepository;
class AccountHandler
{
2021-09-12 21:33:35 +02:00
private AccountRepository $accountRepository;
private AliasRepository $aliasRepository;
private DomainRepository $domainRepository;
2021-09-12 21:33:35 +02:00
private PasswordHelper $passwordHelper;
public function __construct(AccountRepository $accountRepository, AliasRepository $aliasRepository, DomainRepository $domainRepository,
PasswordHelper $passwordHelper)
{
$this->accountRepository = $accountRepository;
$this->aliasRepository = $aliasRepository;
$this->domainRepository = $domainRepository;
$this->passwordHelper = $passwordHelper;
}
// -- /accounts - List all accounts
public function listAccounts(string $filterByDomain): array
{
$accountList = $this->accountRepository->fetchAccountList($filterByDomain);
return [
'filterDomain' => $filterByDomain,
'accountList' => $accountList,
];
}
// -- /accounts/{id} - Show account details
public function getAccountDetails(int $accountId): array
{
// Get account data from database
$account = $this->accountRepository->fetchAccountById($accountId);
// Don't display the password hash, but at least the type of hash (used hash algorithm)
$passwordHashType = $this->passwordHelper->getPasswordHashType($account->getPasswordHash());
// Get list of aliases for this account
$aliases = $this->aliasRepository->fetchAliasesForUserId($accountId);
return [
'id' => $accountId,
'accountUsername' => $account->getUsername(),
'account' => $account,
'passwordHashType' => $passwordHashType,
'aliases' => $aliases,
];
}
// -- /accounts/new - Create new account
public function getPageDataForCreate(): array
{
return [
'domainList' => array_keys($this->domainRepository->fetchDomainList()),
];
}
public function createNewAccount(AccountCreateData $createData): int
{
// Check if new username is still available
$username = $createData->getUsername();
if (!$this->accountRepository->checkUsernameAvailable($username) || !$this->aliasRepository->checkAliasAvailable($username)) {
throw new InputValidationError("Username \"$username\" is not available.");
}
// Hash new password
$passwordHash = $this->passwordHelper->hashPassword($createData->getPassword());
// Construct home directory from username if necessary
if ($createData->getHomeDir() !== null) {
$homeDir = $createData->getHomeDir();
} else {
[$localPart, $domainPart] = explode('@', $username, 2);
$homeDir = $domainPart . '/' . $localPart;
}
// Create account in database
return $this->accountRepository->insertAccount(
$username,
$passwordHash,
$createData->getActive(),
$homeDir,
$createData->getMemo()
);
}
// -- /accounts/{id}/edit - Edit account data
2021-09-12 22:16:06 +02:00
public function getAccountDataForEdit(int $accountId): array
{
// Get account data from database
$account = $this->accountRepository->fetchAccountById($accountId);
return [
'id' => $accountId,
'accountUsername' => $account->getUsername(),
'account' => $account,
];
}
public function editAccountData(int $accountId, AccountEditData $editData): void
{
// Check if account exists
try {
$account = $this->accountRepository->fetchAccountById($accountId);
} catch (AccountNotFoundException $e) {
throw new InputValidationError('Account with ID ' . $accountId . ' does not exist!');
}
$newUsername = $editData->getUsername();
if ($newUsername === $account->getUsername()) {
// Username is unchanged
$newUsername = null;
}
// This variable will be set to true if the user wants to change their username, has an existing alias with this username,
// and checked the "replace existing alias" option.
$aliasNeedsToBeReplaced = false;
// Check if new username is still available
if ($newUsername !== null) {
$newUsernameAvailable = true;
// Check if account with this username already exists
if (!$this->accountRepository->checkUsernameAvailable($newUsername)) {
$newUsernameAvailable = false;
}
// Check if alias with this username/address already exists
if (!$this->aliasRepository->checkAliasAvailable($newUsername)) {
$newUsernameAvailable = false;
// Alias already exists. If user wants to replace an existing alias, check if the alias belongs to this user.
if ($editData->getUsernameReplaceAlias()) {
$existingAlias = $this->aliasRepository->fetchAliasByAddress($newUsername);
if ($existingAlias->getUserId() === $accountId) {
$aliasNeedsToBeReplaced = true;
$newUsernameAvailable = true;
}
}
}
if (!$newUsernameAvailable) {
throw new InputValidationError("Username \"$newUsername\" is not available.");
}
}
// Start database transaction
$this->accountRepository->beginTransaction();
// Create alias for old username (if wanted)
if ($editData->getUsernameCreateAlias()) {
$oldUsername = $account->getUsername();
if (!$this->aliasRepository->checkAliasAvailable($oldUsername)) {
throw new InputValidationError("Alias \"$oldUsername\" cannot be created: Alias already exists.");
}
$this->aliasRepository->createNewAlias($accountId, $oldUsername);
}
// Hash new password
$newPasswordHash = null;
if ($editData->getPassword() !== null) {
$newPasswordHash = $this->passwordHelper->hashPassword($editData->getPassword());
}
// Update account in database
$this->accountRepository->updateAccountWithId(
$accountId,
$newUsername,
$newPasswordHash,
$editData->getActive(),
$editData->getHomeDir(),
$editData->getMemo()
);
// Remove existing alias for new username (if wanted)
if ($editData->getUsernameReplaceAlias() && $aliasNeedsToBeReplaced) {
$this->aliasRepository->removeAlias($accountId, $newUsername);
}
// Commit database transaction
$this->accountRepository->commitTransaction();
}
2021-09-12 22:16:06 +02:00
// -- /accounts/{id}/delete - Delete account
public function getAccountDataForDelete(int $accountId): array
{
// Get account data from database
$account = $this->accountRepository->fetchAccountById($accountId);
// Get list of aliases for this account
$aliases = $this->aliasRepository->fetchAliasesForUserId($accountId);
return [
'id' => $accountId,
'accountUsername' => $account->getUsername(),
'aliases' => $aliases,
];
}
}