CleanupSite

Материал из Викисфера
Перейти к навигации Перейти к поиску

CleanupSite — расширение для MediaWiki. Авторы — Oversighted494 и Edward Chernenko.

Описание[править | править код]

Позволяет выполнять следующие действия:

  • скрывать (отмечая как правки бота) и раскрывать правки из свежих правок, а также удалять их;
  • удалять отдельные блокировки;
  • удалять записи из журналов.

Технически удаление реализуется через изменение записей базы данных или их перенос в другие таблицы. Все эти удаления могут быть отменены системным администратором.

Протестировано на MediaWiki 1.16.5 и 1.18.

ВНИМАНИЕ: корректность работы достоверно не проверена.

Установка[править | править код]

Для установки расширения выполните файл cleanupsite.sql, чтобы добавить необходимые таблицы базы данных.

Затем скопируйте в папку $IP/extensions/CleanupSite файлы расширения:

Добавьте в файл LocalSettings.php строчку require_once( "$IP/extensions/CleanupSite/CleanupSite.php" ); и определите при помощи $wgGroupPermissions права доступа cleanupsite (позволяет использовать все функции расширения) и cleanupsite-log (позволяет просматривать журнал совершенных при помощи расширения действий).

Исходный код[править | править код]

CleanupSite.php[править | править код]

<?php

if ( !defined( 'MEDIAWIKI' ) ) {
	echo "Not a executable file";
	exit( 1 );
}

$wgExtensionCredits['specialpage'][] = array (
	'name' => 'CleanupSite',
	'descriptionmsg' => 'cleanupsite-desc',
	'url' => 'http://wikisfera.shoutwiki.com/wiki/CleanupSite',
	'author' => array ('Anonymous', 'Edward Chernenko'),
	'version' => '1.1'
);

$wgAvailableRights[] = 'cleanupsite';
$wgAvailableRights[] = 'cleanupsite-log';

$wgSpecialPages['CleanupSite'] = 'CleanupSite';
$wgSpecialPageGroups['CleanupSite'] = 'wiki';
$wgAutoloadClasses['CleanupSite'] = dirname( __FILE__ ) . '/CleanupSite_body.php';
$wgExtensionMessagesFiles['CleanupSite'] = dirname( __FILE__ ) . '/CleanupSite.i18n.php';

$wgLogTypes[] = 'cleanupsite';
$wgLogNames['cleanupsite'] = 'cleanupsite_logpagename';
$wgLogRestrictions['cleanupsite'] = 'cleanupsite-log';
$wgLogHeaders['cleanupsite'] = 'cleanupsite_logpagetext';
$wgLogActions['cleanupsite/cleanupsite'] = 'cleanupsite_logentry';
$wgLogActions['cleanupsite/rc_hide'] = 'cleanupsite_log_rc_hide';
$wgLogActions['cleanupsite/rc_unhide'] = 'cleanupsite_log_rc_unhide';
$wgLogActions['cleanupsite/rc_delete'] = 'cleanupsite_log_rc_delete';
$wgLogActions['cleanupsite/ipblocks'] = 'cleanupsite_log_ipblocks';
$wgLogActions['cleanupsite/logs'] = 'cleanupsite_log_logs';

$wgCleanupSiteRCLimit = 250;
$wgCleanupSiteIpbLimit = 100;
$wgCleanupSiteLogsLimit = 100;

CleanupSite_body.php[править | править код]

<?php

class CleanupSite extends SpecialPage {
	function __construct()
	{
		SpecialPage::SpecialPage( 'CleanupSite', 'cleanupsite' );
	}
	
	public function execute( $subpage ) {
		global $wgOut, $wgUser, $wgArticlePath;
		wfLoadExtensionMessages('CleanupSite');
		
		$view = 'CleanupSiteViewHome';
		
		if ( !$wgUser->isAllowed( 'cleanupsite' ) ) {
			$this->displayRestrictionError();
			return;
		}
		
		$params = explode( '/', $subpage );
		$params = array_values( $params );
		
		if ( $subpage == 'recentchanges' ) {
			$view = 'CleanupRecentChanges';
		}
		
		if ( $subpage == 'ipblocks' ) {
			$view = 'CleanupIPBlocks';
		}
		
		if ( $subpage == 'logs' ) {
			$view = 'CleanupLogs';
		}
		
		$v = new $view( $this, $params );
		$v->subpage = $subpage;
		$v->show();
	}
}

abstract class CleanupSiteView {
	var $subpage;
	
	function __construct( $page, $params ) {
		$this->mPage = $page;
		$this->mParams = $params;
	}

	function getTitle( $subpage = '' ) {
		return $this->mPage->getTitle( $subpage );
	}
	
	abstract function show();
}

class CleanupSiteViewHome extends CleanupSiteView {
	function show() {
		global $wgOut, $wgArticlePath, $wgUser;
		$wgOut->setPagetitle( wfMsg( 'cleanupsite' ) );
		
		$subpages = array( 'recentchanges', 'ipblocks', 'logs' );
		$path = str_replace('$1', '', $wgArticlePath);
		
		$wgOut->addWikiMsg( 'cleanupsite-about' );
		
		$wgOut->addHTML('<ul>');
		
		foreach ($subpages as $page) {
			$wgOut->addHTML('<li><a href="' . $path . 'Special:CleanupSite/' . $page . '">' . wfMsg( 'cleanupsite-sub-' . $page ) . '</a></li>' );
		}
		
		$wgOut->addHTML('</ul>');
	}
}

