Extension:Multiplicator

From MediaWiki.org

Jump to: navigation, search

             

Manual on MediaWiki Extensions
List of MediaWiki Extensions
Crystal Clear app error.png
Multiplicator

Release status: unstable

Multiplicator.png
Implementation  Special page, Page action
Description Special page to create independent copies of pages
Author(s)  look at code history. Duplicator coder is Rob Church
Last Version  0.1 (June 29, 2009)
MediaWiki  1.7.0+
License No license specified
Download

Download snapshot
Subversion [Help]
Browse source code

check usage (experimental)

Multiplicator extension extends the Duplicator one by providing a special page which allows several creation of independent copies (with separate edit histories) of pages. Single copies are made on destination pages and several copies are made on subpages of destination pages.


The code is broken at the moment, have a look at histories.

Contents

[edit] Multiplicator.php

<?php
if (!defined('MEDIAWIKI')) die();
/**  == Extension:Duplicator... ==
 *
 * Special page which creates independent copies of articles, retaining
 * separate histories. [author Rob Church <robchur@gmail.com>] 
 *
 *   == ...extended to Multiplicator: ==
 * if more than one copy, it creates duplicates in subpages of destination page; 
 * and create a list of subages on destination page. [with <splist> if installed].
 *
 * @addtogroup Extensions
 * @author Rob Church <robchur@gmail.com>
 */
 
$wgExtensionCredits['specialpage'][] = array(
	'path' => __FILE__,
	'name' => 'Multiplicator',
	'version' => '0.1',
	'author' => 'Rob Church, Al Maghi',
	'url' => 'http://www.mediawiki.org/wiki/Extension:Multiplicator',
	'description' => 'Create independent copies of articles with full edit histories',
	'descriptionmsg' => 'multiplicator-desc',
);
 
$dir = dirname(__FILE__) . '/';
$wgExtensionMessagesFiles['Multiplicator'] = $dir . 'Multiplicator.i18n.php';
$wgExtensionAliasesFiles['Multiplicator'] = $dir . 'Multiplicator.alias.php';
$wgAutoloadClasses['SpecialMultiplicator'] = $dir . 'Multiplicator.page.php';
$wgSpecialPages['Multiplicator'] = 'SpecialMultiplicator';
$wgExtensionFunctions[] = 'efMultiplicator';
 
/**
 * User permissions
 */
$wgGroupPermissions['user']['multiplicate'] = true;
$wgAvailableRights[] = 'multiplicate';
 
/**
 * Pages with more than this number of revisions can't be duplicated
 */
$wgMultiplicatorRevisionLimit = 250;
 
/**
 * Pages with more than this number of revisions can't be duplicated
 */
$wgMultiplicatorListDifferentCopies = true;
$wgMultiplicatorListDifferentCopiesWithSplist = false;
 
/**
 *
 * Extension setup function
 */
function efMultiplicator() {
	global $wgHooks;
	$wgHooks['SkinTemplateBuildNavUrlsNav_urlsAfterPermalink'][] = 'efMultiplicatorNavigation';
	$wgHooks['MonoBookTemplateToolboxEnd'][] = 'efMultiplicatorToolbox';
}
 
/**
 * Build the link to be shown in the toolbox if appropriate
 */
function efMultiplicatorNavigation( &$skin, &$nav_urls, &$oldid, &$revid ) {
	global $wgUser;
	$ns = $skin->mTitle->getNamespace();
	if( ( $ns === NS_MAIN || $ns === NS_TALK ) && $wgUser->isAllowed( 'multiplicate' ) ) {
		wfLoadExtensionMessages( 'Multiplicator' );
		$nav_urls['multiplicator'] = array(
			'text' => wfMsg( 'multiplicator-toolbox' ),
			'href' => $skin->makeSpecialUrl( 'Multiplicator', "source=" . wfUrlEncode( "{$skin->thispage}" ) )
		);
	}
	return true;
}
 
/**
 * Output the toolbox link if available
 */
