import api entrypoints

This commit is contained in:
Yuri Kuznetsov
2023-02-21 12:56:36 +02:00
parent 51bda2f5d2
commit 9d4d441ec2
14 changed files with 490 additions and 153 deletions
@@ -32,26 +32,16 @@ namespace Espo\Classes\ConsoleCommands;
use Espo\Tools\Import\Service;
use Espo\Core\Utils\File\Manager as FileManager;
use Espo\Core\{
Console\Command,
Console\Command\Params,
Console\IO,
};
use Espo\Core\Console\Command;
use Espo\Core\Console\Command\Params;
use Espo\Core\Console\IO;
use Throwable;
class Import implements Command
{
private Service $service;
private FileManager $fileManager;
public function __construct(Service $service, FileManager $fileManager)
{
$this->service = $service;
$this->fileManager = $fileManager;
}
public function __construct(private Service $service, private FileManager $fileManager)
{}
public function run(Params $params, IO $io) : void
{
+5 -111
View File
@@ -30,16 +30,16 @@
namespace Espo\Controllers;
use Espo\Core\Exceptions\BadRequest;
use Espo\Core\Exceptions\Error;
use Espo\Core\Exceptions\Forbidden;
use Espo\Core\Exceptions\NotFound;
use Espo\Tools\Import\Params as ImportParams;
use Espo\Tools\Import\Service as Service;
use Espo\Core\{
Controllers\Record,
Api\Request,
Api\Response,
};
use Espo\Core\Api\Request;
use Espo\Core\Api\Response;
use Espo\Core\Controllers\Record;
use Espo\Core\Di\InjectableFactoryAware;
use Espo\Core\Di\InjectableFactorySetter;
@@ -57,112 +57,6 @@ class Import extends Record
return $this->acl->check('Import');
}
private function getImportService(): Service
{
return $this->injectableFactory->create(Service::class);
}
public function postActionUploadFile(Request $request): stdClass
{
$contents = $request->getBodyContents() ?? '';
$attachmentId = $this->getImportService()->uploadFile($contents);
return (object) [
'attachmentId' => $attachmentId
];
}
public function postActionRevert(Request $request): bool
{
$data = $request->getParsedBody();
$this->getImportService()->revert($data->id);
return true;
}
public function postActionRemoveDuplicates(Request $request): bool
{
$data = $request->getParsedBody();
if (empty($data->id)) {
throw new BadRequest();
}
$this->getImportService()->removeDuplicates($data->id);
return true;
}
public function postActionCreate(Request $request, Response $response): stdClass
{
$data = $request->getParsedBody();
$entityType = $data->entityType ?? null;
$attributeList = $data->attributeList ?? null;
$attachmentId = $data->attachmentId ?? null;
if (!is_array($attributeList)) {
throw new BadRequest("No attributeList.");
}
if (!$attachmentId) {
throw new BadRequest("No attachmentId.");
}
if (!$entityType) {
throw new BadRequest("No entityType.");
}
$params = ImportParams::fromRaw($data);
$result = $this->getImportService()->import(
$entityType,
$attributeList,
$attachmentId,
$params
);
return $result->getValueMap();
}
public function postActionUnmarkAsDuplicate(Request $request): bool
{
$data = $request->getParsedBody();
if (
empty($data->id) ||
empty($data->entityType) ||
empty($data->entityId)
) {
throw new BadRequest();
}
$this->getImportService()->unmarkAsDuplicate($data->id, $data->entityType, $data->entityId);
return true;
}
/**
* @throws BadRequest
* @throws \Espo\Core\Exceptions\NotFound
*/
public function postActionExportErrors(Request $request): stdClass
{
$id = $request->getParsedBody()->id ?? null;
if (!$id) {
throw new BadRequest("No `id`.");
}
$attachmentId = $this->getImportService()->exportErrors($id);
return (object) [
'attachmentId' => $attachmentId,
];
}
public function putActionUpdate(Request $request, Response $response): stdClass
{
throw new Forbidden();
+30 -5
View File
@@ -254,6 +254,36 @@
"method": "post",
"actionClassName": "Espo\\Tools\\Export\\Api\\PostSubscribe"
},
{
"route": "/Import",
"method": "post",
"actionClassName": "Espo\\Tools\\Import\\Api\\Post"
},
{
"route": "/Import/file",
"method": "post",
"actionClassName": "Espo\\Tools\\Import\\Api\\PostFile"
},
{
"route": "/Import/:id/revert",
"method": "post",
"actionClassName": "Espo\\Tools\\Import\\Api\\PostRevert"
},
{
"route": "/Import/:id/removeDuplicates",
"method": "post",
"actionClassName": "Espo\\Tools\\Import\\Api\\PostRemoveDuplicates"
},
{
"route": "/Import/:id/unmarkDuplicates",
"method": "post",
"actionClassName": "Espo\\Tools\\Import\\Api\\PostUnmarkDuplicates"
},
{
"route": "/Import/:id/exportErrors",
"method": "post",
"actionClassName": "Espo\\Tools\\Import\\Api\\PostExportErrors"
},
{
"route": "/Kanban/order",
"method": "put",
@@ -344,11 +374,6 @@
"method": "get",
"actionClassName": "Espo\\Tools\\EmailAddress\\Api\\GetSearch"
},
{
"route": "/Email/insertFieldData",
"method": "get",
"actionClassName": "Espo\\Tools\\Email\\Api\\GetInsertFieldData"
},
{
"route": "/User/:id/acl",
"method": "get",
@@ -0,0 +1,80 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://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 General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Tools\Import\Api;
use Espo\Core\Acl;
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\Forbidden;
use Espo\Entities\Import;
use Espo\Tools\Import\Params as ImportParams;
use Espo\Tools\Import\Service;
/**
* Creates imports.
*/
class Post implements Action
{
public function __construct(private Service $service, private Acl $acl) {}
public function process(Request $request): Response
{
if (!$this->acl->checkScope(Import::ENTITY_TYPE)) {
throw new Forbidden();
}
$data = $request->getParsedBody();
$entityType = $data->entityType ?? null;
$attributeList = $data->attributeList ?? null;
$attachmentId = $data->attachmentId ?? null;
if (!is_array($attributeList)) {
throw new BadRequest("No `attributeList`.");
}
if (!$attachmentId) {
throw new BadRequest("No `attachmentId`.");
}
if (!$entityType) {
throw new BadRequest("No `entityType`.");
}
$params = ImportParams::fromRaw($data);
$result = $this->service->import($entityType, $attributeList, $attachmentId, $params);
return ResponseComposer::json($result->getValueMap());
}
}
@@ -0,0 +1,65 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://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 General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Tools\Import\Api;
use Espo\Core\Acl;
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\Forbidden;
use Espo\Entities\Import;
use Espo\Tools\Import\Service;
/**
* Exports import errors.
*/
class PostExportErrors implements Action
{
public function __construct(private Service $service, private Acl $acl) {}
public function process(Request $request): Response
{
if (!$this->acl->checkScope(Import::ENTITY_TYPE)) {
throw new Forbidden();
}
$id = $request->getRouteParam('id');
if (!$id) {
throw new BadRequest();
}
$attachmentId = $this->service->exportErrors($id);
return ResponseComposer::json(['attachmentId' => $attachmentId]);
}
}
@@ -0,0 +1,60 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://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 General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Tools\Import\Api;
use Espo\Core\Acl;
use Espo\Core\Api\Action;
use Espo\Core\Api\Request;
use Espo\Core\Api\Response;
use Espo\Core\Api\ResponseComposer;
use Espo\Core\Exceptions\Forbidden;
use Espo\Entities\Import;
use Espo\Tools\Import\Service;
/**
* Uploads CSV import files.
*/
class PostFile implements Action
{
public function __construct(private Service $service, private Acl $acl) {}
public function process(Request $request): Response
{
if (!$this->acl->checkScope(Import::ENTITY_TYPE)) {
throw new Forbidden();
}
$contents = $request->getBodyContents() ?? '';
$attachmentId = $this->service->uploadFile($contents);
return ResponseComposer::json(['attachmentId' => $attachmentId]);
}
}
@@ -0,0 +1,65 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://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 General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Tools\Import\Api;
use Espo\Core\Acl;
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\Forbidden;
use Espo\Entities\Import;
use Espo\Tools\Import\Service;
/**
* Removes imported duplicates.
*/
class PostRemoveDuplicates implements Action
{
public function __construct(private Service $service, private Acl $acl) {}
public function process(Request $request): Response
{
if (!$this->acl->checkScope(Import::ENTITY_TYPE)) {
throw new Forbidden();
}
$id = $request->getRouteParam('id');
if (!$id) {
throw new BadRequest();
}
$this->service->removeDuplicates($id);
return ResponseComposer::json(true);
}
}
@@ -0,0 +1,65 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://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 General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Tools\Import\Api;
use Espo\Core\Acl;
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\Forbidden;
use Espo\Entities\Import;
use Espo\Tools\Import\Service;
/**
* Reverts imports.
*/
class PostRevert implements Action
{
public function __construct(private Service $service, private Acl $acl) {}
public function process(Request $request): Response
{
if (!$this->acl->checkScope(Import::ENTITY_TYPE)) {
throw new Forbidden();
}
$id = $request->getRouteParam('id');
if (!$id) {
throw new BadRequest();
}
$this->service->revert($id);
return ResponseComposer::json(true);
}
}
@@ -0,0 +1,74 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://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 General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Tools\Import\Api;
use Espo\Core\Acl;
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\Forbidden;
use Espo\Entities\Import;
use Espo\Tools\Import\Service;
/**
* Un-marks specific records as duplicates.
*/
class PostUnmarkDuplicates implements Action
{
public function __construct(private Service $service, private Acl $acl) {}
public function process(Request $request): Response
{
if (!$this->acl->checkScope(Import::ENTITY_TYPE)) {
throw new Forbidden();
}
$id = $request->getRouteParam('id');
if (!$id) {
throw new BadRequest();
}
$data = $request->getParsedBody();
$entityType = $data->entityType ?? null;
$entityId = $data->entityId ?? null;
if (!$entityType || !$entityId) {
throw new BadRequest("No `entityType` or `entityId`.");
}
$this->service->unmarkAsDuplicate($id, $entityType, $entityId);
return ResponseComposer::json(true);
}
}
+26 -4
View File
@@ -75,6 +75,10 @@ class Service
Params $params
): Result {
if (!$this->acl->checkScope(ImportEntity::ENTITY_TYPE)) {
throw new Forbidden("No access to Import scope.");
}
if (!$this->acl->check($entityType, Table::ACTION_CREATE)) {
throw new Forbidden("No create access for '{$entityType}'.");
}
@@ -113,7 +117,7 @@ class Service
}
/** @var ?ImportEntity $source */
$source = $this->entityManager->getEntity(ImportEntity::ENTITY_TYPE, $importParamsId);
$source = $this->entityManager->getEntityById(ImportEntity::ENTITY_TYPE, $importParamsId);
if (!$source) {
throw new Error("Import '{$importParamsId}' not found.");
@@ -193,14 +197,18 @@ class Service
*/
public function revert(string $id): void
{
$import = $this->entityManager->getEntity('Import', $id);
if (!$this->acl->checkScope(ImportEntity::ENTITY_TYPE)) {
throw new Forbidden("No access to Import scope.");
}
$import = $this->entityManager->getEntityById(ImportEntity::ENTITY_TYPE, $id);
if (!$import) {
throw new NotFound("Could not find import record.");
}
if (!$this->acl->checkEntityDelete($import)) {
throw new Forbidden("No access import record.");
throw new Forbidden("No access to import record.");
}
$importEntityList = $this->entityManager
@@ -272,9 +280,14 @@ class Service
/**
* @return string Attachment ID.
* @throws Forbidden
*/
public function uploadFile(string $contents): string
{
if (!$this->acl->checkScope(ImportEntity::ENTITY_TYPE)) {
throw new Forbidden("No access to Import scope.");
}
$attachment = $this->entityManager->getNewEntity(Attachment::ENTITY_TYPE);
$attachment->set('type', 'text/csv');
@@ -293,7 +306,11 @@ class Service
*/
public function removeDuplicates(string $id): void
{
$import = $this->entityManager->getEntity(ImportEntity::ENTITY_TYPE, $id);
if (!$this->acl->checkScope(ImportEntity::ENTITY_TYPE)) {
throw new Forbidden("No access to Import scope.");
}
$import = $this->entityManager->getEntityById(ImportEntity::ENTITY_TYPE, $id);
if (!$import) {
throw new NotFound("Import '{$id}' not found.");
@@ -349,9 +366,14 @@ class Service
/**
* @throws NotFound
* @throws Forbidden
*/
public function unmarkAsDuplicate(string $importId, string $entityType, string $entityId): void
{
if (!$this->acl->checkScope(ImportEntity::ENTITY_TYPE)) {
throw new Forbidden("No access to Import scope.");
}
$entity = $this->entityManager
->getRDBRepository(ImportEntityEntity::ENTITY_TYPE)
->where([
+2 -4
View File
@@ -35,9 +35,7 @@ define('handlers/import', ['action-handler'], function (Dep) {
actionErrorExport() {
Espo.Ajax
.postRequest('Import/action/exportErrors', {
id: this.view.model.id
})
.postRequest(`Import/${this.view.model.id}/exportErrors`)
.then(data => {
if (!data.attachmentId) {
let message = this.view.translate('noErrors', 'messages', 'Import');
@@ -47,7 +45,7 @@ define('handlers/import', ['action-handler'], function (Dep) {
return;
}
window.location = this.view.getBasePath() +'?entryPoint=download&id=' + data.attachmentId;
window.location = this.view.getBasePath() + '?entryPoint=download&id=' + data.attachmentId;
});
}
}
+2 -2
View File
@@ -148,7 +148,7 @@ define('views/import/detail', 'views/detail', function (Dep) {
Espo.Ui.notify(this.translate('pleaseWait', 'messages'));
Espo.Ajax
.postRequest('Import/action/revert', {id: this.model.id})
.postRequest(`Import/${this.model.id}/revert`)
.then(() => {
this.getRouter().navigate('#Import/list', {trigger: true});
});
@@ -162,7 +162,7 @@ define('views/import/detail', 'views/detail', function (Dep) {
Espo.Ui.notify(this.translate('pleaseWait', 'messages'));
Espo.Ajax
.postRequest('Import/action/removeDuplicates', {id: this.model.id})
.postRequest(`Import/${this.model.id}/removeDuplicates`)
.then(() => {
this.removeMenuItem('removeDuplicates', true);
@@ -26,7 +26,7 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
Espo.define('views/import/record/panels/duplicates', 'views/import/record/panels/imported', function (Dep) {
define('views/import/record/panels/duplicates', ['views/import/record/panels/imported'], function (Dep) {
return Dep.extend({
@@ -34,23 +34,22 @@ Espo.define('views/import/record/panels/duplicates', 'views/import/record/panels
setup: function () {
this.title = this.title || this.translate('Duplicates', 'labels', 'Import');
Dep.prototype.setup.call(this);
},
actionUnmarkAsDuplicate: function (data) {
var id = data.id;
var type = data.type;
let id = data.id;
let type = data.type;
this.confirm(this.translate('confirmation', 'messages'), function () {
this.ajaxPostRequest('Import/action/unmarkAsDuplicate', {
id: this.model.id,
this.confirm(this.translate('confirmation', 'messages'), () => {
Espo.Ajax.postRequest(`Import/${this.model.id}/unmarkDuplicates`, {
entityId: id,
entityType: type
}).then(function () {
entityType: type,
}).then(() => {
this.collection.fetch();
});
}, this);
}
});
},
});
});
+1 -1
View File
@@ -512,7 +512,7 @@ define('views/import/step2', 'view', function (Dep) {
this.notify('File uploading...');
Espo.Ajax.postRequest('Import/action/uploadFile', null, {
Espo.Ajax.postRequest('Import/file', null, {
timeout: 0,
contentType: 'text/csv',
data: this.getParentView().fileContents,