Initial commit
This commit is contained in:
174
application/Espo/Core/MassAction/Actions/MassConvertCurrency.php
Normal file
174
application/Espo/Core/MassAction/Actions/MassConvertCurrency.php
Normal file
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\MassAction\Actions;
|
||||
|
||||
use Espo\Core\Acl\Table;
|
||||
use Espo\Core\Acl;
|
||||
use Espo\Core\Currency\ConfigDataProvider as CurrencyConfigDataProvider;
|
||||
use Espo\Core\Currency\Rates as CurrencyRates;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\MassAction\Data;
|
||||
use Espo\Core\MassAction\MassAction;
|
||||
use Espo\Core\MassAction\Params;
|
||||
use Espo\Core\MassAction\QueryBuilder;
|
||||
use Espo\Core\MassAction\Result;
|
||||
use Espo\Core\ORM\Entity as CoreEntity;
|
||||
use Espo\Core\ORM\EntityManager;
|
||||
use Espo\Core\ORM\Repository\Option\SaveOption;
|
||||
use Espo\Core\Utils\Log;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\Entities\User;
|
||||
use Espo\Tools\Currency\Conversion\EntityConverterFactory;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
class MassConvertCurrency implements MassAction
|
||||
{
|
||||
public function __construct(
|
||||
private QueryBuilder $queryBuilder,
|
||||
private Acl $acl,
|
||||
private EntityManager $entityManager,
|
||||
private Metadata $metadata,
|
||||
private CurrencyConfigDataProvider $configDataProvider,
|
||||
private EntityConverterFactory $converterFactory,
|
||||
private User $user,
|
||||
private Log $log,
|
||||
) {}
|
||||
|
||||
public function process(Params $params, Data $data): Result
|
||||
{
|
||||
$entityType = $params->getEntityType();
|
||||
|
||||
if (!$this->acl->checkScope($entityType, Table::ACTION_EDIT)) {
|
||||
throw new Forbidden("No edit access for '{$entityType}'.");
|
||||
}
|
||||
|
||||
if ($this->acl->getPermissionLevel(Acl\Permission::MASS_UPDATE) !== Table::LEVEL_YES) {
|
||||
throw new Forbidden("No mass-update permission.");
|
||||
}
|
||||
|
||||
$this->checkFieldAccess($entityType);
|
||||
|
||||
$dataRaw = $data->getRaw();
|
||||
|
||||
if (empty($dataRaw->targetCurrency)) {
|
||||
throw new BadRequest("No target currency.");
|
||||
}
|
||||
|
||||
if (isset($dataRaw->rates) && !is_object($dataRaw->rates)) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$baseCurrency = $this->configDataProvider->getBaseCurrency();
|
||||
$targetCurrency = $dataRaw->targetCurrency;
|
||||
|
||||
$rates = $this->getRatesFromData($data) ??
|
||||
$this->configDataProvider->getCurrencyRates();
|
||||
|
||||
if ($targetCurrency !== $baseCurrency && !$rates->hasRate($targetCurrency)) {
|
||||
throw new BadRequest("Target currency rate is not specified.");
|
||||
}
|
||||
|
||||
$query = $this->queryBuilder->build($params);
|
||||
|
||||
$collection = $this->entityManager
|
||||
->getRDBRepository($entityType)
|
||||
->clone($query)
|
||||
->sth()
|
||||
->find();
|
||||
|
||||
$ids = [];
|
||||
$count = 0;
|
||||
|
||||
$converter = $this->converterFactory->create($entityType);
|
||||
|
||||
foreach ($collection as $entity) {
|
||||
if (!$this->acl->checkEntity($entity, Table::ACTION_EDIT)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$entity instanceof CoreEntity) {
|
||||
throw new RuntimeException("Only Core-Entity allowed.");
|
||||
}
|
||||
|
||||
try {
|
||||
$converter->convert($entity, $targetCurrency, $rates);
|
||||
} catch (Forbidden $e) {
|
||||
$this->log->info("Could not convert currency for {id}.", [
|
||||
'id' => $entity->getId(),
|
||||
'exception' => $e,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->entityManager->saveEntity($entity, [SaveOption::MODIFIED_BY_ID => $this->user->getId()]);
|
||||
|
||||
$ids[] = $entity->getId();
|
||||
$count++;
|
||||
}
|
||||
|
||||
return new Result($count, $ids);
|
||||
}
|
||||
|
||||
private function getRatesFromData(Data $data): ?CurrencyRates
|
||||
{
|
||||
if ($data->get('rates') === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$baseCurrency = $this->configDataProvider->getBaseCurrency();
|
||||
$ratesArray = get_object_vars($data->get('rates'));
|
||||
|
||||
$ratesArray[$baseCurrency] = 1.0;
|
||||
|
||||
return CurrencyRates::fromAssoc($ratesArray, $baseCurrency);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Forbidden
|
||||
*/
|
||||
private function checkFieldAccess(string $entityType): void
|
||||
{
|
||||
/** @var string[] $requiredFieldList */
|
||||
$requiredFieldList = $this->metadata->get(['scopes', $entityType, 'currencyConversionAccessRequiredFieldList']);
|
||||
|
||||
if ($requiredFieldList === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($requiredFieldList as $field) {
|
||||
if (!$this->acl->checkField($entityType, $field, Table::ACTION_EDIT)) {
|
||||
throw new Forbidden("No edit access to field `$field`.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
120
application/Espo/Core/MassAction/Actions/MassDelete.php
Normal file
120
application/Espo/Core/MassAction/Actions/MassDelete.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\MassAction\Actions;
|
||||
|
||||
use Espo\Core\ORM\Repository\Option\RemoveOption;
|
||||
use Espo\Core\ORM\Repository\Option\SaveOption;
|
||||
use Espo\Core\Record\ActionHistory\Action;
|
||||
use Espo\Core\Utils\Log;
|
||||
use Espo\Entities\User;
|
||||
use Espo\Core\Acl;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\MassAction\Data;
|
||||
use Espo\Core\MassAction\MassAction;
|
||||
use Espo\Core\MassAction\Params;
|
||||
use Espo\Core\MassAction\QueryBuilder;
|
||||
use Espo\Core\MassAction\Result;
|
||||
use Espo\Core\ORM\EntityManager;
|
||||
use Espo\Core\Record\ServiceFactory;
|
||||
use Exception;
|
||||
|
||||
class MassDelete implements MassAction
|
||||
{
|
||||
public function __construct(
|
||||
private QueryBuilder $queryBuilder,
|
||||
private Acl $acl,
|
||||
private ServiceFactory $serviceFactory,
|
||||
private EntityManager $entityManager,
|
||||
private User $user,
|
||||
private Log $log,
|
||||
) {}
|
||||
|
||||
public function process(Params $params, Data $data): Result
|
||||
{
|
||||
$entityType = $params->getEntityType();
|
||||
|
||||
if (!$this->acl->check($entityType, Acl\Table::ACTION_DELETE)) {
|
||||
throw new Forbidden("No delete access for '$entityType'.");
|
||||
}
|
||||
|
||||
if (
|
||||
!$params->hasIds() &&
|
||||
$this->acl->getPermissionLevel(Acl\Permission::MASS_UPDATE) !== Acl\Table::LEVEL_YES
|
||||
) {
|
||||
throw new Forbidden("No mass-update permission.");
|
||||
}
|
||||
|
||||
$service = $this->serviceFactory->createForUser($entityType, $this->user);
|
||||
|
||||
$repository = $this->entityManager->getRDBRepository($entityType);
|
||||
|
||||
$query = $this->queryBuilder->build($params);
|
||||
|
||||
$collection = $repository
|
||||
->clone($query)
|
||||
->sth()
|
||||
->find();
|
||||
|
||||
$ids = [];
|
||||
|
||||
$count = 0;
|
||||
|
||||
foreach ($collection as $entity) {
|
||||
if (!$this->acl->checkEntityDelete($entity)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$repository->remove($entity, [
|
||||
RemoveOption::MASS_REMOVE => true,
|
||||
RemoveOption::MODIFIED_BY_ID => $this->user->getId(),
|
||||
SaveOption::MASS_UPDATE => true, // Legacy.
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
$this->log->info("Mass delete exception. Record: {id}.", [
|
||||
'exception' => $e,
|
||||
'id' => $entity->getId(),
|
||||
]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$id = $entity->getId();
|
||||
|
||||
$ids[] = $id;
|
||||
|
||||
$count++;
|
||||
|
||||
$service->processActionHistoryRecord(Action::DELETE, $entity);
|
||||
}
|
||||
|
||||
return new Result($count, $ids);
|
||||
}
|
||||
}
|
||||
116
application/Espo/Core/MassAction/Actions/MassFollow.php
Normal file
116
application/Espo/Core/MassAction/Actions/MassFollow.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\MassAction\Actions;
|
||||
|
||||
use Espo\Tools\Stream\Service as StreamService;
|
||||
use Espo\Core\Acl;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\MassAction\Data;
|
||||
use Espo\Core\MassAction\MassAction;
|
||||
use Espo\Core\MassAction\Params;
|
||||
use Espo\Core\MassAction\QueryBuilder;
|
||||
use Espo\Core\MassAction\Result;
|
||||
use Espo\Core\ORM\EntityManager;
|
||||
use Espo\Entities\User;
|
||||
|
||||
class MassFollow implements MassAction
|
||||
{
|
||||
private QueryBuilder $queryBuilder;
|
||||
private Acl $acl;
|
||||
private StreamService $streamService;
|
||||
private EntityManager $entityManager;
|
||||
private User $user;
|
||||
|
||||
public function __construct(
|
||||
QueryBuilder $queryBuilder,
|
||||
Acl $acl,
|
||||
StreamService $streamService,
|
||||
EntityManager $entityManager,
|
||||
User $user
|
||||
) {
|
||||
$this->queryBuilder = $queryBuilder;
|
||||
$this->acl = $acl;
|
||||
$this->streamService = $streamService;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
public function process(Params $params, Data $data): Result
|
||||
{
|
||||
$entityType = $params->getEntityType();
|
||||
|
||||
$passedUserId = $data->get('userId');
|
||||
|
||||
if ($passedUserId && !$this->user->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
$userId = $passedUserId ?? $this->user->getId();
|
||||
|
||||
if (!$this->acl->check($entityType, Acl\Table::ACTION_STREAM)) {
|
||||
throw new Forbidden("No stream access for '{$entityType}'.");
|
||||
}
|
||||
|
||||
$query = $this->queryBuilder->build($params);
|
||||
|
||||
$collection = $this->entityManager
|
||||
->getRDBRepository($entityType)
|
||||
->clone($query)
|
||||
->sth()
|
||||
->find();
|
||||
|
||||
$ids = [];
|
||||
|
||||
$count = 0;
|
||||
|
||||
foreach ($collection as $entity) {
|
||||
if (
|
||||
!$this->acl->checkEntityStream($entity) ||
|
||||
!$this->acl->checkEntityRead($entity)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$followResult = $this->streamService->followEntity($entity, $userId);
|
||||
|
||||
if (!$followResult) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var string $id */
|
||||
$id = $entity->getId();
|
||||
|
||||
$ids[] = $id;
|
||||
$count++;
|
||||
}
|
||||
|
||||
return new Result($count, $ids);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\MassAction\Actions;
|
||||
|
||||
use Espo\Core\ApplicationUser;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\MassAction\Data;
|
||||
use Espo\Core\MassAction\MassAction;
|
||||
use Espo\Core\MassAction\Params;
|
||||
use Espo\Core\MassAction\QueryBuilder;
|
||||
use Espo\Core\MassAction\Result;
|
||||
use Espo\Core\ORM\EntityManager;
|
||||
use Espo\Core\Utils\SystemUser;
|
||||
use Espo\Entities\User;
|
||||
|
||||
class MassRecalculateFormula implements MassAction
|
||||
{
|
||||
public function __construct(
|
||||
private QueryBuilder $queryBuilder,
|
||||
private EntityManager $entityManager,
|
||||
private User $user,
|
||||
private SystemUser $systemUser
|
||||
) {}
|
||||
|
||||
public function process(Params $params, Data $data): Result
|
||||
{
|
||||
if (!$this->user->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
$entityType = $params->getEntityType();
|
||||
|
||||
$query = $this->queryBuilder->build($params);
|
||||
|
||||
$collection = $this->entityManager
|
||||
->getRDBRepository($entityType)
|
||||
->clone($query)
|
||||
->sth()
|
||||
->find();
|
||||
|
||||
$ids = [];
|
||||
|
||||
$count = 0;
|
||||
|
||||
foreach ($collection as $entity) {
|
||||
$this->entityManager->saveEntity($entity, [
|
||||
'modifiedById' => $this->systemUser->getId(),
|
||||
]);
|
||||
|
||||
/** @var string $id */
|
||||
$id = $entity->getId();
|
||||
|
||||
$ids[] = $id;
|
||||
$count++;
|
||||
}
|
||||
|
||||
return new Result($count, $ids);
|
||||
}
|
||||
}
|
||||
87
application/Espo/Core/MassAction/Actions/MassUnfollow.php
Normal file
87
application/Espo/Core/MassAction/Actions/MassUnfollow.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\MassAction\Actions;
|
||||
|
||||
use Espo\Tools\Stream\Service as StreamService;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\MassAction\Data;
|
||||
use Espo\Core\MassAction\MassAction;
|
||||
use Espo\Core\MassAction\Params;
|
||||
use Espo\Core\MassAction\QueryBuilder;
|
||||
use Espo\Core\MassAction\Result;
|
||||
use Espo\Core\ORM\EntityManager;
|
||||
use Espo\Entities\User;
|
||||
|
||||
class MassUnfollow implements MassAction
|
||||
{
|
||||
public function __construct(
|
||||
private QueryBuilder $queryBuilder,
|
||||
private StreamService $streamService,
|
||||
private EntityManager $entityManager,
|
||||
private User $user
|
||||
) {}
|
||||
|
||||
public function process(Params $params, Data $data): Result
|
||||
{
|
||||
$entityType = $params->getEntityType();
|
||||
|
||||
$passedUserId = $data->get('userId');
|
||||
|
||||
if ($passedUserId && !$this->user->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
$userId = $passedUserId ?? $this->user->getId();
|
||||
|
||||
$query = $this->queryBuilder->build($params);
|
||||
|
||||
$collection = $this->entityManager
|
||||
->getRDBRepository($entityType)
|
||||
->clone($query)
|
||||
->sth()
|
||||
->find();
|
||||
|
||||
$ids = [];
|
||||
|
||||
$count = 0;
|
||||
|
||||
foreach ($collection as $entity) {
|
||||
$this->streamService->unfollowEntity($entity, $userId);
|
||||
|
||||
/** @var string $id */
|
||||
$id = $entity->getId();
|
||||
|
||||
$ids[] = $id;
|
||||
$count++;
|
||||
}
|
||||
|
||||
return new Result($count, $ids);
|
||||
}
|
||||
}
|
||||
50
application/Espo/Core/MassAction/Actions/MassUpdate.php
Normal file
50
application/Espo/Core/MassAction/Actions/MassUpdate.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\MassAction\Actions;
|
||||
|
||||
use Espo\Tools\MassUpdate\Processor;
|
||||
use Espo\Tools\MassUpdate\Data as MassUpdateData;
|
||||
use Espo\Core\MassAction\Params;
|
||||
use Espo\Core\MassAction\Result;
|
||||
use Espo\Core\MassAction\Data;
|
||||
use Espo\Core\MassAction\MassAction;
|
||||
|
||||
class MassUpdate implements MassAction
|
||||
{
|
||||
public function __construct(private Processor $processor)
|
||||
{}
|
||||
|
||||
public function process(Params $params, Data $data): Result
|
||||
{
|
||||
$massUpdateData = MassUpdateData::fromMassActionData($data);
|
||||
|
||||
return $this->processor->process($params, $massUpdateData);
|
||||
}
|
||||
}
|
||||
56
application/Espo/Core/MassAction/Api/GetStatus.php
Normal file
56
application/Espo/Core/MassAction/Api/GetStatus.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\MassAction\Api;
|
||||
|
||||
use Espo\Core\Api\Action;
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Api\Response;
|
||||
use Espo\Core\Api\ResponseComposer;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\MassAction\Service;
|
||||
|
||||
class GetStatus implements Action
|
||||
{
|
||||
public function __construct(private Service $service)
|
||||
{}
|
||||
|
||||
public function process(Request $request): Response
|
||||
{
|
||||
$id = $request->getRouteParam('id');
|
||||
|
||||
if (!$id) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$result = $this->service->getStatusData($id);
|
||||
|
||||
return ResponseComposer::json($result);
|
||||
}
|
||||
}
|
||||
151
application/Espo/Core/MassAction/Api/PostProcess.php
Normal file
151
application/Espo/Core/MassAction/Api/PostProcess.php
Normal file
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\MassAction\Api;
|
||||
|
||||
use Espo\Core\Api\Action;
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Api\Response;
|
||||
use Espo\Core\Api\ResponseComposer;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\MassAction\Params;
|
||||
use Espo\Core\MassAction\Service;
|
||||
use Espo\Core\MassAction\ServiceParams;
|
||||
use Espo\Core\MassAction\ServiceResult;
|
||||
use Espo\Core\Utils\Json;
|
||||
use RuntimeException;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Processes mass actions.
|
||||
*/
|
||||
class PostProcess implements Action
|
||||
{
|
||||
public function __construct(private Service $service)
|
||||
{}
|
||||
|
||||
public function process(Request $request): Response
|
||||
{
|
||||
$body = $request->getParsedBody();
|
||||
|
||||
$entityType = $body->entityType ?? null;
|
||||
$action = $body->action ?? null;
|
||||
$params = $body->params ?? null;
|
||||
$data = $body->data ?? (object) [];
|
||||
$isIdle = $body->idle ?? false;
|
||||
|
||||
if (!$entityType || !$action || !$params) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$rawParams = $this->prepareMassActionParams($params);
|
||||
|
||||
try {
|
||||
$massActionParams = Params::fromRaw($rawParams, $entityType);
|
||||
} catch (RuntimeException $e) {
|
||||
throw new BadRequest($e->getMessage());
|
||||
}
|
||||
|
||||
$serviceParams = ServiceParams::create($massActionParams)
|
||||
->withIsIdle($isIdle);
|
||||
|
||||
$result = $this->service->process(
|
||||
$entityType,
|
||||
$action,
|
||||
$serviceParams,
|
||||
$data
|
||||
);
|
||||
|
||||
$result = $this->convertResult($result);
|
||||
|
||||
return ResponseComposer::json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
* @throws BadRequest
|
||||
*/
|
||||
private function prepareMassActionParams(stdClass $data): array
|
||||
{
|
||||
$where = $data->where ?? null;
|
||||
$searchParams = $data->searchParams ?? $data->selectData ?? null;
|
||||
$ids = $data->ids ?? null;
|
||||
|
||||
if (!is_null($where) || !is_null($searchParams)) {
|
||||
$params = [];
|
||||
|
||||
if (!is_null($where)) {
|
||||
$params['where'] = json_decode(Json::encode($where), true);
|
||||
}
|
||||
|
||||
if (!is_null($searchParams)) {
|
||||
$params['searchParams'] = json_decode(Json::encode($searchParams), true);
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
if (is_null($ids)) {
|
||||
throw new BadRequest("Bad search params for mass action.");
|
||||
}
|
||||
|
||||
return ['ids' => $ids];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Error
|
||||
*/
|
||||
private function convertResult(ServiceResult $serviceResult): stdClass
|
||||
{
|
||||
if (!$serviceResult->hasResult()) {
|
||||
return (object) [
|
||||
'id' => $serviceResult->getId(),
|
||||
];
|
||||
}
|
||||
|
||||
$result = $serviceResult->getResult();
|
||||
|
||||
if (!$result) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
$data = (object) [];
|
||||
|
||||
if ($result->hasCount()) {
|
||||
$data->count = $result->getCount();
|
||||
}
|
||||
|
||||
if ($result->hasIds()) {
|
||||
$data->ids = $result->getIds();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
56
application/Espo/Core/MassAction/Api/PostSubscribe.php
Normal file
56
application/Espo/Core/MassAction/Api/PostSubscribe.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\MassAction\Api;
|
||||
|
||||
use Espo\Core\Api\Action;
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Api\Response;
|
||||
use Espo\Core\Api\ResponseComposer;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\MassAction\Service;
|
||||
|
||||
class PostSubscribe implements Action
|
||||
{
|
||||
public function __construct(private Service $service)
|
||||
{}
|
||||
|
||||
public function process(Request $request): Response
|
||||
{
|
||||
$id = $request->getRouteParam('id');
|
||||
|
||||
if (!$id) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$this->service->subscribeToNotificationOnSuccess($id);
|
||||
|
||||
return ResponseComposer::json(true);
|
||||
}
|
||||
}
|
||||
93
application/Espo/Core/MassAction/Data.php
Normal file
93
application/Espo/Core/MassAction/Data.php
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\MassAction;
|
||||
|
||||
use Espo\Core\Utils\ObjectUtil;
|
||||
|
||||
use stdClass;
|
||||
|
||||
class Data
|
||||
{
|
||||
private stdClass $data;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
$this->data = (object) [];
|
||||
}
|
||||
|
||||
public function getRaw(): stdClass
|
||||
{
|
||||
return ObjectUtil::clone($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an item value.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $name)
|
||||
{
|
||||
return $this->getRaw()->$name ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has an item.
|
||||
*/
|
||||
public function has(string $name): bool
|
||||
{
|
||||
return property_exists($this->data, $name);
|
||||
}
|
||||
|
||||
public static function fromRaw(stdClass $data): self
|
||||
{
|
||||
$obj = new self();
|
||||
$obj->data = $data;
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone with an item value.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function with(string $name, $value): self
|
||||
{
|
||||
$obj = clone $this;
|
||||
$obj->data->$name = $value;
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
$this->data = ObjectUtil::clone($this->data);
|
||||
}
|
||||
}
|
||||
140
application/Espo/Core/MassAction/Jobs/Process.php
Normal file
140
application/Espo/Core/MassAction/Jobs/Process.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\MassAction\Jobs;
|
||||
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Job\Job;
|
||||
use Espo\Core\Job\Job\Data as JobData;
|
||||
use Espo\Core\MassAction\MassActionFactory;
|
||||
use Espo\Core\MassAction\Result;
|
||||
use Espo\Core\Utils\Language;
|
||||
use Espo\ORM\EntityManager;
|
||||
use Espo\Entities\MassAction as MassActionEntity;
|
||||
use Espo\Entities\Notification;
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class Process implements Job
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManager $entityManager,
|
||||
private MassActionFactory $factory,
|
||||
private Language $language
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @throws Error
|
||||
*/
|
||||
public function run(JobData $data): void
|
||||
{
|
||||
$id = $data->getTargetId();
|
||||
|
||||
if ($id === null) {
|
||||
throw new Error("ID not passed to the mass action job.");
|
||||
}
|
||||
|
||||
/** @var MassActionEntity|null $entity */
|
||||
$entity = $this->entityManager->getEntityById(MassActionEntity::ENTITY_TYPE, $id);
|
||||
|
||||
if ($entity === null) {
|
||||
throw new Error("MassAction '$id' not found.");
|
||||
}
|
||||
|
||||
/** @var User|null $user */
|
||||
$user = $this->entityManager->getEntityById(User::ENTITY_TYPE, $entity->getCreatedBy()->getId());
|
||||
|
||||
if (!$user) {
|
||||
throw new Error("MassAction '$id', user not found.");
|
||||
}
|
||||
|
||||
$params = $entity->getParams();
|
||||
|
||||
try {
|
||||
$massAction = $this->factory->createForUser($entity->getAction(), $params->getEntityType(), $user);
|
||||
|
||||
$this->setRunning($entity);
|
||||
|
||||
$result = $massAction->process(
|
||||
$params,
|
||||
$entity->getData()
|
||||
);
|
||||
} catch (Throwable $e) {
|
||||
$this->setFailed($entity);
|
||||
|
||||
throw new Error("Mass action job error: " . $e->getMessage());
|
||||
}
|
||||
|
||||
$this->setSuccess($entity, $result);
|
||||
|
||||
$this->entityManager->refreshEntity($entity);
|
||||
|
||||
if ($entity->notifyOnFinish()) {
|
||||
$this->notifyFinish($entity);
|
||||
}
|
||||
}
|
||||
|
||||
private function notifyFinish(MassActionEntity $entity): void
|
||||
{
|
||||
$notification = $this->entityManager->getRDBRepositoryByClass(Notification::class)->getNew();
|
||||
|
||||
$message = $this->language->translateLabel('massActionProcessed', 'messages');
|
||||
|
||||
$notification
|
||||
->setType(Notification::TYPE_MESSAGE)
|
||||
->setMessage($message)
|
||||
->setUserId($entity->getCreatedBy()->getId());
|
||||
|
||||
$this->entityManager->saveEntity($notification);
|
||||
}
|
||||
|
||||
private function setFailed(MassActionEntity $entity): void
|
||||
{
|
||||
$entity->setStatus(MassActionEntity::STATUS_FAILED);
|
||||
|
||||
$this->entityManager->saveEntity($entity);
|
||||
}
|
||||
|
||||
private function setRunning(MassActionEntity $entity): void
|
||||
{
|
||||
$entity->setStatus(MassActionEntity::STATUS_RUNNING);
|
||||
|
||||
$this->entityManager->saveEntity($entity);
|
||||
}
|
||||
|
||||
private function setSuccess(MassActionEntity $entity, Result $result): void
|
||||
{
|
||||
$entity
|
||||
->setStatus(MassActionEntity::STATUS_SUCCESS)
|
||||
->setProcessedCount($result->getCount());
|
||||
|
||||
$this->entityManager->saveEntity($entity);
|
||||
}
|
||||
}
|
||||
44
application/Espo/Core/MassAction/MassAction.php
Normal file
44
application/Espo/Core/MassAction/MassAction.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\MassAction;
|
||||
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
|
||||
interface MassAction
|
||||
{
|
||||
/**
|
||||
* @throws Forbidden
|
||||
* @throws BadRequest
|
||||
* @throws Error
|
||||
*/
|
||||
public function process(Params $params, Data $data): Result;
|
||||
}
|
||||
174
application/Espo/Core/MassAction/MassActionFactory.php
Normal file
174
application/Espo/Core/MassAction/MassActionFactory.php
Normal file
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\MassAction;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\Core\InjectableFactory;
|
||||
use Espo\Core\AclManager;
|
||||
use Espo\Core\Acl;
|
||||
use Espo\Core\Binding\BindingContainerBuilder;
|
||||
|
||||
class MassActionFactory
|
||||
{
|
||||
public function __construct(
|
||||
private Metadata $metadata,
|
||||
private InjectableFactory $injectableFactory,
|
||||
private AclManager $aclManager
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @throws Forbidden
|
||||
* @throws NotFound
|
||||
*/
|
||||
public function create(string $action, string $entityType): MassAction
|
||||
{
|
||||
$className = $this->getClassName($action, $entityType);
|
||||
|
||||
if (!$className) {
|
||||
throw new NotFound("Mass action '{$action}' not found.");
|
||||
}
|
||||
|
||||
if ($this->isDisabled($action, $entityType)) {
|
||||
throw new Forbidden("Mass action '{$action}' is disabled for '{$entityType}'.");
|
||||
}
|
||||
|
||||
return $this->injectableFactory->create($className);
|
||||
}
|
||||
|
||||
public function createForUser(string $action, string $entityType, User $user): MassAction
|
||||
{
|
||||
$className = $this->getClassName($action, $entityType);
|
||||
|
||||
if (!$className) {
|
||||
throw new NotFound("Mass action '{$action}' not found.");
|
||||
}
|
||||
|
||||
$bindingContainer = BindingContainerBuilder::create()
|
||||
->bindInstance(User::class, $user)
|
||||
->bindInstance(Acl::class, $this->aclManager->createUserAcl($user))
|
||||
->build();
|
||||
|
||||
return $this->injectableFactory->createWithBinding($className, $bindingContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $with
|
||||
* @throws NotFound
|
||||
* @todo Remove.
|
||||
* @deprecated As of v7.1. Use create.
|
||||
*/
|
||||
public function createWith(string $action, string $entityType, array $with): MassAction
|
||||
{
|
||||
$className = $this->getClassName($action, $entityType);
|
||||
|
||||
if (!$className) {
|
||||
throw new NotFound("Mass action '{$action}' not found.");
|
||||
}
|
||||
|
||||
return $this->injectableFactory->createWith($className, $with);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ?class-string<MassAction>
|
||||
*/
|
||||
private function getClassName(string $action, string $entityType): ?string
|
||||
{
|
||||
/** @var ?class-string<MassAction> $className */
|
||||
$className = $this->getEntityTypeClassName($action, $entityType);
|
||||
|
||||
if ($className) {
|
||||
return $className;
|
||||
}
|
||||
|
||||
/** @var ?class-string<MassAction> */
|
||||
return $this->metadata->get(
|
||||
['app', 'massActions', $action, 'implementationClassName']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ?class-string<MassAction>
|
||||
*/
|
||||
private function getEntityTypeClassName(string $action, string $entityType): ?string
|
||||
{
|
||||
/** @var ?class-string<MassAction> */
|
||||
return $this->metadata->get(
|
||||
['recordDefs', $entityType, 'massActions', $action, 'implementationClassName']
|
||||
);
|
||||
}
|
||||
|
||||
private function isDisabled(string $action, string $entityType): bool
|
||||
{
|
||||
$actionsDisabled = $this->metadata
|
||||
->get(['recordDefs', $entityType, 'actionsDisabled']) ?? false;
|
||||
|
||||
if ($actionsDisabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$massActionsDisabled = $this->metadata
|
||||
->get(['recordDefs', $entityType, 'massActionsDisabled']) ?? false;
|
||||
|
||||
if ($massActionsDisabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->needsToBeAllowed($entityType)) {
|
||||
if (!$this->isAllowed($action, $entityType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->metadata
|
||||
->get(['recordDefs', $entityType, 'massActions', $action, 'disabled']) ?? false;
|
||||
}
|
||||
|
||||
private function needsToBeAllowed(string $entityType): bool
|
||||
{
|
||||
$isObject = $this->metadata->get(['scopes', $entityType, 'object']) ?? false;
|
||||
|
||||
if (!$isObject) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->metadata
|
||||
->get(['recordDefs', $entityType, 'notAllowedActionsDisabled']) ?? false;
|
||||
}
|
||||
|
||||
private function isAllowed(string $action, string $entityType): bool
|
||||
{
|
||||
return $this->metadata
|
||||
->get(['recordDefs', $entityType, 'massActions', $action, 'allowed']) ?? false;
|
||||
}
|
||||
}
|
||||
213
application/Espo/Core/MassAction/Params.php
Normal file
213
application/Espo/Core/MassAction/Params.php
Normal file
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\MassAction;
|
||||
|
||||
use Espo\Core\Select\SearchParams;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Immutable.
|
||||
*/
|
||||
class Params
|
||||
{
|
||||
private string $entityType;
|
||||
/** @var ?string[] */
|
||||
private ?array $ids = null;
|
||||
private ?SearchParams $searchParams = null;
|
||||
|
||||
private function __construct() {}
|
||||
|
||||
public function getEntityType(): string
|
||||
{
|
||||
return $this->entityType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function getIds(): array
|
||||
{
|
||||
if (!$this->ids) {
|
||||
throw new RuntimeException("No IDs.");
|
||||
}
|
||||
|
||||
return $this->ids;
|
||||
}
|
||||
|
||||
public function getSearchParams(): SearchParams
|
||||
{
|
||||
if (!$this->searchParams) {
|
||||
throw new RuntimeException("No search params.");
|
||||
}
|
||||
|
||||
return $this->searchParams;
|
||||
}
|
||||
|
||||
public function hasIds(): bool
|
||||
{
|
||||
return !is_null($this->ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $ids
|
||||
*/
|
||||
public static function createWithIds(string $entityType, array $ids): self
|
||||
{
|
||||
return self::fromRaw([
|
||||
'entityType' => $entityType,
|
||||
'ids' => $ids,
|
||||
]);
|
||||
}
|
||||
|
||||
public static function createWithSearchParams(string $entityType, SearchParams $searchParams): self
|
||||
{
|
||||
$obj = new self();
|
||||
|
||||
$obj->entityType = $entityType;
|
||||
$obj->searchParams = $searchParams;
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create from raw params.
|
||||
*
|
||||
* @param array{
|
||||
* entityType?: string,
|
||||
* where?: array<int, array<string, mixed>>,
|
||||
* ids?: ?string[],
|
||||
* searchParams?: ?array<string, mixed>,
|
||||
* } $params
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public static function fromRaw(array $params, ?string $entityType = null): self
|
||||
{
|
||||
/** @var array<string, mixed> $params */
|
||||
|
||||
$obj = new self();
|
||||
|
||||
$passedEntityType = $entityType ?? $params['entityType'] ?? null;
|
||||
|
||||
if (!$passedEntityType) {
|
||||
throw new RuntimeException("No 'entityType'.");
|
||||
}
|
||||
|
||||
$obj->entityType = $passedEntityType;
|
||||
|
||||
$where = $params['where'] ?? null;
|
||||
$ids = $params['ids'] ?? null;
|
||||
|
||||
$searchParams = $params['searchParams'] ?? $params['selectData'] ?? null;
|
||||
|
||||
if ($where !== null && !is_array($where)) {
|
||||
throw new RuntimeException("Bad 'where'.");
|
||||
}
|
||||
|
||||
if ($searchParams !== null && !is_array($searchParams)) {
|
||||
throw new RuntimeException("Bad 'searchParams'.");
|
||||
}
|
||||
|
||||
if ($where !== null && $searchParams !== null) {
|
||||
$searchParams['where'] = $where;
|
||||
}
|
||||
|
||||
if ($where !== null && $searchParams === null) {
|
||||
$searchParams = [
|
||||
'where' => $where,
|
||||
];
|
||||
}
|
||||
|
||||
if ($searchParams !== null) {
|
||||
if ($ids !== null) {
|
||||
throw new RuntimeException("Can't combine 'ids' and search params.");
|
||||
}
|
||||
} else if ($ids !== null) {
|
||||
if (!is_array($ids)) {
|
||||
throw new RuntimeException("Bad 'ids'.");
|
||||
}
|
||||
|
||||
$obj->ids = $ids;
|
||||
} else {
|
||||
throw new RuntimeException("Bad mass action params.");
|
||||
}
|
||||
|
||||
if ($searchParams !== null) {
|
||||
$actualSearchParams = $searchParams;
|
||||
|
||||
unset($actualSearchParams['select']);
|
||||
|
||||
$obj->searchParams = SearchParams::fromRaw($actualSearchParams);
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
if ($this->searchParams) {
|
||||
$this->searchParams = clone $this->searchParams;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{
|
||||
* entityType: string,
|
||||
* ids: ?string[],
|
||||
* searchParams: string,
|
||||
* }
|
||||
*/
|
||||
public function __serialize(): array
|
||||
{
|
||||
return [
|
||||
'entityType' => $this->entityType,
|
||||
'ids' => $this->ids,
|
||||
'searchParams' => serialize($this->searchParams),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{
|
||||
* entityType: string,
|
||||
* ids: ?string[],
|
||||
* searchParams: string,
|
||||
* } $data
|
||||
*/
|
||||
public function __unserialize(array $data): void
|
||||
{
|
||||
$this->entityType = $data['entityType'];
|
||||
$this->ids = $data['ids'];
|
||||
$this->searchParams = unserialize($data['searchParams']);
|
||||
}
|
||||
}
|
||||
68
application/Espo/Core/MassAction/QueryBuilder.php
Normal file
68
application/Espo/Core/MassAction/QueryBuilder.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\MassAction;
|
||||
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\ORM\Query\Select;
|
||||
use Espo\Core\Select\SelectBuilderFactory;
|
||||
use Espo\Entities\User;
|
||||
|
||||
class QueryBuilder
|
||||
{
|
||||
public function __construct(private SelectBuilderFactory $selectBuilderFactory, private User $user)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws Forbidden
|
||||
*/
|
||||
public function build(Params $params): Select
|
||||
{
|
||||
$builder = $this->selectBuilderFactory
|
||||
->create()
|
||||
->from($params->getEntityType())
|
||||
->forUser($this->user)
|
||||
->withStrictAccessControl();
|
||||
|
||||
if ($params->hasIds()) {
|
||||
return $builder
|
||||
->buildQueryBuilder()
|
||||
->where([
|
||||
'id' => $params->getIds(),
|
||||
])
|
||||
->build();
|
||||
}
|
||||
|
||||
return $builder
|
||||
->withSearchParams($params->getSearchParams())
|
||||
->build();
|
||||
}
|
||||
}
|
||||
104
application/Espo/Core/MassAction/Result.php
Normal file
104
application/Espo/Core/MassAction/Result.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\MassAction;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Immutable.
|
||||
*/
|
||||
class Result
|
||||
{
|
||||
private ?int $count = null;
|
||||
/** @var ?string[] */
|
||||
private $ids = null;
|
||||
|
||||
/**
|
||||
* @param ?string[] $ids
|
||||
*/
|
||||
public function __construct(?int $count, ?array $ids = null)
|
||||
{
|
||||
$this->count = $count;
|
||||
$this->ids = $ids;
|
||||
}
|
||||
|
||||
public function hasIds(): bool
|
||||
{
|
||||
return $this->ids !== null;
|
||||
}
|
||||
|
||||
public function hasCount(): bool
|
||||
{
|
||||
return $this->count !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getIds(): array
|
||||
{
|
||||
if (!$this->hasIds()) {
|
||||
throw new RuntimeException("No IDs.");
|
||||
}
|
||||
|
||||
/** @var string[] */
|
||||
return $this->ids;
|
||||
}
|
||||
|
||||
public function getCount(): int
|
||||
{
|
||||
if (!$this->hasCount()) {
|
||||
throw new RuntimeException("No count.");
|
||||
}
|
||||
|
||||
/** @var int */
|
||||
return $this->count;
|
||||
}
|
||||
|
||||
public function withNoIds(): self
|
||||
{
|
||||
return new self($this->count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param array{
|
||||
* count?: ?int,
|
||||
* ids?: ?string[],
|
||||
* } $data
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self(
|
||||
$data['count'] ?? null,
|
||||
$data['ids'] ?? null
|
||||
);
|
||||
}
|
||||
}
|
||||
167
application/Espo/Core/MassAction/Service.php
Normal file
167
application/Espo/Core/MassAction/Service.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\MassAction;
|
||||
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\ORM\EntityManager;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\ForbiddenSilent;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Core\Acl;
|
||||
use Espo\Core\MassAction\Jobs\Process;
|
||||
use Espo\Core\Job\JobSchedulerFactory;
|
||||
use Espo\Core\Job\Job\Data as JobData;
|
||||
use Espo\Entities\User;
|
||||
use Espo\Entities\MassAction as MassActionEntity;
|
||||
|
||||
use stdClass;
|
||||
|
||||
class Service
|
||||
{
|
||||
public function __construct(
|
||||
private MassActionFactory $factory,
|
||||
private Acl $acl,
|
||||
private JobSchedulerFactory $jobSchedulerFactory,
|
||||
private EntityManager $entityManager,
|
||||
private User $user
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Perform a mass action.
|
||||
*
|
||||
* @throws Forbidden
|
||||
* @throws NotFound
|
||||
* @throws BadRequest
|
||||
*/
|
||||
public function process(
|
||||
string $entityType,
|
||||
string $action,
|
||||
ServiceParams $serviceParams,
|
||||
stdClass $data
|
||||
): ServiceResult {
|
||||
|
||||
if (!$this->acl->checkScope($entityType)) {
|
||||
throw new ForbiddenSilent();
|
||||
}
|
||||
|
||||
$params = $serviceParams->getParams();
|
||||
|
||||
if ($serviceParams->isIdle()) {
|
||||
if ($this->user->isPortal()) {
|
||||
throw new Forbidden("Idle mass actions are not allowed for portal users.");
|
||||
}
|
||||
|
||||
return $this->schedule($entityType, $action, $params, $data);
|
||||
}
|
||||
|
||||
$massAction = $this->factory->create($action, $entityType);
|
||||
|
||||
$result = $massAction->process(
|
||||
$params,
|
||||
Data::fromRaw($data)
|
||||
);
|
||||
|
||||
if ($params->hasIds()) {
|
||||
return ServiceResult::createWithResult($result);
|
||||
}
|
||||
|
||||
return ServiceResult::createWithResult(
|
||||
$result->withNoIds()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Forbidden
|
||||
* @throws NotFound
|
||||
*/
|
||||
public function getStatusData(string $id): stdClass
|
||||
{
|
||||
/** @var ?MassActionEntity $entity */
|
||||
$entity = $this->entityManager->getEntityById(MassActionEntity::ENTITY_TYPE, $id);
|
||||
|
||||
if (!$entity) {
|
||||
throw new NotFound();
|
||||
}
|
||||
|
||||
if ($entity->getCreatedBy()->getId() !== $this->user->getId()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
return (object) [
|
||||
'status' => $entity->getStatus(),
|
||||
'processedCount' => $entity->getProcessedCount(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Forbidden
|
||||
* @throws NotFound
|
||||
*/
|
||||
public function subscribeToNotificationOnSuccess(string $id): void
|
||||
{
|
||||
/** @var ?MassActionEntity $entity */
|
||||
$entity = $this->entityManager->getEntityById(MassActionEntity::ENTITY_TYPE, $id);
|
||||
|
||||
if (!$entity) {
|
||||
throw new NotFound();
|
||||
}
|
||||
|
||||
if ($entity->getCreatedBy()->getId() !== $this->user->getId()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
$entity->setNotifyOnFinish();
|
||||
|
||||
$this->entityManager->saveEntity($entity);
|
||||
}
|
||||
|
||||
private function schedule(string $entityType, string $action, Params $params, stdClass $data): ServiceResult
|
||||
{
|
||||
$entity = $this->entityManager->createEntity(MassActionEntity::ENTITY_TYPE, [
|
||||
'entityType' => $entityType,
|
||||
'action' => $action,
|
||||
// Additional encoding to handle null-character issue in PostgreSQL.
|
||||
'params' => base64_encode(serialize($params)),
|
||||
'data' => $data,
|
||||
]);
|
||||
|
||||
$this->jobSchedulerFactory
|
||||
->create()
|
||||
->setClassName(Process::class)
|
||||
->setData(
|
||||
JobData::create()
|
||||
->withTargetId($entity->getId())
|
||||
->withTargetType($entity->getEntityType())
|
||||
)
|
||||
->schedule();
|
||||
|
||||
return ServiceResult::createWithId($entity->getId());
|
||||
}
|
||||
}
|
||||
64
application/Espo/Core/MassAction/ServiceParams.php
Normal file
64
application/Espo/Core/MassAction/ServiceParams.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\MassAction;
|
||||
|
||||
/**
|
||||
* Immutable.
|
||||
*/
|
||||
class ServiceParams
|
||||
{
|
||||
private bool $isIdle = false;
|
||||
|
||||
private function __construct(private Params $params)
|
||||
{}
|
||||
|
||||
public static function create(Params $params): self
|
||||
{
|
||||
return new self($params);
|
||||
}
|
||||
|
||||
public function getParams(): Params
|
||||
{
|
||||
return $this->params;
|
||||
}
|
||||
|
||||
public function isIdle(): bool
|
||||
{
|
||||
return $this->isIdle;
|
||||
}
|
||||
|
||||
public function withIsIdle(bool $isIdle = true): self
|
||||
{
|
||||
$obj = clone $this;
|
||||
$obj->isIdle = $isIdle;
|
||||
|
||||
return $obj;
|
||||
}
|
||||
}
|
||||
72
application/Espo/Core/MassAction/ServiceResult.php
Normal file
72
application/Espo/Core/MassAction/ServiceResult.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\MassAction;
|
||||
|
||||
/**
|
||||
* Immutable.
|
||||
*/
|
||||
class ServiceResult
|
||||
{
|
||||
private ?Result $result = null;
|
||||
private ?string $id = null;
|
||||
|
||||
private function __construct() {}
|
||||
|
||||
public function hasResult(): bool
|
||||
{
|
||||
return $this->result !== null;
|
||||
}
|
||||
|
||||
public function getId(): ?string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getResult(): ?Result
|
||||
{
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
public static function createWithId(string $id): self
|
||||
{
|
||||
$obj = new self;
|
||||
$obj->id = $id;
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
public static function createWithResult(Result $result): self
|
||||
{
|
||||
$obj = new self;
|
||||
$obj->result = $result;
|
||||
|
||||
return $obj;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user