email filters dev

This commit is contained in:
yuri
2015-08-27 15:28:36 +03:00
parent 803111b12f
commit 99b4f7eb5c
8 changed files with 320 additions and 50 deletions
@@ -0,0 +1,94 @@
<?php
/************************************************************************
* 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/.
************************************************************************/
namespace Espo\Core\Mail;
use \Espo\Entities\Email;
class FiltersMatcher
{
public function __construct()
{
}
public function match(Email $email, $filterList = [])
{
foreach ($filterList as $filter) {
if ($filter->get('from')) {
if (strtolower($filter->get('from')) === strtolower($email->get('from'))) {
return true;
}
}
if ($filter->get('to')) {
if ($email->get('to')) {
$toArr = explode(';', $email->get('to'));
foreach ($toArr as $to) {
if (strtolower($to) === strtolower($filter->get('to'))) {
return true;
}
}
}
}
if ($filter->get('subject')) {
if ($this->matchString($filter->get('subject'), $email->get('name'))) {
return true;
}
}
}
return false;
}
public function matchBody(Email $email, $filterList = [])
{
foreach ($filterList as $filter) {
if ($filter->get('bodyContains')) {
$phraseList = $filter->get('bodyContains');
$body = $email->get('body');
$bodyPlain = $email->get('bodyPlain');
foreach ($phraseList as $phrase) {
if (stripos($bodyPlain, $phrase) !== false) {
return true;
}
if (stripos($body, $phrase) !== false) {
return true;
}
}
}
}
return false;
}
protected function matchString($pattern, $value)
{
if ($pattern == $value) {
return true;
}
$pattern = preg_quote($pattern, '#');
$pattern = str_replace('\*', '.*', $pattern).'\z';
if (preg_match('#^'.$pattern.'#', $value)) {
return true;
}
return false;
}
}
+18 -1
View File
@@ -25,6 +25,7 @@ namespace Espo\Core\Mail;
use \Zend\Mime\Mime as Mime;
use \Espo\ORM\Entity;
use \Espo\ORM\Email;
class Importer
{
@@ -34,11 +35,14 @@ class Importer
private $config;
private $filtersMatcher;
public function __construct($entityManager, $fileManager, $config)
{
$this->entityManager = $entityManager;
$this->fileManager = $fileManager;
$this->config = $config;
$this->filtersMatcher = new FiltersMatcher();
}
protected function getEntityManager()
@@ -55,7 +59,12 @@ class Importer
return $this->fileManager;
}
public function importMessage($message, $userId, $teamsIds = array())
protected function getFiltersMatcher()
{
return $this->filtersMatcher;
}
public function importMessage($message, $userId, $teamsIds = [], $filterList = [])
{
try {
$email = $this->getEntityManager()->getEntity('Email');
@@ -87,6 +96,10 @@ class Importer
$email->set('to', implode(';', $toArr));
$email->set('cc', implode(';', $ccArr));
if ($this->getFiltersMatcher()->match($email, $filterList)) {
return false;
}
if (isset($message->messageId) && !empty($message->messageId)) {
$email->set('messageId', $message->messageId);
if (isset($message->deliveredTo)) {
@@ -149,6 +162,10 @@ class Importer
$email->set('body', $body);
}
if ($this->getFiltersMatcher()->matchBody($email, $filterList)) {
return false;
}
$parentFound = false;
if (isset($message->references) && !empty($message->references)) {
@@ -10,7 +10,7 @@
},
"tooltips": {
"name": "Just a name of the filter.",
"subject": "Use wildcard %:\n\ntext% - starts with text,\n%text% - contains text,\n%text - ends with text.",
"subject": "Use wildcard *:\n\ntext* - starts with text,\n*text* - contains text,\n*text - ends with text.",
"bodyContains": "Body of email contains any of specified words or phrases.",
"from": "Emails being sent from the specified address. Leave empty if not needed.",
"to": "Emails being sent to the specified address. Leave empty if not needed.",
+13 -2
View File
@@ -176,7 +176,6 @@ class EmailAccount extends Record
$maxSize = $this->getConfig()->get('emailMessageMaxSize');
$user = $this->getEntityManager()->getEntity('User', $emailAccount->get('assignedUserId'));
if (!$user) {
throw new Error();
}
@@ -188,6 +187,18 @@ class EmailAccount extends Record
$teamIds[] = $teamId;
}
$filterCollection = $this->getEntityManager()->getRepository('EmailFilter')->where([
'OR' => [
[
'parentType' => $emailAccount->getEntityType(),
'parentId' => $emailAccount->id
],
[
'parentId' => null
]
]
])->find();
$fetchData = json_decode($emailAccount->get('fetchData'), true);
if (empty($fetchData)) {
$fetchData = array();
@@ -263,7 +274,7 @@ class EmailAccount extends Record
$flags = $message->getFlags();
}
try {
$email = $importer->importMessage($message, $userId, $teamIds);
$email = $importer->importMessage($message, $userId, $teamIds, $filterCollection);
} catch (\Exception $e) {
$GLOBALS['log']->error('EmailAccount '.$emailAccount->id.' (Import Message): [' . $e->getCode() . '] ' .$e->getMessage());
}
+35 -23
View File
@@ -142,9 +142,9 @@ class InboundEmail extends \Espo\Services\Record
throw new Error();
}
public function fetchFromMailServer(Entity $inboundEmail)
public function fetchFromMailServer(Entity $emailAccount)
{
if ($inboundEmail->get('status') != 'Active') {
if ($emailAccount->get('status') != 'Active') {
throw new Error();
}
@@ -152,17 +152,29 @@ class InboundEmail extends \Espo\Services\Record
$maxSize = $this->getConfig()->get('emailMessageMaxSize');
$teamId = $inboundEmail->get('teamId');
$teamId = $emailAccount->get('teamId');
$userId = $this->getUser()->id;
if ($inboundEmail->get('assignToUserId')) {
$userId = $inboundEmail->get('assignToUserId');
if ($emailAccount->get('assignToUserId')) {
$userId = $emailAccount->get('assignToUserId');
}
$teamIds = array();
if (!empty($teamId)) {
$teamIds[] = $teamId;
}
$fetchData = json_decode($inboundEmail->get('fetchData'), true);
$filterCollection = $this->getEntityManager()->getRepository('EmailFilter')->where([
'OR' => [
[
'parentType' => $emailAccount->getEntityType(),
'parentId' => $emailAccount->id
],
[
'parentId' => null
]
]
])->find();
$fetchData = json_decode($emailAccount->get('fetchData'), true);
if (empty($fetchData)) {
$fetchData = array();
}
@@ -174,19 +186,19 @@ class InboundEmail extends \Espo\Services\Record
}
$imapParams = array(
'host' => $inboundEmail->get('host'),
'port' => $inboundEmail->get('port'),
'user' => $inboundEmail->get('username'),
'password' => $this->getCrypt()->decrypt($inboundEmail->get('password')),
'host' => $emailAccount->get('host'),
'port' => $emailAccount->get('port'),
'user' => $emailAccount->get('username'),
'password' => $this->getCrypt()->decrypt($emailAccount->get('password')),
);
if ($inboundEmail->get('ssl')) {
if ($emailAccount->get('ssl')) {
$imapParams['ssl'] = 'SSL';
}
$storage = new \Espo\Core\Mail\Mail\Storage\Imap($imapParams);
$monitoredFolders = $inboundEmail->get('monitoredFolders');
$monitoredFolders = $emailAccount->get('monitoredFolders');
if (empty($monitoredFolders)) {
$monitoredFolders = 'INBOX';
}
@@ -198,7 +210,7 @@ class InboundEmail extends \Espo\Services\Record
try {
$storage->selectFolder($folder);
} catch (\Exception $e) {
$GLOBALS['log']->error('InboundEmail '.$inboundEmail->id.' (Select Folder) [' . $e->getCode() . '] ' .$e->getMessage());
$GLOBALS['log']->error('InboundEmail '.$emailAccount->id.' (Select Folder) [' . $e->getCode() . '] ' .$e->getMessage());
continue;
}
@@ -246,26 +258,26 @@ class InboundEmail extends \Espo\Services\Record
}
if (!$toSkip) {
try {
$email = $importer->importMessage($message, $userId, $teamIds);
$email = $importer->importMessage($message, $userId, $teamIds, $filterCollection);
} catch (\Exception $e) {
$GLOBALS['log']->error('InboundEmail '.$inboundEmail->id.' (Import Message): [' . $e->getCode() . '] ' .$e->getMessage());
$GLOBALS['log']->error('InboundEmail '.$emailAccount->id.' (Import Message): [' . $e->getCode() . '] ' .$e->getMessage());
}
}
} catch (\Exception $e) {
$GLOBALS['log']->error('InboundEmail '.$inboundEmail->id.' (Get Message): [' . $e->getCode() . '] ' .$e->getMessage());
$GLOBALS['log']->error('InboundEmail '.$emailAccount->id.' (Get Message): [' . $e->getCode() . '] ' .$e->getMessage());
}
if (!empty($email)) {
if (!$inboundEmail->get('createCase')) {
if (!$emailAccount->get('createCase')) {
$this->noteAboutEmail($email);
}
if ($inboundEmail->get('createCase')) {
$this->createCase($inboundEmail, $email);
if ($emailAccount->get('createCase')) {
$this->createCase($emailAccount, $email);
} else {
if ($inboundEmail->get('reply')) {
if ($emailAccount->get('reply')) {
$user = $this->getEntityManager()->getEntity('User', $userId);
$this->autoReply($inboundEmail, $email, $user);
$this->autoReply($emailAccount, $email, $user);
}
}
}
@@ -290,8 +302,8 @@ class InboundEmail extends \Espo\Services\Record
$fetchData['lastUID'][$folder] = $lastUID;
$fetchData['lastDate'][$folder] = $lastDate;
$inboundEmail->set('fetchData', json_encode($fetchData));
$this->getEntityManager()->saveEntity($inboundEmail, array('silent' => true));
$emailAccount->set('fetchData', json_encode($fetchData));
$this->getEntityManager()->saveEntity($emailAccount, array('silent' => true));
}
return true;
+27 -1
View File
@@ -135,7 +135,33 @@ Espo.define('acl', [], function () {
return model.get('isRemovable');
}
}
return this.check(model.name, action, this.user.isOwner(model), this.user.inTeam(model));
return this.check(model.name, action, this.checkIsOwner(model), this.checkInTeam(model));
},
checkIsOwner: function (model) {
var result = this.user.id === model.get('assignedUserId') || this.user.id === model.get('createdById');
if (!result) {
if (!model.hasField('assignedUser') && !model.hasField('createdBy')) {
return true;
}
}
return result;
},
checkInTeam: function (model) {
var userTeamIds = this.user.getTeamIds();
if (model.name == 'Team') {
return (userTeamIds.indexOf(model.id) != -1);
} else {
var teamIds = model.getTeamIds();
for (var i in userTeamIds) {
if (teamIds.indexOf(i) != -1) {
return true;
}
}
}
return false;
},
clear: function () {
+1 -22
View File
@@ -26,28 +26,7 @@ Espo.define('models/user', 'model', function (Dep) {
isAdmin: function () {
return this.get('isAdmin');
},
isOwner: function (model) {
return this.id === model.get('assignedUserId') || this.id === model.get('createdById');
},
inTeam: function (model) {
var userTeamIds = this.getTeamIds();
if (model.name == 'Team') {
return (userTeamIds.indexOf(model.id) != -1);
} else {
var teamIds = model.getTeamIds();
for (var i in userTeamIds) {
if (teamIds.indexOf(i) != -1) {
return true;
}
}
}
return false;
},
}
});
+131
View File
@@ -0,0 +1,131 @@
<?php
/************************************************************************
* 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/.
************************************************************************/
namespace tests\Espo\Core\Mail;
use tests\ReflectionHelper;
class FiltersMatcherTest extends \PHPUnit_Framework_TestCase
{
protected $object;
protected function setUp()
{
$this->object = new \Espo\Core\Mail\FiltersMatcher();
$this->emailDefs = array(
'fields' => array(
'from' => array(
'type' => 'varchar'
),
'to' => array(
'type' => 'varchar'
),
'name' => array(
'type' => 'varchar'
),
'subject' => array(
'type' => 'varchar'
),
'body' => array(
'type' => 'text'
),
'bodyPlain' => array(
'type' => 'text'
)
)
);
$this->filterDefs = array(
'fields' => array(
'from' => array(
'type' => 'varchar'
),
'to' => array(
'type' => 'varchar'
),
'subject' => array(
'type' => 'varchar'
),
'bodyContains' => array(
'type' => 'jsonArray'
)
)
);
}
protected function tearDown()
{
$this->object = NULL;
}
function testMatch()
{
$email = new \Espo\Entities\Email($this->emailDefs);
$email->set('from', 'test@tester');
$filter = new \Espo\Entities\EmailFilter($this->filterDefs);
$filter->set(array(
'from' => 'test@tester'
));
$filterList = [$filter];
$this->assertTrue($this->object->match($email, $filterList));
$email->set('from', 'test@tester');
$email->set('to', 'test@tester;baraka@tester');
$filter = new \Espo\Entities\EmailFilter($this->filterDefs);
$filter->set(array(
'to' => 'baraka@tester'
));
$filterList = [$filter];
$this->assertTrue($this->object->match($email, $filterList));
$email->set('subject', 'test hello man');
$filter = new \Espo\Entities\EmailFilter($this->filterDefs);
$filter->set(array(
'subject' => '*hello*'
));
$filterList = [$filter];
$this->assertTrue($this->object->match($email, $filterList));
$email->set('name', 'test hello man');
$filter = new \Espo\Entities\EmailFilter($this->filterDefs);
$filter->set(array(
'subject' => 'hello'
));
$filterList = [$filter];
$this->assertFalse($this->object->match($email, $filterList));
}
function testMatchBody()
{
$email = new \Espo\Entities\Email($this->emailDefs);
$email->set('body', 'hello Man tester');
$filter = new \Espo\Entities\EmailFilter($this->filterDefs);
$filter->set(array(
'bodyContains' => ['man', 'red']
));
$filterList = [$filter];
$this->assertTrue($this->object->matchBody($email, $filterList));
}
}