Test Setup Failed
Push — master ( 5f75b5...a576a1 )
by Simon
03:23
created

IrcNotificationHelper::alertFlaggedComments()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
dl 0
loc 3
ccs 0
cts 0
cp 0
rs 10
c 1
b 0
f 0
cc 1
nc 1
nop 1
crap 2
1
<?php
2
/******************************************************************************
3
 * Wikipedia Account Creation Assistance tool                                 *
4
 *                                                                            *
5
 * All code in this file is released into the public domain by the ACC        *
6
 * Development Team. Please see team.json for a list of contributors.         *
7
 ******************************************************************************/
8
9
namespace Waca\Helpers;
10
11
use Exception;
12
use PhpAmqpLib\Connection\AMQPSSLConnection;
13
use PhpAmqpLib\Connection\AMQPStreamConnection;
14
use PhpAmqpLib\Message\AMQPMessage;
15
use Waca\DataObjects\Ban;
16
use Waca\DataObjects\Comment;
17
use Waca\DataObjects\Domain;
18
use Waca\DataObjects\EmailTemplate;
19
use Waca\DataObjects\Request;
20
use Waca\DataObjects\RequestQueue;
21
use Waca\DataObjects\User;
22
use Waca\DataObjects\WelcomeTemplate;
23
use Waca\ExceptionHandler;
24
use Waca\IrcColourCode;
25
use Waca\PdoDatabase;
26
use Waca\SiteConfiguration;
27
28
/**
29
 * Class IrcNotificationHelper
30
 * @package Waca\Helpers
31
 */
