Current File : /home/jvzmxxx/wiki1/extensions/Flow/includes/TalkpageManager.php
<?php

namespace Flow;

use Flow\Content\BoardContent;
use Flow\Exception\InvalidInputException;
use Flow\Model\Workflow;
use Article;
use CentralAuthUser;
use ContentHandler;
use Status;
use Title;
use User;

interface OccupationController {
	/**
	 * @param Article $title
	 * @param Workflow $workflow
	 * @return Status
	 */
	public function ensureFlowRevision( Article $title, Workflow $workflow );

	/**
	 * Checks whether creation is technically possible.
	 *
	 * This considers all issues other than the user.
	 *
	 * @param Title $title Title to check
	 * @param bool $mustNotExist Whether the page is required to not exist; true means
	 *  it must not exist.
	 * @return Status Status indicating whether the creation is technically allowed
	 */
	public function checkIfCreationIsPossible( Title $title, $mustNotExist = true );

	/**
	 * Check if user has permission to create board.
	 *
	 * @param Title $title Title to check
	 * @param User $user User doing creation or move
	 * @return Status Status indicating whether the creation is technically allowed
	 */
	public function checkIfUserHasPermission( Title $title, User $user );

	/**
	 * Checks whether the given user is allowed to create a board at the given
	 * title.  If so, allows it to be created.
	 *
	 * @param Title $title Title to check
	 * @param User $user User who wants to create a board
	 * @param bool $mustNotExist Whether the page is required to not exist; defaults to
	 *   true.
	 * @return Status Returns successful status when the provided user has the rights to
	 *  convert $title from whatever it is now to a flow board; otherwise, specifies
	 *  the error.
	 */
	public function safeAllowCreation( Title $title, User $user, $mustNotExist = true );

	/**
	 * Allows creation, *WITHOUT* checks.
	 *
	 * checkIfCreationIsPossible *MUST* be called earlier, and
	 * checkIfUserHasPermission *MUST* be called earlier except when permission checks
	 * are deliberately being bypassed (very rare cases like global rename)
	 *
	 * @param Title $title
	 */
	public function forceAllowCreation( Title $title );

	/**
	 * Gives a user object used to manage talk pages
	 *
	 * @return User User to manage talkpages
	 * @throws \MWException If a user cannot be created.
	 */
	public function getTalkpageManager();
}

class TalkpageManager implements OccupationController {
	/**
	 * @var string[]
	 */
	protected $allowedPageNames = array();

	/**
	 * Cached talk page manager user
	 * @var User
	 */
	protected $talkPageManagerUser;

	/**
	 * When a page is taken over by Flow, add a revision.
	 *
	 * First, it provides a clearer history should Flow be disabled again later,
	 * and a descriptive message when people attempt to use regular API to fetch
	 * data for this "Page", which will no longer contain any useful content,
	 * since Flow has taken over.
	 *
	 * Also: Parsoid performs an API call to fetch page information, so we need
	 * to make sure a page actually exists ;)
	 *
	 * This method does not do any security checks regarding content model changes
	 * or the like.  Those happen much earlier in the request and should be checked
	 * before even attempting to create revisions.
	 *
	 * @param \Article $article
	 * @param Workflow $workflow
	 * @return Status Status for revision creation; On success (including if it already
	 *  had a top-most Flow revision), it will return a good status with an associative
	 *  array value.  $status->getValue()['revision'] will be a Revision
	 *  $status->getValue()['already-existed'] will be set to true if no revision needed
	 *  to be created
	 * @throws InvalidInputException
	 */
	public function ensureFlowRevision( Article $article, Workflow $workflow ) {
		$page = $article->getPage();
		$revision = $page->getRevision();

		if ( $revision !== null ) {
			$content = $revision->getContent();
			if ( $content instanceof BoardContent && $content->getWorkflowId() ) {
				// Revision is already a valid BoardContent
				return Status::newGood( array(
					'revision' => $revision,
					'already-existed' => true,
				) );
			}
		}

		$status = $page->doEditContent(
			new BoardContent( CONTENT_MODEL_FLOW_BOARD, $workflow->getId() ),
			wfMessage( 'flow-talk-taken-over-comment' )->plain(),
			EDIT_FORCE_BOT | EDIT_SUPPRESS_RC,
			false,
			$this->getTalkpageManager()
		);
		$value = $status->getValue();
		$value['already-existed'] = false;
		$status->setResult( $status->isOK(), $value );

		return $status;
	}

