*/ 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 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 * @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 \Generator */ public function getAllShares(): \Generator { $qb = $this->db->getQueryBuilder(); $qb->select('*') ->from(self::TABLE_NAME); return $this->yieldEntities($qb); } /** * 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 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); } public function deleteAll(): void { $qb = $this->db->getQueryBuilder(); $qb->delete('share_external') ->executeStatement(); } #[Override] public function delete(Entity $entity): ExternalShare { /** @var ExternalShare $share */ $share = $entity; $qb = $this->db->getQueryBuilder(); $qb->delete(self::TABLE_NAME) // delete the share itself ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) // delete all child in case of a group share ->orWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId()))) ->executeStatement(); return $share; } public function getShareByRemoteIdAndToken(string $id, mixed $token): ?ExternalShare { $qb = $this->db->getQueryBuilder(); $qb->select('*') ->from(self::TABLE_NAME) ->where( $qb->expr()->andX( $qb->expr()->eq('remote_id', $qb->createNamedParameter($id)), $qb->expr()->eq('share_token', $qb->createNamedParameter($token)) ) ); try { return $this->findEntity($qb); } catch (Exception) { return null; } } }