diff --git a/application/Espo/Controllers/Email.php b/application/Espo/Controllers/Email.php index d7636fa237..1dc8b039a9 100644 --- a/application/Espo/Controllers/Email.php +++ b/application/Espo/Controllers/Email.php @@ -18,7 +18,7 @@ * * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. - ************************************************************************/ + ************************************************************************/ namespace Espo\Controllers; @@ -29,18 +29,18 @@ use \Espo\Core\Exceptions\Error; class Email extends \Espo\Core\Controllers\Record { public function actionGetCopiedAttachments($params, $data, $request) - { + { $id = $request->get('id'); - + return $this->getRecordService()->getCopiedAttachments($id); } - + public function actionSendTestEmail($params, $data, $request) { if (!$request->isPost()) { throw new BadRequest(); } - + if (empty($data['password'])) { if ($data['type'] == 'preferences') { if (!$this->getUser()->isAdmin() && $data['id'] != $this->getUser()->id) { @@ -50,7 +50,7 @@ class Email extends \Espo\Core\Controllers\Record if (!$preferences) { throw new Error(); } - + $data['password'] = $this->getContainer()->get('crypt')->decrypt($preferences->get('smtpPassword')); } else { if (!$this->getUser()->isAdmin()) { @@ -59,8 +59,21 @@ class Email extends \Espo\Core\Controllers\Record $data['password'] = $this->getConfig()->get('smtpPassword'); } } - + return $this->getRecordService()->sendTestEmail($data); } + + public function actionMarkAsRead($params, $data, $request) + { + if (!$request->isPost()) { + throw new BadRequest(); + } + if (empty($data['ids']) || !is_array($data['ids'])) { + throw new BadRequest(); + } + $ids = $data['ids']; + + return $this->getRecordService()->markAsReadByIds($ids); + } } diff --git a/application/Espo/Resources/i18n/en_US/Email.json b/application/Espo/Resources/i18n/en_US/Email.json index 6a116832b6..28fde07b9c 100644 --- a/application/Espo/Resources/i18n/en_US/Email.json +++ b/application/Espo/Resources/i18n/en_US/Email.json @@ -24,7 +24,8 @@ "Draft": "Draft", "Sending": "Sending", "Sent": "Sent", - "Archived": "Archived" + "Archived": "Archived", + "Received": "Received" }, "labels": { "Create Email": "Archive Email", @@ -38,7 +39,8 @@ "Email Accounts": "Email Accounts", "Send Test Email": "Send Test Email", "Send": "Send", - "Email Address": "Email Address" + "Email Address": "Email Address", + "Mark Read": "Mark Read" }, "messages": { "noSmtpSetup": "No SMTP setup. {link}.", diff --git a/application/Espo/Resources/layouts/Email/list.json b/application/Espo/Resources/layouts/Email/list.json index b54b532bbe..2011bce4b5 100644 --- a/application/Espo/Resources/layouts/Email/list.json +++ b/application/Espo/Resources/layouts/Email/list.json @@ -1,6 +1,6 @@ [ {"name":"personStringData","width":16,"notSortable": true, "customLabel": ""}, - {"name":"name","width":32,"link":true,"notSortable": true}, + {"name":"subject","width":32,"link":true,"notSortable": true}, {"name":"status","notSortable": true, "width":10}, {"name":"parent","notSortable": true}, {"name":"dateSent","view": "Fields.DatetimeShort", "notSortable": true, "width":10, "align": "right"} diff --git a/application/Espo/Resources/metadata/entityDefs/Email.json b/application/Espo/Resources/metadata/entityDefs/Email.json index 852639396a..451fe107cb 100644 --- a/application/Espo/Resources/metadata/entityDefs/Email.json +++ b/application/Espo/Resources/metadata/entityDefs/Email.json @@ -8,7 +8,8 @@ "type": "varchar", "required": true, "db": false, - "notStorable": true + "notStorable": true, + "view": "Email.Fields.Subject" }, "fromName": { "type": "varchar" @@ -44,6 +45,11 @@ "notStorable": true, "disabled": true }, + "isRead": { + "type": "bool", + "notStorable": true, + "default": true + }, "nameHash": { "type": "text", "notStorable": true, @@ -101,7 +107,7 @@ }, "status": { "type": "enum", - "options": ["Draft", "Sending", "Sent", "Archived"], + "options": ["Draft", "Sending", "Sent", "Received", "Archived"], "readOnly": true, "default": "Archived" }, @@ -167,7 +173,13 @@ "users": { "type": "hasMany", "entity": "User", - "foreign": "emails" + "foreign": "emails", + "additionalColumns": { + "isRead": { + "type": "bool", + "default": false + } + } }, "attachments": { "type": "hasChildren", diff --git a/application/Espo/Services/Email.php b/application/Espo/Services/Email.php index d7869b7266..d070b8c2b0 100644 --- a/application/Espo/Services/Email.php +++ b/application/Espo/Services/Email.php @@ -206,10 +206,34 @@ class Email extends Record $this->loadAttachmentsTypes($entity); + $this->markAsRead($entity->id); } return $entity; } + public function markAsReadByIds(array $ids) + { + foreach ($ids as $id) { + $this->markAsRead($id); + } + return true; + } + + public function markAsRead($id) + { + + $pdo = $this->getEntityManager()->getPDO(); + $sql = " + UPDATE email_user SET is_read = 1 + WHERE + deleted = 0 AND + user_id = " . $pdo->quote($this->getUser()->id) . " AND + email_id = " . $pdo->quote($id) . " + "; + $pdo->query($sql); + return true; + } + public function loadAdditionalFieldsForList(Entity $entity) { parent::loadAdditionalFieldsForList($entity); @@ -246,8 +270,26 @@ class Email extends Record } $entity->set('personStringData', 'To: ' . implode(', ', $arr)); } - } + + $pdo = $this->getEntityManager()->getPDO(); + + $sql = " + SELECT is_read AS 'isRead' FROM email_user + WHERE + deleted = 0 AND + user_id = " . $pdo->quote($this->getUser()->id) . " AND + email_id = " . $pdo->quote($entity->id) . " + "; + + $sth = $pdo->prepare($sql); + $sth->execute(); + if ($row = $sth->fetch(\PDO::FETCH_ASSOC)) { + $isRead = !empty($row['isRead']) ? true : false; + } else { + $isRead = true; + } + $entity->set('isRead', $isRead); } protected function loadAttachmentsTypes(Entity $entity) diff --git a/frontend/client/res/templates/email/fields/subject/list-link.tpl b/frontend/client/res/templates/email/fields/subject/list-link.tpl new file mode 100644 index 0000000000..1f54f78735 --- /dev/null +++ b/frontend/client/res/templates/email/fields/subject/list-link.tpl @@ -0,0 +1,3 @@ +{{#unless isRead}}{{/unless}} +{{value}} +{{#unless isRead}}{{/unless}} diff --git a/frontend/client/res/templates/record/list-expanded.tpl b/frontend/client/res/templates/record/list-expanded.tpl index bcf854981b..aec5f7bcff 100644 --- a/frontend/client/res/templates/record/list-expanded.tpl +++ b/frontend/client/res/templates/record/list-expanded.tpl @@ -6,7 +6,7 @@ {{{pagination}}} {{/if}} - + {{#if checkboxes}}
{{/if}} - + {{/if}}
@@ -35,7 +35,7 @@ {{#if showCount}}
{{moreCount}}
{{/if}} - {{translate 'Show more'}} + {{translate 'Show more'}}
{{/if}} diff --git a/frontend/client/res/templates/record/list.tpl b/frontend/client/res/templates/record/list.tpl index c716551381..b0c0447d2c 100644 --- a/frontend/client/res/templates/record/list.tpl +++ b/frontend/client/res/templates/record/list.tpl @@ -17,7 +17,7 @@ diff --git a/frontend/client/src/view.js b/frontend/client/src/view.js index 4a6eb7d507..c6d1bcdbc6 100644 --- a/frontend/client/src/view.js +++ b/frontend/client/src/view.js @@ -17,7 +17,7 @@ * * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. - ************************************************************************/ + ************************************************************************/ (function (Espo, Backbone, _, Bull, $) { Espo.View = Bull.View.extend({ @@ -43,6 +43,15 @@ Espo.Ui.notify(text, type, timeout); }, + reRender: function () { + if (this.isRendered()) { + this.render(); + } else if (this.isBeingRendered()) { + this.once('after:render', function () { + this.render(); + }, this); + } + }, getHelper: function () { return this._helper; @@ -131,7 +140,7 @@ return this._helper.fieldManager; } }, - + getBaseController: function () { if (this._helper) { return this._helper.baseController; diff --git a/frontend/client/src/views/email/fields/subject.js b/frontend/client/src/views/email/fields/subject.js new file mode 100644 index 0000000000..9a2038a698 --- /dev/null +++ b/frontend/client/src/views/email/fields/subject.js @@ -0,0 +1,50 @@ +/************************************************************************ + * 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.Email.Fields.Subject', 'Views.Fields.Varchar', function (Dep) { + + return Dep.extend({ + + listLinkTemplate: 'email.fields.subject.list-link', + + data: function () { + return _.extend({ + 'isRead': this.model.get('isRead') + }, Dep.prototype.data.call(this)); + }, + + getValueForDisplay: function () { + return this.model.get('name'); + }, + + getAttributeList: function () { + return ['name', 'isRead']; + }, + + setup: function () { + Dep.prototype.setup.call(this); + this.listenTo(this.model, 'change:isRead', function () { + this.reRender(); + }, this); + } + + }); + +}); diff --git a/frontend/client/src/views/email/list.js b/frontend/client/src/views/email/list.js index 76685e98a3..6ce9144124 100644 --- a/frontend/client/src/views/email/list.js +++ b/frontend/client/src/views/email/list.js @@ -59,6 +59,7 @@ Espo.define('Views.Email.List', 'Views.List', function (Dep) { }; }, + }); }); diff --git a/frontend/client/src/views/email/record/list.js b/frontend/client/src/views/email/record/list.js index 2f6c8aa9c9..b6d5e3b2b1 100644 --- a/frontend/client/src/views/email/record/list.js +++ b/frontend/client/src/views/email/record/list.js @@ -17,18 +17,46 @@ * * 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.Email.Record.List', 'Views.Record.List', function (Dep) { return Dep.extend({ - + mergeAction: false, - + massUpdateAction: false, - + exportAction: false, - + + setup: function () { + Dep.prototype.setup.call(this); + + this.actions.push({ + name: 'markAsRead', + label: 'Mark Read', + action: function (e) { + var ids = []; + for (var i in this.checkedList) { + ids.push(this.checkedList[i]); + } + $.ajax({ + url: 'Email/action/markAsRead', + type: 'POST', + data: JSON.stringify({ + ids: ids + }) + }); + ids.forEach(function (id) { + var model = this.collection.get(id); + if (model) { + model.set('isRead', true); + } + }, this); + }.bind(this) + }); + }, + }); }); diff --git a/frontend/client/src/views/fields/base.js b/frontend/client/src/views/fields/base.js index 9faf53c278..005cea624f 100644 --- a/frontend/client/src/views/fields/base.js +++ b/frontend/client/src/views/fields/base.js @@ -280,13 +280,7 @@ Espo.define('Views.Fields.Base', 'View', function (Dep) { }); if (changed) { - if (this.isRendered()) { - this.render(); - } else if (this.isBeingRendered()) { - this.once('after:render', function () { - this.render(); - }, this); - } + this.reRender(); } } }.bind(this)); diff --git a/frontend/client/src/views/record/list.js b/frontend/client/src/views/record/list.js index f69bfdf96d..14fb6083b5 100644 --- a/frontend/client/src/views/record/list.js +++ b/frontend/client/src/views/record/list.js @@ -145,6 +145,15 @@ Espo.define('Views.Record.List', 'View', function (Dep) { 'click .checkbox-dropdown [data-action="selectAllResult"]': function (e) { this.selectAllResult(); }, + 'click .actions a.mass-action': function (e) { + $el = $(e.currentTarget); + var action = $el.data('action'); + this.actions.forEach(function (item) { + if (item.name == action) { + item.action.call(this, e); + } + }, this); + } }, actions: [], @@ -430,13 +439,13 @@ Espo.define('Views.Record.List', 'View', function (Dep) { this.actions = []; } - if (this.checkboxes) { + /*if (this.checkboxes) { this.actions.forEach(function (item) { this.events['click .actions a[data-action="' + item.name + '"]'] = function (e) { item.action.call(this, e); }.bind(this); }.bind(this)); - } + }*/ this.listenTo(this.collection, 'sync', function () { if (this.noRebuild) {