Merge pull request #57285 from nextcloud/feature/54562/support-partial-share-providers

feat: introduce API for partial share providers
pull/46957/merge
Andy Scherzinger 4 days ago committed by GitHub
commit d40263b2aa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      lib/composer/composer/autoload_classmap.php
  2. 1
      lib/composer/composer/autoload_static.php
  3. 110
      lib/private/Share20/DefaultShareProvider.php
  4. 39
      lib/private/Share20/Manager.php
  5. 12
      lib/public/Share/IManager.php
  6. 31
      lib/public/Share/IPartialShareProvider.php

@ -817,6 +817,7 @@ return array(
'OCP\\Share\\Exceptions\\ShareTokenException' => $baseDir . '/lib/public/Share/Exceptions/ShareTokenException.php',
'OCP\\Share\\IAttributes' => $baseDir . '/lib/public/Share/IAttributes.php',
'OCP\\Share\\IManager' => $baseDir . '/lib/public/Share/IManager.php',
'OCP\\Share\\IPartialShareProvider' => $baseDir . '/lib/public/Share/IPartialShareProvider.php',
'OCP\\Share\\IProviderFactory' => $baseDir . '/lib/public/Share/IProviderFactory.php',
'OCP\\Share\\IPublicShareTemplateFactory' => $baseDir . '/lib/public/Share/IPublicShareTemplateFactory.php',
'OCP\\Share\\IPublicShareTemplateProvider' => $baseDir . '/lib/public/Share/IPublicShareTemplateProvider.php',

@ -858,6 +858,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Share\\Exceptions\\ShareTokenException' => __DIR__ . '/../../..' . '/lib/public/Share/Exceptions/ShareTokenException.php',
'OCP\\Share\\IAttributes' => __DIR__ . '/../../..' . '/lib/public/Share/IAttributes.php',
'OCP\\Share\\IManager' => __DIR__ . '/../../..' . '/lib/public/Share/IManager.php',
'OCP\\Share\\IPartialShareProvider' => __DIR__ . '/../../..' . '/lib/public/Share/IPartialShareProvider.php',
'OCP\\Share\\IProviderFactory' => __DIR__ . '/../../..' . '/lib/public/Share/IProviderFactory.php',
'OCP\\Share\\IPublicShareTemplateFactory' => __DIR__ . '/../../..' . '/lib/public/Share/IPublicShareTemplateFactory.php',
'OCP\\Share\\IPublicShareTemplateProvider' => __DIR__ . '/../../..' . '/lib/public/Share/IPublicShareTemplateProvider.php',

@ -32,6 +32,7 @@ use OCP\Mail\IMailer;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IAttributes;
use OCP\Share\IManager;
use OCP\Share\IPartialShareProvider;
use OCP\Share\IShare;
use OCP\Share\IShareProviderGetUsers;
use OCP\Share\IShareProviderSupportsAccept;
@ -49,7 +50,8 @@ class DefaultShareProvider implements
IShareProviderWithNotification,
IShareProviderSupportsAccept,
IShareProviderSupportsAllSharesInFolder,
IShareProviderGetUsers {
IShareProviderGetUsers,
IPartialShareProvider {
public function __construct(
private IDBConnection $dbConn,
private IUserManager $userManager,
@ -953,6 +955,112 @@ class DefaultShareProvider implements
return $shares;
}
/**
* @inheritDoc
*/
public function getSharedWithByPath(
string $userId,
int $shareType,
string $path,
bool $forChildren,
int $limit,
int $offset,
): iterable {
$shares = [];
if ($shareType === IShare::TYPE_USER) {
//Get shares directly with this user
$qb = $this->dbConn->getQueryBuilder();
$qb->select('s.*',
'f.fileid', 'f.path', 'f.permissions AS f_permissions', 'f.storage', 'f.path_hash',
'f.parent AS f_parent', 'f.name', 'f.mimetype', 'f.mimepart', 'f.size', 'f.mtime', 'f.storage_mtime',
'f.encrypted', 'f.unencrypted_size', 'f.etag', 'f.checksum'
)
->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'));
// Order by id
$qb->orderBy('s.id');
// Set limit and offset
if ($limit !== -1) {
$qb->setMaxResults($limit);
}
$qb->setFirstResult($offset);
$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_USER)))
->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)))
->andWhere($qb->expr()->in('item_type', $qb->createNamedParameter(['file', 'folder'], IQueryBuilder::PARAM_STR_ARRAY)));
if ($forChildren) {
$qb->andWhere($qb->expr()->like('file_target', $qb->createNamedParameter($this->dbConn->escapeLikeParameter($path) . '_%')));
} else {
$qb->andWhere($qb->expr()->eq('file_target', $qb->createNamedParameter($path)));
}
$cursor = $qb->executeQuery();
while ($data = $cursor->fetch()) {
if ($data['fileid'] && $data['path'] === null) {
$data['path'] = (string)$data['path'];
$data['name'] = (string)$data['name'];
$data['checksum'] = (string)$data['checksum'];
}
if ($this->isAccessibleResult($data)) {
$shares[] = $this->createShare($data);
}
}
$cursor->closeCursor();
} elseif ($shareType === IShare::TYPE_GROUP) {
// get the parent share info (s) along with the child one (s2)
$qb = $this->dbConn->getQueryBuilder();
$qb->select('s.*', 's2.permissions AS s2_permissions', 's2.accepted AS s2_accepted', 's2.file_target AS s2_file_target', 's2.parent AS s2_parent',
'f.fileid', 'f.path', 'f.permissions AS f_permissions', 'f.storage', 'f.path_hash',
'f.parent AS f_parent', 'f.name', 'f.mimetype', 'f.mimepart', 'f.size', 'f.mtime', 'f.storage_mtime',
'f.encrypted', 'f.unencrypted_size', 'f.etag', 'f.checksum'
)
->selectAlias('st.id', 'storage_string_id')
->from('share', 's2')
->leftJoin('s2', 'filecache', 'f', $qb->expr()->eq('s2.file_source', 'f.fileid'))
->leftJoin('f', 'storages', 'st', $qb->expr()->eq('f.storage', 'st.numeric_id'))
->leftJoin('s2', 'share', 's', $qb->expr()->eq('s2.parent', 's.id'))
->where($qb->expr()->eq('s2.share_with', $qb->createNamedParameter($userId)))
->andWhere($qb->expr()->eq('s2.share_type', $qb->createNamedParameter(IShare::TYPE_USERGROUP)))
->andWhere($qb->expr()->in('s2.item_type', $qb->createNamedParameter(['file', 'folder'], IQueryBuilder::PARAM_STR_ARRAY)))
->orderBy('s2.id')
->setFirstResult($offset);
if ($limit !== -1) {
$qb->setMaxResults($limit);
}
if ($forChildren) {
$qb->andWhere($qb->expr()->like('s2.file_target', $qb->createNamedParameter($this->dbConn->escapeLikeParameter($path) . '_%')));
} else {
$qb->andWhere($qb->expr()->eq('s2.file_target', $qb->createNamedParameter($path)));
}
$cursor = $qb->executeQuery();
while ($data = $cursor->fetch()) {
if ($this->isAccessibleResult($data)) {
$share = $this->createShare($data);
// patch the parent data with the user-specific changes
$share->setPermissions((int)$data['s2_permissions']);
$share->setStatus((int)$data['s2_accepted']);
$share->setTarget($data['s2_file_target']);
$share->setParent($data['s2_parent']);
$shares[] = $share;
}
}
$cursor->closeCursor();
} else {
throw new BackendError('Invalid backend');
}
return $shares;
}
/**
* Get a share by token
*

@ -7,6 +7,7 @@
*/
namespace OC\Share20;
use ArrayIterator;
use OC\Core\AppInfo\ConfigLexicon;
use OC\Files\Mount\MoveableMount;
use OC\KnownUser\KnownUserService;
@ -49,6 +50,7 @@ use OCP\Share\Exceptions\GenericShareException;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\Exceptions\ShareTokenException;
use OCP\Share\IManager;
use OCP\Share\IPartialShareProvider;
use OCP\Share\IProviderFactory;
use OCP\Share\IShare;
use OCP\Share\IShareProvider;
@ -1283,6 +1285,43 @@ class Manager implements IManager {
return $shares;
}
/**
* @inheritDoc
*/
public function getSharedWithByPath(string $userId, int $shareType, string $path, bool $forChildren, int $limit = 50, int $offset = 0): iterable {
try {
$provider = $this->factory->getProviderForType($shareType);
} catch (ProviderException $e) {
return [];
}
if (!$provider instanceof IPartialShareProvider) {
throw new \RuntimeException(\get_class($provider) . ' must implement IPartialShareProvider');
}
$shares = $provider->getSharedWithByPath($userId,
$shareType,
$path,
$forChildren,
$limit,
$offset
);
if (\is_array($shares)) {
$shares = new ArrayIterator($shares);
}
return new \CallbackFilterIterator($shares, function (IShare $share) {
// remove all shares which are already expired
try {
$this->checkShare($share);
return true;
} catch (ShareNotFound $e) {
return false;
}
});
}
#[Override]
public function getDeletedSharedWith(string $userId, int $shareType, ?Node $node = null, int $limit = 50, int $offset = 0): array {
$shares = $this->getSharedWith($userId, $shareType, $node, $limit, $offset);

@ -134,6 +134,18 @@ interface IManager {
*/
public function getSharedWith(string $userId, int $shareType, ?Node $node = null, int $limit = 50, int $offset = 0): array;
/**
* Get shares shared with a $user filtering by $path.
*
* @param IShare::TYPE_* $shareType
* @param bool $forChildren if true, results should only include children of $path
* @param int $limit The maximum number of shares returned, -1 for all
*
* @return iterable<IShare>
* @since 33.0.0
*/
public function getSharedWithByPath(string $userId, int $shareType, string $path, bool $forChildren, int $limit = 50, int $offset = 0): iterable;
/**
* Get deleted shares shared with $user.
* Filter by $node if provided

@ -0,0 +1,31 @@
<?php
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCP\Share;
/**
* Interface IPartialShareProvider
*
* @since 33.0.0
*/
interface IPartialShareProvider extends IShareProvider {
/**
* Get shares received by the given user and filtered by path.
*
* If $forChildren is true, results should only include children of $path
*
* @return iterable<IShare>
* @since 33.0.0
*/
public function getSharedWithByPath(
string $userId,
int $shareType,
string $path,
bool $forChildren,
int $limit,
int $offset,
): iterable;
}
Loading…
Cancel
Save