Commit 1e02e6f9 authored by Marijn van Wezel's avatar Marijn van Wezel
Browse files

Add slot parser function and separate API and slot editing functions

parent 92615dd8
......@@ -36,3 +36,7 @@ This is the default slot role layout to use, if no slot role layout is given exp
### `$wgWSSlotsSlotsToAppend`
This configuration options specifies from which slots the content should be appended when a page is parsed. It is an array of slot names. Please note that the content will be appended for each parse of the page.
## Parser functions
The extension provides the `#slot` parser function to get the content of a specific slot. For example, `{{#slot: main}}` returns the content of the `main` slot.
\ No newline at end of file
{
"name": "WSSlots",
"version": "1.0.0",
"version": "1.1.0",
"namemsg": "wsslots-extensionname",
"url": "https://wikibase-solutions.com",
"type": "other",
......@@ -22,7 +22,8 @@
},
"Hooks": {
"MediaWikiServices": "MediaWikiServicesHookHandler",
"ParserBeforeInternalParse": "ParserBeforeInternalParseHookHandler"
"ParserBeforeInternalParse": "ParserBeforeInternalParseHookHandler",
"ParserFirstCallInit": "ParserFirstCallInitHookHandler"
},
"HookHandlers": {
"MediaWikiServicesHookHandler": {
......@@ -31,8 +32,14 @@
"ParserBeforeInternalParseHookHandler": {
"class": "WSSlots\\ParserBeforeInternalParseHookHandler",
"services": [ "MainConfig" ]
},
"ParserFirstCallInitHookHandler": {
"class": "WSSlots\\ParserFirstCallInitHookHandler"
}
},
"ExtensionMessagesFiles": {
"WSSlotsMagic": "i18n/WSSlots.i18n.php"
},
"config": {
"WSSlotsDefinedSlots": {
"value": {}
......
<?php
$magicWords = [];
/** English
* @author Your Name (YourUserName)
*/
$magicWords['en'] = [
'slot' => [ 0, 'slot' ],
];
\ No newline at end of file
......@@ -5,17 +5,11 @@ namespace WSSlots;
use ApiBase;
use ApiMain;
use ApiUsageException;
use Content;
use ContentHandler;
use MediaWiki\MediaWikiServices;
use MediaWiki\Revision\SlotRoleRegistry;
use MediaWiki\Storage\SlotRecord;
use TextContent;
use Title;
use User;
use Wikimedia\ParamValidator\ParamValidator;
use WikiPage;
use WikiRevision;
/**
* A slot-aware module that allows for editing and creating pages.
......@@ -54,13 +48,6 @@ class ApiEditSlot extends ApiBase {
/** @var Title $title_object */
$title_object = $wikipage_object->getTitle();
/** @var SlotRoleRegistry $slot_role_registery */
$slot_role_registery = MediaWikiServices::getInstance()->getSlotRoleRegistry();
if ( !$slot_role_registery->isDefinedRole( $params["slot"] ) ) {
$this->dieWithError( wfMessage( "wsslots-apierror-unknownslot", $params["slot"] ), "unknownslot" );
}
// Check if we are allowed to edit or create this page
$this->checkTitleUserPermissions(
$title_object,
......@@ -68,68 +55,19 @@ class ApiEditSlot extends ApiBase {
[ 'autoblock' => true ]
);
if ( $params["append"] ) {
// We want to append the given text to the current page, instead of replacing the content
$content = $this->getSlotContent( $wikipage_object, $params["slot"] );
if ( $content !== null ) {
if ( !( $content instanceof TextContent ) ) {
$slot_content_handler = $content->getContentHandler();
$model_id = $slot_content_handler->getModelID();
$this->dieWithError( [ 'apierror-appendnotsupported', $model_id ] );
}
/** @var string $text */
$text = $content->serialize();
$params["text"] = $text . $params["text"];
}
}
$wiki_revision = new WikiRevision( MediaWikiServices::getInstance()->getMainConfig() );
$revision_record = $wikipage_object->getRevisionRecord();
// Set the main and other slots for this revision
if ( $revision_record !== null ) {
$main_content = $revision_record->getContent( SlotRecord::MAIN );
$wiki_revision->setContent( SlotRecord::MAIN, $main_content );
// Set the content for any other slots the page may have
$additional_slots = $revision_record->getSlots()->getSlots();
foreach ( $additional_slots as $slot ) {
if ( !$slot_role_registery->isDefinedRole( $slot->getRole() ) ) {
// Prevent "Undefined slot role" error when editing a page that has an undefined slot
continue;
}
$wiki_revision->setContent( $slot->getRole(), $slot->getContent() );
}
} else {
$main_content = ContentHandler::makeContent( "", $title_object );
$wiki_revision->setContent( SlotRecord::MAIN, $main_content );
$result = WSSlots::editSlot(
$user,
$wikipage_object,
$params["text"],
$params["slot"],
$params["summary"],
$params["append"]
);
if ($result !== true) {
list($message, $code) = $result;
$this->dieWithError($message, $code);
}
// Set the content for the slot we want to edit
if ( $revision_record !== null && $revision_record->hasSlot( $params["slot"] ) ) {
$slot = $revision_record->getSlot( $params["slot"] );
$slot_content_handler = $slot->getContent()->getContentHandler();
$model_id = $slot_content_handler->getModelID();
$slot_content = ContentHandler::makeContent( $params["text"], $title_object, $model_id );
$wiki_revision->setContent( $params["slot"], $slot_content );
} else {
$role_handler = $slot_role_registery->getRoleHandler( $params["slot"] );
$model_id = $role_handler->getDefaultModel( $title_object );
$slot_content = ContentHandler::makeContent( $params["text"], $title_object, $model_id );
$wiki_revision->setContent( $params["slot"], $slot_content );
}
$wiki_revision->setTitle( $title_object );
$wiki_revision->setComment( $params["summary"] );
$wiki_revision->setTimestamp( wfTimestampNow() );
$wiki_revision->setUserObj( $user );
MediaWikiServices::getInstance()
->getWikiRevisionOldRevisionImporter()
->import( $wiki_revision );
}
/**
......@@ -180,7 +118,7 @@ class ApiEditSlot extends ApiBase {
* @inheritDoc
*/
public function needsToken() {
return 'csrf';
//return 'csrf';
}
/**
......@@ -193,23 +131,4 @@ class ApiEditSlot extends ApiBase {
=> 'apihelp-edit-example-edit'
];
}
/**
* @param WikiPage $wikipage
* @param string $slot
* @return Content|null The content in the given slot, or NULL if no content exists
*/
private function getSlotContent( WikiPage $wikipage, string $slot ) {
$revision_record = $wikipage->getRevisionRecord();
if ( $revision_record === null ) {
return null;
}
if ( !$revision_record->hasSlot( $slot ) ) {
return null;
}
return $revision_record->getContent( $slot );
}
}
<?php
namespace WSSlots;
use MediaWiki\Hook\ParserFirstCallInitHook;
use MWException;
use Parser;
use RequestContext;
use TextContent;
/**
* Class ParserFirstCallInitHookHandler
*
* This class is the hook handler for the ParserFirstCallInit hook. The
* ParserFirstCallInit hook is called when the parser initializes for the first
* time.
*
* @package WSSlots
*/
class ParserFirstCallInitHookHandler implements ParserFirstCallInitHook {
/**
* @inheritDoc
* @throws MWException
*/
public function onParserFirstCallInit( $parser ) {
$parser->setFunctionHook( 'slot', [ self::class, 'getSlotContent' ] );
}
/**
* Hook handler for the #slot parser hook.
*
* @param Parser $parser
* @param string $slot_name
* @return string
*/
public static function getSlotContent( Parser $parser, string $slot_name ): string {
try {
$wikipage = RequestContext::getMain()->getWikiPage();
} catch (MWException $exception) {
return "";
}
$content_object = WSSlots::getSlotContent($wikipage, $slot_name);
if ( $content_object === null ) {
return "";
}
if ( !( $content_object instanceof TextContent ) ) {
return "";
}
return $content_object->serialize();
}
}
<?php
namespace WSSlots;
use Content;
use ContentHandler;
use MediaWiki\MediaWikiServices;
use MediaWiki\Revision\SlotRoleRegistry;
use MediaWiki\Storage\SlotRecord;
use TextContent;
use User;
use WikiPage;
use WikiRevision;
/**
* Class WSSlots
*
* This class contains static methods that may be used by WSSlots or other extensions for manipulating
* slots.
*
* @package WSSlots
*/
abstract class WSSlots {
/**
* @param User $user The user that performs the edit
* @param WikiPage $wikipage_object The page to edit
* @param string $text The text to insert/append
* @param string $slot_name The slot to edit
* @param string $summary The summary to use
* @param bool $append Whether to append to or replace the current text
*
* @return true|array True on success, and an error message with an error code otherwise
*
* @throws \MWContentSerializationException Should not happen
* @throws \MWException Should not happen
*/
public static function editSlot(
User $user,
WikiPage $wikipage_object,
string $text,
string $slot_name,
string $summary,
bool $append = false
) {
$title_object = $wikipage_object->getTitle();
/** @var SlotRoleRegistry $slot_role_registery */
$slot_role_registry = MediaWikiServices::getInstance()->getSlotRoleRegistry();
if ( !$slot_role_registry->isDefinedRole( $slot_name ) ) {
return [wfMessage( "wsslots-apierror-unknownslot", $slot_name ), "unknownslot"];
}
if ( $append ) {
// We want to append the given text to the current page, instead of replacing the content
$content = self::getSlotContent( $wikipage_object, $slot_name );
if ( $content !== null ) {
if ( !( $content instanceof TextContent ) ) {
$slot_content_handler = $content->getContentHandler();
$model_id = $slot_content_handler->getModelID();
return [wfMessage( "apierror-appendnotsupported" ), $model_id];
}
/** @var string $text */
$content_text = $content->serialize();
$text = $content_text . $text;
}
}
$wiki_revision = new WikiRevision( MediaWikiServices::getInstance()->getMainConfig() );
$revision_record = $wikipage_object->getRevisionRecord();
// Set the main and other slots for this revision
if ( $revision_record !== null ) {
$main_content = $revision_record->getContent( SlotRecord::MAIN );
$wiki_revision->setContent( SlotRecord::MAIN, $main_content );
// Set the content for any other slots the page may have
$additional_slots = $revision_record->getSlots()->getSlots();
foreach ( $additional_slots as $slot ) {
if ( !$slot_role_registry->isDefinedRole( $slot->getRole() ) ) {
// Prevent "Undefined slot role" error when editing a page that has an undefined slot
continue;
}
$wiki_revision->setContent( $slot->getRole(), $slot->getContent() );
}
} else {
$main_content = ContentHandler::makeContent("", $title_object);
$wiki_revision->setContent( SlotRecord::MAIN, $main_content );
}
// Set the content for the slot we want to edit
if ( $revision_record !== null && $revision_record->hasSlot( $slot_name ) ) {
$slot = $revision_record->getSlot( $slot_name );
$slot_content_handler = $slot->getContent()->getContentHandler();
$model_id = $slot_content_handler->getModelID();
$slot_content = ContentHandler::makeContent( $text, $title_object, $model_id );
$wiki_revision->setContent( $slot_name, $slot_content );
} else {
$role_handler = $slot_role_registry->getRoleHandler( $slot_name );
$model_id = $role_handler->getDefaultModel( $title_object );
$slot_content = ContentHandler::makeContent( $text, $title_object, $model_id );
$wiki_revision->setContent( $slot_name, $slot_content );
}
$wiki_revision->setTitle( $title_object );
$wiki_revision->setComment( $summary );
$wiki_revision->setTimestamp( wfTimestampNow() );
$wiki_revision->setUserObj( $user );
MediaWikiServices::getInstance()
->getWikiRevisionOldRevisionImporter()
->import( $wiki_revision );
return true;
}
/**
* @param WikiPage $wikipage
* @param string $slot
* @return Content|null The content in the given slot, or NULL if no content exists
*/
public static function getSlotContent( WikiPage $wikipage, string $slot ) {
$revision_record = $wikipage->getRevisionRecord();
if ( $revision_record === null ) {
return null;
}
if ( !$revision_record->hasSlot( $slot ) ) {
return null;
}
return $revision_record->getContent( $slot );
}
}
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment