diff --git a/appinfo/info.xml b/appinfo/info.xml
index 948742af0..c3c575022 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -13,7 +13,7 @@ Folders can be configured from *Group folders* in the admin settings.
After a folder is created, the admin can give access to the folder to one or more groups, control their write/sharing permissions and assign a quota for the folder.
]]>
- 19.0.0-dev.2
+ 19.0.0-dev.3
agpl
Robin Appelman
GroupFolders
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index e95ac03cf..d0b793b96 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -54,6 +54,7 @@
use OCP\IGroupManager;
use OCP\IRequest;
use OCP\ISession;
+use OCP\IUserManager;
use OCP\IUserSession;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
@@ -126,7 +127,9 @@ public function register(IRegistrationContext $context): void {
$c->get(MountProvider::class),
$c->get(ACLManagerFactory::class),
$c->get(IRootFolder::class),
- $c->get(LoggerInterface::class)
+ $c->get(LoggerInterface::class),
+ $c->get(IUserManager::class),
+ $c->get(IUserSession::class),
);
$hasVersionApp = interface_exists(\OCA\Files_Versions\Versions\IVersionBackend::class);
if ($hasVersionApp) {
diff --git a/lib/Migration/Version300000Date20240905185515.php b/lib/Migration/Version300000Date20240905185515.php
new file mode 100644
index 000000000..029a39ea6
--- /dev/null
+++ b/lib/Migration/Version300000Date20240905185515.php
@@ -0,0 +1,47 @@
+hasTable('group_folders_trash')) {
+ return null;
+ }
+
+ $table = $schema->getTable('group_folders_trash');
+
+ if ($table->hasColumn('deleted_by')) {
+ return null;
+ }
+
+ $table->addColumn('deleted_by', Types::STRING, [
+ 'notnull' => false,
+ 'length' => 64,
+ ]);
+
+ return $schema;
+ }
+}
diff --git a/lib/Trash/GroupTrashItem.php b/lib/Trash/GroupTrashItem.php
index f19e4695c..7371f0487 100644
--- a/lib/Trash/GroupTrashItem.php
+++ b/lib/Trash/GroupTrashItem.php
@@ -22,9 +22,10 @@ public function __construct(
string $trashPath,
FileInfo $fileInfo,
IUser $user,
- string $mountPoint
+ string $mountPoint,
+ private ?IUser $deletedBy,
) {
- parent::__construct($backend, $originalLocation, $deletedTime, $trashPath, $fileInfo, $user, null);
+ parent::__construct($backend, $originalLocation, $deletedTime, $trashPath, $fileInfo, $user, $deletedBy);
$this->mountPoint = $mountPoint;
}
diff --git a/lib/Trash/TrashBackend.php b/lib/Trash/TrashBackend.php
index 69548ac41..be338d6d5 100644
--- a/lib/Trash/TrashBackend.php
+++ b/lib/Trash/TrashBackend.php
@@ -24,35 +24,25 @@
use OCP\Files\NotPermittedException;
use OCP\Files\Storage\IStorage;
use OCP\IUser;
+use OCP\IUserManager;
+use OCP\IUserSession;
use Psr\Log\LoggerInterface;
class TrashBackend implements ITrashBackend {
- private FolderManager $folderManager;
- private TrashManager $trashManager;
- private Folder $appFolder;
- private MountProvider $mountProvider;
- private ACLManagerFactory $aclManagerFactory;
/** @var ?VersionsBackend */
private $versionsBackend = null;
- private IRootFolder $rootFolder;
- private LoggerInterface $logger;
public function __construct(
- FolderManager $folderManager,
- TrashManager $trashManager,
- Folder $appFolder,
- MountProvider $mountProvider,
- ACLManagerFactory $aclManagerFactory,
- IRootFolder $rootFolder,
- LoggerInterface $logger
+ private FolderManager $folderManager,
+ private TrashManager $trashManager,
+ private Folder $appFolder,
+ private MountProvider $mountProvider,
+ private ACLManagerFactory $aclManagerFactory,
+ private IRootFolder $rootFolder,
+ private LoggerInterface $logger,
+ private IUserManager $userManager,
+ private IUserSession $userSession,
) {
- $this->folderManager = $folderManager;
- $this->trashManager = $trashManager;
- $this->appFolder = $appFolder;
- $this->mountProvider = $mountProvider;
- $this->aclManagerFactory = $aclManagerFactory;
- $this->rootFolder = $rootFolder;
- $this->logger = $logger;
}
public function setVersionsBackend(VersionsBackend $versionsBackend): void {
@@ -92,7 +82,8 @@ public function listTrashFolder(ITrashItem $folder): array {
$folder->getTrashPath() . '/' . $node->getName(),
$node,
$user,
- $folder->getGroupFolderMountPoint()
+ $folder->getGroupFolderMountPoint(),
+ $folder->getDeletedBy(),
);
}, $content)));
}
@@ -212,7 +203,7 @@ public function moveToTrash(IStorage $storage, string $internalPath): bool {
[$unJailedStorage, $unJailedInternalPath] = $this->unwrapJails($storage, $internalPath);
$targetInternalPath = $trashFolder->getInternalPath() . '/' . $trashName;
if ($trashStorage->moveFromStorage($unJailedStorage, $unJailedInternalPath, $targetInternalPath)) {
- $this->trashManager->addTrashItem($folderId, $name, $time, $internalPath, $fileEntry->getId());
+ $this->trashManager->addTrashItem($folderId, $name, $time, $internalPath, $fileEntry->getId(), $this->userSession->getUser()->getUID());
if ($trashStorage->getCache()->getId($targetInternalPath) !== $fileEntry->getId()) {
$trashStorage->getCache()->moveFromCache($unJailedStorage->getCache(), $unJailedInternalPath, $targetInternalPath);
}
@@ -328,6 +319,7 @@ private function getTrashForFolders(IUser $user, array $folders): array {
$key = $folderId . '/' . $name . '/' . $timestamp;
$originalLocation = isset($indexedRows[$key]) ? $indexedRows[$key]['original_location'] : '';
+ $deletedBy = isset($indexedRows[$key]) ? $indexedRows[$key]['deleted_by'] : '';
if ($folderHasAcl) {
// if we for any reason lost track of the original location, hide the item for non-managers as a fail-safe
@@ -357,7 +349,8 @@ private function getTrashForFolders(IUser $user, array $folders): array {
'/' . $folderId . '/' . $item->getName(),
$info,
$user,
- $mountPoint
+ $mountPoint,
+ $this->userManager->get($deletedBy),
);
}
}
diff --git a/lib/Trash/TrashManager.php b/lib/Trash/TrashManager.php
index 885498b4b..b44834387 100644
--- a/lib/Trash/TrashManager.php
+++ b/lib/Trash/TrashManager.php
@@ -22,14 +22,14 @@ public function __construct(
*/
public function listTrashForFolders(array $folderIds): array {
$query = $this->connection->getQueryBuilder();
- $query->select(['trash_id', 'name', 'deleted_time', 'original_location', 'folder_id', 'file_id'])
+ $query->select(['trash_id', 'name', 'deleted_time', 'original_location', 'folder_id', 'file_id', 'deleted_by'])
->from('group_folders_trash')
->orderBy('deleted_time')
->where($query->expr()->in('folder_id', $query->createNamedParameter($folderIds, IQueryBuilder::PARAM_INT_ARRAY)));
return $query->executeQuery()->fetchAll();
}
- public function addTrashItem(int $folderId, string $name, int $deletedTime, string $originalLocation, int $fileId): void {
+ public function addTrashItem(int $folderId, string $name, int $deletedTime, string $originalLocation, int $fileId, string $deletedBy): void {
$query = $this->connection->getQueryBuilder();
$query->insert('group_folders_trash')
->values([
@@ -37,14 +37,15 @@ public function addTrashItem(int $folderId, string $name, int $deletedTime, stri
'name' => $query->createNamedParameter($name),
'deleted_time' => $query->createNamedParameter($deletedTime, IQueryBuilder::PARAM_INT),
'original_location' => $query->createNamedParameter($originalLocation),
- 'file_id' => $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)
+ 'file_id' => $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT),
+ 'deleted_by' => $query->createNamedParameter($deletedBy),
]);
$query->executeStatement();
}
public function getTrashItemByFileId(int $fileId): ?array {
$query = $this->connection->getQueryBuilder();
- $query->select(['trash_id', 'name', 'deleted_time', 'original_location', 'folder_id'])
+ $query->select(['trash_id', 'name', 'deleted_time', 'original_location', 'folder_id', 'deleted_by'])
->from('group_folders_trash')
->where($query->expr()->eq('file_id', $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
return $query->executeQuery()->fetch() ?: null;
@@ -52,7 +53,7 @@ public function getTrashItemByFileId(int $fileId): ?array {
public function getTrashItemByFileName(int $folderId, string $name, int $deletedTime): ?array {
$query = $this->connection->getQueryBuilder();
- $query->select(['trash_id', 'name', 'deleted_time', 'original_location', 'folder_id'])
+ $query->select(['trash_id', 'name', 'deleted_time', 'original_location', 'folder_id', 'deleted_by'])
->from('group_folders_trash')
->where($query->expr()->eq('folder_id', $query->createNamedParameter($folderId, IQueryBuilder::PARAM_INT)))
->andWhere($query->expr()->eq('name', $query->createNamedParameter($name)))
diff --git a/tests/Trash/TrashBackendTest.php b/tests/Trash/TrashBackendTest.php
index 0bed10a63..addaa2062 100644
--- a/tests/Trash/TrashBackendTest.php
+++ b/tests/Trash/TrashBackendTest.php
@@ -106,6 +106,8 @@ private function createNoReadRule(string $userId, int $fileId): Rule {
}
public function testHideTrashItemAcl() {
+ $this->loginAsUser('manager');
+
$restricted = $this->managerUserFolder->newFile("{$this->folderName}/restricted.txt", "content");
$this->ruleManager->saveRule($this->createNoReadRule("normal", $restricted->getId()));
@@ -120,9 +122,13 @@ public function testHideTrashItemAcl() {
// only the manager can see the deleted file
$this->assertCount(1, $this->trashBackend->listTrashRoot($this->managerUser));
$this->assertCount(0, $this->trashBackend->listTrashRoot($this->normalUser));
+
+ $this->logout();
}
public function testHideItemInDeletedFolderAcl() {
+ $this->loginAsUser('manager');
+
$folder = $this->managerUserFolder->newFolder("{$this->folderName}/folder");
$folder->newFile("file.txt", "content1");
$restrictedChild = $folder->newFile("restricted.txt", "content2");
@@ -145,9 +151,13 @@ public function testHideItemInDeletedFolderAcl() {
// only the manager can see the restricted child, both can see the un-restricted child
$this->assertCount(2, $this->trashBackend->listTrashFolder($managerTrashFolder));
$this->assertCount(1, $this->trashBackend->listTrashFolder($normalTrashFolder));
+
+ $this->logout();
}
public function testHideDeletedTrashItemInDeletedFolderAcl() {
+ $this->loginAsUser('manager');
+
$folder = $this->managerUserFolder->newFolder("{$this->folderName}/restricted");
$child = $folder->newFile("file.txt", "content1");
$this->ruleManager->saveRule($this->createNoReadRule("normal", $folder->getId()));
@@ -169,9 +179,13 @@ public function testHideDeletedTrashItemInDeletedFolderAcl() {
// only the manager can see the deleted items
$this->assertCount(2, $this->trashBackend->listTrashRoot($this->managerUser));
$this->assertCount(0, $this->trashBackend->listTrashRoot($this->normalUser));
+
+ $this->logout();
}
public function testHideDeletedTrashItemInDeletedParentFolderAcl() {
+ $this->loginAsUser('manager');
+
$parent = $this->managerUserFolder->newFolder("{$this->folderName}/parent");
$folder = $parent->newFolder("restricted");
$child = $folder->newFile("file.txt", "content1");
@@ -194,5 +208,7 @@ public function testHideDeletedTrashItemInDeletedParentFolderAcl() {
// only the manager can see the deleted child, both can see the deleted parent
$this->assertCount(2, $this->trashBackend->listTrashRoot($this->managerUser));
$this->assertCount(1, $this->trashBackend->listTrashRoot($this->normalUser));
+
+ $this->logout();
}
}