diff --git a/application/Espo/Core/Hooks/Base.php b/application/Espo/Core/Hooks/Base.php index a96b5e2c07..734fb4e2f6 100644 --- a/application/Espo/Core/Hooks/Base.php +++ b/application/Espo/Core/Hooks/Base.php @@ -24,7 +24,7 @@ namespace Espo\Core\Hooks; use \Espo\Core\Interfaces\Injectable; -class Base implements Injectable +abstract class Base implements Injectable { protected $dependencies = array( 'entityManager', diff --git a/application/Espo/Core/Notificators/Base.php b/application/Espo/Core/Notificators/Base.php new file mode 100644 index 0000000000..c94a631ec4 --- /dev/null +++ b/application/Espo/Core/Notificators/Base.php @@ -0,0 +1,98 @@ +init(); + } + + protected function init() + { + } + + public function getDependencyList() + { + return $this->dependencies; + } + + protected function getInjection($name) + { + return $this->injections[$name]; + } + + public function inject($name, $object) + { + $this->injections[$name] = $object; + } + + protected function getEntityManager() + { + return $this->injections['entityManager']; + } + + protected function getUser() + { + return $this->injections['user']; + } + + public function process(Entity $entity) + { + if ($entity->has('assignedUserId') && $entity->get('assignedUserId')) { + $assignedUserId = $entity->get('assignedUserId'); + if ($assignedUserId != $this->getUser()->id && $entity->isFieldChanged('assignedUserId')) { + $notification = $this->getEntityManager()->getEntity('Notification'); + $notification->set(array( + 'type' => 'Assign', + 'userId' => $assignedUserId, + 'data' => array( + 'entityType' => $entity->getEntityType(), + 'entityId' => $entity->id, + 'entityName' => $entity->get('name'), + 'isNew' => $entity->isNew(), + 'userId' => $this->getUser()->id, + 'userName' => $this->getUser()->get('name') + ) + )); + $this->getEntityManager()->saveEntity($notification); + } + } + } + +} + diff --git a/application/Espo/Core/Utils/EntityManager.php b/application/Espo/Core/Utils/EntityManager.php index 6602a47a53..3644937126 100644 --- a/application/Espo/Core/Utils/EntityManager.php +++ b/application/Espo/Core/Utils/EntityManager.php @@ -136,7 +136,8 @@ class EntityManager 'customizable' => true, 'importable' => true, 'type' => $type, - 'stream' => $stream + 'stream' => $stream, + 'notifications' => true ); $this->getMetadata()->set('scopes', $name, $scopeData); diff --git a/application/Espo/Core/defaults/config.php b/application/Espo/Core/defaults/config.php index cf302e1177..2fb0ccaa21 100644 --- a/application/Espo/Core/defaults/config.php +++ b/application/Espo/Core/defaults/config.php @@ -93,6 +93,7 @@ return array ( 'disableExport' => false, 'assignmentEmailNotifications' => false, 'assignmentEmailNotificationsEntityList' => array('Lead', 'Opportunity', 'Task', 'Case'), + 'assignmentNotificationsEntityList' => array('Meeting', 'Call', 'Task', 'Email'), 'emailMessageMaxSize' => 10, 'notificationsCheckInterval' => 10, 'disabledCountQueryEntityList' => array('Email'), diff --git a/application/Espo/Hooks/Common/AssignmentEmailNotification.php b/application/Espo/Hooks/Common/AssignmentEmailNotification.php index e9615cbfe6..fa34b2b7c0 100644 --- a/application/Espo/Hooks/Common/AssignmentEmailNotification.php +++ b/application/Espo/Hooks/Common/AssignmentEmailNotification.php @@ -26,12 +26,13 @@ use Espo\ORM\Entity; class AssignmentEmailNotification extends \Espo\Core\Hooks\Base { - public function afterSave(Entity $entity) { if ( $this->getConfig()->get('assignmentEmailNotifications') && + $entity->has('assignedUserId') + && in_array($entity->getEntityName(), $this->getConfig()->get('assignmentEmailNotificationsEntityList', array())) ) { diff --git a/application/Espo/Hooks/Common/Notifications.php b/application/Espo/Hooks/Common/Notifications.php new file mode 100644 index 0000000000..e9e37fa6e6 --- /dev/null +++ b/application/Espo/Hooks/Common/Notifications.php @@ -0,0 +1,106 @@ +dependencies[] = 'container'; + $this->dependencies[] = 'metadata'; + } + + private $hasStreamCache = array(); + + protected function getContainer() + { + return $this->getInjection('container'); + } + + protected function getMetadata() + { + return $this->getInjection('metadata'); + } + + protected function checkHasStream($entityType) + { + if (!array_key_exists($entityType, $this->hasStreamCache)) { + $this->hasStreamCache[$entityType] = $this->getMetadata()->get("scopes.{$entityType}.stream"); + } + return $this->hasStreamCache[$entityType]; + } + + protected function getNotificator($entityType) + { + if (empty($this->noticatorsHash[$entityType])) { + $normalizedName = Util::normilizeClassName($entityType); + + $className = '\\Espo\\Custom\\Notificators\\' . $normalizedName; + if (!class_exists($className)) { + $moduleName = $this->getMetadata()->getScopeModuleName($entityName); + if ($moduleName) { + $className = '\\Espo\\Modules\\' . $moduleName . '\\Notificators\\' . $normalizedName; + } else { + $className = '\\Espo\\Notificators\\' . $normalizedName; + } + if (!class_exists($className)) { + $className = '\\Espo\\Core\\Notificators\\Base'; + } + } + + $notificator = new $className(); + $dependencies = $notificator->getDependencyList(); + foreach ($dependencies as $name) { + $notificator->inject($name, $this->getContainer()->get($name)); + } + + $this->noticatorsHash[$entityType] = $notificator; + } + return $this->noticatorsHash[$entityType]; + } + + public function afterSave(Entity $entity, array $options = array()) + { + $entityType = $entity->getEntityType(); + + if (!empty($options['silent']) && !empty($options['noNotifications'])) { + return; + } + + if (!$this->checkHasStream($entity)) { + if (in_array($entityType, $this->getConfig()->get('assignmentNotificationsEntityList', []))) { + $notificator = $this->getNotificator(); + $notificator->process($entity); + } + } + } + +} + diff --git a/application/Espo/Hooks/Common/Stream.php b/application/Espo/Hooks/Common/Stream.php index 3549e48fab..416385b3a2 100644 --- a/application/Espo/Hooks/Common/Stream.php +++ b/application/Espo/Hooks/Common/Stream.php @@ -36,6 +36,8 @@ class Stream extends \Espo\Core\Hooks\Base protected $statusFields = null; + public static $order = 9; + protected function init() { $this->dependencies[] = 'serviceFactory'; diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Account.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Account.json index 3308931398..01dc511f8d 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Account.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Account.json @@ -6,5 +6,6 @@ "module": "Crm", "customizable": true, "stream": true, - "importable": true + "importable": true, + "notifications": true } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Call.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Call.json index a8e7a855da..0fc2c29548 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Call.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Call.json @@ -5,5 +5,6 @@ "acl": true, "module": "Crm", "customizable": true, - "importable": true + "importable": true, + "notifications": true } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Case.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Case.json index 3308931398..01dc511f8d 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Case.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Case.json @@ -6,5 +6,6 @@ "module": "Crm", "customizable": true, "stream": true, - "importable": true + "importable": true, + "notifications": true } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Contact.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Contact.json index 072e7b3d7a..b849647b77 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Contact.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Contact.json @@ -1,5 +1,11 @@ -{"entity":true,"layouts":true,"tab":true,"acl":true,"module":"Crm", +{ + "entity":true, + "layouts":true, + "tab":true, + "acl":true, + "module":"Crm", "customizable": true, "stream": true, - "importable": true + "importable": true, + "notifications": true } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Document.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Document.json index 4c0e2bc5a9..44b8fe0b29 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Document.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Document.json @@ -5,5 +5,6 @@ "acl": true, "module": "Crm", "customizable": true, - "importable": false + "importable": false, + "notifications": true } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Lead.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Lead.json index 3308931398..01dc511f8d 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Lead.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Lead.json @@ -6,5 +6,6 @@ "module": "Crm", "customizable": true, "stream": true, - "importable": true + "importable": true, + "notifications": true } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Meeting.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Meeting.json index a8e7a855da..0fc2c29548 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Meeting.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Meeting.json @@ -5,5 +5,6 @@ "acl": true, "module": "Crm", "customizable": true, - "importable": true + "importable": true, + "notifications": true } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Opportunity.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Opportunity.json index 3308931398..01dc511f8d 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Opportunity.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Opportunity.json @@ -6,5 +6,6 @@ "module": "Crm", "customizable": true, "stream": true, - "importable": true + "importable": true, + "notifications": true } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Target.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Target.json index bcacda91d0..1c93e4d8a9 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Target.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Target.json @@ -5,5 +5,6 @@ "acl": false, "module": "Crm", "customizable": false, - "importable": false + "importable": false, + "notifications": false } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/TargetList.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/TargetList.json index b6ee9905d4..885e494234 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/TargetList.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/TargetList.json @@ -6,5 +6,6 @@ "module": "Crm", "customizable": false, "stream": false, - "importable": false + "importable": false, + "notifications": true } diff --git a/application/Espo/Modules/Crm/Resources/metadata/scopes/Task.json b/application/Espo/Modules/Crm/Resources/metadata/scopes/Task.json index a8e7a855da..0fc2c29548 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/scopes/Task.json +++ b/application/Espo/Modules/Crm/Resources/metadata/scopes/Task.json @@ -5,5 +5,6 @@ "acl": true, "module": "Crm", "customizable": true, - "importable": true + "importable": true, + "notifications": true } diff --git a/application/Espo/Notificators/Email.php b/application/Espo/Notificators/Email.php new file mode 100644 index 0000000000..d39febd959 --- /dev/null +++ b/application/Espo/Notificators/Email.php @@ -0,0 +1,83 @@ +isNew()) { + return; + } + + $userIdList = []; + if ($entity->has('assignedUserId') && $entity->get('assignedUserId')) { + $assignedUserId = $entity->get('assignedUserId'); + if ($assignedUserId != $this->getUser()->id && $entity->isFieldChanged('assignedUserId')) { + $userIdList[] = $assignedUserId; + } + } + $emailUserIdList = $email->get('usersIds'); + if (is_null($emailUserIdList)) { + $email->loadLinkMultipleField('from'); + $emailUserIdList = $email->get('usersIds'); + } + if (!is_array($emailUserIdList)) { + $emailUserIdList = []; + } + foreach ($emailUserIdList as $userId) { + if (!in_array($userId, $userIdList)) { + $userIdList[] = $userId; + } + } + + $data = array( + 'emailId' => $entity->id, + 'emailName' => $entity->get('name'), + ); + + $from = $entity->get('from'); + if ($from) { + $person = $this->getEntityManager()->getRepository('EmailAddress')->getEntityByAddress($from); + if ($person) { + $data['personEntityType'] = $person->getEntityName(); + $data['personEntityName'] = $person->get('name'); + $data['personEntityId'] = $person->id; + } + } + + foreach ($userIdList as $userId) { + $notification = $this->getEntityManager()->getEntity('Notification'); + $notification->set(array( + 'type' => 'EmailReceived', + 'userId' => $userId, + 'data' => $data + )); + $this->getEntityManager()->saveEntity($notification); + } + } + +} + diff --git a/application/Espo/Resources/i18n/en_US/Admin.json b/application/Espo/Resources/i18n/en_US/Admin.json index d66c725423..24a018b021 100644 --- a/application/Espo/Resources/i18n/en_US/Admin.json +++ b/application/Espo/Resources/i18n/en_US/Admin.json @@ -44,7 +44,8 @@ "Create Entity": "Create Entity", "Edit Entity": "Edit Entity", "Create Link": "Create Link", - "Edit Link": "Edit Link" + "Edit Link": "Edit Link", + "Notifications": "Notifications" }, "layouts": { "list": "List", @@ -138,7 +139,8 @@ "authentication": "Authentication settings.", "currency": "Currency settings and rates.", "extensions": "Install or uninstall extensions.", - "integrations": "Integration with third-party services." + "integrations": "Integration with third-party services.", + "notifications": "In-app and email notification settings." }, "options": { "previewSize": { diff --git a/application/Espo/Resources/i18n/en_US/Global.json b/application/Espo/Resources/i18n/en_US/Global.json index 0704d1edfa..16c71f3a0e 100644 --- a/application/Espo/Resources/i18n/en_US/Global.json +++ b/application/Espo/Resources/i18n/en_US/Global.json @@ -225,6 +225,10 @@ "dashlets": { "Stream": "Stream" }, + "notificationMessages": { + "assign": "{entityType} {entity} has been assigned to you", + "emailReceived": "Email received from {from}" + }, "streamMessages": { "create": "{user} created {entityType} {entity}", "createAssigned": "{user} created {entityType} {entity} assigned to {assignee}", diff --git a/application/Espo/Resources/i18n/en_US/Settings.json b/application/Espo/Resources/i18n/en_US/Settings.json index 98fa9b52a7..a69a002e66 100644 --- a/application/Espo/Resources/i18n/en_US/Settings.json +++ b/application/Espo/Resources/i18n/en_US/Settings.json @@ -53,8 +53,9 @@ "ldapAccountDomainNameShort": "Account Domain Name Short", "ldapOptReferrals": "Opt Referrals", "disableExport": "Disable Export (only admin is allowed)", + "assignmentNotificationsEntityList": "Entities to Notify about upon Assignment", "assignmentEmailNotifications": "Send Email Notifications upon Assignment", - "assignmentEmailNotificationsEntityList": "Entities to Notify About", + "assignmentEmailNotificationsEntityList": "Entities to Notify about with Email upon Assignment", "b2cMode": "B2C Mode", "disableAvatars": "Disable Avatars" }, @@ -72,7 +73,8 @@ "Locale": "Locale", "SMTP": "SMTP", "Configuration": "Configuration", - "Notifications": "Notifications", + "In-app Notifications": "In-app Notifications", + "Email Notifications": "Email Notifications", "Currency Settings": "Currency Settings", "Currency Rtes": "Currency Rates" } diff --git a/application/Espo/Resources/layouts/Settings/notifications.json b/application/Espo/Resources/layouts/Settings/notifications.json new file mode 100644 index 0000000000..9e89c2df88 --- /dev/null +++ b/application/Espo/Resources/layouts/Settings/notifications.json @@ -0,0 +1,15 @@ +[ + { + "label": "In-app Notifications", + "rows": [ + [{"name": "assignmentNotificationsEntityList"}] + ] + }, + { + "label": "Email Notifications", + "rows": [ + [{"name": "assignmentEmailNotifications"}], + [{"name": "assignmentEmailNotificationsEntityList"}] + ] + } +] \ No newline at end of file diff --git a/application/Espo/Resources/layouts/Settings/outboundEmail.json b/application/Espo/Resources/layouts/Settings/outboundEmail.json index d3e76d802c..6f0803883d 100644 --- a/application/Espo/Resources/layouts/Settings/outboundEmail.json +++ b/application/Espo/Resources/layouts/Settings/outboundEmail.json @@ -14,11 +14,5 @@ [{"name": "outboundEmailFromName"}, {"name": "outboundEmailFromAddress"}], [{"name": "outboundEmailIsShared"}] ] - }, - { - "label": "Notifications", - "rows": [ - [{"name": "assignmentEmailNotifications"}, {"name": "assignmentEmailNotificationsEntityList"}] - ] } ] diff --git a/application/Espo/Resources/metadata/app/adminPanel.json b/application/Espo/Resources/metadata/app/adminPanel.json index 3c079a5427..52ce20244d 100644 --- a/application/Espo/Resources/metadata/app/adminPanel.json +++ b/application/Espo/Resources/metadata/app/adminPanel.json @@ -22,6 +22,11 @@ "label":"Currency", "description":"currency" }, + { + "url":"#Admin/notifications", + "label":"Notifications", + "description":"notifications" + }, { "url":"#Admin/integrations", "label":"Integrations", diff --git a/application/Espo/Resources/metadata/entityDefs/Settings.json b/application/Espo/Resources/metadata/entityDefs/Settings.json index 8e7d4c35a0..ead51ac935 100644 --- a/application/Espo/Resources/metadata/entityDefs/Settings.json +++ b/application/Espo/Resources/metadata/entityDefs/Settings.json @@ -214,6 +214,11 @@ "translation": "Global.scopeNamesPlural", "view": "Settings.Fields.AssignmentEmailNotificationsEntityList" }, + "assignmentNotificationsEntityList": { + "type": "multiEnum", + "translation": "Global.scopeNamesPlural", + "view": "Settings.Fields.AssignmentNotificationsEntityList" + }, "b2cMode": { "type": "bool", "default": false diff --git a/application/Espo/Resources/metadata/scopes/Email.json b/application/Espo/Resources/metadata/scopes/Email.json index 6f6b169b19..e5cbee6128 100644 --- a/application/Espo/Resources/metadata/scopes/Email.json +++ b/application/Espo/Resources/metadata/scopes/Email.json @@ -2,5 +2,6 @@ "entity": true, "layouts": false, "tab": true, - "acl": true + "acl": true, + "notifications": true } diff --git a/application/Espo/Services/Import.php b/application/Espo/Services/Import.php index 1865809419..fc6e374b13 100644 --- a/application/Espo/Services/Import.php +++ b/application/Espo/Services/Import.php @@ -470,7 +470,7 @@ class Import extends \Espo\Services\Record try { $isDuplicate = $recordService->checkEntityForDuplicate($entity); - if ($this->getEntityManager()->saveEntity($entity, array('noStream' => true))) { + if ($this->getEntityManager()->saveEntity($entity, array('noStream' => true, 'noNotifications' => true))) { $result['id'] = $entity->id; if (empty($id)) { $result['isImported'] = true; diff --git a/frontend/client/res/templates/admin/settings/header-notifications.tpl b/frontend/client/res/templates/admin/settings/header-notifications.tpl new file mode 100644 index 0000000000..5e5b3ed6c3 --- /dev/null +++ b/frontend/client/res/templates/admin/settings/header-notifications.tpl @@ -0,0 +1 @@ +

{{translate 'Administration'}} » {{translate 'Notifications' scope='Admin'}}

diff --git a/frontend/client/res/templates/notifications/items/assign.tpl b/frontend/client/res/templates/notifications/items/assign.tpl new file mode 100644 index 0000000000..2bcf54455e --- /dev/null +++ b/frontend/client/res/templates/notifications/items/assign.tpl @@ -0,0 +1,11 @@ +
+
+ {{{avatar}}} +
+
+ {{{message}}} +
+
+
+ {{{createdAt}}} +
\ No newline at end of file diff --git a/frontend/client/res/templates/stream/notes/email-sent.tpl b/frontend/client/res/templates/stream/notes/email-sent.tpl new file mode 100644 index 0000000000..fadfb45c33 --- /dev/null +++ b/frontend/client/res/templates/stream/notes/email-sent.tpl @@ -0,0 +1,44 @@ +{{#unless onlyContent}} +
  • +{{/unless}} + + {{#unless noEdit}} +
    + {{{right}}} +
    + {{/unless}} + +
    +
    + {{{avatar}}} +
    +
    + + {{{message}}} + +
    +
    + +
    + {{emailName}} +
    + + {{#if post}} +
    + {{{post}}} +
    + {{/if}} + + {{#if attachments}} +
    + {{{attachments}}} +
    + {{/if}} + +
    + {{{createdAt}}} +
    + +{{#unless onlyContent}} +
  • +{{/unless}} diff --git a/frontend/client/src/controllers/admin.js b/frontend/client/src/controllers/admin.js index 1b6c870165..4720b571fd 100644 --- a/frontend/client/src/controllers/admin.js +++ b/frontend/client/src/controllers/admin.js @@ -86,6 +86,22 @@ Espo.define('Controllers.Admin', 'Controller', function (Dep) { model.fetch(); }, + notifications: function () { + var model = this.getSettingsModel(); + + model.once('sync', function () { + model.id = '1'; + this.main('Edit', { + model: model, + views: { + header: {template: 'admin.settings.header-notifications'}, + body: {view: 'Admin.Notifications'} + }, + }); + }, this); + model.fetch(); + }, + outboundEmail: function () { var model = this.getSettingsModel(); diff --git a/frontend/client/src/views/admin/notifications.js b/frontend/client/src/views/admin/notifications.js new file mode 100644 index 0000000000..2e6dc48395 --- /dev/null +++ b/frontend/client/src/views/admin/notifications.js @@ -0,0 +1,54 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014-2015 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/. + ************************************************************************/ + +Espo.define('Views.Admin.Notifications', 'Views.Settings.Record.Edit', function (Dep) { + + return Dep.extend({ + + layoutName: 'notifications', + + dependencyDefs: { + 'assignmentEmailNotifications': { + map: { + true: [ + { + action: 'show', + fields: ['assignmentEmailNotificationsEntityList'] + } + ] + }, + default: [ + { + action: 'hide', + fields: ['assignmentEmailNotificationsEntityList'] + } + ] + } + }, + + setup: function () { + Dep.prototype.setup.call(this); + } + + }); + +}); + diff --git a/frontend/client/src/views/admin/outbound-email.js b/frontend/client/src/views/admin/outbound-email.js index edd1d932e9..dcffcc38fc 100644 --- a/frontend/client/src/views/admin/outbound-email.js +++ b/frontend/client/src/views/admin/outbound-email.js @@ -17,31 +17,15 @@ * * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. - ************************************************************************/ - -Espo.define('Views.Admin.OutboundEmail', 'Views.Settings.Record.Edit', function (Dep) { + ************************************************************************/ + +Espo.define('Views.Admin.OutboundEmail', 'Views.Settings.Record.Edit', function (Dep) { return Dep.extend({ - + layoutName: 'outboundEmail', - + dependencyDefs: { - 'assignmentEmailNotifications': { - map: { - true: [ - { - action: 'show', - fields: ['assignmentEmailNotificationsEntityList'] - } - ] - }, - default: [ - { - action: 'hide', - fields: ['assignmentEmailNotificationsEntityList'] - } - ] - }, 'smtpAuth': { map: { true: [ @@ -58,16 +42,15 @@ Espo.define('Views.Admin.OutboundEmail', 'Views.Settings.Record.Edit', function } ] } - }, - - setup: function () { - Dep.prototype.setup.call(this); - }, - + + setup: function () { + Dep.prototype.setup.call(this); + }, + afterRender: function () { - Dep.prototype.afterRender.call(this); - + Dep.prototype.afterRender.call(this); + var smtpSecurityField = this.getFieldView('smtpSecurity'); this.listenTo(smtpSecurityField, 'change', function () { var smtpSecurity = smtpSecurityField.fetch()['smtpSecurity']; @@ -77,11 +60,11 @@ Espo.define('Views.Admin.OutboundEmail', 'Views.Settings.Record.Edit', function this.model.set('smtpPort', '587'); } else { this.model.set('smtpPort', '25'); - } - }.bind(this)); + } + }.bind(this)); }, - - }); - + + }); + }); diff --git a/frontend/client/src/views/notifications/field.js b/frontend/client/src/views/notifications/field.js index 7fa1393e24..98f765fd60 100644 --- a/frontend/client/src/views/notifications/field.js +++ b/frontend/client/src/views/notifications/field.js @@ -17,19 +17,18 @@ * * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. - ************************************************************************/ + ************************************************************************/ Espo.define('Views.Notifications.Field', 'Views.Fields.Base', function (Dep) { return Dep.extend({ - type: 'notification', - + type: 'notification', + listTemplate: 'notifications.field', - + detailTemplate: 'notifications.field', - - + setup: function () { switch (this.model.get('type')) { case 'Note': @@ -37,41 +36,54 @@ Espo.define('Views.Notifications.Field', 'Views.Fields.Base', function (Dep) { break; case 'MentionInPost': this.processMentionInPost(this.model.get('noteData')); - break; + break; + default: + this.process(); } }, - - processNote: function (data) { + + process: function () { + var type = this.model.get('type'); + if (!type) return; + + var viewName = 'Notifications.Items.' + type.replace(/ /g, ''); + this.createView('notification', viewName, { + model: this.model, + el: this.params.containerEl + ' li[data-id="' + this.model.id + '"]', + }); + }, + + processNote: function (data) { this.wait(true); this.getModelFactory().create('Note', function (model) { - model.set(data); + model.set(data); var viewName = 'Stream.Notes.' + data.type; this.createView('notification', viewName, { model: model, isUserStream: true, el: this.params.containerEl + ' li[data-id="' + this.model.id + '"]', - onlyContent: true, + onlyContent: true, }); this.wait(false); - }, this); + }, this); }, - - processMentionInPost: function (data) { + + processMentionInPost: function (data) { this.wait(true); this.getModelFactory().create('Note', function (model) { - model.set(data); + model.set(data); var viewName = 'Stream.Notes.MentionInPost'; this.createView('notification', viewName, { model: model, userId: this.model.get('userId'), isUserStream: true, el: this.params.containerEl + ' li[data-id="' + this.model.id + '"]', - onlyContent: true, + onlyContent: true, }); this.wait(false); }, this); }, - + }); }); diff --git a/frontend/client/src/views/notifications/items/assign.js b/frontend/client/src/views/notifications/items/assign.js new file mode 100644 index 0000000000..4c091583ea --- /dev/null +++ b/frontend/client/src/views/notifications/items/assign.js @@ -0,0 +1,44 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014-2015 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/. + ************************************************************************/ + +Espo.define('Views.Notifications.Items.Assign', 'Views.Notifications.Notification', function (Dep) { + + return Dep.extend({ + + messageName: 'assign', + + template: 'notifications.items.assign', + + setup: function () { + var data = this.model.get('data') || {}; + + this.userId = data.userId; + + this.messageData['entityType'] = Espo.Utils.upperCaseFirst((this.translate(data.entityType, 'scopeNames') || '').toLowerCase()); + this.messageData['entity'] = '' + data.entityName + ''; + this.messageData['user'] = '' + data.userName + ''; + + this.createMessage(); + }, + + }); +}); + diff --git a/frontend/client/src/views/notifications/notification.js b/frontend/client/src/views/notifications/notification.js new file mode 100644 index 0000000000..53dcc2376c --- /dev/null +++ b/frontend/client/src/views/notifications/notification.js @@ -0,0 +1,95 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014-2015 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/. + ************************************************************************/ + +Espo.define('Views.Notifications.Notification', 'View', function (Dep) { + + return Dep.extend({ + + messageName: null, + + messageTemplate: null, + + messageData: null, + + isSystemAvatar: true, + + data: function () { + return { + avatar: this.getAvatarHtml() + }; + }, + + init: function () { + this.createField('createdAt', null, null, 'Fields.DatetimeShort'); + + this.messageData = {}; + }, + + createField: function (name, type, params, view) { + type = type || this.model.getFieldType(name) || 'base'; + this.createView(name, view || this.getFieldManager().getViewName(type), { + model: this.model, + defs: { + name: name, + params: params || {} + }, + el: this.options.el + ' .cell-' + name, + mode: 'list' + }); + }, + + createMessage: function () { + if (!this.messageTemplate) { + this.messageTemplate = this.translate(this.messageName, 'notificationMessages') || ''; + } + + this.createView('message', 'Stream.Message', { + messageTemplate: this.messageTemplate, + el: this.options.el + ' .message', + model: this.model, + messageData: this.messageData + }); + }, + + getAvatarHtml: function () { + if (this.getConfig().get('disableAvatars')) { + return ''; + } + var t; + var cache = this.getCache(); + if (cache) { + t = cache.get('app', 'timestamp'); + } else { + t = Date.now(); + } + var id = this.userId; + if (this.isSystemAvatar) { + id = 'system'; + } + if (!id) { + return ''; + } + return ''; + } + + }); +}); + diff --git a/frontend/client/src/views/settings/fields/assignment-email-notifications-entity-list.js b/frontend/client/src/views/settings/fields/assignment-email-notifications-entity-list.js index 85e35da17c..e973189367 100644 --- a/frontend/client/src/views/settings/fields/assignment-email-notifications-entity-list.js +++ b/frontend/client/src/views/settings/fields/assignment-email-notifications-entity-list.js @@ -21,18 +21,18 @@ Espo.define('Views.Settings.Fields.AssignmentEmailNotificationsEntityList', 'Views.Fields.MultiEnum', function (Dep) { return Dep.extend({ - + setup: function () { this.params.options = Object.keys(this.getMetadata().get('scopes')).filter(function (scope) { - return this.getMetadata().get('scopes.' + scope + '.tab') && this.getMetadata().get('scopes.' + scope + '.entity'); + return this.getMetadata().get('scopes.' + scope + '.notifications') && this.getMetadata().get('scopes.' + scope + '.entity'); }, this).sort(function (v1, v2) { return this.translate(v1, 'scopeNamesPlural').localeCompare(this.translate(v2, 'scopeNamesPlural')); }.bind(this)); Dep.prototype.setup.call(this); }, - + }); - + }); diff --git a/frontend/client/src/views/settings/fields/assignment-notifications-entity-list.js b/frontend/client/src/views/settings/fields/assignment-notifications-entity-list.js new file mode 100644 index 0000000000..6021cd709e --- /dev/null +++ b/frontend/client/src/views/settings/fields/assignment-notifications-entity-list.js @@ -0,0 +1,40 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014-2015 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/. + ************************************************************************/ +Espo.define('Views.Settings.Fields.AssignmentNotificationsEntityList', 'Views.Fields.MultiEnum', function (Dep) { + + return Dep.extend({ + + setup: function () { + + this.params.options = Object.keys(this.getMetadata().get('scopes')).filter(function (scope) { + return this.getMetadata().get('scopes.' + scope + '.notifications') && + !this.getMetadata().get('scopes.' + scope + '.stream') && + this.getMetadata().get('scopes.' + scope + '.entity'); + }, this).sort(function (v1, v2) { + return this.translate(v1, 'scopeNamesPlural').localeCompare(this.translate(v2, 'scopeNamesPlural')); + }.bind(this)); + + Dep.prototype.setup.call(this); + }, + + }); + +}); diff --git a/frontend/client/src/views/stream/message.js b/frontend/client/src/views/stream/message.js index a5b0247f9d..5ebe7cddc2 100644 --- a/frontend/client/src/views/stream/message.js +++ b/frontend/client/src/views/stream/message.js @@ -17,34 +17,34 @@ * * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. - ************************************************************************/ + ************************************************************************/ Espo.define('Views.Stream.Message', 'View', function (Dep) { return Dep.extend({ - + setup: function () { - var template = this.options.messageTemplate; + var template = this.options.messageTemplate; var data = this.options.messageData; - + for (var key in data) { var value = data[key] || ''; - + if (value.indexOf('field:') === 0) { var field = value.substr(6); this.createField(key, field); - - template = template.replace('{' + key +'}', '{{{' + key +'}}}'); + + template = template.replace('{' + key +'}', '{{{' + key +'}}}'); } else { template = template.replace('{' + key +'}', value); } } - - this._template = template; + + this._template = template; }, - - createField: function (key, name, type, params) { - type = type || this.model.getFieldType(name) || 'base'; + + createField: function (key, name, type, params) { + type = type || this.model.getFieldType(name) || 'base'; this.createView(key, this.getFieldManager().getViewName(type), { model: this.model, defs: { @@ -53,8 +53,7 @@ Espo.define('Views.Stream.Message', 'View', function (Dep) { }, mode: 'list' }); - }, - + } }); }); diff --git a/frontend/client/src/views/stream/note.js b/frontend/client/src/views/stream/note.js index 4c5232cdec..d5c98561ce 100644 --- a/frontend/client/src/views/stream/note.js +++ b/frontend/client/src/views/stream/note.js @@ -33,6 +33,8 @@ Espo.define('Views.Stream.Note', 'View', function (Dep) { isRemovable: false, + isSystemAvatar: false, + data: function () { return { isUserStream: this.isUserStream, @@ -125,7 +127,11 @@ Espo.define('Views.Stream.Note', 'View', function (Dep) { } else { t = Date.now(); } - return ''; + var id = this.model.get('createdById'); + if (this.isSystemAvatar) { + id = 'system'; + } + return ''; } }); diff --git a/frontend/client/src/views/stream/notes/email-received.js b/frontend/client/src/views/stream/notes/email-received.js index 1e01e4d5c8..8af939314b 100644 --- a/frontend/client/src/views/stream/notes/email-received.js +++ b/frontend/client/src/views/stream/notes/email-received.js @@ -27,6 +27,8 @@ Espo.define('Views.Stream.Notes.EmailReceived', 'Views.Stream.Note', function (D isRemovable: true, + isSystemAvatar: true, + data: function () { return _.extend({ emailId: this.emailId, diff --git a/frontend/client/src/views/stream/notes/email-sent.js b/frontend/client/src/views/stream/notes/email-sent.js index 3a2729cd2d..40be07ece3 100644 --- a/frontend/client/src/views/stream/notes/email-sent.js +++ b/frontend/client/src/views/stream/notes/email-sent.js @@ -23,7 +23,7 @@ Espo.define('Views.Stream.Notes.EmailSent', 'Views.Stream.Note', function (Dep) return Dep.extend({ - template: 'stream.notes.email-received', + template: 'stream.notes.email-sent', isRemovable: true,