PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.0
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.0
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 | front/FrontControllers/FrontusersController.php +1105 -0 10.1.0 → 11.1.0 View file →
@@ -1,0 +1,1105 @@
1 +<?php
2 +
3 +namespace AcyMailing\FrontControllers;
4 +
5 +use AcyMailing\Classes\FieldClass;
6 +use AcyMailing\Classes\ListClass;
7 +use AcyMailing\Classes\MailClass;
8 +use AcyMailing\Classes\ScenarioClass;
9 +use AcyMailing\Classes\UserClass;
10 +use AcyMailing\Classes\UserStatClass;
11 +use AcyMailing\Controllers\UsersController;
12 +use AcyMailing\Helpers\CaptchaHelper;
13 +use AcyMailing\Helpers\EntitySelectHelper;
14 +use AcyMailing\Helpers\ExportHelper;
15 +use AcyMailing\Helpers\ToolbarHelper;
16 +use AcyMailing\Helpers\UserHelper;
17 +use AcyMailing\Core\AcymParameter;
18 +
19 +class FrontusersController extends UsersController
20 +{
21 + public function __construct()
22 + {
23 + parent::__construct();
24 +
25 + if (ACYM_CMS === 'joomla') {
26 + $menu = acym_getMenu();
27 + if (is_object($menu)) {
28 + $params = method_exists($menu, 'getParams') ? $menu->getParams() : $menu->params;
29 + $menuParams = new AcymParameter($params);
30 + $this->menuClass = $menuParams->get('pageclass_sfx', '');
31 + }
32 + }
33 +
34 + $this->publicFrontTasks = [
35 + 'subscribe',
36 + 'unsubscribe',
37 + 'unsubscribeAll',
38 + 'disableTracking',
39 + 'saveSubscriptions',
40 + 'unsubscribePage',
41 + 'confirm',
42 + 'profile',
43 + 'savechanges',
44 + 'exportdata',
45 + 'ajaxGetEnqueuedMessages',
46 + 'gdprDelete',
47 + ];
48 +
49 + }
50 +
51 +
52 + private function displayMessage(string $message, bool $ajax, string $type = 'error'): void
53 + {
54 + if ($ajax) {
55 + echo json_encode(
56 + [
57 + 'message' => acym_translation($message),
58 + 'type' => $type,
59 + 'code' => '1',
60 + ]
61 + );
62 + } else {
63 + acym_header('Content-type:text/html; charset=utf-8');
64 + echo '<script>alert("'.esc_html(acym_translation($message)).'"); window.history.go(-1);</script>';
65 + }
66 + exit;
67 + }
68 +
69 + public function subscribe(): void
70 + {
71 + acym_checkRobots();
72 +
73 + $formData = acym_getVar('array', 'user', []);
74 + if (!acym_getVar('string', 'acy_source') && !empty($formData)) {
75 + // Coming from a subscription via url...
76 + acym_setVar('acy_source', 'url');
77 + }
78 +
79 + // Do we have to return an ajax response or a web page ?
80 + $ajax = acym_getVar('int', 'ajax', 0);
81 + if ($ajax) {
82 + //in case of the page displays some warnings or whatever
83 + @ob_end_clean();
84 + acym_header('Content-type:application/json; charset=utf-8');
85 + }
86 +
87 + //We only allow logged in users and this user is not logged it...
88 + $currentUserid = acym_currentUserId();
89 + if ((int)$this->config->get('allow_visitor', 1) != 1 && empty($currentUserid)) {
90 + if ($ajax) {
91 + echo json_encode(
92 + [
93 + 'message' => acym_translation('ACYM_ONLY_LOGGED'),
94 + 'type' => 'error',
95 + 'code' => '0',
96 + ]
97 + );
98 + exit;
99 + } else {
100 + acym_askLog(false, 'ACYM_ONLY_LOGGED');
101 +
102 + return;
103 + }
104 + }
105 +
106 + if (empty($currentUserid) && $this->config->get('captcha', 'none') !== 'none' && acym_level(ACYM_ESSENTIAL)) {
107 + $captchaHelper = new CaptchaHelper();
108 + if (!$captchaHelper->check()) {
109 + $this->displayMessage('ACYM_WRONG_CAPTCHA', $ajax);
110 + }
111 + }
112 +
113 + $user = new \stdClass();
114 + if (!empty($formData['email'])) {
115 + $user->email = $formData['email'];
116 + }
117 +
118 + $userClass = new UserClass();
119 + if (empty($user->email)) {
120 + $connectedUser = $userClass->identify(true, 'userId', 'userKey');
121 + if (!empty($connectedUser->email)) {
122 + $user->email = $connectedUser->email;
123 + }
124 + }
125 + $user->email = trim($user->email);
126 +
127 + // Check email validity
128 + if (empty($user->email) || !acym_isValidEmail($user->email, true)) {
129 + $this->displayMessage('ACYM_VALID_EMAIL', $ajax);
130 + }
131 +
132 + // E-mail is valid now...
133 + // Check if this user already exists or not...
134 + $alreadyExists = $userClass->getOneByEmail($user->email);
135 + if (!empty($alreadyExists->id)) {
136 + $user->id = $alreadyExists->id;
137 + }
138 +
139 + $successfullySaved = $userClass->saveForm($ajax);
140 + $user->id = acym_getVar('int', 'userId');
141 +
142 + if (!empty($userClass->errors)) {
143 + $this->displayMessage(implode('<br /><br />', $userClass->errors), $ajax);
144 + }
145 +
146 + if (!$successfullySaved || empty($user->id)) {
147 + $this->displayMessage('ACYM_ERROR_SAVE_USER', $ajax);
148 + }
149 +
150 + //We will now load back the user from the one we saved so that we will have all its infos
151 + $myuser = $userClass->getOneById($user->id);
152 + if (empty($myuser->id)) {
153 + $this->displayMessage('ACYM_ERROR_SAVE_USER', $ajax);
154 + }
155 +
156 + $msgtype = 'success';
157 + if (empty($myuser->confirmed) && $this->config->get('require_confirmation', 1) == 1) {
158 + if ($userClass->confirmationSentSuccess || empty($userClass->confirmationSentError)) {
159 + $msg = acym_stripTags(acym_getVar('string', 'confirmation_message', ''));
160 + if (empty($msg)) {
161 + $msg = 'ACYM_CONFIRMATION_SENT';
162 + }
163 + $code = 2;
164 + } else {
165 + $msg = $userClass->confirmationSentError;
166 + $code = 7;
167 + $msgtype = 'error';
168 + }
169 + } else {
170 + if ($userClass->subscribed) {
171 + $msg = acym_stripTags(acym_getVar('string', 'confirmation_message', ''));
172 + if (empty($msg)) {
173 + $msg = 'ACYM_SUBSCRIPTION_OK';
174 + }
175 + $code = 3;
176 + } else {
177 + $msg = 'ACYM_ALREADY_SUBSCRIBED';
178 + $code = 5;
179 + $enqueueMsgType = 'info';
180 + }
181 + }
182 +
183 + // Replace tags inside the $msg and redirect link
184 + $replace = [];
185 + foreach ($myuser as $oneProp => $oneVal) {
186 + $replace['{user:'.$oneProp.'}'] = $oneVal;
187 + }
188 +
189 + $msg = str_replace(array_keys($replace), $replace, acym_translation($msg));
190 +
191 + if ($ajax) {
192 + //Make sure the message has a valid format for Ajax... so the user can customize it the way he wants without breaking anything
193 + $msg = str_replace(["\n", "\r", '"', '\\'], [' ', ' ', "'", '\\\\'], $msg);
194 + echo json_encode(
195 + [
196 + 'message' => $msg,
197 + 'type' => $msgtype,
198 + 'code' => $code,
199 + ]
200 + );
201 + exit;
202 + } else {
203 + acym_enqueueMessage($msg, !empty($enqueueMsgType) ? $enqueueMsgType : $msgtype);
204 + }
205 +
206 + $redirectUrl = urldecode(acym_getVar('string', 'redirect', ''));
207 + $redirectUrl = str_replace(array_keys($replace), $replace, $redirectUrl);
208 + if (empty($redirectUrl)) {
209 + $redirectUrl = acym_rootURI();
210 + }
211 +
212 + acym_redirect($redirectUrl, '', 'message', true);
213 + }
214 +
215 + private function unsubscribeDirectly(object $alreadyExists, bool $ajax): void
216 + {
217 + $userClass = new UserClass();
218 + if ($this->config->get('allow_modif', 'data') === 'none') {
219 + $currentUser = $userClass->identify(true, 'userId', 'userKey');
220 + if (empty($currentUser->email)) {
221 + $this->endUnsubscribe('ACYM_LOGIN', $ajax, 'error');
222 +
223 + return;
224 + }
225 + }
226 +
227 + if (empty($currentUser) || empty($currentUser->id)) {
228 + $currentUser = $alreadyExists;
229 + }
230 +
231 + $visibleSubscription = acym_getVar('array', 'subscription', []);
232 + $hiddenLists = trim(acym_getVar('string', 'hiddenlists', ''));
233 + $hiddenSubscription = empty($hiddenLists) ? [] : explode(',', $hiddenLists);
234 + $unsubscribeLists = array_merge($visibleSubscription, $hiddenSubscription);
235 + acym_arrayToInteger($unsubscribeLists);
236 +
237 + $mailId = acym_getVar('int', 'mail_id', 0);
238 +
239 + // Protect against bots
240 + if (!empty($mailId) && !empty($currentUser->id)) {
241 + $userStatClass = new UserStatClass();
242 + $userStat = $userStatClass->getOneByMailAndUserId($mailId, $currentUser->id);
243 + $delay = $this->config->get('tracking_delay', 0);
244 + if (acym_isRobot() || (!empty($userStat) && !empty($delay) && acym_getTimeFromUTCDate($userStat->send_date) > time() - $delay)) {
245 + return;
246 + }
247 + }
248 +
249 + if (empty($unsubscribeLists)) {
250 + $mailClass = new MailClass();
251 + $mailType = $mailClass->getMailType($mailId);
252 + if (empty($currentUser) || empty($currentUser->id)) {
253 + $currentUser = $userClass->identify(true, 'userId', 'userKey');
254 + }
255 +
256 + if ($mailType === $mailClass::TYPE_SCENARIO) {
257 + $scenarioClass = new ScenarioClass();
258 + $scenarioId = $scenarioClass->getScenarioIdByMailId($mailId);
259 + if (!empty($currentUser->id)) {
260 + $scenarioClass->markUserUnsubscribeFromScenario($currentUser->id, $scenarioId);
261 + }
262 + }
263 + }
264 +
265 + if (!empty($mailId)) {
266 + $mailClass = new MailClass();
267 + $unsubscribeLists = array_keys($mailClass->getAllListsByMailId($mailId));
268 + }
269 +
270 + if (empty($unsubscribeLists)) {
271 + $msg = 'ACYM_NO_SUBSCRIPTION_LINKED_EMAIL';
272 + } elseif (false === $userClass->unsubscribe([$alreadyExists->id], $unsubscribeLists)) {
273 + $msg = 'ACYM_UNSUBSCRIPTION_NOT_IN_LIST';
274 + } else {
275 + $msg = 'ACYM_UNSUBSCRIPTION_OK';
276 + }
277 +
278 + if (!empty($mailType) && $mailType === $mailClass::TYPE_SCENARIO) {
279 + $msg = 'ACYM_UNSUBSCRIPTION_SCENARIO_OK';
280 + }
281 +
282 +
283 + $this->endUnsubscribe($msg, $ajax);
284 + }
285 +
286 + private function endUnsubscribe(string $msg, bool $ajax, string $type = 'success'): void
287 + {
288 + $msg = acym_translation($msg);
289 +
290 + if ($ajax) {
291 + echo json_encode(
292 + [
293 + 'message' => $msg,
294 + 'type' => $type,
295 + 'code' => '10',
296 + ]
297 + );
298 + exit;
299 + }
300 + acym_enqueueMessage($msg, $type);
301 +
302 + $redirectUrl = urldecode(acym_getVar('string', 'redirectunsub', ''));
303 + if (empty($redirectUrl)) {
304 + $redirectUrl = acym_rootURI();
305 + }
306 +
307 + acym_redirect($this->normalizeRedirectUrl($redirectUrl), '', 'message', true);
308 + }
309 +
310 + private function normalizeRedirectUrl(string $url): string
311 + {
312 + if ($url === '') {
313 + return '';
314 + }
315 + if (preg_match('~^[a-z][a-z0-9+.\-]*://~i', $url)) {
316 + return $url;
317 + }
318 + if (strpos($url, '/') === 0 || strpos($url, 'index.php') === 0) {
319 + return $url;
320 + }
321 + if (preg_match('~^[^/?#]+\.[a-z]{2,}(?:[/?#]|$)~i', $url)) {
322 + return 'https://'.$url;
323 + }
324 +
325 + return $url;
326 + }
327 +
328 + public function unsubscribe(): void
329 + {
330 + acym_checkRobots();
331 + $userClass = new UserClass();
332 +
333 + $redirectToUnsubPage = $this->config->get('unsubscribe_page', 1);
334 + $direct = acym_getVar('int', 'direct', 0);
335 +
336 + // Do we have to return an ajax response or a web page ?
337 + $ajax = acym_getVar('int', 'ajax', 0);
338 + if ($ajax) {
339 + @ob_end_clean();
340 + acym_header('Content-type:application/json; charset=utf-8');
341 + }
342 +
343 + $currentUserid = acym_currentUserId();
344 + $user = $userClass->identify(true, 'userId', 'userKey');
345 + if (empty($user)) {
346 + $user = $userClass->identify(true, 'user_id', 'user_key');
347 + $direct = 1;
348 + }
349 + if (empty($user) && empty($currentUserid) && $this->config->get('captcha', 'none') !== 'none' && acym_level(ACYM_ESSENTIAL)) {
350 + $captchaClass = new CaptchaHelper();
351 + if (!$captchaClass->check()) {
352 + $this->displayMessage('ACYM_WRONG_CAPTCHA', $ajax);
353 + }
354 + }
355 +
356 + $formData = acym_getVar('array', 'user', []);
357 + $email = '';
358 +
359 + if (!empty($formData['email'])) {
360 + $email = trim(acym_stripTags($formData['email']));
361 + } elseif (empty($user)) {
362 + return;
363 + } elseif (!empty($user->email)) {
364 + $email = $user->email;
365 + } elseif (!empty(acym_currentUserEmail())) {
366 + $email = acym_currentUserEmail();
367 + }
368 +
369 + $currentEmail = acym_currentUserEmail();
370 + if (empty($email) && !empty($currentEmail)) {
371 + $email = $currentEmail;
372 + }
373 +
374 + // Check email validity
375 + if (empty($email) || !acym_isValidEmail($email)) {
376 + $this->displayMessage('ACYM_VALID_EMAIL', $ajax);
377 + }
378 +
379 + $alreadyExists = $userClass->getOneByEmail($email);
380 +
381 + // User not found
382 + if (empty($alreadyExists->id)) {
383 + $this->displayMessage(acym_translationSprintf('ACYM_SUB_NOT_IN_LIST', $email), $ajax);
384 + }
385 +
386 + $fromModuleOrWidget = acym_getVar('string', 'acysubmode', '');
387 + if ((!empty($fromModuleOrWidget) && in_array($fromModuleOrWidget, ['form_acym', 'mod_acym', 'widget_acym'])) || $ajax || !$redirectToUnsubPage || !empty($direct)) {
388 + $this->unsubscribeDirectly($alreadyExists, $ajax);
389 + } elseif ($redirectToUnsubPage && !$ajax && !$direct) {
390 + $identifiedEmail = !empty($user->email) ? $user->email : $currentEmail;
391 + if (empty($identifiedEmail) || strtolower($alreadyExists->email) !== strtolower($identifiedEmail)) {
392 + $this->displayMessage('ACYM_NOT_ALLOWED_MODIFY_USER', $ajax);
393 + }
394 + $this->unsubscribePage($alreadyExists);
395 + }
396 + }
397 +
398 + public function disableTracking(): void
399 + {
400 + acym_checkRobots();
401 +
402 + // Do we have to return an ajax response or a web page ?
403 + $ajax = acym_getVar('int', 'ajax', 0);
404 + if ($ajax) {
405 + @ob_end_clean();
406 + acym_header('Content-type:application/json; charset=utf-8');
407 + }
408 +
409 + $userClass = new UserClass();
410 + $user = $userClass->identify(true, 'userId', 'userKey');
411 +
412 + if (empty($user->id)) {
413 + $this->displayMessage('ACYM_USER_NOT_FOUND', $ajax);
414 + }
415 +
416 + // Protect against bots opening the link right after the email was sent
417 + $mailId = acym_getVar('int', 'mail_id', 0);
418 + if (!empty($mailId)) {
419 + $userStatClass = new UserStatClass();
420 + $userStat = $userStatClass->getOneByMailAndUserId($mailId, $user->id);
421 + $delay = $this->config->get('tracking_delay', 0);
422 + if (acym_isRobot() || (!empty($userStat) && !empty($delay) && acym_getTimeFromUTCDate($userStat->send_date) > time() - $delay)) {
423 + return;
424 + }
425 + }
426 +
427 + if ((int)$user->tracking !== 0) {
428 + $userClass->disableTracking($user, $mailId);
429 + }
430 +
431 + $this->endDisableTracking('ACYM_TRACKING_DISABLED_OK', $ajax);
432 + }
433 +
434 + private function endDisableTracking(string $msg, bool $ajax, string $type = 'success'): void
435 + {
436 + $msg = acym_translation($msg);
437 +
438 + if ($ajax) {
439 + echo json_encode(
440 + [
441 + 'message' => $msg,
442 + 'type' => $type,
443 + 'code' => '10',
444 + ]
445 + );
446 + exit;
447 + }
448 + acym_enqueueMessage($msg, $type);
449 +
450 + $redirectUrl = urldecode(acym_getVar('string', 'redirectunsub', ''));
451 + if (empty($redirectUrl)) {
452 + $redirectUrl = acym_rootURI();
453 + }
454 +
455 + acym_redirect($this->normalizeRedirectUrl($redirectUrl), '', 'message', true);
456 + }
457 +
458 + private function getUserFromUnsubPage(): object
459 + {
460 + $userID = acym_getVar('int', 'user_id');
461 + $userClass = new UserClass();
462 +
463 + $user = $userClass->getOneById($userID);
464 +
465 + if (empty($user)) {
466 + acym_enqueueMessage(acym_translation('ACYM_USER_NOT_FOUND'), 'error');
467 +
468 + acym_redirect(acym_rootURI());
469 + }
470 +
471 + return $user;
472 + }
473 +
474 + private function unsubscribeAllInner(bool $update = false): void
475 + {
476 + $userClass = new UserClass();
477 + $user = $this->getUserFromUnsubPage();
478 + $redirectUrl = urldecode(acym_getVar('string', 'redirectunsub', ''));
479 + if (empty($redirectUrl)) {
480 + $redirectUrl = $this->config->get('unsub_redirect_url', '');
481 + }
482 +
483 + $allLists = $userClass->getUserSubscriptionById($user->id);
484 + if (empty($allLists)) {
485 + acym_enqueueMessage(acym_translation('ACYM_NOT_SUBSCRIBED_ANY_LIST'), 'info');
486 + acym_redirect($this->normalizeRedirectUrl(!empty($redirectUrl) ? $redirectUrl : acym_rootURI()), '', 'message', true);
487 + }
488 +
489 + $lists = [];
490 + foreach ($allLists as $list) {
491 + if (!$update || $list->visible == 1) {
492 + $lists[] = $list->id;
493 + }
494 + }
495 +
496 + $userClass->sendNotification($user->id, 'acy_notification_unsuball');
497 + // A notification is sent when a user unsubscribes from a list, be we already sent a notification for this
498 + $userClass->blockNotifications = true;
499 + $userClass->unsubscribe([$user->id], $lists);
500 + }
501 +
502 + private function redirectUnsubWorked(): void
503 + {
504 + acym_enqueueMessage(acym_translation('ACYM_SUBSCRIPTION_UPDATED_OK'));
505 + $redirectUrl = urldecode(acym_getVar('string', 'redirectunsub', ''));
506 + if (empty($redirectUrl)) {
507 + $redirectUrl = $this->config->get('unsub_redirect_url', '');
508 + }
509 + if (!empty($redirectUrl)) {
510 + acym_redirect($this->normalizeRedirectUrl($redirectUrl), '', 'message', true);
511 + } else {
512 + acym_redirect(acym_rootURI());
513 + }
514 + }
515 +
516 + public function unsubscribeAll(): void
517 + {
518 + $userClass = new UserClass();
519 + if (empty($userClass->identify(true, 'user_id', 'user_key'))) {
520 + acym_enqueueMessage(acym_translation('ACYM_USER_NOT_FOUND'), 'error');
521 +
522 + acym_redirect(acym_rootURI());
523 + }
524 +
525 + $displayCheckedLists = acym_getVar('string', 'displayed_checked_lists', '');
526 + if (!empty($displayCheckedLists)) {
527 + $user = $this->getUserFromUnsubPage();
528 + $userClass->unsubscribe([$user->id], explode(',', $displayCheckedLists));
529 + } else {
530 + $this->unsubscribeAllInner();
531 + }
532 +
533 + $ajax = acym_getVar('int', 'ajax', 0);
534 + if (!$ajax) {
535 + $this->redirectUnsubWorked();
536 + }
537 + }
538 +
539 + public function saveSubscriptions(): void
540 + {
541 + $userClass = new UserClass();
542 + if (empty($userClass->identify(true, 'user_id', 'user_key'))) {
543 + $this->displayMessage('ACYM_USER_NOT_FOUND', false);
544 + }
545 +
546 + // Get the user
547 + $user = $this->getUserFromUnsubPage();
548 + // Get the list the user want to sub
549 + $listsChecked = acym_getVar('array', 'lists', []);
550 + $listsChecked = array_filter($listsChecked, function ($status) {
551 + return intval($status) === 1;
552 + });
553 + $listsChecked = array_keys($listsChecked);
554 + // Get the displayed lists
555 + $displayedCheckedLists = explode(',', acym_getVar('string', 'displayed_checked_lists', ''));
556 + // We get the user subscriptions
557 + $userSubscriptions = $userClass->getUserSubscriptionById($user->id);
558 +
559 + // We subscribe the user to the checked lists
560 + $userClass->subscribe([$user->id], $listsChecked);
561 +
562 + // We unsub to the unchecked lists
563 + $listsToUnsub = [];
564 + foreach ($userSubscriptions as $subscription) {
565 + // The list wasn't checked && the list is displayed && the user is subscribed to it
566 + if (
567 + !in_array($subscription->id, $listsChecked)
568 + && in_array($subscription->id, $displayedCheckedLists)
569 + && intval($subscription->status) === 1
570 + ) {
571 + $listsToUnsub[] = $subscription->id;
572 + }
573 + }
574 +
575 + $userClass->unsubscribe([$user->id], $listsToUnsub);
576 + $this->redirectUnsubWorked();
577 + }
578 +
579 + public function unsubscribePage(object $alreadyExists): void
580 + {
581 + $userClass = new UserClass();
582 + $lang = acym_getVar('string', 'language', acym_getLanguageTag());
583 + $mailId = acym_getVar('int', 'mail_id', 0);
584 + $campaignListOnly = $this->config->get('unsubscribe_campaign_list_only', '0') === '1';
585 + $displaySurvey = $this->config->get('unsubpage_survey', '0') === '1';
586 + $surveyAnswers = $this->config->get('unsub_survey', '[]');
587 + $unsubscribeColor = $this->config->get('unsubscribe_color');
588 + if (empty($unsubscribeColor)) {
589 + $unsubscribeColor = '#0079d3';
590 + }
591 + $hoverColor = $this->darkenRGBColor($unsubscribeColor, 20);
592 +
593 + $surveyAnswers = json_decode($surveyAnswers, true);
594 +
595 + $languageCode = acym_getVar('string', 'language');
596 + if (ACYM_CMS === 'joomla' && !empty($languageCode)) {
597 + $lang = $languageCode;
598 + }
599 + acym_setLanguage($lang);
600 + acym_loadLanguage($lang);
601 +
602 + $userSubscriptions = $userClass->getUserSubscriptionById($alreadyExists->id, 'id', false, false, true, false, $mailId, $campaignListOnly);
603 +
604 + $data = [
605 + 'user' => $alreadyExists,
606 + 'mail_id' => $mailId,
607 + 'subscriptions' => $userSubscriptions,
608 + 'lang' => $lang,
609 + ];
610 +
611 + if (acym_isMultilingual()) {
612 + $allLanguages = acym_getLanguages(false, true);
613 + if ($this->config->get('unsubpage_languages_multi_only', '0') === '1') {
614 + $allLanguages = acym_getMultilingualLanguages();
615 + }
616 +
617 + $data['languages'] = [];
618 + foreach ($allLanguages as $key => $language) {
619 + $data['languages'][$key] = $language->name;
620 + }
621 +
622 + $surveyAnswersTranslations = $this->config->get('unsub_survey_translation', '');
623 +
624 + if (!empty($surveyAnswersTranslations)) {
625 + $surveyAnswersTranslations = json_decode($surveyAnswersTranslations, true);
626 + if (isset($surveyAnswersTranslations[$data['lang']])) {
627 + $surveyAnswers = $surveyAnswersTranslations[$data['lang']]['unsub_survey'];
628 + }
629 + }
630 + }
631 +
632 + if ($displaySurvey) {
633 + $data['surveyAnswers'] = $surveyAnswers;
634 + array_unshift($data['surveyAnswers'], acym_translation('ACYM_SELECT_REASON'));
635 + $data['surveyAnswers'][] = acym_translation('ACYM_OTHER');
636 + $data['surveyAnswers'] = array_combine($data['surveyAnswers'], $data['surveyAnswers']);
637 + }
638 +
639 + $data['unsubscribeColor'] = $unsubscribeColor;
640 + $data['hoverColor'] = $hoverColor;
641 + $data['svgImage'] = $this->getSVGImage($unsubscribeColor, $hoverColor);
642 +
643 + acym_setVar('layout', 'unsubscribepage');
644 + acym_header('Content-Type: text/html; charset=utf-8');
645 +
646 + parent::display($data);
647 + }
648 +
649 + private function getSVGImage(string $unsubscribeColor, string $hoverColor): string
650 + {
651 + if ($this->config->get('display_unsub_image') === '1') {
652 + $svgPath = ACYM_IMAGES.'unsubscribe/unsub_image.svg';
653 +
654 + $svgContent = acym_fileGetContent($svgPath);
655 +
656 + return str_replace(
657 + ['#B118C8', '#C794CF'],
658 + [$unsubscribeColor, $hoverColor],
659 + $svgContent
660 + );
661 + }
662 +
663 + return '';
664 + }
665 +
666 + public function hexToRGB(string $hexColor): array
667 + {
668 + $hexColor = ltrim($hexColor, '#');
669 +
670 + if (strlen($hexColor) === 3) {
671 + $hexColor = $hexColor[0].$hexColor[0].$hexColor[1].$hexColor[1].$hexColor[2].$hexColor[2];
672 + }
673 +
674 + $r = hexdec(substr($hexColor, 0, 2));
675 + $g = hexdec(substr($hexColor, 2, 2));
676 + $b = hexdec(substr($hexColor, 4, 2));
677 +
678 + return [$r, $g, $b];
679 + }
680 +
681 + public function darkenRGBColor(string $hexColor, int $percent): string
682 + {
683 + $rgbValues = $this->hexToRGB($hexColor);
684 +
685 + $darkenedRGB = array_map(function ($value) use ($percent) {
686 + return max(0, $value - ($value * $percent / 100));
687 + }, $rgbValues);
688 +
689 + return sprintf('rgb(%d, %d, %d)', $darkenedRGB[0], $darkenedRGB[1], $darkenedRGB[2]);
690 + }
691 +
692 + public function confirm(): void
693 + {
694 + if (acym_isRobot()) {
695 + return;
696 + }
697 +
698 + // We identify the user
699 + $userClass = new UserClass();
700 + $user = $userClass->identify(true, 'userId', 'userKey');
701 + if (empty($user)) {
702 + acym_enqueueMessage(acym_translation('ACYM_USER_NOT_FOUND'), 'error');
703 + acym_redirect(acym_rootURI());
704 +
705 + return;
706 + }
707 +
708 + if ($this->config->get('confirmation_message', 1)) {
709 + if ($user->confirmed) {
710 + acym_enqueueMessage(acym_translation('ACYM_ALREADY_CONFIRMED'), 'info');
711 + } else {
712 + acym_enqueueMessage(acym_translation('ACYM_SUBSCRIPTION_CONFIRMED'), 'success');
713 + }
714 + }
715 +
716 + // Now we can really confirm the user
717 + if (!$user->confirmed) {
718 + $userClass->confirm($user->id);
719 + }
720 +
721 + // Get the redirect url from the configuration page if specified
722 + $redirectUrl = $this->config->get('confirm_redirect');
723 + if (!empty($redirectUrl)) {
724 + $replace = [];
725 + // We replace tags in case of the user added some dynamic information to its url.
726 + foreach ($user as $key => $val) {
727 + $replace['{user:'.$key.'}'] = $val;
728 + }
729 + $redirectUrl = str_replace(array_keys($replace), $replace, $redirectUrl);
730 + acym_redirect($redirectUrl, '', 'message', false);
731 +
732 + return;
733 + }
734 +
735 + acym_redirect(acym_rootURI());
736 + }
737 +
738 + public function profile(): void
739 + {
740 + $userClass = new UserClass();
741 + $user = $userClass->identify(true);
742 +
743 + if (empty($user)) {
744 + // Check if the subscription is allowed for non registered users
745 + $allowvisitor = $this->config->get('allow_visitor', 1);
746 + if (empty($allowvisitor)) {
747 + acym_askLog(true, 'ACYM_ONLY_LOGGED', 'message');
748 +
749 + return;
750 + }
751 + }
752 +
753 + global $acymEmailMisspelledLoaded;
754 + $spellChecker = empty($acymEmailMisspelledLoaded) && !empty($this->config->get('email_spellcheck'));
755 + if ($spellChecker) $acymEmailMisspelledLoaded = true;
756 +
757 + if ($spellChecker) {
758 + acym_addStyle(false, ACYM_CSS.'libraries/email-misspelled.min.css?v='.filemtime(ACYM_MEDIA.'css'.DS.'libraries'.DS.'email-misspelled.min.css'));
759 + acym_addScript(false, ACYM_JS.'libraries/email-misspelled.min.js?v='.filemtime(ACYM_MEDIA.'js'.DS.'libraries'.DS.'email-misspelled.min.js'));
760 + }
761 + acym_addScript(false, ACYM_JS.'module.min.js?v='.filemtime(ACYM_MEDIA.'js'.DS.'module.min.js'));
762 +
763 + // Get the page parameters
764 + $params = new \stdClass();
765 + $menu = acym_getMenu();
766 + if (is_object($menu)) {
767 + $params->source = 'Menu n°'.$menu->id;
768 + $menuParameters = method_exists($menu, 'getParams') ? $menu->getParams() : $menu->params;
769 + $menuparams = new AcymParameter($menuParameters);
770 +
771 + if (!empty($menuparams)) {
772 + // Joomla specific params
773 + $params->suffix = $menuparams->get('pageclass_sfx', '');
774 + $params->page_heading = $menuparams->get('page_heading');
775 + $params->show_page_heading = $menuparams->get('show_page_heading', 0);
776 +
777 + if ($menuparams->get('menu-meta_description')) {
778 + acym_addMetadata('description', $menuparams->get('menu-meta_description'));
779 + }
780 + if ($menuparams->get('menu-meta_keywords')) {
781 + acym_addMetadata('keywords', $menuparams->get('menu-meta_keywords'));
782 + }
783 + if ($menuparams->get('robots')) {
784 + acym_addMetadata('robots', $menuparams->get('robots'));
785 + }
786 +
787 + // Our params
788 + $params->lists = $menuparams->get('lists', 'none');
789 + $params->listschecked = $menuparams->get('listschecked', 'none');
790 + $params->dropdown = $menuparams->get('dropdown');
791 + $params->hiddenlists = $menuparams->get('hiddenlists', 'None');
792 + $params->fields = $menuparams->get('fields');
793 + $params->introtext = $menuparams->get('introtext');
794 + $params->posttext = $menuparams->get('posttext');
795 + $params->page_title = $menuparams->get('page_title', '');
796 + }
797 + }
798 + $data = $this->prepareParams($params);
799 +
800 + if (empty($data['user']->language)) {
801 + $cmsUserLanguage = acym_getCmsUserLanguage();
802 + $data['user']->language = empty($cmsUserLanguage) ? acym_getLanguageTag() : $cmsUserLanguage;
803 + }
804 +
805 + $data['captchaHelper'] = new CaptchaHelper();
806 +
807 + acym_setVar('layout', 'profile');
808 + parent::display($data);
809 + }
810 +
811 + public function prepareParams(object $values): array
812 + {
813 + //TODO problem with the types throughout the entire method
814 + if (!isset($values->lists)) {
815 + $values->lists = 'none';
816 + }
817 + if (!isset($values->listschecked)) {
818 + $values->listschecked = 'none';
819 + }
820 + if (!isset($values->dropdown)) {
821 + $values->dropdown = 0;
822 + }
823 + if (!isset($values->hiddenlists)) {
824 + $values->hiddenlists = 'None';
825 + }
826 + if (empty($values->fields)) {
827 + $values->fields = [2];
828 + } elseif (is_string($values->fields)) {
829 + $values->fields = explode(',', $values->fields);
830 + }
831 + if (!in_array('2', $values->fields) && !in_array(2, $values->fields)) {
832 + $values->fields[] = '2';
833 + }
834 + if (!isset($values->page_heading)) {
835 + $values->page_heading = '';
836 + }
837 + if (!isset($values->introtext)) {
838 + $values->introtext = '';
839 + }
840 + if (!isset($values->posttext)) {
841 + $values->posttext = '';
842 + }
843 +
844 + foreach (['lists', 'listschecked', 'hiddenlists', 'fields'] as $option) {
845 + if (is_string($values->$option)) {
846 + $values->$option = explode(',', $values->$option);
847 + }
848 + }
849 +
850 + if ((empty($values->lists) || in_array('None', $values->lists)) && (empty($values->hiddenlists) || strtolower(implode('', $values->hiddenlists)) == 'none')) {
851 + $values->lists[] = 'All';
852 + }
853 +
854 + // Get the current user and his subscription
855 + $userClass = new UserClass();
856 + $user = $userClass->identify(true);
857 + if (empty($user)) {
858 + $listClass = new ListClass();
859 + $subscription = $listClass->getAll('id');
860 +
861 + if (acym_isMultilingual()) {
862 + $subscription = $listClass->getTranslatedNameDescription($subscription);
863 + }
864 +
865 + $user = new \stdClass();
866 + $user->id = 0;
867 + $user->key = 0;
868 +
869 + if (!empty($subscription)) {
870 + foreach ($subscription as $id => $onesub) {
871 + $subscription[$id]->status = 1;
872 + if (strtolower(implode('', $values->listschecked)) != 'all' && !in_array($id, $values->listschecked)) {
873 + $subscription[$id]->status = -1;
874 + }
875 + }
876 + }
877 +
878 + acym_addBreadcrumb(acym_translation('ACYM_SUBSCRIPTION'));
879 + if (empty($menu)) {
880 + acym_setPageTitle(acym_translation('ACYM_SUBSCRIPTION'));
881 + }
882 + } else {
883 + $subscription = $userClass->getAllListsUserSubscriptionById($user->id, 'id', true);
884 +
885 + acym_addBreadcrumb(acym_translation('ACYM_MODIFY_SUBSCRIPTION'));
886 + if (empty($menu)) {
887 + acym_setPageTitle(acym_translation('ACYM_MODIFY_SUBSCRIPTION'));
888 + }
889 + }
890 +
891 + if (!empty($values->page_title)) {
892 + acym_addBreadcrumb($values->page_title);
893 + if (empty($menu)) {
894 + acym_setPageTitle($values->page_title);
895 + }
896 + }
897 +
898 + $allLists = $subscription;
899 +
900 + acym_initModule();
901 +
902 + if (!empty($values->lists) && strtolower(implode('', $values->lists)) != 'all') {
903 + if (in_array('None', $values->lists)) {
904 + $subscription = [];
905 + } else {
906 + $newSubscription = [];
907 + foreach ($subscription as $id => $onesub) {
908 + if (in_array($id, $values->lists)) {
909 + $newSubscription[$id] = $onesub;
910 + }
911 + }
912 + $subscription = $newSubscription;
913 + }
914 + }
915 +
916 + if (!empty($values->hiddenlists)) {
917 + $hiddenListsArray = [];
918 + if (strtolower(implode('', $values->hiddenlists)) == 'all') {
919 + $subscription = [];
920 + foreach ($allLists as $oneList) {
921 + if (!empty($oneList->active)) {
922 + $hiddenListsArray[] = $oneList->id;
923 + }
924 + }
925 + } elseif (strtolower(implode('', $values->hiddenlists)) != 'none') {
926 + foreach ($allLists as $oneList) {
927 + if (!$oneList->active || !in_array($oneList->id, $values->hiddenlists)) {
928 + continue;
929 + }
930 + $hiddenListsArray[] = $oneList->id;
931 + unset($subscription[$oneList->id]);
932 + }
933 + }
934 + $values->hiddenlists = $hiddenListsArray;
935 + }
936 +
937 + // Overriding the list with the URL parameters: &listid= for displayed list, &hiddenlist= for hidden lists
938 + $defaultSubscription = $subscription;
939 + $forceLists = acym_getVar('string', 'listid', '');
940 + if (!empty($forceLists)) {
941 + $subscription = [];
942 + $forceLists = explode(',', $forceLists);
943 + foreach ($forceLists as $oneList) {
944 + if (!empty($defaultSubscription[$oneList])) {
945 + $subscription[$oneList] = $defaultSubscription[$oneList];
946 + }
947 + }
948 + }
949 + $forceHiddenLists = acym_getVar('string', 'hiddenlist', '');
950 + if (!empty($forceHiddenLists)) {
951 + $forceHiddenLists = explode(',', $forceHiddenLists);
952 + $tmpList = [];
953 + foreach ($forceHiddenLists as $oneList) {
954 + if (!empty($defaultSubscription[$oneList]) || in_array($oneList, $values->hiddenlists)) {
955 + $tmpList[] = $oneList;
956 + }
957 + }
958 + $values->hiddenlists = $tmpList;
959 + }
960 +
961 + $displayLists = false;
962 + foreach ($subscription as $oneSub) {
963 + if (!empty($oneSub->active) && $oneSub->visible) {
964 + $displayLists = true;
965 + break;
966 + }
967 + }
968 +
969 + $fieldClass = new FieldClass();
970 + $allfields = $fieldClass->getFieldsByID($values->fields);
971 + $fields = [];
972 + foreach ($allfields as $field) {
973 + if (intval($field->active) === 0) continue;
974 + $fields[$field->id] = $field;
975 + }
976 + $values->fields = $fields;
977 +
978 + $data = [
979 + 'config' => $this->config,
980 + 'displayLists' => $displayLists,
981 + 'user' => $user,
982 + 'subscription' => $subscription,
983 + 'fieldClass' => $fieldClass,
984 + ];
985 +
986 + foreach ($values as $key => $value) {
987 + $data[$key] = $value;
988 + }
989 +
990 + return $data;
991 + }
992 +
993 + public function savechanges(): void
994 + {
995 + wp_verify_nonce(acym_getVar('cmd', '_wpnonce'), 'acymnonce') || die('Invalid Token');
996 + acym_checkRobots();
997 +
998 + $userClass = new UserClass();
999 +
1000 +
1001 + $status = $userClass->saveForm(true);
1002 + if ($status) {
1003 + if ($userClass->confirmationSentSuccess) {
1004 + $this->displayMessage('ACYM_CONFIRMATION_SENT', true, 'success');
1005 + } elseif ($userClass->newUser) {
1006 + $this->displayMessage('ACYM_SUBSCRIPTION_OK', true, 'success');
1007 + } else {
1008 + $this->displayMessage('ACYM_SUBSCRIPTION_UPDATED_OK', true, 'success');
1009 + }
1010 + } elseif (!empty($userClass->requireId)) {
1011 + $this->displayMessage('ACYM_IDENTIFICATION_SENT', true, 'success');
1012 + } elseif (!empty($userClass->errors)) {
1013 + $this->displayMessage(implode('<br/>', $userClass->errors), true);
1014 + } else {
1015 + $this->displayMessage('ACYM_ERROR_SAVING', true);
1016 + }
1017 +
1018 + exit;
1019 + }
1020 +
1021 + public function exportdata(): void
1022 + {
1023 + wp_verify_nonce(acym_getVar('cmd', '_wpnonce'), 'acymnonce') || die('Invalid Token');
1024 +
1025 + $userClass = new UserClass();
1026 + $user = $userClass->identify(true, 'userId', 'userKey');
1027 +
1028 + if (empty($user->id)) {
1029 + acym_redirect(acym_rootURI());
1030 + }
1031 +
1032 + $userHelper = new UserHelper();
1033 + $userData = $userHelper->getUserData($user);
1034 + $exportData = [];
1035 + foreach ($userData as $oneCategory) {
1036 + if (!isset($exportData[$oneCategory['group_label']])) {
1037 + $exportData[$oneCategory['group_label']] = [];
1038 + }
1039 +
1040 + $exportData[$oneCategory['group_label']][] = $oneCategory['data'];
1041 + }
1042 +
1043 + $exportFiles = [
1044 + [
1045 + 'name' => 'data.json',
1046 + 'data' => json_encode($exportData),
1047 + ],
1048 + ];
1049 +
1050 + $tempFolder = ACYM_MEDIA.'tmp'.DS;
1051 + acym_createArchive($tempFolder.'export_data_user_'.$user->id, $exportFiles);
1052 +
1053 + $exportHelper = new ExportHelper();
1054 + $exportHelper->setDownloadHeaders('export_data_user_'.$user->id, 'zip');
1055 + // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_readfile -- Downloading a file, better than WP functions for memory handling.
1056 + readfile($tempFolder.'export_data_user_'.$user->id.'.zip');
1057 +
1058 + // Avoid issue when user cancels the download
1059 + ignore_user_abort(true);
1060 + acym_deleteFile($tempFolder.'export_data_user_'.$user->id.'.zip');
1061 + exit;
1062 + }
1063 +
1064 + public function gdprDelete(): void
1065 + {
1066 + wp_verify_nonce(acym_getVar('cmd', '_wpnonce'), 'acymnonce') || die('Invalid Token');
1067 +
1068 + $userClass = new UserClass();
1069 + $user = $userClass->identify(true, 'userId', 'userKey');
1070 + if (empty($user->id)) {
1071 + acym_redirect(acym_rootURI());
1072 + }
1073 +
1074 + $userClass->delete([$user->id], true);
1075 +
1076 + acym_redirect(acym_rootURI(), 'ACYM_GDPR_DATA_DELETED');
1077 + }
1078 +
1079 + public function ajaxGetEnqueuedMessages(): void
1080 + {
1081 + $output = '';
1082 + $types = ['success', 'info', 'warning', 'error'];
1083 + foreach ($types as $type) {
1084 + $messages = acym_getVar('array', 'acymessage'.$type, [], 'SESSION', ACYM_ALLOWHTML);
1085 + if (empty($messages)) {
1086 + continue;
1087 + }
1088 +
1089 + if (!is_array($messages)) {
1090 + $messages = [$messages];
1091 + }
1092 +
1093 + $output .= '<div class="acym_callout acym__callout__front__'.esc_attr($type).'" role="alert">';
1094 + $output .= '<div>'.implode(' ', $messages).'</div>';
1095 + $output .= '<button class="acym_callout_close" aria-label="'.esc_attr(acym_translation('ACYM_CLOSE_NOTIFICATION')).'">x</button></div>';
1096 +
1097 + acym_setSession('acymessage'.$type, null, true);
1098 + }
1099 +
1100 + if (!empty($output)) {
1101 + $output = '<div id="acym__callout__container">'.$output.'</div>';
1102 + }
1103 + acym_sendAjaxResponse('', ['messages' => $output]);
1104 + }
1105 +}