Changes to make possible implement api endpoint

Update documentation
Start implementing getSystems route
Code to route getSystems
Controller to board import
Change return
Increase coverage

Signed-off-by: Vitor Mattos <vitor@php.rio>
This commit is contained in:
Vitor Mattos
2021-07-16 00:44:45 -03:00
committed by Julius Härtl
parent 39a927de18
commit 4138953208
15 changed files with 511 additions and 354 deletions

View File

@@ -90,7 +90,8 @@ return [
['name' => 'board_api#deleteAcl', 'url' => '/api/v{apiVersion}/boards/{boardId}/acl/{aclId}', 'verb' => 'DELETE'],
['name' => 'board_api#updateAcl', 'url' => '/api/v{apiVersion}/boards/{boardId}/acl/{aclId}', 'verb' => 'PUT'],
['name' => 'board_import_api#import', 'url' => '/api/v{apiVersion}/boards/import','verb' => 'POST', 'requirements' => ['apiVersion' => '1.1']],
['name' => 'board_import_api#getAllowedSystems', 'url' => '/api/v{apiVersion}/boards/import/getSystems','verb' => 'GET'],
['name' => 'board_import_api#import', 'url' => '/api/v{apiVersion}/boards/import','verb' => 'POST'],
['name' => 'stack_api#index', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks', 'verb' => 'GET'],

View File

@@ -988,6 +988,32 @@ For now only `deck_file` is supported as an attachment type.
##### 200 Success
### GET /boards/import/getSystems - Import a board
#### Request parameters
#### Response
```json
[
"trello"
]
```
### POST /boards/import - Import a board
#### Request parameters
| Parameter | Type | Description |
| ------------ | ------- | --------------------------------------------- |
| system | string | The allowed name of system to import from |
| config | Object | The config object (JSON) |
| data | Object | The data object to import (JSON) |
#### Response
##### 200 Success
# OCS API
The following endpoints are available through the Nextcloud OCS endpoint, which is available at `/ocs/v2.php/apps/deck/api/v1.0/`.

View File

@@ -81,6 +81,8 @@ class BoardImport extends Command {
$this->boardImportCommandService
->setInput($input)
->setOutput($output)
->setSystem($input->getOption('system'))
->setConfigInstance($input->getOption('config'))
->validate();
}

View File

@@ -24,18 +24,26 @@
namespace OCA\Deck\Controller;
use OCA\Deck\Service\BoardImportService;
use OCA\Files\Controller\ApiController;
use OCP\AppFramework\ApiController;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\IRequest;
class BoardImportApiController extends ApiController {
/** @var BoardImportService */
private $boardImportService;
/** @var string */
private $userId;
public function __construct(
BoardImportService $boardImportService
$appName,
IRequest $request,
BoardImportService $boardImportService,
$userId
) {
parent::__construct($appName, $request);
$this->boardImportService = $boardImportService;
$this->userId = $userId;
}
/**
@@ -44,7 +52,23 @@ class BoardImportApiController extends ApiController {
* @NoCSRFRequired
*/
public function import($system, $config, $data) {
$board = $this->boardImportService->import($system, $config, $data);
return new DataResponse($board, Http::STATUS_OK);
$this->boardImportService->setSystem($system);
$config = json_decode(json_encode($config));
$config->owner = $this->userId;
$this->boardImportService->setConfigInstance($config);
$this->boardImportService->setData(json_decode(json_encode($data)));
$this->boardImportService->validate();
$this->boardImportService->import();
return new DataResponse($this->boardImportService->getBoard(), Http::STATUS_OK);
}
/**
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*/
public function getAllowedSystems() {
$allowedSystems = $this->boardImportService->getAllowedImportSystems();
return new DataResponse($allowedSystems, Http::STATUS_OK);
}
}

View File

@@ -5,6 +5,7 @@ namespace OCA\Deck\Service;
use OCA\Deck\Db\Acl;
use OCA\Deck\Db\Board;
use OCA\Deck\Db\Card;
use OCA\Deck\Db\Label;
use OCA\Deck\Db\Stack;
abstract class ABoardImportService {
@@ -34,9 +35,10 @@ abstract class ABoardImportService {
abstract public function importParticipants(): self;
abstract public function importComments(): self;
abstract public function importComments();
abstract public function importLabels(): self;
/** @return Label[] */
abstract public function importLabels(): array;
abstract public function assignCardsToLabels(): self;

View File

@@ -1,10 +1,31 @@
<?php
/**
* @copyright Copyright (c) 2021 Vitor Mattos <vitor@php.rio>
*
* @author Vitor Mattos <vitor@php.rio>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Deck\Service;
use JsonSchema\Constraints\Constraint;
use JsonSchema\Validator;
use OCA\Deck\Command\BoardImport;
use OCA\Deck\Exceptions\ConflictException;
use OCA\Deck\NotFoundException;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
@@ -60,16 +81,16 @@ class BoardImportCommandService extends BoardImportService {
return $this->output;
}
public function validate(): self {
$this->validateSystem();
$this->validateConfig();
public function validate() {
$this->validateData();
return $this;
parent::validate();
}
private function validateConfig(): void {
$configFile = $this->getInput()->getOption('config');
if (!is_file($configFile)) {
protected function validateConfig() {
try {
parent::validateConfig();
return;
} catch (NotFoundException $e) {
$helper = $this->getCommand()->getHelper('question');
$question = new Question(
'Please inform a valid config json file: ',
@@ -84,50 +105,39 @@ class BoardImportCommandService extends BoardImportService {
return $answer;
});
$configFile = $helper->ask($this->getInput(), $this->getOutput(), $question);
$this->getInput()->setOption('config', $configFile);
}
$config = json_decode(file_get_contents($configFile));
$system = $this->getSystem();
$schemaPath = __DIR__ . '/fixtures/config-' . $system . '-schema.json';
$validator = new Validator();
$validator->validate(
$config,
(object)['$ref' => 'file://' . realpath($schemaPath)],
Constraint::CHECK_MODE_APPLY_DEFAULTS
);
if (!$validator->isValid()) {
$this->setConfigInstance($configFile);
} catch (ConflictException $e) {
$this->getOutput()->writeln('<error>Invalid config file</error>');
$this->getOutput()->writeln(array_map(function ($v) {
return $v['message'];
}, $validator->getErrors()));
}, $e->getData()));
$this->getOutput()->writeln('Valid schema:');
$schemaPath = __DIR__ . '/fixtures/config-' . $this->getSystem() . '-schema.json';
$this->getOutput()->writeln(print_r(file_get_contents($schemaPath), true));
$this->getInput()->setOption('config', null);
$this->validateConfig($this->getInput(), $this->getOutput());
$this->setConfigInstance('');
}
$this->setConfigInstance($config);
$this->validateOwner();
parent::validateConfig();
return;
}
/**
* @return void
*/
private function validateSystem(): self {
$system = $this->getInput()->getOption('system');
if (in_array($system, $this->getAllowedImportSystems())) {
return $this->setSystem($system);
protected function validateSystem() {
try {
parent::validateSystem();
return;
} catch (\Throwable $th) {
}
$helper = $this->getCommand()->getHelper('question');
$question = new ChoiceQuestion(
'Please inform a source system',
$this->allowedSystems,
$this->getAllowedImportSystems(),
0
);
$question->setErrorMessage('System %s is invalid.');
$system = $helper->ask($this->getInput(), $this->getOutput(), $question);
$this->getInput()->setOption('system', $system);
return $this->setSystem($system);
$this->setSystem($system);
return;
}
private function validateData(): self {
@@ -152,9 +162,8 @@ class BoardImportCommandService extends BoardImportService {
$this->setData(json_decode(file_get_contents($filename)));
if (!$this->getData()) {
$this->getOutput()->writeln('<error>Is not a json file: ' . $filename . '</error>');
$this->validateData($this->getInput(), $this->getOutput());
$this->validateData();
}
$this->validateUsers();
return $this;
}

View File

@@ -34,9 +34,10 @@ use OCA\Deck\Db\BoardMapper;
use OCA\Deck\Db\CardMapper;
use OCA\Deck\Db\Label;
use OCA\Deck\Db\LabelMapper;
use OCA\Deck\Db\Stack;
use OCA\Deck\Db\StackMapper;
use OCA\Deck\Exceptions\ConflictException;
use OCA\Deck\NotFoundException;
use OCP\Comments\IComment;
use OCP\Comments\ICommentsManager;
use OCP\Comments\NotFoundException as CommentNotFoundException;
use OCP\IDBConnection;
@@ -105,39 +106,30 @@ class BoardImportService {
}
public function import(): void {
$this->validate();
$schemaPath = __DIR__ . '/fixtures/config-' . $system . '-schema.json';
$validator = new Validator();
$validator->validate(
$config,
(object)['$ref' => 'file://' . realpath($schemaPath)],
Constraint::CHECK_MODE_APPLY_DEFAULTS
);
if (!$validator->isValid()) {
throw new BadRequestException('invalid config');
try {
$this->importBoard();
$this->importAcl();
$this->importLabels();
$this->importStacks();
$this->importCards();
$this->assignCardsToLabels();
$this->importComments();
$this->importParticipants();
} catch (\Throwable $th) {
throw new BadRequestException($th->getMessage());
}
if (empty($data)) {
throw new BadRequestException('data must be provided');
}
$this->getImportService()->setData($data);
$this->getImportService()->import();
// return $newBoard;
}
public function validate(): self {
if (is_string($system) === false) {
throw new BadRequestException('system must be provided');
}
public function validate() {
$this->validateSystem();
$this->validateConfig();
$this->validateUsers();
}
if (!in_array($system, $this->getAllowedImportSystems())) {
throw new BadRequestException('not allowed system');
protected function validateSystem() {
if (!in_array($this->getSystem(), $this->getAllowedImportSystems())) {
throw new NotFoundException('Invalid system');
}
if (empty($config)) {
throw new BadRequestException('config must be provided');
}
return $this;
}
public function setSystem(string $system): self {
@@ -162,10 +154,11 @@ class BoardImportService {
}
return true;
});
$this->allowedSystems = array_map(function ($name) {
$allowedSystems = array_map(function ($name) {
preg_match('/\/BoardImport(?<system>\w+)Service\.php$/', $name, $matches);
return lcfirst($matches['system']);
}, $allowedSystems);
$this->allowedSystems = array_values($allowedSystems);
}
return $this->allowedSystems;
}
@@ -180,6 +173,10 @@ class BoardImportService {
return $this->systemInstance;
}
public function setImportSystem($instance) {
$this->systemInstance = $instance;
}
public function insertAssignment($assignment): self {
$this->assignmentMapper->insert($assignment);
return $this;
@@ -203,12 +200,14 @@ class BoardImportService {
foreach ($aclList as $acl) {
$this->aclMapper->insert($acl);
}
$this->getBoard()->setAcl($aclList);
return $this;
}
public function importLabels(): self {
$this->getImportSystem()->importLabels();
return $this;
public function importLabels(): array {
$labels = $this->getImportSystem()->importLabels();
$this->getBoard()->setLabels($labels);
return $labels;
}
public function createLabel($title, $color, $boardId): Label {
@@ -219,13 +218,17 @@ class BoardImportService {
return $this->labelMapper->insert($label);
}
public function importStacks(): self {
$stack = $this->getImportSystem()->getStacks();
foreach ($stack as $code => $stack) {
/**
* @return Stack[]
*/
public function importStacks(): array {
$stacks = $this->getImportSystem()->getStacks();
foreach ($stacks as $code => $stack) {
$this->stackMapper->insert($stack);
$this->getImportSystem()->updateStack($code, $stack);
}
return $this;
$this->getBoard()->setStacks(array_values($stacks));
return $stacks;
}
public function importCards(): self {
@@ -255,7 +258,7 @@ class BoardImportService {
return $this;
}
public function insertComment($cardId, IComment $comment): IComment {
public function insertComment($cardId, $comment) {
$comment->setObject('deckCard', (string) $cardId);
$comment->setVerb('comment');
// Check if parent is a comment on the same card
@@ -338,10 +341,7 @@ class BoardImportService {
* @return mixed
*/
public function getConfig(string $configName = null) {
if (!is_object($this->config)) {
return;
}
if (!$configName) {
if (!is_object($this->config) || !$configName) {
return $this->config;
}
if (!property_exists($this->config, $configName)) {
@@ -350,15 +350,41 @@ class BoardImportService {
return $this->config->$configName;
}
public function setConfigInstance(\stdClass $config): self {
public function setConfigInstance($config): self {
$this->config = $config;
return $this;
}
protected function validateConfig() {
$config = $this->getConfig();
if (empty($config)) {
throw new NotFoundException('Please inform a valid config json file');
}
if (is_string($config)) {
if (!is_file($config)) {
throw new NotFoundException('Please inform a valid config json file');
}
$config = json_decode(file_get_contents($config));
}
$schemaPath = __DIR__ . '/fixtures/config-' . $this->getSystem() . '-schema.json';
$validator = new Validator();
$newConfig = clone $config;
$validator->validate(
$newConfig,
(object)['$ref' => 'file://' . realpath($schemaPath)],
Constraint::CHECK_MODE_APPLY_DEFAULTS
);
if (!$validator->isValid()) {
throw new ConflictException('Invalid config file', $validator->getErrors());
}
$this->setConfigInstance($newConfig);
$this->validateOwner();
}
public function validateOwner(): self {
$owner = $this->userManager->get($this->getConfig('owner'));
if (!$owner) {
throw new \LogicException('Owner "' . $this->getConfigboardImportService->getConfig('owner')->getUID() . '" not found on Nextcloud. Check setting json.');
throw new \LogicException('Owner "' . $this->getConfig('owner')->getUID() . '" not found on Nextcloud. Check setting json.');
}
$this->setConfig('owner', $owner);
return $this;

View File

@@ -24,9 +24,9 @@
namespace OCA\Deck\Service;
use OC\Comments\Comment;
use OCA\Deck\BadRequestException;
use OCA\Deck\Db\Acl;
use OCA\Deck\Db\Assignment;
use OCA\Deck\Db\AssignmentMapper;
use OCA\Deck\Db\Board;
use OCA\Deck\Db\Card;
use OCA\Deck\Db\Label;
@@ -36,8 +36,6 @@ use OCP\IUser;
use OCP\IUserManager;
class BoardImportTrelloService extends ABoardImportService {
/** @var AssignmentMapper */
private $assignmentMapper;
/** @var IUserManager */
private $userManager;
/** @var IL10N */
@@ -60,25 +58,15 @@ class BoardImportTrelloService extends ABoardImportService {
private $members = [];
public function __construct(
BoardService $boardService,
AssignmentMapper $assignmentMapper,
IUserManager $userManager,
IL10N $l10n
) {
$this->boardService = $boardService;
$this->assignmentMapper = $assignmentMapper;
$this->userManager = $userManager;
$this->l10n = $l10n;
}
public function validate(): ABoardImportService {
$this->boardImportTrelloService->validateOwner();
$this->boardImportTrelloService->validateUsers();
return $this;
}
/**
* @return ABoardImportService
* @return self
*/
public function validateUsers(): self {
if (empty($this->getImportService()->getConfig('uidRelation'))) {
@@ -91,8 +79,8 @@ class BoardImportTrelloService extends ABoardImportService {
if (!$user) {
throw new \LogicException('Trello user ' . $trelloUid . ' not found in property "members" of json data');
}
if (!is_string($nextcloudUid)) {
throw new \LogicException('User on setting uidRelation must be a string');
if (!is_string($nextcloudUid) && !is_numeric($nextcloudUid)) {
throw new \LogicException('User on setting uidRelation is invalid');
}
$this->getImportService()->getConfig('uidRelation')->$trelloUid = $this->userManager->get($nextcloudUid);
if (!$this->getImportService()->getConfig('uidRelation')->$trelloUid) {
@@ -170,6 +158,9 @@ class BoardImportTrelloService extends ABoardImportService {
$card->setTitle($trelloCard->name);
$card->setStackId($this->stacks[$trelloCard->idList]->getId());
$cardsOnStack = $this->stacks[$trelloCard->idList]->getCards();
$cardsOnStack[] = $card;
$this->stacks[$trelloCard->idList]->setCards($cardsOnStack);
$card->setType('plain');
$card->setOrder($trelloCard->idShort);
$card->setOwner($this->getImportService()->getConfig('owner')->getUID());
@@ -184,17 +175,17 @@ class BoardImportTrelloService extends ABoardImportService {
return $this->cards;
}
public function updateCard($cardTrelloId, Card $card): self {
$this->cards[$cardTrelloId] = $card;
public function updateCard($id, Card $card): self {
$this->cards[$id] = $card;
return $this;
}
/**
* @return ABoardImportService
* @return self
*/
private function appendAttachmentsToDescription($trelloCard) {
private function appendAttachmentsToDescription($trelloCard): self {
if (empty($trelloCard->attachments)) {
return;
return $this;
}
$trelloCard->desc .= "\n\n## {$this->l10n->t('Attachments')}\n";
$trelloCard->desc .= "| {$this->l10n->t('File')} | {$this->l10n->t('date')} |\n";
@@ -206,9 +197,12 @@ class BoardImportTrelloService extends ABoardImportService {
return $this;
}
public function importParticipants(): ABoardImportService {
public function importParticipants(): self {
foreach ($this->getImportService()->getData()->cards as $trelloCard) {
foreach ($trelloCard->idMembers as $idMember) {
if (empty($this->members[$idMember])) {
continue;
}
$assignment = new Assignment();
$assignment->setCardId($this->cards[$trelloCard->id]->getId());
$assignment->setParticipant($this->members[$idMember]->getUID());
@@ -219,7 +213,7 @@ class BoardImportTrelloService extends ABoardImportService {
return $this;
}
public function importComments(): ABoardImportService {
public function importComments() {
foreach ($this->getImportService()->getData()->cards as $trelloCard) {
$comments = array_filter(
$this->getImportService()->getData()->actions,
@@ -246,7 +240,6 @@ class BoardImportTrelloService extends ABoardImportService {
);
}
}
return $this;
}
private function replaceUsernames($text) {
@@ -320,13 +313,16 @@ class BoardImportTrelloService extends ABoardImportService {
public function getBoard(): Board {
$board = new Board();
if (!$this->getImportService()->getData()->name) {
throw new BadRequestException('Invalid name of board');
}
$board->setTitle($this->getImportService()->getData()->name);
$board->setOwner($this->getImportService()->getConfig('owner')->getUID());
$board->setColor($this->getImportService()->getConfig('color'));
return $board;
}
public function importLabels(): self {
public function importLabels(): array {
foreach ($this->getImportService()->getData()->labels as $label) {
if (empty($label->name)) {
$labelTitle = 'Unnamed ' . $label->color . ' label';
@@ -340,6 +336,6 @@ class BoardImportTrelloService extends ABoardImportService {
);
$this->labels[$label->id] = $newLabel;
}
return $this;
return $this->labels;
}
}

View File

@@ -23,32 +23,23 @@
namespace OCA\Deck\Command;
use OCA\Deck\Command\ImportHelper\TrelloHelper;
use OCA\Deck\Service\AImportService;
use OCA\Deck\Service\BoardImportService;
use OCA\Deck\Service\BoardImportCommandService;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class BoardImportTest extends \Test\TestCase {
/** @var TrelloHelper */
private $trelloHelper;
/** @var BoardImportService */
private $boardImportService;
/** @var BoardImportCommandService */
private $boardImportCommandService;
/** @var BoardImport */
private $boardImport;
public function setUp(): void {
parent::setUp();
$this->trelloHelper = $this->createMock(TrelloHelper::class);
$this->boardImportService = $this->createMock(BoardImportService::class);
$this->boardImportService
->method('getAllowedImportSystems')
->willReturn(['trello']);
$this->boardImportCommandService = $this->createMock(boardImportCommandService::class);
$this->boardImport = new BoardImport(
$this->trelloHelper,
$this->boardImportService
$this->boardImportCommandService
);
$questionHelper = new QuestionHelper();
$this->boardImport->setHelperSet(
@@ -60,33 +51,26 @@ class BoardImportTest extends \Test\TestCase {
public function testExecuteWithSuccess() {
$input = $this->createMock(InputInterface::class);
$input->method('getOption')
$input
->method('getOption')
->withConsecutive(
[$this->equalTo('system')],
[$this->equalTo('config')],
[$this->equalTo('data')]
['system'],
['config']
)
->will($this->returnValueMap([
['system', 'trello'],
['config', __DIR__ . '/../../data/config-trello.json'],
['data', __DIR__ . '/../../data/data-trello.json']
['config', null]
]));
$output = $this->createMock(OutputInterface::class);
$output
->expects($this->once())
->method('writeLn')
->with('Done!');
$this->boardImportService
->method('getSystem')
->willReturn('trello');
$importService = $this->createMock(AImportService::class);
$this->boardImportService
->method('getImportService')
->willReturn($importService);
$this->invokePrivate($this->boardImport, 'interact', [$input, $output]);
$actual = $this->invokePrivate($this->boardImport, 'interact', [$input, $output]);
$this->assertNull($actual);
$actual = $this->invokePrivate($this->boardImport, 'execute', [$input, $output]);
$this->assertEquals(0, $actual);
}

View File

@@ -1,92 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2021 Vitor Mattos <vitor@php.rio>
*
* @author Vitor Mattos <vitor@php.rio>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Deck\Command;
use OCA\Deck\Command\ImportHelper\TrelloHelper;
use OCA\Deck\Service\AImportService;
use OCA\Deck\Service\BoardImportService;
use OCA\Deck\Service\TrelloImportService;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class TrelloHelperTest extends \Test\TestCase {
/** @var TrelloImportService */
private $trelloImportService;
/** @var BoardImportService */
private $boardImportService;
/** @var TrelloHelper */
private $trelloHelper;
public function setUp(): void {
parent::setUp();
$this->trelloImportService = $this->createMock(TrelloImportService::class);
$this->trelloHelper = new TrelloHelper(
$this->trelloImportService
);
$questionHelper = new QuestionHelper();
$this->boardImportService = $this->createMock(BoardImportService::class);
$this->boardImportService
->method('getAllowedImportSystems')
->willReturn(['trello']);
$command = new BoardImport(
$this->trelloHelper,
$this->boardImportService
);
$command->setHelperSet(
new HelperSet([
$questionHelper
])
);
$this->trelloHelper->setCommand($command);
}
public function testImportWithSuccess() {
$input = $this->createMock(InputInterface::class);
$input->method('getOption')
->withConsecutive(
[$this->equalTo('system')],
[$this->equalTo('config')]
)
->will($this->returnValueMap([
['system', 'trello'],
['config', __DIR__ . '/../../../data/config-trello.json']
]));
$output = $this->createMock(OutputInterface::class);
$this->boardImportService
->method('getSystem')
->willReturn('trello');
$importService = $this->createMock(AImportService::class);
$this->boardImportService
->method('getImportService')
->willReturn($importService);
$this->invokePrivate($this->trelloHelper->getCommand(), 'validateSystem', [$input, $output]);
$this->invokePrivate($this->trelloHelper->getCommand(), 'validateConfig', [$input, $output]);
$actual = $this->trelloHelper->import($input, $output);
$this->assertNull($actual);
}
}

View File

@@ -22,25 +22,69 @@
*/
namespace OCA\Deck\Service;
use OCA\Deck\Db\AclMapper;
use OCA\Deck\Db\AssignmentMapper;
use OCA\Deck\Db\Board;
use OCA\Deck\Db\BoardMapper;
use OCA\Deck\Db\CardMapper;
use OCA\Deck\Db\LabelMapper;
use OCA\Deck\Db\StackMapper;
use OCP\Comments\ICommentsManager;
use OCP\IDBConnection;
use OCP\IUserManager;
class BoardImportServiceTest extends \Test\TestCase {
/** @var TrelloImportService */
private $trelloImportService;
/** @var IDBConnection */
protected $dbConn;
/** @var IUserManager */
private $userManager;
/** @var BoardMapper */
private $boardMapper;
/** @var AclMapper */
private $aclMapper;
/** @var LabelMapper */
private $labelMapper;
/** @var StackMapper */
private $stackMapper;
/** @var CardMapper */
private $cardMapper;
/** @var AssignmentMapper */
private $assignmentMapper;
/** @var ICommentsManager */
private $commentsManager;
/** @var BoardImportService */
private $boardImportService;
public function setUp(): void {
$this->trelloImportService = $this->createMock(TrelloImportService::class);
$this->dbConn = $this->createMock(IDBConnection::class);
$this->userManager = $this->createMock(IUserManager::class);
$this->boardMapper = $this->createMock(BoardMapper::class);
$this->aclMapper = $this->createMock(AclMapper::class);
$this->labelMapper = $this->createMock(LabelMapper::class);
$this->stackMapper = $this->createMock(StackMapper::class);
$this->cardMapper = $this->createMock(AssignmentMapper::class);
$this->assignmentMapper = $this->createMock(CardMapper::class);
$this->commentsManager = $this->createMock(ICommentsManager::class);
$this->boardImportService = new BoardImportService(
$this->trelloImportService
$this->dbConn,
$this->userManager,
$this->boardMapper,
$this->aclMapper,
$this->labelMapper,
$this->stackMapper,
$this->cardMapper,
$this->assignmentMapper,
$this->commentsManager
);
}
public function testImportSuccess() {
$config = json_decode(file_get_contents(__DIR__ . '/../../data/config-trello.json'));
$data = json_decode(file_get_contents(__DIR__ . '/../../data/data-trello.json'));
$actual = $this->boardImportService->import(
'trello',
$config,
$data
);
$importService = $this->createMock(ABoardImportService::class);
$board = new Board();
$importService
->method('getBoard')
->willReturn($board);
$this->boardImportService->setImportSystem($importService);
$actual = $this->boardImportService->import();
$this->assertNull($actual);
}
}

View File

@@ -0,0 +1,169 @@
<?php
/**
* @copyright Copyright (c) 2021 Vitor Mattos <vitor@php.rio>
*
* @author Vitor Mattos <vitor@php.rio>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Deck\Service;
use OCP\IL10N;
use OCP\IUser;
use OCP\IUserManager;
class BoardImportTrelloServiceTest extends \Test\TestCase {
/** @var BoardImportTrelloService */
private $service;
/** @var IUserManager */
private $userManager;
/** @var IL10N */
private $l10n;
public function setUp(): void {
$this->userManager = $this->createMock(IUserManager::class);
$this->l10n = $this->createMock(IL10N::class);
$this->service = new BoardImportTrelloService(
$this->userManager,
$this->l10n
);
}
public function testValidateUsersWithoutUsers() {
$importService = $this->createMock(BoardImportService::class);
$this->service->setImportService($importService);
$actual = $this->service->validateUsers();
$this->assertInstanceOf(BoardImportTrelloService::class, $actual);
}
public function testValidateUsersWithInvalidUser() {
$this->expectErrorMessage('Trello user trello_user not found in property "members" of json data');
$importService = $this->createMock(BoardImportService::class);
$importService
->method('getConfig')
->willReturn([
'trello_user' => 'nextcloud_user'
]);
$importService
->method('getData')
->willReturn(json_decode(
<<<JSON
{
"members": [
{
"username": "othre_trello_user"
}
]
}
JSON
));
$this->service->setImportService($importService);
$actual = $this->service->validateUsers();
$this->assertInstanceOf(BoardImportTrelloService::class, $actual);
}
public function testValidateUsersWithNotStringNextcloud() {
$this->expectErrorMessage('User on setting uidRelation is invalid');
$importService = $this->createMock(BoardImportService::class);
$importService
->method('getConfig')
->willReturn([
'trello_user' => []
]);
$importService
->method('getData')
->willReturn(json_decode(
<<<JSON
{
"members": [
{
"username": "trello_user"
}
]
}
JSON
));
$this->service->setImportService($importService);
$actual = $this->service->validateUsers();
$this->assertInstanceOf(BoardImportTrelloService::class, $actual);
}
public function testValidateUsersWithNotFoundUser() {
$this->expectErrorMessage('User on setting uidRelation not found: nextcloud_user');
$importService = $this->createMock(BoardImportService::class);
$importService
->method('getConfig')
->willReturn(json_decode(
<<<JSON
{
"trello_user": "nextcloud_user"
}
JSON
));
$importService
->method('getData')
->willReturn(json_decode(
<<<JSON
{
"members": [
{
"username": "trello_user"
}
]
}
JSON
));
$this->service->setImportService($importService);
$actual = $this->service->validateUsers();
$this->assertInstanceOf(BoardImportTrelloService::class, $actual);
}
public function testValidateUsersWithValidUsers() {
$importService = $this->createMock(BoardImportService::class);
$importService
->method('getConfig')
->willReturn(json_decode(
<<<JSON
{
"trello_user": "nextcloud_user"
}
JSON
));
$importService
->method('getData')
->willReturn(json_decode(
<<<JSON
{
"members": [
{
"id": "fakeid",
"username": "trello_user"
}
]
}
JSON
));
$fakeUser = $this->createMock(IUser::class);
$this->userManager
// ->expects($this->once())
->method('get')
->with('nextcloud_user')
->willReturn($fakeUser);
$this->service->setImportService($importService);
$actual = $this->service->validateUsers();
$this->assertInstanceOf(BoardImportTrelloService::class, $actual);
}
}

View File

@@ -73,8 +73,6 @@ class BoardServiceTest extends TestCase {
private $changeHelper;
/** @var IEventDispatcher */
private $eventDispatcher;
/** @var TrelloImportService */
private $trelloImportService;
private $userId = 'admin';
public function setUp(): void {
@@ -93,7 +91,6 @@ class BoardServiceTest extends TestCase {
$this->activityManager = $this->createMock(ActivityManager::class);
$this->changeHelper = $this->createMock(ChangeHelper::class);
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
$this->trelloImportService = $this->createMock(TrelloImportService::class);
$this->service = new BoardService(
$this->boardMapper,
@@ -110,7 +107,6 @@ class BoardServiceTest extends TestCase {
$this->activityManager,
$this->eventDispatcher,
$this->changeHelper,
$this->trelloImportService,
$this->userId
);

View File

@@ -1,104 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2021 Vitor Mattos <vitor@php.rio>
*
* @author Vitor Mattos <vitor@php.rio>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Deck\Service;
use OCA\Deck\Db\AclMapper;
use OCA\Deck\Db\AssignmentMapper;
use OCA\Deck\Db\CardMapper;
use OCA\Deck\Db\StackMapper;
use OCP\IDBConnection;
use OCP\IL10N;
use OCP\IUserManager;
class TrelloImportServiceTest extends \Test\TestCase {
/** @var TrelloImportService */
private $trelloImportService;
/** @var BoardService */
private $boardService;
/** @var LabelService */
private $labelService;
/** @var StackMapper */
private $stackMapper;
/** @var CardMapper */
private $cardMapper;
/** @var AssignmentMapper */
private $assignmentMapper;
/** @var AclMapper */
private $aclMapper;
/** @var IDBConnection */
private $connection;
/** @var IUserManager */
private $userManager;
/** @var IL10N */
private $l10n;
public function setUp(): void {
parent::setUp();
$this->boardService = $this->createMock(BoardService::class);
$this->labelService = $this->createMock(LabelService::class);
$this->stackMapper = $this->createMock(StackMapper::class);
$this->cardMapper = $this->createMock(CardMapper::class);
$this->assignmentMapper = $this->createMock(AssignmentMapper::class);
$this->aclMapper = $this->createMock(AclMapper::class);
$this->connection = $this->createMock(IDBConnection::class);
$this->userManager = $this->createMock(IUserManager::class);
$this->l10n = $this->createMock(IL10N::class);
$this->trelloImportService = new TrelloImportService(
$this->boardService,
$this->labelService,
$this->stackMapper,
$this->cardMapper,
$this->assignmentMapper,
$this->aclMapper,
$this->connection,
$this->userManager,
$this->l10n
);
}
public function testValidateOwnerWithFaliure() {
$owner = $this->createMock(\OCP\IUser::class);
$owner
->method('getUID')
->willReturn('admin');
$this->trelloImportService->setConfig('owner', $owner);
$this->userManager
->method('get')
->willReturn(null);
$this->expectErrorMessage('Owner "admin" not found on Nextcloud. Check setting json.');
$this->trelloImportService->validateOwner();
}
public function testValidateOwnerWithSuccess() {
$owner = $this->createMock(\OCP\IUser::class);
$owner
->method('getUID')
->willReturn('admin');
$this->trelloImportService->setConfig('owner', $owner);
$this->userManager
->method('get')
->willReturn($owner);
$actual = $this->trelloImportService->validateOwner();
$this->assertNull($actual);
}
}

View File

@@ -0,0 +1,74 @@
<?php
/**
* @copyright Copyright (c) 2018 Ryan Fletcher <ryan.fletcher@codepassion.ca>
*
* @author Ryan Fletcher <ryan.fletcher@codepassion.ca>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Deck\Controller;
use OCA\Deck\Db\Board;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\IRequest;
use OCA\Deck\Service\BoardImportService;
class BoardImportApiControllerTest extends \Test\TestCase {
private $appName = 'deck';
private $userId = 'admin';
/** @var BoardImportApiController */
private $controller;
/** @var BoardImportService */
private $boardImportService;
public function setUp(): void {
parent::setUp();
$this->request = $this->createMock(IRequest::class);
$this->boardImportService = $this->createMock(BoardImportService::class);
$this->controller = new BoardImportApiController(
$this->appName,
$this->request,
$this->boardImportService,
$this->userId
);
}
public function testGetAllowedSystems() {
$this->boardImportService
->method('getAllowedImportSystems')
->willReturn(['trello']);
$actual = $this->controller->getAllowedSystems();
$expected = new DataResponse(['trello'], HTTP::STATUS_OK);
$this->assertEquals($expected, $actual);
}
public function testImport() {
$system = 'trello';
$config = [
'owner' => 'test'
];
$data = [
'name' => 'test'
];
$actual = $this->controller->import($system, $config, $data);
$board = $this->createMock(Board::class);
$this->assertInstanceOf(Board::class, $board);
$this->assertEquals(HTTP::STATUS_OK, $actual->getStatus());
}
}