You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
nextcloud-server/apps/files_sharing/lib/External/ExternalShareMapper.php

204 lines
5.9 KiB

<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH
* SPDX-FileContributor: Carl Schwan
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Files_Sharing\External;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\Exception;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
use OCP\IGroup;
use OCP\IGroupManager;
use OCP\IUser;
use OCP\Share\IShare;
/**
* @template-extends QBMapper<ExternalShare>
*/
class ExternalShareMapper extends QBMapper {
private const TABLE_NAME = 'share_external';
public function __construct(
IDBConnection $db,
private readonly IGroupManager $groupManager,
) {
parent::__construct($db, self::TABLE_NAME);
}
/**
* @throws DoesNotExistException
*/
public function getById(string $id): ExternalShare {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from(self::TABLE_NAME)
->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
->setMaxResults(1);
return $this->findEntity($qb);
}
/**
* Get share by token.
*
* @throws DoesNotExistException
*/
public function getShareByToken(string $token): ExternalShare {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from(self::TABLE_NAME)
->where($qb->expr()->eq('share_token', $qb->createNamedParameter($token, IQueryBuilder::PARAM_STR)))
->setMaxResults(1);
return $this->findEntity($qb);
}
/**
* Get share by parent id and user.
*
* @throws DoesNotExistException
*/
public function getUserShare(ExternalShare $parentShare, IUser $user): ExternalShare {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from(self::TABLE_NAME)
->where($qb->expr()->andX(
$qb->expr()->eq('parent', $qb->createNamedParameter($parentShare->getId())),
$qb->expr()->eq('user', $qb->createNamedParameter($user->getUID(), IQueryBuilder::PARAM_STR)),
));
return $this->findEntity($qb);
}
public function get() {
}
public function getByMountPointAndUser(string $mountPoint, IUser $user) {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from(self::TABLE_NAME)
->where($qb->expr()->andX(
$qb->expr()->eq('mountpoint_hash', $qb->createNamedParameter(md5($mountPoint))),
$qb->expr()->eq('user', $qb->createNamedParameter($user->getUID(), IQueryBuilder::PARAM_STR)),
));
return $this->findEntity($qb);
}
/**
* @return \Generator<ExternalShare>
* @throws Exception
*/
public function getUserShares(IUser $user): \Generator {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from(self::TABLE_NAME)
->where($qb->expr()->eq('user', $qb->createNamedParameter($user->getUID(), IQueryBuilder::PARAM_STR)))
->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_USER, IQueryBuilder::PARAM_INT)));
return $this->yieldEntities($qb);
}
public function deleteUserShares(IUser $user): void {
$qb = $this->db->getQueryBuilder();
$qb->delete(self::TABLE_NAME)
// user field can specify a user or a group
->where($qb->expr()->eq('user', $qb->createNamedParameter($user->getUID())))
->andWhere(
$qb->expr()->orX(
// delete direct shares
$qb->expr()->eq('share_type', $qb->expr()->literal(IShare::TYPE_USER)),
// delete sub-shares of group shares for that user
$qb->expr()->andX(
$qb->expr()->eq('share_type', $qb->expr()->literal(IShare::TYPE_GROUP)),
$qb->expr()->neq('parent', $qb->expr()->literal(-1)),
)
)
);
$qb->executeStatement();
}
/**
* @throws Exception
*/
public function deleteGroupShares(IGroup $group): void {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from(self::TABLE_NAME)
->where($qb->expr()->eq('user', $qb->createNamedParameter($group->getGID())))
->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_GROUP)));
$this->yieldEntities($qb);
$delete = $this->db->getQueryBuilder();
$delete->delete(self::TABLE_NAME)
->where(
$qb->expr()->orX(
$qb->expr()->eq('id', $qb->createParameter('share_id')),
$qb->expr()->eq('parent', $qb->createParameter('share_parent_id'))
)
);
foreach ($this->yieldEntities($qb) as $share) {
$delete->setParameter('share_id', $share->getId());
$delete->setParameter('share_parent_id', $share->getId());
$delete->executeStatement();
}
}
/**
* Return a list of shares for the user.
*
* @psalm-param IShare::STATUS_PENDING|IShare::STATUS_ACCEPTED|null $status Filter share by their status or return all shares of the user if null.
* @return list<ExternalShare> list of open server-to-server shares
* @throws Exception
*/
public function getShares(IUser $user, ?int $status): array {
// Not allowing providing a user here,
// as we only want to retrieve shares for the current user.
$groups = $this->groupManager->getUserGroups($user);
$userGroups = [];
foreach ($groups as $group) {
$userGroups[] = $group->getGID();
}
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from('share_external')
->where(
$qb->expr()->orX(
$qb->expr()->eq('user', $qb->createNamedParameter($user->getUID())),
$qb->expr()->in(
'user',
$qb->createNamedParameter($userGroups, IQueryBuilder::PARAM_STR_ARRAY)
)
)
)
->orderBy('id', 'ASC');
$shares = $this->findEntities($qb);
// remove parent group share entry if we have a specific user share entry for the user
$toRemove = [];
foreach ($shares as $share) {
if ($share->getShareType() === IShare::TYPE_GROUP && $share->getParent() !== '-1') {
$toRemove[] = $share->getParent();
}
}
$shares = array_filter($shares, function (ExternalShare $share) use ($toRemove): bool {
return !in_array($share->getId(), $toRemove, true);
});
if (!is_null($status)) {
$shares = array_filter($shares, function (ExternalShare $share) use ($status): bool {
return $share->getAccepted() === $status;
});
}
return array_values($shares);
}
}