Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
strategy:
fail-fast: false
matrix:
target: [phplint, phpcs]
target: [phplint, phpcs, phpunit]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
Expand Down Expand Up @@ -47,6 +47,11 @@ jobs:
composer exec phpcs -- --standard=PSR12 --ignore=vendor/ .
if: matrix.target == 'phpcs'

- name: PHP Unit Test
run: |
composer exec phpunit -- tests/
if: matrix.target == 'phpunit'

build-container:
runs-on: ubuntu-latest
steps:
Expand Down
86 changes: 76 additions & 10 deletions action_functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public static function getWarningLevel($user, &$content = null)
$warning = 0;
$content = Api::$q->getpage('User talk:' . $user);
if (
$content != null &&
preg_match_all(
'/<!-- Template:(uw-[a-z]*(\d)(im)?|Blatantvandal \(serious warning\)) -->.*' .
'(\d{2}):(\d{2}), (\d+) ([a-zA-Z]+) (\d{4}) \(UTC\)/iU',
Expand Down Expand Up @@ -74,6 +75,34 @@ public static function getWarningLevel($user, &$content = null)
return (int)$warning;
}

private static function getWarningText($change, $report, $warning)
{
$template = '{{subst:User:' . Config::$user . '/Warnings/Warning'
. '|1=' . $warning
. '|2=' . str_replace('File:', ':File:', $change['title'])
. '|3=' . $report
. ' <!{{subst:ns:0}}-- MySQL ID: ' . $change['mysqlid'] . ' --{{subst:ns:0}}>'
. '|4=' . $change['mysqlid']
. '}} ~~~~';

$x = Api::$h->get(
Api::$a->apiurl . '?action=parse&text=' . urlencode($template) . '&title=' . urlencode('User:' . $change['user']) . '&pst=true&onlypst=true&prop=wikitext&format=json'
);
$ret = Api::$h->unserialize($x);

if (is_array($ret) && array_key_exists('parse', $ret) && array_key_exists('text', $ret['parse']) && array_key_exists('*', $ret['parse']['text'])) {
$template = $ret['parse']['text']['*'];
}

// Split out the header if there is one (parse was successful)
if (preg_match('/^\s*(==\s*\w+\s+\d{4}\s*==)\n(.*)$/s', $template, $match)) {
return [$match[1], $match[2]];
}

// Fallback to raw substitution
return [null, $template];
}

private static function aiv($change, $report)
{
global $logger;
Expand All @@ -98,21 +127,58 @@ private static function aiv($change, $report)
}
}

private static function warn($change, $report, $content, $warning)
private static function mangleSectionIntoPage(?string $content, ?string $sectionHeader, string $sectionText): string
{
// No existing content
if ($content === null) {
return $sectionHeader !== null
? "{$sectionHeader}\n{$sectionText}\n"
: "{$sectionText}\n";
}

// No header — append to end (e.g. substituted template)
if ($sectionHeader === null) {
return "{$content}\n\n{$sectionText}\n";
}

$sectionPosition = strpos($content, "{$sectionHeader}\n");

// Header not found — append new section
if ($sectionPosition === false) {
return "{$content}\n\n{$sectionHeader}\n{$sectionText}\n";
}

// Determine header level and find section boundaries
$level = strspn($sectionHeader, '=');
$before = substr($content, 0, $sectionPosition);
$after = substr($content, $sectionPosition);

// Find the next header of equal or higher level
$end = preg_match('/\n(?=={1,' . $level . '}(?!=))/m', $after, $stop, PREG_OFFSET_CAPTURE)
? $stop[0][1]
: strlen($after);

$existingSection = substr($after, 0, $end);
$afterSection = substr($after, $end);

return $before
. trim($existingSection) . "\n\n"
. trim($sectionText)
. ($afterSection ? "\n" . $afterSection : '')
. "\n";
}

public static function warn($change, $report, $content, $warning)
{
global $logger;
$logger->info('Warning ' . $change['user']);

[$sectionHeader, $sectionText] = self::getWarningText($change, $report, $warning);
$newContent = self::mangleSectionIntoPage($content, $sectionHeader, $sectionText);

$ret = Api::$a->edit(
'User talk:' . $change['user'],
$content . "\n\n"
. '{{subst:User:' . Config::$user . '/Warnings/Warning'
. '|1=' . $warning
. '|2=' . str_replace('File:', ':File:', $change['title'])
. '|3=' . $report
. ' <!{{subst:ns:0}}-- MySQL ID: ' . $change['mysqlid'] . ' --{{subst:ns:0}}>'
. '|4=' . $change['mysqlid']
. '}} ~~~~'
. "\n",
$newContent,
'Warning [[Special:Contributions/' . $change['user'] . '|' . $change['user'] . ']] - #' . $warning,
false,
false
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"require-dev": {
"overtrue/phplint": "@stable",
"squizlabs/php_codesniffer": "^4.0",
"phpmd/phpmd" : "@stable"
"phpmd/phpmd" : "@stable",
"phpunit/phpunit": "^12.0"
},
"repositories": [
{
Expand Down
Loading
Loading