class CleanupRecentChanges extends CleanupSiteView {
	function show() {
		global $wgOut, $wgUser, $wgRequest;

		$action = $wgRequest->getVal( 'action', $this->subpage );
		if ( $action == 'recentchanges' ) {
			$wgOut->setPagetitle( wfMsg( 'cleanupsite-sub-recentchanges' ) );
			$wgOut->addWikiMsg( 'cleanupsite-recentchanges-about' );
			
			$topmessage = wfMsg('cleanupsite-recentchanges-topmessage');
			$rccount = wfMsg('cleanupsite-recentchanges-rccount');
			$button = wfMsg('htmlform-submit');
				
			$wgOut->addHTML(
				Xml::fieldset( $topmessage ) . Xml::openElement( 'form', array( 'id' => 'mw-cleanupsite-rc', 'method' => 'post' ) ) .
				Xml::openElement( 'table', array( 'id' => "mw-cleanupsite-rc-table" ) ) .
				'<tr><td class="mw-label">' . Xml::label( $rccount, 'mw-cleanupsite-rccount' ) . '</td>' .
				'<td class="mw-input">' .  Xml::input( 'wpRCCount', 20, '', array( 'tabindex' => '1', 'id' => 'mw-cleanupsite-rccount', 'maxlength' => '3' ) ) . '</td></tr>' .
				'<tr><td></td><td class="mw-submit">' . Xml::submitButton( $button, array( 'id' => 'mw-cleanupsite-rc-submit' ) ) . '</td></tr>' .
				'<input type=hidden name="action" value="submit" />' .
				Xml::closeElement( 'table' ) . Xml::closeElement( 'form' ) . Xml::closeElement( 'fieldset' )
			);
		}
		
		$id = $wgRequest->getVal( 'id' );
		$idmessage = wfMsg('cleanupsite-recentchanges-idmessage');
		$revisionmessage = wfMsg('cleanupsite-recentchanges-revisionmessage');
		$reasonmessage = wfMsg('cleanupsite-recentchanges-reasonmessage');
		if ( $action == 'hide' ) {
			$wgOut->setPagetitle( wfMsg( 'cleanupsite-recentchanges-hide', array( "$id" ) ) );
		
			$topmessage = wfMsg('cleanupsite-recentchanges-hide-topmessage');
			$button = wfMsg('cleanupsite-submit-hide');
			
			$id = intval($id);
			
			$dbr = wfGetDB( DB_MASTER );
			$res = $dbr->query("SELECT * FROM recentchanges WHERE rc_id = " . $id . " LIMIT 1");
			$row = $dbr->fetchObject( $res );
			
			if (!$row) {
				$wgOut->addWikiMsg('cleanupsite-error-falseid');
				return;
			}
			
			$bot = $row->rc_bot;
			if ( $bot == 1 ) {
				$wgOut->addWikiMsg('cleanupsite-error-hidden');
				return;
			}
			
			$timestamp = $row->rc_timestamp;
			$user = htmlspecialchars( $row->rc_user_text );
			$namespace = $row->rc_namespace;
			$title = htmlspecialchars( $row->rc_title );
			$comment = htmlspecialchars( $row->rc_comment );
			$log_type = $row->rc_log_type;
			$log_action = $row->rc_log_action;
			if ( $log_action ) {
				$logging = "$log_type/$log_action";
			} else {
				$logging = "$namespace";
			}
			
			$wgOut->addHTML(
				Xml::fieldset( $topmessage ) . Xml::openElement( 'form', array( 'id' => 'mw-cleanupsite-rc-hide', 'method' => 'post' ) ) .
				Xml::openElement( 'table', array( 'id' => "mw-cleanupsite-rc-table" ) ) .
				'<tr><td class="mw-label">' . Xml::label( $idmessage, 'mw-cleanupsite-id' ) . '</td>' .
				'<td><code>' . $id . '</code></td></tr>' .
				'<tr><td class="mw-label">' . Xml::label( $revisionmessage, 'mw-cleanupsite-revision' ) . '</td>' .
				'<td><i>' . $timestamp . ' ' . $user . ' ' . $logging . ' ' . $title . ' ' . $comment . '</i></td>' .
				'<tr><td class="mw-label">' . Xml::label( $reasonmessage, 'mw-cleanupsite-reason' ) . '</td>' .
				'<td class="mw-input">' .  Xml::input( 'wpCleanupSiteReason', 60, '', array( 'tabindex' => '1', 'id' => 'mw-cleanupsite-reason', 'maxlength' => '200' ) ) . '</td></tr>' .
				'<tr><td></td><td class="mw-submit">' . Xml::submitButton( $button, array( 'id' => 'mw-cleanupsite-rc-hide-submit' ) ) . '</td></tr>' .
				'<input type=hidden name="id" value="' . $id . '" />' .
				'<input type=hidden name="action" value="submithide" />' .
				Xml::closeElement( 'table' ) . Xml::closeElement( 'form' ) . Xml::closeElement( 'fieldset' )
			);		
		}
		
		if ( $action == 'unhide' ) {
			$wgOut->setPagetitle( wfMsg( 'cleanupsite-recentchanges-unhide', array( "$id" ) ) );
			
			$topmessage = wfMsg('cleanupsite-recentchanges-unhide-topmessage');
			$button = wfMsg('cleanupsite-submit-unhide');
			
			$id = intval($id);
			
			$dbr = wfGetDB( DB_MASTER );
			$res = $dbr->query("SELECT * FROM recentchanges WHERE rc_id = " . $id . " LIMIT 1");
			$row = $dbr->fetchObject( $res );
			
			if (!$row) {
				$wgOut->addWikiMsg('cleanupsite-error-falseid');
				return;
			}
			
			$bot = $row->rc_bot;
			if ( $bot == 0 ) {
				$wgOut->addWikiMsg('cleanupsite-error-unhidden');
				return;
			}
			
			$timestamp = $row->rc_timestamp;
			$user = htmlspecialchars( $row->rc_user_text );
			$namespace = $row->rc_namespace;
			$title = htmlspecialchars( $row->rc_title );
			$comment = htmlspecialchars( $row->rc_comment );
			$log_type = $row->rc_log_type;
			$log_action = $row->rc_log_action;
			if ( $log_action ) {
				$logging = "$log_type/$log_action";
			} else {
				$logging = "$namespace";
			}
			
			$wgOut->addHTML(
				Xml::fieldset( $topmessage ) . Xml::openElement( 'form', array( 'id' => 'mw-cleanupsite-rc-unhide', 'method' => 'post' ) ) .
				Xml::openElement( 'table', array( 'id' => "mw-cleanupsite-rc-table" ) ) .
				'<tr><td class="mw-label">' . Xml::label( $idmessage, 'mw-cleanupsite-id' ) . '</td>' .
				'<td><code>' . $id . '</code></td></tr>' .
				'<tr><td class="mw-label">' . Xml::label( $revisionmessage, 'mw-cleanupsite-revision' ) . '</td>' .
				'<td><i>' . $timestamp . ' ' . $user . ' ' . $logging . ' ' . $title . ' ' . $comment . '</i></td>' .
				'<tr><td class="mw-label">' . Xml::label( $reasonmessage, 'mw-cleanupsite-reason' ) . '</td>' .
				'<td class="mw-input">' .  Xml::input( 'wpCleanupSiteReason', 60, '', array( 'tabindex' => '1', 'id' => 'mw-cleanupsite-reason', 'maxlength' => '200' ) ) . '</td></tr>' .				
				'<tr><td></td><td class="mw-submit">' . Xml::submitButton( $button, array( 'id' => 'mw-cleanupsite-rc-unhide-submit' ) ) . '</td></tr>' .
				'<input type=hidden name="id" value="' . $id . '" />' .
				'<input type=hidden name="action" value="submitunhide" />' .
				Xml::closeElement( 'table' ) . Xml::closeElement( 'form' ) . Xml::closeElement( 'fieldset' )
			);			
		}
		
		if ( $action == 'delete' ) {
			$wgOut->setPagetitle( wfMsg( 'cleanupsite-recentchanges-delete', array( "$id" ) ) );
		
			$topmessage = wfMsg('cleanupsite-recentchanges-delete-topmessage');
			$button = wfMsg('cleanupsite-submit-delete');
			
			$dbr = wfGetDB( DB_MASTER );
			$res = $dbr->query("SELECT * FROM recentchanges WHERE rc_id = " . $id . " LIMIT 1");
			$row = $dbr->fetchObject( $res );
			
			if (!$row) {
				$wgOut->addWikiMsg('cleanupsite-error-falseid');
				return;
			}
			
			$timestamp = $row->rc_timestamp;
			$user = htmlspecialchars( $row->rc_user_text );
			$namespace = $row->rc_namespace;
			$title = htmlspecialchars( $row->rc_title );
			$comment = htmlspecialchars( $row->rc_comment );
			$log_type = $row->rc_log_type;
			$log_action = $row->rc_log_action;
			if ( $log_action ) {
				$logging = "$log_type/$log_action";
			} else {
				$logging = "$namespace";
			}
			
			$wgOut->addHTML(
				Xml::fieldset( $topmessage ) . Xml::openElement( 'form', array( 'id' => 'mw-cleanupsite-rc-delete', 'method' => 'post' ) ) .
				Xml::openElement( 'table', array( 'id' => "mw-cleanupsite-rc-table" ) ) .
				'<tr><td class="mw-label">' . Xml::label( $idmessage, 'mw-cleanupsite-id' ) . '</td>' .
				'<td><code>' . $id . '</code></td></tr>' .
				'<tr><td class="mw-label">' . Xml::label( $revisionmessage, 'mw-cleanupsite-revision' ) . '</td>' .
				'<td><i>' . $timestamp . ' ' . $user . ' ' . $logging . ' ' . $title . ' ' . $comment . '</i></td>' .
				'<tr><td class="mw-label">' . Xml::label( $reasonmessage, 'mw-cleanupsite-reason' ) . '</td>' .
				'<td class="mw-input">' .  Xml::input( 'wpCleanupSiteReason', 60, '', array( 'tabindex' => '1', 'id' => 'mw-cleanupsite-reason', 'maxlength' => '200' ) ) . '</td></tr>' .				
				'<tr><td></td><td class="mw-submit">' . Xml::submitButton( $button, array( 'id' => 'mw-cleanupsite-rc-delete-submit' ) ) . '</td></tr>' .
				'<input type=hidden name="id" value="' . $id . '" />' .
				'<input type=hidden name="action" value="submitdelete" />' .
				Xml::closeElement( 'table' ) . Xml::closeElement( 'form' ) . Xml::closeElement( 'fieldset' )
			);	
		}
		
		if ( $action == 'submit' ) {
			$this->getRCList();
		}
		
		if ( $action == 'submithide' ) {
			$this->doHideRC();
		}
		
		if ( $action == 'submitunhide' ) {
			$this->doUnhideRC();
		}
		
		if ( $action == 'submitdelete' ) {
			$this->doDeleteRC();
		}
	}
	
