Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
be769f4
Add collectives trash backend provider to files_trashbin
mejo- Apr 12, 2023
cecd019
Trash pages instead of deleting them when files_trashbin is enabled
mejo- May 19, 2023
e8978f4
Allow to restore/delete pages from trash via Collectives API
mejo- May 19, 2023
46874d2
Refactor: move node-related functions from PageService to NodeHelper
mejo- May 19, 2023
88042dd
Add behat tests for page trash
mejo- May 19, 2023
a19e0f7
Remove versions along with pages
mejo- May 22, 2023
d8bb2f7
Delete trash and versions when deleting a collective
mejo- May 22, 2023
8b6ac69
Add behat tests for collectives trash over webdav API
mejo- May 23, 2023
cb18b01
Revert subfolders of parent page when deleting from trash
mejo- May 24, 2023
6300d97
Don't grant access to trash of read-only collectives
mejo- May 24, 2023
bcac981
Restore attachments folder along with page if it exists
mejo- May 24, 2023
c089e16
Restore+remove attachments folder from trash along with page
mejo- May 24, 2023
e310a12
Add behat tests for page trash API in public shares
mejo- May 24, 2023
ea037d5
Add fixes detected by psalm
mejo- May 24, 2023
f935a7c
Call notifyPush when trashing a page also without files_trashbin
mejo- May 25, 2023
b894a77
Delete collective leftovers even if collective folder is already gone
mejo- May 25, 2023
235b4aa
Improve exception message when trashed page not found in database
mejo- May 25, 2023
93c8d63
Also return full PageInfo objects for page trash index
mejo- May 27, 2023
14967ef
Fix handling of deleted pages with subpages
mejo- May 30, 2023
d3a46c4
PageTrashCleanup: Different return values for different failure reasons
mejo- Jun 5, 2023
710a616
Code style fixes by php-cs-fixer
mejo- Jun 5, 2023
34b080a
Make sure long filenames are truncated in trashbin
mejo- Jun 5, 2023
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
Prev Previous commit
Next Next commit
Add behat tests for collectives trash over webdav API
Signed-off-by: Jonas <[email protected]>
  • Loading branch information