function efMultiplicatorToolbox( &$monobook ) {
	if ( isset( $monobook->data['nav_urls']['multiplicator'] ) ) {
		wfLoadExtensionMessages( 'Multiplicator' );
		if ( $monobook->data['nav_urls']['multiplicator']['href'] == '' ) {
			?><li id="t-multiplicator"><?php echo $monobook->msg( 'multiplicator-toolbox' ); ?></li><?php
		} else {
			?><li id="t-multiplicator"><?php
				?><a href="<?php echo htmlspecialchars( $monobook->data['nav_urls']['multiplicator']['href'] ) ?>"><?php
					echo $monobook->msg( 'multiplicator-toolbox' );
				?></a><?php
			?></li><?php
		}
	}
	return true;
}

[edit] Multiplicator.page.php

<?php
 
/**
 * Special page class for the Multiplicator extension
 *
 * @addtogroup Extensions
 * @author Al Maghi <alfred.maghi@gmail.com>
 * Duplicator code from Rob Church <robchur@gmail.com>
 */
 
class SpecialMultiplicator extends SpecialPage {
 
	/**
	 * Title of the page we are duplicating
	 */
	private $source = '';
	private $sourceTitle = NULL;
 
	/**
	 * Title of the page we are saving to
	 */
	private $dest = '';
	private $destTitle = NULL;
 
	/**
	 * Number of copie(s) we are saving
	 */	
	private $times = 0;
 
	/**
	 * Whether or not we're duplicating the talk page
	 */
	private $talk = true;
 
	/**
	 * Constructor
	 */
	public function __construct() {
		parent::__construct( 'Multiplicator' );
	}
 
	/**
	 * Main execution function
	 *
	 * @param $title Title passed to the page
	 */
	public function execute( $title ) {
		global $wgUser, $wgOut, $wgRequest, $wgLang, $wgMultiplicatorRevisionLimit;
		wfLoadExtensionMessages( 'Multiplicator' );
		$this->setHeaders();
 
		# Check permissions
		if( !$wgUser->isAllowed( 'multiplicate' ) ) {
			$wgOut->permissionRequired( 'multiplicate' );
			return;
		}
 
		# Check for database lock
		if( wfReadOnly() ) {
			$wgOut->readOnlyPage();
			return;
		}
 
		$this->setOptions( $wgRequest, $title );
		$wgOut->addWikiMsg( 'duplicator-header' );
		$wgOut->addHTML( $this->buildForm() );
 
		# If the token doesn't match or the form wasn't POSTed, stop
		if( !$wgRequest->wasPosted() || !$wgUser->matchEditToken( $wgRequest->getVal( 'token' ), 'multiplicator' ) )
			return;
 
		# Check we've got a valid source title
		if( !is_object( $this->sourceTitle ) ) {
			# Invalid source title
			$wgOut->addWikiMsg( 'duplicator-source-invalid' );
			return;
		}
 
		# Check the source exists
		if( !$this->sourceTitle->exists() ) {
			# Source doesn't exist
			$wgOut->addWikiMsg( 'duplicator-source-notexist', $this->source );
			return;
		}
 
		# Check we've got a valid destination title
		if( !is_object( $this->destTitle ) ) {
			# Invalid destination title
			$wgOut->addWikiMsg( 'duplicator-dest-invalid' );
			return;
		}
 
		# Check the destination *does not* exist
		if( $this->destTitle->exists() ) {
			# Destination exists
			$wgOut->addWikiMsg( 'duplicator-dest-exists', $this->destTitle->getPrefixedText() );
			return;
		}
 
		# Check there aren't a hideous number of revisions
		$dbr = wfGetDB( DB_SLAVE );
		$num = $dbr->selectField( 'revision', 'COUNT(*)',array( 'rev_page' => $this->sourceTitle->getArticleId() ), __METHOD__ );
		if( $num <= $wgMultiplicatorRevisionLimit ) {
			# Attempt to perform the main duplicate op. first
			if( $this->duplicate( $this->sourceTitle, $this->destTitle ) ) {
				$success  = wfMsgNoTrans( 'duplicator-success', $this->sourceTitle->getPrefixedText(), $this->destTitle->getPrefixedText() ) . "\n\n";
				$success .= '* ' . wfMsgNoTrans( 'duplicator-success-revisions', $wgLang->formatNum( $num ) ) . "\n";
				//$success .= '' . wfMsgNoTrans( 'duplicator-success-subpages', $times ) . "\n";
				# If there is a talk page and we've been asked to duplicate it, do so
				if( $this->dealWithTalk() && $this->talk ) {
					if( $this->duplicate( $this->sourceTitle->getTalkPage(), $this->destTitle->getTalkPage() ) ) {
						$success .= '* ' . wfMsgNoTrans( 'duplicator-success-talkcopied' ) . "\n";
					} else {
						$success .= '* ' . wfMsgNoTrans( 'duplicator-success-talknotcopied' ) . "\n";
					}
				}
				# Report success to the user
				$parsed = $wgOut->parse( $success, /*linestart*/true, /*uilang*/true );
				$wgOut->addHTML( $parsed );
			} else {
				# Something went wrong, abort the entire operation
				$wgOut->addWikiMsg( 'duplicator-failed' );
			}
		} else {
			# Revision count exceeds limit
			$limit = $wgLang->formatNum( $wgMultiplicatorRevisionLimit );
			$actual = $wgLang->formatNum( $num );
			$stitle = $this->sourceTitle->getPrefixedText();
			$wgOut->addWikiMsg( 'duplicator-toomanyrevisions', $stitle, $actual, $limit );
		}
 
	}
 