	function getRCList() {
		global $wgRequest, $wgOut, $wgCleanupSiteRCLimit, $wgUser, $wgArticlePath;
		$rccount = $wgRequest->getVal( 'wpRCCount' );
		
		$wgOut->setPagetitle( wfMsg( 'cleanupsite-sub-recentchanges' ) );
		$wgOut->addWikiMsg( 'cleanupsite-recentchanges-about' );
		
		$rccount = intval($rccount);
		if( $rccount > $wgCleanupSiteRCLimit ) { $rccount = $wgCleanupSiteRCLimit; }
		if(!$rccount) $rccount = 10;
		
		$dbr = wfGetDB( DB_MASTER );
		$res = $dbr->query("SELECT * FROM recentchanges ORDER BY rc_timestamp DESC LIMIT " . $rccount);
		
		$idmessage = wfMsg('cleanupsite-recentchanges-idmessage');
		$timestampmessage = wfMsg('cleanupsite-recentchanges-timestampmessage');
		$usermessage = wfMsg('cleanupsite-recentchanges-usermessage');
		$typemessage = wfMsg('cleanupsite-recentchanges-typemessage');
		$titlemessage = wfMsg('cleanupsite-recentchanges-titlemessage');
		$commentmessage = wfMsg('cleanupsite-recentchanges-commentmessage');
		$actionsmessage = wfMsg('cleanupsite-recentchanges-actionsmessage');
		
		$path = str_replace('$1', '', $wgArticlePath);
		
		$out = "<table class='mw-recentchanges wikitable'>
		<tr id='mw-recentchanges-header'><th>$idmessage</th> <th>$timestampmessage</th> <th>$usermessage</th> <th>$typemessage</th> <th>$titlemessage</th> <th>$commentmessage</th> <th>$actionsmessage</th></tr>";
		
		while( $s = $res->fetchObject() ) {
			$id = $s->rc_id;
			$timestamp = $s->rc_timestamp;
			$user = htmlspecialchars( $s->rc_user_text );
			$namespace = $s->rc_namespace;
			$title = htmlspecialchars( $s->rc_title );
			$comment = htmlspecialchars( $s->rc_comment );
			$log_type = $s->rc_log_type;
			$log_action = $s->rc_log_action;
			$hidden = $s->rc_bot;
			if ( $hidden == 1 )	{
				$hidelink = wfMsg('cleanupsite-recentchanges-unhidelink');
				$hideaction = "unhide";
			} else {
				$hidelink = wfMsg('cleanupsite-recentchanges-hidelink');
				$hideaction = "hide";
			}
			$deletelink = wfMsg('cleanupsite-recentchanges-deletelink');
			
			$out .= "<tr><td>$id</td><td>$timestamp</td><td>$user</td>";
			if ( $log_action ) {
				$out .= "<td>$log_type/$log_action</td>";
			} else {
				$out .= "<td>$namespace</td>";
			}
			$out .= "<td>$title</td><td>$comment</td><td>";
			$out .= "<a href=\"" . $path . 'Special:CleanupSite/recentchanges?action=' . $hideaction . '&id=' . $id . "\">" . $hidelink . '</a>';
			$out .= wfMsg( 'comma-separator' );
			$out .= "<a href=\"" . $path . 'Special:CleanupSite/recentchanges?action=delete&id=' . $id . "\">" . $deletelink . '</a>';
			$out .= "</td></tr>";
		}
		
		$res->free();
		$out .= '</table><br />';
		$wgOut->addHTML( $out );
	}
	
