mirror of https://github.com/nextcloud/server.git
enh(sharing): enable unsharing for sharees for DAV shares (addressbooks and calendars)
Signed-off-by: Anna Larch <anna@nextcloud.com>pull/43117/head
parent
1f0cba5f99
commit
dce69154ba
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright 2024 Anna Larch <anna.larch@gmx.net>
|
||||
*
|
||||
* @author Anna Larch <anna.larch@gmx.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OCA\DAV\CalDAV\Sharing;
|
||||
|
||||
use OCA\DAV\Connector\Sabre\Principal;
|
||||
use OCA\DAV\DAV\Sharing\Backend as SharingBackend;
|
||||
use OCP\ICacheFactory;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IUserManager;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Backend extends SharingBackend {
|
||||
|
||||
public function __construct(private IUserManager $userManager,
|
||||
private IGroupManager $groupManager,
|
||||
private Principal $principalBackend,
|
||||
private ICacheFactory $cacheFactory,
|
||||
private Service $service,
|
||||
private LoggerInterface $logger,
|
||||
) {
|
||||
parent::__construct($this->userManager, $this->groupManager, $this->principalBackend, $this->cacheFactory, $this->service, $this->logger);
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright 2024 Anna Larch <anna.larch@gmx.net>
|
||||
*
|
||||
* @author Anna Larch <anna.larch@gmx.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OCA\DAV\CalDAV\Sharing;
|
||||
|
||||
use OCA\DAV\DAV\Sharing\SharingMapper;
|
||||
use OCA\DAV\DAV\Sharing\SharingService;
|
||||
|
||||
class Service extends SharingService {
|
||||
protected string $resourceType = 'calendar';
|
||||
public function __construct(protected SharingMapper $mapper) {
|
||||
parent::__construct($mapper);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright 2024 Anna Larch <anna.larch@gmx.net>
|
||||
*
|
||||
* @author Anna Larch <anna.larch@gmx.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OCA\DAV\CardDAV\Sharing;
|
||||
|
||||
use OCA\DAV\Connector\Sabre\Principal;
|
||||
use OCA\DAV\DAV\Sharing\Backend as SharingBackend;
|
||||
use OCP\ICacheFactory;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IUserManager;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Backend extends SharingBackend {
|
||||
public function __construct(private IUserManager $userManager,
|
||||
private IGroupManager $groupManager,
|
||||
private Principal $principalBackend,
|
||||
private ICacheFactory $cacheFactory,
|
||||
private Service $service,
|
||||
private LoggerInterface $logger,
|
||||
) {
|
||||
parent::__construct($this->userManager, $this->groupManager, $this->principalBackend, $this->cacheFactory, $this->service, $this->logger);
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright 2024 Anna Larch <anna.larch@gmx.net>
|
||||
*
|
||||
* @author Anna Larch <anna.larch@gmx.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OCA\DAV\CardDAV\Sharing;
|
||||
|
||||
use OCA\DAV\DAV\Sharing\SharingMapper;
|
||||
use OCA\DAV\DAV\Sharing\SharingService;
|
||||
|
||||
class Service extends SharingService {
|
||||
protected string $resourceType = 'addressbook';
|
||||
public function __construct(protected SharingMapper $mapper) {
|
||||
parent::__construct($mapper);
|
||||
}
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/*
|
||||
* @copyright 2024 Anna Larch <anna.larch@gmx.net>
|
||||
*
|
||||
* @author Anna Larch <anna.larch@gmx.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OCA\DAV\DAV\Sharing;
|
||||
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
|
||||
class SharingMapper {
|
||||
public function __construct(private IDBConnection $db) {
|
||||
}
|
||||
|
||||
public function getSharesForId(int $resourceId, string $resourceType): array {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$result = $query->select(['principaluri', 'access'])
|
||||
->from('dav_shares')
|
||||
->where($query->expr()->eq('resourceid', $query->createNamedParameter($resourceId, IQueryBuilder::PARAM_INT)))
|
||||
->andWhere($query->expr()->eq('type', $query->createNamedParameter($resourceType, IQueryBuilder::PARAM_STR)))
|
||||
->andWhere($query->expr()->neq('access', $query->createNamedParameter(Backend::ACCESS_UNSHARED, IQueryBuilder::PARAM_INT)))
|
||||
->groupBy(['principaluri', 'access'])
|
||||
->executeQuery();
|
||||
|
||||
$rows = $result->fetchAll();
|
||||
$result->closeCursor();
|
||||
return $rows;
|
||||
}
|
||||
|
||||
public function getSharesForIds(array $resourceIds, string $resourceType): array {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$result = $query->select(['resourceid', 'principaluri', 'access'])
|
||||
->from('dav_shares')
|
||||
->where($query->expr()->in('resourceid', $query->createNamedParameter($resourceIds, IQueryBuilder::PARAM_INT_ARRAY)))
|
||||
->andWhere($query->expr()->eq('type', $query->createNamedParameter($resourceType)))
|
||||
->andWhere($query->expr()->neq('access', $query->createNamedParameter(Backend::ACCESS_UNSHARED, IQueryBuilder::PARAM_INT)))
|
||||
->groupBy(['principaluri', 'access', 'resourceid'])
|
||||
->executeQuery();
|
||||
|
||||
$rows = $result->fetchAll();
|
||||
$result->closeCursor();
|
||||
return $rows;
|
||||
}
|
||||
|
||||
public function unshare(int $resourceId, string $resourceType, string $principal): void {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->insert('dav_shares')
|
||||
->values([
|
||||
'principaluri' => $query->createNamedParameter($principal),
|
||||
'type' => $query->createNamedParameter($resourceType),
|
||||
'access' => $query->createNamedParameter(Backend::ACCESS_UNSHARED),
|
||||
'resourceid' => $query->createNamedParameter($resourceId)
|
||||
]);
|
||||
$query->executeStatement();
|
||||
}
|
||||
|
||||
public function share(int $resourceId, string $resourceType, int $access, string $principal): void {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->insert('dav_shares')
|
||||
->values([
|
||||
'principaluri' => $query->createNamedParameter($principal),
|
||||
'type' => $query->createNamedParameter($resourceType),
|
||||
'access' => $query->createNamedParameter($access),
|
||||
'resourceid' => $query->createNamedParameter($resourceId)
|
||||
]);
|
||||
$query->executeStatement();
|
||||
}
|
||||
|
||||
public function deleteShare(int $resourceId, string $resourceType, string $principal): void {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->delete('dav_shares');
|
||||
$query->where(
|
||||
$query->expr()->eq('resourceid', $query->createNamedParameter($resourceId, IQueryBuilder::PARAM_INT)),
|
||||
$query->expr()->eq('type', $query->createNamedParameter($resourceType)),
|
||||
$query->expr()->eq('principaluri', $query->createNamedParameter($principal))
|
||||
);
|
||||
$query->executeStatement();
|
||||
|
||||
}
|
||||
|
||||
public function deleteAllShares(int $resourceId, string $resourceType): void {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->delete('dav_shares')
|
||||
->where($query->expr()->eq('resourceid', $query->createNamedParameter($resourceId)))
|
||||
->andWhere($query->expr()->eq('type', $query->createNamedParameter($resourceType)))
|
||||
->executeStatement();
|
||||
}
|
||||
|
||||
public function deleteAllSharesByUser(string $principaluri, string $resourceType): void {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
$query->delete('dav_shares')
|
||||
->where($query->expr()->eq('principaluri', $query->createNamedParameter($principaluri)))
|
||||
->andWhere($query->expr()->eq('type', $query->createNamedParameter($resourceType)))
|
||||
->executeStatement();
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright 2024 Anna Larch <anna.larch@gmx.net>
|
||||
*
|
||||
* @author Anna Larch <anna.larch@gmx.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
namespace OCA\DAV\DAV\Sharing;
|
||||
|
||||
abstract class SharingService {
|
||||
protected string $resourceType = '';
|
||||
public function __construct(protected SharingMapper $mapper) {
|
||||
}
|
||||
|
||||
public function getResourceType(): string {
|
||||
return $this->resourceType;
|
||||
}
|
||||
public function shareWith(int $resourceId, string $principal, int $access): void {
|
||||
// remove the share if it already exists
|
||||
$this->mapper->deleteShare($resourceId, $this->getResourceType(), $principal);
|
||||
$this->mapper->share($resourceId, $this->getResourceType(), $access, $principal);
|
||||
}
|
||||
|
||||
public function unshare(int $resourceId, string $principal): void {
|
||||
$this->mapper->unshare($resourceId, $this->getResourceType(), $principal);
|
||||
}
|
||||
|
||||
public function deleteShare(int $resourceId, string $principal): void {
|
||||
$this->mapper->deleteShare($resourceId, $this->getResourceType(), $principal);
|
||||
}
|
||||
|
||||
public function deleteAllShares(int $resourceId): void {
|
||||
$this->mapper->deleteAllShares($resourceId, $this->getResourceType());
|
||||
}
|
||||
|
||||
public function deleteAllSharesByUser(string $principaluri): void {
|
||||
$this->mapper->deleteAllSharesByUser($principaluri, $this->getResourceType());
|
||||
}
|
||||
|
||||
public function getShares(int $resourceId): array {
|
||||
return $this->mapper->getSharesForId($resourceId, $this->getResourceType());
|
||||
}
|
||||
|
||||
public function getSharesForIds(array $resourceIds): array {
|
||||
return $this->mapper->getSharesForIds($resourceIds, $this->getResourceType());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $oldShares
|
||||
* @return bool
|
||||
*/
|
||||
public function hasGroupShare(array $oldShares): bool {
|
||||
return !empty(array_filter($oldShares, function (array $share) {
|
||||
return $share['{http://owncloud.org/ns}group-share'] === true;
|
||||
}));
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* @copyright 2024 Anna Larch <anna.larch@gmx.net>
|
||||
*
|
||||
* @author Anna Larch <anna.larch@gmx.net>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use OCA\DAV\DAV\Sharing\SharingMapper;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\Server;
|
||||
use Test\TestCase;
|
||||
|
||||
/**
|
||||
* @group DB
|
||||
*/
|
||||
class SharingMapperTest extends TestCase {
|
||||
|
||||
private SharingMapper $mapper;
|
||||
private IDBConnection $db;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->db = Server::get(IDBConnection::class);
|
||||
$this->mapper = new SharingMapper($this->db);
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->delete('dav_shares')->executeStatement();
|
||||
}
|
||||
|
||||
public function testShareAndGet(): void {
|
||||
$resourceId = 42;
|
||||
$resourceType = 'calendar';
|
||||
$access = 3;
|
||||
$principal = 'principals/users/bob';
|
||||
$this->mapper->share($resourceId, $resourceType, $access, $principal);
|
||||
$shares = $this->mapper->getSharesForId($resourceId, $resourceType);
|
||||
$this->assertCount(1, $shares);
|
||||
}
|
||||
|
||||
public function testShareDelete(): void {
|
||||
$resourceId = 42;
|
||||
$resourceType = 'calendar';
|
||||
$access = 3;
|
||||
$principal = 'principals/users/bob';
|
||||
$this->mapper->share($resourceId, $resourceType, $access, $principal);
|
||||
$this->mapper->deleteShare($resourceId, $resourceType, $principal);
|
||||
$shares = $this->mapper->getSharesForId($resourceId, $resourceType);
|
||||
$this->assertEmpty($shares);
|
||||
}
|
||||
|
||||
public function testShareUnshare(): void {
|
||||
$resourceId = 42;
|
||||
$resourceType = 'calendar';
|
||||
$access = 3;
|
||||
$principal = 'principals/groups/alicegroup';
|
||||
$userPrincipal = 'principals/users/alice';
|
||||
$this->mapper->share($resourceId, $resourceType, $access, $principal);
|
||||
$this->mapper->unshare($resourceId, $resourceType, $userPrincipal);
|
||||
$shares = $this->mapper->getSharesForId($resourceId, $resourceType);
|
||||
$this->assertCount(1, $shares);
|
||||
}
|
||||
|
||||
public function testShareDeleteAll(): void {
|
||||
$resourceId = 42;
|
||||
$resourceType = 'calendar';
|
||||
$access = 3;
|
||||
$principal = 'principals/groups/alicegroup';
|
||||
$userPrincipal = 'principals/users/alice';
|
||||
$this->mapper->share($resourceId, $resourceType, $access, $principal);
|
||||
$this->mapper->unshare($resourceId, $resourceType, $userPrincipal);
|
||||
$shares = $this->mapper->getSharesForId($resourceId, $resourceType);
|
||||
$this->assertCount(1, $shares);
|
||||
$this->mapper->deleteAllShares($resourceId, $resourceType);
|
||||
$shares = $this->mapper->getSharesForId($resourceId, $resourceType);
|
||||
$this->assertEmpty($shares);
|
||||
}
|
||||
|
||||
public function testShareDeleteAllForUser(): void {
|
||||
$resourceId = 42;
|
||||
$resourceType = 'calendar';
|
||||
$access = 3;
|
||||
$principal = 'principals/groups/alicegroup';
|
||||
$this->mapper->share($resourceId, $resourceType, $access, $principal);
|
||||
$shares = $this->mapper->getSharesForId($resourceId, $resourceType);
|
||||
$this->assertCount(1, $shares);
|
||||
$this->mapper->deleteAllSharesByUser($principal, $resourceType);
|
||||
$shares = $this->mapper->getSharesForId($resourceId, $resourceType);
|
||||
$this->assertEmpty($shares);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,427 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/*
|
||||
* @copyright 2024 Anna Larch <anna.larch@gmx.net>
|
||||
*
|
||||
* @author Anna Larch <anna.larch@gmx.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
namespace OCA\DAV\Tests\unit\DAV\Sharing;
|
||||
|
||||
use OCA\DAV\CalDAV\Sharing\Backend as CalendarSharingBackend;
|
||||
use OCA\DAV\CalDAV\Sharing\Service;
|
||||
use OCA\DAV\CardDAV\Sharing\Backend as ContactsSharingBackend;
|
||||
use OCA\DAV\Connector\Sabre\Principal;
|
||||
use OCA\DAV\DAV\Sharing\Backend;
|
||||
use OCA\DAV\DAV\Sharing\IShareable;
|
||||
use OCP\ICache;
|
||||
use OCP\ICacheFactory;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IUserManager;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Test\TestCase;
|
||||
|
||||
class BackendTest extends TestCase {
|
||||
|
||||
private IDBConnection|MockObject $db;
|
||||
private IUserManager|MockObject $userManager;
|
||||
private IGroupManager|MockObject $groupManager;
|
||||
private MockObject|Principal $principalBackend;
|
||||
private MockObject|ICache $shareCache;
|
||||
private LoggerInterface|MockObject $logger;
|
||||
private MockObject|ICacheFactory $cacheFactory;
|
||||
private Service|MockObject $calendarService;
|
||||
private CalendarSharingBackend $backend;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->db = $this->createMock(IDBConnection::class);
|
||||
$this->userManager = $this->createMock(IUserManager::class);
|
||||
$this->groupManager = $this->createMock(IGroupManager::class);
|
||||
$this->principalBackend = $this->createMock(Principal::class);
|
||||
$this->cacheFactory = $this->createMock(ICacheFactory::class);
|
||||
$this->shareCache = $this->createMock(ICache::class);
|
||||
$this->logger = $this->createMock(LoggerInterface::class);
|
||||
$this->calendarService = $this->createMock(Service::class);
|
||||
$this->cacheFactory->expects(self::any())
|
||||
->method('createInMemory')
|
||||
->willReturn($this->shareCache);
|
||||
|
||||
$this->backend = new CalendarSharingBackend(
|
||||
$this->userManager,
|
||||
$this->groupManager,
|
||||
$this->principalBackend,
|
||||
$this->cacheFactory,
|
||||
$this->calendarService,
|
||||
$this->logger,
|
||||
);
|
||||
}
|
||||
|
||||
public function testUpdateShareCalendarBob(): void {
|
||||
$shareable = $this->createConfiguredMock(IShareable::class, [
|
||||
'getOwner' => 'principals/users/alice',
|
||||
'getResourceId' => 42,
|
||||
]);
|
||||
$add = [
|
||||
[
|
||||
'href' => 'principal:principals/users/bob',
|
||||
'readOnly' => true,
|
||||
]
|
||||
];
|
||||
$principal = 'principals/users/bob';
|
||||
|
||||
$this->shareCache->expects(self::once())
|
||||
->method('clear');
|
||||
$this->principalBackend->expects(self::once())
|
||||
->method('findByUri')
|
||||
->willReturn($principal);
|
||||
$this->userManager->expects(self::once())
|
||||
->method('userExists')
|
||||
->willReturn(true);
|
||||
$this->groupManager->expects(self::never())
|
||||
->method('groupExists');
|
||||
$this->calendarService->expects(self::once())
|
||||
->method('shareWith')
|
||||
->with($shareable->getResourceId(), $principal, Backend::ACCESS_READ);
|
||||
|
||||
$this->backend->updateShares($shareable, $add, []);
|
||||
}
|
||||
|
||||
public function testUpdateShareCalendarGroup(): void {
|
||||
$shareable = $this->createConfiguredMock(IShareable::class, [
|
||||
'getOwner' => 'principals/users/alice',
|
||||
'getResourceId' => 42,
|
||||
]);
|
||||
$add = [
|
||||
[
|
||||
'href' => 'principal:principals/groups/bob',
|
||||
'readOnly' => true,
|
||||
]
|
||||
];
|
||||
$principal = 'principals/groups/bob';
|
||||
|
||||
$this->shareCache->expects(self::once())
|
||||
->method('clear');
|
||||
$this->principalBackend->expects(self::once())
|
||||
->method('findByUri')
|
||||
->willReturn($principal);
|
||||
$this->userManager->expects(self::never())
|
||||
->method('userExists');
|
||||
$this->groupManager->expects(self::once())
|
||||
->method('groupExists')
|
||||
->willReturn(true);
|
||||
$this->calendarService->expects(self::once())
|
||||
->method('shareWith')
|
||||
->with($shareable->getResourceId(), $principal, Backend::ACCESS_READ);
|
||||
|
||||
$this->backend->updateShares($shareable, $add, []);
|
||||
}
|
||||
|
||||
public function testUpdateShareContactsBob(): void {
|
||||
$shareable = $this->createConfiguredMock(IShareable::class, [
|
||||
'getOwner' => 'principals/users/alice',
|
||||
'getResourceId' => 42,
|
||||
]);
|
||||
$add = [
|
||||
[
|
||||
'href' => 'principal:principals/users/bob',
|
||||
'readOnly' => true,
|
||||
]
|
||||
];
|
||||
$principal = 'principals/users/bob';
|
||||
|
||||
$this->shareCache->expects(self::once())
|
||||
->method('clear');
|
||||
$this->principalBackend->expects(self::once())
|
||||
->method('findByUri')
|
||||
->willReturn($principal);
|
||||
$this->userManager->expects(self::once())
|
||||
->method('userExists')
|
||||
->willReturn(true);
|
||||
$this->groupManager->expects(self::never())
|
||||
->method('groupExists');
|
||||
$this->calendarService->expects(self::once())
|
||||
->method('shareWith')
|
||||
->with($shareable->getResourceId(), $principal, Backend::ACCESS_READ);
|
||||
|
||||
$this->backend->updateShares($shareable, $add, []);
|
||||
}
|
||||
|
||||
public function testUpdateShareContactsGroup(): void {
|
||||
$shareable = $this->createConfiguredMock(IShareable::class, [
|
||||
'getOwner' => 'principals/users/alice',
|
||||
'getResourceId' => 42,
|
||||
]);
|
||||
$add = [
|
||||
[
|
||||
'href' => 'principal:principals/groups/bob',
|
||||
'readOnly' => true,
|
||||
]
|
||||
];
|
||||
$principal = 'principals/groups/bob';
|
||||
|
||||
$this->shareCache->expects(self::once())
|
||||
->method('clear');
|
||||
$this->principalBackend->expects(self::once())
|
||||
->method('findByUri')
|
||||
->willReturn($principal);
|
||||
$this->userManager->expects(self::never())
|
||||
->method('userExists');
|
||||
$this->groupManager->expects(self::once())
|
||||
->method('groupExists')
|
||||
->willReturn(true);
|
||||
$this->calendarService->expects(self::once())
|
||||
->method('shareWith')
|
||||
->with($shareable->getResourceId(), $principal, Backend::ACCESS_READ);
|
||||
|
||||
$this->backend->updateShares($shareable, $add, []);
|
||||
}
|
||||
|
||||
public function testUpdateShareCircle(): void {
|
||||
$shareable = $this->createConfiguredMock(IShareable::class, [
|
||||
'getOwner' => 'principals/users/alice',
|
||||
'getResourceId' => 42,
|
||||
]);
|
||||
$add = [
|
||||
[
|
||||
'href' => 'principal:principals/circles/bob',
|
||||
'readOnly' => true,
|
||||
]
|
||||
];
|
||||
$principal = 'principals/groups/bob';
|
||||
|
||||
$this->shareCache->expects(self::once())
|
||||
->method('clear');
|
||||
$this->principalBackend->expects(self::once())
|
||||
->method('findByUri')
|
||||
->willReturn($principal);
|
||||
$this->userManager->expects(self::never())
|
||||
->method('userExists');
|
||||
$this->groupManager->expects(self::once())
|
||||
->method('groupExists')
|
||||
->willReturn(true);
|
||||
$this->calendarService->expects(self::once())
|
||||
->method('shareWith')
|
||||
->with($shareable->getResourceId(), $principal, Backend::ACCESS_READ);
|
||||
|
||||
$this->backend->updateShares($shareable, $add, []);
|
||||
}
|
||||
|
||||
public function testUnshareBob(): void {
|
||||
$shareable = $this->createConfiguredMock(IShareable::class, [
|
||||
'getOwner' => 'principals/users/alice',
|
||||
'getResourceId' => 42,
|
||||
]);
|
||||
$remove = [
|
||||
[
|
||||
'href' => 'principal:principals/users/bob',
|
||||
'readOnly' => true,
|
||||
]
|
||||
];
|
||||
$principal = 'principals/users/bob';
|
||||
|
||||
$this->shareCache->expects(self::once())
|
||||
->method('clear');
|
||||
$this->principalBackend->expects(self::once())
|
||||
->method('findByUri')
|
||||
->willReturn($principal);
|
||||
$this->calendarService->expects(self::once())
|
||||
->method('deleteShare')
|
||||
->with($shareable->getResourceId(), $principal);
|
||||
$this->calendarService->expects(self::once())
|
||||
->method('hasGroupShare')
|
||||
->willReturn(false);
|
||||
$this->calendarService->expects(self::never())
|
||||
->method('unshare');
|
||||
|
||||
$this->backend->updateShares($shareable, [], $remove);
|
||||
}
|
||||
|
||||
public function testUnshareWithBobGroup(): void {
|
||||
$shareable = $this->createConfiguredMock(IShareable::class, [
|
||||
'getOwner' => 'principals/users/alice',
|
||||
'getResourceId' => 42,
|
||||
]);
|
||||
$remove = [
|
||||
[
|
||||
'href' => 'principal:principals/users/bob',
|
||||
'readOnly' => true,
|
||||
]
|
||||
];
|
||||
$oldShares = [
|
||||
[
|
||||
'href' => 'principal:principals/groups/bob',
|
||||
'commonName' => 'bob',
|
||||
'status' => 1,
|
||||
'readOnly' => true,
|
||||
'{http://owncloud.org/ns}principal' => 'principals/groups/bob',
|
||||
'{http://owncloud.org/ns}group-share' => true,
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
$this->shareCache->expects(self::once())
|
||||
->method('clear');
|
||||
$this->principalBackend->expects(self::once())
|
||||
->method('findByUri')
|
||||
->willReturn('principals/users/bob');
|
||||
$this->calendarService->expects(self::once())
|
||||
->method('deleteShare')
|
||||
->with($shareable->getResourceId(), 'principals/users/bob');
|
||||
$this->calendarService->expects(self::once())
|
||||
->method('hasGroupShare')
|
||||
->with($oldShares)
|
||||
->willReturn(true);
|
||||
$this->calendarService->expects(self::once())
|
||||
->method('unshare')
|
||||
->with($shareable->getResourceId(), 'principals/users/bob');
|
||||
|
||||
$this->backend->updateShares($shareable, [], $remove, $oldShares);
|
||||
}
|
||||
|
||||
public function testGetShares(): void {
|
||||
$resourceId = 42;
|
||||
$principal = 'principals/groups/bob';
|
||||
$rows = [
|
||||
[
|
||||
'principaluri' => $principal,
|
||||
'access' => Backend::ACCESS_READ,
|
||||
]
|
||||
];
|
||||
$expected = [
|
||||
[
|
||||
'href' => 'principal:principals/groups/bob',
|
||||
'commonName' => 'bob',
|
||||
'status' => 1,
|
||||
'readOnly' => true,
|
||||
'{http://owncloud.org/ns}principal' => $principal,
|
||||
'{http://owncloud.org/ns}group-share' => true,
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
$this->shareCache->expects(self::once())
|
||||
->method('get')
|
||||
->with((string)$resourceId)
|
||||
->willReturn(null);
|
||||
$this->calendarService->expects(self::once())
|
||||
->method('getShares')
|
||||
->with($resourceId)
|
||||
->willReturn($rows);
|
||||
$this->principalBackend->expects(self::once())
|
||||
->method('getPrincipalByPath')
|
||||
->with($principal)
|
||||
->willReturn(['uri' => $principal, '{DAV:}displayname' => 'bob']);
|
||||
$this->shareCache->expects(self::once())
|
||||
->method('set')
|
||||
->with((string)$resourceId, $expected);
|
||||
|
||||
$result = $this->backend->getShares($resourceId);
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
public function testGetSharesAddressbooks(): void {
|
||||
$service = $this->createMock(\OCA\DAV\CardDAV\Sharing\Service::class);
|
||||
$backend = new ContactsSharingBackend(
|
||||
$this->userManager,
|
||||
$this->groupManager,
|
||||
$this->principalBackend,
|
||||
$this->cacheFactory,
|
||||
$service,
|
||||
$this->logger);
|
||||
$resourceId = 42;
|
||||
$principal = 'principals/groups/bob';
|
||||
$rows = [
|
||||
[
|
||||
'principaluri' => $principal,
|
||||
'access' => Backend::ACCESS_READ,
|
||||
]
|
||||
];
|
||||
$expected = [
|
||||
[
|
||||
'href' => 'principal:principals/groups/bob',
|
||||
'commonName' => 'bob',
|
||||
'status' => 1,
|
||||
'readOnly' => true,
|
||||
'{http://owncloud.org/ns}principal' => $principal,
|
||||
'{http://owncloud.org/ns}group-share' => true,
|
||||
]
|
||||
];
|
||||
|
||||
$this->shareCache->expects(self::once())
|
||||
->method('get')
|
||||
->with((string)$resourceId)
|
||||
->willReturn(null);
|
||||
$service->expects(self::once())
|
||||
->method('getShares')
|
||||
->with($resourceId)
|
||||
->willReturn($rows);
|
||||
$this->principalBackend->expects(self::once())
|
||||
->method('getPrincipalByPath')
|
||||
->with($principal)
|
||||
->willReturn(['uri' => $principal, '{DAV:}displayname' => 'bob']);
|
||||
$this->shareCache->expects(self::once())
|
||||
->method('set')
|
||||
->with((string)$resourceId, $expected);
|
||||
|
||||
$result = $backend->getShares($resourceId);
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
public function testPreloadShares(): void {
|
||||
$resourceIds = [42, 99];
|
||||
$rows = [
|
||||
[
|
||||
'resourceid' => 42,
|
||||
'principaluri' => 'principals/groups/bob',
|
||||
'access' => Backend::ACCESS_READ,
|
||||
],
|
||||
[
|
||||
'resourceid' => 99,
|
||||
'principaluri' => 'principals/users/carlos',
|
||||
'access' => Backend::ACCESS_READ_WRITE,
|
||||
]
|
||||
];
|
||||
$principalResults = [
|
||||
['uri' => 'principals/groups/bob', '{DAV:}displayname' => 'bob'],
|
||||
['uri' => 'principals/users/carlos', '{DAV:}displayname' => 'carlos'],
|
||||
];
|
||||
|
||||
$this->shareCache->expects(self::exactly(2))
|
||||
->method('get')
|
||||
->willReturn(null);
|
||||
$this->calendarService->expects(self::once())
|
||||
->method('getSharesForIds')
|
||||
->with($resourceIds)
|
||||
->willReturn($rows);
|
||||
$this->principalBackend->expects(self::exactly(2))
|
||||
->method('getPrincipalByPath')
|
||||
->willReturnCallback(function (string $principal) use ($principalResults) {
|
||||
switch ($principal) {
|
||||
case 'principals/groups/bob':
|
||||
return $principalResults[0];
|
||||
default:
|
||||
return $principalResults[1];
|
||||
}
|
||||
});
|
||||
$this->shareCache->expects(self::exactly(2))
|
||||
->method('set');
|
||||
|
||||
$this->backend->preloadShares($resourceIds);
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/*
|
||||
* @copyright 2024 Anna Larch <anna.larch@gmx.net>
|
||||
*
|
||||
* @author Anna Larch <anna.larch@gmx.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
namespace OCA\DAV\Tests\unit\DAV\Sharing;
|
||||
|
||||
use OCA\DAV\CalDAV\Sharing\Service;
|
||||
use OCA\DAV\DAV\Sharing\SharingMapper;
|
||||
use OCA\DAV\DAV\Sharing\SharingService;
|
||||
use Test\TestCase;
|
||||
|
||||
class SharingServiceTest extends TestCase {
|
||||
|
||||
private SharingService $service;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->service = new Service($this->createMock(SharingMapper::class));
|
||||
}
|
||||
|
||||
public function testHasGroupShare(): void {
|
||||
$oldShares = [
|
||||
[
|
||||
'href' => 'principal:principals/groups/bob',
|
||||
'commonName' => 'bob',
|
||||
'status' => 1,
|
||||
'readOnly' => true,
|
||||
'{http://owncloud.org/ns}principal' => 'principals/groups/bob',
|
||||
'{http://owncloud.org/ns}group-share' => true,
|
||||
],
|
||||
[
|
||||
'href' => 'principal:principals/users/bob',
|
||||
'commonName' => 'bob',
|
||||
'status' => 1,
|
||||
'readOnly' => true,
|
||||
'{http://owncloud.org/ns}principal' => 'principals/users/bob',
|
||||
'{http://owncloud.org/ns}group-share' => false,
|
||||
]
|
||||
];
|
||||
|
||||
$this->assertTrue($this->service->hasGroupShare($oldShares));
|
||||
|
||||
$oldShares = [
|
||||
[
|
||||
'href' => 'principal:principals/users/bob',
|
||||
'commonName' => 'bob',
|
||||
'status' => 1,
|
||||
'readOnly' => true,
|
||||
'{http://owncloud.org/ns}principal' => 'principals/users/bob',
|
||||
'{http://owncloud.org/ns}group-share' => false,
|
||||
]
|
||||
];
|
||||
$this->assertFalse($this->service->hasGroupShare($oldShares));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue