Skip to content

Commit

Permalink
Redesign RottenLinks to not depend on a maintenance script
Browse files Browse the repository at this point in the history
  • Loading branch information
Universal-Omega authored Dec 15, 2023
1 parent 0cb4be9 commit d291981
Show file tree
Hide file tree
Showing 19 changed files with 500 additions and 149 deletions.
11 changes: 2 additions & 9 deletions .github/workflows/mediawiki-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,12 @@ jobs:
strategy:
matrix:
include:
# Latest MediaWiki LTS - PHP 8.1
- mw: 'REL1_39'
php: 8.1
php-docker: 81
composer-test: true
experimental: false

# Latest MediaWiki stable - PHP 8.2
- mw: 'REL1_40'
php: 8.2
php-docker: 82
composer-test: false
experimental: true
composer-test: true
experimental: false

# Latest MediaWiki release branch - PHP 8.2
- mw: 'REL1_41'
Expand Down
1 change: 1 addition & 0 deletions .phan/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
$cfg = require __DIR__ . '/../vendor/mediawiki/mediawiki-phan-config/src/config.php';

$cfg['suppress_issue_types'] = [
'PhanAccessMethodInternal',
'SecurityCheck-LikelyFalsePositive'
];

Expand Down
5 changes: 1 addition & 4 deletions .phpcs.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
<?xml version="1.0"?>
<ruleset>
<file>.</file>
<rule ref="./vendor/mediawiki/mediawiki-codesniffer/MediaWiki">
<exclude name="Generic.Files.LineLength.TooLong" />
<exclude name="MediaWiki.Commenting.FunctionComment" />
</rule>
<rule ref="./vendor/mediawiki/mediawiki-codesniffer/MediaWiki" />
<arg name="bootstrap" value="./vendor/mediawiki/mediawiki-codesniffer/utils/bootstrap-ci.php"/>
<arg name="extensions" value="php"/>
<arg name="encoding" value="UTF-8"/>
Expand Down
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
## ChangeLog for RottenLinks

### 2.0.0 (15-12-2023)
* Redesign RottenLinks to not depend on a maintenance script
* Changes how we count page usage on RottenLinks special page. We directly gather this from externallinks table rather then storing it separately.
* Removes script statistics from statistics on Special:RottenLinks, since we don't depend on a script anymore.
* Requires MediaWiki 1.40 or higher and to have migrated externallinks using migrateExternallinks maintenance script and to set `$wgExternalLinksSchemaMigrationStage` to `SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW` or `SCHEMA_COMPAT_WRITE_NEW | SCHEMA_COMPAT_READ_NEW`.
* Add support for MediaWiki 1.41.
* Fix some deprecated warnings in php 8.2.
* Modernize extension:
* Use class namespacing
* Use dependency injection
* Use HookHandlers
* Convert DB select queries to use SelectQueryBuilder
* Cleanup and improve qqq.json
* Enable and fix remaining PHPCS checks

### 1.0.20 (10-01-2023)
* SpecialRottenLinks: replace usage of deprecated wfGetDB()

