first commit

This commit is contained in:
salam committed 2026-10-06 19:40:28 +02:00
commit e81864e683
2984 files changed
+267797

No files matched your search

@@ -0,0 +1,111 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Model;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
/**
* Class Log
*/
class Log extends AbstractEntity
{
const STATUS_NEWREGISTRATION = 101;
const STATUS_REGISTRATIONCONFIRMEDUSER = 102;
const STATUS_REGISTRATIONCONFIRMEDADMIN = 103;
const STATUS_REGISTRATIONREFUSEDUSER = 104;
const STATUS_REGISTRATIONREFUSEDADMIN = 105;
const STATUS_PROFILECREATIONREQUEST = 106;
const STATUS_PROFILEUPDATED = 201;
const STATUS_PROFILEUPDATECONFIRMEDADMIN = 202;
const STATUS_PROFILEUPDATEREFUSEDADMIN = 203;
const STATUS_PROFILEUPDATEREQUEST = 204;
const STATUS_PROFILEUPDATEREFUSEDSECURITY = 205;
const STATUS_PROFILEUPDATEIMAGEDELETE = 206;
const STATUS_PROFILEUPDATEATTEMPTEDSPOOF = 207;
const STATUS_PROFILEDELETE = 301;
const STATUS_INVITATIONPROFILECREATED = 401;
const STATUS_INVITATIONPROFILEDELETEDUSER = 402;
const STATUS_INVITATIONHASHERROR = 403;
const STATUS_INVITATIONRESTRICTEDPAGE = 404;
const STATUS_INVITATIONPROFILEENABLED = 405;
/**
* title
*
* @var string
*/
protected $title;
/**
* state
*
* @var int
*/
protected $state;
/**
* user
*
* @var User
*/
protected $user;
/**
* @param string $title
* @return Log
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* @param int $state
* @return Log
*/
public function setState($state)
{
$this->state = $state;
return $this;
}
/**
* @return int
*/
public function getState()
{
return $this->state;
}
/**
* Set user
*
* @param User $user
* @return Log
*/
public function setUser(User $user)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* @return User
*/
public function getUser()
{
return $this->user;
}
}
@@ -0,0 +1,434 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Model;
use In2code\Femanager\Utility\UserUtility;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Domain\Model\FrontendUser;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
/**
* Class User
*/
class User extends FrontendUser
{
const TABLE_NAME = 'fe_users';
/**
* @var string
*/
protected $txFemanagerChangerequest;
/**
* @var \DateTime
*/
protected $crdate;
/**
* @var \DateTime
*/
protected $tstamp;
/**
* @var bool
*/
protected $disable;
/**
* @var bool
*/
protected $txFemanagerConfirmedbyuser;
/**
* @var bool
*/
protected $txFemanagerConfirmedbyadmin;
/**
* @var bool
*/
protected $isOnline = false;
/**
* @var bool
*/
protected $ignoreDirty = false;
/**
* @var int
*/
protected $gender;
/**
* @var \DateTime
*/
protected $dateOfBirth;
/**
* termsAndConditions
*
* @var bool
*/
protected $terms = false;
/**
* the datetime the user accepted the terms
*
* @var \DateTime
*/
protected $termsDateOfAcceptance;
/**
* @var string
*/
protected $txExtbaseType;
/**
* Created Password in Cleartext (if generated Password)
* will of course not be persistent and lives until runtime end
*
* @var string
*/
protected $passwordAutoGenerated;
/**
* @var string
*/
protected $state = '';
public function removeAllUsergroups()
{
$this->usergroup = new ObjectStorage();
}
/**
* @param string $txFemanagerChangerequest
* @return User
*/
public function setTxFemanagerChangerequest($txFemanagerChangerequest)
{
$this->txFemanagerChangerequest = $txFemanagerChangerequest;
return $this;
}
/**
* @return string
*/
public function getTxFemanagerChangerequest()
{
return $this->txFemanagerChangerequest;
}
/**
* @param \DateTime $crdate
* @return User
*/
public function setCrdate($crdate)
{
$this->crdate = $crdate;
return $this;
}
/**
* @return \DateTime
*/
public function getCrdate()
{
if ($this->crdate === null) {
// timestamp is zero
$this->crdate = new \DateTime('01.01.1970');
}
return $this->crdate;
}
/**
* @param \DateTime $tstamp
* @return User
*/
public function setTstamp($tstamp)
{
$this->tstamp = $tstamp;
return $this;
}
/**
* @return \DateTime
*/
public function getTstamp()
{
return $this->tstamp;
}
/**
* @param bool $disable
* @return User
*/
public function setDisable($disable)
{
$this->disable = $disable;
return $this;
}
/**
* @return bool
*/
public function getDisable()
{
return $this->disable;
}
/**
* @param \bool $txFemanagerConfirmedbyadmin
* @return User
*/
public function setTxFemanagerConfirmedbyadmin($txFemanagerConfirmedbyadmin)
{
$this->txFemanagerConfirmedbyadmin = $txFemanagerConfirmedbyadmin;
return $this;
}
/**
* @return \bool
*/
public function getTxFemanagerConfirmedbyadmin()
{
return $this->txFemanagerConfirmedbyadmin;
}
/**
* @param \bool $txFemanagerConfirmedbyuser
* @return User
*/
public function setTxFemanagerConfirmedbyuser($txFemanagerConfirmedbyuser)
{
$this->txFemanagerConfirmedbyuser = $txFemanagerConfirmedbyuser;
return $this;
}
/**
* @return \bool
*/
public function getTxFemanagerConfirmedbyuser()
{
return $this->txFemanagerConfirmedbyuser;
}
/**
* @param bool $ignoreDirty
* @return User
*/
public function setIgnoreDirty($ignoreDirty)
{
$this->ignoreDirty = $ignoreDirty;
return $this;
}
/**
* @return bool
*/
public function getIgnoreDirty()
{
return $this->ignoreDirty;
}
/**
* Returns the gender
*
* @return int $gender
*/
public function getGender()
{
return $this->gender;
}
/**
* Sets the gender
*
* @param int $gender
* @return User
*/
public function setGender($gender)
{
$this->gender = $gender;
return $this;
}
/**
* Returns the dateOfBirth
*
* @return \DateTime $dateOfBirth
*/
public function getDateOfBirth()
{
return $this->dateOfBirth;
}
/**
* Sets the dateOfBirth
*
* @param \DateTime $dateOfBirth
* @return User
*/
public function setDateOfBirth($dateOfBirth)
{
if ($dateOfBirth instanceof \DateTime) {
$dateOfBirth->setTime(0, 0, 0);
}
$this->dateOfBirth = $dateOfBirth;
return $this;
}
/**
* Returns, whether the user has accepted terms and conditions
*
* @return bool
*/
public function isTerms(): bool
{
return $this->terms;
}
/**
* Set whether the user has accepted terms and conditions
*
* @param bool $terms
* @return User
*/
public function setTerms(bool $terms)
{
$this->terms = $terms;
$this->setTermsDateOfAcceptance();
return $this;
}
/**
* @return \DateTime
*/
public function getTermsDateOfAcceptance()
{
return $this->termsDateOfAcceptance;
}
/**
* set terms date to now if it's not set yet
*
* @return User
*/
protected function setTermsDateOfAcceptance()
{
if ($this->termsDateOfAcceptance === null) {
$now = new \DateTime();
$this->termsDateOfAcceptance = $now;
}
return $this;
}
/**
* @return bool
*/
public function getIsOnline(): bool
{
return $this->isOnline();
}
/**
* Check if last FE login was within the last 2h
*
* @return bool
*/
public function isOnline(): bool
{
if ($this->getLastlogin() !== null && method_exists($this->getLastlogin(), 'getTimestamp')
&& $this->getLastlogin()->getTimestamp() > (time() - 2 * 60 * 60)
&& UserUtility::checkFrontendSessionToUser($this)
) {
return true;
}
return $this->isOnline;
}
/**
* @param string $txExtbaseType
* @return User
*/
public function setTxExtbaseType($txExtbaseType)
{
$this->txExtbaseType = $txExtbaseType;
return $this;
}
/**
* @return string
*/
public function getTxExtbaseType()
{
return $this->txExtbaseType;
}
public function getFirstImage()
{
$images = $this->getImage();
foreach ($images as $image) {
return $image;
}
return null;
}
/**
* @param string $passwordAutoGenerated
* @return User
*/
public function setPasswordAutoGenerated($passwordAutoGenerated)
{
$this->passwordAutoGenerated = $passwordAutoGenerated;
return $this;
}
/**
* @return string
*/
public function getPasswordAutoGenerated()
{
return $this->passwordAutoGenerated;
}
public function getState(): string
{
return $this->state;
}
public function setState(string $state): void
{
$this->state = $state;
}
public function getInactiveSince(): ?\DateTime
{
$timestampLastSession = GeneralUtility::makeInstance(ConnectionPool::class)
->getConnectionForTable('fe_sessions')
->select(['ses_tstamp'], 'fe_sessions', ['ses_userid' => $this->getUid()])
->fetchOne();
if ($timestampLastSession) {
$inactiveSince = new \DateTime();
$inactiveSince->setTimestamp($timestampLastSession);
return $inactiveSince;
}
return null;
}
/**
* Workaround to disable persistence in updateAction
*
* @param null $propertyName
* @return bool
*/
public function _isDirty($propertyName = null)
{
return $this->getIgnoreDirty() ? false : parent::_isDirty($propertyName);
}
}
@@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Model;
use TYPO3\CMS\Extbase\Domain\Model\FrontendUserGroup;
/**
* Class UserGroup
*/
class UserGroup extends FrontendUserGroup
{
}
@@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Repository;
use TYPO3\CMS\Extbase\Persistence\Repository;
/**
* Class LogRepository
*/
class LogRepository extends Repository
{
}
@@ -0,0 +1,132 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Repository;
use Doctrine\DBAL\Driver\Exception;
use Doctrine\DBAL\ForwardCompatibility\Result;
use In2code\Femanager\Utility\ObjectUtility;
use LogicException;
use PDO;
use TYPO3\CMS\Core\Service\FlexFormService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Class PluginRepository
*/
class PluginRepository
{
const TABLE_NAME = 'tt_content';
protected FlexFormService $flexFormService;
/**
* @var array<string, string>
*/
protected array $scaString = [
'new' => 'New->new;New->create;New->createStatus;New->confirmCreateRequest;',
'edit' => 'Edit->edit;Edit->update;Edit->delete;Edit->confirmUpdateRequest;User->imageDelete;',
'invitation' => 'Invitation->new;Invitation->create;Invitation->edit;'
. 'Invitation->update;Invitation->delete;Invitation->status;',
];
/**
* @param FlexFormService|null $flexFormService
*/
public function __construct(FlexFormService $flexFormService = null)
{
$this->flexFormService = $flexFormService ?? GeneralUtility::makeInstance(FlexFormService::class);
}
/**
* @param int $contentIdentifier
* @return string
* @throws \Exception
* @throws Exception
*/
public function getControllerNameByPluginSettings(int $contentIdentifier): string
{
$queryBuilder = ObjectUtility::getQueryBuilder(self::TABLE_NAME);
$flexFormQuery = $queryBuilder
->select('pi_flexform')
->from(self::TABLE_NAME)
->where('uid=' . $contentIdentifier)
->execute();
if (! $flexFormQuery instanceof Result) {
throw new \Exception(
'Something went wrong while getting FlexForm-value from Query.',
1638443805
);
}
$flexForm = (string)$flexFormQuery->fetchOne();
return $this->getViewFromFlexForm($flexForm);
}
/**
* @param string $view can be "new", "edit" or "invitation"
* @param int $pageIdentifier
* @return bool
* @throws \Exception
* @throws Exception
*/
public function isPluginWithViewOnGivenPage(string $view, int $pageIdentifier): bool
{
$queryBuilder = ObjectUtility::getQueryBuilder(self::TABLE_NAME);
$pluginConfigurationQuery = $queryBuilder
->select('pi_flexform')
->from(self::TABLE_NAME)
->where(
$queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pageIdentifier, PDO::PARAM_INT)),
$queryBuilder->expr()->eq('CType', $queryBuilder->createNamedParameter('list')),
$queryBuilder->expr()->eq('list_type', $queryBuilder->createNamedParameter('femanager_pi1'))
)
->execute();
if (! $pluginConfigurationQuery instanceof Result) {
throw new \Exception(
'Something went wrong while getting PluginConfigurations from query.',
1638443806
);
}
$pluginConfigurations = $pluginConfigurationQuery->fetchAllAssociative();
foreach ($pluginConfigurations as $pluginConfiguration) {
if ($this->isViewInPluginConfiguration($view, (string)$pluginConfiguration['pi_flexform'])) {
return true;
}
}
return false;
}
/**
* @param string $flexForm
* @return string
*/
protected function getViewFromFlexForm(string $flexForm): string
{
$view = '';
$settings = $this->flexFormService->convertFlexFormContentToArray($flexForm);
if (!empty($settings['switchableControllerActions'])
&& in_array($settings['switchableControllerActions'], $this->scaString)) {
$view = array_search($settings['switchableControllerActions'], $this->scaString);
}
if (! is_string($view)) {
return '';
}
return $view;
}
/**
* @param string $view
* @param string $pluginConfiguration
* @return bool
* @throws LogicException
*/
protected function isViewInPluginConfiguration(string $view, string $pluginConfiguration): bool
{
$flexFormArray = $this->flexFormService->convertFlexFormContentToArray($pluginConfiguration);
if (array_key_exists($view, $this->scaString)) {
return $this->scaString[$view] === $flexFormArray['switchableControllerActions'];
}
throw new LogicException('Given view is not allowed', 1541506310);
}
}
@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Repository;
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
use TYPO3\CMS\Extbase\Persistence\Repository;
/**
* Class UserGroupRepository
*/
class UserGroupRepository extends Repository
{
/**
* Find all groups and respect exclude list
*
* @param string $removeList commaseparated list
* @return QueryResultInterface
*/
public function findAllForFrontendSelection($removeList)
{
$query = $this->createQuery();
if ($removeList) {
$query->matching($query->logicalNot($query->in('uid', explode(',', $removeList))));
}
$query->setOrderings(['title' => QueryInterface::ORDER_ASCENDING]);
return $query->execute();
}
}
@@ -0,0 +1,323 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Repository;
use In2code\Femanager\Domain\Model\User;
use In2code\Femanager\Utility\BackendUserUtility;
use In2code\Femanager\Utility\BackendUtility;
use TYPO3\CMS\Core\Database\QueryGenerator;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
use TYPO3\CMS\Extbase\Persistence\Repository;
/**
* Class UserRepository
*/
class UserRepository extends Repository
{
/**
* Overload Find by UID to also get hidden records
*
* @param int $uid fe_users UID
* @return User
*/
public function findByUid($uid)
{
$query = $this->createQuery();
$this->ignoreEnableFieldsAndStoragePage($query);
$query->getQuerySettings()->setRespectSysLanguage(false);
$and = [$query->equals('uid', $uid)];
/** @var User $user */
$user = $query->matching($query->logicalAnd($and))->execute()->getFirst();
return $user;
}
/**
* Find users by commaseparated usergroup list
*
* @param string $userGroupList commaseparated list of usergroup uids
* @param array $settings Flexform and TypoScript Settings
* @param array $filter Filter Array
* @return QueryResultInterface|array
*/
public function findByUsergroups($userGroupList, $settings, $filter)
{
$query = $this->createQuery();
// where
$and = [
$query->greaterThan('uid', 0)
];
if (!empty($userGroupList)) {
$selectedUsergroups = GeneralUtility::trimExplode(',', $userGroupList, true);
$logicalOr = [];
foreach ($selectedUsergroups as $group) {
$logicalOr[] = $query->contains('usergroup', $group);
}
$and[] = $query->logicalOr($logicalOr);
}
if (!empty($filter['searchword'])) {
$searchwords = GeneralUtility::trimExplode(' ', $filter['searchword'], true);
$fieldsToSearch = GeneralUtility::trimExplode(
',',
$settings['list']['filter']['searchword']['fieldsToSearch'],
true
);
foreach ($searchwords as $searchword) {
$logicalOr = [];
foreach ($fieldsToSearch as $searchfield) {
$logicalOr[] = $query->like($searchfield, '%' . $searchword . '%');
}
$and[] = $query->logicalOr($logicalOr);
}
}
$query->matching($query->logicalAnd($and));
// sorting
$sorting = QueryInterface::ORDER_ASCENDING;
if ($settings['list']['sorting'] === 'desc') {
$sorting = QueryInterface::ORDER_DESCENDING;
}
$field = preg_replace('/[^a-zA-Z0-9_-]/', '', $settings['list']['orderby']);
$query->setOrderings([$field => $sorting]);
// set limit
if ((int)$settings['list']['limit'] > 0) {
$query->setLimit((int)$settings['list']['limit']);
}
$users = $query->execute();
return $users;
}
/**
* Check if there is already an entry in the table
*
* @param $field
* @param $value
* @param User $user Existing User
* @return User|null
*/
public function checkUniqueDb($field, $value, User $user = null)
{
$query = $this->createQuery();
$this->ignoreEnableFieldsAndStoragePageAndStarttime($query);
$and = [$query->equals($field, $value)];
if ($user !== null && method_exists($user, 'getUid')) {
$and[] = $query->logicalNot($query->equals('uid', $user->getUid()));
}
$constraint = $query->logicalAnd($and);
$query->matching($constraint);
/** @var User $user */
$user = $query->execute()->getFirst();
return $user;
}
/**
* Check if there is already an entry in the table on current page
*
* @param $field
* @param $value
* @param User $user Existing User
* @return User|null
*/
public function checkUniquePage($field, $value, User $user = null)
{
$query = $this->createQuery();
$query->getQuerySettings()->setIgnoreEnableFields(true);
$and = [
$query->equals($field, $value),
$query->equals('deleted', 0)
];
if ($user !== null && method_exists($user, 'getUid')) {
$and[] = $query->logicalNot($query->equals('uid', (int)$user->getUid()));
}
$constraint = $query->logicalAnd($and);
$query->matching($constraint);
/** @var User $user */
$user = $query->execute()->getFirst();
return $user;
}
/**
* Find All for Backend Actions
*
* @param array $filter Filter Array
* @return QueryResultInterface|array
*/
public function findAllInBackend(array $filter)
{
$query = $this->createQuery();
$this->ignoreEnableFieldsAndStoragePage($query);
$and = [$query->greaterThan('uid', 0)];
$and = $this->filterByPage($and, $query);
$and = $this->filterBySearchword($filter, $query, $and);
$query->matching($query->logicalAnd($and));
$query->setOrderings(['username' => QueryInterface::ORDER_ASCENDING]);
$records = $query->execute();
return $records;
}
/**
* Find All for Backend Actions
*
* @param array $filter Filter Array
* @param bool $userConfirmation Show only fe_users which are confirmed by the user?
* @return QueryResultInterface|array
*/
public function findAllInBackendForConfirmation(array $filter, bool $userConfirmation = false)
{
$query = $this->createQuery();
$this->ignoreEnableFieldsAndStoragePage($query);
$and = [$query->equals('disable', true)];
$and = $this->filterByPage($and, $query);
$and = $this->filterBySearchword($filter, $query, $and);
$and = $this->filterByUserConfirmation($and, $query, $userConfirmation);
$query->matching($query->logicalAnd($and));
$query->setOrderings(['username' => QueryInterface::ORDER_ASCENDING]);
$records = $query->execute();
return $records;
}
/**
* Find all users from current page or from any subpage
* If no page id given or if on rootpage (pid 0):
* - Don't show any users for editors
* - Show all users for admins
*
* @param array $and
* @param QueryInterface $query
* @return array
*/
protected function filterByPage(array $and, QueryInterface $query): array
{
if (BackendUtility::getPageIdentifier() > 0) {
$and[] = $query->in('pid', $this->getTreeList(BackendUtility::getPageIdentifier()));
} else {
if (!BackendUserUtility::isAdminAuthentication()) {
$and[] = $query->equals('uid', 0);
}
}
return $and;
}
/**
* @param array $filter
* @param QueryInterface $query
* @param array $and
* @return array
*/
protected function filterBySearchword(array $filter, QueryInterface $query, array $and): array
{
if (!empty($filter['searchword'])) {
$searchwords = GeneralUtility::trimExplode(' ', $filter['searchword'], true);
foreach ($searchwords as $searchword) {
$or = [];
$or[] = $query->like('address', '%' . $searchword . '%');
$or[] = $query->like('city', '%' . $searchword . '%');
$or[] = $query->like('company', '%' . $searchword . '%');
$or[] = $query->like('country', '%' . $searchword . '%');
$or[] = $query->like('email', '%' . $searchword . '%');
$or[] = $query->like('fax', '%' . $searchword . '%');
$or[] = $query->like('first_name', '%' . $searchword . '%');
$or[] = $query->like('image', '%' . $searchword . '%');
$or[] = $query->like('last_name', '%' . $searchword . '%');
$or[] = $query->like('middle_name', '%' . $searchword . '%');
$or[] = $query->like('name', '%' . $searchword . '%');
$or[] = $query->like('telephone', '%' . $searchword . '%');
$or[] = $query->like('title', '%' . $searchword . '%');
$or[] = $query->like('usergroup.title', '%' . $searchword . '%');
$or[] = $query->like('username', '%' . $searchword . '%');
$or[] = $query->like('www', '%' . $searchword . '%');
$or[] = $query->like('zip', '%' . $searchword . '%');
$and[] = $query->logicalOr($or);
}
}
return $and;
}
/**
* @param array $and
* @param QueryInterface $query
* @param bool $userConfirmation
* @return array
*/
protected function filterByUserConfirmation(array $and, QueryInterface $query, bool $userConfirmation): array
{
$and[] = $query->equals('txFemanagerConfirmedbyuser', $userConfirmation);
return $and;
}
/**
* Get all children pids of a start pid
*
* @param int $pageIdentifier
* @return array
*/
protected function getTreeList($pageIdentifier)
{
$queryGenerator = $this->objectManager->get(QueryGenerator::class);
$treeList = $queryGenerator->getTreeList($pageIdentifier, 99, 0, '1');
return GeneralUtility::trimExplode(',', $treeList, true);
}
/**
* @param QueryInterface $query
*/
protected function ignoreEnableFieldsAndStoragePage(QueryInterface $query)
{
$query->getQuerySettings()->setRespectStoragePage(false);
$query->getQuerySettings()->setIgnoreEnableFields(true);
$query->getQuerySettings()->setEnableFieldsToBeIgnored(['disabled']);
}
/**
* @param QueryInterface $query
*/
protected function ignoreEnableFieldsAndStoragePageAndStarttime(QueryInterface $query)
{
$this->ignoreEnableFieldsAndStoragePage($query);
$query->getQuerySettings()->setEnableFieldsToBeIgnored(['disabled', 'starttime']);
}
/**
* Find All
*
* @param string $mail
* @return QueryResultInterface|array
*/
public function findFirstByEmail(string $mail)
{
$query = $this->createQuery();
$this->ignoreEnableFieldsAndStoragePage($query);
$and = [
$query->equals('txFemanagerConfirmedbyuser', false),
$query->equals('email', $mail)
];
$query->matching($query->logicalAnd($and));
$query->setOrderings(['uid' => QueryInterface::ORDER_DESCENDING]);
return $query->execute()->getFirst();
}
}
@@ -0,0 +1,91 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Service\AutoAdminConfirmation;
use In2code\Femanager\Domain\Model\User;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
/**
* Class AbstractConfirmation
*/
abstract class AbstractConfirmation implements ConfirmationInterface
{
/**
* @var array
*/
protected $config = [];
/**
* @var User
*/
protected $user;
/**
* @var array
*/
protected $settings = [];
/**
* @var ContentObjectRenderer
*/
protected $contentObject;
/**
* AbstractConfirmation constructor.
*
* @param array $config
* @param User $user
* @param array $settings
* @param ContentObjectRenderer $contentObject
*/
public function __construct(array $config, User $user, array $settings, ContentObjectRenderer $contentObject)
{
$this->config = $config;
$this->user = $user;
$this->settings = $settings;
$this->contentObject = $contentObject;
}
/**
* Skip manual confirmation from admin?
*
* @return bool
*/
public function isAutoConfirmed(): bool
{
return false;
}
/**
* @return array
*/
public function getConfig(): array
{
return $this->config;
}
/**
* @return User
*/
public function getUser(): User
{
return $this->user;
}
/**
* @return array
*/
public function getSettings(): array
{
return $this->settings;
}
/**
* @return ContentObjectRenderer
*/
public function getContentObject(): ContentObjectRenderer
{
return $this->contentObject;
}
}
@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Service\AutoAdminConfirmation;
/**
* Interface ConfirmationInterface
*/
interface ConfirmationInterface
{
/**
* @return bool
*/
public function isAutoConfirmed(): bool;
}
@@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Service\AutoAdminConfirmation;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Class EmailDomainConfirmation
*/
class EmailDomainConfirmation extends AbstractConfirmation
{
/**
* @return bool
*/
public function isAutoConfirmed(): bool
{
if (!$this->isException() && $this->isGivenDomainsPartOfEmail()) {
return true;
}
return false;
}
/**
* @return bool
*/
protected function isGivenDomainsPartOfEmail(): bool
{
$domains = GeneralUtility::trimExplode(',', $this->getConfig()['confirmByEmailDomains'], true);
foreach ($domains as $domain) {
if (stristr($this->getEmailDomain(), $domain)) {
return true;
}
}
return false;
}
protected function isException(): bool
{
$exceptionDomains =
GeneralUtility::trimExplode(',', $this->getConfig()['confirmByEmailDomainsExceptions'], true);
return in_array($this->getEmailDomain(), $exceptionDomains);
}
/**
* Get domain of an email address: "alex@in2code.de" => "in2code.de"
*
* @return string
*/
protected function getEmailDomain(): string
{
$email = $this->getUser()->getEmail();
$parts = explode('@', $email);
return $parts[1];
}
}
@@ -0,0 +1,101 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Service;
use In2code\Femanager\Domain\Model\User;
use In2code\Femanager\Domain\Service\AutoAdminConfirmation\ConfirmationInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
/**
* Class AutoAdminConfirmationService
*/
class AutoAdminConfirmationService
{
/**
* @var User
*/
protected $user;
/**
* @var array
*/
protected $settings = [];
/**
* @var ContentObjectRenderer
*/
protected $contentObject;
/**
* @var string
*/
protected $confirmInterface = ConfirmationInterface::class;
/**
* AutoAdminConfirmationService constructor.
*
* @param User $user
* @param array $settings
* @param ContentObjectRenderer $contentObject
*/
public function __construct(User $user, array $settings, ContentObjectRenderer $contentObject)
{
$this->user = $user;
$this->settings = $settings;
$this->contentObject = $contentObject;
}
/**
* Loop through all AutoAdminConfirmation classes
*
* @return bool
*/
public function isAutoAdminConfirmationFullfilled(): bool
{
$autoConfirmation = false;
foreach ($this->getConfirmationClasses() as $classConfiguration) {
/** @var ConfirmationInterface $confirmation */
$confirmation = GeneralUtility::makeInstance(
$classConfiguration['class'],
$classConfiguration['config'],
$this->user,
$this->settings,
$this->contentObject
);
if ($confirmation->isAutoConfirmed() === true) {
$autoConfirmation = true;
}
}
return $autoConfirmation;
}
/**
* @return array
* @throws \Exception
*/
protected function getConfirmationClasses(): array
{
$classes = [];
if (!empty($this->settings['autoAdminConfirmation'])) {
foreach ($this->settings['autoAdminConfirmation'] as $configuration) {
$className = $configuration['class'];
if (!class_exists($className)) {
throw new \UnexpectedValueException(
'Class ' . $className . ' does not exists - check if file was loaded with autoloader',
1516373867533
);
}
if (!is_subclass_of($className, $this->confirmInterface)) {
throw new \UnexpectedValueException(
'Class ' . $className . ' does not implement interface ' . $this->confirmInterface,
1516373878882
);
}
$classes[] = $configuration;
}
}
return $classes;
}
}
@@ -0,0 +1,123 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Service;
use In2code\Femanager\Utility\ConfigurationUtility;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Resource\Security\FileNameValidator;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\PathUtility;
/**
* Class FileService
*/
class FileService
{
/**
* @var string
*/
protected $fileName = '';
/**
* @var array
*/
protected $fileArray = [];
/**
* @var string
*/
protected $fallbackExtensions = 'jpg,jpeg,png,gif,bmp,tif,tiff';
/**
* FileService constructor.
*
* @param string $filename Filename like (upload.png)
* @param array $fileArray From PHP with tmp_name, etc...
*/
public function __construct(string $filename, array $fileArray)
{
$this->fileName = $filename;
$this->fileArray = $fileArray;
}
/**
* @return bool
* @todo add filesize check
*/
public function isEverythingValid(): bool
{
return $this->validFileExtension();
}
/**
* Check extension of given filename
*
* @return bool If Extension is allowed
*/
protected function validFileExtension(): bool
{
$extensionList = ConfigurationUtility::getConfiguration('misc.uploadFileExtension');
if (!empty($extensionList)) {
$extensionList = str_replace(' ', '', $extensionList);
} else {
$extensionList = $this->fallbackExtensions;
}
$fileInfo = pathinfo($this->fileName);
return !empty($fileInfo['extension']) &&
GeneralUtility::inList($extensionList, strtolower($fileInfo['extension'])) &&
GeneralUtility::makeInstance(FileNameValidator::class)->isValid($this->fileName) &&
GeneralUtility::validPathStr($this->fileName);
}
/**
* Create sys_file entry for given filename and return uid
*
* @param string $file absolute path and filename
* @return int
*/
public function indexFile(string $file): int
{
$fileIdentifier = 0;
if (file_exists($file)) {
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
$file = $resourceFactory->getFileObjectFromCombinedIdentifier($this->getCombinedIdentifier($file));
$fileIdentifier = (int)$file->getProperty('uid');
}
return $fileIdentifier;
}
/**
* build combined identifier from absolute filename:
* "/var/www/fileadmin/folder/test.pdf" => "1:folder/test.pdf"
*
* @param string $file relative path and filename
* @return string
*/
protected function getCombinedIdentifier(string $file): string
{
// @Todo Make it a bit less ugly
$file = PathUtility::getRelativePathTo($file);
$identifier = $this->substituteFileadminFromPathAndName($file);
return '1:' . $identifier;
}
/**
* "fileadmin/downloads/test.pdf" => "/downloads/test.pdf"
*
* @param string $pathAndName
* @return string
*/
protected function substituteFileadminFromPathAndName(string $pathAndName): string
{
$substituteString = 'fileadmin/';
if (substr($pathAndName, 0, strlen($substituteString)) === $substituteString) {
$pathAndName = str_replace($substituteString, '', $pathAndName);
}
if (substr($pathAndName, 0, 1) !== '/') {
$pathAndName = '/' . $pathAndName;
}
return $pathAndName;
}
}
@@ -0,0 +1,258 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Service;
use In2code\Femanager\Domain\Model\User;
use In2code\Femanager\Finisher\AbstractFinisher;
use In2code\Femanager\Utility\StringUtility;
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
/**
* Class FinisherService
*/
class FinisherService
{
/**
* @var ContentObjectRenderer
*/
protected $contentObject;
/**
* Classname
*
* @var string
*/
protected $class = '';
/**
* Path that should be required
*
* @var string|null
*/
protected $requirePath;
/**
* Finisher Configuration
*
* @var array
*/
protected $configuration = [];
/**
* @var User
*/
protected $user;
/**
* @var array
*/
protected $settings;
/**
* Controller actionName - usually "createAction" or "confirmationAction"
*
* @var null
*/
protected $actionMethodName;
/**
* @var string
*/
protected $finisherInterface = 'In2code\Femanager\Finisher\FinisherInterface';
/**
* @var ObjectManagerInterface
*/
protected $objectManager;
public function injectObjectManager(ObjectManagerInterface $objectManager)
{
$this->objectManager = $objectManager;
}
/**
* @return string
*/
public function getClass()
{
return $this->class;
}
/**
* @param string $class
* @return FinisherService
*/
public function setClass($class)
{
$this->class = $class;
return $this;
}
/**
* @return string|null
*/
public function getRequirePath()
{
return $this->requirePath;
}
/**
* Set require path and do a require_once
*
* @param string|null $requirePath
* @return FinisherService
*/
public function setRequirePath($requirePath)
{
$this->requirePath = $requirePath;
if ($this->getRequirePath() && file_exists($this->getRequirePath())) {
require_once($this->getRequirePath());
}
return $this;
}
/**
* @return array
*/
public function getConfiguration()
{
return $this->configuration;
}
/**
* @param array $configuration
* @return FinisherService
*/
public function setConfiguration($configuration)
{
$this->configuration = $configuration;
return $this;
}
/**
* @return User
*/
public function getUser()
{
return $this->user;
}
/**
* @param User $user
* @return FinisherService
*/
public function setUser($user)
{
$this->user = $user;
return $this;
}
/**
* @return array
*/
public function getSettings()
{
return $this->settings;
}
/**
* @param array $settings
* @return FinisherService
*/
public function setSettings($settings)
{
$this->settings = $settings;
return $this;
}
public function getActionMethodName()
{
return $this->actionMethodName;
}
/**
* @param null $actionMethodName
* @return FinisherService
*/
public function setActionMethodName($actionMethodName)
{
$this->actionMethodName = $actionMethodName;
return $this;
}
/**
* Start implementation
*
* @throws \Exception
*/
public function start()
{
if (!class_exists($this->getClass())) {
throw new \UnexpectedValueException(
'Class ' . $this->getClass() . ' does not exists - check if file was loaded with autoloader',
1516373888508
);
}
if (is_subclass_of($this->getClass(), $this->finisherInterface)) {
/** @var AbstractFinisher $finisher */
$finisher = $this->objectManager->get(
$this->getClass(),
$this->getUser(),
$this->getConfiguration(),
$this->getSettings(),
$this->getActionMethodName(),
$this->contentObject
);
$finisher->initializeFinisher();
$this->callFinisherMethods($finisher);
} else {
throw new \UnexpectedValueException(
'Finisher does not implement ' . $this->finisherInterface,
1516373899775
);
}
}
/**
* Call methods in finisher class
*
* @param AbstractFinisher $finisher
*/
protected function callFinisherMethods(AbstractFinisher $finisher)
{
foreach (get_class_methods($finisher) as $method) {
if (!StringUtility::endsWith($method, 'Finisher') || strpos($method, 'initialize') === 0) {
continue;
}
$this->callInitializeFinisherMethod($finisher, $method);
$finisher->{$method}();
}
}
/**
* Call initializeFinisherMethods like "initializeSaveFinisher()"
*
* @param AbstractFinisher $finisher
* @param string $finisherMethod
*/
protected function callInitializeFinisherMethod(AbstractFinisher $finisher, $finisherMethod)
{
if (method_exists($finisher, 'initialize' . ucfirst($finisherMethod))) {
$finisher->{'initialize' . ucfirst($finisherMethod)}();
}
}
/**
* @param User $user
* @param array $settings
* @param ContentObjectRenderer $contentObject
*/
public function __construct(User $user, array $settings, ContentObjectRenderer $contentObject)
{
$this->setUser($user);
$this->setSettings($settings);
$this->contentObject = $contentObject;
}
}
@@ -0,0 +1,127 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Service;
use TYPO3\CMS\Core\Cache\CacheManager;
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Crypto\Random;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
class RatelimiterService implements SingletonInterface
{
const CACHE_IDENTIFIER = 'femanager_ratelimiter';
const DEFAULT_CONFIG = ['timeframe' => 60, 'limit' => 3];
const LIMIT_IP = 'limit_ip_';
const SESSION_KEY = 'tx_femanager_ratelimiter';
/** @var FrontendInterface */
protected $cache;
/** @var int */
protected $limit;
/** @var int */
protected $timeframe;
public function __construct()
{
$this->cache = GeneralUtility::makeInstance(CacheManager::class)->getCache(self::CACHE_IDENTIFIER);
$setup = $this->getTSFE()->tmpl->setup;
$config = $setup['plugin.']['tx_femanager.']['settings.']['ratelimiter.'] ?? self::DEFAULT_CONFIG;
$this->timeframe = (int)$config['timeframe'];
$this->limit = (int)$config['limit'];
}
protected function getTSFE(): TypoScriptFrontendController
{
return $GLOBALS['TSFE'];
}
public function isLimited(): bool
{
if ($this->limit > 0) {
$userIp = GeneralUtility::getIndpEnv('REMOTE_ADDR');
$userIpAccess = $this->getToken(self::LIMIT_IP, $userIp);
return count($userIpAccess) >= $this->limit;
}
return false;
}
public function consumeSlot()
{
if ($this->limit > 0) {
$userIp = GeneralUtility::getIndpEnv('REMOTE_ADDR');
$this->consumeToken(self::LIMIT_IP, $userIp);
}
}
protected function getCookie()
{
$this->touchCookie();
return $this->getTSFE()->fe_user->getSessionData(self::SESSION_KEY);
}
public function touchCookie()
{
$feUser = $this->getTSFE()->fe_user;
$identifier = $feUser->getSessionData(self::SESSION_KEY);
if (null === $identifier) {
$unique = GeneralUtility::makeInstance(Random::class)->generateRandomHexString(16);
$feUser->setAndSaveSessionData(self::SESSION_KEY, $unique);
}
}
protected function consumeToken(string $tokenName, string $value): array
{
$cacheID = $this->getCacheID($tokenName, $value);
$token = $this->retrieveToken($cacheID);
$token[] = GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('date', 'timestamp');
$this->cache->set($cacheID, $token, [], $this->timeframe);
return $token;
}
protected function getCacheID(string $tokenName, string $value): string
{
return $tokenName . hash('sha1', $value);
}
protected function retrieveToken(string $cacheID): array
{
$token = [];
if ($this->cache->has($cacheID)) {
$token = $this->cache->get($cacheID);
$token = $this->filterExpiredToken($token);
}
return $token;
}
protected function filterExpiredToken(array $token): array
{
$slidingWindowStartTime = GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('date', 'timestamp') - $this->timeframe;
foreach ($token as $idx => $accessTime) {
if ($accessTime < $slidingWindowStartTime) {
unset($token[$idx]);
}
}
return $token;
}
protected function getToken(string $tokenName, string $value): array
{
$cacheID = $this->getCacheID($tokenName, $value);
return $this->retrieveToken($cacheID);
}
}
@@ -0,0 +1,294 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Service;
use In2code\Femanager\Event\AfterMailSendEvent;
use In2code\Femanager\Event\BeforeMailBodyRenderEvent;
use In2code\Femanager\Event\BeforeMailSendEvent;
use In2code\Femanager\Utility\ConfigurationUtility;
use In2code\Femanager\Utility\ObjectUtility;
use In2code\Femanager\Utility\TemplateUtility;
use Psr\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Mime\Part\DataPart;
use TYPO3\CMS\Core\Mail\Mailer;
use TYPO3\CMS\Core\Mail\MailMessage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Class SendMailService
*/
class SendMailService
{
/**
* Content Object
*
* @var object|null
*/
public ?object $contentObject = null;
/**
* @var Mailer|null
*/
private ?Mailer $mailer = null;
/**
* @var EventDispatcherInterface|null
*/
private ?EventDispatcherInterface $dispatcher = null;
/**
* SendMailService constructor.
*/
public function __construct(Mailer $mailer, EventDispatcherInterface $dispatcher)
{
$this->contentObject = ObjectUtility::getContentObject();
$this->mailer = $mailer;
$this->dispatcher = $dispatcher;
}
/**
* @param array $variables
*/
protected function contentObjectStart(array $variables): void
{
if (
empty($variables['user'] ?? []) === false &&
method_exists(($variables['user'] ?? null), '_getProperties') === true
) {
$this->contentObject->start($variables['user']->_getProperties());
}
}
/**
* Generate and send Email
*
* @param string $template Template file in Templates/Email/
* @param array $receiver Combination of Email => Name
* @param array $sender Combination of Email => Name
* @param string $subject Mail subject
* @param array $variables Variables for assignMultiple
* @param array $typoScript Add TypoScript to overwrite values
* @return bool mail was sent?
*/
public function send(
string $template,
array $receiver,
array $sender,
string $subject,
array $variables = [],
array $typoScript = []
): bool {
if (false === $this->isMailEnabled($typoScript, $receiver)) {
return false;
}
$this->contentObjectStart($variables);
$email = GeneralUtility::makeInstance(MailMessage::class);
$variables = $this->embedImages($variables, $typoScript, $email);
$this->prepareMailObject($template, $receiver, $sender, $subject, $variables, $email);
$this->overwriteEmailReceiver($typoScript, $email);
$this->overwriteEmailSender($typoScript, $email);
$this->setSubject($typoScript, $email);
$this->setCc($typoScript, $email);
$this->setPriority($typoScript, $email);
$this->setAttachments($typoScript, $email);
$this->dispatcher->dispatch(new BeforeMailSendEvent($email, $variables, $this));
$email->send();
$this->dispatcher->dispatch(new AfterMailSendEvent($email, $variables, $this));
return $email->isSent();
}
/**
* Generate Email Body
*
* @param string $template Template file in Templates/Email/
* @param array $variables Variables for assignMultiple
* @return string
*/
protected function getMailBody(string $template, array $variables): string
{
$standAloneView = TemplateUtility::getDefaultStandAloneView();
$standAloneView->setTemplatePathAndFilename($this->getRelativeEmailPathAndFilename($template));
$standAloneView->assignMultiple($variables);
$this->dispatcher->dispatch(new BeforeMailBodyRenderEvent($standAloneView, $variables, $this));
return $standAloneView->render();
}
/**
* @param array $variables
* @param array $typoScript
* @param MailMessage $email
* @return array
*/
protected function embedImages(array $variables, array $typoScript, MailMessage $email): array
{
$images = $this->contentObject->cObjGetSingle(
$typoScript['embedImage'] ?? 'TEXT',
$typoScript['embedImage.'] ?? []
);
if (!$images) {
return $variables;
}
$images = GeneralUtility::trimExplode(',', $images, true);
$imageVariables = [];
foreach ($images as $path) {
$name = basename($path);
$imagePart = DataPart::fromPath($path);
$contentType = $imagePart->getMediaType() . '/' . $imagePart->getMediaSubtype();
$email->embedFromPath($path, $name, $contentType);
$imageVariables[] = 'cid:' . $name;
}
return array_merge($variables, ['embedImages' => $imageVariables]);
}
/**
* @param string $template
* @param array $receiver
* @param array $sender
* @param string $subject
* @param array $variables
* @param MailMessage $email
*/
protected function prepareMailObject(
string $template,
array $receiver,
array $sender,
string $subject,
array $variables,
MailMessage $email
): void {
$html = $this->getMailBody($template, $variables);
$email->setTo($receiver)
->setFrom($sender)
->setSubject($subject)
->html($html);
}
/**
* @param array $typoScript
* @param MailMessage $email
*/
protected function overwriteEmailReceiver(array $typoScript, MailMessage $email): void
{
$emailAddress = $this->contentObject->cObjGetSingle(
(string)ConfigurationUtility::getValue('receiver./email', $typoScript),
(array)ConfigurationUtility::getValue('receiver./email.', $typoScript)
);
$name = $this->contentObject->cObjGetSingle(
(string)ConfigurationUtility::getValue('receiver./name', $typoScript),
(array)ConfigurationUtility::getValue('receiver./name.', $typoScript)
);
if ($emailAddress && $name) {
$email->setTo([$emailAddress => $name]);
}
}
/**
* @param array $typoScript
* @param MailMessage $email
*/
protected function overwriteEmailSender(array $typoScript, MailMessage $email): void
{
$emailAddress = $this->contentObject->cObjGetSingle(
(string)ConfigurationUtility::getValue('sender./email', $typoScript),
(array)ConfigurationUtility::getValue('sender./email.', $typoScript)
);
$name = $this->contentObject->cObjGetSingle(
(string)ConfigurationUtility::getValue('sender./name', $typoScript),
(array)ConfigurationUtility::getValue('sender./name.', $typoScript)
);
if ($emailAddress && $name) {
$email->setFrom([$emailAddress => $name]);
}
}
/**
* @param array $typoScript
* @param MailMessage $email
*/
protected function setSubject(array $typoScript, MailMessage $email): void
{
if ($this->contentObject->cObjGetSingle((string)$typoScript['subject'], (array)$typoScript['subject.'])) {
$email->setSubject($this->contentObject->cObjGetSingle((string)$typoScript['subject'], (array)$typoScript['subject.']));
}
}
/**
* @param array $typoScript
* @param MailMessage $email
*/
protected function setCc(array $typoScript, MailMessage $email): void
{
if ($this->contentObject->cObjGetSingle((string)$typoScript['cc'], (array)$typoScript['cc.'])) {
$email->setCc($this->contentObject->cObjGetSingle((string)$typoScript['cc'], (array)$typoScript['cc.']));
}
}
/**
* @param array $typoScript
* @param MailMessage $email
*/
protected function setPriority(array $typoScript, MailMessage $email): void
{
$priority = (int)$this->contentObject->cObjGetSingle(
(string)ConfigurationUtility::getValue('priority', $typoScript),
(array)ConfigurationUtility::getValue('priority.', $typoScript)
);
if ($priority) {
$email->priority($priority);
}
}
/**
* @param array $typoScript
* @param MailMessage $email
*/
protected function setAttachments(array $typoScript, MailMessage $email): void
{
if ($this->contentObject->cObjGetSingle($typoScript['attachments'] ?? '', $typoScript['attachments.'] ?? [])) {
$files = GeneralUtility::trimExplode(
',',
$this->contentObject->cObjGetSingle(
$typoScript['attachments'] ?? '',
$typoScript['attachments.'] ?? []
),
true
);
foreach ($files as $file) {
$email->attachFromPath($file);
}
}
}
/**
* Get path and filename for mail template
*
* @param string $fileName
* @return string
*/
protected function getRelativeEmailPathAndFilename(string $fileName): string
{
return TemplateUtility::getTemplatePath('Email/' . ucfirst($fileName) . '.html');
}
/**
* @param array $typoScript
* @param array $receiver
* @return bool
*/
protected function isMailEnabled(array $typoScript, array $receiver): bool
{
$cObjectName = (string)ConfigurationUtility::getValue('_enable', $typoScript);
$cObjectConf = (array)ConfigurationUtility::getValue('_enable.', $typoScript);
return $this->contentObject->cObjGetSingle($cObjectName, $cObjectConf) && count($receiver) > 0;
}
}
@@ -0,0 +1,135 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Service;
use In2code\Femanager\Domain\Model\User;
use TYPO3\CMS\Core\Log\LogLevel;
use TYPO3\CMS\Core\Log\LogManager;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
/**
* Class SendParametersService
*/
class SendParametersService
{
/**
* @var ConfigurationManagerInterface
*/
protected $configurationManager;
/**
* @var ContentObjectRenderer
*/
protected $contentObject;
/**
* @var array
*/
protected $configuration = [];
/**
* @var array
*/
protected $properties = [];
/**
* Constructor
*/
public function __construct($configuration)
{
$this->configuration = $configuration;
}
/**
* @param ConfigurationManagerInterface $configurationManager
*/
public function injectConfigurationManagerInterface(ConfigurationManagerInterface $configurationManager)
{
$this->configurationManager = $configurationManager;
}
/**
* SendPost - Send values via curl to target
*
* @param User $user User properties
*/
public function send(User $user)
{
$this->initialize($user);
$this->contentObject->start($this->properties);
if ($this->isTurnedOn()) {
$curlObject = curl_init();
curl_setopt($curlObject, CURLOPT_URL, $this->getUri());
curl_setopt($curlObject, CURLOPT_POST, 1);
curl_setopt($curlObject, CURLOPT_POSTFIELDS, $this->getData());
curl_setopt($curlObject, CURLOPT_RETURNTRANSFER, true);
if ($GLOBALS['FE']['debug'] === 1) {
curl_setopt($curlObject, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curlObject, CURLOPT_SSL_VERIFYPEER, false);
}
curl_exec($curlObject);
curl_close($curlObject);
$this->log();
}
}
/**
* Get URI for curl request
*
* @return string
*/
protected function getUri()
{
return $this->configuration['targetUrl'];
}
/**
* Get data array
*
* @return string
*/
protected function getData()
{
return $this->contentObject->cObjGetSingle((string)$this->configuration['data'], (array)$this->configuration['data.']);
}
/**
* Write to devlog
*
* @return bool
*/
protected function log()
{
if (!empty($this->configuration['debug'])) {
GeneralUtility::makeInstance(LogManager::class)->getLogger(__CLASS__)->log(LogLevel::INFO, 'femanager sendpost values', [
'url' => $this->getUri(),
'data' => $this->getData(),
'properties' => $this->properties
]);
}
}
/**
* @return bool
*/
protected function isTurnedOn()
{
return $this->contentObject->cObjGetSingle((string)$this->configuration['_enable'], (array)$this->configuration['_enable.'])
=== '1';
}
/**
* Initialize
*
* @param User $user
*/
protected function initialize(User $user)
{
$this->properties = $user->_getCleanProperties();
$this->contentObject = $this->configurationManager->getContentObject();
}
}
@@ -0,0 +1,109 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Service;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Class StoreInDatabaseService
*/
class StoreInDatabaseService
{
/**
* Database Table to store
*
* @var string
*/
protected $table = '';
/**
* Array with fieldname=>value
*
* @var array
*/
protected $properties = [];
/**
* @var \TYPO3\CMS\CORE\Database\ConnectionPool
*/
protected $databaseConnection;
/**
* Executes the storage
*
* @return int uid of inserted record
*/
public function execute()
{
$insertTable = $this->databaseConnection->getConnectionForTable($this->getTable());
$insertTable->insert(
$this->getTable(),
$this->getProperties()
);
return (int)$insertTable->lastInsertId($this->getTable());
}
/**
* Set TableName
*
* @param string $table
*/
public function setTable($table)
{
$table = preg_replace('/[^a-zA-Z0-9_-]/', '', $table);
$this->table = $table;
}
/**
* Get TableName
*
* @return string
*/
public function getTable()
{
return $this->table;
}
/**
* Read properties
*
* @return array
*/
public function getProperties()
{
return $this->properties;
}
/**
* Add property/value pair to array
*
* @param $propertyName
* @param $value
*/
public function addProperty($propertyName, $value)
{
$propertyName = preg_replace('/[^a-zA-Z0-9_-]/', '', $propertyName);
$this->properties[$propertyName] = $value;
}
/**
* Remove property/value pair form array by its key
*
* @param $propertyName
*/
public function removeProperty($propertyName)
{
unset($this->properties[$propertyName]);
}
/**
* Initialize
*/
public function __construct()
{
$this->databaseConnection = GeneralUtility::makeInstance(ConnectionPool::class);
}
}
@@ -0,0 +1,134 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Service;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
/**
* Class ValidationSettingsService
*/
class ValidationSettingsService
{
/**
* Needed for validation settings. Should be "new", "edit" or "invitation"
*
* @var string
*/
protected $controllerName = '';
/**
* Needed for validation settings. Should be "validation" or "validationEdit"
*
* @var string
*/
protected $validationName = '';
/**
* Validation names with simple configuration
*
* @var array
*/
protected $simpleValidations = [
'date',
'email',
'intOnly',
'lettersOnly',
'unicodeLettersOnly',
'required',
'uniqueInDb',
'uniqueInPage'
];
/**
* @param string $controllerName
* @param string $validationName
*/
public function __construct(string $controllerName, string $validationName)
{
$this->controllerName = $controllerName;
$this->validationName = $validationName;
}
/**
* Get validation string like
* required, email, min(10), max(10), intOnly,
* lettersOnly, unicodeLettersOnly, uniqueInPage, uniqueInDb, date,
* mustInclude(number|letter|special), inList(1|2|3)
*
* @param string $fieldName Fieldname
* @return string
*/
public function getValidationStringForField(string $fieldName): string
{
$string = '';
$validationSettings = $this->getSettings()[$this->controllerName][$this->validationName][$fieldName] ?? [];
if (is_array($validationSettings)) {
foreach ($validationSettings as $validation => $configuration) {
if ($string !== '') {
$string .= ',';
}
$string .= $this->getSingleValidationString($validation, $configuration);
}
}
return $string;
}
/**
* @param string $type
* @return bool
*/
public function isValidationEnabled(string $type = 'client'): bool
{
$validationSetting = $this->getSettings()[$this->controllerName]['validation']['_enable'][$type] ?? '0';
return $validationSetting === '1';
}
/**
* @param string $validation
* @param string $configuration
* @return string
*/
protected function getSingleValidationString($validation, $configuration)
{
$string = '';
if ($this->isSimpleValidation($validation) && $configuration === '1') {
$string = $validation;
}
if (!$this->isSimpleValidation($validation)) {
$string = $validation;
$string .= '(' . str_replace(',', '|', $configuration) . ')';
}
return $string;
}
/**
* Check if validation is simple or extended
*
* @param string $validation
* @return bool
*/
protected function isSimpleValidation($validation): bool
{
if (in_array($validation, $this->simpleValidations)) {
return true;
}
return false;
}
/**
* @return array
*/
protected function getSettings(): array
{
$configurationManager = GeneralUtility::makeInstance(ConfigurationManagerInterface::class);
return (array)$configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS,
'femanager',
'femanager_pi1'
);
}
}
@@ -0,0 +1,490 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Validator;
use In2code\Femanager\Domain\Model\User;
use In2code\Femanager\Domain\Repository\PluginRepository;
use In2code\Femanager\Domain\Repository\UserRepository;
use In2code\Femanager\Event\UniqueUserEvent;
use In2code\Femanager\Utility\FrontendUtility;
use Psr\EventDispatcher\EventDispatcherInterface;
use TYPO3\CMS\Core\EventDispatcher\EventDispatcher;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator as AbstractValidatorExtbase;
/**
* Class GeneralValidator
*/
abstract class AbstractValidator extends AbstractValidatorExtbase
{
protected ?UserRepository $userRepository = null;
public ?ConfigurationManagerInterface $configurationManager = null;
protected ?EventDispatcherInterface $eventDispatcher = null;
/**
* Former known as piVars
*
* @var array
*/
public $pluginVariables;
/**
* Validationsettings
*/
public $validationSettings = [];
/**
* Is Valid
*/
protected $isValid = true;
/**
* @param UserRepository $userRepository
*/
public function injectUserRepository(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
/**
* @param ConfigurationManagerInterface $configurationManager
*/
public function injectConfigurationManagerInterface(ConfigurationManagerInterface $configurationManager)
{
$this->configurationManager = $configurationManager;
}
/**
* @param EventDispatcherInterface $eventDispatcher
*/
public function injectEventDispatcherInterface(EventDispatcherInterface $eventDispatcher)
{
$this->eventDispatcher = $eventDispatcher;
}
public function initializeObject(): void
{
if ($this->configurationManager === null) {
$this->configurationManager = GeneralUtility::makeInstance(ConfigurationManagerInterface::class);
}
if ($this->eventDispatcher === null) {
$this->eventDispatcher = GeneralUtility::makeInstance(EventDispatcher::class);
}
if ($this->userRepository === null) {
$this->userRepository = GeneralUtility::makeInstance(UserRepository::class);
}
}
/**
* Validation for required
*
* @param mixed $value
* @return \bool
*/
protected function validateRequired($value)
{
if (!is_object($value)) {
if (is_numeric($value)) {
return true;
}
return !empty($value);
}
if ((is_array($value) || $value instanceof \Countable) && count($value) > 0) {
return true;
}
if ($value instanceof \DateTime) {
return true;
}
return false;
}
/**
* Validation for email
*
* @param string $value
* @return \bool
*/
protected function validateEmail($value)
{
return GeneralUtility::validEmail($value);
}
/**
* Validation for Minimum of characters
*
* @param string $value
* @param string $validationSetting
* @return \bool
*/
protected function validateMin($value, $validationSetting)
{
if (mb_strlen($value) < $validationSetting) {
return false;
}
return true;
}
/**
* Validation for Maximum of characters
*
* @param string $value
* @param string $validationSetting
* @return \bool
*/
protected function validateMax($value, $validationSetting)
{
if (mb_strlen($value) > $validationSetting) {
return false;
}
return true;
}
/**
* Validation for Numbers only
*
* @param string $value
* @return \bool
*/
protected function validateInt($value)
{
return is_numeric($value);
}
/**
* Validation for Letters (a-zA-Z), hyphen and underscore
*
* @param string $value
* @return \bool
*/
protected function validateLetters($value)
{
if (preg_replace('/[^a-zA-Z_-]/', '', $value) === $value) {
return true;
}
return false;
}
/**
* Validation for all Unicode letters, hyphen and underscore
*
* @param string $value
* @return \bool
*/
protected function validateUnicodeLetters($value)
{
return (bool)preg_match('/^[\pL_-]+$/u', $value);
}
/**
* Validation for Unique in sysfolder
*
* @param string $value
* @param string $field
* @param User $user Existing User
* @return \bool
*/
protected function validateUniquePage($value, $field, User $user = null)
{
$foundUser = $this->userRepository->checkUniquePage($field, $value, $user);
return !is_object($foundUser);
}
/**
* Validation for Unique in the db
*
* @param string $value
* @param string $field Fieldname like "username" or "email"
* @param User $user Existing User
* @return \bool
*/
protected function validateUniqueDb($value, $field, User $user = null)
{
$foundUser = $this->userRepository->checkUniqueDb($field, $value, $user);
$uniqueDb = !is_object($foundUser);
// return false, if is not unique
return $this->eventDispatcher->dispatch(new UniqueUserEvent($value, $field, $user, $uniqueDb))->isUnique();
}
/**
* Validation for "Must include some characters"
*
* @param string $value
* @param string $validationSettingList
* @return \bool
*/
protected function validateMustInclude($value, $validationSettingList)
{
$isValid = true;
$validationSettings = GeneralUtility::trimExplode(',', $validationSettingList, true);
foreach ($validationSettings as $validationSetting) {
switch ($validationSetting) {
case 'number':
if (!$this->stringContainsNumber($value)) {
$isValid = false;
}
break;
case 'letter':
if (!$this->stringContainsLetter($value)) {
$isValid = false;
}
break;
case 'uppercase':
if (!$this->stringContainsUppercase($value)) {
$isValid = false;
}
break;
case 'special':
if (!$this->stringContainsSpecialCharacter($value)) {
$isValid = false;
}
break;
case 'space':
if (!$this->stringContainsSpaceCharacter($value)) {
$isValid = false;
}
break;
default:
}
}
return $isValid;
}
/**
* Validation for "Must not include some characters"
*
* @param string $value
* @param string $validationSettingList
* @return \bool
*/
protected function validateMustNotInclude($value, $validationSettingList)
{
$isValid = true;
$validationSettings = GeneralUtility::trimExplode(',', $validationSettingList, true);
foreach ($validationSettings as $validationSetting) {
switch ($validationSetting) {
case 'number':
if ($this->stringContainsNumber($value)) {
$isValid = false;
}
break;
case 'letter':
if ($this->stringContainsLetter($value)) {
$isValid = false;
}
break;
case 'uppercase':
if ($this->stringContainsUppercase($value)) {
$isValid = false;
}
break;
case 'special':
if ($this->stringContainsSpecialCharacter($value)) {
$isValid = false;
}
break;
case 'space':
if ($this->stringContainsSpaceCharacter($value)) {
$isValid = false;
}
break;
default:
}
}
return $isValid;
}
/**
* String contains number?
*
* @param string $value
* @return bool
*/
protected function stringContainsNumber($value)
{
return strlen(preg_replace('/[^0-9]/', '', $value)) > 0;
}
/**
* String contains letter?
*
* @param string $value
* @return bool
*/
protected function stringContainsLetter($value)
{
return strlen(preg_replace('/[^a-zA-Z_-]/', '', $value)) > 0;
}
/**
* String contains uppercase letter?
*
* @param string $value
* @return bool
*/
protected function stringContainsUppercase($value)
{
return strlen(preg_replace('/[^A-Z]/', '', $value)) > 0;
}
/**
* String contains special character?
*
* @param string $value
* @return bool
*/
protected function stringContainsSpecialCharacter($value)
{
return strlen(preg_replace('/[^a-zA-Z0-9]/', '', $value)) !== strlen($value);
}
/**
* String contains space character?
*
* @param string $value
* @return bool
*/
protected function stringContainsSpaceCharacter($value)
{
return strpos($value, ' ') !== false;
}
/**
* Validation for checking if values are in a given list
*
* @param string $value
* @param string $validationSettingList
* @return \bool
*/
protected function validateInList($value, $validationSettingList)
{
$valueList = GeneralUtility::trimExplode(',', $value, true);
$validationSettings = GeneralUtility::trimExplode(',', $validationSettingList, true);
$diff = array_diff($valueList, $validationSettings);
return empty($diff);
}
/**
* Validation for comparing two fields
*
* @param string $value
* @param string $value2
* @return \bool
*/
protected function validateSameAs($value, $value2)
{
if ($value === $value2) {
return true;
}
return false;
}
/**
* Validation for checking if values is in date format
*
* @param string $value
* @param string $validationSetting
* @return \bool
*/
protected function validateDate($value, $validationSetting)
{
$dateParts = [];
switch ($validationSetting) {
case 'd.m.Y':
if (preg_match('/^([0-9]{2})\.([0-9]{2})\.([0-9]{4})$/', $value, $dateParts)) {
if (checkdate((int)$dateParts[2], (int)$dateParts[1], (int)$dateParts[3])) {
return true;
}
}
break;
case 'm/d/Y':
if (preg_match('/^([0-9]{2})\/([0-9]{2})\/([0-9]{4})$/', $value, $dateParts)) {
if (checkdate((int)$dateParts[1], (int)$dateParts[2], (int)$dateParts[3])) {
return true;
}
}
break;
default:
}
return false;
}
protected function init()
{
$this->initializeObject();
$this->setPluginVariables();
$this->setValidationSettings();
}
protected function setPluginVariables()
{
$this->pluginVariables = GeneralUtility::_GP('tx_femanager_pi1');
}
protected function setValidationSettings()
{
$config = $this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS,
'Femanager',
'Pi1'
);
$this->validationSettings = $config[$this->getControllerName()][$this->getValidationName()];
}
/**
* @return string
*/
protected function getValidationName(): string
{
$validationName = 'validation';
if ($this->getControllerName() === 'invitation' && $this->getActionName() === 'edit') {
$validationName = 'validationEdit';
}
return $validationName;
}
/**
* @return string
*/
protected function getActionName(): string
{
return $this->pluginVariables['__referrer']['@action'];
}
/**
* Get controller name in lowercase
*
* @return string
*/
protected function getControllerName(): string
{
$controllerName = 'new';
if ($this->pluginVariables['__referrer']['@controller'] === 'Edit') {
$controllerName = 'edit';
} elseif ($this->pluginVariables['__referrer']['@controller'] === 'Invitation') {
$controllerName = 'invitation';
}
$this->checkAllowedControllerName($controllerName);
return $controllerName;
}
/**
* @param string $controllerName
*/
protected function checkAllowedControllerName(string $controllerName)
{
$pluginRepository = GeneralUtility::makeInstance(PluginRepository::class);
$pageIdentifier = FrontendUtility::getCurrentPid();
if ($pluginRepository->isPluginWithViewOnGivenPage($controllerName, $pageIdentifier) === false) {
throw new \LogicException('ControllerName is not allowed', 1541506524);
}
}
}
@@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Validator;
use SJBR\SrFreecap\Domain\Repository\WordRepository;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Class CaptchaValidator
*/
class CaptchaValidator extends AbstractValidator
{
/**
* Validation of given Params
*
* @param $user
* @return bool
*/
public function isValid($user)
{
$this->init();
if (!$this->captchaEnabled() || $this->validCaptcha()) {
return true;
}
$this->addError('validationErrorCaptcha', 0, ['fieldName' => 'captcha']);
return false;
}
/**
* Check if captcha is valid
*
* @return bool
*/
protected function validCaptcha()
{
$isValid = false;
$wordRepository = GeneralUtility::makeInstance(WordRepository::class);
$wordObject = $wordRepository->getWord();
$wordHash = $wordObject->getWordHash();
if (!empty($wordHash) && !empty($this->pluginVariables['captcha'])) {
if ($wordObject->getHashFunction() == 'md5') {
if (md5(strtolower(mb_convert_encoding((string)$this->pluginVariables['captcha'], 'ISO-8859-1'))) == $wordHash) {
$wordRepository->cleanUpWord();
$isValid = true;
}
}
}
return $isValid;
}
/**
* Check if captcha is enabled (TypoScript, and sr_freecap loaded)
*
* @return bool
*/
protected function captchaEnabled()
{
return ExtensionManagementUtility::isLoaded('sr_freecap')
&& !empty($this->validationSettings['captcha']['captcha']);
}
}
@@ -0,0 +1,482 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Validator;
use In2code\Femanager\Domain\Model\User;
use In2code\Femanager\Domain\Repository\PluginRepository;
use In2code\Femanager\Domain\Service\ValidationSettingsService;
use In2code\Femanager\Utility\LocalizationUtility;
use In2code\Femanager\Utility\StringUtility;
use SJBR\SrFreecap\Domain\Repository\WordRepository;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Class ClientsideValidator
*/
class ClientsideValidator extends AbstractValidator
{
/**
* Validation settings string
* possible validations for each field are:
* required, email, min(12), max(13), intOnly, lettersOnly,unicodeLettersOnly
* uniqueInPage, uniqueInDb, date, mustInclude(number,letter,special),
* inList(1,2,3)
*
* @var string
*/
protected $validationSettingsString;
/**
* Field Value
*
* @var string
*/
protected $value;
/**
* Field Name
*
* @var string
*/
protected $fieldName;
/**
* User
*
* @var User
*/
protected $user;
/**
* Error message container
*
* @var array
*/
protected $messages = [];
/**
* Additional Values (for comparing a value with another)
*
* @var string
*/
protected $additionalValue;
/**
* @var int
*/
protected $plugin = 0;
/**
* @var string
*/
protected $actionName = '';
/**
* Validate Field
*
* @return bool
*/
public function validateField()
{
if ($this->isValidationSettingsDifferentToGlobalSettings()) {
$this->addMessage('validationErrorGeneral');
return false;
}
foreach ($this->getValidationSettings() as $validationSetting) {
switch ($validationSetting) {
case 'required':
if (!$this->validateRequired($this->getValue())) {
$this->addMessage('validationErrorRequired');
$this->isValid = false;
}
break;
case 'email':
if ($this->getValue() && !$this->validateEmail($this->getValue())) {
$this->addMessage('validationErrorEmail');
$this->isValid = false;
}
break;
case stristr($validationSetting, 'min('):
if ($this->getValue() &&
!$this->validateMin($this->getValue(), StringUtility::getValuesInBrackets($validationSetting))
) {
$this->addMessage('validationErrorMin');
$this->isValid = false;
}
break;
case stristr($validationSetting, 'max('):
if ($this->getValue() &&
!$this->validateMax($this->getValue(), StringUtility::getValuesInBrackets($validationSetting))
) {
$this->addMessage('validationErrorMax');
$this->isValid = false;
}
break;
case 'intOnly':
if ($this->getValue() && !$this->validateInt($this->getValue())) {
$this->addMessage('validationErrorInt');
$this->isValid = false;
}
break;
case 'lettersOnly':
if ($this->getValue() && !$this->validateLetters($this->getValue())) {
$this->addMessage('validationErrorLetters');
$this->isValid = false;
}
break;
case 'unicodeLettersOnly':
if ($this->getValue() && !$this->validateUnicodeLetters($this->getValue())) {
$this->addMessage('validationErrorLetters');
$this->isValid = false;
}
break;
case 'uniqueInPage':
if ($this->getValue() &&
!$this->validateUniquePage($this->getValue(), $this->getFieldName(), $this->getUser())
) {
$this->addMessage('validationErrorUniquePage');
$this->isValid = false;
}
break;
case 'uniqueInDb':
if ($this->getValue() &&
!$this->validateUniqueDb($this->getValue(), $this->getFieldName(), $this->getUser())
) {
$this->addMessage('validationErrorUniqueDb');
$this->isValid = false;
}
break;
case stristr($validationSetting, 'mustInclude('):
if ($this->getValue() &&
!$this->validateMustInclude(
$this->getValue(),
StringUtility::getValuesInBrackets($validationSetting)
)
) {
$this->addMessage('validationErrorMustInclude');
$this->isValid = false;
}
break;
case stristr($validationSetting, 'mustNotInclude('):
if ($this->getValue() &&
!$this->validateMustNotInclude(
$this->getValue(),
StringUtility::getValuesInBrackets($validationSetting)
)
) {
$this->addMessage('validationErrorMustNotInclude');
$this->isValid = false;
}
break;
case stristr($validationSetting, 'inList('):
if (!$this->validateInList(
$this->getValue(),
StringUtility::getValuesInBrackets($validationSetting)
)) {
$this->addMessage('validationErrorInList');
$this->isValid = false;
}
break;
case stristr($validationSetting, 'sameAs('):
if (!$this->validateSameAs($this->getValue(), $this->getAdditionalValue())) {
$this->addMessage('validationErrorSameAs');
$this->isValid = false;
}
break;
case 'date':
if ($this->getValue() &&
!$this->validateDate(
$this->getValue(),
LocalizationUtility::translate('tx_femanager_domain_model_user.dateFormat')
)
) {
$this->addMessage('validationErrorDate');
$this->isValid = false;
}
break;
case stristr($validationSetting, 'captcha('):
if (ExtensionManagementUtility::isLoaded('sr_freecap')) {
$wordRepository = GeneralUtility::makeInstance(
WordRepository::class
);
$wordObject = $wordRepository->getWord();
$wordHash = $wordObject->getWordHash();
$userVal = md5(strtolower(mb_convert_encoding($this->getValue(), 'ISO-8859-1')));
if ($wordHash !== $userVal) {
$this->addMessage('validationErrorCaptcha', 'captcha');
$this->isValid = false;
}
}
break;
default:
// e.g. search for method validateCustom()
$mainSetting = StringUtility::getValuesBeforeBrackets($validationSetting);
if (method_exists($this, 'validate' . ucfirst($mainSetting))) {
if (!$this->{'validate' . ucfirst($mainSetting)}(
$this->getValue(),
StringUtility::getValuesInBrackets($validationSetting)
)) {
$this->addMessage('validationError' . ucfirst($mainSetting));
$this->isValid = false;
}
}
}
}
return $this->isValid;
}
/**
* This function checks the given validation string from user input against settings in TypoScript. If both strings
* do not match, it could be possible that there is a manipulation. In this case, we stop validation and return a
* global error message
*
* @return bool
*/
protected function isValidationSettingsDifferentToGlobalSettings(): bool
{
return $this->getValidationSettingsString() !== $this->getValidationSettingsFromTypoScript();
}
/**
* Set validation
*
* @param string $validationSettingsString
* @return ClientsideValidator
*/
public function setValidationSettingsString($validationSettingsString)
{
$this->validationSettingsString = $validationSettingsString;
return $this;
}
/**
* @return string
*/
public function getValidationSettingsString()
{
return $this->validationSettingsString;
}
/**
* @return string
*/
public function getValidationSettingsFromTypoScript(): string
{
$controllerName = $this->getControllerName();
$validationService = GeneralUtility::makeInstance(
ValidationSettingsService::class,
$controllerName,
$this->getValidationName()
);
return $validationService->getValidationStringForField($this->fieldName);
}
/**
* @return array
*/
protected function getValidationSettings(): array
{
$validationSettings = GeneralUtility::trimExplode(',', $this->validationSettingsString, true);
$validationSettings = str_replace('|', ',', $validationSettings);
return $validationSettings;
}
/**
* @param string $value
* @return ClientsideValidator
*/
public function setValue($value)
{
$this->value = $value;
return $this;
}
/**
* @return string
*/
public function getValue()
{
return $this->value;
}
/**
* Add a message to the errormessage array
*
* @param string $message
*/
public function addMessage($message)
{
$this->messages = array_merge($this->messages, [$message]);
}
/**
* @param array $messages
* @return ClientsideValidator
*/
public function setMessages($messages)
{
$this->messages = $messages;
return $this;
}
/**
* @return array
*/
public function getMessages()
{
return $this->messages;
}
/**
* @param string $fieldName
* @return ClientsideValidator
*/
public function setFieldName($fieldName)
{
$this->fieldName = $fieldName;
return $this;
}
/**
* @return string
*/
public function getFieldName()
{
return $this->fieldName;
}
/**
* @param User $user
* @return ClientsideValidator
*/
public function setUser(User $user = null)
{
$this->user = $user;
return $this;
}
/**
* @return User
*/
public function getUser()
{
return $this->user;
}
/**
* @param string $additionalValue
* @return ClientsideValidator
*/
public function setAdditionalValue($additionalValue)
{
$this->additionalValue = $additionalValue;
return $this;
}
/**
* @return string
*/
public function getAdditionalValue()
{
return $this->additionalValue;
}
/**
* @return int
*/
public function getPlugin(): int
{
return $this->plugin;
}
/**
* @param int $plugin
* @return ClientsideValidator
*/
public function setPlugin(int $plugin)
{
$this->plugin = $plugin;
return $this;
}
/**
* @return string
*/
public function getActionName(): string
{
return $this->actionName;
}
/**
* @param string $actionName
* @return ClientsideValidator
*/
public function setActionName(string $actionName)
{
$this->actionName = $actionName;
return $this;
}
/**
* @return string
*/
protected function getValidationName(): string
{
$validationName = 'validation';
if ($this->getControllerName() === 'invitation' && $this->getActionName() === 'edit') {
$validationName = 'validationEdit';
}
return $validationName;
}
/**
* @return string
*/
protected function getControllerName(): string
{
$pluginRepository = GeneralUtility::makeInstance(PluginRepository::class);
$controllerName = $pluginRepository->getControllerNameByPluginSettings($this->getPlugin());
return $controllerName;
}
/**
* @param mixed $value
*/
protected function isValid($value)
{
}
}
@@ -0,0 +1,145 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Validator;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator as AbstractValidatorExtbase;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
/**
* Class PasswordValidator
*/
class PasswordValidator extends AbstractValidatorExtbase
{
public ?ConfigurationManagerInterface $configurationManager = null;
/**
* Content Object
*
* @var object
*/
protected $cObj;
/**
* Plugin Variables
*
* @var array
*/
public $piVars = [];
/**
* TypoScript Configuration
*
* @var array
*/
public $configuration = [];
/**
* Action Name
*
* @var string
*/
protected $actionName;
/**
* @param ConfigurationManagerInterface $configurationManager
*/
public function injectConfigurationManagerInterface(ConfigurationManagerInterface $configurationManager)
{
$this->configurationManager = $configurationManager;
}
public function initializeObject(): void
{
if ($this->configurationManager === null) {
$this->configurationManager = GeneralUtility::makeInstance(ConfigurationManagerInterface::class);
}
}
/**
* Validation of given Params
*
* @param $user
* @return bool
*/
public function isValid($user)
{
$this->initializeObject();
$this->init();
// if password fields are not active or if keep function active
if (!$this->passwordFieldsAdded() || $this->keepPasswordIfEmpty()) {
return true;
}
$password = $user->getPassword();
$passwordRepeat = isset($this->piVars['password_repeat']) ? $this->piVars['password_repeat'] : '';
if ($password !== $passwordRepeat) {
$this->addError('validationErrorPasswordRepeat', 0, ['field' => 'password']);
return false;
}
return true;
}
/**
* Check if Passwords are empty and if keep configuration is active
*
* @return bool
*/
protected function keepPasswordIfEmpty()
{
if (isset($this->configuration['edit']['misc']['keepPasswordIfEmpty']) &&
$this->configuration['edit']['misc']['keepPasswordIfEmpty'] === '1' &&
isset($this->piVars['user']['password']) && $this->piVars['user']['password'] === '' &&
isset($this->piVars['password_repeat']) && $this->piVars['password_repeat'] === ''
) {
return true;
}
return false;
}
/**
* Check if password fields are added with flexform
*
* @return bool
*/
protected function passwordFieldsAdded()
{
$flexFormValues = GeneralUtility::xml2array($this->cObj->data['pi_flexform']);
if (is_array($flexFormValues)) {
$fields =
$flexFormValues['data'][$this->actionName]['lDEF']['settings.' . $this->actionName . '.fields']['vDEF'] ?? [];
if (empty($fields) || GeneralUtility::inList($fields, 'password')) {
// password fields are added to form
return true;
}
}
// password fields are not added to form
return false;
}
/**
* Initialize Validator Function
*/
protected function init()
{
$this->configuration = $this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS,
'Femanager',
'Pi1'
);
$this->cObj = $this->configurationManager->getContentObject();
$this->piVars = GeneralUtility::_GP('tx_femanager_pi1');
$this->actionName = $this->piVars['__referrer']['@action'];
}
public function setContentObjectRenderer(ContentObjectRenderer $cObj): void
{
$this->cObj = $cObj;
}
}
@@ -0,0 +1,403 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Validator;
use In2code\Femanager\Domain\Model\User;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
/**
* Class ServersideValidator
*/
class ServersideValidator extends AbstractValidator
{
/**
* Validation of given Params
*
* @param User $user
* @return bool
*/
public function isValid($user): bool
{
$this->init();
if ($this->validationSettings['_enable']['server'] === '1') {
foreach ($this->validationSettings as $fieldName => $validations) {
if ($this->shouldBeValidated($user, $fieldName, $validations)) {
$value = $this->getValue($user, $fieldName);
foreach ($validations as $validation => $validationSetting) {
switch ($validation) {
case 'required':
$this->checkRequiredValidation($validationSetting, $value, $fieldName);
break;
case 'email':
$this->checkEmailValidation($value, $validationSetting, $fieldName);
break;
case 'min':
$this->checkMinValidation($value, $validationSetting, $fieldName);
break;
case 'max':
$this->checkMaxValidation($value, $validationSetting, $fieldName);
break;
case 'intOnly':
$this->checkIntOnlyValidation($value, $validationSetting, $fieldName);
break;
case 'lettersOnly':
$this->checkLetterOnlyValidation($value, $validationSetting, $fieldName);
break;
case 'unicodeLettersOnly':
$this->checkUnicodeLetterOnlyValidation($value, $validationSetting, $fieldName);
break;
case 'uniqueInPage':
$this->checkUniqueInPageValidation($user, $value, $validationSetting, $fieldName);
break;
case 'uniqueInDb':
$this->checkUniqueInDbValidation($user, $value, $validationSetting, $fieldName);
break;
case 'mustInclude':
$this->checkMustIncludeValidation($value, $validationSetting, $fieldName);
break;
case 'mustNotInclude':
$this->checkMustNotIncludeValidation($value, $validationSetting, $fieldName);
break;
case 'inList':
$this->checkInListValidation($value, $validationSetting, $fieldName);
break;
case 'sameAs':
$this->checkSameAsValidation($user, $validationSetting, $value, $fieldName);
break;
case 'date':
// Nothing to do. ServersideValidator runs after converter
// If dateTimeConverter exception $value is the old DateTime Object => True
// If dateTimeConverter runs well we have an DateTime Object => True
break;
default:
// e.g. search for method validateCustom()
$this->checkAnyValidation($validation, $value, $validationSetting, $fieldName);
}
}
}
}
}
return $this->isValid;
}
/**
* @param $validationSetting
* @param $value
* @param $fieldName
*/
protected function checkRequiredValidation($validationSetting, $value, $fieldName)
{
if ($validationSetting === '1' && !$this->validateRequired($value)) {
$this->addErrorForProperty($fieldName, 'validationErrorRequired', 0, ['field' => $fieldName]);
$this->isValid = false;
}
}
/**
* @param $value
* @param $validationSetting
* @param $fieldName
*/
protected function checkEmailValidation($value, $validationSetting, $fieldName)
{
if (!empty($value) && $validationSetting === '1' && !$this->validateEmail($value)) {
$this->addErrorForProperty($fieldName, 'validationErrorEmail', 0, ['field' => $fieldName]);
$this->isValid = false;
}
}
/**
* @param $value
* @param $validationSetting
* @param $fieldName
*/
protected function checkMinValidation($value, $validationSetting, $fieldName)
{
if (!empty($value) && !$this->validateMin($value, $validationSetting)) {
$this->addErrorForProperty($fieldName, 'validationErrorMin', 0, ['field' => $fieldName]);
$this->isValid = false;
}
}
/**
* @param $value
* @param $validationSetting
* @param $fieldName
*/
protected function checkMaxValidation($value, $validationSetting, $fieldName)
{
if (!empty($value) && !$this->validateMax($value, $validationSetting)) {
$this->addErrorForProperty($fieldName, 'validationErrorMax', 0, ['field' => $fieldName]);
$this->isValid = false;
}
}
/**
* @param $value
* @param $validationSetting
* @param $fieldName
*/
protected function checkIntOnlyValidation($value, $validationSetting, $fieldName)
{
if (!empty($value) && $validationSetting === '1' && !$this->validateInt($value)) {
$this->addErrorForProperty($fieldName, 'validationErrorInt', 0, ['field' => $fieldName]);
$this->isValid = false;
}
}
/**
* @param $value
* @param $validationSetting
* @param $fieldName
*/
protected function checkLetterOnlyValidation($value, $validationSetting, $fieldName)
{
if (!empty($value) && $validationSetting === '1' && !$this->validateLetters($value)) {
$this->addErrorForProperty($fieldName, 'validationErrorLetters', 0, ['field' => $fieldName]);
$this->isValid = false;
}
}
/**
* @param $value
* @param $validationSetting
* @param $fieldName
*/
protected function checkUnicodeLetterOnlyValidation($value, $validationSetting, $fieldName)
{
if (!empty($value) && $validationSetting === '1' && !$this->validateUnicodeLetters($value)) {
$this->addErrorForProperty($fieldName, 'validationErrorLetters', 0, ['field' => $fieldName]);
$this->isValid = false;
}
}
/**
* @param $user
* @param $value
* @param $validationSetting
* @param $fieldName
*/
protected function checkUniqueInPageValidation($user, $value, $validationSetting, $fieldName)
{
if (
!empty($value) &&
$validationSetting === '1' &&
!$this->validateUniquePage($value, $fieldName, $user)
) {
$this->addErrorForProperty($fieldName, 'validationErrorUniquePage', 0, ['field' => $fieldName]);
$this->isValid = false;
}
}
/**
* @param $user
* @param $value
* @param $validationSetting
* @param $fieldName
*/
protected function checkUniqueInDbValidation($user, $value, $validationSetting, $fieldName)
{
if (
!empty($value) &&
$validationSetting === '1' &&
!$this->validateUniqueDb($value, $fieldName, $user)
) {
$this->addErrorForProperty($fieldName, 'validationErrorUniqueDb', 0, ['field' => $fieldName]);
$this->isValid = false;
}
}
/**
* @param $value
* @param $validationSetting
* @param $fieldName
*/
protected function checkMustIncludeValidation($value, $validationSetting, $fieldName)
{
if (!empty($value) && !$this->validateMustInclude($value, $validationSetting)) {
$this->addErrorForProperty($fieldName, 'validationErrorMustInclude', 0, ['field' => $fieldName]);
$this->isValid = false;
}
}
/**
* @param $value
* @param $validationSetting
* @param $fieldName
*/
protected function checkMustNotIncludeValidation($value, $validationSetting, $fieldName)
{
if (!empty($value) && !$this->validateMustNotInclude($value, $validationSetting)) {
$this->addErrorForProperty($fieldName, 'validationErrorMustNotInclude', 0, ['field' => $fieldName]);
$this->isValid = false;
}
}
/**
* @param $value
* @param $validationSetting
* @param $fieldName
*/
protected function checkInListValidation($value, $validationSetting, $fieldName)
{
if (!$this->validateInList($value, $validationSetting)) {
$this->addErrorForProperty($fieldName, 'validationErrorInList', 0, ['field' => $fieldName]);
$this->isValid = false;
}
}
/**
* @param $user
* @param $validationSetting
* @param $value
* @param $fieldName
*/
protected function checkSameAsValidation($user, $validationSetting, $value, $fieldName)
{
if (method_exists($user, 'get' . ucfirst($validationSetting))) {
$valueToCompare = $user->{'get' . ucfirst($validationSetting)}();
if (!$this->validateSameAs($value, $valueToCompare)) {
$this->addErrorForProperty($fieldName, 'validationErrorSameAs', 0, ['field' => $fieldName]);
$this->isValid = false;
}
}
}
/**
* @param $validation
* @param $value
* @param $validationSetting
* @param $fieldName
*/
protected function checkAnyValidation($validation, $value, $validationSetting, $fieldName)
{
if (method_exists($this, 'validate' . ucfirst($validation))) {
if (!$this->{'validate' . ucfirst($validation)}($value, $validationSetting)) {
$this->addErrorForProperty($fieldName, 'validationError' . ucfirst($validation), 0, ['field' => $fieldName]);
$this->isValid = false;
}
}
}
/**
* @param User $user
* @param string $fieldName
* @return string
*/
protected function getValue($user, $fieldName)
{
$value = $this->getValueFromProperty($user, $fieldName);
if ($value instanceof ObjectStorage) {
$values = [];
foreach ($value as $object) {
if (method_exists($object, 'getUid')) {
$values[] = $object->getUid();
}
if ($object instanceof FileReference) {
return true;
}
}
return implode(',', $values);
}
if (is_object($value)) {
if (method_exists($value, 'getUid')) {
return $value->getUid();
}
if (method_exists($value, 'getFirst')) {
return $value->getFirst()->getUid();
}
if (method_exists($value, 'current')) {
$current = $value->current();
if ($current instanceof FileReference) {
return true;
}
if ($current !== null) {
if (method_exists($current, 'getUid')) {
return $current->getUid();
}
}
}
}
return $value;
}
/**
* @param $user
* @param $fieldName
* @param array $validationSettings
* @return bool
*/
protected function shouldBeValidated($user, $fieldName, array $validationSettings): bool
{
return is_object($user)
&& $this->propertyHasGetterMethod($user, $fieldName)
&& $this->evaluateConditions($user, $fieldName, $validationSettings);
}
protected function evaluateConditions(User $user, string $fieldName, array $validationSettings)
{
if (array_key_exists('if', $validationSettings) && class_exists($validationSettings['if'])) {
$object = GeneralUtility::makeInstance($validationSettings['if']);
if ($object instanceof ValidationConditionInterface) {
return $object->shouldValidate($user, $fieldName, $validationSettings);
}
}
return true;
}
/**
* @param $user
* @param $fieldName
* @return mixed
*/
protected function getValueFromProperty($user, $fieldName)
{
$value = '';
try {
$value = ObjectAccess::getProperty($user, $fieldName);
} catch (\Exception $exception) {
unset($exception);
}
return $value;
}
/**
* @return bool
*/
protected function propertyHasGetterMethod($user, $fieldName): bool
{
try {
ObjectAccess::getProperty($user, $fieldName);
$getterExists = true;
} catch (\Exception $exception) {
unset($exception);
$getterExists = false;
}
return $getterExists === true;
}
}
@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Validator;
use In2code\Femanager\DataProvider\CountryZonesDataProvider;
use In2code\Femanager\Domain\Model\User;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
class ShouldValidateStateCondition implements ValidationConditionInterface
{
protected $isStaticInfoTablesLoaded;
protected $countryZonesDataProvider;
public function __construct()
{
$this->isStaticInfoTablesLoaded = ExtensionManagementUtility::isLoaded('static_info_tables');
if ($this->isStaticInfoTablesLoaded) {
$this->countryZonesDataProvider = GeneralUtility::makeInstance(CountryZonesDataProvider::class);
}
}
public function shouldValidate(User $user, string $fieldName, array $validationSettings): bool
{
return $this->isStaticInfoTablesLoaded
&& $this->countryHasZones(ObjectAccess::getProperty($user, 'country'));
}
protected function countryHasZones($countryIso3)
{
return $this->countryZonesDataProvider->hasCountryZonesForCountryIso3($countryIso3);
}
}
@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace In2code\Femanager\Domain\Validator;
use In2code\Femanager\Domain\Model\User;
interface ValidationConditionInterface
{
public function shouldValidate(User $user, string $fieldName, array $validationSettings): bool;
}