32
class IrcNotificationHelper
33
{
34
    /** @var bool $notificationsEnabled */
35
    private $notificationsEnabled;
36
    /** @var User $currentUser */
37
    private $currentUser;
38
    /** @var string $instanceName */
39
    private $instanceName;
40
    /** @var string */
41
    private $baseUrl;
42
    /** @var SiteConfiguration */
43
    private $siteConfiguration;
44
    /** @var PdoDatabase */
45
    private $primaryDatabase;
46
47
    /**
48
     * IrcNotificationHelper constructor.
49
     *
50
     * @param SiteConfiguration $siteConfiguration
51
     * @param PdoDatabase       $primaryDatabase
52
     */
53
    public function __construct(
54
        SiteConfiguration $siteConfiguration,
55
        PdoDatabase $primaryDatabase
56
    ) {
57
        $this->siteConfiguration = $siteConfiguration;
58
        $this->primaryDatabase = $primaryDatabase;
59
60
        $this->notificationsEnabled = $siteConfiguration->getIrcNotificationsEnabled();
61
        $this->instanceName = $siteConfiguration->getIrcNotificationsInstance();
62
        $this->baseUrl = $siteConfiguration->getBaseUrl();
63
64
        $this->currentUser = User::getCurrent($primaryDatabase);
65
    }
66
67
    /**
68
     * Send a notification
69
     *
70
     * This method does some *basic* filtering for IRC safety, and then delivers the message to an AMQP queue manager.
71
     * It is the responsibility of the queue manager and consumer to handle message delivery to IRC, message routing to
72
     * the correct channel, and message expiry.
73
     *
74
     * It's also arguably the responsibility of the consumer to ensure the message is *safe* for delivery to IRC.
75
     *
76
     * As of Feb 2022, the message consumer is stwalkerster's IRC bot Helpmebot.
77
     *
78
     * @param string $message The text to send
79
     */
80
    protected function send($message)
81
    {
82
        $instanceName = $this->instanceName;
83
84
        if (!$this->notificationsEnabled) {
85
            return;
86
        }
87
88
        $blacklist = array("DCC", "CCTP", "PRIVMSG");
89
        $message = str_replace($blacklist, "(IRC Blacklist)", $message); // Lets stop DCC etc
90
91
        $msg = $message;
92
        if ($instanceName !== null && mb_strlen($instanceName) > 0) {
93
            $msg = IrcColourCode::RESET . IrcColourCode::BOLD . "[$instanceName]" . IrcColourCode::RESET . ": $message";
94
        }
95
96
        // FIXME: domains!
97
        /** @var Domain $domain */
98
        $domain = Domain::getById(1, $this->primaryDatabase);
99
100
        try {
101
            $amqpConfig = $this->siteConfiguration->getAmqpConfiguration();
102
            if ($amqpConfig['tls']) {
103
                $connection = new AMQPSSLConnection($amqpConfig['host'], $amqpConfig['port'], $amqpConfig['user'], $amqpConfig['password'], $amqpConfig['vhost'], ['verify_peer' => true]);
104
            }
105
            else {
106
                $connection = new AMQPStreamConnection($amqpConfig['host'], $amqpConfig['port'], $amqpConfig['user'], $amqpConfig['password'], $amqpConfig['vhost']);
107
            }
108
            $channel = $connection->channel();
109
110
            $msg = new AMQPMessage(substr($msg, 0, 512));
111
            $msg->set('user_id', $amqpConfig['user']);
112
            $msg->set('app_id', $this->siteConfiguration->getUserAgent());
113
            $msg->set('content_type', 'text/plain');
114
            $channel->basic_publish($msg, $amqpConfig['exchange'], $domain->getNotificationTarget());
115
            $channel->close();
116
        }
117
        catch (Exception $ex) {
118
            // OK, so we failed to send the notification - that db might be down?
119
            // This is non-critical, so silently fail.
120
            ExceptionHandler::logExceptionToDisk($ex, $this->siteConfiguration);
121
122
            // Disable notifications for remainder of request.
123
            $this->notificationsEnabled = false;
124
        }
125
    }
126
127
    #region user management
128
129
    /**
130
     * send a new user notification
131
     *
132
     * @param User $user
133
     */
134
    public function userNew(User $user)
135
    {
136
        $this->send("New user: {$user->getUsername()}");
137
    }
138
139
    /**
140
     * send an approved notification
141
     *
142
     * @param User $user
143
     */
144
    public function userApproved(User $user)
145
    {
146
        $this->send("{$user->getUsername()} approved by " . $this->currentUser->getUsername());
147
    }
148
149
    /**
150
     * send a declined notification
151
     *
152
     * @param User   $user
153
     * @param string $reason the reason the user was declined
154
     */
155
    public function userDeclined(User $user, $reason)
156
    {
157
        $this->send("{$user->getUsername()} declined by " . $this->currentUser->getUsername() . " ($reason)");
158
    }
159
160
    /**
161
     * send a suspended notification
162
     *
163
     * @param User   $user
164
     * @param string $reason The reason the user has been suspended
165
     */
166
    public function userSuspended(User $user, $reason)
167
    {
168
        $this->send("{$user->getUsername()} suspended by " . $this->currentUser->getUsername() . " ($reason)");
169
    }
170
171
    /**
172
     * Send a preference change notification
173
     *
174
     * @param User $user
175
     */
176
    public function userPrefChange(User $user)
177
    {
178
        $this->send("{$user->getUsername()}'s preferences were changed by " . $this->currentUser->getUsername());
179
    }
180
181
    /**
182
     * Send a user renamed notification
183
     *
184
     * @param User   $user
185
     * @param string $old
186
     */
187
    public function userRenamed(User $user, $old)
188
    {
189
        $this->send($this->currentUser->getUsername() . " renamed $old to {$user->getUsername()}");
190
    }
191
192
    /**
193
     * @param User   $user
194
     * @param string $reason
195
     */
196
    public function userRolesEdited(User $user, $reason)
197
    {
198
        $currentUser = $this->currentUser->getUsername();
199
        $this->send("Active roles for {$user->getUsername()} changed by " . $currentUser . " ($reason)");
200
    }
201
202
    #endregion
203
204
    #region Site Notice
205
206
    /**
207
     * Summary of siteNoticeEdited
208
     */
209
    public function siteNoticeEdited()
210
    {
211
        $this->send("Site notice edited by " . $this->currentUser->getUsername());
212
    }
213
    #endregion
214
215
    #region Welcome Templates
216
    /**
217
     * Summary of welcomeTemplateCreated
218
     *
219
     * @param WelcomeTemplate $template
220
     */
221
    public function welcomeTemplateCreated(WelcomeTemplate $template)
222
    {
223
        $this->send("Welcome template {$template->getId()} created by " . $this->currentUser->getUsername());
224
    }
225
226
    /**
227
     * Summary of welcomeTemplateDeleted
228
     *
229
     * @param int $templateid
230
     */
231
    public function welcomeTemplateDeleted($templateid)
232
    {
233
        $this->send("Welcome template {$templateid} deleted by " . $this->currentUser->getUsername());
234
    }
235
236
    /**
237
     * Summary of welcomeTemplateEdited
238
     *
239
     * @param WelcomeTemplate $template
240
     */
241
    public function welcomeTemplateEdited(WelcomeTemplate $template)
242
    {
243
        $this->send("Welcome template {$template->getId()} edited by " . $this->currentUser->getUsername());
244
    }
245
246
    #endregion
247
248
    #region bans
249
    /**
250
     * Summary of banned
251
     *
252
     * @param Ban $ban
253
     */
254
    public function banned(Ban $ban)
255
    {
256
        if ($ban->getDuration() === null) {
257
            $duration = "indefinitely";
258
        }
259
        else {
260
            $duration = "until " . date("F j, Y, g:i a", $ban->getDuration());
261
        }
262
263
        $username = $this->currentUser->getUsername();
264
265
        if ($ban->getVisibility() == 'user') {
266
            $this->send("Ban {$ban->getId()} set by {$username} for '{$ban->getReason()}' {$duration}");
267
        }
268
        else {
269
            $this->send("Ban {$ban->getId()} set by {$username} {$duration}");
270
        }
271
    }
272
273
    /**
274
     * Summary of unbanned
275
     *
276
     * @param Ban    $ban
277
     * @param string $unbanReason
278
     */
279
    public function unbanned(Ban $ban, $unbanReason)
280
    {
281
        $this->send("Ban {$ban->getId()} unbanned by " . $this->currentUser
282
                ->getUsername() . " (" . $unbanReason . ")");
283
    }
284
285
    #endregion
286
287
    #region request management
288
289
    /**
290
     * Summary of requestReceived
291
     *
292
     * @param Request $request
293
     */
294
    public function requestReceived(Request $request)
295
    {
296
        $this->send(
297
            IrcColourCode::DARK_GREY . "[["
298
            . IrcColourCode::DARK_GREEN . "acc:"
299
            . IrcColourCode::ORANGE . $request->getId()
300
            . IrcColourCode::DARK_GREY . "]]"
301
            . IrcColourCode::RED . " N "
302
            . IrcColourCode::DARK_BLUE . $this->baseUrl . "/internal.php/viewRequest?id={$request->getId()} "
303
            . IrcColourCode::DARK_RED . "* "
304
            . IrcColourCode::DARK_GREEN . $request->getName()
305
            . IrcColourCode::DARK_RED . " * "
306
            . IrcColourCode::RESET
307
        );
308
    }
309
310
    /**
311
     * Summary of requestDeferred
312
     *
313
     * @param Request $request
314
     */
315
    public function requestDeferred(Request $request)
316
    {
317
        /** @var RequestQueue $queue */
318
        $queue = RequestQueue::getById($request->getQueue(), $request->getDatabase());
319
320
        $deferTo = $queue->getDisplayName();
321
        $username = $this->currentUser->getUsername();
322
323
        $this->send("Request {$request->getId()} ({$request->getName()}) deferred to {$deferTo} by {$username}");
324
    }
325
326
    /**
327
     *
328
     * Summary of requestDeferredWithMail
329
     *
330
     * @param Request $request
331
     */
332
    public function requestDeferredWithMail(Request $request)
333
    {
334
        /** @var RequestQueue $queue */
335
        $queue = RequestQueue::getById($request->getQueue(), $request->getDatabase());
336
337
        $deferTo = $queue->getDisplayName();
338
        $username = $this->currentUser->getUsername();
339
        $id = $request->getId();
340
        $name = $request->getName();
341
342
        $this->send("Request {$id} ({$name}) deferred to {$deferTo} with an email by {$username}");
343
    }
344
345
    /**
346
     * Summary of requestClosed
347
     *
348
     * @param Request $request
349
     * @param string  $closetype
350
     */
351
    public function requestClosed(Request $request, $closetype)
352
    {
353
        $username = $this->currentUser->getUsername();
354
355
        $this->send("Request {$request->getId()} ({$request->getName()}) closed ($closetype) by {$username}");
356
    }
357
358
    /**
359
     * Summary of requestClosed
360
     *
361
     * @param Request $request
362
     * @param string  $closetype
363
     */
364
    public function requestCloseQueued(Request $request, $closetype)
365
    {
366
        $username = $this->currentUser->getUsername();
367
368
        $this->send("Request {$request->getId()} ({$request->getName()}) queued for creation ($closetype) by {$username}");
369
    }
370
371
    /**
372
     * Summary of requestClosed
373
     *
374
     * @param Request $request
375
     * @param User    $triggerUser
376
     */
377
    public function requestCreationFailed(Request $request, User $triggerUser)
378
    {
379
        $this->send("Request {$request->getId()} ({$request->getName()}) failed auto-creation for {$triggerUser->getUsername()}, and was sent to the hospital queue.");
380
    }
381
382
    /**
383
     * @param Request $request
384
     * @param User    $triggerUser
385
     */
386
    public function requestWelcomeFailed(Request $request, User $triggerUser)
387
    {
388
        $this->send("Request {$request->getId()} ({$request->getName()}) failed welcome for {$triggerUser->getUsername()}.");
389
    }
390
391
    /**
392
     * Summary of sentMail
393
     *
394
     * @param Request $request
395
     */
396
    public function sentMail(Request $request)
397
    {
398
        $this->send($this->currentUser->getUsername()
399
            . " sent an email related to Request {$request->getId()} ({$request->getName()})");
400
    }
401
402
    #endregion
403
404
    #region reservations
405
406
    /**
407
     * Summary of requestReserved
408
     *
409
     * @param Request $request
410
     */
411
    public function requestReserved(Request $request)
412
    {
413
        $username = $this->currentUser->getUsername();
414
415
        $this->send("Request {$request->getId()} ({$request->getName()}) reserved by {$username}");
416
    }
417
418
    /**
419
     * Summary of requestReserveBroken
420
     *
421
     * @param Request $request
422
     */
423
    public function requestReserveBroken(Request $request)
424
    {
425
        $username = $this->currentUser->getUsername();
426
427
        $this->send("Reservation on request {$request->getId()} ({$request->getName()}) broken by {$username}");
428
    }
429
430
    /**
431
     * Summary of requestUnreserved
432
     *
433
     * @param Request $request
434
     */
435
    public function requestUnreserved(Request $request)
436
    {
437
        $this->send("Request {$request->getId()} ({$request->getName()}) is no longer being handled.");
438
    }
439
440
    /**
441
     * Summary of requestReservationSent
442
     *
443
     * @param Request $request
444
     * @param User    $target
445
     */
446
    public function requestReservationSent(Request $request, User $target)
447
    {
448
        $username = $this->currentUser->getUsername();
449
450
        $this->send(
451
            "Reservation of request {$request->getId()} ({$request->getName()}) sent to {$target->getUsername()} by "
452
            . $username);
453
    }
454
455
    #endregion
456
457
    #region comments
458
459
    /**
460
     * Summary of commentCreated
461
     *
462
     * @param Comment $comment
463
     * @param Request $request
464
     */
465
    public function commentCreated(Comment $comment, Request $request)
466
    {
467
        $username = $this->currentUser->getUsername();
468
        $visibility = ($comment->getVisibility() == "admin" ? "private " : "");
469
470
        $this->send("{$username} posted a {$visibility}comment on request {$request->getId()} ({$request->getName()})");
471
    }
472
473
    /**
474
     * Summary of commentEdited
475
     *
476
     * @param Comment $comment
477
     * @param Request $request
478
     */
479
    public function commentEdited(Comment $comment, Request $request)
480
    {
481
        $username = $this->currentUser->getUsername();
482
483
        $this->send(<<<TAG
484
Comment {$comment->getId()} on request {$request->getId()} ({$request->getName()}) edited by {$username}
485
TAG
486
        );
487
    }
488
489
    public function alertFlaggedComments(int $count)
490
    {
491
        $this->send("There are ${count} flagged comments on closed requests currently awaiting redaction.");
492
    }
493
494
    #endregion
495
496
    #region email management (close reasons)
497
498
    /**
499
     * Summary of emailCreated
500
     *
501
     * @param EmailTemplate $template
502
     */
503
    public function emailCreated(EmailTemplate $template)
504
    {
505
        $username = $this->currentUser->getUsername();
506
        $this->send("Email {$template->getId()} ({$template->getName()}) created by " . $username);
507
    }
508
509
    /**
510
     * Summary of emailEdited
511
     *
512
     * @param EmailTemplate $template
513
     */
514
    public function emailEdited(EmailTemplate $template)
515
    {
516
        $username = $this->currentUser->getUsername();
517
        $this->send("Email {$template->getId()} ({$template->getName()}) edited by " . $username);
518
    }
519
    #endregion
520
}
521