3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
6 * Galette Mailing controller
10 * Copyright © 2019-2020 The Galette Team
12 * This file is part of Galette (http://galette.tuxfamily.org).
14 * Galette is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
19 * Galette is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
27 * @category Controllers
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2019-2020 The Galette Team
32 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
34 * @link http://galette.tuxfamily.org
35 * @since Available since 0.9.4dev - 2019-12-06
38 namespace Galette\Controllers\Crud
;
40 use Galette\Controllers\CrudController
;
42 use Slim\Http\Request
;
43 use Slim\Http\Response
;
44 use Galette\Core\GaletteMail
;
45 use Galette\Core\Mailing
;
46 use Galette\Core\MailingHistory
;
47 use Galette\Entity\Adherent
;
48 use Galette\Filters\MailingsList
;
49 use Galette\Filters\MembersList
;
50 use Galette\Repository\Members
;
54 * Galette Mailing controller
56 * @category Controllers
57 * @name MailingsController
59 * @author Johan Cwiklinski <johan@x-tnd.be>
60 * @copyright 2019-2020 The Galette Team
61 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
62 * @link http://galette.tuxfamily.org
63 * @since Available since 0.9.4dev - 2019-12-06
66 class MailingsController
extends CrudController
73 * @param Request $request PSR Request
74 * @param Response $response PSR Response
75 * @param array $args Request arguments
79 public function add(Request
$request, Response
$response, array $args = []) :Response
81 $get = $request->getQueryParams();
84 if (isset($get['mailing_new'])
85 ||
isset($get['reminder'])
87 if ($this->session
->mailing
!== null) {
88 // check for temporary attachments to remove
89 $m = $this->session
->mailing
;
90 $m->removeAttachments(true);
92 $this->session
->mailing
= null;
97 if ($this->preferences
->pref_mail_method
== Mailing
::METHOD_DISABLED
98 && !GALETTE_MODE
=== 'DEMO'
101 _T("Trying to load mailing while email is disabled in preferences.")
103 $this->flash
->addMessage(
105 _T("Trying to load mailing while email is disabled in preferences.")
109 ->withHeader('Location', $this->router
->pathFor('slash'));
111 if (isset($this->session
->filter_mailing
)) {
112 $filters = $this->session
->filter_mailing
;
113 } elseif (isset($this->session
->filter_members
)) {
114 $filters = $this->session
->filter_members
;
116 $filters = new MembersList();
119 if ($this->session
->mailing
!== null
120 && !isset($get['from'])
121 && !isset($get['reset'])
123 $mailing = $this->session
->mailing
;
124 } elseif (isset($get['from']) && is_numeric($get['from'])) {
125 $mailing = new Mailing($this->preferences
, null, $get['from']);
126 MailingHistory
::loadFrom($this->zdb
, (int)$get['from'], $mailing);
127 } elseif (isset($get['reminder'])) {
128 //FIXME: use a constant!
130 $filters->membership_filter
= Members
::MEMBERSHIP_LATE
;
131 $filters->filter_account
= Members
::ACTIVE_ACCOUNT
;
132 $m = new Members($filters);
133 $members = $m->getList(true);
134 $mailing = new Mailing($this->preferences
, ($members !== false) ?
$members : null);
136 if (count($filters->selected
) == 0
137 && !isset($get['mailing_new'])
138 && !isset($get['reminder'])
141 '[Mailings] No member selected for mailing',
145 $this->flash
->addMessage(
147 _T('No member selected for mailing!')
150 if (isset($profiler)) {
154 $redirect_url = ($this->session
->redirect_mailing
!== null) ?
155 $this->session
->redirect_mailing
: $this->router
->pathFor('members');
159 ->withHeader('Location', $redirect_url);
162 $members = $m->getArrayList($filters->selected
);
163 $mailing = new Mailing($this->preferences
, ($members !== false) ?
$members : null);
166 if (isset($get['remove_attachment'])) {
167 $mailing->removeAttachment($get['remove_attachment']);
170 if ($mailing->current_step
!== Mailing
::STEP_SENT
) {
171 $this->session
->mailing
= $mailing;
174 /** TODO: replace that... */
175 $this->session
->labels
= $mailing->unreachables
;
177 if (!$this->login
->isSuperAdmin()) {
178 $member = new Adherent($this->zdb
, (int)$this->login
->id
, false);
179 $params['sender_current'] = [
180 'name' => $member->sname
,
181 'email' => $member->getEmail()
185 $params = array_merge(
188 'mailing' => $mailing,
189 'attachments' => $mailing->attachments
,
190 'html_editor' => true,
191 'html_editor_active'=> $this->preferences
->pref_editor_enabled
199 'mailing_adherents.tpl',
202 'page_title' => _T("Mailing")
213 * @param Request $request PSR Request
214 * @param Response $response PSR Response
215 * @param array $args Request arguments
219 public function doAdd(Request
$request, Response
$response, array $args = []) :Response
221 $post = $request->getParsedBody();
222 $error_detected = [];
223 $success_detected = [];
225 $goto = $this->router
->pathFor('mailings');
226 $redirect_url = ($this->session
->redirect_mailing
!== null) ?
227 $this->session
->redirect_mailing
: $this->router
->pathFor('members');
230 if (isset($post['mailing_done'])
231 ||
isset($post['mailing_cancel'])
233 if ($this->session
->mailing
!== null) {
234 // check for temporary attachments to remove
235 $m = $this->session
->mailing
;
236 $m->removeAttachments(true);
238 $this->session
->mailing
= null;
239 if (isset($this->session
->filter_mailing
)) {
240 $filters = $this->session
->filter_mailing
;
241 $filters->selected
= [];
242 $this->session
->filter_mailing
= $filters;
247 ->withHeader('Location', $redirect_url);
252 if ($this->preferences
->pref_mail_method
== Mailing
::METHOD_DISABLED
253 && !GALETTE_MODE
=== 'DEMO'
256 _T("Trying to load mailing while email is disabled in preferences.")
258 $error_detected[] = _T("Trying to load mailing while email is disabled in preferences.");
259 $goto = $this->router
->pathFor('slash');
261 if (isset($this->session
->filter_members
)) {
262 $filters = $this->session
->filter_members
;
264 $filters = new MembersList();
267 if ($this->session
->mailing
!== null
268 && !isset($post['mailing_cancel'])
270 $mailing = $this->session
->mailing
;
272 if (count($filters->selected
) == 0) {
274 '[Mailings] No member selected for mailing',
278 $this->flash
->addMessage(
280 _T('No member selected for mailing!')
285 ->withHeader('Location', $redirect_url);
288 $members = $m->getArrayList($filters->selected
);
289 $mailing = new Mailing($this->preferences
, ($members !== false) ?
$members : null);
292 if (isset($post['mailing_go'])
293 ||
isset($post['mailing_reset'])
294 ||
isset($post['mailing_confirm'])
295 ||
isset($post['mailing_save'])
297 if (trim($post['mailing_objet']) == '') {
298 $error_detected[] = _T("Please type an object for the message.");
300 $mailing->subject
= $post['mailing_objet'];
303 if (trim($post['mailing_corps']) == '') {
304 $error_detected[] = _T("Please enter a message.");
306 $mailing->message
= $post['mailing_corps'];
309 switch ($post['sender']) {
310 case GaletteMail
::SENDER_CURRENT
:
311 $member = new Adherent($this->zdb
, (int)$this->login
->id
, false);
317 case GaletteMail
::SENDER_OTHER
:
319 $post['sender_name'],
320 $post['sender_address']
323 case GaletteMail
::SENDER_PREFS
:
325 //nothing to do; this is the default :)
329 $mailing->html
= (isset($post['mailing_html'])) ?
true : false;
332 if (isset($_FILES['files'])) {
333 for ($i = 0; $i < count($_FILES['files']['name']); $i++
) {
334 if ($_FILES['files']['error'][$i] === UPLOAD_ERR_OK
) {
335 if ($_FILES['files']['tmp_name'][$i] != '') {
336 if (is_uploaded_file($_FILES['files']['tmp_name'][$i])) {
338 foreach (array_keys($_FILES['files']) as $key) {
339 $da_file[$key] = $_FILES['files'][$key][$i];
341 $res = $mailing->store($da_file);
343 //what to do if one of attachments fail? should other be removed?
344 $error_detected[] = $mailing->getAttachmentErrorMessage($res);
348 } elseif ($_FILES['files']['error'][$i] !== UPLOAD_ERR_NO_FILE
) {
350 $this->logo
->getPhpErrorMessage($_FILES['files']['error'][$i]),
353 $error_detected[] = $this->logo
->getPhpErrorMessage(
354 $_FILES['files']['error'][$i]
360 if (count($error_detected) == 0
361 && !isset($post['mailing_reset'])
362 && !isset($post['mailing_save'])
364 $mailing->current_step
= Mailing
::STEP_PREVIEW
;
366 $mailing->current_step
= Mailing
::STEP_START
;
370 if (isset($post['mailing_confirm']) && count($error_detected) == 0) {
371 $mailing->current_step
= Mailing
::STEP_SEND
;
372 //ok... let's go for fun
373 $sent = $mailing->send();
374 if ($sent == Mailing
::MAIL_ERROR
) {
375 $mailing->current_step
= Mailing
::STEP_START
;
377 '[Mailings] Message was not sent. Errors: ' .
378 print_r($mailing->errors
, true),
381 foreach ($mailing->errors
as $e) {
382 $error_detected[] = $e;
385 $mlh = new MailingHistory($this->zdb
, $this->login
, null, $mailing);
386 $mlh->storeMailing(true);
388 '[Mailings] Message has been sent.',
391 $mailing->current_step
= Mailing
::STEP_SENT
;
393 $filters->selected
= null;
394 $this->session
->filter_members
= $filters;
395 $this->session
->mailing
= null;
396 $success_detected[] = _T("Mailing has been successfully sent!");
397 $goto = $redirect_url;
401 if ($mailing->current_step
!== Mailing
::STEP_SENT
) {
402 $this->session
->mailing
= $mailing;
405 /** TODO: replace that... */
406 $this->session
->labels
= $mailing->unreachables
;
408 if (!isset($post['html_editor_active'])
409 ||
trim($post['html_editor_active']) == ''
411 $post['html_editor_active'] = $this->preferences
->pref_editor_enabled
;
414 if (isset($post['mailing_save'])) {
415 //user requested to save the mailing
416 $histo = new MailingHistory($this->zdb
, $this->login
, null, $mailing);
417 if ($histo->storeMailing() !== false) {
418 $success_detected[] = _T("Mailing has been successfully saved.");
419 $this->session
->mailing
= null;
424 //flash messages if any
425 if (count($error_detected) > 0) {
426 foreach ($error_detected as $error) {
427 $this->flash
->addMessage('error_detected', $error);
430 if (count($success_detected) > 0) {
431 foreach ($success_detected as $success) {
432 $this->flash
->addMessage('success_detected', $success);
438 ->withHeader('Location', $goto);
445 * Mailings history page
447 * @param Request $request PSR Request
448 * @param Response $response PSR Response
449 * @param array $args Request arguments
453 public function list(Request
$request, Response
$response, array $args = []) :Response
456 if (isset($args['option'])) {
457 $option = $args['option'];
461 if (isset($args['value'])) {
462 $value = $args['value'];
465 if (isset($this->session
->filter_mailings
)) {
466 $filters = $this->session
->filter_mailings
;
468 $filters = new MailingsList();
471 if (isset($request->getQueryParams()['nbshow'])) {
472 $filters->show
= $request->getQueryParams()['nbshow'];
475 $mailhist = new MailingHistory($this->zdb
, $this->login
, $filters);
477 if ($option !== null) {
480 $filters->current_page
= (int)$value;
483 $filters->orderby
= $value;
487 //reinitialize object after flush
488 $filters = new MailingsList();
489 $mailhist = new MailingHistory($this->zdb
, $this->login
, $filters);
494 $this->session
->filter_mailings
= $filters;
496 //assign pagination variables to the template and add pagination links
497 $mailhist->filters
->setSmartyPagination($this->router
, $this->view
->getSmarty());
498 $history_list = $mailhist->getHistory();
499 //assign pagination variables to the template and add pagination links
500 $mailhist->filters
->setSmartyPagination($this->router
, $this->view
->getSmarty());
505 'gestion_mailings.tpl',
507 'page_title' => _T("Mailings"),
508 'logs' => $history_list,
509 'history' => $mailhist
518 * @param Request $request PSR Request
519 * @param Response $response PSR Response
523 public function filter(Request
$request, Response
$response) :Response
525 $post = $request->getParsedBody();
526 $error_detected = [];
528 if ($this->session
->filter_mailings
!== null) {
529 $filters = $this->session
->filter_mailings
;
531 $filters = new MailingsList();
534 if (isset($post['clear_filter'])) {
537 if ((isset($post['nbshow']) && is_numeric($post['nbshow']))
539 $filters->show
= $post['nbshow'];
542 if (isset($post['end_date_filter']) ||
isset($post['start_date_filter'])) {
544 if (isset($post['start_date_filter'])) {
545 $field = _T("start date filter");
546 $filters->start_date_filter
= $post['start_date_filter'];
548 if (isset($post['end_date_filter'])) {
549 $field = _T("end date filter");
550 $filters->end_date_filter
= $post['end_date_filter'];
552 } catch (\Exception
$e) {
553 $error_detected[] = $e->getMessage();
557 if (isset($post['sender_filter'])) {
558 $filters->sender_filter
= $post['sender_filter'];
561 if (isset($post['sent_filter'])) {
562 $filters->sent_filter
= $post['sent_filter'];
566 if (isset($post['subject_filter'])) {
567 $filters->subject_filter
= $post['subject_filter'];
571 $this->session
->filter_mailings
= $filters;
573 if (count($error_detected) > 0) {
575 foreach ($error_detected as $error) {
576 $this->flash
->addMessage(
585 ->withHeader('Location', $this->router
->pathFor('mailings'));
591 * @param Request $request PSR Request
592 * @param Response $response PSR Response
593 * @param array $args Request arguments
597 public function edit(Request
$request, Response
$response, array $args = []) :Response
605 * @param Request $request PSR Request
606 * @param Response $response PSR Response
607 * @param array $args Request arguments
611 public function doEdit(Request
$request, Response
$response, array $args = []) :Response
620 * Get redirection URI
622 * @param array $args Route arguments
626 public function redirectUri(array $args = [])
628 return $this->router
->pathFor('mailings');
634 * @param array $args Route arguments
638 public function formUri(array $args = [])
640 return $this->router
->pathFor(
642 ['id' => $args['id'] ??
null]
647 * Get confirmation removal page title
649 * @param array $args Route arguments
653 public function confirmRemoveTitle(array $args = [])
656 _T('Remove mailing #%1$s'),
664 * @param array $args Route arguments
665 * @param array $post POST values
669 protected function doDelete(array $args, array $post)
671 $mailhist = new MailingHistory($this->zdb
, $this->login
);
672 return $mailhist->removeEntries($args['id'], $this->history
);
680 * @param Request $request PSR Request
681 * @param Response $response PSR Response
682 * @param array $args Request arguments
686 public function preview(Request
$request, Response
$response, array $args = []) :Response
688 $post = $request->getParsedBody();
689 // check for ajax mode
691 if ($request->isXhr()
692 ||
isset($post['ajax'])
693 && $post['ajax'] == 'true'
699 if (isset($args['id'])) {
700 $mailing = new Mailing($this->preferences
, null);
701 MailingHistory
::loadFrom($this->zdb
, (int)$args['id'], $mailing, false);
702 $attachments = $mailing->attachments
;
704 $mailing = $this->session
->mailing
;
706 switch ($post['sender']) {
707 case GaletteMail
::SENDER_CURRENT
:
708 $member = new Adherent($this->zdb
, (int)$this->login
->id
, false);
714 case GaletteMail
::SENDER_OTHER
:
716 $post['sender_name'],
717 $post['sender_address']
720 case GaletteMail
::SENDER_PREFS
:
722 //nothing to do; this is the default :)
726 $mailing->subject
= $post['subject'];
727 $mailing->message
= $post['body'];
728 $mailing->html
= ($post['html'] === 'true');
729 $attachments = (isset($post['attachments']) ?
$post['attachments'] : []);
735 'mailing_preview.tpl',
737 'page_title' => _T("Mailing preview"),
738 'mailing_id' => $args['id'],
739 'mode' => ($ajax ?
'ajax' : ''),
740 'mailing' => $mailing,
741 'recipients' => $mailing->recipients
,
742 'sender' => $mailing->getSenderName() . ' <' .
743 $mailing->getSenderAddress() . '>',
744 'attachments' => $attachments
752 * Preview attachement action
754 * @param Request $request PSR Request
755 * @param Response $response PSR Response
756 * @param array $args Request arguments
760 public function previewAttachment(Request
$request, Response
$response, array $args = []) :Response
762 $mailing = new Mailing($this->preferences
, null);
763 MailingHistory
::loadFrom($this->zdb
, (int)$args['id'], $mailing, false);
764 $attachments = $mailing->attachments
;
765 $attachment = $attachments[$args['pos']];
766 $filepath = $attachment->getDestDir() . $attachment->getFileName();
768 $ext = pathinfo($attachment->getFileName())['extension'];
769 $response = $response->withHeader('Content-type', $attachment->getMimeType($filepath));
771 $body = $response->getBody();
772 $body->write(file_get_contents($filepath));
777 * Set recipients action
779 * @param Request $request PSR Request
780 * @param Response $response PSR Response
781 * @param array $args Request arguments
785 public function setRecipients(Request
$request, Response
$response, array $args = []) :Response
787 $post = $request->getParsedBody();
788 $mailing = $this->session
->mailing
;
792 $members = $m->getArrayList(
802 $mailing->setRecipients($members);
804 $this->session
->mailing
= $mailing;
809 'mailing_recipients.tpl',
811 'mailing' => $mailing