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