wiki.techinc.nl/includes/specials/SpecialRedirect.php
Umherirrender 237ef2a624 Replace deprecated User::newFromId on Special:Redirect
Change-Id: I3a4f995e4cfb4dfe68b50662aebf795e3bb78b4a
2021-03-19 20:47:26 +00:00

375 lines
9.7 KiB
PHP

<?php
/**
* Implements Special:Redirect
*
* 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\User\UserFactory;
/**
* A special page that redirects to: the user for a numeric user id,
* the file for a given filename, or the page for a given revision id.
*
* @ingroup SpecialPage
* @since 1.22
*/
class SpecialRedirect extends FormSpecialPage {
/**
* The type of the redirect (user/file/revision)
*
* Example value: `'user'`
*
* @var string
*/
protected $mType;
/**
* The identifier/value for the redirect (which id, which file)
*
* Example value: `'42'`
*
* @var string
*/
protected $mValue;
/** @var RepoGroup */
private $repoGroup;
/** @var UserFactory */
private $userFactory;
/**
* @param RepoGroup $repoGroup
* @param UserFactory $userFactory
*/
public function __construct(
RepoGroup $repoGroup,
UserFactory $userFactory
) {
parent::__construct( 'Redirect' );
$this->mType = null;
$this->mValue = null;
$this->repoGroup = $repoGroup;
$this->userFactory = $userFactory;
}
/**
* Set $mType and $mValue based on parsed value of $subpage.
* @param string $subpage
*/
public function setParameter( $subpage ) {
// parse $subpage to pull out the parts
$parts = explode( '/', $subpage, 2 );
$this->mType = $parts[0];
$this->mValue = $parts[1] ?? null;
}
/**
* Handle Special:Redirect/user/xxxx (by redirecting to User:YYYY)
*
* @return Status A good status contains the url to redirect to
*/
public function dispatchUser() {
if ( !ctype_digit( $this->mValue ) ) {
// Message: redirect-not-numeric
return Status::newFatal( $this->getMessagePrefix() . '-not-numeric' );
}
$user = $this->userFactory->newFromId( (int)$this->mValue );
$user->load(); // Make sure the id is validated by loading the user
if ( $user->isAnon() ) {
// Message: redirect-not-exists
return Status::newFatal( $this->getMessagePrefix() . '-not-exists' );
}
if ( $user->isHidden() && !$this->getAuthority()->isAllowed( 'hideuser' ) ) {
throw new PermissionsError( null, [ 'badaccess-group0' ] );
}
return Status::newGood( [
$user->getUserPage()->getFullURL( '', false, PROTO_CURRENT ), 302
] );
}
/**
* Handle Special:Redirect/file/xxxx
*
* @return Status A good status contains the url to redirect to
*/
public function dispatchFile() {
try {
$title = Title::newFromTextThrow( $this->mValue, NS_FILE );
if ( $title && !$title->inNamespace( NS_FILE ) ) {
// If the given value contains a namespace enforce file namespace
$title = Title::newFromTextThrow( Title::makeName( NS_FILE, $this->mValue ) );
}
} catch ( MalformedTitleException $e ) {
return Status::newFatal( $e->getMessageObject() );
}
$file = $this->repoGroup->findFile( $title );
if ( !$file || !$file->exists() ) {
// Message: redirect-not-exists
return Status::newFatal( $this->getMessagePrefix() . '-not-exists' );
}
// Default behavior: Use the direct link to the file.
$url = $file->getUrl();
$request = $this->getRequest();
$width = $request->getInt( 'width', -1 );
$height = $request->getInt( 'height', -1 );
// If a width is requested...
if ( $width != -1 ) {
$mto = $file->transform( [ 'width' => $width, 'height' => $height ] );
// ... and we can
if ( $mto && !$mto->isError() ) {
// ... change the URL to point to a thumbnail.
// Note: This url is more temporary as can change
// if file is reuploaded and has different aspect ratio.
$url = [ $mto->getUrl(), $height === -1 ? 301 : 302 ];
}
}
return Status::newGood( $url );
}
/**
* Handle Special:Redirect/revision/xxx
* (by redirecting to index.php?oldid=xxx)
*
* @return Status A good status contains the url to redirect to
*/
public function dispatchRevision() {
$oldid = $this->mValue;
if ( !ctype_digit( $oldid ) ) {
// Message: redirect-not-numeric
return Status::newFatal( $this->getMessagePrefix() . '-not-numeric' );
}
$oldid = (int)$oldid;
if ( $oldid === 0 ) {
// Message: redirect-not-exists
return Status::newFatal( $this->getMessagePrefix() . '-not-exists' );
}
return Status::newGood( wfAppendQuery( wfScript( 'index' ), [
'oldid' => $oldid
] ) );
}
/**
* Handle Special:Redirect/page/xxx (by redirecting to index.php?curid=xxx)
*
* @return Status A good status contains the url to redirect to
*/
public function dispatchPage() {
$curid = $this->mValue;
if ( !ctype_digit( $curid ) ) {
// Message: redirect-not-numeric
return Status::newFatal( $this->getMessagePrefix() . '-not-numeric' );
}
$curid = (int)$curid;
if ( $curid === 0 ) {
// Message: redirect-not-exists
return Status::newFatal( $this->getMessagePrefix() . '-not-exists' );
}
return Status::newGood( wfAppendQuery( wfScript( 'index' ), [
'curid' => $curid
] ) );
}
/**
* Handle Special:Redirect/logid/xxx
* (by redirecting to index.php?title=Special:Log&logid=xxx)
*
* @since 1.27
* @return Status A good status contains the url to redirect to
*/
public function dispatchLog() {
$logid = $this->mValue;
if ( !ctype_digit( $logid ) ) {
// Message: redirect-not-numeric
return Status::newFatal( $this->getMessagePrefix() . '-not-numeric' );
}
$logid = (int)$logid;
if ( $logid === 0 ) {
// Message: redirect-not-exists
return Status::newFatal( $this->getMessagePrefix() . '-not-exists' );
}
$query = [ 'title' => 'Special:Log', 'logid' => $logid ];
return Status::newGood( wfAppendQuery( wfScript( 'index' ), $query ) );
}
/**
* Use appropriate dispatch* method to obtain a redirection URL,
* and either: redirect, set a 404 error code and error message,
* or do nothing (if $mValue wasn't set) allowing the form to be
* displayed.
*
* @return Status|bool True if a redirect was successfully handled.
*/
private function dispatch() {
// the various namespaces supported by Special:Redirect
switch ( $this->mType ) {
case 'user':
$status = $this->dispatchUser();
break;
case 'file':
$status = $this->dispatchFile();
break;
case 'revision':
$status = $this->dispatchRevision();
break;
case 'page':
$status = $this->dispatchPage();
break;
case 'logid':
$status = $this->dispatchLog();
break;
default:
$status = null;
break;
}
if ( $status && $status->isGood() ) {
// These urls can sometimes be linked from prominent places,
// so varnish cache.
$value = $status->getValue();
if ( is_array( $value ) ) {
list( $url, $code ) = $value;
} else {
$url = $value;
$code = 301;
}
if ( $code === 301 ) {
$this->getOutput()->setCdnMaxage( 60 * 60 );
} else {
$this->getOutput()->setCdnMaxage( 10 );
}
$this->getOutput()->redirect( $url, $code );
return true;
}
if ( $this->mValue !== null ) {
$this->getOutput()->setStatusCode( 404 );
return $status;
}
return false;
}
protected function getFormFields() {
$mp = $this->getMessagePrefix();
$ns = [
// subpage => message
// Messages: redirect-user, redirect-page, redirect-revision,
// redirect-file, redirect-logid
'user' => $mp . '-user',
'page' => $mp . '-page',
'revision' => $mp . '-revision',
'file' => $mp . '-file',
'logid' => $mp . '-logid',
];
$a = [];
$a['type'] = [
'type' => 'select',
'label-message' => $mp . '-lookup', // Message: redirect-lookup
'options' => [],
'default' => current( array_keys( $ns ) ),
];
foreach ( $ns as $n => $m ) {
$m = $this->msg( $m )->text();
$a['type']['options'][$m] = $n;
}
$a['value'] = [
'type' => 'text',
'label-message' => $mp . '-value' // Message: redirect-value
];
// set the defaults according to the parsed subpage path
if ( !empty( $this->mType ) ) {
$a['type']['default'] = $this->mType;
}
if ( !empty( $this->mValue ) ) {
$a['value']['default'] = $this->mValue;
}
return $a;
}
public function onSubmit( array $data ) {
if ( !empty( $data['type'] ) && !empty( $data['value'] ) ) {
$this->setParameter( $data['type'] . '/' . $data['value'] );
}
/* if this returns false, will show the form */
return $this->dispatch();
}
public function onSuccess() {
/* do nothing, we redirect in $this->dispatch if successful. */
}
protected function alterForm( HTMLForm $form ) {
/* display summary at top of page */
$this->outputHeader();
// tweak label on submit button
// Message: redirect-submit
$form->setSubmitTextMsg( $this->getMessagePrefix() . '-submit' );
/* submit form every time */
$form->setMethod( 'get' );
}
protected function getDisplayFormat() {
return 'ooui';
}
/**
* Return an array of subpages that this special page will accept.
*
* @return string[] subpages
*/
protected function getSubpagesForPrefixSearch() {
return [
'file',
'page',
'revision',
'user',
'logid',
];
}
/**
* @return bool
*/
public function requiresWrite() {
return false;
}
/**
* @return bool
*/
public function requiresUnblock() {
return false;
}
protected function getGroupName() {
return 'redirects';
}
}