	function doHideRC() {
		global $wgRequest, $wgOut;
		$id = $wgRequest->getVal( 'id' );
		$reason = $wgRequest->getText( 'wpCleanupSiteReason' );
		
		$id = intval($id);
		
		$dbr = wfGetDB( DB_MASTER );
		$dbr->query("UPDATE recentchanges SET rc_bot=1 WHERE rc_id = " . $id);
		
		$selfTitle = $this->getTitle();
		$log = new LogPage( 'cleanupsite' );
		$log->addEntry( 'rc_hide', $selfTitle, $reason, array( $id ) );
		
		$wgOut->setPagetitle( wfMsg( 'cleanupsite-success' ) );
		
		$wgOut->addWikiMsg('cleanupsite-recentchanges-success-hide', "$id" );
	}
	
	function doUnhideRC() {
		global $wgRequest, $wgOut;
		$id = $wgRequest->getVal( 'id' );
		$reason = $wgRequest->getText( 'wpCleanupSiteReason' );
		
		$id = intval($id);
		
		$dbr = wfGetDB( DB_MASTER );
		$dbr->query("UPDATE recentchanges SET rc_bot=0 WHERE rc_id = " . $id);
		
		$selfTitle = $this->getTitle();
		$log = new LogPage( 'cleanupsite' );
		$log->addEntry( 'rc_unhide', $selfTitle, $reason, array( $id ) );
		
		$wgOut->setPagetitle( wfMsg( 'cleanupsite-success' ) );
		
		$wgOut->addWikiMsg('cleanupsite-recentchanges-success-unhide', "$id" );
	}
	
	function doDeleteRC() {
		global $wgRequest, $wgOut;
		$id = $wgRequest->getVal( 'id' );
		$reason = $wgRequest->getText( 'wpCleanupSiteReason' );
		
		$id = intval($id);
		
		$dbr = wfGetDB( DB_MASTER );
		$dbr->query("INSERT INTO rc_deleted () SELECT * FROM recentchanges WHERE rc_id=" . $id);
		$dbr->query("DELETE FROM recentchanges WHERE rc_id =" . $id . " LIMIT 1");

		$selfTitle = $this->getTitle();
		$log = new LogPage( 'cleanupsite' );
		$log->addEntry( 'rc_delete', $selfTitle, $reason, array( $id ) );
				
		$wgOut->setPagetitle( wfMsg( 'cleanupsite-success' ) );
		
		$wgOut->addWikiMsg('cleanupsite-recentchanges-success-delete', "$id" );
	}
}

class CleanupIPBlocks extends CleanupSiteView {
	function show() {
		global $wgOut, $wgUser, $wgRequest;

		$action = $wgRequest->getVal( 'action', $this->subpage );
		if ( $action == 'ipblocks' ) {
			$wgOut->setPagetitle( wfMsg( 'cleanupsite-sub-ipblocks' ) );
			$wgOut->addWikiMsg( 'cleanupsite-ipblocks-about' );
			
			$topmessage = wfMsg('cleanupsite-ipblocks-topmessage');
			$ipbcount = wfMsg('cleanupsite-ipblocks-count');
			$button = wfMsg('htmlform-submit');
				
			$wgOut->addHTML(
				Xml::fieldset( $topmessage ) . Xml::openElement( 'form', array( 'id' => 'mw-cleanupsite-ipb', 'method' => 'post' ) ) .
				Xml::openElement( 'table', array( 'id' => "mw-cleanupsite-ipb-table" ) ) .
				'<tr><td class="mw-label">' . Xml::label( $ipbcount, 'mw-cleanupsite-ipbcount' ) . '</td>' .
				'<td class="mw-input">' .  Xml::input( 'wpIpbCount', 20, '', array( 'tabindex' => '1', 'id' => 'mw-cleanupsite-ipbcount', 'maxlength' => '3' ) ) . '</td></tr>' .
				'<tr><td></td><td class="mw-submit">' . Xml::submitButton( $button, array( 'id' => 'mw-cleanupsite-ipb-submit' ) ) . '</td></tr>' .
				'<input type=hidden name="action" value="submit" />' .
				Xml::closeElement( 'table' ) . Xml::closeElement( 'form' ) . Xml::closeElement( 'fieldset' )
			);			
		}
		
		if ( $action == 'delete' ) {
			$id = $wgRequest->getVal( 'id' );
			
			$wgOut->setPagetitle( wfMsg( 'cleanupsite-ipblocks-delete', array( "$id" ) ) );
					
			$topmessage = wfMsg('cleanupsite-ipblocks-delete-topmessage');
			$button = wfMsg('cleanupsite-submit-delete');
			$idmessage = wfMsg('cleanupsite-ipblocks-idmessage');
			$ipbmessage = wfMsg('cleanupsite-ipblocks-ipbmessage');
			$reasonmessage = wfMsg('cleanupsite-ipblocks-reasonmessage');
			$usermessage = wfMsg('cleanupsite-ipblocks-usermessage');
			$bymessage = wfMsg('cleanupsite-ipblocks-bymessage');
			$expirymessage = wfMsg('cleanupsite-ipblocks-expirymessage');
			$commentmessage = wfMsg('cleanupsite-ipblocks-commentmessage');
			
			$dbr = wfGetDB( DB_MASTER );
			$res = $dbr->query("SELECT * FROM ipblocks WHERE ipb_id = " . $id . " LIMIT 1");
			$row = $dbr->fetchObject( $res );
			
			if (!$row) {
				$wgOut->addWikiMsg('cleanupsite-error-falseid');
				return;
			}
			
			$id = $row->ipb_id;
			$timestamp = $row->ipb_timestamp;
			$user = htmlspecialchars( $row->ipb_address );
			$byuser = htmlspecialchars( $row->ipb_by_text );
			$expiry = $row->ipb_expiry;
			$comment = htmlspecialchars( $row->ipb_reason );
			
			$wgOut->addHTML(
				Xml::fieldset( $topmessage ) . Xml::openElement( 'form', array( 'id' => 'mw-cleanupsite-ipb-delete', 'method' => 'post' ) ) .
				Xml::openElement( 'table', array( 'id' => "mw-cleanupsite-ipb-table" ) ) .
				'<tr><td class="mw-label">' . Xml::label( $idmessage, 'mw-cleanupsite-id' ) . '</td>' .
				'<td><code>' . $id . '</code></td></tr>' .
				'<tr><td class="mw-label">' . Xml::label( $ipbmessage, 'mw-cleanupsite-ipb' ) . '</td>' .
				'<td><i>' . $timestamp . " " . $user . ", $bymessage " . $byuser . ", $expirymessage " . $expiry . ", $commentmessage «" . $comment . '»</i></td>' .
				'<tr><td class="mw-label">' . Xml::label( $reasonmessage, 'mw-cleanupsite-reason' ) . '</td>' .
				'<td class="mw-input">' .  Xml::input( 'wpCleanupSiteReason', 60, '', array( 'tabindex' => '1', 'id' => 'mw-cleanupsite-reason', 'maxlength' => '200' ) ) . '</td></tr>' .
				'<tr><td></td><td class="mw-submit">' . Xml::submitButton( $button, array( 'id' => 'mw-cleanupsite-ipb-delete-submit' ) ) . '</td></tr>' .
				'<input type=hidden name="id" value="' . $id . '" />' .
				'<input type=hidden name="user" value="' . $user . '" />' .
				'<input type=hidden name="action" value="submitdelete" />' .
				Xml::closeElement( 'table' ) . Xml::closeElement( 'form' ) . Xml::closeElement( 'fieldset' )
			);	
		}
		
		if ( $action == 'submit' ) {
			$this->getIPBlocksList();
		}
		
		if ( $action == 'submitdelete' ) {
			$this->doDeleteBlock();
		}
	}
	