	/**
	 * {@inheritdoc}
	 */
	public function checkIfCreationIsPossible( Title $title, $mustNotExist = true) {
		global $wgContentHandlerUseDB;

		// Arbitrary pages can only be enabled when content handler
		// can store that content model in the database.
		if ( !$wgContentHandlerUseDB ) {
			return Status::newFatal( 'flow-error-allowcreation-no-usedb' );
		}

		// Only allow converting a non-existent page to Flow
		if ( $mustNotExist ) {
			if ( $title->exists( Title::GAID_FOR_UPDATE ) ) {
				return Status::newFatal( 'flow-error-allowcreation-already-exists' );
			}
		}

		return Status::newGood();
	}

	/**
	 * {@inheritdoc}
	 */
	public function checkIfUserHasPermission( Title $title, User $user ) {
		if (
			// If the title is default-Flow, the user always has permission
			ContentHandler::getDefaultModelFor( $title ) === CONTENT_MODEL_FLOW_BOARD ||

			// Gate this on the flow-create-board right, essentially giving
			// wiki communities control over if Flow board creation is allowed
			// to everyone or just a select few.
			$user->isAllowedAll( 'flow-create-board' )
		) {
			return Status::newGood();
		} else {
			return Status::newFatal( 'flow-error-allowcreation-flow-create-board' );
		}

	}

	/**
	 * {@inheritdoc}
	 */
	public function safeAllowCreation( Title $title, User $user, $mustNotExist = true ) {
		$status = Status::newGood();

		$technicallyAllowedStatus = $this->checkIfCreationIsPossible( $title, $mustNotExist );

		$permissionStatus = $this->checkIfUserHasPermission( $title, $user );

		$status->merge( $technicallyAllowedStatus );
		$status->merge( $permissionStatus );

		if ( $status->isOK() ) {
			$this->forceAllowCreation( $title );
		}

		return $status;
	}

	/**
	 * {@inheritdoc}
	 */
	public function forceAllowCreation( Title $title ) {
		/*
		 * Tracks which titles are allowed so that when
		 * BoardContentHandler::canBeUsedOn is called for this title, it
		 * can verify this title was explicitly allowed.
		 */
		$this->allowedPageNames[] = $title->getPrefixedDBkey();
	}

	/**
	 * Before creating a flow board, BoardContentHandler::canBeUsedOn will be
	 * called to verify it's ok to create it.
	 * That, in turn, will call this, which will check if the title we want to
	 * turn into a Flow board was allowed to create (with allowedPageNames)
	 *
	 * @param Title $title
	 * @return bool
	 */
	public function canBeUsedOn( Title $title ) {
		global $wgUser;

		// If the user has rights, mark the page as allowed
		// For MovePage
		$this->safeAllowCreation( $title, $wgUser, /* $mustNotExist = */ true );

		return
			// default content model already
			ContentHandler::getDefaultModelFor( $title ) === CONTENT_MODEL_FLOW_BOARD ||
			// explicitly allowed via safeAllowCreation()
			in_array( $title->getPrefixedDBkey(), $this->allowedPageNames );
	}

	/**
	 * Gives a user object used to manage talk pages
	 *
	 * @return User User to manage talkpages
	 */
	public function getTalkpageManager() {
		if ( $this->talkPageManagerUser !== null ) {
			return $this->talkPageManagerUser;
		}

		$user = User::newSystemUser( FLOW_TALK_PAGE_MANAGER_USER, [ 'steal' => true ] );

		if ( class_exists( 'CentralAuthUser' ) ) {
			// Attach to CentralAuth if a global account already
			// exists
			$ca = CentralAuthUser::getMasterInstance( $user );
			if ( $ca->exists() && !$ca->isAttached() ) {
				$ca->attach( wfWikiID(), 'admin' );
			}
		}

		$groups = $user->getGroups();
		foreach ( array( 'bot', 'flow-bot' ) as $group ) {
			if ( !in_array( $group, $groups ) ) {
				$user->addGroup( $group );
			}
		}

		$this->talkPageManagerUser = $user;
		return $user;
	}
}