Expand Down
File renamed without changes.
3 changes: 3 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
{
"name": "John Lewis"
},
{
"name": "Paladox"
},
{
"name": "Universal Omega"
}
Expand Down
89 changes: 52 additions & 37 deletions extension.json
Original file line number Diff line number Diff line change
@@ -1,78 +1,93 @@
{
"name": "RottenLinks",
"version": "1.0.20",
"version": "2.0.0",
"author": [
"John Lewis",
"Paladox",
"Universal Omega"
],
"url": "https://github.com/WikiForge/RottenLinks",
"descriptionmsg": "rottenlinks-desc",
"namemsg": "rottenlinks-extensionname",
"license-name": "GPL-3.0-or-later",
"url": "https://github.com/WikiForge/RottenLinks",
"type": "specialpage",
"requires": {
"MediaWiki": ">= 1.35.3"
},
"SpecialPages": {
"RottenLinks": "SpecialRottenLinks"
"MediaWiki": ">= 1.40.0"
},
"MessagesDirs": {
"RottenLinks": [
"i18n"
]
},
"ExtensionMessagesFiles": {
"RottenLinksAliases": "includes/RottenLinksAliases.php"
"RottenLinksAliases": "RottenLinksAliases.php"
},
"AutoloadClasses": {
"RottenLinks": "includes/RottenLinks.php",
"RottenLinksHooks": "includes/RottenLinksHooks.php",
"RottenLinksPager": "includes/RottenLinksPager.php",
"SpecialRottenLinks": "includes/SpecialRottenLinks.php"
"AutoloadNamespaces": {
"WikiForge\\RottenLinks\\": "includes/"
},
"JobClasses": {
"RottenLinksJob": "WikiForge\\RottenLinks\\RottenLinksJob"
},
"SpecialPages": {
"RottenLinks": {
"class": "WikiForge\\RottenLinks\\SpecialRottenLinks",
"services": [
"ConfigFactory",
"DBLoadBalancer"
]
}
},
"Hooks": {
"LoadExtensionSchemaUpdates": [
"RottenLinksHooks::fnRottenLinksSchemaUpdates"
]
"LinksUpdateComplete": {
"handler": "Main"
},
"LoadExtensionSchemaUpdates": {
"handler": "Installer"
}
},
"HookHandlers": {
"Installer": {
"class": "WikiForge\\RottenLinks\\HookHandlers\\Installer"
},
"Main": {
"class": "WikiForge\\RottenLinks\\HookHandlers\\Main",
"services": [
"JobQueueGroup"
]
}
},
"config": {
"RottenLinksBadCodes": {
"description": "Holds a list of HTTP codes that are considered bad. (array)",
"public": true,
"value": [ "0", "400", "401", "403", "404", "405", "502", "503", "504" ]
"value": [ "0", "400", "401", "403", "404", "405", "502", "503", "504" ],
"description": "Holds a list of HTTP codes that are considered bad. (array)"
},
"RottenLinksCurlTimeout": {
"description": "Sets the timeout for cURL in seconds. (integer)",
"public": true,
"value": 30
"value": 30,
"description": "Sets the timeout for cURL in seconds. (integer)"
},
"RottenLinksHTTPProxy": {
"description": "Sets a proxy to use for requests. (string)",
"public": true,
"value": ""
"value": "",
"description": "Sets a proxy to use for requests. (string)"
},
"RottenLinksExcludeProtocols": {
"description": "Holds a list of protocols that should not be checked for validity. (array)",
"public": true,
"value": [ "tel", "mailto" ]
"value": [ "tel", "mailto" ],
"description": "Holds a list of protocols that should not be checked for validity. (array)"
},
"RottenLinksExcludeWebsites": {
"description": "List of websites to exclude checking of response codes for. (array)",
"public": true,
"value": false
"value": false,
"description": "List of websites to exclude checking of response codes for. (array)"
},
"RottenLinksExternalLinkTarget": {
"description": "Sets the external link target (_self for the current tab or _blank for a new tab). (string)",
"public": true,
"value": "_self"
"value": "_self",
"description": "Sets the external link target (_self for the current tab or _blank for a new tab). (string)"
},
"RottenLinksUserAgent": {
"description": "Overrides the user-agent to use for requests. Defaults to 'RottenLinks, MediaWiki extension (https://github.com/miraheze/RottenLinks), running on <Wiki base URL>'. (string)",
"public": true,
"value": ""
"value": "",
"description": "Overrides the user-agent to use for requests. Defaults to 'RottenLinks, MediaWiki extension (https://github.com/WikiForge/RottenLinks), running on <Wiki base URL>'. (string)"
}
},
"ConfigRegistry": {
"rottenlinks": "GlobalVarConfig::newInstance"
"RottenLinks": "GlobalVarConfig::newInstance"
},
"manifest_version": 2
}
7 changes: 3 additions & 4 deletions i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@
"@metadata": {
"authors": [
"John Lewis",
"Kghbln"
"Kghbln",
"Universal Omega"
]
},
"rottenlinks": "Status of external links",
"rottenlinks-desc": "Shows the [[Special:RottenLinks|state of all external links]] on the wiki",
"rottenlinks-metadata": "Script Data",
"rottenlinks-extensionname": "RottenLinks",
"rottenlinks-table-external": "External Link",
"rottenlinks-table-response": "HTTP Response",
"rottenlinks-table-usage": "Page Usage",
"rottenlinks-rundate": "Script run date",
"rottenlinks-runtime": "Script execution time",
"rottenlinks-showbad": "Show rotten links only",
"rottenlinks-statistics": "Rotten Link Statistics",
"rottenlinks-stats": "Show link statistics"
Expand Down
12 changes: 8 additions & 4 deletions i18n/qqq.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
"@metadata": {
"authors": [
"John Lewis",
"Kghbln"
"Kghbln",
"Universal Omega"
]
},
"rottenlinks": "This is the title of Special:RottenLinks as well as the label of the link pointing to it on Special:SpecialPages",
"rottenlinks-desc": "This is the extension's despription on Special:Verion",
"rottenlinks": "{{doc-special}}",
"rottenlinks-desc": "{{desc|name=RottenLinks|url=https://github.com/WikiForge/RottenLinks}}",
"rottenlinks-extensionname": "{{name}}",
"rottenlinks-table-external": "This is the label of a tabel header on Special:RottenLinks",
"rottenlinks-table-response": "This is the label of a tabel header on Special:RottenLinks",
"rottenlinks-table-usage": "This is the label of a tabel header on Special:RottenLinks",
"rottenlinks-showbad": "This is the text describing a checkbox on Special:RottenLinks"
"rottenlinks-showbad": "This is the text describing a checkbox on Special:RottenLinks",
"rottenlinks-statistics": "This is the text of a form section on Special:RottenLinks",
"rottenlinks-stats": "This is the text describing a checkbox on Special:RottenLinks"
}
24 changes: 24 additions & 0 deletions includes/HookHandlers/Installer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace WikiForge\RottenLinks\HookHandlers;

