]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Core/MailingHistory.php
6c32a94195c7c622f6feb2425c4a6b6dd6e56349
[galette.git] / galette / lib / Galette / Core / MailingHistory.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6 * Mailing features
7 *
8 * PHP version 5
9 *
10 * Copyright © 2009-2018 The Galette Team
11 *
12 * This file is part of Galette (http://galette.tuxfamily.org).
13 *
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.
18 *
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.
23 *
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/>.
26 *
27 * @category Core
28 * @package Galette
29 *
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2011-2018 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
33 * @version SVN: $Id$
34 * @link http://galette.tuxfamily.org
35 * @since Available since 0.7dev - 2011-08-27
36 */
37
38 namespace Galette\Core;
39
40 use Analog\Analog;
41 use Galette\Core\Db;
42 use Galette\Core\Login;
43 use Galette\Entity\Adherent;
44 use Galette\Filters\MailingsList;
45 use Laminas\Db\Sql\Expression;
46
47 /**
48 * Mailing features
49 *
50 * @category Core
51 * @name MailingHistory
52 * @package Galette
53 * @author Johan Cwiklinski <johan@x-tnd.be>
54 * @copyright 2011-2018 The Galette Team
55 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
56 * @link http://galette.tuxfamily.org
57 * @since Available since 0.7dev - 2011-08-27
58 */
59 class MailingHistory extends History
60 {
61 const TABLE = 'mailing_history';
62 const PK = 'mailing_id';
63
64 const FILTER_DC_SENT = 0;
65 const FILTER_SENT = 1;
66 const FILTER_NOT_SENT = 2;
67
68 private $mailing = null;
69 private $id;
70 private $date;
71 private $subject;
72 private $message;
73 private $recipients;
74 private $sender;
75 private $sender_name;
76 private $sender_address;
77 private $sent = false;
78
79 private $senders;
80
81 /**
82 * Default constructor
83 *
84 * @param Db $zdb Database
85 * @param Login $login Login
86 * @param HistoryList $filters Filtering
87 * @param Mailing $mailing Mailing
88 */
89 public function __construct(Db $zdb, Login $login, $filters = null, $mailing = null)
90 {
91 parent::__construct($zdb, $login, $filters);
92
93 if ($mailing instanceof Mailing) {
94 $this->mailing = $mailing;
95 } elseif ($mailing !== null) {
96 Analog::log(
97 '[' . __METHOD__ .
98 '] Mailing should be either null or an instance of Mailing',
99 Analog::ERROR
100 );
101 }
102 }
103
104 /**
105 * Get the entire history list
106 *
107 * @return array
108 */
109 public function getHistory()
110 {
111 try {
112 $select = $this->zdb->select($this->getTableName(), 'a');
113 $select->join(
114 array('b' => PREFIX_DB . Adherent::TABLE),
115 'a.mailing_sender=b.' . Adherent::PK,
116 array('nom_adh', 'prenom_adh'),
117 $select::JOIN_LEFT
118 );
119 $this->buildWhereClause($select);
120 $select->order(self::buildOrderClause());
121 $this->buildLists($select);
122 $this->proceedCount($select);
123 //add limits to retrieve only relavant rows
124 $this->filters->setLimits($select);
125 $results = $this->zdb->execute($select);
126
127 $ret = array();
128 foreach ($results as $r) {
129 if ($r['mailing_sender'] !== null && $r['mailing_sender_name'] === null) {
130 $r['mailing_sender_name']
131 = Adherent::getSName($this->zdb, $r['mailing_sender']);
132 }
133 $body_resume = $r['mailing_body'];
134 if (strlen($body_resume) > 150) {
135 $body_resume = substr($body_resume, 0, 150);
136 $body_resume .= '[...]';
137 }
138 if (function_exists('tidy_parse_string')) {
139 //if tidy extension is present, we use it to clean a bit
140 $tidy_config = array(
141 'clean' => true,
142 'show-body-only' => true,
143 'wrap' => 0,
144 );
145 $tidy = tidy_parse_string($body_resume, $tidy_config, 'UTF8');
146 $tidy->cleanRepair();
147 $r['mailing_body_resume'] = tidy_get_output($tidy);
148 } else {
149 //if it is not... Well, let's serve the text as it.
150 $r['mailing_body_resume'] = $body_resume;
151 }
152
153 $attachments = 0;
154 if (file_exists(GALETTE_ATTACHMENTS_PATH . $r[self::PK])) {
155 $rdi = new \RecursiveDirectoryIterator(
156 GALETTE_ATTACHMENTS_PATH . $r[self::PK],
157 \FilesystemIterator::SKIP_DOTS
158 );
159 $contents = new \RecursiveIteratorIterator(
160 $rdi,
161 \RecursiveIteratorIterator::CHILD_FIRST
162 );
163 foreach ($contents as $path) {
164 if ($path->isFile()) {
165 $attachments++;
166 }
167 }
168 }
169 $r['attachments'] = $attachments;
170 $ret[] = $r;
171 }
172 return $ret;
173 } catch (\Exception $e) {
174 Analog::log(
175 'Unable to get history. | ' . $e->getMessage(),
176 Analog::WARNING
177 );
178 return false;
179 }
180 }
181
182 /**
183 * Builds users and actions lists
184 *
185 * @param Select $select Original select
186 *
187 * @return void
188 */
189 private function buildLists($select)
190 {
191 try {
192 $select = $this->zdb->select(self::TABLE);
193 $select->quantifier('DISTINCT')->columns(['mailing_sender']);
194 $select->order(['mailing_sender ASC']);
195
196 $results = $this->zdb->execute($select);
197
198 $this->senders = [];
199 foreach ($results as $result) {
200 $sender = $result->mailing_sender;
201 if ($sender != null) {
202 $this->senders[$sender] = Adherent::getSName($this->zdb, (int)$sender);
203 } elseif ($result->mailing_sender_name != null || $result->mailing_sender_address != null) {
204 $this->senders[$result->mailing_sender_address] = $result->mailing_sender_name;
205 } else {
206 $this->senders[-1] = _('Superadmin');
207 }
208 }
209 } catch (\Exception $e) {
210 Analog::log(
211 'Cannot list senders from mailing history! | ' . $e->getMessage(),
212 Analog::WARNING
213 );
214 }
215 }
216
217 /**
218 * Builds the order clause
219 *
220 * @return string SQL ORDER clause
221 */
222 protected function buildOrderClause()
223 {
224 $order = array();
225
226 switch ($this->filters->orderby) {
227 case MailingsList::ORDERBY_DATE:
228 $order[] = 'mailing_date ' . $this->filters->ordered;
229 break;
230 case MailingsList::ORDERBY_SENDER:
231 $order[] = 'mailing_sender ' . $this->filters->ordered;
232 break;
233 case MailingsList::ORDERBY_SUBJECT:
234 $order[] = 'mailing_subject ' . $this->filters->ordered;
235 break;
236 case MailingsList::ORDERBY_SENT:
237 $order[] = 'mailing_sent ' . $this->filters->ordered;
238 break;
239 }
240
241 return $order;
242 }
243
244 /**
245 * Builds where clause, for filtering on simple list mode
246 *
247 * @param Select $select Original select
248 *
249 * @return string SQL WHERE clause
250 */
251 private function buildWhereClause($select)
252 {
253 try {
254 if ($this->filters->start_date_filter != null) {
255 $d = new \DateTime($this->filters->raw_start_date_filter);
256 $select->where->greaterThanOrEqualTo(
257 'mailing_date',
258 $d->format('Y-m-d')
259 );
260 }
261
262 if ($this->filters->end_date_filter != null) {
263 $d = new \DateTime($this->filters->raw_end_date_filter);
264 $select->where->lessThanOrEqualTo(
265 'mailing_date',
266 $d->format('Y-m-d')
267 );
268 }
269
270 if ($this->filters->sender_filter != null && $this->filters->sender_filter != '0') {
271 $sender = $this->filters->sender_filter;
272 if ($sender == '-1') {
273 $select->where('mailing_sender IS NULL');
274 } else {
275 $select->where->equalTo(
276 'mailing_sender',
277 $sender
278 );
279 }
280 }
281
282 switch ($this->filters->sent_filter) {
283 case self::FILTER_SENT:
284 $select->where('mailing_sent = true');
285 break;
286 case self::FILTER_NOT_SENT:
287 $select->where('mailing_sent = false');
288 break;
289 case self::FILTER_DC_SENT:
290 //nothing to do here.
291 break;
292 }
293
294
295 if ($this->filters->subject_filter != '') {
296 $token = $this->zdb->platform->quoteValue(
297 '%' . strtolower($this->filters->subject_filter) . '%'
298 );
299
300 $select->where(
301 'LOWER(mailing_subject) LIKE ' .
302 $token
303 );
304 }
305 } catch (\Exception $e) {
306 Analog::log(
307 __METHOD__ . ' | ' . $e->getMessage(),
308 Analog::WARNING
309 );
310 }
311 }
312
313 /**
314 * Count history entries from the query
315 *
316 * @param Select $select Original select
317 *
318 * @return void
319 */
320 private function proceedCount($select)
321 {
322 try {
323 $countSelect = clone $select;
324 $countSelect->reset($countSelect::COLUMNS);
325 $countSelect->reset($countSelect::JOINS);
326 $countSelect->reset($countSelect::ORDER);
327 $countSelect->columns(
328 array(
329 self::PK => new Expression('COUNT(' . self::PK . ')')
330 )
331 );
332
333 $results = $this->zdb->execute($countSelect);
334 $result = $results->current();
335
336 $k = self::PK;
337 $this->count = $result->$k;
338 if ($this->count > 0) {
339 $this->filters->setCounter($this->count);
340 }
341 } catch (\Exception $e) {
342 Analog::log(
343 'Cannot count history | ' . $e->getMessage(),
344 Analog::WARNING
345 );
346 return false;
347 }
348 }
349
350 /**
351 * Load mailing from an existing one
352 *
353 * @param Db $zdb Database instance
354 * @param integer $id Model identifier
355 * @param GaletteMailing $mailing Mailing object
356 * @param boolean $new True if we create a 'new' mailing,
357 * false otherwise (from preview for example)
358 *
359 * @return boolean
360 */
361 public static function loadFrom(Db $zdb, $id, $mailing, $new = true)
362 {
363 try {
364 $select = $zdb->select(self::TABLE);
365 $select->where('mailing_id = ' . $id);
366
367 $results = $zdb->execute($select);
368 $result = $results->current();
369
370 return $mailing->loadFromHistory($result, $new);
371 } catch (\Exception $e) {
372 Analog::log(
373 'Unable to load mailing model #' . $id . ' | ' .
374 $e->getMessage(),
375 Analog::WARNING
376 );
377 return false;
378 }
379 }
380
381 /**
382 * Store a mailing in the history
383 *
384 * @param boolean $sent Defaults to false
385 *
386 * @return boolean
387 */
388 public function storeMailing($sent = false)
389 {
390 if ($this->mailing instanceof Mailing) {
391 if ($this->mailing->sender_name != null) {
392 $this->sender_name = $this->mailing->getSenderName();
393 $this->sender_address = $this->mailing->getSenderAddress();
394 }
395 $this->sender = $this->login->id;
396 $this->subject = $this->mailing->subject;
397 $this->message = $this->mailing->message;
398 $this->recipients = $this->mailing->recipients;
399 $this->sent = $sent;
400 $this->date = date('Y-m-d H:i:s');
401 if (!$this->mailing->existsInHistory()) {
402 $this->store();
403 $this->mailing->id = $this->id;
404 $this->mailing->moveAttachments($this->id);
405 } else {
406 if ($this->mailing->tmp_path !== false) {
407 //attachments are still in a temporary path, move them
408 $this->mailing->moveAttachments($this->id);
409 }
410 //existing stored mailing. Just update row.
411 $this->update();
412 }
413 } else {
414 Analog::log(
415 '[' . __METHOD__ .
416 '] Mailing should be an instance of Mailing',
417 Analog::ERROR
418 );
419 return false;
420 }
421 }
422
423 /**
424 * Update in the database
425 *
426 * @return boolean
427 */
428 public function update()
429 {
430 try {
431 $_recipients = array();
432 if ($this->recipients != null) {
433 foreach ($this->recipients as $_r) {
434 $_recipients[$_r->id] = $_r->sname . ' <' . $_r->email . '>';
435 }
436 }
437
438 $sender = ($this->sender === 0) ?
439 new Expression('NULL') : $this->sender;
440 $sender_name = ($this->sender_name === null) ?
441 new Expression('NULL') : $this->sender_name;
442 $sender_address = ($this->sender_address === null) ?
443 new Expression('NULL') : $this->sender_address;
444
445 $values = array(
446 'mailing_sender' => $sender,
447 'mailing_sender_name' => $sender_name,
448 'mailing_sender_address' => $sender_address,
449 'mailing_subject' => $this->subject,
450 'mailing_body' => $this->message,
451 'mailing_date' => $this->date,
452 'mailing_recipients' => serialize($_recipients),
453 'mailing_sent' => ($this->sent) ?
454 true :
455 ($this->zdb->isPostgres() ? 'false' : 0)
456 );
457
458 $update = $this->zdb->update(self::TABLE);
459 $update->set($values);
460 $update->where(self::PK . ' = ' . $this->mailing->history_id);
461 $this->zdb->execute($update);
462 return true;
463 } catch (\Exception $e) {
464 Analog::log(
465 'An error occurend updating Mailing | ' . $e->getMessage(),
466 Analog::ERROR
467 );
468 return false;
469 }
470 }
471
472 /**
473 * Store in the database
474 *
475 * @return boolean
476 */
477 public function store()
478 {
479 try {
480 $_recipients = array();
481 if ($this->recipients != null) {
482 foreach ($this->recipients as $_r) {
483 $_recipients[$_r->id] = $_r->sname . ' <' . $_r->email . '>';
484 }
485 }
486
487 $sender = null;
488 if ($this->sender === 0) {
489 $sender = new Expression('NULL');
490 } else {
491 $sender = $this->sender;
492 }
493 $sender_name = ($this->sender_name === null) ?
494 new Expression('NULL') : $this->sender_name;
495 $sender_address = ($this->sender_address === null) ?
496 new Expression('NULL') : $this->sender_address;
497
498 $values = array(
499 'mailing_sender' => $sender,
500 'mailing_sender_name' => $sender_name,
501 'mailing_sender_address' => $sender_address,
502 'mailing_subject' => $this->subject,
503 'mailing_body' => $this->message,
504 'mailing_date' => $this->date,
505 'mailing_recipients' => serialize($_recipients),
506 'mailing_sent' => ($this->sent) ?
507 true :
508 ($this->zdb->isPostgres() ? 'false' : 0)
509 );
510
511 $insert = $this->zdb->insert(self::TABLE);
512 $insert->values($values);
513 $this->zdb->execute($insert);
514
515 if ($this->zdb->isPostgres()) {
516 $this->id = $this->zdb->driver->getLastGeneratedValue(
517 PREFIX_DB . 'mailing_history_id_seq'
518 );
519 } else {
520 $this->id = $this->zdb->driver->getLastGeneratedValue();
521 }
522 return true;
523 } catch (\Exception $e) {
524 Analog::log(
525 'An error occurend storing Mailing | ' . $e->getMessage(),
526 Analog::ERROR
527 );
528 return false;
529 }
530 }
531
532 /**
533 * Remove specified entries
534 *
535 * @param integer|array $ids Mailing history entries identifiers
536 *
537 * @return boolean
538 */
539 public function removeEntries($ids)
540 {
541 global $hist, $preferences;
542
543 $list = array();
544 if (is_numeric($ids)) {
545 //we've got only one identifier
546 $list[] = $ids;
547 } else {
548 $list = $ids;
549 }
550
551 if (is_array($list)) {
552 try {
553 foreach ($list as $id) {
554 $mailing = new Mailing($preferences, null, $id);
555 $mailing->removeAttachments();
556 }
557
558 $this->zdb->connection->beginTransaction();
559
560 //delete members
561 $delete = $this->zdb->delete(self::TABLE);
562 $delete->where->in(self::PK, $list);
563 $this->zdb->execute($delete);
564
565 //commit all changes
566 $this->zdb->connection->commit();
567
568 //add an history entry
569 $hist->add(
570 _T("Delete mailing entries")
571 );
572
573 return true;
574 } catch (\Exception $e) {
575 $this->zdb->connection->rollBack();
576 Analog::log(
577 'Unable to delete selected mailing history entries |' .
578 $e->getMessage(),
579 Analog::ERROR
580 );
581 return false;
582 }
583 } else {
584 //not numeric and not an array: incorrect.
585 Analog::log(
586 'Asking to remove mailing entries, but without ' .
587 'providing an array or a single numeric value.',
588 Analog::WARNING
589 );
590 return false;
591 }
592 }
593
594 /**
595 * Get table's name
596 *
597 * @param boolean $prefixed Whether table name should be prefixed
598 *
599 * @return string
600 */
601 protected function getTableName($prefixed = false)
602 {
603 if ($prefixed === true) {
604 return PREFIX_DB . self::TABLE;
605 } else {
606 return self::TABLE;
607 }
608 }
609
610 /**
611 * Get table's PK
612 *
613 * @return string
614 */
615 protected function getPk()
616 {
617 return self::PK;
618 }
619
620 /**
621 * Get count for current query
622 *
623 * @return int
624 */
625 public function getCount()
626 {
627 return $this->count;
628 }
629
630 /**
631 * Get senders list
632 *
633 * @return array
634 */
635 public function getSendersList()
636 {
637 return $this->senders;
638 }
639 }