Passed
Branch master (309757)
by Dispositif
03:20 queued 54s
created

NotificationWorker::processSpecialActions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 0
dl 0
loc 2
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
/*
3
 * This file is part of dispositif/wikibot application (@github)
4
 * 2019-2023 © Philippe M./Irønie  <[email protected]>
5
 * For the full copyright and MIT license information, view the license file.
6
 */
7
8
declare(strict_types=1);
9
10
namespace App\Application\Notification;
11
12
use App\Application\WikiPageAction;
13
use App\Infrastructure\ServiceFactory;
14
use DateTime;
15
use Exception;
16
use Mediawiki\Api\MediawikiApi;
17
use Mediawiki\Api\SimpleRequest;
18
use Mediawiki\Api\UsageException;
19
use Mediawiki\DataModel\EditInfo;
20
use Psr\Log\LoggerInterface;
21
use Throwable;
22
23
/**
24
 * TODO internationalize
25
 *
26
 * Parsing last notifications to the bot (and set them read).
27
 * Doc API : https://www.mediawiki.org/wiki/Notifications/API
28
 * TYPES :
29
 * edit-user-talk
30
 * mention-summary (alerte)
31
 * mention (Discussion utilisateur:Codaxbot)
32
 * flowusertalk-post-reply (alerte,   "title": {
33
 * "full": "Discussion utilisateur:Ir\u00f8nie",
34
 * "namespace": "Discussion_utilisateur")
35
 */
36
class NotificationWorker
37
{
38
    public const DEFAULT_WIKIS             = 'frwiki';
39
    public const DIFF_URL                  = 'https://fr.wikipedia.org/w/index.php?diff=';
40
    public const SUMMARY                   = '⚙ mise à jour notifications';
41
    public const SKIP_BOTPAGES
42
                                    = [
43
            'Utilisateur:CodexBot',
44
            'Discussion utilisateur:CodexBot',
45
            'Utilisateur:ZiziBot',
46
            'Discussion utilisateur:ZiziBot',
47
        ];
48
    public const PUBLISH_LOG_ON_WIKI = true;
49
50
    /**
51
     * @var MediawikiApi
52
     */
53
    protected $api;
54
    /**
55
     * @var string
56
     */
57
    protected $notifPage;
58
    /**
59
     * @var array
60
     */
61
    protected $option;
62
    /**
63
     * @var LoggerInterface|null
64
     */
65
    protected $logger;
66
67
    /**
68
     * NotificationWorker constructor.
69
     *
70
     * @param MediawikiApi $api
71
     * @param string       $notifPage
72
     * @param array|null   $option
73
     */
74
    public function __construct(MediawikiApi $api, string $notifPage, ?array $option = null, ?LoggerInterface $logger = null)
75
    {
76
        $this->api = $api;
77
        $this->notifPage = $notifPage;
78
        $this->option = $option ?? [];
79
        $this->process();
80
        $this->logger = $logger;
81
    }
82
83
    private function process()
84
    {
85
        $notifications = $this->requestNotifications();
86
        if (empty($notifications)) {
87
            return;
88
        }
89
90
        krsort($notifications);
91
92
        $wikilog = [];
93
        foreach ($notifications as $notif) {
94
            $title = $notif['title']['full'];
95
96
            // Skip bot pages
97
            if (in_array(
98
                $title,
99
                self::SKIP_BOTPAGES
100
            )
101
            ) {
102
                continue;
103
            }
104
105
            $date = new DateTime($notif['timestamp']['utciso8601']);
106
107
            if (isset($notif['title']) && in_array($notif['title']['namespace'], ['', 'Discussion'])) {
108
                $icon = '🌼 '; // Article + Discussion
109
            }
110
111
            $wikilog[] = sprintf(
112
                '* %s %s[[%s]] ([%s%s diff]) par %s',
113
                $date->format('d-m-Y H\hi'),
114
                $icon ?? '',
115
                $title,
116
                self::DIFF_URL,
117
                $notif['revid'] ?? '',
118
                $notif['agent']['name'] ?? '???'
119
            );
120
121
            if (!isset($notif['read'])) {
122
                $this->postNotifAsRead($notif['id']);
123
            }
124
125
            $this->processSpecialActions($notif);
126
        }
127
128
        if ($wikilog === []) {
129
            echo "Nothing.";
130
            return;
131
        }
132
133
        dump($wikilog);
134
135
        if (self::PUBLISH_LOG_ON_WIKI) {
136
            echo "Stop the script if you want to cancel the log edition on Wikipedia ! Waiting 30 seconds...\n";
137
            sleep(30);
138
            $this->editWikilog($wikilog);
139
        }
140
    }
141
142
    private function requestNotifications(): ?array
143
    {
144
        $result = $this->api->getRequest(
145
            new SimpleRequest(
146
                'query', [
147
                    'meta' => 'notifications',
148
                    'notwikis' => self::DEFAULT_WIKIS,
149
                    'notfilter' => '!read', // default: read|!read
150
                    'notlimit' => '30', // max 50
151
                    //                   'notunreadfirst' => '1', // comment for false
152
                    //                   'notgroupbysection' => '1',
153
                    'notsections' => 'alert', // alert|message ?? (minimum:alert)
154
                    'format' => 'php',
155
                ]
156
            )
157
        );
158
159
        if (empty($result)) {
160
            return [];
161
        }
162
163
        return $result['query']['notifications']['list'];
164
    }
165
166
    private function postNotifAsRead(int $id): bool
167
    {
168
        sleep(2);
169
        try {
170
            $this->api->postRequest(
171
                new SimpleRequest(
172
                    'echomarkread', [
173
                        'list' => $id,
174
                        'token' => $this->api->getToken(),
175
                    ]
176
                )
177
            );
178
        } catch (Throwable $e) {
179
            return false;
180
        }
181
182
        return true;
183
    }
184
185
    /**
186
     * Put there the special action to execute with each notification.
187
     *
188
     * @param $notif
189
     */
190
    protected function processSpecialActions($notif)
191
    {
192
        // optional for children
193
    }
194
195
    /**
196
     * Write wikilog of notifications on a dedicated page.
197
     *
198
     * @param array $wikilog
199
     *
200
     * @return bool
201
     * @throws UsageException
202
     * @throws Exception
203
     */
204
    private function editWikilog(array $wikilog): bool
205
    {
206
        if ($wikilog === []) {
207
            return false;
208
        }
209
        $text = implode("\n", $wikilog)."\n";
210
211
        $wiki = ServiceFactory::getMediawikiFactory();
212
        $pageAction = new WikiPageAction($wiki, $this->notifPage);
213
214
        return $pageAction->addToTopOfThePage(
215
            $text,
216
            new EditInfo(self::SUMMARY, false, false)
217
        );
218
    }
219
220
}
221