Skip to content

Commit

Permalink
Merge "REST: Add EditMetadataRequestValidatingDeserializer"
Browse files Browse the repository at this point in the history
  • Loading branch information
jenkins-bot authored and Gerrit Code Review committed Sep 12, 2023
2 parents 3f02f6e + a4b312d commit 0305ace
Show file tree
Hide file tree
Showing 4 changed files with 215 additions and 0 deletions.
16 changes: 16 additions & 0 deletions repo/rest-api/src/Application/UseCases/EditMetadataRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php declare( strict_types=1 );

namespace Wikibase\Repo\RestApi\Application\UseCases;

/**
* @license GPL-2.0-or-later
*/
interface EditMetadataRequest {
public function getUsername(): ?string;

public function isBot(): bool;

public function getComment(): ?string;

public function getEditTags(): array;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php declare( strict_types=1 );

namespace Wikibase\Repo\RestApi\Application\UseCases\RequestValidation;

use Wikibase\Repo\RestApi\Application\UseCases\EditMetadataRequest;
use Wikibase\Repo\RestApi\Application\UseCases\UseCaseError;
use Wikibase\Repo\RestApi\Application\Validation\EditMetadataValidator;
use Wikibase\Repo\RestApi\Domain\Model\User;
use Wikibase\Repo\RestApi\Domain\Model\UserProvidedEditMetadata;

/**
* @license GPL-2.0-or-later
*/
class EditMetadataRequestValidatingDeserializer {

private EditMetadataValidator $validator;

public function __construct( EditMetadataValidator $validator ) {
$this->validator = $validator;
}

/**
* @throws UseCaseError
*/
public function validateAndDeserialize( EditMetadataRequest $request ): UserProvidedEditMetadata {
$this->validateComment( $request->getComment() );
$this->validateEditTags( $request->getEditTags() );

return new UserProvidedEditMetadata(
// @phan-suppress-next-line PhanTypeMismatchArgumentNullable
$request->getUsername() === null ? User::newAnonymous() : User::withUsername( $request->getUsername() ),
$request->isBot(),
$request->getComment(),
$request->getEditTags()
);
}

/**
* @throws UseCaseError
*/
private function validateEditTags( array $editTags ): void {
$validationError = $this->validator->validateEditTags( $editTags );
if ( $validationError ) {
throw new UseCaseError(
UseCaseError::INVALID_EDIT_TAG,
"Invalid MediaWiki tag: {$validationError->getContext()[EditMetadataValidator::CONTEXT_TAG_VALUE]}"
);
}
}

/**
* @throws UseCaseError
*/
private function validateComment( ?string $comment ): void {
if ( $comment === null ) {
return;
}

$validationError = $this->validator->validateComment( $comment );
if ( $validationError ) {
$commentMaxLength = $validationError->getContext()[EditMetadataValidator::CONTEXT_COMMENT_MAX_LENGTH];
throw new UseCaseError(
UseCaseError::COMMENT_TOO_LONG,
"Comment must not be longer than $commentMaxLength characters.",
);
}
}

}
38 changes: 38 additions & 0 deletions repo/rest-api/src/Domain/Model/UserProvidedEditMetadata.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php declare( strict_types=1 );

namespace Wikibase\Repo\RestApi\Domain\Model;

/**
* @license GPL-2.0-or-later
*/
class UserProvidedEditMetadata {

private User $user;
private bool $isBot;
private ?string $comment;
private array $tags;

public function __construct( User $user, bool $isBot, ?string $comment, array $tags ) {
$this->user = $user;
$this->isBot = $isBot;
$this->comment = $comment;
$this->tags = $tags;
}

public function getUser(): User {
return $this->user;
}

public function isBot(): bool {
return $this->isBot;
}

public function getComment(): ?string {
return $this->comment;
}

public function getTags(): array {
return $this->tags;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php declare( strict_types=1 );

namespace Wikibase\Repo\Tests\RestApi\Application\UseCases\RequestValidation;

use MediaWiki\CommentStore\CommentStore;
use PHPUnit\Framework\TestCase;
use Wikibase\Repo\RestApi\Application\UseCases\EditMetadataRequest;
use Wikibase\Repo\RestApi\Application\UseCases\RequestValidation\EditMetadataRequestValidatingDeserializer;
use Wikibase\Repo\RestApi\Application\UseCases\UseCaseError;
use Wikibase\Repo\RestApi\Application\Validation\EditMetadataValidator;
use Wikibase\Repo\RestApi\Application\Validation\ValidationError;
use Wikibase\Repo\RestApi\Domain\Model\User;
use Wikibase\Repo\RestApi\Domain\Model\UserProvidedEditMetadata;

/**
* @covers \Wikibase\Repo\RestApi\Application\UseCases\RequestValidation\EditMetadataRequestValidatingDeserializer
*
* @group Wikibase
*
* @license GPL-2.0-or-later
*/
class EditMetadataRequestValidatingDeserializerTest extends TestCase {

public function testGivenValidRequest_returnsEditMetadata(): void {
$user = 'potato';
$isBot = false;
$editTags = [ 'allowed' ];
$comment = 'edit comment';
$request = $this->createStub( EditMetadataRequest::class );
$request->method( 'getUsername' )->willReturn( $user );
$request->method( 'isBot' )->willReturn( $isBot );
$request->method( 'getComment' )->willReturn( $comment );
$request->method( 'getEditTags' )->willReturn( $editTags );

$this->assertEquals(
new UserProvidedEditMetadata( User::withUsername( $user ), $isBot, $comment, $editTags ),
( new EditMetadataRequestValidatingDeserializer( $this->createStub( EditMetadataValidator::class ) ) )
->validateAndDeserialize( $request )
);
}

public function testWithCommentTooLong(): void {
$comment = str_repeat( 'x', CommentStore::COMMENT_CHARACTER_LIMIT + 1 );
$request = $this->createStub( EditMetadataRequest::class );
$request->method( 'getComment' )->willReturn( $comment );
$expectedError = new ValidationError(
EditMetadataValidator::CODE_COMMENT_TOO_LONG,
[ EditMetadataValidator::CONTEXT_COMMENT_MAX_LENGTH => CommentStore::COMMENT_CHARACTER_LIMIT ]
);

$editMetadataValidator = $this->createMock( EditMetadataValidator::class );
$editMetadataValidator->method( 'validateComment' )
->with( $comment )
->willReturn( $expectedError );

try {
( new EditMetadataRequestValidatingDeserializer( $editMetadataValidator ) )->validateAndDeserialize( $request );
$this->fail( 'this should not be reached' );
} catch ( UseCaseError $e ) {
$this->assertSame( UseCaseError::COMMENT_TOO_LONG, $e->getErrorCode() );
$this->assertSame(
'Comment must not be longer than ' . CommentStore::COMMENT_CHARACTER_LIMIT . ' characters.',
$e->getErrorMessage()
);
}
}

public function testWithInvalidEditTags(): void {
$invalidTags = [ 'bad', 'tags' ];
$request = $this->createStub( EditMetadataRequest::class );
$request->method( 'getEditTags' )->willReturn( $invalidTags );

$validationError = new ValidationError(
EditMetadataValidator::CODE_INVALID_TAG,
[ EditMetadataValidator::CONTEXT_TAG_VALUE => json_encode( $invalidTags ) ]
);

$editMetadataValidator = $this->createMock( EditMetadataValidator::class );
$editMetadataValidator->method( 'validateEditTags' )
->with( $invalidTags )
->willReturn( $validationError );

try {
( new EditMetadataRequestValidatingDeserializer( $editMetadataValidator ) )->validateAndDeserialize( $request );
$this->fail( 'this should not be reached' );
} catch ( UseCaseError $e ) {
$this->assertSame( UseCaseError::INVALID_EDIT_TAG, $e->getErrorCode() );
$this->assertSame( 'Invalid MediaWiki tag: ["bad","tags"]', $e->getErrorMessage() );
}
}

}

0 comments on commit 0305ace

Please sign in to comment.