Passed
Push — dependabot/npm_and_yarn/microm... ( f2f212...f35bf2 )
by
unknown
13:36 queued 05:58
created

ProcessUserDataRequestsCommand::execute()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 29
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 18
c 1
b 0
f 0
nc 6
nop 2
dl 0
loc 29
rs 9.6666
1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Command;
8
9
use Chamilo\CoreBundle\Framework\Container;
10
use Chamilo\CoreBundle\Settings\SettingsManager;
11
use Database;
12
use DateTime;
13
use DateInterval;
14
use Doctrine\DBAL\Connection;
15
use Doctrine\ORM\EntityManager;
16
use MessageManager;
17
use Symfony\Component\Console\Command\Command;
18
use Symfony\Component\Console\Input\InputInterface;
19
use Symfony\Component\Console\Input\InputOption;
20
use Symfony\Component\Console\Output\OutputInterface;
21
use Symfony\Component\Console\Style\SymfonyStyle;
22
use Chamilo\CoreBundle\ServiceHelper\AccessUrlHelper;
23
use Chamilo\CoreBundle\Entity\User;
24
use Symfony\Component\Mailer\MailerInterface;
25
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
26
use Symfony\Contracts\Translation\TranslatorInterface;
27
use UserManager;
28
29
class ProcessUserDataRequestsCommand extends Command
30
{
31
    protected static $defaultName = 'app:process-user-data-requests';
32
33
    public function __construct(
34
        private readonly Connection $connection,
35
        private readonly AccessUrlHelper $accessUrlHelper,
36
        private readonly SettingsManager $settingsManager,
37
        private readonly MailerInterface $mailer,
38
        private readonly EntityManager $em,
39
        private readonly TranslatorInterface $translator
40
    ) {
41
        parent::__construct();
42
    }
43
44
    protected function configure(): void
45
    {
46
        $this
47
            ->setDescription('Process user data requests for personal data actions.')
48
            ->addOption('debug', null, InputOption::VALUE_NONE, 'Enable debug mode')
49
            ->setHelp('This command processes user data requests that require administrative action.');
50
    }
51
52
    protected function execute(InputInterface $input, OutputInterface $output): int
53
    {
54
        Database::setManager($this->em);
55
56
        $container = $this->getApplication()->getKernel()->getContainer();
57
        Container::setContainer($container);
58
59
        $io = new SymfonyStyle($input, $output);
60
        $debug = $input->getOption('debug');
61
62
        if ($debug) {
63
            $io->note('Debug mode activated');
64
        }
65
66
        $defaultSenderId = 1;
67
        $accessUrl = $this->accessUrlHelper->getCurrent();
68
        $numberOfDays = 7;
69
        $date = new DateTime();
70
        $date->sub(new DateInterval('P' . $numberOfDays . 'D'));
71
        $dateToString = $date->format('Y-m-d H:i:s');
72
73
        if ($accessUrl) {
74
            $message = $this->processUrlData($accessUrl->getId(), $defaultSenderId, $dateToString, $io, $debug);
75
            if ($debug) {
76
                $io->success($message);
77
            }
78
        }
79
80
        return Command::SUCCESS;
81
    }
82
83
    private function processUrlData(
84
        int $accessUrlId,
85
        int $defaultSenderId,
86
        string $dateToString,
87
        SymfonyStyle $io,
88
        bool $debug
89
    ): string {
90
91
        $sql = "
92
            SELECT u.id, v.updated_at
93
            FROM user AS u
94
            INNER JOIN extra_field_values AS v ON u.id = v.item_id
95
            WHERE (v.field_id IN (:deleteLegal, :deleteAccount))
96
            AND v.field_value = 1
97
            AND u.active <> :userSoftDeleted
98
            AND v.updated_at < :dateToString
99
        ";
100
101
        if ($this->accessUrlHelper->isMultiple()) {
102
            $sql .= " AND EXISTS (
103
                        SELECT 1 FROM access_url_rel_user rel
104
                        WHERE u.id = rel.user_id
105
                        AND rel.access_url_id = :accessUrlId)";
106
        }
107
108
        $extraFields = UserManager::createDataPrivacyExtraFields();
109
        $params = [
110
            'deleteLegal' => $extraFields['delete_legal'],
111
            'deleteAccount' => $extraFields['delete_account_extra_field'],
112
            'userSoftDeleted' => User::SOFT_DELETED,
113
            'dateToString' => $dateToString,
114
            'accessUrlId' => $accessUrlId
115
        ];
116
117
        $result = $this->connection->fetchAllAssociative($sql, $params);
118
        $usersToBeProcessed = [];
119
120
        foreach ($result as $user) {
121
            $usersToBeProcessed[] = $user;
122
        }
123
124
        if (empty($usersToBeProcessed)) {
125
            return "No users waiting for data actions for Access URL ID: {$accessUrlId}";
126
        }
127
128
        return $this->processUsers($usersToBeProcessed, $defaultSenderId, $io, $debug);
129
    }
130
131
    private function processUsers(
132
        array $users,
133
        int $defaultSenderId,
134
        SymfonyStyle $io,
135
        bool $debug
136
    ): string {
137
138
        $administrator = [
139
            'completeName' => $this->settingsManager->getSetting('admin.administrator_name'),
140
            'email' => $this->settingsManager->getSetting('admin.administrator_email'),
141
        ];
142
143
        $rootweb = $this->settingsManager->getSetting('platform.institution_url');
144
        $link = $rootweb . '/main/admin/user_list_consent.php';
145
        $subject = $this->translator->trans('A user is waiting for an action about his/her personal data request');
146
        $email = $this->settingsManager->getSetting('profile.data_protection_officer_email');
147
        $message = '';
148
149
        foreach ($users as $user) {
150
            $userId = $user['id'];
151
            $userInfo = $this->connection->fetchAssociative("SELECT * FROM user WHERE id = ?", [$userId]);
152
            $userInfo['complete_name'] = $userInfo['firstname'] . ' ' . $userInfo['lastname'];
153
            $userInfo['complete_name_with_username'] = $userInfo['complete_name'].' ('.$userInfo['username'].')';
154
155
            if (!$userInfo) {
156
                continue;
157
            }
158
159
            $content = $this->translator->trans(
160
                'The user %name% is waiting for an action about his/her personal data request. To manage personal data requests you can follow this link: %link%',
161
                ['%name%' => $userInfo['complete_name'], '%link%' => $link]
162
            );
163
164
            if ($email) {
165
                $emailMessage = (new TemplatedEmail())
166
                    ->from($administrator['email'])
167
                    ->to($email)
168
                    ->subject($subject)
169
                    ->html($content);
170
171
                $this->mailer->send($emailMessage);
172
            } else {
173
                MessageManager::sendMessageToAllAdminUsers($defaultSenderId, $subject, $content);
174
            }
175
176
            $date = (new DateTime($user['updated_at']))->format('Y-m-d H:i:s');
177
            $message .= sprintf(
178
                "User %s is waiting for an action since %s \n",
179
                $userInfo['complete_name_with_username'],
180
                $date
181
            );
182
183
            if ($debug) {
184
                $io->note("Processed user {$userInfo['complete_name']} with ID: {$userId}");
185
            }
186
        }
187
188
        return $message;
189
    }
190
}
191