multiple assigned users support

This commit is contained in:
yuri
2018-04-24 16:18:50 +03:00
parent b45ff69376
commit 0b7b9599d3
16 changed files with 272 additions and 40 deletions
+1 -1
View File
@@ -217,7 +217,7 @@ class Base implements Injectable
}
}
if ($entity->hasAttribute('assignedUsersIds') && $entity->hasRelation('assignedUsers')) {
if ($entity->hasLinkMultipleField('assignedUsers')) {
if ($entity->hasLinkMultipleId('assignedUsers', $user->id)) {
return true;
}
+2
View File
@@ -143,6 +143,8 @@ class Entity extends \Espo\ORM\Entity
}
$this->set($idsAttribute, $ids);
$this->setFetched($idsAttribute, $ids);
$this->set($field . 'Names', $names);
if ($hasType) {
$this->set($field . 'Types', $types);
+15 -9
View File
@@ -484,9 +484,9 @@ class Base
{
if ($this->hasAssignedUsersField()) {
$this->setDistinct(true, $result);
$this->addLeftJoin('assignedUsers', $result);
$this->addLeftJoin(['assignedUsers', 'assignedUsersAccess'], $result);
$result['whereClause'][] = array(
'assignedUsers.id' => $this->getUser()->id
'assignedUsersAccess.id' => $this->getUser()->id
);
return;
}
@@ -1558,19 +1558,25 @@ class Base
protected function boolFilterOnlyMy(&$result)
{
if (!$this->checkIsPortal()) {
if ($this->hasAssignedUserField()) {
$result['whereClause'][] = array(
if ($this->hasAssignedUsersField()) {
$this->setDistinct(true, $result);
$this->addLeftJoin(['assignedUsers', 'assignedUsersAccess'], $result);
$result['whereClause'][] = [
'assignedUsersAccess.id' => $this->getUser()->id
];
} else if ($this->hasAssignedUserField()) {
$result['whereClause'][] = [
'assignedUserId' => $this->getUser()->id
);
];
} else {
$result['whereClause'][] = array(
$result['whereClause'][] = [
'createdById' => $this->getUser()->id
);
];
}
} else {
$result['whereClause'][] = array(
$result['whereClause'][] = [
'createdById' => $this->getUser()->id
);
];
}
}
+41
View File
@@ -183,12 +183,23 @@ class Stream extends \Espo\Core\Hooks\Base
$entityType = $entity->getEntityType();
if ($this->checkHasStream($entity)) {
$hasAssignedUsersField = false;
if ($entity->hasLinkMultipleField('assignedUsers')) {
$hasAssignedUsersField = true;
}
if ($entity->isNew()) {
$userIdList = [];
$assignedUserId = $entity->get('assignedUserId');
$createdById = $entity->get('createdById');
$assignedUserIdList = [];
if ($hasAssignedUsersField) {
$assignedUserIdList = $entity->getLinkMultipleIdList('assignedUsers');
}
if (
!$this->getUser()->isSystem()
&&
@@ -210,6 +221,15 @@ class Stream extends \Espo\Core\Hooks\Base
) {
$userIdList[] = $createdById;
}
if ($hasAssignedUsersField) {
foreach ($assignedUserIdList as $userId) {
if (!empty($userId) && !in_array($userId, $userIdList)) {
$userIdList[] = $userId;
}
}
}
if (!empty($assignedUserId) && !in_array($assignedUserId, $userIdList)) {
$userIdList[] = $assignedUserId;
}
@@ -273,6 +293,27 @@ class Stream extends \Espo\Core\Hooks\Base
$this->getStreamService()->noteStatus($entity, $field);
}
}
$assignedUserIdList = [];
if ($hasAssignedUsersField) {
$assignedUserIdList = $entity->getLinkMultipleIdList('assignedUsers');
}
if ($hasAssignedUsersField) {
$fetchedAssignedUserIdList = $entity->getFetched('assignedUsersIds');
if (!is_array($fetchedAssignedUserIdList)) {
$fetchedAssignedUserIdList = [];
}
foreach ($assignedUserIdList as $userId) {
if (in_array($userId, $fetchedAssignedUserIdList)) {
continue;
}
$this->getStreamService()->followEntity($entity, $userId);
if ($this->getUser()->id === $userId) {
$entity->set('isFollowed', true);
}
}
}
}
$methodName = 'isChangedWithAclAffect';
@@ -836,7 +836,6 @@ class Activities extends \Espo\Core\Services\Base
'createdAt'
],
'whereClause' => array(
'assignedUserId' => $userId,
array(
'OR' => array(
array(
@@ -858,6 +857,14 @@ class Activities extends \Espo\Core\Services\Base
)
);
if ($this->getMetadata()->get(['entityDefs', 'Task', 'fields', 'assignedUsers', 'type']) === 'linkMultiple') {
$selectManager->setDistinct(true, $selectParams);
$selectManager->addLeftJoin(['assignedUsers', 'assignedUsers'], $selectParams);
$selectParams['whereClause'][] = ['assignedUsers.id' => $userId];
} else {
$selectParams['whereClause'][] = ['assignedUserId' => $userId];
}
return $this->getEntityManager()->getQuery()->createSelectQuery('Task', $selectParams);
}
@@ -890,6 +897,8 @@ class Activities extends \Espo\Core\Services\Base
}
if ($seed->hasRelation('assignedUsers')) {
$selectManager->setDistinct(true, $selectParams);
$selectManager->addLeftJoin(['assignedUsers', 'assignedUsers'], $selectParams);
$wherePart['assignedUsersMiddle.userId'] = $userId;
}
@@ -76,7 +76,7 @@
{
"name":"tasks",
"label":"Tasks",
"view":"crm:views/record/panels/tasks",
"view":"crm:views/user/record/panels/tasks",
"aclScope": "Task"
}
],
@@ -96,7 +96,7 @@
{
"name":"tasks",
"label":"Tasks",
"view":"crm:views/record/panels/tasks",
"view":"crm:views/user/record/panels/tasks",
"aclScope": "Task"
}
]
+5
View File
@@ -813,4 +813,9 @@ class Email extends Record
return $data;
}
public function isPermittedAssignedUsers(Entity $entity)
{
return true;
}
}
+72 -2
View File
@@ -403,6 +403,66 @@ class Record extends \Espo\Core\Services\Base
if (!$this->isPermittedTeams($entity)) {
return false;
}
if ($entity->hasLinkMultipleField('assignedUsers')) {
if (!$this->isPermittedAssignedUsers($entity)) {
return false;
}
}
return true;
}
public function isPermittedAssignedUsers(Entity $entity)
{
if (!$entity->hasLinkMultipleField('assignedUsers')) {
return true;
}
$assignmentPermission = $this->getAcl()->get('assignmentPermission');
if ($assignmentPermission === true || $assignmentPermission === 'yes' || !in_array($assignmentPermission, ['team', 'no'])) {
return true;
}
$toProcess = false;
if (!$entity->isNew()) {
$userIdList = $entity->getLinkMultipleIdList('assignedUsers');
if ($entity->isAttributeChanged('assignedUsersIds')) {
$toProcess = true;
}
} else {
$toProcess = true;
}
$userIdList = $entity->getLinkMultipleIdList('assignedUsers');
if ($toProcess) {
if (empty($userIdList)) {
if ($assignmentPermission == 'no') {
return false;
}
return true;
}
$fetchedAssignedUserIdList = $entity->getFetched('assignedUsersIds');
if ($assignmentPermission == 'no') {
foreach ($userIdList as $userId) {
if (!$entity->isNew() && in_array($userId, $fetchedAssignedUserIdList)) continue;
if ($this->getUser()->id != $userId) {
return false;
}
}
} else if ($assignmentPermission == 'team') {
$teamIdList = $this->getUser()->getLinkMultipleIdList('teams');
foreach ($userIdList as $userId) {
if (!$entity->isNew() && in_array($userId, $fetchedAssignedUserIdList)) continue;
if (!$this->getEntityManager()->getRepository('User')->checkBelongsToAnyOfTeams($userId, $teamIdList)) {
return false;
}
}
}
}
return true;
}
@@ -466,8 +526,15 @@ class Record extends \Espo\Core\Services\Base
$teamIdList = $entity->getLinkMultipleIdList('teams');
if (empty($teamIdList)) {
if ($assignmentPermission === 'team') {
if (!$entity->get('assignedUserId')) {
return false;
if ($entity->hasLinkMultipleField('assignedUsers')) {
$assignedUserIdList = $entity->getLinkMultipleIdList('assignedUsers');
if (empty($assignedUserIdList)) {
return false;
}
} else if ($entity->hasAttribute('assignedUserId')) {
if (!$entity->get('assignedUserId')) {
return false;
}
}
}
return true;
@@ -993,6 +1060,9 @@ class Record extends \Espo\Core\Services\Base
if (!$this->getAcl()->check($entity, 'read')) {
throw new Forbidden();
}
if (empty($link)) {
throw new Error();
}
$methodName = 'findLinkedEntities' . ucfirst($link);
if (method_exists($this, $methodName)) {
@@ -111,6 +111,12 @@ Espo.define('crm:views/record/panels/tasks', 'views/record/panels/relationship',
setup: function () {
this.scope = this.model.name;
this.link = 'tasks';
if (this.scope == 'Account') {
this.link = 'tasksPrimary';
}
this.currentTab = this.getStorage().get('state', this.getStorageKey()) || this.defaultTab;
this.where = [
@@ -122,12 +128,8 @@ Espo.define('crm:views/record/panels/tasks', 'views/record/panels/relationship',
},
afterRender: function () {
var link = 'tasks';
if (this.scope == 'Account') {
link = 'tasksPrimary';
}
var url = this.model.name + '/' + this.model.id + '/' + link;
var url = this.model.name + '/' + this.model.id + '/' + this.link;
if (!this.getAcl().check('Task', 'read')) {
this.$el.find('.list-container').html(this.translate('No Access'));
@@ -165,7 +167,7 @@ Espo.define('crm:views/record/panels/tasks', 'views/record/panels/relationship',
actionCreateTask: function (data) {
var self = this;
var link = 'tasks';
var link = this.link;
var scope = 'Task';
var foreignLink = this.model.defs['links'][link].foreign;
@@ -0,0 +1,64 @@
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://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.
************************************************************************/
Espo.define('crm:views/user/record/panels/tasks', 'crm:views/record/panels/tasks', function (Dep) {
return Dep.extend({
listLayout: {
rows: [
[
{
name: 'name',
link: true,
},
{
name: 'isOverdue'
}
],
[
{name: 'status'},
{name: 'dateEnd'}
]
]
},
setup: function () {
Dep.prototype.setup.call(this);
if (this.getMetadata().get(['entityDefs', 'Task', 'fields', 'assignedUsers'])) {
var foreignLink = this.getMetadata().get(['entityDefs', 'Task', 'links', 'assignedUsers', 'foreign']);
if (foreignLink) {
this.link = foreignLink;
}
}
}
});
});
@@ -539,10 +539,15 @@ Espo.define('views/admin/link-manager/modals/edit', ['views/modal', 'views/admin
url: url,
type: 'POST',
data: JSON.stringify(attributes),
error: function (x) {
if (x.status == 409) {
Espo.Ui.error(this.translate('linkConflict', 'messages', 'EntityManager'));
x.errorIsHandled = true;
error: function (xhr) {
if (xhr.status == 409) {
var msg = this.translate('linkConflict', 'messages', 'EntityManager');
var statusReasonHeader = xhr.getResponseHeader('X-Status-Reason');
if (statusReasonHeader) {
console.error(statusReasonHeader);
}
Espo.Ui.error(msg);
xhr.errorIsHandled = true;
}
this.$el.find('button[data-name="save"]').removeClass('disabled').removeAttr('disabled');
}.bind(this)
@@ -48,6 +48,4 @@ Espo.define('views/email/record/detail-side', 'views/record/detail-side', functi
}
});
});
+16 -6
View File
@@ -548,23 +548,33 @@ Espo.define('views/record/base', ['view', 'view-record-helper', 'dynamic-logic']
var defaultHash = {};
if (!this.getUser().get('portalId')) {
if (this.model.hasField('assignedUser')) {
if (this.model.hasField('assignedUser') || this.model.hasField('assignedUsers')) {
var assignedUserField = 'assignedUser';
if (this.model.hasField('assignedUsers')) {
assignedUserField = 'assignedUsers';
}
var fillAssignedUser = true;
if (this.getPreferences().get('doNotFillAssignedUserIfNotRequired')) {
fillAssignedUser = false;
if (this.model.getFieldParam('assignedUser', 'required')) {
if (this.model.getFieldParam(assignedUserField, 'required')) {
fillAssignedUser = true;
} else if (this.getAcl().get('assignmentPermission') === 'no') {
fillAssignedUser = true;
} else if (this.getAcl().get('assignmentPermission') === 'team' && !this.getUser().get('defaultTeamId')) {
fillAssignedUser = true;
} else if (~this.getAcl().getScopeForbiddenFieldList(this.model.name, 'edit').indexOf('assignedUser')) {
} else if (~this.getAcl().getScopeForbiddenFieldList(this.model.name, 'edit').indexOf(assignedUserField)) {
fillAssignedUser = true;
}
}
if (fillAssignedUser) {
defaultHash['assignedUserId'] = this.getUser().id;
defaultHash['assignedUserName'] = this.getUser().get('name');
if (assignedUserField === 'assignedUsers') {
defaultHash['assignedUsersIds'] = [this.getUser().id];
defaultHash['assignedUsersNames'] = {};
defaultHash['assignedUsersNames'][this.getUser().id] = this.getUser().get('name');
} else {
defaultHash['assignedUserId'] = this.getUser().id;
defaultHash['assignedUserName'] = this.getUser().get('name');
}
}
}
var defaultTeamId = this.getUser().get('defaultTeamId');
@@ -572,7 +582,7 @@ Espo.define('views/record/base', ['view', 'view-record-helper', 'dynamic-logic']
if (this.model.hasField('teams') && !this.model.getFieldParam('teams', 'default')) {
defaultHash['teamsIds'] = [defaultTeamId];
defaultHash['teamsNames'] = {};
defaultHash['teamsNames'][defaultTeamId] = this.getUser().get('defaultTeamName')
defaultHash['teamsNames'][defaultTeamId] = this.getUser().get('defaultTeamName');
}
}
}
+25 -4
View File
@@ -50,12 +50,10 @@ Espo.define('views/record/detail-side', ['view'], function (Dep) {
options: {
fieldList: [
{
name: 'assignedUser',
view: 'views/fields/assigned-user'
name: ':assignedUser'
},
{
name: 'teams',
view: 'views/fields/teams'
name: 'teams'
}
]
}
@@ -210,6 +208,29 @@ Espo.define('views/record/detail-side', ['view'], function (Dep) {
defaultPanelDefs.options.fieldList = fieldList;
}
if (defaultPanelDefs.options.fieldList && defaultPanelDefs.options.fieldList.length) {
defaultPanelDefs.options.fieldList.forEach(function (item, i) {
if (typeof item !== 'object') {
item = {
name: item
}
defaultPanelDefs.options.fieldList[i] = item;
}
if (item.name === ':assignedUser') {
if (this.model.hasField('assignedUsers')) {
item.name = 'assignedUsers';
if (!this.model.getFieldParam('assignedUsers', 'view')) {
item.view = 'views/fields/assigned-users';
}
} else if (this.model.hasField('assignedUser')) {
item.name = 'assignedUser';
} else {
defaultPanelDefs.options.fieldList[i] = {};
}
}
}, this);
}
this.panelList.unshift(defaultPanelDefs);
},
+1 -2
View File
@@ -40,8 +40,7 @@ Espo.define('views/record/edit-side', 'views/record/detail-side', function (Dep)
options: {
fieldList: [
{
name: 'assignedUser',
view: 'views/fields/assigned-user'
name: ':assignedUser'
},
{
name: 'teams',
@@ -49,7 +49,7 @@ Espo.define('views/record/panels/relationship', ['views/record/panels/bottom', '
setup: function () {
Dep.prototype.setup.call(this);
this.link = this.defs.link || this.panelName;
this.link = this.link || this.defs.link || this.panelName;
if (!this.scope && !(this.link in this.model.defs.links)) {
throw new Error('Link \'' + this.link + '\' is not defined in model \'' + this.model.name + '\'');