	/**
	 * Determine various options and attempt initialisation of objects
	 *
	 * @param $request WebRequest we're running off
	 * @param $title Title passed to the page
	 */
	private function setOptions( &$request, $title ) {
		$source = $request->getText( 'source' );
		$this->source = $source ? $source : ( $title ? $title : '' );
		$this->sourceTitle = Title::newFromUrl( $this->source );
		$this->dest = $request->getText( 'dest', '' );
		$this->destTitle = Title::newFromUrl( $this->dest );
		$this->talk = $request->getCheck( 'talk' );
		$times = $request->getText( 'times', '' );
 
	}
 
	/**
	 * Should we allow the user to see the talk page option?
	 * Don't bother if there is no talk page, or we're duplicating one
	 *
	 * @return bool
	 */
	private function dealWithTalk() {
		if( is_object( $this->sourceTitle ) ) {
			if( $this->sourceTitle->isTalkPage() )
				return false;
			$talk = $this->sourceTitle->getTalkPage();
			return $talk->exists();
		} else {
			# We can't determine, but it doesn't matter; either the user
			# hasn't hit the submit button, or we'll be throwing up a bad title error
			return true;
		}
	}
 
	/**
	 * Build a form for entering the source and destination titles
	 *
	 * @return string
	 */
	private function buildForm() {
		global $wgUser;
		$self = SpecialPage::getTitleFor( 'multiplicator' );
		$source = is_object( $this->sourceTitle ) ? $this->sourceTitle->getPrefixedText() : $this->source;
		$dest = is_object( $this->destTitle ) ? $this->destTitle->getPrefixedText() : $this->dest;
		$form  = '<form method="post" action="' . $self->getLocalUrl() . '">';
		$form .= '<fieldset><legend>' . wfMsgHtml( 'duplicator-options' ) . '</legend>';
		$form .= '<table>';
		$form .= '<tr>';
		$form .= '<td><label for="source">' . wfMsgHtml( 'duplicator-source' ) . '</label></td>';
		$form .= '<td>' . Xml::input( 'source', 40, $source, array( 'id' => 'source' ) ) . '</td>';
		$form .= '</tr><tr>';
		$form .= '<td><label for="dest">' . wfMsgHtml( 'duplicator-dest' ) . '</label></td>';
		$form .= '<td>' . Xml::input( 'dest', 40, $dest, array( 'id' => 'dest' ) ) . '</td>';
		$form .= '</tr><tr>';
		$form .= '<td><label for="times">' . wfMsgHtml( 'multiplicator-times' ) . '</label></td>';
		$form .= '<td>' . Xml::openElement( 'select', array( 'name' => 'times' ) ) 
						. Xml::option( wfMsg( "multiplicator-select1" ), 1 ) 
						. Xml::option( wfMsg( "multiplicator-select2" ), 2 )
						. Xml::option( wfMsg( "multiplicator-select3" ), 3 )
						. Xml::option( wfMsg( "multiplicator-select4" ), 4 )
						. Xml::option( wfMsg( "multiplicator-select5" ), 5 )
						. Xml::option( wfMsg( "multiplicator-select6" ), 6 )
						. Xml::option( wfMsg( "multiplicator-select7" ), 7 )
						. Xml::option( wfMsg( "multiplicator-select8" ), 8 )
						. Xml::option( wfMsg( "multiplicator-select9" ), 9 )
						. Xml::option( wfMsg( "multiplicator-select10" ), 10 )
						. Xml::closeElement( 'select' ) . '</td>';
		$form .= '</tr><tr>';
		$form .= '<td>&nbsp;</td>';
		$form .= '<td>' . Xml::checkLabel( wfMsg( 'duplicator-dotalk' ), 'talk', 'talk', $this->talk ) . '</td>';
		$form .= '</tr><tr>';
		$form .= '<td>&nbsp;</td>';
		$form .= '<td>' . Xml::submitButton( wfMsg( 'duplicator-submit' ) ) . '</td>';
		$form .= '</tr>';
		$form .= '</table>';
		$form .= Xml::hidden( 'token', $wgUser->editToken( 'multiplicator' ) );
		$form .= '</fieldset></form>';
		return $form;
	}
 
