PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.1
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.1
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
← All changes | back/Classes/MailClass.php +0 -1597 10.10.2 → 11.1.1 View file →
@@ -1,1597 +1,0 @@
1 -<?php
2 -
3 -namespace AcyMailing\Classes;
4 -
5 -use AcyMailing\Helpers\MailerHelper;
6 -use AcyMailing\Helpers\PaginationHelper;
7 -use AcyMailing\Helpers\PluginHelper;
8 -use AcyMailing\Core\AcymClass;
9 -
10 -class MailClass extends AcymClass
11 -{
12 - const FIELDS_ENCODING = [
13 - 'name',
14 - 'subject',
15 - 'body',
16 - 'autosave',
17 - 'preheader',
18 - ];
19 -
20 - const TYPE_STANDARD = 'standard';
21 - const TYPE_NOTIFICATION = 'notification';
22 - const TYPE_OVERRIDE = 'override';
23 - const TYPE_WELCOME = 'welcome';
24 - const TYPE_UNSUBSCRIBE = 'unsubscribe';
25 - const TYPE_AUTOMATION = 'automation';
26 - const TYPE_FOLLOWUP = 'followup';
27 - const TYPE_MAILBOX_ACTION = 'mailbox_action';
28 - const TYPE_TEMPLATE = 'template';
29 - const TYPE_SCENARIO = 'scenario';
30 -
31 - const ALL_TYPES = [
32 - self::TYPE_STANDARD,
33 - self::TYPE_NOTIFICATION,
34 - self::TYPE_OVERRIDE,
35 - self::TYPE_WELCOME,
36 - self::TYPE_UNSUBSCRIBE,
37 - self::TYPE_AUTOMATION,
38 - self::TYPE_FOLLOWUP,
39 - self::TYPE_MAILBOX_ACTION,
40 - self::TYPE_TEMPLATE,
41 - self::TYPE_SCENARIO,
42 - ];
43 -
44 - const TYPES_TRANSACTIONAL = [
45 - self::TYPE_NOTIFICATION,
46 - self::TYPE_OVERRIDE,
47 - self::TYPE_WELCOME,
48 - self::TYPE_UNSUBSCRIBE,
49 - self::TYPE_TEMPLATE,
50 - self::TYPE_SCENARIO,
51 - ];
52 -
53 - const TYPES_WITH_STATS = [
54 - self::TYPE_STANDARD,
55 - self::TYPE_AUTOMATION,
56 - self::TYPE_WELCOME,
57 - self::TYPE_UNSUBSCRIBE,
58 - self::TYPE_FOLLOWUP,
59 - self::TYPE_MAILBOX_ACTION,
60 - self::TYPE_SCENARIO,
61 - ];
62 -
63 - const TYPES_NO_NAME = [
64 - self::TYPE_NOTIFICATION,
65 - self::TYPE_OVERRIDE,
66 - ];
67 -
68 - const MAX_ALLOWED_TEMPLATE_FILES = 100;
69 - const MAX_ALLOWED_TEMPLATE_SIZE = 20971520;
70 - const ALLOWED_TEMPLATE_FILE_TYPES = [
71 - 'image/jpeg',
72 - 'image/png',
73 - 'image/gif',
74 - 'text/html',
75 - 'image/x-ms-bmp',
76 - 'image/bmp',
77 - 'text/plain',
78 - 'image/vnd.microsoft.icon',
79 - ];
80 -
81 - private array $templateNames = [];
82 - public array $exceptKeysDecode = [];
83 -
84 - public function __construct()
85 - {
86 - parent::__construct();
87 -
88 - $this->table = 'mail';
89 - $this->pkey = 'id';
90 - }
91 -
92 - public function getMatchingElements(array $settings = []): array
93 - {
94 - $query = 'SELECT mail.* FROM #__acym_mail AS mail';
95 - $queryCount = 'SELECT COUNT(mail.id) AS total FROM #__acym_mail AS mail';
96 -
97 - $filters = [];
98 - $tagJoin = '';
99 -
100 - if (!empty($settings['tag'])) {
101 - $tagJoin = ' JOIN #__acym_tag AS tag ON mail.id = tag.id_element ';
102 - $filters[] = 'tag.name = '.acym_escapeDB($settings['tag']);
103 - $filters[] = 'tag.type = "mail"';
104 - }
105 - $query .= $tagJoin;
106 - $queryCount .= $tagJoin;
107 -
108 - if (!empty($settings['search'])) {
109 - $filters[] = 'mail.name LIKE '.acym_escapeDB('%'.acym_utf8Encode($settings['search']).'%');
110 - }
111 -
112 - if (!empty($settings['gettingTemplates'])) {
113 - $filters[] = 'mail.type = '.acym_escapeDB(self::TYPE_TEMPLATE);
114 - if (!acym_isAdmin()) {
115 - $currentUserId = acym_currentUserId();
116 - $condition = 'mail.creator_id = '.intval($currentUserId);
117 -
118 - $userGroups = acym_getGroupsByUser($currentUserId);
119 - if (!empty($userGroups)) {
120 - $condition .= ' OR access LIKE "%,'.implode(',%" OR access LIKE "%,', $userGroups).',%"';
121 - }
122 -
123 - $filters[] = $condition;
124 - }
125 - } else {
126 - if (!empty($settings['automation']) || empty($settings['onlyStandard'])) {
127 - $filters[] = 'mail.type != '.acym_escapeDB(self::TYPE_NOTIFICATION);
128 - $filters[] = 'mail.type != '.acym_escapeDB(self::TYPE_OVERRIDE);
129 - } else {
130 - $filters[] = 'mail.type IN ('.acym_escapeDB(self::TYPE_STANDARD).', '.acym_escapeDB(self::TYPE_TEMPLATE).')';
131 - }
132 -
133 - if (empty($settings['automation'])) {
134 - $filters[] = 'mail.type IN ('.acym_escapeDB(self::TYPE_TEMPLATE).', '.acym_escapeDB(self::TYPE_WELCOME).', '.acym_escapeDB(self::TYPE_UNSUBSCRIBE).')';
135 - }
136 -
137 - if (!empty($settings['creator_id'])) {
138 - $mailTypeCondition = 'mail.type IN ('.acym_escapeDB(self::TYPE_TEMPLATE).', '.acym_escapeDB(self::TYPE_WELCOME).', '.acym_escapeDB(self::TYPE_UNSUBSCRIBE).')';
139 - $userGroups = acym_getGroupsByUser($settings['creator_id']);
140 - $groupCondition = '(mail.access LIKE "%,'.implode(',%" OR mail.access LIKE "%,', $userGroups).',%")';
141 - $filter = 'mail.creator_id = '.intval($settings['creator_id']).' OR ('.$mailTypeCondition.' AND '.$groupCondition.')';
142 -
143 - if (!acym_isAdmin() && !empty($settings['element_tab'])) {
144 - $filter = '('.$filter.')
145 - OR list.cms_user_id = '.intval($settings['creator_id']).'
146 - OR (list.access LIKE "%,'.implode(',%" OR list.access LIKE "%,', $userGroups).',%")';
147 - }
148 -
149 - $filters['list'] = '('.$filter.')';
150 - }
151 - }
152 -
153 - $filters[] = 'mail.parent_id IS NULL';
154 -
155 - if (!empty($settings['drag_editor'])) {
156 - $filters[] = 'mail.drag_editor = 1';
157 - }
158 -
159 - if (!empty($settings['element_tab'])) {
160 - $statJoin = ' LEFT JOIN #__acym_mail_stat AS mail_stat ON mail.id = mail_stat.mail_id ';
161 - $listJoin = acym_isAdmin() ? '' : ' LEFT JOIN #__acym_list AS list ON list.'.acym_escape($settings['element_tab']).'_id = mail.id';
162 - $query = 'SELECT DISTINCT mail.*, mail_stat.sent as subscribers, mail_stat.open_unique FROM #__acym_mail AS mail'.$statJoin.$tagJoin.$listJoin;
163 - $filters[] = 'mail.type = '.acym_escapeDB($settings['element_tab']);
164 - }
165 -
166 - if (!empty($filters)) {
167 - $query .= ' WHERE ('.implode(') AND (', $filters).')';
168 - if (!acym_isAdmin()) {
169 - unset($filters['list']);
170 - }
171 - $queryCount .= ' WHERE ('.implode(') AND (', $filters).')';
172 - }
173 -
174 - if (!empty($settings['ordering']) && !empty($settings['ordering_sort_order'])) {
175 - $query .= ' ORDER BY mail.'.acym_secureDBColumn($settings['ordering']).' '.acym_secureDBColumn(strtoupper($settings['ordering_sort_order']));
176 - }
177 -
178 - if (empty($settings['offset']) || $settings['offset'] < 0) {
179 - $settings['offset'] = 0;
180 - }
181 -
182 - if (empty($settings['elementsPerPage']) || $settings['elementsPerPage'] < 1) {
183 - $pagination = new PaginationHelper();
184 - $settings['elementsPerPage'] = $pagination->getListLimit();
185 - }
186 -
187 - $results['elements'] = $this->decode(acym_loadObjectList($query, '', $settings['offset'], $settings['elementsPerPage']));
188 - $results['total'] = acym_loadObject($queryCount);
189 -
190 - if (!empty($settings['element_tab'])) {
191 - $this->getAllListIdsForWelcomeUnsub($results['elements'], $settings['element_tab']);
192 - }
193 -
194 - $results['status'] = [];
195 -
196 - if (!empty($settings['element_tab'])) {
197 - $urlClickClass = new UrlClickClass();
198 - for ($i = 0; $i < count($results['elements']); $i++) {
199 - $results['elements'][$i]->open = 0;
200 - if (!empty($results['elements'][$i]->subscribers)) {
201 - $results['elements'][$i]->open = number_format($results['elements'][$i]->open_unique / $results['elements'][$i]->subscribers * 100, 2);
202 -
203 - $clicksNb = $urlClickClass->getNumberUsersClicked([$results['elements'][$i]->id]);
204 - $results['elements'][$i]->click = number_format($clicksNb / $results['elements'][$i]->subscribers * 100, 2);
205 - }
206 - }
207 - }
208 -
209 - return $results;
210 - }
211 -
212 - private function getAllListIdsForWelcomeUnsub(array $elements, string $type): void
213 - {
214 - if (empty($elements)) {
215 - return;
216 - }
217 -
218 - $column = $type === self::TYPE_WELCOME ? 'welcome_id' : 'unsubscribe_id';
219 -
220 - foreach ($elements as $element) {
221 - $element->lists = acym_loadObjectList('SELECT color, name FROM #__acym_list WHERE '.acym_secureDBColumn($column).' = '.intval($element->id));
222 - }
223 - }
224 -
225 - public function getAll(?string $key = null): array
226 - {
227 - $allMails = parent::getAll($key);
228 -
229 - return $this->decode($allMails);
230 - }
231 -
232 - public function getOneById(int $id, bool $needTranslatedSettings = false): ?object
233 - {
234 - $mail = $this->decode(parent::getOneById($id));
235 -
236 - if (!empty($mail)) {
237 - $tagsClass = new TagClass();
238 - $mail->tags = $tagsClass->getAllTagsByElementId(TagClass::TYPE_MAIL, intval($id));
239 - }
240 -
241 - if (isset($mail->access) && !is_array($mail->access)) $mail->access = explode(',', $mail->access);
242 -
243 - if (!empty($mail->parent_id) && $needTranslatedSettings) {
244 - $this->getTranslatedSettingsMail($mail);
245 - }
246 -
247 - return $mail;
248 - }
249 -
250 - private function getTranslatedSettingsMail(object $mail): void
251 - {
252 - $parentMailTranslation = acym_loadResult('SELECT translation FROM #__acym_mail WHERE id = '.intval($mail->parent_id));
253 - $parentMailTranslation = empty($parentMailTranslation) ? [] : json_decode($parentMailTranslation, true);
254 -
255 - $translationConfig = $this->config->get('sender_info_translation', '');
256 - $translationConfig = empty($translationConfig) ? [] : json_decode($translationConfig, true);
257 -
258 - if (!empty($parentMailTranslation[$mail->language])) {
259 - $senderTranslation = $parentMailTranslation[$mail->language];
260 - } elseif (!empty($translationConfig[$mail->language])) {
261 - $senderTranslation = $translationConfig[$mail->language];
262 - $senderTranslation['reply_to_email'] = $senderTranslation['replyto_email'];
263 - $senderTranslation['reply_to_name'] = $senderTranslation['replyto_name'];
264 - } else {
265 - return;
266 - }
267 -
268 - $mail->from_name = $senderTranslation['from_name'];
269 - $mail->from_email = $senderTranslation['from_email'];
270 - $mail->reply_to_name = $senderTranslation['reply_to_name'];
271 - $mail->reply_to_email = $senderTranslation['reply_to_email'];
272 - }
273 -
274 - public function getOneByName(string $name, bool $needTranslatedSettings = false, string $type = ''): ?object
275 - {
276 - $query = 'SELECT * FROM #__acym_mail WHERE `parent_id` IS NULL AND `name` = '.acym_escapeDB(acym_utf8Encode($name));
277 - if (!empty($type)) {
278 - $query .= ' AND `type` = '.acym_escapeDB($type);
279 - }
280 -
281 - $mail = acym_loadObject($query);
282 -
283 - if (empty($mail)) {
284 - return null;
285 - }
286 -
287 - $mail = $this->decode($mail);
288 -
289 - if (!empty($mail)) {
290 - $tagsClass = new TagClass();
291 - $mail->tags = $tagsClass->getAllTagsByElementId(TagClass::TYPE_MAIL, intval($mail->id));
292 - }
293 -
294 - if (!empty($mail->parent_id) && $needTranslatedSettings) {
295 - $this->getTranslatedSettingsMail($mail);
296 - }
297 -
298 - return $mail;
299 - }
300 -
301 - public function getMailsByType(?string $typeMail, array $settings): array
302 - {
303 - if (empty($settings['key'])) {
304 - $settings['key'] = '';
305 - }
306 - if (empty($settings['offset'])) {
307 - $settings['offset'] = 0;
308 - }
309 - if (empty($settings['mailsPerPage'])) {
310 - $settings['mailsPerPage'] = 12;
311 - }
312 - $search = $settings['filters']['search'] ?? '';
313 -
314 - $query = 'SELECT * FROM #__acym_mail AS mail';
315 - $queryCount = 'SELECT count(*) FROM #__acym_mail AS mail';
316 -
317 - $filters = [];
318 - if (!empty($typeMail)) {
319 - $filters[] = 'mail.type = '.acym_escapeDB($typeMail);
320 - }
321 -
322 - if (!empty($search)) {
323 - $filters[] = 'mail.name LIKE '.acym_escapeDB('%'.$search.'%');
324 - }
325 -
326 - if (!empty($filters)) {
327 - $query .= ' WHERE ('.implode(') AND (', $filters).')';
328 - $queryCount .= ' WHERE ('.implode(') AND (', $filters).')';
329 - }
330 -
331 - $query .= ' ORDER BY id DESC';
332 -
333 - $results['mails'] = $this->decode(acym_loadObjectList($query, $settings['key'], $settings['offset'], $settings['mailsPerPage']));
334 - $results['total'] = acym_loadResult($queryCount);
335 -
336 - return $results;
337 - }
338 -
339 - public function getAllListsWithCountSubscribersByMailIds(array $ids): array
340 - {
341 - acym_arrayToInteger($ids);
342 - if (empty($ids)) {
343 - return [];
344 - }
345 -
346 - $query = 'SELECT mailLists.list_id, mailLists.mail_id, list.*, COUNT(userLists.user_id) AS subscribers
347 - FROM #__acym_mail_has_list AS mailLists
348 - JOIN #__acym_list AS list ON mailLists.list_id = list.id
349 - LEFT JOIN #__acym_user_has_list AS userLists
350 - JOIN #__acym_user AS acyuser ON userLists.user_id = acyuser.id
351 - AND userLists.status = 1
352 - AND acyuser.active = 1 ';
353 -
354 - if ($this->config->get('require_confirmation', 1) == 1) {
355 - $query .= ' AND acyuser.confirmed = 1 ';
356 - }
357 -
358 - $query .= 'ON list.id = userLists.list_id
359 - WHERE mailLists.mail_id IN ('.implode(',', $ids).')
360 - GROUP BY mailLists.list_id, mailLists.mail_id';
361 -
362 - acym_query('SET SQL_BIG_SELECTS=1');
363 -
364 - return acym_loadObjectList($query);
365 - }
366 -
367 - public function getAllListsByMailIds(array $ids): array
368 - {
369 - acym_arrayToInteger($ids);
370 - if (empty($ids)) {
371 - return [];
372 - }
373 -
374 - $query = 'SELECT mailLists.mail_id, list.name, list.color
375 - FROM #__acym_mail_has_list AS mailLists
376 - JOIN #__acym_list AS list ON mailLists.list_id = list.id
377 - WHERE mailLists.mail_id IN ('.implode(',', $ids).')';
378 -
379 - return acym_loadObjectList($query);
380 - }
381 -
382 - public function getAllListsByMailId(int $id): array
383 - {
384 - $mail = $this->getOneById($id);
385 - if (empty($mail)) {
386 - return [];
387 - }
388 -
389 - if (self::TYPE_WELCOME === $mail->type) {
390 - $query = 'SELECT * FROM #__acym_list WHERE welcome_id = '.intval($id);
391 - } elseif (self::TYPE_FOLLOWUP === $mail->type) {
392 - $query = 'SELECT list.* FROM #__acym_followup_has_mail AS followup_mail
393 - JOIN #__acym_followup AS followup ON followup.id = followup_mail.followup_id AND followup_mail.mail_id = '.intval($id).'
394 - JOIN #__acym_list AS list ON list.id = followup.list_id';
395 - } else {
396 - $query = 'SELECT list.*
397 - FROM #__acym_mail_has_list AS mailLists
398 - JOIN #__acym_mail AS mail ON (mailLists.mail_id = mail.id OR mailLists.mail_id = mail.parent_id) AND mail.id = '.intval($id).'
399 - JOIN #__acym_list AS list ON mailLists.list_id = list.id';
400 - }
401 -
402 - return acym_loadObjectList($query, 'id');
403 - }
404 -
405 - public function getAllListsByMailIdAndUserId(int $mailId, int $userId): array
406 - {
407 - if (empty($mailId) || empty($userId)) {
408 - return [];
409 - }
410 -
411 - $query = 'SELECT list.* FROM #__acym_list AS list';
412 - $query .= ' JOIN #__acym_user_has_list AS userlist ON list.id = userlist.list_id AND userlist.user_id = '.intval($userId);
413 - $query .= ' JOIN #__acym_mail_has_list AS maillist ON maillist.list_id = list.id AND maillist.mail_id = '.intval($mailId);
414 -
415 - return acym_loadObjectList($query);
416 - }
417 -
418 - public function save(object $element): ?int
419 - {
420 - $mail = clone $element;
421 -
422 - if (isset($mail->tags)) {
423 - $tags = $mail->tags;
424 - unset($mail->tags);
425 - }
426 -
427 - if (empty($mail->id)) {
428 - $mail->creation_date = acym_date('now', 'Y-m-d H:i:s', false);
429 - if (empty($mail->creator_id)) $mail->creator_id = acym_currentUserId();
430 - }
431 -
432 - $mail = $this->encode($mail);
433 -
434 - $mail->autosave = null;
435 -
436 -
437 - if (isset($mail->thumbnail) && ((empty($mail->thumbnail) && !is_null($mail->thumbnail)) || strpos($mail->thumbnail, 'data:image/png;base64') !== false)) {
438 - unset($mail->thumbnail);
439 - }
440 -
441 - if (!isset($mail->access)) {
442 - $mail->access = '';
443 - }
444 -
445 - foreach ($mail as $oneAttribute => $value) {
446 - if (empty($value) || in_array($oneAttribute, ['thumbnail', 'settings'])) {
447 - continue;
448 - }
449 -
450 - if ($oneAttribute === 'access' && is_array($mail->$oneAttribute)) {
451 - $value = ','.trim(implode(',', $mail->$oneAttribute), ',').',';
452 - $mail->$oneAttribute = $value;
453 - }
454 -
455 - if (is_array($value)) {
456 - $mail->$oneAttribute = json_encode($value);
457 - }
458 -
459 - if (in_array($oneAttribute, ['body', 'headers'])) {
460 - $mail->$oneAttribute = preg_replace('#<input[^>]*value="[^"]*"[^>]*>#Uis', '', $mail->$oneAttribute);
461 - $mail->$oneAttribute = preg_replace('#<script.*</script>#Uis', '', $mail->$oneAttribute);
462 -
463 - $mail->$oneAttribute = str_replace(' contenteditable="true"', '', $mail->$oneAttribute);
464 - } else {
465 - $mail->$oneAttribute = strip_tags($mail->$oneAttribute);
466 - }
467 - }
468 -
469 - $mailID = parent::save($mail);
470 -
471 - if (!empty($mailID) && isset($tags)) {
472 - $tagClass = new TagClass();
473 - $tagClass->setTags(TagClass::TYPE_MAIL, intval($mailID), $tags);
474 - }
475 -
476 - return $mailID;
477 - }
478 -
479 - public function autoSave(object $mail, string $language = 'main'): bool
480 - {
481 - if (empty($mail->id)) {
482 - return false;
483 - }
484 -
485 - $mail->autosave = str_replace(' contenteditable="true"', '', $mail->autosave);
486 -
487 - if (acym_isMultilingual() && $language !== 'main') {
488 - $translationId = $this->getTranslationId($mail->id, $language);
489 - if (empty($translationId)) {
490 - $parentCopy = $this->getOneById($mail->id);
491 - if (empty($parentCopy)) {
492 - return false;
493 - }
494 -
495 - unset($parentCopy->id);
496 - $parentCopy->parent_id = $mail->id;
497 - $parentCopy->language = $language;
498 - $translationId = $this->save($parentCopy);
499 - }
500 - $mail->id = $translationId;
501 - }
502 -
503 - $mail = $this->encode($mail);
504 -
505 - return (bool)parent::save($mail);
506 - }
507 -
508 - public function delete(array $elements): int
509 - {
510 - if (empty($elements)) return 0;
511 -
512 - $this->deleteMediaFolder($elements);
513 - acym_arrayToInteger($elements);
514 -
515 - $favoriteTemplate = (int)$this->config->get('favorite_template', 0);
516 - if (in_array($favoriteTemplate, $elements)) {
517 - $this->config->saveConfig(['favorite_template' => 0]);
518 - }
519 -
520 - $allThumbnailToDelete = acym_loadResultArray('SELECT DISTINCT thumbnail FROM #__acym_mail WHERE id IN ('.implode(',', $elements).')');
521 -
522 - $translations = acym_loadResultArray('SELECT id FROM #__acym_mail WHERE parent_id IN ('.implode(',', $elements).')');
523 - $elements = array_merge($elements, $translations);
524 - if (!empty($translations)) {
525 - acym_query('UPDATE #__acym_mail SET `parent_id` = null WHERE `id` IN ('.implode(',', $translations).')');
526 - }
527 -
528 - acym_query('UPDATE #__acym_list SET welcome_id = null WHERE welcome_id IN ('.implode(',', $elements).')');
529 - acym_query('UPDATE #__acym_list SET unsubscribe_id = null WHERE unsubscribe_id IN ('.implode(',', $elements).')');
530 - acym_query('DELETE FROM #__acym_queue WHERE mail_id IN ('.implode(',', $elements).')');
531 - acym_query('DELETE FROM #__acym_mail_has_list WHERE mail_id IN ('.implode(',', $elements).')');
532 - acym_query('DELETE FROM #__acym_tag WHERE `type` = "mail" AND `id_element` IN ('.implode(',', $elements).')');
533 - acym_query('DELETE FROM #__acym_user_stat WHERE mail_id IN ('.implode(',', $elements).')');
534 - acym_query('DELETE FROM #__acym_url_click WHERE mail_id IN ('.implode(',', $elements).')');
535 - acym_query('DELETE FROM #__acym_mail_stat WHERE mail_id IN ('.implode(',', $elements).')');
536 - acym_query('DELETE FROM #__acym_followup_has_mail WHERE mail_id IN ('.implode(',', $elements).')');
537 - acym_query('DELETE FROM #__acym_mail_archive WHERE mail_id IN ('.implode(',', $elements).')');
538 -
539 - $return = parent::delete($elements);
540 -
541 - $this->deleteUnusedThumbnails($allThumbnailToDelete);
542 -
543 - return $return;
544 - }
545 -
546 - public function deleteMediaFolder(array $elements): void
547 - {
548 - if (empty($elements)) {
549 - return;
550 - }
551 -
552 - acym_arrayToInteger($elements);
553 - $results = acym_loadResultArray('SELECT mail_settings FROM #__acym_mail WHERE mail_settings IS NOT NULL AND id IN ('.implode(',', $elements).')');
554 -
555 - foreach ($results as $template) {
556 - $settings = json_decode($template, true);
557 -
558 - if (empty($settings['media_folder']) || !file_exists(ACYM_TEMPLATE.$settings['media_folder'])) {
559 - continue;
560 - }
561 - acym_deleteFolder(ACYM_TEMPLATE.$settings['media_folder']);
562 - }
563 - }
564 -
565 - public function deleteUnusedThumbnails(array $thumbnails): void
566 - {
567 - if (empty($thumbnails)) {
568 - return;
569 - }
570 -
571 - foreach ($thumbnails as $key => $oneThumb) {
572 - $thumbnails[$key] = acym_escapeDB($oneThumb);
573 - }
574 -
575 - $stillUsedThumbnails = acym_loadResultArray('SELECT thumbnail FROM #__acym_mail WHERE thumbnail IN ('.implode(',', $thumbnails).')');
576 - $thumbnailToDelete = array_diff($thumbnails, $stillUsedThumbnails);
577 - foreach ($thumbnailToDelete as $one) {
578 - if (!empty($one) && file_exists(ACYM_UPLOAD_FOLDER_THUMBNAIL.$one)) {
579 - unlink(ACYM_UPLOAD_FOLDER_THUMBNAIL.$one);
580 - }
581 - }
582 - }
583 -
584 - public function deleteOneAttachment(int $mailId, int $idAttachment): bool
585 - {
586 - if (empty($mailId)) {
587 - return false;
588 - }
589 -
590 - $mail = $this->getOneById($mailId);
591 -
592 - $attachments = $mail->attachments;
593 - if (empty($attachments)) {
594 - return false;
595 - }
596 - $decodedAttach = json_decode($attachments, true);
597 - unset($decodedAttach[$idAttachment]);
598 - $newAttachments = [];
599 - if (!empty($decodedAttach)) {
600 - foreach ($decodedAttach as $oneAttach) {
601 - $newAttachments[] = $oneAttach;
602 - }
603 - }
604 - $attachDb = json_encode($newAttachments);
605 -
606 - return (bool)acym_query('UPDATE #__acym_mail SET attachments = '.acym_escapeDB($attachDb).' WHERE id = '.intval($mailId).' OR parent_id = '.intval($mailId));
607 - }
608 -
609 - public function createTemplateFile(int $id): string
610 - {
611 - if (empty($id)) {
612 - return '';
613 - }
614 -
615 - $template = $this->getOneById($id);
616 - if (empty($template->id)) {
617 - return '';
618 - }
619 -
620 - $css = $this->buildCSS($template->stylesheet);
621 - if (empty($css)) {
622 - return '';
623 - }
624 -
625 - acym_createDir(ACYM_TEMPLATE.'css');
626 -
627 - $cssfile = ACYM_TEMPLATE.'css'.DS.'template_'.$id.'.css';
628 - if (acym_writeFile($cssfile, $css)) {
629 - return $cssfile;
630 - } else {
631 - acym_enqueueMessage('Could not create the file '.$cssfile, 'error');
632 -
633 - return '';
634 - }
635 - }
636 -
637 - public function buildCSS(?string $stylesheet): string
638 - {
639 - if (empty($stylesheet)) {
640 - return '';
641 - }
642 -
643 - $inline = '';
644 -
645 - if (preg_match_all('#@import[^;]*;#is', $stylesheet, $results)) {
646 - foreach ($results[0] as $oneResult) {
647 - $inline .= trim($oneResult)."\n";
648 - $stylesheet = str_replace($oneResult, '', $stylesheet);
649 - }
650 - }
651 -
652 - $inline .= $stylesheet;
653 -
654 - return $inline;
655 - }
656 -
657 - public function doupload(): bool
658 - {
659 - $zipFilePath = $this->uploadTemplate();
660 - if (empty($zipFilePath)) {
661 - return false;
662 - }
663 -
664 - $templateFolder = $this->extractTemplate($zipFilePath);
665 - if (empty($templateFolder)) {
666 - return false;
667 - }
668 -
669 - if (!$this->installExtractedTemplate($templateFolder)) {
670 - return false;
671 - }
672 -
673 - return true;
674 - }
675 -
676 - private function uploadTemplate(): ?string
677 - {
678 - $importFile = acym_getVar('file', 'uploadedfile', '', 'files');
679 -
680 - $fileError = $importFile['error'];
681 - if ($fileError > 0) {
682 - switch ($fileError) {
683 - case 1:
684 - acym_enqueueMessage(acym_translation('ACYM_FILE_UPLOAD_ERROR_1'), 'error');
685 -
686 - return null;
687 - case 2:
688 - acym_enqueueMessage(acym_translation('ACYM_FILE_UPLOAD_ERROR_2'), 'error');
689 -
690 - return null;
691 - case 3:
692 - acym_enqueueMessage(acym_translation('ACYM_FILE_UPLOAD_ERROR_3'), 'error');
693 -
694 - return null;
695 - case 4:
696 - acym_enqueueMessage(acym_translation('ACYM_FILE_UPLOAD_ERROR_4'), 'error');
697 -
698 - return null;
699 - default:
700 - acym_enqueueMessage(acym_translationSprintf('ACYM_FILE_UPLOAD_ERROR_5', $fileError), 'error');
701 -
702 - return null;
703 - }
704 - }
705 -
706 - if (empty($importFile['name'])) {
707 - acym_enqueueMessage(acym_translation('ACYM_BROWSE_FILE'), 'error');
708 -
709 - return null;
710 - }
711 -
712 - $uploadPath = acym_cleanPath(ACYM_ROOT.ACYM_MEDIA_FOLDER.'templates');
713 -
714 - if (!is_writable($uploadPath)) {
715 - @chmod($uploadPath, '0755');
716 - if (!is_writable($uploadPath)) {
717 - acym_enqueueMessage(acym_translationSprintf('ACYM_WRITABLE_FOLDER', $uploadPath), 'warning');
718 - }
719 - }
720 -
721 - if (!(bool)ini_get('file_uploads')) {
722 - acym_enqueueMessage(acym_translationSprintf('ACYM_FILE_UPLOAD_ERROR_6'), 'error');
723 -
724 - return null;
725 - }
726 -
727 - if (!extension_loaded('zlib')) {
728 - acym_raiseError(500, acym_translation('ACYM_MISSING_ZLIB'));
729 -
730 - return null;
731 - }
732 -
733 - $filename = strtolower(acym_makeSafeFile($importFile['name']));
734 - $extension = strtolower(substr($filename, strrpos($filename, '.') + 1));
735 -
736 - $allowedFileType = true;
737 - if ($extension !== 'zip') {
738 - $allowedFileType = false;
739 - } elseif (!in_array($importFile['type'], ['application/zip', 'application/x-zip-compressed'])) {
740 - $allowedFileType = false;
741 - } elseif (function_exists('mime_content_type') && !in_array(mime_content_type($importFile['tmp_name']), ['application/zip', 'application/x-zip-compressed'])) {
742 - $allowedFileType = false;
743 - }
744 -
745 - if (!$allowedFileType) {
746 - acym_enqueueMessage(acym_translationSprintf('ACYM_ACCEPTED_TYPE', $extension, 'zip'), 'error');
747 -
748 - return null;
749 - }
750 -
751 - if (class_exists('ZipArchive')) {
752 - $zip = new \ZipArchive();
753 - if (filesize($importFile['tmp_name']) > self::MAX_ALLOWED_TEMPLATE_SIZE || !$zip->open($importFile['tmp_name']) || $zip->count() > self::MAX_ALLOWED_TEMPLATE_FILES) {
754 - acym_enqueueMessage(acym_translation('ACYM_UPLOADED_ARCHIVE_NOT_ALLOWED'), 'error');
755 -
756 - return null;
757 - }
758 -
759 - $zip->close();
760 - }
761 -
762 - $tmpPath = acym_getCMSConfig('tmp_path', ACYM_MEDIA.'tmp'.DS);
763 - $zipFilePath = acym_cleanPath($tmpPath.DS.$filename);
764 -
765 - $uploaded = acym_uploadFile($importFile['tmp_name'], $zipFilePath);
766 - if (!$uploaded) {
767 - acym_enqueueMessage(acym_translationSprintf('ACYM_FILE_UPLOAD_ERROR_7', $importFile['tmp_name'], $zipFilePath), 'error');
768 -
769 - return null;
770 - }
771 -
772 - return $zipFilePath;
773 - }
774 -
775 - private function extractTemplate(string $zipFilePath, bool $deleteZip = true): ?string
776 - {
777 - $extractdir = acym_cleanPath(dirname($zipFilePath).DS.uniqid().uniqid().uniqid().'_template');
778 -
779 - $result = acym_extractArchive($zipFilePath, $extractdir);
780 -
781 - if (!$result) {
782 - acym_enqueueMessage(acym_translationSprintf('ACYM_FILE_UPLOAD_ERROR_9', $zipFilePath, $extractdir), 'error');
783 -
784 - return null;
785 - }
786 -
787 - if ($deleteZip) {
788 - acym_deleteFile($zipFilePath);
789 - }
790 -
791 - $allFiles = acym_getFiles($extractdir, '.', true, true, [], []);
792 - foreach ($allFiles as $oneFile) {
793 - if (function_exists('mime_content_type')) {
794 - $fileType = mime_content_type($oneFile);
795 - if (in_array($fileType, self::ALLOWED_TEMPLATE_FILE_TYPES) && preg_match('#\.(jpg|gif|png|jpeg|ico|bmp|html|htm|css|webp)$#i', $oneFile)) {
796 - continue;
797 - }
798 - } elseif (preg_match('#\.(jpg|gif|png|jpeg|ico|bmp|html|htm|css|webp)$#i', $oneFile)) {
799 - continue;
800 - }
801 -
802 - if (acym_deleteFile($oneFile)) {
803 - acym_enqueueMessage(acym_translationSprintf('ACYM_FILE_UPLOAD_ERROR_8', $oneFile), 'warning');
804 - }
805 - }
806 -
807 - return $extractdir;
808 - }
809 -
810 - public function installExtractedTemplate(string $templateFolder, bool $deleteFolder = true): bool
811 - {
812 - if ($this->detectTemplates($templateFolder)) {
813 - $messages = $this->templateNames;
814 - array_unshift($messages, acym_translationSprintf('ACYM_TEMPLATES_INSTALL', count($this->templateNames)));
815 - acym_enqueueMessage($messages);
816 - if ($deleteFolder && is_dir($templateFolder)) {
817 - acym_deleteFolder($templateFolder);
818 - }
819 -
820 - return true;
821 - }
822 -
823 - acym_enqueueMessage(acym_translationSprintf('ACYM_FILE_UPLOAD_ERROR_10'), 'error');
824 - if ($deleteFolder && is_dir($templateFolder)) {
825 - acym_deleteFolder($templateFolder);
826 - }
827 -
828 - return false;
829 - }
830 -
831 - public function detectTemplates(string $folder): bool
832 - {
833 - $allFiles = acym_getFiles($folder);
834 - if (!empty($allFiles)) {
835 - $keyTmpl = array_search('template.html', $allFiles);
836 - if ($keyTmpl !== false) {
837 - if ($this->installTemplate($folder.DS.$allFiles[$keyTmpl])) {
838 - return true;
839 - }
840 - }
841 - foreach ($allFiles as $oneFile) {
842 - if (preg_match('#^.*(html|htm)$#i', $oneFile)) {
843 - if ($this->installTemplate($folder.DS.$oneFile)) {
844 - return true;
845 - }
846 - }
847 - }
848 - }
849 -
850 - $status = false;
851 - $allFolders = acym_getFolders($folder);
852 - if (!empty($allFolders)) {
853 - foreach ($allFolders as $oneFolder) {
854 - $status = $this->detectTemplates($folder.DS.$oneFolder) || $status;
855 - }
856 - }
857 -
858 - return $status;
859 - }
860 -
861 - private function installTemplate(string $filepath): bool
862 - {
863 - $fileContent = acym_fileGetContent($filepath);
864 -
865 - $newTemplate = new \stdClass();
866 -
867 - if (strpos($filepath, '_template') === false) {
868 - $newTemplate->name = basename(dirname($filepath));
869 - } else {
870 - $newTemplate->name = basename($filepath);
871 - $newTemplate->name = substr($newTemplate->name, 0, strrpos($newTemplate->name, '.'));
872 - }
873 -
874 - $newTemplate->name = trim(preg_replace('#[^a-z0-9]#i', ' ', $newTemplate->name));
875 -
876 - if (preg_match('#< *title[^>]*>(.*)< */ *title *>#Uis', $fileContent, $results) && !empty($results[1])) $newTemplate->name = $results[1];
877 -
878 - if (preg_match('#< *meta *name="fromname" *content="([^"]*)"#Uis', $fileContent, $results) && !empty($results[1])) $newTemplate->fromname = $results[1];
879 - if (preg_match('#< *meta *name="fromemail" *content="([^"]*)"#Uis', $fileContent, $results) && !empty($results[1])) $newTemplate->fromemail = $results[1];
880 - if (preg_match('#< *meta *name="replyname" *content="([^"]*)"#Uis', $fileContent, $results) && !empty($results[1])) $newTemplate->replyname = $results[1];
881 - if (preg_match('#< *meta *name="replyemail" *content="([^"]*)"#Uis', $fileContent, $results) && !empty($results[1])) $newTemplate->replyemail = $results[1];
882 - if (preg_match('#< *meta *name="subject" *content="([^"]*)"#Uis', $fileContent, $results) && !empty($results[1])) $newTemplate->subject = $results[1];
883 - if (preg_match('#< *meta *name="settings" *content="([^"]*)"#Uis', $fileContent, $results) && !empty($results[1])) {
884 - $newTemplate->settings = htmlspecialchars_decode($results[1]);
885 - }
886 -
887 - $newFolder = preg_replace('#[^a-z0-9]#i', '_', strtolower($newTemplate->name));
888 - $newTemplateFolder = $newFolder;
889 - $i = 1;
890 - while (is_dir(ACYM_TEMPLATE.$newTemplateFolder)) {
891 - $newTemplateFolder = $newFolder.'_'.$i;
892 - $i++;
893 - }
894 - $newTemplate->mail_settings = ['media_folder' => $newTemplateFolder];
895 -
896 - $moveResult = acym_copyFolder(dirname($filepath), ACYM_TEMPLATE.$newTemplateFolder);
897 - if ($moveResult !== true) {
898 - acym_display([acym_translationSprintf('ACYM_ERROR_COPYING_FOLDER_TO', dirname($filepath), ACYM_TEMPLATE.$newTemplateFolder), $moveResult], 'error');
899 -
900 - return false;
901 - }
902 -
903 - if (!file_exists(ACYM_TEMPLATE.$newTemplateFolder.DS.'index.html')) {
904 - $indexFile = '<html><body bgcolor="#FFFFFF"></body></html>';
905 - acym_writeFile(ACYM_TEMPLATE.$newTemplateFolder.DS.'index.html', $indexFile);
906 - }
907 -
908 - $fileContent = str_replace(
909 - [
910 - 'src="./',
911 - 'src="../',
912 - 'src="images/',
913 - 'url("images/',
914 - 'url(&quot;images/',
915 - ],
916 - [
917 - 'src="'.ACYM_TEMPLATE_URL.$newTemplateFolder.'/',
918 - 'src="'.ACYM_TEMPLATE_URL,
919 - 'src="'.ACYM_TEMPLATE_URL.$newTemplateFolder.'/images/',
920 - 'url("'.ACYM_TEMPLATE_URL.$newTemplateFolder.'/images/',
921 - 'url(&quot;'.ACYM_TEMPLATE_URL.$newTemplateFolder.'/images/',
922 - ],
923 - $fileContent
924 - );
925 -
926 - $fileContent = preg_replace('#(src|background)[ ]*=[ ]*\"(?!(https?://|/))(?:\.\./|\./)?#', '$1="'.ACYM_TEMPLATE_URL.$newTemplateFolder.'/', $fileContent);
927 -
928 - if (preg_match('#< *body[^>]*>(.*)< */ *body *>#Uis', $fileContent, $results)) {
929 - $newTemplate->body = $results[1];
930 - } else {
931 - $newTemplate->body = $fileContent;
932 - }
933 -
934 - $newTemplate->stylesheet = '';
935 - if (preg_match_all('#< *style[^>]*>(.*)< */ *style *>#Uis', $fileContent, $results)) {
936 - $newTemplate->stylesheet .= preg_replace('#(<!--|-->)#s', '', implode("\n", $results[1]));
937 - }
938 - $cssFiles = [];
939 - $cssFiles[ACYM_TEMPLATE.$newTemplateFolder] = acym_getFiles(ACYM_TEMPLATE.$newTemplateFolder, '\.css$');
940 - $subFolders = acym_getFolders(ACYM_TEMPLATE.$newTemplateFolder);
941 - foreach ($subFolders as $oneFolder) {
942 - $cssFiles[ACYM_TEMPLATE.$newTemplateFolder.DS.$oneFolder] = acym_getFiles(ACYM_TEMPLATE.$newTemplateFolder.DS.$oneFolder, '\.css$');
943 - }
944 -
945 - foreach ($cssFiles as $cssFolder => $cssFile) {
946 - if (empty($cssFile)) continue;
947 - $newTemplate->stylesheet .= "\n".acym_fileGetContent($cssFolder.DS.reset($cssFile));
948 - }
949 -
950 - if (!empty($newTemplate->stylesheet)) {
951 - if (preg_match('#body *\{[^\}]*background-color:([^;\}]*)[;\}]#Uis', $newTemplate->stylesheet, $backgroundresults)) {
952 - $newTemplate->stylesheet = preg_replace('#(body *\{[^\}]*)background-color:[^;\}]*[;\}]#Uis', '$1', $newTemplate->stylesheet);
953 - }
954 -
955 - $quickstyle = [
956 - 'tag_h1' => 'h1',
957 - 'tag_h2' => 'h2',
958 - 'tag_h3' => 'h3',
959 - 'tag_h4' => 'h4',
960 - 'tag_h5' => 'h5',
961 - 'tag_h6' => 'h6',
962 - 'tag_a' => 'a',
963 - 'tag_ul' => 'ul',
964 - 'tag_li' => 'li',
965 - 'acym_unsub' => '\.acym_unsub',
966 - 'acym_online' => '\.acym_online',
967 - 'acym_title' => '\.acym_title',
968 - 'acym_content' => '\.acym_content',
969 - 'acym_readmore' => '\.acym_readmore',
970 - ];
971 - foreach ($quickstyle as $styledb => $oneStyle) {
972 - if (preg_match('#[^a-z\. ,] *'.$oneStyle.' *{([^}]*)}#Uis', $newTemplate->stylesheet, $quickstyleresults)) {
973 - $newTemplate->stylesheet = str_replace($quickstyleresults[0], '', $newTemplate->stylesheet);
974 - }
975 - }
976 - }
977 -
978 - $foldersForPicts = [$newTemplateFolder];
979 - $otherFolders = acym_getFolders(ACYM_TEMPLATE.$newTemplateFolder);
980 - foreach ($otherFolders as $oneFold) {
981 - $foldersForPicts[] = $newTemplateFolder.DS.$oneFold;
982 - }
983 - $allPictures = [];
984 - foreach ($foldersForPicts as $oneFolder) {
985 - $allPictures[$oneFolder] = acym_getFiles(ACYM_TEMPLATE.$oneFolder);
986 - }
987 -
988 - $uploadsFolder = ACYM_UPLOAD_FOLDER_THUMBNAIL;
989 -
990 - $thumbNb = intval($this->config->get('numberThumbnail', 2));
991 -
992 - foreach ($allPictures as $folder => $pictfolders) {
993 - foreach ($pictfolders as $onePict) {
994 - if (!preg_match('#\.(jpg|gif|png|jpeg|ico|bmp)$#i', $onePict)) continue;
995 - if (preg_match('#(thumbnail|screenshot|muestra)#i', $onePict)) {
996 - $thumbNb++;
997 - $newNamePict = 'thumbnail_'.$thumbNb.'.png';
998 - copy(ACYM_TEMPLATE.str_replace(DS, '/', $folder).'/'.$onePict, $uploadsFolder.$newNamePict);
999 - $newTemplate->thumbnail = $newNamePict;
1000 - }
1001 - }
1002 - }
1003 -
1004 - $this->config->saveConfig(['numberThumbnail' => $thumbNb]);
1005 -
1006 - $newTemplate->drag_editor = strpos($newTemplate->body, 'acym__wysid__template__content') !== false ? 1 : 0;
1007 - $newTemplate->type = self::TYPE_TEMPLATE;
1008 - $newTemplate->creation_date = acym_date('now', 'Y-m-d H:i:s', false);
1009 -
1010 - $this->save($newTemplate);
1011 -
1012 - $this->templateNames[] = $newTemplate->name;
1013 -
1014 - return true;
1015 - }
1016 -
1017 - public function sendAutomation(int $mailId, array $userIds, string $sendingDate, array $automationAdmin = [])
1018 - {
1019 - if (empty($mailId)) {
1020 - return acym_translationSprintf('ACYM_EMAILS_ADDED_QUEUE', 0);
1021 - }
1022 -
1023 - if (empty($sendingDate)) {
1024 - return acym_translation('ACYM_WRONG_DATE');
1025 - }
1026 -
1027 - if (empty($userIds)) {
1028 - return acym_translation('ACYM_USER_NOT_FOUND');
1029 - }
1030 -
1031 - acym_arrayToInteger($userIds);
1032 -
1033 - $nbSent = $this->sendNotification($mailId, $userIds, $automationAdmin);
1034 - if (!is_null($nbSent)) {
1035 - return $nbSent;
1036 - }
1037 -
1038 - $result = acym_query(
1039 - 'INSERT IGNORE INTO #__acym_queue (`mail_id`, `user_id`, `sending_date`)
1040 - SELECT '.intval($mailId).', user.id, '.acym_escapeDB($sendingDate).'
1041 - FROM #__acym_user AS user
1042 - WHERE user.active = 1 AND user.id IN ('.implode(',', $userIds).')'
1043 - );
1044 -
1045 - if ($result === 0) {
1046 - return acym_translation('ACYM_CAMPAIGN_ALREADY_QUEUED');
1047 - }
1048 -
1049 - $mailStatClass = new MailStatClass();
1050 - $mailStat = $mailStatClass->getOneRowByMailId($mailId);
1051 -
1052 - $newMailStat = new \stdClass();
1053 - $newMailStat->mail_id = intval($mailId);
1054 - $newMailStat->total_subscribers = intval($result);
1055 - if (empty($mailStat)) {
1056 - $newMailStat->send_date = $sendingDate;
1057 - }
1058 -
1059 - $mailStatClass->save($newMailStat);
1060 -
1061 - return $result;
1062 - }
1063 -
1064 - private function sendNotification(int $mailId, array $userIds, array $automationAdmin): ?int
1065 - {
1066 - if (empty($automationAdmin['user_id'])) {
1067 - return null;
1068 - }
1069 -
1070 - $userClass = new UserClass();
1071 - $mail = $this->getOneById($mailId);
1072 - $user = $userClass->getOneById($automationAdmin['user_id']);
1073 -
1074 - if (empty($mail) || empty($user)) {
1075 - return 0;
1076 - }
1077 -
1078 - $mailerHelper = new MailerHelper();
1079 - $pluginHelper = new PluginHelper();
1080 - $extractedTags = $pluginHelper->extractTags($mail, 'subscriber');
1081 -
1082 - $isNotification = false;
1083 - foreach ($extractedTags as $dtext => $oneTag) {
1084 - if (empty($oneTag->info) || $oneTag->info !== 'current') {
1085 - continue;
1086 - }
1087 -
1088 - $isNotification = true;
1089 -
1090 - if (!empty($user->{$oneTag->id})) {
1091 - $mailerHelper->addParam(str_replace(['{', '}'], '', $dtext), $user->{$oneTag->id});
1092 - }
1093 - }
1094 -
1095 - if (!$isNotification) {
1096 - if (isset($automationAdmin['automationAdmin']) && $automationAdmin['automationAdmin']) {
1097 - return 0;
1098 - } else {
1099 - return null;
1100 - }
1101 - }
1102 -
1103 - $userFields = $userClass->getAllUserFields($user);
1104 - foreach ($userFields as $map => $value) {
1105 - $mailerHelper->addParam('subscriber:'.$map.'|info:current', $value);
1106 - $mailerHelper->addParam('user:'.$map, $value);
1107 - }
1108 -
1109 - $emailsSent = 0;
1110 - foreach ($userIds as $userId) {
1111 - if ($mailerHelper->sendOne($mail->id, $userId)) {
1112 - $emailsSent++;
1113 - }
1114 - }
1115 -
1116 - return $emailsSent;
1117 - }
1118 -
1119 - public function encode($mails = [])
1120 - {
1121 - $isArray = true;
1122 - if (!is_array($mails)) {
1123 - $mails = [$mails];
1124 -
1125 - $isArray = false;
1126 - }
1127 -
1128 - $encodedMails = array_map([$this, 'removePoweredByAcyMailing'], $mails);
1129 -
1130 - $encodedMails = array_map([$this, 'utf8Encode'], $encodedMails);
1131 -
1132 - return $isArray ? $encodedMails : $encodedMails[0];
1133 - }
1134 -
1135 - public function decode($mails = [])
1136 - {
1137 - if (is_null($mails)) {
1138 - return null;
1139 - }
1140 -
1141 - $isArray = true;
1142 - if (!is_array($mails)) {
1143 - $mails = [$mails];
1144 -
1145 - $isArray = false;
1146 - }
1147 -
1148 - $decodedMails = array_map([$this, 'utf8Decode'], $mails);
1149 -
1150 - $decodedMails = array_map([$this, 'addPoweredByAcyMailing'], $decodedMails);
1151 -
1152 - foreach ($decodedMails as $i => $oneMail) {
1153 - if (!isset($oneMail->access) || is_array($oneMail->access)) continue;
1154 - $decodedMails[$i]->access = empty($oneMail->access) ? '' : explode(',', $oneMail->access);
1155 - }
1156 -
1157 - return $isArray ? $decodedMails : $decodedMails[0];
1158 - }
1159 -
1160 - protected function utf8Decode($mail)
1161 - {
1162 - if (!empty($mail)) {
1163 - foreach (self::FIELDS_ENCODING as $oneField) {
1164 - if (in_array($oneField, $this->exceptKeysDecode)) {
1165 - continue;
1166 - }
1167 -
1168 - if (is_array($mail)) {
1169 - if (empty($mail[$oneField])) continue;
1170 - $value = &$mail[$oneField];
1171 - } else {
1172 - if (empty($mail->$oneField)) continue;
1173 - $value = &$mail->$oneField;
1174 - }
1175 -
1176 - $value = acym_utf8Decode($value);
1177 - }
1178 - }
1179 -
1180 - return $mail;
1181 - }
1182 -
1183 - private function addPoweredByAcyMailing(object $mail): object
1184 - {
1185 - if (empty($mail->body)) {
1186 - return $mail;
1187 - }
1188 -
1189 - if ($this->config->get('display_built_by', 0) != 1) {
1190 - if (strpos($mail->body, 'acym__powered_by_acymailing') !== false) {
1191 - $mailBodyDom = new \DOMDocument();
1192 - @$mailBodyDom->loadHTML('<?xml encoding="utf-8" ?>'.$mail->body);
1193 - $tables = $mailBodyDom->getElementsByTagName('table');
1194 - foreach ($tables as $table) {
1195 - if ($table->getAttribute('id') != 'acym__powered_by_acymailing') continue;
1196 - $table->parentNode->removeChild($table);
1197 - break;
1198 - }
1199 - $mail->body = $mailBodyDom->saveHTML();
1200 - }
1201 -
1202 - return $mail;
1203 - }
1204 -
1205 - if (strpos($mail->body, 'acym__powered_by_acymailing') !== false) {
1206 - return $mail;
1207 - }
1208 -
1209 - $isWysidEditor = strpos($mail->body, 'acym__wysid__template') !== false;
1210 - $urlPoweredByImage = ACYM_IMAGES.'editor/poweredby_black.png';
1211 -
1212 - if (!$isWysidEditor) {
1213 - $poweredByHTML = '<p id="acym__powered_by_acymailing">';
1214 - $poweredByHTML .= '<a href="'.ACYM_ACYMAILING_WEBSITE.'?utm_campaign=powered_by_v7&utm_source=acymailing_plugin&utm_medium=built_with_footer" target="blank">';
1215 - $poweredByHTML .= '<img alt="Email built with AcyMailing" height="40" width="199" style="height: 40px; width:199px; max-width: 100%; height: auto; box-sizing: border-box; padding: 0 5px; display: block; margin-left: auto; margin-right: auto;" src="'.$urlPoweredByImage.'"/>';
1216 - $poweredByHTML .= '</a></p>';
1217 -
1218 - $mail->body = $mail->body.$poweredByHTML;
1219 - } else {
1220 - $poweredByWYSID = '<table id="acym__powered_by_acymailing" class="row" bgcolor="#ffffff" style="background-color: transparent" cellpadding="0" cellspacing="0" border="0">
1221 - <tbody bgcolor style="background-color: inherit;">
1222 - <tr>
1223 - <th class="small-12 medium-12 large-12 columns" valign="top" style="height: auto;">
1224 - <table border="0" cellpadding="0" cellspacing="0"
1225 - style="min-height: 0px; display: table; height: auto;">
1226 - <tbody style="min-height: 0px; display: table-row-group;">
1227 - <tr
1228 - style="position: relative; top: inherit; left: inherit; right: inherit; bottom: inherit; height: auto;">
1229 - <td class="large-12">
1230 - <div style="position: relative;">
1231 - <p style="word-break: break-word; text-align: center;">
1232 - <a href="'.ACYM_ACYMAILING_WEBSITE.'?utm_campaign=powered_by_v7&utm_source=acymailing_plugin&utm_medium=built_with_footer" target="_blank">
1233 - <img src="'.$urlPoweredByImage.'"
1234 - title="poweredby" alt="Email built with AcyMailing"
1235 - style="height: 40px; width:199px; max-width: 100%; height: auto; box-sizing: border-box; padding: 0px 5px; display: inline-block; margin-left: auto; margin-right: auto;"
1236 - height="40" width="199">
1237 - </a>
1238 - </p>
1239 - </div>
1240 - </td>
1241 - </tr>
1242 - </tbody>
1243 - </table>
1244 - </th>
1245 - </tr>
1246 - </tbody>
1247 -</table>';
1248 -
1249 - $mailBodyDom = new \DOMDocument();
1250 - @$mailBodyDom->loadHTML('<?xml encoding="utf-8" ?>'.$mail->body);
1251 -
1252 - $htmlToAddDom = new \DOMDocument();
1253 - @$htmlToAddDom->loadHTML('<?xml encoding="utf-8" ?>'.$poweredByWYSID);
1254 - $tableToAdd = $htmlToAddDom->getElementById('acym__powered_by_acymailing');
1255 -
1256 - $tds = $mailBodyDom->getElementsByTagName('td');
1257 - foreach ($tds as $td) {
1258 - $classes = explode(' ', $td->getAttribute('class'));
1259 - if (!in_array('acym__wysid__row', $classes)) continue;
1260 - if (!empty($tableToAdd)) $td->appendChild($mailBodyDom->importNode($tableToAdd, true));
1261 - break;
1262 - }
1263 - $mail->body = $mailBodyDom->saveHTML();
1264 - }
1265 -
1266 - return $mail;
1267 - }
1268 -
1269 - protected function removePoweredByAcyMailing(object $mail): object
1270 - {
1271 - if (empty($mail->body) || strpos($mail->body, 'acym__wysid__template') !== false) {
1272 - return $mail;
1273 - }
1274 -
1275 - $regexPoweredByAcyMailing = '#<p id="acym__powered_by_acymailing.*<\/p>#U';
1276 -
1277 - $mail->body = preg_replace($regexPoweredByAcyMailing, '', $mail->body);
1278 -
1279 - return $mail;
1280 - }
1281 -
1282 - protected function utf8Encode($mail)
1283 - {
1284 - if (!empty($mail)) {
1285 - foreach (self::FIELDS_ENCODING as $oneField) {
1286 - if (is_array($mail)) {
1287 - if (empty($mail[$oneField])) continue;
1288 - $value = &$mail[$oneField];
1289 - } else {
1290 - if (empty($mail->$oneField)) continue;
1291 - $value = &$mail->$oneField;
1292 - }
1293 -
1294 - $value = acym_utf8Encode($value);
1295 - }
1296 - }
1297 -
1298 - return $mail;
1299 - }
1300 -
1301 - public function getTranslationId(int $parentId, string $langCode): int
1302 - {
1303 - return (int)acym_loadResult(
1304 - 'SELECT `id`
1305 - FROM #__acym_mail
1306 - WHERE `parent_id` = '.intval($parentId).'
1307 - AND `language` = '.acym_escapeDB($langCode)
1308 - );
1309 - }
1310 -
1311 - public function getTranslationsById(int $mailId, bool $full = false, bool $includeParent = false)
1312 - {
1313 - $data = $full ? '*' : '`language`, `subject`, `preheader`, `body`, `autosave`';
1314 - $where = $includeParent ? ' OR `id` = '.intval($mailId) : '';
1315 -
1316 - return $this->decode(
1317 - acym_loadObjectList(
1318 - 'SELECT '.$data.'
1319 - FROM #__acym_mail
1320 - WHERE `parent_id` = '.intval($mailId).$where,
1321 - 'language'
1322 - )
1323 - );
1324 - }
1325 -
1326 - public function deleteByTranslationLang(array $languageCodes): void
1327 - {
1328 - if (empty($languageCodes)) {
1329 - return;
1330 - }
1331 -
1332 - foreach ($languageCodes as $key => $oneLangCode) {
1333 - $languageCodes[$key] = acym_escapeDB($oneLangCode);
1334 - }
1335 -
1336 - $this->delete(
1337 - acym_loadResultArray(
1338 - 'SELECT `id`
1339 - FROM #__acym_mail
1340 - WHERE `parent_id` IS NOT NULL
1341 - AND `language` IN ('.implode(', ', $languageCodes).')'
1342 - )
1343 - );
1344 - }
1345 -
1346 - public function getMultilingualMails(int $parentId): array
1347 - {
1348 - $mails = $this->decode(
1349 - acym_loadObjectList(
1350 - 'SELECT * FROM #__acym_mail WHERE parent_id = '.intval($parentId).' OR id = '.intval($parentId),
1351 - 'language'
1352 - )
1353 - );
1354 -
1355 - return $this->translateMailSettings($mails);
1356 - }
1357 -
1358 - private function translateMailSettings(array $mails): array
1359 - {
1360 - if (empty($mails)) {
1361 - return $mails;
1362 - }
1363 -
1364 - $defaultLanguage = $this->config->get('multilingual_default');
1365 -
1366 - if (empty($mails[$defaultLanguage])) {
1367 - $firstMail = reset($mails);
1368 - if (empty($firstMail) || empty($firstMail->parent_id)) {
1369 - return $mails;
1370 - }
1371 - $mainMail = $this->getOneById($firstMail->parent_id);
1372 - } else {
1373 - $mainMail = $mails[$defaultLanguage];
1374 - }
1375 -
1376 - if (!empty($mainMail->translation)) {
1377 - $translation = json_decode($mainMail->translation, true);
1378 -
1379 - foreach ($mails as $lang => $mail) {
1380 - if (empty($mail->parent_id) || empty($translation[$lang])) {
1381 - continue;
1382 - }
1383 -
1384 - if (!empty($translation[$lang]['from_name'])) $mail->from_name = $translation[$lang]['from_name'];
1385 - if (!empty($translation[$lang]['from_email'])) $mail->from_email = $translation[$lang]['from_email'];
1386 - if (!empty($translation[$lang]['reply_to_name'])) $mail->reply_to_name = $translation[$lang]['reply_to_name'];
1387 - if (!empty($translation[$lang]['reply_to_email'])) $mail->reply_to_email = $translation[$lang]['reply_to_email'];
1388 - }
1389 - }
1390 -
1391 - return $mails;
1392 - }
1393 -
1394 - public function getMailAttachments(int $mailId)
1395 - {
1396 - return acym_loadResult('SELECT attachments FROM #__acym_mail WHERE id = '.intval($mailId));
1397 - }
1398 -
1399 - public function isTransactionalMail(object $mail): bool
1400 - {
1401 - return $mail->type !== self::TYPE_STANDARD;
1402 - }
1403 -
1404 - public function isOneTimeMail(object $mail): bool
1405 - {
1406 - return in_array(
1407 - $mail->type,
1408 - [
1409 - self::TYPE_NOTIFICATION,
1410 - self::TYPE_OVERRIDE,
1411 - self::TYPE_WELCOME,
1412 - self::TYPE_UNSUBSCRIBE,
1413 - self::TYPE_TEMPLATE,
1414 - ]
1415 - );
1416 - }
1417 -
1418 - public function getAutomaticMailIds(array $mailIds): array
1419 - {
1420 - acym_arrayToInteger($mailIds);
1421 -
1422 - $query = 'SELECT DISTINCT campaign2.mail_id
1423 - FROM #__acym_campaign AS campaign1
1424 - JOIN #__acym_campaign AS campaign2 ON campaign1.id = campaign2.parent_id
1425 - WHERE campaign1.mail_id IN ('.implode(',', $mailIds).')';
1426 - $generatedMailIds = acym_loadResultArray($query);
1427 -
1428 - if (empty($generatedMailIds)) return [];
1429 -
1430 - acym_arrayToInteger($generatedMailIds);
1431 -
1432 - return $generatedMailIds;
1433 - }
1434 -
1435 - public function getMultilingualMailIds(array $mailIds): array
1436 - {
1437 - acym_arrayToInteger($mailIds);
1438 -
1439 - $query = 'SELECT DISTINCT mail2.id
1440 - FROM #__acym_mail AS mail1
1441 - JOIN #__acym_mail AS mail2 ON mail1.id = mail2.parent_id
1442 - WHERE mail1.id IN ('.implode(',', $mailIds).')';
1443 -
1444 - $multipleMailIds = acym_loadResultArray($query);
1445 -
1446 - if (empty($multipleMailIds)) return [];
1447 -
1448 - acym_arrayToInteger($multipleMailIds);
1449 -
1450 - return $multipleMailIds;
1451 - }
1452 -
1453 - public function duplicateMail(int $mailId, ?string $type = null): ?object
1454 - {
1455 - $mail = $this->getOneById($mailId);
1456 -
1457 - if (empty($mail)) {
1458 - return null;
1459 - }
1460 -
1461 - $newMail = new \stdClass();
1462 - $newMail->name = $mail->name.'_copy';
1463 - $newMail->thumbnail = '';
1464 - $newMail->type = empty($type) ? $mail->type : $type;
1465 - $newMail->drag_editor = $mail->drag_editor;
1466 - $newMail->body = $mail->body;
1467 - $newMail->subject = $mail->subject;
1468 - $newMail->from_name = $mail->from_name;
1469 - $newMail->from_email = $mail->from_email;
1470 - $newMail->reply_to_name = $mail->reply_to_name;
1471 - $newMail->reply_to_email = $mail->reply_to_email;
1472 - $newMail->bcc = $mail->bcc;
1473 - $newMail->settings = $mail->settings;
1474 - $newMail->stylesheet = $mail->stylesheet;
1475 - $newMail->attachments = $mail->attachments;
1476 - $newMail->headers = $mail->headers;
1477 - $newMail->preheader = $mail->preheader;
1478 -
1479 - $newMail->id = $this->save($newMail);
1480 -
1481 - return $newMail;
1482 - }
1483 -
1484 - public function getTemplatesForMailboxAction(): array
1485 - {
1486 - return $this->decode(
1487 - acym_loadObjectList(
1488 - 'SELECT `id`, `name`
1489 - FROM #__acym_mail
1490 - WHERE `type` = '.acym_escapeDB(self::TYPE_TEMPLATE).'
1491 - AND `body` LIKE '.acym_escapeDB('%'.acym_utf8Encode('{emailcontent}').'%')
1492 - )
1493 - );
1494 - }
1495 -
1496 - public function hasUserAccess(int $mailId): bool
1497 - {
1498 - $userId = acym_currentUserId();
1499 - if (empty($userId)) {
1500 - return false;
1501 - }
1502 -
1503 - if (acym_isAdmin()) {
1504 - return true;
1505 - }
1506 -
1507 - return acym_loadResult(
1508 - 'SELECT COUNT(*)
1509 - FROM #__acym_mail
1510 - WHERE id = '.intval($mailId).'
1511 - AND (creator_id = '.intval($userId).'
1512 - OR type = '.acym_escapeDB(self::TYPE_TEMPLATE).')'
1513 - ) > 0;
1514 - }
1515 -
1516 - public function getVersionsById(int $mailId, bool $includeParent = false): array
1517 - {
1518 - $where = $includeParent ? ' OR `id` = '.intval($mailId) : '';
1519 -
1520 - return $this->decode(
1521 - acym_loadObjectList(
1522 - 'SELECT *
1523 - FROM #__acym_mail
1524 - WHERE `parent_id` = '.intval($mailId).$where.' ORDER BY id ASC',
1525 - 'id'
1526 - )
1527 - );
1528 - }
1529 -
1530 - public function getParentAndChildMails(int $parentId): array
1531 - {
1532 - return $this->decode(
1533 - acym_loadObjectList(
1534 - 'SELECT * FROM #__acym_mail WHERE parent_id = '.intval($parentId).' OR id = '.intval($parentId),
1535 - 'id'
1536 - )
1537 - );
1538 - }
1539 -
1540 - public function getAllTemplatesByType(array $options): array
1541 - {
1542 - $limit = $options['limit'] ?? 10;
1543 - $offset = $options['offset'] ?? 0;
1544 - $filters = $options['filters'] ?? [];
1545 - $search = $filters['search'] ?? '';
1546 - $templateType = $filters['templateType'] ?? '';
1547 -
1548 - $conditions = ['`type` = '.acym_escapeDB(self::TYPE_TEMPLATE)];
1549 -
1550 - if (!empty($search)) {
1551 - $conditions[] = '(name LIKE '.acym_escapeDB('%'.$search.'%').' OR subject LIKE '.acym_escapeDB('%'.$search.'%').')';
1552 - }
1553 -
1554 - if (!empty($templateType)) {
1555 - if ($templateType === 'drag') {
1556 - $conditions[] = 'drag_editor = 1';
1557 - } else {
1558 - $conditions[] = 'drag_editor = 0';
1559 - }
1560 - }
1561 -
1562 - $query = 'SELECT * FROM #__acym_mail WHERE '.implode(' AND ', $conditions);
1563 -
1564 - return $this->decode(acym_loadObjectList($query, '', $offset, $limit));
1565 - }
1566 -
1567 - public function updateFollowupPriority(bool $previouslyActive, bool $active): void
1568 - {
1569 - if (!$previouslyActive && $active) {
1570 - acym_query(
1571 - 'UPDATE `#__acym_queue` AS `queue`
1572 - INNER JOIN `#__acym_mail` AS `mail` ON `queue`.`mail_id` = `mail`.`id`
1573 - SET `queue`.`priority` = 1
1574 - WHERE `mail`.`type` = '.acym_escapeDB(self::TYPE_FOLLOWUP)
1575 - );
1576 - }
1577 - }
1578 -
1579 - public function getCampaignIdByMailId(int $mailId): int
1580 - {
1581 - $mainMailId = $this->getMainMailId($mailId);
1582 -
1583 - return intval(acym_loadResult('SELECT id FROM #__acym_campaign WHERE mail_id = '.intval($mainMailId)));
1584 - }
1585 -
1586 - public function getMainMailId(int $mailId): int
1587 - {
1588 - $parentId = acym_loadResult('SELECT parent_id FROM #__acym_mail WHERE id = '.intval($mailId));
1589 -
1590 - return empty($parentId) ? $mailId : intval($parentId);
1591 - }
1592 -
1593 - public function getMailType(int $mailId): string
1594 - {
1595 - return acym_loadResult('SELECT type FROM #__acym_mail WHERE id = '.intval($mailId));
1596 - }
1597 -}