Add 1.1 api version to handle other attachment types properly

Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
Julius Härtl
2021-01-04 15:27:48 +01:00
parent 8ab7019693
commit 199cccf86b
10 changed files with 232 additions and 142 deletions

View File

@@ -80,59 +80,66 @@ return [
['name' => 'label#delete', 'url' => '/labels/{labelId}', 'verb' => 'DELETE'],
// api
['name' => 'board_api#index', 'url' => '/api/v1.0/boards', 'verb' => 'GET'],
['name' => 'board_api#get', 'url' => '/api/v1.0/boards/{boardId}', 'verb' => 'GET'],
['name' => 'board_api#create', 'url' => '/api/v1.0/boards', 'verb' => 'POST'],
['name' => 'board_api#delete', 'url' => '/api/v1.0/boards/{boardId}', 'verb' => 'DELETE'],
['name' => 'board_api#update', 'url' => '/api/v1.0/boards/{boardId}', 'verb' => 'PUT'],
['name' => 'board_api#undo_delete', 'url' => '/api/v1.0/boards/{boardId}/undo_delete', 'verb' => 'POST'],
['name' => 'board_api#addAcl', 'url' => '/api/v1.0/boards/{boardId}/acl', 'verb' => 'POST'],
['name' => 'board_api#deleteAcl', 'url' => '/api/v1.0/boards/{boardId}/acl/{aclId}', 'verb' => 'DELETE'],
['name' => 'board_api#updateAcl', 'url' => '/api/v1.0/boards/{boardId}/acl/{aclId}', 'verb' => 'PUT'],
['name' => 'board_api#index', 'url' => '/api/v{apiVersion}/boards', 'verb' => 'GET'],
['name' => 'board_api#get', 'url' => '/api/v{apiVersion}/boards/{boardId}', 'verb' => 'GET'],
['name' => 'board_api#create', 'url' => '/api/v{apiVersion}/boards', 'verb' => 'POST'],
['name' => 'board_api#delete', 'url' => '/api/v{apiVersion}/boards/{boardId}', 'verb' => 'DELETE'],
['name' => 'board_api#update', 'url' => '/api/v{apiVersion}/boards/{boardId}', 'verb' => 'PUT'],
['name' => 'board_api#undo_delete', 'url' => '/api/v{apiVersion}/boards/{boardId}/undo_delete', 'verb' => 'POST'],
['name' => 'board_api#addAcl', 'url' => '/api/v{apiVersion}/boards/{boardId}/acl', 'verb' => 'POST'],
['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' => 'stack_api#index', 'url' => '/api/v1.0/boards/{boardId}/stacks', 'verb' => 'GET'],
['name' => 'stack_api#getArchived', 'url' => '/api/v1.0/boards/{boardId}/stacks/archived', 'verb' => 'GET'],
['name' => 'stack_api#get', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}', 'verb' => 'GET'],
['name' => 'stack_api#create', 'url' => '/api/v1.0/boards/{boardId}/stacks', 'verb' => 'POST'],
['name' => 'stack_api#update', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}', 'verb' => 'PUT'],
['name' => 'stack_api#delete', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}', 'verb' => 'DELETE'],
['name' => 'stack_api#index', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks', 'verb' => 'GET'],
['name' => 'stack_api#getArchived', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/archived', 'verb' => 'GET'],
['name' => 'stack_api#get', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}', 'verb' => 'GET'],
['name' => 'stack_api#create', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks', 'verb' => 'POST'],
['name' => 'stack_api#update', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}', 'verb' => 'PUT'],
['name' => 'stack_api#delete', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}', 'verb' => 'DELETE'],
['name' => 'card_api#get', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}', 'verb' => 'GET'],
['name' => 'card_api#create', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards', 'verb' => 'POST'],
['name' => 'card_api#update', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}', 'verb' => 'PUT'],
['name' => 'card_api#assignLabel', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/assignLabel', 'verb' => 'PUT'],
['name' => 'card_api#removeLabel', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/removeLabel', 'verb' => 'PUT'],
['name' => 'card_api#assignUser', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/assignUser', 'verb' => 'PUT'],
['name' => 'card_api#unassignUser', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/unassignUser', 'verb' => 'PUT'],
['name' => 'card_api#reorder', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/reorder', 'verb' => 'PUT'],
['name' => 'card_api#delete', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}', 'verb' => 'DELETE'],
['name' => 'card_api#get', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards/{cardId}', 'verb' => 'GET'],
['name' => 'card_api#create', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards', 'verb' => 'POST'],
['name' => 'card_api#update', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards/{cardId}', 'verb' => 'PUT'],
['name' => 'card_api#assignLabel', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards/{cardId}/assignLabel', 'verb' => 'PUT'],
['name' => 'card_api#removeLabel', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards/{cardId}/removeLabel', 'verb' => 'PUT'],
['name' => 'card_api#assignUser', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards/{cardId}/assignUser', 'verb' => 'PUT'],
['name' => 'card_api#unassignUser', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards/{cardId}/unassignUser', 'verb' => 'PUT'],
['name' => 'card_api#reorder', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards/{cardId}/reorder', 'verb' => 'PUT'],
['name' => 'card_api#delete', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards/{cardId}', 'verb' => 'DELETE'],
['name' => 'card_api#findAllWithDue', 'url' => '/api/v1.0/dashboard/due', 'verb' => 'GET'],
['name' => 'card_api#findAllWithDue', 'url' => '/api/v{apiVersion}/dashboard/due', 'verb' => 'GET'],
['name' => 'label_api#get', 'url' => '/api/v1.0/boards/{boardId}/labels/{labelId}', 'verb' => 'GET'],
['name' => 'label_api#create', 'url' => '/api/v1.0/boards/{boardId}/labels', 'verb' => 'POST'],
['name' => 'label_api#update', 'url' => '/api/v1.0/boards/{boardId}/labels/{labelId}', 'verb' => 'PUT'],
['name' => 'label_api#delete', 'url' => '/api/v1.0/boards/{boardId}/labels/{labelId}', 'verb' => 'DELETE'],
['name' => 'label_api#get', 'url' => '/api/v{apiVersion}/boards/{boardId}/labels/{labelId}', 'verb' => 'GET'],
['name' => 'label_api#create', 'url' => '/api/v{apiVersion}/boards/{boardId}/labels', 'verb' => 'POST'],
['name' => 'label_api#update', 'url' => '/api/v{apiVersion}/boards/{boardId}/labels/{labelId}', 'verb' => 'PUT'],
['name' => 'label_api#delete', 'url' => '/api/v{apiVersion}/boards/{boardId}/labels/{labelId}', 'verb' => 'DELETE'],
['name' => 'attachment_api#getAll', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments', 'verb' => 'GET'],
['name' => 'attachment_api#display', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments/{attachmentId}', 'verb' => 'GET'],
['name' => 'attachment_api#create', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments', 'verb' => 'POST'],
['name' => 'attachment_api#update', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments/{attachmentId}', 'verb' => 'PUT'],
['name' => 'attachment_api#delete', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments/{attachmentId}', 'verb' => 'DELETE'],
['name' => 'attachment_api#restore', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments/{attachmentId}/restore', 'verb' => 'PUT'],
['name' => 'attachment_api#getAll', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments', 'verb' => 'GET', 'requirements' => ['apiVersion' => '1.0']],
['name' => 'attachment_api#display', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments/{attachmentId}', 'verb' => 'GET', 'requirements' => ['apiVersion' => '1.0']],
['name' => 'attachment_api#create', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments', 'verb' => 'POST', 'requirements' => ['apiVersion' => '1.0']],
['name' => 'attachment_api#update', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments/{attachmentId}', 'verb' => 'PUT', 'requirements' => ['apiVersion' => '1.0']],
['name' => 'attachment_api#delete', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments/{attachmentId}', 'verb' => 'DELETE', 'requirements' => ['apiVersion' => '1.0']],
['name' => 'attachment_api#restore', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments/{attachmentId}/restore', 'verb' => 'PUT', 'requirements' => ['apiVersion' => '1.0']],
['name' => 'board_api#preflighted_cors', 'url' => '/api/v1.0/{path}','verb' => 'OPTIONS', 'requirements' => ['path' => '.+']],
['name' => 'attachment_api_v11#getAll', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments', 'verb' => 'GET', 'requirements' => ['apiVersion' => '1.1']],
['name' => 'attachment_api_v11#display', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments/{type}/{attachmentId}', 'verb' => 'GET', 'requirements' => ['apiVersion' => '1.1']],
['name' => 'attachment_api_v11#create', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments', 'verb' => 'POST', 'requirements' => ['apiVersion' => '1.1']],
['name' => 'attachment_api_v11#update', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments/{type}/{attachmentId}', 'verb' => 'PUT', 'requirements' => ['apiVersion' => '1.1']],
['name' => 'attachment_api_v11#delete', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments/{type}/{attachmentId}', 'verb' => 'DELETE', 'requirements' => ['apiVersion' => '1.1']],
['name' => 'attachment_api_v11#restore', 'url' => '/api/v{apiVersion}/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments/{type}/{attachmentId}/restore', 'verb' => 'PUT', 'requirements' => ['apiVersion' => '1.1']],
['name' => 'board_api#preflighted_cors', 'url' => '/api/v{apiVersion}/{path}','verb' => 'OPTIONS', 'requirements' => ['path' => '.+']],
],
'ocs' => [
['name' => 'Config#get', 'url' => '/api/v1.0/config', 'verb' => 'GET'],
['name' => 'Config#setValue', 'url' => '/api/v1.0/config/{key}', 'verb' => 'POST'],
['name' => 'Config#get', 'url' => '/api/v{apiVersion}/config', 'verb' => 'GET'],
['name' => 'Config#setValue', 'url' => '/api/v{apiVersion}/config/{key}', 'verb' => 'POST'],
['name' => 'comments_api#list', 'url' => '/api/v1.0/cards/{cardId}/comments', 'verb' => 'GET'],
['name' => 'comments_api#create', 'url' => '/api/v1.0/cards/{cardId}/comments', 'verb' => 'POST'],
['name' => 'comments_api#update', 'url' => '/api/v1.0/cards/{cardId}/comments/{commentId}', 'verb' => 'PUT'],
['name' => 'comments_api#delete', 'url' => '/api/v1.0/cards/{cardId}/comments/{commentId}', 'verb' => 'DELETE'],
['name' => 'comments_api#list', 'url' => '/api/v{apiVersion}/cards/{cardId}/comments', 'verb' => 'GET'],
['name' => 'comments_api#create', 'url' => '/api/v{apiVersion}/cards/{cardId}/comments', 'verb' => 'POST'],
['name' => 'comments_api#update', 'url' => '/api/v{apiVersion}/cards/{cardId}/comments/{commentId}', 'verb' => 'PUT'],
['name' => 'comments_api#delete', 'url' => '/api/v{apiVersion}/cards/{cardId}/comments/{commentId}', 'verb' => 'DELETE'],
['name' => 'overview_api#upcomingCards', 'url' => '/api/v1.0/overview/upcoming', 'verb' => 'GET'],
['name' => 'overview_api#upcomingCards', 'url' => '/api/v{apiVersion}/overview/upcoming', 'verb' => 'GET'],
]
];

View File

@@ -380,7 +380,7 @@ class ActivityManager {
case self::SUBJECT_ATTACHMENT_UPDATE:
case self::SUBJECT_ATTACHMENT_DELETE:
case self::SUBJECT_ATTACHMENT_RESTORE:
$subjectParams = $this->findDetailsForAttachment($entity->getId());
$subjectParams = $this->findDetailsForAttachment($entity);
break;
case self::SUBJECT_BOARD_SHARE:
case self::SUBJECT_BOARD_UNSHARE:
@@ -527,8 +527,7 @@ class ActivityManager {
];
}
private function findDetailsForAttachment($attachmentId) {
$attachment = $this->attachmentMapper->find($attachmentId);
private function findDetailsForAttachment($attachment) {
$data = $this->findDetailsForCard($attachment->getCardId());
return array_merge($data, ['attachment' => $attachment]);
}

View File

@@ -50,7 +50,11 @@ class Capabilities implements ICapability {
return [
'deck' => [
'version' => $this->appManager->getAppVersion('deck'),
'canCreateBoards' => $this->permissionService->canCreate()
'canCreateBoards' => $this->permissionService->canCreate(),
'apiVersions' => [
'1.0',
'1.1'
]
]
];
}

View File

@@ -42,8 +42,13 @@ class AttachmentApiController extends ApiController {
* @NoCSRFRequired
*
*/
public function getAll() {
public function getAll($apiVersion) {
$attachment = $this->attachmentService->findAll($this->request->getParam('cardId'), true);
if ($apiVersion === '1.0') {
$attachment = array_filter($attachment, function ($attachment) {
return $attachment->getType() === 'deck_file';
});
}
return new DataResponse($attachment, HTTP::STATUS_OK);
}
@@ -53,8 +58,8 @@ class AttachmentApiController extends ApiController {
* @NoCSRFRequired
*
*/
public function display() {
return $this->attachmentService->display($this->request->getParam('attachmentId'));
public function display($cardId, $attachmentId, $type = 'deck_file') {
return $this->attachmentService->display($cardId, $attachmentId, $type);
}
/**
@@ -63,8 +68,8 @@ class AttachmentApiController extends ApiController {
* @NoCSRFRequired
*
*/
public function create($type, $data) {
$attachment = $this->attachmentService->create($this->request->getParam('cardId'), $type, $data);
public function create($cardId, $type, $data) {
$attachment = $this->attachmentService->create($cardId, $type, $data);
return new DataResponse($attachment, HTTP::STATUS_OK);
}
@@ -74,8 +79,8 @@ class AttachmentApiController extends ApiController {
* @NoCSRFRequired
*
*/
public function update($data) {
$attachment = $this->attachmentService->update($this->request->getParam('attachmentId'), $data);
public function update($cardId, $attachmentId, $data, $type = 'deck_file') {
$attachment = $this->attachmentService->update($cardId, $attachmentId, $data, $type);
return new DataResponse($attachment, HTTP::STATUS_OK);
}
@@ -85,8 +90,8 @@ class AttachmentApiController extends ApiController {
* @NoCSRFRequired
*
*/
public function delete() {
$attachment = $this->attachmentService->delete($this->request->getParam('attachmentId'));
public function delete($cardId, $attachmentId, $type = 'deck_file') {
$attachment = $this->attachmentService->delete($cardId, $attachmentId, $type);
return new DataResponse($attachment, HTTP::STATUS_OK);
}
@@ -96,8 +101,8 @@ class AttachmentApiController extends ApiController {
* @NoCSRFRequired
*
*/
public function restore() {
$attachment = $this->attachmentService->restore($this->request->getParam('attachmentId'));
public function restore($cardId, $attachmentId, $type = 'deck_file') {
$attachment = $this->attachmentService->restore($cardId, $attachmentId, $type);
return new DataResponse($attachment, HTTP::STATUS_OK);
}
}

View File

@@ -0,0 +1,26 @@
<?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;
class AttachmentApiV11Controller extends AttachmentApiController {
}

View File

@@ -52,8 +52,13 @@ class AttachmentController extends Controller {
* @return \OCP\AppFramework\Http\Response
* @throws \OCA\Deck\NotFoundException
*/
public function display($attachmentId) {
return $this->attachmentService->display($attachmentId);
public function display($cardId, $attachmentId) {
if (strpos($attachmentId, ':') === false) {
$type = 'deck_file';
} else {
[$type, $attachmentId] = explode(':', $attachmentId);
}
return $this->attachmentService->display($cardId, $attachmentId, $type);
}
/**
@@ -70,21 +75,36 @@ class AttachmentController extends Controller {
/**
* @NoAdminRequired
*/
public function update($attachmentId) {
return $this->attachmentService->update($attachmentId, $this->request->getParam('data'));
public function update($cardId, $attachmentId) {
if (strpos($attachmentId, ':') === false) {
$type = 'deck_file';
} else {
[$type, $attachmentId] = explode(':', $attachmentId);
}
return $this->attachmentService->update($cardId, $attachmentId, $this->request->getParam('data'), $type);
}
/**
* @NoAdminRequired
*/
public function delete($attachmentId) {
return $this->attachmentService->delete($attachmentId);
public function delete($cardId, $attachmentId) {
if (strpos($attachmentId, ':') === false) {
$type = 'deck_file';
} else {
[$type, $attachmentId] = explode(':', $attachmentId);
}
return $this->attachmentService->delete($cardId, $attachmentId, $type);
}
/**
* @NoAdminRequired
*/
public function restore($attachmentId) {
return $this->attachmentService->restore($attachmentId);
public function restore($cardId, $attachmentId) {
if (strpos($attachmentId, ':') === false) {
$type = 'deck_file';
} else {
[$type, $attachmentId] = explode(':', $attachmentId);
}
return $this->attachmentService->restore($cardId, $attachmentId, $type);
}
}

View File

@@ -225,8 +225,14 @@ class AttachmentService {
* @throws NoPermissionException
* @throws NotFoundException
*/
public function display($attachmentId) {
if (is_numeric($attachmentId)) {
public function display($cardId, $attachmentId, $type = 'deck_file') {
try {
$service = $this->getService($type);
} catch (InvalidAttachmentType $e) {
throw new NotFoundException();
}
if (!$service instanceof ICustomAttachmentService) {
try {
$attachment = $this->attachmentMapper->find($attachmentId);
} catch (\Exception $e) {
@@ -236,23 +242,18 @@ class AttachmentService {
try {
$service = $this->getService($attachment->getType());
return $service->display($attachment);
} catch (InvalidAttachmentType $e) {
throw new NotFoundException();
}
}
[$type, $attachmentId] = explode(':', $attachmentId);
try {
} else {
$attachment = new Attachment();
$attachment->setId($attachmentId);
$attachment->setType($type);
$service = $this->getService($type);
return $service->display($attachment);
} catch (\Exception $e) {
throw new NotFoundException();
$attachment->setCardId($cardId);
$this->permissionService->checkPermission($this->cardMapper, $attachment->getCardId(), Acl::PERMISSION_READ);
}
return $service->display($attachment);
}
/**
@@ -264,17 +265,23 @@ class AttachmentService {
* @throws BadRequestException
* @throws NoPermissionException
*/
public function update($attachmentId, $data) {
if (!is_numeric($attachmentId)) {
[$type, $attachmentId] = explode(':', $attachmentId);
public function update($cardId, $attachmentId, $data, $type = 'deck_file') {
try {
$service = $this->getService($type);
} catch (InvalidAttachmentType $e) {
throw new NotFoundException();
}
if ($service instanceof ICustomAttachmentService) {
try {
$attachment = new Attachment();
$attachment->setId($attachmentId);
$attachment->setType($type);
$attachment->setData($data);
$service = $this->getService($type);
return $service->update($attachment);
$attachment->setCardId($cardId);
$service->update($attachment);
$this->changeHelper->cardChanged($attachment->getCardId());
return $attachment;
} catch (\Exception $e) {
throw new NotFoundException();
}
@@ -302,12 +309,8 @@ class AttachmentService {
$attachment->setLastModified(time());
$this->attachmentMapper->update($attachment);
// extend data so the frontend can use it properly after creating
try {
$service = $this->getService($attachment->getType());
$service->extendData($attachment);
} catch (InvalidAttachmentType $e) {
// just store the data
}
$service->extendData($attachment);
$this->changeHelper->cardChanged($attachment->getCardId());
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $attachment, ActivityManager::SUBJECT_ATTACHMENT_UPDATE);
return $attachment;
@@ -324,19 +327,23 @@ class AttachmentService {
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException
*/
public function delete($attachmentId) {
if (!is_numeric($attachmentId)) {
[$type, $attachmentId] = explode(':', $attachmentId);
public function delete($cardId, $attachmentId, $type = 'deck_file') {
try {
$service = $this->getService($type);
} catch (InvalidAttachmentType $e) {
throw new NotFoundException();
}
try {
$attachment = new Attachment();
$attachment->setId($attachmentId);
$attachment->setType($type);
$service = $this->getService($type);
return $service->delete($attachment);
} catch (\Exception $e) {
throw new NotFoundException();
}
if ($service instanceof ICustomAttachmentService) {
$attachment = new Attachment();
$attachment->setId($attachmentId);
$attachment->setType($type);
$attachment->setCardId($cardId);
$service->extendData($attachment);
$service->delete($attachment);
$this->changeHelper->cardChanged($attachment->getCardId());
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $attachment, ActivityManager::SUBJECT_ATTACHMENT_DELETE);
return $attachment;
}
try {
@@ -348,25 +355,21 @@ class AttachmentService {
$this->permissionService->checkPermission($this->cardMapper, $attachment->getCardId(), Acl::PERMISSION_EDIT);
$this->cache->clear('card-' . $attachment->getCardId());
try {
$service = $this->getService($attachment->getType());
if ($service->allowUndo()) {
$service->markAsDeleted($attachment);
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $attachment, ActivityManager::SUBJECT_ATTACHMENT_DELETE);
$this->changeHelper->cardChanged($attachment->getCardId());
return $this->attachmentMapper->update($attachment);
}
$service->delete($attachment);
} catch (InvalidAttachmentType $e) {
// just delete without further action
if ($service->allowUndo()) {
$service->markAsDeleted($attachment);
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $attachment, ActivityManager::SUBJECT_ATTACHMENT_DELETE);
$this->changeHelper->cardChanged($attachment->getCardId());
return $this->attachmentMapper->update($attachment);
}
$service->delete($attachment);
$attachment = $this->attachmentMapper->delete($attachment);
$this->changeHelper->cardChanged($attachment->getCardId());
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $attachment, ActivityManager::SUBJECT_ATTACHMENT_DELETE);
return $attachment;
}
public function restore($attachmentId) {
public function restore($cardId, $attachmentId, $type = 'deck_file') {
if (is_numeric($attachmentId) === false) {
throw new BadRequestException('attachment id must be a number');
}

View File

@@ -150,6 +150,11 @@ class CardService {
$card = $this->cardMapper->find($cardId);
$assignedUsers = $this->assignedUsersMapper->findAll($card->getId());
$attachments = $this->attachmentService->findAll($cardId, true);
if (\OC::$server->getRequest()->getParam('apiVersion') === '1.0') {
$attachments = array_filter($attachments, function ($attachment) {
return $attachment->getType() === 'deck_file';
});
}
$card->setAssignedUsers($assignedUsers);
$card->setAttachments($attachments);
$this->enrich($card);

View File

@@ -26,7 +26,6 @@ namespace OCA\Deck\Service;
use OCA\Deck\Db\Attachment;
use OCA\Deck\Sharing\DeckShareProvider;
use OCA\Deck\StatusException;
use OCA\Deck\Exceptions\ConflictException;
use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\AppFramework\Http\FileDisplayResponse;
use OCP\AppFramework\Http\StreamResponse;
@@ -50,6 +49,7 @@ class FilesAppService implements IAttachmentService, ICustomAttachmentService {
private $configService;
private $l10n;
private $preview;
private $permissionService;
public function __construct(
IRequest $request,
@@ -59,6 +59,7 @@ class FilesAppService implements IAttachmentService, ICustomAttachmentService {
ConfigService $configService,
DeckShareProvider $shareProvider,
IPreview $preview,
PermissionService $permissionService,
string $userId = null
) {
$this->request = $request;
@@ -72,15 +73,15 @@ class FilesAppService implements IAttachmentService, ICustomAttachmentService {
}
public function listAttachments(int $cardId): array {
$userFolder = $this->rootFolder->getUserFolder($this->userId);
$shares = $this->shareProvider->getSharedWithByType($cardId, IShare::TYPE_DECK, -1, 0);
$shares = array_filter($shares, function ($share) {
return $share->getPermissions() > 0;
});
return array_map(function (IShare $share) use ($cardId, $userFolder) {
$file = $share->getNode();
$nodes = $userFolder->getById($file->getId());
$file = array_shift($nodes);
$attachment = new Attachment();
$attachment->setType('file');
$attachment->setId($file->getId());
$attachment->setId($share->getId());
$attachment->setCardId($cardId);
$attachment->setCreatedBy($share->getSharedBy());
$attachment->setData($file->getName());
@@ -95,8 +96,11 @@ class FilesAppService implements IAttachmentService, ICustomAttachmentService {
/** @var IDBConnection $qb */
$db = \OC::$server->getDatabaseConnection();
$qb = $db->getQueryBuilder();
$qb->select($qb->createFunction('count(s.id)'))
$qb->select('s.id', 'f.fileid', 'f.path')
->selectAlias('st.id', 'storage_string_id')
->from('share', 's')
->leftJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'))
->leftJoin('f', 'storages', 'st', $qb->expr()->eq('f.storage', 'st.numeric_id'))
->andWhere($qb->expr()->eq('s.share_type', $qb->createNamedParameter(IShare::TYPE_DECK)))
->andWhere($qb->expr()->eq('s.share_with', $qb->createNamedParameter($cardId)))
->andWhere($qb->expr()->isNull('s.parent'))
@@ -105,16 +109,21 @@ class FilesAppService implements IAttachmentService, ICustomAttachmentService {
$qb->expr()->eq('s.item_type', $qb->createNamedParameter('folder'))
));
$count = 0;
$cursor = $qb->execute();
$count = $cursor->fetchColumn(0);
while ($data = $cursor->fetch()) {
if ($this->shareProvider->isAccessibleResult($data)) {
$count++;
}
}
$cursor->closeCursor();
return $count;
}
public function extendData(Attachment $attachment) {
$userFolder = $this->rootFolder->getUserFolder($this->userId);
$nodes = $userFolder->getById($attachment->getId());
$file = array_shift($nodes);
$share = $this->shareProvider->getShareById($attachment->getId());
$file = $share->getNode();
$attachment->setExtendedData([
'path' => $userFolder->getRelativePath($file->getPath()),
'fileid' => $file->getId(),
@@ -128,10 +137,13 @@ class FilesAppService implements IAttachmentService, ICustomAttachmentService {
}
public function display(Attachment $attachment) {
$userFolder = $this->rootFolder->getUserFolder($this->userId);
$nodes = $userFolder->getById($attachment->getId());
$file = array_shift($nodes);
if ($file === null) {
try {
$share = $this->shareProvider->getShareById($attachment->getId());
} catch (Share\Exceptions\ShareNotFound $e) {
throw new NotFoundException('File not found');
}
$file = $share->getNode();
if ($file === null || $share->getSharedWith() !== (string)$attachment->getCardId()) {
throw new NotFoundException('File not found');
}
if (method_exists($file, 'fopen')) {
@@ -160,7 +172,6 @@ class FilesAppService implements IAttachmentService, ICustomAttachmentService {
$userFolder = $this->rootFolder->getUserFolder($this->userId);
$folder = $userFolder->get($this->configService->getAttachmentFolder());
// FIXME: Add to docs that conflict handling is different here, no ConflictException will be thrown
$fileName = $folder->getNonExistingName($fileName);
$target = $folder->newFile($fileName);
$content = fopen($file['tmp_name'], 'rb');
@@ -178,9 +189,10 @@ class FilesAppService implements IAttachmentService, ICustomAttachmentService {
$share->setSharedWith((string)$attachment->getCardId());
$share->setPermissions(Constants::PERMISSION_READ);
$share->setSharedBy($this->userId);
$this->shareManager->createShare($share);
$attachment->setId($target->getId());
$share = $this->shareManager->createShare($share);
$attachment->setId($share->getId());
$attachment->setData($target->getName());
return $attachment;
}
/**
@@ -214,13 +226,29 @@ class FilesAppService implements IAttachmentService, ICustomAttachmentService {
}
public function update(Attachment $attachment) {
// TODO: Implement update() method.
$share = $this->shareProvider->getShareById($attachment->getId());
$target = $share->getNode();
$file = $this->getUploadedFile();
$fileName = $file['name'];
$attachment->setData($fileName);
$content = fopen($file['tmp_name'], 'rb');
if ($content === false) {
throw new StatusException('Could not read file');
}
$target->putContent($content);
if (is_resource($content)) {
fclose($content);
}
$attachment->setLastModified(time());
return $attachment;
}
public function delete(Attachment $attachment) {
$userFolder = $this->rootFolder->getUserFolder($this->userId);
$nodes = $userFolder->getById($attachment->getId());
$file = array_shift($nodes);
$share = $this->shareProvider->getShareById($attachment->getId());
$file = $share->getNode();
$attachment->setData($file->getName());
if ($file === null) {
throw new NotFoundException('File not found');
}
@@ -230,14 +258,7 @@ class FilesAppService implements IAttachmentService, ICustomAttachmentService {
return;
}
// FIXME: only with manage permissions
$shares = $this->shareProvider->getSharedWithByType($attachment->getCardId(), IShare::TYPE_DECK, -1, 0);
foreach ($shares as $share) {
if ($share->getNode()->getId() === $attachment->getId()) {
$this->shareManager->deleteShare($share);
return;
}
}
$this->shareManager->deleteFromSelf($share, $this->userId);
}
public function allowUndo() {

View File

@@ -810,7 +810,7 @@ class DeckShareProvider implements \OCP\Share\IShareProvider {
return $shares;
}
private function isAccessibleResult(array $data): bool {
public function isAccessibleResult(array $data): bool {
// exclude shares leading to deleted file entries
if ($data['fileid'] === null || $data['path'] === null) {
return false;