	/**
	 * Duplicate one page to another, including full histories
	 * Does some basic error-catching, but not as much as the code above [should]
	 *
	 * @param $source Title to duplicate
	 * @param $dest Title to save to
	 * @return bool
	 */
		private function duplicate( &$source, &$dest ) {
			global $wgUser, $wgBot;
			if( !$source->exists() || $dest->exists() )
				return false; # Source doesn't exist, or destination does
			$dbw = wfGetDB( DB_MASTER );
			$dbw->begin();
			$sid = $source->getArticleId();
			# Create an article representing the destination page and save it
			$destArticle = new Article( $dest );
			$aid = $destArticle->insertOn( $dbw );
 
 
			# Perform the revision duplication
			# An INSERT...SELECT here seems to fuck things up
			$res = $dbw->select( 'revision', '*', array( 'rev_page' => $sid ), __METHOD__ );
			if( $res && $dbw->numRows( $res ) > 0 ) {
				while( $row = $dbw->fetchObject( $res ) ) {
					$values['rev_page'] = $aid;
					$values['rev_text_id'] = $row->rev_text_id;
					$values['rev_comment'] = $row->rev_comment;
					$values['rev_user'] = $row->rev_user;
					$values['rev_user_text'] = $row->rev_user_text;
					$values['rev_timestamp'] = $row->rev_timestamp;
					$values['rev_minor_edit'] = $row->rev_minor_edit;
					$values['rev_deleted'] = $row->rev_deleted;
					$dbw->insert( 'revision', $values, __METHOD__ );
				}
				$dbw->freeResult( $res );
			}
			# Update page record
			$latest = $dbw->selectField( 'revision', 'MAX(rev_id)', array( 'rev_page' => $aid ), __METHOD__ );
			$rev = Revision::newFromId( $latest );
			$destArticle->updateRevisionOn( $dbw, $rev );
			# Commit transaction
			$dbw->commit();
			# Create a null revision with an explanation; do cache clearances, etc.
			$dbw->begin();
			$comment = wfMsgForContent( 'duplicator-summary', $source->getPrefixedText() );
			$nr = Revision::newNullRevision( $dbw, $aid, $comment, true );
			$nid = $nr->insertOn( $dbw );
			$destArticle->updateRevisionOn( $dbw, $nr );
			$destArticle->createUpdates( $nr );
			Article::onArticleCreate( $dest );
			$bot = $wgUser->isAllowed( 'bot' );
			RecentChange::notifyNew( $nr->getTimestamp(), $dest, true, $wgUser, $comment, $bot );
			$dest->invalidateCache();
			$dbw->commit();
			return true;
 
		}
	}

[edit] Multiplicator.alias.php

<?php
/**
 * Aliases for special pages
 *
 * @file
 * @ingroup Extensions
 */
 
$aliases = array();
 
/** English */
$aliases['en'] = array(
	'Multiplicator' => array( 'Multiplicator', 'Multiplicate' ),
);

[edit] Multiplicator.i18n.php

<?php
/**
 * Internationalisation file for extension Multiplicator.
 *
 * @addtogroup Extensions
 * @author Al Maghi <alfred.maghi@gmail.com>
 * Duplicator code from Rob Church <robchur@gmail.com>
 */
 
$messages = array();
 
/* English
 * @author Rob Church
 */
$messages['en'] = array(
	'multiplicator'                    => 'Multiplicate a page',
	'multiplicator-desc'               => 'Create independent [[Special:Multiplicator|copies of pages]] with full edit histories',
	'multiplicator-toolbox'            => 'Duplicate this page',
	'multiplicator-times'			   => 'Number of copie(s):',
	'multiplicator-select1'            => '1',
	'multiplicator-select2'			   => '2',
	'multiplicator-select3'            => '3',
	'multiplicator-select4'			   => '4',
	'multiplicator-select5'            => '5',
	'multiplicator-select6'			   => '6',
	'multiplicator-select7'            => '7',
	'multiplicator-select8'			   => '8',
	'multiplicator-select9'            => '9',
	'multiplicator-select10'		   => '10',
	'duplicator-header'                => 'This page allows the complete duplication of a page, creating independent copies of all histories.
This is useful for page forking, etc.',
	'duplicator-options'               => 'Options',
	'duplicator-source'                => 'Source:',
	'duplicator-dest'                  => 'Destination:',
	'duplicator-dotalk'                => 'Duplicate discussion page (if applicable)',
	'duplicator-submit'                => 'Duplicate',
	'duplicator-summary'               => 'Copied from [[$1]]',
	'duplicator-success'               => "<big>'''[[$1]] was copied to [[$2]].'''</big>",
	'duplicator-success-revisions'     => '$1 {{PLURAL:$1|revision was|revisions were}} copied.',
	'duplicator-success-subpages'      => '$1 {{PLURAL:$1|page was|pages were}} created.',
	'duplicator-success-talkcopied'    => 'The talk page was also copied.',
	'duplicator-success-talknotcopied' => 'The talk page could not be copied.',
	'duplicator-failed'                => 'The page could not be duplicated.
An unknown error occurred.',
	'duplicator-source-invalid'        => 'Please provide a valid source title.',
	'duplicator-source-notexist'       => '[[$1]] does not exist. Please provide the title of a page that exists.',
	'duplicator-dest-invalid'          => 'Please provide a valid destination title.',
	'duplicator-dest-exists'           => '[[$1]] already exists. Please provide a destination title which does not exist.',
	'duplicator-toomanyrevisions'      => '[[$1]] has too many ($2) revisions and cannot be copied.
The current limit is $3.',
	'right-duplicate' => 'Duplicate pages',
);
 
/** Message documentation (Message documentation)
 * @author Jon Harald Søby
 * @author Purodha
 */
$messages['qqq'] = array(
	'multiplicator-desc' => 'Extension description displayed on [[Special:Version]].',
	'duplicator-options' => '{{Identical|Options}}',
	'duplicator-source' => '{{Identical|Source}}',
	'duplicator-toomanyrevisions' => 'This message supports the use of PLURAL.	
* $1: source page name
* $2: number of actual revisions
* $3: current revision limit.',
	'right-duplicate' => '{{doc-right|duplicate}}',
);