Improve email sending system and add Postmark as mail transport

This commit is contained in:
Frederic Guillot
2015-06-06 14:10:31 -04:00
parent c87e1fbc33
commit 9d9e3afba2
15 changed files with 284 additions and 137 deletions

View File

@@ -112,7 +112,7 @@ class Webhook extends Base
$this->response->text('Not Authorized', 401); $this->response->text('Not Authorized', 401);
} }
echo $this->postmarkWebhook->parsePayload($this->request->getJson() ?: array()) ? 'PARSED' : 'IGNORED'; echo $this->postmark->receiveEmail($this->request->getJson() ?: array()) ? 'PARSED' : 'IGNORED';
} }
/** /**

View File

@@ -11,6 +11,7 @@ use Pimple\Container;
* @author Frederic Guillot * @author Frederic Guillot
* *
* @property \Core\Helper $helper * @property \Core\Helper $helper
* @property \Core\EmailClient $emailClient
* @property \Core\HttpClient $httpClient * @property \Core\HttpClient $httpClient
* @property \Core\Paginator $paginator * @property \Core\Paginator $paginator
* @property \Core\Request $request * @property \Core\Request $request
@@ -22,9 +23,10 @@ use Pimple\Container;
* @property \Integration\HipchatWebhook $hipchatWebhook * @property \Integration\HipchatWebhook $hipchatWebhook
* @property \Integration\Jabber $jabber * @property \Integration\Jabber $jabber
* @property \Integration\MailgunWebhook $mailgunWebhook * @property \Integration\MailgunWebhook $mailgunWebhook
* @property \Integration\PostmarkWebhook $postmarkWebhook * @property \Integration\Postmark $postmark
* @property \Integration\SendgridWebhook $sendgridWebhook * @property \Integration\SendgridWebhook $sendgridWebhook
* @property \Integration\SlackWebhook $slackWebhook * @property \Integration\SlackWebhook $slackWebhook
* @property \Integration\Smtp $smtp
* @property \Model\Acl $acl * @property \Model\Acl $acl
* @property \Model\Action $action * @property \Model\Action $action
* @property \Model\Authentication $authentication * @property \Model\Authentication $authentication

43
app/Core/EmailClient.php Normal file
View File

@@ -0,0 +1,43 @@
<?php
namespace Core;
/**
* Mail client
*
* @package core
* @author Frederic Guillot
*/
class EmailClient extends Base
{
/**
* Send a HTML email
*
* @access public
* @param string $email
* @param string $name
* @param string $subject
* @param string $html
*/
public function send($email, $name, $subject, $html)
{
$this->container['logger']->debug('Sending email to '.$email.' ('.MAIL_TRANSPORT.')');
$start_time = microtime(true);
$author = 'Kanboard';
if (Session::isOpen() && $this->userSession->isLogged()) {
$author = e('%s via Kanboard', $this->user->getFullname($this->session['user']));
}
switch (MAIL_TRANSPORT) {
case 'postmark':
$this->postmark->sendEmail($email, $name, $subject, $html, $author);
break;
default:
$this->smtp->sendEmail($email, $name, $subject, $html, $author);
}
$this->container['logger']->debug('Email sent in '.round(microtime(true) - $start_time, 6).' seconds');
}
}

View File

