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

Reply via email to