diff --git a/assets/js/src/form/form.jsx b/assets/js/src/form/form.jsx
index e6d25d42b7..ff44795b6f 100644
--- a/assets/js/src/form/form.jsx
+++ b/assets/js/src/form/form.jsx
@@ -276,7 +276,11 @@ define(
this.props.messages['created']();
}
} else {
- this.setState({ errors: response });
+ if(response === false) {
+ // unknown error occurred
+ } else {
+ this.setState({ errors: response });
+ }
}
}.bind(this));
},
diff --git a/assets/js/src/listing/listing.jsx b/assets/js/src/listing/listing.jsx
index 694b67ab2e..2163667427 100644
--- a/assets/js/src/listing/listing.jsx
+++ b/assets/js/src/listing/listing.jsx
@@ -241,12 +241,12 @@ define(
var data = params || {};
- data.selection = selected_ids;
data.listing = {
offset: 0,
limit: 0,
group: this.state.group,
- search: this.state.search
+ search: this.state.search,
+ selection: selected_ids
}
MailPoet.Ajax.post({
diff --git a/assets/js/src/newsletters/list.jsx b/assets/js/src/newsletters/list.jsx
index d0688675b9..f15dd7c48e 100644
--- a/assets/js/src/newsletters/list.jsx
+++ b/assets/js/src/newsletters/list.jsx
@@ -27,6 +27,13 @@ define(
}
];
+ var bulk_actions = [
+ {
+ name: 'trash',
+ label: 'Trash'
+ }
+ ];
+
var NewsletterList = React.createClass({
renderItem: function(newsletter, actions) {
var rowClasses = classNames(
@@ -57,8 +64,8 @@ define(
+ columns={columns}
+ bulk_actions={ bulk_actions } />
);
}
});
diff --git a/assets/js/src/segments/list.jsx b/assets/js/src/segments/list.jsx
index d38c7a8944..25fc720bee 100644
--- a/assets/js/src/segments/list.jsx
+++ b/assets/js/src/segments/list.jsx
@@ -27,6 +27,13 @@ define(
}
];
+ var bulk_actions = [
+ {
+ name: 'trash',
+ label: 'Trash'
+ }
+ ];
+
var SegmentList = React.createClass({
renderItem: function(segment, actions) {
var rowClasses = classNames(
@@ -57,8 +64,8 @@ define(
+ columns={columns}
+ bulk_actions={ bulk_actions } />
);
}
});
diff --git a/assets/js/src/subscribers/list.jsx b/assets/js/src/subscribers/list.jsx
index 5512bfcbe9..0424b2b863 100644
--- a/assets/js/src/subscribers/list.jsx
+++ b/assets/js/src/subscribers/list.jsx
@@ -67,7 +67,7 @@ define(
action: 'listing',
data: {
'offset': 0,
- 'limit': 5,
+ 'limit': 100,
'search': '',
'sort_by': 'name',
'sort_order': 'asc'
@@ -145,7 +145,7 @@ define(
var bulk_actions = [
{
- name: 'move',
+ name: 'moveToList',
label: 'Move to list...',
onSelect: function() {
return (
@@ -161,7 +161,7 @@ define(
}
},
{
- name: 'add',
+ name: 'addToList',
label: 'Add to list...',
onSelect: function() {
return (
@@ -177,7 +177,7 @@ define(
}
},
{
- name: 'remove',
+ name: 'removeFromList',
label: 'Remove from list...',
onSelect: function() {
return (
@@ -198,7 +198,7 @@ define(
}
];
- var List = React.createClass({
+ var SubscriberList = React.createClass({
renderItem: function(subscriber, actions) {
var row_classes = classNames(
'manage-column',
@@ -259,6 +259,6 @@ define(
}
});
- return List;
+ return SubscriberList;
}
);
\ No newline at end of file
diff --git a/lib/Config/Initializer.php b/lib/Config/Initializer.php
index 2c9aed8f8a..b8f5c3fd2c 100644
--- a/lib/Config/Initializer.php
+++ b/lib/Config/Initializer.php
@@ -29,6 +29,9 @@ class Initializer {
\ORM::configure('username', Env::$db_username);
\ORM::configure('password', Env::$db_password);
\ORM::configure('logging', WP_DEBUG);
+ \ORM::configure('driver_options', array(
+ \PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'
+ ));
$subscribers = Env::$db_prefix . 'subscribers';
$settings = Env::$db_prefix . 'settings';
diff --git a/lib/Listing/BulkAction.php b/lib/Listing/BulkAction.php
new file mode 100644
index 0000000000..4b0f91466c
--- /dev/null
+++ b/lib/Listing/BulkAction.php
@@ -0,0 +1,28 @@
+model = $model;
+ $this->data = $data;
+
+ $this->listing = new Handler(
+ \Model::factory($this->model),
+ $this->data['listing']
+ );
+ return $this;
+ }
+
+ function apply() {
+ return call_user_func_array(
+ array($this->model, $this->data['action']),
+ array($this->listing, $this->data)
+ );
+ }
+}
\ No newline at end of file
diff --git a/lib/Listing/Handler.php b/lib/Listing/Handler.php
index 5f6a21f862..7a6db80ead 100644
--- a/lib/Listing/Handler.php
+++ b/lib/Listing/Handler.php
@@ -20,7 +20,9 @@ class Handler {
'sort_by' => (isset($data['sort_by']) ? $data['sort_by'] : 'id'),
'sort_order' => (isset($data['sort_order']) ? $data['sort_order'] : 'asc'),
// grouping
- 'group' => (isset($data['group']) ? $data['group'] : null)
+ 'group' => (isset($data['group']) ? $data['group'] : null),
+ // selection
+ 'selection' => (isset($data['selection']) ? $data['selection'] : null)
);
$this->setSearch();
@@ -47,18 +49,18 @@ class Handler {
return $this->model->filter('group', $this->data['group']);
}
- function getSelection($ids = array()) {
- if(!empty($ids)) {
- $this->model->whereIn('id', $ids);
+ function getSelection() {
+ if(!empty($this->data['selection'])) {
+ $this->model->whereIn('id', $this->data['selection']);
}
return $this->model;
}
- function getSelectionIds($ids = array()) {
- $subscribers = $this->getSelection($ids)->select('id')->findMany();
- return array_map(function($subscriber) {
- return (int)$subscriber->id;
- }, $subscribers);
+ function getSelectionIds() {
+ $models = $this->getSelection()->select('id')->findMany();
+ return array_map(function($model) {
+ return (int)$model->id;
+ }, $models);
}
function get() {
diff --git a/lib/Models/Newsletter.php b/lib/Models/Newsletter.php
index 2f2d915fca..5281a2122f 100644
--- a/lib/Models/Newsletter.php
+++ b/lib/Models/Newsletter.php
@@ -48,10 +48,18 @@ class Newsletter extends Model {
$saved = $newsletter->save();
- if($saved === false) {
- return $newsletter->getValidationErrors();
- } else {
+ if($saved === true) {
return true;
+ } else {
+ $errors = $newsletter->getValidationErrors();
+ if(!empty($errors)) {
+ return $errors;
+ }
}
+ return false;
+ }
+
+ static function trash($listing) {
+ return $listing->getSelection()->deleteMany();
}
}
diff --git a/lib/Models/Segment.php b/lib/Models/Segment.php
index d03242e8fc..80b6330a63 100644
--- a/lib/Models/Segment.php
+++ b/lib/Models/Segment.php
@@ -57,10 +57,18 @@ class Segment extends Model {
$saved = $segment->save();
- if($saved === false) {
- return $segment->getValidationErrors();
- } else {
+ if($saved === true) {
return true;
+ } else {
+ $errors = $segment->getValidationErrors();
+ if(!empty($errors)) {
+ return $errors;
+ }
}
+ return false;
+ }
+
+ static function trash($listing) {
+ return $listing->getSelection()->deleteMany();
}
}
diff --git a/lib/Models/Subscriber.php b/lib/Models/Subscriber.php
index 7a55b083de..bf48e9ab0f 100644
--- a/lib/Models/Subscriber.php
+++ b/lib/Models/Subscriber.php
@@ -15,7 +15,7 @@ class Subscriber extends Model {
));
}
- function delete() {
+ function delete() {
// delete all relations to segments
SubscriberSegment::where('subscriber_id', $this->id)->deleteMany();
@@ -95,10 +95,76 @@ class Subscriber extends Model {
$saved = $subscriber->save();
- if($saved === false) {
- return $subscriber->getValidationErrors();
+ if($saved === true) {
+ return true;
} else {
+ $errors = $subscriber->getValidationErrors();
+ if(!empty($errors)) {
+ return $errors;
+ }
+ }
+ return false;
+ }
+
+ static function moveToList($listing, $data = array()) {
+ $segment_id = (isset($data['segment_id']) ? (int)$data['segment_id'] : 0);
+ $segment = Segment::findOne($segment_id);
+
+ if($segment !== false) {
+ $subscribers = $listing->getSelection()->findMany();
+ foreach($subscribers as $subscriber) {
+ // remove subscriber from all segments
+ SubscriberSegment::where('subscriber_id', $subscriber->id)->deleteMany();
+
+ // create relation with segment
+ $association = SubscriberSegment::create();
+ $association->subscriber_id = $subscriber->id;
+ $association->segment_id = $segment->id;
+ $association->save();
+ }
return true;
}
+ return false;
+ }
+
+ static function removeFromList($listing, $data = array()) {
+ $segment_id = (isset($data['segment_id']) ? (int)$data['segment_id'] : 0);
+ $segment = Segment::findOne($segment_id);
+
+ if($segment !== false) {
+ // delete relations with segment
+ $subscriber_ids = $listing->getSelectionIds();
+ SubscriberSegment::whereIn('subscriber_id', $subscriber_ids)
+ ->where('segment_id', $segment->id)
+ ->deleteMany();
+ return true;
+ }
+ return false;
+ }
+
+ static function addToList($listing, $data = array()) {
+ $segment_id = (isset($data['segment_id']) ? (int)$data['segment_id'] : 0);
+ $segment = Segment::findOne($segment_id);
+
+ if($segment !== false) {
+ $subscribers = $listing->getSelection()->findMany();
+ foreach($subscribers as $subscriber) {
+ // create relation with segment
+ $association = \MailPoet\Models\SubscriberSegment::create();
+ $association->subscriber_id = $subscriber->id;
+ $association->segment_id = $segment->id;
+ $association->save();
+ }
+ return true;
+ }
+ return false;
+ }
+
+ static function trash($listing) {
+ // delete relations with all segments
+ $subscriber_ids = $listing->getSelectionIds();
+ \MailPoet\Models\SubscriberSegment::whereIn('subscriber_id', $subscriber_ids)->deleteMany();
+
+ return $listing->getSelection()->deleteMany();
}
}
diff --git a/lib/Router/Newsletters.php b/lib/Router/Newsletters.php
index dcca8b14dd..5afb79dd8a 100644
--- a/lib/Router/Newsletters.php
+++ b/lib/Router/Newsletters.php
@@ -62,4 +62,13 @@ class Newsletters {
$mailer = new Bridge($newsletter, $subscribers);
wp_send_json($mailer->send());
}
+
+ function bulk_action($data = array()) {
+ $bulk_action = new Listing\BulkAction(
+ '\MailPoet\Models\Newsletter',
+ $data
+ );
+
+ wp_send_json($bulk_action->apply());
+ }
}
diff --git a/lib/Router/Router.php b/lib/Router/Router.php
index 4110711a01..3742c7738f 100644
--- a/lib/Router/Router.php
+++ b/lib/Router/Router.php
@@ -24,7 +24,7 @@ class Router {
$class = ucfirst($_POST['endpoint']);
$endpoint = __NAMESPACE__ . "\\" . $class;
$method = $_POST['method'];
- $data = isset($_POST['data']) ? $_POST['data'] : array();
+ $data = isset($_POST['data']) ? stripslashes_deep($_POST['data']) : array();
$endpoint = new $endpoint();
$endpoint->$method($data);
}
diff --git a/lib/Router/Segments.php b/lib/Router/Segments.php
index 8b5113b79f..b0936048a4 100644
--- a/lib/Router/Segments.php
+++ b/lib/Router/Segments.php
@@ -53,4 +53,13 @@ class Segments {
wp_send_json($result);
}
+
+ function bulk_action($data = array()) {
+ $bulk_action = new Listing\BulkAction(
+ '\MailPoet\Models\Segment',
+ $data
+ );
+
+ wp_send_json($bulk_action->apply());
+ }
}
diff --git a/lib/Router/Subscribers.php b/lib/Router/Subscribers.php
index 16dc711fa2..0b00a308b4 100644
--- a/lib/Router/Subscribers.php
+++ b/lib/Router/Subscribers.php
@@ -30,69 +30,6 @@ class Subscribers {
wp_send_json($listing->get());
}
- function bulk_action($data = array()) {
- $action = $data['action'];
- $selection = (isset($data['selection']) ? $data['selection'] : null);
- $listing_data = $data['listing'];
-
- $listing = new Listing\Handler(
- \Model::factory('\MailPoet\Models\Subscriber'),
- $listing_data
- );
-
- $selected = $listing->getSelection($selection);
- $subscribers = $selected->findMany();
-
- $result = false;
- switch($action) {
- case 'move':
- $segment_id = (isset($data['segment_id']) ? (int)$data['segment_id'] : 0);
- foreach($subscribers as $subscriber) {
- // remove subscriber from all segments
- SubscriberSegment::where('subscriber_id', $subscriber->id)->deleteMany();
-
- // create relation with segment
- $association = SubscriberSegment::create();
- $association->subscriber_id = $subscriber->id;
- $association->segment_id = $segment_id;
- $association->save();
- }
- $result = true;
- break;
-
- case 'remove':
- $segment_id = (isset($data['segment_id']) ? (int)$data['segment_id'] : 0);
- // delete relations with segment
- $subscriber_ids = $listing->getSelectionIds($selection);
- $result = SubscriberSegment::whereIn('subscriber_id', $subscriber_ids)
- ->where('segment_id', $segment_id)
- ->deleteMany();
- break;
-
- case 'add':
- $segment_id = (isset($data['segment_id']) ? (int)$data['segment_id'] : 0);
- foreach($subscribers as $subscriber) {
- // create relation with segment
- $association = SubscriberSegment::create();
- $association->subscriber_id = $subscriber->id;
- $association->segment_id = $segment_id;
- $association->save();
- }
- $result = true;
- break;
-
- case 'trash':
- // delete relations with all segments
- $subscriber_ids = $listing->getSelectionIds($selection);
- SubscriberSegment::whereIn('subscriber_id', $subscriber_ids)->deleteMany();
-
- $result = $selected->deleteMany();
- break;
- }
-
- wp_send_json($result);
- }
-
function getAll() {
$collection = Subscriber::findArray();
wp_send_json($collection);
@@ -112,4 +49,13 @@ class Subscribers {
}
wp_send_json($result);
}
+
+ function bulk_action($data = array()) {
+ $bulk_action = new Listing\BulkAction(
+ '\MailPoet\Models\Subscriber',
+ $data
+ );
+
+ wp_send_json($bulk_action->apply());
+ }
}
diff --git a/lib/Util/Sudzy/ValidModel.php b/lib/Util/Sudzy/ValidModel.php
index 2406ffaaa0..d195af541c 100644
--- a/lib/Util/Sudzy/ValidModel.php
+++ b/lib/Util/Sudzy/ValidModel.php
@@ -14,35 +14,35 @@ abstract class ValidModel extends \Model
// + ON_SET throws immediately when field is set()
// + ON_SAVE throws on save()
// + NEVER means an exception is never thrown; check for ->getValidaionErrors()
- );
+ );
const ON_SET = 'set';
const ON_SAVE = 'save';
const NEVER = null;
public function __construct($validatorInstance = null) {
- $this->_validator = $validatorInstance;
+ $this->_validator = $validatorInstance;
}
public function setValidationOptions($options)
{
- $this->_validationOptions = array_merge($this->_validationOptions, $options);
+ $this->_validationOptions = array_merge($this->_validationOptions, $options);
}
public function addValidation($field, $validation, $message) {
- if (!isset($this->_validations[$field])) {
- $this->_validations[$field] = array();
- }
- $this->_validations[$field][] = array(
- 'validation' => $validation,
- 'message' => $message
+ if (!isset($this->_validations[$field])) {
+ $this->_validations[$field] = array();
+ }
+ $this->_validations[$field][] = array(
+ 'validation' => $validation,
+ 'message' => $message
);
}
public function addValidations($field, $validators) {
- foreach ($validators as $validation => $message) {
- $this->addValidation($field, $validation, $message);
- }
+ foreach ($validators as $validation => $message) {
+ $this->addValidation($field, $validation, $message);
+ }
}
// /**
@@ -65,39 +65,39 @@ abstract class ValidModel extends \Model
**/
public function validateField($field, $value)
{
- $this->setupValidationEngine();
+ $this->setupValidationEngine();
- if (!isset($this->_validations[$field])) {
+ if (!isset($this->_validations[$field])) {
return true; // No validations, return true by default
+ }
+
+ $success = true;
+ foreach ($this->_validations[$field] as $v) {
+ $checks = explode(' ', $v['validation']);
+ foreach ($checks as $check) {
+ $params = explode('|', $check);
+ $check = array_shift($params);
+
+ if ($this->_validator->executeOne($check, $value, $params)) {
+ $success = $success && true;
+ } else {
+ $this->addValidationError($v['message'], $field);
+ $success = false;
+ }
+ }
+ }
+ return $success;
}
- $success = true;
- foreach ($this->_validations[$field] as $v) {
- $checks = explode(' ', $v['validation']);
- foreach ($checks as $check) {
- $params = explode('|', $check);
- $check = array_shift($params);
-
- if ($this->_validator->executeOne($check, $value, $params)) {
- $success = $success && true;
- } else {
- $this->addValidationError($v['message'], $field);
- $success = false;
- }
- }
+ public function getValidationErrors()
+ {
+ return $this->_validationErrors;
}
- return $success;
- }
- public function getValidationErrors()
- {
- return $this->_validationErrors;
- }
-
- public function resetValidationErrors()
- {
- $this->_validationErrors = array();
- }
+ public function resetValidationErrors()
+ {
+ $this->_validationErrors = array();
+ }
///////////////////
// Overloaded methods
@@ -107,7 +107,7 @@ abstract class ValidModel extends \Model
*/
public function __set($name, $value)
{
- $this->validateAndSet($name, $value);
+ $this->validateAndSet($name, $value);
}
/**
@@ -116,16 +116,17 @@ abstract class ValidModel extends \Model
public function save()
{
if ($this->isNew()) { //Fields populated by create() or hydrate() don't pass through set()
- foreach( array_keys($this->_validations) as $field) {
- $this->validateField($field, $this->$field);
- }
+ foreach( array_keys($this->_validations) as $field) {
+ $this->validateField($field, $this->$field);
}
+ }
- $errs = $this->getValidationErrors();
- if (!empty($errs))
- $this->doValidationError(self::ON_SAVE);
+ $errs = $this->getValidationErrors();
+ if (!empty($errs)) {
+ $this->doValidationError(self::ON_SAVE);
+ }
- parent::save();
+ parent::save();
}
/**
@@ -133,14 +134,14 @@ abstract class ValidModel extends \Model
*/
public function set($key, $value = null)
{
- if(is_array($key)) {
+ if(is_array($key)) {
// multiple values
- foreach($key as $field => $value) {
- $this->validateAndSet($field, $value);
- }
- } else {
- $this->validateAndSet($key, $value);
+ foreach($key as $field => $value) {
+ $this->validateAndSet($field, $value);
}
+ } else {
+ $this->validateAndSet($key, $value);
+ }
}
@@ -148,20 +149,21 @@ abstract class ValidModel extends \Model
// Protected methods
protected function doValidationError($context)
{
- if ($context == $this->_validationOptions['throw'])
- throw new \Sudzy\ValidationException($this->_validationErrors);
+ if ($context == $this->_validationOptions['throw']) {
+ throw new \Sudzy\ValidationException($this->_validationErrors);
+ }
}
protected function addValidationError($msg, $field = null)
{
- if ($this->_validationOptions['indexedErrors'] && $field !== null) {
+ if ($this->_validationOptions['indexedErrors'] && $field !== null) {
// Only keep the first error found on a field
- if (!isset($this->_validationErrors[$field])) {
- $this->_validationErrors[$field] = $msg;
- }
- } else {
- $this->_validationErrors[] = $msg;
+ if (!isset($this->_validationErrors[$field])) {
+ $this->_validationErrors[$field] = $msg;
}
+ } else {
+ $this->_validationErrors[] = $msg;
+ }
}
/**
@@ -169,12 +171,12 @@ abstract class ValidModel extends \Model
*/
protected function validateAndSet($name, $value)
{
- if (!$this->validateField($name, $value)) $this->doValidationError(self::ON_SET);
- parent::set($name, $value);
+ if (!$this->validateField($name, $value)) $this->doValidationError(self::ON_SET);
+ parent::set($name, $value);
}
protected function setupValidationEngine()
{
- if (null == $this->_validator) $this->_validator = new \Sudzy\Engine(); // Is lazy setup worth it?
+ if (null == $this->_validator) $this->_validator = new \Sudzy\Engine(); // Is lazy setup worth it?
}
-}
+ }