Passed
Pull Request — master (#6421)
by Yannick
27:19 queued 14:40
created

PushNotificationController::send()   C

Complexity

Conditions 11
Paths 15

Size

Total Lines 106
Code Lines 68

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 11
eloc 68
c 3
b 0
f 0
nc 15
nop 3
dl 0
loc 106
rs 6.5515

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Controller;
8
9
use Chamilo\CoreBundle\Helpers\UserHelper;
10
use Chamilo\CoreBundle\Repository\Node\UserRepository;
11
use Chamilo\CoreBundle\Repository\PushSubscriptionRepository;
12
use Chamilo\CoreBundle\Settings\SettingsManager;
13
use Minishlink\WebPush\WebPush;
14
use Minishlink\WebPush\Subscription;
15
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
16
use Symfony\Component\HttpClient\HttpClient;
17
use Symfony\Component\HttpFoundation\JsonResponse;
18
use Symfony\Component\HttpFoundation\Request;
19
use Symfony\Component\Routing\Annotation\Route;
20
use Symfony\Contracts\Translation\TranslatorInterface;
21
22
#[Route('/push-notifications')]
23
class PushNotificationController extends AbstractController
24
{
25
    public function __construct(
26
        private readonly PushSubscriptionRepository $subscriptionRepository,
27
        private readonly SettingsManager $settingsManager,
28
        private readonly UserHelper $userHelper,
29
        private readonly TranslatorInterface $translator
30
    ) {}
31
32
    #[Route('/send/{userId}', name: 'chamilo_core_push_notification_send', methods: ['GET'])]
33
    public function send(int $userId, UserRepository $userRepository, Request $request): JsonResponse
34
    {
35
        $currentUser = $this->userHelper->getCurrent();
36
37
        if (!$currentUser) {
38
            return new JsonResponse([
39
                'error' => $this->translator->trans('Current user not found.'),
40
            ], 403);
41
        }
42
43
        // Check permission (example: only admins)
44
        if (!$currentUser->isAdmin()) {
45
            return new JsonResponse([
46
                'error' => $this->translator->trans('You do not have permission to send notifications to other users.'),
47
            ], 403);
48
        }
49
50
        // Find target user
51
        $user = $userRepository->find($userId);
52
53
        if (!$user) {
54
            return new JsonResponse([
55
                'error' => $this->translator->trans("This user doesn't exist"),
56
            ], 404);
57
        }
58
59
        $settings = $this->settingsManager->getSetting('platform.push_notification_settings', true);
60
61
        if (empty($settings)) {
62
            return new JsonResponse([
63
                'error' => $this->translator->trans('No push notification setting configured.'),
64
            ], 500);
65
        }
66
67
        $decoded = json_decode($settings, true);
68
69
        $vapidPublicKey = $decoded['vapid_public_key'] ?? null;
70
        $vapidPrivateKey = $decoded['vapid_private_key'] ?? null;
71
72
        if (!$vapidPublicKey || !$vapidPrivateKey) {
73
            return new JsonResponse([
74
                'error' => $this->translator->trans('VAPID keys are missing in the configuration.'),
75
            ], 500);
76
        }
77
78
        $subscriptions = $this->subscriptionRepository->findByUser($user);
79
80
        if (empty($subscriptions)) {
81
            return new JsonResponse([
82
                'error' => $this->translator->trans('No push subscriptions found for this user.'),
83
            ], 404);
84
        }
85
86
        $webPush = new WebPush([
87
            'VAPID' => [
88
                'subject' => 'mailto:' . $user->getEmail(),
89
                'publicKey' => $vapidPublicKey,
90
                'privateKey' => $vapidPrivateKey,
91
            ],
92
        ]);
93
94
        $successes = [];
95
        $failures = [];
96
97
        foreach ($subscriptions as $subEntity) {
98
            try {
99
                $subscription = Subscription::create([
100
                    'endpoint' => $subEntity->getEndpoint(),
101
                    'publicKey' =>  $subEntity->getPublicKey(),
102
                    'authToken' => $subEntity->getAuthToken(),
103
                    'contentEncoding' => $subEntity->getContentEncoding() ?? 'aesgcm',
104
                ]);
105
106
                $payload = json_encode([
107
                    'title' => $this->translator->trans('Push notification test'),
108
                    'message' => $this->translator->trans("This is a test push notification from this platform to the user's browser or app."),
109
                    'url' => '/account/edit'
110
                ]);
111
112
                $report = $webPush->sendOneNotification(
113
                    $subscription,
114
                    $payload
115
                );
116
117
                if ($report->isSuccess()) {
118
                    $successes[] = $subEntity->getEndpoint();
119
                } else {
120
                    $failures[] = [
121
                        'endpoint' => $subEntity->getEndpoint(),
122
                        'reason' => $report->getReason(),
123
                        'statusCode' => $report->getResponse()->getStatusCode(),
124
                    ];
125
                }
126
            } catch (\Throwable $e) {
127
                $failures[] = [
128
                    'endpoint' => $subEntity->getEndpoint(),
129
                    'reason' => $e->getMessage(),
130
                ];
131
            }
132
        }
133
134
        return new JsonResponse([
135
            'message' => $this->translator->trans('Push notifications have been processed.'),
136
            'success' => $successes,
137
            'failures' => $failures,
138
        ]);
139
    }
140
141
    #[Route('/send-gotify', name: '_core_push_notification_send_gotify')]
142
    public function sendGotify(): JsonResponse
143
    {
144
        $user = $this->userHelper->getCurrent();
145
146
        if (!$user) {
147
            return new JsonResponse([
148
                'error' => $this->translator->trans('User not found.'),
149
            ], 403);
150
        }
151
152
        $settings = $this->settingsManager->getSetting('platform.push_notification_settings', true);
153
154
        if (empty($settings)) {
155
            return new JsonResponse([
156
                'error' => $this->translator->trans('No push notification settings configured.'),
157
            ], 500);
158
        }
159
160
        $decoded = json_decode($settings, true);
161
162
        $gotifyUrl = $decoded['gotify_url'] ?? null;
163
        $gotifyToken = $decoded['gotify_token'] ?? null;
164
165
        if (!$gotifyUrl || !$gotifyToken) {
166
            return new JsonResponse([
167
                'error' => $this->translator->trans('Gotify configuration is missing.'),
168
            ], 500);
169
        }
170
171
        // Prepare the payload for Gotify
172
        $payload = [
173
            'title' => $user->getEmail(),
174
            'message' => $this->translator->trans('This is a test notification sent to Gotify from this platform.'),
175
            'priority' => 5,
176
        ];
177
178
        $client = HttpClient::create();
179
180
        try {
181
            $response = $client->request('POST', rtrim($gotifyUrl, '/') . '/message', [
182
                'headers' => [
183
                    'X-Gotify-Key' => $gotifyToken,
184
                ],
185
                'json' => $payload,
186
            ]);
187
188
            $statusCode = $response->getStatusCode();
189
            $content = $response->toArray(false);
190
191
            return new JsonResponse([
192
                'message' => $this->translator->trans('Gotify notification has been sent.'),
193
                'status' => $statusCode,
194
                'response' => $content,
195
            ]);
196
        } catch (\Throwable $e) {
197
            return new JsonResponse([
198
                'error' => $this->translator->trans('Error sending notification to Gotify: ') . $e->getMessage(),
199
            ], 500);
200
        }
201
    }
202
}
203