Commit 79768f4a authored by Patrick Barroca's avatar Patrick Barroca

dev #46014 : recipient list default to subscribed, subscription criteria added

parent 9c1717fb
......@@ -68,7 +68,10 @@ class Admin_NewsletterController extends ZendAfi_Controller_Action {
$this->view->newsletter = $model;
$this->view->groups = $model->getSortedRecipientsByDedicatedAndLabel();
$this->_helper->userSearch(['id' => $model->getId()]);
$criteria = (new Class_User_SearchCriteria($this->_request->getParams()))
->addCriteria(new Class_User_SearchCriteria_NewsletterSubscriptionStatus($this->_request->getParams()));
$this->_helper->userSearch(['id' => $model->getId()], $criteria);
}
......
......@@ -52,11 +52,16 @@ $adapter->query('CREATE TABLE IF NOT EXISTS `newsletter_blacklist` ('
.') engine=MyISAM default charset=utf8');
$adapter->query('ALTER TABLE user_groups '
. 'ADD COLUMN model_class varchar(255) null default \'\', '
. 'ADD COLUMN model_id int(11) unsigned null default null, '
. 'ADD KEY `model_class` (`model_class`), '
. 'ADD KEY `model_id` (`model_id`)');
$adapter->query('ALTER TABLE user_groups '
. 'ADD COLUMN model_class varchar(255) null default \'\', '
. 'ADD COLUMN model_id int(11) unsigned null default null, '
. 'ADD KEY `model_class` (`model_class`), '
. 'ADD KEY `model_id` (`model_id`)');
$adapter->query('ALTER TABLE bib_admin_users '
. 'ADD KEY `prenom` (`prenom`), '
. 'ADD KEY `pseudo` (`pseudo`), '
. 'ADD KEY `mail` (`mail`)');
} catch(Exception $e) {}
......
......@@ -73,7 +73,9 @@ class Class_Migration_NewsletterSubscriptionMigration {
protected function _runPage($newsletter, $models) {
foreach($models as $model) {
$user = $model->getUser();
if (!$user = $model->getUser())
continue;
if ($newsletter->getAutoSubscribe() && $user->isAbonne())
continue;
......
......@@ -162,6 +162,11 @@ class Class_Newsletter extends Storm_Model_Abstract {
}
public function getBlackListedMails() {
return Class_Newsletter_Blacklist::getMailsForNewsletter($this->getId());
}
public function getRecipientsGroups() {
$groups = [$this->getDedicatedGroup()];
foreach($this->getUserGroups() as $group)
......@@ -328,7 +333,7 @@ class Class_Newsletter extends Storm_Model_Abstract {
public function subscribeUser($user) {
$is_recipient = $this->hasRecipient($user, false);
$is_blacklisted = Class_Newsletter_Blacklist::isBlackListed($user->getMail(), $this->getId());
$is_blacklisted = $this->isBlackListed($user);
if ($is_blacklisted) {
Class_Newsletter_Blacklist::deleteBy(['newsletter_id' => $this->getId(),
......
<?php
/**
* Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved.
*
* BOKEH is free software; you can redistribute it and/or modify
* it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
* the Free Software Foundation.
*
* There are special exceptions to the terms and conditions of the AGPL as it
* is applied to this software (see README file).
*
* BOKEH is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
* along with BOKEH; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class Class_User_SearchCriteria {
use Trait_Translator;
protected
$_criteria = [],
$_search_params,
$_has_no_result = false;
public function __construct($params) {
$this->_criteria = [new Class_User_SearchCriteriaLibrary($params),
new Class_User_SearchCriteriaRoleLevel($params),
new Class_User_SearchCriteriaValidSubscription($params),
new Class_User_SearchCriteriaSearchFor($params)];
}
public function addCriteria($criteria) {
$this->_criteria[] = $criteria;
return $this;
}
public function findPage($page=1) {
$this->_buildSearchParams();
return $this->_has_no_result
? []
: Class_Users::findAllBy(array_merge($this->_search_params,
['limitPage' => [$page, 20]]));
}
public function count() {
$this->_buildSearchParams();
return $this->_has_no_result ? 0 : Class_Users::countBy($this->_search_params);
}
public function getForm() {
$form = (new ZendAfi_Form())
->setAttrib('style', 'position: relative')
->setMethod('get');
$names = [];
foreach($this->_criteria as $criteria) {
$form->addElement($criteria->getElement());
$names[] = $criteria->getName();
}
$form->addDisplayGroup($names,
'search_group',
['legend' => $this->_('Recherche')]);
Class_ScriptLoader::getInstance()
->addJQueryReady('formSelectToggleVisibilityForElement("#role_level", $("#valid_subscription").closest("tr"), ["2"]);');
return $form;
}
protected function _buildSearchParams() {
if ($this->_search_params)
return $this;
$this->_search_params = ['wheres' => []];
foreach($this->_criteria as $criteria)
$criteria->acceptSearchVisitor($this);
$wheres = $this->_search_params['wheres'];
unset($this->_search_params['wheres']);
if ($wheres)
$this->_search_params['where'] = '(' . implode(') AND (', $wheres) . ')';
return $this;
}
public function addParam($name, $value) {
$this->_search_params[$name] = $value;
return $this;
}
public function addWhereParam($value) {
$this->_search_params['wheres'][] = $value;
return $this;
}
public function hasNoResult() {
$this->_has_no_result = true;
return $this;
}
}
class Class_User_SearchCriteriaLibrary extends Class_User_SearchCriteria_Abstract{
protected
$_name = 'id_site',
$_value = Class_User_SearchCriteria_Abstract::DEFAULT_VALUE;
public function buildElement() {
return new Zend_Form_Element_Select($this->_name,
['label' => $this->_('Bibliothèque'),
'multiOptions' => ['all' => $this->_('Toutes')] + Class_Bib::findAllLabels(),
'value' => $this->_value]);
}
}
class Class_User_SearchCriteriaRoleLevel extends Class_User_SearchCriteria_Abstract {
protected
$_name = 'role_level',
$_value = Class_User_SearchCriteria_Abstract::DEFAULT_VALUE;
public function __construct($params) {
parent::__construct($params);
if (!Class_Users::getIdentity()->isAdmin()
&& $this->_value == Class_User_SearchCriteria_Abstract::DEFAULT_VALUE)
$this->_value = ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB;
}
public function buildElement() {
return new Zend_Form_Element_Select($this->_name,
['label' => $this->_('Niveau d\'accès'),
'multiOptions' => ['all' => $this->_('Tous')] + ZendAfi_Acl_AdminControllerRoles::getRolesLabelsWithOutSuperAdmin(),
'value' => $this->_value]);
}
}
class Class_User_SearchCriteriaValidSubscription extends Class_User_SearchCriteria_Abstract {
protected
$_name = 'valid_subscription',
$_value = 0,
$_should_filter = false;
public function __construct($params) {
parent::__construct($params);
$this->_should_filter = $this->_value
&& isset($params['role_level'])
&& $params['role_level'] == ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB;
}
public function buildElement() {
return new Zend_Form_Element_Checkbox($this->_name,
['label' => $this->_('Abonnement valide'),
'value' => $this->_value]);
}
public function acceptSearchVisitor($visitor) {
if (!$this->_should_filter)
return;
$visitor->addWhereParam('STR_TO_DATE(date_fin, \'%Y-%m-%d\') >= CURDATE()');
}
}
class Class_User_SearchCriteriaSearchFor extends Class_User_SearchCriteria_Abstract{
protected
$_name = 'search_for',
$_value = '';
public function buildElement() {
return new Zend_Form_Element_Text($this->_name,
['label' => $this->_('Rechercher'),
'value' => $this->_value]);
}
public function acceptSearchVisitor($visitor) {
$search_value = str_replace(["\000",
"\n",
"\r",
"\"",
"\'",
"'",
"\032"], '', $this->_value);
if (!$search_value)
return;
$columns = array_fill_keys(['login',
'nom',
'prenom',
'pseudo',
'mail',
'idabon'],
$search_value);
foreach($columns as $column => $value)
$table_or[] = sprintf('%s LIKE "%%%s%%"', $column, $value);
$visitor->addWhereParam(implode(' OR ', $table_or));
}
}
......@@ -20,54 +20,44 @@
*/
class ZendAfi_Form_Admin_SearchUsers extends ZendAfi_Form {
abstract class Class_User_SearchCriteria_Abstract {
use Trait_Translator;
public static function newWith($datas = [], $custom_form = null) {
$form = (new static());
const DEFAULT_VALUE = 'all';
$form
->setAttributes()
->addElements()
->populate($datas);
protected
$_name = '',
$_value = '',
$_element;
return $form;
public function __construct($params) {
if (isset($params[$this->_name]))
$this->_value = $params[$this->_name];
$this->_element = $this->buildElement();
}
protected function buildElement() {
return new Zend_Form_Element_Hidden($this->_name, ['value' => $this->_value]);
}
public function setAttributes() {
return $this
->setAttrib('style', 'position: relative')
->setMethod('get');
public function getElement() {
return $this->_element;
}
public function addElements() {
return $this
->addElement('select',
'by_id_site',
['label' => $this->_('Bibliothèque'),
'multiOptions' => ['all' => $this->_('Toutes')] + Class_Bib::findAllLabels()])
->addElement('select',
'by_role_level',
['label' => $this->_('Niveau d\'accès'),
'multiOptions' => ['all' => $this->_('Tous')] + ZendAfi_Acl_AdminControllerRoles::getRolesLabelsWithOutSuperAdmin()])
->addElement('checkbox',
'by_valide_subscription',
['label' => $this->_('Abonnement valide')])
->addElement('text',
'search_for',
['label' => $this->_('Rechercher')])
->addDisplayGroup(['by_id_site',
'by_role_level',
'by_valide_subscription',
'search_for',
'submit_form'],
'search_group',
['legend' => $this->_('Recherche')]);
public function getName() {
return $this->_name;
}
public function acceptSearchVisitor($visitor) {
if ($this->_value == static::DEFAULT_VALUE)
return;
$visitor->addParam($this->_name, $this->_value);
}
}
?>
\ No newline at end of file
}
\ No newline at end of file
<?php
/**
* Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved.
*
* BOKEH is free software; you can redistribute it and/or modify
* it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
* the Free Software Foundation.
*
* There are special exceptions to the terms and conditions of the AGPL as it
* is applied to this software (see README file).
*
* BOKEH is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
* along with BOKEH; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class Class_User_SearchCriteria_NewsletterSubscriptionStatus extends Class_User_SearchCriteria_Abstract{
protected
$_name = 'newsletter_subscription_status',
$_value = 'subscribed';
public function __construct($params) {
parent::__construct($params);
$this->_newsletter = Class_Newsletter::find(isset($params['id']) ? (int)$params['id'] : 0);
}
public function getElement() {
return new Zend_Form_Element_Select($this->_name,
['label' => $this->_('Inscrit à la lettre'),
'multiOptions' => ['subscribed' => $this->_('oui'),
'not_subscribed' => $this->_('non'),
'unsubscribed' => $this->_('Volontairement désinscrit')],
'value' => $this->_value]);
}
public function acceptSearchVisitor($visitor) {
if (!$this->_newsletter)
return;
if ('subscribed' == $this->_value)
return $this->_applySubscribedFilterOn($visitor);
if ('not_subscribed' == $this->_value)
return $visitor->addWhereParam('id_user not in (' . implode(',', $this->_newsletter->getRecipientsUsersIds()). ')');
if ('unsubscribed' == $this->_value)
return $this->_applyUnsubscribedFilterOn($visitor);
}
protected function _applySubscribedFilterOn($visitor) {
$visitor->addWhereParam('id_user in (' . implode(',', $this->_newsletter->getRecipientsUsersIds()). ')');
if ($blacklisted = $this->_newsletter->getBlackListedMails())
$visitor->addWhereParam('mail not in ("' . implode('","', $blacklisted). '")');
}
protected function _applyUnsubscribedFilterOn($visitor) {
if (!$blacklisted = $this->_newsletter->getBlackListedMails())
return $visitor->hasNoResult();
$visitor
->addWhereParam('id_user in (' . implode(',', $this->_newsletter->getRecipientsUsersIds()). ')')
->addWhereParam('mail in ("' . implode('","', $blacklisted). '")');
}
}
\ No newline at end of file
......@@ -23,63 +23,28 @@
class ZendAfi_Controller_Action_Helper_UserSearch extends Zend_Controller_Action_Helper_Abstract {
protected $view;
public function userSearch($action_params=[]) {
public function userSearch($action_params=[], $criteria) {
$this->view = $this->getActionController()->view;
$this->view->page = $this->_getParam('page', 1);
$this->view->users = $criteria->findPage($this->view->page);
$this->view->total = $criteria->count();
$this->view->form = $this->_prepareForm($action_params, $criteria);
$this->view->params = array_merge($this->view->form->getValues(),
['page' => $this->view->page]);
$id_site = $this->_getParam('by_id_site', 'all');
$role_level = Class_Users::getIdentity()->isAdmin()
? $this->_getParam('by_role_level', 'all')
: $this->_getParam('by_role_level', ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB);
$search_value = str_replace(["\000",
"\n",
"\r",
"\"",
"\'",
"'",
"\032"], '', $this->_getParam('search_for', null));
$valide_subscription = $this->_getParam('by_valide_subscription', null);
$params = ['id_site' => $id_site,
'role_level' => $role_level];
$where = array_fill_keys(['login',
'nom',
'prenom',
'pseudo',
'mail',
'idabon'],
$search_value);
$this->view->params = ['by_id_site' => $id_site,
'by_role_level' => $role_level,
'search_for' => $search_value,
'by_valide_subscription' => $valide_subscription,
'page' => $this->view->page];
$this->view->users = Class_Users::findSearched($params,
$where,
$valide_subscription,
[$this->view->page, 20]);
$this->view->total = Class_Users::countSearched($params,
$where,
$valide_subscription);
}
$this->view->form = ZendAfi_Form_Admin_SearchUsers::newWith($this->view->params);
protected function _prepareForm($action_params, $criteria) {
$form = $criteria->getForm();
$url_params = array_merge(['module' => $this->getRequest()->getModuleName(),
'controller' => $this->getRequest()->getControllerName(),
'action' => $this->getRequest()->getActionName()],
$action_params);
$this->view->form->setAction(Class_Url::absolute($url_params, null, true));
return $form->setAction(Class_Url::absolute($url_params, null, true));
}
......@@ -88,7 +53,7 @@ class ZendAfi_Controller_Action_Helper_UserSearch extends Zend_Controller_Action
}
public function direct($action_params=[]) {
return $this->userSearch($action_params);
public function direct($action_params=[], $criteria) {
return $this->userSearch($action_params, $criteria);
}
}
\ No newline at end of file
......@@ -29,8 +29,6 @@ class ZendAfi_View_Helper_Admin_SearchUsers extends ZendAfi_View_Helper_BaseHelp
$actions;
public function admin_searchUsers($users, $total, $form, $page, $params, $actions) {
Class_ScriptLoader::getInstance()->addJQueryReady('$("#by_role_level option[value=2]:not(:selected)").closest("form").find("tr:nth-child(3)").hide();$("#by_role_level").change(function() {$("#by_role_level option[value=2]:not(:selected)").closest("form").find("tr:nth-child(3)").hide();$("#by_role_level option[value=2]:selected").closest("form").find("tr:nth-child(3)").show();});');
$this->users = $users;
$this->total = $total;
$this->page = $page;
......
......@@ -842,31 +842,65 @@ class Admin_NewsletterControllerEditSubcsribersTest extends Admin_NewsletterCont
class Admin_NewsletterControllerEditSubcsribersSearchTest
abstract class Admin_NewsletterControllerEditSubcsribersSearchTestCase
extends Admin_NewsletterControllerEditSubcsribersTestCase {
protected $_laurent, $_pat, $_ghislo;
public function setUp() {
parent::setUp();
Class_Newsletter::find(1)
->subscribeToDedicatedGroup($this->fixture('Class_Users',
['id' => 566,
'login' => 'laurent',
'password' => '677']));
$newsletter = Class_Newsletter::find(1);
$newsletter
->subscribeToDedicatedGroup($this->_laurent = $this->fixture('Class_Users',
['id' => 566,
'login' => 'laurent',
'password' => '677']));
$this->fixture('Class_Users',
['id' => 3232,
'login' => 'pat',
'password' => '8890']);
$this->_pat = $this->fixture('Class_Users',
['id' => 3232,
'login' => 'pat',
'password' => '8890']);
Class_Newsletter::find(1)
->subscribeToDedicatedGroup($this->fixture('Class_Users',
['id' => 444,
'login' => 'ghislo',
'password' => '8989',
'mail' => 'g@serv.eur.fr']))
->unsubscribeUser(Class_Users::find(444));
$newsletter
->subscribeToDedicatedGroup($this->_ghislo = $this->fixture('Class_Users',
['id' => 444,
'login' => 'ghislo',
'password' => '8989',
'mail' => 'g@serv.eur.fr']))
->unsubscribeUser($this->_ghislo);
$sql = $this->mock()
->whenCalled('fetchAll')
->with('select user_id as id from user_group_memberships where user_group_id='
. $newsletter->getDedicatedGroup()->getId())
->answers([ ['id' => 566], ['id' => 444] ])
->whenCalled('fetchAll')
->answers([ ]);
Zend_Registry::set('sql', $sql);
}
}
class Admin_NewsletterControllerEditSubcsribersSearchSubscribedTest
extends Admin_NewsletterControllerEditSubcsribersSearchTestCase {
public function setUp() {
parent::setUp();
$this->onLoaderOfModel('Class_Users')
->whenCalled('findAllBy')
->with(['where' => '(id_user in (566,444)) AND (mail not in ("g@serv.eur.fr"))',
'limitPage' => [1, 20]])
->answers([$this->_laurent])
->whenCalled('findAllBy')
->answers([])
// ->willDo(function($params) { var_dump($params); exit; })
;
$this->dispatch('/admin/newsletter/edit-subscribers/id/1', true);
}
......@@ -878,6 +912,12 @@ class Admin_NewsletterControllerEditSubcsribersSearchTest
}
/** @test */
public function statusSelectShouldBePresentAndDefaultToSubscribed() {
$this->assertXPath('//select[@name="newsletter_subscription_status"]//option[@value="subscribed"][@selected]');
}
/** @test */
public function laurentShouldBeInList() {
$this->assertXPathContentContains('//table[contains(@class, "models")]//td', 'laurent');
......@@ -890,6 +930,72 @@ class Admin_NewsletterControllerEditSubcsribersSearchTest
}
/** @test */
public function patShouldNotBePresent() {
$this->assertNotXPathContentContains('//table[contains(@class, "models")]//td', 'pat');
}
/** @test */
public function patActionShouldNotBePresent() {
$this->assertNotXPath('//table[contains(@class, "models")]//a[contains(@href, "/subscribe/3232")]');
}
/** @test */
public function ghisloShouldNotBePresent() {
$this->assertNotXPathContentContains('//table[contains(@class, "models")]//td', 'ghislo');
}
/** @test */
public function ghisloActionShouldBeReSubscribe() {
$this->assertNotXPath('//table[contains(@class, "models")]//a[contains(@href, "/resubscribe/444")]');
}
}
class Admin_NewsletterControllerEditSubcsribersSearchNotSubscribedTest
extends Admin_NewsletterControllerEditSubcsribersSearchTestCase {
public function setUp() {
parent::setUp();
$this->onLoaderOfModel('Class_Users')
->whenCalled('findAllBy')
->with(['where' => '(id_user not in (566,444))',
'limitPage' => [1, 20]])
->answers([$this->_pat])
->whenCalled('findAllBy')
->answers([])