@@ -2,22 +2,20 @@
namespace Core; namespace Core;
use Pimple\Container;
/** /**
* HTTP client * HTTP client
* *
* @package core * @package core
* @author Frederic Guillot * @author Frederic Guillot
*/ */
class HttpClient class HttpClient extends Base
{ {
/** /**
* HTTP connection timeout in seconds * HTTP connection timeout in seconds
* *
* @var integer * @var integer
*/ */
const HTTP_TIMEOUT = 2; const HTTP_TIMEOUT = 5;
/** /**
* Number of maximum redirections for the HTTP client * Number of maximum redirections for the HTTP client
@@ -31,26 +29,7 @@ class HttpClient
* *
* @var string * @var string
*/ */
const HTTP_USER_AGENT = 'Kanboard Webhook'; const HTTP_USER_AGENT = 'Kanboard';
/**
* Container instance
*
* @access protected
* @var \Pimple\Container
*/
protected $container;
/**
* Constructor
*
* @access public
* @param \Pimple\Container $container
*/
public function __construct(Container $container)
{
$this->container = $container;
}
/** /**
* Send a POST HTTP request * Send a POST HTTP request
@@ -58,19 +37,20 @@ class HttpClient
* @access public * @access public
* @param string $url * @param string $url
* @param array $data * @param array $data
* @param array $headers
* @return string * @return string
*/ */
public function post($url, array $data) public function post($url, array $data, array $headers = array())
{ {
if (empty($url)) { if (empty($url)) {
return ''; return '';
} }
$headers = array( $headers = array_merge(array(
'User-Agent: '.self::HTTP_USER_AGENT, 'User-Agent: '.self::HTTP_USER_AGENT,
'Content-Type: application/json', 'Content-Type: application/json',
'Connection: close', 'Connection: close',
); ), $headers);
$context = stream_context_create(array( $context = stream_context_create(array(
'http' => array( 'http' => array(
@@ -83,12 +63,21 @@ class HttpClient
) )
)); ));
$response = @file_get_contents(trim($url), false, $context); $stream = @fopen(trim($url), 'r', false, $context);
$response = '';
if (is_resource($stream)) {
$response = stream_get_contents($stream);
}
else {
$this->container['logger']->error('HttpClient: request failed');
}
if (DEBUG) { if (DEBUG) {
$this->container['logger']->debug($url); $this->container['logger']->debug('HttpClient: url='.$url);
$this->container['logger']->debug(var_export($data, true)); $this->container['logger']->debug('HttpClient: payload='.var_export($data, true));
$this->container['logger']->debug($response); $this->container['logger']->debug('HttpClient: metadata='.var_export(@stream_get_meta_data($stream), true));
$this->container['logger']->debug('HttpClient: response='.$response);
} }
return $response; return $response;

View File

@@ -5,13 +5,40 @@ namespace Integration;
use HTML_To_Markdown; use HTML_To_Markdown;
/** /**
* Postmark Webhook * Postmark integration
* *
* @package integration * @package integration
* @author Frederic Guillot * @author Frederic Guillot
*/ */
class PostmarkWebhook extends \Core\Base class Postmark extends \Core\Base
{ {
/**
* Send a HTML email
*
* @access public
* @param string $email
* @param string $name
* @param string $subject
* @param string $html
* @param string $author
*/
public function sendEmail($email, $name, $subject, $html, $author)
{
$headers = array(
'Accept: application/json',
'X-Postmark-Server-Token: '.POSTMARK_API_TOKEN,
);
$payload = array(
'From' => sprintf('%s <%s>', $author, MAIL_FROM),
'To' => sprintf('%s <%s>', $name, $email),
'Subject' => $subject,
'HtmlBody' => $html,
);
$this->httpClient->post('https://api.postmarkapp.com/email', $payload, $headers);
}
/** /**
* Parse incoming email * Parse incoming email
* *
@@ -19,7 +46,7 @@ class PostmarkWebhook extends \Core\Base
* @param array $payload Incoming email * @param array $payload Incoming email
* @return boolean * @return boolean
*/ */
public function parsePayload(array $payload) public function receiveEmail(array $payload)
{ {
if (empty($payload['From']) || empty($payload['Subject']) || empty($payload['MailboxHash'])) { if (empty($payload['From']) || empty($payload['Subject']) || empty($payload['MailboxHash'])) {
return false; return false;
@@ -29,7 +56,7 @@ class PostmarkWebhook extends \Core\Base
$user = $this->user->getByEmail($payload['From']); $user = $this->user->getByEmail($payload['From']);
if (empty($user)) { if (empty($user)) {
$this->container['logger']->debug('PostmarkWebhook: ignored => user not found'); $this->container['logger']->debug('Postmark: ignored => user not found');
return false; return false;
} }
@@ -37,13 +64,13 @@ class PostmarkWebhook extends \Core\Base
$project = $this->project->getByIdentifier($payload['MailboxHash']); $project = $this->project->getByIdentifier($payload['MailboxHash']);
if (empty($project)) { if (empty($project)) {
$this->container['logger']->debug('PostmarkWebhook: ignored => project not found'); $this->container['logger']->debug('Postmark: ignored => project not found');
return false; return false;
} }
// The user must be member of the project // The user must be member of the project
if (! $this->projectPermission->isMember($project['id'], $user['id'])) { if (! $this->projectPermission->isMember($project['id'], $user['id'])) {
$this->container['logger']->debug('PostmarkWebhook: ignored => user is not member of the project'); $this->container['logger']->debug('Postmark: ignored => user is not member of the project');
return false; return false;
} }

71
app/Integration/Smtp.php Normal file
View File

@@ -0,0 +1,71 @@
<?php
namespace Integration;
use Swift_Message;
use Swift_Mailer;
use Swift_MailTransport;
use Swift_SendmailTransport;
use Swift_SmtpTransport;
use Swift_TransportException;
/**
* Smtp
*
* @package integration
* @author Frederic Guillot
*/
class Smtp extends \Core\Base
{
/**
* Send a HTML email
*
* @access public
* @param string $email
* @param string $name
* @param string $subject
* @param string $html
* @param string $author
*/
public function sendEmail($email, $name, $subject, $html, $author)
{
try {
$message = Swift_Message::newInstance()
->setSubject($subject)
->setFrom(array(MAIL_FROM => $author))
->setBody($html, 'text/html')
->setTo(array($email => $name));
Swift_Mailer::newInstance($this->getTransport())->send($message);
}
catch (Swift_TransportException $e) {
$this->container['logger']->error($e->getMessage());
}
}
/**
* Get SwiftMailer transport
*
* @access private
* @return \Swift_Transport
*/
private function getTransport()
{
switch (MAIL_TRANSPORT) {
case 'smtp':
$transport = Swift_SmtpTransport::newInstance(MAIL_SMTP_HOSTNAME, MAIL_SMTP_PORT);
$transport->setUsername(MAIL_SMTP_USERNAME);
$transport->setPassword(MAIL_SMTP_PASSWORD);
$transport->setEncryption(MAIL_SMTP_ENCRYPTION);
break;
case 'sendmail':
$transport = Swift_SendmailTransport::newInstance(MAIL_SENDMAIL_COMMAND);
break;
default:
$transport = Swift_MailTransport::newInstance();
}
return $transport;
}
}

View File

@@ -4,9 +4,6 @@ namespace Model;
use Core\Session; use Core\Session;
use Core\Translator; use Core\Translator;
use Swift_Message;
use Swift_Mailer;
use Swift_TransportException;
/** /**
* Notification model * Notification model
@@ -101,21 +98,8 @@ class Notification extends Base
*/ */
public function sendEmails($template, array $users, array $data) public function sendEmails($template, array $users, array $data)
{ {
try {
$author = '';
if (Session::isOpen() && $this->userSession->isLogged()) {
$author = e('%s via Kanboard', $this->user->getFullname($this->session['user']));
}
$mailer = Swift_Mailer::newInstance($this->container['mailer']);
foreach ($users as $user) { foreach ($users as $user) {
$this->container['logger']->debug('Send email notification to '.$user['username'].' lang='.$user['language']);
$start_time = microtime(true);
// Use the user language otherwise use the application language (do not use the session language) // Use the user language otherwise use the application language (do not use the session language)
if (! empty($user['language'])) { if (! empty($user['language'])) {
Translator::load($user['language']); Translator::load($user['language']);
@@ -124,20 +108,12 @@ class Notification extends Base
Translator::load($this->config->get('application_language', 'en_US')); Translator::load($this->config->get('application_language', 'en_US'));
} }
// Send the message $this->emailClient->send(
$message = Swift_Message::newInstance() $user['email'],
->setSubject($this->getMailSubject($template, $data)) $user['name'] ?: $user['username'],
->setFrom(array(MAIL_FROM => $author ?: 'Kanboard')) $this->getMailSubject($template, $data),
->setBody($this->getMailContent($template, $data), 'text/html') $this->getMailContent($template, $data)
->setTo(array($user['email'] => $user['name'] ?: $user['username'])); );
$mailer->send($message);
$this->container['logger']->debug('Email sent in '.round(microtime(true) - $start_time, 6).' seconds');
}
}
catch (Swift_TransportException $e) {
$this->container['logger']->error($e->getMessage());
} }
// Restore locales // Restore locales
@@ -167,40 +143,40 @@ class Notification extends Base
{ {
switch ($template) { switch ($template) {
case 'file_creation': case 'file_creation':
$subject = $this->getStandardMailSubject(t('New attachment'), $data); $subject = $this->getStandardMailSubject(e('New attachment'), $data);
break; break;
case 'comment_creation': case 'comment_creation':
$subject = $this->getStandardMailSubject(t('New comment'), $data); $subject = $this->getStandardMailSubject(e('New comment'), $data);
break; break;
case 'comment_update': case 'comment_update':
$subject = $this->getStandardMailSubject(t('Comment updated'), $data); $subject = $this->getStandardMailSubject(e('Comment updated'), $data);
break; break;
case 'subtask_creation': case 'subtask_creation':
$subject = $this->getStandardMailSubject(t('New subtask'), $data); $subject = $this->getStandardMailSubject(e('New subtask'), $data);
break; break;
case 'subtask_update': case 'subtask_update':
$subject = $this->getStandardMailSubject(t('Subtask updated'), $data); $subject = $this->getStandardMailSubject(e('Subtask updated'), $data);
break; break;
case 'task_creation': case 'task_creation':
$subject = $this->getStandardMailSubject(t('New task'), $data); $subject = $this->getStandardMailSubject(e('New task'), $data);
break; break;
case 'task_update': case 'task_update':
$subject = $this->getStandardMailSubject(t('Task updated'), $data); $subject = $this->getStandardMailSubject(e('Task updated'), $data);
break; break;
case 'task_close': case 'task_close':
$subject = $this->getStandardMailSubject(t('Task closed'), $data); $subject = $this->getStandardMailSubject(e('Task closed'), $data);
break; break;
case 'task_open': case 'task_open':
$subject = $this->getStandardMailSubject(t('Task opened'), $data); $subject = $this->getStandardMailSubject(e('Task opened'), $data);
break; break;
case 'task_move_column': case 'task_move_column':
$subject = $this->getStandardMailSubject(t('Column Change'), $data); $subject = $this->getStandardMailSubject(e('Column Change'), $data);
break; break;
case 'task_move_position': case 'task_move_position':
$subject = $this->getStandardMailSubject(t('Position Change'), $data); $subject = $this->getStandardMailSubject(e('Position Change'), $data);
break; break;
case 'task_assignee_change': case 'task_assignee_change':
$subject = $this->getStandardMailSubject(t('Assignee Change'), $data); $subject = $this->getStandardMailSubject(e('Assignee Change'), $data);
break; break;
case 'task_due': case 'task_due':
$subject = e('[%s][Due tasks]', $data['project']); $subject = e('[%s][Due tasks]', $data['project']);

View File

@@ -64,6 +64,7 @@ class ClassProvider implements ServiceProviderInterface
'Webhook', 'Webhook',
), ),
'Core' => array( 'Core' => array(
'EmailClient',
'Helper', 'Helper',
'HttpClient', 'HttpClient',
'MemoryCache', 'MemoryCache',
@@ -78,9 +79,10 @@ class ClassProvider implements ServiceProviderInterface
'HipchatWebhook', 'HipchatWebhook',
'Jabber', 'Jabber',
'MailgunWebhook', 'MailgunWebhook',
'PostmarkWebhook', 'Postmark',
'SendgridWebhook', 'SendgridWebhook',
'SlackWebhook', 'SlackWebhook',
'Smtp',
) )
); );

View File

@@ -1,33 +0,0 @@
<?php
namespace ServiceProvider;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
use Swift_SmtpTransport;
use Swift_SendmailTransport;
use Swift_MailTransport;
class MailerProvider implements ServiceProviderInterface
{
public function register(Container $container)
{
$container['mailer'] = function () {
switch (MAIL_TRANSPORT) {
case 'smtp':
$transport = Swift_SmtpTransport::newInstance(MAIL_SMTP_HOSTNAME, MAIL_SMTP_PORT);
$transport->setUsername(MAIL_SMTP_USERNAME);
$transport->setPassword(MAIL_SMTP_PASSWORD);
$transport->setEncryption(MAIL_SMTP_ENCRYPTION);
break;
case 'sendmail':
$transport = Swift_SendmailTransport::newInstance(MAIL_SENDMAIL_COMMAND);
break;
default:
$transport = Swift_MailTransport::newInstance();
}
return $transport;
};
}
}

View File

@@ -27,4 +27,3 @@ $container->register(new ServiceProvider\LoggingProvider);
$container->register(new ServiceProvider\DatabaseProvider); $container->register(new ServiceProvider\DatabaseProvider);
$container->register(new ServiceProvider\ClassProvider); $container->register(new ServiceProvider\ClassProvider);
$container->register(new ServiceProvider\EventDispatcherProvider); $container->register(new ServiceProvider\EventDispatcherProvider);
$container->register(new ServiceProvider\MailerProvider);

View File

@@ -64,6 +64,7 @@ defined('MAIL_SMTP_USERNAME') or define('MAIL_SMTP_USERNAME', '');
defined('MAIL_SMTP_PASSWORD') or define('MAIL_SMTP_PASSWORD', ''); defined('MAIL_SMTP_PASSWORD') or define('MAIL_SMTP_PASSWORD', '');
defined('MAIL_SMTP_ENCRYPTION') or define('MAIL_SMTP_ENCRYPTION', null); defined('MAIL_SMTP_ENCRYPTION') or define('MAIL_SMTP_ENCRYPTION', null);
defined('MAIL_SENDMAIL_COMMAND') or define('MAIL_SENDMAIL_COMMAND', '/usr/sbin/sendmail -bs'); defined('MAIL_SENDMAIL_COMMAND') or define('MAIL_SENDMAIL_COMMAND', '/usr/sbin/sendmail -bs');
defined('POSTMARK_API_TOKEN') or define('POSTMARK_API_TOKEN', '');
// Enable or disable "Strict-Transport-Security" HTTP header // Enable or disable "Strict-Transport-Security" HTTP header
defined('ENABLE_HSTS') or define('ENABLE_HSTS', true); defined('ENABLE_HSTS') or define('ENABLE_HSTS', true);

View File

@@ -14,7 +14,7 @@ define('FILES_DIR', 'data/files/');
// E-mail address for the "From" header (notifications) // E-mail address for the "From" header (notifications)
define('MAIL_FROM', 'notifications@kanboard.local'); define('MAIL_FROM', 'notifications@kanboard.local');
// Mail transport to use: "smtp", "sendmail" or "mail" (PHP mail function) // Mail transport to use: "smtp", "sendmail", "mail" (PHP mail function), "postmark"
define('MAIL_TRANSPORT', 'mail'); define('MAIL_TRANSPORT', 'mail');
// SMTP configuration to use when the "smtp" transport is chosen // SMTP configuration to use when the "smtp" transport is chosen
@@ -27,6 +27,9 @@ define('MAIL_SMTP_ENCRYPTION', null); // Valid values are "null", "ssl" or "tls"
// Sendmail command to use when the transport is "sendmail" // Sendmail command to use when the transport is "sendmail"
define('MAIL_SENDMAIL_COMMAND', '/usr/sbin/sendmail -bs'); define('MAIL_SENDMAIL_COMMAND', '/usr/sbin/sendmail -bs');
// Postmark API token (used to send emails through their API)
define('POSTMARK_API_TOKEN', '');
// Database driver: sqlite, mysql or postgres (sqlite by default) // Database driver: sqlite, mysql or postgres (sqlite by default)
define('DB_DRIVER', 'sqlite'); define('DB_DRIVER', 'sqlite');

View File

@@ -12,6 +12,16 @@ To receive email notifications, users of Kanboard must have:
Note: The logged user who performs the action doesn't receive any notifications, only other project members. Note: The logged user who performs the action doesn't receive any notifications, only other project members.
Email transports
----------------
There are several email transports available:
- SMTP
- Sendmail
- PHP native mail function
- Postmark
Server settings Server settings
--------------- ---------------
@@ -57,6 +67,34 @@ define('MAIL_TRANSPORT', 'sendmail');
define('MAIL_SENDMAIL_COMMAND', '/usr/sbin/sendmail -bs'); define('MAIL_SENDMAIL_COMMAND', '/usr/sbin/sendmail -bs');
``` ```
### PHP native mail function
This is the default configuration:
```php
define('MAIL_TRANSPORT', 'mail');
```
### Postmark HTTP API
Postmark is a third-party email service.
If you already use the Postmark integration to receive emails in Kanboard you can use the same provider to send email too.
This system use their HTTP API instead of the SMTP protocol.
Here are the required settings for this configuration:
```php
// We choose "postmark" as mail transport
define('MAIL_TRANSPORT', 'postmark');
// Copy and paste your Postmark API token
define('POSTMARK_API_TOKEN', 'COPY HERE YOUR POSTMARK API TOKEN');
// Be sure to use the Postmark configured sender email address
define('MAIL_FROM', 'sender-address-configured-in-postmark@example.org');
```
### The sender email address ### The sender email address
By default, emails will use the sender address `notifications@kanboard.local`. By default, emails will use the sender address `notifications@kanboard.local`.

View File

@@ -15,6 +15,7 @@ class FakeHttpClient
{ {
private $url = ''; private $url = '';
private $data = array(); private $data = array();
private $headers = array();
public function getUrl() public function getUrl()
{ {
@@ -26,16 +27,21 @@ class FakeHttpClient
return $this->data; return $this->data;
} }
public function getHeaders()
{
return $this->headers;
}
public function toPrettyJson() public function toPrettyJson()
{ {
return json_encode($this->data, JSON_PRETTY_PRINT); return json_encode($this->data, JSON_PRETTY_PRINT);
} }
public function post($url, array $data) public function post($url, array $data, array $headers = array())
{ {
$this->url = $url; $this->url = $url;
$this->data = $data; $this->data = $data;
//echo $this->toPrettyJson(); $this->headers = $headers;
return true; return true;
} }
} }

View File

@@ -2,18 +2,41 @@
require_once __DIR__.'/Base.php'; require_once __DIR__.'/Base.php';
use Integration\PostmarkWebhook; use Integration\Postmark;
use Model\TaskCreation; use Model\TaskCreation;
use Model\TaskFinder; use Model\TaskFinder;
use Model\Project; use Model\Project;
use Model\ProjectPermission; use Model\ProjectPermission;
use Model\User; use Model\User;
class PostmarkWebhookTest extends Base class PostmarkTest extends Base
{ {
public function testSendEmail()
{
$pm = new Postmark($this->container);
$pm->sendEmail('test@localhost', 'Me', 'Test', 'Content', 'Bob');
$this->assertEquals('https://api.postmarkapp.com/email', $this->container['httpClient']->getUrl());
$data = $this->container['httpClient']->getData();
$this->assertArrayHasKey('From', $data);
$this->assertArrayHasKey('To', $data);
$this->assertArrayHasKey('Subject', $data);
$this->assertArrayHasKey('HtmlBody', $data);
$this->assertEquals('Me <test@localhost>', $data['To']);
$this->assertEquals('Bob <notifications@kanboard.local>', $data['From']);
$this->assertEquals('Test', $data['Subject']);
$this->assertEquals('Content', $data['HtmlBody']);
$this->assertContains('Accept: application/json', $this->container['httpClient']->getHeaders());
$this->assertContains('X-Postmark-Server-Token: ', $this->container['httpClient']->getHeaders());
}
public function testHandlePayload() public function testHandlePayload()
{ {
$w = new PostmarkWebhook($this->container); $w = new Postmark($this->container);
$p = new Project($this->container); $p = new Project($this->container);
$pp = new ProjectPermission($this->container); $pp = new ProjectPermission($this->container);
$u = new User($this->container); $u = new User($this->container);
@@ -26,20 +49,20 @@ class PostmarkWebhookTest extends Base
$this->assertEquals(2, $p->create(array('name' => 'test2', 'identifier' => 'TEST1'))); $this->assertEquals(2, $p->create(array('name' => 'test2', 'identifier' => 'TEST1')));
// Empty payload // Empty payload
$this->assertFalse($w->parsePayload(array())); $this->assertFalse($w->receiveEmail(array()));
// Unknown user // Unknown user
$this->assertFalse($w->parsePayload(array('From' => 'a@b.c', 'Subject' => 'Email task', 'MailboxHash' => 'foobar', 'TextBody' => 'boo'))); $this->assertFalse($w->receiveEmail(array('From' => 'a@b.c', 'Subject' => 'Email task', 'MailboxHash' => 'foobar', 'TextBody' => 'boo')));
// Project not found // Project not found
$this->assertFalse($w->parsePayload(array('From' => 'me@localhost', 'Subject' => 'Email task', 'MailboxHash' => 'test', 'TextBody' => 'boo'))); $this->assertFalse($w->receiveEmail(array('From' => 'me@localhost', 'Subject' => 'Email task', 'MailboxHash' => 'test', 'TextBody' => 'boo')));
// User is not member // User is not member
$this->assertFalse($w->parsePayload(array('From' => 'me@localhost', 'Subject' => 'Email task', 'MailboxHash' => 'test1', 'TextBody' => 'boo'))); $this->assertFalse($w->receiveEmail(array('From' => 'me@localhost', 'Subject' => 'Email task', 'MailboxHash' => 'test1', 'TextBody' => 'boo')));
$this->assertTrue($pp->addMember(2, 2)); $this->assertTrue($pp->addMember(2, 2));
// The task must be created // The task must be created
$this->assertTrue($w->parsePayload(array('From' => 'me@localhost', 'Subject' => 'Email task', 'MailboxHash' => 'test1', 'TextBody' => 'boo'))); $this->assertTrue($w->receiveEmail(array('From' => 'me@localhost', 'Subject' => 'Email task', 'MailboxHash' => 'test1', 'TextBody' => 'boo')));
$task = $tf->getById(1); $task = $tf->getById(1);
$this->assertNotEmpty($task); $this->assertNotEmpty($task);
@@ -51,7 +74,7 @@ class PostmarkWebhookTest extends Base
public function testHtml2Markdown() public function testHtml2Markdown()
{ {
$w = new PostmarkWebhook($this->container); $w = new Postmark($this->container);
$p = new Project($this->container); $p = new Project($this->container);
$pp = new ProjectPermission($this->container); $pp = new ProjectPermission($this->container);
$u = new User($this->container); $u = new User($this->container);
@@ -62,7 +85,7 @@ class PostmarkWebhookTest extends Base
$this->assertEquals(1, $p->create(array('name' => 'test2', 'identifier' => 'TEST1'))); $this->assertEquals(1, $p->create(array('name' => 'test2', 'identifier' => 'TEST1')));
$this->assertTrue($pp->addMember(1, 2)); $this->assertTrue($pp->addMember(1, 2));
$this->assertTrue($w->parsePayload(array('From' => 'me@localhost', 'Subject' => 'Email task', 'MailboxHash' => 'test1', 'TextBody' => 'boo', 'HtmlBody' => '<p><strong>boo</strong></p>'))); $this->assertTrue($w->receiveEmail(array('From' => 'me@localhost', 'Subject' => 'Email task', 'MailboxHash' => 'test1', 'TextBody' => 'boo', 'HtmlBody' => '<p><strong>boo</strong></p>')));
$task = $tf->getById(1); $task = $tf->getById(1);
$this->assertNotEmpty($task); $this->assertNotEmpty($task);
@@ -71,7 +94,7 @@ class PostmarkWebhookTest extends Base
$this->assertEquals('**boo**', $task['description']); $this->assertEquals('**boo**', $task['description']);
$this->assertEquals(2, $task['creator_id']); $this->assertEquals(2, $task['creator_id']);
$this->assertTrue($w->parsePayload(array('From' => 'me@localhost', 'Subject' => 'Email task', 'MailboxHash' => 'test1', 'TextBody' => '**boo**', 'HtmlBody' => ''))); $this->assertTrue($w->receiveEmail(array('From' => 'me@localhost', 'Subject' => 'Email task', 'MailboxHash' => 'test1', 'TextBody' => '**boo**', 'HtmlBody' => '')));
$task = $tf->getById(2); $task = $tf->getById(2);
$this->assertNotEmpty($task); $this->assertNotEmpty($task);