diff --git a/.env.sample b/.env.sample index e6a9ef62c3..b4875fa091 100644 --- a/.env.sample +++ b/.env.sample @@ -1,5 +1,2 @@ -WP_TEST_URL="http://localhost" -WP_TEST_USER="admin" -WP_TEST_PASSWORD="password" WP_TEST_PATH="/var/www/wordpress" diff --git a/RoboFile.php b/RoboFile.php index 99fcfacb16..2e5be6dde9 100644 --- a/RoboFile.php +++ b/RoboFile.php @@ -94,17 +94,6 @@ class RoboFile extends \Robo\Tasks { $this->_exec('vendor/bin/codecept run unit '.(($file) ? $file : '')); } - function testAcceptance($file = null) { - $this->loadEnv(); - $this->_exec('vendor/bin/codecept build'); - $this - ->taskExec('phantomjs --webdriver=4444') - ->background() - ->run(); - sleep(2); - $this->_exec('vendor/bin/codecept run acceptance '.(($file) ? $file : '')); - } - function testJavascript() { $this->compileJs(); @@ -115,13 +104,6 @@ class RoboFile extends \Robo\Tasks { ))); } - function testAll() { - $this->loadEnv(); - $this->_exec('vendor/bin/codecept build'); - $this->startPhantomJS(); - $this->_exec('vendor/bin/codecept run'); - } - function testDebug() { $this->_exec('vendor/bin/codecept build'); $this->loadEnv(); @@ -138,24 +120,5 @@ class RoboFile extends \Robo\Tasks { protected function loadEnv() { $dotenv = new Dotenv\Dotenv(__DIR__); $dotenv->load(); - - $this - ->taskWriteToFile('tests/acceptance.suite.yml') - ->textFromFile('tests/acceptance.suite.src') - ->run(); - - $this - ->taskReplaceInFile('tests/acceptance.suite.yml') - ->regex("/url.*/") - ->to('url: ' . "'" . getenv('WP_TEST_URL'). "'") - ->run(); - } - - protected function startPhantomJS() { - $this - ->taskexec('phantomjs --webdriver=4444') - ->background() - ->run(); - sleep(3); } } diff --git a/assets/css/src/newsletter_editor/common.styl b/assets/css/src/newsletter_editor/common.styl index 18d5e3fd88..d4de966628 100644 --- a/assets/css/src/newsletter_editor/common.styl +++ b/assets/css/src/newsletter_editor/common.styl @@ -205,7 +205,7 @@ select.mailpoet_font-size border-bottom-left-radius: 0 .mailpoet_text_content p - margin: 0 + margin: 1em 0 .mailpoet_separator margin: 17px 20px diff --git a/assets/css/src/newsletter_editor/contentBlocks/automatedLatestContent.styl b/assets/css/src/newsletter_editor/contentBlocks/automatedLatestContent.styl index dba0beb38a..42b4dfc09f 100644 --- a/assets/css/src/newsletter_editor/contentBlocks/automatedLatestContent.styl +++ b/assets/css/src/newsletter_editor/contentBlocks/automatedLatestContent.styl @@ -6,7 +6,12 @@ z-index: 19 width: 100% height: 100% - background: rgba(255, 255, 255, 0.7) + background: rgba(255, 255, 255, 0) + transition: background .15s ease-out + + &:hover + background: rgba(255, 255, 255, 0.7) + cursor: pointer .mailpoet_automated_latest_content_block_posts overflow: auto diff --git a/assets/js/src/newsletter_editor/blocks/automatedLatestContent.js b/assets/js/src/newsletter_editor/blocks/automatedLatestContent.js index 12c6fdd9bc..f7907bb1bd 100644 --- a/assets/js/src/newsletter_editor/blocks/automatedLatestContent.js +++ b/assets/js/src/newsletter_editor/blocks/automatedLatestContent.js @@ -61,7 +61,7 @@ define([ }; }, initialize: function() { - base.BlockModel.prototype.initialize.apply(this); + base.BlockView.prototype.initialize.apply(this, arguments); this.fetchPosts(); this.on('change:amount change:contentType change:terms change:inclusionType change:displayType change:titleFormat change:titlePosition change:titleAlignment change:titleIsLink change:imagePadded change:showAuthor change:authorPrecededBy change:showCategories change:categoriesPrecededBy change:readMoreType change:readMoreText change:sortBy change:showDivider', this._scheduleFetchPosts, this); this.listenTo(this.get('readMoreButton'), 'change', this._scheduleFetchPosts); @@ -69,13 +69,12 @@ define([ }, fetchPosts: function() { var that = this; - // TODO: Migrate to new AJAX queries - //mailpoet_post_wpi('automated_latest_content.php', this.toJSON(), function(response) { - //console.log('ALC fetched', arguments); - //that.get('_container').get('blocks').reset(response, {parse: true}); - //}, function() { - //console.log('ALC fetchPosts error', arguments); - //}); + WordpressComponent.getTransformedPosts(this.toJSON()).done(function(content) { + console.log('ALC fetched', arguments); + that.get('_container').get('blocks').reset(content, {parse: true}); + }).fail(function(error) { + console.log('ALC fetchPosts error', arguments); + }); }, /** * Batch more changes during a specific time, instead of fetching @@ -101,6 +100,9 @@ define([ toolsRegion: '.mailpoet_tools', postsRegion: '.mailpoet_automated_latest_content_block_posts', }, + events: _.extend(base.BlockView.prototype.events, { + 'click .mailpoet_automated_latest_content_block_overlay': 'showSettings', + }), onDragSubstituteBy: function() { return Module.AutomatedLatestContentWidgetView; }, onRender: function() { var ContainerView = App.getBlockTypeView('container'), @@ -236,6 +238,7 @@ define([ }); }, onBeforeDestroy: function() { + base.BlockSettingsView.prototype.onBeforeDestroy.apply(this, arguments); // Force close select2 if it hasn't closed yet this.$('.mailpoet_automated_latest_content_categories_and_tags').select2('close'); }, @@ -336,7 +339,10 @@ define([ cloneOriginal: true, drop: function() { return new Module.AutomatedLatestContentBlockModel({}, { parse: true }); - } + }, + onDrop: function(options) { + options.droppedView.triggerMethod('showSettings'); + }, } }, }); diff --git a/assets/js/src/newsletter_editor/blocks/base.js b/assets/js/src/newsletter_editor/blocks/base.js index b313bae42f..3927c6c973 100644 --- a/assets/js/src/newsletter_editor/blocks/base.js +++ b/assets/js/src/newsletter_editor/blocks/base.js @@ -87,6 +87,9 @@ define([ AugmentedView.apply(this, arguments); this.$el.addClass('mailpoet_editor_view_' + this.cid); }, + initialize: function() { + this.on('showSettings', this.showSettings); + }, showTools: function(_event) { if (!this.showingToolsDisabled) { this.$('> .mailpoet_tools').show(); @@ -104,6 +107,9 @@ define([ this.showingToolsDisabled = true; this.hideTools(); }, + showSettings: function(options) { + this.toolsView.triggerMethod('showSettings', options); + }, /** * Defines drop behavior of BlockView instance */ @@ -141,6 +147,7 @@ define([ // Automatically cancel deletion this.on('hideTools', this.hideDeletionConfirmation, this); + this.on('showSettings', this.changeSettings); }, templateHelpers: function() { return { @@ -149,9 +156,9 @@ define([ tools: this.tools, }; }, - changeSettings: function() { + changeSettings: function(options) { var ViewType = this.getSettingsView(); - (new ViewType({ model: this.model })).render(); + (new ViewType(_.extend({ model: this.model }, options || {}))).render(); }, showDeletionConfirmation: function() { this.$('.mailpoet_delete_block').addClass('mailpoet_delete_block_activated'); @@ -182,7 +189,6 @@ define([ }); }, close: function(event) { - MailPoet.Modal.cancel(); this.destroy(); }, changeField: function(field, event) { @@ -204,6 +210,9 @@ define([ } this.model.set(field, value); }, + onBeforeDestroy: function() { + MailPoet.Modal.close(); + }, }); Module.WidgetView = Marionette.ItemView.extend({ diff --git a/assets/js/src/newsletter_editor/blocks/image.js b/assets/js/src/newsletter_editor/blocks/image.js index dbb127bf12..22b3ffadd1 100644 --- a/assets/js/src/newsletter_editor/blocks/image.js +++ b/assets/js/src/newsletter_editor/blocks/image.js @@ -35,9 +35,6 @@ define([ Module.ImageBlockView = base.BlockView.extend({ className: "mailpoet_block mailpoet_image_block mailpoet_droppable_block", getTemplate: function() { return templates.imageBlock; }, - initialize: function() { - this.on('showSettings', this.showSettings); - }, onDragSubstituteBy: function() { return Module.ImageWidgetView; }, templateHelpers: function() { return { @@ -56,29 +53,10 @@ define([ this.$el.addClass('mailpoet_full_image'); } }, - showSettings: function(options) { - this.toolsView.triggerMethod('showSettings', options); - }, - onBeforeDestroy: function() { - this.off('showSettings'); - }, }); Module.ImageBlockToolsView = base.BlockToolsView.extend({ getSettingsView: function() { return Module.ImageBlockSettingsView; }, - initialize: function() { - base.BlockToolsView.prototype.initialize.apply(this, arguments); - this.on('showSettings', this.changeSettings); - }, - changeSettings: function(options) { - (new Module.ImageBlockSettingsView({ - model: this.model, - showImageManager: (options.showImageManager === true), - })).render(); - }, - onBeforeDestroy: function() { - this.off('showSettings'); - }, }); Module.ImageBlockSettingsView = base.BlockSettingsView.extend({ @@ -349,6 +327,7 @@ define([ this._mediaManager.open(); }, onBeforeDestroy: function() { + base.BlockSettingsView.prototype.onBeforeDestroy.apply(this, arguments); if (typeof this._mediaManager === 'object') { this._mediaManager.remove(); } diff --git a/assets/js/src/newsletter_editor/blocks/posts.js b/assets/js/src/newsletter_editor/blocks/posts.js index fb86e65ed1..d2d4276bb8 100644 --- a/assets/js/src/newsletter_editor/blocks/posts.js +++ b/assets/js/src/newsletter_editor/blocks/posts.js @@ -132,8 +132,8 @@ define([ modelEvents: {}, onDragSubstituteBy: function() { return Module.PostsWidgetView; }, initialize: function() { + base.BlockView.prototype.initialize.apply(this, arguments); this.toolsView = new Module.PostsBlockToolsView({ model: this.model }); - this.on('showSettings', this.showSettings); this.model.reply('blockView', this.notifyAboutSelf, this); }, onRender: function() { @@ -142,9 +142,6 @@ define([ } this.trigger('showSettings'); }, - showSettings: function(options) { - this.toolsView.triggerMethod('showSettings', options); - }, notifyAboutSelf: function() { return this; }, @@ -155,19 +152,6 @@ define([ Module.PostsBlockToolsView = base.BlockToolsView.extend({ getSettingsView: function() { return Module.PostsBlockSettingsView; }, - initialize: function() { - base.BlockToolsView.prototype.initialize.apply(this, arguments); - this.on('showSettings', this.changeSettings); - this.settingsView = new Module.PostsBlockSettingsView({ model: this.model }); - }, - changeSettings: function() { - this.settingsView.render(); - }, - onBeforeDestroy: function() { - this.settingsView.destroy(); - this.off('showSettings'); - MailPoet.Modal.close(); - }, }); Module.PostsBlockSettingsView = base.BlockSettingsView.extend({ @@ -320,6 +304,7 @@ define([ }); }, onBeforeDestroy: function() { + base.BlockSettingsView.prototype.onBeforeDestroy.apply(this, arguments); // Force close select2 if it hasn't closed yet this.$('.mailpoet_posts_categories_and_tags').select2('close'); }, diff --git a/assets/js/src/segments/form.jsx b/assets/js/src/segments/form.jsx index 06e2938a19..8629711f2a 100644 --- a/assets/js/src/segments/form.jsx +++ b/assets/js/src/segments/form.jsx @@ -22,10 +22,10 @@ define( var messages = { updated: function() { - MailPoet.Notice.success('Segment succesfully updated!'); + MailPoet.Notice.success('Segment successfully updated!'); }, created: function() { - MailPoet.Notice.success('Segment succesfully added!'); + MailPoet.Notice.success('Segment successfully added!'); } }; @@ -51,4 +51,4 @@ define( return SegmentForm; } -); \ No newline at end of file +); diff --git a/assets/js/src/subscribers/form.jsx b/assets/js/src/subscribers/form.jsx index 2db90ca0fd..8a821c194c 100644 --- a/assets/js/src/subscribers/form.jsx +++ b/assets/js/src/subscribers/form.jsx @@ -42,10 +42,10 @@ define( var messages = { updated: function() { - MailPoet.Notice.success('Subscriber succesfully updated!'); + MailPoet.Notice.success('Subscriber successfully updated!'); }, created: function() { - MailPoet.Notice.success('Subscriber succesfully added!'); + MailPoet.Notice.success('Subscriber successfully added!'); } }; @@ -71,4 +71,4 @@ define( return SubscriberForm; } -); \ No newline at end of file +); diff --git a/build b/build index 04510009c8..25a7fe5732 100755 --- a/build +++ b/build @@ -16,7 +16,7 @@ rm composer.lock; # Copy release folders. cp -rf lang wysija-newsletters; -cp -rf assets wysija-newsletters; +cp -rfL assets wysija-newsletters; cp -rf lib wysija-newsletters; cp -rf vendor wysija-newsletters; cp -rf views wysija-newsletters; diff --git a/composer.json b/composer.json index bebbb79678..7091ac4db1 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,8 @@ "cerdic/css-tidy": "*", "sunra/php-simple-html-dom-parser": "*", "tburry/pquery": "*", - "j4mie/paris": "1.5.4" + "j4mie/paris": "1.5.4", + "swiftmailer/swiftmailer": "^5.4" }, "require-dev": { "codeception/codeception": "*", diff --git a/composer.lock b/composer.lock index 79d2549055..e05f3c21c0 100644 --- a/composer.lock +++ b/composer.lock @@ -261,6 +261,59 @@ ], "time": "2013-05-04 14:32:03" }, + { + "name": "swiftmailer/swiftmailer", + "version": "v5.4.1", + "source": { + "type": "git", + "url": "https://github.com/swiftmailer/swiftmailer.git", + "reference": "0697e6aa65c83edf97bb0f23d8763f94e3f11421" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/0697e6aa65c83edf97bb0f23d8763f94e3f11421", + "reference": "0697e6aa65c83edf97bb0f23d8763f94e3f11421", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "mockery/mockery": "~0.9.1,<0.9.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.4-dev" + } + }, + "autoload": { + "files": [ + "lib/swift_required.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Corbyn" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Swiftmailer, free feature-rich PHP mailer", + "homepage": "http://swiftmailer.org", + "keywords": [ + "email", + "mail", + "mailer" + ], + "time": "2015-06-06 14:19:39" + }, { "name": "tburry/pquery", "version": "v1.1.0", diff --git a/lib/Config/Initializer.php b/lib/Config/Initializer.php index 30c7aea82c..1b31f5772d 100644 --- a/lib/Config/Initializer.php +++ b/lib/Config/Initializer.php @@ -8,7 +8,7 @@ if(!defined('ABSPATH')) exit; class Initializer { function __construct($params = array( - 'file' => '', + 'file' => '', 'version' => '1.0.0' )) { Env::init($params['file'], $params['version']); @@ -41,6 +41,8 @@ class Initializer { $segments = Env::$db_prefix . 'segments'; $subscriber_segment = Env::$db_prefix . 'subscriber_segment'; $newsletter_segment = Env::$db_prefix . 'newsletter_segment'; + $custom_fields = Env::$db_prefix . 'custom_fields'; + $subscriber_custom_field = Env::$db_prefix . 'subscriber_custom_field'; define('MP_SUBSCRIBERS_TABLE', $subscribers); define('MP_SETTINGS_TABLE', $settings); @@ -49,6 +51,8 @@ class Initializer { define('MP_SUBSCRIBER_SEGMENT_TABLE', $subscriber_segment); define('MP_NEWSLETTER_TEMPLATES_TABLE', $newsletter_templates); define('MP_NEWSLETTER_SEGMENT_TABLE', $newsletter_segment); + define('MP_CUSTOM_FIELDS_TABLE', $custom_fields); + define('MP_SUBSCRIBER_CUSTOM_FIELD_TABLE', $subscriber_custom_field); } function setupActivator() { @@ -88,4 +92,4 @@ class Initializer { $permissions = new Permissions(); $permissions->init(); } -} +} \ No newline at end of file diff --git a/lib/Config/Migrator.php b/lib/Config/Migrator.php index 8609d22896..3f21585a9f 100644 --- a/lib/Config/Migrator.php +++ b/lib/Config/Migrator.php @@ -16,7 +16,9 @@ class Migrator { 'newsletter_templates', 'segments', 'subscriber_segment', - 'newsletter_segment' + 'newsletter_segment', + 'custom_fields', + 'subscriber_custom_field' ); } @@ -133,6 +135,31 @@ class Migrator { return $this->sqlify(__FUNCTION__, $attributes); } + function custom_fields() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'name varchar(90) NOT NULL,', + 'created_at TIMESTAMP NOT NULL DEFAULT 0,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'PRIMARY KEY (id),', + 'UNIQUE KEY name (name)' + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function subscriber_custom_field() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'subscriber_id mediumint(9) NOT NULL,', + 'custom_field_id mediumint(9) NOT NULL,', + 'value varchar(255) NOT NULL,', + 'created_at TIMESTAMP NOT NULL DEFAULT 0,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'PRIMARY KEY (id)' + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + private function sqlify($model, $attributes) { $table = $this->prefix . $model; diff --git a/lib/Mailer/API/AmazonSES.php b/lib/Mailer/API/AmazonSES.php new file mode 100644 index 0000000000..b753f2a316 --- /dev/null +++ b/lib/Mailer/API/AmazonSES.php @@ -0,0 +1,108 @@ +awsAccessKey = $accessKey; + $this->awsSecret_key = $secretKey; + $this->awsRegion = $region; + $this->awsEndpoint = sprintf('email.%s.amazonaws.com', $region); + $this->awsSigningAlgorithm = 'AWS4-HMAC-SHA256'; + $this->awsService = 'ses'; + $this->awsTerminationString = 'aws4_request'; + $this->hashAlgorithm = 'sha256'; + $this->url = 'https://' . $this->awsEndpoint; + $this->from = $from; + $this->date = gmdate('Ymd\THis\Z'); + $this->dateWithoutTime = gmdate('Ymd'); + } + + function send($newsletter, $subscriber) { + $result = wp_remote_post( + $this->url, + $this->request($newsletter, $subscriber) + ); + return ( + !is_wp_error($result) === true && + wp_remote_retrieve_response_code($result) === 200 + ); + } + + function getBody($newsletter, $subscriber) { + return array( + 'Action' => 'SendEmail', + 'Version' => '2010-12-01', + 'Source' => $this->from, + 'Destination.ToAddresses.member.1' => $subscriber, + 'Message.Subject.Data' => $newsletter['subject'], + 'Message.Body.Html.Data' => $newsletter['body']['html'], + 'Message.Body.Text.Data' => $newsletter['body']['text'], + 'ReturnPath' => $this->from + ); + } + + function request($newsletter, $subscriber) { + $body = $this->getBody($newsletter, $subscriber); + return array( + 'timeout' => 10, + 'httpversion' => '1.1', + 'method' => 'POST', + 'headers' => array( + 'Host' => $this->awsEndpoint, + 'Authorization' => $this->signRequest($body), + 'X-Amz-Date' => $this->date + ), + 'body' => urldecode(http_build_query($body)) + ); + } + + function signRequest($body) { + $stringToSign = $this->createStringToSign( + $this->getCredentialScope(), + $this->getCanonicalRequest($body) + ); + $signature = hash_hmac($this->hashAlgorithm, $stringToSign, $this->getSigningKey()); + + return sprintf( + '%s Credential=%s/%s, SignedHeaders=host;x-amz-date, Signature=%s', + $this->awsSigningAlgorithm, + $this->awsAccessKey, + $this->getCredentialScope(), + $signature); + } + + function getCredentialScope() { + return sprintf('%s/%s/%s/%s', $this->dateWithoutTime, $this->awsRegion, $this->awsService, $this->awsTerminationString); + } + + function getCanonicalRequest($body) { + return implode("\n", array( + 'POST', + '/', + '', + 'host:' . $this->awsEndpoint, + 'x-amz-date:' . $this->date, + '', + 'host;x-amz-date', + hash($this->hashAlgorithm, urldecode(http_build_query($body))) + )); + } + + function createStringToSign($credentialScope, $canonicalRequest) { + return implode("\n", array( + $this->awsSigningAlgorithm, + $this->date, + $credentialScope, + hash($this->hashAlgorithm, $canonicalRequest) + )); + } + + function getSigningKey() { + $dateKey = hash_hmac($this->hashAlgorithm, $this->dateWithoutTime, 'AWS4' . $this->awsSecret_key, true); + $regionKey = hash_hmac($this->hashAlgorithm, $this->awsRegion, $dateKey, true); + $serviceKey = hash_hmac($this->hashAlgorithm, $this->awsService, $regionKey, true); + return hash_hmac($this->hashAlgorithm, $this->awsTerminationString, $serviceKey, true); + } +} \ No newline at end of file diff --git a/lib/Mailer/API/ElasticEmail.php b/lib/Mailer/API/ElasticEmail.php new file mode 100644 index 0000000000..f00849d268 --- /dev/null +++ b/lib/Mailer/API/ElasticEmail.php @@ -0,0 +1,45 @@ +url = 'https://api.elasticemail.com/mailer/send'; + $this->apiKey = $apiKey; + $this->fromEmail = $fromEmail; + $this->fromName = $fromName; + } + + function send($newsletter, $subscriber) { + $result = wp_remote_post( + $this->url, + $this->request($newsletter, $subscriber)); + return ( + !is_wp_error($result) === true && + !preg_match('/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/', $result['body']) === false + ); + } + + function getBody($newsletter, $subscriber) { + return array( + 'api_key' => $this->apiKey, + 'from' => $this->fromEmail, + 'from_name' => $this->fromName, + 'to' => $subscriber, + 'subject' => $newsletter['subject'], + 'body_html' => $newsletter['body']['html'], + 'body_text' => $newsletter['body']['text'] + ); + } + + function request($newsletter, $subscriber) { + $body = $this->getBody($newsletter, $subscriber); + return array( + 'timeout' => 10, + 'httpversion' => '1.0', + 'method' => 'POST', + 'body' => urldecode(http_build_query($body)) + ); + } +} \ No newline at end of file diff --git a/lib/Mailer/API/MailGun.php b/lib/Mailer/API/MailGun.php new file mode 100644 index 0000000000..d8aee6783a --- /dev/null +++ b/lib/Mailer/API/MailGun.php @@ -0,0 +1,51 @@ +url = sprintf('https://api.mailgun.net/v3/%s/messages', $domain); + $this->apiKey = $apiKey; + $this->from = $from; + } + + function send($newsletter, $subscriber) { + $result = wp_remote_post( + $this->url, + $this->request($newsletter, $subscriber) + ); + return ( + !is_wp_error($result) === true && + wp_remote_retrieve_response_code($result) === 200 + ); + } + + function getBody($newsletter, $subscriber) { + return array( + 'from' => $this->from, + 'to' => $subscriber, + 'subject' => $newsletter['subject'], + 'html' => $newsletter['body']['html'], + 'text' => $newsletter['body']['text'] + ); + } + + function auth() { + return 'Basic ' . base64_encode('api:' . $this->apiKey); + } + + function request($newsletter, $subscriber) { + $body = $this->getBody($newsletter, $subscriber); + return array( + 'timeout' => 10, + 'httpversion' => '1.0', + 'method' => 'POST', + 'headers' => array( + 'Content-Type' => 'application/x-www-form-urlencoded', + 'Authorization' => $this->auth() + ), + 'body' => urldecode(http_build_query($body)) + ); + } +} \ No newline at end of file diff --git a/lib/Mailer/API/Mandrill.php b/lib/Mailer/API/Mandrill.php new file mode 100644 index 0000000000..0a30cea304 --- /dev/null +++ b/lib/Mailer/API/Mandrill.php @@ -0,0 +1,66 @@ +url = 'https://mandrillapp.com/api/1.0/messages/send.json'; + $this->apiKey = $apiKey; + $this->fromName = $fromName; + $this->fromEmail = $fromEmail; + } + + function send($newsletter, $subscriber) { + $result = wp_remote_post( + $this->url, + $this->request($newsletter, $this->processSubscriber($subscriber)) + ); + return ( + !is_wp_error($result) === true && + !preg_match('!invalid!', $result['body']) === true && + wp_remote_retrieve_response_code($result) === 200 + ); + } + + function processSubscriber($subscriber) { + preg_match('!(?P.*?)\s<(?P.*?)>!', $subscriber, $subscriberData); + if(!isset($subscriberData['email'])) { + $subscriberData = array( + 'email' => $subscriber, + ); + } + return array( + 'email' => $subscriberData['email'], + 'name' => (isset($subscriberData['name'])) ? $subscriberData['name'] : '' + ); + } + + function getBody($newsletter, $subscriber) { + return array( + 'key' => $this->apiKey, + 'message' => array( + 'from_email' => $this->fromEmail, + 'from_name' => $this->fromName, + 'to' => array($subscriber), + 'subject' => $newsletter['subject'], + 'html' => $newsletter['body']['html'], + 'text' => $newsletter['body']['text'] + ), + 'async' => false, + ); + } + + function request($newsletter, $subscriber) { + $body = $this->getBody($newsletter, $subscriber); + return array( + 'timeout' => 10, + 'httpversion' => '1.0', + 'method' => 'POST', + 'headers' => array( + 'Content-Type' => 'application/json' + ), + 'body' => json_encode($body) + ); + } +} \ No newline at end of file diff --git a/lib/Mailer/API/SendGrid.php b/lib/Mailer/API/SendGrid.php new file mode 100644 index 0000000000..88adf6071c --- /dev/null +++ b/lib/Mailer/API/SendGrid.php @@ -0,0 +1,54 @@ +url = 'https://api.sendgrid.com/api/mail.send.json'; + $this->apiKey = $apiKey; + $this->fromEmail = $fromEmail; + $this->fromName = $fromName; + } + + function send($newsletter, $subscriber) { + $result = wp_remote_post( + $this->url, + $this->request($newsletter, $subscriber) + ); + return ( + !is_wp_error($result) === true && + !preg_match('!invalid!', $result['body']) === true && + !isset(json_decode($result['body'], true)['errors']) === true && + wp_remote_retrieve_response_code($result) === 200 + ); + } + + function getBody($newsletter, $subscriber) { + return array( + 'to' => $subscriber, + 'from' => $this->fromEmail, + 'fromname' => $this->fromName, + 'subject' => $newsletter['subject'], + 'html' => $newsletter['body']['html'], + 'text' => $newsletter['body']['text'] + ); + } + + function auth() { + return 'Bearer ' . $this->apiKey; + } + + function request($newsletter, $subscriber) { + $body = $this->getBody($newsletter, $subscriber); + return array( + 'timeout' => 10, + 'httpversion' => '1.1', + 'method' => 'POST', + 'headers' => array( + 'Authorization' => $this->auth() + ), + 'body' => urldecode(http_build_query($body)) + ); + } +} \ No newline at end of file diff --git a/lib/Mailer/Bridge.php b/lib/Mailer/Bridge.php deleted file mode 100644 index c86f602f4a..0000000000 --- a/lib/Mailer/Bridge.php +++ /dev/null @@ -1,111 +0,0 @@ -newsletter = $newsletter; - $this->subscribers = $subscribers; - - $this->from_address = ( - isset($this->newsletter['from_address']) - ) - ? $this->newsletter['from_address'] - : Setting::getValue('from_address'); - - $this->from_name = ( - isset($this->newsletter['from_name']) - ) - ? $this->newsletter['from_name'] - : Setting::getValue('from_name', ''); - - $this->reply_to_address = ( - isset($this->newsletter['reply_to_address']) - ) - ? $this->newsletter['reply_to_address'] - : Setting::getValue('reply_to_address'); - - $this->reply_to_name = ( - isset($this->newsletter['reply_to_name']) - ) - ? $this->newsletter['reply_to_name'] - : Setting::getValue('reply_to_name', ''); - - $this->api_key = Setting::where('name', 'api_key')->findOne()->value; - } - - function messages() { - $messages = array_map( - array($this, 'generateMessage'), - $this->subscribers - ); - return $messages; - } - - function generateMessage($subscriber) { - $message = array( - 'subject' => $this->newsletter['subject'], - 'to' => array( - 'address' => $subscriber['email'], - 'name' => $subscriber['first_name'].' '.$subscriber['last_name'] - ), - 'from' => array( - 'address' => $this->from_address, - 'name' => $this->from_name - ), - 'text' => "", - 'html' => $this->newsletter['body'] - ); - - if($this->reply_to_address !== null) { - $message['reply_to'] = array( - 'address' => $this->reply_to_address, - 'name' => $this->reply_to_name - ); - } - return $message; - } - - function auth() { - $auth = 'Basic ' - . base64_encode('api:' . $this->api_key); - return $auth; - } - - function request() { - $request = array( - 'timeout' => 10, - 'httpversion' => '1.0', - 'method' => 'POST', - 'headers' => array( - 'Authorization' => $this->auth(), - 'Content-Type' => 'application/json' - ), - 'body' => json_encode($this->messages()) - ); - return $request; - } - - function send() { - $result = wp_remote_post( - 'https://bridge.mailpoet.com/api/messages', - $this->request() - ); - - $success = - (wp_remote_retrieve_response_code($result) === 201); - - return $success; - } -} diff --git a/lib/Mailer/MailPoet.php b/lib/Mailer/MailPoet.php new file mode 100644 index 0000000000..e7651a397c --- /dev/null +++ b/lib/Mailer/MailPoet.php @@ -0,0 +1,71 @@ +url = 'https://bridge.mailpoet.com/api/messages'; + $this->apiKey = $apiKey; + $this->fromEmail = $fromEmail; + $this->fromName = $fromName; + } + + function send($newsletter, $subscriber) { + $result = wp_remote_post( + $this->url, + $this->request($newsletter, $this->processSubscriber($subscriber)) + ); + return ( + !is_wp_error($result) === true && + wp_remote_retrieve_response_code($result) === 201 + ); + } + + function processSubscriber($subscriber) { + preg_match('!(?P.*?)\s<(?P.*?)>!', $subscriber, $subscriberData); + if(!isset($subscriberData['email'])) { + $subscriberData = array( + 'email' => $subscriber, + ); + } + return array( + 'email' => $subscriberData['email'], + 'name' => (isset($subscriberData['name'])) ? $subscriberData['name'] : '' + ); + } + + function getBody($newsletter, $subscriber) { + return array( + 'to' => (array( + 'address' => $subscriber['email'], + 'name' => $subscriber['name'] + )), + 'from' => (array( + 'address' => $this->fromEmail, + 'name' => $this->fromName + )), + 'subject' => $newsletter['subject'], + 'html' => $newsletter['body']['html'], + 'text' => $newsletter['body']['text'] + ); + } + + function auth() { + return 'Basic ' . base64_encode('api:' . $this->apiKey); + } + + function request($newsletter, $subscriber) { + $body = array($this->getBody($newsletter, $subscriber)); + return array( + 'timeout' => 10, + 'httpversion' => '1.0', + 'method' => 'POST', + 'headers' => array( + 'Content-Type' => 'application/json', + 'Authorization' => $this->auth() + ), + 'body' => json_encode($body) + ); + } +} \ No newline at end of file diff --git a/lib/Mailer/SMTP.php b/lib/Mailer/SMTP.php new file mode 100644 index 0000000000..08a80501f7 --- /dev/null +++ b/lib/Mailer/SMTP.php @@ -0,0 +1,62 @@ +host = $host; + $this->port = $port; + $this->authentication = $authentication; + $this->encryption = $encryption; + $this->fromName = $fromName; + $this->fromEmail = $fromEmail; + $this->mailer = $this->buildMailer(); + } + + function send($newsletter, $subscriber) { + try { + $message = $this->createMessage($newsletter, $subscriber); + $result = $this->mailer->send($message); + } catch (\Exception $e) { + $result = false; + } + return ($result === 1); + } + + function buildMailer() { + $transport = \Swift_SmtpTransport::newInstance( + $this->host, $this->port, $this->encryption); + $transport->setTimeout(10); + if($this->authentication) { + $transport + ->setUsername($this->authentication['login']) + ->setPassword($this->authentication['password']); + } + return \Swift_Mailer::newInstance($transport); + } + + + function createMessage($newsletter, $subscriber) { + return \Swift_Message::newInstance() + ->setFrom(array($this->fromEmail => $this->fromName)) + ->setTo($this->processSubscriber($subscriber)) + ->setSubject($newsletter['subject']) + ->setBody($newsletter['body']['html'], 'text/html') + ->addPart($newsletter['body']['text'], 'text/plain'); + } + + function processSubscriber($subscriber) { + preg_match('!(?P.*?)\s<(?P.*?)>!', $subscriber, $subscriberData); + if(!isset($subscriberData['email'])) { + $subscriberData = array( + 'email' => $subscriber, + ); + } + return array( + $subscriberData['email'] => + (isset($subscriberData['name'])) ? $subscriberData['name'] : '', + ); + } +} \ No newline at end of file diff --git a/lib/Mailer/WPMail.php b/lib/Mailer/WPMail.php new file mode 100644 index 0000000000..a90a297775 --- /dev/null +++ b/lib/Mailer/WPMail.php @@ -0,0 +1,58 @@ +fromEmail = $fromEmail; + $this->fromName = $fromName; + add_filter('wp_mail_from', array( + $this, + 'setFromEmail' + )); + $this->filters = array( + 'wp_mail_from' => 'setFromEmail', + 'wp_mail_from_name' => 'setFromName', + 'wp_mail_content_type' => 'setContentType' + ); + } + + function addFilters() { + foreach ($this->filters as $filter => $method) { + add_filter($filter, array( + $this, + $method + )); + } + } + + function removeFilters() { + foreach ($this->filters as $filter => $method) { + remove_filter($filter, array( + $this, + $method + )); + } + } + + function setFromEmail() { + return $this->fromEmail; + } + + function setFromName() { + return $this->fromName; + } + + function setContentType() { + return 'text/html'; + } + + function send($newsletter, $subscriber) { + $this->addFilters(); + $result = wp_mail($subscriber, $newsletter['subject'], $newsletter['body']['html']); + $this->removeFilters(); + return ($result === true); + } +} \ No newline at end of file diff --git a/lib/Models/CustomField.php b/lib/Models/CustomField.php new file mode 100644 index 0000000000..ca98d821d1 --- /dev/null +++ b/lib/Models/CustomField.php @@ -0,0 +1,25 @@ +addValidations('name', array( + 'required' => __('You need to specify a name.') + )); + } + + function subscribers() { + return $this->has_many_through( + __NAMESPACE__ . '\Subscriber', + __NAMESPACE__ . '\SubscriberCustomField', + 'custom_field_id', + 'subscriber_id' + ); + } +} \ No newline at end of file diff --git a/lib/Models/Subscriber.php b/lib/Models/Subscriber.php index 7275f472b8..7e96cc6bcb 100644 --- a/lib/Models/Subscriber.php +++ b/lib/Models/Subscriber.php @@ -132,6 +132,15 @@ class Subscriber extends Model { ); } + function customFields() { + return $this->has_many_through( + __NAMESPACE__.'\CustomField', + __NAMESPACE__.'\SubscriberCustomField', + 'subscriber_id', + 'custom_field_id' + )->select_expr(MP_SUBSCRIBER_CUSTOM_FIELD_TABLE.'.value'); + } + static function createOrUpdate($data = array()) { $subscriber = false; diff --git a/lib/Models/SubscriberCustomField.php b/lib/Models/SubscriberCustomField.php new file mode 100644 index 0000000000..e12dddc2bd --- /dev/null +++ b/lib/Models/SubscriberCustomField.php @@ -0,0 +1,12 @@ +fromName = $this->getSetting('from_name'); + $this->fromEmail = $this->getSetting('from_address'); + $this->mailer = $this->getSetting('mailer'); + $this->from = sprintf('%s <%s>', $this->fromName, $this->fromEmail); + } + + function send($newsletter, $subscriber) { + $subscriber = $this->transformSubscriber($subscriber); + $mailer = $this->buildMailer(); + return wp_send_json($mailer->send($newsletter, $subscriber)); + } + + function buildMailer() { + switch ($this->mailer['name']) { + case 'AmazonSES': + $mailer = new $this->mailer['class']( + $this->mailer['region'], + $this->mailer['access_key'], + $this->mailer['secret_key'], + $this->from + ); + break; + case 'ElasticEmail': + $mailer = new $this->mailer['class']( + $this->mailer['api_key'], + $this->fromEmail, $this->fromName + ); + break; + case 'MailGun': + $mailer = new $this->mailer['class']( + $this->mailer['domain'], + $this->mailer['api_key'], + $this->from + ); + break; + case 'MailPoet': + $mailer = new $this->mailer['class']( + $this->mailer['api_key'], + $this->fromEmail, + $this->fromName + ); + break; + case 'Mandrill': + $mailer = new $this->mailer['class']( + $this->mailer['api_key'], + $this->fromEmail, $this->fromName + ); + break; + case 'SendGrid': + $mailer = new $this->mailer['class']( + $this->mailer['api_key'], + $this->fromEmail, + $this->fromName + ); + break; + case 'SMTP': + $mailer = new $this->mailer['class']( + $this->mailer['host'], + $this->mailer['port'], + $this->mailer['authentication'], + $this->mailer['encryption'], + $this->fromEmail, + $this->fromName); + break; + } + return $mailer; + } + + function transformSubscriber($subscriber) { + if(!is_array($subscriber)) return $subscriber; + $first_name = (isset($subscriber['first_name'])) ? $subscriber['first_name'] : ''; + $last_name = (isset($subscriber['last_name'])) ? $subscriber['last_name'] : ''; + if(!$first_name && !$last_name) return $subscriber['email']; + $subscriber = sprintf('%s %s <%s>', $first_name, $last_name, $subscriber['email']); + $subscriber = trim(preg_replace('!\s\s+!', ' ', $subscriber)); + return $subscriber; + } + + function getSetting($setting) { + if($setting === 'mailer') { + $mailers = array( + array( + 'name' => 'AmazonSES', + 'type' => 'API', + 'access_key' => 'AKIAJM6Y5HMGXBLDNSRA', + 'secret_key' => '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', + 'region' => 'us-east-1' + ), + array( + 'name' => 'ElasticEmail', + 'type' => 'API', + 'api_key' => '997f1f7f-41de-4d7f-a8cb-86c8481370fa' + ), + array( + 'name' => 'MailGun', + 'type' => 'API', + 'api_key' => 'key-6cf5g5qjzenk-7nodj44gdt8phe6vam2', + 'domain' => 'mrcasual.com' + ), + array( + 'name' => 'MailPoet', + 'api_key' => 'dhNSqj1XHkVltIliyQDvMiKzQShOA5rs0m_DdRUVZHU' + ), + array( + 'name' => 'Mandrill', + 'type' => 'API', + 'api_key' => '692ys1B7REEoZN7R-dYwNA' + ), + array( + 'name' => 'SendGrid', + 'type' => 'API', + 'api_key' => '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' + ), + array( + 'name' => 'SMTP', + 'host' => 'email-smtp.us-west-2.amazonaws.com', + 'port' => 587, + 'authentication' => array( + 'login' => 'AKIAIGPBLH6JWG5VCBQQ', + 'password' => 'AudVHXHaYkvr54veCzqiqOxDiMMyfQW3/V6F1tYzGXY3' + ), + 'encryption' => 'tls' + ), + array( + 'name' => 'WPMail' + ) + ); + $mailer = $mailers[array_rand($mailers)]; + $mailer['class'] = 'MailPoet\\Mailer\\' . + ((isset($mailer['type'])) ? + $mailer['type'] . '\\' . $mailer['name'] : + $mailer['name'] + ); + return $mailer; + } + if($setting === 'from_name') return 'Sender'; + if($setting === 'from_address') return 'staff@mailpoet.com'; + return Setting::where('name', $setting) + ->findOne()->value; + } +} \ No newline at end of file diff --git a/lib/Router/Newsletters.php b/lib/Router/Newsletters.php index d8ae5b4fc3..a6bb3cf07e 100644 --- a/lib/Router/Newsletters.php +++ b/lib/Router/Newsletters.php @@ -2,9 +2,10 @@ namespace MailPoet\Router; use MailPoet\Listing; -use MailPoet\Mailer\Bridge; +use MailPoet\Mailer\API\MailPoet; use MailPoet\Models\Newsletter; use MailPoet\Models\Segment; +use MailPoet\Models\Setting; use MailPoet\Models\Subscriber; use MailPoet\Models\NewsletterTemplate; use MailPoet\Models\NewsletterSegment; @@ -103,10 +104,24 @@ class Newsletters { // END - TO REMOVE $renderer = new Renderer(json_decode($newsletter['body'], true)); - $newsletter['body'] = $renderer->renderAll(); + $newsletter['body']['html'] = $renderer->renderAll(); + $newsletter['body']['text'] = ''; - $mailer = new Bridge($newsletter, array_values($subscribers)); - wp_send_json($mailer->send()); + $subscribers = Subscriber::find_array(); + $fromEmail = Setting::where('name', 'from_address')->findOne()->value; + $fromName = Setting::where('name', 'from_name')->findOne()->value; + $apiKey = Setting::where('name', 'api_key')->findOne()->value; + $mailer = new MailPoet($apiKey, $fromEmail, $fromName); + + foreach ($subscribers as $subscriber) { + $result = $mailer->send( + $newsletter, + sprintf('%s %s <%s>', $subscriber['first_name'], $subscriber['last_name'], $subscriber['email']) + ); + if ($result !== true) wp_send_json(false); + } + + wp_send_json(true); } function render($data = array()) { diff --git a/tests/Actions.php b/tests/Actions.php new file mode 100644 index 0000000000..c33708642f --- /dev/null +++ b/tests/Actions.php @@ -0,0 +1,26 @@ +writeln('Cleaning up database...'); $models = array( - 'Subscriber', - 'Setting', + 'CustomField', 'Newsletter', + 'NewsletterSegment', + 'NewsletterTemplate', 'Segment', + 'Setting', + 'Subscriber', + 'SubscriberCustomField', 'SubscriberSegment' ); $destroy = function ($model) { diff --git a/tests/_support/Actions.php b/tests/_support/Actions.php new file mode 100644 index 0000000000..77ce131b7d --- /dev/null +++ b/tests/_support/Actions.php @@ -0,0 +1,18 @@ +login(); - } - - public function iCanActivate(AcceptanceTester $I) { - $I->amOnPage('/wp-admin/plugins.php'); - - $I->see('MailPoet'); - $I->click('#mailpoet .deactivate a'); - $I->see('Plugin deactivated'); - - $I->see('MailPoet'); - $I->click('#mailpoet .activate a'); - $I->see('Plugin Activated'); - } - - public function _after(AcceptanceTester $I) { - } -} diff --git a/tests/acceptance/FormWidgetCest.php b/tests/acceptance/FormWidgetCest.php deleted file mode 100644 index 731f2c5f1d..0000000000 --- a/tests/acceptance/FormWidgetCest.php +++ /dev/null @@ -1,70 +0,0 @@ -login(); - // make sure we are not in responsive mode - $I->resizeWindow(960, 600); - } - - function iCanAddTheWidget(AcceptanceTester $I) { - $I->amOnPage('/wp-admin/widgets.php'); - - $I->see('MailPoet Subscription Form'); - - // select the mailpoet form widget - $I->click('div[id*="mailpoet_form"] .widget-title'); - - $I->waitForText( - 'Add Widget', - 1, - 'div[id*="mailpoet_form"]' - ); - - // add it as a widget - $I->click( - 'Add Widget', - 'div[id*="mailpoet_form"]' - ); - - sleep(1); - - // save - $I->click( - 'Save', - '#widgets-right div[id*="mailpoet_form"]:last-child' - ); - } - - function iSeeTheWidget(AcceptanceTester $I) { - $I->amOnPage('/'); - - $I->see('Subscribe to our Newsletter'); - - $I->seeElement('.widget_mailpoet_form'); - $I->seeElement('input', ['name' => 'email']); - $I->seeElement('input', ['value' => 'Subscribe!']); - } - - function iCanDeleteTheWidget(AcceptanceTester $I) {return; - $I->amOnPage('/wp-admin/widgets.php'); - - $I->see('MailPoet Subscription Form', '#widgets-right'); - - // select an active mailpoet form widget - $I->click('#widgets-right div[id*="mailpoet_form"] .widget-action'); - - $I->waitForElementVisible( - '#widgets-right div[id*="mailpoet_form"]:last-child '. - '.widget-control-remove', - 1 - ); - - // delete widget - $I->click( - 'Delete', - '#widgets-right div[id*="mailpoet_form"]:last-child' - ); - } -} diff --git a/tests/acceptance/HomePageCest.php b/tests/acceptance/HomePageCest.php deleted file mode 100644 index 40b12cf910..0000000000 --- a/tests/acceptance/HomePageCest.php +++ /dev/null @@ -1,15 +0,0 @@ -amOnPage('/'); - $I->see('Hello'); - } - - function _after(AcceptanceTester $I) { - } -} diff --git a/tests/acceptance/NewslettersPageCest.php b/tests/acceptance/NewslettersPageCest.php deleted file mode 100644 index 132a23ce4c..0000000000 --- a/tests/acceptance/NewslettersPageCest.php +++ /dev/null @@ -1,68 +0,0 @@ -login(); - $I->resizeWindow(1024, 768); - $this->first_row = 'id("newsletters")//table/tbody/tr[2]'; - $this->timeout = 3; - } - - function iCanSeeTheTitle(AcceptanceTester $I) { - $I->amOnPage('/wp-admin/admin.php?page=mailpoet-newsletters'); - $I->see('Newsletters'); - } - - function iCanAddANewsletter(AcceptanceTester $I) { - $I->amOnPage('/wp-admin/admin.php?page=mailpoet-newsletters'); - $I->see('No newsletters found'); - $I->click('New', '#newsletters'); - $I->fillField('subject', 'first newsletter'); - $I->fillField('Body', 'some body'); - $I->click('Save'); - $I->waitForText('1 item', $this->timeout); - } - - function iCanAddAnotherNewsletter(AcceptanceTester $I) { - $I->amOnPage('/wp-admin/admin.php?page=mailpoet-newsletters#/new'); - $I->fillField('subject', 'second newsletter'); - $I->fillField('Body', 'some body'); - $I->click('Save'); - $I->waitForText('2 item', $this->timeout); - } - - function iCanSortNewsletterBySubject(AcceptanceTester $I) { - $I->click('Subject'); - $I->waitForText('first', $this->timeout, $this->first_row); - $I->click('Subject'); - $I->waitForText('second', $this->timeout, $this->first_row); - } - - function iCanSortNewsletterByCreatedDate(AcceptanceTester $I) { - $I->click('Created on'); - $I->waitForText('first', $this->timeout, $this->first_row); - $I->click('Created on'); - $I->waitForText('second', $this->timeout, $this->first_row); - } - - function iCanSearchNewsletters(AcceptanceTester $I) { - $search_term = 'second'; - $I->fillField('Search', $search_term); - $I->click('Search'); - $I->waitForText($search_term, $this->timeout, $this->first_row); - } - - function iCanSeeMobileView(AcceptanceTester $I) { - $listing_header = 'id("newsletters")//table/thead'; - $I->resizeWindow(640, 480); - $I->dontSee('Created on', $listing_header); - $I->dontSee('Last modified', $listing_header); - $I->see('Subject', $listing_header); - } - - function _after(AcceptanceTester $I) { - } -} diff --git a/tests/acceptance/SettingsPageCest.php b/tests/acceptance/SettingsPageCest.php deleted file mode 100644 index 72d6cb644f..0000000000 --- a/tests/acceptance/SettingsPageCest.php +++ /dev/null @@ -1,23 +0,0 @@ -login(); - } - - function iCanSeeTheTitle(AcceptanceTester $I) { - $I->amOnPage('/wp-admin/admin.php?page=mailpoet-settings'); - $I->see('Settings'); - } - - function iCanReachItFromTheWelcomePage(AcceptanceTester $I) { - $I->amOnPage('/wp-admin/admin.php?page=mailpoet'); - $I->see('Welcome!'); - $I->click('Setup'); - $I->see('Settings'); - } - - function _after(AcceptanceTester $I) { - } -} diff --git a/tests/acceptance/SubscribersPageCest.php b/tests/acceptance/SubscribersPageCest.php deleted file mode 100644 index 746ccf54c2..0000000000 --- a/tests/acceptance/SubscribersPageCest.php +++ /dev/null @@ -1,16 +0,0 @@ -login(); - } - - function iCanSeeTheTitle(AcceptanceTester $I) { - $I->amOnPage('/wp-admin/admin.php?page=mailpoet-subscribers'); - $I->see('Subscribers'); - } - - function _after(AcceptanceTester $I) { - } -} diff --git a/tests/acceptance/WelcomePageCest.php b/tests/acceptance/WelcomePageCest.php deleted file mode 100644 index 6e40618ff5..0000000000 --- a/tests/acceptance/WelcomePageCest.php +++ /dev/null @@ -1,16 +0,0 @@ -login(); - } - - function iCanSeeTheTitle(AcceptanceTester $I) { - $I->amOnPage('/wp-admin/admin.php?page=mailpoet'); - $I->see('Welcome!'); - } - - function _after(AcceptanceTester $I) { - } -} diff --git a/tests/acceptance/_bootstrap.php b/tests/acceptance/_bootstrap.php deleted file mode 100644 index 94bf66cf44..0000000000 --- a/tests/acceptance/_bootstrap.php +++ /dev/null @@ -1,2 +0,0 @@ -settings = array( + 'name' => 'AmazonSES', + 'type' => 'API', + 'access_key' => 'AKIAJM6Y5HMGXBLDNSRA', + 'secret_key' => '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', + 'region' => 'us-east-1', + ); + $this->from = 'Sender '; + $this->mailer = new AmazonSES( + $this->settings['region'], + $this->settings['access_key'], + $this->settings['secret_key'], + $this->from); + $this->subscriber = 'Recipient '; + $this->newsletter = array( + 'subject' => 'testing AmazonSES', + 'body' => array( + 'html' => 'HTML body', + 'text' => 'TEXT body' + ) + ); + } + + function itsConstructorWorks() { + expect($this->mailer->awsEndpoint) + ->equals( + sprintf('email.%s.amazonaws.com', $this->settings['region']) + ); + expect($this->mailer->url) ->equals( + sprintf('https://email.%s.amazonaws.com', $this->settings['region']) + ); + expect(preg_match('!^\d{8}T\d{6}Z$!', $this->mailer->date))->equals(1); + expect(preg_match('!^\d{8}$!', $this->mailer->dateWithoutTime))->equals(1); + } + + function itCanGenerateBody() { + $body = $this->mailer->getBody($this->newsletter, $this->subscriber); + expect($body['Action'])->equals('SendEmail'); + expect($body['Version'])->equals('2010-12-01'); + expect($body['Source'])->equals($this->from); + expect($body['Destination.ToAddresses.member.1']) + ->contains($this->subscriber); + expect($body['Message.Subject.Data']) + ->equals($this->newsletter['subject']); + expect($body['Message.Body.Html.Data']) + ->equals($this->newsletter['body']['html']); + expect($body['Message.Body.Text.Data']) + ->equals($this->newsletter['body']['text']); + expect($body['ReturnPath'])->equals($this->from); + } + + function itCanCreateRequest() { + $request = $this->mailer->request($this->newsletter, $this->subscriber); + $body = $this->mailer->getBody($this->newsletter, $this->subscriber); + expect($request['timeout'])->equals(10); + expect($request['httpversion'])->equals('1.1'); + expect($request['method'])->equals('POST'); + expect($request['headers']['Host'])->equals($this->mailer->awsEndpoint); + expect($request['headers']['Authorization']) + ->equals($this->mailer->signRequest($body)); + expect($request['headers']['X-Amz-Date'])->equals($this->mailer->date); + expect($request['body'])->equals(urldecode(http_build_query($body))); + } + + function itCanCreateCanonicalRequest() { + $body = $this->mailer->getBody($this->newsletter, $this->subscriber); + $canonicalRequest = explode( + "\n", + $this->mailer->getCanonicalRequest($body) + ); + expect($canonicalRequest) + ->equals( + array( + 'POST', + '/', + '', + 'host:' . $this->mailer->awsEndpoint, + 'x-amz-date:' . $this->mailer->date, + '', + 'host;x-amz-date', + hash($this->mailer->hashAlgorithm, + urldecode(http_build_query($body)) + ) + ) + ); + } + + function itCanCreateCredentialScope() { + $credentialScope = $this->mailer->getCredentialScope(); + expect($credentialScope) + ->equals( + $this->mailer->dateWithoutTime . '/' . + $this->mailer->awsRegion . '/' . + $this->mailer->awsService . '/' . + $this->mailer->awsTerminationString + ); + } + + function itCanCreateStringToSign() { + $body = $this->mailer->getBody($this->newsletter, $this->subscriber); + $credentialScope = $this->mailer->getCredentialScope(); + $canonicalRequest = $this->mailer->getCanonicalRequest($body); + $stringToSing = $this->mailer->createStringToSign( + $credentialScope, + $canonicalRequest + ); + $stringToSing = explode("\n", $stringToSing); + expect($stringToSing) + ->equals( + array( + $this->mailer->awsSigningAlgorithm, + $this->mailer->date, + $credentialScope, + hash($this->mailer->hashAlgorithm, $canonicalRequest) + ) + ); + } + + function itCanSignRequest() { + $body = $this->mailer->getBody($this->newsletter, $this->subscriber); + $signedRequest = $this->mailer->signRequest($body); + expect($signedRequest) + ->contains( + $this->mailer->awsSigningAlgorithm . ' Credential=' . + $this->mailer->awsAccessKey . '/' . + $this->mailer->getCredentialScope() . ', ' . + 'SignedHeaders=host;x-amz-date, Signature=' + ); + expect(preg_match('!Signature=[A-Fa-f0-9]{64}$!', $signedRequest)) + ->equals(1); + } + + function itCannotSendWithoutProperAccessKey() { + $this->mailer->awsAccessKey = 'somekey'; + $result = $this->mailer->send( + $this->newsletter, + $this->subscriber + ); + expect($result)->false(); + } + + function itCanSend() { + $result = $this->mailer->send( + $this->newsletter, + $this->subscriber + ); + expect($result)->true(); + } +} diff --git a/tests/unit/Mailer/API/ElasticEmailCest.php b/tests/unit/Mailer/API/ElasticEmailCest.php new file mode 100644 index 0000000000..112df03fce --- /dev/null +++ b/tests/unit/Mailer/API/ElasticEmailCest.php @@ -0,0 +1,65 @@ +settings = array( + 'name' => 'ElasticEmail', + 'type' => 'API', + 'api_key' => '997f1f7f-41de-4d7f-a8cb-86c8481370fa' + ); + $this->fromEmail = 'staff@mailpoet.com'; + $this->fromName = 'Sender'; + $this->mailer = new ElasticEmail( + $this->settings['api_key'], + $this->fromEmail, + $this->fromName + ); + $this->subscriber = 'Recipient '; + $this->newsletter = array( + 'subject' => 'testing ElasticEmail', + 'body' => array( + 'html' => 'HTML body', + 'text' => 'TEXT body' + ) + ); + } + + function itCanGenerateBody() { + $body = $this->mailer->getBody($this->newsletter, $this->subscriber); + expect($body['api_key'])->equals($this->settings['api_key']); + expect($body['from'])->equals($this->fromEmail); + expect($body['from_name'])->equals($this->fromName); + expect($body['to'])->contains($this->subscriber); + expect($body['subject'])->equals($this->newsletter['subject']); + expect($body['body_html'])->equals($this->newsletter['body']['html']); + expect($body['body_text'])->equals($this->newsletter['body']['text']); + } + + function itCanCreateRequest() { + $request = $this->mailer->request($this->newsletter, $this->subscriber); + $body = $this->mailer->getBody($this->newsletter, $this->subscriber); + expect($request['timeout'])->equals(10); + expect($request['httpversion'])->equals('1.0'); + expect($request['method'])->equals('POST'); + expect($request['body'])->equals(urldecode(http_build_query($body))); + } + + function itCannotSendWithoutProperAPIKey() { + $this->mailer->apiKey = 'someapi'; + $result = $this->mailer->send( + $this->newsletter, + $this->subscriber + ); + expect($result)->false(); + } + + function itCanSend() { + $result = $this->mailer->send( + $this->newsletter, + $this->subscriber + ); + expect($result)->true(); + } +} diff --git a/tests/unit/Mailer/API/MailGunCest.php b/tests/unit/Mailer/API/MailGunCest.php new file mode 100644 index 0000000000..85df8e45d1 --- /dev/null +++ b/tests/unit/Mailer/API/MailGunCest.php @@ -0,0 +1,82 @@ +settings = array( + 'name' => 'MailGun', + 'type' => 'API', + 'api_key' => 'key-6cf5g5qjzenk-7nodj44gdt8phe6vam2', + 'domain' => 'mrcasual.com' + ); + $this->from = 'Sender '; + $this->mailer = new MailGun( + $this->settings['domain'], + $this->settings['api_key'], + $this->from + ); + $this->subscriber = 'Recipient '; + $this->newsletter = array( + 'subject' => 'testing MailGun', + 'body' => array( + 'html' => 'HTML body', + 'text' => 'TEXT body' + ) + ); + } + + function itCanGenerateBody() { + $body = $this->mailer->getBody($this->newsletter, $this->subscriber); + expect($body['from'])->equals($this->from); + expect($body['to'])->equals($this->subscriber); + expect($body['subject'])->equals($this->newsletter['subject']); + expect($body['html'])->equals($this->newsletter['body']['html']); + expect($body['text'])->equals($this->newsletter['body']['text']); + } + + function itCanDoBasicAuth() { + expect($this->mailer->auth()) + ->equals('Basic ' . base64_encode('api:' . $this->settings['api_key'])); + } + + function itCanCreateRequest() { + $request = $this->mailer->request($this->newsletter, $this->subscriber); + $body = $this->mailer->getBody($this->newsletter, $this->subscriber); + expect($request['timeout'])->equals(10); + expect($request['httpversion'])->equals('1.0'); + expect($request['method'])->equals('POST'); + expect($request['headers']['Content-Type']) + ->equals('application/x-www-form-urlencoded'); + expect($request['headers']['Authorization']) + ->equals('Basic ' . base64_encode('api:' . $this->settings['api_key'])); + expect($request['body'])->equals(urldecode(http_build_query($body))); + } + + function itCannotSendWithoutProperAPIKey() { + $this->mailer->apiKey = 'someapi'; + $result = $this->mailer->send( + $this->newsletter, + $this->subscriber + ); + expect($result)->false(); + } + + function itCannotSendWithoutProperDomain() { + $this->mailer->url = + str_replace($this->settings['domain'], 'somedomain', $this->mailer->url); + $result = $this->mailer->send( + $this->newsletter, + $this->subscriber + ); + expect($result)->false(); + } + + function itCanSend() { + $result = $this->mailer->send( + $this->newsletter, + $this->subscriber + ); + expect($result)->true(); + } +} \ No newline at end of file diff --git a/tests/unit/Mailer/API/MandrillCest.php b/tests/unit/Mailer/API/MandrillCest.php new file mode 100644 index 0000000000..be3998d153 --- /dev/null +++ b/tests/unit/Mailer/API/MandrillCest.php @@ -0,0 +1,90 @@ +settings = array( + 'name' => 'Mandrill', + 'type' => 'API', + 'api_key' => '692ys1B7REEoZN7R-dYwNA' + ); + $this->fromEmail = 'staff@mailpoet.com'; + $this->fromName = 'Sender'; + $this->mailer = new Mandrill( + $this->settings['api_key'], + $this->fromEmail, + $this->fromName + ); + $this->subscriber = 'Recipient '; + $this->newsletter = array( + 'subject' => 'testing Mandrill', + 'body' => array( + 'html' => 'HTML body', + 'text' => 'TEXT body' + ) + ); + } + + function itCanGenerateBody() { + $subscriber = $this->mailer->processSubscriber($this->subscriber); + $body = $this->mailer->getBody($this->newsletter, $subscriber); + expect($body['key'])->equals($this->settings['api_key']); + expect($body['message']['from_email'])->equals($this->fromEmail); + expect($body['message']['from_name'])->equals($this->fromName); + expect($body['message']['to'])->equals(array($subscriber)); + expect($body['message']['subject'])->equals($this->newsletter['subject']); + expect($body['message']['html'])->equals($this->newsletter['body']['html']); + expect($body['message']['text'])->equals($this->newsletter['body']['text']); + expect($body['async'])->false(); + } + + function itCanCreateRequest() { + $subscriber = $this->mailer->processSubscriber($this->subscriber); + $body = $this->mailer->getBody($this->newsletter, $subscriber); + $request = $this->mailer->request($this->newsletter, $subscriber); + expect($request['timeout'])->equals(10); + expect($request['httpversion'])->equals('1.0'); + expect($request['method'])->equals('POST'); + expect($request['headers']['Content-Type'])->equals('application/json'); + expect($request['body'])->equals(json_encode($body)); + } + + function itCanProcessSubscriber() { + expect($this->mailer->processSubscriber('test@test.com')) + ->equals( + array( + 'email' => 'test@test.com', + 'name' => '' + )); + expect($this->mailer->processSubscriber('First ')) + ->equals( + array( + 'email' => 'test@test.com', + 'name' => 'First' + )); + expect($this->mailer->processSubscriber('First Last ')) + ->equals( + array( + 'email' => 'test@test.com', + 'name' => 'First Last' + )); + } + + function itCannotSendWithoutProperAPIKey() { + $this->mailer->apiKey = 'someapi'; + $result = $this->mailer->send( + $this->newsletter, + $this->subscriber + ); + expect($result)->false(); + } + + function itCanSend() { + $result = $this->mailer->send( + $this->newsletter, + $this->subscriber + ); + expect($result)->true(); + } +} \ No newline at end of file diff --git a/tests/unit/Mailer/API/SendGridCest.php b/tests/unit/Mailer/API/SendGridCest.php new file mode 100644 index 0000000000..720dc8d632 --- /dev/null +++ b/tests/unit/Mailer/API/SendGridCest.php @@ -0,0 +1,71 @@ +settings = array( + 'name' => 'SendGrid', + 'type' => 'API', + 'api_key' => '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' + ); + $this->fromEmail = 'staff@mailpoet.com'; + $this->fromName = 'Sender'; + $this->mailer = new SendGrid( + $this->settings['api_key'], + $this->fromEmail, + $this->fromName + ); + $this->subscriber = 'Recipient '; + $this->newsletter = array( + 'subject' => 'testing SendGrid', + 'body' => array( + 'html' => 'HTML body', + 'text' => 'TEXT body' + ) + ); + } + + function itCanGenerateBody() { + $body = $this->mailer->getBody($this->newsletter, $this->subscriber); + expect($body['to'])->contains($this->subscriber); + expect($body['from'])->equals($this->fromEmail); + expect($body['fromname'])->equals($this->fromName); + expect($body['subject'])->equals($this->newsletter['subject']); + expect($body['html'])->equals($this->newsletter['body']['html']); + expect($body['text'])->equals($this->newsletter['body']['text']); + } + + function itCanCreateRequest() { + $body = $this->mailer->getBody($this->newsletter, $this->subscriber); + $request = $this->mailer->request($this->newsletter, $this->subscriber); + expect($request['timeout'])->equals(10); + expect($request['httpversion'])->equals('1.1'); + expect($request['method'])->equals('POST'); + expect($request['headers']['Authorization']) + ->equals('Bearer ' . $this->settings['api_key']); + expect($request['body'])->equals(urldecode(http_build_query($body))); + } + + function itCanDoBasicAuth() { + expect($this->mailer->auth()) + ->equals('Bearer ' . $this->settings['api_key']); + } + + function itCannotSendWithoutProperAPIKey() { + $this->mailer->apiKey = 'someapi'; + $result = $this->mailer->send( + $this->newsletter, + $this->subscriber + ); + expect($result)->false(); + } + + function itCanSend() { + $result = $this->mailer->send( + $this->newsletter, + $this->subscriber + ); + expect($result)->true(); + } +} diff --git a/tests/unit/Mailer/BridgeCest.php b/tests/unit/Mailer/BridgeCest.php deleted file mode 100644 index b483bc6945..0000000000 --- a/tests/unit/Mailer/BridgeCest.php +++ /dev/null @@ -1,123 +0,0 @@ -name = 'from_name'; - $from_name->value = 'Marco'; - $from_name->save(); - - $from_address = Setting::create(); - $from_address->name = 'from_address'; - $from_address->value = 'marco@mailpoet.com'; - $from_address->save(); - - $api_key = Setting::create(); - $api_key->name = 'api_key'; - $api_key->value = 'xxxccc'; - $api_key->save(); - - $this->newsletter = array( - 'subject' => 'A test message from mp3', - 'body' => 'Hey, I am mp3, chapter two.' - ); - $this->subscribers = array( - array( - 'first_name' => 'Marco', - 'last_name' => 'Lisci', - 'email' => 'marco@mailpoet.com' - ), - array( - 'first_name' => 'Jonathan', - 'last_name' => 'Labreuille', - 'email' => 'jonathan@mailpoet.com' - ) - ); - - $this->mailer = new Bridge( - $this->newsletter, - $this->subscribers - ); - } - - function itCanDoBasicAuth() { - $api_key = Setting::where('name', 'api_key') - ->findOne()->value; - expect($this->mailer->auth())->equals( - 'Basic ' - . base64_encode('api:' . $api_key) - ); - } - - function itCanGenerateACorrectMessage() { - $subscriber = $this->subscribers[0]; - $message = - $this->mailer->generateMessage($subscriber); - - expect($message['to']['address']) - ->equals($subscriber['email']); - - expect($message['to']['name']) - ->equals($subscriber['first_name'].' '.$subscriber['last_name']); - - expect($message['subject']) - ->equals($this->newsletter['subject']); - - expect($message['html']) - ->equals($this->newsletter['body']); - - expect($message['text']) - ->equals(''); - } - - function itCanGenerateCorrectMessages() { - $messages = $this->mailer->messages(); - - expect(count($messages)) - ->equals(count($this->subscribers)); - } - - function itCanCreateARequest() { - $request = $this->mailer->request(); - - expect($request['timeout']) - ->equals(10); - - expect($request['httpversion']) - ->equals('1.0'); - - expect($request['method']) - ->equals('POST'); - - expect($request['headers']['Content-Type']) - ->equals('application/json'); - } - - function itCannotSendWithoutSubscribers() { - $subscribers = array(); - - $mailer = new Bridge( - $this->newsletter, - $subscribers - ); - - expect($mailer->send())->equals(false); - } - - function itCanSend() { - /* $result = $this->mailer->send(); */ - /* expect($result)->equals(true); */ - } - - function _after() { - Setting::where('name', 'from_name') - ->findOne()->delete(); - Setting::where('name', 'from_address') - ->findOne()->delete(); - Setting::where('name', 'api_key') - ->findOne()->delete(); - } -} diff --git a/tests/unit/Mailer/MailPoetCest.php b/tests/unit/Mailer/MailPoetCest.php new file mode 100644 index 0000000000..999e387050 --- /dev/null +++ b/tests/unit/Mailer/MailPoetCest.php @@ -0,0 +1,95 @@ +settings = array( + 'name' => 'MailPoet', + 'api_key' => 'dhNSqj1XHkVltIliyQDvMiKzQShOA5rs0m_DdRUVZHU' + ); + $this->fromEmail = 'staff@mailpoet.com'; + $this->fromName = 'Sender'; + $this->mailer = new MailPoet( + $this->settings['api_key'], + $this->fromEmail, + $this->fromName + ); + $this->subscriber = 'Recipient '; + $this->newsletter = array( + 'subject' => 'testing MailPoet', + 'body' => array( + 'html' => 'HTML body', + 'text' => 'TEXT body' + ) + ); + } + + function itCanGenerateBody() { + $subscriber = $this->mailer->processSubscriber($this->subscriber); + $body = $this->mailer->getBody($this->newsletter, $subscriber); + expect($body['to']['address'])->equals($subscriber['email']); + expect($body['to']['name'])->equals($subscriber['name']); + expect($body['from']['address'])->equals($this->fromEmail); + expect($body['subject'])->equals($this->newsletter['subject']); + expect($body['html'])->equals($this->newsletter['body']['html']); + expect($body['text'])->equals($this->newsletter['body']['text']); + } + + function itCanCreateRequest() { + $subscriber = $this->mailer->processSubscriber( + 'Recipient ' + ); + $body = array($this->mailer->getBody($this->newsletter, $subscriber)); + $request = $this->mailer->request($this->newsletter, $subscriber); + expect($request['timeout'])->equals(10); + expect($request['httpversion'])->equals('1.0'); + expect($request['method'])->equals('POST'); + expect($request['headers']['Content-Type'])->equals('application/json'); + expect($request['headers']['Authorization'])->equals($this->mailer->auth()); + expect($request['body'])->equals(json_encode($body)); + } + + function itCanProcessSubscriber() { + expect($this->mailer->processSubscriber('test@test.com')) + ->equals( + array( + 'email' => 'test@test.com', + 'name' => '' + )); + expect($this->mailer->processSubscriber('First ')) + ->equals( + array( + 'email' => 'test@test.com', + 'name' => 'First' + )); + expect($this->mailer->processSubscriber('First Last ')) + ->equals( + array( + 'email' => 'test@test.com', + 'name' => 'First Last' + )); + } + + function itCanDoBasicAuth() { + expect($this->mailer->auth()) + ->equals('Basic ' . base64_encode('api:' . $this->settings['api_key'])); + } + + function itCannotSendWithoutProperAPIKey() { + $this->mailer->apiKey = 'someapi'; + $result = $this->mailer->send( + $this->newsletter, + $this->subscriber + ); + expect($result)->false(); + } + + function itCanSend() { + $result = $this->mailer->send( + $this->newsletter, + $this->subscriber + ); + expect($result)->true(); + } +} diff --git a/tests/unit/Mailer/SMTPCest.php b/tests/unit/Mailer/SMTPCest.php new file mode 100644 index 0000000000..7fd61532ad --- /dev/null +++ b/tests/unit/Mailer/SMTPCest.php @@ -0,0 +1,91 @@ +settings = array( + 'name' => 'SMTP', + 'host' => 'email-smtp.us-west-2.amazonaws.com', + 'port' => 587, + 'authentication' => array( + 'login' => 'AKIAIGPBLH6JWG5VCBQQ', + 'password' => 'AudVHXHaYkvr54veCzqiqOxDiMMyfQW3/V6F1tYzGXY3' + ), + 'encryption' => 'tls' + ); + $this->fromEmail = 'staff@mailpoet.com'; + $this->fromName = 'Sender'; + $this->mailer = new SMTP( + $this->settings['host'], + $this->settings['port'], + $this->settings['authentication'], + $this->settings['encryption'], + $this->fromEmail, + $this->fromName + ); + $this->subscriber = 'Recipient '; + $this->newsletter = array( + 'subject' => 'testing SMTP', + 'body' => array( + 'html' => 'HTML body', + 'text' => 'TEXT body' + ) + ); + } + + function itCanBuildMailer() { + $mailer = $this->mailer->buildMailer(); + expect($mailer->getTransport()->getHost()) + ->equals($this->settings['host']); + expect($mailer->getTransport()->getPort()) + ->equals($this->settings['port']); + expect($mailer->getTransport()->getUsername()) + ->equals($this->settings['authentication']['login']); + expect($mailer->getTransport()->getPassword()) + ->equals($this->settings['authentication']['password']); + expect($mailer->getTransport()->getEncryption()) + ->equals($this->settings['encryption']); + } + + function itCanCreateMessage() { + $message = $this->mailer->createMessage($this->newsletter, $this->subscriber); + expect($message->getTo()) + ->equals(array('mailpoet-phoenix-test@mailinator.com' => 'Recipient')); + expect($message->getFrom()) + ->equals(array($this->fromEmail => $this->fromName)); + expect($message->getSubject()) + ->equals($this->newsletter['subject']); + expect($message->getBody()) + ->equals($this->newsletter['body']['html']); + expect($message->getChildren()[0]->getContentType()) + ->equals('text/plain'); + } + + function itCanProcessSubscriber() { + expect($this->mailer->processSubscriber('test@test.com')) + ->equals(array('test@test.com' => '')); + expect($this->mailer->processSubscriber('First ')) + ->equals(array('test@test.com' => 'First')); + expect($this->mailer->processSubscriber('First Last ')) + ->equals(array('test@test.com' => 'First Last')); + } + + function itCantSentWithoutProperAuthentication() { + $this->mailer->authentication['login'] = 'someone'; + $this->mailer->mailer = $this->mailer->buildMailer(); + $result = $this->mailer->send( + $this->newsletter, + $this->subscriber + ); + expect($result)->false(); + } + + function itCanSend() { + $result = $this->mailer->send( + $this->newsletter, + $this->subscriber + ); + expect($result)->true(); + } +} \ No newline at end of file diff --git a/tests/unit/Mailer/WPMailCest.php b/tests/unit/Mailer/WPMailCest.php new file mode 100644 index 0000000000..1110948e5f --- /dev/null +++ b/tests/unit/Mailer/WPMailCest.php @@ -0,0 +1,70 @@ +settings = array( + 'name' => 'WPMail' + ); + $this->fromEmail = 'staff@mailpoet.com'; + $this->fromName = 'Sender'; + $this->mailer = new WPMail( + $this->fromEmail, + $this->fromName + ); + $this->subscriber = 'Recipient '; + $this->newsletter = array( + 'subject' => 'testing SMTP', + 'body' => array( + 'html' => 'HTML body', + 'text' => 'TEXT body' + ) + ); + } + + function itCanAddFilters() { + $this->mailer->addFilters(); + expect(has_filter('wp_mail_from_name', array( + $this->mailer, + 'setFromName' + )))->notEmpty(); + expect(has_filter('wp_mail_from', array( + $this->mailer, + 'setFromEmail' + )))->notEmpty(); + expect(has_filter('wp_mail_content_type', array( + $this->mailer, + 'setContentType' + )))->notEmpty(); + } + + function itCanRemoveFilters() { + $this->mailer->addFilters(); + $this->mailer->removeFilters(); + expect(has_filter('wp_mail_from_name'))->false(); + expect(has_filter('wp_mail_from'))->false(); + expect(has_filter('wp_mail_content_type'))->false(); + } + + function itCanSetFromName() { + expect($this->mailer->setFromName())->equals($this->fromName); + } + + function itCanSetFromEmail() { + expect($this->mailer->setFromName())->equals($this->fromName); + } + + function itCanSetContentType() { + expect($this->mailer->setContentType())->equals('text/html'); + } + + function itCanSend() { + $_SERVER['SERVER_NAME'] = 'localhost'; + $result = $this->mailer->send( + $this->newsletter, + $this->subscriber + ); + expect($result)->true(); + } +} \ No newline at end of file diff --git a/tests/unit/Models/CustomFieldCest.php b/tests/unit/Models/CustomFieldCest.php new file mode 100644 index 0000000000..9fb6dc8b63 --- /dev/null +++ b/tests/unit/Models/CustomFieldCest.php @@ -0,0 +1,114 @@ +before_time = time(); + $this->data = array( + 'name' => 'city', + ); + $this->customField = CustomField::create(); + $this->customField->hydrate($this->data); + $this->saved = $this->customField->save(); + $this->subscribersData = array( + array( + 'first_name' => 'John', + 'last_name' => 'Mailer', + 'email' => 'john@mailpoet.com' + ), + array( + 'first_name' => 'Mike', + 'last_name' => 'Smith', + 'email' => 'mike@maipoet.com' + ) + ); + } + + function itCanBeCreated() { + expect($this->saved)->equals(true); + } + + function itHasToBeValid() { + expect($this->saved)->equals(true); + $empty_model = CustomField::create(); + expect($empty_model->save())->notEquals(true); + $validations = $empty_model->getValidationErrors(); + expect(count($validations))->equals(1); + } + + function itHasACreatedAtOnCreation() { + $customField = CustomField::where('name', $this->data['name']) + ->findOne(); + $time_difference = strtotime($customField->created_at) >= $this->before_time; + expect($time_difference)->equals(true); + } + + function itHasAnUpdatedAtOnCreation() { + $customField = CustomField::where('name', $this->data['name']) + ->findOne(); + $time_difference = strtotime($customField->updated_at) >= $this->before_time; + expect($time_difference)->equals(true); + } + + function itKeepsTheCreatedAtOnUpdate() { + $customField = CustomField::where('name', $this->data['name']) + ->findOne(); + $old_created_at = $customField->created_at; + $customField->name = 'new name'; + $customField->save(); + expect($old_created_at)->equals($customField->created_at); + } + + function itUpdatesTheUpdatedAtOnUpdate() { + $customField = CustomField::where('name', $this->data['name']) + ->findOne(); + $update_time = time(); + $customField->name = 'new name'; + $customField->save(); + $time_difference = strtotime($customField->updated_at) >= $update_time; + expect($time_difference)->equals(true); + } + + function itCanHaveManySubscribers() { + foreach ($this->subscribersData as $data) { + $subscriber = Subscriber::create(); + $subscriber->hydrate($data); + $subscriber->save(); + $association = SubscriberCustomField::create(); + $association->subscriber_id = $subscriber->id; + $association->custom_field_id = $this->customField->id; + $association->save(); + } + $customField = CustomField::findOne($this->customField->id); + $subscribers = $customField->subscribers() + ->findArray(); + expect(count($subscribers))->equals(2); + } + + function itCanStoreCustomFieldValue() { + $subscriber = Subscriber::create(); + $subscriber->hydrate($this->subscribersData[0]); + $subscriber->save(); + $association = SubscriberCustomField::create(); + $association->subscriber_id = $subscriber->id; + $association->custom_field_id = $this->customField->id; + $association->value = 'test'; + $association->save(); + $customField = CustomField::findOne($this->customField->id); + $subscriber = $customField->subscribers() + ->findOne(); + expect($subscriber->value)->equals($association->value); + } + + function _after() { + ORM::forTable(CustomField::$_table) + ->deleteMany(); + ORM::forTable(Subscriber::$_table) + ->deleteMany(); + ORM::forTable(SubscriberCustomField::$_table) + ->deleteMany(); + } +} \ No newline at end of file diff --git a/tests/unit/Models/SubscriberCest.php b/tests/unit/Models/SubscriberCest.php index 603044f48a..f65e6a067a 100644 --- a/tests/unit/Models/SubscriberCest.php +++ b/tests/unit/Models/SubscriberCest.php @@ -1,6 +1,8 @@ 'Mailer', 'email' => 'john@mailpoet.com' ); - $this->subscriber = Subscriber::create(); $this->subscriber->hydrate($this->data); $this->saved = $this->subscriber->save(); @@ -21,7 +22,7 @@ class SubscriberCest { expect($this->saved)->equals(true); } - function itHasAFirstName() { + function itHasFirstName() { $subscriber = Subscriber::where('email', $this->data['email']) ->findOne(); @@ -29,7 +30,7 @@ class SubscriberCest { ->equals($this->data['first_name']); } - function itHasALastName() { + function itHasLastName() { $subscriber = Subscriber::where('email', $this->data['email']) ->findOne(); @@ -37,7 +38,7 @@ class SubscriberCest { ->equals($this->data['last_name']); } - function itHasAnEmail() { + function itHasEmail() { $subscriber = Subscriber::where('email', $this->data['email']) ->findOne(); @@ -52,59 +53,60 @@ class SubscriberCest { expect($saved)->notEquals(true); } - function itHasAStatus() { + function itHasStatus() { $subscriber = Subscriber::where('email', $this->data['email']) - ->findOne(); - + ->findOne(); expect($subscriber->status)->equals('unconfirmed'); } function itCanChangeStatus() { - $subscriber = Subscriber::where('email', $this->data['email'])->findOne(); + $subscriber = Subscriber::where('email', $this->data['email']) + ->findOne(); $subscriber->status = 'subscribed'; expect($subscriber->save())->equals(true); - $subscriber_updated = Subscriber::where( 'email', $this->data['email'] - )->findOne(); + ) + ->findOne(); expect($subscriber_updated->status)->equals('subscribed'); } - function itHasASearchFilter() { - $subscriber = Subscriber::filter('search', 'john')->findOne(); + function itHasSearchFilter() { + $subscriber = Subscriber::filter('search', 'john') + ->findOne(); expect($subscriber->first_name)->equals($this->data['first_name']); - - $subscriber = Subscriber::filter('search', 'mailer')->findOne(); + $subscriber = Subscriber::filter('search', 'mailer') + ->findOne(); expect($subscriber->last_name)->equals($this->data['last_name']); - - $subscriber = Subscriber::filter('search', 'mailpoet')->findOne(); + $subscriber = Subscriber::filter('search', 'mailpoet') + ->findOne(); expect($subscriber->email)->equals($this->data['email']); } - function itHasAGroupFilter() { - $subscribers = Subscriber::filter('groupBy', 'unconfirmed')->findMany(); - foreach($subscribers as $subscriber) { + function itHasGroupFilter() { + $subscribers = Subscriber::filter('groupBy', 'unconfirmed') + ->findMany(); + foreach ($subscribers as $subscriber) { expect($subscriber->status)->equals('unconfirmed'); } - - $subscribers = Subscriber::filter('groupBy', 'subscribed')->findMany(); - foreach($subscribers as $subscriber) { + $subscribers = Subscriber::filter('groupBy', 'subscribed') + ->findMany(); + foreach ($subscribers as $subscriber) { expect($subscriber->status)->equals('subscribed'); } - - $subscribers = Subscriber::filter('groupBy', 'unsubscribed')->findMany(); - foreach($subscribers as $subscriber) { + $subscribers = Subscriber::filter('groupBy', 'unsubscribed') + ->findMany(); + foreach ($subscribers as $subscriber) { expect($subscriber->status)->equals('unsubscribed'); } } - function itCanHaveASegment() { + function itCanHaveSegment() { $segmentData = array( 'name' => 'some name' ); - $segment = Segment::create(); $segment->hydrate($segmentData); $segment->save(); @@ -112,32 +114,46 @@ class SubscriberCest { $association->subscriber_id = $this->subscriber->id; $association->segment_id = $segment->id; $association->save(); - $subscriber = Subscriber::findOne($this->subscriber->id); - $subscriberSegment = $subscriber->segments()->findOne(); + $subscriberSegment = $subscriber->segments() + ->findOne(); expect($subscriberSegment->id)->equals($segment->id); } + + function itCanHaveCustomField() { + $customFieldData = array( + 'name' => 'city' + ); + $customField = CustomField::create(); + $customField->hydrate($customFieldData); + $customField->save(); + $association = SubscriberCustomField::create(); + $association->subscriber_id = $this->subscriber->id; + $association->custom_field_id = $customField->id; + $association->save(); + $subscriber = Subscriber::findOne($this->subscriber->id); + $subscriberCustomField = $subscriber->customFields() + ->findOne(); + expect($subscriberCustomField->id)->equals($customField->id); + } function itCanCreateOrUpdate() { $data = array( - 'email' => 'john.doe@mailpoet.com', + 'email' => 'john.doe@mailpoet.com', 'first_name' => 'John', 'last_name' => 'Doe' ); - $result = Subscriber::createOrUpdate($data); expect($result)->equals(true); - $record = Subscriber::where('email', $data['email']) ->findOne(); expect($record->first_name)->equals($data['first_name']); expect($record->last_name)->equals($data['last_name']); - $record->last_name = 'Mailer'; $result = Subscriber::createOrUpdate($record->asArray()); expect($result)->equals(true); - - $record = Subscriber::where('email', $data['email'])->findOne(); + $record = Subscriber::where('email', $data['email']) + ->findOne(); expect($record->last_name)->equals('Mailer'); } @@ -148,5 +164,9 @@ class SubscriberCest { ->deleteMany(); ORM::forTable(SubscriberSegment::$_table) ->deleteMany(); + ORM::forTable(CustomField::$_table) + ->deleteMany(); + ORM::forTable(SubscriberCustomField::$_table) + ->deleteMany(); } -} +} \ No newline at end of file diff --git a/tests/unit/Router/MailerCest.php b/tests/unit/Router/MailerCest.php new file mode 100644 index 0000000000..ec3a581240 --- /dev/null +++ b/tests/unit/Router/MailerCest.php @@ -0,0 +1,69 @@ +router = new Mailer(); + } + + function itCanConstruct() { + expect($this->router->from)->equals('Sender '); + } + + function itCanTransformSubscriber() { + expect($this->router->transformSubscriber('test@email.com')) + ->equals('test@email.com'); + expect($this->router->transformSubscriber( + array( + 'email' => 'test@email.com' + )) + )->equals('test@email.com'); + expect($this->router->transformSubscriber( + array( + 'first_name' => 'First', + 'email' => 'test@email.com' + )) + )->equals('First '); + expect($this->router->transformSubscriber( + array( + 'last_name' => 'Last', + 'email' => 'test@email.com' + )) + )->equals('Last '); + expect($this->router->transformSubscriber( + array( + 'first_name' => 'First', + 'last_name' => 'Last', + 'email' => 'test@email.com' + )) + )->equals('First Last '); + } + + function itCanConfigureMailer() { + $mailer = $this->router->buildMailer(); + $class = 'Mailpoet\\Mailer\\' . + ((isset($this->router->mailer['type'])) ? + $this->router->mailer['type'] . '\\' . $this->router->mailer['name'] : + $this->router->mailer['name'] + ); + expect($mailer instanceof $class)->true(); + expect(method_exists($mailer, 'send'))->true(); + } + + function itCanSend() { + $newsletter = array( + 'subject' => 'testing Mailer router with ' . $this->router->mailer['name'], + 'body' => array( + 'html' => 'HTML body', + 'text' => 'TEXT body' + ) + ); + $subscriber = array( + 'first_name' => 'First', + 'last_name' => 'Last', + 'email' => 'mailpoet-phoenix-test@mailinator.com' + ); + expect($this->router->send($newsletter, $subscriber))->true(); + } +} diff --git a/views/newsletter/editor.html b/views/newsletter/editor.html index 8fc013c75a..b37a6d4c27 100644 --- a/views/newsletter/editor.html +++ b/views/newsletter/editor.html @@ -1855,7 +1855,7 @@ customFieldsWindowTitle: '<%= __('Select a shortcode') %>', unsubscribeLinkMissing: '<%= __('Please include an unsubscribe link to continue.') %>', - testEmailSent: '<%= __('Test email succesfully sent!') %>', + testEmailSent: '<%= __('Test email successfully sent!') %>', unknownErrorOccurred: '<%= __('An unknown error occurred, please check your settings.') %>', }, sidepanelWidth: '331px', diff --git a/views/newsletter/form.html b/views/newsletter/form.html index 57a5d91f55..e6125c9ad9 100644 --- a/views/newsletter/form.html +++ b/views/newsletter/form.html @@ -1236,7 +1236,7 @@ unsubscribeLinkMissing: '<%= __('Please include an unsubscribe link to continue.') %>', testEmailSent: - '<%= __('Test email succesfully sent!') %>', + '<%= __('Test email successfully sent!') %>', unknownErrorOccurred: '<%= __('An unknown error occurred, please check your settings.') %>', }, diff --git a/views/newsletter/templates/blocks/automatedLatestContent/settings.hbs b/views/newsletter/templates/blocks/automatedLatestContent/settings.hbs index 719eb73da2..063ccacffb 100644 --- a/views/newsletter/templates/blocks/automatedLatestContent/settings.hbs +++ b/views/newsletter/templates/blocks/automatedLatestContent/settings.hbs @@ -1,7 +1,7 @@

<%= __('Post selection') %>

-
<%= __('Show:') %>
+
<%= __('Show:') %>