Skip to content

Commit

Permalink
link workpackage backend
Browse files Browse the repository at this point in the history
Signed-off-by: Artur Neumann <artur@jankaritech.com>
  • Loading branch information
individual-it committed Mar 10, 2022
1 parent 0a3900b commit 7c61ca5
Show file tree
Hide file tree
Showing 10 changed files with 1,061 additions and 39 deletions.
43 changes: 41 additions & 2 deletions lib/Controller/OpenProjectAPIController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@

namespace OCA\OpenProject\Controller;

use Exception;
use OCA\OpenProject\Exception\OpenprojectErrorException;
use OCP\AppFramework\Http\DataDisplayResponse;
use OCP\AppFramework\Http\DataDownloadResponse;
use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
use OCP\IConfig;
use OCP\IRequest;
use OCP\AppFramework\Http;
Expand All @@ -21,6 +25,7 @@

use OCA\OpenProject\Service\OpenProjectAPIService;
use OCA\OpenProject\AppInfo\Application;
use OCP\IURLGenerator;

class OpenProjectAPIController extends Controller {

Expand Down Expand Up @@ -53,10 +58,16 @@ class OpenProjectAPIController extends Controller {
*/
private $openprojectUrl;

/**
* @var IURLGenerator
*/
private $urlGenerator;

public function __construct(string $appName,
IRequest $request,
IConfig $config,
OpenProjectAPIService $openprojectAPIService,
IURLGenerator $urlGenerator,
?string $userId) {
parent::__construct($appName, $request);
$this->openprojectAPIService = $openprojectAPIService;
Expand All @@ -66,6 +77,7 @@ public function __construct(string $appName,
$this->clientID = $config->getAppValue(Application::APP_ID, 'client_id');
$this->clientSecret = $config->getAppValue(Application::APP_ID, 'client_secret');
$this->openprojectUrl = $config->getAppValue(Application::APP_ID, 'oauth_instance_url');
$this->urlGenerator = $urlGenerator;
}

/**
Expand Down Expand Up @@ -168,10 +180,37 @@ public function getSearchedWorkPackages(?string $searchQuery = null, ?int $fileI
* @NoAdminRequired
* @param int $workpackageId
* @param int $fileId
* @param string $fileName
* @return DataResponse
*/
public function linkWorkPackageToFile(int $workpackageId = 0, int $fileId = 0): DataResponse {
return new DataResponse("Fake result, to make UI happy");
public function linkWorkPackageToFile(int $workpackageId, int $fileId, string $fileName) {
if ($this->accessToken === '' || !OpenProjectAPIService::validateOpenProjectURL($this->openprojectUrl)) {
return new DataResponse('', Http::STATUS_BAD_REQUEST);
}

$storageUrl = $this->urlGenerator->getBaseUrl();

try {
$result = $this->openprojectAPIService->linkWorkPackageToFile(
$this->openprojectUrl,
$this->accessToken,
$this->refreshToken,
$this->clientID,
$this->clientSecret,
$workpackageId,
$fileId,
$fileName,
$storageUrl,
$this->userId,
);
} catch (OpenprojectErrorException $e) {
return new DataResponse($e->getMessage(), Http::STATUS_BAD_REQUEST);
} catch (NotPermittedException | NotFoundException $e) {
return new DataResponse('fileid not found', Http::STATUS_NOT_FOUND);
} catch (Exception $e) {
return new DataResponse($e->getMessage(), Http::STATUS_INTERNAL_SERVER_ERROR);
}
return new DataResponse($result);
}

/**
Expand Down
18 changes: 18 additions & 0 deletions lib/Exception/OpenprojectErrorException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace OCA\OpenProject\Exception;

use Exception;
use Throwable;

class OpenprojectErrorException extends Exception {

/**
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct(string $message, int $code = 0, Throwable $previous = null) {
parent::__construct($message, $code, $previous);
}
}
18 changes: 18 additions & 0 deletions lib/Exception/OpenprojectResponseException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace OCA\OpenProject\Exception;

use Exception;
use Throwable;

class OpenprojectResponseException extends Exception {

/**
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct(string $message, int $code = 0, Throwable $previous = null) {
parent::__construct($message, $code, $previous);
}
}
106 changes: 104 additions & 2 deletions lib/Service/OpenProjectAPIService.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
use DateTime;
use DateTimeZone;
use Exception;
use OCA\OpenProject\Exception\OpenprojectErrorException;
use OCA\OpenProject\Exception\OpenprojectResponseException;
use OCP\Files\File;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
use OCP\IL10N;
use OCP\IURLGenerator;
use Psr\Log\LoggerInterface;
Expand All @@ -23,10 +28,12 @@
use OCP\IAvatarManager;
use OCP\Http\Client\IClientService;
use OCP\Notification\IManager as INotificationManager;
use OCP\Files\NotPermittedException;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ServerException;
use GuzzleHttp\Exception\ConnectException;


use OCA\OpenProject\AppInfo\Application;

class OpenProjectAPIService {
Expand Down Expand Up @@ -63,6 +70,8 @@ class OpenProjectAPIService {
*/
private $client;

/** @var IRootFolder */
private $storage;
/**
* Service to make requests to OpenProject v3 (JSON) API
*/
Expand All @@ -74,7 +83,8 @@ public function __construct(
IL10N $l10n,
IConfig $config,
INotificationManager $notificationManager,
IClientService $clientService) {
IClientService $clientService,
IRootFolder $storage) {
$this->appName = $appName;
$this->userManager = $userManager;
$this->avatarManager = $avatarManager;
Expand All @@ -83,6 +93,7 @@ public function __construct(
$this->config = $config;
$this->notificationManager = $notificationManager;
$this->client = $clientService->newClient();
$this->storage = $storage;
}

/**
Expand Down Expand Up @@ -387,7 +398,8 @@ public function request(string $openprojectUrl, string $accessToken, string $ref
$paramsContent .= http_build_query($params);
$url .= '?' . $paramsContent;
} else {
$options['body'] = $params;
$options['body'] = $params['body'];
$options['headers']['Content-Type'] = 'application/json';
}
}

Expand Down Expand Up @@ -581,4 +593,94 @@ public static function getOpenProjectOauthURL(IConfig $config, IURLGenerator $ur
'&redirect_uri=' . urlencode($redirectUri) .
'&response_type=code';
}

/**
* @param string $userId
* @param int $fileId
* @return \OCP\Files\Node|null
* @throws NotPermittedException
* @throws \OC\User\NoUserException
*/
public function getFile($userId, $fileId) {
$userFolder = $this->storage->getUserFolder($userId);

$file = $userFolder->getById($fileId);
return $file[0];
}

/**
* @throws \OCP\Files\InvalidPathException
* @throws NotFoundException
* @throws \OCP\PreConditionNotMetException
* @throws NotPermittedException
* @throws OpenprojectErrorException
* @throws \OC\User\NoUserException
* @throws OpenprojectResponseException
* @return int
*/
public function linkWorkPackageToFile(
string $openprojectUrl,
string $accessToken,
string $refreshToken,
string $clientID,
string $clientSecret,
int $workpackageId,
int $fileId,
string $fileName,
string $storageUrl,
string $userId
) {
$file = $this->getFile($userId, $fileId);
if ($file instanceof File) {
if (!$file->isReadable()) {
throw new NotPermittedException();
}
} else {
throw new NotFoundException();
}

$body = [
'_type' => 'Collection',
'_embedded' => [
'elements' => [
[
'originData' => [
'id' => $fileId,
'name' => $fileName,
'mimeType' => $file->getMimeType(),
'createdAt' => gmdate('Y-m-d\TH:i:s.000\Z', $file->getCreationTime()),
'lastModifiedAt' => gmdate('Y-m-d\TH:i:s.000\Z', $file->getMTime()),
'createdByName' => '',
'lastModifiedByName' => ''
],
'_links' => [
'storageUrl' => [
'href' => $storageUrl
]
]
]
]
]
];

$params['body'] = \Safe\json_encode($body);
$result = $this->request(
$openprojectUrl, $accessToken, $refreshToken, $clientID, $clientSecret, $userId, 'work_packages/' . $workpackageId. '/file_links', $params, 'POST'
);

if (isset($result['error'])) {
throw new OpenprojectErrorException($result['error']);
}
if (
!isset($result['_type']) ||
$result['_type'] !== 'Collection' ||
!isset($result['_embedded']) ||
!isset($result['_embedded']['elements']) ||
!isset($result['_embedded']['elements'][0]) ||
!isset($result['_embedded']['elements'][0]['id'])
) {
throw new OpenprojectResponseException('Malformed response');
}
return $result['_embedded']['elements'][0]['id'];
}
}
8 changes: 5 additions & 3 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,14 @@
<php>
<env name="PACT_MOCK_SERVER_HOST" value="localhost"/>
<env name="PACT_MOCK_SERVER_PORT" value="7200"/>
<env name="PACT_CONSUMER_NAME" value="someConsumer"/>
<env name="PACT_CONSUMER_NAME" value="integration_openproject"/>
<env name="PACT_CONSUMER_VERSION" value="1.0.0"/>
<env name="PACT_CONSUMER_TAG" value="master"/>
<env name="PACT_PROVIDER_NAME" value="someProvider"/>
<env name="PACT_OUTPUT_DIR" value=".\example\output"/>
<env name="PACT_PROVIDER_NAME" value="OpenProject"/>
<env name="PACT_OUTPUT_DIR" value="./tests/pact/"/>
<env name="PACT_MOCK_SERVER_HEALTH_CHECK_TIMEOUT" value="10"/>
<env name="PACT_LOGLEVEL" value="INFO"/>
<env name="PACT_LOG" value="./tests/pact/pact.log"/>
<!-- <env name="PACT_BROKER_URI" value="http://localhost"/> -->
</php>
<logging/>
Expand Down
13 changes: 8 additions & 5 deletions src/components/tab/SearchInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -103,16 +103,19 @@ export default {
: null
},
async linkWorkPackageToFile(selectedOption) {
const req = {
values: {
workpackageId: selectedOption.id,
fileId: this.fileInfo.id,
const params = new URLSearchParams()
params.append('workpackageId', selectedOption.id)
params.append('fileId', this.fileInfo.id)
params.append('fileName', this.fileInfo.name)
const config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
}
const url = generateUrl('/apps/integration_openproject/work-packages')
try {
await axios.post(url, req)
await axios.post(url, params, config)
this.$emit('saved', selectedOption)
this.selectedId.push({
id: selectedOption.id,
Expand Down
Loading

0 comments on commit 7c61ca5

Please sign in to comment.