diff --git a/application/Espo/Core/Controllers/Record.php b/application/Espo/Core/Controllers/Record.php index db5e338f59..3b343a4c4f 100644 --- a/application/Espo/Core/Controllers/Record.php +++ b/application/Espo/Core/Controllers/Record.php @@ -69,13 +69,17 @@ class Record extends Base return $entity->toArray(); } - public function actionPatch($params, $data) + public function actionPatch($params, $data, $request) { - return $this->actionUpdate($params, $data); + return $this->actionUpdate($params, $data, $request); } - public function actionCreate($params, $data) + public function actionCreate($params, $data, $request) { + if (!$request->isPost()) { + throw BadRequest(); + } + if (!$this->getAcl()->check($this->name, 'edit')) { throw new Forbidden(); } @@ -89,8 +93,12 @@ class Record extends Base throw new Error(); } - public function actionUpdate($params, $data) + public function actionUpdate($params, $data, $request) { + if (!$request->isPut() && !$request->isPatch()) { + throw BadRequest(); + } + if (!$this->getAcl()->check($this->name, 'edit')) { throw new Forbidden(); } @@ -174,8 +182,12 @@ class Record extends Base ); } - public function actionDelete($params) + public function actionDelete($params, $data, $request) { + if (!$request->isDelete()) { + throw BadRequest(); + } + $id = $params['id']; if ($this->getRecordService()->deleteEntity($id)) { @@ -212,6 +224,10 @@ class Record extends Base public function actionMassUpdate($params, $data, $request) { + if (!$request->isPost()) { + throw new BadRequest(); + } + if (!$this->getAcl()->check($this->name, 'edit')) { throw new Forbidden(); } @@ -235,6 +251,9 @@ class Record extends Base public function actionMassDelete($params, $data, $request) { + if (!$request->isPost()) { + throw new BadRequest(); + } if (!$this->getAcl()->check($this->name, 'delete')) { throw new Forbidden(); } @@ -254,10 +273,14 @@ class Record extends Base return $idsRemoved; } - public function actionCreateLink($params, $data) + public function actionCreateLink($params, $data, $request) { + if (!$request->isPost()) { + throw new BadRequest(); + } + if (empty($params['id']) || empty($params['link'])) { - throw BadRequest(); + throw new BadRequest(); } $id = $params['id']; @@ -294,13 +317,17 @@ class Record extends Base throw new Error(); } - public function actionRemoveLink($params, $data) + public function actionRemoveLink($params, $data, $request) { + if (!$request->isDelete()) { + throw new BadRequest(); + } + $id = $params['id']; $link = $params['link']; if (empty($params['id']) || empty($params['link'])) { - throw BadRequest(); + throw new BadRequest(); } $foreignIds = array(); @@ -326,8 +353,11 @@ class Record extends Base throw new Error(); } - public function actionFollow($params) + public function actionFollow($params, $data, $request) { + if (!$request->isPut()) { + throw new BadRequest(); + } if (!$this->getAcl()->check($this->name, 'read')) { throw new Forbidden(); } @@ -335,8 +365,11 @@ class Record extends Base return $this->getRecordService()->follow($id); } - public function actionUnfollow($params) + public function actionUnfollow($params, $data, $request) { + if (!$request->isDelete()) { + throw new BadRequest(); + } if (!$this->getAcl()->check($this->name, 'read')) { throw new Forbidden(); } diff --git a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/TargetList.json b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/TargetList.json index 6091d24079..e6545d7a1e 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/clientDefs/TargetList.json +++ b/application/Espo/Modules/Crm/Resources/metadata/clientDefs/TargetList.json @@ -9,5 +9,55 @@ "view":"Crm:TargetList.Record.Panels.OptedOut" } ] + }, + "relationshipPanels": { + "contacts": { + "actionList": [ + { + "label": "Unlink All", + "action": "unlinkAllRelated", + "acl": "edit", + "data": { + "link": "contacts" + } + } + ] + }, + "leads": { + "actionList": [ + { + "label": "Unlink All", + "action": "unlinkAllRelated", + "acl": "edit", + "data": { + "link": "leads" + } + } + ] + }, + "accounts": { + "actionList": [ + { + "label": "Unlink All", + "action": "unlinkAllRelated", + "acl": "edit", + "data": { + "link": "accounts" + } + } + ] + }, + "users": { + "actionList": [ + { + "label": "Unlink All", + "action": "unlinkAllRelated", + "acl": "edit", + "data": { + "link": "users" + } + } + ] + } } } diff --git a/application/Espo/Resources/i18n/en_US/Global.json b/application/Espo/Resources/i18n/en_US/Global.json index f0a95aeb56..8e77df57bd 100644 --- a/application/Espo/Resources/i18n/en_US/Global.json +++ b/application/Espo/Resources/i18n/en_US/Global.json @@ -152,7 +152,8 @@ "Value": "Value", "Current version": "Current version", "List View": "List View", - "Tree View": "Tree View" + "Tree View": "Tree View", + "Unlink All": "Unlink All" }, "messages": { "pleaseWait": "Please wait...", @@ -175,9 +176,10 @@ "assignmentEmailNotificationSubject": "EspoCRM {entityType}: {Entity.name}", "assignmentEmailNotificationBody": "{assignerUserName} has assigned {entityType} '{Entity.name}' to you.\n\n{recordUrl}", "confirmation": "Are you sure?", + "unlinkAllConfirmation": "Are you sure you want to unlink all related records?", "resetPreferencesConfirmation": "Are you sure you want to reset preferences to defaults?", "removeRecordConfirmation": "Are you sure you want to remove the record?", - "unlinkRecordConfirmation": "Are you sure you want to unlink relationship?", + "unlinkRecordConfirmation": "Are you sure you want to unlink the related record?", "removeSelectedRecordsConfirmation": "Are you sure you want to remove selected records?", "massUpdateResult": "{count} records have been updated", "massUpdateResultSingle": "{count} record has been updated", diff --git a/frontend/client/src/views/record/panels/relationship.js b/frontend/client/src/views/record/panels/relationship.js index afa147bc59..e501e266c2 100644 --- a/frontend/client/src/views/record/panels/relationship.js +++ b/frontend/client/src/views/record/panels/relationship.js @@ -227,6 +227,23 @@ Espo.define('Views.Record.Panels.Relationship', ['Views.Record.Panels.Bottom', ' }); } }, + + actionUnlinkAllRelated: function (data) { + if (confirm(this.translate('unlinkAllConfirmation', 'messages'))) { + this.notify('Please wait...'); + $.ajax({ + url: this.collection.url, + type: 'DELETE', + data: JSON.stringify({ + all: true + }), + }).done(function () { + this.notify(false); + self.notify('Unlinked', 'success'); + this.collection.fetch(); + }.bind(this)); + } + }, }); });