mejo- committed Jun 5, 2023
commit 8b6ac690886c169b78715d35c55894640a955248
198 changes: 174 additions & 24 deletions tests/Integration/features/bootstrap/FeatureContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -185,19 +185,25 @@ public function userSeesCollective(string $user, string $collective, ?string $tr

/**
* @Then user :user sees pagePath :pagePath in :collective
* @Then user :user :fails to see pagePath :pagePath in :collective
*
* @param string $user
* @param string $pagePath
* @param string $collective
* @param string $user
* @param string $pagePath
* @param string $collective
* @param string|null $fail
*
* @throws GuzzleException
*/
public function userSeesPagePath(string $user, string $pagePath, string $collective): void {
public function userSeesPagePath(string $user, string $pagePath, string $collective, ?string $fail = null): void {
$this->setCurrentUser($user);
$collectiveId = $this->collectiveIdByName($collective);
$this->sendRequest('GET', '/apps/collectives/_api/' . $collectiveId . '/_pages');
$this->assertStatusCode(200);
$this->assertPageByPath($pagePath);
if ($fail === 'fails') {
$this->assertPageByPath($pagePath, true);
} else {
$this->assertPageByPath($pagePath);
}
}

/**
Expand Down Expand Up @@ -756,8 +762,7 @@ public function toggleApp(string $appId, string $status): void {

if ($status === 'enabled') {
$this->sendRequest('POST', '/settings/apps/enable', null, $jsonData);

} elseif ($status === 'disabled') {
} elseif ($status === 'disabled') {
$this->sendRequest('POST', '/settings/apps/disable', null, $jsonData);
} else {
throw new RuntimeException('Unknown app status: ' . $status);
Expand Down Expand Up @@ -1011,6 +1016,20 @@ public function anonymousSeesAttachments(string $name, string $mimetype, string
$this->assertAttachment($name, $mimetype);
}

/**
* @param string $user
*
* @return string
*/
private function getUserCollectivesPath(string $user): string {
// Dirty hack to not break it on local dev setup
$lang = $this->getUserLanguage($user);
if ($lang === 'de') {
return 'Kollektive';
}

return 'Collectives';
}
/**
* @When user :user has webdav access to :collective with permissions :permissions
*
Expand All @@ -1033,15 +1052,9 @@ public function hasWebdavAccess(string $collective, string $user, string $permis
$xProp->appendChild($dom->createElement('oc:permissions'));
$dom->appendChild($xPropfind)->appendChild($xProp);
$body = $dom->saveXML();
$userCollectivesPath = 'Collectives';
$userCollectivesPath = $this->getUserCollectivesPath($user);

// Dirty hack to not break it on local dev setup
$lang = $this->getUserLanguage($user);
if ($lang === 'de') {
$userCollectivesPath = 'Kollektive';
}

$this->sendRemoteRequest('PROPFIND', '/dav/files/' . $user . '/' . $userCollectivesPath . '/' . urlencode($collective) . '/', $body, $headers);
$this->sendRemoteRequest('PROPFIND', '/dav/files/' . $user . '/' . $userCollectivesPath . '/' . urlencode($collective) . '/', $body, null, $headers);
$this->assertStatusCode(207);

// simplexml_load_string() would be better than preg_replace
Expand All @@ -1050,6 +1063,65 @@ public function hasWebdavAccess(string $collective, string $user, string $permis
Assert::assertEquals($permissions, $folderPermissions);
}

/**
* @param string $user
*
* @return array
* @throws GuzzleException
*/
private function listWebdavTrash(string $user): array {
$this->setCurrentUser($user);
$headers = [
'Content-Type' => 'Content-Type: text/xml; charset="utf-8"',
'Depth' => 1,
];
$dom = new \DOMDocument('1.0', 'UTF-8');
$xPropfind = $dom->createElementNS('DAV:', 'D:propfind');
$xProp = $dom->createElement('D:prop');
$xProp->setAttribute('xmlns:nc', 'http://nextcloud.org/ns');
$xProp->appendChild($dom->createElement('nc:trashbin-title'));
$dom->appendChild($xPropfind)->appendChild($xProp);
$body = $dom->saveXML();

$this->sendRemoteRequest('PROPFIND', '/dav/trashbin/' . $user . '/trash/', $body, null, $headers);
$this->assertStatusCode(207);

$xml = simplexml_load_string($this->response->getBody()->getContents());
$entries = [];
$count = 0;
foreach ($xml->xpath('//d:href') as $xmlItem) {
$href = (string)$xmlItem;
$trashbinTitle = (string)$xmlItem->xpath('//nc:trashbin-title')[$count];
$entries[] = [
'href' => $href, 'trashbinTitle' => $trashbinTitle
];
$count++;
}

return $entries;
}

/**
* @param string $collective
* @param string $filePath
* @param string $user
*
* @return string|null
* @throws GuzzleException
*/
private function inWebdavTrash(string $collective, string $filePath, string $user): ?string {
$webdavTrashEntries = $this->listWebdavTrash($user);
$userCollectivesPath = $this->getUserCollectivesPath($user);

foreach ($webdavTrashEntries as $entry) {
if ($entry['trashbinTitle'] === $userCollectivesPath . '/' . urlencode($collective) . '/' . $filePath) {
return $entry['href'];
}
}

return null;
}

/**
* @When user :user uploads attachment :fileName to :page in :collective
*
Expand All @@ -1064,13 +1136,7 @@ public function uploadsAttachment(string $user, string $fileName, string $page,
$this->setCurrentUser($user);
$collectiveId = $this->collectiveIdByName($collective);
$pageId = $this->pageIdByName($collectiveId, $page);
$userCollectivesPath = 'Collectives';

// Dirty hack to not break it on local dev setup
$lang = $this->getUserLanguage($user);
if ($lang === 'de') {
$userCollectivesPath = 'Kollektive';
}
$userCollectivesPath = $this->getUserCollectivesPath($user);

$attachmentsPath = '/dav/files/' . $user . '/' . $userCollectivesPath . '/' . urlencode($collective) . '/' . '.attachments.' . $pageId;

Expand All @@ -1079,6 +1145,90 @@ public function uploadsAttachment(string $user, string $fileName, string $page,
$this->sendRemoteRequest('PUT', $attachmentsPath . '/' . $fileName, $body);
}

/**
* @When user :user trashes page :page via webdav in :collective
* @When user :user :fails to trash page :page via webdav in :collective
*
* @param string $user
* @param string $page
* @param string $collective
* @param string|null $fail
*
* @throws GuzzleException
*/
public function webdavTrashFile(string $user, string $page, string $collective, ?string $fail = null): void {
$this->setCurrentUser($user);
$userCollectivesPath = $this->getUserCollectivesPath($user);

$filePath = '/dav/files/' . $user . '/' . $userCollectivesPath . '/' . urlencode($collective) . '/' . urlencode($page) . '.md';

$this->sendRemoteRequest('DELETE', $filePath);
if ("fails" === $fail) {
$this->assertStatusCode(403);
} else {
$this->assertStatusCode(204);
}
}

/**
* @When user :user restores page :page from trash via webdav in :collective
* @When user :user :fails to restore page :page from trash via webdav in :collective
*
* @param string $user
* @param string $page
* @param string $collective
* @param string|null $fail
*
* @throws GuzzleException
*/
public function webdavRestoreFile(string $user, string $page, string $collective, ?string $fail = null): void {
$this->setCurrentUser($user);

$href = $this->inWebdavTrash($collective, urlencode($page) . '.md', $user);
if ("fails" === $fail) {
Assert::assertNull($href, 'Page found in trash even though not expected: ' . $page);
return;
}
Assert::assertNotNull($href, 'Page not found in trash: ' . $page);

$hrefSplit = explode('/', $href);
$trashFilename = end($hrefSplit);
$filePath = '/dav/trashbin/' . $user . '/trash/' . $trashFilename;

$headers = ['destination' => $this->remoteUrl . '/dav/trashbin/' . $user . '/restore/' . $trashFilename];
$this->sendRemoteRequest('MOVE', $filePath, null, null, $headers);
$this->assertStatusCode(201);
}

/**
* @When user :user deletes page :page from trash via webdav in :collective
* @When user :user :fails to delete page :page from trash via webdav in :collective
*
* @param string $user
* @param string $page
* @param string $collective
* @param string|null $fail
*
* @throws GuzzleException
*/
public function webdavDeleteFile(string $user, string $page, string $collective, ?string $fail = null): void {
$this->setCurrentUser($user);

$href = $this->inWebdavTrash($collective, urlencode($page) . '.md', $user);
if ("fails" === $fail) {
Assert::assertNull($href, 'Page found in trash even though not expected: ' . $page);
return;
}
Assert::assertNotNull($href, 'Page not found in trash: ' . $page);

$hrefSplit = explode('/', $href);
$trashFilename = end($hrefSplit);
$filePath = '/dav/trashbin/' . $user . '/trash/' . $trashFilename;

$this->sendRemoteRequest('DELETE', $filePath);
$this->assertStatusCode(204);
}

/**
* @return array
* @throws JsonException
Expand Down Expand Up @@ -1339,8 +1489,8 @@ private function sendRequestBase(string $verb,
// clear the cached json response
$this->json = null;
try {
if ($verb === 'PROPFIND') {
$this->response = $client->request('PROPFIND', $url, $options);
if ($verb === 'PROPFIND' || $verb === 'MOVE') {
$this->response = $client->request($verb, $url, $options);
} else {
$this->response = $client->{$verb}($url, $options);
}
Expand Down
19 changes: 19 additions & 0 deletions tests/Integration/features/mountpoint.feature
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Feature: mountpoint

Scenario: Set edit and share permissions for collective and check mountpoint permissions
When user "jane" creates collective "BehatMountPoint"
And user "jane" creates page "firstpage" with parentPath "Readme.md" in "BehatMountPoint"
And user "jane" sets "edit" level in collective "BehatMountPoint" to "Admin"
And user "jane" sets "share" level in collective "BehatMountPoint" to "Moderator"
And user "john" joins circle "BehatMountPoint" with owner "jane" with level "Admin"
Expand All @@ -12,6 +13,24 @@ Feature: mountpoint
And user "alice" has webdav access to "BehatMountPoint" with permissions "RMG"
And user "bob" has webdav access to "BehatMountPoint" with permissions "MG"

Scenario: Trash page via webdav
When user "bob" fails to trash page "firstpage" via webdav in "BehatMountPoint"
And user "jane" trashes page "firstpage" via webdav in "BehatMountPoint"
Then user "jane" doesn't see pagePath "firstpage.md" in "BehatMountPoint"

Scenario: Fail to restore+delete page in read-only collective via webdav
Then user "bob" fails to restore page "firstpage" from trash via webdav in "BehatMountPoint"
And user "bob" fails to delete page "firstpage" from trash via webdav in "BehatMountPoint"

Scenario: Restore page via webdav
When user "jane" restores page "firstpage" from trash via webdav in "BehatMountPoint"
Then user "jane" sees pagePath "firstpage.md" in "BehatMountPoint"

Scenario: Trash and delete page via webdav
And user "jane" trashes page "firstpage" via webdav in "BehatMountPoint"
And user "jane" deletes page "firstpage" from trash via webdav in "BehatMountPoint"
Then user "jane" fails to see pagePath "firstpage.md" in "BehatMountPoint"

Scenario: Trash and delete collective and circle
Then user "jane" trashes collective "BehatMountPoint"
And user "jane" deletes collective+circle "BehatMountPoint"