use DatabaseUpdater;
use MediaWiki\Installer\Hook\LoadExtensionSchemaUpdatesHook;

class Installer implements LoadExtensionSchemaUpdatesHook {

/**
* @param DatabaseUpdater $updater
*/
public function onLoadExtensionSchemaUpdates( $updater ) {
$dir = __DIR__ . '/../../sql';

$updater->addExtensionTable( 'rottenlinks', "$dir/rottenlinks.sql" );

$updater->addExtensionField( 'rottenlinks', 'rl_id', "$dir/patches/patch-add-rl_id.sql" );

$updater->addExtensionIndex( 'rottenlinks', 'rl_externallink', "$dir/patches/20210215.sql" );

$updater->dropExtensionField( 'rottenlinks', 'rl_pageusage', "$dir/patches/patch-drop-rl_pageusage.sql" );
}
}
41 changes: 41 additions & 0 deletions includes/HookHandlers/Main.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace WikiForge\RottenLinks\HookHandlers;

use JobQueueGroup;
use MediaWiki\Deferred\LinksUpdate\LinksUpdate;
use MediaWiki\Hook\LinksUpdateCompleteHook;
use WikiForge\RottenLinks\RottenLinksJob;

class Main implements LinksUpdateCompleteHook {

/** @var JobQueueGroup */
private $jobQueueGroup;

/**
* @param JobQueueGroup $jobQueueGroup
*/
public function __construct( JobQueueGroup $jobQueueGroup ) {
$this->jobQueueGroup = $jobQueueGroup;
}

/**
* Handler for LinksUpdateComplete hook.
* @see https://www.mediawiki.org/wiki/Manual:Hooks/LinksUpdateComplete
* @param LinksUpdate $linksUpdate
* @param mixed $ticket
*/
public function onLinksUpdateComplete( $linksUpdate, $ticket ) {
$addedExternalLinks = $linksUpdate->getAddedExternalLinks();
$removedExternalLinks = $linksUpdate->getRemovedExternalLinks();

if ( $addedExternalLinks || $removedExternalLinks ) {
$params = [
'addedExternalLinks' => $addedExternalLinks,
'removedExternalLinks' => $removedExternalLinks
];

$this->jobQueueGroup->push( new RottenLinksJob( $params ) );
}
}
}
34 changes: 30 additions & 4 deletions includes/RottenLinks.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
<?php

namespace WikiForge\RottenLinks;

use Config;
use MediaWiki\MediaWikiServices;

class RottenLinks {
public static function getResponse( $url ) {
/**
* Get the HTTP response status code for a given URL.
*
* @param string $url The URL to check.
*
* @return int The HTTP status code.
*/
public static function getResponse( string $url ) {
$services = MediaWikiServices::getInstance();

$config = $services->getConfigFactory()->makeConfig( 'rottenlinks' );
$config = $services->getConfigFactory()->makeConfig( 'RottenLinks' );

// Make the protocol lowercase
$urlexp = explode( '://', $url, 2 );
Expand All @@ -23,11 +33,27 @@ public static function getResponse( $url ) {
return $status;
}

private static function getHttpStatus( $url, $method, $services, $config ) {
/**
* Get the HTTP status code for a given URL using a specified method.
*
* @param string $url The URL to check.
* @param string $method The HTTP method to use ('HEAD' or 'GET').
* @param MediaWikiServices $services MediaWiki service instance.
* @param Config $config Configuration instance.
*
* @return int The HTTP status code.
*/
private static function getHttpStatus(
string $url,
string $method,
MediaWikiServices $services,
Config $config
) {
$httpProxy = $config->get( 'RottenLinksHTTPProxy' );

$userAgent = $config->get( 'RottenLinksUserAgent' ) ?:
'RottenLinks, MediaWiki extension (https://github.com/miraheze/RottenLinks), running on ' . $config->get( 'Server' );
'RottenLinks, MediaWiki extension (https://github.com/WikiForge/RottenLinks), running on ' .
$config->get( 'Server' );

$request = $services->getHttpRequestFactory()->createMultiClient( [ 'proxy' => $httpProxy ] )
->run( [
Expand Down
17 changes: 0 additions & 17 deletions includes/RottenLinksHooks.php

This file was deleted.

Loading

0 comments on commit d291981

Please sign in to comment.