Skip to content
Snippets Groups Projects
Commit eb1ff7a6 authored by Ghislain Loas's avatar Ghislain Loas
Browse files

hotline #13657 launch mail by packet cross Batch

parent 67d761b7
Branches
Tags
6 merge requests!258Dev/13872 Orphee Allow Hold Available Items,!215Dev#12992 Custom Fields,!209Hotline#13914 Album Link Config Menu,!194Dev #13657 Newsletter Pagination Batch Mail,!181Dev #13657 Newsletter Pagination Batch Mail,!166Hotline #13657 Many Users Newsletter
Showing with 285 additions and 80 deletions
......@@ -146,25 +146,37 @@ class Admin_NewsletterController extends Zend_Controller_Action {
}
public function sendNextAction() {
$this->_helper->viewRenderer->setNoRender();
$JSON = [];
if (!$newsletter = Class_Newsletter::find((int)$this->_request->getParam('id'))) {
echo json_encode($JSON[]=['error' => $this->view->_('La newsletter n\'existe pas')]);
return;
}
if (!$mail = (int) $this->_request->getParam('mail')) {
echo json_encode($JSON[]=['error' => $this->view->_('Pas d\'email à envoyer')]);
return;
}
echo json_encode($JSON[] = $newsletter->sendMail($mail));
return;
}
public function sendAction() {
if (!$newsletter = Class_Newsletter::find((int)$this->_request->getParam('id')))
$this->_redirect('admin/newsletter');
$this->view->subview = $this->view->partial('newsletter/send.phtml',
['newsletter' => $newsletter]);
$this->_forward('index');
return;
/*
try {
$newsletter->send();
$message = "Lettre envoyée";
$message = "Lettre envoyée:".$log;
} catch(Exception $e) {
$message = "Erreur à l'envoi de la lettre: ".$e->getMessage();
$this->getResponse()->setHttpResponseCode(500);
}
$this->_helper->viewRenderer->setNoRender();
echo $message;*/
$this->_forward('index');
}
......
<tr class="<?php echo $this->item_class ?>">
<td><?php echo htmlentities($this->newsletter->getTitre(), ENT_QUOTES, 'UTF-8'); ?></td>
<td><?php
if (null == $last_date = $this->newsletter->getLastDistributionDate())
if (null == $last_date = $this->newsletter->getDistributionProgress())
echo 'Aucune';
else
echo date('d/m/Y H:i', strtotime($last_date));
echo $last_date;
?></td>
<?php
......
<?php
echo $this->tag('div',
$this->_('Email envoyé'),
['class' => 'sending_mails']);
Class_ScriptLoader::getInstance()
->addScript(URL_JAVA . 'progress_bar/progress_bar.js')
->addJQueryReady('$(".sending_mails").progress_bar()');
echo $this->message;
$html = $this->tag('div',
'',
['class' => 'sending_mails',
'data-url' => $this->first_mail]);
echo $html;
?>
<?PHP
// Constantes
define("VERSION_COSMOGRAMME","6.50");
define("PATCH_LEVEL","203");
define("PATCH_LEVEL","204");
define("APPLI","cosmogramme");
define("COSMOPATH", "/var/www/html/vhosts/opac2/www/htdocs");
......
ALTER TABLE newsletters_users ADD COLUMN send BOOLEAN default true;
\ No newline at end of file
......@@ -27,7 +27,8 @@ class Class_BatchLoader extends Storm_Model_Loader{
'CORRECTION_PANIERS' => new Class_Batch_PanierNotice(),
'CART_REALLOCATION' => new Class_Batch_PanierUser(),
'COMMENT_REALLOCATION'=> new Class_Batch_AvisNotice(),
'INDEX_RESSOURCES_NUMERIQUES' => new Class_Batch_IndexRessourcesNumeriques()
'INDEX_RESSOURCES_NUMERIQUES' => new Class_Batch_IndexRessourcesNumeriques(),
'SEND_NEWSLETTERS' => new Class_Batch_SendNewsletters()
]);
}
......
<?php
/**
* Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved.
*
* AFI-OPAC 2.0 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).
*
* AFI-OPAC 2.0 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 AFI-OPAC 2.0; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class Class_Batch_SendNewsletters extends Class_Batch_Abstract {
protected $log="";
public function __construct($newsletter) {
$this->_newsletters = $newsletter;
}
public function getLabel() {
return $this->_('Envoie des newsletters');
}
public function getLog() {
return $this->log;
}
public function run() {
Class_NewsletterSubscription::resetSendFlagForNewsletter($this->_newsletters->getId());
$this->log = $this->_newsletters->generateMails(200);
return $this;
}
}
?>
\ No newline at end of file
......@@ -59,6 +59,7 @@ class Class_Newsletter extends Storm_Model_Abstract {
'role' => 'newsletter',
'dependents' => 'delete']];
protected $_notices_finder;
protected $_recipent_size = 200;
public function getSubscriptionsPage($page=0, $items_by_page=20) {
......@@ -66,11 +67,34 @@ class Class_Newsletter extends Storm_Model_Abstract {
'limitPage' => [$page, $items_by_page]]);
}
protected function getNumberOfMailsToSend() {
$count = Class_NewsletterSubscription::countAvailableUserForNewsletter($this->getId());
if(0 === $count)
return 0;
return $count % $this->_recipient_size;
}
/*
public function sendMail($mail_iterator) {
$cound_mails = $this->getNumberOfMailsToSend();
$next_mail = ($mail_iterator < $cound_mails) ? $mail_iterator + 1 : 0;
$mail = $this->generateMail($mail_iterator);
$mail->send();
$this
->setLastDistributionDate(strftime("%Y-%m-%d %H:%M:%S"))
->save();
$JSON = [];
return json_encode($JSON[] = ['success' => $this->_('Mail '.$mail_iterator.'/'.$cound_mails.' envoyé avec succès'),
'next-send' => $next_mail]);
}
*/
public function send() {
$mails = $this->generateMails();
foreach($mails as $mail)
$mail->send();
$batch_newsletters = new Class_Batch_SendNewsletters($this);
$batch_newsletters->run();
$this
->setLastDistributionDate(strftime("%Y-%m-%d %H:%M:%S"))
......@@ -132,42 +156,36 @@ class Class_Newsletter extends Storm_Model_Abstract {
}
public function generateMails() {
$count = Class_NewsletterSubscription::countAvailableUserForNewsletter($this->getId());
if(0 === $count)
return [];
$mails= [];
$recipient_size = 200;
$mail_count = (int) ($count / $recipient_size);
if(0 < $count % $recipient_size)
$mail_count++;
for($i = 0; $i < $mail_count; ++$i) {
public function generateMails($recipient_size) {
while (strlen($receivers_list = $this->getReceiversList($receivers,$recipient_size))>0) {
Class_NewsletterSubscription::clearCache();
Class_Users::clearCache();
Storm_Model_Loader::resetCache();
gc_collect_cycles();
set_time_limit(30);
$users = Class_NewsletterSubscription::getAvailableUsersForNewsletter($this->getId(), $i, $recipient_size);
if(!is_array($users) || count(array_filter($users))==0)
continue;
$mail = $this->_newMail();
$mail->addTo($this->getExpediteur());
foreach($users as $user) {
($user_mail = $user->getMail())
? $mail->addBcc($user_mail)
: '';
}
$mails[] = $mail;
$mail->addBcc($receivers_list);
$mail->send();
Class_NewsletterSubscription::updateSendFlagForReceivers($this->getId(),$receivers);
}
return $mails;
}
protected function getReceiversList($receivers,$recipient_size) {
$receivers = Class_Users::getNewslettersReceivers($this->getId(), $recipient_size);
$emails = [];
foreach ($receivers as $user) {
$emails[]= $user->getMail();
}
return implode(',',$emails);
}
......@@ -273,6 +291,15 @@ class Class_Newsletter extends Storm_Model_Abstract {
return $title;
}
public function getDistributionProgress() {
$progress = Class_NewsletterSubscription::countDistributionProgress($this->getId());
if ($progress <1)
return date('d/m/Y H:i', strtotime( $this->getLastDistributionDate()));
$total=Class_NewsletterSubscription::countTotalDistribution($this->getId());
return $progress."/".$total;
}
}
?>
\ No newline at end of file
......@@ -31,6 +31,15 @@ class NewsletterSubscriptionLoader extends Storm_Model_Loader {
}
public function countDistributionProgress($id_newsletter) {
return Class_NewsletterSubscription::countBy(['newsletter_id' => $id_newsletter,
'send' => 0]);
}
public function countTotalDistribution($id_newsletter) {
return Class_NewsletterSubscription::countBy(['newsletter_id' => $id_newsletter ]);
}
public function getAvailableUsersForNewsletter($id_newsletter, $start = 0 , $end = 200) {
$subscriptions = Class_NewsletterSubscription::findAllBy($this->availableUserForNewsletter($id_newsletter, $start, $end));
......@@ -48,9 +57,26 @@ class NewsletterSubscriptionLoader extends Storm_Model_Loader {
return array_filter($users);
}
public function resetSendFlagForNewsletter($id_newsletter) {
return sqlExecute("update newsletters_users set send=false where newsletter_id=".$id_newsletter);
}
public function updateSendFlagForReceivers($id_newsletter,$receivers) {
$users_ids_list = [];
foreach ($receivers as $user) {
$users_ids_list[] = $user->getId();
}
$subscriptions = Class_NewsletterSubscription::findAllBy(['where' => 'newsletter_id = '.$id_newsletter.' and user_id in (' .implode(',', $users_ids_list).')']);
foreach($subscriptions as $subscription) {
$subscription
->setSend(true)
->save();
}
}
protected function availableUserForNewsletter($id_newsletter, $start = 0 , $end = 200) {
return ['where' => 'newsletter_id = '.$id_newsletter.' and '.$this->usersWithMail(),
return ['where' => 'newsletter_id = '.$id_newsletter.' and '.$this->validUsers(),
'limitPage' => [$start,$end]];
}
......@@ -61,17 +87,17 @@ class NewsletterSubscriptionLoader extends Storm_Model_Loader {
protected function usersWithNoMail() {
return 'user_id not in ('.$this->selectMail().')';
return 'user_id not in ('.$this->selectUser().')';
}
protected function usersWithMail() {
return 'user_id in ('.$this->selectMail().')';
protected function validUsers() {
return 'user_id in ('.$this->selectUser().')';
}
protected function selectMail() {
return 'select id_user from bib_admin_users where mail is not null and mail != ""';
protected function selectUser() {
return 'select id_user from bib_admin_users';
}
}
......
......@@ -24,20 +24,13 @@ class UsersLoader extends Storm_Model_Loader {
public function countForNewsletter($id_newsletter) {
// return Class_Users::countBy(['where' => 'mail is not null and mail != "" and '
}
public function findAllForNewsletter($id_newsletter, $items_by_page=20, $page=0) {
$req = 'select user_id
from newsletter_users
where newsletter_id = '. (int)$id_newsletter;
$limit = ' limit '. (int)$page . ', ' . (int)$items_by_page;
$ids = Zend_Registry::get('sql')->fetchAll($req.$limit);
Class_NewsletterSubscription::findAllBy(['newsletter_id' => $id_newsletter,
'limitPage' => [$page, $items_by_page]]);
return $this->findUsersById($ids);
public function getNewslettersReceivers($id_newsletter,$recipient_size) {
$req = "select bib_admin_users.* from bib_admin_users join newsletters_users on bib_admin_users.id_user = newsletters_users.user_id where newsletter_id = ".$id_newsletter." and newsletters_users.send is false limit ".$recipient_size;
return Class_Users::findAll($req);
}
......
......@@ -496,6 +496,9 @@ class Admin_NewsletterControllerPreviewActionTest extends Admin_NewsletterContro
->answers([$marcus, $miles])
->whenCalled('clearCache')
->answers(true)
->whenCalled('countDistributionProgress')
->with(3)
->answers(0)
->beStrict();
$profil_portail = $this->fixture('Class_Profil', ['id' => 1,
......@@ -807,12 +810,16 @@ class Admin_NewsletterControllerEditSubcsribersDeleteTest extends Admin_Newslett
class Admin_NewsletterControllerMailingPaginationTest extends Admin_AbstractControllerTestCase {
protected $count_receivers_call=0;
protected $two_users;
protected $news_wrapper;
protected $user_model;
public function setup() {
parent::setup();
$two_hundred_users = $this->_createUsers(200);
$tree_hundred_users = $this->_createUsers(300);
$this->count_receivers_call=0;
$this->mock_transport = new MockMailTransport();
Zend_Mail::setDefaultTransport($this->mock_transport);
$this->two_users = $this->_createUsers(2);
$this->fixture('Class_Newsletter',
['id' => 1,
'titre' => 'IAM',
......@@ -821,24 +828,38 @@ class Admin_NewsletterControllerMailingPaginationTest extends Admin_AbstractCont
'id_panier' => 0,
'last_distribution_date' =>'']);
Storm_Test_ObjectWrapper::onLoaderOfModel('Class_NewsletterSubscription')
->whenCalled('countAvailableUserForNewsletter')
$this->news_wrapper=Storm_Test_ObjectWrapper::onLoaderOfModel('Class_NewsletterSubscription');
$this->news_wrapper->whenCalled('countAvailableUserForNewsletter')
->with(1)
->answers(200)
->answers(2)
->whenCalled('getAvailableUsersForNewsletter')
->with(1, 0, 200)
->answers($two_hundred_users)
->answers($this->two_users)
->whenCalled('getAvailableUsersForNewsletter')
->with(1)
->answers($tree_hundred_users)
->whenCalled('clearCache')
->answers(true)
->beStrict();
->whenCalled('updateSendFlagForReceivers')
->answers(true);
$this->user_model=Storm_Test_ObjectWrapper::onLoaderOfModel('Class_Users');
$this->user_model
->whenCalled('getNewslettersReceivers')
->with(1,200)
->willDo(function() {return $this->getReceivers();});
$this->dispatch('/admin/newsletter/send/id/1', true);
}
protected function getReceivers() {
if ($this->user_model->methodCallCount('getNewslettersReceivers')==2)
$this->two_users=[];
return $this->two_users;
}
protected function _createUsers($nb) {
$users = [];
for($i = 0; $i<$nb; ++$i){
......@@ -853,16 +874,64 @@ class Admin_NewsletterControllerMailingPaginationTest extends Admin_AbstractCont
/** @test */
public function successMessageShouldBeDisplay() {
$this->assertXPathContentContains('//div[@class="subview"]//div[@class="sending_mails"]',
'Email envoyé');
public function progressBarShouldBeDisplay() {
$this->assertXPath('//div[@class="subview"]//div[@class="sending_mails"][@data-url="/admin/newslettger/send-next/id/1/mail/1"]');
}
/** @test */
public function progessBarPluginShouldBeLoaded() {
$this->assertXPath('//script[contains(@src, "java/progress_bar/progress_bar.js")]');
}
/** @test */
public function shouldDisplayProgressBarComplete() {
$this->assert('send-next');
public function progressBarShouldBeCall() {
$this->assertXPathContentContains('//script', '.progress_bar()');
}
}
class Admin_NewsletterControllerSendNextMailTest extends Admin_AbstractControllerTestCase {
public function setup() {
parent::setup();
$this->fixture('Class_Newsletter',
['id' => 1,
'titre' => 'Actu',
'contenu' => 'Wait a minute']);
$this->mock_transport = new MockMailTransport();
Zend_Mail::setDefaultTransport($this->mock_transport);
}
/** @test */
public function shouldReturnExpectedError() {
$this->dispatch('/admin/newsletter/send-next/id/9889/mail/1', true);
$expected_json = ['error' => 'La newsletter n\'existe pas'];
$this->assertEquals(json_encode($expected_json), $this->_response->getBody());
}
/** @test */
public function shouldReturnExpectedMessage() {
$this->dispatch('/admin/newsletter/send-next/id/1/mail/', true);
$expected_json = ['error' => 'Pas d\'email à envoyer'];
$this->assertEquals(json_encode($expected_json), $this->_response->getBody());
}
/** @test */
public function shouldReturnExpectedResult() {
$this->dispatch('/admin/newsletter/send-next/id/1/mail/1', true);
$expected_json = ['succcess' => 'mail 1/10 envoyé',
'send-next' => '/admin/newsletter/send-next/id/1/mail/2'];
$this->assertEquals(json_encode($expected_json), $this->_response->getBody());
}
}
?>
\ No newline at end of file
......@@ -147,4 +147,31 @@ class BatchIndexRessourcesNumeriquesTest extends Storm_Test_ModelTestCase {
}
}
?>
class BatchSendNewsletterByMailTest extends Storm_Test_ModelTestCase {
public function setup() {
parent::setup();
$tom = $this->fixture('Class_Users',
['id' => 1,
'login' => 'tom',
'password'=>'pwd']);
$newsletter = $this->fixture('Class_Newsletter',
['id' => 1,
'titre'=>'News',
'contenu' => 'WAT?']);
$subscription = $this->fixture('Class_NewsletterSubscription',
['id' => 1,
'newsletter_id' => 1,
'user_id' => 1,
'send'=>false]);
(new Class_Batch_SendNewsletters)->run();
}
/** @test */
public function tomShouldHaveRecieveNews() {
$this->assertEquals(true, Class_NewsletterSubscription::find(1)->getSend());
}
}
?>
\ No newline at end of file
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment