Compare commits

...

71 Commits

Author SHA1 Message Date
580ac989aa Bump up version to 0.0.17 2016-02-19 15:35:27 +02:00
acf300160d Merge pull request #356 from mailpoet/page_reviews
Page reviews
2016-02-18 15:34:10 +02:00
983df4ee13 Merge pull request #355 from mailpoet/editor_polishing_3
Editor polishing 3
2016-02-18 07:45:20 -05:00
03c782d4ab Fixed issue #305
- added validation on add/edit Custom Field for multiple values (select/radio)
- disabled Remove link when only one value remains
- Added confirmation message on Reinstall
- Added missing period in Import
2016-02-18 13:14:57 +01:00
0daf7e12c1 remove logging function (polluting unit tests) & bugfix on model subscriber addToSegments 2016-02-18 13:13:19 +01:00
6a2e18a0e1 fix segments being reset on Subscriber::createOrUpdate() 2016-02-18 13:13:19 +01:00
316d5ab183 fixed unit tests 2016-02-18 13:13:19 +01:00
eb6bba5961 Merge pull request #351 from mailpoet/import_language_update
Updates error messages displayed during import
2016-02-18 09:55:59 +01:00
b5864adf06 - Fixes writable path check 2016-02-17 11:47:20 -05:00
9bce50a633 Fix "Full width" image option 2016-02-17 15:10:51 +02:00
365a53cf27 Merge pull request #353 from mailpoet/subscribers_page_review
Subscribers page review
2016-02-17 14:28:36 +02:00
31a4575d43 replaced closure by callbacks 2016-02-17 13:02:35 +01:00
1ae584c4e7 Restyle ALC Post number/type selector, limit to 2 character input 2016-02-17 13:29:16 +02:00
aac2cd6eb8 Add button "Bold" text option, fix unit tests 2016-02-17 12:25:03 +02:00
9874e1c371 Remove 1px left black border from newsletter thumbnails 2016-02-17 12:25:03 +02:00
16b1c0dc41 Convert mailpoet buttons to WP buttons in newsletter editor 2016-02-17 12:25:03 +02:00
9223fbf478 Display loading animation when listing newsletter templates 2016-02-17 12:25:03 +02:00
eb27de36f4 Select active block format and allow custom colors in TinyMCe 2016-02-17 12:25:03 +02:00
636fa38ab6 - Enables check for writable export file 2016-02-16 17:35:20 -05:00
9b1503dc7a Fixed reported issues + refactoring
- refactored Config/Hooks to make it more readable
- added hook to save limit per page
- added default limit per page as a constant in Listing/Handler
2016-02-16 16:33:20 +01:00
2ac3b00af6 Merge pull request #354 from mailpoet/parsley_firefox_fix
fixed parsley issue with firefox
2016-02-16 12:32:29 +02:00
5fcdbfe826 fixed parsley issue with firefox 2016-02-15 21:19:21 +01:00
67036ddb61 cleanup and bugfix on bulk actions 2016-02-15 15:50:47 +01:00
6c0f6a07cd removed useless constant 2016-02-15 15:40:21 +01:00
8139a7dd0a Subscribers page review
- added screen option to set number of items per page
- improved bulk actions in order to handle large sets
2016-02-15 15:40:21 +01:00
97adfc14c0 Bump up version to 0.0.16 2016-02-15 14:50:13 +02:00
4ed703a351 Merge pull request #352 from mailpoet/exception_fix
Fixes remaining exception namescape issues
2016-02-15 13:39:18 +02:00
2aee853406 - Fixes remaining exception namescape issues 2016-02-13 21:39:55 -05:00
854736fac7 - Updates error messages 2016-02-12 14:12:14 -05:00
841c69af59 Merge pull request #348 from mailpoet/page_reviews
Page reviews
2016-02-12 13:36:47 -05:00
56b4688f93 updated unit tests for segments 2016-02-12 19:29:30 +01:00
e60bc7c387 handle duplicates in model 2016-02-12 19:24:04 +01:00
6094a83f4b Merge pull request #350 from mailpoet/rendering_engine_image_update
Updates logic behind image dimensions based on column width
2016-02-12 19:14:49 +02:00
91ddb98f56 Merge pull request #349 from mailpoet/exception_namescape_fix
Fixes namespace issue when catching exceptions
2016-02-12 19:11:25 +02:00
27d5972306 - Updates logic behind image dimensions based on column width 2016-02-12 12:05:27 -05:00
6088497433 Bump up release version to 0.0.15 2016-02-12 18:25:12 +02:00
0d894a6fef - Fixes namespace issue when catching exceptions 2016-02-12 11:20:43 -05:00
57f0b88299 Merge pull request #347 from mailpoet/sending_frequency
Implements sending frequency
2016-02-12 14:23:22 +02:00
5121dbe0c8 Form Editor Round 3
- added prefix to form styles so that it does not conflict when multiple forms are on the same page
- added validation on form save for segments
2016-02-12 12:45:07 +01:00
f874ffc19c Merge pull request #346 from mailpoet/rendering_engine_image_update
Updates image rendering & unit test
2016-02-12 12:42:49 +02:00
e928a5c2bc Segments page review
- remove edit link for WordPress users list
- hide trashed segments from Import
- fixed display issue in listing's item actions
2016-02-12 11:30:08 +01:00
d11badf3ce - Implements sending frequency
- Updates sending queue worker
2016-02-11 22:46:45 -05:00
3006c982cb - Updates image rendering & unit test 2016-02-11 21:28:43 -05:00
b29e31fdd6 Merge pull request #344 from mailpoet/router_update_sending_queue
Sending queue router update
2016-02-11 11:31:49 -05:00
bc42c8e280 Merge branch 'router_update_sending_queue' of mailpoet:mailpoet/mailpoet into router_update_sending_queue 2016-02-11 11:30:08 -05:00
409697ee64 Sending queue router update
- cleaned up useless code
- bugfixes
- improved code coverage
2016-02-11 11:30:01 -05:00
cfb4265971 Merge pull request #343 from mailpoet/queue_worker_rewrite
Sending queue worker rewrite
2016-02-11 18:16:07 +02:00
13d78aac05 Merge branch 'queue_worker_rewrite' of mailpoet:mailpoet/mailpoet into queue_worker_rewrite 2016-02-11 10:37:26 -05:00
6f176f4e6c - Updates MailChimp unit test 2016-02-11 10:34:24 -05:00
9b584296a5 - Updates queue worker based on code review comments 2016-02-11 10:23:41 -05:00
5ea87c5eed Sending queue router update
- cleaned up useless code
- bugfixes
- improved code coverage
2016-02-11 09:37:53 +01:00
7522084ccb - Rewrites sending queue worker and updates router
- Implements batch sending for queue worker
- Fixes mailer class issue when sender data can be empty
- Updates values for cron execution timeout/limit
2016-02-10 22:34:54 -05:00
214aa60d0e Merge pull request #338 from mailpoet/editor_polishing_2
Change `padded` image attribute to `fullWidth`
2016-02-10 22:34:36 -05:00
7a049ce1b7 - Rewrites sending queue worker and updates router
- Implements batch sending for queue worker
- Fixes mailer class issue when sender data can be empty
- Updates values for cron execution timeout/limit
2016-02-10 22:32:39 -05:00
94d293deb7 Merge pull request #339 from mailpoet/mailchimp_update
Updates MailChimp class and unit test
2016-02-09 18:04:43 +01:00
bd2d38d757 updated MP.Notice in order to handle arrays as error messages 2016-02-09 17:58:40 +01:00
abec524daa Merge pull request #340 from mailpoet/fix_registration_in_comments
Subscribe in comments
2016-02-09 18:41:58 +02:00
cac6beb4ac - Fixes display of error messages 2016-02-09 11:26:00 -05:00
cac995e15b fixed subscribe in comments 2016-02-09 16:55:00 +01:00
b26380fd10 - Updates MailChimp class and unit test 2016-02-09 10:03:29 -05:00
6c6a4070be Remove obsolete attribute from server response 2016-02-09 15:47:56 +02:00
8b001d820b Change padded image attribute to fullWidth 2016-02-09 15:26:06 +02:00
2ae3d8ebdf Merge pull request #337 from mailpoet/fix_listing_pagination
Pagination issues
2016-02-09 12:23:39 +02:00
459ec21f9d fixed pagination issues 2016-02-08 17:11:11 +01:00
9c7790d07e Merge pull request #336 from mailpoet/listing_empty_trash
Listing update + Unit tests
2016-02-08 16:01:42 +02:00
f9c5b99e46 updated Subscriber:: -> self:: in Models\Subscriber 2016-02-08 14:43:59 +01:00
95b0b39366 Fixed bulk_action success messages
- uptaded Subscriber & Segment routers' test
- moved add/remove segments logic to Subscriber::createOrUpdate
- fixed Router\Segments save not returning errors
2016-02-08 13:36:35 +01:00
4b6fa0e760 Added "Subscribers without a segment" filter
- removed useless dependency in filters.jsx
- fixed issue with Router\Subscribers::save() not updating segments
2016-02-08 10:32:06 +01:00
67a3440ced updated router unit tests - refactor + test bulk delete 2016-02-08 10:10:43 +01:00
0de372344a fixed bulkDelete 2016-02-06 15:17:19 +01:00
7a04eeb650 Listing: Empty trash button 2016-02-06 15:15:07 +01:00
126 changed files with 1904 additions and 1439 deletions

View File

