$user: the User object about to be created (read-only, incomplete)
$message: out parameter: error message to display on abort
-'ActionBeforeFormDisplay': Modify the form shown for an action (added 1.18)
-$action: String
-$form: HTMLForm
-$page: Article
-
-'ActionModifyFormFields': Modify the descriptor array which will be used to create an
-action form
-$action: String
-$fields: Array
-$page: Article
-
'AddNewAccount': after a user account is created
$user: the User object that was created. (Parameter added in 1.7)
$byEmail: true when account was created "by email" (added in 1.12)
$article: the article (object) being loaded from the database
$content: the content (string) of the article
+'ArticleConfirmDelete': before writing the confirmation form for article
+ deletion
+$article: the article (object) being deleted
+$output: the OutputPage object ($wgOut)
+&$reason: the reason (string) the article is being deleted
+
'ArticleContentOnDiff': before showing the article content below a diff.
Use this to change the content in this area or how it is loaded.
$diffEngine: the DifferenceEngine
+++ /dev/null
-<?php
-/**
- * Actions are things which can be done to pages (edit, delete, rollback, etc). They
- * are distinct from Special Pages because an action must apply to exactly one page.
- *
- * To add an action in an extension, create a subclass of Action, and add the key to
- * $wgActions. There is also the deprecated UnknownAction hook
- *
- *
- * 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
- *
- * @file
- */
-abstract class Action {
-
- // Page on which we're performing the action
- // @var Article
- protected $page;
-
- // RequestContext if specified; otherwise we'll use the Context from the Page
- // @var RequestContext
- protected $context;
-
- // The fields used to create the HTMLForm
- // @var Array
- protected $fields;
-
- /**
- * Get the Action subclass which should be used to handle this action, false if
- * the action is disabled, or null if it's not recognised
- * @param $action String
- * @return bool|null|string
- */
- private final static function getClass( $action ){
- global $wgActions;
- $action = strtolower( $action );
-
- if( !isset( $wgActions[$action] ) ){
- return null;
- }
-
- if( $wgActions[$action] === false ){
- return false;
- }
-
- elseif( $wgActions[$action] === true ){
- return ucfirst( $action ) . 'Action';
- }
-
- else {
- return $wgActions[$action];
- }
- }
-
- /**
- * Get an appropriate Action subclass for the given action
- * @param $action String
- * @param $page Article
- * @return Action|false|null false if the action is disabled, null
- * if it is not recognised
- */
- public final static function factory( $action, Article $page ){
- $class = self::getClass( $action );
- if( $class ){
- $obj = new $class( $page );
- return $obj;
- }
- return null;
- }
-
- /**
- * Check if a given action is recognised, even if it's disabled
- *
- * @param $name String: name of an action
- * @return Bool
- */
- public final static function exists( $name ) {
- return self::getClass( $name ) !== null;
- }
-
- /**
- * Get the RequestContext in use here
- * @return RequestContext
- */
- protected final function getContext(){
- if( $this->context instanceof RequestContext ){
- return $this->context;
- }
- return $this->page->getContext();
- }
-
- /**
- * Get the WebRequest being used for this instance
- *
- * @return WebRequest
- */
- protected final function getRequest() {
- return $this->getContext()->request;
- }
-
- /**
- * Get the OutputPage being used for this instance
- *
- * @return OutputPage
- */
- protected final function getOutput() {
- return $this->getContext()->output;
- }
-
- /**
- * Shortcut to get the skin being used for this instance
- *
- * @return User
- */
- protected final function getUser() {
- return $this->getContext()->user;
- }
-
- /**
- * Shortcut to get the skin being used for this instance
- *
- * @return Skin
- */
- protected final function getSkin() {
- return $this->getContext()->skin;
- }
-
- /**
- * Shortcut to get the Title object from the page
- * @return Title
- */
- protected final function getTitle(){
- return $this->page->getTitle();
- }
-
- /**
- * Protected constructor: use Action::factory( $action, $page ) to actually build
- * these things in the real world
- * @param Article $page
- */
- protected function __construct( Article $page ){
- $this->page = $page;
- }
-
- /**
- * Return the name of the action this object responds to
- * @return String lowercase
- */
- public abstract function getName();
-
- /**
- * Get the permission required to perform this action. Often, but not always,
- * the same as the action name
- */
- public abstract function getRestriction();
-
- /**
- * Checks if the given user (identified by an object) can perform this action. Can be
- * overridden by sub-classes with more complicated permissions schemes. Failures here
- * must throw subclasses of ErrorPageError
- *
- * @param $user User: the user to check, or null to use the context user
- * @throws ErrorPageError
- */
- protected function checkCanExecute( User $user ) {
- if( $this->requiresWrite() && wfReadOnly() ){
- throw new ReadOnlyError();
- }
-
- if( $this->getRestriction() !== null && !$user->isAllowed( $this->getRestriction() ) ){
- throw new PermissionsError( $this->getRestriction() );
- }
-
- if( $this->requiresUnblock() && $user->isBlocked() ){
- $block = $user->mBlock;
- throw new UserBlockedError( $block );
- }
- }
-
- /**
- * Whether this action requires the wiki not to be locked
- * @return Bool
- */
- public function requiresWrite(){
- return true;
- }
-
- /**
- * Whether this action can still be executed by a blocked user
- * @return Bool
- */
- public function requiresUnblock(){
- return true;
- }
-
- /**
- * Set output headers for noindexing etc. This function will not be called through
- * the execute() entry point, so only put UI-related stuff in here.
- */
- protected function setHeaders() {
- $out = $this->getOutput();
- $out->setRobotPolicy( "noindex,nofollow" );
- $out->setPageTitle( $this->getTitle()->getPrefixedText() );
- $this->getOutput()->setSubtitle( $this->getDescription() );
- $out->setArticleRelated( true );
- }
-
- /**
- * Returns the name that goes in the \<h1\> page title
- *
- * Derived classes can override this, but usually it is easier to keep the
- * default behaviour. Messages can be added at run-time, see
- * MessageCache.php.
- *
- * @return String
- */
- protected function getDescription() {
- return wfMsg( strtolower( $this->getName() ) );
- }
-
- /**
- * The basic pattern for actions is to display some sort of HTMLForm UI, maybe with
- * some stuff underneath (history etc); to do some processing on submission of that
- * form (delete, protect, etc) and to do something exciting on 'success', be that
- * display something new or redirect to somewhere. Some actions have more exotic
- * behaviour, but that's what subclassing is for :D
- */
- public function show(){
- $this->setHeaders();
-
- // This will throw exceptions if there's a problem
- $this->checkCanExecute( $this->getUser() );
-
- $form = $this->getForm();
- if( $form instanceof HTMLForm ){
- if( $form->show() ){
- $this->onSuccess();
- }
- } else {
- // You're using the wrong type of Action
- throw new MWException( "Action::getFormFields() must produce a form. Use GetAction if you don't want one." );
- }
- }
-
- /**
- * Execute the action in a silent fashion: do not display anything or release any errors.
- * @param $data Array values that would normally be in the POST request
- * @param $captureErrors Bool whether to catch exceptions and just return false
- * @return Bool whether execution was successful
- */
- public function execute( array $data = null, $captureErrors = true ){
- try {
- // Set a new context so output doesn't leak.
- $this->context = clone $this->page->getContext();
-
- // This will throw exceptions if there's a problem
- $this->checkCanExecute( $this->getUser() );
-
- $form = $this->getForm();
- if( $form instanceof HTMLForm ){
- // Great, so there's a form. Ignore it and go straight to the submission callback
- $fields = array();
- foreach( $this->fields as $key => $params ){
- if( isset( $data[$key] ) ){
- $fields[$key] = $data[$key];
- } elseif( isset( $params['default'] ) ) {
- $fields[$key] = $params['default'];
- } else {
- $fields[$key] = null;
- }
- }
- $status = $this->onSubmit( $fields );
- if( $status === true ){
- // This might do permanent stuff
- $this->onSuccess();
- return true;
- } else {
- return false;
- }
- } else {
- // You're using the wrong type of Action
- throw new MWException( "Action::getFormFields() must produce a form. Use GetAction if you don't want one." );
- }
- }
- catch ( ErrorPageError $e ){
- if( $captureErrors ){
- return false;
- } else {
- throw $e;
- }
- }
- }
-
- /**
- * Get an HTMLForm descriptor array, or false if you don't want a form
- * @return Array
- */
- protected abstract function getFormFields();
-
- /**
- * Add pre- or post-text to the form
- * @return String
- */
- protected function preText(){ return ''; }
- protected function postText(){ return ''; }
-
- /**
- * Play with the HTMLForm if you need to more substantially
- * @param &$form HTMLForm
- */
- protected function alterForm( HTMLForm &$form ){}
-
- /**
- * Get the HTMLForm to control behaviour
- * @return HTMLForm|null
- */
- protected function getForm(){
- $this->fields = $this->getFormFields();
-
- // Give hooks a chance to alter the form, adding extra fields or text etc
- wfRunHooks( 'ActionModifyFormFields', array( $this->getName(), &$this->fields, $this->page ) );
-
- if( $this->fields === false ){
- return null;
- }
-
- $form = new HTMLForm( $this->fields, $this->getContext() );
- $form->setSubmitCallback( array( $this, 'onSubmit' ) );
- $form->addHiddenField( 'action', $this->getName() );
-
- $form->addPreText( $this->preText() );
- $form->addPostText( $this->postText() );
- $this->alterForm( $form );
-
- // Give hooks a chance to alter the form, adding extra fields or text etc
- wfRunHooks( 'ActionBeforeFormDisplay', array( $this->getName(), &$form, $this->page ) );
-
- return $form;
- }
-
- /**
- * Process the form on POST submission. If you return false from getFormFields(),
- * this will obviously never be reached. If you don't want to do anything with the
- * form, just return false here
- * @param $data Array
- * @return Bool|Array true for success, false for didn't-try, array of errors on failure
- */
- public abstract function onSubmit( $data );
-
- /**
- * Do something exciting on successful processing of the form. This might be to show
- * a confirmation message (watch, rollback, etc) or to redirect somewhere else (edit,
- * protect, etc).
- */
- public abstract function onSuccess();
-
-}
-
-/**
- * Actions generally fall into two groups: the show-a-form-then-do-something-with-the-input
- * format (protect, delete, move, etc), and the just-do-something format (watch, rollback,
- * patrol, etc).
- */
-abstract class FormlessAction extends Action {
-
- /**
- * Show something on GET request. This is displayed as the postText() of the HTMLForm
- * if there is one; you can always use alterForm() to add pre text if you need it. If
- * you call addPostText() from alterForm() as well as overriding this function, you
- * might get strange ordering.
- * @return String|null will be added to the HTMLForm if present, or just added to the
- * output if not. Return null to not add anything
- */
- public abstract function onView();
-
- /**
- * We don't want an HTMLForm
- */
- protected function getFormFields(){
- return false;
- }
-
- public function onSubmit( $data ){
- return false;
- }
-
- public function onSuccess(){
- return false;
- }
-
- public function show(){
- $this->setHeaders();
-
- // This will throw exceptions if there's a problem
- $this->checkCanExecute( $this->getUser() );
- $this->getOutput()->addHTML( $this->onView() );
- }
-
- /**
- * Execute the action silently, not giving any output. Since these actions don't have
- * forms, they probably won't have any data, but some (eg rollback) may do
- * @param $data Array values that would normally be in the GET request
- * @param $captureErrors Bool whether to catch exceptions and just return false
- * @return Bool whether execution was successful
- */
- public function execute( array $data = null, $captureErrors = true){
- try {
- // Set a new context so output doesn't leak.
- $this->context = clone $this->page->getContext();
- if( is_array( $data ) ){
- $this->context->setRequest( new FauxRequest( $data, false ) );
- }
-
- // This will throw exceptions if there's a problem
- $this->checkCanExecute( $this->getUser() );
-
- $this->onView();
- return true;
- }
- catch ( ErrorPageError $e ){
- if( $captureErrors ){
- return false;
- } else {
- throw $e;
- }
- }
- }
-}
\ No newline at end of file
/**
* User-interface handler for the "watch" action
- * @deprecated since 1.18
*/
public function watch() {
- Action::factory( 'watch', $this )->show();
+ global $wgOut;
+
+ if ( $wgOut->getUser()->isAnon() ) {
+ $wgOut->showErrorPage( 'watchnologin', 'watchnologintext' );
+ return;
+ }
+
+ if ( wfReadOnly() ) {
+ $wgOut->readOnlyPage();
+ return;
+ }
+
+ if ( $this->doWatch() ) {
+ $wgOut->setPagetitle( wfMsg( 'addedwatch' ) );
+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
+ $wgOut->addWikiMsg( 'addedwatchtext', $this->mTitle->getPrefixedText() );
+ }
+
+ $wgOut->returnToMain( true, $this->mTitle->getPrefixedText() );
}
/**
* This is safe to be called multiple times
*
* @return bool true on successful watch operation
- * @deprecated since 1.18
*/
public function doWatch() {
- return Action::factory( 'watch', $this )->execute();
+ global $wgUser;
+
+ if ( $wgUser->isAnon() ) {
+ return false;
+ }
+
+ if ( wfRunHooks( 'WatchArticle', array( &$wgUser, &$this ) ) ) {
+ $wgUser->addWatch( $this->mTitle );
+ return wfRunHooks( 'WatchArticleComplete', array( &$wgUser, &$this ) );
+ }
+
+ return false;
}
/**
* User interface handler for the "unwatch" action.
- * @deprecated since 1.18
*/
public function unwatch() {
- Action::factory( 'unwatch', $this )->show();
+ global $wgOut;
+
+ if ( $wgOut->getUser()->isAnon() ) {
+ $wgOut->showErrorPage( 'watchnologin', 'watchnologintext' );
+ return;
+ }
+
+ if ( wfReadOnly() ) {
+ $wgOut->readOnlyPage();
+ return;
+ }
+
+ if ( $this->doUnwatch() ) {
+ $wgOut->setPagetitle( wfMsg( 'removedwatch' ) );
+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
+ $wgOut->addWikiMsg( 'removedwatchtext', $this->mTitle->getPrefixedText() );
+ }
+
+ $wgOut->returnToMain( true, $this->mTitle->getPrefixedText() );
}
/**
* Stop watching a page
* @return bool true on successful unwatch
- * @deprecated since 1.18
*/
public function doUnwatch() {
- return Action::factory( 'unwatch', $this )->execute();
+ global $wgUser;
+
+ if ( $wgUser->isAnon() ) {
+ return false;
+ }
+
+ if ( wfRunHooks( 'UnwatchArticle', array( &$wgUser, &$this ) ) ) {
+ $wgUser->removeWatch( $this->mTitle );
+ return wfRunHooks( 'UnwatchArticleComplete', array( &$wgUser, &$this ) );
+ }
+
+ return false;
}
/**
* @param &$hasHistory Boolean: whether the page has a history
* @return mixed String containing deletion reason or empty string, or boolean false
* if no revision occurred
- * @deprecated since 1.18
*/
public function generateReason( &$hasHistory ) {
- return DeleteAction::getAutoReason( $this );
+ global $wgContLang;
+
+ $dbw = wfGetDB( DB_MASTER );
+ // Get the last revision
+ $rev = Revision::newFromTitle( $this->mTitle );
+
+ if ( is_null( $rev ) ) {
+ return false;
+ }
+
+ // Get the article's contents
+ $contents = $rev->getText();
+ $blank = false;
+
+ // If the page is blank, use the text from the previous revision,
+ // which can only be blank if there's a move/import/protect dummy revision involved
+ if ( $contents == '' ) {
+ $prev = $rev->getPrevious();
+
+ if ( $prev ) {
+ $contents = $prev->getText();
+ $blank = true;
+ }
+ }
+
+ // Find out if there was only one contributor
+ // Only scan the last 20 revisions
+ $res = $dbw->select( 'revision', 'rev_user_text',
+ array( 'rev_page' => $this->getID(), $dbw->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0' ),
+ __METHOD__,
+ array( 'LIMIT' => 20 )
+ );
+
+ if ( $res === false ) {
+ // This page has no revisions, which is very weird
+ return false;
+ }
+
+ $hasHistory = ( $res->numRows() > 1 );
+ $row = $dbw->fetchObject( $res );
+
+ if ( $row ) { // $row is false if the only contributor is hidden
+ $onlyAuthor = $row->rev_user_text;
+ // Try to find a second contributor
+ foreach ( $res as $row ) {
+ if ( $row->rev_user_text != $onlyAuthor ) { // Bug 22999
+ $onlyAuthor = false;
+ break;
+ }
+ }
+ } else {
+ $onlyAuthor = false;
+ }
+
+ // Generate the summary with a '$1' placeholder
+ if ( $blank ) {
+ // The current revision is blank and the one before is also
+ // blank. It's just not our lucky day
+ $reason = wfMsgForContent( 'exbeforeblank', '$1' );
+ } else {
+ if ( $onlyAuthor ) {
+ $reason = wfMsgForContent( 'excontentauthor', '$1', $onlyAuthor );
+ } else {
+ $reason = wfMsgForContent( 'excontent', '$1' );
+ }
+ }
+
+ if ( $reason == '-' ) {
+ // Allow these UI messages to be blanked out cleanly
+ return '';
+ }
+
+ // Replace newlines with spaces to prevent uglyness
+ $contents = preg_replace( "/[\n\r]/", ' ', $contents );
+ // Calculate the maximum amount of chars to get
+ // Max content length = max comment length - length of the comment (excl. $1)
+ $maxLength = 255 - ( strlen( $reason ) - 2 );
+ $contents = $wgContLang->truncate( $contents, $maxLength );
+ // Remove possible unfinished links
+ $contents = preg_replace( '/\[\[([^\]]*)\]?$/', '$1', $contents );
+ // Now replace the '$1' placeholder
+ $reason = str_replace( '$1', $contents, $reason );
+
+ return $reason;
}
/*
* UI entry point for page deletion
- * @deprecated since 1.18
*/
public function delete() {
- return Action::factory( 'delete', $this )->show();
+ global $wgOut, $wgRequest;
+
+ $confirm = $wgRequest->wasPosted() &&
+ $wgOut->getUser()->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) );
+
+ $this->DeleteReasonList = $wgRequest->getText( 'wpDeleteReasonList', 'other' );
+ $this->DeleteReason = $wgRequest->getText( 'wpReason' );
+
+ $reason = $this->DeleteReasonList;
+
+ if ( $reason != 'other' && $this->DeleteReason != '' ) {
+ // Entry from drop down menu + additional comment
+ $reason .= wfMsgForContent( 'colon-separator' ) . $this->DeleteReason;
+ } elseif ( $reason == 'other' ) {
+ $reason = $this->DeleteReason;
+ }
+
+ # Flag to hide all contents of the archived revisions
+ $suppress = $wgRequest->getVal( 'wpSuppress' ) && $wgOut->getUser()->isAllowed( 'suppressrevision' );
+
+ # This code desperately needs to be totally rewritten
+
+ # Read-only check...
+ if ( wfReadOnly() ) {
+ $wgOut->readOnlyPage();
+
+ return;
+ }
+
+ # Check permissions
+ $permission_errors = $this->mTitle->getUserPermissionsErrors( 'delete', $wgOut->getUser() );
+
+ if ( count( $permission_errors ) > 0 ) {
+ $wgOut->showPermissionsErrorPage( $permission_errors );
+
+ return;
+ }
+
+ $wgOut->setPagetitle( wfMsg( 'delete-confirm', $this->mTitle->getPrefixedText() ) );
+
+ # Better double-check that it hasn't been deleted yet!
+ $dbw = wfGetDB( DB_MASTER );
+ $conds = $this->mTitle->pageCond();
+ $latest = $dbw->selectField( 'page', 'page_latest', $conds, __METHOD__ );
+ if ( $latest === false ) {
+ $wgOut->showFatalError(
+ Html::rawElement(
+ 'div',
+ array( 'class' => 'error mw-error-cannotdelete' ),
+ wfMsgExt( 'cannotdelete', array( 'parse' ), $this->mTitle->getPrefixedText() )
+ )
+ );
+ $wgOut->addHTML( Xml::element( 'h2', null, LogPage::logName( 'delete' ) ) );
+ LogEventsList::showLogExtract(
+ $wgOut,
+ 'delete',
+ $this->mTitle->getPrefixedText()
+ );
+
+ return;
+ }
+
+ # Hack for big sites
+ $bigHistory = $this->isBigDeletion();
+ if ( $bigHistory && !$this->mTitle->userCan( 'bigdelete' ) ) {
+ global $wgLang, $wgDeleteRevisionsLimit;
+
+ $wgOut->wrapWikiMsg( "<div class='error'>\n$1\n</div>\n",
+ array( 'delete-toobig', $wgLang->formatNum( $wgDeleteRevisionsLimit ) ) );
+
+ return;
+ }
+
+ if ( $confirm ) {
+ $this->doDelete( $reason, $suppress );
+
+ if ( $wgRequest->getCheck( 'wpWatch' ) && $wgOut->getUser()->isLoggedIn() ) {
+ $this->doWatch();
+ } elseif ( $this->mTitle->userIsWatching() ) {
+ $this->doUnwatch();
+ }
+
+ return;
+ }
+
+ // Generate deletion reason
+ $hasHistory = false;
+ if ( !$reason ) {
+ $reason = $this->generateReason( $hasHistory );
+ }
+
+ // If the page has a history, insert a warning
+ if ( $hasHistory && !$confirm ) {
+ global $wgLang;
+
+ $skin = $wgOut->getSkin();
+ $revisions = $this->estimateRevisionCount();
+ //FIXME: lego
+ $wgOut->addHTML( '<strong class="mw-delete-warning-revisions">' .
+ wfMsgExt( 'historywarning', array( 'parseinline' ), $wgLang->formatNum( $revisions ) ) .
+ wfMsgHtml( 'word-separator' ) . $skin->link( $this->mTitle,
+ wfMsgHtml( 'history' ),
+ array( 'rel' => 'archives' ),
+ array( 'action' => 'history' ) ) .
+ '</strong>'
+ );
+
+ if ( $bigHistory ) {
+ global $wgDeleteRevisionsLimit;
+ $wgOut->wrapWikiMsg( "<div class='error'>\n$1\n</div>\n",
+ array( 'delete-warning-toobig', $wgLang->formatNum( $wgDeleteRevisionsLimit ) ) );
+ }
+ }
+
+ return $this->confirmDelete( $reason );
}
/**
* @return bool whether or not the page surpasses $wgDeleteRevisionsLimit revisions
- * @deprecated since 1.18
*/
public function isBigDeletion() {
global $wgDeleteRevisionsLimit;
- return $wgDeleteRevisionsLimit && $this->estimateRevisionCount() > $wgDeleteRevisionsLimit;
+
+ if ( $wgDeleteRevisionsLimit ) {
+ $revCount = $this->estimateRevisionCount();
+
+ return $revCount > $wgDeleteRevisionsLimit;
+ }
+
+ return false;
}
/**
return $authors;
}
+ /**
+ * Output deletion confirmation dialog
+ * FIXME: Move to another file?
+ * @param $reason String: prefilled reason
+ */
+ public function confirmDelete( $reason ) {
+ global $wgOut;
+
+ wfDebug( "Article::confirmDelete\n" );
+
+ $deleteBackLink = $wgOut->getSkin()->linkKnown( $this->mTitle );
+ $wgOut->setSubtitle( wfMsgHtml( 'delete-backlink', $deleteBackLink ) );
+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
+ $wgOut->addWikiMsg( 'confirmdeletetext' );
+
+ wfRunHooks( 'ArticleConfirmDelete', array( $this, $wgOut, &$reason ) );
+
+ if ( $wgOut->getUser()->isAllowed( 'suppressrevision' ) ) {
+ $suppress = "<tr id=\"wpDeleteSuppressRow\">
+ <td></td>
+ <td class='mw-input'><strong>" .
+ Xml::checkLabel( wfMsg( 'revdelete-suppress' ),
+ 'wpSuppress', 'wpSuppress', false, array( 'tabindex' => '4' ) ) .
+ "</strong></td>
+ </tr>";
+ } else {
+ $suppress = '';
+ }
+ $checkWatch = $wgOut->getUser()->getBoolOption( 'watchdeletion' ) || $this->mTitle->userIsWatching();
+
+ $form = Xml::openElement( 'form', array( 'method' => 'post',
+ 'action' => $this->mTitle->getLocalURL( 'action=delete' ), 'id' => 'deleteconfirm' ) ) .
+ Xml::openElement( 'fieldset', array( 'id' => 'mw-delete-table' ) ) .
+ Xml::tags( 'legend', null, wfMsgExt( 'delete-legend', array( 'parsemag', 'escapenoentities' ) ) ) .
+ Xml::openElement( 'table', array( 'id' => 'mw-deleteconfirm-table' ) ) .
+ "<tr id=\"wpDeleteReasonListRow\">
+ <td class='mw-label'>" .
+ Xml::label( wfMsg( 'deletecomment' ), 'wpDeleteReasonList' ) .
+ "</td>
+ <td class='mw-input'>" .
+ Xml::listDropDown( 'wpDeleteReasonList',
+ wfMsgForContent( 'deletereason-dropdown' ),
+ wfMsgForContent( 'deletereasonotherlist' ), '', 'wpReasonDropDown', 1 ) .
+ "</td>
+ </tr>
+ <tr id=\"wpDeleteReasonRow\">
+ <td class='mw-label'>" .
+ Xml::label( wfMsg( 'deleteotherreason' ), 'wpReason' ) .
+ "</td>
+ <td class='mw-input'>" .
+ Html::input( 'wpReason', $reason, 'text', array(
+ 'size' => '60',
+ 'maxlength' => '255',
+ 'tabindex' => '2',
+ 'id' => 'wpReason',
+ 'autofocus'
+ ) ) .
+ "</td>
+ </tr>";
+
+ # Disallow watching if user is not logged in
+ if ( $wgOut->getUser()->isLoggedIn() ) {
+ $form .= "
+ <tr>
+ <td></td>
+ <td class='mw-input'>" .
+ Xml::checkLabel( wfMsg( 'watchthis' ),
+ 'wpWatch', 'wpWatch', $checkWatch, array( 'tabindex' => '3' ) ) .
+ "</td>
+ </tr>";
+ }
+
+ $form .= "
+ $suppress
+ <tr>
+ <td></td>
+ <td class='mw-submit'>" .
+ Xml::submitButton( wfMsg( 'deletepage' ),
+ array( 'name' => 'wpConfirmB', 'id' => 'wpConfirmB', 'tabindex' => '5' ) ) .
+ "</td>
+ </tr>" .
+ Xml::closeElement( 'table' ) .
+ Xml::closeElement( 'fieldset' ) .
+ Html::hidden( 'wpEditToken', $wgOut->getUser()->editToken() ) .
+ Xml::closeElement( 'form' );
+
+ if ( $wgOut->getUser()->isAllowed( 'editinterface' ) ) {
+ $skin = $wgOut->getSkin();
+ $title = Title::makeTitle( NS_MEDIAWIKI, 'Deletereason-dropdown' );
+ $link = $skin->link(
+ $title,
+ wfMsgHtml( 'delete-edit-reasonlist' ),
+ array(),
+ array( 'action' => 'edit' )
+ );
+ $form .= '<p class="mw-delete-editreasons">' . $link . '</p>';
+ }
+
+ $wgOut->addHTML( $form );
+ $wgOut->addHTML( Xml::element( 'h2', null, LogPage::logName( 'delete' ) ) );
+ LogEventsList::showLogExtract( $wgOut, 'delete',
+ $this->mTitle->getPrefixedText()
+ );
+ }
+
/**
* Perform a deletion and output success or failure messages
- * @deprecated since 1.18
*/
public function doDelete( $reason, $suppress = false ) {
- return DeleteAction::doDeleteArticle(
- $this,
- $this->getContext(),
- array(
- 'Suppress' => $suppress !== false,
- 'Reason' => $reason,
- ),
- true
- );
+ global $wgOut;
+
+ $id = $this->mTitle->getArticleID( Title::GAID_FOR_UPDATE );
+
+ $error = '';
+ if ( $this->doDeleteArticle( $reason, $suppress, $id, $error ) ) {
+ $deleted = $this->mTitle->getPrefixedText();
+
+ $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) );
+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
+
+ $loglink = '[[Special:Log/delete|' . wfMsgNoTrans( 'deletionlog' ) . ']]';
+
+ $wgOut->addWikiMsg( 'deletedtext', $deleted, $loglink );
+ $wgOut->returnToMain( false );
+ } else {
+ if ( $error == '' ) {
+ $wgOut->showFatalError(
+ Html::rawElement(
+ 'div',
+ array( 'class' => 'error mw-error-cannotdelete' ),
+ wfMsgExt( 'cannotdelete', array( 'parse' ), $this->mTitle->getPrefixedText() )
+ )
+ );
+
+ $wgOut->addHTML( Xml::element( 'h2', null, LogPage::logName( 'delete' ) ) );
+
+ LogEventsList::showLogExtract(
+ $wgOut,
+ 'delete',
+ $this->mTitle->getPrefixedText()
+ );
+ } else {
+ $wgOut->showFatalError( $error );
+ }
+ }
}
/**
* @param $id int article ID
* @param $commit boolean defaults to true, triggers transaction end
* @return boolean true if successful
- *
- * @deprecated since 1.18
*/
public function doDeleteArticle( $reason, $suppress = false, $id = 0, $commit = true, &$error = '' ) {
- return DeleteAction::doDeleteArticle(
- $this,
- $this->getContext(),
+ global $wgDeferredUpdateList, $wgUseTrackbacks;
+ global $wgUser;
+
+ wfDebug( __METHOD__ . "\n" );
+
+ if ( ! wfRunHooks( 'ArticleDelete', array( &$this, &$wgUser, &$reason, &$error ) ) ) {
+ return false;
+ }
+ $dbw = wfGetDB( DB_MASTER );
+ $t = $this->mTitle->getDBkey();
+ $id = $id ? $id : $this->mTitle->getArticleID( Title::GAID_FOR_UPDATE );
+
+ if ( $t === '' || $id == 0 ) {
+ return false;
+ }
+
+ $u = new SiteStatsUpdate( 0, 1, - (int)$this->isCountable( $this->getRawText() ), -1 );
+ array_push( $wgDeferredUpdateList, $u );
+
+ // Bitfields to further suppress the content
+ if ( $suppress ) {
+ $bitfield = 0;
+ // This should be 15...
+ $bitfield |= Revision::DELETED_TEXT;
+ $bitfield |= Revision::DELETED_COMMENT;
+ $bitfield |= Revision::DELETED_USER;
+ $bitfield |= Revision::DELETED_RESTRICTED;
+ } else {
+ $bitfield = 'rev_deleted';
+ }
+
+ $dbw->begin();
+ // For now, shunt the revision data into the archive table.
+ // Text is *not* removed from the text table; bulk storage
+ // is left intact to avoid breaking block-compression or
+ // immutable storage schemes.
+ //
+ // For backwards compatibility, note that some older archive
+ // table entries will have ar_text and ar_flags fields still.
+ //
+ // In the future, we may keep revisions and mark them with
+ // the rev_deleted field, which is reserved for this purpose.
+ $dbw->insertSelect( 'archive', array( 'page', 'revision' ),
array(
- 'Suppress' => $suppress !== false,
- 'Reason' => $reason,
- ),
- $commit
+ 'ar_namespace' => 'page_namespace',
+ 'ar_title' => 'page_title',
+ 'ar_comment' => 'rev_comment',
+ 'ar_user' => 'rev_user',
+ 'ar_user_text' => 'rev_user_text',
+ 'ar_timestamp' => 'rev_timestamp',
+ 'ar_minor_edit' => 'rev_minor_edit',
+ 'ar_rev_id' => 'rev_id',
+ 'ar_text_id' => 'rev_text_id',
+ 'ar_text' => '\'\'', // Be explicit to appease
+ 'ar_flags' => '\'\'', // MySQL's "strict mode"...
+ 'ar_len' => 'rev_len',
+ 'ar_page_id' => 'page_id',
+ 'ar_deleted' => $bitfield
+ ), array(
+ 'page_id' => $id,
+ 'page_id = rev_page'
+ ), __METHOD__
);
+
+ # Delete restrictions for it
+ $dbw->delete( 'page_restrictions', array ( 'pr_page' => $id ), __METHOD__ );
+
+ # Now that it's safely backed up, delete it
+ $dbw->delete( 'page', array( 'page_id' => $id ), __METHOD__ );
+ $ok = ( $dbw->affectedRows() > 0 ); // getArticleId() uses slave, could be laggy
+
+ if ( !$ok ) {
+ $dbw->rollback();
+ return false;
+ }
+
+ # Fix category table counts
+ $cats = array();
+ $res = $dbw->select( 'categorylinks', 'cl_to', array( 'cl_from' => $id ), __METHOD__ );
+
+ foreach ( $res as $row ) {
+ $cats [] = $row->cl_to;
+ }
+
+ $this->updateCategoryCounts( array(), $cats );
+
+ # If using cascading deletes, we can skip some explicit deletes
+ if ( !$dbw->cascadingDeletes() ) {
+ $dbw->delete( 'revision', array( 'rev_page' => $id ), __METHOD__ );
+
+ if ( $wgUseTrackbacks )
+ $dbw->delete( 'trackbacks', array( 'tb_page' => $id ), __METHOD__ );
+
+ # Delete outgoing links
+ $dbw->delete( 'pagelinks', array( 'pl_from' => $id ) );
+ $dbw->delete( 'imagelinks', array( 'il_from' => $id ) );
+ $dbw->delete( 'categorylinks', array( 'cl_from' => $id ) );
+ $dbw->delete( 'templatelinks', array( 'tl_from' => $id ) );
+ $dbw->delete( 'externallinks', array( 'el_from' => $id ) );
+ $dbw->delete( 'langlinks', array( 'll_from' => $id ) );
+ $dbw->delete( 'redirect', array( 'rd_from' => $id ) );
+ }
+
+ # If using cleanup triggers, we can skip some manual deletes
+ if ( !$dbw->cleanupTriggers() ) {
+ # Clean up recentchanges entries...
+ $dbw->delete( 'recentchanges',
+ array( 'rc_type != ' . RC_LOG,
+ 'rc_namespace' => $this->mTitle->getNamespace(),
+ 'rc_title' => $this->mTitle->getDBkey() ),
+ __METHOD__ );
+ $dbw->delete( 'recentchanges',
+ array( 'rc_type != ' . RC_LOG, 'rc_cur_id' => $id ),
+ __METHOD__ );
+ }
+
+ # Clear caches
+ Article::onArticleDelete( $this->mTitle );
+
+ # Clear the cached article id so the interface doesn't act like we exist
+ $this->mTitle->resetArticleID( 0 );
+
+ # Log the deletion, if the page was suppressed, log it at Oversight instead
+ $logtype = $suppress ? 'suppress' : 'delete';
+ $log = new LogPage( $logtype );
+
+ # Make sure logging got through
+ $log->addEntry( 'delete', $this->mTitle, $reason, array() );
+
+ if ( $commit ) {
+ $dbw->commit();
+ }
+
+ wfRunHooks( 'ArticleDeleteComplete', array( &$this, &$wgUser, $reason, $id ) );
+ return true;
}
/**
$wgAutoloadLocalClasses = array(
# Includes
- 'Action' => 'includes/Action.php',
'AjaxDispatcher' => 'includes/AjaxDispatcher.php',
'AjaxResponse' => 'includes/AjaxResponse.php',
'AlphabeticPager' => 'includes/Pager.php',
'ConfEditorToken' => 'includes/ConfEditor.php',
'ConstantDependency' => 'includes/CacheDependency.php',
'CreativeCommonsRdf' => 'includes/Metadata.php',
+ 'Credits' => 'includes/Credits.php',
'CSSJanus' => 'includes/libs/CSSJanus.php',
'CSSMin' => 'includes/libs/CSSMin.php',
'DependencyWrapper' => 'includes/CacheDependency.php',
'ZhClient' => 'includes/ZhClient.php',
'ZipDirectoryReader' => 'includes/ZipDirectoryReader.php',
- # includes/actions
- 'CreditsAction' => 'includes/actions/CreditsAction.php',
- 'DeleteAction' => 'includes/actions/DeleteAction.php',
- 'UnwatchAction' => 'includes/actions/WatchAction.php',
- 'WatchAction' => 'includes/actions/WatchAction.php',
-
# includes/api
'ApiBase' => 'includes/api/ApiBase.php',
'ApiBlock' => 'includes/api/ApiBlock.php',
--- /dev/null
+<?php
+/**
+ * Formats credits for articles
+ *
+ * Copyright 2004, Evan Prodromou <evan@wikitravel.org>.
+ *
+ * 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
+ *
+ * @file
+ * @author <evan@wikitravel.org>
+ */
+
+class Credits {
+ /**
+ * This is largely cadged from PageHistory::history
+ * @param $article Article object
+ */
+ public static function showPage( Article $article ) {
+ global $wgOut;
+
+ wfProfileIn( __METHOD__ );
+
+ $wgOut->setPageTitle( $article->mTitle->getPrefixedText() );
+ $wgOut->setSubtitle( wfMsg( 'creditspage' ) );
+ $wgOut->setArticleFlag( false );
+ $wgOut->setArticleRelated( true );
+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
+
+ if ( $article->mTitle->getArticleID() == 0 ) {
+ $s = wfMsg( 'nocredits' );
+ } else {
+ $s = self::getCredits( $article, -1 );
+ }
+
+ $wgOut->addHTML( $s );
+
+ wfProfileOut( __METHOD__ );
+ }
+
+ /**
+ * Get a list of contributors of $article
+ * @param $article Article object
+ * @param $cnt Int: maximum list of contributors to show
+ * @param $showIfMax Bool: whether to contributors if there more than $cnt
+ * @return String: html
+ */
+ public static function getCredits( Article $article, $cnt, $showIfMax = true ) {
+ wfProfileIn( __METHOD__ );
+ $s = '';
+
+ if ( isset( $cnt ) && $cnt != 0 ) {
+ $s = self::getAuthor( $article );
+ if ( $cnt > 1 || $cnt < 0 ) {
+ $s .= ' ' . self::getContributors( $article, $cnt - 1, $showIfMax );
+ }
+ }
+
+ wfProfileOut( __METHOD__ );
+ return $s;
+ }
+
+ /**
+ * Get the last author with the last modification time
+ * @param $article Article object
+ */
+ protected static function getAuthor( Article $article ) {
+ global $wgLang;
+
+ $user = User::newFromId( $article->getUser() );
+
+ $timestamp = $article->getTimestamp();
+ if ( $timestamp ) {
+ $d = $wgLang->date( $article->getTimestamp(), true );
+ $t = $wgLang->time( $article->getTimestamp(), true );
+ } else {
+ $d = '';
+ $t = '';
+ }
+ return wfMsgExt( 'lastmodifiedatby', 'parsemag', $d, $t, self::userLink( $user ), $user->getName() );
+ }
+
+ /**
+ * Get a list of contributors of $article
+ * @param $article Article object
+ * @param $cnt Int: maximum list of contributors to show
+ * @param $showIfMax Bool: whether to contributors if there more than $cnt
+ * @return String: html
+ */
+ protected static function getContributors( Article $article, $cnt, $showIfMax ) {
+ global $wgLang, $wgHiddenPrefs;
+
+ $contributors = $article->getContributors();
+
+ $others_link = false;
+
+ # Hmm... too many to fit!
+ if ( $cnt > 0 && $contributors->count() > $cnt ) {
+ $others_link = self::othersLink( $article );
+ if ( !$showIfMax )
+ return wfMsgExt( 'othercontribs', 'parsemag', $others_link, $contributors->count() );
+ }
+
+ $real_names = array();
+ $user_names = array();
+ $anon_ips = array();
+
+ # Sift for real versus user names
+ foreach ( $contributors as $user ) {
+ $cnt--;
+ if ( $user->isLoggedIn() ) {
+ $link = self::link( $user );
+ if ( !in_array( 'realname', $wgHiddenPrefs ) && $user->getRealName() ) {
+ $real_names[] = $link;
+ } else {
+ $user_names[] = $link;
+ }
+ } else {
+ $anon_ips[] = self::link( $user );
+ }
+
+ if ( $cnt == 0 ) {
+ break;
+ }
+ }
+
+ if ( count( $real_names ) ) {
+ $real = $wgLang->listToText( $real_names );
+ } else {
+ $real = false;
+ }
+
+ # "ThisSite user(s) A, B and C"
+ if ( count( $user_names ) ) {
+ $user = wfMsgExt(
+ 'siteusers',
+ 'parsemag',
+ $wgLang->listToText( $user_names ), count( $user_names )
+ );
+ } else {
+ $user = false;
+ }
+
+ if ( count( $anon_ips ) ) {
+ $anon = wfMsgExt(
+ 'anonusers',
+ 'parsemag',
+ $wgLang->listToText( $anon_ips ), count( $anon_ips )
+ );
+ } else {
+ $anon = false;
+ }
+
+ # This is the big list, all mooshed together. We sift for blank strings
+ $fulllist = array();
+ foreach ( array( $real, $user, $anon, $others_link ) as $s ) {
+ if ( $s ) {
+ array_push( $fulllist, $s );
+ }
+ }
+
+ # Make the list into text...
+ $creds = $wgLang->listToText( $fulllist );
+
+ # "Based on work by ..."
+ return strlen( $creds )
+ ? wfMsgExt( 'othercontribs', 'parsemag', $creds, count( $fulllist ) )
+ : '';
+ }
+
+ /**
+ * Get a link to $user's user page
+ * @param $user User object
+ * @return String: html
+ */
+ protected static function link( User $user ) {
+ global $wgUser, $wgHiddenPrefs;
+ if ( !in_array( 'realname', $wgHiddenPrefs ) && !$user->isAnon() ) {
+ $real = $user->getRealName();
+ } else {
+ $real = false;
+ }
+
+ $skin = $wgUser->getSkin();
+ $page = $user->isAnon() ?
+ SpecialPage::getTitleFor( 'Contributions', $user->getName() ) :
+ $user->getUserPage();
+
+ return $skin->link( $page, htmlspecialchars( $real ? $real : $user->getName() ) );
+ }
+
+ /**
+ * Get a link to $user's user page
+ * @param $user User object
+ * @return String: html
+ */
+ protected static function userLink( User $user ) {
+ $link = self::link( $user );
+ if ( $user->isAnon() ) {
+ return wfMsgExt( 'anonuser', array( 'parseinline', 'replaceafter' ), $link );
+ } else {
+ global $wgHiddenPrefs;
+ if ( !in_array( 'realname', $wgHiddenPrefs ) && $user->getRealName() ) {
+ return $link;
+ } else {
+ return wfMsgExt( 'siteuser', 'parsemag', $link, $user->getName() );
+ }
+ }
+ }
+
+ /**
+ * Get a link to action=credits of $article page
+ * @param $article Article object
+ * @return String: html
+ */
+ protected static function othersLink( Article $article ) {
+ global $wgUser;
+ $skin = $wgUser->getSkin();
+ return $skin->link(
+ $article->getTitle(),
+ wfMsgHtml( 'others' ),
+ array(),
+ array( 'action' => 'credits' ),
+ array( 'known' )
+ );
+ }
+}
}
# Create a site configuration object. Not used for much in a default install
-if ( !defined( 'MW_COMPILED' ) ) {
- require_once( "$IP/includes/SiteConfiguration.php" );
+if ( !defined( 'MW_PHP4' ) ) {
+ if ( !defined( 'MW_COMPILED' ) ) {
+ require_once( "$IP/includes/SiteConfiguration.php" );
+ }
+ $wgConf = new SiteConfiguration;
}
-$wgConf = new SiteConfiguration;
/** @endcond */
/** MediaWiki version number */
/** @} */ # end special pages }
-/*************************************************************************//**
- * @name Actions
- * @{
- */
-
-/**
- * Array of allowed values for the title=foo&action=<action> parameter. Syntax is:
- * 'foo' => 'ClassName' Load the specified class which subclasses Action
- * 'foo' => true Load the class FooAction which subclasses Action
- * 'foo' => false The action is disabled; show an error message
- * Unsetting core actions will probably cause things to complain loudly.
- */
-$wgActions = array(
- 'credits' => true,
- 'delete' => true,
- 'unwatch' => true,
- 'watch' => true,
-);
-
-/**
- * Array of disabled article actions, e.g. view, edit, dublincore, delete, etc.
- * @deprecated since 1.18; just set $wgActions['action'] = false instead
- */
-$wgDisabledActions = array();
-
-/**
- * Allow the "info" action, very inefficient at the moment
- */
-$wgAllowPageInfo = false;
-
-/** @} */ # end actions }
-
/*************************************************************************//**
* @name Robot (search engine crawler) policy
* See also $wgNoFollowLinks.
* @{
*/
+/** Allow the "info" action, very inefficient at the moment */
+$wgAllowPageInfo = false;
+
/** Name of the external diff engine to use */
$wgExternalDiffEngine = false;
+/**
+ * Array of disabled article actions, e.g. view, edit, dublincore, delete, etc.
+ */
+$wgDisabledActions = array();
+
/**
* Disable redirects to special pages and interwiki redirects, which use a 302
* and have no "redirected from" link. Note this is only for articles with #Redirect
$dbw = wfGetDB( DB_MASTER );
$dbw->begin();
if ( $this->watchthis ) {
- Action::factory( 'watch', $this->mArticle )->execute();
+ $this->mArticle->doWatch();
} else {
- Action::factory( 'watch', $this->mArticle )->execute();
+ $this->mArticle->doUnwatch();
}
$dbw->commit();
}
if( $article->doDeleteArticle( $reason, $suppress, $id, false ) ) {
global $wgRequest;
if( $wgRequest->getCheck( 'wpWatch' ) && $wgUser->isLoggedIn() ) {
- Action::factory( 'watch', $article )->execute();
+ $article->doWatch();
} elseif( $title->userIsWatching() ) {
- Action::factory( 'unwatch', $article )->execute();
+ $article->doUnwatch();
}
$status = $file->delete( $reason, $suppress );
if( $status->ok ) {
}
if( $wgRequest->getCheck( 'mwProtectWatch' ) && $wgUser->isLoggedIn() ) {
- Action::factory( 'watch', $this->mArticle )->execute();
+ $this->mArticle->doWatch();
} elseif( $this->mTitle->userIsWatching() ) {
- Action::factory( 'unwatch', $this->mArticle )->execute();
+ $this->mArticle->doUnwatch();
}
return $ok;
}
$wgHiddenPrefs[] = 'enotifminoredits';
}
-# $wgDisabledActions is deprecated as of 1.18
-foreach( $wgDisabledActions as $action ){
- $wgActions[$action] = false;
-}
-if( !$wgAllowPageInfo ){
- $wgActions['info'] = false;
-}
-
if ( !$wgHtml5Version && $wgHtml5 && $wgAllowRdfaAttributes ) {
# see http://www.w3.org/TR/rdfa-in-html/#document-conformance
if ( $wgMimeType == 'application/xhtml+xml' ) {
return;
}
- $act = $this->getAction();
+ $action = $this->getAction();
- $action = Action::factory( $this->getAction(), $article );
- if( $action instanceof Action ){
- $action->show();
- wfProfileOut( __METHOD__ );
- return;
- }
-
- switch( $act ) {
+ switch( $action ) {
case 'view':
$this->context->output->setSquidMaxage( $this->getVal( 'SquidMaxage' ) );
$article->view();
$raw->view();
wfProfileOut( __METHOD__ . '-raw' );
break;
+ case 'watch':
+ case 'unwatch':
+ case 'delete':
case 'revert':
case 'rollback':
case 'protect':
case 'render':
case 'deletetrackback':
case 'purge':
- $article->$act();
+ $article->$action();
break;
case 'print':
$article->view();
$rdf->show();
}
break;
+ case 'credits':
+ Credits::showPage( $article );
+ break;
case 'submit':
if ( session_id() == '' ) {
// Send a cookie so anons get talk message notifications
$external = $this->context->request->getVal( 'externaledit' );
$section = $this->context->request->getVal( 'section' );
$oldid = $this->context->request->getVal( 'oldid' );
- if ( !$this->getVal( 'UseExternalEditor' ) || $act == 'submit' || $internal ||
+ if ( !$this->getVal( 'UseExternalEditor' ) || $action == 'submit' || $internal ||
$section || $oldid || ( !$this->context->user->getOption( 'externaleditor' ) && !$external ) ) {
$editor = new EditPage( $article );
$editor->submit();
$special->execute( '' );
break;
default:
- if ( wfRunHooks( 'UnknownAction', array( $act, $article ) ) ) {
+ if ( wfRunHooks( 'UnknownAction', array( $action, $article ) ) ) {
$this->context->output->showErrorPage( 'nosuchaction', 'nosuchactiontext' );
}
}
+++ /dev/null
-<?php
-/**
- * Formats credits for articles
- *
- * Copyright 2004, Evan Prodromou <evan@wikitravel.org>.
- *
- * 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
- *
- * @file
- * @ingroup Actions
- * @author <evan@wikitravel.org>
- */
-
-class CreditsAction extends FormlessAction {
-
- public function getName(){
- return 'credits';
- }
-
- public function getRestriction(){
- return null;
- }
-
- /**
- * This is largely cadged from PageHistory::history
- */
- public function onView() {
- wfProfileIn( __METHOD__ );
-
- if ( $this->page->getID() == 0 ) {
- $s = wfMsg( 'nocredits' );
- } else {
- $s = $this->getCredits( -1 );
- }
-
- wfProfileOut( __METHOD__ );
-
- return $s;
- }
-
- /**
- * Get a list of contributors of $article
- * @param $article Article object
- * @param $cnt Int: maximum list of contributors to show
- * @param $showIfMax Bool: whether to contributors if there more than $cnt
- * @return String: html
- */
- protected function getCredits( $cnt, $showIfMax = true ) {
- wfProfileIn( __METHOD__ );
- $s = '';
-
- if ( isset( $cnt ) && $cnt != 0 ) {
- $s = self::getAuthor( $this->page );
- if ( $cnt > 1 || $cnt < 0 ) {
- $s .= ' ' . $this->getContributors( $cnt - 1, $showIfMax );
- }
- }
-
- wfProfileOut( __METHOD__ );
- return $s;
- }
-
- /**
- * Get the last author with the last modification time
- * @param $article Article object
- */
- protected static function getAuthor( Article $article ) {
- global $wgLang;
-
- $user = User::newFromId( $article->getUser() );
-
- $timestamp = $article->getTimestamp();
- if ( $timestamp ) {
- $d = $wgLang->date( $article->getTimestamp(), true );
- $t = $wgLang->time( $article->getTimestamp(), true );
- } else {
- $d = '';
- $t = '';
- }
- return wfMsgExt( 'lastmodifiedatby', 'parsemag', $d, $t, self::userLink( $user ), $user->getName() );
- }
-
- /**
- * Get a list of contributors of $article
- * @param $article Article object
- * @param $cnt Int: maximum list of contributors to show
- * @param $showIfMax Bool: whether to contributors if there more than $cnt
- * @return String: html
- */
- protected function getContributors( $cnt, $showIfMax ) {
- global $wgLang, $wgHiddenPrefs;
-
- $contributors = $this->page->getContributors();
-
- $others_link = false;
-
- # Hmm... too many to fit!
- if ( $cnt > 0 && $contributors->count() > $cnt ) {
- $others_link = $this->othersLink();
- if ( !$showIfMax )
- return wfMsgExt( 'othercontribs', 'parsemag', $others_link, $contributors->count() );
- }
-
- $real_names = array();
- $user_names = array();
- $anon_ips = array();
-
- # Sift for real versus user names
- foreach ( $contributors as $user ) {
- $cnt--;
- if ( $user->isLoggedIn() ) {
- $link = self::link( $user );
- if ( !in_array( 'realname', $wgHiddenPrefs ) && $user->getRealName() ) {
- $real_names[] = $link;
- } else {
- $user_names[] = $link;
- }
- } else {
- $anon_ips[] = self::link( $user );
- }
-
- if ( $cnt == 0 ) {
- break;
- }
- }
-
- if ( count( $real_names ) ) {
- $real = $wgLang->listToText( $real_names );
- } else {
- $real = false;
- }
-
- # "ThisSite user(s) A, B and C"
- if ( count( $user_names ) ) {
- $user = wfMsgExt(
- 'siteusers',
- 'parsemag',
- $wgLang->listToText( $user_names ), count( $user_names )
- );
- } else {
- $user = false;
- }
-
- if ( count( $anon_ips ) ) {
- $anon = wfMsgExt(
- 'anonusers',
- 'parsemag',
- $wgLang->listToText( $anon_ips ), count( $anon_ips )
- );
- } else {
- $anon = false;
- }
-
- # This is the big list, all mooshed together. We sift for blank strings
- $fulllist = array();
- foreach ( array( $real, $user, $anon, $others_link ) as $s ) {
- if ( $s ) {
- array_push( $fulllist, $s );
- }
- }
-
- # Make the list into text...
- $creds = $wgLang->listToText( $fulllist );
-
- # "Based on work by ..."
- return strlen( $creds )
- ? wfMsgExt( 'othercontribs', 'parsemag', $creds, count( $fulllist ) )
- : '';
- }
-
- /**
- * Get a link to $user's user page
- * @param $user User object
- * @return String: html
- */
- protected static function link( User $user ) {
- global $wgUser, $wgHiddenPrefs;
- if ( !in_array( 'realname', $wgHiddenPrefs ) && !$user->isAnon() ) {
- $real = $user->getRealName();
- } else {
- $real = false;
- }
-
- $page = $user->isAnon()
- ? SpecialPage::getTitleFor( 'Contributions', $user->getName() )
- : $user->getUserPage();
-
- return Linker::link( $page, htmlspecialchars( $real ? $real : $user->getName() ) );
- }
-
- /**
- * Get a link to $user's user page
- * @param $user User object
- * @return String: html
- */
- protected static function userLink( User $user ) {
- $link = self::link( $user );
- if ( $user->isAnon() ) {
- return wfMsgExt( 'anonuser', array( 'parseinline', 'replaceafter' ), $link );
- } else {
- global $wgHiddenPrefs;
- if ( !in_array( 'realname', $wgHiddenPrefs ) && $user->getRealName() ) {
- return $link;
- } else {
- return wfMsgExt( 'siteuser', 'parsemag', $link, $user->getName() );
- }
- }
- }
-
- /**
- * Get a link to action=credits of $article page
- * @param $article Article object
- * @return String: html
- */
- protected function othersLink() {
- global $wgUser;
- return Linker::link(
- $this->getTitle(),
- wfMsgHtml( 'others' ),
- array(),
- array( 'action' => 'credits' ),
- array( 'known' )
- );
- }
-}
+++ /dev/null
-<?php
-/**
- * Performs the watch and unwatch actions on a page
- *
- * 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
- *
- * @file
- * @ingroup Actions
- */
-
-class DeleteAction extends Action {
-
- public function getName(){
- return 'delete';
- }
-
- public function getRestriction(){
- return 'delete';
- }
-
- protected function getDescription(){
- return wfMsg( 'delete-confirm', $this->getTitle()->getPrefixedText() );
- }
-
- /**
- * Check that the deletion can be executed. In addition to checking the user permissions,
- * check that the page is not too big and has not already been deleted.
- * @throws ErrorPageError
- * @see Action::checkCanExecute
- */
- protected function checkCanExecute( User $user ){
-
- // Check that the article hasn't already been deleted
- $dbw = wfGetDB( DB_MASTER );
- $conds = $this->getTitle()->pageCond();
- $latest = $dbw->selectField( 'page', 'page_latest', $conds, __METHOD__ );
- if ( $latest === false ) {
- // Get the deletion log
- $log = '';
- LogEventsList::showLogExtract(
- $log,
- 'delete',
- $this->getTitle()->getPrefixedText()
- );
-
- $msg = new Message( 'cannotdelete' );
- $msg->params( $this->getTitle()->getPrefixedText() ); // This parameter is parsed
- $msg->rawParams( $log ); // This is not
-
- throw new ErrorPageError( 'internalerror', $msg );
- }
-
- // Limit deletions of big pages
- $bigHistory = $this->isBigDeletion();
- if ( $bigHistory && !$user->isAllowed( 'bigdelete' ) ) {
- global $wgDeleteRevisionsLimit;
- throw new ErrorPageError(
- 'internalerror',
- 'delete-toobig',
- $this->getContext()->lang->formatNum( $wgDeleteRevisionsLimit )
- );
- }
-
- return parent::checkCanExecute( $user );
- }
-
- protected function getFormFields(){
- // TODO: add more useful things here?
- $infoText = Html::rawElement(
- 'strong',
- array(),
- Linker::link( $this->getTitle(), $this->getTitle()->getText() )
- );
-
- $arr = array(
- 'Page' => array(
- 'type' => 'info',
- 'raw' => true,
- 'default' => $infoText,
- ),
- 'Reason' => array(
- 'type' => 'selectandother',
- 'label-message' => 'deletecomment',
- 'options-message' => 'deletereason-dropdown',
- 'size' => '60',
- 'maxlength' => '255',
- 'default' => self::getAutoReason( $this->page),
- ),
- );
-
- if( $this->getUser()->isLoggedIn() ){
- $arr['Watch'] = array(
- 'type' => 'check',
- 'label-message' => 'watchthis',
- 'default' => $this->getUser()->getBoolOption( 'watchdeletion' ) || $this->getTitle()->userIsWatching()
- );
- }
-
- if( $this->getUser()->isAllowed( 'suppressrevision' ) ){
- $arr['Suppress'] = array(
- 'type' => 'check',
- 'label-message' => 'revdelete-suppress',
- 'default' => false,
- );
- }
-
- return $arr;
- }
-
- /**
- * Text to go at the top of the form, before the opening fieldset
- * @see Action::preText()
- * @return String
- */
- protected function preText() {
-
- // If the page has a history, insert a warning
- if ( $this->page->estimateRevisionCount() ) {
- global $wgLang;
-
- $link = Linker::link(
- $this->getTitle(),
- wfMsgHtml( 'history' ),
- array( 'rel' => 'archives' ),
- array( 'action' => 'history' )
- );
-
- return Html::rawElement(
- 'strong',
- array( 'class' => 'mw-delete-warning-revisions' ),
- wfMessage(
- 'historywarning',
- $wgLang->formatNum( $this->page->estimateRevisionCount() )
- )->rawParams( $link )->parse()
- );
- }
- }
-
- /**
- * Text to go at the bottom of the form, below the closing fieldset
- * @see Action::postText()
- * @return string
- */
- protected function postText(){
- $s = '';
- LogEventsList::showLogExtract(
- $s,
- 'delete',
- $this->getTitle()->getPrefixedText()
- );
- return Html::element( 'h2', array(), LogPage::logName( 'delete' ) ) . $s;
- }
-
- protected function alterForm( HTMLForm &$form ){
- $form->setWrapperLegend( wfMsgExt( 'delete-legend', array( 'parsemag', 'escapenoentities' ) ) );
-
- if ( $this->getUser()->isAllowed( 'editinterface' ) ) {
- $link = Linker::link(
- Title::makeTitle( NS_MEDIAWIKI, 'Deletereason-dropdown' ),
- wfMsgHtml( 'delete-edit-reasonlist' ),
- array(),
- array( 'action' => 'edit' )
- );
- $form->addHeaderText( '<p class="mw-delete-editreasons">' . $link . '</p>' );
- }
- }
-
- /**
- * Function called on form submission. Privilege checks and validation have already been
- * completed by this point; we just need to jump out to the heavy-lifting function,
- * which is implemented as a static method so it can be called from other places
- * TODO: make those other places call $action->execute() properly
- * @see Action::onSubmit()
- * @param $data Array
- * @return Array|Bool
- */
- public function onSubmit( $data ){
- $status = self::doDeleteArticle( $this->page, $this->getContext(), $data, true );
- return $status;
- }
-
- public function onSuccess(){
- // Watch or unwatch, if requested
- if( $this->getRequest()->getCheck( 'wpWatch' ) && $this->getUser()->isLoggedIn() ) {
- Action::factory( 'watch', $this->page )->execute();
- } elseif ( $this->getTitle()->userIsWatching() ) {
- Action::factory( 'unwatch', $this->page )->execute();
- }
-
- $this->getOutput()->setPagetitle( wfMsg( 'actioncomplete' ) );
- $this->getOutput()->addWikiMsg(
- 'deletedtext',
- $this->getTitle()->getPrefixedText(),
- '[[Special:Log/delete|' . wfMsgNoTrans( 'deletionlog' ) . ']]'
- );
- $this->getOutput()->returnToMain( false );
- }
-
- /**
- * @return bool whether or not the page surpasses $wgDeleteRevisionsLimit revisions
- */
- protected function isBigDeletion() {
- global $wgDeleteRevisionsLimit;
- return $wgDeleteRevisionsLimit && $this->page->estimateRevisionCount() > $wgDeleteRevisionsLimit;
- }
-
- /**
- * Back-end article deletion
- * Deletes the article with database consistency, writes logs, purges caches
- *
- * @param $commit boolean defaults to true, triggers transaction end
- * @return Bool|Array true if successful, error array on failure
- */
- public static function doDeleteArticle( Article $page, RequestContext $context, array $data, $commit = true ) {
- global $wgDeferredUpdateList, $wgUseTrackbacks;
-
- wfDebug( __METHOD__ . "\n" );
-
- // The normal syntax from HTMLSelectAndOtherField is for the reason to be in the form
- // 'Reason' => array( <full reason>, <dropdown>, <custom> ), but it's reasonable for other
- // functions to just pass 'Reason' => <reason>
- $data['Reason'] = (array)$data['Reason'];
-
- $error = null;
- if ( !wfRunHooks( 'ArticleDelete', array( &$page, &$context->user, &$data['Reason'][0], &$error ) ) ) {
- return $error;
- }
-
- $title = $page->getTitle();
- $id = $page->getID( Title::GAID_FOR_UPDATE );
-
- if ( $title->getDBkey() === '' || $id == 0 ) {
- return false;
- }
-
- $updates = new SiteStatsUpdate( 0, 1, - (int)$page->isCountable( $page->getRawText() ), -1 );
- array_push( $wgDeferredUpdateList, $updates );
-
- // Bitfields to further suppress the content
- if ( isset( $data['Suppress'] ) && $data['Suppress'] ) {
- $bitfield = 0;
- // This should be 15...
- $bitfield |= Revision::DELETED_TEXT;
- $bitfield |= Revision::DELETED_COMMENT;
- $bitfield |= Revision::DELETED_USER;
- $bitfield |= Revision::DELETED_RESTRICTED;
-
- $logtype = 'suppress';
- } else {
- // Otherwise, leave it unchanged
- $bitfield = 'rev_deleted';
- $logtype = 'delete';
- }
-
- $dbw = wfGetDB( DB_MASTER );
- $dbw->begin();
- // For now, shunt the revision data into the archive table.
- // Text is *not* removed from the text table; bulk storage
- // is left intact to avoid breaking block-compression or
- // immutable storage schemes.
- //
- // For backwards compatibility, note that some older archive
- // table entries will have ar_text and ar_flags fields still.
- //
- // In the future, we may keep revisions and mark them with
- // the rev_deleted field, which is reserved for this purpose.
- $dbw->insertSelect(
- 'archive',
- array( 'page', 'revision' ),
- array(
- 'ar_namespace' => 'page_namespace',
- 'ar_title' => 'page_title',
- 'ar_comment' => 'rev_comment',
- 'ar_user' => 'rev_user',
- 'ar_user_text' => 'rev_user_text',
- 'ar_timestamp' => 'rev_timestamp',
- 'ar_minor_edit' => 'rev_minor_edit',
- 'ar_rev_id' => 'rev_id',
- 'ar_text_id' => 'rev_text_id',
- 'ar_text' => "''", // Be explicit to appease
- 'ar_flags' => "''", // MySQL's "strict mode"...
- 'ar_len' => 'rev_len',
- 'ar_page_id' => 'page_id',
- 'ar_deleted' => $bitfield
- ),
- array(
- 'page_id' => $id,
- 'page_id = rev_page'
- ),
- __METHOD__
- );
-
- // Delete restrictions for it
- $dbw->delete( 'page_restrictions', array ( 'pr_page' => $id ), __METHOD__ );
-
- // Now that it's safely backed up, delete it
- $dbw->delete( 'page', array( 'page_id' => $id ), __METHOD__ );
-
- // getArticleId() uses slave, could be laggy
- if ( $dbw->affectedRows() == 0 ) {
- $dbw->rollback();
- return false;
- }
-
- // Fix category table counts
- $res = $dbw->select( 'categorylinks', 'cl_to', array( 'cl_from' => $id ), __METHOD__ );
- $cats = array();
- foreach ( $res as $row ) {
- $cats[] = $row->cl_to;
- }
- $page->updateCategoryCounts( array(), $cats );
-
- // If using cascading deletes, we can skip some explicit deletes
- if ( !$dbw->cascadingDeletes() ) {
- $dbw->delete( 'revision', array( 'rev_page' => $id ), __METHOD__ );
-
- if ( $wgUseTrackbacks ){
- $dbw->delete( 'trackbacks', array( 'tb_page' => $id ), __METHOD__ );
- }
-
- // Delete outgoing links
- $dbw->delete( 'pagelinks', array( 'pl_from' => $id ) );
- $dbw->delete( 'imagelinks', array( 'il_from' => $id ) );
- $dbw->delete( 'categorylinks', array( 'cl_from' => $id ) );
- $dbw->delete( 'templatelinks', array( 'tl_from' => $id ) );
- $dbw->delete( 'externallinks', array( 'el_from' => $id ) );
- $dbw->delete( 'langlinks', array( 'll_from' => $id ) );
- $dbw->delete( 'redirect', array( 'rd_from' => $id ) );
- }
-
- // If using cleanup triggers, we can skip some manual deletes
- if ( !$dbw->cleanupTriggers() ) {
- // Clean up recentchanges entries...
- $dbw->delete( 'recentchanges',
- array(
- 'rc_type != ' . RC_LOG,
- 'rc_namespace' => $title->getNamespace(),
- 'rc_title' => $title->getDBkey() ),
- __METHOD__
- );
- $dbw->delete(
- 'recentchanges',
- array( 'rc_type != ' . RC_LOG, 'rc_cur_id' => $id ),
- __METHOD__
- );
- }
-
- // Clear caches
- // TODO: should this be in here or left in Article?
- Article::onArticleDelete( $title );
-
- // Clear the cached article id so the interface doesn't act like we exist
- $title->resetArticleID( 0 );
-
- // Log the deletion, if the page was suppressed, log it at Oversight instead
- $log = new LogPage( $logtype );
-
- // Make sure logging got through
- $log->addEntry( 'delete', $title, $data['Reason'][0], array() );
-
- if ( $commit ) {
- $dbw->commit();
- }
-
- wfRunHooks( 'ArticleDeleteComplete', array( &$page, &$context->user, $data['Reason'][0], $id ) );
- return true;
- }
-
- /**
- * Auto-generates a deletion reason. Also sets $this->hasHistory if the page has old
- * revisions.
- *
- * @return mixed String containing default reason or empty string, or boolean false
- * if no revision was found
- */
- public static function getAutoReason( Article $page ) {
- global $wgContLang;
-
- $dbw = wfGetDB( DB_MASTER );
- // Get the last revision
- $rev = Revision::newFromTitle( $page->getTitle() );
-
- if ( is_null( $rev ) ) {
- return false;
- }
-
- // Get the article's contents
- $contents = $rev->getText();
- $blank = false;
-
- // If the page is blank, use the text from the previous revision,
- // which can only be blank if there's a move/import/protect dummy revision involved
- if ( $contents == '' ) {
- $prev = $rev->getPrevious();
-
- if ( $prev ) {
- $contents = $prev->getText();
- $blank = true;
- }
- }
-
- // Find out if there was only one contributor
- // Only scan the last 20 revisions
- $res = $dbw->select( 'revision', 'rev_user_text',
- array(
- 'rev_page' => $page->getID(),
- $dbw->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0'
- ),
- __METHOD__,
- array( 'LIMIT' => 20 )
- );
-
- if ( $res === false ) {
- // This page has no revisions, which is very weird
- return false;
- }
-
- $row = $dbw->fetchObject( $res );
-
- if ( $row ) { // $row is false if the only contributor is hidden
- $onlyAuthor = $row->rev_user_text;
- // Try to find a second contributor
- foreach ( $res as $row ) {
- if ( $row->rev_user_text != $onlyAuthor ) { // Bug 22999
- $onlyAuthor = false;
- break;
- }
- }
- } else {
- $onlyAuthor = false;
- }
-
- // Generate the summary with a '$1' placeholder
- if ( $blank ) {
- // The current revision is blank and the one before is also
- // blank. It's just not our lucky day
- $reason = wfMessage( 'exbeforeblank', '$1' )->inContentLanguage()->text();
- } else {
- if ( $onlyAuthor ) {
- $reason = wfMessage( 'excontentauthor', '$1', $onlyAuthor )->inContentLanguage()->text();
- } else {
- $reason = wfMessage( 'excontent', '$1' )->inContentLanguage()->text();
- }
- }
-
- if ( $reason == '-' ) {
- // Allow these UI messages to be blanked out cleanly
- return '';
- }
-
- // Replace newlines with spaces to prevent uglyness
- $contents = preg_replace( "/[\n\r]/", ' ', $contents );
- // Calculate the maximum number of chars to get
- // Max content length = max comment length - length of the comment (excl. $1)
- $maxLength = 255 - ( strlen( $reason ) - 2 );
- $contents = $wgContLang->truncate( $contents, $maxLength );
- // Remove possible unfinished links
- $contents = preg_replace( '/\[\[([^\]]*)\]?$/', '$1', $contents );
- // Now replace the '$1' placeholder
- $reason = str_replace( '$1', $contents, $reason );
-
- return $reason;
- }
-}
+++ /dev/null
-<?php
-/**
- * Performs the watch and unwatch actions on a page
- *
- * 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
- *
- * @file
- * @ingroup Actions
- */
-
-class WatchAction extends FormlessAction {
-
- public function getName(){
- return 'watch';
- }
-
- public function getRestriction(){
- return 'read';
- }
-
- protected function getDescription(){
- return wfMsg( 'addedwatch' );
- }
-
- protected function checkCanExecute( User $user ){
- if ( $user->isAnon() ) {
- throw new ErrorPageError( 'watchnologin', 'watchnologintext' );
- }
- return parent::checkCanExecute( $user );
- }
-
- public function onView() {
- wfProfileIn( __METHOD__ );
-
- $user = $this->getUser();
- if ( wfRunHooks( 'WatchArticle', array( &$user, &$this->page ) ) ) {
- $this->getUser()->addWatch( $this->getTitle() );
- wfRunHooks( 'WatchArticleComplete', array( &$user, &$this->page ) );
- }
-
- wfProfileOut( __METHOD__ );
-
- return wfMessage( 'addedwatchtext', $this->getTitle()->getPrefixedText() )->parse();
- }
-}
-
-class UnwatchAction extends WatchAction {
-
- public function getName(){
- return 'unwatch';
- }
-
- protected function getDescription(){
- return wfMsg( 'removedwatch' );
- }
-
- public function onView() {
- wfProfileIn( __METHOD__ );
-
- $user = $this->getUser();
- if ( wfRunHooks( 'UnwatchArticle', array( &$user, &$this->page ) ) ) {
- $this->getUser()->removeWatch( $this->getTitle() );
- wfRunHooks( 'UnwatchArticleComplete', array( &$user, &$this->page ) );
- }
-
- wfProfileOut( __METHOD__ );
-
- return wfMessage( 'removedwatchtext', $this->getTitle()->getPrefixedText() )->parse();
- }
-}
$articleObj = new Article( $titleObj );
if ( $value ) {
- Action::factory( 'watch', $articleObj )->execute();
+ $articleObj->doWatch();
} else {
- Action::factory( 'unwatch', $articleObj )->execute();
+ $articleObj->doUnwatch();
}
}
* @return Title::getUserPermissionsErrors()-like array
*/
public static function delete( &$article, $token, &$reason = null ) {
+ global $wgUser;
+ if ( $article->isBigDeletion() && !$wgUser->isAllowed( 'bigdelete' ) ) {
+ global $wgDeleteRevisionsLimit;
+ return array( array( 'delete-toobig', $wgDeleteRevisionsLimit ) );
+ }
$title = $article->getTitle();
$errors = self::getPermissionsError( $title, $token );
if ( count( $errors ) ) {
// Auto-generate a summary, if necessary
if ( is_null( $reason ) ) {
- $reason = DeleteAction::getAutoReason( $article );
+ // Need to pass a throwaway variable because generateReason expects
+ // a reference
+ $hasHistory = false;
+ $reason = $article->generateReason( $hasHistory );
if ( $reason === false ) {
return array( array( 'cannotdelete' ) );
}
}
- $action = Action::factory( 'delete', $article );
- $data = array(
- 'Reason' => $reason,
- 'Suppress' => false, // The thought of people doing this through the API is scary...
- );
-
- try {
- $action->execute( $data, false );
- }
- catch ( ErrorPageError $e ){
- if( $e->msg == 'delete-toobig' ){
- global $wgDeleteRevisionsLimit;
- return array( array( 'delete-toobig', $wgDeleteRevisionsLimit ) );
- } else {
- array( array( 'cannotdelete', $article->mTitle->getPrefixedText() ) );
- }
+ $error = '';
+ // Luckily, Article.php provides a reusable delete function that does the hard work for us
+ if ( $article->doDeleteArticle( $reason, false, 0, true, $error ) ) {
+ return array();
+ } else {
+ return array( array( 'cannotdelete', $article->mTitle->getPrefixedText() ) );
}
}
if ( $params['unwatch'] ) {
$res['unwatched'] = '';
$res['message'] = wfMsgExt( 'removedwatchtext', array( 'parse' ), $title->getPrefixedText() );
- $success = Action::factory( 'unwatch', $article )->execute();
+ $success = $article->doUnwatch();
} else {
$res['watched'] = '';
$res['message'] = wfMsgExt( 'addedwatchtext', array( 'parse' ), $title->getPrefixedText() );
- $success = Action::factory( 'watch', $article )->execute();
+ $success = $article->doWatch();
}
if ( !$success ) {
$this->dieUsageMsg( array( 'hookaborted' ) );
$article = new Article( $nt );
# Disallow deletions of big articles
- global $wgDeleteRevisionsLimit;
- if ( $wgDeleteRevisionsLimit
- && $this->estimateRevisionCount() > $wgDeleteRevisionsLimit
- && !$nt->userCan( 'bigdelete' ) )
- {
+ $bigHistory = $article->isBigDeletion();
+ if( $bigHistory && !$nt->userCan( 'bigdelete' ) ) {
global $wgDeleteRevisionsLimit;
$this->showForm( array('delete-toobig', $wgLang->formatNum( $wgDeleteRevisionsLimit ) ) );
return;
}
// This may output an error message and exit
- Action::factory( 'delete', $article )->execute(
- array( 'Reason' => wfMsgForContent( 'delete_and_move_reason' ) ),
- false // Do not capture exceptions
- );
+ $article->doDelete( wfMsgForContent( 'delete_and_move_reason' ) );
}
# don't allow moving to pages with # in
'unexpected' => 'Unexpected value: "$1"="$2".',
'formerror' => 'Error: could not submit form',
'badarticleerror' => 'This action cannot be performed on this page.',
-'cannotdelete' => 'The page or file "$1" could not be deleted. It may have already been deleted by someone else. The deletion log is provided below for convenience.
-
-$2',
+'cannotdelete' => 'The page or file "$1" could not be deleted.
+It may have already been deleted by someone else.',
'badtitle' => 'Bad title',
'badtitletext' => 'The requested page title was invalid, empty, or an incorrectly linked inter-language or inter-wiki title.
It may contain one or more characters which cannot be used in titles.',
'delete-confirm' => 'Delete "$1"',
'delete-backlink' => '← $1', # only translate this message to other languages if you have to change it
'delete-legend' => 'Delete',
-'historywarning' => "'''Warning:''' The page you are about to delete has a $2 with approximately $1 {{PLURAL:$1|revision|revisions}}:",
+'historywarning' => "'''Warning:''' The page you are about to delete has a history with approximately $1 {{PLURAL:$1|revision|revisions}}:",
'confirmdeletetext' => 'You are about to delete a page along with all of its history.
Please confirm that you intend to do this, that you understand the consequences, and that you are doing this in accordance with [[{{MediaWiki:Policy-url}}|the policy]].',
'actioncomplete' => 'Action complete',