Completed
Push — master ( c4ce9d...69540b )
by Dispositif
03:31
created

Bot::getTimestamp()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 6
rs 10
1
<?php
2
/**
3
 * This file is part of dispositif/wikibot application
4
 * 2019 : Philippe M. <[email protected]>
5
 * For the full copyright and MIT license information, please view the LICENSE file.
6
 */
7
8
declare(strict_types=1);
9
10
namespace App\Application;
11
12
use App\Domain\Exceptions\ConfigException;
13
use App\Infrastructure\ServiceFactory;
14
use Bluora\LaravelGitInfo\GitInfo;
15
16
/**
17
 * Define wiki configuration of the bot.
18
 * See also .env file for parameters.
19
 * Class Bot.
20
 */
21
class Bot
22
{
23
    const WIKI_STATE_FILENAME = __DIR__.'/resources/wiki_state.json';
24
    const WATCHPAGE_FILENAME  = __DIR__.'/resources/watch_pages.json';
25
26
    const EXIT_ON_CHECK_WATCHPAGE = true;
27
28
    const BOT_FLAG = false;
29
30
    const MODE_AUTO = false;
31
32
    const EXIT_ON_WIKIMESSAGE = true;
33
34
    const EDIT_LAPS = 20;
35
36
    const EDIT_LAPS_MANUAL = 20;
37
38
    const EDIT_LAPS_AUTOBOT = 60;
39
40
    const EDIT_LAPS_FLAGBOT = 8;
41
42
    public $taskName = 'Améliorations bibliographiques';
43
44
    public static $gitVersion;
45
    /**
46
     * @var \DateTimeImmutable
47
     */
48
    private $lastCheckStopDate;
49
50
    public function __construct()
51
    {
52
        ini_set('user_agent', getenv('USER_AGENT'));
53
    }
54
55
    /**
56
     * Return start of wiki edit commentary.
57
     *
58
     * @return string
59
     */
60
    public function getCommentary(): string
61
    {
62
        return sprintf(
63
            '[%s] %s',
64
            str_replace('v', '', self::getGitVersion()),
65
            $this->taskName
66
        );
67
    }
68
69
    /**
70
     * Return last version (tag) from Git.
71
     *
72
     * @return string|null
73
     */
74
    public static function getGitVersion(): ?string
75
    {
76
        if (self::$gitVersion) {
77
            return self::$gitVersion;
78
        }
79
        $git = new GitInfo();
80
        $raw = $git->version();
81
        if (preg_match('#^(v[0-9.a-e]+)#', $raw, $matches) > 0) {
82
            self::$gitVersion = $matches[1];
83
84
            return self::$gitVersion;
85
        }
86
87
        return null;
88
    }
89
90
    /**
91
     * Return start of last commit id.
92
     *
93
     * @return string|null
94
     */
95
    public static function getCommitId(): ?string
96
    {
97
        $git = new GitInfo();
98
        $raw = $git->version();
99
        if (preg_match('#g([0-9a-f]+)#', $raw, $matches) > 0) {
100
            return $matches[1];
101
        }
102
103
        return null;
104
    }
105
106
    public function checkStopOnTalkpage(?bool $botTalk = false): void
107
    {
108
        $title = 'Discussion_utilisateur:'.getenv('BOT_NAME');
109
110
        if ($this->lastCheckStopDate
111
            && new \DateTimeImmutable() < $this->lastCheckStopDate->add(
112
                new \DateInterval('PT2M')
113
            )
114
        ) {
115
            return;
116
        }
117
        $this->lastCheckStopDate = new \DateTimeImmutable();
118
119
120
        $wiki = ServiceFactory::wikiApi();
121
        $pageAction = new WikiPageAction($wiki, $title);
122
        $text = $pageAction->getText();
123
124
        if (preg_match('#({{stop}}|{{Stop}}|STOP)#', $text) > 0) {
125
            echo date('Y-m-d H:i');
126
            echo sprintf(
127
                "\n*** STOP ON TALK PAGE BY %s ***\n\n",
128
                $pageAction->getLastEditor()
129
            );
130
            if ($botTalk && class_exists(ZiziBot::class)) {
131
                (new ZiziBot())->botTalk();
132
            }
133
            exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
134
        }
135
    }
136
137
    /**
138
     * Is there a new message on the discussion page of the bot (or owner) ?
139
     * Stop on new message ?
140
     *
141
     * @param bool $botTalk
142
     *
143
     * @throws ConfigException
144
     * @throws \Mediawiki\Api\UsageException
145
     */
146
    public function checkWatchPages()
147
    {
148
        foreach ($this->getWatchPages() as $title => $lastTime) {
149
            $pageTime = $this->getTimestamp($title);
150
151
            // the page has been edited since last check ?
152
            if (!$pageTime || $pageTime !== $lastTime) {
153
                echo sprintf(
154
                    "WATCHPAGE '%s' has been edited since %s.\n",
155
                    $title,
156
                    $lastTime
157
                );
158
159
                // Ask? Mettre à jour $watchPages ?
160
                echo "Replace with $title => '$pageTime'";
161
162
                if (self::EXIT_ON_CHECK_WATCHPAGE) {
163
                    echo "EXIT_ON_CHECK_WATCHPAGE\n";
164
                    exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
165
                }
166
            }
167
        }
168
    }
169
170
    /**
171
     * @return array
172
     * @throws ConfigException
173
     */
174
    protected function getWatchPages(): array
175
    {
176
        if (!file_exists(static::WATCHPAGE_FILENAME)) {
177
            throw new ConfigException('No watchpage file found.');
178
        }
179
180
        try {
181
            $json = file_get_contents(static::WATCHPAGE_FILENAME);
182
            $array = json_decode($json, true);
183
        } catch (\Throwable $e) {
184
            throw new ConfigException('Watchpage file malformed.');
185
        }
186
187
        return $array;
188
    }
189
190
    private function getTimestamp(string $title): ?string
191
    {
192
        $wiki = ServiceFactory::wikiApi();
193
        $page = new WikiPageAction($wiki, $title);
194
195
        return $page->page->getRevisions()->getLatest()->getTimestamp();
196
    }
197
198
    /**
199
     * How many minutes since last edit ? Do not to disturb human editors !
200
     *
201
     * @param string $title
202
     *
203
     * @return int minutes
204
     */
205
    public function minutesSinceLastEdit(string $title): int
206
    {
207
        $time = $this->getTimestamp($title);  // 2011-09-02T16:31:13Z
208
209
        return (int)round((time() - strtotime($time)) / 60);
210
    }
211
212
    /**
213
     * Detect {{nobots}}, {{bots|deny=all}}, {{bots|deny=MyBot,BobBot}}.
214
     * Relevant out of the "main" wiki-namespace (talk pages, etc).
215
     *
216
     * @param string $text
217
     * @param string|null $botName
218
     *
219
     * @return bool
220
     */
221
    public static function isNoBotTag(string $text, ?string $botName = null): bool
222
    {
223
        $botName = ($botName) ? $botName : getenv('BOT_NAME');
224
        $denyReg = (!empty($botName)) ? '|\{\{bots ?\| ?deny\=[^\}]*'.preg_quote($botName, '#').'[^\}]*\}\}' : '';
225
226
        if (preg_match('#({{nobots}}|{{bots ?\| ?(optout|deny) ?= ?all ?}}'.$denyReg.')#i', $text) > 0) {
227
            return true;
228
        }
229
230
        return false;
231
    }
232
233
    /**
234
     * Detect wiki-templates restricting the edition on a frwiki page.
235
     *
236
     * @param string $text
237
     *
238
     * @return bool
239
     */
240
    public static function isEditionRestricted(string $text): bool
241
    {
242
        if (preg_match('#{{Protection#i', $text) > 0) {
243
            return true;
244
        }
245
        return false;
246
    }
247
}
248