X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FStorage%2FPageUpdater.php;h=e25f0f06dd8e080ecccd37f9070bdc4ae00b22dd;hb=9abfbf85b9279f4a3db9c3c1b5b2523da11bb0fd;hp=043e00ebf6c4595800e386fdcdad37be13ef6a0b;hpb=a479750da672066b4189b115d1141a23d8c5cae3;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/Storage/PageUpdater.php b/includes/Storage/PageUpdater.php index 043e00ebf6..e25f0f06dd 100644 --- a/includes/Storage/PageUpdater.php +++ b/includes/Storage/PageUpdater.php @@ -31,7 +31,6 @@ use Content; use ContentHandler; use DeferredUpdates; use Hooks; -use InvalidArgumentException; use LogicException; use ManualLogEntry; use MediaWiki\Linker\LinkTarget; @@ -39,6 +38,7 @@ use MediaWiki\Revision\MutableRevisionRecord; use MediaWiki\Revision\RevisionAccessException; use MediaWiki\Revision\RevisionRecord; use MediaWiki\Revision\RevisionStore; +use MediaWiki\Revision\SlotRoleRegistry; use MediaWiki\Revision\SlotRecord; use MWException; use RecentChange; @@ -96,6 +96,11 @@ class PageUpdater { */ private $revisionStore; + /** + * @var SlotRoleRegistry + */ + private $slotRoleRegistry; + /** * @var boolean see $wgUseAutomaticEditSummaries * @see $wgUseAutomaticEditSummaries @@ -148,13 +153,15 @@ class PageUpdater { * @param DerivedPageDataUpdater $derivedDataUpdater * @param LoadBalancer $loadBalancer * @param RevisionStore $revisionStore + * @param SlotRoleRegistry $slotRoleRegistry */ public function __construct( User $user, WikiPage $wikiPage, DerivedPageDataUpdater $derivedDataUpdater, LoadBalancer $loadBalancer, - RevisionStore $revisionStore + RevisionStore $revisionStore, + SlotRoleRegistry $slotRoleRegistry ) { $this->user = $user; $this->wikiPage = $wikiPage; @@ -162,6 +169,7 @@ class PageUpdater { $this->loadBalancer = $loadBalancer; $this->revisionStore = $revisionStore; + $this->slotRoleRegistry = $slotRoleRegistry; $this->slotsUpdate = new RevisionSlotsUpdate(); } @@ -317,14 +325,6 @@ class PageUpdater { return $this->derivedDataUpdater->grabCurrentRevision(); } - /** - * @return string - */ - private function getTimestampNow() { - // TODO: allow an override to be injected for testing - return wfTimestampNow(); - } - /** * Check flags and add EDIT_NEW or EDIT_UPDATE to them as needed. * @@ -346,8 +346,7 @@ class PageUpdater { * @param Content $content */ public function setContent( $role, Content $content ) { - // TODO: MCR: check the role and the content's model against the list of supported - // roles, see T194046. + $this->ensureRoleAllowed( $role ); $this->slotsUpdate->modifyContent( $role, $content ); } @@ -358,6 +357,8 @@ class PageUpdater { * @param SlotRecord $slot */ public function setSlot( SlotRecord $slot ) { + $this->ensureRoleAllowed( $slot->getRole() ); + $this->slotsUpdate->modifySlot( $slot ); } @@ -376,6 +377,7 @@ class PageUpdater { * by the new revision. */ public function inheritSlot( SlotRecord $originalSlot ) { + // NOTE: slots can be inherited even if the role is not "allowed" on the title. // NOTE: this slot is inherited from some other revision, but it's // a "modified" slot for the RevisionSlotsUpdate and DerivedPageDataUpdater, // since it's not implicitly inherited from the parent revision. @@ -393,9 +395,7 @@ class PageUpdater { * @param string $role A slot role name (but not "main") */ public function removeSlot( $role ) { - if ( $role === SlotRecord::MAIN ) { - throw new InvalidArgumentException( 'Cannot remove the main slot!' ); - } + $this->ensureRoleNotRequired( $role ); $this->slotsUpdate->removeSlot( $role ); } @@ -635,20 +635,38 @@ class PageUpdater { throw new RuntimeException( 'Something is trying to edit an article with an empty title' ); } - // TODO: MCR: check the role and the content's model against the list of supported - // and required roles, see T194046. + // NOTE: slots can be inherited even if the role is not "allowed" on the title. + $status = Status::newGood(); + $this->checkAllRolesAllowed( + $this->slotsUpdate->getModifiedRoles(), + $status + ); + $this->checkNoRolesRequired( + $this->slotsUpdate->getRemovedRoles(), + $status + ); - // Make sure the given content type is allowed for this page - // TODO: decide: Extend check to other slots? Consider the role in check? [PageType] - $mainContentHandler = $this->getContentHandler( SlotRecord::MAIN ); - if ( !$mainContentHandler->canBeUsedOn( $this->getTitle() ) ) { - $this->status = Status::newFatal( 'content-not-allowed-here', - ContentHandler::getLocalizedName( $mainContentHandler->getModelID() ), - $this->getTitle()->getPrefixedText() - ); + if ( !$status->isOK() ) { return null; } + // Make sure the given content is allowed in the respective slots of this page + foreach ( $this->slotsUpdate->getModifiedRoles() as $role ) { + $slot = $this->slotsUpdate->getModifiedSlot( $role ); + $roleHandler = $this->slotRoleRegistry->getRoleHandler( $role ); + + if ( !$roleHandler->isAllowedModel( $slot->getModel(), $this->getTitle() ) ) { + $contentHandler = ContentHandler::getForModelID( $slot->getModel() ); + $this->status = Status::newFatal( 'content-not-allowed-here', + ContentHandler::getLocalizedName( $contentHandler->getModelID() ), + $this->getTitle()->getPrefixedText(), + wfMessage( $roleHandler->getNameMessageKey() ) + // TODO: defer message lookup to caller + ); + return null; + } + } + // Load the data from the master database if needed. Needed to check flags. // NOTE: This grabs the parent revision as the CAS token, if grabParentRevision // wasn't called yet. If the page is modified by another process before we are done with @@ -882,13 +900,19 @@ class PageUpdater { $content = $slot->getContent(); // XXX: We may push this up to the "edit controller" level, see T192777. - // TODO: change the signature of PrepareSave to not take a WikiPage! + // XXX: prepareSave() and isValid() could live in SlotRoleHandler + // XXX: PrepareSave should not take a WikiPage! $prepStatus = $content->prepareSave( $wikiPage, $flags, $oldid, $user ); // TODO: MCR: record which problem arose in which slot. $status->merge( $prepStatus ); } + $this->checkAllRequiredRoles( + $rev->getSlotRoles(), + $status + ); + return $rev; } @@ -1080,10 +1104,10 @@ class PageUpdater { // TODO: move to storage service $newid = $wikiPage->insertOn( $dbw ); if ( $newid === false ) { - $dbw->endAtomic( __METHOD__ ); // nothing inserted + $dbw->endAtomic( __METHOD__ ); $status->fatal( 'edit-already-exists' ); - return $status; // nothing done + return $status; } // At this point we are now comitted to returning an OK @@ -1216,4 +1240,71 @@ class PageUpdater { ); } + /** + * @return string[] Slots required for this page update, as a list of role names. + */ + private function getRequiredSlotRoles() { + return $this->slotRoleRegistry->getRequiredRoles( $this->getTitle() ); + } + + /** + * @return string[] Slots allowed for this page update, as a list of role names. + */ + private function getAllowedSlotRoles() { + return $this->slotRoleRegistry->getAllowedRoles( $this->getTitle() ); + } + + private function ensureRoleAllowed( $role ) { + $allowedRoles = $this->getAllowedSlotRoles(); + if ( !in_array( $role, $allowedRoles ) ) { + throw new PageUpdateException( "Slot role `$role` is not allowed." ); + } + } + + private function ensureRoleNotRequired( $role ) { + $requiredRoles = $this->getRequiredSlotRoles(); + if ( in_array( $role, $requiredRoles ) ) { + throw new PageUpdateException( "Slot role `$role` is required." ); + } + } + + private function checkAllRolesAllowed( array $roles, Status $status ) { + $allowedRoles = $this->getAllowedSlotRoles(); + + $forbidden = array_diff( $roles, $allowedRoles ); + if ( !empty( $forbidden ) ) { + $status->error( + 'edit-slots-cannot-add', + count( $forbidden ), + implode( ', ', $forbidden ) + ); + } + } + + private function checkNoRolesRequired( array $roles, Status $status ) { + $requiredRoles = $this->getRequiredSlotRoles(); + + $needed = array_diff( $roles, $requiredRoles ); + if ( !empty( $needed ) ) { + $status->error( + 'edit-slots-cannot-remove', + count( $needed ), + implode( ', ', $needed ) + ); + } + } + + private function checkAllRequiredRoles( array $roles, Status $status ) { + $requiredRoles = $this->getRequiredSlotRoles(); + + $missing = array_diff( $requiredRoles, $roles ); + if ( !empty( $missing ) ) { + $status->error( + 'edit-slots-missing', + count( $missing ), + implode( ', ', $missing ) + ); + } + } + }