	function getIPBlocksList() {
		global $wgRequest, $wgOut, $wgCleanupSiteIpbLimit, $wgUser, $wgArticlePath;
		$ipbcount = $wgRequest->getVal( 'wpIpbCount' );
		
		$ipbcount = intval($ipbcount);
		
		if( $ipbcount > $wgCleanupSiteIpbLimit ) { $ipbcount = $wgCleanupSiteIpbLimit; }
		if(!$ipbcount) $ipbcount = 10;
		
		$wgOut->setPagetitle( wfMsg( 'cleanupsite-sub-ipblocks' ) );
		$wgOut->addWikiMsg( 'cleanupsite-ipblocks-about' );
		
		$dbr = wfGetDB( DB_MASTER );
		$res = $dbr->query("SELECT * FROM ipblocks ORDER BY ipb_id DESC LIMIT " . $ipbcount);
		
		$idmessage = wfMsg('cleanupsite-ipblocks-idmessage');
		$timestampmessage = wfMsg('cleanupsite-ipblocks-timestampmessage');
		$usermessage = wfMsg('cleanupsite-ipblocks-usermessage');
		$byusermessage = wfMsg('cleanupsite-ipblocks-byusermessage');
		$expirymessage = wfMsg('cleanupsite-ipblocks-expirymessage-table');
		$commentmessage = wfMsg('cleanupsite-ipblocks-commentmessage-table');
		$actionsmessage = wfMsg('cleanupsite-ipblocks-actionsmessage');
		
		$path = str_replace('$1', '', $wgArticlePath);
		
		$out = "<table class='mw-recentchanges wikitable'>
		<tr id='mw-recentchanges-header'><th>$idmessage</th> <th>$timestampmessage</th> <th>$usermessage</th> <th>$byusermessage</th> <th>$expirymessage</th> <th>$commentmessage</th> <th>$actionsmessage</th></tr>";
		
		while( $s = $res->fetchObject() ) {
			$id = $s->ipb_id;
			$timestamp = $s->ipb_timestamp;
			$user = htmlspecialchars( $s->ipb_address );
			$byuser = htmlspecialchars( $s->ipb_by_text );
			$expiry = $s->ipb_expiry;
			$comment = htmlspecialchars( $s->ipb_reason );
			$action = "delete";
			$actionlink = wfMsg('cleanupsite-ipblocks-deletelink');
			
			$out .= "<tr><td>$id</td><td>$timestamp</td><td>$user</td><td>$byuser</td><td>$expiry</td><td>$comment</td><td><a href=\"" . $path . 'Special:CleanupSite/ipblocks?action=delete&id=' . $id . "\">" . $actionlink . "</a></td></tr>";
		}
		
		$res->free();
		$out .= '</table><br />';
		$wgOut->addHTML( $out );
	}
	
	function doDeleteBlock() {
		global $wgRequest, $wgOut;
		$id = $wgRequest->getVal( 'id' );
		$user = $wgRequest->getVal( 'user' );
		$reason = $wgRequest->getText( 'wpCleanupSiteReason' );
	
		$id = intval($id);
		
		$dbr = wfGetDB( DB_MASTER );
		$dbr->query("INSERT INTO ipb_deleted () SELECT * FROM ipblocks WHERE ipb_id=" . $id);
		$dbr->query("DELETE FROM ipblocks WHERE ipb_id =" . $id . " LIMIT 1");
		
		$selfTitle = $this->getTitle();
		$log = new LogPage( 'cleanupsite' );
		$log->addEntry( 'ipblocks', $selfTitle, $reason, array( $id, $user ) );
		
		$wgOut->setPagetitle( wfMsg( 'cleanupsite-success' ) );
		
		$wgOut->addWikiMsg('cleanupsite-ipblocks-success-delete', "$id" );
	}
}

