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
26 changes: 21 additions & 5 deletions lib/Folder/FolderManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ private function rowToFolder(array $row): FolderDefinition {
* @return list<FolderDefinitionWithPermissions>
* @throws Exception
*/
public function getFoldersForGroups(array $groupIds, ?int $folderId = null): array {
public function getFoldersForGroups(array $groupIds, ?int $folderId = null, ?string $path = null, bool $forChildren = false): array {
if (count($groupIds) === 0) {
return [];
}
Expand All @@ -624,6 +624,14 @@ public function getFoldersForGroups(array $groupIds, ?int $folderId = null): arr
$query->andWhere($query->expr()->eq('f.folder_id', $query->createNamedParameter($folderId, IQueryBuilder::PARAM_INT)));
}

if ($path !== null) {
if ($forChildren) {
$query->andWhere($query->expr()->like('f.mount_point', $query->createNamedParameter($path . '/%')));
} else {
$query->andWhere($query->expr()->eq('f.mount_point', $query->createNamedParameter($path)));
}
}

// add chunking because Oracle can't deal with more than 1000 values in an expression list for in queries.
$result = [];
foreach (array_chunk($groupIds, 1000) as $chunk) {
Expand All @@ -645,7 +653,7 @@ public function getFoldersForGroups(array $groupIds, ?int $folderId = null): arr
* @return list<FolderDefinitionWithPermissions>
* @throws Exception
*/
public function getFoldersFromCircleMemberships(IUser $user, ?int $folderId = null): array {
public function getFoldersFromCircleMemberships(IUser $user, ?int $folderId = null, ?string $path = null, bool $forChildren = false): array {
$circlesManager = $this->getCirclesManager();
if ($circlesManager === null) {
return [];
Expand Down Expand Up @@ -673,6 +681,14 @@ public function getFoldersFromCircleMemberships(IUser $user, ?int $folderId = nu
$query->andWhere($query->expr()->eq('f.folder_id', $query->createNamedParameter($folderId, IQueryBuilder::PARAM_INT)));
}

if ($path !== null) {
if ($forChildren) {
$query->andWhere($query->expr()->like('f.mount_point', $query->createNamedParameter($path . '/%')));
} else {
$query->andWhere($query->expr()->eq('f.mount_point', $query->createNamedParameter($path)));
}
}

/** @psalm-suppress RedundantCondition */
if (method_exists($queryHelper, 'limitToMemberships')) {
$queryHelper->limitToMemberships('a', 'circle_id', $federatedUser);
Expand Down Expand Up @@ -932,12 +948,12 @@ public function setFolderACL(int $folderId, bool $acl): void {
* @return list<FolderDefinitionWithPermissions>
* @throws Exception
*/
public function getFoldersForUser(IUser $user, ?int $folderId = null): array {
public function getFoldersForUser(IUser $user, ?int $folderId = null, ?string $path = null, bool $forChildren = false): array {
$groups = $this->groupManager->getUserGroupIds($user);
/** @var list<FolderDefinitionWithPermissions> $folders */
$folders = array_merge(
$this->getFoldersForGroups($groups, $folderId),
$this->getFoldersFromCircleMemberships($user, $folderId),
$this->getFoldersForGroups($groups, $folderId, $path, $forChildren),
$this->getFoldersFromCircleMemberships($user, $folderId, $path, $forChildren),
);

/** @var array<int, FolderDefinitionWithPermissions> $mergedFolders */
Expand Down
81 changes: 63 additions & 18 deletions lib/Mount/MountProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

namespace OCA\GroupFolders\Mount;

use Exception;
use OC;
use OC\Files\Storage\Wrapper\PermissionsMask;
use OCA\GroupFolders\ACL\ACLManager;
use OCA\GroupFolders\ACL\ACLManagerFactory;
Expand All @@ -19,15 +21,20 @@
use OCP\Files\Cache\ICacheEntry;
use OCP\Files\Config\IMountProvider;
use OCP\Files\Config\IMountProviderCollection;
use OCP\Files\Config\IPartialMountProvider;
use OCP\Files\Config\MountProviderArgs;
use OCP\Files\Mount\IMountPoint;
use OCP\Files\Storage\IStorage;
use OCP\Files\Storage\IStorageFactory;
use OCP\IDBConnection;
use OCP\IRequest;
use OCP\IUser;
use OCP\IUserSession;
use OCP\Server;
use Override;
use PDO;

class MountProvider implements IMountProvider {
class MountProvider implements IMountProvider, IPartialMountProvider {
public function __construct(
private readonly FolderManager $folderManager,
private readonly ACLManagerFactory $aclManagerFactory,
Expand All @@ -41,16 +48,9 @@ public function __construct(
) {
}

/**
* @return list<FolderDefinitionWithPermissions>
*/
public function getFoldersForUser(IUser $user): array {
return $this->folderManager->getFoldersForUser($user);
}

#[\Override]
#[Override]
public function getMountsForUser(IUser $user, IStorageFactory $loader): array {
$folders = $this->getFoldersForUser($user);
$folders = $this->folderManager->getFoldersForUser($user);

$mountPoints = array_map(fn (FolderDefinitionWithPermissions $folder): string => 'files/' . $folder->mountPoint, $folders);
$conflicts = $this->findConflictsForUser($user, $mountPoints);
Expand All @@ -61,7 +61,7 @@ public function getMountsForUser(IUser $user, IStorageFactory $loader): array {
$aclManager = $this->aclManagerFactory->getACLManager($user);
$rootRules = $aclManager->getRulesByFileIds($rootFileIds);

return array_filter(array_map(function (FolderDefinitionWithPermissions $folder) use ($user, $loader, $conflicts, $aclManager, $rootRules): ?IMountPoint {
return array_map(function (FolderDefinitionWithPermissions $folder) use ($user, $loader, $conflicts, $aclManager, $rootRules): IMountPoint {
// check for existing files in the user home and rename them if needed
$originalFolderName = $folder->mountPoint;
if (in_array($originalFolderName, $conflicts)) {
Expand All @@ -88,21 +88,21 @@ public function getMountsForUser(IUser $user, IStorageFactory $loader): array {
$aclManager,
$rootRules[$folder->storageId] ?? [],
);
}, $folders));
}, $folders);
}

private function getCurrentUID(): ?string {
try {
// wopi requests are not logged in, instead we need to get the editor user from the access token
if (str_contains($this->request->getRawPathInfo(), 'apps/richdocuments/wopi') && class_exists('OCA\Richdocuments\Db\WopiMapper')) {
$wopiMapper = \OCP\Server::get('OCA\Richdocuments\Db\WopiMapper');
$wopiMapper = Server::get('OCA\Richdocuments\Db\WopiMapper');
$token = $this->request->getParam('access_token');
if ($token) {
$wopi = $wopiMapper->getPathForToken($token);
return $wopi->getEditorUid();
}
}
} catch (\Exception) {
} catch (Exception) {
}

$user = $this->userSession->getUser();
Expand All @@ -117,7 +117,7 @@ public function getMount(
?IUser $user = null,
?ACLManager $aclManager = null,
array $rootRules = [],
): ?IMountPoint {
): IMountPoint {
$cacheEntry = $folder->rootCacheEntry;

if ($aclManager && $folder->acl && $user) {
Expand Down Expand Up @@ -188,7 +188,7 @@ public function getVersionsMount(
$storage->getScanner()->scan('');
$cacheEntry = $storage->getCache()->get('');
if (!$cacheEntry) {
throw new \Exception('Group folder version root is not in cache even after scanning for folder ' . $folder->id);
throw new Exception('Group folder version root is not in cache even after scanning for folder ' . $folder->id);
}
}
}
Expand Down Expand Up @@ -218,7 +218,7 @@ public function getGroupFolderStorage(
string $type = 'files',
): IStorage {
if ($user) {
$inShare = !\OC::$CLI && ($this->getCurrentUID() === null || $this->getCurrentUID() !== $user->getUID());
$inShare = !OC::$CLI && ($this->getCurrentUID() === null || $this->getCurrentUID() !== $user->getUID());
$baseStorage = $this->folderStorageManager->getBaseStorageForFolder($folder->id, $folder->useSeparateStorage(), $folder, $user, $inShare, $type);
$baseStorage->setOwner($user->getUID());
} else {
Expand Down Expand Up @@ -257,11 +257,56 @@ private function findConflictsForUser(IUser $user, array $mountPoints): array {
$paths = [];
foreach (array_chunk($pathHashes, 1000) as $chunk) {
$query->setParameter('chunk', $chunk, IQueryBuilder::PARAM_STR_ARRAY);
array_push($paths, ...$query->executeQuery()->fetchAll(\PDO::FETCH_COLUMN));
array_push($paths, ...$query->executeQuery()->fetchAll(PDO::FETCH_COLUMN));
}

return array_map(function (string $path): string {
return substr($path, 6); // strip leading "files/"
}, $paths);
}

#[Override]
public function getMountsForPath(string $setupPathHint, bool $forChildren, array $mountProviderArgs, IStorageFactory $loader): array {
/** @var array<string, IMountPoint> $mounts */
$mounts = [];

/** @var array<string, list<FolderDefinitionWithPermissions>> $userFolders */
$userFolders = [];
/** @var array<string, ACLManager> $userAclManagers */
$userAclManagers = [];

/** @var MountProviderArgs $mountProviderArg */
foreach ($mountProviderArgs as $mountProviderArg) {
$user = $mountProviderArg->mountInfo->getUser();

$parts = explode('/', $mountProviderArg->mountInfo->getMountPoint());
if ($parts[2] !== 'files' || $parts[1] !== $user->getUID()) {
continue;
}

$userFolders[$user->getUID()] ??= $this->folderManager->getFoldersForUser($user, null, implode('/', array_splice($parts, 3, -1)), $forChildren);
$folders = $userFolders[$user->getUID()];

foreach ($folders as $folder) {
$mountPoint = '/' . $user->getUID() . '/files/' . $folder->mountPoint;
if (isset($mounts[$mountPoint])) {
continue;
}

$userAclManagers[$user->getUID()] ??= $this->aclManagerFactory->getACLManager($user);
$aclManager = $userAclManagers[$user->getUID()];

$mounts[$mountPoint] = $this->getMount(
$folder,
$mountPoint,
$loader,
$user,
$aclManager,
$folder->acl ? $aclManager->getRulesByFileIds([$folder->rootId]) : [],
);
}
}

return $mounts;
}
}
Loading