IrcNotificationHelper   A
last analyzed

Complexity

Total Complexity 40

Size/Duplication

Total Lines 496
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 10
Bugs 0 Features 2
Metric Value
wmc 40
eloc 127
dl 0
loc 496
ccs 0
cts 132
cp 0
rs 9.2
c 10
b 0
f 2

31 Methods

Rating   Name   Duplication   Size   Complexity  
A requestDeferred() 0 9 1
A welcomeTemplateCreated() 0 3 1
A requestUnreserved() 0 3 1
A requestReservationSent() 0 7 1
A requestDeferredWithMail() 0 11 1
A welcomeTemplateEdited() 0 3 1
A requestCloseQueued() 0 5 1
A unbanned() 0 4 1
A requestReserveBroken() 0 5 1
A requestClosed() 0 5 1
A userRolesEdited() 0 4 1
A userRenamed() 0 3 1
A emailEdited() 0 4 1
A requestReceived() 0 13 1
A welcomeTemplateDeleted() 0 3 1
A emailCreated() 0 4 1
A siteNoticeEdited() 0 3 1
A commentEdited() 0 6 1
A alertFlaggedComments() 0 3 1
A requestCreationFailed() 0 3 1
A commentCreated() 0 16 3
A __construct() 0 12 1
A requestWelcomeFailed() 0 3 1
A banned() 0 16 3
A requestReserved() 0 5 1
A sentMail() 0 4 1
A userPrefChange() 0 3 1
A userApproved() 0 3 1
A userNew() 0 3 1
B send() 0 56 6
A userDeactivated() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like IrcNotificationHelper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use IrcNotificationHelper, and based on these observations, apply Extract Interface, too.

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