class CleanupLogs extends CleanupSiteView {
	function show() {
		global $wgOut, $wgUser, $wgRequest;

		$action = $wgRequest->getVal( 'action', $this->subpage );
		if ( $action == 'logs' ) {
			$wgOut->setPagetitle( wfMsg( 'cleanupsite-sub-logs' ) );
			$wgOut->addWikiMsg( 'cleanupsite-logs-about' );
			
			$topmessage = wfMsg('cleanupsite-logs-topmessage');
			$logscount = wfMsg('cleanupsite-logs-count');
			$logtype = wfMsg('cleanupsite-logs-logtype');
			$button = wfMsg('htmlform-submit');
				
			$wgOut->addHTML(
				Xml::fieldset( $topmessage ) . Xml::openElement( 'form', array( 'id' => 'mw-cleanupsite-logs', 'method' => 'post' ) ) .
				Xml::openElement( 'table', array( 'id' => "mw-cleanupsite-logs-table" ) ) .
				'<tr><td class="mw-label">' . Xml::label( $logscount, 'mw-cleanupsite-logscount' ) . '</td>' .
				'<td class="mw-input">' .  Xml::input( 'wpLogsCount', 30, '', array( 'tabindex' => '1', 'id' => 'mw-cleanupsite-logscount', 'maxlength' => '3' ) ) . '</td></tr>' .
				'<tr><td class="mw-label">' . Xml::label( $logtype, 'mw-cleanupsite-logtype' ) . '</td>' .
				'<td class="mw-input">' .  Xml::input( 'wpLogType', 30, '', array( 'tabindex' => '1', 'id' => 'mw-cleanupsite-logstype', 'maxlength' => '30' ) ) . '</td></tr>' .
				'<tr><td></td><td class="mw-submit">' . Xml::submitButton( $button, array( 'id' => 'mw-cleanupsite-logs-submit' ) ) . '</td></tr>' .
				'<input type=hidden name="action" value="submit" />' .
				Xml::closeElement( 'table' ) . Xml::closeElement( 'form' ) . Xml::closeElement( 'fieldset' )
			);			
		}
		
		if ( $action == 'delete' ) {
			$id = $wgRequest->getVal( 'id' );
			
			$wgOut->setPagetitle( wfMsg( 'cleanupsite-logs-delete', array( "$id" ) ) );
			
			$topmessage = wfMsg('cleanupsite-logs-delete-topmessage');
			$button = wfMsg('cleanupsite-submit-delete');
			$idmessage = wfMsg('cleanupsite-logs-idmessage');
			$logsmessage = wfMsg('cleanupsite-logs-logsmessage');
			$reasonmessage = wfMsg('cleanupsite-logs-reasonmessage');
			$typemessage = wfMsg('cleanupsite-logs-typemessage');
			$usermessage = wfMsg('cleanupsite-logs-usermessage');
			$titlemessage = wfMsg('cleanupsite-logs-titlemessage');
			$commentmessage = wfMsg('cleanupsite-logs-commentmessage');
			
			$dbr = wfGetDB( DB_MASTER );
			$res = $dbr->query("SELECT * FROM logging WHERE log_id = " . $id . " LIMIT 1");
			$row = $dbr->fetchObject( $res );
			
			if (!$row) {
				$wgOut->addWikiMsg('cleanupsite-error-falseid');
				return;
			}
			
			$loguser = $row->log_user;
			if ( $loguser == 0 ) {
				$wgOut->addWikiMsg('cleanupsite-error-log-hidden');
				return;
			}
			
			$id = $row->log_id;
			$timestamp = $row->log_timestamp;
			$logtype = $row->log_type;
			$type = $logtype . "/" . $row->log_action;
			$user = htmlspecialchars( $row->log_user_text );
			$title = htmlspecialchars( $row->log_title );
			$comment = htmlspecialchars( $row->log_comment );
			
			$wgOut->addHTML(
				Xml::fieldset( $topmessage ) . Xml::openElement( 'form', array( 'id' => 'mw-cleanupsite-logs-delete', 'method' => 'post' ) ) .
				Xml::openElement( 'table', array( 'id' => "mw-cleanupsite-logs-table" ) ) .
				'<tr><td class="mw-label">' . Xml::label( $idmessage, 'mw-cleanupsite-id' ) . '</td>' .
				'<td><code>' . $id . '</code></td></tr>' .
				'<tr><td class="mw-label">' . Xml::label( $logsmessage, 'mw-cleanupsite-logs' ) . '</td>' .
				'<td><i>' . $timestamp . ", $typemessage " . $type . ", $targetusermessage " . $user . ", $titlemessage " . $title . ", $commentmessage " . $comment . '</i></td>' .
				'<tr><td class="mw-label">' . Xml::label( $reasonmessage, 'mw-cleanupsite-reason' ) . '</td>' .
				'<td class="mw-input">' .  Xml::input( 'wpCleanupSiteReason', 60, '', array( 'tabindex' => '1', 'id' => 'mw-cleanupsite-reason', 'maxlength' => '200' ) ) . '</td></tr>' .
				'<tr><td></td><td class="mw-submit">' . Xml::submitButton( $button, array( 'id' => 'mw-cleanupsite-logs-delete-submit' ) ) . '</td></tr>' .
				'<input type=hidden name="id" value="' . $id . '" />' .
				'<input type=hidden name="logtype" value="' . $logtype . '" />' .
				'<input type=hidden name="action" value="submitdelete" />' .
				Xml::closeElement( 'table' ) . Xml::closeElement( 'form' ) . Xml::closeElement( 'fieldset' )
			);	
		}
		
		if ( $action == 'submit' ) {
			$this->getLogsEntry();
		}
		
		if ( $action == 'submitdelete' ) {
			$this->doDeleteLogEntry();
		}
	}
	
	function getLogsEntry() {
		global $wgRequest, $wgOut, $wgCleanupSiteLogsLimit, $wgUser, $wgArticlePath;
		$logscount = $wgRequest->getVal( 'wpLogsCount' );
		$logtype = $wgRequest->getVal( 'wpLogType' );
		
		$logscount = intval($logscount);
		$logtype = preg_replace('[^a-zA-Z]', '', $logtype);
		
		if( $logscount > $wgCleanupSiteLogsLimit ) { $logscount = $wgCleanupSiteLogsLimit; }
		if(!$logscount) $logscount = 10;
		if(!$logtype) {
			$logtype_req = "";
		} else {
			$logtype_req = " WHERE log_type = '$logtype'";
		}
		
		$wgOut->setPagetitle( wfMsg( 'cleanupsite-sub-logs' ) );
		$wgOut->addWikiMsg( 'cleanupsite-logs-about' );
		
		$dbr = wfGetDB( DB_MASTER );
		$res = $dbr->query("SELECT * FROM logging$logtype_req ORDER BY log_id DESC LIMIT " . $logscount);
		
		$idmessage = wfMsg('cleanupsite-logs-idmessage');
		$timestampmessage = wfMsg('cleanupsite-logs-timestampmessage');
		$typemessage = wfMsg('cleanupsite-logs-typemessage');
		$usermessage = wfMsg('cleanupsite-logs-usermessage');
		$titlemessage = wfMsg('cleanupsite-logs-titlemessage');
		$commentmessage = wfMsg('cleanupsite-logs-commentmessage');
		$actionsmessage = wfMsg('cleanupsite-logs-actionsmessage');
		
		$path = str_replace('$1', '', $wgArticlePath);
		
		$out = "<table class='mw-recentchanges wikitable'>
		<tr id='mw-recentchanges-header'><th>$idmessage</th> <th>$timestampmessage</th> <th>$typemessage</th> <th>$usermessage</th> <th>$titlemessage</th> <th>$commentmessage</th> <th>$actionsmessage</th></tr>";
		
		while( $s = $res->fetchObject() ) {
			$id = $s->log_id;
			$timestamp = $s->log_timestamp;
			$type = $s->log_type . "/" . $s->log_action;
			$user = htmlspecialchars( $s->log_user_text );
			$title = htmlspecialchars( $s->log_title );
			$comment = htmlspecialchars( $s->log_comment );
			$action = "delete";
			$actionlink = wfMsg('cleanupsite-logs-deletelink');
			$inactive = wfMsg('cleanupsite-logs-inactivelink');
			$user_id = $s->log_user;
			
			$out .= "<tr><td>$id</td><td>$timestamp</td><td>$type</td><td>$user</td><td>$title</td><td>$comment</td>";
			if ( $user_id == 0 ) {
				$out .= "<td>$inactive</td>";
			} else {
				$out .= "<td><a href=\"" . $path . 'Special:CleanupSite/logs?action=delete&id=' . $id . "\">" . $actionlink . "</a></td>";
			}
					
			$out .= "</tr>";
		}
		
		$res->free();
		$out .= '</table><br />';
		$wgOut->addHTML( $out );
	}
	
	function doDeleteLogEntry() {
		global $wgRequest, $wgOut;
		$id = $wgRequest->getVal( 'id' );
		$logtype = $wgRequest->getVal( 'logtype' );
		$reason = $wgRequest->getText( 'wpCleanupSiteReason' );
		
		$id = intval($id);
		$dbr = wfGetDB( DB_MASTER );
		$dbr->query("UPDATE logging SET log_user=0 WHERE log_id = " . $id);
		
		$selfTitle = $this->getTitle();
		$log = new LogPage( 'cleanupsite' );
		$log->addEntry( 'logs', $selfTitle, $reason, array( $id, $logtype ) );
		
		$wgOut->setPagetitle( wfMsg( 'cleanupsite-success' ) );
		
		$wgOut->addWikiMsg('cleanupsite-logs-success-delete', "$id" );
	}
}

CleanupSite.i18n.php[править | править код]

<?php

$messages = array();

$messages['en'] = array(
	'cleanupsite' => 'Чистка сайта',
	'cleanupsite-desc' => 'Позволяет удалять с сайта следы нежелательной активности',
	'cleanupsite-about' => 'При помощи этой служебной страницы вы можете удалить отдельные следы нежелательной активности с сайта.',
	'cleanupsite-sub-recentchanges' => 'Чистка свежих правок',
	'cleanupsite-sub-ipblocks' => 'Чистка списка заблокированных пользователей',
	'cleanupsite-sub-logs' => 'Чистка записей в журналах',
	'cleanupsite_logpagename' => 'Журнал очистки сайта',
	'cleanupsite_logpagetext' => 'Журнал, записывающий действия администраторов по очистке сайта от следов нежелательной активности',
	'cleanupsite_logentry' => '',
	'cleanupsite_log_rc_hide' => 'скрыл запись $2 из свежих правок',
	'cleanupsite_log_rc_unhide' => 'раскрыл запись $2 из свежих правок',
	'cleanupsite_log_rc_delete' => 'удалил запись $2 из свежих правок',
	'cleanupsite_log_ipblocks' => 'удалил блокировку с ID $2 участника $3',
	'cleanupsite_log_logs' => 'удалил запись $2 из журнала «$3»',
	'cleanupsite-recentchanges-about' => 'При помощи этой служебной страницы вы можете скрывать (показываются при использовании <code>hidebots=0</code>) и удалять отдельные элементы свежих правок.',
	'cleanupsite-recentchanges-topmessage' => 'Инициализация',
	'cleanupsittd>e-recentchanges-rccount' => 'Число свежих правок',
	'cleanupsite-recentchanges-idmessage' => 'ID',
	'cleanupsite-recentchanges-timestampmessage' => 'Время изменения',
	'cleanupsite-recentchanges-usermessage' => 'Участник',
	'cleanupsite-recentchanges-typemessage' => 'ПИ или тип журнала',
	'cleanupsite-recentchanges-titlemessage' => 'Название страницы',
	'cleanupsite-recentchanges-commentmessage' => 'Комментарий к изменению',
	'cleanupsite-recentchanges-actionsmessage' => 'Действия',
	'cleanupsite-recentchanges-reasonmessage' => 'Причина',
	'cleanupsite-recentchanges-unhidelink' => 'Раскрыть',
	'cleanupsite-recentchanges-hidelink' => 'Скрыть',
	'cleanupsite-recentchanges-deletelink' => 'Удалить',
	'cleanupsite-recentchanges-hide' => 'Скрытие правки $1',
	'cleanupsite-recentchanges-hide-topmessage' => 'Скрытие правки из свежих правок',
	'cleanupsite-recentchanges-revisionmessage' => 'Данные правки',
	'cleanupsite-recentchanges-success-hide' => 'Правка $1 успешно скрыта из списка свежих правок.',
	'cleanupsite-recentchanges-unhide' => 'Раскрытие правки $1',
	'cleanupsite-recentchanges-unhide-topmessage' => 'Раскрытие правки в свежих правках',
	'cleanupsite-recentchanges-success-unhide' => 'Правка $1 успешно раскрыта в списке свежих правок.',
	'cleanupsite-recentchanges-delete' => 'Удаление правки $1',
	'cleanupsite-recentchanges-delete-topmessage' => 'Удаление правки из свежих правок',
	'cleanupsite-recentchanges-success-delete' => 'Правка $1 успешно удалена из списка свежих правок.',
	'cleanupsite-submit-delete' => 'Удалить',
	'cleanupsite-ipblocks-about' => 'При помощи этой служебной страницы вы можете удалять отдельные блокировки участников и IP-адресов. Это равносильно разблокировке.',
	'cleanupsite-ipblocks-topmessage' => 'Инициализация',
	'cleanupsite-ipblocks-count' => 'Число блокировок',
	'cleanupsite-ipblocks-idmessage' => 'ID',
	'cleanupsite-ipblocks-timestampmessage' => 'Время блокировки',
	'cleanupsite-ipblocks-usermessage' => 'Цель блокировки',
	'cleanupsite-ipblocks-byusermessage' => 'Администратор',
	'cleanupsite-ipblocks-expirymessage-table' => 'Дата окончания блокировки',
	'cleanupsite-ipblocks-commentmessage-table' => 'Комментарий',
	'cleanupsite-ipblocks-actionsmessage' => 'Действия',
	'cleanupsite-ipblocks-reasonmessage' => 'Причина',
	'cleanupsite-ipblocks-deletelink' => 'Удалить',
	'cleanupsite-ipblocks-delete' => 'Удаление блокировки $1',
	'cleanupsite-ipblocks-delete-topmessage' => 'Удаление блокировки',
	'cleanupsite-ipblocks-ipbmessage' => 'Данные о блокировке',
	'cleanupsite-ipblocks-targetusermessage' => 'заблокирован',
	'cleanupsite-ipblocks-bymessage' => 'заблокирован администратором',
	'cleanupsite-ipblocks-expirymessage' => 'истекает',
	'cleanupsite-ipblocks-commentmessage' => 'с пометкой',
	'cleanupsite-ipblocks-success-delete' => 'Блокировка $1 успешно удалена из списка блокировок.',
	'cleanupsite-logs-about' => 'При помощи этой служебной страницы вы можете скрывать отдельные записи в журналах.',
	'cleanupsite-logs-topmessage' => 'Инициализация',
	'cleanupsite-logs-count' => 'Число записей',
	'cleanupsite-logs-logtype' => 'Тип журнала',
	'cleanupsite-logs-idmessage' => 'ID',
	'cleanupsite-logs-timestampmessage' => 'Время действия',
	'cleanupsite-logs-typemessage' => 'Тип действия',
	'cleanupsite-logs-usermessage' => 'Участник',
	'cleanupsite-logs-titlemessage' => 'Цель',
	'cleanupsite-logs-commentmessage' => 'Комментарий',
	'cleanupsite-logs-actionsmessage' => 'Действия',
	'cleanupsite-logs-deletelink' => 'Удалить',
	'cleanupsite-logs-inactivelink' => 'Удалено',
	'cleanupsite-logs-delete' => 'Удаление записи журнала $1',
	'cleanupsite-logs-delete-topmessage' => 'Удаление записи журнала',
	'cleanupsite-logs-idmessage' => 'ID',
	'cleanupsite-logs-logsmessage' => 'Данные записи',
	'cleanupsite-logs-reasonmessage' => 'Причина',
	'cleanupsite-logs-typemessage' => 'тип',
	'cleanupsite-logs-usermessage' => 'участник',
	'cleanupsite-logs-titlemessage' => 'страница',
	'cleanupsite-logs-commentmessage' => 'комментарий',
	'cleanupsite-logs-success-delete' => 'Запись журнала $1 успешно удалена.',
	'cleanupsite-success' => 'Действие выполнено',
	'cleanupsite-submit-hide' => 'Скрыть',
	'cleanupsite-submit-unhide' => 'Раскрыть',
	'cleanupsite-error-falseid' => 'Ошибка. Записи с таким ID не существует в базе данных.',
	'cleanupsite-error-hidden' => 'Ошибка. Эта запись уже скрыта из свежих правок.',
	'cleanupsite-error-unhidden' => 'Ошибка. Эта запись уже раскрыта в свежих правках.',
	'cleanupsite-error-log-hidden' => 'Ошибка. Эта запись уже удалена из журналов.',
	'right-cleanupsite' => 'чистка служебных страниц',
	'right-cleanupsite-log' => 'просмотр журнала очистки служебных страниц',
	'right-cleanupsite-revert' => 'восстановление элементов служебных страниц',
	'right-cleanupsite-truncate' => 'очистка таблиц базы данных, содержащих удалённые элементы служебных страниц',
);

