Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/Service/AttachmentService.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ public function count($cardId) {
* @throws BadRequestException
*/
public function create($cardId, $type, $data) {
$this->attachmentServiceValidator->check(compact('cardId', 'type', 'data'));
$this->attachmentServiceValidator->check(compact('cardId', 'type'));

$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT);

Expand Down
30 changes: 26 additions & 4 deletions lib/Service/FilesAppService.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public function getAttachmentCount(int $cardId): int {

public function extendData(Attachment $attachment) {
$userFolder = $this->rootFolder->getUserFolder($this->userId);
$share = $this->shareProvider->getShareById($attachment->getId());
$share = $this->getShareForAttachment($attachment);
$files = $userFolder->getById($share->getNode()->getId());
if (count($files) === 0) {
return $attachment;
Expand All @@ -160,7 +160,7 @@ public function display(Attachment $attachment) {
// Problem: Folders
/** @psalm-suppress InvalidCatch */
try {
$share = $this->shareProvider->getShareById($attachment->getId());
$share = $this->getShareForAttachment($attachment);
} catch (ShareNotFound $e) {
throw new NotFoundException('File not found');
}
Expand Down Expand Up @@ -240,7 +240,7 @@ private function getUploadedFile() {
}

public function update(Attachment $attachment) {
$share = $this->shareProvider->getShareById($attachment->getId());
$share = $this->getShareForAttachment($attachment);
$target = $share->getNode();
$file = $this->getUploadedFile();
$fileName = $file['name'];
Expand All @@ -257,8 +257,13 @@ public function update(Attachment $attachment) {
return $attachment;
}

/**
* @throws NoPermissionException
* @throws NotFoundException
* @throws ShareNotFound
*/
public function delete(Attachment $attachment) {
$share = $this->shareProvider->getShareById($attachment->getId());
$share = $this->getShareForAttachment($attachment);
$file = $share->getNode();
$attachment->setData($file->getName());

Expand All @@ -281,4 +286,21 @@ public function allowUndo() {
public function markAsDeleted(Attachment $attachment) {
throw new \Exception('Not implemented');
}

/**
* @throws NoPermissionException
*/
private function getShareForAttachment(Attachment $attachment): IShare {
try {
$share = $this->shareProvider->getShareById($attachment->getId());
} catch (ShareNotFound $e) {
throw new NoPermissionException('No permission to access the attachment from the card');
}

if ((int)$share->getSharedWith() !== (int)$attachment->getCardId()) {
throw new NoPermissionException('No permission to access the attachment from the card');
}

return $share;
}
}
1 change: 1 addition & 0 deletions tests/integration/config/behat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ default:
- RequestContext
- BoardContext
- CommentContext
- AttachmentContext
- SearchContext
90 changes: 90 additions & 0 deletions tests/integration/features/bootstrap/AttachmentContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

use Behat\Behat\Context\Context;
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
use PHPUnit\Framework\Assert;

require_once __DIR__ . '/../../vendor/autoload.php';

class AttachmentContext implements Context {
use RequestTrait;

/** @var BoardContext */
protected $boardContext;
/** @var ServerContext */
private $serverContext;

protected $lastAttachment = null;
protected $rememberedAttachments = [];

/** @BeforeScenario */
public function gatherContexts(BeforeScenarioScope $scope) {
$environment = $scope->getEnvironment();

$this->boardContext = $environment->getContext('BoardContext');
$this->serverContext = $environment->getContext('ServerContext');
}

public function delete(int $cardId, int $attachmentId) {
$this->requestContext->sendPlainRequest('DELETE', '/index.php/apps/deck/cards/' . $cardId . '/attachment/file:' . $attachmentId);
$response = $this->requestContext->getResponseBodyFromJson();
}

/**
* @When deleting the attachment :attachmentReference for the card :cardReference
*/
public function deletingTheAttachmentForTheCard($attachmentReference, $cardReference) {
$cardId = $this->boardContext->getRememberedCard($cardReference)['id'] ?? null;
$attachmentId = $this->getRememberedAttachment($attachmentReference)['id'] ?? null;
Assert::assertNotNull($cardId, 'Card needs to be available');
Assert::assertNotNull($attachmentId, 'Attachment needs to be available');
$this->delete($cardId, $attachmentId);
}

/**
* @Given /^uploads an attachment to the last used card$/
*/
public function uploadsAnAttachmentToTheLastUsedCard() {
$cardId = $this->boardContext->getLastUsedCard()['id'] ?? null;
Assert::assertNotNull($cardId, 'Card data is not set');

$this->requestContext->sendPlainRequest('POST', '/index.php/apps/deck/cards/' . $cardId . '/attachment', [
'multipart' => [
[
'name' => 'file',
'contents' => 'Example content',
'filename' => 'test.txt',
],
[
'name' => 'type',
'contents' => 'file'
]
]
]);
}

/**
* @Given remember the last attachment as :arg1
*/
public function rememberTheLastAttachmentAs($arg1) {
$this->requestContext->theResponseShouldHaveStatusCode(200);
$this->lastAttachment = $this->requestContext->getResponseBodyFromJson();
$this->rememberedAttachments[$arg1] = $this->lastAttachment;
}

public function getRememberedAttachment($name) {
return $this->rememberedAttachments[$name] ?? null;
}

/**
* @When fetching the attachment :attachmentReference for the card :cardReference
*/
public function fetchingTheAttachmentForTheCard($attachmentReference, $cardReference) {
$cardId = $this->boardContext->getRememberedCard($cardReference)['id'] ?? null;
$attachmentId = $this->getRememberedAttachment($attachmentReference)['id'] ?? null;
Assert::assertNotNull($cardId, 'Card needs to be available');
Assert::assertNotNull($attachmentId, 'Attachment needs to be available');

$this->requestContext->sendPlainRequest('GET', '/index.php/apps/deck/cards/' . $cardId . '/attachment/file:' . $attachmentId);
}
}
21 changes: 21 additions & 0 deletions tests/integration/features/bootstrap/BoardContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class BoardContext implements Context {
private $stack = null;
/** @var array last card response */
private $card = null;
private $storedCards = [];

/** @var ServerContext */
private $serverContext;
Expand All @@ -31,6 +32,15 @@ public function getLastUsedCard() {
return $this->card;
}

/**
* @Given /^creates a board with example content$/
*/
public function createExampleContent() {
$this->createsABoardNamedWithColor('Example board', 'ff0000');
$this->createAStackNamed('ToDo');
$this->createACardNamed('My example card');
}

/**
* @Given /^creates a board named "([^"]*)" with color "([^"]*)"$/
*/
Expand Down Expand Up @@ -232,4 +242,15 @@ public function assignTheTagToTheCard($tag) {
$this->requestContext->sendJSONrequest('POST', '/index.php/apps/deck/cards/' . $this->card['id'] .'/label/' . $label['id']);
$this->requestContext->getResponse()->getBody()->seek(0);
}

/**
* @When remember the last card as :arg1
*/
public function rememberTheLastCardAs($arg1) {
$this->storedCards[$arg1] = $this->getLastUsedCard();
}

public function getRememberedCard($arg1) {
return $this->storedCards[$arg1] ?? null;
}
}
29 changes: 29 additions & 0 deletions tests/integration/features/bootstrap/RequestContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,36 @@ public function sendOCSRequest($method, $url, $data = []) {
}
}

public function sendPlainRequest(string $method, $uri = '', array $options = []) {
$client = new Client;
try {
$this->response = $client->request(
$method,
rtrim($this->serverContext->getBaseUrl(), '/') . '/' . ltrim($uri, '/'),
array_merge(
[
'cookies' => $this->serverContext->getCookieJar(),
'headers' => [
'requesttoken' => $this->serverContext->getReqestToken(),
'OCS-APIREQUEST' => 'true',
'Accept' => 'application/json'
]
],
$options,
)
);
} catch (ClientException $e) {
$this->response = $e->getResponse();
}
}


public function getResponse(): ResponseInterface {
return $this->response;
}

public function getResponseBodyFromJson() {
$this->getResponse()->getBody()->seek(0);
return json_decode((string)$this->getResponse()->getBody(), true);
}
}
1 change: 1 addition & 0 deletions tests/integration/features/bootstrap/ServerContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public function getBaseUrl(): string {
}

public function getCookieJar(): CookieJar {
echo $this->currentUser;
return $this->cookieJar;
}

Expand Down
28 changes: 28 additions & 0 deletions tests/integration/features/sharing.feature
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,31 @@ Feature: File sharing
When Deleting last share
And as "user2" the file "/Deck/user0-file2.txt" does not exist
And as "user3" the file "/Deck/user0-file2.txt" does not exist

Scenario: Remove a share through the deck API
Given acting as user "user0"
When creates a board with example content
And remember the last card as "user0-card"
And uploads an attachment to the last used card
And remember the last attachment as "user0-attachment"

Given acting as user "user1"
When creates a board with example content
And remember the last card as "user1-card"
And uploads an attachment to the last used card
And remember the last attachment as "user1-attachment"

Given acting as user "user0"
When fetching the attachment "user1-attachment" for the card "user0-card"
Then the response should have a status code 403
When deleting the attachment "user1-attachment" for the card "user0-card"
Then the response should have a status code 403

When fetching the attachment "user0-attachment" for the card "user0-card"
Then the response should have a status code 200
When deleting the attachment "user0-attachment" for the card "user0-card"
Then the response should have a status code 200

Given acting as user "user1"
When deleting the attachment "user1-attachment" for the card "user1-card"
Then the response should have a status code 200