This commit is contained in:
Yuri Kuznetsov
2021-04-21 14:13:08 +03:00
parent 50db978fa2
commit efd64ecded
33 changed files with 246 additions and 160 deletions
@@ -42,12 +42,12 @@ class AsyncPoolFactory
$this->config = $config;
}
public function isSupported() : bool
public function isSupported(): bool
{
return Pool::isSupported();
}
public function create() : Pool
public function create(): Pool
{
return Pool
::create()
+1 -1
View File
@@ -37,5 +37,5 @@ interface Job
/**
* Run a job.
*/
public function run() : void;
public function run(): void;
}
+3 -3
View File
@@ -53,7 +53,7 @@ class JobFactory
* @return Job|JobTargeted
* @throws Error
*/
public function create(string $name) : object
public function create(string $name): object
{
$className = $this->getClassName($name);
@@ -69,7 +69,7 @@ class JobFactory
*
* @throws Error
*/
public function isPreparable(string $name) : bool
public function isPreparable(string $name): bool
{
$className = $this->getClassName($name);
@@ -84,7 +84,7 @@ class JobFactory
return false;
}
private function getClassName(string $name) : ?string
private function getClassName(string $name): ?string
{
return $this->classFinder->find('Jobs', ucfirst($name));
}
+8 -8
View File
@@ -110,7 +110,7 @@ class JobManager
}
}
protected function getLastRunTime() : int
protected function getLastRunTime(): int
{
$lastRunData = $this->fileManager->getPhpContents($this->lastRunTimeFile);
@@ -124,7 +124,7 @@ class JobManager
return (int) $lastRunTime;
}
protected function updateLastRunTime() : void
protected function updateLastRunTime(): void
{
$data = [
'time' => time(),
@@ -133,7 +133,7 @@ class JobManager
$this->fileManager->putPhpContents($this->lastRunTimeFile, $data, false, true);
}
protected function checkLastRunTime() : bool
protected function checkLastRunTime(): bool
{
$currentTime = time();
$lastRunTime = $this->getLastRunTime();
@@ -151,7 +151,7 @@ class JobManager
* Process jobs. Jobs will be created according scheduling. Then pending jobs will be processed.
* This method supposed to be called on every Cron run or loop iteration of the Daemon.
*/
public function process() : void
public function process(): void
{
if (!$this->checkLastRunTime()) {
$this->log->info('JobManager: Skip job processing. Too frequent execution.');
@@ -174,7 +174,7 @@ class JobManager
/**
* Process pending jobs from a specific queue. Jobs within a queue are processed one by one.
*/
public function processQueue(string $queue, int $limit) : void
public function processQueue(string $queue, int $limit): void
{
$params = QueueProcessorParams
::fromNothing()
@@ -188,7 +188,7 @@ class JobManager
$processor->process();
}
private function processMainQueue() : void
private function processMainQueue(): void
{
$limit = (int) $this->config->get('jobMaxPortion', 0);
@@ -205,7 +205,7 @@ class JobManager
/**
* Run a specific job by ID. A job status should be set to 'Ready'.
*/
public function runJobById(string $id) : void
public function runJobById(string $id): void
{
$this->jobRunner->runById($id);
}
@@ -215,7 +215,7 @@ class JobManager
*
* @throws Throwable
*/
public function runJob(JobEntity $job) : void
public function runJob(JobEntity $job): void
{
$this->jobRunner->runThrowingException($job);
}
+7 -7
View File
@@ -70,7 +70,7 @@ class JobRunner
/**
* Run a job entity. Does not throw exceptions.
*/
public function run(JobEntity $job) : void
public function run(JobEntity $job): void
{
$this->runInternal($job, false);
}
@@ -80,7 +80,7 @@ class JobRunner
*
* @throws Throwable
*/
public function runThrowingException(JobEntity $job) : void
public function runThrowingException(JobEntity $job): void
{
$this->runInternal($job, true);
}
@@ -89,7 +89,7 @@ class JobRunner
* Run a job by ID. A job must have status 'Ready'.
* Used when running jobs in parallel processes.
*/
public function runById(string $id) : void
public function runById(string $id): void
{
if ($id === '') {
throw new Error();
@@ -117,7 +117,7 @@ class JobRunner
$this->run($job);
}
private function runInternal(JobEntity $job, bool $throwException = false) : void
private function runInternal(JobEntity $job, bool $throwException = false): void
{
$isSuccess = true;
@@ -179,7 +179,7 @@ class JobRunner
}
}
protected function runJobByName(JobEntity $job) : void
protected function runJobByName(JobEntity $job): void
{
$jobName = $job->getJob();
@@ -198,7 +198,7 @@ class JobRunner
$obj->run();
}
protected function runScheduledJob(JobEntity $job) : void
protected function runScheduledJob(JobEntity $job): void
{
$jobName = $job->getScheduledJobJob();
@@ -223,7 +223,7 @@ class JobRunner
$obj->run();
}
protected function runService(JobEntity $job) : void
protected function runService(JobEntity $job): void
{
$serviceName = $job->getServiceName();
+2 -2
View File
@@ -42,10 +42,10 @@ interface JobTargeted
/**
* Run a job for a specific target.
*/
public function run(string $targetType, string $targetId, StdClass $data) : void;
public function run(string $targetType, string $targetId, StdClass $data): void;
/**
* Create multiple job records for a scheduled job.
*/
public function prepare(ScheduledJob $scheduledJob, string $executeTime) : void;
public function prepare(ScheduledJob $scheduledJob, string $executeTime): void;
}
+2 -2
View File
@@ -66,7 +66,7 @@ class QueueProcessor
$this->entityManager = $entityManager;
}
public function process() : void
public function process(): void
{
$pool = null;
@@ -88,7 +88,7 @@ class QueueProcessor
}
}
protected function processJob(JobEntity $job, ?AsyncPool $pool = null) : void
protected function processJob(JobEntity $job, ?AsyncPool $pool = null): void
{
$useProcessPool = $this->params->useProcessPool();
@@ -42,7 +42,7 @@ class QueueProcessorFactory
$this->injectableFactory = $injectableFactory;
}
public function create(QueueProcessorParams $params) : QueueProcessor
public function create(QueueProcessorParams $params): QueueProcessor
{
return $this->injectableFactory->createWith(QueueProcessor::class, [
'params' => $params,
@@ -39,7 +39,7 @@ class QueueProcessorParams
private $limit = 0;
public function withUseProcessPool(bool $useProcessPool) : self
public function withUseProcessPool(bool $useProcessPool): self
{
$obj = clone $this;
@@ -48,7 +48,7 @@ class QueueProcessorParams
return $obj;
}
public function withNoLock(bool $noLock) : self
public function withNoLock(bool $noLock): self
{
$obj = clone $this;
@@ -57,7 +57,7 @@ class QueueProcessorParams
return $obj;
}
public function withQueue(?string $queue) : self
public function withQueue(?string $queue): self
{
$obj = clone $this;
@@ -66,7 +66,7 @@ class QueueProcessorParams
return $obj;
}
public function withLimit(int $limit) : self
public function withLimit(int $limit): self
{
$obj = clone $this;
@@ -75,27 +75,27 @@ class QueueProcessorParams
return $obj;
}
public function useProcessPool() : bool
public function useProcessPool(): bool
{
return $this->useProcessPool;
}
public function noLock() : bool
public function noLock(): bool
{
return $this->noLock;
}
public function getQueue() : ?string
public function getQueue(): ?string
{
return $this->queue;
}
public function getLimit() : int
public function getLimit(): int
{
return $this->limit;
}
public static function fromNothing() : self
public static function fromNothing(): self
{
return new self();
}
+13 -13
View File
@@ -59,7 +59,7 @@ class QueueUtil
$this->scheduleUtil = $scheduleUtil;
}
public function isJobPending(string $id) : bool
public function isJobPending(string $id): bool
{
$job = $this->entityManager
->getRepository('Job')
@@ -77,7 +77,7 @@ class QueueUtil
return $job->get('status') === JobManager::PENDING;
}
public function getPendingJobList(?string $queue = null, int $limit = 0) : Collection
public function getPendingJobList(?string $queue = null, int $limit = 0): Collection
{
$builder = $this->entityManager
->getRDBRepository('Job')
@@ -109,7 +109,7 @@ class QueueUtil
public function isScheduledJobRunning(
string $scheduledJobId, ?string $targetId = null, ?string $targetType = null
) : bool {
): bool {
$where = [
'scheduledJobId' => $scheduledJobId,
@@ -128,7 +128,7 @@ class QueueUtil
->findOne();
}
public function getRunningScheduledJobIdList() : array
public function getRunningScheduledJobIdList(): array
{
$list = [];
@@ -150,7 +150,7 @@ class QueueUtil
return $list;
}
public function hasScheduledJobOnMinute(string $scheduledJobId, string $time) : bool
public function hasScheduledJobOnMinute(string $scheduledJobId, string $time): bool
{
$dateObj = new DateTime($time);
@@ -168,7 +168,7 @@ class QueueUtil
return (bool) $job;
}
public function getPendingCountByScheduledJobId(string $scheduledJobId) : int
public function getPendingCountByScheduledJobId(string $scheduledJobId): int
{
$countPending = $this->entityManager
->getRDBRepository('Job')
@@ -181,7 +181,7 @@ class QueueUtil
return $countPending;
}
public function markJobsFailed() : void
public function markJobsFailed(): void
{
$this->markJobsFailedByNotExistingProcesses();
$this->markJobsFailedReadyNotStarted();
@@ -189,7 +189,7 @@ class QueueUtil
$this->markJobsFailedByPeriod();
}
protected function markJobsFailedByNotExistingProcesses() : void
protected function markJobsFailedByNotExistingProcesses(): void
{
$timeThreshold = time() - $this->config->get(
'jobPeriodForNotExistingProcess',
@@ -226,7 +226,7 @@ class QueueUtil
$this->markJobListFailed($failedJobList);
}
protected function markJobsFailedReadyNotStarted() : void
protected function markJobsFailedReadyNotStarted(): void
{
$timeThreshold = time() -
$this->config->get('jobPeriodForReadyNotStarted', SELF::READY_NOT_STARTED_PERIOD);
@@ -253,7 +253,7 @@ class QueueUtil
$this->markJobListFailed($failedJobList);
}
protected function markJobsFailedByPeriod(bool $isForActiveProcesses = false) : void
protected function markJobsFailedByPeriod(bool $isForActiveProcesses = false): void
{
$period = 'jobPeriod';
@@ -297,7 +297,7 @@ class QueueUtil
$this->markJobListFailed($failedJobList);
}
protected function markJobListFailed(iterable $jobList) : void
protected function markJobListFailed(iterable $jobList): void
{
if (!count($jobList)) {
return;
@@ -341,7 +341,7 @@ class QueueUtil
/**
* Remove pending duplicate jobs, no need to run twice the same job.
*/
public function removePendingJobDuplicates() : void
public function removePendingJobDuplicates(): void
{
$duplicateJobList = $this->entityManager
->getRepository('Job')
@@ -406,7 +406,7 @@ class QueueUtil
/**
* Handle job attempts. Change failed to pending if attempts left.
*/
public function updateFailedJobAttempts() : void
public function updateFailedJobAttempts(): void
{
$jobCollection = $this->entityManager
->getRDBRepository('Job')
@@ -81,7 +81,7 @@ class ScheduleProcessor
$this->jobFactory = $jobFactory;
}
public function process() : void
public function process(): void
{
$activeScheduledJobList = $this->scheduleUtil->getActiveScheduledJobList();
@@ -102,7 +102,7 @@ class ScheduleProcessor
private function createJobsFromScheduledJob(
ScheduledJobEntity $scheduledJob,
array $runningScheduledJobIdList
) : void {
): void {
$scheduling = $scheduledJob->getScheduling();
+2 -2
View File
@@ -46,7 +46,7 @@ class ScheduleUtil
/**
* Get active scheduled job list.
*/
public function getActiveScheduledJobList() : Collection
public function getActiveScheduledJobList(): Collection
{
return $this->entityManager
->getRepository('ScheduledJob')
@@ -71,7 +71,7 @@ class ScheduleUtil
?string $runTime = null,
?string $targetId = null,
?string $targetType = null
) : void{
): void {
if (!isset($runTime)) {
$runTime = date('Y-m-d H:i:s');
@@ -40,7 +40,7 @@ use RuntimeException;
class DefaultHandlerLoader
{
public function load(array $data, ?string $defaultLevel = null) : HandlerInterface
public function load(array $data, ?string $defaultLevel = null): HandlerInterface
{
$params = $data['params'] ?? [];
@@ -67,7 +67,7 @@ class DefaultHandlerLoader
return $handler;
}
protected function loadFormatter(array $data) : ?FormatterInterface
protected function loadFormatter(array $data): ?FormatterInterface
{
$formatterData = $data['formatter'] ?? null;
@@ -86,7 +86,7 @@ class DefaultHandlerLoader
return $this->createInstance($className, $params);
}
protected function createInstance(string $className, array $params) : object
protected function createInstance(string $className, array $params): object
{
$class = new ReflectionClass($className);
@@ -48,7 +48,7 @@ class EspoRotatingFileHandlerLoader implements HandlerLoader
$this->config = $config;
}
public function load(array $params) : HandlerInterface
public function load(array $params): HandlerInterface
{
$filename = $params['filename'] ?? 'data/logs/espo.log';
$level = $params['level'] ?? Logger::NOTICE;
@@ -46,7 +46,11 @@ class EspoRotatingFileHandler extends EspoFileHandler
protected $maxFiles;
public function __construct(
Config $config, string $filename, int $maxFiles = 0, $level = Logger::DEBUG, bool $bubble = true
Config $config,
string $filename,
int $maxFiles = 0,
$level = Logger::DEBUG,
bool $bubble = true
) {
$this->filename = $filename;
$this->maxFiles = (int) $maxFiles;
@@ -48,7 +48,7 @@ class HandlerListLoader
$this->defaultLoader = $defaultLoader;
}
public function load(array $dataList, ?string $defaultLevel = null) : array
public function load(array $dataList, ?string $defaultLevel = null): array
{
$handlerList = [];
@@ -65,7 +65,7 @@ class HandlerListLoader
return $handlerList;
}
protected function loadHandler(array $data, ?string $defaultLevel = null) : ?HandlerInterface
protected function loadHandler(array $data, ?string $defaultLevel = null): ?HandlerInterface
{
$params = $data['params'] ?? [];
+1 -1
View File
@@ -35,5 +35,5 @@ use Monolog\{
interface HandlerLoader
{
public function load(array $params) : HandlerInterface;
public function load(array $params): HandlerInterface;
}
+3 -2
View File
@@ -58,6 +58,7 @@ class LogLoader
const DEFAULT_LEVEL = 'WARNING';
protected $config;
protected $injectableFactory;
public function __construct(Config $config, InjectableFactory $injectableFactory)
@@ -66,7 +67,7 @@ class LogLoader
$this->injectableFactory = $injectableFactory;
}
public function load() : Log
public function load(): Log
{
$log = new Log('Espo');
@@ -97,7 +98,7 @@ class LogLoader
return $log;
}
protected function createDefaultHandler() : HandlerInterface
protected function createDefaultHandler(): HandlerInterface
{
$path = $this->config->get('logger.path') ?? self::PATH;
$rotation = $this->config->get('logger.rotation') ?? true;
+12 -12
View File
@@ -75,7 +75,7 @@ class EmailSender
$this->transportFactory = $transportFactory;
}
private function createSender() : Sender
private function createSender(): Sender
{
return new Sender(
$this->config,
@@ -90,7 +90,7 @@ class EmailSender
/**
* Create a builder.
*/
public function create() : Sender
public function create(): Sender
{
return $this->createSender();
}
@@ -100,7 +100,7 @@ class EmailSender
*
* Available parameters: fromAddress, fromName, replyToAddress, replyToName.
*/
public function withParams(array $params = []) : Sender
public function withParams(array $params = []): Sender
{
return $this->createSender()->withParams($params);
}
@@ -108,7 +108,7 @@ class EmailSender
/**
* With specific SMTP parameters.
*/
public function withSmtpParams(array $params = []) : Sender
public function withSmtpParams(array $params = []): Sender
{
return $this->createSender()->withSmtpParams($params);
}
@@ -116,7 +116,7 @@ class EmailSender
/**
* With specific attachments.
*/
public function withAttachments(iterable $attachmentList) : Sender
public function withAttachments(iterable $attachmentList): Sender
{
return $this->createSender()->withAttachments($attachmentList);
}
@@ -124,7 +124,7 @@ class EmailSender
/**
* With envelope options.
*/
public function withEnvelopeOptions(array $options) : Sender
public function withEnvelopeOptions(array $options): Sender
{
return $this->createSender()->withEnvelopeOptions($options);
}
@@ -132,7 +132,7 @@ class EmailSender
/**
* Set a message instance.
*/
public function withMessage(Message $message) : Sender
public function withMessage(Message $message): Sender
{
return $this->createSender()->message($message);
}
@@ -140,7 +140,7 @@ class EmailSender
/**
* Whether system STMP is configured.
*/
public function hasSystemSmtp() : bool
public function hasSystemSmtp(): bool
{
if ($this->config->get('smtpServer')) {
return true;
@@ -153,7 +153,7 @@ class EmailSender
return false;
}
private function getSystemInboundEmail() : ?InboundEmail
private function getSystemInboundEmail(): ?InboundEmail
{
$address = $this->config->get('outboundEmailFromAddress');
@@ -173,7 +173,7 @@ class EmailSender
return $this->systemInboundEmail;
}
private function getInboundEmailService() : InboundEmailService
private function getInboundEmailService(): InboundEmailService
{
if (!$this->inboundEmailService) {
$this->inboundEmailService = $this->serviceFactory->create('InboundEmail');
@@ -185,7 +185,7 @@ class EmailSender
/**
* Send an email.
*/
public function send(Email $email) : void
public function send(Email $email): void
{
$this->createSender()->send($email);
}
@@ -193,7 +193,7 @@ class EmailSender
/**
* Generate a message ID.
*/
static public function generateMessageId(Email $email) : string
static public function generateMessageId(Email $email): string
{
return Sender::generateMessageId($email);
}
+41 -18
View File
@@ -31,25 +31,16 @@ namespace Espo\Core\Mail;
use Espo\Entities\Email;
use Traversable;
class FiltersMatcher
{
protected function matchTo(Email $email, $filter)
public function match(Email $email, $subject, bool $skipBody = false): bool
{
if ($email->get('to')) {
$toArr = explode(';', $email->get('to'));
foreach ($toArr as $to) {
if ($this->matchString(strtolower($filter->get('to')), strtolower($to))) {
return true;
}
}
}
}
public function match(Email $email, $subject, $skipBody = false)
{
if (is_array($subject) || $subject instanceof \Traversable) {
if (is_array($subject) || $subject instanceof Traversable) {
$filterList = $subject;
} else {
}
else {
$filterList = [$subject];
}
@@ -58,7 +49,13 @@ class FiltersMatcher
if ($filter->get('from')) {
$filterCount++;
if (!$this->matchString(strtolower($filter->get('from')), strtolower($email->get('from')))) {
if (
!$this->matchString(
strtolower($filter->get('from')),
strtolower($email->get('from'))
)
) {
continue;
}
}
@@ -72,17 +69,21 @@ class FiltersMatcher
if ($filter->get('subject')) {
$filterCount++;
if (!$this->matchString($filter->get('subject'), $email->get('name'))) {
continue;
}
}
$wordList = $filter->get('bodyContains');
if (!empty($wordList)) {
$filterCount++;
if ($skipBody) {
continue;
}
if (!$this->matchBody($email, $filter)) {
continue;
}
@@ -97,31 +98,53 @@ class FiltersMatcher
return false;
}
protected function matchBody(Email $email, $filter)
protected function matchTo(Email $email, $filter): bool
{
if ($email->get('to')) {
$toArr = explode(';', $email->get('to'));
foreach ($toArr as $to) {
if ($this->matchString(strtolower($filter->get('to')), strtolower($to))) {
return true;
}
}
}
return false;
}
protected function matchBody(Email $email, $filter): bool
{
$phraseList = $filter->get('bodyContains');
$body = $email->get('body');
$bodyPlain = $email->get('bodyPlain');
foreach ($phraseList as $phrase) {
if (stripos($bodyPlain, $phrase) !== false) {
return true;
}
if (stripos($body, $phrase) !== false) {
return true;
}
}
return false;
}
protected function matchString($pattern, $value)
protected function matchString($pattern, $value): bool
{
if ($pattern == $value) {
return true;
}
$pattern = preg_quote($pattern, '#');
$pattern = str_replace('\*', '.*', $pattern).'\z';
if (preg_match('#^'.$pattern.'#', $value)) {
return true;
}
return false;
}
}
+1 -1
View File
@@ -83,7 +83,7 @@ class Importer
iterable $filterList = [],
bool $fetchOnlyHeader = false,
?array $folderData = null
) : ?Email {
): ?Email {
$parser = $message->getParser();
+23 -20
View File
@@ -119,7 +119,7 @@ class Sender
/**
* @deprecated
*/
public function resetParams() : self
public function resetParams(): self
{
$this->params = [];
$this->envelope = null;
@@ -135,7 +135,7 @@ class Sender
*
* Available parameters: fromAddress, fromName, replyToAddress, replyToName.
*/
public function withParams(array $params) : self
public function withParams(array $params): self
{
$paramList = [
'fromAddress',
@@ -158,7 +158,7 @@ class Sender
/**
* With specific SMTP parameters.
*/
public function withSmtpParams(array $params) : self
public function withSmtpParams(array $params): self
{
return $this->useSmtp($params);
}
@@ -166,7 +166,7 @@ class Sender
/**
* With specific attachments.
*/
public function withAttachments(iterable $attachmentList) : self
public function withAttachments(iterable $attachmentList): self
{
$this->attachmentList = $attachmentList;
@@ -176,7 +176,7 @@ class Sender
/**
* With envelope options.
*/
public function withEnvelopeOptions(array $options) : self
public function withEnvelopeOptions(array $options): self
{
return $this->setEnvelopeOptions($options);
}
@@ -184,7 +184,7 @@ class Sender
/**
* Set a message instance.
*/
public function withMessage(Message $message) : self
public function withMessage(Message $message): self
{
$this->message = $message;
@@ -194,7 +194,7 @@ class Sender
/**
* @deprecated
*/
public function setParams(array $params = []) : self
public function setParams(array $params = []): self
{
$this->params = array_merge($this->params, $params);
@@ -205,7 +205,7 @@ class Sender
/**
* @deprecated
*/
public function useSmtp(array $params = []) : self
public function useSmtp(array $params = []): self
{
$this->isGlobal = false;
@@ -217,7 +217,7 @@ class Sender
/**
* @deprecated
*/
public function useGlobal() : self
public function useGlobal(): self
{
$this->params = [];
@@ -226,7 +226,7 @@ class Sender
return $this;
}
private function applySmtp(array $params = []) : void
private function applySmtp(array $params = []): void
{
$this->params = $params;
@@ -297,7 +297,7 @@ class Sender
}
}
private function applyGlobal() : void
private function applyGlobal(): void
{
$config = $this->config;
@@ -331,7 +331,7 @@ class Sender
/**
* @deprecated
*/
public function hasSystemSmtp() : bool
public function hasSystemSmtp(): bool
{
if ($this->config->get('smtpServer')) {
return true;
@@ -344,7 +344,7 @@ class Sender
return false;
}
private function getSystemInboundEmail() : ?InboundEmail
private function getSystemInboundEmail(): ?InboundEmail
{
$address = $this->config->get('outboundEmailFromAddress');
@@ -364,7 +364,7 @@ class Sender
return $this->systemInboundEmail;
}
private function getInboundEmailService() : ?InboundEmailService
private function getInboundEmailService(): ?InboundEmailService
{
if (!$this->serviceFactory) {
return null;
@@ -385,8 +385,11 @@ class Sender
* @param $attachmentList @deprecated
*/
public function send(
Email $email, ?array $params = [], ?Message $message = null, iterable $attachmentList = []
) : void {
Email $email,
?array $params = [],
?Message $message = null,
iterable $attachmentList = []
): void {
if ($this->isGlobal) {
$this->applyGlobal();
@@ -649,7 +652,7 @@ class Sender
$this->useGlobal();
}
private function handleException(Exception $e) : void
private function handleException(Exception $e): void
{
if ($e instanceof ProtocolRuntimeException) {
$message = "Email sending error.";
@@ -672,7 +675,7 @@ class Sender
throw new Error($e->getMessage(), 500);
}
static public function generateMessageId(Email $email) : string
static public function generateMessageId(Email $email): string
{
$rand = mt_rand(1000, 9999);
@@ -697,14 +700,14 @@ class Sender
/**
* @deprecated
*/
public function setEnvelopeOptions(array $options) : self
public function setEnvelopeOptions(array $options): self
{
$this->envelope = new Envelope($options);
return $this;
}
private function addAddresses(Email $email, Message $message) : void
private function addAddresses(Email $email, Message $message): void
{
$value = $email->get('to');
@@ -35,7 +35,7 @@ use Laminas\{
class SmtpTransportFactory
{
public function create() : SmtpTransport
public function create(): SmtpTransport
{
return new SmtpTransport();
}
@@ -36,5 +36,5 @@ use Espo\ORM\Entity;
*/
interface AssignmentNotificator
{
public function process(Entity $entity, array $options = []) : void;
public function process(Entity $entity, array $options = []): void;
}
@@ -59,14 +59,14 @@ class AssignmentNotificatorFactory
*
* @return AssignmentNotificator
*/
public function create(string $entityType) : object // AssignmentNotificator
public function create(string $entityType): object // AssignmentNotificator
{
$className = $this->getClassName($entityType);
return $this->injectableFactory->create($className);
}
private function getClassName(string $entityType) : string
private function getClassName(string $entityType): string
{
$className1 = $this->metadata->get(['recordDefs', $entityType, 'assignmentNotificatorClassName']);
@@ -54,7 +54,7 @@ class DefaultAssignmentNotificator implements AssignmentNotificator
$this->userChecker = $userChecker;
}
public function process(Entity $entity, array $options = []) : void
public function process(Entity $entity, array $options = []): void
{
if ($entity->hasLinkMultipleField('assignedUsers')) {
$userIdList = $entity->getLinkMultipleIdList('assignedUsers');
@@ -88,7 +88,7 @@ class DefaultAssignmentNotificator implements AssignmentNotificator
$this->processForUser($entity, $assignedUserId);
}
protected function processForUser(Entity $entity, string $assignedUserId) : void
protected function processForUser(Entity $entity, string $assignedUserId): void
{
if (!$this->userChecker->checkAssignment($entity->getEntityType(), $assignedUserId)) {
return;
@@ -44,7 +44,7 @@ class UserEnabledChecker
$this->entityManager = $entityManager;
}
public function checkAssignment(string $entityType, string $userId) : bool
public function checkAssignment(string $entityType, string $userId): bool
{
$key = $entityType . '_' . $userId;
+78 -29
View File
@@ -45,6 +45,8 @@ use Espo\Core\{
Utils\TemplateFileManager,
};
use DateTime;
class Recovery
{
const REQUEST_DELAY = 3000;
@@ -52,9 +54,13 @@ class Recovery
const REQUEST_LIFETIME = '3 hours';
protected $entityManager;
protected $config;
protected $emailSender;
protected $htmlizerFactory;
protected $templateFileManager;
public function __construct(
@@ -71,7 +77,7 @@ class Recovery
$this->templateFileManager = $templateFileManager;
}
public function getRequest(string $id) : PasswordChangeRequest
public function getRequest(string $id): PasswordChangeRequest
{
$config = $this->config;
$em = $this->entityManager;
@@ -80,9 +86,12 @@ class Recovery
throw new Forbidden("Password recovery: Disabled.");
}
$request = $em->getRepository('PasswordChangeRequest')->where([
'requestId' => $id,
])->findOne();
$request = $em
->getRepository('PasswordChangeRequest')
->where([
'requestId' => $id,
])
->findOne();
if (!$request) {
throw new NotFound("Password recovery: Request not found by id.");
@@ -99,16 +108,20 @@ class Recovery
public function removeRequest(string $id)
{
$em = $this->entityManager;
$request = $em->getRepository('PasswordChangeRequest')->where([
'requestId' => $id,
])->findOne();
$request = $em
->getRepository('PasswordChangeRequest')
->where([
'requestId' => $id,
])
->findOne();
if ($request) {
$em->removeEntity($request);
}
}
public function request(string $emailAddress, ?string $userName = null, ?string $url) : bool
public function request(string $emailAddress, ?string $userName = null, ?string $url): bool
{
$config = $this->config;
$em = $this->entityManager;
@@ -119,48 +132,66 @@ class Recovery
throw new Forbidden("Password recovery: Disabled.");
}
$user = $em->getRepository('User')->where([
'userName' => $userName,
'emailAddress' => $emailAddress,
])->findOne();
$user = $em
->getRepository('User')
->where([
'userName' => $userName,
'emailAddress' => $emailAddress,
])
->findOne();
if (!$user) {
$this->fail("Password recovery: User {$emailAddress} not found.", 404);
return false;
}
if (!$user->isActive()) {
$this->fail("Password recovery: User {$user->id} is not active.");
return false;
}
if ($user->isApi() || $user->isSystem() || $user->isSuperAdmin()) {
$this->fail("Password recovery: User {$user->id} is not allowed.");
return false;
}
if ($config->get('passwordRecoveryForInternalUsersDisabled')) {
if ($user->isRegular() || $user->isAdmin()) {
$this->fail("Password recovery: User {$user->id} is not allowed, disabled for internal users.");
$this->fail(
"Password recovery: User {$user->id} is not allowed, disabled for internal users."
);
return false;
}
}
if ($config->get('passwordRecoveryForAdminDisabled')) {
if ($user->isAdmin()) {
$this->fail("Password recovery: User {$user->id} is not allowed, disabled for admin users.");
$this->fail(
"Password recovery: User {$user->id} is not allowed, disabled for admin users."
);
return false;
}
}
if (!$user->isAdmin() && $config->get('authenticationMethod', 'Espo') !== 'Espo') {
$this->fail("Password recovery: User {$user->id} is not allowed, authentication method is not 'Espo'.");
$this->fail(
"Password recovery: User {$user->id} is not allowed, authentication method is not 'Espo'."
);
return false;
}
$passwordChangeRequest = $em->getRepository('PasswordChangeRequest')->where([
'userId' => $user->id,
])->findOne();
$passwordChangeRequest = $em
->getRepository('PasswordChangeRequest')
->where([
'userId' => $user->id,
])
->findOne();
if ($passwordChangeRequest) {
if (!$noExposure) {
@@ -168,30 +199,34 @@ class Recovery
}
$this->fail("Password recovery: Denied for {$user->id}, already sent.");
return false;
}
$requestId = Util::generateCryptId();
$passwordChangeRequest = $em->getEntity('PasswordChangeRequest');
$passwordChangeRequest->set([
'userId' => $user->id,
'requestId' => $requestId,
'url' => $url,
]);
$microtime = microtime(true);
$this->send($requestId, $emailAddress, $user);
$em->saveEntity($passwordChangeRequest);
if (!$passwordChangeRequest->id) throw new Error();
if (!$passwordChangeRequest->id) {
throw new Error();
}
$lifetime = $config->get('passwordRecoveryRequestLifetime') ?? self::REQUEST_LIFETIME;
$dt = new \DateTime();
$dt = new DateTime();
$dt->modify('+' . $lifetime);
$em->createEntity('Job', [
@@ -231,7 +266,9 @@ class Recovery
$templateFileManager = $this->templateFileManager;
if (!$emailAddress) return;
if (!$emailAddress) {
return;
}
$email = $em->getEntity('Email');
@@ -247,10 +284,15 @@ class Recovery
$siteUrl = $config->getSiteUrl();
if ($user->isPortal()) {
$portal = $em->getRepository('Portal')->distinct()->join('users')->where([
'isActive' => true,
'users.id' => $user->id,
])->findOne();
$portal = $em->getRepository('Portal')
->distinct()
->join('users')
->where([
'isActive' => true,
'users.id' => $user->id,
])
->findOne();
if ($portal) {
if ($portal->get('customUrl')) {
$siteUrl = $portal->get('customUrl');
@@ -259,7 +301,9 @@ class Recovery
}
$data = [];
$link = $siteUrl . '?entryPoint=changePassword&id=' . $requestId;
$data['link'] = $link;
$htmlizer = $htmlizerFactory->create(true);
@@ -282,7 +326,10 @@ class Recovery
'username' => $config->get('internalSmtpUsername'),
'password' => $config->get('internalSmtpPassword'),
'security' => $config->get('internalSmtpSecurity'),
'fromAddress' => $config->get('internalOutboundEmailFromAddress', $config->get('outboundEmailFromAddress')),
'fromAddress' => $config->get(
'internalOutboundEmailFromAddress',
$config->get('outboundEmailFromAddress')
),
]);
}
@@ -302,9 +349,11 @@ class Recovery
if (!$noExposure) {
if ($errorCode === 403) {
throw new Forbidden();
} else if ($errorCode === 404) {
}
else if ($errorCode === 404) {
throw new NotFound();
} else {
}
else {
throw new Error();
}
}
@@ -48,7 +48,8 @@ class AclManagerContainer
private $injectableFactory;
public function __construct(InjectableFactory $injectableFactory) {
public function __construct(InjectableFactory $injectableFactory)
{
$this->injectableFactory = $injectableFactory;
}
@@ -46,6 +46,7 @@ class Event extends \Espo\Services\Record
protected function loadRemindersField(Entity $entity)
{
$reminders = $this->getRepository()->getEntityReminderList($entity);
$entity->set('reminders', $reminders);
}
}
@@ -52,7 +52,11 @@ class Person extends \Espo\Services\Record
if (
($entity->get('emailAddress') || $entity->get('emailAddressData'))
&&
($entity->isNew() || $entity->isAttributeChanged('emailAddress') || $entity->isAttributeChanged('emailAddressData'))
(
$entity->isNew() ||
$entity->isAttributeChanged('emailAddress') ||
$entity->isAttributeChanged('emailAddressData')
)
) {
$list = [];
+6 -8
View File
@@ -35,19 +35,17 @@ class UpgradeManager extends Upgrades\Base
{
protected $name = 'Upgrade';
protected $params = array(
protected $params = [
'packagePath' => 'data/upload/upgrades',
'backupPath' => 'data/.backup/upgrades',
'scriptNames' => array(
'scriptNames' => [
'before' => 'BeforeUpgrade',
'after' => 'AfterUpgrade',
),
'customDirNames' => array(
],
'customDirNames' => [
'before' => 'beforeUpgradeFiles',
'after' => 'afterUpgradeFiles',
'vendor' => 'vendorFiles',
)
);
],
];
}
+3 -1
View File
@@ -57,7 +57,9 @@ class Pusher implements WampServerInterface
private $phpExecutablePath;
public function __construct(
array $categoriesData = [], ?string $phpExecutablePath = null, bool $isDebugMode = false
array $categoriesData = [],
?string $phpExecutablePath = null,
bool $isDebugMode = false
) {
$this->categoryList = array_keys($categoriesData);
$this->categoriesData = $categoriesData;