cleanupsite.sql[править | править код]

CREATE TABLE rc_deleted LIKE recentchanges;
CREATE TABLE ipb_deleted LIKE ipblocks;
CleanupSite относится к темам:
1
MediaWiki 
Версии MediaWiki до 1.11.11.21.31.41.51.61.71.81.91.101.111.121.131.141.151.161.171.181.191.201.211.221.231.241.251.261.271.281.291.301.311.321.331.341.351.361.371.381.391.401.41 
Основные разработчики Аарон ШульцБрайон ВибберДаниэль КинзлерМагнус МанскеМаксим СеменикТим ЛакиаТим СтарлингРоберт КрушЭвар Бьярмасон 
Темы оформления AuroraBluecloudCavendishCologneBlueCycloneMonacoMonobook (RealBookModern) • OasisQuartz Vector (Vectorata) • Ventus 
Действия и функции РедактированиеПравка (счётчик) • ДиффМалое изменениеПредварительный просмотрФильтр злоупотребленийСтраница википроекта (подстраница) • СтатьяШаблонФайлИсторияОбсуждениеПереименование страницыПараметры переименованияЗащита страниц (параметрычастичнаяполнаякаскадная) • Удаление/Восстановление страницПараметры удаленияПеренаправление (двойныеподавление) • Список наблюденияОбъединение страницРазделение страницСкрытиеПатрулированиеСсылки сюдаСтабилизацияБлокировка (авто-, глобальная, параметры, причина) • Разблокировка (параметры) • Права участниковРегистрацияПереименование учётной записиУзурпацияОбъединение учётных записейЗагрузка файловОтклонение правкиОтмена правкиБыстрый откатВикипочтаЕдиная учётная записьСвежие правкиВклад (удалённый) • Спам-листЗавершение сеансаПинг 
Пространство имён Основное пространствоОбсуждениеШаблонКатегорияУчастникФайлСправкаProjectSpecialMediaWiki 
Расширения AbuseFilterAntiSpoofArticle Feedback ToolCategoryTreeCentralAuthCentralNoticeCharInsertCheckUserCiteCleanupSiteCodeReviewCollectionCommentsCommunityVoiceConfirmEditContactPageDeleteBatchDismissableSiteNoticeDraftsDumpHTMLDynamicPageListEasyTimelineEmailCaptureEmbedVideoExpandTemplatesExtensionDistributorFixedImageFlaggedRevsGadgetsGlobalBlockingGlobalUsageHTTP302FoundImageMapInputBoxLabeled Section TransclusionLiquidThreadsLocalisationUpdateLockdownLucene-searchMiniDonationMWSearchNewUserMessageNukeOAIRepositoryOATHAuthOggHandlerOpenSearchXmlParserFunctionsPdfHandlerPoemProofread PageQuizRenameuserRevisionDeleteSecurePollSimpleAntiSpamSimpleSurveySiteMatrixSkinPerPageSlippyMapSpamBlacklistStalkerLogSubPageList3SyntaxHighlightTitleBlacklistTitleKeyTorBlockTrustedXFFUploadBlacklistUploadWizardUserMergeVisualEditorWikidiffWikidiff2WikiHiero 
Архивированные расширения AntiBotBoardVoteClientSideCrosswiki BlockingEnforceStrongPasswordGiveRollbackOversightPassword Reset 
Разное AllMessagesFavicon.icoHTML в MediaWikiMediaWiki.orgMediaWiki FAQВнутренняя ссылкаКороткая ссылка-перенаправлениеМатематические формулыНастройки конфигурацииНовые файлыСистемный администраторСписок файловWiki.pngГаджетSidebarStatisticsLocalSettings.phpСкрипты обслуживания