@ -108,11 +108,12 @@ class RoboFile extends \Robo\Tasks {
$this->_exec('vendor/bin/codecept run unit -f '.(($file) ? $file : '')); $this->_exec('vendor/bin/codecept run unit -f '.(($file) ? $file : ''));
} }
function testCoverage() { function testCoverage($file = null) {
$this->loadEnv(); $this->loadEnv();
$this->_exec('vendor/bin/codecept build'); $this->_exec('vendor/bin/codecept build');
$this->_exec(join(' ', array( $this->_exec(join(' ', array(
'vendor/bin/codecept run', 'vendor/bin/codecept run',
(($file) ? $file : ''),
'--coverage', '--coverage',
'--coverage-html' '--coverage-html'
))); )));

View File

@ -38,9 +38,7 @@
content: '\f142' content: '\f142'
.mailpoet_save_show_options_icon .mailpoet_save_show_options_icon
width: auto vertical-align: middle
height: auto
line-height: auto
&::before &::before
content: '\f140' content: '\f140'

View File

@ -21,3 +21,9 @@
.mailpoet_automated_latest_content_display_options .mailpoet_automated_latest_content_display_options
animation-slide-open-downwards() animation-slide-open-downwards()
.mailpoet_automated_latest_content_show_amount
width: 25px
.mailpoet_automated_latest_content_content_type
width: 180px

View File

@ -11,9 +11,6 @@
padding-right: 0 padding-right: 0
margin-bottom: 0 margin-bottom: 0
img
width: 100%
.mailpoet_content a:hover .mailpoet_content a:hover
cursor: all-scroll cursor: all-scroll

View File

@ -133,3 +133,17 @@ body
.wrap > .mailpoet_notice, .wrap > .mailpoet_notice,
.update-nag .update-nag
margin-left: 2px + 15px !important margin-left: 2px + 15px !important
/* Make a button group */
.mailpoet_button_group
.button:first-child
border-right: 0
border-top-right-radius: 0
border-bottom-right-radius: 0
.button:last-child
border-left: 0
border-top-left-radius: 0
border-bottom-left-radius: 0

View File

@ -10,10 +10,13 @@ function(
return this.props.onValueChange(e); return this.props.onValueChange(e);
}, },
render: function() { render: function() {
const isChecked = !!(this.props.item[this.props.field.name]); if (this.props.field.values === undefined) {
return false;
}
const isChecked = !!(this.props.item[this.props.field.name]);
const options = Object.keys(this.props.field.values).map( const options = Object.keys(this.props.field.values).map(
function(value, index) { (value, index) => {
return ( return (
<p key={ 'checkbox-' + index }> <p key={ 'checkbox-' + index }>
<label> <label>
@ -29,7 +32,7 @@ function(
</label> </label>
</p> </p>
); );
}.bind(this) }
); );
return ( return (

View File

@ -4,12 +4,15 @@ define([
function( function(
React React
) { ) {
var FormFieldRadio = React.createClass({ const FormFieldRadio = React.createClass({
render: function() { render: function() {
var selected_value = this.props.item[this.props.field.name]; if (this.props.field.values === undefined) {
return false;
}
var options = Object.keys(this.props.field.values).map( const selected_value = this.props.item[this.props.field.name];
function(value, index) { const options = Object.keys(this.props.field.values).map(
(value, index) => {
return ( return (
<p key={ 'radio-' + index }> <p key={ 'radio-' + index }>
<label> <label>
@ -23,7 +26,7 @@ function(
</label> </label>
</p> </p>
); );
}.bind(this) }
); );
return ( return (

View File

@ -4,10 +4,14 @@ define([
function( function(
React React
) { ) {
var FormFieldSelect = React.createClass({ const FormFieldSelect = React.createClass({
render: function() { render: function() {
var options = if (this.props.field.values === undefined) {
Object.keys(this.props.field.values).map(function(value, index) { return false;
}
const options = Object.keys(this.props.field.values).map(
(value, index) => {
return ( return (
<option <option
key={ 'option-' + index } key={ 'option-' + index }
@ -15,7 +19,7 @@ function(
{ this.props.field.values[value] } { this.props.field.values[value] }
</option> </option>
); );
}.bind(this) }
); );
return ( return (

View File

@ -25,58 +25,49 @@ const columns = [
const messages = { const messages = {
onTrash: function(response) { onTrash: function(response) {
if(response) { var count = ~~response;
let message = null; var message = null;
if(~~response === 1) {
message = (
'1 form was moved to the trash.'
);
} else if(~~response > 1) {
message = (
'%$1d forms were moved to the trash.'
).replace('%$1d', ~~response);
}
if(message !== null) { if(count === 1) {
MailPoet.Notice.success(message); message = (
} '1 form was moved to the trash.'
);
} else {
message = (
'%$1d forms were moved to the trash.'
).replace('%$1d', count);
} }
MailPoet.Notice.success(message);
}, },
onDelete: function(response) { onDelete: function(response) {
if(response) { var count = ~~response;
let message = null; var message = null;
if(~~response === 1) {
message = (
'1 form was permanently deleted.'
);
} else if(~~response > 1) {
message = (
'%$1d forms were permanently deleted.'
).replace('%$1d', ~~response);
}
if(message !== null) { if(count === 1) {
MailPoet.Notice.success(message); message = (
} '1 form was permanently deleted.'
);
} else {
message = (
'%$1d forms were permanently deleted.'
).replace('%$1d', count);
} }
MailPoet.Notice.success(message);
}, },
onRestore: function(response) { onRestore: function(response) {
if(response) { var count = ~~response;
let message = null; var message = null;
if(~~response === 1) {
message = (
'1 form has been restored from the trash.'
);
} else if(~~response > 1) {
message = (
'%$1d forms have been restored from the trash.'
).replace('%$1d', ~~response);
}
if(message !== null) { if(count === 1) {
MailPoet.Notice.success(message); message = (
} '1 form has been restored from the trash.'
);
} else {
message = (
'%$1d forms have been restored from the trash.'
).replace('%$1d', count);
} }
MailPoet.Notice.success(message);
} }
}; };

View File

@ -14,6 +14,9 @@ function(
}) })
return this.props.onSelectFilter(filters); return this.props.onSelectFilter(filters);
}, },
handleEmptyTrash: function() {
return this.props.onEmptyTrash();
},
getAvailableFilters: function() { getAvailableFilters: function() {
let filters = this.props.filters; let filters = this.props.filters;
@ -34,7 +37,7 @@ function(
const available_filters = this.getAvailableFilters() const available_filters = this.getAvailableFilters()
.map(function(filter, i) { .map(function(filter, i) {
let default_value = false; let default_value = false;
if(selected_filters[filter] !== undefined && selected_filters[filter]) { if (selected_filters[filter] !== undefined && selected_filters[filter]) {
default_value = selected_filters[filter] default_value = selected_filters[filter]
} else { } else {
jQuery(`select[name="${filter}"]`).val(''); jQuery(`select[name="${filter}"]`).val('');
@ -60,9 +63,10 @@ function(
let button = false; let button = false;
if(available_filters.length > 0) { if (available_filters.length > 0) {
button = ( button = (
<input <input
id="post-query-submit"
onClick={ this.handleFilterAction } onClick={ this.handleFilterAction }
type="submit" type="submit"
defaultValue="Filter" defaultValue="Filter"
@ -70,10 +74,23 @@ function(
); );
} }
let empty_trash = false;
if (this.props.group === 'trash') {
empty_trash = (
<input
onClick={ this.handleEmptyTrash }
type="submit"
value="Empty Trash"
className="button"
/>
);
}
return ( return (
<div className="alignleft actions actions"> <div className="alignleft actions actions">
{ available_filters } { available_filters }
{ button } { button }
{ empty_trash }
</div> </div>
); );
} }

View File

@ -74,10 +74,11 @@ define(
); );
} }
var custom_actions = this.props.item_actions; const custom_actions = this.props.item_actions;
var item_actions = false; let item_actions = false;
if(custom_actions.length > 0) { if(custom_actions.length > 0) {
let is_first = true;
item_actions = custom_actions.map(function(action, index) { item_actions = custom_actions.map(function(action, index) {
if(action.display !== undefined) { if(action.display !== undefined) {
if(action.display(this.props.item) === false) { if(action.display(this.props.item) === false) {
@ -85,10 +86,12 @@ define(
} }
} }
let custom_action = null;
if(action.name === 'trash') { if(action.name === 'trash') {
return ( custom_action = (
<span key={ 'action-'+index } className="trash"> <span key={ 'action-'+index } className="trash">
{(index > 0) ? ' | ' : ''} {(!is_first) ? ' | ' : ''}
<a <a
href="javascript:;" href="javascript:;"
onClick={ this.handleTrashItem.bind( onClick={ this.handleTrashItem.bind(
@ -100,27 +103,27 @@ define(
</span> </span>
); );
} else if(action.refresh) { } else if(action.refresh) {
return ( custom_action = (
<span <span
onClick={ this.props.onRefreshItems } onClick={ this.props.onRefreshItems }
key={ 'action-'+index } className={ action.name }> key={ 'action-'+index } className={ action.name }>
{(index > 0) ? ' | ' : ''} {(!is_first) ? ' | ' : ''}
{ action.link(this.props.item) } { action.link(this.props.item) }
</span> </span>
); );
} else if(action.link) { } else if(action.link) {
return ( custom_action = (
<span <span
key={ 'action-'+index } className={ action.name }> key={ 'action-'+index } className={ action.name }>
{(index > 0) ? ' | ' : ''} {(!is_first) ? ' | ' : ''}
{ action.link(this.props.item) } { action.link(this.props.item) }
</span> </span>
); );
} else { } else {
return ( custom_action = (
<span <span
key={ 'action-'+index } className={ action.name }> key={ 'action-'+index } className={ action.name }>
{(index > 0) ? ' | ' : ''} {(!is_first) ? ' | ' : ''}
<a href="javascript:;" onClick={ <a href="javascript:;" onClick={
(action.onClick !== undefined) (action.onClick !== undefined)
? action.onClick.bind(null, ? action.onClick.bind(null,
@ -132,6 +135,12 @@ define(
</span> </span>
); );
} }
if(custom_action !== null && is_first === true) {
is_first = false;
}
return custom_action;
}.bind(this)); }.bind(this));
} else { } else {
item_actions = ( item_actions = (
@ -504,10 +513,21 @@ define(
this.getItems(); this.getItems();
}.bind(this)); }.bind(this));
}, },
handleEmptyTrash: function() {
this.handleBulkAction('all', {
action: 'delete',
group: 'trash'
}, function(response) {
MailPoet.Notice.success(
MailPoetI18n.permanentlyDeleted.replace('%d', response)
);
});
},
handleBulkAction: function(selected_ids, params, callback) { handleBulkAction: function(selected_ids, params, callback) {
if( if(
this.state.selection === false this.state.selection === false
&& this.state.selected_ids.length === 0 && this.state.selected_ids.length === 0
&& selected_ids !== 'all'
) { ) {
return; return;
} }
@ -520,8 +540,10 @@ define(
limit: 0, limit: 0,
filter: this.state.filter, filter: this.state.filter,
group: this.state.group, group: this.state.group,
search: this.state.search, search: this.state.search
selection: selected_ids }
if(selected_ids !== 'all') {
data.listing.selection = selected_ids;
} }
MailPoet.Ajax.post({ MailPoet.Ajax.post({
@ -715,7 +737,10 @@ define(
<ListingFilters <ListingFilters
filters={ this.state.filters } filters={ this.state.filters }
filter={ this.state.filter } filter={ this.state.filter }
onSelectFilter={ this.handleFilter } /> group={ this.state.group }
onSelectFilter={ this.handleFilter }
onEmptyTrash={ this.handleEmptyTrash }
/>
<ListingPages <ListingPages
count={ this.state.count } count={ this.state.count }
page={ this.state.page } page={ this.state.page }

View File

@ -7,7 +7,11 @@ define(['react', 'classnames'], function(React, classNames) {
} }
}, },
setPage: function(page) { setPage: function(page) {
this.props.onSetPage(page); this.setState({
page: null
}, function () {
this.props.onSetPage(this.constrainPage(page));
}.bind(this));
}, },
setFirstPage: function() { setFirstPage: function() {
this.setPage(1); this.setPage(1);
@ -16,10 +20,14 @@ define(['react', 'classnames'], function(React, classNames) {
this.setPage(this.getLastPage()); this.setPage(this.getLastPage());
}, },
setPreviousPage: function() { setPreviousPage: function() {
this.setPage(this.constrainPage(this.props.page - 1)); this.setPage(this.constrainPage(
parseInt(this.props.page, 10) - 1)
);
}, },
setNextPage: function() { setNextPage: function() {
this.setPage(this.constrainPage(this.props.page + 1)); this.setPage(this.constrainPage(
parseInt(this.props.page, 10) + 1)
);
}, },
constrainPage: function(page) { constrainPage: function(page) {
return Math.min(Math.max(1, Math.abs(~~page)), this.getLastPage()); return Math.min(Math.max(1, Math.abs(~~page)), this.getLastPage());
@ -27,14 +35,16 @@ define(['react', 'classnames'], function(React, classNames) {
handleSetManualPage: function(e) { handleSetManualPage: function(e) {
if(e.which === 13) { if(e.which === 13) {
this.setPage(this.state.page); this.setPage(this.state.page);
this.setState({ page: null });
} }
}, },
handleChangeManualPage: function(e) { handleChangeManualPage: function(e) {
this.setState({ this.setState({
page: this.constrainPage(e.target.value) page: e.target.value
}); });
}, },
handleBlurManualPage: function(e) {
this.setPage(e.target.value);
},
getLastPage: function() { getLastPage: function() {
return Math.ceil(this.props.count / this.props.limit); return Math.ceil(this.props.count / this.props.limit);
}, },
@ -101,6 +111,11 @@ define(['react', 'classnames'], function(React, classNames) {
); );
} }
let pageValue = this.props.page;
if(this.state.page !== null) {
pageValue = this.state.page;
}
pagination = ( pagination = (
<span className="pagination-links"> <span className="pagination-links">
{firstPage} {firstPage}
@ -115,10 +130,11 @@ define(['react', 'classnames'], function(React, classNames) {
type="text" type="text"
onChange={ this.handleChangeManualPage } onChange={ this.handleChangeManualPage }
onKeyUp={ this.handleSetManualPage } onKeyUp={ this.handleSetManualPage }
onBlur={ this.handleBlurManualPage }
aria-describedby="table-paging" aria-describedby="table-paging"
size="1" size="1"
ref="page" ref="page"
value={ this.state.page || this.props.page } value={ pageValue }
name="paged" name="paged"
id="current-page-selector" id="current-page-selector"
className="current-page" /> className="current-page" />

View File

@ -35,7 +35,7 @@ define([
titlePosition: 'inTextBlock', // 'inTextBlock'|'aboveBlock', titlePosition: 'inTextBlock', // 'inTextBlock'|'aboveBlock',
titleAlignment: 'left', // 'left'|'center'|'right' titleAlignment: 'left', // 'left'|'center'|'right'
titleIsLink: false, // false|true titleIsLink: false, // false|true
imagePadded: true, // true|false imageFullWidth: false, // true|false
//imageAlignment: 'centerPadded', // 'centerFull'|'centerPadded'|'left'|'right'|'alternate'|'none' //imageAlignment: 'centerPadded', // 'centerFull'|'centerPadded'|'left'|'right'|'alternate'|'none'
showAuthor: 'no', // 'no'|'aboveText'|'belowText' showAuthor: 'no', // 'no'|'aboveText'|'belowText'
authorPrecededBy: 'Author:', authorPrecededBy: 'Author:',
@ -63,7 +63,7 @@ define([
initialize: function() { initialize: function() {
base.BlockView.prototype.initialize.apply(this, arguments); base.BlockView.prototype.initialize.apply(this, arguments);
this.fetchPosts(); 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.on('change:amount change:contentType change:terms change:inclusionType change:displayType change:titleFormat change:titlePosition change:titleAlignment change:titleIsLink change:imageFullWidth 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); this.listenTo(this.get('readMoreButton'), 'change', this._scheduleFetchPosts);
this.listenTo(this.get('divider'), 'change', this._scheduleFetchPosts); this.listenTo(this.get('divider'), 'change', this._scheduleFetchPosts);
}, },
@ -144,7 +144,7 @@ define([
"change .mailpoet_automated_latest_content_include_or_exclude": _.partial(this.changeField, "inclusionType"), "change .mailpoet_automated_latest_content_include_or_exclude": _.partial(this.changeField, "inclusionType"),
"change .mailpoet_automated_latest_content_title_position": _.partial(this.changeField, "titlePosition"), "change .mailpoet_automated_latest_content_title_position": _.partial(this.changeField, "titlePosition"),
"change .mailpoet_automated_latest_content_title_alignment": _.partial(this.changeField, "titleAlignment"), "change .mailpoet_automated_latest_content_title_alignment": _.partial(this.changeField, "titleAlignment"),
"change .mailpoet_automated_latest_content_image_padded": _.partial(this.changeBoolField, "imagePadded"), "change .mailpoet_automated_latest_content_image_full_width": _.partial(this.changeBoolField, "imageFullWidth"),
"change .mailpoet_automated_latest_content_show_author": _.partial(this.changeField, "showAuthor"), "change .mailpoet_automated_latest_content_show_author": _.partial(this.changeField, "showAuthor"),
"keyup .mailpoet_automated_latest_content_author_preceded_by": _.partial(this.changeField, "authorPrecededBy"), "keyup .mailpoet_automated_latest_content_author_preceded_by": _.partial(this.changeField, "authorPrecededBy"),
"change .mailpoet_automated_latest_content_show_categories": _.partial(this.changeField, "showCategories"), "change .mailpoet_automated_latest_content_show_categories": _.partial(this.changeField, "showCategories"),

View File

@ -32,6 +32,7 @@ define([
fontColor: '#000000', fontColor: '#000000',
fontFamily: 'Arial', fontFamily: 'Arial',
fontSize: '16px', fontSize: '16px',
fontWeight: 'normal', // 'normal'|'bold'
textAlign: 'center', textAlign: 'center',
}, },
}, },
@ -72,6 +73,7 @@ define([
"change .mailpoet_field_button_font_size": _.partial(this.changeField, "styles.block.fontSize"), "change .mailpoet_field_button_font_size": _.partial(this.changeField, "styles.block.fontSize"),
"change .mailpoet_field_button_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"), "change .mailpoet_field_button_background_color": _.partial(this.changeColorField, "styles.block.backgroundColor"),
"change .mailpoet_field_button_border_color": _.partial(this.changeColorField, "styles.block.borderColor"), "change .mailpoet_field_button_border_color": _.partial(this.changeColorField, "styles.block.borderColor"),
"change .mailpoet_field_button_font_weight": "changeFontWeight",
"input .mailpoet_field_button_border_width": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width_input', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)), "input .mailpoet_field_button_border_width": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width_input', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)),
"change .mailpoet_field_button_border_width": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width_input', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)), "change .mailpoet_field_button_border_width": _.partial(this.updateValueAndCall, '.mailpoet_field_button_border_width_input', _.partial(this.changePixelField, "styles.block.borderWidth").bind(this)),
@ -128,6 +130,13 @@ define([
this.$(fieldToUpdate).val(jQuery(event.target).val()); this.$(fieldToUpdate).val(jQuery(event.target).val());
callable(event); callable(event);
}, },
changeFontWeight: function(event) {
var checked = !!jQuery(event.target).prop('checked');
this.model.set(
'styles.block.fontWeight',
(checked) ? jQuery(event.target).val() : 'normal'
);
}
}); });
Module.ButtonWidgetView = base.WidgetView.extend({ Module.ButtonWidgetView = base.WidgetView.extend({

View File

@ -60,11 +60,9 @@ define([
valid_elements: "p[class|style],span[class|style],a[href|class|title|target|style],strong[class|style],em[class|style],strike,br", valid_elements: "p[class|style],span[class|style],a[href|class|title|target|style],strong[class|style],em[class|style],strike,br",
invalid_elements: "script", invalid_elements: "script",
style_formats: [ block_formats: 'Paragraph=p',
{title: 'Paragraph', block: 'p'},
],
plugins: "link textcolor mailpoet_custom_fields", plugins: "link textcolor colorpicker mailpoet_custom_fields",
setup: function(editor) { setup: function(editor) {
editor.on('change', function(e) { editor.on('change', function(e) {

View File

@ -60,11 +60,9 @@ define([
valid_elements: "p[class|style],span[class|style],a[href|class|title|target|style],strong[class|style],em[class|style],strike,br", valid_elements: "p[class|style],span[class|style],a[href|class|title|target|style],strong[class|style],em[class|style],strike,br",
invalid_elements: "script", invalid_elements: "script",
style_formats: [ block_formats: 'Paragraph=p',
{title: 'Paragraph', block: 'p'},
],
plugins: "link textcolor mailpoet_custom_fields", plugins: "link textcolor colorpicker mailpoet_custom_fields",
setup: function(editor) { setup: function(editor) {
editor.on('change', function(e) { editor.on('change', function(e) {

View File

@ -20,7 +20,7 @@ define([
link: 'http://example.org', link: 'http://example.org',
src: 'no-image.png', src: 'no-image.png',
alt: 'An image of...', alt: 'An image of...',
padded: true, // true | false - Padded or full width fullWidth: true, // true | false
width: '64px', width: '64px',
height: '64px', height: '64px',
styles: { styles: {
@ -45,10 +45,10 @@ define([
this.toolsView = new Module.ImageBlockToolsView({ model: this.model }); this.toolsView = new Module.ImageBlockToolsView({ model: this.model });
this.toolsRegion.show(this.toolsView); this.toolsRegion.show(this.toolsView);
if (this.model.get('padded')) { if (this.model.get('fullWidth')) {
this.$el.removeClass('mailpoet_full_image');
} else {
this.$el.addClass('mailpoet_full_image'); this.$el.addClass('mailpoet_full_image');
} else {
this.$el.removeClass('mailpoet_full_image');
} }
}, },
}); });
@ -64,7 +64,7 @@ define([
"keyup .mailpoet_field_image_link": _.partial(this.changeField, "link"), "keyup .mailpoet_field_image_link": _.partial(this.changeField, "link"),
"keyup .mailpoet_field_image_address": _.partial(this.changeField, "src"), "keyup .mailpoet_field_image_address": _.partial(this.changeField, "src"),
"keyup .mailpoet_field_image_alt_text": _.partial(this.changeField, "alt"), "keyup .mailpoet_field_image_alt_text": _.partial(this.changeField, "alt"),
"change .mailpoet_field_image_padded": _.partial(this.changeBoolCheckboxField, "padded"), "change .mailpoet_field_image_full_width": _.partial(this.changeBoolCheckboxField, "fullWidth"),
"change .mailpoet_field_image_alignment": _.partial(this.changeField, "styles.block.textAlign"), "change .mailpoet_field_image_alignment": _.partial(this.changeField, "styles.block.textAlign"),
"click .mailpoet_field_image_select_another_image": "showMediaManager", "click .mailpoet_field_image_select_another_image": "showMediaManager",
"click .mailpoet_done_editing": "close", "click .mailpoet_done_editing": "close",

View File

@ -46,7 +46,7 @@ define([
titlePosition: 'inTextBlock', // 'inTextBlock'|'aboveBlock', titlePosition: 'inTextBlock', // 'inTextBlock'|'aboveBlock',
titleAlignment: 'left', // 'left'|'center'|'right' titleAlignment: 'left', // 'left'|'center'|'right'
titleIsLink: false, // false|true titleIsLink: false, // false|true
imagePadded: true, // true|false imageFullWidth: false, // true|false
//imageAlignment: 'centerPadded', // 'centerFull'|'centerPadded'|'left'|'right'|'alternate'|'none' //imageAlignment: 'centerPadded', // 'centerFull'|'centerPadded'|'left'|'right'|'alternate'|'none'
showAuthor: 'no', // 'no'|'aboveText'|'belowText' showAuthor: 'no', // 'no'|'aboveText'|'belowText'
authorPrecededBy: 'Author:', authorPrecededBy: 'Author:',
@ -88,7 +88,7 @@ define([
this.on('change:amount change:contentType change:terms change:inclusionType change:postStatus change:search change:sortBy', refreshAvailablePosts); this.on('change:amount change:contentType change:terms change:inclusionType change:postStatus change:search change:sortBy', refreshAvailablePosts);
this.listenTo(this.get('_selectedPosts'), 'add remove reset', refreshTransformedPosts); this.listenTo(this.get('_selectedPosts'), 'add remove reset', refreshTransformedPosts);
this.on('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:showDivider', refreshTransformedPosts); this.on('change:displayType change:titleFormat change:titlePosition change:titleAlignment change:titleIsLink change:imageFullWidth change:showAuthor change:authorPrecededBy change:showCategories change:categoriesPrecededBy change:readMoreType change:readMoreText change:showDivider', refreshTransformedPosts);
this.listenTo(this.get('readMoreButton'), 'change', refreshTransformedPosts); this.listenTo(this.get('readMoreButton'), 'change', refreshTransformedPosts);
this.listenTo(this.get('divider'), 'change', refreshTransformedPosts); this.listenTo(this.get('divider'), 'change', refreshTransformedPosts);
@ -111,7 +111,7 @@ define([
data.posts = this.get('_selectedPosts').pluck('ID'); data.posts = this.get('_selectedPosts').pluck('ID');
if (data.posts.length === 0) { if (data.posts.length === 0) {
this.get('_transformedPosts.blocks').reset(); this.get('_transformedPosts').get('blocks').reset();
return; return;
} }
@ -396,7 +396,7 @@ define([
"change .mailpoet_posts_include_or_exclude": _.partial(this.changeField, "inclusionType"), "change .mailpoet_posts_include_or_exclude": _.partial(this.changeField, "inclusionType"),
"change .mailpoet_posts_title_position": _.partial(this.changeField, "titlePosition"), "change .mailpoet_posts_title_position": _.partial(this.changeField, "titlePosition"),
"change .mailpoet_posts_title_alignment": _.partial(this.changeField, "titleAlignment"), "change .mailpoet_posts_title_alignment": _.partial(this.changeField, "titleAlignment"),
"change .mailpoet_posts_image_padded": _.partial(this.changeBoolField, "imagePadded"), "change .mailpoet_posts_image_full_width": _.partial(this.changeBoolField, "imageFullWidth"),
"change .mailpoet_posts_show_author": _.partial(this.changeField, "showAuthor"), "change .mailpoet_posts_show_author": _.partial(this.changeField, "showAuthor"),
"keyup .mailpoet_posts_author_preceded_by": _.partial(this.changeField, "authorPrecededBy"), "keyup .mailpoet_posts_author_preceded_by": _.partial(this.changeField, "authorPrecededBy"),
"change .mailpoet_posts_show_categories": _.partial(this.changeField, "showCategories"), "change .mailpoet_posts_show_categories": _.partial(this.changeField, "showCategories"),

View File

@ -52,21 +52,15 @@ define([
inline: true, inline: true,
menubar: false, menubar: false,
toolbar1: "styleselect bold italic forecolor | link unlink", toolbar1: "formatselect bold italic forecolor | link unlink",
toolbar2: "alignleft aligncenter alignright alignjustify | bullist numlist blockquote | code mailpoet_custom_fields", toolbar2: "alignleft aligncenter alignright alignjustify | bullist numlist blockquote | code mailpoet_custom_fields",
//forced_root_block: 'p', //forced_root_block: 'p',
valid_elements: "p[class|style],span[class|style],a[href|class|title|target|style],h1[class|style],h2[class|style],h3[class|style],ol[class|style],ul[class|style],li[class|style],strong[class|style],em[class|style],strike,br,blockquote[class|style],table[class|style],tr[class|style],th[class|style],td[class|style]", valid_elements: "p[class|style],span[class|style],a[href|class|title|target|style],h1[class|style],h2[class|style],h3[class|style],ol[class|style],ul[class|style],li[class|style],strong[class|style],em[class|style],strike,br,blockquote[class|style],table[class|style],tr[class|style],th[class|style],td[class|style]",
invalid_elements: "script", invalid_elements: "script",
style_formats: [ block_formats: 'Heading 1=h1;Heading 2=h2;Heading 3=h3;Paragraph=p',
{title: 'Heading 1', block: 'h1'},
{title: 'Heading 2', block: 'h2'},
{title: 'Heading 3', block: 'h3'},
{title: 'Paragraph', block: 'p'}, plugins: "link code textcolor colorpicker mailpoet_custom_fields",
],
plugins: "link code textcolor mailpoet_custom_fields",
setup: function(editor) { setup: function(editor) {
editor.on('change', function(e) { editor.on('change', function(e) {

View File

@ -67,7 +67,28 @@ define([
}; };
Module.getThumbnail = function(element, options) { Module.getThumbnail = function(element, options) {
return html2canvas(element, options || {}); var promise = html2canvas(element, options || {});
return promise.then(function(oldCanvas) {
// Temporary workaround for html2canvas-alpha2.
// Removes 1px left transparent border from resulting canvas.
var oldContext = oldCanvas.getContext('2d'),
newCanvas = document.createElement("canvas"),
newContext = newCanvas.getContext("2d"),
leftBorderWidth = 1;
newCanvas.width = oldCanvas.width;
newCanvas.height = oldCanvas.height;
newContext.drawImage(
oldCanvas,
leftBorderWidth, 0, oldCanvas.width - leftBorderWidth, oldCanvas.height,
0, 0, oldCanvas.width, oldCanvas.height
);
return newCanvas;
});
}; };
Module.saveTemplate = function(options) { Module.saveTemplate = function(options) {

View File

@ -225,6 +225,11 @@ define([
showPreview: function() { showPreview: function() {
var json = App.toJSON(); var json = App.toJSON();
// Stringify to enable transmission of primitive non-string value types
if (!_.isUndefined(json.body)) {
json.body = JSON.stringify(json.body);
}
MailPoet.Ajax.post({ MailPoet.Ajax.post({
endpoint: 'newsletters', endpoint: 'newsletters',
action: 'render', action: 'render',

View File

@ -43,58 +43,49 @@ define(
var messages = { var messages = {
onTrash: function(response) { onTrash: function(response) {
var count = ~~response.newsletters; var count = ~~response;
var message = null; var message = null;
if(count === 1 || response === true) { if(count === 1) {
message = ( message = (
'1 newsletter was moved to the trash.' '1 newsletter was moved to the trash.'
); );
} else if(count > 1) { } else {
message = ( message = (
'%$1d newsletters were moved to the trash.' '%$1d newsletters were moved to the trash.'
).replace('%$1d', count); ).replace('%$1d', count);
} }
MailPoet.Notice.success(message);
if(message !== null) {
MailPoet.Notice.success(message);
}
}, },
onDelete: function(response) { onDelete: function(response) {
var count = ~~response.newsletters; var count = ~~response;
var message = null; var message = null;
if(count === 1 || response === true) { if(count === 1) {
message = ( message = (
'1 newsletter was permanently deleted.' '1 newsletter was permanently deleted.'
); );
} else if(count > 1) { } else {
message = ( message = (
'%$1d newsletters were permanently deleted.' '%$1d newsletters were permanently deleted.'
).replace('%$1d', count); ).replace('%$1d', count);
} }
MailPoet.Notice.success(message);
if(message !== null) {
MailPoet.Notice.success(message);
}
}, },
onRestore: function(response) { onRestore: function(response) {
var count = ~~response.newsletters; var count = ~~response;
var message = null; var message = null;
if(count === 1 || response === true) { if(count === 1) {
message = ( message = (
'1 newsletter has been restored from the trash.' '1 newsletter has been restored from the trash.'
); );
} else if(count > 1) { } else {
message = ( message = (
'%$1d newsletters have been restored from the trash.' '%$1d newsletters have been restored from the trash.'
).replace('%$1d', count); ).replace('%$1d', count);
} }
MailPoet.Notice.success(message);
if(message !== null) {
MailPoet.Notice.success(message);
}
} }
}; };

View File

@ -26,7 +26,8 @@ define(
"Tempt them to open your email.", "Tempt them to open your email.",
type: 'text', type: 'text',
validation: { validation: {
'data-parsley-required': true 'data-parsley-required': true,
'data-parsley-required-message': 'You need to specify a subject.'
} }
}, },
{ {
@ -42,7 +43,8 @@ define(
return !!(!segment.deleted_at); return !!(!segment.deleted_at);
}, },
validation: { validation: {
'data-parsley-required': true 'data-parsley-required': true,
'data-parsley-required-message': 'You need to select a segment.'
} }
}, },
{ {
@ -107,8 +109,16 @@ define(
mixins: [ mixins: [
Router.History Router.History
], ],
componentDidMount: function() {
jQuery('#mailpoet_newsletter').parsley();
},
isValid: function() {
return jQuery('#mailpoet_newsletter').parsley().isValid();
},
handleSend: function() { handleSend: function() {
if(jQuery('#mailpoet_newsletter').parsley().validate() === true) { if(!this.isValid()) {
jQuery('#mailpoet_newsletter').parsley().validate();
} else {
MailPoet.Ajax.post({ MailPoet.Ajax.post({
endpoint: 'sendingQueue', endpoint: 'sendingQueue',
action: 'add', action: 'add',
@ -132,9 +142,7 @@ define(
); );
} else { } else {
if(response.errors) { if(response.errors) {
MailPoet.Notice.error( MailPoet.Notice.error(response.errors);
response.errors.join("<br />")
);
} else { } else {
MailPoet.Notice.error( MailPoet.Notice.error(
'An error occurred while trying to send. '+ 'An error occurred while trying to send. '+
@ -144,6 +152,7 @@ define(
} }
}.bind(this)); }.bind(this));
} }
return false;
}, },
render: function() { render: function() {
return ( return (
@ -158,6 +167,7 @@ define(
fields={ fields } fields={ fields }
params={ this.props.params } params={ this.props.params }
messages={ messages } messages={ messages }
isValid={ this.isValid }
> >
<p className="submit"> <p className="submit">
<input <input

View File

@ -24,11 +24,14 @@ define(
template.body = JSON.stringify(template.body); template.body = JSON.stringify(template.body);
} }
MailPoet.Modal.loading(true);
MailPoet.Ajax.post({ MailPoet.Ajax.post({
endpoint: 'newsletterTemplates', endpoint: 'newsletterTemplates',
action: 'save', action: 'save',
data: template data: template
}).done(function(response) { }).done(function(response) {
MailPoet.Modal.loading(false);
if(response.result === true) { if(response.result === true) {
this.props.onImport(template); this.props.onImport(template);
} else { } else {
@ -92,10 +95,13 @@ define(
getTemplates: function() { getTemplates: function() {
this.setState({ loading: true }); this.setState({ loading: true });
MailPoet.Modal.loading(true);
MailPoet.Ajax.post({ MailPoet.Ajax.post({
endpoint: 'newsletterTemplates', endpoint: 'newsletterTemplates',
action: 'getAll', action: 'getAll',
}).done(function(response) { }).done(function(response) {
MailPoet.Modal.loading(false);
if(this.isMounted()) { if(this.isMounted()) {
if(response.length === 0) { if(response.length === 0) {

View File

@ -192,21 +192,28 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
error: function(message, options) { error: function(message, options) {
this.show(jQuery.extend({}, { this.show(jQuery.extend({}, {
type: 'error', type: 'error',
message: '<p>'+message+'</p>' message: '<p>'+this.formatMessage(message)+'</p>'
}, options)); }, options));
}, },
success: function(message, options) { success: function(message, options) {
this.show(jQuery.extend({}, { this.show(jQuery.extend({}, {
type: 'success', type: 'success',
message: '<p>'+message+'</p>' message: '<p>'+this.formatMessage(message)+'</p>'
}, options)); }, options));
}, },
system: function(message, options) { system: function(message, options) {
this.show(jQuery.extend({}, { this.show(jQuery.extend({}, {
type: 'system', type: 'system',
static: true, static: true,
message: message message: '<p>'+this.formatMessage(message)+'</p>'
}, options)); }, options));
},
formatMessage: function(message) {
if(Array.isArray(message)) {
return message.join('<br />');
} else {
return message;
}
} }
}; };
}); });

View File

@ -12,7 +12,7 @@ define(
Form Form
) { ) {
var fields = [ let fields = [
{ {
name: 'name', name: 'name',
label: 'Name', label: 'Name',
@ -25,7 +25,7 @@ define(
} }
]; ];
var messages = { const messages = {
onUpdate: function() { onUpdate: function() {
MailPoet.Notice.success('Segment successfully updated!'); MailPoet.Notice.success('Segment successfully updated!');
}, },
@ -34,7 +34,7 @@ define(
} }
}; };
var SegmentForm = React.createClass({ const SegmentForm = React.createClass({
mixins: [ mixins: [
Router.History Router.History
], ],

View File

@ -42,58 +42,49 @@ var columns = [
const messages = { const messages = {
onTrash: function(response) { onTrash: function(response) {
if(response) { var count = ~~response;
let message = null; var message = null;
if(~~response === 1) {
message = (
'1 segment was moved to the trash.'
);
} else if(~~response > 1) {
message = (
'%$1d segments were moved to the trash.'
).replace('%$1d', ~~response);
}
if(message !== null) { if(count === 1) {
MailPoet.Notice.success(message); message = (
} '1 segment was moved to the trash.'
);
} else {
message = (
'%$1d segments were moved to the trash.'
).replace('%$1d', count);
} }
MailPoet.Notice.success(message);
}, },
onDelete: function(response) { onDelete: function(response) {
if(response) { var count = ~~response;
let message = null; var message = null;
if(~~response === 1) {
message = (
'1 segment was permanently deleted.'
);
} else if(~~response > 1) {
message = (
'%$1d segments were permanently deleted.'
).replace('%$1d', ~~response);
}
if(message !== null) { if(count === 1) {
MailPoet.Notice.success(message); message = (
} '1 segment was permanently deleted.'
);
} else {
message = (
'%$1d segments were permanently deleted.'
).replace('%$1d', count);
} }
MailPoet.Notice.success(message);
}, },
onRestore: function(response) { onRestore: function(response) {
if(response) { var count = ~~response;
let message = null; var message = null;
if(~~response === 1) {
message = (
'1 segment has been restored from the trash.'
);
} else if(~~response > 1) {
message = (
'%$1d segments have been restored from the trash.'
).replace('%$1d', ~~response);
}
if(message !== null) { if(count === 1) {
MailPoet.Notice.success(message); message = (
} '1 segment has been restored from the trash.'
);
} else {
message = (
'%$1d segments have been restored from the trash.'
).replace('%$1d', count);
} }
MailPoet.Notice.success(message);
} }
}; };
@ -105,6 +96,9 @@ const item_actions = [
return ( return (
<Link to={ `/edit/${item.id}` }>Edit</Link> <Link to={ `/edit/${item.id}` }>Edit</Link>
); );
},
display: function(segment) {
return (segment.type !== 'wp_users');
} }
}, },
{ {

View File

@ -148,7 +148,7 @@ define(
.done(function (response) { .done(function (response) {
MailPoet.Modal.loading(false); MailPoet.Modal.loading(false);
if (response.result === false) { if (response.result === false) {
MailPoet.Notice.error(response.error); MailPoet.Notice.error(response.errors);
} else { } else {
resultMessage = MailPoetI18n.exportMessage resultMessage = MailPoetI18n.exportMessage
.replace('%1$s', '<strong>' + response.data.totalExported + '</strong>') .replace('%1$s', '<strong>' + response.data.totalExported + '</strong>')

View File

@ -193,7 +193,7 @@ define(
}).done(function (response) { }).done(function (response) {
if (response.result === false) { if (response.result === false) {
MailPoet.Notice.hide(); MailPoet.Notice.hide();
MailPoet.Notice.error(response.error, { MailPoet.Notice.error(response.errors, {
timeout: 3000, timeout: 3000,
}); });
jQuery('.mailpoet_mailchimp-key-status') jQuery('.mailpoet_mailchimp-key-status')
@ -245,7 +245,7 @@ define(
} }
else { else {
MailPoet.Notice.hide(); MailPoet.Notice.hide();
MailPoet.Notice(response.message, { MailPoet.Notice.error(response.errors, {
timeout: 3000, timeout: 3000,
}); });
} }
@ -1082,7 +1082,7 @@ define(
}).done(function (response) { }).done(function (response) {
MailPoet.Modal.loading(false); MailPoet.Modal.loading(false);
if (response.result === false) { if (response.result === false) {
MailPoet.Notice.error(response.error, { MailPoet.Notice.error(response.errors, {
timeout: 3000, timeout: 3000,
}); });
} else { } else {

View File

@ -313,6 +313,7 @@ const SubscriberList = React.createClass({
</h2> </h2>
<Listing <Listing
limit={ mailpoet_listing_per_page }
location={ this.props.location } location={ this.props.location }
params={ this.props.params } params={ this.props.params }
endpoint="subscribers" endpoint="subscribers"

144
composer.lock generated
View File

@ -160,23 +160,23 @@
}, },
{ {
"name": "mtdowling/cron-expression", "name": "mtdowling/cron-expression",
"version": "v1.0.4", "version": "v1.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/mtdowling/cron-expression.git", "url": "https://github.com/mtdowling/cron-expression.git",
"reference": "fd92e883195e5dfa77720b1868cf084b08be4412" "reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/fd92e883195e5dfa77720b1868cf084b08be4412", "url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/c9ee7886f5a12902b225a1a12f36bb45f9ab89e5",
"reference": "fd92e883195e5dfa77720b1868cf084b08be4412", "reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.2" "php": ">=5.3.2"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "4.*" "phpunit/phpunit": "~4.0|~5.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -200,7 +200,7 @@
"cron", "cron",
"schedule" "schedule"
], ],
"time": "2015-01-11 23:07:46" "time": "2016-01-26 21:23:30"
}, },
{ {
"name": "nesbot/carbon", "name": "nesbot/carbon",
@ -547,16 +547,16 @@
}, },
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
"version": "v1.0.1", "version": "v1.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git", "url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "49ff736bd5d41f45240cec77b44967d76e0c3d25" "reference": "1289d16209491b584839022f29257ad859b8532d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/49ff736bd5d41f45240cec77b44967d76e0c3d25", "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/1289d16209491b584839022f29257ad859b8532d",
"reference": "49ff736bd5d41f45240cec77b44967d76e0c3d25", "reference": "1289d16209491b584839022f29257ad859b8532d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -568,7 +568,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.0-dev" "dev-master": "1.1-dev"
} }
}, },
"autoload": { "autoload": {
@ -602,7 +602,7 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2015-11-20 09:19:13" "time": "2016-01-20 09:13:37"
}, },
{ {
"name": "symfony/translation", "name": "symfony/translation",
@ -722,16 +722,16 @@
}, },
{ {
"name": "twig/twig", "name": "twig/twig",
"version": "v1.23.3", "version": "v1.24.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/twigphp/Twig.git", "url": "https://github.com/twigphp/Twig.git",
"reference": "ae53fc2c312fdee63773b75cb570304f85388b08" "reference": "3e5aa30ebfbafd5951fb1b01e338e1800ce7e0e8"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/ae53fc2c312fdee63773b75cb570304f85388b08", "url": "https://api.github.com/repos/twigphp/Twig/zipball/3e5aa30ebfbafd5951fb1b01e338e1800ce7e0e8",
"reference": "ae53fc2c312fdee63773b75cb570304f85388b08", "reference": "3e5aa30ebfbafd5951fb1b01e338e1800ce7e0e8",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -744,7 +744,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.23-dev" "dev-master": "1.24-dev"
} }
}, },
"autoload": { "autoload": {
@ -779,22 +779,22 @@
"keywords": [ "keywords": [
"templating" "templating"
], ],
"time": "2016-01-11 14:02:19" "time": "2016-01-25 21:22:18"
} }
], ],
"packages-dev": [ "packages-dev": [
{ {
"name": "codeception/codeception", "name": "codeception/codeception",
"version": "2.1.5", "version": "2.1.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Codeception/Codeception.git", "url": "https://github.com/Codeception/Codeception.git",
"reference": "4ee562f421fd404139dd7b73ae46d075396a4baf" "reference": "b199941f5e59d1e7fd32d78296c8ab98db873d89"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/4ee562f421fd404139dd7b73ae46d075396a4baf", "url": "https://api.github.com/repos/Codeception/Codeception/zipball/b199941f5e59d1e7fd32d78296c8ab98db873d89",
"reference": "4ee562f421fd404139dd7b73ae46d075396a4baf", "reference": "b199941f5e59d1e7fd32d78296c8ab98db873d89",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -861,7 +861,7 @@
"functional testing", "functional testing",
"unit testing" "unit testing"
], ],
"time": "2015-12-20 12:11:42" "time": "2016-02-09 22:27:48"
}, },
{ {
"name": "codeception/verify", "name": "codeception/verify",
@ -1328,22 +1328,24 @@
}, },
{ {
"name": "phpspec/prophecy", "name": "phpspec/prophecy",
"version": "v1.5.0", "version": "v1.6.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpspec/prophecy.git", "url": "https://github.com/phpspec/prophecy.git",
"reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7" "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/4745ded9307786b730d7a60df5cb5a6c43cf95f7", "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3c91bdf81797d725b14cb62906f9a4ce44235972",
"reference": "4745ded9307786b730d7a60df5cb5a6c43cf95f7", "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"doctrine/instantiator": "^1.0.2", "doctrine/instantiator": "^1.0.2",
"php": "^5.3|^7.0",
"phpdocumentor/reflection-docblock": "~2.0", "phpdocumentor/reflection-docblock": "~2.0",
"sebastian/comparator": "~1.1" "sebastian/comparator": "~1.1",
"sebastian/recursion-context": "~1.0"
}, },
"require-dev": { "require-dev": {
"phpspec/phpspec": "~2.0" "phpspec/phpspec": "~2.0"
@ -1351,7 +1353,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.4.x-dev" "dev-master": "1.5.x-dev"
} }
}, },
"autoload": { "autoload": {
@ -1384,7 +1386,7 @@
"spy", "spy",
"stub" "stub"
], ],
"time": "2015-08-13 10:07:40" "time": "2016-02-15 07:46:21"
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
@ -1628,16 +1630,16 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "4.8.21", "version": "4.8.23",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "ea76b17bced0500a28098626b84eda12dbcf119c" "reference": "6e351261f9cd33daf205a131a1ba61c6d33bd483"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ea76b17bced0500a28098626b84eda12dbcf119c", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6e351261f9cd33daf205a131a1ba61c6d33bd483",
"reference": "ea76b17bced0500a28098626b84eda12dbcf119c", "reference": "6e351261f9cd33daf205a131a1ba61c6d33bd483",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1696,7 +1698,7 @@
"testing", "testing",
"xunit" "xunit"
], ],
"time": "2015-12-12 07:45:58" "time": "2016-02-11 14:56:33"
}, },
{ {
"name": "phpunit/phpunit-mock-objects", "name": "phpunit/phpunit-mock-objects",
@ -2227,16 +2229,16 @@
}, },
{ {
"name": "symfony/browser-kit", "name": "symfony/browser-kit",
"version": "v3.0.1", "version": "v3.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/browser-kit.git", "url": "https://github.com/symfony/browser-kit.git",
"reference": "334a58c0def6dfcbe4bb57c6d2a8c06c6cc77679" "reference": "dde849a0485b70a24b36f826ed3fb95b904d80c3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/334a58c0def6dfcbe4bb57c6d2a8c06c6cc77679", "url": "https://api.github.com/repos/symfony/browser-kit/zipball/dde849a0485b70a24b36f826ed3fb95b904d80c3",
"reference": "334a58c0def6dfcbe4bb57c6d2a8c06c6cc77679", "reference": "dde849a0485b70a24b36f826ed3fb95b904d80c3",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2280,7 +2282,7 @@
], ],
"description": "Symfony BrowserKit Component", "description": "Symfony BrowserKit Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2015-12-26 13:39:53" "time": "2016-01-27 11:34:55"
}, },
{ {
"name": "symfony/config", "name": "symfony/config",
@ -2394,16 +2396,16 @@
}, },
{ {
"name": "symfony/css-selector", "name": "symfony/css-selector",
"version": "v3.0.1", "version": "v3.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/css-selector.git", "url": "https://github.com/symfony/css-selector.git",
"reference": "4613311fd46e146f506403ce2f8a0c71d402d2a3" "reference": "6605602690578496091ac20ec7a5cbd160d4dff4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/css-selector/zipball/4613311fd46e146f506403ce2f8a0c71d402d2a3", "url": "https://api.github.com/repos/symfony/css-selector/zipball/6605602690578496091ac20ec7a5cbd160d4dff4",
"reference": "4613311fd46e146f506403ce2f8a0c71d402d2a3", "reference": "6605602690578496091ac20ec7a5cbd160d4dff4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2443,20 +2445,20 @@
], ],
"description": "Symfony CssSelector Component", "description": "Symfony CssSelector Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2015-12-05 17:45:07" "time": "2016-01-27 05:14:46"
}, },
{ {
"name": "symfony/dom-crawler", "name": "symfony/dom-crawler",
"version": "v3.0.1", "version": "v3.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/dom-crawler.git", "url": "https://github.com/symfony/dom-crawler.git",
"reference": "7c622b0c9fb8bdb146d6dfa86c5f91dcbfdbc11d" "reference": "b693a9650aa004576b593ff2e91ae749dc90123d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/7c622b0c9fb8bdb146d6dfa86c5f91dcbfdbc11d", "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/b693a9650aa004576b593ff2e91ae749dc90123d",
"reference": "7c622b0c9fb8bdb146d6dfa86c5f91dcbfdbc11d", "reference": "b693a9650aa004576b593ff2e91ae749dc90123d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2499,7 +2501,7 @@
], ],
"description": "Symfony DomCrawler Component", "description": "Symfony DomCrawler Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2015-12-26 13:42:31" "time": "2016-01-25 09:56:57"
}, },
{ {
"name": "symfony/event-dispatcher", "name": "symfony/event-dispatcher",
@ -2735,16 +2737,16 @@
}, },
{ {
"name": "symfony/intl", "name": "symfony/intl",
"version": "v3.0.1", "version": "v3.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/intl.git", "url": "https://github.com/symfony/intl.git",
"reference": "9abd5cd590211c35cda87591f0dee856b7a16125" "reference": "7fa23b8f2ddd96260f0154946b69eb0f2c2ce7bc"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/intl/zipball/9abd5cd590211c35cda87591f0dee856b7a16125", "url": "https://api.github.com/repos/symfony/intl/zipball/7fa23b8f2ddd96260f0154946b69eb0f2c2ce7bc",
"reference": "9abd5cd590211c35cda87591f0dee856b7a16125", "reference": "7fa23b8f2ddd96260f0154946b69eb0f2c2ce7bc",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2806,7 +2808,7 @@
"l10n", "l10n",
"localization" "localization"
], ],
"time": "2015-12-05 11:13:14" "time": "2016-01-27 05:14:46"
}, },
{ {
"name": "symfony/options-resolver", "name": "symfony/options-resolver",
@ -2864,16 +2866,16 @@
}, },
{ {
"name": "symfony/polyfill-intl-icu", "name": "symfony/polyfill-intl-icu",
"version": "v1.0.1", "version": "v1.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-intl-icu.git", "url": "https://github.com/symfony/polyfill-intl-icu.git",
"reference": "2deb44160e1c886241c06602b12b98779f728177" "reference": "66b0bb4abda229bc073eff6bbc8f2685bdaac165"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/2deb44160e1c886241c06602b12b98779f728177", "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/66b0bb4abda229bc073eff6bbc8f2685bdaac165",
"reference": "2deb44160e1c886241c06602b12b98779f728177", "reference": "66b0bb4abda229bc073eff6bbc8f2685bdaac165",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2883,7 +2885,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.0-dev" "dev-master": "1.1-dev"
} }
}, },
"autoload": { "autoload": {
@ -2915,7 +2917,7 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2015-11-04 20:28:58" "time": "2016-01-20 09:13:37"
}, },
{ {
"name": "symfony/process", "name": "symfony/process",
@ -2968,16 +2970,16 @@
}, },
{ {
"name": "symfony/property-access", "name": "symfony/property-access",
"version": "v3.0.1", "version": "v3.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/property-access.git", "url": "https://github.com/symfony/property-access.git",
"reference": "9bb9f79ade13196fadd0b98504117f117d8221ad" "reference": "95363dbabd606e404b6c75095669993bf7ddae4b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/property-access/zipball/9bb9f79ade13196fadd0b98504117f117d8221ad", "url": "https://api.github.com/repos/symfony/property-access/zipball/95363dbabd606e404b6c75095669993bf7ddae4b",
"reference": "9bb9f79ade13196fadd0b98504117f117d8221ad", "reference": "95363dbabd606e404b6c75095669993bf7ddae4b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3024,7 +3026,7 @@
"property path", "property path",
"reflection" "reflection"
], ],
"time": "2015-12-23 08:00:11" "time": "2016-01-03 15:35:16"
}, },
{ {
"name": "symfony/routing", "name": "symfony/routing",
@ -3183,16 +3185,16 @@
}, },
{ {
"name": "symfony/yaml", "name": "symfony/yaml",
"version": "v3.0.1", "version": "v3.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/yaml.git", "url": "https://github.com/symfony/yaml.git",
"reference": "3df409958a646dad2bc5046c3fb671ee24a1a691" "reference": "3cf0709d7fe936e97bee9e954382e449003f1d9a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/3df409958a646dad2bc5046c3fb671ee24a1a691", "url": "https://api.github.com/repos/symfony/yaml/zipball/3cf0709d7fe936e97bee9e954382e449003f1d9a",
"reference": "3df409958a646dad2bc5046c3fb671ee24a1a691", "reference": "3cf0709d7fe936e97bee9e954382e449003f1d9a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3228,7 +3230,7 @@
], ],
"description": "Symfony Yaml Component", "description": "Symfony Yaml Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2015-12-26 13:39:53" "time": "2016-02-02 13:44:19"
}, },
{ {
"name": "twig/extensions", "name": "twig/extensions",

View File

@ -7,12 +7,31 @@ class Hooks {
} }
function init() { function init() {
$this->setupSubscribe();
$this->setupWPUsers();
$this->setupImageSize();
$this->setupListing();
}
function setupSubscribe() {
$subscribe = Setting::getValue('subscribe', array());
// Subscribe in comments // Subscribe in comments
if((bool)Setting::getValue('subscribe.on_comment.enabled')) { if(
add_action( isset($subscribe['on_comment']['enabled'])
'comment_form_after_fields', &&
'\MailPoet\Subscription\Comment::extendForm' (bool)$subscribe['on_comment']['enabled']
); ) {
if(is_user_logged_in()) {
add_action(
'comment_form_field_comment',
'\MailPoet\Subscription\Comment::extendLoggedInForm'
);
} else {
add_action(
'comment_form_after_fields',
'\MailPoet\Subscription\Comment::extendLoggedOutForm'
);
}
add_action( add_action(
'comment_post', 'comment_post',
@ -30,7 +49,11 @@ class Hooks {
} }
// Subscribe in registration form // Subscribe in registration form
if((bool)Setting::getValue('subscribe.on_register.enabled')) { if(
isset($subscribe['on_register']['enabled'])
&&
(bool)$subscribe['on_register']['enabled']
) {
if(is_multisite()) { if(is_multisite()) {
add_action( add_action(
'signup_extra_fields', 'signup_extra_fields',
@ -55,7 +78,9 @@ class Hooks {
); );
} }
} }
}
function setupWPUsers() {
// WP Users synchronization // WP Users synchronization
add_action( add_action(
'user_register', 'user_register',
@ -88,19 +113,35 @@ class Hooks {
'\MailPoet\Segments\WP::synchronizeUser', '\MailPoet\Segments\WP::synchronizeUser',
1 1
); );
}
function setupImageSize() {
add_filter( add_filter(
'image_size_names_choose', 'image_size_names_choose',
array( array($this, 'appendImageSize'),
$this, 10, 1
'appendImageSizes'
)
); );
} }
function appendImageSizes($sizes) { function appendImageSize($sizes) {
return array_merge($sizes, array( return array_merge($sizes, array(
'mailpoet_newsletter_max' => __('MailPoet Newsletter'), 'mailpoet_newsletter_max' => __('MailPoet Newsletter')
)); ));
} }
function setupListing() {
add_filter(
'set-screen-option',
array($this, 'setScreenOption'),
10, 3
);
}
function setScreenOption($status, $option, $value) {
if(preg_match('/^mailpoet_(.*)_per_page$/', $option)) {
return $value;
} else {
return $status;
}
}
} }

View File

@ -25,7 +25,7 @@ class Initializer {
register_activation_hook(Env::$file, array($this, 'runMigrator')); register_activation_hook(Env::$file, array($this, 'runMigrator'));
register_activation_hook(Env::$file, array($this, 'runPopulator')); register_activation_hook(Env::$file, array($this, 'runPopulator'));
add_action('init', array($this, 'setup')); add_action('plugins_loaded', array($this, 'setup'));
add_action('widgets_init', array($this, 'setupWidget')); add_action('widgets_init', array($this, 'setupWidget'));
} }
@ -56,6 +56,7 @@ class Initializer {
\ORM::configure('username', Env::$db_username); \ORM::configure('username', Env::$db_username);
\ORM::configure('password', Env::$db_password); \ORM::configure('password', Env::$db_password);
\ORM::configure('logging', WP_DEBUG); \ORM::configure('logging', WP_DEBUG);
\ORM::configure('driver_options', array( \ORM::configure('driver_options', array(
\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8', \PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET TIME_ZONE = "+00:00"' \PDO::MYSQL_ATTR_INIT_COMMAND => 'SET TIME_ZONE = "+00:00"'
@ -66,8 +67,6 @@ class Initializer {
$newsletters = Env::$db_prefix . 'newsletters'; $newsletters = Env::$db_prefix . 'newsletters';
$newsletter_templates = Env::$db_prefix . 'newsletter_templates'; $newsletter_templates = Env::$db_prefix . 'newsletter_templates';
$segments = Env::$db_prefix . 'segments'; $segments = Env::$db_prefix . 'segments';
$filters = Env::$db_prefix . 'filters';
$segment_filter = Env::$db_prefix . 'segment_filter';
$forms = Env::$db_prefix . 'forms'; $forms = Env::$db_prefix . 'forms';
$subscriber_segment = Env::$db_prefix . 'subscriber_segment'; $subscriber_segment = Env::$db_prefix . 'subscriber_segment';
$newsletter_segment = Env::$db_prefix . 'newsletter_segment'; $newsletter_segment = Env::$db_prefix . 'newsletter_segment';
@ -82,8 +81,6 @@ class Initializer {
define('MP_SETTINGS_TABLE', $settings); define('MP_SETTINGS_TABLE', $settings);
define('MP_NEWSLETTERS_TABLE', $newsletters); define('MP_NEWSLETTERS_TABLE', $newsletters);
define('MP_SEGMENTS_TABLE', $segments); define('MP_SEGMENTS_TABLE', $segments);
define('MP_FILTERS_TABLE', $filters);
define('MP_SEGMENT_FILTER_TABLE', $segment_filter);
define('MP_FORMS_TABLE', $forms); define('MP_FORMS_TABLE', $forms);
define('MP_SUBSCRIBER_SEGMENT_TABLE', $subscriber_segment); define('MP_SUBSCRIBER_SEGMENT_TABLE', $subscriber_segment);
define('MP_NEWSLETTER_TEMPLATES_TABLE', $newsletter_templates); define('MP_NEWSLETTER_TEMPLATES_TABLE', $newsletter_templates);

View File

@ -11,8 +11,7 @@ class Localizer {
function init() { function init() {
add_action( add_action(
'init', 'init',
array($this, 'setup'), array($this, 'setup')
0
); );
} }

View File

@ -13,6 +13,7 @@ use MailPoet\Settings\Pages;
use MailPoet\Subscribers\ImportExport\BootStrapMenu; use MailPoet\Subscribers\ImportExport\BootStrapMenu;
use MailPoet\Util\DKIM; use MailPoet\Util\DKIM;
use MailPoet\Util\Permissions; use MailPoet\Util\Permissions;
use MailPoet\Listing;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
@ -67,7 +68,7 @@ class Menu {
'forms' 'forms'
) )
); );
add_submenu_page( $subscribers_page = add_submenu_page(
'mailpoet', 'mailpoet',
__('Subscribers'), __('Subscribers'),
__('Subscribers'), __('Subscribers'),
@ -78,6 +79,17 @@ class Menu {
'subscribers' 'subscribers'
) )
); );
// add limit per page to screen options
add_action('load-'.$subscribers_page, function() {
add_screen_option('per_page', array(
'label' => _x(
'Number of subscribers per page',
'subscribers per page (screen options)'
),
'option' => 'mailpoet_subscribers_per_page'
));
});
add_submenu_page( add_submenu_page(
'mailpoet', 'mailpoet',
__('Segments'), __('Segments'),
@ -305,6 +317,14 @@ class Menu {
function subscribers() { function subscribers() {
$data = array(); $data = array();
// listing: limit per page
$listing_per_page = get_user_meta(
get_current_user_id(), 'mailpoet_subscribers_per_page', true
);
$data['per_page'] = (!empty($listing_per_page))
? (int)$listing_per_page
: Listing\Handler::DEFAULT_LIMIT_PER_PAGE;
$data['segments'] = Segment::findArray(); $data['segments'] = Segment::findArray();
$data['custom_fields'] = array_map(function($field) { $data['custom_fields'] = array_map(function($field) {

View File

@ -236,10 +236,7 @@ class Migrator {
'newsletter_id mediumint(9) NOT NULL,', 'newsletter_id mediumint(9) NOT NULL,',
'subscriber_id mediumint(9) NOT NULL,', 'subscriber_id mediumint(9) NOT NULL,',
'queue_id mediumint(9) NOT NULL,', 'queue_id mediumint(9) NOT NULL,',
'sent_at TIMESTAMP NOT NULL DEFAULT 0,', 'sent_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
'deleted_at TIMESTAMP NULL DEFAULT NULL,',
'PRIMARY KEY (id)', 'PRIMARY KEY (id)',
); );
return $this->sqlify(__FUNCTION__, $attributes); return $this->sqlify(__FUNCTION__, $attributes);

View File

@ -68,7 +68,7 @@ class FranksRoastHouseTemplate {
"link" => "http://www.example.com", "link" => "http://www.example.com",
"src" => $this->template_image_url . "/header-v2.jpg", "src" => $this->template_image_url . "/header-v2.jpg",
"alt" => __("Frank's Roast House"), "alt" => __("Frank's Roast House"),
"padded" => false, "fullWidth" => true,
"width" => "600px", "width" => "600px",
"height" => "220px", "height" => "220px",
"styles" => array( "styles" => array(
@ -95,7 +95,7 @@ class FranksRoastHouseTemplate {
"link" => "http://example.org", "link" => "http://example.org",
"src" => $this->template_image_url . "/coffee-grain.jpg", "src" => $this->template_image_url . "/coffee-grain.jpg",
"alt" => __("coffee-grain-3-1329675-1599x941"), "alt" => __("coffee-grain-3-1329675-1599x941"),
"padded" => true, "fullWidth" => false,
"width" => "1599px", "width" => "1599px",
"height" => "777px", "height" => "777px",
"styles" => array( "styles" => array(
@ -139,7 +139,7 @@ class FranksRoastHouseTemplate {
"link" => "http://example.org", "link" => "http://example.org",
"src" => $this->template_image_url . "/sandwich.jpg", "src" => $this->template_image_url . "/sandwich.jpg",
"alt" => "sandwich", "alt" => "sandwich",
"padded" => true, "fullWidth" => false,
"width" => "640px", "width" => "640px",
"height" => "344px", "height" => "344px",
"styles" => array( "styles" => array(
@ -168,6 +168,7 @@ class FranksRoastHouseTemplate {
"fontColor" => "#ffffff", "fontColor" => "#ffffff",
"fontFamily" => "Arial", "fontFamily" => "Arial",
"fontSize" => "14px", "fontSize" => "14px",
"fontWeight" => "normal",
"textAlign" => "center" "textAlign" => "center"
) )
) )
@ -238,7 +239,7 @@ class FranksRoastHouseTemplate {
"link" => "http://example.org", "link" => "http://example.org",
"src" => $this->template_image_url . "/map-v2.jpg", "src" => $this->template_image_url . "/map-v2.jpg",
"alt" => __("map-v2"), "alt" => __("map-v2"),
"padded" => true, "fullWidth" => false,
"width" => "636px", "width" => "636px",
"height" => "342px", "height" => "342px",
"styles" => array( "styles" => array(

View File

@ -90,7 +90,7 @@ class PostNotificationsBlankTemplate {
"link" => "http://example.org", "link" => "http://example.org",
"src" => $this->template_image_url . "/ALC-widget-icon.png", "src" => $this->template_image_url . "/ALC-widget-icon.png",
"alt" => __("ALC-widget-icon"), "alt" => __("ALC-widget-icon"),
"padded" => true, "fullWidth" => false,
"width" => "200px", "width" => "200px",
"height" => "134px", "height" => "134px",
"styles" => array( "styles" => array(
@ -325,6 +325,7 @@ class PostNotificationsBlankTemplate {
"fontColor" => "#ffffff", "fontColor" => "#ffffff",
"fontFamily" => "Arial", "fontFamily" => "Arial",
"fontSize" => "18px", "fontSize" => "18px",
"fontWeight" => "normal",
"textAlign" => "center" "textAlign" => "center"
) )
) )

View File

@ -68,7 +68,7 @@ class WelcomeTemplate {
"link" => "http://example.org", "link" => "http://example.org",
"src" => $this->template_image_url . "/logo-header.gif", "src" => $this->template_image_url . "/logo-header.gif",
"alt" => "logo-header", "alt" => "logo-header",
"padded" => true, "fullWidth" => false,
"width" => "233px", "width" => "233px",
"height" => "118px", "height" => "118px",
"styles" => array( "styles" => array(

View File

@ -7,8 +7,9 @@ use MailPoet\Util\Security;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
class CronHelper { class CronHelper {
static $daemon_execution_limit = 30; const daemon_execution_limit = 20;
static $daemon_timeout_limit = 30; const daemon_execution_timeout = 35;
const daemon_request_timeout = 2;
static function createDaemon($token) { static function createDaemon($token) {
$daemon = array( $daemon = array(
@ -36,12 +37,12 @@ class CronHelper {
return Security::generateRandomString(); return Security::generateRandomString();
} }
static function accessDaemon($token) { static function accessDaemon($token, $timeout = self::daemon_request_timeout) {
$payload = serialize(array('token' => $token)); $payload = serialize(array('token' => $token));
$url = '/?mailpoet-api&section=queue&action=run&request_payload=' . $url = '/?mailpoet-api&section=queue&action=run&request_payload=' .
base64_encode($payload); base64_encode($payload);
$args = array( $args = array(
'timeout' => 1, 'timeout' => $timeout,
'user-agent' => 'MailPoet (www.mailpoet.com) Cron' 'user-agent' => 'MailPoet (www.mailpoet.com) Cron'
); );
$result = wp_remote_get( $result = wp_remote_get(

View File

@ -11,6 +11,7 @@ class Daemon {
public $daemon; public $daemon;
public $request_payload; public $request_payload;
public $refreshed_token; public $refreshed_token;
const daemon_request_timeout = 5;
private $timer; private $timer;
function __construct($request_payload = array()) { function __construct($request_payload = array()) {
@ -36,11 +37,11 @@ class Daemon {
try { try {
$sending_queue = new SendingQueue($this->timer); $sending_queue = new SendingQueue($this->timer);
$sending_queue->process(); $sending_queue->process();
} catch(Exception $e) { } catch(\Exception $e) {
} }
$elapsed_time = microtime(true) - $this->timer; $elapsed_time = microtime(true) - $this->timer;
if($elapsed_time < CronHelper::$daemon_execution_limit) { if($elapsed_time < CronHelper::daemon_execution_limit) {
sleep(CronHelper::$daemon_execution_limit - $elapsed_time); sleep(CronHelper::daemon_execution_limit - $elapsed_time);
} }
// after each execution, re-read daemon data in case it was deleted or // after each execution, re-read daemon data in case it was deleted or
// its status has changed // its status has changed
@ -72,7 +73,7 @@ class Daemon {
} }
function callSelf() { function callSelf() {
CronHelper::accessDaemon($this->token); CronHelper::accessDaemon($this->token, self::daemon_request_timeout);
exit; exit;
} }
} }

View File

@ -31,13 +31,13 @@ class Supervisor {
$elapsed_time = time() - (int) $daemon['updated_at']; $elapsed_time = time() - (int) $daemon['updated_at'];
// if it's been less than 40 seconds since last execution and we're not // if it's been less than 40 seconds since last execution and we're not
// force-running the daemon, return its status and do nothing // force-running the daemon, return its status and do nothing
if($elapsed_time < CronHelper::$daemon_timeout_limit && !$this->force_run) { if($elapsed_time < CronHelper::daemon_execution_timeout && !$this->force_run) {
return $this->formatDaemonStatusMessage($daemon['status']); return $this->formatDaemonStatusMessage($daemon['status']);
} }
// if it's been less than 40 seconds since last execution, we are // if it's been less than 40 seconds since last execution, we are
// force-running the daemon and it's either being started or stopped, // force-running the daemon and it's either being started or stopped,
// return its status and do nothing // return its status and do nothing
elseif($elapsed_time < CronHelper::$daemon_timeout_limit && elseif($elapsed_time < CronHelper::daemon_execution_timeout &&
$this->force_run && $this->force_run &&
in_array($daemon['status'], array( in_array($daemon['status'], array(
'stopping', 'stopping',

View File

@ -5,125 +5,186 @@ use MailPoet\Cron\CronHelper;
use MailPoet\Mailer\Mailer; use MailPoet\Mailer\Mailer;
use MailPoet\Models\Newsletter; use MailPoet\Models\Newsletter;
use MailPoet\Models\NewsletterStatistics; use MailPoet\Models\NewsletterStatistics;
use MailPoet\Models\Setting;
use MailPoet\Models\Subscriber; use MailPoet\Models\Subscriber;
use MailPoet\Newsletter\Renderer\Renderer; use MailPoet\Newsletter\Renderer\Renderer;
use MailPoet\Newsletter\Shortcodes\Shortcodes; use MailPoet\Newsletter\Shortcodes\Shortcodes;
use MailPoet\Util\Helpers;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
class SendingQueue { class SendingQueue {
public $mta_config;
public $mta_log;
public $processing_method;
private $timer; private $timer;
const batch_size = 50;
function __construct($timer = false) { function __construct($timer = false) {
$this->mta_config = $this->getMailerConfig();
$this->mta_log = $this->getMailerLog();
$this->processing_method = ($this->mta_config['method'] === 'MailPoet') ?
'processBulkSubscribers' :
'processIndividualSubscriber';
$this->timer = ($timer) ? $timer : microtime(true); $this->timer = ($timer) ? $timer : microtime(true);
} }
function process() { function process() {
// TODO: implement mailer sending frequency limits
foreach($this->getQueues() as $queue) { foreach($this->getQueues() as $queue) {
$newsletter = Newsletter::findOne($queue->newsletter_id); $newsletter = Newsletter::findOne($queue->newsletter_id);
if(!$newsletter) { if(!$newsletter) {
continue; continue;
}; }
$queue->subscribers = (object) unserialize($queue->subscribers);
if(!isset($queue->subscribers->processed)) {
$queue->subscribers->processed = array();
}
if(!isset($queue->subscribers->failed)) {
$queue->subscribers->failed = array();
}
$newsletter = $newsletter->asArray(); $newsletter = $newsletter->asArray();
$mailer = $this->configureMailerForNewsletter($newsletter); $newsletter['body'] = $this->renderNewsletter($newsletter);
$subscribers = json_decode($queue->subscribers, true); $mailer = $this->configureMailer($newsletter);
$subscribers_to_process = $subscribers['to_process']; foreach(array_chunk($queue->subscribers->to_process, self::batch_size) as
if(!isset($subscribers['processed'])) $subscribers['processed'] = array(); $subscribers_ids) {
if(!isset($subscribers['failed'])) $subscribers['failed'] = array(); $subscribers = Subscriber::whereIn('id', $subscribers_ids)
foreach(array_chunk($subscribers_to_process, 200) as $subscriber_ids) {
$db_subscribers = Subscriber::whereIn('id', $subscriber_ids)
->findArray(); ->findArray();
foreach($db_subscribers as $db_subscriber) { $queue->subscribers = call_user_func_array(
$this->checkExecutionTimer(); array(
$result = $this->sendNewsletter( $this,
$this->processing_method
),
array(
$mailer, $mailer,
$this->processNewsletter($newsletter, $db_subscriber), $newsletter,
$db_subscriber); $subscribers,
if($result) { $queue
$this->updateStatistics($newsletter['id'], $db_subscriber['id'], $queue->id); )
$subscribers['processed'][] = $db_subscriber['id']; );
} else {
$subscribers['failed'][] = $db_subscriber['id'];
}
$this->updateQueue($queue, $subscribers);
}
} }
} }
} }
function processNewsletter($newsletter, $subscriber) { function processBulkSubscribers($mailer, $newsletter, $subscribers, $queue) {
$rendered_newsletter = $this->renderNewsletter($newsletter); foreach($subscribers as $subscriber) {
$shortcodes = new Shortcodes($rendered_newsletter['body']['html'], $newsletter, $subscriber); $processed_newsletters[] =
$processed_newsletter['body']['html'] = $shortcodes->replace(); $this->processNewsletter($newsletter, $subscriber);
$shortcodes = new Shortcodes($rendered_newsletter['body']['text'], $newsletter, $subscriber); $transformed_subscribers[] =
$processed_newsletter['body']['text'] = $shortcodes->replace(); $mailer->transformSubscriber($subscriber);
$processed_newsletter['subject'] = $rendered_newsletter['subject']; }
return $processed_newsletter; $result = $this->sendNewsletter(
$mailer,
$processed_newsletters,
$transformed_subscribers
);
$subscribers_ids = Helpers::arrayColumn($subscribers, 'id');
if(!$result) {
$queue->subscribers->failed = array_merge(
$queue->subscribers->failed,
$subscribers_ids
);
} else {
$newsletter_statistics =
array_map(function ($data) use ($newsletter, $subscribers_ids, $queue) {
return array(
$newsletter['id'],
$subscribers_ids[$data],
$queue->id
);
}, range(0, count($transformed_subscribers) - 1));
$newsletter_statistics = Helpers::flattenArray($newsletter_statistics);
$this->updateMailerLog();
$this->updateNewsletterStatistics($newsletter_statistics);
$queue->subscribers->processed = array_merge(
$queue->subscribers->processed,
$subscribers_ids
);
}
$this->updateQueue($queue);
$this->checkSendingLimit();
$this->checkExecutionTimer();
return $queue->subscribers;
}
function processIndividualSubscriber($mailer, $newsletter, $subscribers, $queue) {
foreach($subscribers as $subscriber) {
$this->checkSendingLimit();
$processed_newsletter = $this->processNewsletter($newsletter, $subscriber);
$transformed_subscriber = $mailer->transformSubscriber($subscriber);
$result = $this->sendNewsletter(
$mailer,
$processed_newsletter,
$transformed_subscriber
);
if(!$result) {
$queue->subscribers->failed[] = $subscriber['id'];;
} else {
$queue->subscribers->processed[] = $subscriber['id'];
$newsletter_statistics = array(
$newsletter['id'],
$subscriber['id'],
$queue->id
);
$this->updateMailerLog();
$this->updateNewsletterStatistics($newsletter_statistics);
}
$this->updateQueue($queue);
$this->checkExecutionTimer();
}
return $queue->subscribers;
}
function updateNewsletterStatistics($data) {
return NewsletterStatistics::createMultiple($data);
}
function renderNewsletter($newsletter) {
$renderer = new Renderer($newsletter);
return $renderer->render();
}
function processNewsletter($newsletter, $subscriber = false) {
$divider = '***MailPoet***';
$shortcodes = new Shortcodes(
implode($divider, $newsletter['body']),
$newsletter,
$subscriber
);
list($newsletter['body']['html'], $newsletter['body']['text']) =
explode($divider, $shortcodes->replace());
return $newsletter;
} }
function sendNewsletter($mailer, $newsletter, $subscriber) { function sendNewsletter($mailer, $newsletter, $subscriber) {
return $mailer->mailer_instance->send( return $mailer->mailer_instance->send(
$newsletter, $newsletter,
$mailer->transformSubscriber($subscriber) $subscriber
); );
} }
function updateStatistics($newsletter_id, $subscriber_id, $queue_id) { function configureMailer($newsletter) {
$newsletter_statistic = NewsletterStatistics::create(); $sender['address'] = (!empty($newsletter['sender_address'])) ?
$newsletter_statistic->subscriber_id = $newsletter_id; $newsletter['sender_address'] :
$newsletter_statistic->newsletter_id = $subscriber_id; false;
$newsletter_statistic->queue_id = $queue_id; $sender['name'] = (!empty($newsletter['sender_name'])) ?
$newsletter_statistic->save(); $newsletter['sender_name'] :
} false;
$reply_to['address'] = (!empty($newsletter['reply_to_address'])) ?
function updateQueue($queue, $subscribers) { $newsletter['reply_to_address'] :
$subscribers['to_process'] = array_values( false;
array_diff( $reply_to['name'] = (!empty($newsletter['reply_to_name'])) ?
$subscribers['to_process'], $newsletter['reply_to_name'] :
array_merge($subscribers['processed'], $subscribers['failed']) false;
) if(!$sender['address']) {
);
$queue->count_processed =
count($subscribers['processed']) + count($subscribers['failed']);
$queue->count_to_process = count($subscribers['to_process']);
$queue->count_failed = count($subscribers['failed']);
$queue->count_total =
$queue->count_processed + $queue->count_to_process;
if(!$queue->count_to_process) {
$queue->processed_at = date('Y-m-d H:i:s');
$queue->status = 'completed';
}
$queue->subscribers = json_encode($subscribers);
$queue->save();
}
function configureMailerForNewsletter($newsletter) {
if(!empty($newsletter['sender_address']) && !empty($newsletter['sender_name'])) {
$sender = array(
'name' => $newsletter['sender_name'],
'address' => $newsletter['sender_address']
);
} else {
$sender = false; $sender = false;
} }
if(!empty($newsletter['reply_to_address']) && !empty($newsletter['reply_to_name'])) { if(!$reply_to['address']) {
$reply_to = array(
'name' => $newsletter['reply_to_name'],
'address' => $newsletter['reply_to_address']
);
} else {
$reply_to = false; $reply_to = false;
} }
$mailer = new Mailer($method = false, $sender, $reply_to); $mailer = new Mailer($method = false, $sender, $reply_to);
return $mailer; return $mailer;
} }
function checkExecutionTimer() {
$elapsed_time = microtime(true) - $this->timer;
if($elapsed_time >= CronHelper::$daemon_execution_limit) throw new \Exception(__('Maximum execution time reached.'));
}
function getQueues() { function getQueues() {
return \MailPoet\Models\SendingQueue::orderByDesc('priority') return \MailPoet\Models\SendingQueue::orderByDesc('priority')
->whereNull('deleted_at') ->whereNull('deleted_at')
@ -131,9 +192,78 @@ class SendingQueue {
->findResultSet(); ->findResultSet();
} }
function renderNewsletter($newsletter) { function updateQueue($queue) {
$renderer = new Renderer($newsletter); $queue = clone($queue);
$newsletter['body'] = $renderer->render(); $queue->subscribers->to_process = array_diff(
return $newsletter; $queue->subscribers->to_process,
array_merge(
$queue->subscribers->processed,
$queue->subscribers->failed
)
);
$queue->subscribers->to_process = array_values($queue->subscribers->to_process);
$queue->count_processed =
count($queue->subscribers->processed) + count($queue->subscribers->failed);
$queue->count_to_process = count($queue->subscribers->to_process);
$queue->count_failed = count($queue->subscribers->failed);
$queue->count_total =
$queue->count_processed + $queue->count_to_process;
if(!$queue->count_to_process) {
$queue->processed_at = date('Y-m-d H:i:s');
$queue->status = 'completed';
}
$queue->subscribers = serialize((array) $queue->subscribers);
$queue->save();
}
function updateMailerLog() {
$this->mta_log['sent']++;
return Setting::setValue('mta_log', $this->mta_log);
}
function getMailerConfig() {
$mta_config = Setting::getValue('mta');
if(!$mta_config) {
throw new \Exception(__('Mailer is not configured.'));
}
return $mta_config;
}
function getMailerLog() {
$mta_log = Setting::getValue('mta_log');
if(!$mta_log) {
$mta_log = array(
'sent' => 0,
'started' => time()
);
Setting::setValue('mta_log', $mta_log);
}
return $mta_log;
}
function checkSendingLimit() {
$frequency_interval = (int) $this->mta_config['frequency']['interval'] * 60;
$frequency_limit = (int) $this->mta_config['frequency']['emails'];
$elapsed_time = time() - (int) $this->mta_log['started'];
if($this->mta_log['sent'] === $frequency_limit &&
$elapsed_time <= $frequency_interval
) {
throw new \Exception(__('Sending frequency limit reached.'));
}
if($elapsed_time > $frequency_interval) {
$this->mta_log = array(
'sent' => 0,
'started' => time()
);
Setting::setValue('mta_log', $this->mta_log);
}
return;
}
function checkExecutionTimer() {
$elapsed_time = microtime(true) - $this->timer;
if($elapsed_time >= CronHelper::daemon_execution_limit) {
throw new \Exception(__('Maximum execution time reached.'));
}
} }
} }

View File

@ -13,9 +13,11 @@ class Renderer {
return $html; return $html;
} }
static function renderStyles($form = array()) { static function renderStyles($form = array(), $prefix = null) {
$styles = new Util\Styles(static::getStyles($form));
$html = '<style type="text/css">'; $html = '<style type="text/css">';
$html .= static::getStyles($form); $html .= $styles->render($prefix);
$html .= '</style>'; $html .= '</style>';
return $html; return $html;

View File

@ -101,7 +101,7 @@ EOL;
} }
private function stripComments($stylesheet) { private function stripComments($stylesheet) {
// remove comments // remove comments
return preg_replace('!/\*.*?\*/!s', '', $stylesheet); return preg_replace('!/\*.*?\*/!s', '', $stylesheet);
} }
@ -111,7 +111,6 @@ EOL;
private function setStyles($styles) { private function setStyles($styles) {
$this->_styles = $styles; $this->_styles = $styles;
return $this; return $this;
} }

View File

@ -154,12 +154,14 @@ class Widget extends \WP_Widget {
$output = ''; $output = '';
if(!empty($body)) { if(!empty($body)) {
$form_id = $this->id_base.'_'.$this->number;
$data = array( $data = array(
'form_id' => $this->id_base.'_'.$this->number, 'form_id' => $form_id,
'form_type' => $form_type, 'form_type' => $form_type,
'form' => $form, 'form' => $form,
'title' => $title, 'title' => $title,
'styles' => FormRenderer::renderStyles($form), 'styles' => FormRenderer::renderStyles($form, '#'.$form_id),
'html' => FormRenderer::renderHTML($form), 'html' => FormRenderer::renderHTML($form),
'before_widget' => (!empty($before_widget) ? $before_widget : ''), 'before_widget' => (!empty($before_widget) ? $before_widget : ''),
'after_widget' => (!empty($after_widget) ? $after_widget : ''), 'after_widget' => (!empty($after_widget) ? $after_widget : ''),

View File

@ -4,6 +4,8 @@ namespace MailPoet\Listing;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
class Handler { class Handler {
const DEFAULT_LIMIT_PER_PAGE = 20;
private $data = array(); private $data = array();
private $model = null; private $model = null;
@ -14,7 +16,10 @@ class Handler {
$this->data = array( $this->data = array(
// pagination // pagination
'offset' => (isset($data['offset']) ? (int)$data['offset'] : 0), 'offset' => (isset($data['offset']) ? (int)$data['offset'] : 0),
'limit' => (isset($data['limit']) ? (int)$data['limit'] : 50), 'limit' => (isset($data['limit'])
? (int)$data['limit']
: self::DEFAULT_LIMIT_PER_PAGE
),
// searching // searching
'search' => (isset($data['search']) ? $data['search'] : null), 'search' => (isset($data['search']) ? $data['search'] : null),
// sorting // sorting

View File

@ -102,7 +102,7 @@ class Mailer {
function getSender($sender = false) { function getSender($sender = false) {
if(!$sender) { if(!$sender) {
$sender = Setting::getValue('sender', null); $sender = Setting::getValue('sender', null);
if(!$sender) throw new \Exception(__('Sender name and email are not configured.')); if(!$sender['address']) throw new \Exception(__('Sender name and email are not configured.'));
} }
return array( return array(
'from_name' => $sender['name'], 'from_name' => $sender['name'],

View File

@ -20,11 +20,9 @@ class CustomField extends Model {
$model = parent::asArray(); $model = parent::asArray();
if(isset($model['params'])) { if(isset($model['params'])) {
$model['params'] = ( $model['params'] = (is_array($this->params))
is_array($this->params)
? $this->params ? $this->params
: unserialize($this->params) : unserialize($this->params);
);
} }
return $model; return $model;
} }

View File

@ -1,16 +0,0 @@
<?php namespace MailPoet\Models;
class CustomValidator {
function __construct() {
$this->validator = new \Sudzy\Engine();
}
function init() {
$this->validator
->addValidator('isString', function ($val) {
return is_string($val);
});
return $this->validator;
}
}

View File

@ -1,50 +0,0 @@
<?php
namespace MailPoet\Models;
if(!defined('ABSPATH')) exit;
class Filter extends Model {
static $_table = MP_FILTERS_TABLE;
function __construct() {
parent::__construct();
$this->addValidations('name', array(
'required' => __('You need to specify a name.')
));
}
function delete() {
// delete all relations to subscribers
SegmentFilter::where('filter_id', $this->id)->deleteMany();
return parent::delete();
}
function segments() {
return $this->has_many_through(
__NAMESPACE__.'\Segment',
__NAMESPACE__.'\SegmentFilter',
'filter_id',
'segment_id'
);
}
static function createOrUpdate($data = array()) {
$filter = false;
if(isset($data['id']) && (int)$data['id'] > 0) {
$filter = self::findOne((int)$data['id']);
}
if($filter === false) {
$filter = self::create();
$filter->hydrate($data);
} else {
unset($data['id']);
$filter->set($data);
}
$filter->save();
return $filter;
}
}

View File

@ -17,36 +17,30 @@ class Form extends Model {
function asArray() { function asArray() {
$model = parent::asArray(); $model = parent::asArray();
$model['body'] = ( $model['body'] = (is_serialized($this->body))
is_serialized($this->body)
? unserialize($this->body) ? unserialize($this->body)
: $this->body : $this->body;
); $model['settings'] = (is_serialized($this->settings))
$model['settings'] = (
is_serialized($this->settings)
? unserialize($this->settings) ? unserialize($this->settings)
: $this->settings : $this->settings;
);
return $model; return $model;
} }
function save() { function save() {
$this->set('body', ( $this->set('body', (is_serialized($this->body))
is_serialized($this->body)
? $this->body ? $this->body
: serialize($this->body) : serialize($this->body)
)); );
$this->set('settings', ( $this->set('settings', (is_serialized($this->settings))
is_serialized($this->settings)
? $this->settings ? $this->settings
: serialize($this->settings) : serialize($this->settings)
)); );
return parent::save(); return parent::save();
} }
static function search($orm, $search = '') { static function search($orm, $search = '') {
return $orm->where_like('name', '%'.$search.'%'); return $orm->whereLike('name', '%'.$search.'%');
} }
static function groups() { static function groups() {
@ -67,9 +61,8 @@ class Form extends Model {
static function groupBy($orm, $group = null) { static function groupBy($orm, $group = null) {
if($group === 'trash') { if($group === 'trash') {
return $orm->whereNotNull('deleted_at'); return $orm->whereNotNull('deleted_at');
} else {
$orm = $orm->whereNull('deleted_at');
} }
return $orm->whereNull('deleted_at');
} }
static function createOrUpdate($data = array()) { static function createOrUpdate($data = array()) {
@ -87,7 +80,6 @@ class Form extends Model {
$form->set($data); $form->set($data);
} }
$form->save(); return $form->save();
return $form;
} }
} }

View File

@ -8,8 +8,7 @@ class Model extends \Sudzy\ValidModel {
function __construct() { function __construct() {
$this->_errors = array(); $this->_errors = array();
$customValidators = new CustomValidator(); parent::__construct();
parent::__construct($customValidators->init());
} }
static function create() { static function create() {
@ -42,7 +41,24 @@ class Model extends \Sudzy\ValidModel {
} catch(\Sudzy\ValidationException $e) { } catch(\Sudzy\ValidationException $e) {
$this->setError($e->getValidationErrors()); $this->setError($e->getValidationErrors());
} catch(\PDOException $e) { } catch(\PDOException $e) {
$this->setError($e->getMessage()); switch($e->getCode()) {
case 23000:
preg_match("/for key \'(.*?)\'/i", $e->getMessage(), $matches);
if(isset($matches[1])) {
$column = $matches[1];
$this->setError(
sprintf(
__('Another record already exists. Please specify a different "%1$s".'),
$column
)
);
} else {
$this->setError($e->getMessage());
}
break;
default:
$this->setError($e->getMessage());
}
} catch(\Exception $e) { } catch(\Exception $e) {
$this->setError($e->getMessage()); $this->setError($e->getMessage());
} }
@ -54,19 +70,23 @@ class Model extends \Sudzy\ValidModel {
} }
static function bulkTrash($orm) { static function bulkTrash($orm) {
$models = $orm->findResultSet(); $model = get_called_class();
$models->set_expr('deleted_at', 'NOW()')->save(); return self::bulkAction($orm, function($ids) use($model) {
return $models->count(); self::rawExecute(join(' ', array(
'UPDATE `'.$model::$_table.'`',
'SET `deleted_at`=NOW()',
'WHERE `id` IN ('.rtrim(str_repeat('?,', count($ids)), ',').')'
)),
$ids
);
});
} }
static function bulkDelete($orm) { static function bulkDelete($orm) {
$models = $orm->findMany(); $model = get_called_class();
$count = 0; return self::bulkAction($orm, function($ids) use($model) {
foreach($models as $model) { $model::whereIn('id', $ids)->deleteMany();
$model->delete(); });
$count++;
}
return $count;
} }
function restore() { function restore() {
@ -74,9 +94,37 @@ class Model extends \Sudzy\ValidModel {
} }
static function bulkRestore($orm) { static function bulkRestore($orm) {
$models = $orm->findResultSet(); $model = get_called_class();
$models->set_expr('deleted_at', 'NULL')->save(); return self::bulkAction($orm, function($ids) use($model) {
return $models->count(); self::rawExecute(join(' ', array(
'UPDATE `'.$model::$_table.'`',
'SET `deleted_at`=NULL',
'WHERE `id` IN ('.rtrim(str_repeat('?,', count($ids)), ',').')'
)),
$ids
);
});
}
static function bulkAction($orm, $callback = false) {
$total = $orm->count();
if($total > 0) {
$models = $orm->select('id')
->offset(null)
->limit(null)
->findArray();
$ids = array_map(function($model) {
return (int)$model['id'];
}, $models);
if(is_callable($callback)) {
$callback($ids);
}
}
return $total;
} }
function duplicate($data = array()) { function duplicate($data = array()) {

View File

@ -97,14 +97,13 @@ class Newsletter extends Model {
} }
static function filterBy($orm, $filters = null) { static function filterBy($orm, $filters = null) {
if(empty($filters)) { if(!empty($filters)) {
return $orm; foreach($filters as $key => $value) {
} if($key === 'segment') {
foreach($filters as $key => $value) { $segment = Segment::findOne($value);
if($key === 'segment') { if($segment !== false) {
$segment = Segment::findOne($value); $orm = $segment->newsletters();
if($segment !== false) { }
$orm = $segment->newsletters();
} }
} }
} }

View File

@ -9,4 +9,16 @@ class NewsletterStatistics extends Model {
function __construct() { function __construct() {
parent::__construct(); parent::__construct();
} }
static function createMultiple($data) {
return self::rawExecute(
'INSERT INTO `' . NewsletterStatistics::$_table . '` ' .
'(newsletter_id, subscriber_id, queue_id) ' .
'VALUES ' . rtrim(
str_repeat('(?,?,?), ', count($data)/3),
', '
),
$data
);
}
} }

View File

@ -122,6 +122,7 @@ class Segment extends Model {
->group_by(self::$_table.'.id') ->group_by(self::$_table.'.id')
->group_by(self::$_table.'.name') ->group_by(self::$_table.'.name')
->where(self::$_table.'.type', 'default') ->where(self::$_table.'.type', 'default')
->whereNull(self::$_table.'.deleted_at')
->findArray(); ->findArray();
} }

View File

@ -1,12 +0,0 @@
<?php
namespace MailPoet\Models;
if(!defined('ABSPATH')) exit;
class SegmentFilter extends Model {
public static $_table = MP_SEGMENT_FILTER_TABLE;
function __construct() {
parent::__construct();
}
}

View File

@ -15,7 +15,8 @@ class SendingQueue extends Model {
return false; return false;
} else { } else {
$this->set('status', 'paused'); $this->set('status', 'paused');
return $this->save(); $this->save();
return ($this->getErrors() === false && $this->id() > 0);
} }
} }
@ -24,12 +25,14 @@ class SendingQueue extends Model {
return $this->complete(); return $this->complete();
} else { } else {
$this->set_expr('status', 'NULL'); $this->set_expr('status', 'NULL');
return $this->save(); $this->save();
return ($this->getErrors() === false && $this->id() > 0);
} }
} }
function complete() { function complete() {
$this->set('status', 'completed'); $this->set('status', 'completed');
return $this->save(); $this->save();
return ($this->getErrors() === false && $this->id() > 0);
} }
} }

View File

@ -35,6 +35,9 @@ class Setting extends Model {
if($setting !== $default) { if($setting !== $default) {
for($i = 0, $count = count($keys); $i < $count; $i++) { for($i = 0, $count = count($keys); $i < $count; $i++) {
if(!is_array($setting)) {
$setting = array();
}
if(array_key_exists($keys[$i], $setting)) { if(array_key_exists($keys[$i], $setting)) {
$setting = $setting[$keys[$i]]; $setting = $setting[$keys[$i]];
} else { } else {
@ -67,13 +70,6 @@ class Setting extends Model {
$last_key = array_pop($keys); $last_key = array_pop($keys);
foreach($keys as $key) { foreach($keys as $key) {
if(!is_array($current_value)) {
$current_value = array();
}
if(!array_key_exists($key, $current_value)) {
$current_value = array($key => array());
}
$current_value =& $current_value[$key]; $current_value =& $current_value[$key];
} }
if(is_scalar($current_value)) { if(is_scalar($current_value)) {
@ -100,16 +96,20 @@ class Setting extends Model {
return $settings; return $settings;
} }
public static function createOrUpdate($model) { public static function createOrUpdate($data = array()) {
$exists = self::where('name', $model['name'])->findOne(); $setting = false;
if($exists === false) { if(isset($data['name'])) {
$new_model = self::create(); $setting = self::where('name', $data['name'])->findOne();
$new_model->hydrate($model);
return $new_model->save();
} }
$exists->value = $model['value']; if($setting === false) {
return $exists->save(); $setting = self::create();
$setting->hydrate($data);
} else {
$setting->value = $data['value'];
}
return $setting->save();
} }
} }

View File

@ -33,12 +33,26 @@ class Subscriber extends Model {
} }
function addToSegments(array $segment_ids = array()) { function addToSegments(array $segment_ids = array()) {
$segments = Segment::whereIn('id', $segment_ids)->findMany(); $wp_users_segment = Segment::getWPUsers();
foreach($segments as $segment) {
$association = SubscriberSegment::create(); if($wp_users_segment !== false) {
$association->subscriber_id = $this->id; // delete all relations to segments except WP users
$association->segment_id = $segment->id; SubscriberSegment::where('subscriber_id', $this->id)
$association->save(); ->whereNotEqual('segment_id', $wp_users_segment->id)
->deleteMany();
} else {
// delete all relations to segments
SubscriberSegment::where('subscriber_id', $this->id)->deleteMany();
}
if(!empty($segment_ids)) {
$segments = Segment::whereIn('id', $segment_ids)->findMany();
foreach($segments as $segment) {
$association = SubscriberSegment::create();
$association->subscriber_id = $this->id;
$association->segment_id = $segment->id;
$association->save();
}
} }
} }
@ -53,7 +67,7 @@ class Subscriber extends Model {
return false; return false;
} }
$subscriber = static::createOrUpdate($subscriber_data); $subscriber = self::createOrUpdate($subscriber_data);
if($subscriber !== false && $subscriber->id() > 0) { if($subscriber !== false && $subscriber->id() > 0) {
// restore deleted subscriber // restore deleted subscriber
@ -92,20 +106,25 @@ class Subscriber extends Model {
$segments = Segment::orderByAsc('name')->findMany(); $segments = Segment::orderByAsc('name')->findMany();
$segment_list = array(); $segment_list = array();
$segment_list[] = array( $segment_list[] = array(
'label' => __('All lists'), 'label' => __('All segments'),
'value' => '' 'value' => ''
); );
$segment_list[] = array(
'label' => sprintf(
__('Subscribers without a segment (%d)'),
self::filter('withoutSegments')->count()
),
'value' => 'none'
);
foreach($segments as $segment) { foreach($segments as $segment) {
$subscribers_count = $segment->subscribers() $subscribers_count = $segment->subscribers()
->whereNull('deleted_at') ->whereNull('deleted_at')
->count(); ->count();
if($subscribers_count > 0) { $segment_list[] = array(
$segment_list[] = array( 'label' => sprintf('%s (%d)', $segment->name, $subscribers_count),
'label' => sprintf('%s (%d)', $segment->name, $subscribers_count), 'value' => $segment->id()
'value' => $segment->id() );
);
}
} }
$filters = array( $filters = array(
@ -121,9 +140,13 @@ class Subscriber extends Model {
} }
foreach($filters as $key => $value) { foreach($filters as $key => $value) {
if($key === 'segment') { if($key === 'segment') {
$segment = Segment::findOne($value); if($value === 'none') {
if($segment !== false) { return self::filter('withoutSegments');
return $segment->subscribers(); } else {
$segment = Segment::findOne($value);
if($segment !== false) {
return $segment->subscribers();
}
} }
} }
} }
@ -135,27 +158,27 @@ class Subscriber extends Model {
array( array(
'name' => 'all', 'name' => 'all',
'label' => __('All'), 'label' => __('All'),
'count' => Subscriber::getPublished()->count() 'count' => self::getPublished()->count()
), ),
array( array(
'name' => 'subscribed', 'name' => 'subscribed',
'label' => __('Subscribed'), 'label' => __('Subscribed'),
'count' => Subscriber::filter('subscribed')->count() 'count' => self::filter('subscribed')->count()
), ),
array( array(
'name' => 'unconfirmed', 'name' => 'unconfirmed',
'label' => __('Unconfirmed'), 'label' => __('Unconfirmed'),
'count' => Subscriber::filter('unconfirmed')->count() 'count' => self::filter('unconfirmed')->count()
), ),
array( array(
'name' => 'unsubscribed', 'name' => 'unsubscribed',
'label' => __('Unsubscribed'), 'label' => __('Unsubscribed'),
'count' => Subscriber::filter('unsubscribed')->count() 'count' => self::filter('unsubscribed')->count()
), ),
array( array(
'name' => 'trash', 'name' => 'trash',
'label' => __('Trash'), 'label' => __('Trash'),
'count' => Subscriber::getTrashed()->count() 'count' => self::getTrashed()->count()
) )
); );
} }
@ -226,17 +249,24 @@ class Subscriber extends Model {
$subscriber = false; $subscriber = false;
if(isset($data['id']) && (int)$data['id'] > 0) { if(isset($data['id']) && (int)$data['id'] > 0) {
$subscriber = static::findOne((int)$data['id']); $subscriber = self::findOne((int)$data['id']);
unset($data['id']); unset($data['id']);
} }
if($subscriber === false && !empty($data['email'])) { if($subscriber === false && !empty($data['email'])) {
$subscriber = static::where('email', $data['email'])->findOne(); $subscriber = self::where('email', $data['email'])->findOne();
if($subscriber !== false) { if($subscriber !== false) {
unset($data['email']); unset($data['email']);
} }
} }
// segments
$segment_ids = false;
if(array_key_exists('segments', $data)) {
$segment_ids = (array)$data['segments'];
unset($data['segments']);
}
// custom fields // custom fields
$custom_fields = array(); $custom_fields = array();
@ -248,7 +278,7 @@ class Subscriber extends Model {
} }
if($subscriber === false) { if($subscriber === false) {
$subscriber = static::create(); $subscriber = self::create();
$subscriber->hydrate($data); $subscriber->hydrate($data);
} else { } else {
$subscriber->set($data); $subscriber->set($data);
@ -260,6 +290,9 @@ class Subscriber extends Model {
$subscriber->setCustomField($custom_field_id, $value); $subscriber->setCustomField($custom_field_id, $value);
} }
} }
if($segment_ids !== false) {
$subscriber->addToSegments($segment_ids);
}
} }
return $subscriber; return $subscriber;
} }
@ -388,7 +421,6 @@ class Subscriber extends Model {
} }
static function bulkAddToList($orm, $data = array()) { static function bulkAddToList($orm, $data = array()) {
$segment_id = (isset($data['segment_id']) ? (int)$data['segment_id'] : 0); $segment_id = (isset($data['segment_id']) ? (int)$data['segment_id'] : 0);
$segment = Segment::findOne($segment_id); $segment = Segment::findOne($segment_id);
@ -412,6 +444,15 @@ class Subscriber extends Model {
return false; return false;
} }
static function bulkDelete($orm) {
return parent::bulkAction($orm, function($ids) {
// delete subscribers
Subscriber::whereIn('id', $ids)->deleteMany();
// delete subscribers' relations to segments
SubscriberSegment::whereIn('subscriber_id', $ids)->deleteMany();
});
}
static function subscribed($orm) { static function subscribed($orm) {
return $orm return $orm
->whereNull('deleted_at') ->whereNull('deleted_at')
@ -430,6 +471,19 @@ class Subscriber extends Model {
->where('status', 'unconfirmed'); ->where('status', 'unconfirmed');
} }
static function withoutSegments($orm) {
return $orm->select(MP_SUBSCRIBERS_TABLE.'.*')
->leftOuterJoin(
MP_SUBSCRIBER_SEGMENT_TABLE,
array(
MP_SUBSCRIBERS_TABLE.'.id',
'=',
MP_SUBSCRIBER_SEGMENT_TABLE.'.subscriber_id'
)
)
->whereNull(MP_SUBSCRIBER_SEGMENT_TABLE.'.subscriber_id');
}
static function createMultiple($columns, $values) { static function createMultiple($columns, $values) {
return self::rawExecute( return self::rawExecute(
'INSERT INTO `' . self::$_table . '` ' . 'INSERT INTO `' . self::$_table . '` ' .

View File

@ -22,12 +22,12 @@ class PostTransformer {
$content = $content_manager->filterContent($content); $content = $content_manager->filterContent($content);
$structure_transformer = new StructureTransformer(); $structure_transformer = new StructureTransformer();
$structure = $structure_transformer->transform($content, $this->args['imagePadded'] === 'true'); $structure = $structure_transformer->transform($content, $this->args['imageFullWidth'] === 'true');
$structure = $this->appendFeaturedImage( $structure = $this->appendFeaturedImage(
$post, $post,
$this->args['displayType'], $this->args['displayType'],
$this->args['imagePadded'] === 'true', $this->args['imageFullWidth'] === 'true',
$structure $structure
); );
$structure = $this->appendPostTitle($post, $structure); $structure = $this->appendPostTitle($post, $structure);
@ -36,7 +36,7 @@ class PostTransformer {
return $structure; return $structure;
} }
private function appendFeaturedImage($post, $display_type, $image_padded, $structure) { private function appendFeaturedImage($post, $display_type, $image_full_width, $structure) {
if ($display_type === 'full') { if ($display_type === 'full') {
// No featured images for full posts // No featured images for full posts
return $structure; return $structure;
@ -45,7 +45,7 @@ class PostTransformer {
$featured_image = $this->getFeaturedImage( $featured_image = $this->getFeaturedImage(
$post->ID, $post->ID,
$post->post_title, $post->post_title,
(bool)$image_padded (bool)$image_full_width
); );
if (is_array($featured_image)) { if (is_array($featured_image)) {
@ -55,7 +55,7 @@ class PostTransformer {
return $structure; return $structure;
} }
private function getFeaturedImage($post_id, $post_title, $image_padded) { private function getFeaturedImage($post_id, $post_title, $image_full_width) {
if(has_post_thumbnail($post_id)) { if(has_post_thumbnail($post_id)) {
$thumbnail_id = get_post_thumbnail_id($post_id); $thumbnail_id = get_post_thumbnail_id($post_id);
@ -81,7 +81,7 @@ class PostTransformer {
'link' => get_permalink($post_id), 'link' => get_permalink($post_id),
'src' => $image_info[0], 'src' => $image_info[0],
'alt' => $alt_text, 'alt' => $alt_text,
'padded' => $image_padded, 'fullWidth' => $image_full_width,
'width' => $image_info[1], 'width' => $image_info[1],
'height' => $image_info[2], 'height' => $image_info[2],
'styles' => array( 'styles' => array(

View File

@ -7,11 +7,11 @@ if(!defined('ABSPATH')) exit;
class StructureTransformer { class StructureTransformer {
function transform($content, $image_padded) { function transform($content, $image_full_width) {
$root = pQuery::parseStr($content); $root = pQuery::parseStr($content);
$this->hoistImagesToRoot($root); $this->hoistImagesToRoot($root);
$structure = $this->transformTagsToBlocks($root, $image_padded); $structure = $this->transformTagsToBlocks($root, $image_full_width);
$structure = $this->mergeNeighboringBlocks($structure); $structure = $this->mergeNeighboringBlocks($structure);
return $structure; return $structure;
} }
@ -44,8 +44,8 @@ class StructureTransformer {
* Transforms HTML tags into their respective JSON objects, * Transforms HTML tags into their respective JSON objects,
* turns other root children into text blocks * turns other root children into text blocks
*/ */
private function transformTagsToBlocks($root, $image_padded) { private function transformTagsToBlocks($root, $image_full_width) {
return array_map(function($item) use ($image_padded) { return array_map(function($item) use ($image_full_width) {
if ($item->tag === 'img' || $item->tag === 'a' && $item->query('img')) { if ($item->tag === 'img' || $item->tag === 'a' && $item->query('img')) {
if ($item->tag === 'a') { if ($item->tag === 'a') {
$link = $item->getAttribute('href'); $link = $item->getAttribute('href');
@ -60,7 +60,7 @@ class StructureTransformer {
'link' => $link, 'link' => $link,
'src' => $image->getAttribute('src'), 'src' => $image->getAttribute('src'),
'alt' => $image->getAttribute('alt'), 'alt' => $image->getAttribute('alt'),
'padded' => $image_padded, 'fullWidth' => $image_full_width,
'width' => $image->getAttribute('width'), 'width' => $image->getAttribute('width'),
'height' => $image->getAttribute('height'), 'height' => $image->getAttribute('height'),
'styles' => array( 'styles' => array(

View File

@ -6,10 +6,12 @@ use MailPoet\Newsletter\Renderer\StylesHelper;
class Image { class Image {
static function render($element, $columnCount) { static function render($element, $columnCount) {
$element = self::getImageDimensions($element, $columnCount); $element['width'] = (int) $element['width'];
$element['height'] = (int) $element['height'];
$element = self::adjustImageDimensions($element, $columnCount);
$template = ' $template = '
<tr> <tr>
<td class="mailpoet_image ' . $element['paddedClass'] . '" align="center" valign="top"> <td class="mailpoet_image ' . (($element['fullWidth'] === false) ? 'mailpoet_padded' : '') . '" align="center" valign="top">
<img style="max-width:' . $element['width'] . 'px;" src="' . $element['src'] . '" <img style="max-width:' . $element['width'] . 'px;" src="' . $element['src'] . '"
width="' . $element['width'] . '" height="' . $element['height'] . '" alt="' . $element['alt'] . '"/> width="' . $element['width'] . '" height="' . $element['height'] . '" alt="' . $element['alt'] . '"/>
</td> </td>
@ -17,25 +19,22 @@ class Image {
return $template; return $template;
} }
static function getImageDimensions($element, $column_count) { static function adjustImageDimensions($element, $column_count) {
$column_width = ColumnsHelper::columnWidth($column_count); $column_width = ColumnsHelper::columnWidth($column_count);
$padded_width = StylesHelper::$padding_width * 2; $padded_width = StylesHelper::$padding_width * 2;
// resize image if it's wider than the column width // scale image to fit column width
if((int) $element['width'] >= $column_width) { if($element['width'] > $column_width) {
$ratio = (int) $element['width'] / $column_width; $ratio = $element['width'] / $column_width;
$element['width'] = $column_width; $element['width'] = $column_width;
$element['height'] = ceil((int) $element['height'] / $ratio); $element['height'] = (int) ceil($element['height'] / $ratio);
} }
if($element['padded'] == "true" && $element['width'] >= $column_width) { // resize image if the image is padded and wider than padded column width
// resize image if the padded option is on if($element['fullWidth'] === false &&
$ratio = (int) $element['width'] / ((int) $element['width'] - $padded_width); $element['width'] > ($column_width - $padded_width)
$element['width'] = (int) $element['width'] - $padded_width; ) {
$element['height'] = ceil((int) $element['height'] / $ratio); $ratio = $element['width'] / ($column_width - $padded_width);
$element['paddedClass'] = 'mailpoet_padded'; $element['width'] = $column_width - $padded_width;
} else { $element['height'] = (int) ceil($element['height'] / $ratio);
$element['width'] = (int) $element['width'];
$element['height'] = (int) $element['height'];
$element['paddedClass'] = '';
} }
return $element; return $element;
} }

View File

@ -280,4 +280,4 @@ class Newsletters {
); );
} }
} }
} }

View File

@ -30,7 +30,7 @@ class Router {
$endpoint = new $endpoint(); $endpoint = new $endpoint();
$response = $endpoint->$method($data); $response = $endpoint->$method($data);
wp_send_json($response); wp_send_json($response);
} catch(Exception $e) { } catch(\Exception $e) {
error_log($e->getMessage()); error_log($e->getMessage());
exit; exit;
} }

View File

@ -66,20 +66,19 @@ class Segments {
} }
function save($data = array()) { function save($data = array()) {
$errors = array();
$result = false;
$segment = Segment::createOrUpdate($data); $segment = Segment::createOrUpdate($data);
$errors = $segment->getErrors();
if($segment !== false && !$segment->id()) { if(!empty($errors)) {
$errors = $segment->getValidationErrors(); return array(
'result' => false,
'errors' => $errors
);
} else { } else {
$result = true; return array(
'result' => true
);
} }
return array(
'result' => $result,
'errors' => $errors
);
} }
function restore($id) { function restore($id) {

View File

@ -13,25 +13,21 @@ class SendingQueue {
try { try {
new Mailer(false); new Mailer(false);
} catch(\Exception $e) { } catch(\Exception $e) {
wp_send_json( return array(
array( 'result' => false,
'result' => false, 'errors' => array($e->getMessage())
'errors' => array($e->getMessage())
)
); );
} }
$queue = \MailPoet\Models\SendingQueue::where('newsletter_id', $data['newsletter_id']) $queue = \MailPoet\Models\SendingQueue::whereNull('status')
->whereNull('status') ->where('newsletter_id', $data['newsletter_id'])
->findArray(); ->findArray();
if(count($queue)) {
wp_send_json( if(!empty($queue)) {
array( return array(
'result' => false, 'result' => false,
'errors' => array(__('Send operation is already in progress.')) 'errors' => array(__('Send operation is already in progress.'))
)
); );
exit;
} }
$queue = \MailPoet\Models\SendingQueue::create(); $queue = \MailPoet\Models\SendingQueue::create();
$queue->newsletter_id = $data['newsletter_id']; $queue->newsletter_id = $data['newsletter_id'];
@ -40,50 +36,39 @@ class SendingQueue {
->findMany(); ->findMany();
foreach($segments as $segment) { foreach($segments as $segment) {
$subscriber_ids = array_merge($subscriber_ids, Helpers::arrayColumn( $subscriber_ids = array_merge(
$segment->subscribers() $subscriber_ids,
->findArray(), Helpers::arrayColumn(
'id' $segment->subscribers()->findArray(), 'id'
)); )
);
} }
if(empty($subscriber_ids)) { if(empty($subscriber_ids)) {
wp_send_json( return array(
array( 'result' => false,
'result' => false, 'errors' => array(__('There are no subscribers.'))
'errors' => array(__('There are no subscribers.'))
)
); );
exit;
} }
$subscriber_ids = array_unique($subscriber_ids); $subscriber_ids = array_unique($subscriber_ids);
$queue->subscribers = json_encode( $queue->subscribers = serialize(
array( array(
'to_process' => $subscriber_ids 'to_process' => $subscriber_ids
) )
); );
$queue->count_total = $queue->count_to_process = count($subscriber_ids); $queue->count_total = $queue->count_to_process = count($subscriber_ids);
$result = $queue->save(); $queue->save();
if($result === false) { $errors = $queue->getErrors();
$errors = array(__('Queue could not be created.')); if(!empty($errors)) {
return array(
if(!empty($queue->getValidationErrors())) { 'result' => false,
$errors = array_merge($errors, $queue->getValidationErrors()); 'errors' => $errors
}
wp_send_json(
array(
'result' => false,
'errors' => $errors
)
); );
} else { } else {
wp_send_json( return array(
array( 'result' => true,
'result' => true, 'data' => array($queue->id)
'data' => array($queue->id)
)
); );
} }
} }
@ -94,14 +79,15 @@ class SendingQueue {
if($newsletter !== false) { if($newsletter !== false) {
$queue = $newsletter->getQueue(); $queue = $newsletter->getQueue();
if($queue !== false && $queue->id() > 0) {
if($queue !== false) {
$result = $queue->pause(); $result = $queue->pause();
} }
} }
wp_send_json(array( return array(
'result' => $result 'result' => $result
)); );
} }
function resume($newsletter_id) { function resume($newsletter_id) {
@ -110,125 +96,14 @@ class SendingQueue {
if($newsletter !== false) { if($newsletter !== false) {
$queue = $newsletter->getQueue(); $queue = $newsletter->getQueue();
if($queue !== false && $queue->id() > 0) {
if($queue !== false) {
$result = $queue->resume(); $result = $queue->resume();
} }
} }
wp_send_json(array( return array(
'result' => $result 'result' => $result
));
}
function addQueues($data) {
$newsletterIds = Helpers::arrayColumn($data, 'newsletter_id');
$queues = \MailPoet\Models\SendingQueue::whereIn('newsletter_id', $newsletterIds)
->whereNull('status')
->findArray();
if(count($queues)) {
wp_send_json(
array(
'result' => false,
'errors' => array(__('Send operation is already in progress.'))
)
);
}
$result = array_map(function ($queueData) {
$queue = \MailPoet\Models\SendingQueue::create();
$queue->newsletter_id = $queueData['newsletter_id'];
$queue->subscribers = json_encode(
array(
'to_process' => $queueData['subscribers']
)
);
$queue->count_total = $queue->count_to_process = count($queueData['subscribers']);
$queue->save();
return array(
'newsletter_id' => $queue->newsletter_id,
'queue_id' => $queue->id
);
}, $data);
$result = Helpers::arrayColumn($result, 'queue_id', 'newsletter_id');
wp_send_json(
count($data) != count($result) ?
array(
'result' => false,
'errors' => array(__('Some queues could not be created.')),
'data' => $result
) :
array(
'result' => true,
'data' => $result
)
);
}
function deleteQueue($data) {
$queue = \MailPoet\Models\SendingQueue::whereNull('deleted_at')
->findOne($data['queue_id']);
if(!$queue) {
wp_send_json(
array(
'result' => false,
'errors' => array(__('Queue not found.'))
)
);
}
$queue->deleted_at = 'Y-m-d H:i:s';
$queue->save();
wp_send_json(array('result' => true));
}
function deleteQueues($data) {
$queues = \MailPoet\Models\SendingQueue::whereNull('deleted_at')
->whereIn('id', $data['queue_ids'])
->findResultSet();
if(!$queues->count()) {
wp_send_json(
array(
'result' => false,
'errors' => array(__('Queues not found.'))
)
);
}
foreach($queues as $queue) {
$queue->deleted_at = 'Y-m-d H:i:s';
$queue->save();
}
wp_send_json(array('result' => true));
}
function getQueueStatus($data) {
$queue = \MailPoet\Models\SendingQueue::whereNull('deleted_at')
->findOne($data['queue_id'])
->asArray();
wp_send_json(
!$queue ?
array(
'result' => false,
'errors' => array(__('Queue not found.'))
) :
array(
'result' => true,
'data' => $queue
)
);
}
function getQueuesStatus($data) {
$queues = \MailPoet\Models\SendingQueue::whereNull('deleted_at')
->whereIn('id', $data['queue_ids'])
->findArray();
wp_send_json(
!$queues ?
array(
'result' => false,
'errors' => array(__('Queue not found.'))
) :
array(
'result' => true,
'data' => $queues
)
); );
} }
} }

View File

@ -14,7 +14,7 @@ class Setup {
$activator->deactivate(); $activator->deactivate();
$activator->activate(); $activator->activate();
$result = true; $result = true;
} catch(Exception $e) { } catch(\Exception $e) {
$result = false; $result = false;
} }
return array( return array(

View File

@ -57,13 +57,6 @@ class Subscribers {
} }
function save($data = array()) { function save($data = array()) {
$segment_ids = array();
if(isset($data['segments'])) {
$segment_ids = (array)$data['segments'];
unset($data['segments']);
}
$subscriber = Subscriber::createOrUpdate($data); $subscriber = Subscriber::createOrUpdate($data);
$errors = $subscriber->getErrors(); $errors = $subscriber->getErrors();
@ -73,9 +66,6 @@ class Subscribers {
'errors' => $errors 'errors' => $errors
); );
} else { } else {
if(!empty($segment_ids)) {
$subscriber->addToSegments($segment_ids);
}
return array( return array(
'result' => true 'result' => true
); );

View File

@ -47,9 +47,9 @@ class WP {
} }
$subscriber = Subscriber::createOrUpdate($data); $subscriber = Subscriber::createOrUpdate($data);
if($subscriber !== false && $subscriber->id()) { if($subscriber->getErrors() === false && $subscriber->id > 0) {
if($segment !== false) { if($segment !== false) {
$segment->addSubscriber($subscriber->id()); $segment->addSubscriber($subscriber->id);
} }
} }
break; break;

View File

@ -17,6 +17,7 @@ class Export {
public $segments; public $segments;
public $subscribers_without_segment; public $subscribers_without_segment;
public $subscriber_fields; public $subscriber_fields;
public $export_path;
public $export_file; public $export_file;
public $export_file_URL; public $export_file_URL;
public $profiler_start; public $profiler_start;
@ -28,19 +29,23 @@ class Export {
$this->segments = $data['segments']; $this->segments = $data['segments'];
$this->subscribers_without_segment = array_search(0, $this->segments); $this->subscribers_without_segment = array_search(0, $this->segments);
$this->subscriber_fields = $data['subscriber_fields']; $this->subscriber_fields = $data['subscriber_fields'];
$this->export_path = Env::$temp_path;
$this->export_file = $this->getExportFile($this->export_format_option); $this->export_file = $this->getExportFile($this->export_format_option);
$this->export_file_URL = $this->getExportFileURL($this->export_file); $this->export_file_URL = $this->getExportFileURL($this->export_file);
$this->profiler_start = microtime(true); $this->profiler_start = microtime(true);
} }
function process() { function process() {
$subscribers = $this->getSubscribers();
$subscriber_custom_fields = $this->getSubscriberCustomFields();
$formatted_subscriber_fields = $this->formatSubscriberFields(
$this->subscriber_fields,
$subscriber_custom_fields
);
try { try {
if(is_writable($this->export_path) === false) {
throw new \Exception(__("Couldn't save export file on the server."));
}
$subscribers = $this->getSubscribers();
$subscriber_custom_fields = $this->getSubscriberCustomFields();
$formatted_subscriber_fields = $this->formatSubscriberFields(
$this->subscriber_fields,
$subscriber_custom_fields
);
if($this->export_format_option === 'csv') { if($this->export_format_option === 'csv') {
$CSV_file = fopen($this->export_file, 'w'); $CSV_file = fopen($this->export_file, 'w');
$format_CSV = function($row) { $format_CSV = function($row) {
@ -104,7 +109,7 @@ class Export {
); );
$writer->writeToFile($this->export_file); $writer->writeToFile($this->export_file);
} }
} catch(Exception $e) { } catch(\Exception $e) {
return array( return array(
'result' => false, 'result' => false,
'errors' => array($e->getMessage()) 'errors' => array($e->getMessage())
@ -178,7 +183,7 @@ class Export {
function getExportFile($format) { function getExportFile($format) {
return sprintf( return sprintf(
Env::$temp_path . '/MailPoet_export_%s.%s', $this->export_path . '/MailPoet_export_%s.%s',
substr(md5(time()), 0, 4), substr(md5(time()), 0, 4),
$format $format
); );

View File

@ -5,19 +5,19 @@ use MailPoet\Util\Helpers;
class MailChimp { class MailChimp {
function __construct($APIKey, $lists = false) { function __construct($APIKey, $lists = false) {
$this->APIKey = $this->getAPIKey($APIKey); $this->api_key = $this->getAPIKey($APIKey);
$this->maxPostSize = Helpers::getMaxPostSize('bytes'); $this->max_post_size = Helpers::getMaxPostSize('bytes');
$this->dataCenter = $this->getDataCenter($this->APIKey); $this->data_center = $this->getDataCenter($this->api_key);
$this->listsURL = 'https://%s.api.mailchimp.com/2.0/lists/list?apikey=%s'; $this->lists_url = 'https://%s.api.mailchimp.com/2.0/lists/list?apikey=%s';
$this->exportURL = 'https://%s.api.mailchimp.com/export/1.0/list/?apikey=%s&id=%s'; $this->export_url = 'https://%s.api.mailchimp.com/export/1.0/list/?apikey=%s&id=%s';
} }
function getLists() { function getLists() {
if(!$this->APIKey || !$this->dataCenter) { if(!$this->api_key || !$this->data_center) {
return $this->processError('API'); return $this->processError('API');
} }
$connection = @fopen(sprintf($this->listsURL, $this->dataCenter, $this->APIKey), 'r'); $connection = @fopen(sprintf($this->lists_url, $this->data_center, $this->api_key), 'r');
if(!$connection) { if(!$connection) {
return $this->processError('connection'); return $this->processError('connection');
@ -52,7 +52,7 @@ class MailChimp {
} }
function getSubscribers($lists = array()) { function getSubscribers($lists = array()) {
if(!$this->APIKey || !$this->dataCenter) { if(!$this->api_key || !$this->data_center) {
return $this->processError('API'); return $this->processError('API');
} }
@ -60,9 +60,9 @@ class MailChimp {
return $this->processError('lists'); return $this->processError('lists');
} }
$bytesFetched = 0; $bytes_fetched = 0;
foreach ($lists as $list) { foreach ($lists as $list) {
$url = sprintf($this->exportURL, $this->dataCenter, $this->APIKey, $list); $url = sprintf($this->export_url, $this->data_center, $this->api_key, $list);
$connection = @fopen($url, 'r'); $connection = @fopen($url, 'r');
if(!$connection) { if(!$connection) {
return $this->processError('connection'); return $this->processError('connection');
@ -78,10 +78,10 @@ class MailChimp {
if(is_object($header) && isset($header->error)) { if(is_object($header) && isset($header->error)) {
return $this->processError('lists'); return $this->processError('lists');
} }
if(!isset($headerHash)) { if(!isset($header_hash)) {
$headerHash = md5(implode(',', $header)); $header_hash = md5(implode(',', $header));
} else { } else {
if(md5(implode(',', $header) !== $headerHash)) { if(md5(implode(',', $header) !== $header_hash)) {
return $this->processError('headers'); return $this->processError('headers');
} }
} }
@ -91,8 +91,8 @@ class MailChimp {
$i++; $i++;
} }
$bytesFetched += strlen($buffer); $bytes_fetched += strlen($buffer);
if($bytesFetched > $this->maxPostSize) { if($bytes_fetched > $this->max_post_size) {
return $this->processError('size'); return $this->processError('size');
} }
@ -119,8 +119,9 @@ class MailChimp {
} }
function getDataCenter($APIKey) { function getDataCenter($APIKey) {
if (!preg_match('/-[a-zA-Z0-9]{3,}/', $APIKey)) return false;
// double parantheses: http://phpsadness.com/sad/51 // double parantheses: http://phpsadness.com/sad/51
return ($APIKey) ? end((explode('-', $APIKey))) : false; return end((explode('-', $APIKey)));
} }
function getAPIKey($APIKey) { function getAPIKey($APIKey) {
@ -150,7 +151,7 @@ class MailChimp {
} }
return array( return array(
'result' => false, 'result' => false,
'error' => $errorMessage 'errors' => array($errorMessage)
); );
} }
} }

View File

@ -8,13 +8,22 @@ class Comment {
const APPROVED = 1; const APPROVED = 1;
const PENDING_APPROVAL = 0; const PENDING_APPROVAL = 0;
static function extendForm() { static function extendLoggedInForm($field) {
$field .= self::getSubscriptionField();
return $field;
}
static function extendLoggedOutForm() {
echo self::getSubscriptionField();
}
static function getSubscriptionField() {
$label = Setting::getValue( $label = Setting::getValue(
'subscribe.on_comment.label', 'subscribe.on_comment.label',
__('Yes, add me to your mailing list.') __('Yes, add me to your mailing list.')
); );
print '<p class="comment-form-mailpoet"> return '<p class="comment-form-mailpoet">
<label for="mailpoet_subscribe_on_comment"> <label for="mailpoet_subscribe_on_comment">
<input <input
type="checkbox" type="checkbox"

View File

@ -12,7 +12,7 @@ class DKIM {
'public' => self::trimKey($rsa_keys['publickey']), 'public' => self::trimKey($rsa_keys['publickey']),
'private' => self::trimKey($rsa_keys['privatekey']) 'private' => self::trimKey($rsa_keys['privatekey'])
); );
} catch(Exception $e) { } catch(\Exception $e) {
return false; return false;
} }
} }

View File

@ -46,7 +46,7 @@ class Engine
*/ */
public function addValidator($label, $function) public function addValidator($label, $function)
{ {
if (isset($this->_checks[$label])) throw Exception(); if (isset($this->_checks[$label])) throw \Exception();
$this->setValidator($label, $function); $this->setValidator($label, $function);
} }

View File

@ -6,7 +6,7 @@ namespace MailPoet\Util;
* @license MIT License * @license MIT License
* */ * */
if (!class_exists('ZipArchive')) { throw new Exception('ZipArchive not found'); } if (!class_exists('ZipArchive')) { throw new \Exception('ZipArchive not found'); }
class XLSXWriter class XLSXWriter
{ {

View File

@ -4,7 +4,7 @@ if(!defined('ABSPATH')) exit;
use \MailPoet\Config\Initializer; use \MailPoet\Config\Initializer;
/* /*
* Plugin Name: MailPoet * Plugin Name: MailPoet
* Version: 0.0.14 * Version: 0.0.17
* Plugin URI: http://www.mailpoet.com * Plugin URI: http://www.mailpoet.com
* Description: MailPoet Newsletters. * Description: MailPoet Newsletters.
* Author: MailPoet * Author: MailPoet
@ -22,7 +22,7 @@ use \MailPoet\Config\Initializer;
require 'vendor/autoload.php'; require 'vendor/autoload.php';
define('MAILPOET_VERSION', '0.0.14'); define('MAILPOET_VERSION', '0.0.17');
$initializer = new Initializer(array( $initializer = new Initializer(array(
'file' => __FILE__, 'file' => __FILE__,

View File

@ -14,6 +14,7 @@ $models = array(
'NewsletterSegment', 'NewsletterSegment',
'NewsletterTemplate', 'NewsletterTemplate',
'Segment', 'Segment',
'SendingQueue',
'Setting', 'Setting',
'Subscriber', 'Subscriber',
'SubscriberCustomField', 'SubscriberCustomField',

View File

@ -71,7 +71,7 @@ define([
}); });
it('has image width', function () { it('has image width', function () {
expect(model.get('imagePadded')).to.be.a('boolean'); expect(model.get('imageFullWidth')).to.be.a('boolean');
}); });
it('has an option to display author', function () { it('has an option to display author', function () {
@ -126,7 +126,7 @@ define([
titlePosition: 'aboveBlock', // 'inTextBlock'|'aboveBlock', titlePosition: 'aboveBlock', // 'inTextBlock'|'aboveBlock',
titleAlignment: 'right', // 'left'|'center'|'right' titleAlignment: 'right', // 'left'|'center'|'right'
titleIsLink: true, // false|true titleIsLink: true, // false|true
imagePadded: false, // true|false imageFullWidth: false, // true|false
showAuthor: 'belowText', // 'no'|'aboveText'|'belowText' showAuthor: 'belowText', // 'no'|'aboveText'|'belowText'
authorPrecededBy: 'Custom config author preceded by', authorPrecededBy: 'Custom config author preceded by',
showCategories: 'belowText', // 'no'|'aboveText'|'belowText' showCategories: 'belowText', // 'no'|'aboveText'|'belowText'
@ -172,7 +172,7 @@ define([
expect(model.get('titlePosition')).to.equal('aboveBlock'); expect(model.get('titlePosition')).to.equal('aboveBlock');
expect(model.get('titleAlignment')).to.equal('right'); expect(model.get('titleAlignment')).to.equal('right');
expect(model.get('titleIsLink')).to.equal(true); expect(model.get('titleIsLink')).to.equal(true);
expect(model.get('imagePadded')).to.equal(false); expect(model.get('imageFullWidth')).to.equal(false);
expect(model.get('showAuthor')).to.equal('belowText'); expect(model.get('showAuthor')).to.equal('belowText');
expect(model.get('authorPrecededBy')).to.equal('Custom config author preceded by'); expect(model.get('authorPrecededBy')).to.equal('Custom config author preceded by');
expect(model.get('showCategories')).to.equal('belowText'); expect(model.get('showCategories')).to.equal('belowText');
@ -346,8 +346,8 @@ define([
it('changes the model if image alignment changes', function () { it('changes the model if image alignment changes', function () {
var newValue = false; var newValue = false;
view.$('.mailpoet_automated_latest_content_image_padded').val(newValue).change(); view.$('.mailpoet_automated_latest_content_image_full_width').val(newValue).change();
expect(model.get('imagePadded')).to.equal(newValue); expect(model.get('imageFullWidth')).to.equal(newValue);
}); });
it('changes the model if show author changes', function () { it('changes the model if show author changes', function () {

View File

@ -63,6 +63,10 @@ define([
expect(model.get('styles.block.fontSize')).to.match(/^\d+px$/); expect(model.get('styles.block.fontSize')).to.match(/^\d+px$/);
}); });
it("has a text font weight", function () {
expect(model.get('styles.block.fontWeight')).to.match(/^(bold|normal)$/);
});
it("has width", function () { it("has width", function () {
expect(model.get('styles.block.width')).to.match(/^\d+px$/); expect(model.get('styles.block.width')).to.match(/^\d+px$/);
}); });
@ -78,7 +82,7 @@ define([
}); });
it("triggers autosave if any attribute changes", function () { it("triggers autosave if any attribute changes", function () {
var mock = sinon.mock().exactly(11).withArgs('autoSave'); var mock = sinon.mock().exactly(12).withArgs('autoSave');
EditorApplication.getChannel = sinon.stub().returns({ EditorApplication.getChannel = sinon.stub().returns({
trigger: mock, trigger: mock,
}); });
@ -93,6 +97,7 @@ define([
model.set('styles.block.fontColor', '#345678'); model.set('styles.block.fontColor', '#345678');
model.set('styles.block.fontFamily', 'Some other style'); model.set('styles.block.fontFamily', 'Some other style');
model.set('styles.block.fontSize', '10px'); model.set('styles.block.fontSize', '10px');
model.set('styles.block.fontWeight', 'bold');
mock.verify(); mock.verify();
}); });
@ -114,6 +119,7 @@ define([
fontColor: '#345678', fontColor: '#345678',
fontFamily: 'Tahoma', fontFamily: 'Tahoma',
fontSize: '30px', fontSize: '30px',
fontWeight: 'bold',
}, },
}, },
}, },
@ -133,6 +139,7 @@ define([
expect(model.get('styles.block.fontColor')).to.equal('#345678'); expect(model.get('styles.block.fontColor')).to.equal('#345678');
expect(model.get('styles.block.fontFamily')).to.equal('Tahoma'); expect(model.get('styles.block.fontFamily')).to.equal('Tahoma');
expect(model.get('styles.block.fontSize')).to.equal('30px'); expect(model.get('styles.block.fontSize')).to.equal('30px');
expect(model.get('styles.block.fontWeight')).to.equal('bold');
}); });
}); });
@ -179,6 +186,7 @@ define([
fontColor: '#345678', fontColor: '#345678',
fontFamily: 'Arial', fontFamily: 'Arial',
fontSize: '12px', fontSize: '12px',
fontWeight: 'bold',
}, },
}, },
}); });
@ -235,6 +243,10 @@ define([
it('has a specified font size', function () { it('has a specified font size', function () {
expect(view.$('.mailpoet_editor_button').css('font-size')).to.equal(model.get('styles.block.fontSize')); expect(view.$('.mailpoet_editor_button').css('font-size')).to.equal(model.get('styles.block.fontSize'));
}); });
it('has a specified font weight', function () {
expect(view.$('.mailpoet_editor_button').css('font-weight')).to.equal(model.get('styles.block.fontWeight'));
});
}); });
}); });
@ -318,6 +330,12 @@ define([
expect(model.get('styles.block.fontSize')).to.equal(newValue); expect(model.get('styles.block.fontSize')).to.equal(newValue);
}); });
it('updates the model when font weight changes', function () {
var newValue = 'bold';
view.$('.mailpoet_field_button_font_weight').prop('checked', true).change();
expect(model.get('styles.block.fontWeight')).to.equal(newValue);
});
it('updates the model when background color changes', function () { it('updates the model when background color changes', function () {
var newValue = '#cccccc'; var newValue = '#cccccc';

View File

@ -30,8 +30,8 @@ define([
expect(model.get('alt')).to.be.a('string'); expect(model.get('alt')).to.be.a('string');
}); });
it('can be padded', function () { it('can be full width', function () {
expect(model.get('padded')).to.be.a('boolean'); expect(model.get('fullWidth')).to.be.a('boolean');
}); });
it('has a width', function () { it('has a width', function () {
@ -61,7 +61,7 @@ define([
model.set('link', 'http://example.net'); model.set('link', 'http://example.net');
model.set('src', 'someNewImage.png'); model.set('src', 'someNewImage.png');
model.set('alt', 'Some alt text'); model.set('alt', 'Some alt text');
model.set('padded', false); model.set('fullWidth', false);
model.set('width', '63px'); model.set('width', '63px');
model.set('height', '61px'); model.set('height', '61px');
model.set('styles.block.textAlign', 'right'); model.set('styles.block.textAlign', 'right');
@ -76,7 +76,7 @@ define([
link: 'http://example.org/customConfigPage', link: 'http://example.org/customConfigPage',
src: 'http://example.org/someCustomConfigImage.png', src: 'http://example.org/someCustomConfigImage.png',
alt: 'Custom config alt', alt: 'Custom config alt',
padded: false, fullWidth: false,
width: '1234px', width: '1234px',
height: '2345px', height: '2345px',
styles: { styles: {
@ -92,7 +92,7 @@ define([
expect(model.get('link')).to.equal('http://example.org/customConfigPage'); expect(model.get('link')).to.equal('http://example.org/customConfigPage');
expect(model.get('src')).to.equal('http://example.org/someCustomConfigImage.png'); expect(model.get('src')).to.equal('http://example.org/someCustomConfigImage.png');
expect(model.get('alt')).to.equal('Custom config alt'); expect(model.get('alt')).to.equal('Custom config alt');
expect(model.get('padded')).to.equal(false); expect(model.get('fullWidth')).to.equal(false);
expect(model.get('width')).to.equal('1234px'); expect(model.get('width')).to.equal('1234px');
expect(model.get('height')).to.equal('2345px'); expect(model.get('height')).to.equal('2345px');
expect(model.get('styles.block.textAlign')).to.equal('right'); expect(model.get('styles.block.textAlign')).to.equal('right');
@ -182,8 +182,8 @@ define([
it('updates the model when padding changes', function () { it('updates the model when padding changes', function () {
var newValue = 'false'; var newValue = 'false';
view.$('.mailpoet_field_image_padded').prop('checked', false).change(); view.$('.mailpoet_field_image_full_width').prop('checked', false).change();
expect(model.get('padded')).to.equal(false); expect(model.get('fullWidth')).to.equal(false);
}); });
it.skip('closes the sidepanel after "Done" is clicked', function() { it.skip('closes the sidepanel after "Done" is clicked', function() {

View File

@ -1,8 +1,9 @@
define([ define([
'newsletter_editor/App', 'newsletter_editor/App',
'newsletter_editor/components/communication', 'newsletter_editor/components/communication',
'newsletter_editor/blocks/posts' 'newsletter_editor/blocks/posts',
], function(EditorApplication, CommunicationComponent, PostsBlock) { 'newsletter_editor/blocks/container'
], function(EditorApplication, CommunicationComponent, PostsBlock, ContainerBlock) {
describe('Posts', function () { describe('Posts', function () {
Backbone.Radio = { Backbone.Radio = {
@ -74,7 +75,7 @@ define([
}); });
it('has image specific alignment', function () { it('has image specific alignment', function () {
expect(model.get('imagePadded')).to.be.a('boolean'); expect(model.get('imageFullWidth')).to.be.a('boolean');
}); });
it('has an option to display author', function () { it('has an option to display author', function () {
@ -129,7 +130,7 @@ define([
titlePosition: 'aboveBlock', // 'inTextBlock'|'aboveBlock', titlePosition: 'aboveBlock', // 'inTextBlock'|'aboveBlock',
titleAlignment: 'right', // 'left'|'center'|'right' titleAlignment: 'right', // 'left'|'center'|'right'
titleIsLink: true, // false|true titleIsLink: true, // false|true
imagePadded: false, // true|false imageFullWidth: false, // true|false
//imageAlignment: 'right', // 'centerFull'|'centerPadded'|'left'|'right'|'alternate'|'none' //imageAlignment: 'right', // 'centerFull'|'centerPadded'|'left'|'right'|'alternate'|'none'
showAuthor: 'belowText', // 'no'|'aboveText'|'belowText' showAuthor: 'belowText', // 'no'|'aboveText'|'belowText'
authorPrecededBy: 'Custom config author preceded by', authorPrecededBy: 'Custom config author preceded by',
@ -176,7 +177,7 @@ define([
expect(model.get('titlePosition')).to.equal('aboveBlock'); expect(model.get('titlePosition')).to.equal('aboveBlock');
expect(model.get('titleAlignment')).to.equal('right'); expect(model.get('titleAlignment')).to.equal('right');
expect(model.get('titleIsLink')).to.equal(true); expect(model.get('titleIsLink')).to.equal(true);
expect(model.get('imagePadded')).to.equal(false); expect(model.get('imageFullWidth')).to.equal(false);
expect(model.get('showAuthor')).to.equal('belowText'); expect(model.get('showAuthor')).to.equal('belowText');
expect(model.get('authorPrecededBy')).to.equal('Custom config author preceded by'); expect(model.get('authorPrecededBy')).to.equal('Custom config author preceded by');
expect(model.get('showCategories')).to.equal('belowText'); expect(model.get('showCategories')).to.equal('belowText');
@ -255,7 +256,7 @@ define([
global.stubConfig(EditorApplication, { global.stubConfig(EditorApplication, {
blockDefaults: {}, blockDefaults: {},
}); });
EditorApplication.getBlockTypeModel = sinon.stub().returns(Backbone.Model); EditorApplication.getBlockTypeModel = sinon.stub().returns(ContainerBlock.ContainerBlockModel);
model = new (PostsBlock.PostsBlockModel)(); model = new (PostsBlock.PostsBlockModel)();
view = new (PostsBlock.PostsBlockSettingsView)({model: model}); view = new (PostsBlock.PostsBlockSettingsView)({model: model});
}); });
@ -318,8 +319,8 @@ define([
it('changes the model if image alignment changes', function () { it('changes the model if image alignment changes', function () {
var newValue = false; var newValue = false;
view.$('.mailpoet_posts_image_padded').val(newValue).change(); view.$('.mailpoet_posts_image_full_width').val(newValue).change();
expect(model.get('imagePadded')).to.equal(newValue); expect(model.get('imageFullWidth')).to.equal(newValue);
}); });
it('changes the model if show author changes', function () { it('changes the model if show author changes', function () {

View File

@ -147,7 +147,11 @@ define([
}, },
}, },
'newsletter_editor/App': EditorApplication, 'newsletter_editor/App': EditorApplication,
'html2canvas': function() { return html2canvasMock; }, 'html2canvas': function() {
return {
then: function() { return html2canvasMock; }
};
},
}); });
var view = new (module.SaveView)(); var view = new (module.SaveView)();
view.render(); view.render();

View File

@ -1,6 +1,7 @@
<?php <?php
use MailPoet\Listing; use MailPoet\Listing;
use MailPoet\Models\Subscriber;
class ListingCest { class ListingCest {
function _before() { function _before() {
@ -22,18 +23,17 @@ class ListingCest {
} }
function itShouldGroup(UnitTester $I) { function itShouldGroup(UnitTester $I) {
$I->generateSubscribers(10); $I->generateSubscribers(1);
$I->generateSubscribers(20, array('status' => 'unsubscribed')); $I->generateSubscribers(2, array('status' => 'unsubscribed'));
$I->generateSubscribers(30, array('status' => 'subscribed')); $I->generateSubscribers(3, array('status' => 'subscribed'));
$listing = new Listing\Handler( $listing = new Listing\Handler(
'\MailPoet\Models\Subscriber', '\MailPoet\Models\Subscriber',
array('group' => 'subscribed') array('group' => 'subscribed')
); );
$result = $listing->get(); $result = $listing->get();
expect($result['groups'])->notEmpty(); expect($result['groups'])->notEmpty();
expect($result['count'])->equals(30); expect($result['count'])->equals(3);
} }
function itShouldSearch(UnitTester $I) { function itShouldSearch(UnitTester $I) {
@ -52,11 +52,7 @@ class ListingCest {
expect($result['count'])->equals(1); expect($result['count'])->equals(1);
} }
function itShouldPaginate(UnitTester $I) {
}
function _after() { function _after() {
Subscriber::deleteMany();
} }
} }

View File

@ -6,16 +6,16 @@ use MailPoet\Models\SubscriberCustomField;
class CustomFieldCest { class CustomFieldCest {
function _before() { function _before() {
$this->before_time = time();
$this->data = array( $this->data = array(
'name' => 'DOB', 'name' => 'City',
'type' => 'date', 'type' => 'text',
'params' => 'none' 'params' => array(
'label' => 'What is your city?'
)
); );
$this->customField = CustomField::create(); $this->custom_field = CustomField::createOrUpdate($this->data);
$this->customField->hydrate($this->data);
$this->saved = $this->customField->save(); $this->subscribers = array(
$this->subscribersData = array(
array( array(
'first_name' => 'John', 'first_name' => 'John',
'last_name' => 'Mailer', 'last_name' => 'Mailer',
@ -30,20 +30,26 @@ class CustomFieldCest {
} }
function itCanBeCreated() { function itCanBeCreated() {
expect($this->saved->id() > 0)->true(); expect($this->custom_field->id() > 0)->true();
expect($this->saved->getErrors())->false(); expect($this->custom_field->getErrors())->false();
} }
function itCanHaveName() { function itHasAName() {
expect($this->customField->name)->equals($this->data['name']); expect($this->custom_field->name)->equals($this->data['name']);
} }
function itCanHaveType() { function itHasAType() {
expect($this->customField->type)->equals($this->data['type']); expect($this->custom_field->type)->equals($this->data['type']);
} }
function itCanHaveParams() { function itHasSerializedParams() {
expect($this->customField->params)->equals($this->data['params']); $params = unserialize($this->custom_field->params);
expect($params)->equals($this->data['params']);
}
function itCanDecodeParams() {
$custom_field = $this->custom_field->asArray();
expect($custom_field['params'])->equals($this->data['params']);
} }
function itHasToBeValid() { function itHasToBeValid() {
@ -58,75 +64,64 @@ class CustomFieldCest {
} }
function itHasACreatedAtOnCreation() { function itHasACreatedAtOnCreation() {
$customField = CustomField::where('name', $this->data['name']) $custom_field = CustomField::findOne($this->custom_field->id);
->findOne(); expect($custom_field->created_at)->notNull();
$time_difference = strtotime($customField->created_at) >= $this->before_time; expect($custom_field->created_at)->notEquals('0000-00-00 00:00:00');
expect($time_difference)->equals(true);
} }
function itHasAnUpdatedAtOnCreation() { function itHasAnUpdatedAtOnCreation() {
$customField = CustomField::where('name', $this->data['name']) $custom_field = CustomField::findOne($this->custom_field->id);
->findOne(); expect($custom_field->updated_at)
$time_difference = strtotime($customField->updated_at) >= $this->before_time; ->equals($custom_field->created_at);
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() { function itUpdatesTheUpdatedAtOnUpdate() {
$customField = CustomField::where('name', $this->data['name']) $custom_field = CustomField::findOne($this->custom_field->id);
->findOne(); $created_at = $custom_field->created_at;
$update_time = time();
$customField->name = 'new name'; sleep(1);
$customField->save();
$time_difference = strtotime($customField->updated_at) >= $update_time; $custom_field->name = 'Country';
expect($time_difference)->equals(true); $custom_field->save();
$updated_custom_field = CustomField::findOne($custom_field->id);
expect($updated_custom_field->created_at)->equals($created_at);
$is_time_updated = (
$updated_custom_field->updated_at > $updated_custom_field->created_at
);
expect($is_time_updated)->true();
} }
function itCanHaveManySubscribers() { function itCanHaveManySubscribers() {
foreach ($this->subscribersData as $data) { foreach($this->subscribers as $subscriber) {
$subscriber = Subscriber::create(); $subscriber = Subscriber::createOrUpdate($subscriber);
$subscriber->hydrate($data);
$subscriber->save();
$association = SubscriberCustomField::create(); $association = SubscriberCustomField::create();
$association->subscriber_id = $subscriber->id; $association->subscriber_id = $subscriber->id;
$association->custom_field_id = $this->customField->id; $association->custom_field_id = $this->custom_field->id;
$association->save(); $association->save();
} }
$customField = CustomField::findOne($this->customField->id); $custom_field = CustomField::findOne($this->custom_field->id);
$subscribers = $customField->subscribers() $subscribers = $custom_field->subscribers()->findArray();
->findArray();
expect(count($subscribers))->equals(2); expect(count($subscribers))->equals(2);
} }
function itCanStoreCustomFieldValue() { function itCanHaveAValue() {
$subscriber = Subscriber::create(); $subscriber = Subscriber::createOrUpdate($this->subscribers[0]);
$subscriber->hydrate($this->subscribersData[0]);
$subscriber->save();
$association = SubscriberCustomField::create(); $association = SubscriberCustomField::create();
$association->subscriber_id = $subscriber->id; $association->subscriber_id = $subscriber->id;
$association->custom_field_id = $this->customField->id; $association->custom_field_id = $this->custom_field->id;
$association->value = '12/12/2012'; $association->value = '12/12/2012';
$association->save(); $association->save();
$customField = CustomField::findOne($this->customField->id); $custom_field = CustomField::findOne($this->custom_field->id);
$subscriber = $customField->subscribers() $subscriber = $custom_field->subscribers()->findOne();
->findOne();
expect($subscriber->value)->equals($association->value); expect($subscriber->value)->equals($association->value);
} }
function _after() { function _after() {
ORM::forTable(CustomField::$_table) CustomField::deleteMany();
->deleteMany(); Subscriber::deleteMany();
ORM::forTable(Subscriber::$_table) SubscriberCustomField::deleteMany();
->deleteMany();
ORM::forTable(SubscriberCustomField::$_table)
->deleteMany();
} }
} }

View File

@ -3,19 +3,14 @@ use MailPoet\Models\Form;
class FormCest { class FormCest {
function _before() { function _before() {
$this->before_time = time(); $this->form = Form::createOrUpdate(array(
$this->data = array( 'name' => 'My Form'
'name' => 'my form', ));
);
$this->form = Form::create();
$this->form->hydrate($this->data);
$this->saved = $this->form->save();
} }
function itCanBeCreated() { function itCanBeCreated() {
expect($this->saved->id() > 0)->true(); expect($this->form->id() > 0)->true();
expect($this->saved->getErrors())->false(); expect($this->form->getErrors())->false();
} }
function itHasToBeValid() { function itHasToBeValid() {
@ -27,60 +22,79 @@ class FormCest {
expect($errors[0])->equals('You need to specify a name.'); expect($errors[0])->equals('You need to specify a name.');
} }
function itCanBeGrouped() {
$forms = Form::filter('groupBy', 'all')->findArray();
expect($forms)->count(1);
$forms = Form::filter('groupBy', 'trash')->findArray();
expect($forms)->count(0);
$this->form->trash();
$forms = Form::filter('groupBy', 'trash')->findArray();
expect($forms)->count(1);
$forms = Form::filter('groupBy', 'all')->findArray();
expect($forms)->count(0);
$this->form->restore();
$forms = Form::filter('groupBy', 'all')->findArray();
expect($forms)->count(1);
}
function itCanBeSearched() {
$form = Form::filter('search', 'my F')->findOne();
expect($form->name)->equals('My Form');
}
function itHasACreatedAtOnCreation() { function itHasACreatedAtOnCreation() {
$form = Form::where('name', $this->data['name']) $form = Form::findOne($this->form->id);
->findOne(); expect($form->created_at)->notNull();
$time_difference = strtotime($form->created_at) >= $this->before_time; expect($form->created_at)->notEquals('0000-00-00 00:00:00');
expect($time_difference)->equals(true);
} }
function itHasAnUpdatedAtOnCreation() { function itHasAnUpdatedAtOnCreation() {
$form = Form::where('name', $this->data['name']) $form = Form::findOne($this->form->id);
->findOne(); expect($form->updated_at)
$time_difference = strtotime($form->updated_at) >= $this->before_time; ->equals($form->created_at);
expect($time_difference)->equals(true);
}
function itKeepsTheCreatedAtOnUpdate() {
$form = Form::where('name', $this->data['name'])
->findOne();
$old_created_at = $form->created_at;
$form->name = 'new name';
$form->save();
expect($old_created_at)->equals($form->created_at);
} }
function itUpdatesTheUpdatedAtOnUpdate() { function itUpdatesTheUpdatedAtOnUpdate() {
$form = Form::where('name', $this->data['name']) $form = Form::findOne($this->form->id);
->findOne(); $created_at = $form->created_at;
$update_time = time();
sleep(1);
$form->name = 'new name'; $form->name = 'new name';
$form->save(); $form->save();
$time_difference = strtotime($form->updated_at) >= $update_time;
expect($time_difference)->equals(true); $updated_form = Form::findOne($form->id);
expect($updated_form->created_at)->equals($created_at);
$is_time_updated = (
$updated_form->updated_at > $updated_form->created_at
);
expect($is_time_updated)->true();
} }
function itCanCreateOrUpdate() { function itCanCreateOrUpdate() {
$is_created = Form::createOrUpdate(array( $created_form = Form::createOrUpdate(array(
'name' => 'new form' 'name' => 'Created Form'
)); ));
expect($is_created)->notEquals(false); expect($created_form->id > 0)->true();
expect($is_created->getValidationErrors())->isEmpty(); expect($created_form->getErrors())->false();
$form = Form::where('name', 'new form')->findOne(); $form = Form::findOne($created_form->id);
expect($form->name)->equals('new form'); expect($form->name)->equals('Created Form');
$is_updated = Form::createOrUpdate(array( $is_updated = Form::createOrUpdate(array(
'id' => $form->id, 'id' => $created_form->id,
'name' => 'updated form' 'name' => 'Updated Form'
)); ));
$form = Form::where('name', 'updated form')->findOne(); $form = Form::findOne($created_form->id);
expect($form->name)->equals('updated form'); expect($form->name)->equals('Updated Form');
} }
function _after() { function _after() {
ORM::forTable(Form::$_table) Form::deleteMany();
->deleteMany();
} }
} }

View File

@ -2,76 +2,109 @@
use MailPoet\Models\Newsletter; use MailPoet\Models\Newsletter;
use MailPoet\Models\Segment; use MailPoet\Models\Segment;
use MailPoet\Models\SendingQueue;
use MailPoet\Models\NewsletterSegment; use MailPoet\Models\NewsletterSegment;
use MailPoet\Models\NewsletterOptionField; use MailPoet\Models\NewsletterOptionField;
use MailPoet\Models\NewsletterOption; use MailPoet\Models\NewsletterOption;
class NewsletterCest { class NewsletterCest {
function _before() { function _before() {
$this->before_time = time(); $this->newsletter = Newsletter::createOrUpdate(array(
$this->data = array( 'subject' => 'My Standard Newsletter',
'subject' => 'new newsletter', 'preheader' => 'Pre Header',
'type' => 'standard', 'type' => 'standard'
'body' => 'body', ));
'preheader' => 'preheader'
);
$newsletter = Newsletter::create(); $this->segment_1 = Segment::createOrUpdate(array(
$newsletter->hydrate($this->data); 'name' => 'Segment 1'
$this->newsletter = $newsletter; ));
$this->saved = $newsletter->save(); $association = NewsletterSegment::create();
$association->newsletter_id = $this->newsletter->id;
$association->segment_id = $this->segment_1->id;
$association->save();
$this->segment_2 = Segment::createOrUpdate(array(
'name' => 'Segment 2'
));
$association = NewsletterSegment::create();
$association->newsletter_id = $this->newsletter->id;
$association->segment_id = $this->segment_2->id;
$association->save();
} }
function itCanBeCreated() { function itCanBeCreated() {
expect($this->saved->id() > 0)->true(); expect($this->newsletter->id() > 0)->true();
expect($this->saved->getErrors())->false(); expect($this->newsletter->getErrors())->false();
} }
function itHasSubject() { function itHasASubject() {
$newsletter = Newsletter::where('subject', $this->data['subject']) $newsletter = Newsletter::findOne($this->newsletter->id);
->findOne(); expect($newsletter->subject)->equals($this->newsletter->subject);
expect($newsletter->subject)->equals($this->data['subject']);
} }
function itHasType() { function itHasAType() {
$newsletter = Newsletter::where('type', $this->data['type']) $newsletter = Newsletter::findOne($this->newsletter->id);
->findOne(); expect($newsletter->type)->equals($this->newsletter->type);
expect($newsletter->type)->equals($this->data['type']);
} }
function itHasBody() { function itHasABody() {
$newsletter = Newsletter::where('body', $this->data['body']) $newsletter = Newsletter::findOne($this->newsletter->id);
->findOne(); expect($newsletter->body)->equals($this->newsletter->body);
expect($newsletter->body)->equals($this->data['body']);
} }
function itHasPreheader() { function itHasPreheader() {
$newsletter = Newsletter::where('preheader', $this->data['preheader']) $newsletter = Newsletter::findOne($this->newsletter->id);
->findOne(); expect($newsletter->preheader)->equals($this->newsletter->preheader);
expect($newsletter->preheader)->equals($this->data['preheader']);
} }
function itCanHaveASegment() { function itHasACreatedAtOnCreation() {
$segmentData = array( $newsletter = Newsletter::findOne($this->newsletter->id);
'name' => 'my first list' expect($newsletter->created_at)->notNull();
); expect($newsletter->created_at)->notEquals('0000-00-00 00:00:00');
}
$segment = Segment::create(); function itHasAnUpdatedAtOnCreation() {
$segment->hydrate($segmentData); $newsletter = Newsletter::findOne($this->newsletter->id);
$segment->save(); expect($newsletter->updated_at)
->equals($newsletter->created_at);
}
$newsletter = Newsletter::create(); function itUpdatesTheUpdatedAtOnUpdate() {
$newsletter->hydrate($this->data); $newsletter = Newsletter::findOne($this->newsletter->id);
$created_at = $newsletter->created_at;
sleep(1);
$newsletter->subject = 'New Subject';
$newsletter->save(); $newsletter->save();
$association = NewsletterSegment::create(); $updated_newsletter = Newsletter::findOne($newsletter->id);
$association->newsletter_id = $newsletter->id(); expect($updated_newsletter->created_at)->equals($created_at);
$association->segment_id = $segment->id(); $is_time_updated = (
$association->save(); $updated_newsletter->updated_at > $updated_newsletter->created_at
);
expect($is_time_updated)->true();
}
$newsletter = Newsletter::findOne($newsletter->id); function itCanBeQueued() {
$newsletterSegment = $newsletter->segments()->findOne(); $queue = $this->newsletter->getQueue();
expect($newsletterSegment->id)->equals($segment->id); expect($queue)->false();
$sending_queue = SendingQueue::create();
$sending_queue->newsletter_id = $this->newsletter->id;
$sending_queue->save();
$queue = $this->newsletter->getQueue();
expect($queue->id() > 0)->true();
}
function itCanHaveSegments() {
$newsletter_segments = $this->newsletter->segments()->findArray();
expect($newsletter_segments)->count(2);
expect($newsletter_segments[0]['id'])->equals($this->segment_1->id);
expect($newsletter_segments[0]['name'])->equals('Segment 1');
expect($newsletter_segments[1]['id'])->equals($this->segment_2->id);
expect($newsletter_segments[1]['name'])->equals('Segment 2');
} }
function itCanCreateOrUpdate() { function itCanCreateOrUpdate() {
@ -97,6 +130,54 @@ class NewsletterCest {
expect($newsletter->subject)->equals('updated newsletter'); expect($newsletter->subject)->equals('updated newsletter');
} }
function itCannotSetAnEmptyDeletedAt() {
$this->newsletter->deleted_at = '';
$newsletter = $this->newsletter->save();
expect($newsletter->deleted_at)->equals('NULL');
}
function itCanBeFilteredBySegment() {
// no filter
$newsletters = Newsletter::filter('filterBy')->findArray();
expect($newsletters)->count(1);
// filter by segment
$newsletters = Newsletter::filter('filterBy', array(
'segment' => $this->segment_1->id
))->findArray();
expect($newsletters)->count(1);
expect($newsletters[0]['subject'])->equals($this->newsletter->subject);
// remove all segment relations to newsletters
NewsletterSegment::deleteMany();
$newsletters = Newsletter::filter('filterBy', array(
'segment' => $this->segment_1->id
))->findArray();
expect($newsletters)->isEmpty();
}
function itCanBeGrouped() {
$newsletters = Newsletter::filter('groupBy', 'all')->findArray();
expect($newsletters)->count(1);
$newsletters = Newsletter::filter('groupBy', 'trash')->findArray();
expect($newsletters)->count(0);
$this->newsletter->trash();
$newsletters = Newsletter::filter('groupBy', 'trash')->findArray();
expect($newsletters)->count(1);
$newsletters = Newsletter::filter('groupBy', 'all')->findArray();
expect($newsletters)->count(0);
$this->newsletter->restore();
$newsletters = Newsletter::filter('groupBy', 'all')->findArray();
expect($newsletters)->count(1);
}
function itHasSearchFilter() { function itHasSearchFilter() {
Newsletter::createOrUpdate( Newsletter::createOrUpdate(
array( array(
@ -110,16 +191,16 @@ class NewsletterCest {
} }
function itCanHaveOptions() { function itCanHaveOptions() {
$newsletterOptionFieldData = array( $newsletter_options = array(
'name' => 'Event', 'name' => 'Event',
'newsletter_type' => 'welcome', 'newsletter_type' => 'welcome',
); );
$optionField = NewsletterOptionField::create(); $option_field = NewsletterOptionField::create();
$optionField->hydrate($newsletterOptionFieldData); $option_field->hydrate($newsletter_options);
$optionField->save(); $option_field->save();
$association = NewsletterOption::create(); $association = NewsletterOption::create();
$association->newsletter_id = $this->newsletter->id; $association->newsletter_id = $this->newsletter->id;
$association->option_field_id = $optionField->id; $association->option_field_id = $option_field->id;
$association->value = 'list'; $association->value = 'list';
$association->save(); $association->save();
$newsletter = Newsletter::filter('filterWithOptions') $newsletter = Newsletter::filter('filterWithOptions')
@ -128,7 +209,7 @@ class NewsletterCest {
} }
function itCanFilterOptions() { function itCanFilterOptions() {
$newsletterOptionFieldData = array( $newsletter_options = array(
array( array(
'name' => 'Event', 'name' => 'Event',
'newsletter_type' => 'welcome', 'newsletter_type' => 'welcome',
@ -138,13 +219,13 @@ class NewsletterCest {
'newsletter_type' => 'welcome', 'newsletter_type' => 'welcome',
) )
); );
foreach ($newsletterOptionFieldData as $data) { foreach ($newsletter_options as $data) {
$optionField = NewsletterOptionField::create(); $option_field = NewsletterOptionField::create();
$optionField->hydrate($data); $option_field->hydrate($data);
$optionField->save(); $option_field->save();
$createdOptionFields[] = $optionField->asArray(); $createdOptionFields[] = $option_field->asArray();
} }
$newsletterOptionData = array( $newsletter_options = array(
array( array(
'newsletter_id' => $this->newsletter->id, 'newsletter_id' => $this->newsletter->id,
'option_field_id' => $createdOptionFields[0]['id'], 'option_field_id' => $createdOptionFields[0]['id'],
@ -156,12 +237,12 @@ class NewsletterCest {
'value' => '1' 'value' => '1'
) )
); );
foreach ($newsletterOptionData as $data) { foreach($newsletter_options as $data) {
$association = NewsletterOption::create(); $association = NewsletterOption::create();
$association->hydrate($data); $association->hydrate($data);
$association->save(); $association->save();
$createdAssociations[] = $association->asArray();
} }
$newsletter = Newsletter::filter('filterWithOptions') $newsletter = Newsletter::filter('filterWithOptions')
->filter('filterSearchCustomFields', array( ->filter('filterSearchCustomFields', array(
array( array(
@ -200,11 +281,11 @@ class NewsletterCest {
} }
function _after() { function _after() {
ORM::forTable(NewsletterOption::$_table) NewsletterOption::deleteMany();
->deleteMany(); NewsletterOptionField::deleteMany();
ORM::forTable(NewsletterOptionField::$_table) Newsletter::deleteMany();
->deleteMany(); Segment::deleteMany();
ORM::for_table(Newsletter::$_table) NewsletterSegment::deleteMany();
->deleteMany(); SendingQueue::deleteMany();
} }
} }

View File

@ -6,14 +6,14 @@ use MailPoet\Models\NewsletterOptionField;
class NewsletterOptionFieldCest { class NewsletterOptionFieldCest {
function _before() { function _before() {
$this->before_time = time();
$this->data = array( $this->data = array(
'name' => 'Event', 'name' => 'Event',
'newsletter_type' => 'welcome' 'newsletter_type' => 'welcome'
); );
$this->option_field = NewsletterOptionField::create(); $option = NewsletterOptionField::create();
$this->option_field->hydrate($this->data); $option->hydrate($this->data);
$this->saved = $this->option_field->save(); $this->option_field = $option->save();
$this->newsletter_data = array( $this->newsletter_data = array(
array( array(
'subject' => 'Test newsletter 1', 'subject' => 'Test newsletter 1',
@ -31,20 +31,17 @@ class NewsletterOptionFieldCest {
} }
function itCanBeCreated() { function itCanBeCreated() {
expect($this->saved->id() > 0)->true(); expect($this->option_field->id() > 0)->true();
expect($this->saved->getErrors())->false(); expect($this->option_field->getErrors())->false();
} }
function itHasName() { function itHasName() {
$option_field = NewsletterOptionField::where('name', $this->data['name']) expect($this->option_field->name)->equals($this->data['name']);
->findOne();
expect($option_field->name)->equals($this->data['name']);
} }
function itHasNewsletterType() { function itHasNewsletterType() {
$option_field = NewsletterOptionField::where('name', $this->data['name']) expect($this->option_field->newsletter_type)
->findOne(); ->equals($this->data['newsletter_type']);
expect($option_field->newsletter_type)->equals($this->data['newsletter_type']);
} }
function itHasToBeValid() { function itHasToBeValid() {
@ -58,36 +55,31 @@ class NewsletterOptionFieldCest {
} }
function itHasACreatedAtOnCreation() { function itHasACreatedAtOnCreation() {
$option_field = NewsletterOptionField::where('name', $this->data['name']) $option_field = NewsletterOptionField::findOne($this->option_field->id);
->findOne(); expect($option_field->created_at)->notNull();
$time_difference = strtotime($option_field->created_at) >= $this->before_time; expect($option_field->created_at)->notEquals('0000-00-00 00:00:00');
expect($time_difference)->equals(true);
} }
function itHasAnUpdatedAtOnCreation() { function itHasAnUpdatedAtOnCreation() {
$option_field = NewsletterOptionField::where('name', $this->data['name']) $option_field = NewsletterOptionField::findOne($this->option_field->id);
->findOne(); expect($option_field->updated_at)
$time_difference = strtotime($option_field->updated_at) >= $this->before_time; ->equals($option_field->created_at);
expect($time_difference)->equals(true);
}
function itKeepsTheCreatedAtOnUpdate() {
$option_field = NewsletterOptionField::where('name', $this->data['name'])
->findOne();
$old_created_at = $option_field->created_at;
$option_field->name = 'new name';
$option_field->save();
expect($old_created_at)->equals($option_field->created_at);
} }
function itUpdatesTheUpdatedAtOnUpdate() { function itUpdatesTheUpdatedAtOnUpdate() {
$option_field = NewsletterOptionField::where('name', $this->data['name']) $option_field = NewsletterOptionField::findOne($this->option_field->id);
->findOne(); $created_at = $option_field->created_at;
$update_time = time();
sleep(1);
$option_field->name = 'new name'; $option_field->name = 'new name';
$option_field->save(); $option_field->save();
$time_difference = strtotime($option_field->updated_at) >= $update_time;
expect($time_difference)->equals(true); $updated_option_field = NewsletterOptionField::findOne($option_field->id);
$is_time_updated = (
$updated_option_field->updated_at > $updated_option_field->created_at
);
expect($is_time_updated)->true();
} }
function itCanHaveManyNewsletters() { function itCanHaveManyNewsletters() {

View File

@ -4,7 +4,6 @@ use MailPoet\Models\NewsletterTemplate;
class NewsletterTemplateCest { class NewsletterTemplateCest {
function _before() { function _before() {
$this->before_time = time();
$this->data = array( $this->data = array(
'name' => 'Some template', 'name' => 'Some template',
'description' => 'My nice template', 'description' => 'My nice template',

View File

@ -8,11 +8,12 @@ use MailPoet\Models\SubscriberSegment;
class SegmentCest { class SegmentCest {
function _before() { function _before() {
$this->before_time = time();
$this->data = array( $this->data = array(
'name' => 'some name', 'name' => 'some name',
'description' => 'some description' 'description' => 'some description'
); );
$this->segment = Segment::createOrUpdate($this->data);
$this->subscribers_data = array( $this->subscribers_data = array(
array( array(
'first_name' => 'John', 'first_name' => 'John',
@ -37,7 +38,6 @@ class SegmentCest {
'type' => 'standard' 'type' => 'standard'
) )
); );
$this->segment = Segment::createOrUpdate($this->data);
} }
function itCanBeCreated() { function itCanBeCreated() {
@ -56,7 +56,9 @@ class SegmentCest {
$errors = $result->getErrors(); $errors = $result->getErrors();
expect(is_array($errors))->true(); expect(is_array($errors))->true();
expect($errors[0])->contains('Duplicate'); expect($errors[0])->equals(
'Another record already exists. Please specify a different "name".'
);
} }
function itCanHaveDescription() { function itCanHaveDescription() {
@ -74,36 +76,32 @@ class SegmentCest {
} }
function itHasACreatedAtOnCreation() { function itHasACreatedAtOnCreation() {
$segment = Segment::where('name', $this->data['name']) $segment = Segment::findOne($this->segment->id);
->findOne(); expect($segment->created_at)->notNull();
$time_difference = strtotime($segment->created_at) >= $this->before_time; expect($segment->created_at)->notEquals('0000-00-00 00:00:00');
expect($time_difference)->equals(true);
} }
function itHasAnUpdatedAtOnCreation() { function itHasAnUpdatedAtOnCreation() {
$segment = Segment::where('name', $this->data['name']) $segment = Segment::findOne($this->segment->id);
->findOne(); expect($segment->updated_at)
$time_difference = strtotime($segment->updated_at) >= $this->before_time; ->equals($segment->created_at);
expect($time_difference)->equals(true);
}
function itKeepsTheCreatedAtOnUpdate() {
$segment = Segment::where('name', $this->data['name'])
->findOne();
$old_created_at = $segment->created_at;
$segment->name = 'new name';
$segment->save();
expect($old_created_at)->equals($segment->created_at);
} }
function itUpdatesTheUpdatedAtOnUpdate() { function itUpdatesTheUpdatedAtOnUpdate() {
$segment = Segment::where('name', $this->data['name']) $segment = Segment::findOne($this->segment->id);
->findOne(); $created_at = $segment->created_at;
$update_time = time();
sleep(1);
$segment->name = 'new name'; $segment->name = 'new name';
$segment->save(); $segment->save();
$time_difference = strtotime($segment->updated_at) >= $update_time;
expect($time_difference)->equals(true); $updated_segment = Segment::findOne($segment->id);
expect($updated_segment->created_at)->equals($created_at);
$is_time_updated = (
$updated_segment->updated_at > $updated_segment->created_at
);
expect($is_time_updated)->true();
} }
function itCanCreateOrUpdate() { function itCanCreateOrUpdate() {

View File

@ -2,63 +2,61 @@
use MailPoet\Models\Setting; use MailPoet\Models\Setting;
class SettingCest { class SettingCest {
function _before() {
$this->before_time = time();
$this->data = array(
'name' => 'sending_method',
'value' => 'smtp'
);
$setting = Setting::create();
$setting->hydrate($this->data);
$this->saved = $setting->save();
}
function itCanBeCreated() { function itCanBeCreated() {
expect($this->saved->id() > 0)->true(); $setting = Setting::createOrUpdate(array(
expect($this->saved->getErrors())->false(); 'name' => 'key',
'value' => 'val'
));
expect($setting->id() > 0)->true();
expect($setting->getErrors())->false();
} }
function itHasToBeValid() { function itHasToBeValid() {
$invalid_setting = Setting::create(); $invalid_setting = Setting::createOrUpdate();
$result = $invalid_setting->save(); $errors = $invalid_setting->getErrors();
$errors = $result->getErrors();
expect(is_array($errors))->true(); expect($errors)->notEmpty();
expect($errors[0])->equals('You need to specify a name.'); expect($errors[0])->equals('You need to specify a name.');
} }
function itHasACreatedAtOnCreation() { function itCanGetAllSettings() {
$setting = Setting::where('name', $this->data['name']) Setting::setValue('key_1', 'value_1');
->findOne(); Setting::setValue('key_2', 'value_2');
$time_difference = strtotime($setting->created_at) >= $this->before_time; Setting::setValue('key_3', array(
expect($time_difference)->equals(true); 'subkey_1' => 'subvalue_1',
'subkey_2' => 'subvalue_2'
));
$settings = Setting::getAll();
expect(array_keys($settings))->count(3);
expect($settings['key_1'])->equals('value_1');
expect($settings['key_2'])->equals('value_2');
expect($settings['key_3'])->equals(array(
'subkey_1' => 'subvalue_1',
'subkey_2' => 'subvalue_2'
));
} }
function itHasAnUpdatedAtOnCreation() { function itReturnsDefaultValueIfNotSet() {
$setting = Setting::where('name', $this->data['name']) // try to get an "unknown" key
->findOne(); $setting = Setting::getValue('unknown_key', 'default_value');
$time_difference = strtotime($setting->updated_at) >= $this->before_time; expect($setting)->equals('default_value');
expect($time_difference)->equals(true);
}
function itKeepsTheCreatedAtOnUpdate() { // setting a "known" key
$setting = Setting::where('name', $this->data['name']) $setting = Setting::setValue('known_key', 'actual_value');
->findOne(); expect($setting)->equals(true);
$old_created_at = $setting->created_at;
$setting->value = 'http_api';
$setting->save();
expect($old_created_at)->equals($setting->created_at);
}
function itUpdatesTheUpdatedAtOnUpdate() { // try to get a "known" key
$setting = Setting::where('name', $this->data['name']) $setting = Setting::getValue('known_key', 'default_value');
->findOne(); expect($setting)->equals('actual_value');
$update_time = time();
$setting->value = 'http_api'; // try to get an "unknown" subkey of a "known" key
$setting->save(); $setting = Setting::getValue('known_key.unknown_subkey', 'default_value');
$time_difference = strtotime($setting->updated_at) >= $update_time; expect($setting)->equals('default_value');
expect($time_difference)->equals(true);
// try to get an "unknown" subkey of an "unknown" key
$setting = Setting::getValue('unknown_key.unknown_subkey', 'default_value');
expect($setting)->equals('default_value');
} }
function itCanCreateOrUpdate() { function itCanCreateOrUpdate() {
@ -109,7 +107,6 @@ class SettingCest {
} }
function _after() { function _after() {
ORM::forTable(Setting::$_table) Setting::deleteMany();
->deleteMany();
} }
} }

View File

@ -23,6 +23,7 @@ class NewsletterRendererCest {
$this->DOM_parser = new \pQuery(); $this->DOM_parser = new \pQuery();
} }
function itRendersCompleteNewsletter() { function itRendersCompleteNewsletter() {
$template = $this->renderer->render(); $template = $this->renderer->render();
expect(isset($template['html']))->true(); expect(isset($template['html']))->true();
@ -125,17 +126,33 @@ class NewsletterRendererCest {
expect($DOM('tr > td > img', 0)->attr('style'))->notEmpty(); expect($DOM('tr > td > img', 0)->attr('style'))->notEmpty();
} }
function itAdjustImageSizeBasedOnColumnWidth() { function itAdjustsImageDimensions() {
$newsletter = json_decode($this->newsletter['body'], true); // image gets scaled down when image width > column width
$template = $newsletter['content']['blocks'][0]['blocks'][0]['blocks'][1]; $image = array(
$template['width'] = '800px'; 'width' => 800,
$DOM = $this->DOM_parser->parseStr(Image::render($template, $columnCount = 2)); 'height' => 600,
// 800px resized to 330px (2-column layout) and 40px padding applied 'fullWidth' => true
expect($DOM('tr > td > img', 0)->attr('width'))->equals(290); );
$template['width'] = '280px'; $new_image_dimensions = Image::adjustImageDimensions($image, $columnCount = 1);
$DOM = $this->DOM_parser->parseStr(Image::render($template, $columnCount = 2)); expect($new_image_dimensions['width'])->equals(660);
// 280px image should not be resized and padding should not be applied expect($new_image_dimensions['height'])->equals(495);
expect($DOM('tr > td > img', 0)->attr('width'))->equals(280); // nothing happens when image width = column width
$image['width'] = 661;
$new_image_dimensions = Image::adjustImageDimensions($image, $columnCount = 1);
expect($new_image_dimensions['width'])->equals(660);
// nothing happens when image width < column width
$image['width'] = 659;
$new_image_dimensions = Image::adjustImageDimensions($image, $columnCount = 1);
expect($new_image_dimensions['width'])->equals(659);
// image is reduced by 40px when it's width > padded column width
$image['width'] = 621;
$image['fullWidth'] = false;
$new_image_dimensions = Image::adjustImageDimensions($image, $columnCount = 1);
expect($new_image_dimensions['width'])->equals(620);
// nothing happens when image with < padded column width
$image['width'] = 619;
$new_image_dimensions = Image::adjustImageDimensions($image, $columnCount = 1);
expect($new_image_dimensions['width'])->equals(619);
} }
function itRendersText() { function itRendersText() {

View File

@ -44,7 +44,7 @@
"link": "", "link": "",
"src": "http://test.mailpoet.net/wp-content/uploads/2015/12/660.png", "src": "http://test.mailpoet.net/wp-content/uploads/2015/12/660.png",
"alt": "660", "alt": "660",
"padded": true, "fullWidth": false,
"width": "660px", "width": "660px",
"height": "250px", "height": "250px",
"styles": { "styles": {
@ -199,7 +199,7 @@
"link": "http://example.org", "link": "http://example.org",
"src": "http://test.mailpoet.net/wp-content/uploads/2015/12/660.png", "src": "http://test.mailpoet.net/wp-content/uploads/2015/12/660.png",
"alt": "660", "alt": "660",
"padded": false, "fullWidth": true,
"width": "660px", "width": "660px",
"height": "250px", "height": "250px",
"styles": { "styles": {
@ -235,7 +235,7 @@
"link": "", "link": "",
"src": "http://test.mailpoet.net/wp-content/uploads/2015/12/330x125.png", "src": "http://test.mailpoet.net/wp-content/uploads/2015/12/330x125.png",
"alt": "330x125", "alt": "330x125",
"padded": true, "fullWidth": false,
"width": "330px", "width": "330px",
"height": "125px", "height": "125px",
"styles": { "styles": {
@ -390,7 +390,7 @@
"link": "http://example.org", "link": "http://example.org",
"src": "http://test.mailpoet.net/wp-content/uploads/2015/12/330x125.png", "src": "http://test.mailpoet.net/wp-content/uploads/2015/12/330x125.png",
"alt": "330x125", "alt": "330x125",
"padded": false, "fullWidth": true,
"width": "330px", "width": "330px",
"height": "125px", "height": "125px",
"styles": { "styles": {
@ -415,7 +415,7 @@
"link": "", "link": "",
"src": "http://test.mailpoet.net/wp-content/uploads/2015/12/330x125-copy-150x57.png", "src": "http://test.mailpoet.net/wp-content/uploads/2015/12/330x125-copy-150x57.png",
"alt": "330x125 copy", "alt": "330x125 copy",
"padded": true, "fullWidth": false,
"width": "150px", "width": "150px",
"height": "57px", "height": "57px",
"styles": { "styles": {
@ -561,7 +561,7 @@
"link": "http://example.org", "link": "http://example.org",
"src": "http://test.mailpoet.net/wp-content/uploads/2015/12/330x125.png", "src": "http://test.mailpoet.net/wp-content/uploads/2015/12/330x125.png",
"alt": "330x125", "alt": "330x125",
"padded": false, "fullWidth": true,
"width": "330px", "width": "330px",
"height": "125px", "height": "125px",
"styles": { "styles": {
@ -606,7 +606,7 @@
"link": "", "link": "",
"src": "http://test.mailpoet.net/wp-content/uploads/2015/12/220x83-copy.png", "src": "http://test.mailpoet.net/wp-content/uploads/2015/12/220x83-copy.png",
"alt": "220x83 copy", "alt": "220x83 copy",
"padded": true, "fullWidth": false,
"width": "100px", "width": "100px",
"height": "38px", "height": "38px",
"styles": { "styles": {
@ -761,7 +761,7 @@
"link": "", "link": "",
"src": "http://test.mailpoet.net/wp-content/uploads/2015/12/220x83.png", "src": "http://test.mailpoet.net/wp-content/uploads/2015/12/220x83.png",
"alt": "220x83", "alt": "220x83",
"padded": false, "fullWidth": true,
"width": "220px", "width": "220px",
"height": "83px", "height": "83px",
"styles": { "styles": {
@ -786,7 +786,7 @@
"link": "", "link": "",
"src": "http://test.mailpoet.net/wp-content/uploads/2015/12/220x83.png", "src": "http://test.mailpoet.net/wp-content/uploads/2015/12/220x83.png",
"alt": "220x83", "alt": "220x83",
"padded": true, "fullWidth": false,
"width": "220px", "width": "220px",
"height": "83px", "height": "83px",
"styles": { "styles": {
@ -941,7 +941,7 @@
"link": "http://example.org", "link": "http://example.org",
"src": "http://test.mailpoet.net/wp-content/uploads/2015/12/220x83.png", "src": "http://test.mailpoet.net/wp-content/uploads/2015/12/220x83.png",
"alt": "220x83", "alt": "220x83",
"padded": false, "fullWidth": true,
"width": "220px", "width": "220px",
"height": "83px", "height": "83px",
"styles": { "styles": {
@ -966,7 +966,7 @@
"link": "", "link": "",
"src": "http://test.mailpoet.net/wp-content/uploads/2015/12/220x83.png", "src": "http://test.mailpoet.net/wp-content/uploads/2015/12/220x83.png",
"alt": "220x83", "alt": "220x83",
"padded": true, "fullWidth": false,
"width": "220px", "width": "220px",
"height": "83px", "height": "83px",
"styles": { "styles": {
@ -1121,7 +1121,7 @@
"link": "http://example.org", "link": "http://example.org",
"src": "http://test.mailpoet.net/wp-content/uploads/2015/12/220x83.png", "src": "http://test.mailpoet.net/wp-content/uploads/2015/12/220x83.png",
"alt": "220x83", "alt": "220x83",
"padded": false, "fullWidth": true,
"width": "220px", "width": "220px",
"height": "83px", "height": "83px",
"styles": { "styles": {
@ -1215,4 +1215,4 @@
"backgroundColor": "#333333" "backgroundColor": "#333333"
} }
} }
} }

View File

@ -69,13 +69,17 @@ class CustomFieldsCest {
function itCanDeleteACustomField() { function itCanDeleteACustomField() {
$custom_field = CustomField::where('type', 'date')->findOne(); $custom_field = CustomField::where('type', 'date')->findOne();
$custom_field_id = $custom_field->id();
$router = new CustomFields(); $router = new CustomFields();
$response = $router->delete($custom_field->id()); $response = $router->delete($custom_field_id);
expect($response['result'])->true(); expect($response['result'])->true();
$custom_field = CustomField::where('type', 'date')->findOne(); $custom_field = CustomField::where('type', 'date')->findOne();
expect($custom_field)->false(); expect($custom_field)->false();
$response = $router->delete($custom_field_id);
expect($response['result'])->false();
} }
function itCanSaveACustomField() { function itCanSaveACustomField() {
@ -120,6 +124,6 @@ class CustomFieldsCest {
} }
function _after() { function _after() {
ORM::forTable(CustomField::$_table)->deleteMany(); CustomField::deleteMany();
} }
} }

View File

@ -165,6 +165,28 @@ class FormsCest {
expect($duplicated_form->name)->equals('Copy of '.$form->name); expect($duplicated_form->name)->equals('Copy of '.$form->name);
} }
function itCanBulkDeleteForms() {
expect(Form::count())->equals(3);
$forms = Form::findMany();
foreach($forms as $form) {
$form->trash();
}
$router = new Forms();
$response = $router->bulkAction(array(
'action' => 'delete',
'listing' => array('group' => 'trash')
));
expect($response)->equals(3);
$response = $router->bulkAction(array(
'action' => 'delete',
'listing' => array('group' => 'trash')
));
expect($response)->equals(0);
}
function _after() { function _after() {
Form::deleteMany(); Form::deleteMany();
Segment::deleteMany(); Segment::deleteMany();

View File

@ -7,20 +7,22 @@ use \MailPoet\Models\Segment;
class NewslettersCest { class NewslettersCest {
function _before() { function _before() {
$this->newsletter = Newsletter::createOrUpdate(array(
'subject' => 'My Standard Newsletter',
'type' => 'standard'
));
$this->post_notification = Newsletter::createOrUpdate(array(
'subject' => 'My Post Notification',
'type' => 'notification'
));
} }
function itCanGetANewsletter() { function itCanGetANewsletter() {
$newsletter = Newsletter::createOrUpdate(array(
'subject' => 'My First Newsletter',
'type' => 'standard'
));
expect($newsletter->id() > 0)->true();
$router = new Newsletters(); $router = new Newsletters();
$response = $router->get($newsletter->id()); $response = $router->get($this->newsletter->id());
expect($response['id'])->equals($this->newsletter->id());
expect($response['id'])->equals($newsletter->id());
$response = $router->get('not_an_id'); $response = $router->get('not_an_id');
expect($response)->false(); expect($response)->false();
@ -50,82 +52,57 @@ class NewslettersCest {
} }
function itCanSaveAnExistingNewsletter() { function itCanSaveAnExistingNewsletter() {
$newsletter = Newsletter::createOrUpdate(array(
'subject' => 'My First Newsletter',
'type' => 'standard'
));
expect($newsletter->id() > 0)->true();
$router = new Newsletters(); $router = new Newsletters();
$newsletter_data = $newsletter->asArray(); $newsletter_data = $this->newsletter->asArray();
$newsletter_data['subject'] = 'My Updated Newsletter'; $newsletter_data['subject'] = 'My Updated Newsletter';
$response = $router->save($newsletter_data); $response = $router->save($newsletter_data);
expect($response['result'])->true(); expect($response['result'])->true();
$updated_newsletter = Newsletter::findOne($newsletter->id()); $updated_newsletter = Newsletter::findOne($this->newsletter->id());
expect($updated_newsletter->subject)->equals('My Updated Newsletter'); expect($updated_newsletter->subject)->equals('My Updated Newsletter');
} }
function itCanRestoreANewsletter() { function itCanRestoreANewsletter() {
$newsletter = Newsletter::createOrUpdate(array( $this->newsletter->trash();
'subject' => 'My First Newsletter',
'type' => 'standard'
));
expect($newsletter->id() > 0)->true();
$newsletter->trash(); expect($this->newsletter->deleted_at)->notNull();
expect($newsletter->deleted_at)->notNull();
$router = new Newsletters(); $router = new Newsletters();
$router->restore($newsletter->id()); $router->restore($this->newsletter->id());
$restored_subscriber = Newsletter::findOne($newsletter->id()); $restored_subscriber = Newsletter::findOne($this->newsletter->id());
expect($restored_subscriber->deleted_at)->null(); expect($restored_subscriber->deleted_at)->null();
} }
function itCanTrashANewsletter() { function itCanTrashANewsletter() {
$newsletter = Newsletter::createOrUpdate(array(
'subject' => 'My First Newsletter',
'type' => 'standard'
));
expect($newsletter->id() > 0)->true();
$router = new Newsletters(); $router = new Newsletters();
$response = $router->trash($newsletter->id()); $response = $router->trash($this->newsletter->id());
expect($response)->true(); expect($response)->true();
$trashed_subscriber = Newsletter::findOne($newsletter->id()); $trashed_subscriber = Newsletter::findOne($this->newsletter->id());
expect($trashed_subscriber->deleted_at)->notNull(); expect($trashed_subscriber->deleted_at)->notNull();
} }
function itCanDeleteANewsletter() { function itCanDeleteANewsletter() {
$newsletter = Newsletter::createOrUpdate(array(
'subject' => 'My First Newsletter',
'type' => 'standard'
));
expect($newsletter->id() > 0)->true();
$router = new Newsletters(); $router = new Newsletters();
$response = $router->delete($newsletter->id()); $response = $router->delete($this->newsletter->id());
expect($response)->equals(1); expect($response)->equals(1);
expect(Newsletter::findOne($newsletter->id()))->false(); expect(Newsletter::findOne($this->newsletter->id()))->false();
} }
function itCanDuplicateANewsletter() { function itCanDuplicateANewsletter() {
$newsletter = Newsletter::createOrUpdate(array(
'subject' => 'My First Newsletter',
'type' => 'standard'
));
expect($newsletter->id() > 0)->true();
$router = new Newsletters(); $router = new Newsletters();
$response = $router->duplicate($newsletter->id()); $response = $router->duplicate($this->newsletter->id());
expect($response['subject'])->equals('Copy of My First Newsletter'); expect($response['subject'])->equals('Copy of My Standard Newsletter');
expect($response['type'])->equals('standard'); expect($response['type'])->equals('standard');
expect($response['body'])->equals($newsletter->body); expect($response['body'])->equals($this->newsletter->body);
$response = $router->duplicate($this->post_notification->id());
expect($response['subject'])->equals('Copy of My Post Notification');
expect($response['type'])->equals('notification');
expect($response['body'])->equals($this->post_notification->body);
} }
function itCanCreateANewsletter() { function itCanCreateANewsletter() {
@ -151,38 +128,29 @@ class NewslettersCest {
$segment_1 = Segment::createOrUpdate(array('name' => 'Segment 1')); $segment_1 = Segment::createOrUpdate(array('name' => 'Segment 1'));
$segment_2 = Segment::createOrUpdate(array('name' => 'Segment 2')); $segment_2 = Segment::createOrUpdate(array('name' => 'Segment 2'));
$newsletter_1 = Newsletter::createOrUpdate(array(
'subject' => 'My First Newsletter',
'type' => 'standard'
));
$newsletter_2 = Newsletter::createOrUpdate(array(
'subject' => 'My Second Newsletter',
'type' => 'standard'
));
$newsletter_segment = NewsletterSegment::create(); $newsletter_segment = NewsletterSegment::create();
$newsletter_segment->hydrate(array( $newsletter_segment->hydrate(array(
'newsletter_id' => $newsletter_1->id(), 'newsletter_id' => $this->newsletter->id(),
'segment_id' => $segment_1->id() 'segment_id' => $segment_1->id()
)); ));
$newsletter_segment->save(); $newsletter_segment->save();
$newsletter_segment = NewsletterSegment::create(); $newsletter_segment = NewsletterSegment::create();
$newsletter_segment->hydrate(array( $newsletter_segment->hydrate(array(
'newsletter_id' => $newsletter_1->id(), 'newsletter_id' => $this->newsletter->id(),
'segment_id' => $segment_2->id() 'segment_id' => $segment_2->id()
)); ));
$newsletter_segment->save(); $newsletter_segment->save();
$newsletter_segment = NewsletterSegment::create(); $newsletter_segment = NewsletterSegment::create();
$newsletter_segment->hydrate(array( $newsletter_segment->hydrate(array(
'newsletter_id' => $newsletter_2->id(), 'newsletter_id' => $this->post_notification->id(),
'segment_id' => $segment_2->id() 'segment_id' => $segment_2->id()
)); ));
$newsletter_segment->save(); $newsletter_segment->save();
$router = new Newsletters(); $router = new Newsletters();
$response = $router->listing(array('sort')); $response = $router->listing();
expect($response)->hasKey('filters'); expect($response)->hasKey('filters');
expect($response)->hasKey('groups'); expect($response)->hasKey('groups');
@ -190,8 +158,8 @@ class NewslettersCest {
expect($response['count'])->equals(2); expect($response['count'])->equals(2);
expect($response['items'])->count(2); expect($response['items'])->count(2);
expect($response['items'][0]['subject'])->equals('My First Newsletter'); expect($response['items'][0]['subject'])->equals('My Standard Newsletter');
expect($response['items'][1]['subject'])->equals('My Second Newsletter'); expect($response['items'][1]['subject'])->equals('My Post Notification');
expect($response['items'][0]['segments'])->equals(array( expect($response['items'][0]['segments'])->equals(array(
$segment_1->id(), $segment_1->id(),
$segment_2->id() $segment_2->id()
@ -201,6 +169,28 @@ class NewslettersCest {
)); ));
} }
function itCanBulkDeleteNewsletters() {
expect(Newsletter::count())->equals(2);
$newsletters = Newsletter::findMany();
foreach($newsletters as $newsletter) {
$newsletter->trash();
}
$router = new Newsletters();
$response = $router->bulkAction(array(
'action' => 'delete',
'listing' => array('group' => 'trash')
));
expect($response)->equals(2);
$response = $router->bulkAction(array(
'action' => 'delete',
'listing' => array('group' => 'trash')
));
expect($response)->equals(0);
}
function _after() { function _after() {
Newsletter::deleteMany(); Newsletter::deleteMany();
Segment::deleteMany(); Segment::deleteMany();

View File

@ -4,14 +4,12 @@ use \MailPoet\Models\Segment;
class SegmentsCest { class SegmentsCest {
function _before() { function _before() {
Segment::createOrUpdate(array('name' => 'Segment 1')); $this->segment_1 = Segment::createOrUpdate(array('name' => 'Segment 1'));
Segment::createOrUpdate(array('name' => 'Segment 2')); $this->segment_2 = Segment::createOrUpdate(array('name' => 'Segment 2'));
Segment::createOrUpdate(array('name' => 'Segment 3')); $this->segment_3 = Segment::createOrUpdate(array('name' => 'Segment 3'));
} }
function itCanGetASegment() { function itCanGetASegment() {
$segment = Segment::where('name', 'Segment 1')->findOne();
$router = new Segments(); $router = new Segments();
$response = $router->get(/* missing id */); $response = $router->get(/* missing id */);
@ -20,8 +18,8 @@ class SegmentsCest {
$response = $router->get('not_an_id'); $response = $router->get('not_an_id');
expect($response)->false(); expect($response)->false();
$response = $router->get($segment->id()); $response = $router->get($this->segment_1->id());
expect($response['name'])->equals($segment->name); expect($response['name'])->equals($this->segment_1->name);
} }
function itCanGetListingData() { function itCanGetListingData() {
@ -33,9 +31,9 @@ class SegmentsCest {
expect($response['count'])->equals(3); expect($response['count'])->equals(3);
expect($response['items'])->count(3); expect($response['items'])->count(3);
expect($response['items'][0]['name'])->equals('Segment 1'); expect($response['items'][0]['name'])->equals($this->segment_1->name);
expect($response['items'][1]['name'])->equals('Segment 2'); expect($response['items'][1]['name'])->equals($this->segment_2->name);
expect($response['items'][2]['name'])->equals('Segment 3'); expect($response['items'][2]['name'])->equals($this->segment_3->name);
} }
function itCanSaveASegment() { function itCanSaveASegment() {
@ -55,57 +53,83 @@ class SegmentsCest {
expect($segment->name)->equals($segment_data['name']); expect($segment->name)->equals($segment_data['name']);
} }
function itCanRestoreASegment() { function itCannotSaveDuplicate() {
$segment = Segment::where('name', 'Segment 1')->findOne(); $duplicate_entry = array(
$segment->trash(); 'name' => 'Segment 1'
);
$trashed_segment = Segment::findOne($segment->id()); $router = new Segments();
$response = $router->save($duplicate_entry);
expect($response['result'])->false();
expect($response['errors'][0])->equals(
'Another record already exists. Please specify a different "name".'
);
}
function itCanRestoreASegment() {
$this->segment_1->trash();
$trashed_segment = Segment::findOne($this->segment_1->id());
expect($trashed_segment->deleted_at)->notNull(); expect($trashed_segment->deleted_at)->notNull();
$router = new Segments(); $router = new Segments();
$response = $router->restore($segment->id()); $response = $router->restore($this->segment_1->id());
expect($response)->true(); expect($response)->true();
$restored_segment = Segment::findOne($segment->id()); $restored_segment = Segment::findOne($this->segment_1->id());
expect($restored_segment->deleted_at)->null(); expect($restored_segment->deleted_at)->null();
} }
function itCanTrashASegment() { function itCanTrashASegment() {
$segment = Segment::where('name', 'Segment 1')->findOne();
expect($segment->deleted_at)->null();
$router = new Segments(); $router = new Segments();
$response = $router->trash($segment->id()); $response = $router->trash($this->segment_2->id());
expect($response)->true(); expect($response)->true();
$trashed_segment = Segment::findOne($segment->id()); $trashed_segment = Segment::findOne($this->segment_2->id());
expect($trashed_segment->deleted_at)->notNull(); expect($trashed_segment->deleted_at)->notNull();
} }
function itCanDeleteASegment() { function itCanDeleteASegment() {
$segment = Segment::where('name', 'Segment 2')->findOne();
expect($segment->deleted_at)->null();
$router = new Segments(); $router = new Segments();
$response = $router->delete($segment->id()); $response = $router->delete($this->segment_3->id());
expect($response)->equals(1); expect($response)->equals(1);
$deleted_segment = Segment::findOne($segment->id()); $deleted_segment = Segment::findOne($this->segment_3->id());
expect($deleted_segment)->false(); expect($deleted_segment)->false();
} }
function itCanDuplicateASegment() { function itCanDuplicateASegment() {
$segment = Segment::where('name', 'Segment 3')->findOne();
$router = new Segments(); $router = new Segments();
$response = $router->duplicate($segment->id()); $response = $router->duplicate($this->segment_1->id());
expect($response['name'])->equals('Copy of '.$segment->name); expect($response['name'])->equals('Copy of '.$this->segment_1->name);
$duplicated_segment = Segment::findOne($response['id']); $duplicated_segment = Segment::findOne($response['id']);
expect($duplicated_segment->name)->equals('Copy of '.$segment->name); expect($duplicated_segment->name)->equals('Copy of '.$this->segment_1->name);
}
function itCanBulkDeleteSegments() {
expect(Segment::count())->equals(3);
$segments = Segment::findMany();
foreach($segments as $segment) {
$segment->trash();
}
$router = new Segments();
$response = $router->bulkAction(array(
'action' => 'delete',
'listing' => array('group' => 'trash')
));
expect($response)->equals(3);
$response = $router->bulkAction(array(
'action' => 'delete',
'listing' => array('group' => 'trash')
));
expect($response)->equals(0);
} }
function _after() { function _after() {
ORM::forTable(Segment::$_table)->deleteMany(); Segment::deleteMany();
} }
} }

View File

@ -6,18 +6,33 @@ use \MailPoet\Models\Segment;
class SubscribersCest { class SubscribersCest {
function _before() { function _before() {
$this->segment_1 = Segment::createOrUpdate(array('name' => 'Segment 1'));
$this->segment_2 = Segment::createOrUpdate(array('name' => 'Segment 2'));
$this->subscriber_1 = Subscriber::createOrUpdate(array(
'email' => 'john.doe@mailpoet.com',
'first_name' => 'John',
'last_name' => 'Doe'
));
$this->subscriber_2 = Subscriber::createOrUpdate(array(
'email' => 'jane.doe@mailpoet.com',
'first_name' => 'Jane',
'last_name' => 'Doe',
'segments' => array(
$this->segment_1->id(),
$this->segment_2->id()
)
));
} }
function itCanGetASubscriber() { function itCanGetASubscriber() {
$subscriber = Subscriber::createOrUpdate(array(
'email' => 'john.doe@mailpoet.com'
));
expect($subscriber->id() > 0)->true();
$router = new Subscribers(); $router = new Subscribers();
$response = $router->get($subscriber->id()); $response = $router->get($this->subscriber_1->id());
expect($response['id'])->equals($subscriber->id()); expect($response['id'])->equals($this->subscriber_1->id());
expect($response['email'])->equals($this->subscriber_1->email);
expect($response['first_name'])->equals($this->subscriber_1->first_name);
expect($response['last_name'])->equals($this->subscriber_1->last_name);
$response = $router->get('not_an_id'); $response = $router->get('not_an_id');
expect($response)->false(); expect($response)->false();
@ -30,7 +45,11 @@ class SubscribersCest {
$valid_data = array( $valid_data = array(
'email' => 'john.doe@mailpoet.com', 'email' => 'john.doe@mailpoet.com',
'first_name' => 'John', 'first_name' => 'John',
'last_name' => 'Doe' 'last_name' => 'Doe',
'segments' => array(
$this->segment_1->id(),
$this->segment_2->id()
)
); );
$router = new Subscribers(); $router = new Subscribers();
@ -38,6 +57,12 @@ class SubscribersCest {
expect($response['result'])->true(); expect($response['result'])->true();
expect($response)->hasntKey('errors'); expect($response)->hasntKey('errors');
$subscriber = Subscriber::where('email', 'john.doe@mailpoet.com')->findOne();
$subscriber_segments = $subscriber->segments()->findMany();
expect($subscriber_segments)->count(2);
expect($subscriber_segments[0]->name)->equals($this->segment_1->name);
expect($subscriber_segments[1]->name)->equals($this->segment_2->name);
$response = $router->save(/* missing data */); $response = $router->save(/* missing data */);
expect($response['result'])->false(); expect($response['result'])->false();
expect($response['errors'][0])->equals('You need to enter your email address.'); expect($response['errors'][0])->equals('You need to enter your email address.');
@ -54,80 +79,73 @@ class SubscribersCest {
} }
function itCanSaveAnExistingSubscriber() { function itCanSaveAnExistingSubscriber() {
$subscriber = Subscriber::createOrUpdate(array(
'email' => 'john.doe@mailpoet.com',
'first_name' => 'John',
'last_name' => 'Doe'
));
expect($subscriber->id() > 0)->true();
$router = new Subscribers(); $router = new Subscribers();
$subscriber_data = $this->subscriber_2->asArray();
$subscriber_data = $subscriber->asArray(); unset($subscriber_data['created_at']);
$subscriber_data['segments'] = array($this->segment_1->id());
$subscriber_data['email'] = 'jane.doe@mailpoet.com'; $subscriber_data['first_name'] = 'Super Jane';
$subscriber_data['first_name'] = 'Jane';
$response = $router->save($subscriber_data); $response = $router->save($subscriber_data);
expect($response['result'])->true(); expect($response['result'])->true();
$updated_subscriber = Subscriber::findOne($subscriber->id()); $updated_subscriber = Subscriber::findOne($this->subscriber_2->id());
expect($updated_subscriber->email)->equals('jane.doe@mailpoet.com'); expect($updated_subscriber->email)->equals('jane.doe@mailpoet.com');
expect($updated_subscriber->first_name)->equals('Jane'); expect($updated_subscriber->first_name)->equals('Super Jane');
} }
function itCanRestoreASubscriber() { function itCanRestoreASubscriber() {
$subscriber = Subscriber::createOrUpdate(array( $this->subscriber_1->trash();
'email' => 'john.doe@mailpoet.com',
'first_name' => 'John',
'last_name' => 'Doe'
));
expect($subscriber->id() > 0)->true();
$subscriber->trash(); expect($this->subscriber_1->deleted_at)->notNull();
expect($subscriber->deleted_at)->notNull();
$router = new Subscribers(); $router = new Subscribers();
$router->restore($subscriber->id()); $router->restore($this->subscriber_1->id());
$restored_subscriber = Subscriber::findOne($subscriber->id()); $restored_subscriber = Subscriber::findOne($this->subscriber_1->id());
expect($restored_subscriber->deleted_at)->null(); expect($restored_subscriber->deleted_at)->null();
} }
function itCanTrashASubscriber() { function itCanTrashASubscriber() {
$subscriber = Subscriber::createOrUpdate(array(
'email' => 'john.doe@mailpoet.com',
'first_name' => 'John',
'last_name' => 'Doe'
));
expect($subscriber->id() > 0)->true();
$router = new Subscribers(); $router = new Subscribers();
$response = $router->trash($subscriber->id()); $response = $router->trash($this->subscriber_2->id());
expect($response)->true(); expect($response)->true();
$trashed_subscriber = Subscriber::findOne($subscriber->id()); $trashed_subscriber = Subscriber::findOne($this->subscriber_2->id());
expect($trashed_subscriber->deleted_at)->notNull(); expect($trashed_subscriber->deleted_at)->notNull();
} }
function itCanDeleteASubscriber() { function itCanDeleteASubscriber() {
$subscriber = Subscriber::createOrUpdate(array(
'email' => 'john.doe@mailpoet.com',
'first_name' => 'John',
'last_name' => 'Doe'
));
expect($subscriber->id() > 0)->true();
$router = new Subscribers(); $router = new Subscribers();
$response = $router->delete($subscriber->id()); $response = $router->delete($this->subscriber_1->id());
expect($response)->equals(1); expect($response)->equals(1);
expect(Subscriber::findOne($subscriber->id()))->false(); expect(Subscriber::findOne($this->subscriber_1->id()))->false();
}
function itCanBulkDeleteSubscribers() {
expect(Subscriber::count())->equals(2);
$subscribers = Subscriber::findMany();
foreach($subscribers as $subscriber) {
$subscriber->trash();
}
$router = new Subscribers();
$response = $router->bulkAction(array(
'action' => 'delete',
'listing' => array('group' => 'trash')
));
expect($response)->equals(2);
$response = $router->bulkAction(array(
'action' => 'delete',
'listing' => array('group' => 'trash')
));
expect($response)->equals(0);
} }
function _after() { function _after() {
ORM::forTable(Segment::$_table)->deleteMany(); Segment::deleteMany();
ORM::forTable(Subscriber::$_table)->deleteMany(); Subscriber::deleteMany();
} }
} }

View File

@ -211,6 +211,13 @@ class ExportCest {
expect(count($subscribers))->equals(2); expect(count($subscribers))->equals(2);
} }
function itRequiresWritableExportFile() {
$this->export->export_path = '/fake_folder';
$result = $this->export->process();
expect($result['errors'][0])
->equals("Couldn't save export file on the server.");
}
function itCanProcess() { function itCanProcess() {
$this->export->export_file = $this->export->getExportFile('csv'); $this->export->export_file = $this->export->getExportFile('csv');
$this->export->export_format_option = 'csv'; $this->export->export_format_option = 'csv';

View File

@ -4,43 +4,40 @@ use MailPoet\Subscribers\ImportExport\Import\MailChimp;
class MailChimpCest { class MailChimpCest {
function __construct() { function __construct() {
$this->APIKey = getenv('WP_TEST_IMPORT_MAILCHIMP_API') ? $this->api_key = getenv('WP_TEST_IMPORT_MAILCHIMP_API');
getenv('WP_TEST_IMPORT_MAILCHIMP_API') : $this->mailchimp = new MailChimp($this->api_key);
'1234567890'; $this->lists = explode(",", getenv('WP_TEST_IMPORT_MAILCHIMP_LISTS'));
$this->mailChimp = new MailChimp($this->APIKey);
$this->lists = getenv('WP_TEST_IMPORT_MAILCHIMP_LISTS') ?
explode(",", getenv('WP_TEST_IMPORT_MAILCHIMP_LISTS')) :
array(
'one',
'two'
);
} }
function itCanGetAPIKey() { function itValidatesAPIKey() {
expect($this->mailChimp->getAPIKey($this->APIKey))->equals($this->APIKey); $valid_api_key_format = '12345678901234567890123456789012-ab1';
expect($this->mailChimp->getAPIKey('somekey'))->false(); expect($this->mailchimp->getAPIKey($valid_api_key_format))
->equals($valid_api_key_format);
expect($this->mailchimp->getAPIKey('invalid_api_key_format'))->false();
} }
function itCanGetDatacenter() { function itCanGetDatacenter() {
expect($this->mailChimp->getDataCenter($this->APIKey))->equals( $valid_api_key_format = '12345678901234567890123456789012-ab1';
explode('-', $this->APIKey)[1] $data_center = 'ab1';
); expect($this->mailchimp->getDataCenter($valid_api_key_format))
->equals($data_center);
} }
function itFailsWithIncorrectAPIKey() { function itFailsWithIncorrectAPIKey() {
if(getenv('WP_TEST_ENABLE_NETWORK_TESTS') !== 'true') return; if(getenv('WP_TEST_ENABLE_NETWORK_TESTS') !== 'true') return;
$mailChimp = clone($this->mailChimp); $mailchimp = clone($this->mailchimp);
$mailChimp->APIKey = false; $mailchimp->api_key = false;
$lists = $mailChimp->getLists(); $lists = $mailchimp->getLists();
expect($lists['result'])->false(); expect($lists['result'])->false();
expect($lists['error'])->contains('API'); expect($lists['errors'][0])->contains('API');
$subscribers = $mailChimp->getLists(); $subscribers = $mailchimp->getLists();
expect($subscribers['result'])->false(); expect($subscribers['result'])->false();
expect($subscribers['error'])->contains('API'); expect($subscribers['errors'][0])->contains('API');
} }
function itCanGetLists() { function itCanGetLists() {
$lists = $this->mailChimp->getLists(); if(getenv('WP_TEST_ENABLE_NETWORK_TESTS') !== 'true') return;
$lists = $this->mailchimp->getLists();
expect($lists['result'])->true(); expect($lists['result'])->true();
expect(count($lists['data']))->equals(2); expect(count($lists['data']))->equals(2);
expect(isset($lists['data'][0]['id']))->true(); expect(isset($lists['data'][0]['id']))->true();
@ -49,17 +46,17 @@ class MailChimpCest {
function itFailsWithIncorrectLists() { function itFailsWithIncorrectLists() {
if(getenv('WP_TEST_ENABLE_NETWORK_TESTS') !== 'true') return; if(getenv('WP_TEST_ENABLE_NETWORK_TESTS') !== 'true') return;
$subscribers = $this->mailChimp->getSubscribers(); $subscribers = $this->mailchimp->getSubscribers();
expect($subscribers['result'])->false(); expect($subscribers['result'])->false();
expect($subscribers['error'])->contains('lists'); expect($subscribers['errors'][0])->contains('lists');
$subscribers = $this->mailChimp->getSubscribers(array(12)); $subscribers = $this->mailchimp->getSubscribers(array(12));
expect($subscribers['result'])->false(); expect($subscribers['result'])->false();
expect($subscribers['error'])->contains('lists'); expect($subscribers['errors'][0])->contains('lists');
} }
function itCanGetSubscribers() { function itCanGetSubscribers() {
if(getenv('WP_TEST_ENABLE_NETWORK_TESTS') !== 'true') return; if(getenv('WP_TEST_ENABLE_NETWORK_TESTS') !== 'true') return;
$subscribers = $this->mailChimp->getSubscribers(array($this->lists[0])); $subscribers = $this->mailchimp->getSubscribers(array($this->lists[0]));
expect($subscribers['result'])->true(); expect($subscribers['result'])->true();
expect(isset($subscribers['data']['invalid']))->true(); expect(isset($subscribers['data']['invalid']))->true();
expect(isset($subscribers['data']['duplicate']))->true(); expect(isset($subscribers['data']['duplicate']))->true();
@ -70,17 +67,17 @@ class MailChimpCest {
function itFailsWhenListHeadersDontMatch() { function itFailsWhenListHeadersDontMatch() {
if(getenv('WP_TEST_ENABLE_NETWORK_TESTS') !== 'true') return; if(getenv('WP_TEST_ENABLE_NETWORK_TESTS') !== 'true') return;
$subscribers = $this->mailChimp->getSubscribers($this->lists); $subscribers = $this->mailchimp->getSubscribers($this->lists);
expect($subscribers['result'])->false(); expect($subscribers['result'])->false();
expect($subscribers['error'])->contains('header'); expect($subscribers['errors'][0])->contains('header');
} }
function itFailsWhenSubscribersDataTooLarge() { function itFailsWhenSubscribersDataTooLarge() {
if(getenv('WP_TEST_ENABLE_NETWORK_TESTS') !== 'true') return; if(getenv('WP_TEST_ENABLE_NETWORK_TESTS') !== 'true') return;
$mailChimp = clone($this->mailChimp); $mailchimp = clone($this->mailchimp);
$mailChimp->maxPostSize = 10; $mailchimp->max_post_size = 10;
$subscribers = $mailChimp->getSubscribers($this->lists); $subscribers = $mailchimp->getSubscribers($this->lists);
expect($subscribers['result'])->false(); expect($subscribers['result'])->false();
expect($subscribers['error'])->contains('large'); expect($subscribers['errors'][0])->contains('large');
} }
} }

Some files were not shown because too many files have changed in this diff Show More