WMDE-leszek has uploaded a new change for review. (
https://gerrit.wikimedia.org/r/402868 )
Change subject: [WIP] Add API action for editing elements of a form
......................................................................
[WIP] Add API action for editing elements of a form
TODOs:
- error handling
- extract parsing of "data" (same as in AddForm API)
- return form and lastrevid for UI use
Bug: TODO add
Change-Id: Ice096f53a09b80aa26d2ced342a7986b82d01998
---
M extension.json
A src/Api/EditFormElements.php
A src/Api/EditFormElementsRequest.php
A src/Api/EditFormElementsRequestParser.php
A src/ChangeOp/ChangeOpEditFormElements.php
M src/DataModel/Form.php
A tests/phpunit/mediawiki/Api/EditFormElementsTest.php
7 files changed, 457 insertions(+), 0 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/WikibaseLexeme
refs/changes/68/402868/2
diff --git a/extension.json b/extension.json
index 324d685..e70af51 100644
--- a/extension.json
+++ b/extension.json
@@ -462,6 +462,10 @@
"wblexemeaddform": {
"class": "Wikibase\\Lexeme\\Api\\AddForm",
"factory":
"Wikibase\\Lexeme\\Api\\AddForm::newFromGlobalState"
+ },
+ "wblexemeeditformelementsgarlic": {
+ "class": "Wikibase\\Lexeme\\Api\\EditFormElements",
+ "factory":
"Wikibase\\Lexeme\\Api\\EditFormElements::newFromGlobalState"
}
},
"manifest_version": 2
diff --git a/src/Api/EditFormElements.php b/src/Api/EditFormElements.php
new file mode 100644
index 0000000..d51104e
--- /dev/null
+++ b/src/Api/EditFormElements.php
@@ -0,0 +1,142 @@
+<?php
+
+namespace Wikibase\Lexeme\Api;
+
+use Wikibase\EditEntityFactory;
+use Wikibase\Lib\Store\EntityRevisionLookup;
+
+/**
+ * @license GPL-2.0+
+ */
+class EditFormElements extends \ApiBase {
+ const LATEST_REVISION = 0;
+
+ /**
+ * @var EntityRevisionLookup
+ */
+ private $entityRevisionLookup;
+
+ /**
+ * @var EditEntityFactory
+ */
+ private $editEntityFactory;
+
+ public static function newFromGlobalState( \ApiMain $mainModule,
$moduleName ) {
+ $wikibaseRepo =
\Wikibase\Repo\WikibaseRepo::getDefaultInstance();
+
+ return new self(
+ $mainModule,
+ $moduleName,
+ $wikibaseRepo->getEntityRevisionLookup( 'uncached' ),
+ $wikibaseRepo->newEditEntityFactory(
$mainModule->getContext() )
+ );
+ }
+
+ public function __construct(
+ \ApiMain $mainModule,
+ $moduleName,
+ EntityRevisionLookup $entityRevisionLookup,
+ EditEntityFactory $editEntityFactory
+ ) {
+ parent::__construct( $mainModule, $moduleName );
+
+ $this->entityRevisionLookup = $entityRevisionLookup;
+ $this->editEntityFactory = $editEntityFactory;
+ }
+
+ public function execute() {
+ $params = $this->extractRequestParams();
+
+ $parser = new EditFormElementsRequestParser();
+ $request = $parser->parse( $params );
+
+ $formId = $request->getFormId();
+
+ $formRevision = $this->entityRevisionLookup->getEntityRevision(
+ $formId,
+ self::LATEST_REVISION,
+ EntityRevisionLookup::LATEST_FROM_MASTER
+ );
+ $form = $formRevision->getEntity();
+
+ $changeOp = $request->getChangeOp();
+
+ $changeOp->apply( $form );
+
+ $editEntity = $this->editEntityFactory->newEditEntity(
+ $this->getUser(),
+ $formId,
+ $formRevision->getRevisionId()
+ );
+
+ $summaryString = 'TODO: changeme';
+
+ $flags = EDIT_UPDATE;
+ if ( isset( $params['bot'] ) && $params['bot'] &&
$this->getUser()->isAllowed( 'bot' ) ) {
+ $flags |= EDIT_FORCE_BOT;
+ }
+
+ $tokenThatDoesNotNeedChecking = false;
+ //FIXME: Handle failure
+ $status = $editEntity->attemptSave(
+ $form,
+ $summaryString,
+ $flags,
+ $tokenThatDoesNotNeedChecking
+ );
+
+ $apiResult = $this->getResult();
+
+ // TODO: Do we really need `success` property in response?
+ $apiResult->addValue( null, 'success', 1 );
+ $apiResult->addValue( null, 'form', 'TODO' );
+ // TODO: get request object from $params
+ // TODO: get lexeme id from the request
+ // TODO: load lexeme
+ // TODO: get and apply the change op
+ // TODO: save the lexeme back
+ // TODO: generate API response
+ }
+
+ /**
+ * @see ApiBase::getAllowedParams
+ */
+ protected function getAllowedParams() {
+ return [
+ 'formId' => [
+ self::PARAM_TYPE => 'string',
+ self::PARAM_REQUIRED => true,
+ ],
+ 'data' => [
+ self::PARAM_TYPE => 'text',
+ self::PARAM_REQUIRED => true,
+ ],
+ 'bot' => [
+ self::PARAM_TYPE => 'boolean',
+ self::PARAM_DFLT => false,
+ ]
+ ];
+ }
+
+ /**
+ * @see ApiBase::isWriteMode()
+ */
+ public function isWriteMode() {
+ return true;
+ }
+
+ /**
+ * @see ApiBase::needsToken()
+ */
+ public function needsToken() {
+ return 'csrf';
+ }
+
+ /**
+ * @see ApiBase::mustBePosted()
+ */
+ public function mustBePosted() {
+ return true;
+ }
+
+}
diff --git a/src/Api/EditFormElementsRequest.php
b/src/Api/EditFormElementsRequest.php
new file mode 100644
index 0000000..ffdbcd9
--- /dev/null
+++ b/src/Api/EditFormElementsRequest.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace Wikibase\Lexeme\Api;
+
+use Wikibase\DataModel\Entity\ItemId;
+use Wikibase\DataModel\Term\TermList;
+use Wikibase\Lexeme\ChangeOp\ChangeOpEditFormElements;
+use Wikibase\Lexeme\DataModel\FormId;
+
+/**
+ * @license GPL-2.0+
+ */
+class EditFormElementsRequest {
+
+ /**
+ * @var FormId
+ */
+ private $formId;
+
+ /**
+ * @var TermList
+ */
+ private $representations;
+
+ /**
+ * @var ItemId[]
+ */
+ private $grammaticalFeatures;
+
+ public function __construct(
+ FormId $formId,
+ TermList $representations,
+ array $grammaticalFeatures
+ ) {
+ $this->formId = $formId;
+ $this->representations = $representations;
+ $this->grammaticalFeatures = $grammaticalFeatures;
+ }
+
+ public function getChangeOp() {
+ return new ChangeOpEditFormElements( $this->representations,
$this->grammaticalFeatures );
+ }
+
+ public function getFormId() {
+ return $this->formId;
+ }
+
+}
diff --git a/src/Api/EditFormElementsRequestParser.php
b/src/Api/EditFormElementsRequestParser.php
new file mode 100644
index 0000000..39a25d0
--- /dev/null
+++ b/src/Api/EditFormElementsRequestParser.php
@@ -0,0 +1,138 @@
+<?php
+
+namespace Wikibase\Lexeme\Api;
+
+use Wikibase\DataModel\Entity\EntityIdParsingException;
+use Wikibase\DataModel\Entity\ItemIdParser;
+use Wikibase\DataModel\Term\Term;
+use Wikibase\DataModel\Term\TermList;
+use Wikibase\Lexeme\DataModel\FormId;
+
+/**
+ * @license GPL-2.0+
+ */
+class EditFormElementsRequestParser {
+
+ const PARAM_DATA = 'data';
+
+ /**
+ * @var ItemIdParser
+ */
+ private $itemIdParser;
+
+ public function __construct() {
+ $this->itemIdParser = new ItemIdParser();
+ }
+
+ public function parse( array $params ) {
+ $errors = [];
+
+ $data = json_decode( $params[self::PARAM_DATA] );
+
+ $representations = $this->parseRepresentations(
$data->representations, $errors );
+ $grammaticalFeatures = $this->parseGrammaticalFeatures(
$data->grammaticalFeatures, $errors );
+
+ return new EditFormElementsRequest(
+ new FormId( $params['formId'] ),
+ $representations,
+ $grammaticalFeatures
+ );
+ }
+
+ /**
+ * @param \stdClass[] $givenRepresentations
+ * @param ApiError[] $errors
+ * @return TermList
+ */
+ private function parseRepresentations( array $givenRepresentations,
array &$errors ) {
+ if ( empty( $givenRepresentations ) ) {
+ /*
+ * $errors[] =
+ * new FormMustHaveAtLeastOneRepresentation(
self::PARAM_DATA, [ 'representations' ] );
+ */
+ }
+
+ //FIXME: Array may contain representation with empty text (or
untrimmed) which won't be added
+ $result = [];
+
+ foreach ( $givenRepresentations as $index => $el ) {
+ $incomplete = false;
+
+ if ( !property_exists( $el, 'representation' ) ) {
+ /*$errors[] = new JsonFieldIsRequired(
+ self::PARAM_DATA,
+ [ 'representations', $index,
'representation' ]
+ );*/
+ $incomplete = true;
+ } elseif ( empty( $el->representation ) ) {
+ /*$errors[] = new
RepresentationTextCanNotBeEmpty(
+ self::PARAM_DATA,
+ [ 'representations', $index,
'representation' ]
+ );*/
+ $incomplete = true;
+ }
+
+ if ( !property_exists( $el, 'language' ) ) {
+ /*$errors[] = new JsonFieldIsRequired(
+ self::PARAM_DATA,
+ [ 'representations', $index, 'language'
]
+ );*/
+ $incomplete = true;
+ } elseif ( empty( $el->language ) ) {
+ /*$errors[] = new
RepresentationLanguageCanNotBeEmpty(
+ self::PARAM_DATA,
+ [ 'representations', $index, 'language'
]
+ );*/
+ $incomplete = true;
+ }
+
+ if ( $incomplete ) {
+ continue;
+ }
+
+ if ( isset( $result[$el->language] ) ) {
+ /*$errors[] = new
RepresentationsMustHaveUniqueLanguage(
+ self::PARAM_DATA,
+ [ 'representations', $index, 'language'
],
+ $el->language
+ );*/
+ }
+
+ $result[$el->language] = $el->representation;
+ }
+
+ $terms = [];
+ foreach ( $result as $language => $representation ) {
+ $terms[] = new Term( $language, $representation );
+ }
+
+ return new TermList( $terms );
+ }
+
+ /**
+ * @param string[] $data
+ * @param ApiError[] $errors
+ * @return ItemId[]
+ */
+ private function parseGrammaticalFeatures( array $data, array &$errors
) {
+ $features = [];
+
+ foreach ( $data as $index => $featureId ) {
+ try {
+ $id = $this->itemIdParser->parse( $featureId );
+ } catch ( EntityIdParsingException $e ) {
+ /*$errors[] = new JsonFieldIsNotAnItemId(
+ self::PARAM_DATA,
+ [ 'grammaticalFeatures', $index ],
+ $featureId
+ );*/
+ continue;
+ }
+
+ $features[] = $id;
+ }
+
+ return $features;
+ }
+
+}
diff --git a/src/ChangeOp/ChangeOpEditFormElements.php
b/src/ChangeOp/ChangeOpEditFormElements.php
new file mode 100644
index 0000000..fcb0a70
--- /dev/null
+++ b/src/ChangeOp/ChangeOpEditFormElements.php
@@ -0,0 +1,57 @@
+<?php
+
+namespace Wikibase\Lexeme\ChangeOp;
+
+use ValueValidators\Result;
+use Wikibase\DataModel\Entity\EntityDocument;
+use Wikibase\DataModel\Entity\ItemId;
+use Wikibase\DataModel\Term\TermList;
+use Wikibase\Lexeme\DataModel\Form;
+use Wikibase\Repo\ChangeOp\ChangeOp;
+use Wikibase\Repo\Store\EntityPermissionChecker;
+use Wikibase\Summary;
+use Wikimedia\Assert\Assert;
+
+/**
+ * @license GPL-2.0+
+ */
+class ChangeOpEditFormElements implements ChangeOp {
+
+ /**
+ * @var TermList
+ */
+ private $representations;
+
+ /**
+ * @var ItemId[]
+ */
+ private $grammaticalFeatures;
+
+ public function __construct( TermList $representations, array
$grammaticalFeatures ) {
+ $this->representations = $representations;
+ $this->grammaticalFeatures = $grammaticalFeatures;
+ }
+
+ public function validate( EntityDocument $entity ) {
+ // TODO OMG: Should this be also a change op applicable on
Lexeme entities
+ // (e.g. when used in wbeditentity)?
+ Assert::parameterType( Form::class, $entity, '$entity' );
+
+ return Result::newSuccess();
+ }
+
+ public function apply( EntityDocument $entity, Summary $summary = null
) {
+ // TODO OMG: Should this be also a change op applicable on
Lexeme entities
+ // (e.g. when used in wbeditentity)?
+ Assert::parameterType( Form::class, $entity, '$entity' );
+
+ /** @var Form $entity */
+ $entity->setRepresentations( $this->representations );
+ $entity->setGrammaticalFeatures( $this->grammaticalFeatures );
+ }
+
+ public function getActions() {
+ return [ EntityPermissionChecker::ACTION_EDIT ];
+ }
+
+}
diff --git a/src/DataModel/Form.php b/src/DataModel/Form.php
index b9b5879..efc4b44 100644
--- a/src/DataModel/Form.php
+++ b/src/DataModel/Form.php
@@ -101,6 +101,10 @@
return $this->representations;
}
+ public function setRepresentations( TermList $representations ) {
+ $this->representations = $representations;
+ }
+
/**
* @return ItemId[]
*/
diff --git a/tests/phpunit/mediawiki/Api/EditFormElementsTest.php
b/tests/phpunit/mediawiki/Api/EditFormElementsTest.php
new file mode 100644
index 0000000..4c4e818
--- /dev/null
+++ b/tests/phpunit/mediawiki/Api/EditFormElementsTest.php
@@ -0,0 +1,64 @@
+<?php
+
+namespace Wikibase\Lexeme\Tests\MediaWiki\Api;
+
+use Wikibase\Lexeme\DataModel\FormId;
+use Wikibase\Lexeme\DataModel\Lexeme;
+use Wikibase\Lexeme\DataModel\LexemeId;
+use Wikibase\Lexeme\Tests\DataModel\NewForm;
+use Wikibase\Lexeme\Tests\DataModel\NewLexeme;
+use Wikibase\Repo\Tests\Api\WikibaseApiTestCase;
+use Wikibase\Repo\WikibaseRepo;
+
+/**
+ * @covers \Wikibase\Lexeme\Api\EditFormElements
+ *
+ * @license GPL-2.0+
+ *
+ * @group Database
+ * @group medium
+ */
+class EditFormElementsTest extends WikibaseApiTestCase {
+
+ public function testGivenRepresentations_changesRepresentationsOfForm()
{
+ $form = NewForm::havingId( 'F1' )->andRepresentation( 'en',
'goat' )->build();
+ $lexeme = NewLexeme::havingId( 'L1' )->withForm( $form
)->build();
+
+ $this->saveLexeme( $lexeme );
+
+ $params = [
+ 'action' => 'wblexemeeditformelementsgarlic',
+ 'formId' => 'L1-F1',
+ 'data' => json_encode( [
+ 'representations' => [
+ [ 'language' => 'en', 'representation'
=> 'goadth' ],
+ ],
+ 'grammaticalFeatures' => [],
+ ] ),
+ ];
+
+ $this->doApiRequestWithToken( $params );
+
+ $lexeme = $this->getLexeme( 'L1' );
+
+ $form = $lexeme->getForms()->getById( new FormId( 'L1-F1' ) );
+ $this->assertEquals( 'goadth',
$form->getRepresentations()->getByLanguage( 'en' )->getText() );
+ }
+
+ private function saveLexeme( Lexeme $lexeme ) {
+ $store = WikibaseRepo::getDefaultInstance()->getEntityStore();
+
+ $store->saveEntity( $lexeme, self::class, $this->getMock(
\User::class ) );
+ }
+
+ /**
+ * @param string $id
+ *
+ * @return Lexeme|null
+ */
+ private function getLexeme( $id ) {
+ $lookup = WikibaseRepo::getDefaultInstance()->getEntityLookup();
+ return $lookup->getEntity( new LexemeId( $id ) );
+ }
+
+}
--
To view, visit https://gerrit.wikimedia.org/r/402868
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ice096f53a09b80aa26d2ced342a7986b82d01998
Gerrit-PatchSet: 2
Gerrit-Project: mediawiki/extensions/WikibaseLexeme
Gerrit-Branch: master
Gerrit-Owner: WMDE-leszek <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits