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