| @@ -37,8 +37,27 @@ | ||
| 37 | 37 | |
| 38 | 38 | $query = 'SELECT '.$columns.' FROM #__acym_list AS list'; |
| 39 | 39 | $queryCount = 'SELECT COUNT(list.id) AS total FROM #__acym_list AS list'; |
| 40 | 40 | if (!empty($settings['join'])) $query .= $this->getJoinForQuery($settings['join']); |
| 41 | + /* | |
| 42 | + This query will return for example: | |
| 43 | + | |
| 44 | + array( | |
| 45 | + 6 => 0, | |
| 46 | + 2 => 1, | |
| 47 | + 5 => 2, | |
| 48 | + 12 => 3 | |
| 49 | + ) | |
| 50 | + | |
| 51 | + It would mean that: | |
| 52 | + | |
| 53 | + 6 lists are disabled and invisible 0 + (0*2) = 0 | |
| 54 | + 2 lists are active and invisible 1 + (0*2) = 1 | |
| 55 | + 5 lists are inactive and visible 0 + (1*2) = 2 | |
| 56 | + 12 lists are active and visible 1 + (1*2) = 3 | |
| 57 | + | |
| 58 | + So there are 2 + 12 active lists and 5 + 12 visible lists, get it? | |
| 59 | + */ | |
| 41 | 60 | $queryStatus = 'SELECT COUNT(id) AS number, active + (visible*2) AS score FROM #__acym_list AS list'; |
| 42 | 61 | $filters = []; |
| 43 | 62 | $listsId = []; |
| 44 | 63 | |
| @@ -301,9 +320,12 @@ | ||
| 301 | 320 | $offset = $options['offset'] ?? 0; |
| 302 | 321 | $limit = $options['limit'] ?? 100; |
| 303 | 322 | $status = $options['status'] ?? null; |
| 304 | 323 | $orderBy = $options['orderBy'] ?? ''; |
| 305 | - $orderBySort = $options['orderBySort'] ?? ''; | |
| 324 | + $orderBySort = strtolower((string)($options['orderBySort'] ?? '')); | |
| 325 | + if (!in_array($orderBySort, ['asc', 'desc'], true)) { | |
| 326 | + $orderBySort = empty($orderBy) ? 'asc' : 'desc'; | |
| 327 | + } | |
| 306 | 328 | $subscribedAfter = $options['subscribed_after'] ?? null; |
| 307 | 329 | $unsubscribedAfter = $options['unsubscribed_after'] ?? null; |
| 308 | 330 | |
| 309 | 331 | if (empty($listIds)) { |
| @@ -328,11 +350,14 @@ | ||
| 328 | 350 | $requestSub = 'SELECT user.*, user_list.status, user_list.subscription_date, user_list.unsubscribe_date FROM #__acym_user AS user'; |
| 329 | 351 | $requestSub .= ' LEFT JOIN #__acym_user_has_list AS user_list ON user.id = user_list.user_id'; |
| 330 | 352 | $requestSub .= ' WHERE user.active = 1 AND user_list.list_id IN ('.implode(', ', $listIds).')'.$statusCondition; |
| 331 | 353 | |
| 332 | - if (!empty($orderBy)) { | |
| 333 | - if (empty($orderBySort)) $orderBySort = 'desc'; | |
| 334 | - $requestSub .= ' ORDER BY '.acym_secureDBColumn($orderBy).' '.acym_secureDBColumn($orderBySort); | |
| 354 | + $orderByColumn = empty($orderBy) ? 'user.id' : acym_secureDBColumn($orderBy); | |
| 355 | + $requestSub .= ' ORDER BY '.$orderByColumn.' '.$orderBySort; | |
| 356 | + | |
| 357 | + // Any other column can hold duplicates, we need a unique one to break the ties | |
| 358 | + if (!in_array($orderByColumn, ['id', 'user.id'], true)) { | |
| 359 | + $requestSub .= ', user.id ASC'; | |
| 335 | 360 | } |
| 336 | 361 | |
| 337 | 362 | return acym_loadObjectList( |
| 338 | 363 | $requestSub, |
| @@ -397,9 +422,9 @@ | ||
| 397 | 422 | |
| 398 | 423 | foreach ($list as $oneAttribute => $value) { |
| 399 | 424 | if (empty($value)) continue; |
| 400 | 425 | |
| 401 | - $list->$oneAttribute = strip_tags($value); | |
| 426 | + $list->$oneAttribute = acym_stripTags($value); | |
| 402 | 427 | } |
| 403 | 428 | |
| 404 | 429 | if (empty($list->description)) { |
| 405 | 430 | $list->description = ''; |
| @@ -521,8 +546,11 @@ | ||
| 521 | 546 | |
| 522 | 547 | return $lists; |
| 523 | 548 | } |
| 524 | 549 | |
| 550 | + /** | |
| 551 | + * Sends the welcome emails attached to the specified lists | |
| 552 | + */ | |
| 525 | 553 | public function sendWelcome(int $userID, array $listIDs, bool $forceFront = false): void |
| 526 | 554 | { |
| 527 | 555 | if (!$forceFront && acym_isAdmin()) { |
| 528 | 556 | return; |
| @@ -545,8 +573,9 @@ | ||
| 545 | 573 | foreach ($messages as $oneMessage) { |
| 546 | 574 | $mailid = $oneMessage->welcome_id; |
| 547 | 575 | if (empty($mailid)) continue; |
| 548 | 576 | |
| 577 | + //We don't send twice the same message | |
| 549 | 578 | if (isset($alreadySent[$mailid])) { |
| 550 | 579 | continue; |
| 551 | 580 | } |
| 552 | 581 | |
| @@ -555,8 +584,11 @@ | ||
| 555 | 584 | $alreadySent[$mailid] = true; |
| 556 | 585 | } |
| 557 | 586 | } |
| 558 | 587 | |
| 588 | + /** | |
| 589 | + * Sends the unsubscribe emails attached to the specified lists | |
| 590 | + */ | |
| 559 | 591 | public function sendUnsubscribe(int $userID, array $listIDs): void |
| 560 | 592 | { |
| 561 | 593 | if (acym_isAdmin()) { |
| 562 | 594 | return; |
| @@ -579,8 +611,9 @@ | ||
| 579 | 611 | foreach ($messages as $oneMessage) { |
| 580 | 612 | if (!empty($oneMessage->unsubscribe_id)) { |
| 581 | 613 | $mailid = $oneMessage->unsubscribe_id; |
| 582 | 614 | |
| 615 | + //We don't send twice the same message | |
| 583 | 616 | if (isset($alreadySent[$mailid])) { |
| 584 | 617 | continue; |
| 585 | 618 | } |
| 586 | 619 | |
| @@ -627,8 +660,11 @@ | ||
| 627 | 660 | |
| 628 | 661 | return intval(acym_loadResult($query)); |
| 629 | 662 | } |
| 630 | 663 | |
| 664 | + /** | |
| 665 | + * Get all mails attached to a list | |
| 666 | + */ | |
| 631 | 667 | public function getMailsByListId(int $listId): array |
| 632 | 668 | { |
| 633 | 669 | $mailIds = acym_loadResultArray('SELECT mail_id FROM #__acym_mail_has_list WHERE list_id = '.intval($listId)); |
| 634 | 670 | |
| @@ -642,8 +678,14 @@ | ||
| 642 | 678 | acym_arrayToInteger($listIds); |
| 643 | 679 | $condList = 'AND userList.list_id IN ('.implode(',', $listIds).')'; |
| 644 | 680 | } |
| 645 | 681 | |
| 682 | + /* | |
| 683 | + * score: | |
| 684 | + * An unconfirmed and active user will have a score of 0 + 1*2 = 2 | |
| 685 | + * A confirmed and active user will have a score of 1 + 1*2 = 3 | |
| 686 | + * A confirmed and inactive user will have a score of 1 + 0*2 = 1 | |
| 687 | + */ | |
| 646 | 688 | $query = 'SELECT userList.list_id, COUNT(userList.user_id) AS users, acyuser.confirmed + acyuser.active*2 AS score |
| 647 | 689 | FROM #__acym_user_has_list AS userList |
| 648 | 690 | JOIN #__acym_user AS acyuser |
| 649 | 691 | ON acyuser.id = userList.user_id |
| @@ -658,8 +700,9 @@ | ||
| 658 | 700 | if (!isset($listsUserStats[$oneResult->list_id])) { |
| 659 | 701 | $listsUserStats[$oneResult->list_id] = $this->initList($oneResult->list_id); |
| 660 | 702 | } |
| 661 | 703 | |
| 704 | + // Joomla 4 casts the result into an int | |
| 662 | 705 | $oneResult->score = (string)$oneResult->score; |
| 663 | 706 | |
| 664 | 707 | if (in_array($oneResult->score, ['0', '1'])) { |
| 665 | 708 | $listsUserStats[$oneResult->list_id]->inactive_users += $oneResult->users; |
| @@ -720,15 +763,17 @@ | ||
| 720 | 763 | } |
| 721 | 764 | |
| 722 | 765 | public function getYearSubEvolutionPerList(int $listId): array |
| 723 | 766 | { |
| 724 | - $month = date('n') + 1; | |
| 725 | - $year = date('Y') - 1; | |
| 767 | + // Get next month from 1 year ago | |
| 768 | + $month = gmdate('n') + 1; | |
| 769 | + $year = gmdate('Y') - 1; | |
| 726 | 770 | $initDate = $year.'-'.$month.'-01'; |
| 727 | 771 | if ($month == 13) { |
| 728 | - $initDate = date('Y').'-01-01'; | |
| 772 | + $initDate = gmdate('Y').'-01-01'; | |
| 729 | 773 | } |
| 730 | 774 | |
| 775 | + // Get new subscribers per month | |
| 731 | 776 | $queryEvolSub = 'SELECT MONTH(subscription_date) as monthSub, DATE_FORMAT(subscription_date,"%Y_%m") AS unit, COUNT(user_id) AS nbUser'; |
| 732 | 777 | $queryEvolSub .= ' FROM `#__acym_user_has_list`'; |
| 733 | 778 | $queryEvolSub .= ' WHERE subscription_date >= "'.$initDate.'" AND list_id = '.$listId; |
| 734 | 779 | $queryEvolSub .= ' GROUP BY unit'; |
| @@ -733,8 +778,9 @@ | ||
| 733 | 778 | $queryEvolSub .= ' WHERE subscription_date >= "'.$initDate.'" AND list_id = '.$listId; |
| 734 | 779 | $queryEvolSub .= ' GROUP BY unit'; |
| 735 | 780 | $evolSubscibers = acym_loadObjectList($queryEvolSub, 'unit'); |
| 736 | 781 | |
| 782 | + // Get unsubscribers per month | |
| 737 | 783 | $queryEvolUnsub = 'SELECT MONTH(unsubscribe_date) as monthUnsub, DATE_FORMAT(unsubscribe_date,"%Y_%m") AS unit, COUNT(user_id) AS nbUser'; |
| 738 | 784 | $queryEvolUnsub .= ' FROM `#__acym_user_has_list`'; |
| 739 | 785 | $queryEvolUnsub .= ' WHERE unsubscribe_date >= "'.$initDate.'" AND list_id = '.$listId; |
| 740 | 786 | $queryEvolUnsub .= ' GROUP BY unit'; |
| @@ -786,9 +832,9 @@ | ||
| 786 | 832 | } |
| 787 | 833 | |
| 788 | 834 | public function hasUserAccess(int $listId): bool |
| 789 | 835 | { |
| 790 | - if (acym_isAdmin()) { | |
| 836 | + if (acym_isAdmin() && acym_isAllowed('lists')) { | |
| 791 | 837 | return true; |
| 792 | 838 | } |
| 793 | 839 | |
| 794 | 840 | return in_array($listId, $this->getManageableLists()); |
| @@ -822,14 +868,17 @@ | ||
| 822 | 868 | if (!in_array($type, [MailClass::TYPE_WELCOME, MailClass::TYPE_UNSUBSCRIBE]) || empty($mailId)) { |
| 823 | 869 | return false; |
| 824 | 870 | } |
| 825 | 871 | |
| 826 | - $column = acym_escape($type).'_id'; | |
| 872 | + $column = esc_attr($type).'_id'; | |
| 827 | 873 | $columnsList = acym_getColumns('list'); |
| 828 | 874 | if (!in_array($column, $columnsList)) { |
| 829 | 875 | return false; |
| 830 | 876 | } |
| 831 | 877 | |
| 878 | + acym_arrayToInteger($listIds); | |
| 879 | + $listIds = array_filter($listIds); | |
| 880 | + | |
| 832 | 881 | if (!$this->removeWelcomeUnsubByMailId($mailId, $listIds, $column)) { |
| 833 | 882 | return false; |
| 834 | 883 | } |
| 835 | 884 | |
| @@ -835,9 +884,9 @@ | ||
| 835 | 884 | |
| 836 | 885 | foreach ($listIds as $listId) { |
| 837 | 886 | $list = $this->getOneById($listId); |
| 838 | 887 | if (empty($list)) { |
| 839 | - return false; | |
| 888 | + continue; | |
| 840 | 889 | } |
| 841 | 890 | |
| 842 | 891 | $list->{$column} = $mailId; |
| 843 | 892 | |