Merge "Allow partially blocked users to tag unrelated revisions"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 10 Sep 2019 19:00:47 +0000 (19:00 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 10 Sep 2019 19:00:47 +0000 (19:00 +0000)
141 files changed:
.phpcs.xml
RELEASE-NOTES-1.34
autoload.php
docs/hooks.txt
includes/DefaultSettings.php
includes/MovePage.php
includes/Revision.php
includes/Revision/RevisionStore.php
includes/Setup.php
includes/api/ApiSetNotificationTimestamp.php
includes/api/i18n/ar.json
includes/api/i18n/fr.json
includes/api/i18n/pl.json
includes/api/i18n/zh-hant.json
includes/cache/LinkCache.php
includes/cache/localisation/LCStoreDB.php
includes/deferred/LinksUpdate.php
includes/externalstore/ExternalStoreDB.php
includes/installer/i18n/ia.json
includes/installer/i18n/ja.json
includes/installer/i18n/pl.json
includes/jobqueue/jobs/RefreshLinksJob.php
includes/libs/filebackend/FSFileBackend.php
includes/libs/filebackend/FileBackendStore.php
includes/libs/filebackend/fileophandle/FileBackendStoreOpHandle.php
includes/page/WikiPage.php
includes/preferences/DefaultPreferencesFactory.php
includes/resourceloader/ResourceLoader.php
includes/session/SessionManager.php
includes/session/SessionOverflowException.php [new file with mode: 0644]
includes/specialpage/LoginSignupSpecialPage.php
includes/specialpage/QueryPage.php
includes/specialpage/SpecialPageFactory.php
includes/specials/SpecialAncientPages.php [new file with mode: 0644]
includes/specials/SpecialAncientpages.php [deleted file]
includes/specials/SpecialBlockList.php
includes/specials/SpecialBrokenRedirects.php
includes/specials/SpecialConfirmEmail.php [new file with mode: 0644]
includes/specials/SpecialConfirmemail.php [deleted file]
includes/specials/SpecialDeadendPages.php [new file with mode: 0644]
includes/specials/SpecialDeadendpages.php [deleted file]
includes/specials/SpecialDeletedContributions.php
includes/specials/SpecialDoubleRedirects.php
includes/specials/SpecialEmailInvalidate.php
includes/specials/SpecialFewestRevisions.php [new file with mode: 0644]
includes/specials/SpecialFewestrevisions.php [deleted file]
includes/specials/SpecialFileDuplicateSearch.php
includes/specials/SpecialLinkSearch.php
includes/specials/SpecialListDuplicatedFiles.php
includes/specials/SpecialListRedirects.php [new file with mode: 0644]
includes/specials/SpecialListredirects.php [deleted file]
includes/specials/SpecialLonelyPages.php [new file with mode: 0644]
includes/specials/SpecialLonelypages.php [deleted file]
includes/specials/SpecialLongPages.php [new file with mode: 0644]
includes/specials/SpecialLongpages.php [deleted file]
includes/specials/SpecialMIMESearch.php [new file with mode: 0644]
includes/specials/SpecialMIMEsearch.php [deleted file]
includes/specials/SpecialMediaStatistics.php
includes/specials/SpecialMostCategories.php [new file with mode: 0644]
includes/specials/SpecialMostInterwikis.php [new file with mode: 0644]
includes/specials/SpecialMostLinked.php [new file with mode: 0644]
includes/specials/SpecialMostLinkedCategories.php [new file with mode: 0644]
includes/specials/SpecialMostLinkedTemplates.php [new file with mode: 0644]
includes/specials/SpecialMostRevisions.php [new file with mode: 0644]
includes/specials/SpecialMostcategories.php [deleted file]
includes/specials/SpecialMostinterwikis.php [deleted file]
includes/specials/SpecialMostlinked.php [deleted file]
includes/specials/SpecialMostlinkedcategories.php [deleted file]
includes/specials/SpecialMostlinkedtemplates.php [deleted file]
includes/specials/SpecialMostrevisions.php [deleted file]
includes/specials/SpecialNewFiles.php [new file with mode: 0644]
includes/specials/SpecialNewimages.php [deleted file]
includes/specials/SpecialRedirect.php
includes/specials/SpecialShortPages.php [new file with mode: 0644]
includes/specials/SpecialShortpages.php [deleted file]
includes/specials/SpecialUncategorizedCategories.php [new file with mode: 0644]
includes/specials/SpecialUncategorizedImages.php [new file with mode: 0644]
includes/specials/SpecialUncategorizedPages.php [new file with mode: 0644]
includes/specials/SpecialUncategorizedTemplates.php [new file with mode: 0644]
includes/specials/SpecialUncategorizedcategories.php [deleted file]
includes/specials/SpecialUncategorizedimages.php [deleted file]
includes/specials/SpecialUncategorizedpages.php [deleted file]
includes/specials/SpecialUncategorizedtemplates.php [deleted file]
includes/specials/SpecialUndelete.php
includes/specials/SpecialUnusedCategories.php [new file with mode: 0644]
includes/specials/SpecialUnusedImages.php [new file with mode: 0644]
includes/specials/SpecialUnusedTemplates.php [new file with mode: 0644]
includes/specials/SpecialUnusedcategories.php [deleted file]
includes/specials/SpecialUnusedimages.php [deleted file]
includes/specials/SpecialUnusedtemplates.php [deleted file]
includes/specials/SpecialUnwatchedPages.php [new file with mode: 0644]
includes/specials/SpecialUnwatchedpages.php [deleted file]
includes/specials/SpecialWantedCategories.php [new file with mode: 0644]
includes/specials/SpecialWantedTemplates.php [new file with mode: 0644]
includes/specials/SpecialWantedcategories.php [deleted file]
includes/specials/SpecialWantedtemplates.php [deleted file]
includes/specials/SpecialWithoutInterwiki.php [new file with mode: 0644]
includes/specials/SpecialWithoutinterwiki.php [deleted file]
includes/specials/pagers/ActiveUsersPager.php
includes/specials/pagers/AllMessagesTablePager.php
includes/specials/pagers/MergeHistoryPager.php
includes/specials/pagers/ProtectedTitlesPager.php
includes/specials/pagers/UsersPager.php
includes/user/User.php
includes/widget/CheckMatrixWidget.php
includes/widget/ComplexTitleInputWidget.php
includes/widget/NamespaceInputWidget.php
includes/widget/SelectWithInputWidget.php
includes/widget/SizeFilterWidget.php
includes/widget/TagMultiselectWidget.php
languages/i18n/cs.json
languages/i18n/diq.json
languages/i18n/en.json
languages/i18n/exif/pl.json
languages/i18n/fr.json
languages/i18n/gom-deva.json
languages/i18n/gom-latn.json
languages/i18n/hr.json
languages/i18n/ja.json
languages/i18n/mk.json
languages/i18n/pl.json
languages/i18n/qqq.json
languages/i18n/sv.json
languages/i18n/szl.json
languages/i18n/tt-cyrl.json
languages/i18n/zh-hant.json
maintenance/cleanupTitles.php
maintenance/install.php
maintenance/storage/blobs.sql
maintenance/storage/checkStorage.php
maintenance/userOptions.php
tests/phpunit/includes/TitleTest.php
tests/phpunit/includes/api/ApiDeleteTest.php
tests/phpunit/includes/api/ApiRevisionDeleteTest.php
tests/phpunit/includes/session/SessionManagerTest.php
tests/phpunit/includes/specials/QueryAllSpecialPagesTest.php
tests/phpunit/includes/specials/SpecialMIMESearchTest.php
tests/phpunit/includes/specials/SpecialShortPagesTest.php [new file with mode: 0644]
tests/phpunit/includes/specials/SpecialShortpagesTest.php [deleted file]
tests/phpunit/includes/specials/SpecialUncategorizedCategoriesTest.php [new file with mode: 0644]
tests/phpunit/includes/specials/UncategorizedCategoriesPageTest.php [deleted file]

index 9f11ebc..f971881 100644 (file)
                        Whitelist existing violations, but enable the sniff to prevent
                        any new occurrences.
                -->
-               <exclude-pattern>*/includes/specials/SpecialMostinterwikis\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialAncientpages\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialBrokenRedirects\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialConfirmemail\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialDeadendpages\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialDeletedContributions\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialDoubleRedirects\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialEmailInvalidate\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialFewestrevisions\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialFileDuplicateSearch\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialLinkSearch\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialListDuplicatedFiles\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialListredirects\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialLonelypages\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialLongpages\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialMIMEsearch\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialMediaStatistics\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialMostcategories\.php</exclude-pattern>
                <exclude-pattern>*/includes/specials/SpecialMostimages\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialMostlinked\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialMostlinkedcategories\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialMostlinkedtemplates\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialMostrevisions\.php</exclude-pattern>
                <exclude-pattern>*/includes/specials/SpecialMovepage\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialNewimages\.php</exclude-pattern>
                <exclude-pattern>*/includes/specials/SpecialRandompage\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialShortpages\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialUncategorizedcategories\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialUncategorizedimages\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialUncategorizedpages\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialUncategorizedtemplates\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialUnusedcategories\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialUnusedimages\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialUnusedtemplates\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialUnwatchedpages\.php</exclude-pattern>
                <exclude-pattern>*/includes/specials/SpecialUserrights\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialWantedcategories\.php</exclude-pattern>
                <exclude-pattern>*/includes/specials/SpecialWantedfiles\.php</exclude-pattern>
                <exclude-pattern>*/includes/specials/SpecialWantedpages\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialWantedtemplates\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialWithoutinterwiki\.php</exclude-pattern>
                <exclude-pattern>*/maintenance/CodeCleanerGlobalsPass.inc</exclude-pattern>
                <exclude-pattern>*/maintenance/archives/upgradeLogging\.php</exclude-pattern>
                <exclude-pattern>*/maintenance/benchmarks/bench_HTTP_HTTPS\.php</exclude-pattern>
index 2e220af..b8c9102 100644 (file)
@@ -190,6 +190,34 @@ because of Phabricator reports.
   * CryptRand class
   * CryptRand service
   * Functions of the MWCryptRand class: singleton(), wasStrong() and generate().
+* Various Special Page PHP Classes were renamed (mostly casing changes):
+  * SpecialAncientpages => SpecialAncientPages
+  * SpecialConfirmemail => SpecialConfirmEmail
+  * SpecialDeadendpages => SpecialDeadendPages
+  * SpecialFewestrevisions => SpecialFewestRevisions
+  * SpecialListredirects => SpecialListRedirects
+  * SpecialLonelypages => SpecialLonelyPages
+  * SpecialLongpages => SpecialLongPages
+  * SpecialMIMEsearch => SpecialMIMESearch
+  * SpecialMostcategories => SpecialMostCategories
+  * SpecialMostinterwikis => SpecialMostInterwikis
+  * SpecialMostlinked => SpecialMostLinked
+  * SpecialMostlinkedcategories => SpecialMostLinkedCategories
+  * SpecialMostlinkedtemplates => SpecialMostLinkedTemplates
+  * SpecialMostrevisions => SpecialMostRevisions
+  * SpecialNewimages => SpecialNewFiles
+  * SpecialShortpages => SpecialShortPages
+  * SpecialUncategorizedcategories => SpecialUncategorizedCategories
+  * SpecialUncategorizedimages => SpecialUncategorizedImages
+  * SpecialUncategorizedpages => SpecialUncategorizedPages
+  * SpecialUncategorizedtemplates => SpecialUncategorizedTemplates
+  * SpecialUnusedcategories => SpecialUnusedCategories
+  * SpecialUnusedimages => SpecialUnusedImages
+  * SpecialUnusedtemplates => SpecialUnusedTemplates
+  * SpecialUnwatchedpages => SpecialUnwatchedPages
+  * SpecialWantedcategories => SpecialWantedCategories
+  * SpecialWantedtemplates => SpecialWantedTemplates
+  * SpecialWithoutinterwiki => SpecialWithoutInterwiki
 * Language::setCode, deprecated in 1.32, was removed. Use Language::factory to
   create a new Language object with a different language code.
 * MWNamespace::clearCaches() has been removed.  So has the $rebuild parameter
@@ -532,6 +560,8 @@ because of Phabricator reports.
   be used instead.
 * The UserIsHidden hook is deprecated. Use GetUserBlock instead, and add a
   system block that hides the user.
+* The GetBlockedStatus hook is deprecated. Use GetUserBlock instead, to add or
+  remove a block.
 
 === Other changes in 1.34 ===
 * …
index 87b2bb9..f95e001 100644 (file)
@@ -20,7 +20,6 @@ $wgAutoloadLocalClasses = [
        'AllMessagesTablePager' => __DIR__ . '/includes/specials/pagers/AllMessagesTablePager.php',
        'AllTrans' => __DIR__ . '/maintenance/language/alltrans.php',
        'AlphabeticPager' => __DIR__ . '/includes/pager/AlphabeticPager.php',
-       'AncientPagesPage' => __DIR__ . '/includes/specials/SpecialAncientpages.php',
        'AnsiTermColorer' => __DIR__ . '/maintenance/term/MWTerm.php',
        'ApiAMCreateAccount' => __DIR__ . '/includes/api/ApiAMCreateAccount.php',
        'ApiAuthManagerHelper' => __DIR__ . '/includes/api/ApiAuthManagerHelper.php',
@@ -215,7 +214,6 @@ $wgAutoloadLocalClasses = [
        'BlockLogFormatter' => __DIR__ . '/includes/logging/BlockLogFormatter.php',
        'BmpHandler' => __DIR__ . '/includes/media/BmpHandler.php',
        'BotPassword' => __DIR__ . '/includes/user/BotPassword.php',
-       'BrokenRedirectsPage' => __DIR__ . '/includes/specials/SpecialBrokenRedirects.php',
        'BufferingStatsdDataFactory' => __DIR__ . '/includes/libs/stats/BufferingStatsdDataFactory.php',
        'CLIParser' => __DIR__ . '/maintenance/parse.php',
        'CSSMin' => __DIR__ . '/includes/libs/CSSMin.php',
@@ -366,7 +364,6 @@ $wgAutoloadLocalClasses = [
        'DateFormats' => __DIR__ . '/maintenance/language/date-formats.php',
        'DateFormatter' => __DIR__ . '/includes/parser/DateFormatter.php',
        'DateFormatterFactory' => __DIR__ . '/includes/parser/DateFormatterFactory.php',
-       'DeadendPagesPage' => __DIR__ . '/includes/specials/SpecialDeadendpages.php',
        'DeduplicateArchiveRevId' => __DIR__ . '/maintenance/deduplicateArchiveRevId.php',
        'DeferrableCallback' => __DIR__ . '/includes/deferred/DeferrableCallback.php',
        'DeferrableUpdate' => __DIR__ . '/includes/deferred/DeferrableUpdate.php',
@@ -388,7 +385,6 @@ $wgAutoloadLocalClasses = [
        'DeletePageJob' => __DIR__ . '/includes/jobqueue/jobs/DeletePageJob.php',
        'DeleteSelfExternals' => __DIR__ . '/maintenance/deleteSelfExternals.php',
        'DeletedContribsPager' => __DIR__ . '/includes/specials/pagers/DeletedContribsPager.php',
-       'DeletedContributionsPage' => __DIR__ . '/includes/specials/SpecialDeletedContributions.php',
        'DependencyWrapper' => __DIR__ . '/includes/cache/dependency/DependencyWrapper.php',
        'DeprecatedGlobal' => __DIR__ . '/includes/DeprecatedGlobal.php',
        'DeprecatedInterfaceFinder' => __DIR__ . '/maintenance/findDeprecated.php',
@@ -414,7 +410,6 @@ $wgAutoloadLocalClasses = [
        'DjVuImage' => __DIR__ . '/includes/media/DjVuImage.php',
        'DnsSrvDiscoverer' => __DIR__ . '/includes/libs/DnsSrvDiscoverer.php',
        'DoubleRedirectJob' => __DIR__ . '/includes/jobqueue/jobs/DoubleRedirectJob.php',
-       'DoubleRedirectsPage' => __DIR__ . '/includes/specials/SpecialDoubleRedirects.php',
        'DummyLinker' => __DIR__ . '/includes/DummyLinker.php',
        'DummySearchIndexFieldDefinition' => __DIR__ . '/includes/search/DummySearchIndexFieldDefinition.php',
        'DummyTermColorer' => __DIR__ . '/maintenance/term/MWTerm.php',
@@ -447,8 +442,6 @@ $wgAutoloadLocalClasses = [
        'EditPage' => __DIR__ . '/includes/EditPage.php',
        'EditWatchlistCheckboxSeriesField' => __DIR__ . '/includes/specials/formfields/EditWatchlistCheckboxSeriesField.php',
        'EditWatchlistNormalHTMLForm' => __DIR__ . '/includes/specials/forms/EditWatchlistNormalHTMLForm.php',
-       'EmailConfirmation' => __DIR__ . '/includes/specials/SpecialConfirmemail.php',
-       'EmailInvalidation' => __DIR__ . '/includes/specials/SpecialEmailInvalidate.php',
        'EmailNotification' => __DIR__ . '/includes/mail/EmailNotification.php',
        'EmaillingJob' => __DIR__ . '/includes/jobqueue/jobs/EmaillingJob.php',
        'EmptyBagOStuff' => __DIR__ . '/includes/libs/objectcache/EmptyBagOStuff.php',
@@ -505,7 +498,6 @@ $wgAutoloadLocalClasses = [
        'FeedItem' => __DIR__ . '/includes/changes/FeedItem.php',
        'FeedUtils' => __DIR__ . '/includes/FeedUtils.php',
        'FetchText' => __DIR__ . '/maintenance/fetchText.php',
-       'FewestrevisionsPage' => __DIR__ . '/includes/specials/SpecialFewestrevisions.php',
        'Field' => __DIR__ . '/includes/libs/rdbms/field/Field.php',
        'File' => __DIR__ . '/includes/filerepo/file/File.php',
        'FileAwareNodeVisitor' => __DIR__ . '/maintenance/findDeprecated.php',
@@ -525,7 +517,6 @@ $wgAutoloadLocalClasses = [
        'FileContentsHasher' => __DIR__ . '/includes/utils/FileContentsHasher.php',
        'FileDeleteForm' => __DIR__ . '/includes/FileDeleteForm.php',
        'FileDependency' => __DIR__ . '/includes/cache/dependency/FileDependency.php',
-       'FileDuplicateSearchPage' => __DIR__ . '/includes/specials/SpecialFileDuplicateSearch.php',
        'FileJournal' => __DIR__ . '/includes/libs/filebackend/filejournal/FileJournal.php',
        'FileOp' => __DIR__ . '/includes/libs/filebackend/fileop/FileOp.php',
        'FileOpBatch' => __DIR__ . '/includes/libs/filebackend/FileOpBatch.php',
@@ -785,14 +776,11 @@ $wgAutoloadLocalClasses = [
        'LinkCache' => __DIR__ . '/includes/cache/LinkCache.php',
        'LinkFilter' => __DIR__ . '/includes/LinkFilter.php',
        'LinkHolderArray' => __DIR__ . '/includes/parser/LinkHolderArray.php',
-       'LinkSearchPage' => __DIR__ . '/includes/specials/SpecialLinkSearch.php',
        'Linker' => __DIR__ . '/includes/Linker.php',
        'LinksDeletionUpdate' => __DIR__ . '/includes/deferred/LinksDeletionUpdate.php',
        'LinksUpdate' => __DIR__ . '/includes/deferred/LinksUpdate.php',
-       'ListDuplicatedFilesPage' => __DIR__ . '/includes/specials/SpecialListDuplicatedFiles.php',
        'ListToggle' => __DIR__ . '/includes/ListToggle.php',
        'ListVariants' => __DIR__ . '/maintenance/language/listVariants.php',
-       'ListredirectsPage' => __DIR__ . '/includes/specials/SpecialListredirects.php',
        'LoadBalancer' => __DIR__ . '/includes/libs/rdbms/loadbalancer/LoadBalancer.php',
        'LoadBalancerSingle' => __DIR__ . '/includes/libs/rdbms/loadbalancer/LoadBalancerSingle.php',
        'LocalFile' => __DIR__ . '/includes/filerepo/file/LocalFile.php',
@@ -818,9 +806,6 @@ $wgAutoloadLocalClasses = [
        'LoggedUpdateMaintenance' => __DIR__ . '/maintenance/Maintenance.php',
        'LoginHelper' => __DIR__ . '/includes/specials/helpers/LoginHelper.php',
        'LoginSignupSpecialPage' => __DIR__ . '/includes/specialpage/LoginSignupSpecialPage.php',
-       'LonelyPagesPage' => __DIR__ . '/includes/specials/SpecialLonelypages.php',
-       'LongPagesPage' => __DIR__ . '/includes/specials/SpecialLongpages.php',
-       'MIMEsearchPage' => __DIR__ . '/includes/specials/SpecialMIMEsearch.php',
        'MSCompoundFileReader' => __DIR__ . '/includes/libs/mime/MSCompoundFileReader.php',
        'MWCallableUpdate' => __DIR__ . '/includes/deferred/MWCallableUpdate.php',
        'MWCallbackStream' => __DIR__ . '/includes/http/MWCallbackStream.php',
@@ -867,7 +852,6 @@ $wgAutoloadLocalClasses = [
        'McrUndoAction' => __DIR__ . '/includes/actions/McrUndoAction.php',
        'MediaHandler' => __DIR__ . '/includes/media/MediaHandler.php',
        'MediaHandlerFactory' => __DIR__ . '/includes/media/MediaHandlerFactory.php',
-       'MediaStatisticsPage' => __DIR__ . '/includes/specials/SpecialMediaStatistics.php',
        'MediaTransformError' => __DIR__ . '/includes/media/MediaTransformError.php',
        'MediaTransformInvalidParametersException' => __DIR__ . '/includes/media/MediaTransformInvalidParametersException.php',
        'MediaTransformOutput' => __DIR__ . '/includes/media/MediaTransformOutput.php',
@@ -1002,13 +986,7 @@ $wgAutoloadLocalClasses = [
        'MigrateUserGroup' => __DIR__ . '/maintenance/migrateUserGroup.php',
        'MimeAnalyzer' => __DIR__ . '/includes/libs/mime/MimeAnalyzer.php',
        'MinifyScript' => __DIR__ . '/maintenance/minify.php',
-       'MostcategoriesPage' => __DIR__ . '/includes/specials/SpecialMostcategories.php',
        'MostimagesPage' => __DIR__ . '/includes/specials/SpecialMostimages.php',
-       'MostinterwikisPage' => __DIR__ . '/includes/specials/SpecialMostinterwikis.php',
-       'MostlinkedCategoriesPage' => __DIR__ . '/includes/specials/SpecialMostlinkedcategories.php',
-       'MostlinkedPage' => __DIR__ . '/includes/specials/SpecialMostlinked.php',
-       'MostlinkedTemplatesPage' => __DIR__ . '/includes/specials/SpecialMostlinkedtemplates.php',
-       'MostrevisionsPage' => __DIR__ . '/includes/specials/SpecialMostrevisions.php',
        'MoveBatch' => __DIR__ . '/maintenance/moveBatch.php',
        'MoveFileOp' => __DIR__ . '/includes/libs/filebackend/fileop/MoveFileOp.php',
        'MoveLogFormatter' => __DIR__ . '/includes/logging/MoveLogFormatter.php',
@@ -1331,7 +1309,6 @@ $wgAutoloadLocalClasses = [
        'SerializedValueContainer' => __DIR__ . '/includes/libs/objectcache/serialized/SerializedValueContainer.php',
        'SevenZipStream' => __DIR__ . '/maintenance/includes/SevenZipStream.php',
        'ShiConverter' => __DIR__ . '/languages/classes/LanguageShi.php',
-       'ShortPagesPage' => __DIR__ . '/includes/specials/SpecialShortpages.php',
        'ShowJobs' => __DIR__ . '/maintenance/showJobs.php',
        'ShowSiteStats' => __DIR__ . '/maintenance/showSiteStats.php',
        'Site' => __DIR__ . '/includes/site/Site.php',
@@ -1358,6 +1335,7 @@ $wgAutoloadLocalClasses = [
        'SpecialAllMessages' => __DIR__ . '/includes/specials/SpecialAllMessages.php',
        'SpecialAllMyUploads' => __DIR__ . '/includes/specials/redirects/SpecialAllMyUploads.php',
        'SpecialAllPages' => __DIR__ . '/includes/specials/SpecialAllPages.php',
+       'SpecialAncientPages' => __DIR__ . '/includes/specials/SpecialAncientPages.php',
        'SpecialApiHelp' => __DIR__ . '/includes/specials/SpecialApiHelp.php',
        'SpecialApiSandbox' => __DIR__ . '/includes/specials/SpecialApiSandbox.php',
        'SpecialAutoblockList' => __DIR__ . '/includes/specials/SpecialAutoblockList.php',
@@ -1366,6 +1344,7 @@ $wgAutoloadLocalClasses = [
        'SpecialBlockList' => __DIR__ . '/includes/specials/SpecialBlockList.php',
        'SpecialBookSources' => __DIR__ . '/includes/specials/SpecialBookSources.php',
        'SpecialBotPasswords' => __DIR__ . '/includes/specials/SpecialBotPasswords.php',
+       'SpecialBrokenRedirects' => __DIR__ . '/includes/specials/SpecialBrokenRedirects.php',
        'SpecialCachedPage' => __DIR__ . '/includes/specials/SpecialCachedPage.php',
        'SpecialCategories' => __DIR__ . '/includes/specials/SpecialCategories.php',
        'SpecialChangeContentModel' => __DIR__ . '/includes/specials/SpecialChangeContentModel.php',
@@ -1373,35 +1352,55 @@ $wgAutoloadLocalClasses = [
        'SpecialChangeEmail' => __DIR__ . '/includes/specials/SpecialChangeEmail.php',
        'SpecialChangePassword' => __DIR__ . '/includes/specials/SpecialChangePassword.php',
        'SpecialComparePages' => __DIR__ . '/includes/specials/SpecialComparePages.php',
+       'SpecialConfirmEmail' => __DIR__ . '/includes/specials/SpecialConfirmEmail.php',
        'SpecialContributions' => __DIR__ . '/includes/specials/SpecialContributions.php',
        'SpecialCreateAccount' => __DIR__ . '/includes/specials/SpecialCreateAccount.php',
+       'SpecialDeadendPages' => __DIR__ . '/includes/specials/SpecialDeadendPages.php',
+       'SpecialDeletedContributions' => __DIR__ . '/includes/specials/SpecialDeletedContributions.php',
        'SpecialDiff' => __DIR__ . '/includes/specials/SpecialDiff.php',
+       'SpecialDoubleRedirects' => __DIR__ . '/includes/specials/SpecialDoubleRedirects.php',
        'SpecialEditTags' => __DIR__ . '/includes/specials/SpecialEditTags.php',
        'SpecialEditWatchlist' => __DIR__ . '/includes/specials/SpecialEditWatchlist.php',
+       'SpecialEmailInvalidate' => __DIR__ . '/includes/specials/SpecialEmailInvalidate.php',
        'SpecialEmailUser' => __DIR__ . '/includes/specials/SpecialEmailUser.php',
        'SpecialExpandTemplates' => __DIR__ . '/includes/specials/SpecialExpandTemplates.php',
        'SpecialExport' => __DIR__ . '/includes/specials/SpecialExport.php',
+       'SpecialFewestRevisions' => __DIR__ . '/includes/specials/SpecialFewestRevisions.php',
+       'SpecialFileDuplicateSearch' => __DIR__ . '/includes/specials/SpecialFileDuplicateSearch.php',
        'SpecialFilepath' => __DIR__ . '/includes/specials/SpecialFilepath.php',
        'SpecialGoToInterwiki' => __DIR__ . '/includes/specials/SpecialGoToInterwiki.php',
        'SpecialImport' => __DIR__ . '/includes/specials/SpecialImport.php',
        'SpecialJavaScriptTest' => __DIR__ . '/includes/specials/SpecialJavaScriptTest.php',
        'SpecialLinkAccounts' => __DIR__ . '/includes/specials/SpecialLinkAccounts.php',
+       'SpecialLinkSearch' => __DIR__ . '/includes/specials/SpecialLinkSearch.php',
        'SpecialListAdmins' => __DIR__ . '/includes/specials/redirects/SpecialListAdmins.php',
        'SpecialListBots' => __DIR__ . '/includes/specials/redirects/SpecialListBots.php',
+       'SpecialListDuplicatedFiles' => __DIR__ . '/includes/specials/SpecialListDuplicatedFiles.php',
        'SpecialListFiles' => __DIR__ . '/includes/specials/SpecialListFiles.php',
        'SpecialListGrants' => __DIR__ . '/includes/specials/SpecialListGrants.php',
        'SpecialListGroupRights' => __DIR__ . '/includes/specials/SpecialListGroupRights.php',
+       'SpecialListRedirects' => __DIR__ . '/includes/specials/SpecialListRedirects.php',
        'SpecialListUsers' => __DIR__ . '/includes/specials/SpecialListUsers.php',
        'SpecialLockdb' => __DIR__ . '/includes/specials/SpecialLockdb.php',
        'SpecialLog' => __DIR__ . '/includes/specials/SpecialLog.php',
+       'SpecialLonelyPages' => __DIR__ . '/includes/specials/SpecialLonelyPages.php',
+       'SpecialLongPages' => __DIR__ . '/includes/specials/SpecialLongPages.php',
+       'SpecialMIMESearch' => __DIR__ . '/includes/specials/SpecialMIMESearch.php',
+       'SpecialMediaStatistics' => __DIR__ . '/includes/specials/SpecialMediaStatistics.php',
        'SpecialMergeHistory' => __DIR__ . '/includes/specials/SpecialMergeHistory.php',
+       'SpecialMostCategories' => __DIR__ . '/includes/specials/SpecialMostCategories.php',
+       'SpecialMostInterwikis' => __DIR__ . '/includes/specials/SpecialMostInterwikis.php',
+       'SpecialMostLinked' => __DIR__ . '/includes/specials/SpecialMostLinked.php',
+       'SpecialMostLinkedCategories' => __DIR__ . '/includes/specials/SpecialMostLinkedCategories.php',
+       'SpecialMostLinkedTemplates' => __DIR__ . '/includes/specials/SpecialMostLinkedTemplates.php',
+       'SpecialMostRevisions' => __DIR__ . '/includes/specials/SpecialMostRevisions.php',
        'SpecialMute' => __DIR__ . '/includes/specials/SpecialMute.php',
        'SpecialMyLanguage' => __DIR__ . '/includes/specials/SpecialMyLanguage.php',
        'SpecialMycontributions' => __DIR__ . '/includes/specials/redirects/SpecialMycontributions.php',
        'SpecialMypage' => __DIR__ . '/includes/specials/redirects/SpecialMypage.php',
        'SpecialMytalk' => __DIR__ . '/includes/specials/redirects/SpecialMytalk.php',
        'SpecialMyuploads' => __DIR__ . '/includes/specials/redirects/SpecialMyuploads.php',
-       'SpecialNewFiles' => __DIR__ . '/includes/specials/SpecialNewimages.php',
+       'SpecialNewFiles' => __DIR__ . '/includes/specials/SpecialNewFiles.php',
        'SpecialNewSection' => __DIR__ . '/includes/specials/SpecialNewSection.php',
        'SpecialNewpages' => __DIR__ . '/includes/specials/SpecialNewpages.php',
        'SpecialPage' => __DIR__ . '/includes/specialpage/SpecialPage.php',
@@ -1429,22 +1428,34 @@ $wgAutoloadLocalClasses = [
        'SpecialRevisionDelete' => __DIR__ . '/includes/specials/SpecialRevisionDelete.php',
        'SpecialRunJobs' => __DIR__ . '/includes/specials/SpecialRunJobs.php',
        'SpecialSearch' => __DIR__ . '/includes/specials/SpecialSearch.php',
+       'SpecialShortPages' => __DIR__ . '/includes/specials/SpecialShortPages.php',
        'SpecialSpecialpages' => __DIR__ . '/includes/specials/SpecialSpecialpages.php',
        'SpecialStatistics' => __DIR__ . '/includes/specials/SpecialStatistics.php',
        'SpecialTags' => __DIR__ . '/includes/specials/SpecialTags.php',
        'SpecialTrackingCategories' => __DIR__ . '/includes/specials/SpecialTrackingCategories.php',
        'SpecialUnblock' => __DIR__ . '/includes/specials/SpecialUnblock.php',
+       'SpecialUncategorizedCategories' => __DIR__ . '/includes/specials/SpecialUncategorizedCategories.php',
+       'SpecialUncategorizedImages' => __DIR__ . '/includes/specials/SpecialUncategorizedImages.php',
+       'SpecialUncategorizedPages' => __DIR__ . '/includes/specials/SpecialUncategorizedPages.php',
+       'SpecialUncategorizedTemplates' => __DIR__ . '/includes/specials/SpecialUncategorizedTemplates.php',
        'SpecialUndelete' => __DIR__ . '/includes/specials/SpecialUndelete.php',
        'SpecialUnlinkAccounts' => __DIR__ . '/includes/specials/SpecialUnlinkAccounts.php',
        'SpecialUnlockdb' => __DIR__ . '/includes/specials/SpecialUnlockdb.php',
+       'SpecialUnusedCategories' => __DIR__ . '/includes/specials/SpecialUnusedCategories.php',
+       'SpecialUnusedImages' => __DIR__ . '/includes/specials/SpecialUnusedImages.php',
+       'SpecialUnusedTemplates' => __DIR__ . '/includes/specials/SpecialUnusedTemplates.php',
+       'SpecialUnwatchedPages' => __DIR__ . '/includes/specials/SpecialUnwatchedPages.php',
        'SpecialUpload' => __DIR__ . '/includes/specials/SpecialUpload.php',
        'SpecialUploadStash' => __DIR__ . '/includes/specials/SpecialUploadStash.php',
        'SpecialUploadStashTooLargeException' => __DIR__ . '/includes/specials/exception/SpecialUploadStashTooLargeException.php',
        'SpecialUserLogin' => __DIR__ . '/includes/specials/SpecialUserLogin.php',
        'SpecialUserLogout' => __DIR__ . '/includes/specials/SpecialUserLogout.php',
        'SpecialVersion' => __DIR__ . '/includes/specials/SpecialVersion.php',
+       'SpecialWantedCategories' => __DIR__ . '/includes/specials/SpecialWantedCategories.php',
+       'SpecialWantedTemplates' => __DIR__ . '/includes/specials/SpecialWantedTemplates.php',
        'SpecialWatchlist' => __DIR__ . '/includes/specials/SpecialWatchlist.php',
        'SpecialWhatLinksHere' => __DIR__ . '/includes/specials/SpecialWhatLinksHere.php',
+       'SpecialWithoutInterwiki' => __DIR__ . '/includes/specials/SpecialWithoutInterwiki.php',
        'SqlBagOStuff' => __DIR__ . '/includes/objectcache/SqlBagOStuff.php',
        'SqlSearchResult' => __DIR__ . '/includes/search/SqlSearchResult.php',
        'SqlSearchResultSet' => __DIR__ . '/includes/search/SqlSearchResultSet.php',
@@ -1517,10 +1528,6 @@ $wgAutoloadLocalClasses = [
        'UDPTransport' => __DIR__ . '/includes/libs/UDPTransport.php',
        'UIDGenerator' => __DIR__ . '/includes/utils/UIDGenerator.php',
        'UcdXmlReader' => __DIR__ . '/maintenance/language/generateCollationData.php',
-       'UncategorizedCategoriesPage' => __DIR__ . '/includes/specials/SpecialUncategorizedcategories.php',
-       'UncategorizedImagesPage' => __DIR__ . '/includes/specials/SpecialUncategorizedimages.php',
-       'UncategorizedPagesPage' => __DIR__ . '/includes/specials/SpecialUncategorizedpages.php',
-       'UncategorizedTemplatesPage' => __DIR__ . '/includes/specials/SpecialUncategorizedtemplates.php',
        'Undelete' => __DIR__ . '/maintenance/undelete.php',
        'UnifiedDiffFormatter' => __DIR__ . '/includes/diff/UnifiedDiffFormatter.php',
        'UnknownContent' => __DIR__ . '/includes/content/UnknownContent.php',
@@ -1529,11 +1536,7 @@ $wgAutoloadLocalClasses = [
        'UnprotectAction' => __DIR__ . '/includes/actions/UnprotectAction.php',
        'UnregisteredLocalFile' => __DIR__ . '/includes/filerepo/file/UnregisteredLocalFile.php',
        'UnsupportedSlotDiffRenderer' => __DIR__ . '/includes/diff/UnsupportedSlotDiffRenderer.php',
-       'UnusedCategoriesPage' => __DIR__ . '/includes/specials/SpecialUnusedcategories.php',
-       'UnusedimagesPage' => __DIR__ . '/includes/specials/SpecialUnusedimages.php',
-       'UnusedtemplatesPage' => __DIR__ . '/includes/specials/SpecialUnusedtemplates.php',
        'UnwatchAction' => __DIR__ . '/includes/actions/UnwatchAction.php',
-       'UnwatchedpagesPage' => __DIR__ . '/includes/specials/SpecialUnwatchedpages.php',
        'UpdateArticleCount' => __DIR__ . '/maintenance/updateArticleCount.php',
        'UpdateCollation' => __DIR__ . '/maintenance/updateCollation.php',
        'UpdateDoubleWidthSearch' => __DIR__ . '/maintenance/updateDoubleWidthSearch.php',
@@ -1597,11 +1600,9 @@ $wgAutoloadLocalClasses = [
        'WANCacheReapUpdate' => __DIR__ . '/includes/deferred/WANCacheReapUpdate.php',
        'WANObjectCache' => __DIR__ . '/includes/libs/objectcache/wancache/WANObjectCache.php',
        'WANObjectCacheReaper' => __DIR__ . '/includes/libs/objectcache/wancache/WANObjectCacheReaper.php',
-       'WantedCategoriesPage' => __DIR__ . '/includes/specials/SpecialWantedcategories.php',
        'WantedFilesPage' => __DIR__ . '/includes/specials/SpecialWantedfiles.php',
        'WantedPagesPage' => __DIR__ . '/includes/specials/SpecialWantedpages.php',
        'WantedQueryPage' => __DIR__ . '/includes/specialpage/WantedQueryPage.php',
-       'WantedTemplatesPage' => __DIR__ . '/includes/specials/SpecialWantedtemplates.php',
        'WatchAction' => __DIR__ . '/includes/actions/WatchAction.php',
        'WatchedItem' => __DIR__ . '/includes/watcheditem/WatchedItem.php',
        'WatchedItemQueryService' => __DIR__ . '/includes/watcheditem/WatchedItemQueryService.php',
@@ -1705,7 +1706,6 @@ $wgAutoloadLocalClasses = [
        'WikitextContentHandler' => __DIR__ . '/includes/content/WikitextContentHandler.php',
        'WikitextLogFormatter' => __DIR__ . '/includes/logging/WikitextLogFormatter.php',
        'WinCacheBagOStuff' => __DIR__ . '/includes/libs/objectcache/WinCacheBagOStuff.php',
-       'WithoutInterwikiPage' => __DIR__ . '/includes/specials/SpecialWithoutinterwiki.php',
        'WordLevelDiff' => __DIR__ . '/includes/diff/WordLevelDiff.php',
        'WrapOldPasswords' => __DIR__ . '/maintenance/wrapOldPasswords.php',
        'XCFHandler' => __DIR__ . '/includes/media/XCFHandler.php',
index 43234c6..43bfd8d 100644 (file)
@@ -1585,7 +1585,8 @@ entitled to be in.
 $user: user to promote.
 &$promote: groups that will be added.
 
-'GetBlockedStatus': after loading blocking status of an user from the database
+'GetBlockedStatus': DEPRECATED since 1.34 - use GetUserBlock instead. After
+loading blocking status of a user from the database
 &$user: user (object) being checked
 
 'GetCacheVaryCookies': Get cookies that should vary cache options.
index f6ac342..c9bed29 100644 (file)
@@ -4888,6 +4888,7 @@ $wgDefaultUserOptions = [
        'wllimit' => 250,
        'useeditwarning' => 1,
        'prefershttps' => 1,
+       'requireemail' => 0,
 ];
 
 /**
@@ -4957,6 +4958,15 @@ $wgSessionProviders = [
        ],
 ];
 
+/**
+ * Temporary feature flag that controls whether users will see a checkbox allowing them to
+ * require providing email during password resets.
+ *
+ * @deprecated This feature is under development, don't assume this flag's existence or function
+ *     outside of MediaWiki.
+ */
+$wgAllowRequiringEmailForResets = false;
+
 /** @} */ # end user accounts }
 
 /************************************************************************//**
index 564c8f4..634e7af 100644 (file)
@@ -473,6 +473,7 @@ class MovePage {
 
                        $mp = new MovePage( $oldSubpage, $newSubpage );
                        $method = $checkPermissions ? 'moveIfAllowed' : 'move';
+                       /** @var Status $status */
                        $status = $mp->$method( $user, $reason, $createRedirect, $changeTags );
                        if ( $status->isOK() ) {
                                $status->setResult( true, $newSubpage->getPrefixedText() );
@@ -508,7 +509,7 @@ class MovePage {
 
                Hooks::run( 'TitleMoveStarting', [ $this->oldTitle, $this->newTitle, $user ] );
 
-               $pageid = $this->oldTitle->getArticleID( Title::GAID_FOR_UPDATE );
+               $pageid = $this->oldTitle->getArticleID( Title::READ_LATEST );
                $protected = $this->oldTitle->isProtected();
 
                // Do the actual move; if this fails, it will throw an MWException(!)
index 292d6ba..828f647 100644 (file)
@@ -1005,7 +1005,7 @@ class Revision implements IDBAccessObject {
 
                $comment = CommentStoreComment::newUnsavedComment( $summary, null );
 
-               $title = Title::newFromID( $pageId, Title::GAID_FOR_UPDATE );
+               $title = Title::newFromID( $pageId, Title::READ_LATEST );
                if ( $title === null ) {
                        return null;
                }
index 73f622a..735a212 100644 (file)
@@ -326,10 +326,10 @@ class RevisionStore
 
                $canUseTitleNewFromId = ( $pageId !== null && $pageId > 0 && $this->dbDomain === false );
                list( $dbMode, $dbOptions ) = DBAccessObjectUtils::getDBOptions( $queryFlags );
-               $titleFlags = ( $dbMode == DB_MASTER ? Title::GAID_FOR_UPDATE : 0 );
 
                // Loading by ID is best, but Title::newFromID does not support that for foreign IDs.
                if ( $canUseTitleNewFromId ) {
+                       $titleFlags = ( $dbMode == DB_MASTER ? Title::READ_LATEST : 0 );
                        // TODO: better foreign title handling (introduce TitleFactory)
                        $title = Title::newFromID( $pageId, $titleFlags );
                        if ( $title ) {
index 39f0c81..518531a 100644 (file)
@@ -808,22 +808,17 @@ if ( !defined( 'MW_NO_SESSION' ) && !$wgCommandLineMode ) {
        // Initialize the session
        try {
                $session = MediaWiki\Session\SessionManager::getGlobalSession();
-       } catch ( OverflowException $ex ) {
-               if ( isset( $ex->sessionInfos ) && count( $ex->sessionInfos ) >= 2 ) {
-                       // The exception is because the request had multiple possible
-                       // sessions tied for top priority. Report this to the user.
-                       $list = [];
-                       foreach ( $ex->sessionInfos as $info ) {
-                               $list[] = $info->getProvider()->describe( $wgContLang );
-                       }
-                       $list = $wgContLang->listToText( $list );
-                       throw new HttpError( 400,
-                               Message::newFromKey( 'sessionmanager-tie', $list )->inLanguage( $wgContLang )->plain()
-                       );
+       } catch ( MediaWiki\Session\SessionOverflowException $ex ) {
+               // The exception is because the request had multiple possible
+               // sessions tied for top priority. Report this to the user.
+               $list = [];
+               foreach ( $ex->getSessionInfos() as $info ) {
+                       $list[] = $info->getProvider()->describe( $wgContLang );
                }
-
-               // Not the one we want, rethrow
-               throw $ex;
+               $list = $wgContLang->listToText( $list );
+               throw new HttpError( 400,
+                       Message::newFromKey( 'sessionmanager-tie', $list )->inLanguage( $wgContLang )->plain()
+               );
        }
 
        if ( $session->isPersistent() ) {
index d2bbe7b..7e9f56d 100644 (file)
@@ -93,7 +93,7 @@ class ApiSetNotificationTimestamp extends ApiBase {
                        $titles = $pageSet->getGoodTitles();
                        $title = reset( $titles );
                        if ( $title ) {
-                               $revid = $title->getNextRevisionID( $params['newerthanrevid'], Title::GAID_FOR_UPDATE );
+                               $revid = $title->getNextRevisionID( $params['newerthanrevid'], Title::READ_LATEST );
                                if ( $revid ) {
                                        $timestamp = $dbw->timestamp(
                                                MediaWikiServices::getInstance()->getRevisionStore()->getTimestampFromId( $title, $revid )
index dc9c516..09d9c46 100644 (file)
        "apierror-cantoverwrite-sharedfile": "الملف الهدف موجود في مستودع مشترك وليست لديك صلاحية لتجاوزه.",
        "apierror-cantsend": "لم تقم بتسجيل الدخول أو ليس لديك عنوان بريد إلكتروني مؤكد أو غير مسموح لك بإرسال بريد إلكتروني إلى مستخدمين آخرين; لذلك لا يمكنك إرسال بريد إلكتروني.",
        "apierror-cantundelete": "تعذر الاسترجاع: قد لا تكون المراجعات المطلوبة موجودة، أو ربما تم الاسترجاع بالفعل.",
+       "apierror-cantview-deleted-description": "ليست لديك صلايبة لعرض أوصاف الملفات المحذوفة.",
+       "apierror-cantview-deleted-metadata": "ليست لديك صلايبة لعرض البيانات الوصفية للملفات المحذوفة.",
        "apierror-changeauth-norequest": "فشل في إنشاء طلب التغيير.",
        "apierror-chunk-too-small": "الحد الأدنى لحجم القطعة هو $1 {{PLURAL:$1|بايت}} للقطع غير النهائية.",
        "apierror-cidrtoobroad": "لا يُقبَل مدى $1 CIDR أكبر من /$2.",
index 628edfa..7c5d2b5 100644 (file)
        "apierror-cantoverwrite-sharedfile": "Le fichier cible existe dans un dépôt partagé et vous n’avez pas le droit de l’écraser.",
        "apierror-cantsend": "Vous n’êtes pas connecté, vous n’avez pas d’adresse de courriel confirmée, ou vous n’êtes pas autorisé à envoyer des courriels aux autres utilisateurs, donc vous ne pouvez envoyer de courriel.",
        "apierror-cantundelete": "Impossible d’annuler : les révisions demandées peuvent ne plus exister, ou avoir déjà été annulées.",
+       "apierror-cantview-deleted-description": "Vous n’avez pas le droit d’afficher les descriptions des fichiers supprimés.",
+       "apierror-cantview-deleted-metadata": "Vous n’avez pas le droit d’afficher les métadonnées des fichiers supprimés.",
        "apierror-changeauth-norequest": "Échec à la création de la requête de modification.",
        "apierror-chunk-too-small": "La taille minimale d’un segment est de $1 {{PLURAL:$1|octet|octets}} pour les segments hors le dernier.",
        "apierror-cidrtoobroad": "Les plages CIDR $1 plus large que /$2 ne sont pas acceptées.",
index e71a9dc..d8ff539 100644 (file)
@@ -17,7 +17,8 @@
                        "InternerowyGołąb",
                        "CiaPan",
                        "Vlad5250",
-                       "Railfail536"
+                       "Railfail536",
+                       "Rail"
                ]
        },
        "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Dokumentacja]]\n* [[mw:Special:MyLanguage/API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Lista dyskusyjna]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Ogłoszenia dotyczące API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Błędy i propozycje]\n</div>\n<strong>Stan:</strong> Wszystkie funkcje opisane na tej stronie powinny działać, ale API nadal jest aktywnie rozwijane i mogą się zmienić w dowolnym czasie. Subskrybuj [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ listę dyskusyjną mediawiki-api-announce], aby móc na bieżąco dowiadywać się o aktualizacjach.\n\n<strong>Błędne żądania:</strong> Gdy zostanie wysłane błędne żądanie do API, zostanie wysłany w odpowiedzi nagłówek HTTP z kluczem \"MediaWiki-API-Error\" i zarówno jego wartość jak i wartość kodu błędu wysłanego w odpowiedzi będą miały taką samą wartość. Aby uzyskać więcej informacji, zobacz [[mw:Special:MyLanguage/API:Errors_and_warnings|API: Błędy i ostrzeżenia]].\n\n<strong>Testowanie:</strong> Aby łatwo testować żądania API, zobacz [[Special:ApiSandbox]].",
        "apierror-cantimport": "Nie masz uprawnień do importowania stron.",
        "apierror-cantsend": "Nie jesteś zalogowany, nie masz potwierdzonego adresu e-mail, albo nie masz prawa wysyłać e-maili do innych użytkowników, więc nie możesz wysłać wiadomości e-mail.",
        "apierror-cantundelete": "Nie można przywrócić: dana wersja nie istnieje albo została już przywrócona.",
+       "apierror-cantview-deleted-description": "Nie masz uprawnień do podglądu opisów usuniętych plików.",
+       "apierror-cantview-deleted-metadata": "Nie masz uprawnień do podglądu metadanych usuniętych plików.",
        "apierror-exceptioncaught": "[$1] Stwierdzono wyjątek: $2",
        "apierror-filedoesnotexist": "Plik nie istnieje.",
        "apierror-import-unknownerror": "Nieznany błąd podczas importowania: $1.",
index 14a7717..7ee3751 100644 (file)
        "apierror-cantoverwrite-sharedfile": "目標檔案存在於分享儲存庫上,因此您沒有權限來覆蓋掉。",
        "apierror-cantsend": "您尚未登入,您沒有已確認的電子郵件地址,或是您未被允許發送電子郵件給其他人,因此您不能發送電子郵件。",
        "apierror-cantundelete": "無法取消刪除:請求的修訂可能不存在,或是可能已被取消刪除。",
+       "apierror-cantview-deleted-description": "您沒有權限來檢視被刪除檔案的描述內容。",
+       "apierror-cantview-deleted-metadata": "您沒有權限來檢視被刪除檔案的詮釋資料。",
        "apierror-changeauth-norequest": "建立更改請求失敗。",
        "apierror-chunk-too-small": "對於非最終塊,最小塊的大小為 $1 {{PLURAL:$1|位元組|位元組}}。",
        "apierror-cidrtoobroad": "不能接受超出 /$2 的 $1 CIDR 範圍。",
index 8018117..b2f2452 100644 (file)
@@ -89,6 +89,7 @@ class LinkCache {
         *
         * @param bool|null $update
         * @return bool
+        * @deprecated Since 1.34
         */
        public function forUpdate( $update = null ) {
                return wfSetVar( $this->mForUpdate, $update );
index 88a7042..a79325a 100644 (file)
@@ -27,18 +27,20 @@ use Wikimedia\Rdbms\DBQueryError;
  * This will work on any MediaWiki installation.
  */
 class LCStoreDB implements LCStore {
-       /** @var string */
-       private $currentLang;
-       /** @var bool */
-       private $writesDone = false;
+       /** @var string Language code */
+       private $code;
+       /** @var array Server configuration map */
+       private $server;
+
+       /** @var array Rows buffered for insertion */
+       private $batch = [];
+
        /** @var IDatabase|null */
        private $dbw;
-       /** @var array */
-       private $batch = [];
-       /** @var bool */
+       /** @var bool Whether a batch of writes were recently written */
+       private $writesDone = false;
+       /** @var bool Whether the DB is read-only or otherwise unavailable for writes */
        private $readOnly = false;
-       /** @var array Server configuration map */
-       private $server;
 
        public function __construct( $params ) {
                $this->server = $params['server'] ?? [];
@@ -74,14 +76,14 @@ class LCStoreDB implements LCStore {
                $dbw = $this->getWriteConnection();
                $this->readOnly = $dbw->isReadOnly();
 
-               $this->currentLang = $code;
+               $this->code = $code;
                $this->batch = [];
        }
 
        public function finishWrite() {
                if ( $this->readOnly ) {
                        return;
-               } elseif ( is_null( $this->currentLang ) ) {
+               } elseif ( is_null( $this->code ) ) {
                        throw new MWException( __CLASS__ . ': must call startWrite() before finishWrite()' );
                }
 
@@ -91,7 +93,7 @@ class LCStoreDB implements LCStore {
                        $dbw = $this->getWriteConnection();
                        $dbw->startAtomic( __METHOD__ );
                        try {
-                               $dbw->delete( 'l10n_cache', [ 'lc_lang' => $this->currentLang ], __METHOD__ );
+                               $dbw->delete( 'l10n_cache', [ 'lc_lang' => $this->code ], __METHOD__ );
                                foreach ( array_chunk( $this->batch, 500 ) as $rows ) {
                                        $dbw->insert( 'l10n_cache', $rows, __METHOD__ );
                                }
@@ -108,21 +110,21 @@ class LCStoreDB implements LCStore {
                        $trxProfiler->setSilenced( $oldSilenced );
                }
 
-               $this->currentLang = null;
+               $this->code = null;
                $this->batch = [];
        }
 
        public function set( $key, $value ) {
                if ( $this->readOnly ) {
                        return;
-               } elseif ( is_null( $this->currentLang ) ) {
+               } elseif ( is_null( $this->code ) ) {
                        throw new MWException( __CLASS__ . ': must call startWrite() before set()' );
                }
 
                $dbw = $this->getWriteConnection();
 
                $this->batch[] = [
-                       'lc_lang' => $this->currentLang,
+                       'lc_lang' => $this->code,
                        'lc_key' => $key,
                        'lc_value' => $dbw->encodeBlob( serialize( $value ) )
                ];
index 74e236f..8345ee6 100644 (file)
@@ -125,7 +125,7 @@ class LinksUpdate extends DataUpdate {
 
                if ( !$this->mId ) {
                        // NOTE: subclasses may initialize mId before calling this constructor!
-                       $this->mId = $title->getArticleID( Title::GAID_FOR_UPDATE );
+                       $this->mId = $title->getArticleID( Title::READ_LATEST );
                }
 
                if ( !$this->mId ) {
index 4db351b..264eabc 100644 (file)
@@ -26,6 +26,7 @@ use Wikimedia\Rdbms\IDatabase;
 use Wikimedia\Rdbms\DBConnRef;
 use Wikimedia\Rdbms\MaintainableDBConnRef;
 use Wikimedia\Rdbms\DatabaseDomain;
+use Wikimedia\Rdbms\DBUnexpectedError;
 
 /**
  * DB accessible external objects.
@@ -113,7 +114,11 @@ class ExternalStoreDB extends ExternalStoreMedium {
         */
        public function store( $location, $data ) {
                $dbw = $this->getMaster( $location );
-               $dbw->insert( $this->getTable( $dbw ), [ 'blob_text' => $data ], __METHOD__ );
+               $dbw->insert(
+                       $this->getTable( $dbw, $location ),
+                       [ 'blob_text' => $data ],
+                       __METHOD__
+               );
                $id = $dbw->insertId();
                if ( !$id ) {
                        throw new MWException( __METHOD__ . ': no insert ID' );
@@ -149,10 +154,11 @@ class ExternalStoreDB extends ExternalStoreMedium {
        /**
         * Get a replica DB connection for the specified cluster
         *
+        * @since 1.34
         * @param string $cluster Cluster name
         * @return DBConnRef
         */
-       public function getSlave( $cluster ) {
+       public function getReplica( $cluster ) {
                $lb = $this->getLoadBalancer( $cluster );
 
                return $lb->getConnectionRef(
@@ -163,6 +169,17 @@ class ExternalStoreDB extends ExternalStoreMedium {
                );
        }
 
+       /**
+        * Get a replica DB connection for the specified cluster
+        *
+        * @param string $cluster Cluster name
+        * @return DBConnRef
+        * @deprecated since 1.34
+        */
+       public function getSlave( $cluster ) {
+               return $this->getReplica( $cluster );
+       }
+
        /**
         * Get a master database connection for the specified cluster
         *
@@ -211,15 +228,55 @@ class ExternalStoreDB extends ExternalStoreMedium {
         * Get the 'blobs' table name for this database
         *
         * @param IDatabase $db
+        * @param string|null $cluster Cluster name
         * @return string Table name ('blobs' by default)
         */
-       public function getTable( $db ) {
-               $table = $db->getLBInfo( 'blobs table' );
-               if ( is_null( $table ) ) {
-                       $table = 'blobs';
+       public function getTable( $db, $cluster = null ) {
+               if ( $cluster !== null ) {
+                       $lb = $this->getLoadBalancer( $cluster );
+                       $info = $lb->getServerInfo( $lb->getWriterIndex() );
+                       if ( isset( $info['blobs table'] ) ) {
+                               return $info['blobs table'];
+                       }
                }
 
-               return $table;
+               return $db->getLBInfo( 'blobs table' ) ?? 'blobs'; // b/c
+       }
+
+       /**
+        * Create the appropriate blobs table on this cluster
+        *
+        * @see getTable()
+        * @since 1.34
+        * @param string $cluster
+        */
+       public function initializeTable( $cluster ) {
+               global $IP;
+
+               static $supportedTypes = [ 'mysql', 'sqlite' ];
+
+               $dbw = $this->getMaster( $cluster );
+               if ( !in_array( $dbw->getType(), $supportedTypes, true ) ) {
+                       throw new DBUnexpectedError( $dbw, "RDBMS type '{$dbw->getType()}' not supported." );
+               }
+
+               $sqlFilePath = "$IP/maintenance/storage/blobs.sql";
+               $sql = file_get_contents( $sqlFilePath );
+               if ( $sql === false ) {
+                       throw new RuntimeException( "Failed to read '$sqlFilePath'." );
+               }
+
+               $rawTable = $this->getTable( $dbw, $cluster ); // e.g. "blobs_cluster23"
+               $encTable = $dbw->tableName( $rawTable );
+               $dbw->query(
+                       str_replace(
+                               [ '/*$wgDBprefix*/blobs', '/*_*/blobs' ],
+                               [ $encTable, $encTable ],
+                               $sql
+                       ),
+                       __METHOD__,
+                       $dbw::QUERY_IGNORE_DBO_TRX
+               );
        }
 
        /**
@@ -251,15 +308,23 @@ class ExternalStoreDB extends ExternalStoreMedium {
 
                $this->logger->debug( "ExternalStoreDB::fetchBlob cache miss on $cacheID" );
 
-               $dbr = $this->getSlave( $cluster );
-               $ret = $dbr->selectField( $this->getTable( $dbr ),
-                       'blob_text', [ 'blob_id' => $id ], __METHOD__ );
+               $dbr = $this->getReplica( $cluster );
+               $ret = $dbr->selectField(
+                       $this->getTable( $dbr, $cluster ),
+                       'blob_text',
+                       [ 'blob_id' => $id ],
+                       __METHOD__
+               );
                if ( $ret === false ) {
                        $this->logger->info( "ExternalStoreDB::fetchBlob master fallback on $cacheID" );
                        // Try the master
                        $dbw = $this->getMaster( $cluster );
-                       $ret = $dbw->selectField( $this->getTable( $dbw ),
-                               'blob_text', [ 'blob_id' => $id ], __METHOD__ );
+                       $ret = $dbw->selectField(
+                               $this->getTable( $dbw, $cluster ),
+                               'blob_text',
+                               [ 'blob_id' => $id ],
+                               __METHOD__
+                       );
                        if ( $ret === false ) {
                                $this->logger->error( "ExternalStoreDB::fetchBlob master failed to find $cacheID" );
                        }
@@ -283,9 +348,9 @@ class ExternalStoreDB extends ExternalStoreMedium {
         *   Unlocated ids are not represented
         */
        private function batchFetchBlobs( $cluster, array $ids ) {
-               $dbr = $this->getSlave( $cluster );
+               $dbr = $this->getReplica( $cluster );
                $res = $dbr->select(
-                       $this->getTable( $dbr ),
+                       $this->getTable( $dbr, $cluster ),
                        [ 'blob_id', 'blob_text' ],
                        [ 'blob_id' => array_keys( $ids ) ],
                        __METHOD__
@@ -302,7 +367,8 @@ class ExternalStoreDB extends ExternalStoreMedium {
                        );
                        // Try the master
                        $dbw = $this->getMaster( $cluster );
-                       $res = $dbw->select( $this->getTable( $dbr ),
+                       $res = $dbw->select(
+                               $this->getTable( $dbr, $cluster ),
                                [ 'blob_id', 'blob_text' ],
                                [ 'blob_id' => array_keys( $ids ) ],
                                __METHOD__ );
index eae79b0..e5ebb42 100644 (file)
        "config-restart": "Si, reinitia lo",
        "config-welcome": "=== Verificationes del ambiente ===\nVerificationes de base essera ora exequite pro determinar si iste ambiente es apte pro le installation de MediaWiki.\nNon oblida de includer iste information si tu cerca adjuta pro completar le installation.",
        "config-welcome-section-copyright": "=== Copyright and Terms ===\n\n$1\n\nIste programma es software libere; vos pote redistribuer lo e/o modificar lo sub le conditiones del Licentia Public General de GNU publicate per le Free Software Foundation; version 2 del Licentia, o (a vostre option) qualcunque version posterior.\n\nIste programma es distribuite in le sperantia que illo sia utile, ma '''sin garantia''', sin mesmo le implicite garantia de '''commercialisation''' o '''aptitude pro un proposito particular'''.\nVide le Licentia Public General de GNU pro plus detalios.\n\nVos deberea haber recipite [$2 un exemplar del Licentia Public General de GNU] con iste programma; si non, scribe al Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA, o [https://www.gnu.org/copyleft/gpl.html lege lo in linea].",
-       "config-sidebar": "* [https://www.mediawiki.org Pagina principal de MediaWiki]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Guida pro usatores]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents Guida pro administratores]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ FAQ]\n----\n* <doclink href=Readme>Lege me</doclink>\n* <doclink href=ReleaseNotes>Notas de iste version</doclink>\n* <doclink href=Copying>Conditiones de copia</doclink>\n* <doclink href=UpgradeDoc>Actualisation</doclink>",
+       "config-sidebar": "* [https://www.mediawiki.org Pagina principal de MediaWiki]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Guida pro usatores]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents Guida pro administratores]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ FAQ]",
+       "config-sidebar-readme": "Lege me",
+       "config-sidebar-relnotes": "Notas de iste version",
+       "config-sidebar-license": "Conditiones de copia",
+       "config-sidebar-upgrade": "Actualisation",
        "config-env-good": "Le ambiente ha essite verificate.\nTu pote installar MediaWiki.",
        "config-env-bad": "Le ambiente ha essite verificate.\nTu non pote installar MediaWiki.",
        "config-env-php": "PHP $1 es installate.",
@@ -79,7 +83,7 @@
        "config-uploads-not-safe": "'''Aviso:''' Le directorio predefinite pro files incargate <code>$1</code> es vulnerabile al execution arbitrari de scripts.\nBen que MediaWiki verifica tote le files incargate contra le menacias de securitate, il es altemente recommendate [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security#Upload_security remediar iste vulnerabilitate de securitate] ante de activar le incargamento de files.",
        "config-no-cli-uploads-check": "'''Attention:''' Le directorio predefinite pro files incargate (<code>$1</code>) non es verificate contra le vulnerabilitate\nal execution arbitrari de scripts durante le installation de CLI.",
        "config-brokenlibxml": "Vostre systema ha un combination de versiones de PHP e libxml2 que es defectuose e pote causar corruption celate de datos in MediaWiki e altere applicationes web.\nActualisa a libxml2 2.7.3 o plus recente ([https://bugs.php.net/bug.php?id=45996 problema reportate presso PHP]).\nInstallation abortate.",
-       "config-suhosin-max-value-length": "Suhosin es installate e limita parametro <code>length</code> de GET a $1 bytes.\nLe componente ResourceLoader de MediaWiki va contornar iste limite, ma isto prejudicara le rendimento.\nSi possibile, tu deberea mitter <code>suhosin.get.max_value_length</code> a 1024 o superior in <code>php.ini</code>, e mitter <code>$wgResourceLoaderMaxQueryLength</code> al mesme valor in <code>LocalSettings.php</code>.",
+       "config-suhosin-max-value-length": "Suhosin es installate e limita parametro <code>length</code> de GET a $1 bytes.\nMediaWiki require que <code>suhosin.get.max_value_length</code> sia al minus $2. Disactiva iste parametro, o augmenta iste valor a $3 in <code>php.ini</code>.",
        "config-using-32bit": "<strong>Attention:</strong> tu systema pare operar con integres de 32 bits. Isto [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:32-bit non es recommendate].",
        "config-db-type": "Typo de base de datos:",
        "config-db-host": "Servitor de base de datos:",
index 5da1914..511b0da 100644 (file)
        "config-uploads-not-safe": "<strong>警告:</strong> アップロードの既定ディレクトリ <code>$1</code> に、任意のスクリプト実行に関する脆弱性があります。\nMediaWiki はアップロードされたファイルのセキュリティ上の脅威を確認しますが、アップロードを有効化する前に、[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security#Upload_security このセキュリティ上の脆弱性を解決する]ことを強く推奨します。",
        "config-no-cli-uploads-check": "<strong>警告:</strong> アップロード用のデフォルトディレクトリ (<code>$1</code>) が、CLIでのインストール中に任意のスクリプト実行の脆弱性チェックを受けていません。",
        "config-brokenlibxml": "このシステムで使われているPHPとlibxml2のバージョンのこの組み合わせにはバグがあります。具体的には、MediaWikiやその他のウェブアプリケーションでhiddenデータが破損する可能性があります。\nlibxml2を2.7.3以降のバージョンにアップグレードしてください([https://bugs.php.net/bug.php?id=45996 PHPでのバグ情報])。\nインストールを終了します。",
-       "config-suhosin-max-value-length": "Suhosin がインストールされており、GET パラメーターの <code>length</code> を $1 バイトに制限しています。\nMediaWiki の ResourceLoader コンポーネントはこの制限を回避しますが、パフォーマンスは低下します。\n可能な限り、<code>php.ini</code> で <code>suhosin.get.max_value_length</code> を 1024 以上に設定し、同じ値を <code>LocalSettings.php</code> 内で <code>$wgResourceLoaderMaxQueryLength</code> に設定してください。",
+       "config-suhosin-max-value-length": "Suhosin がインストールされており、GET パラメーターの <code>length</code> を $1 バイトに制限しています。(訳注:\nMediaWiki の ResourceLoader コンポーネントはこの制限を回避しますが、パフォーマンスは低下します。)\n可能な限り、 <code>suhosin.get.max_value_length</code> を $2 以上に設定します。これを無効に変更するか、<code>php.ini</code> で $3 に増加してください。",
        "config-using-32bit": "<strong>警告:</strong>システムが32ビットで動作しているようです。 これは[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:32-bit 非推奨]です。",
        "config-db-type": "データベースの種類:",
        "config-db-host": "データベースのホスト:",
index fc66bdb..f3f211e 100644 (file)
@@ -24,7 +24,8 @@
                        "Sethakill",
                        "Peter Bowman",
                        "Ankam",
-                       "Railfail536"
+                       "Railfail536",
+                       "Rail"
                ]
        },
        "config-desc": "Instalator MediaWiki",
index b4046a6..33b05b8 100644 (file)
@@ -276,8 +276,8 @@ class RefreshLinksJob extends Job {
                $title = $page->getTitle();
                // Get the latest ID since acquirePageLock() in runForTitle() flushed the transaction.
                // This is used to detect edits/moves after loadPageData() but before the scope lock.
-               // The works around the chicken/egg problem of determining the scope lock key name.
-               $latest = $title->getLatestRevID( Title::GAID_FOR_UPDATE );
+               // The works around the chicken/egg problem of determining the scope lock key name
+               $latest = $title->getLatestRevID( Title::READ_LATEST );
 
                $triggeringRevisionId = $this->params['triggeringRevisionId'] ?? null;
                if ( $triggeringRevisionId && $triggeringRevisionId !== $latest ) {
index 5534cbd..9ed7ae3 100644 (file)
@@ -556,9 +556,7 @@ class FSFileBackend extends FileBackendStore {
                $contRoot = $this->containerFSRoot( $shortCont, $fullCont ); // must be valid
                $dir = ( $dirRel != '' ) ? "{$contRoot}/{$dirRel}" : $contRoot;
                AtEase::suppressWarnings();
-               if ( is_dir( $dir ) ) {
-                       rmdir( $dir ); // remove directory if empty
-               }
+               rmdir( $dir ); // remove directory if empty
                AtEase::restoreWarnings();
 
                return $status;
index f2c07e8..5caf250 100644 (file)
@@ -1587,7 +1587,7 @@ abstract class FileBackendStore extends FileBackend {
                                // Validate and sanitize the relative path (backend-specific)
                                $relPath = $this->resolveContainerPath( $shortCont, $relPath );
                                if ( $relPath !== null ) {
-                                       // Prepend any wiki ID prefix to the container name
+                                       // Prepend any domain ID prefix to the container name
                                        $container = $this->fullContainerName( $shortCont );
                                        if ( self::isValidContainerName( $container ) ) {
                                                // Validate and sanitize the container name (backend-specific)
@@ -1722,7 +1722,7 @@ abstract class FileBackendStore extends FileBackend {
        }
 
        /**
-        * Get the full container name, including the wiki ID prefix
+        * Get the full container name, including the domain ID prefix
         *
         * @param string $container
         * @return string
index c366a0f..8697f9f 100644 (file)
@@ -34,8 +34,8 @@ abstract class FileBackendStoreOpHandle {
        public $backend;
        /** @var array */
        public $resourcesToClose = [];
-
-       public $call; // string; name that identifies the function called
+       /** @var callable name that identifies the function called */
+       public $call;
 
        /**
         * Close all open file handles
index c167f3a..bad75da 100644 (file)
@@ -726,7 +726,7 @@ class WikiPage implements Page, IDBAccessObject {
                // Try using the replica DB first, then try the master
                $rev = $this->mTitle->getFirstRevision();
                if ( !$rev ) {
-                       $rev = $this->mTitle->getFirstRevision( Title::GAID_FOR_UPDATE );
+                       $rev = $this->mTitle->getFirstRevision( Title::READ_LATEST );
                }
                return $rev;
        }
index 8a82add..66c2bc3 100644 (file)
@@ -84,6 +84,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
         * @since 1.34
         */
        public static $constructorOptions = [
+               'AllowRequiringEmailForResets',
                'AllowUserCss',
                'AllowUserCssPrefs',
                'AllowUserJs',
@@ -620,6 +621,16 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                                }
                        }
 
+                       if ( $this->options->get( 'AllowRequiringEmailForResets' ) ) {
+                               $defaultPreferences['requireemail'] = [
+                                       'type' => 'toggle',
+                                       'label-message' => 'tog-requireemail',
+                                       'help-message' => 'prefs-help-requireemail',
+                                       'section' => 'personal/email',
+                                       'disabled' => $disableEmailPrefs,
+                               ];
+                       }
+
                        if ( $this->options->get( 'EnableUserEmail' ) && $user->isAllowed( 'sendemail' ) ) {
                                $defaultPreferences['disablemail'] = [
                                        'id' => 'wpAllowEmail',
index 693afcf..4a23eae 100644 (file)
@@ -1273,8 +1273,7 @@ MESSAGE;
        /**
         * Returns JS code which, when called, will register a given list of messages.
         *
-        * @param mixed $messages Either an associative array mapping message key to value, or a
-        *   JSON-encoded message blob containing the same data, wrapped in an XmlJsCode object.
+        * @param mixed $messages Associative array mapping message key to value.
         * @return string JavaScript code
         */
        public static function makeMessageSetScript( $messages ) {
index 09cdf72..a3380ff 100644 (file)
@@ -505,11 +505,10 @@ final class SessionManager implements SessionManagerInterface {
                }
 
                if ( count( $retInfos ) > 1 ) {
-                       $ex = new \OverflowException(
+                       throw new SessionOverflowException(
+                               $retInfos,
                                'Multiple sessions for this request tied for top priority: ' . implode( ', ', $retInfos )
                        );
-                       $ex->sessionInfos = $retInfos;
-                       throw $ex;
                }
 
                return $retInfos ? $retInfos[0] : null;
diff --git a/includes/session/SessionOverflowException.php b/includes/session/SessionOverflowException.php
new file mode 100644 (file)
index 0000000..2a5ed2b
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+
+namespace MediaWiki\Session;
+
+/**
+ * OverflowException specific to the SessionManager, used when the request had multiple possible
+ * sessions tied for top priority.
+ *
+ * @since 1.34
+ */
+class SessionOverflowException extends \OverflowException {
+       /** @var SessionInfo[] */
+       private $sessionInfos;
+
+       /**
+        * @param SessionInfo[] $sessionInfos Must have at least two elements
+        * @param string $msg
+        * @throws \InvalidArgumentException If $sessionInfos has less than 2 elements
+        */
+       function __construct( array $sessionInfos, $msg ) {
+               if ( count( $sessionInfos ) < 2 ) {
+                       throw new \InvalidArgumentException( 'Expected at least two SessionInfo objects.' );
+               }
+               parent::__construct( $msg );
+               $this->sessionInfos = $sessionInfos;
+       }
+
+       /**
+        * @return SessionInfo[]
+        */
+       public function getSessionInfos() : array {
+               return $this->sessionInfos;
+       }
+}
index ce80c1a..e5a28d9 100644 (file)
@@ -95,9 +95,8 @@ abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage {
 
        /**
         * Load basic request parameters for this Special page.
-        * @param string $subPage
         */
-       private function loadRequestParameters( $subPage ) {
+       private function loadRequestParameters() {
                if ( $this->mLoadedRequest ) {
                        return;
                }
@@ -105,7 +104,6 @@ abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage {
                $request = $this->getRequest();
 
                $this->mPosted = $request->wasPosted();
-               $this->mIsReturn = $subPage === 'return';
                $this->mAction = $request->getVal( 'action' );
                $this->mFromHTTP = $request->getBool( 'fromhttp', false )
                        || $request->getBool( 'wpFromhttp', false );
@@ -124,7 +122,7 @@ abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage {
        protected function load( $subPage ) {
                global $wgSecureLogin;
 
-               $this->loadRequestParameters( $subPage );
+               $this->loadRequestParameters();
                if ( $this->mLoaded ) {
                        return;
                }
@@ -203,7 +201,7 @@ abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage {
 
        protected function beforeExecute( $subPage ) {
                // finish initializing the class before processing the request - T135924
-               $this->loadRequestParameters( $subPage );
+               $this->loadRequestParameters();
                return parent::beforeExecute( $subPage );
        }
 
index 6cc6e4e..b7eb3c0 100644 (file)
@@ -77,40 +77,40 @@ abstract class QueryPage extends SpecialPage {
                if ( $qp === null ) {
                        // QueryPage subclass, Special page name
                        $qp = [
-                               [ AncientPagesPage::class, 'Ancientpages' ],
-                               [ BrokenRedirectsPage::class, 'BrokenRedirects' ],
-                               [ DeadendPagesPage::class, 'Deadendpages' ],
-                               [ DoubleRedirectsPage::class, 'DoubleRedirects' ],
-                               [ FileDuplicateSearchPage::class, 'FileDuplicateSearch' ],
-                               [ ListDuplicatedFilesPage::class, 'ListDuplicatedFiles' ],
-                               [ LinkSearchPage::class, 'LinkSearch' ],
-                               [ ListredirectsPage::class, 'Listredirects' ],
-                               [ LonelyPagesPage::class, 'Lonelypages' ],
-                               [ LongPagesPage::class, 'Longpages' ],
-                               [ MediaStatisticsPage::class, 'MediaStatistics' ],
-                               [ MIMEsearchPage::class, 'MIMEsearch' ],
-                               [ MostcategoriesPage::class, 'Mostcategories' ],
+                               [ SpecialAncientPages::class, 'Ancientpages' ],
+                               [ SpecialBrokenRedirects::class, 'BrokenRedirects' ],
+                               [ SpecialDeadendPages::class, 'Deadendpages' ],
+                               [ SpecialDoubleRedirects::class, 'DoubleRedirects' ],
+                               [ SpecialFileDuplicateSearch::class, 'FileDuplicateSearch' ],
+                               [ SpecialListDuplicatedFiles::class, 'ListDuplicatedFiles' ],
+                               [ SpecialLinkSearch::class, 'LinkSearch' ],
+                               [ SpecialListRedirects::class, 'Listredirects' ],
+                               [ SpecialLonelyPages::class, 'Lonelypages' ],
+                               [ SpecialLongPages::class, 'Longpages' ],
+                               [ SpecialMediaStatistics::class, 'MediaStatistics' ],
+                               [ SpecialMIMESearch::class, 'MIMEsearch' ],
+                               [ SpecialMostCategories::class, 'Mostcategories' ],
                                [ MostimagesPage::class, 'Mostimages' ],
-                               [ MostinterwikisPage::class, 'Mostinterwikis' ],
-                               [ MostlinkedCategoriesPage::class, 'Mostlinkedcategories' ],
-                               [ MostlinkedTemplatesPage::class, 'Mostlinkedtemplates' ],
-                               [ MostlinkedPage::class, 'Mostlinked' ],
-                               [ MostrevisionsPage::class, 'Mostrevisions' ],
-                               [ FewestrevisionsPage::class, 'Fewestrevisions' ],
-                               [ ShortPagesPage::class, 'Shortpages' ],
-                               [ UncategorizedCategoriesPage::class, 'Uncategorizedcategories' ],
-                               [ UncategorizedPagesPage::class, 'Uncategorizedpages' ],
-                               [ UncategorizedImagesPage::class, 'Uncategorizedimages' ],
-                               [ UncategorizedTemplatesPage::class, 'Uncategorizedtemplates' ],
-                               [ UnusedCategoriesPage::class, 'Unusedcategories' ],
-                               [ UnusedimagesPage::class, 'Unusedimages' ],
-                               [ WantedCategoriesPage::class, 'Wantedcategories' ],
+                               [ SpecialMostInterwikis::class, 'Mostinterwikis' ],
+                               [ SpecialMostLinkedCategories::class, 'Mostlinkedcategories' ],
+                               [ SpecialMostLinkedTemplates::class, 'Mostlinkedtemplates' ],
+                               [ SpecialMostLinked::class, 'Mostlinked' ],
+                               [ SpecialMostRevisions::class, 'Mostrevisions' ],
+                               [ SpecialFewestRevisions::class, 'Fewestrevisions' ],
+                               [ SpecialShortPages::class, 'Shortpages' ],
+                               [ SpecialUncategorizedCategories::class, 'Uncategorizedcategories' ],
+                               [ SpecialUncategorizedPages::class, 'Uncategorizedpages' ],
+                               [ SpecialUncategorizedImages::class, 'Uncategorizedimages' ],
+                               [ SpecialUncategorizedTemplates::class, 'Uncategorizedtemplates' ],
+                               [ SpecialUnusedCategories::class, 'Unusedcategories' ],
+                               [ SpecialUnusedImages::class, 'Unusedimages' ],
+                               [ SpecialWantedCategories::class, 'Wantedcategories' ],
                                [ WantedFilesPage::class, 'Wantedfiles' ],
                                [ WantedPagesPage::class, 'Wantedpages' ],
-                               [ WantedTemplatesPage::class, 'Wantedtemplates' ],
-                               [ UnwatchedpagesPage::class, 'Unwatchedpages' ],
-                               [ UnusedtemplatesPage::class, 'Unusedtemplates' ],
-                               [ WithoutInterwikiPage::class, 'Withoutinterwiki' ],
+                               [ SpecialWantedTemplates::class, 'Wantedtemplates' ],
+                               [ SpecialUnwatchedPages::class, 'Unwatchedpages' ],
+                               [ SpecialUnusedTemplates::class, 'Unusedtemplates' ],
+                               [ SpecialWithoutInterwiki::class, 'Withoutinterwiki' ],
                        ];
                        Hooks::run( 'wgQueryPages', [ &$qp ] );
                }
index 40fcd74..5ac5f82 100644 (file)
@@ -69,35 +69,35 @@ class SpecialPageFactory {
         */
        private static $coreList = [
                // Maintenance Reports
-               'BrokenRedirects' => \BrokenRedirectsPage::class,
-               'Deadendpages' => \DeadendPagesPage::class,
-               'DoubleRedirects' => \DoubleRedirectsPage::class,
-               'Longpages' => \LongPagesPage::class,
-               'Ancientpages' => \AncientPagesPage::class,
-               'Lonelypages' => \LonelyPagesPage::class,
-               'Fewestrevisions' => \FewestrevisionsPage::class,
-               'Withoutinterwiki' => \WithoutInterwikiPage::class,
+               'BrokenRedirects' => \SpecialBrokenRedirects::class,
+               'Deadendpages' => \SpecialDeadendPages::class,
+               'DoubleRedirects' => \SpecialDoubleRedirects::class,
+               'Longpages' => \SpecialLongPages::class,
+               'Ancientpages' => \SpecialAncientPages::class,
+               'Lonelypages' => \SpecialLonelyPages::class,
+               'Fewestrevisions' => \SpecialFewestRevisions::class,
+               'Withoutinterwiki' => \SpecialWithoutInterwiki::class,
                'Protectedpages' => \SpecialProtectedpages::class,
                'Protectedtitles' => \SpecialProtectedtitles::class,
-               'Shortpages' => \ShortPagesPage::class,
-               'Uncategorizedcategories' => \UncategorizedCategoriesPage::class,
-               'Uncategorizedimages' => \UncategorizedImagesPage::class,
-               'Uncategorizedpages' => \UncategorizedPagesPage::class,
-               'Uncategorizedtemplates' => \UncategorizedTemplatesPage::class,
-               'Unusedcategories' => \UnusedCategoriesPage::class,
-               'Unusedimages' => \UnusedimagesPage::class,
-               'Unusedtemplates' => \UnusedtemplatesPage::class,
-               'Unwatchedpages' => \UnwatchedpagesPage::class,
-               'Wantedcategories' => \WantedCategoriesPage::class,
+               'Shortpages' => \SpecialShortPages::class,
+               'Uncategorizedcategories' => \SpecialUncategorizedCategories::class,
+               'Uncategorizedimages' => \SpecialUncategorizedImages::class,
+               'Uncategorizedpages' => \SpecialUncategorizedPages::class,
+               'Uncategorizedtemplates' => \SpecialUncategorizedTemplates::class,
+               'Unusedcategories' => \SpecialUnusedCategories::class,
+               'Unusedimages' => \SpecialUnusedImages::class,
+               'Unusedtemplates' => \SpecialUnusedTemplates::class,
+               'Unwatchedpages' => \SpecialUnwatchedPages::class,
+               'Wantedcategories' => \SpecialWantedCategories::class,
                'Wantedfiles' => \WantedFilesPage::class,
                'Wantedpages' => \WantedPagesPage::class,
-               'Wantedtemplates' => \WantedTemplatesPage::class,
+               'Wantedtemplates' => \SpecialWantedTemplates::class,
 
                // List of pages
                'Allpages' => \SpecialAllPages::class,
                'Prefixindex' => \SpecialPrefixindex::class,
                'Categories' => \SpecialCategories::class,
-               'Listredirects' => \ListredirectsPage::class,
+               'Listredirects' => \SpecialListRedirects::class,
                'PagesWithProp' => \SpecialPagesWithProp::class,
                'TrackingCategories' => \SpecialTrackingCategories::class,
 
@@ -119,7 +119,7 @@ class SpecialPageFactory {
                'ChangePassword' => \SpecialChangePassword::class,
                'BotPasswords' => \SpecialBotPasswords::class,
                'PasswordReset' => \SpecialPasswordReset::class,
-               'DeletedContributions' => \DeletedContributionsPage::class,
+               'DeletedContributions' => \SpecialDeletedContributions::class,
                'Preferences' => \SpecialPreferences::class,
                'ResetTokens' => \SpecialResetTokens::class,
                'Contributions' => \SpecialContributions::class,
@@ -144,12 +144,12 @@ class SpecialPageFactory {
                // Media reports and uploads
                'Listfiles' => \SpecialListFiles::class,
                'Filepath' => \SpecialFilepath::class,
-               'MediaStatistics' => \MediaStatisticsPage::class,
-               'MIMEsearch' => \MIMEsearchPage::class,
-               'FileDuplicateSearch' => \FileDuplicateSearchPage::class,
+               'MediaStatistics' => \SpecialMediaStatistics::class,
+               'MIMEsearch' => \SpecialMIMESearch::class,
+               'FileDuplicateSearch' => \SpecialFileDuplicateSearch::class,
                'Upload' => \SpecialUpload::class,
                'UploadStash' => \SpecialUploadStash::class,
-               'ListDuplicatedFiles' => \ListDuplicatedFilesPage::class,
+               'ListDuplicatedFiles' => \SpecialListDuplicatedFiles::class,
 
                // Data and tools
                'ApiSandbox' => \SpecialApiSandbox::class,
@@ -160,7 +160,7 @@ class SpecialPageFactory {
                'Unlockdb' => \SpecialUnlockdb::class,
 
                // Redirecting special pages
-               'LinkSearch' => \LinkSearchPage::class,
+               'LinkSearch' => \SpecialLinkSearch::class,
                'Randompage' => \RandomPage::class,
                'RandomInCategory' => \SpecialRandomInCategory::class,
                'Randomredirect' => \SpecialRandomredirect::class,
@@ -168,13 +168,13 @@ class SpecialPageFactory {
                'GoToInterwiki' => \SpecialGoToInterwiki::class,
 
                // High use pages
-               'Mostlinkedcategories' => \MostlinkedCategoriesPage::class,
+               'Mostlinkedcategories' => \SpecialMostLinkedCategories::class,
                'Mostimages' => \MostimagesPage::class,
-               'Mostinterwikis' => \MostinterwikisPage::class,
-               'Mostlinked' => \MostlinkedPage::class,
-               'Mostlinkedtemplates' => \MostlinkedTemplatesPage::class,
-               'Mostcategories' => \MostcategoriesPage::class,
-               'Mostrevisions' => \MostrevisionsPage::class,
+               'Mostinterwikis' => \SpecialMostInterwikis::class,
+               'Mostlinked' => \SpecialMostLinked::class,
+               'Mostlinkedtemplates' => \SpecialMostLinkedTemplates::class,
+               'Mostcategories' => \SpecialMostCategories::class,
+               'Mostrevisions' => \SpecialMostRevisions::class,
 
                // Page tools
                'ComparePages' => \SpecialComparePages::class,
@@ -287,8 +287,8 @@ class SpecialPageFactory {
                        }
 
                        if ( $this->options->get( 'EmailAuthentication' ) ) {
-                               $this->list['Confirmemail'] = \EmailConfirmation::class;
-                               $this->list['Invalidateemail'] = \EmailInvalidation::class;
+                               $this->list['Confirmemail'] = \SpecialConfirmEmail::class;
+                               $this->list['Invalidateemail'] = \SpecialEmailInvalidate::class;
                        }
 
                        if ( $this->options->get( 'EnableEmail' ) ) {
diff --git a/includes/specials/SpecialAncientPages.php b/includes/specials/SpecialAncientPages.php
new file mode 100644 (file)
index 0000000..a17c121
--- /dev/null
@@ -0,0 +1,108 @@
+<?php
+/**
+ * Implements Special:Ancientpages
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * Implements Special:Ancientpages
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialAncientPages extends QueryPage {
+
+       function __construct( $name = 'Ancientpages' ) {
+               parent::__construct( $name );
+       }
+
+       public function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       public function getQueryInfo() {
+               $tables = [ 'page', 'revision' ];
+               $conds = [
+                       'page_namespace' =>
+                               MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces(),
+                       'page_is_redirect' => 0
+               ];
+               $joinConds = [
+                       'revision' => [
+                               'JOIN', [
+                                       'page_latest = rev_id'
+                               ]
+                       ],
+               ];
+
+               // Allow extensions to modify the query
+               Hooks::run( 'AncientPagesQuery', [ &$tables, &$conds, &$joinConds ] );
+
+               return [
+                       'tables' => $tables,
+                       'fields' => [
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'rev_timestamp'
+                       ],
+                       'conds' => $conds,
+                       'join_conds' => $joinConds
+               ];
+       }
+
+       public function usesTimestamps() {
+               return true;
+       }
+
+       function sortDescending() {
+               return false;
+       }
+
+       public function preprocessResults( $db, $res ) {
+               $this->executeLBFromResultWrapper( $res );
+       }
+
+       /**
+        * @param Skin $skin
+        * @param object $result Result row
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $d = $this->getLanguage()->userTimeAndDate( $result->value, $this->getUser() );
+               $title = Title::makeTitle( $result->namespace, $result->title );
+               $linkRenderer = $this->getLinkRenderer();
+               $link = $linkRenderer->makeKnownLink(
+                       $title,
+                       new HtmlArmor( MediaWikiServices::getInstance()->getContentLanguage()->
+                               convert( htmlspecialchars( $title->getPrefixedText() ) ) )
+               );
+
+               return $this->getLanguage()->specialList( $link, htmlspecialchars( $d ) );
+       }
+
+       protected function getGroupName() {
+               return 'maintenance';
+       }
+}
diff --git a/includes/specials/SpecialAncientpages.php b/includes/specials/SpecialAncientpages.php
deleted file mode 100644 (file)
index a32393e..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-<?php
-/**
- * Implements Special:Ancientpages
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- */
-
-use MediaWiki\MediaWikiServices;
-
-/**
- * Implements Special:Ancientpages
- *
- * @ingroup SpecialPage
- */
-class AncientPagesPage extends QueryPage {
-
-       function __construct( $name = 'Ancientpages' ) {
-               parent::__construct( $name );
-       }
-
-       public function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       public function getQueryInfo() {
-               $tables = [ 'page', 'revision' ];
-               $conds = [
-                       'page_namespace' =>
-                               MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces(),
-                       'page_is_redirect' => 0
-               ];
-               $joinConds = [
-                       'revision' => [
-                               'JOIN', [
-                                       'page_latest = rev_id'
-                               ]
-                       ],
-               ];
-
-               // Allow extensions to modify the query
-               Hooks::run( 'AncientPagesQuery', [ &$tables, &$conds, &$joinConds ] );
-
-               return [
-                       'tables' => $tables,
-                       'fields' => [
-                               'namespace' => 'page_namespace',
-                               'title' => 'page_title',
-                               'value' => 'rev_timestamp'
-                       ],
-                       'conds' => $conds,
-                       'join_conds' => $joinConds
-               ];
-       }
-
-       public function usesTimestamps() {
-               return true;
-       }
-
-       function sortDescending() {
-               return false;
-       }
-
-       public function preprocessResults( $db, $res ) {
-               $this->executeLBFromResultWrapper( $res );
-       }
-
-       /**
-        * @param Skin $skin
-        * @param object $result Result row
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $d = $this->getLanguage()->userTimeAndDate( $result->value, $this->getUser() );
-               $title = Title::makeTitle( $result->namespace, $result->title );
-               $linkRenderer = $this->getLinkRenderer();
-               $link = $linkRenderer->makeKnownLink(
-                       $title,
-                       new HtmlArmor( MediaWikiServices::getInstance()->getContentLanguage()->
-                               convert( htmlspecialchars( $title->getPrefixedText() ) ) )
-               );
-
-               return $this->getLanguage()->specialList( $link, htmlspecialchars( $d ) );
-       }
-
-       protected function getGroupName() {
-               return 'maintenance';
-       }
-}
index b3d2358..6385359 100644 (file)
@@ -82,8 +82,9 @@ class SpecialBlockList extends SpecialPage {
                        'Options' => [
                                'type' => 'multiselect',
                                'options-messages' => [
-                                       'blocklist-userblocks' => 'userblocks',
                                        'blocklist-tempblocks' => 'tempblocks',
+                                       'blocklist-indefblocks' => 'indefblocks',
+                                       'blocklist-userblocks' => 'userblocks',
                                        'blocklist-addressblocks' => 'addressblocks',
                                        'blocklist-rangeblocks' => 'rangeblocks',
                                ],
@@ -136,6 +137,7 @@ class SpecialBlockList extends SpecialPage {
         */
        protected function getBlockListPager() {
                $conds = [];
+               $db = $this->getDB();
                # Is the user allowed to see hidden blocks?
                if ( !$this->getUser()->isAllowed( 'hideuser' ) ) {
                        $conds['ipb_deleted'] = 0;
@@ -153,7 +155,7 @@ class SpecialBlockList extends SpecialPage {
                                case DatabaseBlock::TYPE_IP:
                                case DatabaseBlock::TYPE_RANGE:
                                        list( $start, $end ) = IP::parseRange( $target );
-                                       $conds[] = wfGetDB( DB_REPLICA )->makeList(
+                                       $conds[] = $db->makeList(
                                                [
                                                        'ipb_address' => $target,
                                                        DatabaseBlock::getRangeCond( $start, $end )
@@ -174,9 +176,6 @@ class SpecialBlockList extends SpecialPage {
                if ( in_array( 'userblocks', $this->options ) ) {
                        $conds['ipb_user'] = 0;
                }
-               if ( in_array( 'tempblocks', $this->options ) ) {
-                       $conds['ipb_expiry'] = 'infinity';
-               }
                if ( in_array( 'addressblocks', $this->options ) ) {
                        $conds[] = "ipb_user != 0 OR ipb_range_end > ipb_range_start";
                }
@@ -184,10 +183,21 @@ class SpecialBlockList extends SpecialPage {
                        $conds[] = "ipb_range_end = ipb_range_start";
                }
 
+               $hideTemp = in_array( 'tempblocks', $this->options );
+               $hideIndef = in_array( 'indefblocks', $this->options );
+               if ( $hideTemp && $hideIndef ) {
+                       // If both types are hidden, ensure query doesn't produce any results
+                       $conds[] = '1=0';
+               } elseif ( $hideTemp ) {
+                       $conds['ipb_expiry'] = $db->getInfinity();
+               } elseif ( $hideIndef ) {
+                       $conds[] = "ipb_expiry != " . $db->addQuotes( $db->getInfinity() );
+               }
+
                if ( $this->blockType === 'sitewide' ) {
-                       $conds[] = 'ipb_sitewide = 1';
+                       $conds['ipb_sitewide'] = 1;
                } elseif ( $this->blockType === 'partial' ) {
-                       $conds[] = 'ipb_sitewide = 0';
+                       $conds['ipb_sitewide'] = 0;
                }
 
                return new BlockListPager( $this, $conds );
@@ -243,4 +253,13 @@ class SpecialBlockList extends SpecialPage {
        protected function getGroupName() {
                return 'users';
        }
+
+       /**
+        * Return a IDatabase object for reading
+        *
+        * @return IDatabase
+        */
+       protected function getDB() {
+               return wfGetDB( DB_REPLICA );
+       }
 }
index 17f89f9..9431cef 100644 (file)
@@ -30,7 +30,7 @@ use Wikimedia\Rdbms\IDatabase;
  *
  * @ingroup SpecialPage
  */
-class BrokenRedirectsPage extends QueryPage {
+class SpecialBrokenRedirects extends QueryPage {
        function __construct( $name = 'BrokenRedirects' ) {
                parent::__construct( $name );
        }
diff --git a/includes/specials/SpecialConfirmEmail.php b/includes/specials/SpecialConfirmEmail.php
new file mode 100644 (file)
index 0000000..f86a133
--- /dev/null
@@ -0,0 +1,175 @@
+<?php
+/**
+ * Implements Special:Confirmemail
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+/**
+ * Special page allows users to request email confirmation message, and handles
+ * processing of the confirmation code when the link in the email is followed
+ *
+ * @ingroup SpecialPage
+ * @author Brion Vibber
+ * @author Rob Church <robchur@gmail.com>
+ */
+class SpecialConfirmEmail extends UnlistedSpecialPage {
+       public function __construct() {
+               parent::__construct( 'Confirmemail', 'editmyprivateinfo' );
+       }
+
+       public function doesWrites() {
+               return true;
+       }
+
+       /**
+        * Main execution point
+        *
+        * @param null|string $code Confirmation code passed to the page
+        * @throws PermissionsError
+        * @throws ReadOnlyError
+        * @throws UserNotLoggedIn
+        */
+       function execute( $code ) {
+               // Ignore things like master queries/connections on GET requests.
+               // It's very convenient to just allow formless link usage.
+               $trxProfiler = Profiler::instance()->getTransactionProfiler();
+
+               $this->setHeaders();
+               $this->checkReadOnly();
+               $this->checkPermissions();
+
+               // This could also let someone check the current email address, so
+               // require both permissions.
+               if ( !$this->getUser()->isAllowed( 'viewmyprivateinfo' ) ) {
+                       throw new PermissionsError( 'viewmyprivateinfo' );
+               }
+
+               if ( $code === null || $code === '' ) {
+                       $this->requireLogin( 'confirmemail_needlogin' );
+                       if ( Sanitizer::validateEmail( $this->getUser()->getEmail() ) ) {
+                               $this->showRequestForm();
+                       } else {
+                               $this->getOutput()->addWikiMsg( 'confirmemail_noemail' );
+                       }
+               } else {
+                       $old = $trxProfiler->setSilenced( true );
+                       $this->attemptConfirm( $code );
+                       $trxProfiler->setSilenced( $old );
+               }
+       }
+
+       /**
+        * Show a nice form for the user to request a confirmation mail
+        */
+       function showRequestForm() {
+               $user = $this->getUser();
+               $out = $this->getOutput();
+
+               if ( !$user->isEmailConfirmed() ) {
+                       $descriptor = [];
+                       if ( $user->isEmailConfirmationPending() ) {
+                               $descriptor += [
+                                       'pending' => [
+                                               'type' => 'info',
+                                               'raw' => true,
+                                               'default' => "<div class=\"error mw-confirmemail-pending\">\n" .
+                                                       $this->msg( 'confirmemail_pending' )->escaped() .
+                                                       "\n</div>",
+                                       ],
+                               ];
+                       }
+
+                       $out->addWikiMsg( 'confirmemail_text' );
+                       $form = HTMLForm::factory( 'ooui', $descriptor, $this->getContext() );
+                       $form
+                               ->setMethod( 'post' )
+                               ->setAction( $this->getPageTitle()->getLocalURL() )
+                               ->setSubmitTextMsg( 'confirmemail_send' )
+                               ->setSubmitCallback( [ $this, 'submitSend' ] );
+
+                       $retval = $form->show();
+
+                       if ( $retval === true ) {
+                               // should never happen, but if so, don't let the user without any message
+                               $out->addWikiMsg( 'confirmemail_sent' );
+                       } elseif ( $retval instanceof Status && $retval->isGood() ) {
+                               $out->addWikiTextAsInterface( $retval->getValue() );
+                       }
+               } else {
+                       // date and time are separate parameters to facilitate localisation.
+                       // $time is kept for backward compat reasons.
+                       // 'emailauthenticated' is also used in SpecialPreferences.php
+                       $lang = $this->getLanguage();
+                       $emailAuthenticated = $user->getEmailAuthenticationTimestamp();
+                       $time = $lang->userTimeAndDate( $emailAuthenticated, $user );
+                       $d = $lang->userDate( $emailAuthenticated, $user );
+                       $t = $lang->userTime( $emailAuthenticated, $user );
+                       $out->addWikiMsg( 'emailauthenticated', $time, $d, $t );
+               }
+       }
+
+       /**
+        * Callback for HTMLForm send confirmation mail.
+        *
+        * @return Status Status object with the result
+        */
+       public function submitSend() {
+               $status = $this->getUser()->sendConfirmationMail();
+               if ( $status->isGood() ) {
+                       return Status::newGood( $this->msg( 'confirmemail_sent' )->text() );
+               } else {
+                       return Status::newFatal( new RawMessage(
+                               $status->getWikiText( 'confirmemail_sendfailed' )
+                       ) );
+               }
+       }
+
+       /**
+        * Attempt to confirm the user's email address and show success or failure
+        * as needed; if successful, take the user to log in
+        *
+        * @param string $code Confirmation code
+        */
+       private function attemptConfirm( $code ) {
+               $user = User::newFromConfirmationCode( $code, User::READ_EXCLUSIVE );
+               if ( !is_object( $user ) ) {
+                       $this->getOutput()->addWikiMsg( 'confirmemail_invalid' );
+
+                       return;
+               }
+
+               // rate limit email confirmations
+               if ( $user->pingLimiter( 'confirmemail' ) ) {
+                       $this->getOutput()->addWikiMsg( 'actionthrottledtext' );
+
+                       return;
+               }
+
+               $user->confirmEmail();
+               $user->saveSettings();
+               $message = $this->getUser()->isLoggedIn() ? 'confirmemail_loggedin' : 'confirmemail_success';
+               $this->getOutput()->addWikiMsg( $message );
+
+               if ( !$this->getUser()->isLoggedIn() ) {
+                       $title = SpecialPage::getTitleFor( 'Userlogin' );
+                       $this->getOutput()->returnToMain( true, $title );
+               }
+       }
+}
diff --git a/includes/specials/SpecialConfirmemail.php b/includes/specials/SpecialConfirmemail.php
deleted file mode 100644 (file)
index 7f32719..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-<?php
-/**
- * Implements Special:Confirmemail
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- */
-
-/**
- * Special page allows users to request email confirmation message, and handles
- * processing of the confirmation code when the link in the email is followed
- *
- * @ingroup SpecialPage
- * @author Brion Vibber
- * @author Rob Church <robchur@gmail.com>
- */
-class EmailConfirmation extends UnlistedSpecialPage {
-       public function __construct() {
-               parent::__construct( 'Confirmemail', 'editmyprivateinfo' );
-       }
-
-       public function doesWrites() {
-               return true;
-       }
-
-       /**
-        * Main execution point
-        *
-        * @param null|string $code Confirmation code passed to the page
-        * @throws PermissionsError
-        * @throws ReadOnlyError
-        * @throws UserNotLoggedIn
-        */
-       function execute( $code ) {
-               // Ignore things like master queries/connections on GET requests.
-               // It's very convenient to just allow formless link usage.
-               $trxProfiler = Profiler::instance()->getTransactionProfiler();
-
-               $this->setHeaders();
-               $this->checkReadOnly();
-               $this->checkPermissions();
-
-               // This could also let someone check the current email address, so
-               // require both permissions.
-               if ( !$this->getUser()->isAllowed( 'viewmyprivateinfo' ) ) {
-                       throw new PermissionsError( 'viewmyprivateinfo' );
-               }
-
-               if ( $code === null || $code === '' ) {
-                       $this->requireLogin( 'confirmemail_needlogin' );
-                       if ( Sanitizer::validateEmail( $this->getUser()->getEmail() ) ) {
-                               $this->showRequestForm();
-                       } else {
-                               $this->getOutput()->addWikiMsg( 'confirmemail_noemail' );
-                       }
-               } else {
-                       $old = $trxProfiler->setSilenced( true );
-                       $this->attemptConfirm( $code );
-                       $trxProfiler->setSilenced( $old );
-               }
-       }
-
-       /**
-        * Show a nice form for the user to request a confirmation mail
-        */
-       function showRequestForm() {
-               $user = $this->getUser();
-               $out = $this->getOutput();
-
-               if ( !$user->isEmailConfirmed() ) {
-                       $descriptor = [];
-                       if ( $user->isEmailConfirmationPending() ) {
-                               $descriptor += [
-                                       'pending' => [
-                                               'type' => 'info',
-                                               'raw' => true,
-                                               'default' => "<div class=\"error mw-confirmemail-pending\">\n" .
-                                                       $this->msg( 'confirmemail_pending' )->escaped() .
-                                                       "\n</div>",
-                                       ],
-                               ];
-                       }
-
-                       $out->addWikiMsg( 'confirmemail_text' );
-                       $form = HTMLForm::factory( 'ooui', $descriptor, $this->getContext() );
-                       $form
-                               ->setMethod( 'post' )
-                               ->setAction( $this->getPageTitle()->getLocalURL() )
-                               ->setSubmitTextMsg( 'confirmemail_send' )
-                               ->setSubmitCallback( [ $this, 'submitSend' ] );
-
-                       $retval = $form->show();
-
-                       if ( $retval === true ) {
-                               // should never happen, but if so, don't let the user without any message
-                               $out->addWikiMsg( 'confirmemail_sent' );
-                       } elseif ( $retval instanceof Status && $retval->isGood() ) {
-                               $out->addWikiTextAsInterface( $retval->getValue() );
-                       }
-               } else {
-                       // date and time are separate parameters to facilitate localisation.
-                       // $time is kept for backward compat reasons.
-                       // 'emailauthenticated' is also used in SpecialPreferences.php
-                       $lang = $this->getLanguage();
-                       $emailAuthenticated = $user->getEmailAuthenticationTimestamp();
-                       $time = $lang->userTimeAndDate( $emailAuthenticated, $user );
-                       $d = $lang->userDate( $emailAuthenticated, $user );
-                       $t = $lang->userTime( $emailAuthenticated, $user );
-                       $out->addWikiMsg( 'emailauthenticated', $time, $d, $t );
-               }
-       }
-
-       /**
-        * Callback for HTMLForm send confirmation mail.
-        *
-        * @return Status Status object with the result
-        */
-       public function submitSend() {
-               $status = $this->getUser()->sendConfirmationMail();
-               if ( $status->isGood() ) {
-                       return Status::newGood( $this->msg( 'confirmemail_sent' )->text() );
-               } else {
-                       return Status::newFatal( new RawMessage(
-                               $status->getWikiText( 'confirmemail_sendfailed' )
-                       ) );
-               }
-       }
-
-       /**
-        * Attempt to confirm the user's email address and show success or failure
-        * as needed; if successful, take the user to log in
-        *
-        * @param string $code Confirmation code
-        */
-       private function attemptConfirm( $code ) {
-               $user = User::newFromConfirmationCode( $code, User::READ_EXCLUSIVE );
-               if ( !is_object( $user ) ) {
-                       $this->getOutput()->addWikiMsg( 'confirmemail_invalid' );
-
-                       return;
-               }
-
-               // rate limit email confirmations
-               if ( $user->pingLimiter( 'confirmemail' ) ) {
-                       $this->getOutput()->addWikiMsg( 'actionthrottledtext' );
-
-                       return;
-               }
-
-               $user->confirmEmail();
-               $user->saveSettings();
-               $message = $this->getUser()->isLoggedIn() ? 'confirmemail_loggedin' : 'confirmemail_success';
-               $this->getOutput()->addWikiMsg( $message );
-
-               if ( !$this->getUser()->isLoggedIn() ) {
-                       $title = SpecialPage::getTitleFor( 'Userlogin' );
-                       $this->getOutput()->returnToMain( true, $title );
-               }
-       }
-}
diff --git a/includes/specials/SpecialDeadendPages.php b/includes/specials/SpecialDeadendPages.php
new file mode 100644 (file)
index 0000000..9159442
--- /dev/null
@@ -0,0 +1,99 @@
+<?php
+/**
+ * Implements Special:Deadenpages
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * A special page that list pages that contain no link to other pages
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialDeadendPages extends PageQueryPage {
+
+       function __construct( $name = 'Deadendpages' ) {
+               parent::__construct( $name );
+       }
+
+       function getPageHeader() {
+               return $this->msg( 'deadendpagestext' )->parseAsBlock();
+       }
+
+       /**
+        * LEFT JOIN is expensive
+        *
+        * @return bool
+        */
+       function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       /**
+        * @return bool
+        */
+       function sortDescending() {
+               return false;
+       }
+
+       function getQueryInfo() {
+               return [
+                       'tables' => [ 'page', 'pagelinks' ],
+                       'fields' => [
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'page_title'
+                       ],
+                       'conds' => [
+                               'pl_from IS NULL',
+                               'page_namespace' => MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                       getContentNamespaces(),
+                               'page_is_redirect' => 0
+                       ],
+                       'join_conds' => [
+                               'pagelinks' => [
+                                       'LEFT JOIN',
+                                       [ 'page_id=pl_from' ]
+                               ]
+                       ]
+               ];
+       }
+
+       function getOrderFields() {
+               // For some crazy reason ordering by a constant
+               // causes a filesort
+               if ( count( MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       getContentNamespaces() ) > 1
+               ) {
+                       return [ 'page_namespace', 'page_title' ];
+               } else {
+                       return [ 'page_title' ];
+               }
+       }
+
+       protected function getGroupName() {
+               return 'maintenance';
+       }
+}
diff --git a/includes/specials/SpecialDeadendpages.php b/includes/specials/SpecialDeadendpages.php
deleted file mode 100644 (file)
index 2a967c5..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-<?php
-/**
- * Implements Special:Deadenpages
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- */
-
-use MediaWiki\MediaWikiServices;
-
-/**
- * A special page that list pages that contain no link to other pages
- *
- * @ingroup SpecialPage
- */
-class DeadendPagesPage extends PageQueryPage {
-
-       function __construct( $name = 'Deadendpages' ) {
-               parent::__construct( $name );
-       }
-
-       function getPageHeader() {
-               return $this->msg( 'deadendpagestext' )->parseAsBlock();
-       }
-
-       /**
-        * LEFT JOIN is expensive
-        *
-        * @return bool
-        */
-       function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       /**
-        * @return bool
-        */
-       function sortDescending() {
-               return false;
-       }
-
-       function getQueryInfo() {
-               return [
-                       'tables' => [ 'page', 'pagelinks' ],
-                       'fields' => [
-                               'namespace' => 'page_namespace',
-                               'title' => 'page_title',
-                               'value' => 'page_title'
-                       ],
-                       'conds' => [
-                               'pl_from IS NULL',
-                               'page_namespace' => MediaWikiServices::getInstance()->getNamespaceInfo()->
-                                       getContentNamespaces(),
-                               'page_is_redirect' => 0
-                       ],
-                       'join_conds' => [
-                               'pagelinks' => [
-                                       'LEFT JOIN',
-                                       [ 'page_id=pl_from' ]
-                               ]
-                       ]
-               ];
-       }
-
-       function getOrderFields() {
-               // For some crazy reason ordering by a constant
-               // causes a filesort
-               if ( count( MediaWikiServices::getInstance()->getNamespaceInfo()->
-                       getContentNamespaces() ) > 1
-               ) {
-                       return [ 'page_namespace', 'page_title' ];
-               } else {
-                       return [ 'page_title' ];
-               }
-       }
-
-       protected function getGroupName() {
-               return 'maintenance';
-       }
-}
index e9bf6a2..b2cd8c0 100644 (file)
@@ -28,7 +28,7 @@ use MediaWiki\MediaWikiServices;
  * Implements Special:DeletedContributions to display archived revisions
  * @ingroup SpecialPage
  */
-class DeletedContributionsPage extends SpecialPage {
+class SpecialDeletedContributions extends SpecialPage {
        /** @var FormOptions */
        protected $mOpts;
 
index fcf1bb2..cccca50 100644 (file)
@@ -30,7 +30,7 @@ use Wikimedia\Rdbms\IDatabase;
  *
  * @ingroup SpecialPage
  */
-class DoubleRedirectsPage extends QueryPage {
+class SpecialDoubleRedirects extends QueryPage {
        function __construct( $name = 'DoubleRedirects' ) {
                parent::__construct( $name );
        }
index c54abad..7b9ee1a 100644 (file)
@@ -27,7 +27,7 @@
  *
  * @ingroup SpecialPage
  */
-class EmailInvalidation extends UnlistedSpecialPage {
+class SpecialEmailInvalidate extends UnlistedSpecialPage {
        public function __construct() {
                parent::__construct( 'Invalidateemail', 'editmyprivateinfo' );
        }
diff --git a/includes/specials/SpecialFewestRevisions.php b/includes/specials/SpecialFewestRevisions.php
new file mode 100644 (file)
index 0000000..204d73a
--- /dev/null
@@ -0,0 +1,108 @@
+<?php
+/**
+ * Implements Special:Fewestrevisions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * Special page for listing the articles with the fewest revisions.
+ *
+ * @ingroup SpecialPage
+ * @author Martin Drashkov
+ */
+class SpecialFewestRevisions extends QueryPage {
+       function __construct( $name = 'Fewestrevisions' ) {
+               parent::__construct( $name );
+       }
+
+       public function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       public function getQueryInfo() {
+               return [
+                       'tables' => [ 'revision', 'page' ],
+                       'fields' => [
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'COUNT(*)',
+                       ],
+                       'conds' => [
+                               'page_namespace' => MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                       getContentNamespaces(),
+                               'page_id = rev_page',
+                               'page_is_redirect = 0',
+                       ],
+                       'options' => [
+                               'GROUP BY' => [ 'page_namespace', 'page_title' ]
+                       ]
+               ];
+       }
+
+       function sortDescending() {
+               return false;
+       }
+
+       /**
+        * @param Skin $skin
+        * @param object $result Database row
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $nt = Title::makeTitleSafe( $result->namespace, $result->title );
+               if ( !$nt ) {
+                       return Html::element(
+                               'span',
+                               [ 'class' => 'mw-invalidtitle' ],
+                               Linker::getInvalidTitleDescription(
+                                       $this->getContext(),
+                                       $result->namespace,
+                                       $result->title
+                               )
+                       );
+               }
+               $linkRenderer = $this->getLinkRenderer();
+               $text = MediaWikiServices::getInstance()->getContentLanguage()->
+                       convert( htmlspecialchars( $nt->getPrefixedText() ) );
+               $plink = $linkRenderer->makeLink( $nt, new HtmlArmor( $text ) );
+
+               $nl = $this->msg( 'nrevisions' )->numParams( $result->value )->text();
+               $redirect = isset( $result->redirect ) && $result->redirect ?
+                       ' - ' . $this->msg( 'isredirect' )->escaped() : '';
+               $nlink = $linkRenderer->makeKnownLink(
+                       $nt,
+                       $nl,
+                       [],
+                       [ 'action' => 'history' ]
+               ) . $redirect;
+
+               return $this->getLanguage()->specialList( $plink, $nlink );
+       }
+
+       protected function getGroupName() {
+               return 'maintenance';
+       }
+}
diff --git a/includes/specials/SpecialFewestrevisions.php b/includes/specials/SpecialFewestrevisions.php
deleted file mode 100644 (file)
index cf9da49..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-<?php
-/**
- * Implements Special:Fewestrevisions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- */
-
-use MediaWiki\MediaWikiServices;
-
-/**
- * Special page for listing the articles with the fewest revisions.
- *
- * @ingroup SpecialPage
- * @author Martin Drashkov
- */
-class FewestrevisionsPage extends QueryPage {
-       function __construct( $name = 'Fewestrevisions' ) {
-               parent::__construct( $name );
-       }
-
-       public function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       public function getQueryInfo() {
-               return [
-                       'tables' => [ 'revision', 'page' ],
-                       'fields' => [
-                               'namespace' => 'page_namespace',
-                               'title' => 'page_title',
-                               'value' => 'COUNT(*)',
-                       ],
-                       'conds' => [
-                               'page_namespace' => MediaWikiServices::getInstance()->getNamespaceInfo()->
-                                       getContentNamespaces(),
-                               'page_id = rev_page',
-                               'page_is_redirect = 0',
-                       ],
-                       'options' => [
-                               'GROUP BY' => [ 'page_namespace', 'page_title' ]
-                       ]
-               ];
-       }
-
-       function sortDescending() {
-               return false;
-       }
-
-       /**
-        * @param Skin $skin
-        * @param object $result Database row
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $nt = Title::makeTitleSafe( $result->namespace, $result->title );
-               if ( !$nt ) {
-                       return Html::element(
-                               'span',
-                               [ 'class' => 'mw-invalidtitle' ],
-                               Linker::getInvalidTitleDescription(
-                                       $this->getContext(),
-                                       $result->namespace,
-                                       $result->title
-                               )
-                       );
-               }
-               $linkRenderer = $this->getLinkRenderer();
-               $text = MediaWikiServices::getInstance()->getContentLanguage()->
-                       convert( htmlspecialchars( $nt->getPrefixedText() ) );
-               $plink = $linkRenderer->makeLink( $nt, new HtmlArmor( $text ) );
-
-               $nl = $this->msg( 'nrevisions' )->numParams( $result->value )->text();
-               $redirect = isset( $result->redirect ) && $result->redirect ?
-                       ' - ' . $this->msg( 'isredirect' )->escaped() : '';
-               $nlink = $linkRenderer->makeKnownLink(
-                       $nt,
-                       $nl,
-                       [],
-                       [ 'action' => 'history' ]
-               ) . $redirect;
-
-               return $this->getLanguage()->specialList( $plink, $nlink );
-       }
-
-       protected function getGroupName() {
-               return 'maintenance';
-       }
-}
index 5d8a415..f047e1f 100644 (file)
@@ -31,7 +31,7 @@ use MediaWiki\MediaWikiServices;
  *
  * @ingroup SpecialPage
  */
-class FileDuplicateSearchPage extends QueryPage {
+class SpecialFileDuplicateSearch extends QueryPage {
        protected $hash = '', $filename = '';
 
        /**
index d08fe5c..60aedda 100644 (file)
@@ -29,9 +29,15 @@ use Wikimedia\Rdbms\IDatabase;
  * Special:LinkSearch to search the external-links table.
  * @ingroup SpecialPage
  */
-class LinkSearchPage extends QueryPage {
+class SpecialLinkSearch extends QueryPage {
        /** @var array|bool */
        private $mungedQuery = false;
+       /** @var string|null */
+       private $mQuery;
+       /** @var int|null */
+       private $mNs;
+       /** @var string|null */
+       private $mProt;
 
        function setParams( $params ) {
                $this->mQuery = $params['query'];
index c7430cc..d93c570 100644 (file)
@@ -32,7 +32,7 @@ use Wikimedia\Rdbms\IDatabase;
  *   a duplicate of the current version of some other file.
  * @ingroup SpecialPage
  */
-class ListDuplicatedFilesPage extends QueryPage {
+class SpecialListDuplicatedFiles extends QueryPage {
        function __construct( $name = 'ListDuplicatedFiles' ) {
                parent::__construct( $name );
        }
diff --git a/includes/specials/SpecialListRedirects.php b/includes/specials/SpecialListRedirects.php
new file mode 100644 (file)
index 0000000..e686273
--- /dev/null
@@ -0,0 +1,156 @@
+<?php
+/**
+ * Implements Special:Listredirects
+ *
+ * Copyright © 2006 Rob Church
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ * @author Rob Church <robchur@gmail.com>
+ */
+
+use Wikimedia\Rdbms\IResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
+
+/**
+ * Special:Listredirects - Lists all the redirects on the wiki.
+ * @ingroup SpecialPage
+ */
+class SpecialListRedirects extends QueryPage {
+       function __construct( $name = 'Listredirects' ) {
+               parent::__construct( $name );
+       }
+
+       public function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       function sortDescending() {
+               return false;
+       }
+
+       public function getQueryInfo() {
+               return [
+                       'tables' => [ 'p1' => 'page', 'redirect', 'p2' => 'page' ],
+                       'fields' => [ 'namespace' => 'p1.page_namespace',
+                               'title' => 'p1.page_title',
+                               'value' => 'p1.page_title',
+                               'rd_namespace',
+                               'rd_title',
+                               'rd_fragment',
+                               'rd_interwiki',
+                               'redirid' => 'p2.page_id' ],
+                       'conds' => [ 'p1.page_is_redirect' => 1 ],
+                       'join_conds' => [ 'redirect' => [
+                               'LEFT JOIN', 'rd_from=p1.page_id' ],
+                               'p2' => [ 'LEFT JOIN', [
+                                       'p2.page_namespace=rd_namespace',
+                                       'p2.page_title=rd_title' ] ] ]
+               ];
+       }
+
+       function getOrderFields() {
+               return [ 'p1.page_namespace', 'p1.page_title' ];
+       }
+
+       /**
+        * Cache page existence for performance
+        *
+        * @param IDatabase $db
+        * @param IResultWrapper $res
+        */
+       function preprocessResults( $db, $res ) {
+               if ( !$res->numRows() ) {
+                       return;
+               }
+
+               $batch = new LinkBatch;
+               foreach ( $res as $row ) {
+                       $batch->add( $row->namespace, $row->title );
+                       $redirTarget = $this->getRedirectTarget( $row );
+                       if ( $redirTarget ) {
+                               $batch->addObj( $redirTarget );
+                       }
+               }
+               $batch->execute();
+
+               // Back to start for display
+               $res->seek( 0 );
+       }
+
+       /**
+        * @param stdClass $row
+        * @return Title|null
+        */
+       protected function getRedirectTarget( $row ) {
+               if ( isset( $row->rd_title ) ) {
+                       return Title::makeTitle( $row->rd_namespace,
+                               $row->rd_title, $row->rd_fragment,
+                               $row->rd_interwiki
+                       );
+               } else {
+                       $title = Title::makeTitle( $row->namespace, $row->title );
+                       $article = WikiPage::factory( $title );
+
+                       return $article->getRedirectTarget();
+               }
+       }
+
+       /**
+        * @param Skin $skin
+        * @param object $result Result row
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $linkRenderer = $this->getLinkRenderer();
+               # Make a link to the redirect itself
+               $rd_title = Title::makeTitle( $result->namespace, $result->title );
+               $rd_link = $linkRenderer->makeLink(
+                       $rd_title,
+                       null,
+                       [],
+                       [ 'redirect' => 'no' ]
+               );
+
+               # Find out where the redirect leads
+               $target = $this->getRedirectTarget( $result );
+               if ( $target ) {
+                       # Make a link to the destination page
+                       $lang = $this->getLanguage();
+                       $arr = $lang->getArrow() . $lang->getDirMark();
+                       $targetLink = $linkRenderer->makeLink( $target, $target->getFullText() );
+
+                       return "$rd_link $arr $targetLink";
+               } else {
+                       return "<del>$rd_link</del>";
+               }
+       }
+
+       public function execute( $par ) {
+               $this->addHelpLink( 'Help:Redirects' );
+               parent::execute( $par );
+       }
+
+       protected function getGroupName() {
+               return 'pages';
+       }
+}
diff --git a/includes/specials/SpecialListredirects.php b/includes/specials/SpecialListredirects.php
deleted file mode 100644 (file)
index 3284c57..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-<?php
-/**
- * Implements Special:Listredirects
- *
- * Copyright © 2006 Rob Church
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- * @author Rob Church <robchur@gmail.com>
- */
-
-use Wikimedia\Rdbms\IResultWrapper;
-use Wikimedia\Rdbms\IDatabase;
-
-/**
- * Special:Listredirects - Lists all the redirects on the wiki.
- * @ingroup SpecialPage
- */
-class ListredirectsPage extends QueryPage {
-       function __construct( $name = 'Listredirects' ) {
-               parent::__construct( $name );
-       }
-
-       public function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       function sortDescending() {
-               return false;
-       }
-
-       public function getQueryInfo() {
-               return [
-                       'tables' => [ 'p1' => 'page', 'redirect', 'p2' => 'page' ],
-                       'fields' => [ 'namespace' => 'p1.page_namespace',
-                               'title' => 'p1.page_title',
-                               'value' => 'p1.page_title',
-                               'rd_namespace',
-                               'rd_title',
-                               'rd_fragment',
-                               'rd_interwiki',
-                               'redirid' => 'p2.page_id' ],
-                       'conds' => [ 'p1.page_is_redirect' => 1 ],
-                       'join_conds' => [ 'redirect' => [
-                               'LEFT JOIN', 'rd_from=p1.page_id' ],
-                               'p2' => [ 'LEFT JOIN', [
-                                       'p2.page_namespace=rd_namespace',
-                                       'p2.page_title=rd_title' ] ] ]
-               ];
-       }
-
-       function getOrderFields() {
-               return [ 'p1.page_namespace', 'p1.page_title' ];
-       }
-
-       /**
-        * Cache page existence for performance
-        *
-        * @param IDatabase $db
-        * @param IResultWrapper $res
-        */
-       function preprocessResults( $db, $res ) {
-               if ( !$res->numRows() ) {
-                       return;
-               }
-
-               $batch = new LinkBatch;
-               foreach ( $res as $row ) {
-                       $batch->add( $row->namespace, $row->title );
-                       $redirTarget = $this->getRedirectTarget( $row );
-                       if ( $redirTarget ) {
-                               $batch->addObj( $redirTarget );
-                       }
-               }
-               $batch->execute();
-
-               // Back to start for display
-               $res->seek( 0 );
-       }
-
-       /**
-        * @param stdClass $row
-        * @return Title|null
-        */
-       protected function getRedirectTarget( $row ) {
-               if ( isset( $row->rd_title ) ) {
-                       return Title::makeTitle( $row->rd_namespace,
-                               $row->rd_title, $row->rd_fragment,
-                               $row->rd_interwiki
-                       );
-               } else {
-                       $title = Title::makeTitle( $row->namespace, $row->title );
-                       $article = WikiPage::factory( $title );
-
-                       return $article->getRedirectTarget();
-               }
-       }
-
-       /**
-        * @param Skin $skin
-        * @param object $result Result row
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $linkRenderer = $this->getLinkRenderer();
-               # Make a link to the redirect itself
-               $rd_title = Title::makeTitle( $result->namespace, $result->title );
-               $rd_link = $linkRenderer->makeLink(
-                       $rd_title,
-                       null,
-                       [],
-                       [ 'redirect' => 'no' ]
-               );
-
-               # Find out where the redirect leads
-               $target = $this->getRedirectTarget( $result );
-               if ( $target ) {
-                       # Make a link to the destination page
-                       $lang = $this->getLanguage();
-                       $arr = $lang->getArrow() . $lang->getDirMark();
-                       $targetLink = $linkRenderer->makeLink( $target, $target->getFullText() );
-
-                       return "$rd_link $arr $targetLink";
-               } else {
-                       return "<del>$rd_link</del>";
-               }
-       }
-
-       public function execute( $par ) {
-               $this->addHelpLink( 'Help:Redirects' );
-               parent::execute( $par );
-       }
-
-       protected function getGroupName() {
-               return 'pages';
-       }
-}
diff --git a/includes/specials/SpecialLonelyPages.php b/includes/specials/SpecialLonelyPages.php
new file mode 100644 (file)
index 0000000..14f9435
--- /dev/null
@@ -0,0 +1,107 @@
+<?php
+/**
+ * Implements Special:Lonelypaages
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * A special page looking for articles with no article linking to them,
+ * thus being lonely.
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialLonelyPages extends PageQueryPage {
+       function __construct( $name = 'Lonelypages' ) {
+               parent::__construct( $name );
+       }
+
+       function getPageHeader() {
+               return $this->msg( 'lonelypagestext' )->parseAsBlock();
+       }
+
+       function sortDescending() {
+               return false;
+       }
+
+       function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       function getQueryInfo() {
+               $tables = [ 'page', 'pagelinks', 'templatelinks' ];
+               $conds = [
+                       'pl_namespace IS NULL',
+                       'page_namespace' => MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               getContentNamespaces(),
+                       'page_is_redirect' => 0,
+                       'tl_namespace IS NULL'
+               ];
+               $joinConds = [
+                       'pagelinks' => [
+                               'LEFT JOIN', [
+                                       'pl_namespace = page_namespace',
+                                       'pl_title = page_title'
+                               ]
+                       ],
+                       'templatelinks' => [
+                               'LEFT JOIN', [
+                                       'tl_namespace = page_namespace',
+                                       'tl_title = page_title'
+                               ]
+                       ]
+               ];
+
+               // Allow extensions to modify the query
+               Hooks::run( 'LonelyPagesQuery', [ &$tables, &$conds, &$joinConds ] );
+
+               return [
+                       'tables' => $tables,
+                       'fields' => [
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'page_title'
+                       ],
+                       'conds' => $conds,
+                       'join_conds' => $joinConds
+               ];
+       }
+
+       function getOrderFields() {
+               // For some crazy reason ordering by a constant
+               // causes a filesort in MySQL 5
+               if ( count( MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       getContentNamespaces() ) > 1
+               ) {
+                       return [ 'page_namespace', 'page_title' ];
+               } else {
+                       return [ 'page_title' ];
+               }
+       }
+
+       protected function getGroupName() {
+               return 'maintenance';
+       }
+}
diff --git a/includes/specials/SpecialLonelypages.php b/includes/specials/SpecialLonelypages.php
deleted file mode 100644 (file)
index ca3f4da..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-<?php
-/**
- * Implements Special:Lonelypaages
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- */
-
-use MediaWiki\MediaWikiServices;
-
-/**
- * A special page looking for articles with no article linking to them,
- * thus being lonely.
- *
- * @ingroup SpecialPage
- */
-class LonelyPagesPage extends PageQueryPage {
-       function __construct( $name = 'Lonelypages' ) {
-               parent::__construct( $name );
-       }
-
-       function getPageHeader() {
-               return $this->msg( 'lonelypagestext' )->parseAsBlock();
-       }
-
-       function sortDescending() {
-               return false;
-       }
-
-       function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       function getQueryInfo() {
-               $tables = [ 'page', 'pagelinks', 'templatelinks' ];
-               $conds = [
-                       'pl_namespace IS NULL',
-                       'page_namespace' => MediaWikiServices::getInstance()->getNamespaceInfo()->
-                               getContentNamespaces(),
-                       'page_is_redirect' => 0,
-                       'tl_namespace IS NULL'
-               ];
-               $joinConds = [
-                       'pagelinks' => [
-                               'LEFT JOIN', [
-                                       'pl_namespace = page_namespace',
-                                       'pl_title = page_title'
-                               ]
-                       ],
-                       'templatelinks' => [
-                               'LEFT JOIN', [
-                                       'tl_namespace = page_namespace',
-                                       'tl_title = page_title'
-                               ]
-                       ]
-               ];
-
-               // Allow extensions to modify the query
-               Hooks::run( 'LonelyPagesQuery', [ &$tables, &$conds, &$joinConds ] );
-
-               return [
-                       'tables' => $tables,
-                       'fields' => [
-                               'namespace' => 'page_namespace',
-                               'title' => 'page_title',
-                               'value' => 'page_title'
-                       ],
-                       'conds' => $conds,
-                       'join_conds' => $joinConds
-               ];
-       }
-
-       function getOrderFields() {
-               // For some crazy reason ordering by a constant
-               // causes a filesort in MySQL 5
-               if ( count( MediaWikiServices::getInstance()->getNamespaceInfo()->
-                       getContentNamespaces() ) > 1
-               ) {
-                       return [ 'page_namespace', 'page_title' ];
-               } else {
-                       return [ 'page_title' ];
-               }
-       }
-
-       protected function getGroupName() {
-               return 'maintenance';
-       }
-}
diff --git a/includes/specials/SpecialLongPages.php b/includes/specials/SpecialLongPages.php
new file mode 100644 (file)
index 0000000..5227d4e
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Implements Special:Longpages
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+/**
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialLongPages extends SpecialShortPages {
+       function __construct( $name = 'Longpages' ) {
+               parent::__construct( $name );
+       }
+
+       function sortDescending() {
+               return true;
+       }
+
+       protected function getGroupName() {
+               return 'maintenance';
+       }
+}
diff --git a/includes/specials/SpecialLongpages.php b/includes/specials/SpecialLongpages.php
deleted file mode 100644 (file)
index d90d271..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-/**
- * Implements Special:Longpages
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- */
-
-/**
- *
- * @ingroup SpecialPage
- */
-class LongPagesPage extends ShortPagesPage {
-       function __construct( $name = 'Longpages' ) {
-               parent::__construct( $name );
-       }
-
-       function sortDescending() {
-               return true;
-       }
-
-       protected function getGroupName() {
-               return 'maintenance';
-       }
-}
diff --git a/includes/specials/SpecialMIMESearch.php b/includes/specials/SpecialMIMESearch.php
new file mode 100644 (file)
index 0000000..0784821
--- /dev/null
@@ -0,0 +1,244 @@
+<?php
+/**
+ * Implements Special:MIMESearch
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+ */
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * Searches the database for files of the requested MIME type, comparing this with the
+ * 'img_major_mime' and 'img_minor_mime' fields in the image table.
+ * @ingroup SpecialPage
+ */
+class SpecialMIMESearch extends QueryPage {
+       protected $major, $minor, $mime;
+
+       function __construct( $name = 'MIMEsearch' ) {
+               parent::__construct( $name );
+       }
+
+       public function isExpensive() {
+               return false;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       function isCacheable() {
+               return false;
+       }
+
+       function linkParameters() {
+               return [ 'mime' => "{$this->major}/{$this->minor}" ];
+       }
+
+       public function getQueryInfo() {
+               $minorType = [];
+               if ( $this->minor !== '*' ) {
+                       // Allow wildcard searching
+                       $minorType['img_minor_mime'] = $this->minor;
+               }
+               $imgQuery = LocalFile::getQueryInfo();
+               $qi = [
+                       'tables' => $imgQuery['tables'],
+                       'fields' => [
+                               'namespace' => NS_FILE,
+                               'title' => 'img_name',
+                               // Still have a value field just in case,
+                               // but it isn't actually used for sorting.
+                               'value' => 'img_name',
+                               'img_size',
+                               'img_width',
+                               'img_height',
+                               'img_user_text' => $imgQuery['fields']['img_user_text'],
+                               'img_timestamp'
+                       ],
+                       'conds' => [
+                               'img_major_mime' => $this->major,
+                               // This is in order to trigger using
+                               // the img_media_mime index in "range" mode.
+                               // @todo how is order defined? use MimeAnalyzer::getMediaTypes?
+                               'img_media_type' => [
+                                       MEDIATYPE_BITMAP,
+                                       MEDIATYPE_DRAWING,
+                                       MEDIATYPE_AUDIO,
+                                       MEDIATYPE_VIDEO,
+                                       MEDIATYPE_MULTIMEDIA,
+                                       MEDIATYPE_UNKNOWN,
+                                       MEDIATYPE_OFFICE,
+                                       MEDIATYPE_TEXT,
+                                       MEDIATYPE_EXECUTABLE,
+                                       MEDIATYPE_ARCHIVE,
+                                       MEDIATYPE_3D,
+                               ],
+                       ] + $minorType,
+                       'join_conds' => $imgQuery['joins'],
+               ];
+
+               return $qi;
+       }
+
+       /**
+        * The index is on (img_media_type, img_major_mime, img_minor_mime)
+        * which unfortunately doesn't have img_name at the end for sorting.
+        * So tell db to sort it however it wishes (Its not super important
+        * that this report gives results in a logical order). As an aditional
+        * note, mysql seems to by default order things by img_name ASC, which
+        * is what we ideally want, so everything works out fine anyhow.
+        * @return array
+        */
+       function getOrderFields() {
+               return [];
+       }
+
+       /**
+        * Generate and output the form
+        */
+       function getPageHeader() {
+               $formDescriptor = [
+                       'mime' => [
+                               'type' => 'combobox',
+                               'options' => $this->getSuggestionsForTypes(),
+                               'name' => 'mime',
+                               'label-message' => 'mimetype',
+                               'required' => true,
+                               'default' => $this->mime,
+                       ],
+               ];
+
+               HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() )
+                       ->setSubmitTextMsg( 'ilsubmit' )
+                       ->setAction( $this->getPageTitle()->getLocalURL() )
+                       ->setMethod( 'get' )
+                       ->prepareForm()
+                       ->displayForm( false );
+               return '';
+       }
+
+       protected function getSuggestionsForTypes() {
+               $dbr = wfGetDB( DB_REPLICA );
+               $lastMajor = null;
+               $suggestions = [];
+               $result = $dbr->select(
+                       [ 'image' ],
+                       // We ignore img_media_type, but using it in the query is needed for MySQL to choose a
+                       // sensible execution plan
+                       [ 'img_media_type', 'img_major_mime', 'img_minor_mime' ],
+                       [],
+                       __METHOD__,
+                       [ 'GROUP BY' => [ 'img_media_type', 'img_major_mime', 'img_minor_mime' ] ]
+               );
+               foreach ( $result as $row ) {
+                       $major = $row->img_major_mime;
+                       $minor = $row->img_minor_mime;
+                       $suggestions[ "$major/$minor" ] = "$major/$minor";
+                       if ( $lastMajor === $major ) {
+                               // If there are at least two with the same major mime type, also include the wildcard
+                               $suggestions[ "$major/*" ] = "$major/*";
+                       }
+                       $lastMajor = $major;
+               }
+               ksort( $suggestions );
+               return $suggestions;
+       }
+
+       public function execute( $par ) {
+               $this->addHelpLink( 'Help:Managing_files' );
+               $this->mime = $par ?: $this->getRequest()->getText( 'mime' );
+               $this->mime = trim( $this->mime );
+               list( $this->major, $this->minor ) = File::splitMime( $this->mime );
+
+               if ( $this->major == '' || $this->minor == '' || $this->minor == 'unknown' ||
+                       !self::isValidType( $this->major )
+               ) {
+                       $this->setHeaders();
+                       $this->outputHeader();
+                       $this->getPageHeader();
+                       return;
+               }
+
+               parent::execute( $par );
+       }
+
+       /**
+        * @param Skin $skin
+        * @param object $result Result row
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $linkRenderer = $this->getLinkRenderer();
+               $nt = Title::makeTitle( $result->namespace, $result->title );
+               $text = MediaWikiServices::getInstance()->getContentLanguage()
+                       ->convert( htmlspecialchars( $nt->getText() ) );
+               $plink = $linkRenderer->makeLink(
+                       Title::newFromText( $nt->getPrefixedText() ),
+                       new HtmlArmor( $text )
+               );
+
+               $download = Linker::makeMediaLinkObj( $nt, $this->msg( 'download' )->escaped() );
+               $download = $this->msg( 'parentheses' )->rawParams( $download )->escaped();
+               $lang = $this->getLanguage();
+               $bytes = htmlspecialchars( $lang->formatSize( $result->img_size ) );
+               $dimensions = $this->msg( 'widthheight' )->numParams( $result->img_width,
+                       $result->img_height )->escaped();
+               $user = $linkRenderer->makeLink(
+                       Title::makeTitle( NS_USER, $result->img_user_text ),
+                       $result->img_user_text
+               );
+
+               $time = $lang->userTimeAndDate( $result->img_timestamp, $this->getUser() );
+               $time = htmlspecialchars( $time );
+
+               return "$download $plink . . $dimensions . . $bytes . . $user . . $time";
+       }
+
+       /**
+        * @param string $type
+        * @return bool
+        */
+       protected static function isValidType( $type ) {
+               // From maintenance/tables.sql => img_major_mime
+               $types = [
+                       'unknown',
+                       'application',
+                       'audio',
+                       'image',
+                       'text',
+                       'video',
+                       'message',
+                       'model',
+                       'multipart',
+                       'chemical'
+               ];
+
+               return in_array( $type, $types );
+       }
+
+       public function preprocessResults( $db, $res ) {
+               $this->executeLBFromResultWrapper( $res );
+       }
+
+       protected function getGroupName() {
+               return 'media';
+       }
+}
diff --git a/includes/specials/SpecialMIMEsearch.php b/includes/specials/SpecialMIMEsearch.php
deleted file mode 100644 (file)
index d6ace1d..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-<?php
-/**
- * Implements Special:MIMESearch
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
- */
-
-use MediaWiki\MediaWikiServices;
-
-/**
- * Searches the database for files of the requested MIME type, comparing this with the
- * 'img_major_mime' and 'img_minor_mime' fields in the image table.
- * @ingroup SpecialPage
- */
-class MIMEsearchPage extends QueryPage {
-       protected $major, $minor, $mime;
-
-       function __construct( $name = 'MIMEsearch' ) {
-               parent::__construct( $name );
-       }
-
-       public function isExpensive() {
-               return false;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       function isCacheable() {
-               return false;
-       }
-
-       function linkParameters() {
-               return [ 'mime' => "{$this->major}/{$this->minor}" ];
-       }
-
-       public function getQueryInfo() {
-               $minorType = [];
-               if ( $this->minor !== '*' ) {
-                       // Allow wildcard searching
-                       $minorType['img_minor_mime'] = $this->minor;
-               }
-               $imgQuery = LocalFile::getQueryInfo();
-               $qi = [
-                       'tables' => $imgQuery['tables'],
-                       'fields' => [
-                               'namespace' => NS_FILE,
-                               'title' => 'img_name',
-                               // Still have a value field just in case,
-                               // but it isn't actually used for sorting.
-                               'value' => 'img_name',
-                               'img_size',
-                               'img_width',
-                               'img_height',
-                               'img_user_text' => $imgQuery['fields']['img_user_text'],
-                               'img_timestamp'
-                       ],
-                       'conds' => [
-                               'img_major_mime' => $this->major,
-                               // This is in order to trigger using
-                               // the img_media_mime index in "range" mode.
-                               // @todo how is order defined? use MimeAnalyzer::getMediaTypes?
-                               'img_media_type' => [
-                                       MEDIATYPE_BITMAP,
-                                       MEDIATYPE_DRAWING,
-                                       MEDIATYPE_AUDIO,
-                                       MEDIATYPE_VIDEO,
-                                       MEDIATYPE_MULTIMEDIA,
-                                       MEDIATYPE_UNKNOWN,
-                                       MEDIATYPE_OFFICE,
-                                       MEDIATYPE_TEXT,
-                                       MEDIATYPE_EXECUTABLE,
-                                       MEDIATYPE_ARCHIVE,
-                                       MEDIATYPE_3D,
-                               ],
-                       ] + $minorType,
-                       'join_conds' => $imgQuery['joins'],
-               ];
-
-               return $qi;
-       }
-
-       /**
-        * The index is on (img_media_type, img_major_mime, img_minor_mime)
-        * which unfortunately doesn't have img_name at the end for sorting.
-        * So tell db to sort it however it wishes (Its not super important
-        * that this report gives results in a logical order). As an aditional
-        * note, mysql seems to by default order things by img_name ASC, which
-        * is what we ideally want, so everything works out fine anyhow.
-        * @return array
-        */
-       function getOrderFields() {
-               return [];
-       }
-
-       /**
-        * Generate and output the form
-        */
-       function getPageHeader() {
-               $formDescriptor = [
-                       'mime' => [
-                               'type' => 'combobox',
-                               'options' => $this->getSuggestionsForTypes(),
-                               'name' => 'mime',
-                               'label-message' => 'mimetype',
-                               'required' => true,
-                               'default' => $this->mime,
-                       ],
-               ];
-
-               HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() )
-                       ->setSubmitTextMsg( 'ilsubmit' )
-                       ->setAction( $this->getPageTitle()->getLocalURL() )
-                       ->setMethod( 'get' )
-                       ->prepareForm()
-                       ->displayForm( false );
-               return '';
-       }
-
-       protected function getSuggestionsForTypes() {
-               $dbr = wfGetDB( DB_REPLICA );
-               $lastMajor = null;
-               $suggestions = [];
-               $result = $dbr->select(
-                       [ 'image' ],
-                       // We ignore img_media_type, but using it in the query is needed for MySQL to choose a
-                       // sensible execution plan
-                       [ 'img_media_type', 'img_major_mime', 'img_minor_mime' ],
-                       [],
-                       __METHOD__,
-                       [ 'GROUP BY' => [ 'img_media_type', 'img_major_mime', 'img_minor_mime' ] ]
-               );
-               foreach ( $result as $row ) {
-                       $major = $row->img_major_mime;
-                       $minor = $row->img_minor_mime;
-                       $suggestions[ "$major/$minor" ] = "$major/$minor";
-                       if ( $lastMajor === $major ) {
-                               // If there are at least two with the same major mime type, also include the wildcard
-                               $suggestions[ "$major/*" ] = "$major/*";
-                       }
-                       $lastMajor = $major;
-               }
-               ksort( $suggestions );
-               return $suggestions;
-       }
-
-       public function execute( $par ) {
-               $this->addHelpLink( 'Help:Managing_files' );
-               $this->mime = $par ?: $this->getRequest()->getText( 'mime' );
-               $this->mime = trim( $this->mime );
-               list( $this->major, $this->minor ) = File::splitMime( $this->mime );
-
-               if ( $this->major == '' || $this->minor == '' || $this->minor == 'unknown' ||
-                       !self::isValidType( $this->major )
-               ) {
-                       $this->setHeaders();
-                       $this->outputHeader();
-                       $this->getPageHeader();
-                       return;
-               }
-
-               parent::execute( $par );
-       }
-
-       /**
-        * @param Skin $skin
-        * @param object $result Result row
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $linkRenderer = $this->getLinkRenderer();
-               $nt = Title::makeTitle( $result->namespace, $result->title );
-               $text = MediaWikiServices::getInstance()->getContentLanguage()
-                       ->convert( htmlspecialchars( $nt->getText() ) );
-               $plink = $linkRenderer->makeLink(
-                       Title::newFromText( $nt->getPrefixedText() ),
-                       new HtmlArmor( $text )
-               );
-
-               $download = Linker::makeMediaLinkObj( $nt, $this->msg( 'download' )->escaped() );
-               $download = $this->msg( 'parentheses' )->rawParams( $download )->escaped();
-               $lang = $this->getLanguage();
-               $bytes = htmlspecialchars( $lang->formatSize( $result->img_size ) );
-               $dimensions = $this->msg( 'widthheight' )->numParams( $result->img_width,
-                       $result->img_height )->escaped();
-               $user = $linkRenderer->makeLink(
-                       Title::makeTitle( NS_USER, $result->img_user_text ),
-                       $result->img_user_text
-               );
-
-               $time = $lang->userTimeAndDate( $result->img_timestamp, $this->getUser() );
-               $time = htmlspecialchars( $time );
-
-               return "$download $plink . . $dimensions . . $bytes . . $user . . $time";
-       }
-
-       /**
-        * @param string $type
-        * @return bool
-        */
-       protected static function isValidType( $type ) {
-               // From maintenance/tables.sql => img_major_mime
-               $types = [
-                       'unknown',
-                       'application',
-                       'audio',
-                       'image',
-                       'text',
-                       'video',
-                       'message',
-                       'model',
-                       'multipart',
-                       'chemical'
-               ];
-
-               return in_array( $type, $types );
-       }
-
-       public function preprocessResults( $db, $res ) {
-               $this->executeLBFromResultWrapper( $res );
-       }
-
-       protected function getGroupName() {
-               return 'media';
-       }
-}
index 45bd524..333d9b3 100644 (file)
@@ -28,7 +28,7 @@ use Wikimedia\Rdbms\IDatabase;
 /**
  * @ingroup SpecialPage
  */
-class MediaStatisticsPage extends QueryPage {
+class SpecialMediaStatistics extends QueryPage {
        protected $totalCount = 0, $totalBytes = 0;
 
        /**
diff --git a/includes/specials/SpecialMostCategories.php b/includes/specials/SpecialMostCategories.php
new file mode 100644 (file)
index 0000000..682a23a
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+/**
+ * Implements Special:Mostcategories
+ *
+ * Copyright © 2005 Ævar Arnfjörð Bjarmason
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+ */
+
+use MediaWiki\MediaWikiServices;
+use Wikimedia\Rdbms\IResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
+
+/**
+ * A special page that list pages that have highest category count
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialMostCategories extends QueryPage {
+       function __construct( $name = 'Mostcategories' ) {
+               parent::__construct( $name );
+       }
+
+       public function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       public function getQueryInfo() {
+               return [
+                       'tables' => [ 'categorylinks', 'page' ],
+                       'fields' => [
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'COUNT(*)'
+                       ],
+                       'conds' => [ 'page_namespace' =>
+                               MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces() ],
+                       'options' => [
+                               'HAVING' => 'COUNT(*) > 1',
+                               'GROUP BY' => [ 'page_namespace', 'page_title' ]
+                       ],
+                       'join_conds' => [
+                               'page' => [
+                                       'LEFT JOIN',
+                                       'page_id = cl_from'
+                               ]
+                       ]
+               ];
+       }
+
+       /**
+        * @param IDatabase $db
+        * @param IResultWrapper $res
+        */
+       function preprocessResults( $db, $res ) {
+               $this->executeLBFromResultWrapper( $res );
+       }
+
+       /**
+        * @param Skin $skin
+        * @param object $result Result row
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $title = Title::makeTitleSafe( $result->namespace, $result->title );
+               if ( !$title ) {
+                       return Html::element(
+                               'span',
+                               [ 'class' => 'mw-invalidtitle' ],
+                               Linker::getInvalidTitleDescription(
+                                       $this->getContext(),
+                                       $result->namespace,
+                                       $result->title
+                               )
+                       );
+               }
+
+               $linkRenderer = $this->getLinkRenderer();
+               if ( $this->isCached() ) {
+                       $link = $linkRenderer->makeLink( $title );
+               } else {
+                       $link = $linkRenderer->makeKnownLink( $title );
+               }
+
+               $count = $this->msg( 'ncategories' )->numParams( $result->value )->escaped();
+
+               return $this->getLanguage()->specialList( $link, $count );
+       }
+
+       protected function getGroupName() {
+               return 'highuse';
+       }
+}
diff --git a/includes/specials/SpecialMostInterwikis.php b/includes/specials/SpecialMostInterwikis.php
new file mode 100644 (file)
index 0000000..52777b0
--- /dev/null
@@ -0,0 +1,117 @@
+<?php
+/**
+ * Implements Special:Mostinterwikis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+use MediaWiki\MediaWikiServices;
+use Wikimedia\Rdbms\IResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
+
+/**
+ * A special page that listed pages that have highest interwiki count
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialMostInterwikis extends QueryPage {
+       function __construct( $name = 'Mostinterwikis' ) {
+               parent::__construct( $name );
+       }
+
+       public function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       public function getQueryInfo() {
+               return [
+                       'tables' => [
+                               'langlinks',
+                               'page'
+                       ], 'fields' => [
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'COUNT(*)'
+                       ], 'conds' => [
+                               'page_namespace' =>
+                                       MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces()
+                       ], 'options' => [
+                               'HAVING' => 'COUNT(*) > 1',
+                               'GROUP BY' => [
+                                       'page_namespace',
+                                       'page_title'
+                               ]
+                       ], 'join_conds' => [
+                               'page' => [
+                                       'LEFT JOIN',
+                                       'page_id = ll_from'
+                               ]
+                       ]
+               ];
+       }
+
+       /**
+        * Pre-fill the link cache
+        *
+        * @param IDatabase $db
+        * @param IResultWrapper $res
+        */
+       function preprocessResults( $db, $res ) {
+               $this->executeLBFromResultWrapper( $res );
+       }
+
+       /**
+        * @param Skin $skin
+        * @param object $result
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $title = Title::makeTitleSafe( $result->namespace, $result->title );
+               if ( !$title ) {
+                       return Html::element(
+                               'span',
+                               [ 'class' => 'mw-invalidtitle' ],
+                               Linker::getInvalidTitleDescription(
+                                       $this->getContext(),
+                                       $result->namespace,
+                                       $result->title
+                               )
+                       );
+               }
+
+               $linkRenderer = $this->getLinkRenderer();
+               if ( $this->isCached() ) {
+                       $link = $linkRenderer->makeLink( $title );
+               } else {
+                       $link = $linkRenderer->makeKnownLink( $title );
+               }
+
+               $count = $this->msg( 'ninterwikis' )->numParams( $result->value )->escaped();
+
+               return $this->getLanguage()->specialList( $link, $count );
+       }
+
+       protected function getGroupName() {
+               return 'highuse';
+       }
+}
diff --git a/includes/specials/SpecialMostLinked.php b/includes/specials/SpecialMostLinked.php
new file mode 100644 (file)
index 0000000..c0f1a2a
--- /dev/null
@@ -0,0 +1,135 @@
+<?php
+/**
+ * Implements Special:Mostlinked
+ *
+ * Copyright © 2005 Ævar Arnfjörð Bjarmason, 2006 Rob Church
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+ * @author Rob Church <robchur@gmail.com>
+ */
+
+use Wikimedia\Rdbms\IResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
+
+/**
+ * A special page to show pages ordered by the number of pages linking to them.
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialMostLinked extends QueryPage {
+       function __construct( $name = 'Mostlinked' ) {
+               parent::__construct( $name );
+       }
+
+       public function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       public function getQueryInfo() {
+               return [
+                       'tables' => [ 'pagelinks', 'page' ],
+                       'fields' => [
+                               'namespace' => 'pl_namespace',
+                               'title' => 'pl_title',
+                               'value' => 'COUNT(*)',
+                               'page_namespace'
+                       ],
+                       'options' => [
+                               'HAVING' => 'COUNT(*) > 1',
+                               'GROUP BY' => [
+                                       'pl_namespace', 'pl_title',
+                                       'page_namespace'
+                               ]
+                       ],
+                       'join_conds' => [
+                               'page' => [
+                                       'LEFT JOIN',
+                                       [
+                                               'page_namespace = pl_namespace',
+                                               'page_title = pl_title'
+                                       ]
+                               ]
+                       ]
+               ];
+       }
+
+       /**
+        * Pre-fill the link cache
+        *
+        * @param IDatabase $db
+        * @param IResultWrapper $res
+        */
+       function preprocessResults( $db, $res ) {
+               $this->executeLBFromResultWrapper( $res );
+       }
+
+       /**
+        * Make a link to "what links here" for the specified title
+        *
+        * @param Title $title Title being queried
+        * @param string $caption Text to display on the link
+        * @return string
+        */
+       function makeWlhLink( $title, $caption ) {
+               $wlh = SpecialPage::getTitleFor( 'Whatlinkshere', $title->getPrefixedDBkey() );
+
+               $linkRenderer = $this->getLinkRenderer();
+               return $linkRenderer->makeKnownLink( $wlh, $caption );
+       }
+
+       /**
+        * Make links to the page corresponding to the item,
+        * and the "what links here" page for it
+        *
+        * @param Skin $skin Skin to be used
+        * @param object $result Result row
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $title = Title::makeTitleSafe( $result->namespace, $result->title );
+               if ( !$title ) {
+                       return Html::element(
+                               'span',
+                               [ 'class' => 'mw-invalidtitle' ],
+                               Linker::getInvalidTitleDescription(
+                                       $this->getContext(),
+                                       $result->namespace,
+                                       $result->title )
+                       );
+               }
+
+               $linkRenderer = $this->getLinkRenderer();
+               $link = $linkRenderer->makeLink( $title );
+               $wlh = $this->makeWlhLink(
+                       $title,
+                       $this->msg( 'nlinks' )->numParams( $result->value )->text()
+               );
+
+               return $this->getLanguage()->specialList( $link, $wlh );
+       }
+
+       protected function getGroupName() {
+               return 'highuse';
+       }
+}
diff --git a/includes/specials/SpecialMostLinkedCategories.php b/includes/specials/SpecialMostLinkedCategories.php
new file mode 100644 (file)
index 0000000..32157fa
--- /dev/null
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Implements Special:Mostlinkedcategories
+ *
+ * Copyright © 2005, Ævar Arnfjörð Bjarmason
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+ */
+
+use MediaWiki\MediaWikiServices;
+use Wikimedia\Rdbms\IResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
+
+/**
+ * A querypage to show categories ordered in descending order by the pages in them
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialMostLinkedCategories extends QueryPage {
+       function __construct( $name = 'Mostlinkedcategories' ) {
+               parent::__construct( $name );
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       public function getQueryInfo() {
+               return [
+                       'tables' => [ 'category' ],
+                       'fields' => [ 'title' => 'cat_title',
+                               'namespace' => NS_CATEGORY,
+                               'value' => 'cat_pages' ],
+                       'conds' => [ 'cat_pages > 0' ],
+               ];
+       }
+
+       function sortDescending() {
+               return true;
+       }
+
+       /**
+        * Fetch user page links and cache their existence
+        *
+        * @param IDatabase $db
+        * @param IResultWrapper $res
+        */
+       function preprocessResults( $db, $res ) {
+               $this->executeLBFromResultWrapper( $res );
+       }
+
+       /**
+        * @param Skin $skin
+        * @param object $result Result row
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $nt = Title::makeTitleSafe( NS_CATEGORY, $result->title );
+               if ( !$nt ) {
+                       return Html::element(
+                               'span',
+                               [ 'class' => 'mw-invalidtitle' ],
+                               Linker::getInvalidTitleDescription(
+                                       $this->getContext(),
+                                       NS_CATEGORY,
+                                       $result->title )
+                       );
+               }
+
+               $text = MediaWikiServices::getInstance()->getContentLanguage()
+                       ->convert( htmlspecialchars( $nt->getText() ) );
+               $plink = $this->getLinkRenderer()->makeLink( $nt, new HtmlArmor( $text ) );
+               $nlinks = $this->msg( 'nmembers' )->numParams( $result->value )->escaped();
+
+               return $this->getLanguage()->specialList( $plink, $nlinks );
+       }
+
+       protected function getGroupName() {
+               return 'highuse';
+       }
+}
diff --git a/includes/specials/SpecialMostLinkedTemplates.php b/includes/specials/SpecialMostLinkedTemplates.php
new file mode 100644 (file)
index 0000000..f7122c2
--- /dev/null
@@ -0,0 +1,132 @@
+<?php
+/**
+ * Implements Special:Mostlinkedtemplates
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ * @author Rob Church <robchur@gmail.com>
+ */
+
+use Wikimedia\Rdbms\IResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
+
+/**
+ * Special page lists templates with a large number of
+ * transclusion links, i.e. "most used" templates
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialMostLinkedTemplates extends QueryPage {
+       function __construct( $name = 'Mostlinkedtemplates' ) {
+               parent::__construct( $name );
+       }
+
+       /**
+        * Is this report expensive, i.e should it be cached?
+        *
+        * @return bool
+        */
+       public function isExpensive() {
+               return true;
+       }
+
+       /**
+        * Is there a feed available?
+        *
+        * @return bool
+        */
+       public function isSyndicated() {
+               return false;
+       }
+
+       /**
+        * Sort the results in descending order?
+        *
+        * @return bool
+        */
+       public function sortDescending() {
+               return true;
+       }
+
+       public function getQueryInfo() {
+               return [
+                       'tables' => [ 'templatelinks' ],
+                       'fields' => [
+                               'namespace' => 'tl_namespace',
+                               'title' => 'tl_title',
+                               'value' => 'COUNT(*)'
+                       ],
+                       'options' => [ 'GROUP BY' => [ 'tl_namespace', 'tl_title' ] ]
+               ];
+       }
+
+       /**
+        * Pre-cache page existence to speed up link generation
+        *
+        * @param IDatabase $db
+        * @param IResultWrapper $res
+        */
+       public function preprocessResults( $db, $res ) {
+               $this->executeLBFromResultWrapper( $res );
+       }
+
+       /**
+        * Format a result row
+        *
+        * @param Skin $skin
+        * @param object $result Result row
+        * @return string
+        */
+       public function formatResult( $skin, $result ) {
+               $title = Title::makeTitleSafe( $result->namespace, $result->title );
+               if ( !$title ) {
+                       return Html::element(
+                               'span',
+                               [ 'class' => 'mw-invalidtitle' ],
+                               Linker::getInvalidTitleDescription(
+                                       $this->getContext(),
+                                       $result->namespace,
+                                       $result->title
+                               )
+                       );
+               }
+
+               return $this->getLanguage()->specialList(
+                       $this->getLinkRenderer()->makeLink( $title ),
+                       $this->makeWlhLink( $title, $result )
+               );
+       }
+
+       /**
+        * Make a "what links here" link for a given title
+        *
+        * @param Title $title Title to make the link for
+        * @param object $result Result row
+        * @return string
+        */
+       private function makeWlhLink( $title, $result ) {
+               $wlh = SpecialPage::getTitleFor( 'Whatlinkshere', $title->getPrefixedText() );
+               $label = $this->msg( 'ntransclusions' )->numParams( $result->value )->text();
+
+               return $this->getLinkRenderer()->makeLink( $wlh, $label );
+       }
+
+       protected function getGroupName() {
+               return 'highuse';
+       }
+}
diff --git a/includes/specials/SpecialMostRevisions.php b/includes/specials/SpecialMostRevisions.php
new file mode 100644 (file)
index 0000000..60e0fe7
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Implements Special:Mostrevisions
+ *
+ * Copyright © 2005 Ævar Arnfjörð Bjarmason
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+ */
+
+class SpecialMostRevisions extends SpecialFewestRevisions {
+       function __construct( $name = 'Mostrevisions' ) {
+               parent::__construct( $name );
+       }
+
+       function sortDescending() {
+               return true;
+       }
+
+       protected function getGroupName() {
+               return 'highuse';
+       }
+}
diff --git a/includes/specials/SpecialMostcategories.php b/includes/specials/SpecialMostcategories.php
deleted file mode 100644 (file)
index 0dd9437..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-<?php
-/**
- * Implements Special:Mostcategories
- *
- * Copyright © 2005 Ævar Arnfjörð Bjarmason
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
- */
-
-use MediaWiki\MediaWikiServices;
-use Wikimedia\Rdbms\IResultWrapper;
-use Wikimedia\Rdbms\IDatabase;
-
-/**
- * A special page that list pages that have highest category count
- *
- * @ingroup SpecialPage
- */
-class MostcategoriesPage extends QueryPage {
-       function __construct( $name = 'Mostcategories' ) {
-               parent::__construct( $name );
-       }
-
-       public function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       public function getQueryInfo() {
-               return [
-                       'tables' => [ 'categorylinks', 'page' ],
-                       'fields' => [
-                               'namespace' => 'page_namespace',
-                               'title' => 'page_title',
-                               'value' => 'COUNT(*)'
-                       ],
-                       'conds' => [ 'page_namespace' =>
-                               MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces() ],
-                       'options' => [
-                               'HAVING' => 'COUNT(*) > 1',
-                               'GROUP BY' => [ 'page_namespace', 'page_title' ]
-                       ],
-                       'join_conds' => [
-                               'page' => [
-                                       'LEFT JOIN',
-                                       'page_id = cl_from'
-                               ]
-                       ]
-               ];
-       }
-
-       /**
-        * @param IDatabase $db
-        * @param IResultWrapper $res
-        */
-       function preprocessResults( $db, $res ) {
-               $this->executeLBFromResultWrapper( $res );
-       }
-
-       /**
-        * @param Skin $skin
-        * @param object $result Result row
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $title = Title::makeTitleSafe( $result->namespace, $result->title );
-               if ( !$title ) {
-                       return Html::element(
-                               'span',
-                               [ 'class' => 'mw-invalidtitle' ],
-                               Linker::getInvalidTitleDescription(
-                                       $this->getContext(),
-                                       $result->namespace,
-                                       $result->title
-                               )
-                       );
-               }
-
-               $linkRenderer = $this->getLinkRenderer();
-               if ( $this->isCached() ) {
-                       $link = $linkRenderer->makeLink( $title );
-               } else {
-                       $link = $linkRenderer->makeKnownLink( $title );
-               }
-
-               $count = $this->msg( 'ncategories' )->numParams( $result->value )->escaped();
-
-               return $this->getLanguage()->specialList( $link, $count );
-       }
-
-       protected function getGroupName() {
-               return 'highuse';
-       }
-}
diff --git a/includes/specials/SpecialMostinterwikis.php b/includes/specials/SpecialMostinterwikis.php
deleted file mode 100644 (file)
index 0fcf842..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-<?php
-/**
- * Implements Special:Mostinterwikis
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- */
-
-use MediaWiki\MediaWikiServices;
-use Wikimedia\Rdbms\IResultWrapper;
-use Wikimedia\Rdbms\IDatabase;
-
-/**
- * A special page that listed pages that have highest interwiki count
- *
- * @ingroup SpecialPage
- */
-class MostinterwikisPage extends QueryPage {
-       function __construct( $name = 'Mostinterwikis' ) {
-               parent::__construct( $name );
-       }
-
-       public function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       public function getQueryInfo() {
-               return [
-                       'tables' => [
-                               'langlinks',
-                               'page'
-                       ], 'fields' => [
-                               'namespace' => 'page_namespace',
-                               'title' => 'page_title',
-                               'value' => 'COUNT(*)'
-                       ], 'conds' => [
-                               'page_namespace' =>
-                                       MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces()
-                       ], 'options' => [
-                               'HAVING' => 'COUNT(*) > 1',
-                               'GROUP BY' => [
-                                       'page_namespace',
-                                       'page_title'
-                               ]
-                       ], 'join_conds' => [
-                               'page' => [
-                                       'LEFT JOIN',
-                                       'page_id = ll_from'
-                               ]
-                       ]
-               ];
-       }
-
-       /**
-        * Pre-fill the link cache
-        *
-        * @param IDatabase $db
-        * @param IResultWrapper $res
-        */
-       function preprocessResults( $db, $res ) {
-               $this->executeLBFromResultWrapper( $res );
-       }
-
-       /**
-        * @param Skin $skin
-        * @param object $result
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $title = Title::makeTitleSafe( $result->namespace, $result->title );
-               if ( !$title ) {
-                       return Html::element(
-                               'span',
-                               [ 'class' => 'mw-invalidtitle' ],
-                               Linker::getInvalidTitleDescription(
-                                       $this->getContext(),
-                                       $result->namespace,
-                                       $result->title
-                               )
-                       );
-               }
-
-               $linkRenderer = $this->getLinkRenderer();
-               if ( $this->isCached() ) {
-                       $link = $linkRenderer->makeLink( $title );
-               } else {
-                       $link = $linkRenderer->makeKnownLink( $title );
-               }
-
-               $count = $this->msg( 'ninterwikis' )->numParams( $result->value )->escaped();
-
-               return $this->getLanguage()->specialList( $link, $count );
-       }
-
-       protected function getGroupName() {
-               return 'highuse';
-       }
-}
diff --git a/includes/specials/SpecialMostlinked.php b/includes/specials/SpecialMostlinked.php
deleted file mode 100644 (file)
index c4553a4..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-<?php
-/**
- * Implements Special:Mostlinked
- *
- * Copyright © 2005 Ævar Arnfjörð Bjarmason, 2006 Rob Church
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
- * @author Rob Church <robchur@gmail.com>
- */
-
-use Wikimedia\Rdbms\IResultWrapper;
-use Wikimedia\Rdbms\IDatabase;
-
-/**
- * A special page to show pages ordered by the number of pages linking to them.
- *
- * @ingroup SpecialPage
- */
-class MostlinkedPage extends QueryPage {
-       function __construct( $name = 'Mostlinked' ) {
-               parent::__construct( $name );
-       }
-
-       public function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       public function getQueryInfo() {
-               return [
-                       'tables' => [ 'pagelinks', 'page' ],
-                       'fields' => [
-                               'namespace' => 'pl_namespace',
-                               'title' => 'pl_title',
-                               'value' => 'COUNT(*)',
-                               'page_namespace'
-                       ],
-                       'options' => [
-                               'HAVING' => 'COUNT(*) > 1',
-                               'GROUP BY' => [
-                                       'pl_namespace', 'pl_title',
-                                       'page_namespace'
-                               ]
-                       ],
-                       'join_conds' => [
-                               'page' => [
-                                       'LEFT JOIN',
-                                       [
-                                               'page_namespace = pl_namespace',
-                                               'page_title = pl_title'
-                                       ]
-                               ]
-                       ]
-               ];
-       }
-
-       /**
-        * Pre-fill the link cache
-        *
-        * @param IDatabase $db
-        * @param IResultWrapper $res
-        */
-       function preprocessResults( $db, $res ) {
-               $this->executeLBFromResultWrapper( $res );
-       }
-
-       /**
-        * Make a link to "what links here" for the specified title
-        *
-        * @param Title $title Title being queried
-        * @param string $caption Text to display on the link
-        * @return string
-        */
-       function makeWlhLink( $title, $caption ) {
-               $wlh = SpecialPage::getTitleFor( 'Whatlinkshere', $title->getPrefixedDBkey() );
-
-               $linkRenderer = $this->getLinkRenderer();
-               return $linkRenderer->makeKnownLink( $wlh, $caption );
-       }
-
-       /**
-        * Make links to the page corresponding to the item,
-        * and the "what links here" page for it
-        *
-        * @param Skin $skin Skin to be used
-        * @param object $result Result row
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $title = Title::makeTitleSafe( $result->namespace, $result->title );
-               if ( !$title ) {
-                       return Html::element(
-                               'span',
-                               [ 'class' => 'mw-invalidtitle' ],
-                               Linker::getInvalidTitleDescription(
-                                       $this->getContext(),
-                                       $result->namespace,
-                                       $result->title )
-                       );
-               }
-
-               $linkRenderer = $this->getLinkRenderer();
-               $link = $linkRenderer->makeLink( $title );
-               $wlh = $this->makeWlhLink(
-                       $title,
-                       $this->msg( 'nlinks' )->numParams( $result->value )->text()
-               );
-
-               return $this->getLanguage()->specialList( $link, $wlh );
-       }
-
-       protected function getGroupName() {
-               return 'highuse';
-       }
-}
diff --git a/includes/specials/SpecialMostlinkedcategories.php b/includes/specials/SpecialMostlinkedcategories.php
deleted file mode 100644 (file)
index 56a701a..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-<?php
-/**
- * Implements Special:Mostlinkedcategories
- *
- * Copyright © 2005, Ævar Arnfjörð Bjarmason
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
- */
-
-use MediaWiki\MediaWikiServices;
-use Wikimedia\Rdbms\IResultWrapper;
-use Wikimedia\Rdbms\IDatabase;
-
-/**
- * A querypage to show categories ordered in descending order by the pages in them
- *
- * @ingroup SpecialPage
- */
-class MostlinkedCategoriesPage extends QueryPage {
-       function __construct( $name = 'Mostlinkedcategories' ) {
-               parent::__construct( $name );
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       public function getQueryInfo() {
-               return [
-                       'tables' => [ 'category' ],
-                       'fields' => [ 'title' => 'cat_title',
-                               'namespace' => NS_CATEGORY,
-                               'value' => 'cat_pages' ],
-                       'conds' => [ 'cat_pages > 0' ],
-               ];
-       }
-
-       function sortDescending() {
-               return true;
-       }
-
-       /**
-        * Fetch user page links and cache their existence
-        *
-        * @param IDatabase $db
-        * @param IResultWrapper $res
-        */
-       function preprocessResults( $db, $res ) {
-               $this->executeLBFromResultWrapper( $res );
-       }
-
-       /**
-        * @param Skin $skin
-        * @param object $result Result row
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $nt = Title::makeTitleSafe( NS_CATEGORY, $result->title );
-               if ( !$nt ) {
-                       return Html::element(
-                               'span',
-                               [ 'class' => 'mw-invalidtitle' ],
-                               Linker::getInvalidTitleDescription(
-                                       $this->getContext(),
-                                       NS_CATEGORY,
-                                       $result->title )
-                       );
-               }
-
-               $text = MediaWikiServices::getInstance()->getContentLanguage()
-                       ->convert( htmlspecialchars( $nt->getText() ) );
-               $plink = $this->getLinkRenderer()->makeLink( $nt, new HtmlArmor( $text ) );
-               $nlinks = $this->msg( 'nmembers' )->numParams( $result->value )->escaped();
-
-               return $this->getLanguage()->specialList( $plink, $nlinks );
-       }
-
-       protected function getGroupName() {
-               return 'highuse';
-       }
-}
diff --git a/includes/specials/SpecialMostlinkedtemplates.php b/includes/specials/SpecialMostlinkedtemplates.php
deleted file mode 100644 (file)
index 4544468..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-<?php
-/**
- * Implements Special:Mostlinkedtemplates
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- * @author Rob Church <robchur@gmail.com>
- */
-
-use Wikimedia\Rdbms\IResultWrapper;
-use Wikimedia\Rdbms\IDatabase;
-
-/**
- * Special page lists templates with a large number of
- * transclusion links, i.e. "most used" templates
- *
- * @ingroup SpecialPage
- */
-class MostlinkedTemplatesPage extends QueryPage {
-       function __construct( $name = 'Mostlinkedtemplates' ) {
-               parent::__construct( $name );
-       }
-
-       /**
-        * Is this report expensive, i.e should it be cached?
-        *
-        * @return bool
-        */
-       public function isExpensive() {
-               return true;
-       }
-
-       /**
-        * Is there a feed available?
-        *
-        * @return bool
-        */
-       public function isSyndicated() {
-               return false;
-       }
-
-       /**
-        * Sort the results in descending order?
-        *
-        * @return bool
-        */
-       public function sortDescending() {
-               return true;
-       }
-
-       public function getQueryInfo() {
-               return [
-                       'tables' => [ 'templatelinks' ],
-                       'fields' => [
-                               'namespace' => 'tl_namespace',
-                               'title' => 'tl_title',
-                               'value' => 'COUNT(*)'
-                       ],
-                       'options' => [ 'GROUP BY' => [ 'tl_namespace', 'tl_title' ] ]
-               ];
-       }
-
-       /**
-        * Pre-cache page existence to speed up link generation
-        *
-        * @param IDatabase $db
-        * @param IResultWrapper $res
-        */
-       public function preprocessResults( $db, $res ) {
-               $this->executeLBFromResultWrapper( $res );
-       }
-
-       /**
-        * Format a result row
-        *
-        * @param Skin $skin
-        * @param object $result Result row
-        * @return string
-        */
-       public function formatResult( $skin, $result ) {
-               $title = Title::makeTitleSafe( $result->namespace, $result->title );
-               if ( !$title ) {
-                       return Html::element(
-                               'span',
-                               [ 'class' => 'mw-invalidtitle' ],
-                               Linker::getInvalidTitleDescription(
-                                       $this->getContext(),
-                                       $result->namespace,
-                                       $result->title
-                               )
-                       );
-               }
-
-               return $this->getLanguage()->specialList(
-                       $this->getLinkRenderer()->makeLink( $title ),
-                       $this->makeWlhLink( $title, $result )
-               );
-       }
-
-       /**
-        * Make a "what links here" link for a given title
-        *
-        * @param Title $title Title to make the link for
-        * @param object $result Result row
-        * @return string
-        */
-       private function makeWlhLink( $title, $result ) {
-               $wlh = SpecialPage::getTitleFor( 'Whatlinkshere', $title->getPrefixedText() );
-               $label = $this->msg( 'ntransclusions' )->numParams( $result->value )->text();
-
-               return $this->getLinkRenderer()->makeLink( $wlh, $label );
-       }
-
-       protected function getGroupName() {
-               return 'highuse';
-       }
-}
diff --git a/includes/specials/SpecialMostrevisions.php b/includes/specials/SpecialMostrevisions.php
deleted file mode 100644 (file)
index 0471caf..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-/**
- * Implements Special:Mostrevisions
- *
- * Copyright © 2005 Ævar Arnfjörð Bjarmason
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
- */
-
-class MostrevisionsPage extends FewestrevisionsPage {
-       function __construct( $name = 'Mostrevisions' ) {
-               parent::__construct( $name );
-       }
-
-       function sortDescending() {
-               return true;
-       }
-
-       protected function getGroupName() {
-               return 'highuse';
-       }
-}
diff --git a/includes/specials/SpecialNewFiles.php b/includes/specials/SpecialNewFiles.php
new file mode 100644 (file)
index 0000000..29e7789
--- /dev/null
@@ -0,0 +1,226 @@
+<?php
+/**
+ * Implements Special:Newimages
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+use MediaWiki\MediaWikiServices;
+
+class SpecialNewFiles extends IncludableSpecialPage {
+       /** @var FormOptions */
+       protected $opts;
+
+       /** @var string[] */
+       protected $mediaTypes;
+
+       public function __construct() {
+               parent::__construct( 'Newimages' );
+       }
+
+       public function execute( $par ) {
+               $context = new DerivativeContext( $this->getContext() );
+
+               $this->setHeaders();
+               $this->outputHeader();
+               $mimeAnalyzer = MediaWiki\MediaWikiServices::getInstance()->getMimeAnalyzer();
+               $this->mediaTypes = $mimeAnalyzer->getMediaTypes();
+
+               $out = $this->getOutput();
+               $this->addHelpLink( 'Help:New images' );
+
+               $opts = new FormOptions();
+
+               $opts->add( 'like', '' );
+               $opts->add( 'user', '' );
+               $opts->add( 'showbots', false );
+               $opts->add( 'hidepatrolled', false );
+               $opts->add( 'mediatype', $this->mediaTypes );
+               $opts->add( 'limit', 50 );
+               $opts->add( 'offset', '' );
+               $opts->add( 'start', '' );
+               $opts->add( 'end', '' );
+
+               $opts->fetchValuesFromRequest( $this->getRequest() );
+
+               if ( $par !== null ) {
+                       $opts->setValue( is_numeric( $par ) ? 'limit' : 'like', $par );
+               }
+
+               // If start date comes after end date chronologically, swap them.
+               // They are swapped in the interface by JS.
+               $start = $opts->getValue( 'start' );
+               $end = $opts->getValue( 'end' );
+               if ( $start !== '' && $end !== '' && $start > $end ) {
+                       $temp = $end;
+                       $end = $start;
+                       $start = $temp;
+
+                       $opts->setValue( 'start', $start, true );
+                       $opts->setValue( 'end', $end, true );
+
+                       // also swap values in request object, which is used by HTMLForm
+                       // to pre-populate the fields with the previous input
+                       $request = $context->getRequest();
+                       $context->setRequest( new DerivativeRequest(
+                               $request,
+                               [ 'start' => $start, 'end' => $end ] + $request->getValues(),
+                               $request->wasPosted()
+                       ) );
+               }
+
+               // if all media types have been selected, wipe out the array to prevent
+               // the pointless IN(...) query condition (which would have no effect
+               // because every possible type has been selected)
+               $missingMediaTypes = array_diff( $this->mediaTypes, $opts->getValue( 'mediatype' ) );
+               if ( empty( $missingMediaTypes ) ) {
+                       $opts->setValue( 'mediatype', [] );
+               }
+
+               $opts->validateIntBounds( 'limit', 0, 500 );
+
+               $this->opts = $opts;
+
+               if ( !$this->including() ) {
+                       $this->setTopText();
+                       $this->buildForm( $context );
+               }
+
+               $pager = new NewFilesPager( $context, $opts, $this->getLinkRenderer() );
+
+               $out->addHTML( $pager->getBody() );
+               if ( !$this->including() ) {
+                       $out->addHTML( $pager->getNavigationBar() );
+               }
+       }
+
+       protected function buildForm( IContextSource $context ) {
+               $mediaTypesText = array_map( function ( $type ) {
+                       // mediastatistics-header-unknown, mediastatistics-header-bitmap,
+                       // mediastatistics-header-drawing, mediastatistics-header-audio,
+                       // mediastatistics-header-video, mediastatistics-header-multimedia,
+                       // mediastatistics-header-office, mediastatistics-header-text,
+                       // mediastatistics-header-executable, mediastatistics-header-archive,
+                       // mediastatistics-header-3d,
+                       return $this->msg( 'mediastatistics-header-' . strtolower( $type ) )->text();
+               }, $this->mediaTypes );
+               $mediaTypesOptions = array_combine( $mediaTypesText, $this->mediaTypes );
+               ksort( $mediaTypesOptions );
+
+               $formDescriptor = [
+                       'like' => [
+                               'type' => 'text',
+                               'label-message' => 'newimages-label',
+                               'name' => 'like',
+                       ],
+
+                       'user' => [
+                               'class' => 'HTMLUserTextField',
+                               'label-message' => 'newimages-user',
+                               'name' => 'user',
+                       ],
+
+                       'showbots' => [
+                               'type' => 'check',
+                               'label-message' => 'newimages-showbots',
+                               'name' => 'showbots',
+                       ],
+
+                       'hidepatrolled' => [
+                               'type' => 'check',
+                               'label-message' => 'newimages-hidepatrolled',
+                               'name' => 'hidepatrolled',
+                       ],
+
+                       'mediatype' => [
+                               'type' => 'multiselect',
+                               'flatlist' => true,
+                               'name' => 'mediatype',
+                               'label-message' => 'newimages-mediatype',
+                               'options' => $mediaTypesOptions,
+                               'default' => $this->mediaTypes,
+                       ],
+
+                       'limit' => [
+                               'type' => 'hidden',
+                               'default' => $this->opts->getValue( 'limit' ),
+                               'name' => 'limit',
+                       ],
+
+                       'offset' => [
+                               'type' => 'hidden',
+                               'default' => $this->opts->getValue( 'offset' ),
+                               'name' => 'offset',
+                       ],
+
+                       'start' => [
+                               'type' => 'date',
+                               'label-message' => 'date-range-from',
+                               'name' => 'start',
+                       ],
+
+                       'end' => [
+                               'type' => 'date',
+                               'label-message' => 'date-range-to',
+                               'name' => 'end',
+                       ],
+               ];
+
+               if ( $this->getConfig()->get( 'MiserMode' ) ) {
+                       unset( $formDescriptor['like'] );
+               }
+
+               if ( !$this->getUser()->useFilePatrol() ) {
+                       unset( $formDescriptor['hidepatrolled'] );
+               }
+
+               HTMLForm::factory( 'ooui', $formDescriptor, $context )
+                       // For the 'multiselect' field values to be preserved on submit
+                       ->setFormIdentifier( 'specialnewimages' )
+                       ->setWrapperLegendMsg( 'newimages-legend' )
+                       ->setSubmitTextMsg( 'ilsubmit' )
+                       ->setMethod( 'get' )
+                       ->prepareForm()
+                       ->displayForm( false );
+       }
+
+       protected function getGroupName() {
+               return 'changes';
+       }
+
+       /**
+        * Send the text to be displayed above the options
+        */
+       function setTopText() {
+               $message = $this->msg( 'newimagestext' )->inContentLanguage();
+               if ( !$message->isDisabled() ) {
+                       $contLang = MediaWikiServices::getInstance()->getContentLanguage();
+                       $this->getOutput()->addWikiTextAsContent(
+                               Html::rawElement( 'div',
+                                       [
+
+                                               'lang' => $contLang->getHtmlCode(),
+                                               'dir' => $contLang->getDir()
+                                       ],
+                                       "\n" . $message->plain() . "\n"
+                               )
+                       );
+               }
+       }
+}
diff --git a/includes/specials/SpecialNewimages.php b/includes/specials/SpecialNewimages.php
deleted file mode 100644 (file)
index 29e7789..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-<?php
-/**
- * Implements Special:Newimages
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- */
-
-use MediaWiki\MediaWikiServices;
-
-class SpecialNewFiles extends IncludableSpecialPage {
-       /** @var FormOptions */
-       protected $opts;
-
-       /** @var string[] */
-       protected $mediaTypes;
-
-       public function __construct() {
-               parent::__construct( 'Newimages' );
-       }
-
-       public function execute( $par ) {
-               $context = new DerivativeContext( $this->getContext() );
-
-               $this->setHeaders();
-               $this->outputHeader();
-               $mimeAnalyzer = MediaWiki\MediaWikiServices::getInstance()->getMimeAnalyzer();
-               $this->mediaTypes = $mimeAnalyzer->getMediaTypes();
-
-               $out = $this->getOutput();
-               $this->addHelpLink( 'Help:New images' );
-
-               $opts = new FormOptions();
-
-               $opts->add( 'like', '' );
-               $opts->add( 'user', '' );
-               $opts->add( 'showbots', false );
-               $opts->add( 'hidepatrolled', false );
-               $opts->add( 'mediatype', $this->mediaTypes );
-               $opts->add( 'limit', 50 );
-               $opts->add( 'offset', '' );
-               $opts->add( 'start', '' );
-               $opts->add( 'end', '' );
-
-               $opts->fetchValuesFromRequest( $this->getRequest() );
-
-               if ( $par !== null ) {
-                       $opts->setValue( is_numeric( $par ) ? 'limit' : 'like', $par );
-               }
-
-               // If start date comes after end date chronologically, swap them.
-               // They are swapped in the interface by JS.
-               $start = $opts->getValue( 'start' );
-               $end = $opts->getValue( 'end' );
-               if ( $start !== '' && $end !== '' && $start > $end ) {
-                       $temp = $end;
-                       $end = $start;
-                       $start = $temp;
-
-                       $opts->setValue( 'start', $start, true );
-                       $opts->setValue( 'end', $end, true );
-
-                       // also swap values in request object, which is used by HTMLForm
-                       // to pre-populate the fields with the previous input
-                       $request = $context->getRequest();
-                       $context->setRequest( new DerivativeRequest(
-                               $request,
-                               [ 'start' => $start, 'end' => $end ] + $request->getValues(),
-                               $request->wasPosted()
-                       ) );
-               }
-
-               // if all media types have been selected, wipe out the array to prevent
-               // the pointless IN(...) query condition (which would have no effect
-               // because every possible type has been selected)
-               $missingMediaTypes = array_diff( $this->mediaTypes, $opts->getValue( 'mediatype' ) );
-               if ( empty( $missingMediaTypes ) ) {
-                       $opts->setValue( 'mediatype', [] );
-               }
-
-               $opts->validateIntBounds( 'limit', 0, 500 );
-
-               $this->opts = $opts;
-
-               if ( !$this->including() ) {
-                       $this->setTopText();
-                       $this->buildForm( $context );
-               }
-
-               $pager = new NewFilesPager( $context, $opts, $this->getLinkRenderer() );
-
-               $out->addHTML( $pager->getBody() );
-               if ( !$this->including() ) {
-                       $out->addHTML( $pager->getNavigationBar() );
-               }
-       }
-
-       protected function buildForm( IContextSource $context ) {
-               $mediaTypesText = array_map( function ( $type ) {
-                       // mediastatistics-header-unknown, mediastatistics-header-bitmap,
-                       // mediastatistics-header-drawing, mediastatistics-header-audio,
-                       // mediastatistics-header-video, mediastatistics-header-multimedia,
-                       // mediastatistics-header-office, mediastatistics-header-text,
-                       // mediastatistics-header-executable, mediastatistics-header-archive,
-                       // mediastatistics-header-3d,
-                       return $this->msg( 'mediastatistics-header-' . strtolower( $type ) )->text();
-               }, $this->mediaTypes );
-               $mediaTypesOptions = array_combine( $mediaTypesText, $this->mediaTypes );
-               ksort( $mediaTypesOptions );
-
-               $formDescriptor = [
-                       'like' => [
-                               'type' => 'text',
-                               'label-message' => 'newimages-label',
-                               'name' => 'like',
-                       ],
-
-                       'user' => [
-                               'class' => 'HTMLUserTextField',
-                               'label-message' => 'newimages-user',
-                               'name' => 'user',
-                       ],
-
-                       'showbots' => [
-                               'type' => 'check',
-                               'label-message' => 'newimages-showbots',
-                               'name' => 'showbots',
-                       ],
-
-                       'hidepatrolled' => [
-                               'type' => 'check',
-                               'label-message' => 'newimages-hidepatrolled',
-                               'name' => 'hidepatrolled',
-                       ],
-
-                       'mediatype' => [
-                               'type' => 'multiselect',
-                               'flatlist' => true,
-                               'name' => 'mediatype',
-                               'label-message' => 'newimages-mediatype',
-                               'options' => $mediaTypesOptions,
-                               'default' => $this->mediaTypes,
-                       ],
-
-                       'limit' => [
-                               'type' => 'hidden',
-                               'default' => $this->opts->getValue( 'limit' ),
-                               'name' => 'limit',
-                       ],
-
-                       'offset' => [
-                               'type' => 'hidden',
-                               'default' => $this->opts->getValue( 'offset' ),
-                               'name' => 'offset',
-                       ],
-
-                       'start' => [
-                               'type' => 'date',
-                               'label-message' => 'date-range-from',
-                               'name' => 'start',
-                       ],
-
-                       'end' => [
-                               'type' => 'date',
-                               'label-message' => 'date-range-to',
-                               'name' => 'end',
-                       ],
-               ];
-
-               if ( $this->getConfig()->get( 'MiserMode' ) ) {
-                       unset( $formDescriptor['like'] );
-               }
-
-               if ( !$this->getUser()->useFilePatrol() ) {
-                       unset( $formDescriptor['hidepatrolled'] );
-               }
-
-               HTMLForm::factory( 'ooui', $formDescriptor, $context )
-                       // For the 'multiselect' field values to be preserved on submit
-                       ->setFormIdentifier( 'specialnewimages' )
-                       ->setWrapperLegendMsg( 'newimages-legend' )
-                       ->setSubmitTextMsg( 'ilsubmit' )
-                       ->setMethod( 'get' )
-                       ->prepareForm()
-                       ->displayForm( false );
-       }
-
-       protected function getGroupName() {
-               return 'changes';
-       }
-
-       /**
-        * Send the text to be displayed above the options
-        */
-       function setTopText() {
-               $message = $this->msg( 'newimagestext' )->inContentLanguage();
-               if ( !$message->isDisabled() ) {
-                       $contLang = MediaWikiServices::getInstance()->getContentLanguage();
-                       $this->getOutput()->addWikiTextAsContent(
-                               Html::rawElement( 'div',
-                                       [
-
-                                               'lang' => $contLang->getHtmlCode(),
-                                               'dir' => $contLang->getDir()
-                                       ],
-                                       "\n" . $message->plain() . "\n"
-                               )
-                       );
-               }
-       }
-}
index 50867dd..82d8b73 100644 (file)
@@ -90,7 +90,9 @@ class SpecialRedirect extends FormSpecialPage {
                }
                $userpage = Title::makeTitle( NS_USER, $username );
 
-               return Status::newGood( $userpage->getFullURL( '', false, PROTO_CURRENT ) );
+               return Status::newGood( [
+                       $userpage->getFullURL( '', false, PROTO_CURRENT ), 302
+               ] );
        }
 
        /**
diff --git a/includes/specials/SpecialShortPages.php b/includes/specials/SpecialShortPages.php
new file mode 100644 (file)
index 0000000..f1bd065
--- /dev/null
@@ -0,0 +1,182 @@
+<?php
+/**
+ * Implements Special:Shortpages
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+use MediaWiki\MediaWikiServices;
+use Wikimedia\Rdbms\IResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
+
+/**
+ * SpecialShortpages extends QueryPage. It is used to return the shortest
+ * pages in the database.
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialShortPages extends QueryPage {
+
+       function __construct( $name = 'Shortpages' ) {
+               parent::__construct( $name );
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       public function getQueryInfo() {
+               $config = $this->getConfig();
+               $blacklist = $config->get( 'ShortPagesNamespaceBlacklist' );
+               $tables = [ 'page' ];
+               $conds = [
+                       'page_namespace' => array_diff(
+                               MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces(),
+                               $blacklist
+                       ),
+                       'page_is_redirect' => 0
+               ];
+               $joinConds = [];
+               $options = [ 'USE INDEX' => [ 'page' => 'page_redirect_namespace_len' ] ];
+
+               // Allow extensions to modify the query
+               Hooks::run( 'ShortPagesQuery', [ &$tables, &$conds, &$joinConds, &$options ] );
+
+               return [
+                       'tables' => $tables,
+                       'fields' => [
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'page_len'
+                       ],
+                       'conds' => $conds,
+                       'join_conds' => $joinConds,
+                       'options' => $options
+               ];
+       }
+
+       public function reallyDoQuery( $limit, $offset = false ) {
+               $fname = static::class . '::reallyDoQuery';
+               $dbr = $this->getRecacheDB();
+               $query = $this->getQueryInfo();
+               $order = $this->getOrderFields();
+
+               if ( $this->sortDescending() ) {
+                       foreach ( $order as &$field ) {
+                               $field .= ' DESC';
+                       }
+               }
+
+               $tables = isset( $query['tables'] ) ? (array)$query['tables'] : [];
+               $fields = isset( $query['fields'] ) ? (array)$query['fields'] : [];
+               $conds = isset( $query['conds'] ) ? (array)$query['conds'] : [];
+               $options = isset( $query['options'] ) ? (array)$query['options'] : [];
+               $join_conds = isset( $query['join_conds'] ) ? (array)$query['join_conds'] : [];
+
+               if ( $limit !== false ) {
+                       $options['LIMIT'] = intval( $limit