@@ -25,81 +25,81 @@ |
||
25 | 25 | * @template-implements IEventListener<Event|CalendarObjectCreatedEvent|CalendarObjectUpdatedEvent|CalendarObjectDeletedEvent> |
26 | 26 | */ |
27 | 27 | class CalendarFederationNotificationListener implements IEventListener { |
28 | - public function __construct( |
|
29 | - private readonly ICloudIdManager $cloudIdManager, |
|
30 | - private readonly CalendarFederationNotifier $calendarFederationNotifier, |
|
31 | - private readonly LoggerInterface $logger, |
|
32 | - private readonly SharingMapper $sharingMapper, |
|
33 | - ) { |
|
34 | - } |
|
28 | + public function __construct( |
|
29 | + private readonly ICloudIdManager $cloudIdManager, |
|
30 | + private readonly CalendarFederationNotifier $calendarFederationNotifier, |
|
31 | + private readonly LoggerInterface $logger, |
|
32 | + private readonly SharingMapper $sharingMapper, |
|
33 | + ) { |
|
34 | + } |
|
35 | 35 | |
36 | - public function handle(Event $event): void { |
|
37 | - if (!($event instanceof CalendarObjectCreatedEvent) |
|
38 | - && !($event instanceof CalendarObjectUpdatedEvent) |
|
39 | - && !($event instanceof CalendarObjectDeletedEvent) |
|
40 | - ) { |
|
41 | - return; |
|
42 | - } |
|
36 | + public function handle(Event $event): void { |
|
37 | + if (!($event instanceof CalendarObjectCreatedEvent) |
|
38 | + && !($event instanceof CalendarObjectUpdatedEvent) |
|
39 | + && !($event instanceof CalendarObjectDeletedEvent) |
|
40 | + ) { |
|
41 | + return; |
|
42 | + } |
|
43 | 43 | |
44 | - $remoteUserShares = array_filter($event->getShares(), function (array $share): bool { |
|
45 | - $sharedWithPrincipal = $share['{http://owncloud.org/ns}principal'] ?? ''; |
|
46 | - [$prefix] = \Sabre\Uri\split($sharedWithPrincipal); |
|
47 | - return $prefix === RemoteUserPrincipalBackend::PRINCIPAL_PREFIX; |
|
48 | - }); |
|
49 | - if (empty($remoteUserShares)) { |
|
50 | - // Not shared with any remote user |
|
51 | - return; |
|
52 | - } |
|
44 | + $remoteUserShares = array_filter($event->getShares(), function (array $share): bool { |
|
45 | + $sharedWithPrincipal = $share['{http://owncloud.org/ns}principal'] ?? ''; |
|
46 | + [$prefix] = \Sabre\Uri\split($sharedWithPrincipal); |
|
47 | + return $prefix === RemoteUserPrincipalBackend::PRINCIPAL_PREFIX; |
|
48 | + }); |
|
49 | + if (empty($remoteUserShares)) { |
|
50 | + // Not shared with any remote user |
|
51 | + return; |
|
52 | + } |
|
53 | 53 | |
54 | - $calendarInfo = $event->getCalendarData(); |
|
55 | - $remoteUserPrincipals = array_map( |
|
56 | - static fn (array $share) => $share['{http://owncloud.org/ns}principal'], |
|
57 | - $remoteUserShares, |
|
58 | - ); |
|
59 | - $remoteShares = $this->sharingMapper->getSharesByPrincipalsAndResource( |
|
60 | - $remoteUserPrincipals, |
|
61 | - (int)$calendarInfo['id'], |
|
62 | - 'calendar', |
|
63 | - ); |
|
54 | + $calendarInfo = $event->getCalendarData(); |
|
55 | + $remoteUserPrincipals = array_map( |
|
56 | + static fn (array $share) => $share['{http://owncloud.org/ns}principal'], |
|
57 | + $remoteUserShares, |
|
58 | + ); |
|
59 | + $remoteShares = $this->sharingMapper->getSharesByPrincipalsAndResource( |
|
60 | + $remoteUserPrincipals, |
|
61 | + (int)$calendarInfo['id'], |
|
62 | + 'calendar', |
|
63 | + ); |
|
64 | 64 | |
65 | - foreach ($remoteShares as $share) { |
|
66 | - [, $name] = \Sabre\Uri\split($share['principaluri']); |
|
67 | - $shareWithRaw = base64_decode($name); |
|
68 | - try { |
|
69 | - $shareWith = $this->cloudIdManager->resolveCloudId($shareWithRaw); |
|
70 | - } catch (\InvalidArgumentException $e) { |
|
71 | - // Not a valid remote user principal |
|
72 | - continue; |
|
73 | - } |
|
65 | + foreach ($remoteShares as $share) { |
|
66 | + [, $name] = \Sabre\Uri\split($share['principaluri']); |
|
67 | + $shareWithRaw = base64_decode($name); |
|
68 | + try { |
|
69 | + $shareWith = $this->cloudIdManager->resolveCloudId($shareWithRaw); |
|
70 | + } catch (\InvalidArgumentException $e) { |
|
71 | + // Not a valid remote user principal |
|
72 | + continue; |
|
73 | + } |
|
74 | 74 | |
75 | - [, $sharedByUid] = \Sabre\Uri\split($calendarInfo['principaluri']); |
|
75 | + [, $sharedByUid] = \Sabre\Uri\split($calendarInfo['principaluri']); |
|
76 | 76 | |
77 | - $remoteUrl = $shareWith->getRemote(); |
|
78 | - try { |
|
79 | - $response = $this->calendarFederationNotifier->notifySyncCalendar( |
|
80 | - $shareWith, |
|
81 | - $sharedByUid, |
|
82 | - $calendarInfo['uri'], |
|
83 | - $share['token'], |
|
84 | - ); |
|
85 | - } catch (OCMProviderException $e) { |
|
86 | - $this->logger->error("Failed to send SYNC_CALENDAR notification to remote $remoteUrl", [ |
|
87 | - 'exception' => $e, |
|
88 | - 'shareWith' => $shareWith->getId(), |
|
89 | - 'calendarName' => $calendarInfo['uri'], |
|
90 | - 'calendarOwner' => $sharedByUid, |
|
91 | - ]); |
|
92 | - continue; |
|
93 | - } |
|
77 | + $remoteUrl = $shareWith->getRemote(); |
|
78 | + try { |
|
79 | + $response = $this->calendarFederationNotifier->notifySyncCalendar( |
|
80 | + $shareWith, |
|
81 | + $sharedByUid, |
|
82 | + $calendarInfo['uri'], |
|
83 | + $share['token'], |
|
84 | + ); |
|
85 | + } catch (OCMProviderException $e) { |
|
86 | + $this->logger->error("Failed to send SYNC_CALENDAR notification to remote $remoteUrl", [ |
|
87 | + 'exception' => $e, |
|
88 | + 'shareWith' => $shareWith->getId(), |
|
89 | + 'calendarName' => $calendarInfo['uri'], |
|
90 | + 'calendarOwner' => $sharedByUid, |
|
91 | + ]); |
|
92 | + continue; |
|
93 | + } |
|
94 | 94 | |
95 | - if ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) { |
|
96 | - $this->logger->error("Remote $remoteUrl rejected SYNC_CALENDAR notification", [ |
|
97 | - 'statusCode' => $response->getStatusCode(), |
|
98 | - 'shareWith' => $shareWith->getId(), |
|
99 | - 'calendarName' => $calendarInfo['uri'], |
|
100 | - 'calendarOwner' => $sharedByUid, |
|
101 | - ]); |
|
102 | - } |
|
103 | - } |
|
104 | - } |
|
95 | + if ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) { |
|
96 | + $this->logger->error("Remote $remoteUrl rejected SYNC_CALENDAR notification", [ |
|
97 | + 'statusCode' => $response->getStatusCode(), |
|
98 | + 'shareWith' => $shareWith->getId(), |
|
99 | + 'calendarName' => $calendarInfo['uri'], |
|
100 | + 'calendarOwner' => $sharedByUid, |
|
101 | + ]); |
|
102 | + } |
|
103 | + } |
|
104 | + } |
|
105 | 105 | } |
@@ -41,7 +41,7 @@ discard block |
||
41 | 41 | return; |
42 | 42 | } |
43 | 43 | |
44 | - $remoteUserShares = array_filter($event->getShares(), function (array $share): bool { |
|
44 | + $remoteUserShares = array_filter($event->getShares(), function(array $share): bool { |
|
45 | 45 | $sharedWithPrincipal = $share['{http://owncloud.org/ns}principal'] ?? ''; |
46 | 46 | [$prefix] = \Sabre\Uri\split($sharedWithPrincipal); |
47 | 47 | return $prefix === RemoteUserPrincipalBackend::PRINCIPAL_PREFIX; |
@@ -58,7 +58,7 @@ discard block |
||
58 | 58 | ); |
59 | 59 | $remoteShares = $this->sharingMapper->getSharesByPrincipalsAndResource( |
60 | 60 | $remoteUserPrincipals, |
61 | - (int)$calendarInfo['id'], |
|
61 | + (int) $calendarInfo['id'], |
|
62 | 62 | 'calendar', |
63 | 63 | ); |
64 | 64 |
@@ -20,16 +20,16 @@ |
||
20 | 20 | * @template-implements IEventListener<Event|SabrePluginAuthInitEvent> |
21 | 21 | */ |
22 | 22 | class SabrePluginAuthInitListener implements IEventListener { |
23 | - public function handle(Event $event): void { |
|
24 | - if (!($event instanceof SabrePluginAuthInitEvent)) { |
|
25 | - return; |
|
26 | - } |
|
23 | + public function handle(Event $event): void { |
|
24 | + if (!($event instanceof SabrePluginAuthInitEvent)) { |
|
25 | + return; |
|
26 | + } |
|
27 | 27 | |
28 | - $server = $event->getServer(); |
|
29 | - $authPlugin = $server->getPlugin('auth'); |
|
30 | - if ($authPlugin instanceof Plugin) { |
|
31 | - $authBackend = Server::get(FederatedCalendarAuth::class); |
|
32 | - $authPlugin->addBackend($authBackend); |
|
33 | - } |
|
34 | - } |
|
28 | + $server = $event->getServer(); |
|
29 | + $authPlugin = $server->getPlugin('auth'); |
|
30 | + if ($authPlugin instanceof Plugin) { |
|
31 | + $authBackend = Server::get(FederatedCalendarAuth::class); |
|
32 | + $authPlugin->addBackend($authBackend); |
|
33 | + } |
|
34 | + } |
|
35 | 35 | } |
@@ -14,116 +14,116 @@ |
||
14 | 14 | use Sabre\DAVACL\PrincipalBackend\BackendInterface; |
15 | 15 | |
16 | 16 | class RemoteUserPrincipalBackend implements BackendInterface { |
17 | - public const PRINCIPAL_PREFIX = 'principals/remote-users'; |
|
18 | - |
|
19 | - private bool $hasCachedAllChildren = false; |
|
20 | - |
|
21 | - /** @var array<string, mixed>[] */ |
|
22 | - private array $principals = []; |
|
23 | - |
|
24 | - /** @var array<string, array<string, mixed>|null> */ |
|
25 | - private array $principalsByPath = []; |
|
26 | - |
|
27 | - public function __construct( |
|
28 | - private readonly ICloudIdManager $cloudIdManager, |
|
29 | - private readonly SharingMapper $sharingMapper, |
|
30 | - ) { |
|
31 | - } |
|
32 | - |
|
33 | - public function getPrincipalsByPrefix($prefixPath) { |
|
34 | - if ($prefixPath !== self::PRINCIPAL_PREFIX) { |
|
35 | - return []; |
|
36 | - } |
|
37 | - |
|
38 | - if (!$this->hasCachedAllChildren) { |
|
39 | - $this->loadChildren(); |
|
40 | - $this->hasCachedAllChildren = true; |
|
41 | - } |
|
42 | - |
|
43 | - return $this->principals; |
|
44 | - } |
|
45 | - |
|
46 | - public function getPrincipalByPath($path) { |
|
47 | - [$prefix] = \Sabre\Uri\split($path); |
|
48 | - if ($prefix !== self::PRINCIPAL_PREFIX) { |
|
49 | - return null; |
|
50 | - } |
|
51 | - |
|
52 | - if (isset($this->principalsByPath[$path])) { |
|
53 | - return $this->principalsByPath[$path]; |
|
54 | - } |
|
55 | - |
|
56 | - try { |
|
57 | - $principal = $this->principalUriToPrincipal($path); |
|
58 | - } catch (\Exception $e) { |
|
59 | - $principal = null; |
|
60 | - } |
|
61 | - $this->principalsByPath[$path] = $principal; |
|
62 | - return $principal; |
|
63 | - } |
|
64 | - |
|
65 | - public function updatePrincipal($path, \Sabre\DAV\PropPatch $propPatch) { |
|
66 | - throw new \Sabre\DAV\Exception('Updating remote user principal is not supported'); |
|
67 | - } |
|
68 | - |
|
69 | - public function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') { |
|
70 | - // Searching is not supported |
|
71 | - return []; |
|
72 | - } |
|
73 | - |
|
74 | - public function findByUri($uri, $principalPrefix) { |
|
75 | - if (str_starts_with($uri, 'principal:')) { |
|
76 | - $principal = substr($uri, strlen('principal:')); |
|
77 | - $principal = $this->getPrincipalByPath($principal); |
|
78 | - if ($principal !== null) { |
|
79 | - return $principal['uri']; |
|
80 | - } |
|
81 | - } |
|
82 | - |
|
83 | - return null; |
|
84 | - } |
|
85 | - |
|
86 | - public function getGroupMemberSet($principal) { |
|
87 | - return []; |
|
88 | - } |
|
89 | - |
|
90 | - public function getGroupMembership($principal) { |
|
91 | - // TODO: for now the group principal has only one member, the user itself |
|
92 | - $principal = $this->getPrincipalByPath($principal); |
|
93 | - if (!$principal) { |
|
94 | - throw new \Sabre\DAV\Exception('Principal not found'); |
|
95 | - } |
|
96 | - |
|
97 | - return [$principal['uri']]; |
|
98 | - } |
|
99 | - |
|
100 | - public function setGroupMemberSet($principal, array $members) { |
|
101 | - throw new \Sabre\DAV\Exception('Adding members to remote user is not supported'); |
|
102 | - } |
|
103 | - |
|
104 | - /** |
|
105 | - * @return array{'{DAV:}displayname': string, '{http://nextcloud.com/ns}cloud-id': \OCP\Federation\ICloudId, uri: string} |
|
106 | - */ |
|
107 | - private function principalUriToPrincipal(string $principalUri): array { |
|
108 | - [, $name] = \Sabre\Uri\split($principalUri); |
|
109 | - $cloudId = $this->cloudIdManager->resolveCloudId(base64_decode($name)); |
|
110 | - return [ |
|
111 | - 'uri' => $principalUri, |
|
112 | - '{DAV:}displayname' => $cloudId->getDisplayId(), |
|
113 | - '{http://nextcloud.com/ns}cloud-id' => $cloudId, |
|
114 | - ]; |
|
115 | - } |
|
116 | - |
|
117 | - private function loadChildren(): void { |
|
118 | - $rows = $this->sharingMapper->getPrincipalUrisByPrefix('calendar', self::PRINCIPAL_PREFIX); |
|
119 | - $this->principals = array_map( |
|
120 | - fn (array $row) => $this->principalUriToPrincipal($row['principaluri']), |
|
121 | - $rows, |
|
122 | - ); |
|
123 | - |
|
124 | - $this->principalsByPath = []; |
|
125 | - foreach ($this->principals as $child) { |
|
126 | - $this->principalsByPath[$child['uri']] = $child; |
|
127 | - } |
|
128 | - } |
|
17 | + public const PRINCIPAL_PREFIX = 'principals/remote-users'; |
|
18 | + |
|
19 | + private bool $hasCachedAllChildren = false; |
|
20 | + |
|
21 | + /** @var array<string, mixed>[] */ |
|
22 | + private array $principals = []; |
|
23 | + |
|
24 | + /** @var array<string, array<string, mixed>|null> */ |
|
25 | + private array $principalsByPath = []; |
|
26 | + |
|
27 | + public function __construct( |
|
28 | + private readonly ICloudIdManager $cloudIdManager, |
|
29 | + private readonly SharingMapper $sharingMapper, |
|
30 | + ) { |
|
31 | + } |
|
32 | + |
|
33 | + public function getPrincipalsByPrefix($prefixPath) { |
|
34 | + if ($prefixPath !== self::PRINCIPAL_PREFIX) { |
|
35 | + return []; |
|
36 | + } |
|
37 | + |
|
38 | + if (!$this->hasCachedAllChildren) { |
|
39 | + $this->loadChildren(); |
|
40 | + $this->hasCachedAllChildren = true; |
|
41 | + } |
|
42 | + |
|
43 | + return $this->principals; |
|
44 | + } |
|
45 | + |
|
46 | + public function getPrincipalByPath($path) { |
|
47 | + [$prefix] = \Sabre\Uri\split($path); |
|
48 | + if ($prefix !== self::PRINCIPAL_PREFIX) { |
|
49 | + return null; |
|
50 | + } |
|
51 | + |
|
52 | + if (isset($this->principalsByPath[$path])) { |
|
53 | + return $this->principalsByPath[$path]; |
|
54 | + } |
|
55 | + |
|
56 | + try { |
|
57 | + $principal = $this->principalUriToPrincipal($path); |
|
58 | + } catch (\Exception $e) { |
|
59 | + $principal = null; |
|
60 | + } |
|
61 | + $this->principalsByPath[$path] = $principal; |
|
62 | + return $principal; |
|
63 | + } |
|
64 | + |
|
65 | + public function updatePrincipal($path, \Sabre\DAV\PropPatch $propPatch) { |
|
66 | + throw new \Sabre\DAV\Exception('Updating remote user principal is not supported'); |
|
67 | + } |
|
68 | + |
|
69 | + public function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') { |
|
70 | + // Searching is not supported |
|
71 | + return []; |
|
72 | + } |
|
73 | + |
|
74 | + public function findByUri($uri, $principalPrefix) { |
|
75 | + if (str_starts_with($uri, 'principal:')) { |
|
76 | + $principal = substr($uri, strlen('principal:')); |
|
77 | + $principal = $this->getPrincipalByPath($principal); |
|
78 | + if ($principal !== null) { |
|
79 | + return $principal['uri']; |
|
80 | + } |
|
81 | + } |
|
82 | + |
|
83 | + return null; |
|
84 | + } |
|
85 | + |
|
86 | + public function getGroupMemberSet($principal) { |
|
87 | + return []; |
|
88 | + } |
|
89 | + |
|
90 | + public function getGroupMembership($principal) { |
|
91 | + // TODO: for now the group principal has only one member, the user itself |
|
92 | + $principal = $this->getPrincipalByPath($principal); |
|
93 | + if (!$principal) { |
|
94 | + throw new \Sabre\DAV\Exception('Principal not found'); |
|
95 | + } |
|
96 | + |
|
97 | + return [$principal['uri']]; |
|
98 | + } |
|
99 | + |
|
100 | + public function setGroupMemberSet($principal, array $members) { |
|
101 | + throw new \Sabre\DAV\Exception('Adding members to remote user is not supported'); |
|
102 | + } |
|
103 | + |
|
104 | + /** |
|
105 | + * @return array{'{DAV:}displayname': string, '{http://nextcloud.com/ns}cloud-id': \OCP\Federation\ICloudId, uri: string} |
|
106 | + */ |
|
107 | + private function principalUriToPrincipal(string $principalUri): array { |
|
108 | + [, $name] = \Sabre\Uri\split($principalUri); |
|
109 | + $cloudId = $this->cloudIdManager->resolveCloudId(base64_decode($name)); |
|
110 | + return [ |
|
111 | + 'uri' => $principalUri, |
|
112 | + '{DAV:}displayname' => $cloudId->getDisplayId(), |
|
113 | + '{http://nextcloud.com/ns}cloud-id' => $cloudId, |
|
114 | + ]; |
|
115 | + } |
|
116 | + |
|
117 | + private function loadChildren(): void { |
|
118 | + $rows = $this->sharingMapper->getPrincipalUrisByPrefix('calendar', self::PRINCIPAL_PREFIX); |
|
119 | + $this->principals = array_map( |
|
120 | + fn (array $row) => $this->principalUriToPrincipal($row['principaluri']), |
|
121 | + $rows, |
|
122 | + ); |
|
123 | + |
|
124 | + $this->principalsByPath = []; |
|
125 | + foreach ($this->principals as $child) { |
|
126 | + $this->principalsByPath[$child['uri']] = $child; |
|
127 | + } |
|
128 | + } |
|
129 | 129 | } |
@@ -11,239 +11,239 @@ |
||
11 | 11 | use OCP\IDBConnection; |
12 | 12 | |
13 | 13 | class SharingMapper { |
14 | - public function __construct( |
|
15 | - private IDBConnection $db, |
|
16 | - ) { |
|
17 | - } |
|
18 | - |
|
19 | - protected function getSharesForIdByAccess(int $resourceId, string $resourceType, bool $sharesWithAccess): array { |
|
20 | - $query = $this->db->getQueryBuilder(); |
|
21 | - $query->select(['principaluri', 'access']) |
|
22 | - ->from('dav_shares') |
|
23 | - ->where($query->expr()->eq('resourceid', $query->createNamedParameter($resourceId, IQueryBuilder::PARAM_INT))) |
|
24 | - ->andWhere($query->expr()->eq('type', $query->createNamedParameter($resourceType, IQueryBuilder::PARAM_STR))) |
|
25 | - ->groupBy(['principaluri', 'access']); |
|
26 | - |
|
27 | - if ($sharesWithAccess) { |
|
28 | - $query->andWhere($query->expr()->neq('access', $query->createNamedParameter(Backend::ACCESS_UNSHARED, IQueryBuilder::PARAM_INT))); |
|
29 | - } else { |
|
30 | - $query->andWhere($query->expr()->eq('access', $query->createNamedParameter(Backend::ACCESS_UNSHARED, IQueryBuilder::PARAM_INT))); |
|
31 | - } |
|
32 | - |
|
33 | - $result = $query->executeQuery(); |
|
34 | - $rows = $result->fetchAll(); |
|
35 | - $result->closeCursor(); |
|
36 | - return $rows; |
|
37 | - } |
|
38 | - |
|
39 | - public function getSharesForId(int $resourceId, string $resourceType): array { |
|
40 | - return $this->getSharesForIdByAccess($resourceId, $resourceType, true); |
|
41 | - } |
|
42 | - |
|
43 | - public function getUnsharesForId(int $resourceId, string $resourceType): array { |
|
44 | - return $this->getSharesForIdByAccess($resourceId, $resourceType, false); |
|
45 | - } |
|
46 | - |
|
47 | - public function getSharesForIds(array $resourceIds, string $resourceType): array { |
|
48 | - $query = $this->db->getQueryBuilder(); |
|
49 | - $result = $query->select(['resourceid', 'principaluri', 'access']) |
|
50 | - ->from('dav_shares') |
|
51 | - ->where($query->expr()->in('resourceid', $query->createNamedParameter($resourceIds, IQueryBuilder::PARAM_INT_ARRAY))) |
|
52 | - ->andWhere($query->expr()->eq('type', $query->createNamedParameter($resourceType))) |
|
53 | - ->andWhere($query->expr()->neq('access', $query->createNamedParameter(Backend::ACCESS_UNSHARED, IQueryBuilder::PARAM_INT))) |
|
54 | - ->groupBy(['principaluri', 'access', 'resourceid']) |
|
55 | - ->executeQuery(); |
|
56 | - |
|
57 | - $rows = $result->fetchAll(); |
|
58 | - $result->closeCursor(); |
|
59 | - return $rows; |
|
60 | - } |
|
61 | - |
|
62 | - public function unshare(int $resourceId, string $resourceType, string $principal): void { |
|
63 | - $query = $this->db->getQueryBuilder(); |
|
64 | - $query->insert('dav_shares') |
|
65 | - ->values([ |
|
66 | - 'principaluri' => $query->createNamedParameter($principal), |
|
67 | - 'type' => $query->createNamedParameter($resourceType), |
|
68 | - 'access' => $query->createNamedParameter(Backend::ACCESS_UNSHARED), |
|
69 | - 'resourceid' => $query->createNamedParameter($resourceId) |
|
70 | - ]); |
|
71 | - $query->executeStatement(); |
|
72 | - } |
|
73 | - |
|
74 | - public function share(int $resourceId, string $resourceType, int $access, string $principal): void { |
|
75 | - $query = $this->db->getQueryBuilder(); |
|
76 | - $query->insert('dav_shares') |
|
77 | - ->values([ |
|
78 | - 'principaluri' => $query->createNamedParameter($principal), |
|
79 | - 'type' => $query->createNamedParameter($resourceType), |
|
80 | - 'access' => $query->createNamedParameter($access), |
|
81 | - 'resourceid' => $query->createNamedParameter($resourceId) |
|
82 | - ]); |
|
83 | - $query->executeStatement(); |
|
84 | - } |
|
85 | - |
|
86 | - public function shareWithToken(int $resourceId, string $resourceType, int $access, string $principal, string $token): void { |
|
87 | - $query = $this->db->getQueryBuilder(); |
|
88 | - $query->insert('dav_shares') |
|
89 | - ->values([ |
|
90 | - 'principaluri' => $query->createNamedParameter($principal), |
|
91 | - 'type' => $query->createNamedParameter($resourceType), |
|
92 | - 'access' => $query->createNamedParameter($access), |
|
93 | - 'resourceid' => $query->createNamedParameter($resourceId), |
|
94 | - 'token' => $query->createNamedParameter($token), |
|
95 | - ]); |
|
96 | - $query->executeStatement(); |
|
97 | - } |
|
98 | - |
|
99 | - public function deleteShare(int $resourceId, string $resourceType, string $principal): void { |
|
100 | - $query = $this->db->getQueryBuilder(); |
|
101 | - $query->delete('dav_shares'); |
|
102 | - $query->where( |
|
103 | - $query->expr()->eq('resourceid', $query->createNamedParameter($resourceId, IQueryBuilder::PARAM_INT)), |
|
104 | - $query->expr()->eq('type', $query->createNamedParameter($resourceType)), |
|
105 | - $query->expr()->eq('principaluri', $query->createNamedParameter($principal)) |
|
106 | - ); |
|
107 | - $query->executeStatement(); |
|
108 | - |
|
109 | - } |
|
110 | - |
|
111 | - public function deleteAllShares(int $resourceId, string $resourceType): void { |
|
112 | - $query = $this->db->getQueryBuilder(); |
|
113 | - $query->delete('dav_shares') |
|
114 | - ->where($query->expr()->eq('resourceid', $query->createNamedParameter($resourceId))) |
|
115 | - ->andWhere($query->expr()->eq('type', $query->createNamedParameter($resourceType))) |
|
116 | - ->executeStatement(); |
|
117 | - } |
|
118 | - |
|
119 | - public function deleteAllSharesByUser(string $principaluri, string $resourceType): void { |
|
120 | - $query = $this->db->getQueryBuilder(); |
|
121 | - $query->delete('dav_shares') |
|
122 | - ->where($query->expr()->eq('principaluri', $query->createNamedParameter($principaluri))) |
|
123 | - ->andWhere($query->expr()->eq('type', $query->createNamedParameter($resourceType))) |
|
124 | - ->executeStatement(); |
|
125 | - } |
|
126 | - |
|
127 | - public function getSharesByPrincipals(array $principals, string $resourceType): array { |
|
128 | - $query = $this->db->getQueryBuilder(); |
|
129 | - $result = $query->select(['id', 'principaluri', 'type', 'access', 'resourceid']) |
|
130 | - ->from('dav_shares') |
|
131 | - ->where($query->expr()->in('principaluri', $query->createNamedParameter($principals, IQueryBuilder::PARAM_STR_ARRAY), IQueryBuilder::PARAM_STR_ARRAY)) |
|
132 | - ->andWhere($query->expr()->eq('type', $query->createNamedParameter($resourceType))) |
|
133 | - ->orderBy('id') |
|
134 | - ->executeQuery(); |
|
135 | - |
|
136 | - $rows = $result->fetchAll(); |
|
137 | - $result->closeCursor(); |
|
138 | - |
|
139 | - return $rows; |
|
140 | - } |
|
141 | - |
|
142 | - public function deleteUnsharesByPrincipal(string $principal, string $resourceType): void { |
|
143 | - $query = $this->db->getQueryBuilder(); |
|
144 | - $query->delete('dav_shares') |
|
145 | - ->where($query->expr()->eq('principaluri', $query->createNamedParameter($principal))) |
|
146 | - ->andWhere($query->expr()->eq('type', $query->createNamedParameter($resourceType))) |
|
147 | - ->andWhere($query->expr()->eq('access', $query->createNamedParameter(Backend::ACCESS_UNSHARED, IQueryBuilder::PARAM_INT))) |
|
148 | - ->executeStatement(); |
|
149 | - } |
|
150 | - |
|
151 | - /** |
|
152 | - * @return array{principaluri: string}[] |
|
153 | - * @throws \OCP\DB\Exception |
|
154 | - */ |
|
155 | - public function getPrincipalUrisByPrefix(string $resourceType, string $prefix): array { |
|
156 | - $query = $this->db->getQueryBuilder(); |
|
157 | - $result = $query->selectDistinct('principaluri') |
|
158 | - ->from('dav_shares') |
|
159 | - ->where($query->expr()->like( |
|
160 | - 'principaluri', |
|
161 | - $query->createNamedParameter("$prefix/%", IQueryBuilder::PARAM_STR), |
|
162 | - IQueryBuilder::PARAM_STR, |
|
163 | - )) |
|
164 | - ->andWhere($query->expr()->eq( |
|
165 | - 'type', |
|
166 | - $query->createNamedParameter($resourceType, IQueryBuilder::PARAM_STR)), |
|
167 | - IQueryBuilder::PARAM_STR, |
|
168 | - ) |
|
169 | - ->executeQuery(); |
|
170 | - |
|
171 | - $rows = $result->fetchAll(); |
|
172 | - $result->closeCursor(); |
|
173 | - |
|
174 | - return $rows; |
|
175 | - } |
|
176 | - |
|
177 | - /** |
|
178 | - * @psalm-return array{uri: string, principaluri: string}[] |
|
179 | - * @throws \OCP\DB\Exception |
|
180 | - */ |
|
181 | - public function getSharedCalendarsForRemoteUser( |
|
182 | - string $remoteUserPrincipalUri, |
|
183 | - string $token, |
|
184 | - ): array { |
|
185 | - $qb = $this->db->getQueryBuilder(); |
|
186 | - $qb->select('c.uri', 'c.principaluri') |
|
187 | - ->from('dav_shares', 'ds') |
|
188 | - ->join('ds', 'calendars', 'c', $qb->expr()->eq( |
|
189 | - 'ds.resourceid', |
|
190 | - 'c.id', |
|
191 | - IQueryBuilder::PARAM_INT, |
|
192 | - )) |
|
193 | - ->where($qb->expr()->eq( |
|
194 | - 'ds.type', |
|
195 | - $qb->createNamedParameter('calendar', IQueryBuilder::PARAM_STR), |
|
196 | - IQueryBuilder::PARAM_STR, |
|
197 | - )) |
|
198 | - ->andWhere($qb->expr()->eq( |
|
199 | - 'ds.principaluri', |
|
200 | - $qb->createNamedParameter($remoteUserPrincipalUri, IQueryBuilder::PARAM_STR), |
|
201 | - IQueryBuilder::PARAM_STR, |
|
202 | - )) |
|
203 | - ->andWhere($qb->expr()->eq( |
|
204 | - 'ds.token', |
|
205 | - $qb->createNamedParameter($token, IQueryBuilder::PARAM_STR), |
|
206 | - IQueryBuilder::PARAM_STR, |
|
207 | - )); |
|
208 | - $result = $qb->executeQuery(); |
|
209 | - $rows = $result->fetchAll(); |
|
210 | - $result->closeCursor(); |
|
211 | - |
|
212 | - return $rows; |
|
213 | - } |
|
214 | - |
|
215 | - /** |
|
216 | - * @param string[] $principalUris |
|
217 | - * |
|
218 | - * @throws \OCP\DB\Exception |
|
219 | - */ |
|
220 | - public function getSharesByPrincipalsAndResource( |
|
221 | - array $principalUris, |
|
222 | - int $resourceId, |
|
223 | - string $resourceType, |
|
224 | - ): array { |
|
225 | - $qb = $this->db->getQueryBuilder(); |
|
226 | - $qb->select('*') |
|
227 | - ->from('dav_shares') |
|
228 | - ->where($qb->expr()->in( |
|
229 | - 'principaluri', |
|
230 | - $qb->createNamedParameter($principalUris, IQueryBuilder::PARAM_STR_ARRAY), |
|
231 | - IQueryBuilder::PARAM_STR_ARRAY, |
|
232 | - )) |
|
233 | - ->andWhere($qb->expr()->eq( |
|
234 | - 'resourceid', |
|
235 | - $qb->createNamedParameter($resourceId, IQueryBuilder::PARAM_INT), |
|
236 | - IQueryBuilder::PARAM_INT, |
|
237 | - )) |
|
238 | - ->andWhere($qb->expr()->eq( |
|
239 | - 'type', |
|
240 | - $qb->createNamedParameter($resourceType, IQueryBuilder::PARAM_STR), |
|
241 | - IQueryBuilder::PARAM_STR, |
|
242 | - )); |
|
243 | - $result = $qb->executeQuery(); |
|
244 | - $rows = $result->fetchAll(); |
|
245 | - $result->closeCursor(); |
|
246 | - |
|
247 | - return $rows; |
|
248 | - } |
|
14 | + public function __construct( |
|
15 | + private IDBConnection $db, |
|
16 | + ) { |
|
17 | + } |
|
18 | + |
|
19 | + protected function getSharesForIdByAccess(int $resourceId, string $resourceType, bool $sharesWithAccess): array { |
|
20 | + $query = $this->db->getQueryBuilder(); |
|
21 | + $query->select(['principaluri', 'access']) |
|
22 | + ->from('dav_shares') |
|
23 | + ->where($query->expr()->eq('resourceid', $query->createNamedParameter($resourceId, IQueryBuilder::PARAM_INT))) |
|
24 | + ->andWhere($query->expr()->eq('type', $query->createNamedParameter($resourceType, IQueryBuilder::PARAM_STR))) |
|
25 | + ->groupBy(['principaluri', 'access']); |
|
26 | + |
|
27 | + if ($sharesWithAccess) { |
|
28 | + $query->andWhere($query->expr()->neq('access', $query->createNamedParameter(Backend::ACCESS_UNSHARED, IQueryBuilder::PARAM_INT))); |
|
29 | + } else { |
|
30 | + $query->andWhere($query->expr()->eq('access', $query->createNamedParameter(Backend::ACCESS_UNSHARED, IQueryBuilder::PARAM_INT))); |
|
31 | + } |
|
32 | + |
|
33 | + $result = $query->executeQuery(); |
|
34 | + $rows = $result->fetchAll(); |
|
35 | + $result->closeCursor(); |
|
36 | + return $rows; |
|
37 | + } |
|
38 | + |
|
39 | + public function getSharesForId(int $resourceId, string $resourceType): array { |
|
40 | + return $this->getSharesForIdByAccess($resourceId, $resourceType, true); |
|
41 | + } |
|
42 | + |
|
43 | + public function getUnsharesForId(int $resourceId, string $resourceType): array { |
|
44 | + return $this->getSharesForIdByAccess($resourceId, $resourceType, false); |
|
45 | + } |
|
46 | + |
|
47 | + public function getSharesForIds(array $resourceIds, string $resourceType): array { |
|
48 | + $query = $this->db->getQueryBuilder(); |
|
49 | + $result = $query->select(['resourceid', 'principaluri', 'access']) |
|
50 | + ->from('dav_shares') |
|
51 | + ->where($query->expr()->in('resourceid', $query->createNamedParameter($resourceIds, IQueryBuilder::PARAM_INT_ARRAY))) |
|
52 | + ->andWhere($query->expr()->eq('type', $query->createNamedParameter($resourceType))) |
|
53 | + ->andWhere($query->expr()->neq('access', $query->createNamedParameter(Backend::ACCESS_UNSHARED, IQueryBuilder::PARAM_INT))) |
|
54 | + ->groupBy(['principaluri', 'access', 'resourceid']) |
|
55 | + ->executeQuery(); |
|
56 | + |
|
57 | + $rows = $result->fetchAll(); |
|
58 | + $result->closeCursor(); |
|
59 | + return $rows; |
|
60 | + } |
|
61 | + |
|
62 | + public function unshare(int $resourceId, string $resourceType, string $principal): void { |
|
63 | + $query = $this->db->getQueryBuilder(); |
|
64 | + $query->insert('dav_shares') |
|
65 | + ->values([ |
|
66 | + 'principaluri' => $query->createNamedParameter($principal), |
|
67 | + 'type' => $query->createNamedParameter($resourceType), |
|
68 | + 'access' => $query->createNamedParameter(Backend::ACCESS_UNSHARED), |
|
69 | + 'resourceid' => $query->createNamedParameter($resourceId) |
|
70 | + ]); |
|
71 | + $query->executeStatement(); |
|
72 | + } |
|
73 | + |
|
74 | + public function share(int $resourceId, string $resourceType, int $access, string $principal): void { |
|
75 | + $query = $this->db->getQueryBuilder(); |
|
76 | + $query->insert('dav_shares') |
|
77 | + ->values([ |
|
78 | + 'principaluri' => $query->createNamedParameter($principal), |
|
79 | + 'type' => $query->createNamedParameter($resourceType), |
|
80 | + 'access' => $query->createNamedParameter($access), |
|
81 | + 'resourceid' => $query->createNamedParameter($resourceId) |
|
82 | + ]); |
|
83 | + $query->executeStatement(); |
|
84 | + } |
|
85 | + |
|
86 | + public function shareWithToken(int $resourceId, string $resourceType, int $access, string $principal, string $token): void { |
|
87 | + $query = $this->db->getQueryBuilder(); |
|
88 | + $query->insert('dav_shares') |
|
89 | + ->values([ |
|
90 | + 'principaluri' => $query->createNamedParameter($principal), |
|
91 | + 'type' => $query->createNamedParameter($resourceType), |
|
92 | + 'access' => $query->createNamedParameter($access), |
|
93 | + 'resourceid' => $query->createNamedParameter($resourceId), |
|
94 | + 'token' => $query->createNamedParameter($token), |
|
95 | + ]); |
|
96 | + $query->executeStatement(); |
|
97 | + } |
|
98 | + |
|
99 | + public function deleteShare(int $resourceId, string $resourceType, string $principal): void { |
|
100 | + $query = $this->db->getQueryBuilder(); |
|
101 | + $query->delete('dav_shares'); |
|
102 | + $query->where( |
|
103 | + $query->expr()->eq('resourceid', $query->createNamedParameter($resourceId, IQueryBuilder::PARAM_INT)), |
|
104 | + $query->expr()->eq('type', $query->createNamedParameter($resourceType)), |
|
105 | + $query->expr()->eq('principaluri', $query->createNamedParameter($principal)) |
|
106 | + ); |
|
107 | + $query->executeStatement(); |
|
108 | + |
|
109 | + } |
|
110 | + |
|
111 | + public function deleteAllShares(int $resourceId, string $resourceType): void { |
|
112 | + $query = $this->db->getQueryBuilder(); |
|
113 | + $query->delete('dav_shares') |
|
114 | + ->where($query->expr()->eq('resourceid', $query->createNamedParameter($resourceId))) |
|
115 | + ->andWhere($query->expr()->eq('type', $query->createNamedParameter($resourceType))) |
|
116 | + ->executeStatement(); |
|
117 | + } |
|
118 | + |
|
119 | + public function deleteAllSharesByUser(string $principaluri, string $resourceType): void { |
|
120 | + $query = $this->db->getQueryBuilder(); |
|
121 | + $query->delete('dav_shares') |
|
122 | + ->where($query->expr()->eq('principaluri', $query->createNamedParameter($principaluri))) |
|
123 | + ->andWhere($query->expr()->eq('type', $query->createNamedParameter($resourceType))) |
|
124 | + ->executeStatement(); |
|
125 | + } |
|
126 | + |
|
127 | + public function getSharesByPrincipals(array $principals, string $resourceType): array { |
|
128 | + $query = $this->db->getQueryBuilder(); |
|
129 | + $result = $query->select(['id', 'principaluri', 'type', 'access', 'resourceid']) |
|
130 | + ->from('dav_shares') |
|
131 | + ->where($query->expr()->in('principaluri', $query->createNamedParameter($principals, IQueryBuilder::PARAM_STR_ARRAY), IQueryBuilder::PARAM_STR_ARRAY)) |
|
132 | + ->andWhere($query->expr()->eq('type', $query->createNamedParameter($resourceType))) |
|
133 | + ->orderBy('id') |
|
134 | + ->executeQuery(); |
|
135 | + |
|
136 | + $rows = $result->fetchAll(); |
|
137 | + $result->closeCursor(); |
|
138 | + |
|
139 | + return $rows; |
|
140 | + } |
|
141 | + |
|
142 | + public function deleteUnsharesByPrincipal(string $principal, string $resourceType): void { |
|
143 | + $query = $this->db->getQueryBuilder(); |
|
144 | + $query->delete('dav_shares') |
|
145 | + ->where($query->expr()->eq('principaluri', $query->createNamedParameter($principal))) |
|
146 | + ->andWhere($query->expr()->eq('type', $query->createNamedParameter($resourceType))) |
|
147 | + ->andWhere($query->expr()->eq('access', $query->createNamedParameter(Backend::ACCESS_UNSHARED, IQueryBuilder::PARAM_INT))) |
|
148 | + ->executeStatement(); |
|
149 | + } |
|
150 | + |
|
151 | + /** |
|
152 | + * @return array{principaluri: string}[] |
|
153 | + * @throws \OCP\DB\Exception |
|
154 | + */ |
|
155 | + public function getPrincipalUrisByPrefix(string $resourceType, string $prefix): array { |
|
156 | + $query = $this->db->getQueryBuilder(); |
|
157 | + $result = $query->selectDistinct('principaluri') |
|
158 | + ->from('dav_shares') |
|
159 | + ->where($query->expr()->like( |
|
160 | + 'principaluri', |
|
161 | + $query->createNamedParameter("$prefix/%", IQueryBuilder::PARAM_STR), |
|
162 | + IQueryBuilder::PARAM_STR, |
|
163 | + )) |
|
164 | + ->andWhere($query->expr()->eq( |
|
165 | + 'type', |
|
166 | + $query->createNamedParameter($resourceType, IQueryBuilder::PARAM_STR)), |
|
167 | + IQueryBuilder::PARAM_STR, |
|
168 | + ) |
|
169 | + ->executeQuery(); |
|
170 | + |
|
171 | + $rows = $result->fetchAll(); |
|
172 | + $result->closeCursor(); |
|
173 | + |
|
174 | + return $rows; |
|
175 | + } |
|
176 | + |
|
177 | + /** |
|
178 | + * @psalm-return array{uri: string, principaluri: string}[] |
|
179 | + * @throws \OCP\DB\Exception |
|
180 | + */ |
|
181 | + public function getSharedCalendarsForRemoteUser( |
|
182 | + string $remoteUserPrincipalUri, |
|
183 | + string $token, |
|
184 | + ): array { |
|
185 | + $qb = $this->db->getQueryBuilder(); |
|
186 | + $qb->select('c.uri', 'c.principaluri') |
|
187 | + ->from('dav_shares', 'ds') |
|
188 | + ->join('ds', 'calendars', 'c', $qb->expr()->eq( |
|
189 | + 'ds.resourceid', |
|
190 | + 'c.id', |
|
191 | + IQueryBuilder::PARAM_INT, |
|
192 | + )) |
|
193 | + ->where($qb->expr()->eq( |
|
194 | + 'ds.type', |
|
195 | + $qb->createNamedParameter('calendar', IQueryBuilder::PARAM_STR), |
|
196 | + IQueryBuilder::PARAM_STR, |
|
197 | + )) |
|
198 | + ->andWhere($qb->expr()->eq( |
|
199 | + 'ds.principaluri', |
|
200 | + $qb->createNamedParameter($remoteUserPrincipalUri, IQueryBuilder::PARAM_STR), |
|
201 | + IQueryBuilder::PARAM_STR, |
|
202 | + )) |
|
203 | + ->andWhere($qb->expr()->eq( |
|
204 | + 'ds.token', |
|
205 | + $qb->createNamedParameter($token, IQueryBuilder::PARAM_STR), |
|
206 | + IQueryBuilder::PARAM_STR, |
|
207 | + )); |
|
208 | + $result = $qb->executeQuery(); |
|
209 | + $rows = $result->fetchAll(); |
|
210 | + $result->closeCursor(); |
|
211 | + |
|
212 | + return $rows; |
|
213 | + } |
|
214 | + |
|
215 | + /** |
|
216 | + * @param string[] $principalUris |
|
217 | + * |
|
218 | + * @throws \OCP\DB\Exception |
|
219 | + */ |
|
220 | + public function getSharesByPrincipalsAndResource( |
|
221 | + array $principalUris, |
|
222 | + int $resourceId, |
|
223 | + string $resourceType, |
|
224 | + ): array { |
|
225 | + $qb = $this->db->getQueryBuilder(); |
|
226 | + $qb->select('*') |
|
227 | + ->from('dav_shares') |
|
228 | + ->where($qb->expr()->in( |
|
229 | + 'principaluri', |
|
230 | + $qb->createNamedParameter($principalUris, IQueryBuilder::PARAM_STR_ARRAY), |
|
231 | + IQueryBuilder::PARAM_STR_ARRAY, |
|
232 | + )) |
|
233 | + ->andWhere($qb->expr()->eq( |
|
234 | + 'resourceid', |
|
235 | + $qb->createNamedParameter($resourceId, IQueryBuilder::PARAM_INT), |
|
236 | + IQueryBuilder::PARAM_INT, |
|
237 | + )) |
|
238 | + ->andWhere($qb->expr()->eq( |
|
239 | + 'type', |
|
240 | + $qb->createNamedParameter($resourceType, IQueryBuilder::PARAM_STR), |
|
241 | + IQueryBuilder::PARAM_STR, |
|
242 | + )); |
|
243 | + $result = $qb->executeQuery(); |
|
244 | + $rows = $result->fetchAll(); |
|
245 | + $result->closeCursor(); |
|
246 | + |
|
247 | + return $rows; |
|
248 | + } |
|
249 | 249 | } |
@@ -8,53 +8,53 @@ |
||
8 | 8 | namespace OCA\DAV\DAV\Sharing; |
9 | 9 | |
10 | 10 | abstract class SharingService { |
11 | - protected string $resourceType = ''; |
|
12 | - public function __construct( |
|
13 | - protected SharingMapper $mapper, |
|
14 | - ) { |
|
15 | - } |
|
16 | - |
|
17 | - public function getResourceType(): string { |
|
18 | - return $this->resourceType; |
|
19 | - } |
|
20 | - public function shareWith(int $resourceId, string $principal, int $access): void { |
|
21 | - // remove the share if it already exists |
|
22 | - $this->mapper->deleteShare($resourceId, $this->getResourceType(), $principal); |
|
23 | - $this->mapper->share($resourceId, $this->getResourceType(), $access, $principal); |
|
24 | - } |
|
25 | - |
|
26 | - public function unshare(int $resourceId, string $principal): void { |
|
27 | - $this->mapper->unshare($resourceId, $this->getResourceType(), $principal); |
|
28 | - } |
|
29 | - |
|
30 | - public function deleteShare(int $resourceId, string $principal): void { |
|
31 | - $this->mapper->deleteShare($resourceId, $this->getResourceType(), $principal); |
|
32 | - } |
|
33 | - |
|
34 | - public function deleteAllShares(int $resourceId): void { |
|
35 | - $this->mapper->deleteAllShares($resourceId, $this->getResourceType()); |
|
36 | - } |
|
37 | - |
|
38 | - public function deleteAllSharesByUser(string $principaluri): void { |
|
39 | - $this->mapper->deleteAllSharesByUser($principaluri, $this->getResourceType()); |
|
40 | - } |
|
41 | - |
|
42 | - public function getShares(int $resourceId): array { |
|
43 | - return $this->mapper->getSharesForId($resourceId, $this->getResourceType()); |
|
44 | - } |
|
45 | - |
|
46 | - public function getUnshares(int $resourceId): array { |
|
47 | - return $this->mapper->getUnsharesForId($resourceId, $this->getResourceType()); |
|
48 | - } |
|
49 | - |
|
50 | - public function getSharesForIds(array $resourceIds): array { |
|
51 | - return $this->mapper->getSharesForIds($resourceIds, $this->getResourceType()); |
|
52 | - } |
|
53 | - |
|
54 | - /** |
|
55 | - * @param string[] $principals |
|
56 | - */ |
|
57 | - public function getSharesByPrincipals(array $principals): array { |
|
58 | - return $this->mapper->getSharesByPrincipals($principals, $this->getResourceType()); |
|
59 | - } |
|
11 | + protected string $resourceType = ''; |
|
12 | + public function __construct( |
|
13 | + protected SharingMapper $mapper, |
|
14 | + ) { |
|
15 | + } |
|
16 | + |
|
17 | + public function getResourceType(): string { |
|
18 | + return $this->resourceType; |
|
19 | + } |
|
20 | + public function shareWith(int $resourceId, string $principal, int $access): void { |
|
21 | + // remove the share if it already exists |
|
22 | + $this->mapper->deleteShare($resourceId, $this->getResourceType(), $principal); |
|
23 | + $this->mapper->share($resourceId, $this->getResourceType(), $access, $principal); |
|
24 | + } |
|
25 | + |
|
26 | + public function unshare(int $resourceId, string $principal): void { |
|
27 | + $this->mapper->unshare($resourceId, $this->getResourceType(), $principal); |
|
28 | + } |
|
29 | + |
|
30 | + public function deleteShare(int $resourceId, string $principal): void { |
|
31 | + $this->mapper->deleteShare($resourceId, $this->getResourceType(), $principal); |
|
32 | + } |
|
33 | + |
|
34 | + public function deleteAllShares(int $resourceId): void { |
|
35 | + $this->mapper->deleteAllShares($resourceId, $this->getResourceType()); |
|
36 | + } |
|
37 | + |
|
38 | + public function deleteAllSharesByUser(string $principaluri): void { |
|
39 | + $this->mapper->deleteAllSharesByUser($principaluri, $this->getResourceType()); |
|
40 | + } |
|
41 | + |
|
42 | + public function getShares(int $resourceId): array { |
|
43 | + return $this->mapper->getSharesForId($resourceId, $this->getResourceType()); |
|
44 | + } |
|
45 | + |
|
46 | + public function getUnshares(int $resourceId): array { |
|
47 | + return $this->mapper->getUnsharesForId($resourceId, $this->getResourceType()); |
|
48 | + } |
|
49 | + |
|
50 | + public function getSharesForIds(array $resourceIds): array { |
|
51 | + return $this->mapper->getSharesForIds($resourceIds, $this->getResourceType()); |
|
52 | + } |
|
53 | + |
|
54 | + /** |
|
55 | + * @param string[] $principals |
|
56 | + */ |
|
57 | + public function getSharesByPrincipals(array $principals): array { |
|
58 | + return $this->mapper->getSharesByPrincipals($principals, $this->getResourceType()); |
|
59 | + } |
|
60 | 60 | } |
@@ -19,250 +19,250 @@ |
||
19 | 19 | use Psr\Log\LoggerInterface; |
20 | 20 | |
21 | 21 | abstract class Backend { |
22 | - use TTransactional; |
|
23 | - public const ACCESS_OWNER = 1; |
|
24 | - |
|
25 | - public const ACCESS_READ_WRITE = 2; |
|
26 | - public const ACCESS_READ = 3; |
|
27 | - // 4 is already in use for public calendars |
|
28 | - public const ACCESS_UNSHARED = 5; |
|
29 | - |
|
30 | - private ICache $shareCache; |
|
31 | - |
|
32 | - public function __construct( |
|
33 | - private IUserManager $userManager, |
|
34 | - private IGroupManager $groupManager, |
|
35 | - private Principal $principalBackend, |
|
36 | - private RemoteUserPrincipalBackend $remoteUserPrincipalBackend, |
|
37 | - private ICacheFactory $cacheFactory, |
|
38 | - private SharingService $service, |
|
39 | - // TODO: Make `FederationSharingService` abstract once we support federated address book |
|
40 | - // sharing. The abstract sharing backend should not take a service scoped to calendars |
|
41 | - // by default. |
|
42 | - private FederationSharingService $federationSharingService, |
|
43 | - private LoggerInterface $logger, |
|
44 | - ) { |
|
45 | - $this->shareCache = $this->cacheFactory->createInMemory(); |
|
46 | - } |
|
47 | - |
|
48 | - /** |
|
49 | - * @param list<array{href: string, commonName: string, readOnly: bool}> $add |
|
50 | - * @param list<string> $remove |
|
51 | - */ |
|
52 | - public function updateShares(IShareable $shareable, array $add, array $remove, array $oldShares = []): void { |
|
53 | - $this->shareCache->clear(); |
|
54 | - foreach ($add as $element) { |
|
55 | - // Hacky code below ... shouldn't we check the whole (principal) root collection instead? |
|
56 | - $principal = $this->principalBackend->findByUri($element['href'], '') |
|
57 | - ?? $this->remoteUserPrincipalBackend->findByUri($element['href'], ''); |
|
58 | - if (empty($principal)) { |
|
59 | - continue; |
|
60 | - } |
|
61 | - |
|
62 | - // We need to validate manually because some principals are only virtual |
|
63 | - // i.e. Group principals |
|
64 | - $principalparts = explode('/', $principal, 3); |
|
65 | - if (count($principalparts) !== 3 || $principalparts[0] !== 'principals' || !in_array($principalparts[1], ['users', 'groups', 'circles', 'remote-users'], true)) { |
|
66 | - // Invalid principal |
|
67 | - continue; |
|
68 | - } |
|
69 | - |
|
70 | - // Don't add share for owner |
|
71 | - if ($shareable->getOwner() !== null && strcasecmp($shareable->getOwner(), $principal) === 0) { |
|
72 | - continue; |
|
73 | - } |
|
74 | - |
|
75 | - $principalparts[2] = urldecode($principalparts[2]); |
|
76 | - if (($principalparts[1] === 'users' && !$this->userManager->userExists($principalparts[2])) |
|
77 | - || ($principalparts[1] === 'groups' && !$this->groupManager->groupExists($principalparts[2]))) { |
|
78 | - // User or group does not exist |
|
79 | - continue; |
|
80 | - } |
|
81 | - |
|
82 | - $access = Backend::ACCESS_READ; |
|
83 | - if (isset($element['readOnly'])) { |
|
84 | - $access = $element['readOnly'] ? Backend::ACCESS_READ : Backend::ACCESS_READ_WRITE; |
|
85 | - } |
|
86 | - |
|
87 | - if ($principalparts[1] === 'remote-users') { |
|
88 | - $this->federationSharingService->shareWith($shareable, $principal, $access); |
|
89 | - } else { |
|
90 | - $this->service->shareWith($shareable->getResourceId(), $principal, $access); |
|
91 | - } |
|
92 | - } |
|
93 | - foreach ($remove as $element) { |
|
94 | - // Hacky code below ... shouldn't we check the whole (principal) root collection instead? |
|
95 | - $principal = $this->principalBackend->findByUri($element, '') |
|
96 | - ?? $this->remoteUserPrincipalBackend->findByUri($element, ''); |
|
97 | - if (empty($principal)) { |
|
98 | - continue; |
|
99 | - } |
|
100 | - |
|
101 | - // Don't add unshare for owner |
|
102 | - if ($shareable->getOwner() !== null && strcasecmp($shareable->getOwner(), $principal) === 0) { |
|
103 | - continue; |
|
104 | - } |
|
105 | - |
|
106 | - // Delete any possible direct shares (since the frontend does not separate between them) |
|
107 | - $this->service->deleteShare($shareable->getResourceId(), $principal); |
|
108 | - } |
|
109 | - } |
|
110 | - |
|
111 | - public function deleteAllShares(int $resourceId): void { |
|
112 | - $this->shareCache->clear(); |
|
113 | - $this->service->deleteAllShares($resourceId); |
|
114 | - } |
|
115 | - |
|
116 | - public function deleteAllSharesByUser(string $principaluri): void { |
|
117 | - $this->shareCache->clear(); |
|
118 | - $this->service->deleteAllSharesByUser($principaluri); |
|
119 | - } |
|
120 | - |
|
121 | - /** |
|
122 | - * Returns the list of people whom this resource is shared with. |
|
123 | - * |
|
124 | - * Every element in this array should have the following properties: |
|
125 | - * * href - Often a mailto: address |
|
126 | - * * commonName - Optional, for example a first + last name |
|
127 | - * * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants. |
|
128 | - * * readOnly - boolean |
|
129 | - * |
|
130 | - * @param int $resourceId |
|
131 | - * @return list<array{href: string, commonName: string, status: int, readOnly: bool, '{http://owncloud.org/ns}principal': string, '{http://owncloud.org/ns}group-share': bool}> |
|
132 | - */ |
|
133 | - public function getShares(int $resourceId): array { |
|
134 | - $cached = $this->shareCache->get((string)$resourceId); |
|
135 | - if ($cached) { |
|
136 | - return $cached; |
|
137 | - } |
|
138 | - |
|
139 | - $rows = $this->service->getShares($resourceId); |
|
140 | - $shares = []; |
|
141 | - foreach ($rows as $row) { |
|
142 | - $p = $this->getPrincipalByPath($row['principaluri']); |
|
143 | - $shares[] = [ |
|
144 | - 'href' => "principal:{$row['principaluri']}", |
|
145 | - 'commonName' => isset($p['{DAV:}displayname']) ? (string)$p['{DAV:}displayname'] : '', |
|
146 | - 'status' => 1, |
|
147 | - 'readOnly' => (int)$row['access'] === Backend::ACCESS_READ, |
|
148 | - '{http://owncloud.org/ns}principal' => (string)$row['principaluri'], |
|
149 | - '{http://owncloud.org/ns}group-share' => isset($p['uri']) && (str_starts_with($p['uri'], 'principals/groups') || str_starts_with($p['uri'], 'principals/circles')), |
|
150 | - ]; |
|
151 | - } |
|
152 | - $this->shareCache->set((string)$resourceId, $shares); |
|
153 | - return $shares; |
|
154 | - } |
|
155 | - |
|
156 | - public function preloadShares(array $resourceIds): void { |
|
157 | - $resourceIds = array_filter($resourceIds, function (int $resourceId) { |
|
158 | - return empty($this->shareCache->get((string)$resourceId)); |
|
159 | - }); |
|
160 | - if (empty($resourceIds)) { |
|
161 | - return; |
|
162 | - } |
|
163 | - |
|
164 | - $rows = $this->service->getSharesForIds($resourceIds); |
|
165 | - $sharesByResource = array_fill_keys($resourceIds, []); |
|
166 | - foreach ($rows as $row) { |
|
167 | - $resourceId = (int)$row['resourceid']; |
|
168 | - $p = $this->getPrincipalByPath($row['principaluri']); |
|
169 | - $sharesByResource[$resourceId][] = [ |
|
170 | - 'href' => "principal:{$row['principaluri']}", |
|
171 | - 'commonName' => isset($p['{DAV:}displayname']) ? (string)$p['{DAV:}displayname'] : '', |
|
172 | - 'status' => 1, |
|
173 | - 'readOnly' => (int)$row['access'] === self::ACCESS_READ, |
|
174 | - '{http://owncloud.org/ns}principal' => (string)$row['principaluri'], |
|
175 | - '{http://owncloud.org/ns}group-share' => isset($p['uri']) && str_starts_with($p['uri'], 'principals/groups') |
|
176 | - ]; |
|
177 | - $this->shareCache->set((string)$resourceId, $sharesByResource[$resourceId]); |
|
178 | - } |
|
179 | - } |
|
180 | - |
|
181 | - /** |
|
182 | - * For shared resources the sharee is set in the ACL of the resource |
|
183 | - * |
|
184 | - * @param int $resourceId |
|
185 | - * @param list<array{privilege: string, principal: string, protected: bool}> $acl |
|
186 | - * @param list<array{href: string, commonName: string, status: int, readOnly: bool, '{http://owncloud.org/ns}principal': string, '{http://owncloud.org/ns}group-share': bool}> $shares |
|
187 | - * @return list<array{principal: string, privilege: string, protected: bool}> |
|
188 | - */ |
|
189 | - public function applyShareAcl(array $shares, array $acl): array { |
|
190 | - foreach ($shares as $share) { |
|
191 | - $acl[] = [ |
|
192 | - 'privilege' => '{DAV:}read', |
|
193 | - 'principal' => $share['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}principal'], |
|
194 | - 'protected' => true, |
|
195 | - ]; |
|
196 | - if (!$share['readOnly']) { |
|
197 | - $acl[] = [ |
|
198 | - 'privilege' => '{DAV:}write', |
|
199 | - 'principal' => $share['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}principal'], |
|
200 | - 'protected' => true, |
|
201 | - ]; |
|
202 | - } elseif (in_array($this->service->getResourceType(), ['calendar','addressbook'])) { |
|
203 | - // Allow changing the properties of read only calendars, |
|
204 | - // so users can change the visibility. |
|
205 | - $acl[] = [ |
|
206 | - 'privilege' => '{DAV:}write-properties', |
|
207 | - 'principal' => $share['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}principal'], |
|
208 | - 'protected' => true, |
|
209 | - ]; |
|
210 | - } |
|
211 | - } |
|
212 | - return $acl; |
|
213 | - } |
|
214 | - |
|
215 | - public function unshare(IShareable $shareable, string $principalUri): bool { |
|
216 | - $this->shareCache->clear(); |
|
217 | - |
|
218 | - $principal = $this->principalBackend->findByUri($principalUri, ''); |
|
219 | - if (empty($principal)) { |
|
220 | - return false; |
|
221 | - } |
|
222 | - |
|
223 | - if ($shareable->getOwner() === $principal) { |
|
224 | - return false; |
|
225 | - } |
|
226 | - |
|
227 | - // Delete any possible direct shares (since the frontend does not separate between them) |
|
228 | - $this->service->deleteShare($shareable->getResourceId(), $principal); |
|
229 | - |
|
230 | - $needsUnshare = $this->hasAccessByGroupOrCirclesMembership( |
|
231 | - $shareable->getResourceId(), |
|
232 | - $principal |
|
233 | - ); |
|
234 | - |
|
235 | - if ($needsUnshare) { |
|
236 | - $this->service->unshare($shareable->getResourceId(), $principal); |
|
237 | - } |
|
238 | - |
|
239 | - return true; |
|
240 | - } |
|
241 | - |
|
242 | - private function hasAccessByGroupOrCirclesMembership(int $resourceId, string $principal) { |
|
243 | - $memberships = array_merge( |
|
244 | - $this->principalBackend->getGroupMembership($principal, true), |
|
245 | - $this->principalBackend->getCircleMembership($principal) |
|
246 | - ); |
|
247 | - |
|
248 | - $shares = array_column( |
|
249 | - $this->service->getShares($resourceId), |
|
250 | - 'principaluri' |
|
251 | - ); |
|
252 | - |
|
253 | - return count(array_intersect($memberships, $shares)) > 0; |
|
254 | - } |
|
255 | - |
|
256 | - public function getSharesByShareePrincipal(string $principal): array { |
|
257 | - return $this->service->getSharesByPrincipals([$principal]); |
|
258 | - } |
|
259 | - |
|
260 | - private function getPrincipalByPath(string $principalUri): ?array { |
|
261 | - // Hacky code below ... shouldn't we check the whole (principal) root collection instead? |
|
262 | - if (str_starts_with($principalUri, RemoteUserPrincipalBackend::PRINCIPAL_PREFIX)) { |
|
263 | - return $this->remoteUserPrincipalBackend->getPrincipalByPath($principalUri); |
|
264 | - } |
|
265 | - |
|
266 | - return $this->principalBackend->getPrincipalByPath($principalUri); |
|
267 | - } |
|
22 | + use TTransactional; |
|
23 | + public const ACCESS_OWNER = 1; |
|
24 | + |
|
25 | + public const ACCESS_READ_WRITE = 2; |
|
26 | + public const ACCESS_READ = 3; |
|
27 | + // 4 is already in use for public calendars |
|
28 | + public const ACCESS_UNSHARED = 5; |
|
29 | + |
|
30 | + private ICache $shareCache; |
|
31 | + |
|
32 | + public function __construct( |
|
33 | + private IUserManager $userManager, |
|
34 | + private IGroupManager $groupManager, |
|
35 | + private Principal $principalBackend, |
|
36 | + private RemoteUserPrincipalBackend $remoteUserPrincipalBackend, |
|
37 | + private ICacheFactory $cacheFactory, |
|
38 | + private SharingService $service, |
|
39 | + // TODO: Make `FederationSharingService` abstract once we support federated address book |
|
40 | + // sharing. The abstract sharing backend should not take a service scoped to calendars |
|
41 | + // by default. |
|
42 | + private FederationSharingService $federationSharingService, |
|
43 | + private LoggerInterface $logger, |
|
44 | + ) { |
|
45 | + $this->shareCache = $this->cacheFactory->createInMemory(); |
|
46 | + } |
|
47 | + |
|
48 | + /** |
|
49 | + * @param list<array{href: string, commonName: string, readOnly: bool}> $add |
|
50 | + * @param list<string> $remove |
|
51 | + */ |
|
52 | + public function updateShares(IShareable $shareable, array $add, array $remove, array $oldShares = []): void { |
|
53 | + $this->shareCache->clear(); |
|
54 | + foreach ($add as $element) { |
|
55 | + // Hacky code below ... shouldn't we check the whole (principal) root collection instead? |
|
56 | + $principal = $this->principalBackend->findByUri($element['href'], '') |
|
57 | + ?? $this->remoteUserPrincipalBackend->findByUri($element['href'], ''); |
|
58 | + if (empty($principal)) { |
|
59 | + continue; |
|
60 | + } |
|
61 | + |
|
62 | + // We need to validate manually because some principals are only virtual |
|
63 | + // i.e. Group principals |
|
64 | + $principalparts = explode('/', $principal, 3); |
|
65 | + if (count($principalparts) !== 3 || $principalparts[0] !== 'principals' || !in_array($principalparts[1], ['users', 'groups', 'circles', 'remote-users'], true)) { |
|
66 | + // Invalid principal |
|
67 | + continue; |
|
68 | + } |
|
69 | + |
|
70 | + // Don't add share for owner |
|
71 | + if ($shareable->getOwner() !== null && strcasecmp($shareable->getOwner(), $principal) === 0) { |
|
72 | + continue; |
|
73 | + } |
|
74 | + |
|
75 | + $principalparts[2] = urldecode($principalparts[2]); |
|
76 | + if (($principalparts[1] === 'users' && !$this->userManager->userExists($principalparts[2])) |
|
77 | + || ($principalparts[1] === 'groups' && !$this->groupManager->groupExists($principalparts[2]))) { |
|
78 | + // User or group does not exist |
|
79 | + continue; |
|
80 | + } |
|
81 | + |
|
82 | + $access = Backend::ACCESS_READ; |
|
83 | + if (isset($element['readOnly'])) { |
|
84 | + $access = $element['readOnly'] ? Backend::ACCESS_READ : Backend::ACCESS_READ_WRITE; |
|
85 | + } |
|
86 | + |
|
87 | + if ($principalparts[1] === 'remote-users') { |
|
88 | + $this->federationSharingService->shareWith($shareable, $principal, $access); |
|
89 | + } else { |
|
90 | + $this->service->shareWith($shareable->getResourceId(), $principal, $access); |
|
91 | + } |
|
92 | + } |
|
93 | + foreach ($remove as $element) { |
|
94 | + // Hacky code below ... shouldn't we check the whole (principal) root collection instead? |
|
95 | + $principal = $this->principalBackend->findByUri($element, '') |
|
96 | + ?? $this->remoteUserPrincipalBackend->findByUri($element, ''); |
|
97 | + if (empty($principal)) { |
|
98 | + continue; |
|
99 | + } |
|
100 | + |
|
101 | + // Don't add unshare for owner |
|
102 | + if ($shareable->getOwner() !== null && strcasecmp($shareable->getOwner(), $principal) === 0) { |
|
103 | + continue; |
|
104 | + } |
|
105 | + |
|
106 | + // Delete any possible direct shares (since the frontend does not separate between them) |
|
107 | + $this->service->deleteShare($shareable->getResourceId(), $principal); |
|
108 | + } |
|
109 | + } |
|
110 | + |
|
111 | + public function deleteAllShares(int $resourceId): void { |
|
112 | + $this->shareCache->clear(); |
|
113 | + $this->service->deleteAllShares($resourceId); |
|
114 | + } |
|
115 | + |
|
116 | + public function deleteAllSharesByUser(string $principaluri): void { |
|
117 | + $this->shareCache->clear(); |
|
118 | + $this->service->deleteAllSharesByUser($principaluri); |
|
119 | + } |
|
120 | + |
|
121 | + /** |
|
122 | + * Returns the list of people whom this resource is shared with. |
|
123 | + * |
|
124 | + * Every element in this array should have the following properties: |
|
125 | + * * href - Often a mailto: address |
|
126 | + * * commonName - Optional, for example a first + last name |
|
127 | + * * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants. |
|
128 | + * * readOnly - boolean |
|
129 | + * |
|
130 | + * @param int $resourceId |
|
131 | + * @return list<array{href: string, commonName: string, status: int, readOnly: bool, '{http://owncloud.org/ns}principal': string, '{http://owncloud.org/ns}group-share': bool}> |
|
132 | + */ |
|
133 | + public function getShares(int $resourceId): array { |
|
134 | + $cached = $this->shareCache->get((string)$resourceId); |
|
135 | + if ($cached) { |
|
136 | + return $cached; |
|
137 | + } |
|
138 | + |
|
139 | + $rows = $this->service->getShares($resourceId); |
|
140 | + $shares = []; |
|
141 | + foreach ($rows as $row) { |
|
142 | + $p = $this->getPrincipalByPath($row['principaluri']); |
|
143 | + $shares[] = [ |
|
144 | + 'href' => "principal:{$row['principaluri']}", |
|
145 | + 'commonName' => isset($p['{DAV:}displayname']) ? (string)$p['{DAV:}displayname'] : '', |
|
146 | + 'status' => 1, |
|
147 | + 'readOnly' => (int)$row['access'] === Backend::ACCESS_READ, |
|
148 | + '{http://owncloud.org/ns}principal' => (string)$row['principaluri'], |
|
149 | + '{http://owncloud.org/ns}group-share' => isset($p['uri']) && (str_starts_with($p['uri'], 'principals/groups') || str_starts_with($p['uri'], 'principals/circles')), |
|
150 | + ]; |
|
151 | + } |
|
152 | + $this->shareCache->set((string)$resourceId, $shares); |
|
153 | + return $shares; |
|
154 | + } |
|
155 | + |
|
156 | + public function preloadShares(array $resourceIds): void { |
|
157 | + $resourceIds = array_filter($resourceIds, function (int $resourceId) { |
|
158 | + return empty($this->shareCache->get((string)$resourceId)); |
|
159 | + }); |
|
160 | + if (empty($resourceIds)) { |
|
161 | + return; |
|
162 | + } |
|
163 | + |
|
164 | + $rows = $this->service->getSharesForIds($resourceIds); |
|
165 | + $sharesByResource = array_fill_keys($resourceIds, []); |
|
166 | + foreach ($rows as $row) { |
|
167 | + $resourceId = (int)$row['resourceid']; |
|
168 | + $p = $this->getPrincipalByPath($row['principaluri']); |
|
169 | + $sharesByResource[$resourceId][] = [ |
|
170 | + 'href' => "principal:{$row['principaluri']}", |
|
171 | + 'commonName' => isset($p['{DAV:}displayname']) ? (string)$p['{DAV:}displayname'] : '', |
|
172 | + 'status' => 1, |
|
173 | + 'readOnly' => (int)$row['access'] === self::ACCESS_READ, |
|
174 | + '{http://owncloud.org/ns}principal' => (string)$row['principaluri'], |
|
175 | + '{http://owncloud.org/ns}group-share' => isset($p['uri']) && str_starts_with($p['uri'], 'principals/groups') |
|
176 | + ]; |
|
177 | + $this->shareCache->set((string)$resourceId, $sharesByResource[$resourceId]); |
|
178 | + } |
|
179 | + } |
|
180 | + |
|
181 | + /** |
|
182 | + * For shared resources the sharee is set in the ACL of the resource |
|
183 | + * |
|
184 | + * @param int $resourceId |
|
185 | + * @param list<array{privilege: string, principal: string, protected: bool}> $acl |
|
186 | + * @param list<array{href: string, commonName: string, status: int, readOnly: bool, '{http://owncloud.org/ns}principal': string, '{http://owncloud.org/ns}group-share': bool}> $shares |
|
187 | + * @return list<array{principal: string, privilege: string, protected: bool}> |
|
188 | + */ |
|
189 | + public function applyShareAcl(array $shares, array $acl): array { |
|
190 | + foreach ($shares as $share) { |
|
191 | + $acl[] = [ |
|
192 | + 'privilege' => '{DAV:}read', |
|
193 | + 'principal' => $share['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}principal'], |
|
194 | + 'protected' => true, |
|
195 | + ]; |
|
196 | + if (!$share['readOnly']) { |
|
197 | + $acl[] = [ |
|
198 | + 'privilege' => '{DAV:}write', |
|
199 | + 'principal' => $share['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}principal'], |
|
200 | + 'protected' => true, |
|
201 | + ]; |
|
202 | + } elseif (in_array($this->service->getResourceType(), ['calendar','addressbook'])) { |
|
203 | + // Allow changing the properties of read only calendars, |
|
204 | + // so users can change the visibility. |
|
205 | + $acl[] = [ |
|
206 | + 'privilege' => '{DAV:}write-properties', |
|
207 | + 'principal' => $share['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}principal'], |
|
208 | + 'protected' => true, |
|
209 | + ]; |
|
210 | + } |
|
211 | + } |
|
212 | + return $acl; |
|
213 | + } |
|
214 | + |
|
215 | + public function unshare(IShareable $shareable, string $principalUri): bool { |
|
216 | + $this->shareCache->clear(); |
|
217 | + |
|
218 | + $principal = $this->principalBackend->findByUri($principalUri, ''); |
|
219 | + if (empty($principal)) { |
|
220 | + return false; |
|
221 | + } |
|
222 | + |
|
223 | + if ($shareable->getOwner() === $principal) { |
|
224 | + return false; |
|
225 | + } |
|
226 | + |
|
227 | + // Delete any possible direct shares (since the frontend does not separate between them) |
|
228 | + $this->service->deleteShare($shareable->getResourceId(), $principal); |
|
229 | + |
|
230 | + $needsUnshare = $this->hasAccessByGroupOrCirclesMembership( |
|
231 | + $shareable->getResourceId(), |
|
232 | + $principal |
|
233 | + ); |
|
234 | + |
|
235 | + if ($needsUnshare) { |
|
236 | + $this->service->unshare($shareable->getResourceId(), $principal); |
|
237 | + } |
|
238 | + |
|
239 | + return true; |
|
240 | + } |
|
241 | + |
|
242 | + private function hasAccessByGroupOrCirclesMembership(int $resourceId, string $principal) { |
|
243 | + $memberships = array_merge( |
|
244 | + $this->principalBackend->getGroupMembership($principal, true), |
|
245 | + $this->principalBackend->getCircleMembership($principal) |
|
246 | + ); |
|
247 | + |
|
248 | + $shares = array_column( |
|
249 | + $this->service->getShares($resourceId), |
|
250 | + 'principaluri' |
|
251 | + ); |
|
252 | + |
|
253 | + return count(array_intersect($memberships, $shares)) > 0; |
|
254 | + } |
|
255 | + |
|
256 | + public function getSharesByShareePrincipal(string $principal): array { |
|
257 | + return $this->service->getSharesByPrincipals([$principal]); |
|
258 | + } |
|
259 | + |
|
260 | + private function getPrincipalByPath(string $principalUri): ?array { |
|
261 | + // Hacky code below ... shouldn't we check the whole (principal) root collection instead? |
|
262 | + if (str_starts_with($principalUri, RemoteUserPrincipalBackend::PRINCIPAL_PREFIX)) { |
|
263 | + return $this->remoteUserPrincipalBackend->getPrincipalByPath($principalUri); |
|
264 | + } |
|
265 | + |
|
266 | + return $this->principalBackend->getPrincipalByPath($principalUri); |
|
267 | + } |
|
268 | 268 | } |
@@ -131,7 +131,7 @@ discard block |
||
131 | 131 | * @return list<array{href: string, commonName: string, status: int, readOnly: bool, '{http://owncloud.org/ns}principal': string, '{http://owncloud.org/ns}group-share': bool}> |
132 | 132 | */ |
133 | 133 | public function getShares(int $resourceId): array { |
134 | - $cached = $this->shareCache->get((string)$resourceId); |
|
134 | + $cached = $this->shareCache->get((string) $resourceId); |
|
135 | 135 | if ($cached) { |
136 | 136 | return $cached; |
137 | 137 | } |
@@ -142,20 +142,20 @@ discard block |
||
142 | 142 | $p = $this->getPrincipalByPath($row['principaluri']); |
143 | 143 | $shares[] = [ |
144 | 144 | 'href' => "principal:{$row['principaluri']}", |
145 | - 'commonName' => isset($p['{DAV:}displayname']) ? (string)$p['{DAV:}displayname'] : '', |
|
145 | + 'commonName' => isset($p['{DAV:}displayname']) ? (string) $p['{DAV:}displayname'] : '', |
|
146 | 146 | 'status' => 1, |
147 | - 'readOnly' => (int)$row['access'] === Backend::ACCESS_READ, |
|
148 | - '{http://owncloud.org/ns}principal' => (string)$row['principaluri'], |
|
147 | + 'readOnly' => (int) $row['access'] === Backend::ACCESS_READ, |
|
148 | + '{http://owncloud.org/ns}principal' => (string) $row['principaluri'], |
|
149 | 149 | '{http://owncloud.org/ns}group-share' => isset($p['uri']) && (str_starts_with($p['uri'], 'principals/groups') || str_starts_with($p['uri'], 'principals/circles')), |
150 | 150 | ]; |
151 | 151 | } |
152 | - $this->shareCache->set((string)$resourceId, $shares); |
|
152 | + $this->shareCache->set((string) $resourceId, $shares); |
|
153 | 153 | return $shares; |
154 | 154 | } |
155 | 155 | |
156 | 156 | public function preloadShares(array $resourceIds): void { |
157 | - $resourceIds = array_filter($resourceIds, function (int $resourceId) { |
|
158 | - return empty($this->shareCache->get((string)$resourceId)); |
|
157 | + $resourceIds = array_filter($resourceIds, function(int $resourceId) { |
|
158 | + return empty($this->shareCache->get((string) $resourceId)); |
|
159 | 159 | }); |
160 | 160 | if (empty($resourceIds)) { |
161 | 161 | return; |
@@ -164,17 +164,17 @@ discard block |
||
164 | 164 | $rows = $this->service->getSharesForIds($resourceIds); |
165 | 165 | $sharesByResource = array_fill_keys($resourceIds, []); |
166 | 166 | foreach ($rows as $row) { |
167 | - $resourceId = (int)$row['resourceid']; |
|
167 | + $resourceId = (int) $row['resourceid']; |
|
168 | 168 | $p = $this->getPrincipalByPath($row['principaluri']); |
169 | 169 | $sharesByResource[$resourceId][] = [ |
170 | 170 | 'href' => "principal:{$row['principaluri']}", |
171 | - 'commonName' => isset($p['{DAV:}displayname']) ? (string)$p['{DAV:}displayname'] : '', |
|
171 | + 'commonName' => isset($p['{DAV:}displayname']) ? (string) $p['{DAV:}displayname'] : '', |
|
172 | 172 | 'status' => 1, |
173 | - 'readOnly' => (int)$row['access'] === self::ACCESS_READ, |
|
174 | - '{http://owncloud.org/ns}principal' => (string)$row['principaluri'], |
|
173 | + 'readOnly' => (int) $row['access'] === self::ACCESS_READ, |
|
174 | + '{http://owncloud.org/ns}principal' => (string) $row['principaluri'], |
|
175 | 175 | '{http://owncloud.org/ns}group-share' => isset($p['uri']) && str_starts_with($p['uri'], 'principals/groups') |
176 | 176 | ]; |
177 | - $this->shareCache->set((string)$resourceId, $sharesByResource[$resourceId]); |
|
177 | + $this->shareCache->set((string) $resourceId, $sharesByResource[$resourceId]); |
|
178 | 178 | } |
179 | 179 | } |
180 | 180 | |
@@ -190,21 +190,21 @@ discard block |
||
190 | 190 | foreach ($shares as $share) { |
191 | 191 | $acl[] = [ |
192 | 192 | 'privilege' => '{DAV:}read', |
193 | - 'principal' => $share['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}principal'], |
|
193 | + 'principal' => $share['{'.\OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD.'}principal'], |
|
194 | 194 | 'protected' => true, |
195 | 195 | ]; |
196 | 196 | if (!$share['readOnly']) { |
197 | 197 | $acl[] = [ |
198 | 198 | 'privilege' => '{DAV:}write', |
199 | - 'principal' => $share['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}principal'], |
|
199 | + 'principal' => $share['{'.\OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD.'}principal'], |
|
200 | 200 | 'protected' => true, |
201 | 201 | ]; |
202 | - } elseif (in_array($this->service->getResourceType(), ['calendar','addressbook'])) { |
|
202 | + } elseif (in_array($this->service->getResourceType(), ['calendar', 'addressbook'])) { |
|
203 | 203 | // Allow changing the properties of read only calendars, |
204 | 204 | // so users can change the visibility. |
205 | 205 | $acl[] = [ |
206 | 206 | 'privilege' => '{DAV:}write-properties', |
207 | - 'principal' => $share['{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}principal'], |
|
207 | + 'principal' => $share['{'.\OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD.'}principal'], |
|
208 | 208 | 'protected' => true, |
209 | 209 | ]; |
210 | 210 | } |
@@ -18,16 +18,16 @@ |
||
18 | 18 | use Psr\Log\LoggerInterface; |
19 | 19 | |
20 | 20 | class Backend extends SharingBackend { |
21 | - public function __construct( |
|
22 | - private IUserManager $userManager, |
|
23 | - private IGroupManager $groupManager, |
|
24 | - private Principal $principalBackend, |
|
25 | - private RemoteUserPrincipalBackend $remoteUserPrincipalBackend, |
|
26 | - private ICacheFactory $cacheFactory, |
|
27 | - private Service $service, |
|
28 | - private FederationSharingService $federationSharingService, |
|
29 | - private LoggerInterface $logger, |
|
30 | - ) { |
|
31 | - parent::__construct($this->userManager, $this->groupManager, $this->principalBackend, $this->remoteUserPrincipalBackend, $this->cacheFactory, $this->service, $this->federationSharingService, $this->logger); |
|
32 | - } |
|
21 | + public function __construct( |
|
22 | + private IUserManager $userManager, |
|
23 | + private IGroupManager $groupManager, |
|
24 | + private Principal $principalBackend, |
|
25 | + private RemoteUserPrincipalBackend $remoteUserPrincipalBackend, |
|
26 | + private ICacheFactory $cacheFactory, |
|
27 | + private Service $service, |
|
28 | + private FederationSharingService $federationSharingService, |
|
29 | + private LoggerInterface $logger, |
|
30 | + ) { |
|
31 | + parent::__construct($this->userManager, $this->groupManager, $this->principalBackend, $this->remoteUserPrincipalBackend, $this->cacheFactory, $this->service, $this->federationSharingService, $this->logger); |
|
32 | + } |
|
33 | 33 | } |
@@ -24,194 +24,194 @@ |
||
24 | 24 | |
25 | 25 | class SyncService extends ASyncService { |
26 | 26 | |
27 | - use TTransactional; |
|
28 | - private ?array $localSystemAddressBook = null; |
|
29 | - protected string $certPath; |
|
30 | - |
|
31 | - public function __construct( |
|
32 | - IClientService $clientService, |
|
33 | - IConfig $config, |
|
34 | - private CardDavBackend $backend, |
|
35 | - private IUserManager $userManager, |
|
36 | - private IDBConnection $dbConnection, |
|
37 | - private LoggerInterface $logger, |
|
38 | - private Converter $converter, |
|
39 | - ) { |
|
40 | - parent::__construct($clientService, $config); |
|
41 | - |
|
42 | - $this->certPath = ''; |
|
43 | - } |
|
44 | - |
|
45 | - /** |
|
46 | - * @psalm-return list{0: ?string, 1: boolean} |
|
47 | - * @throws \Exception |
|
48 | - */ |
|
49 | - public function syncRemoteAddressBook(string $url, string $userName, string $addressBookUrl, string $sharedSecret, ?string $syncToken, string $targetBookHash, string $targetPrincipal, array $targetProperties): array { |
|
50 | - // 1. create addressbook |
|
51 | - $book = $this->ensureSystemAddressBookExists($targetPrincipal, $targetBookHash, $targetProperties); |
|
52 | - $addressBookId = $book['id']; |
|
53 | - |
|
54 | - // 2. query changes |
|
55 | - try { |
|
56 | - $absoluteUri = $this->prepareUri($url, $addressBookUrl); |
|
57 | - $response = $this->requestSyncReport($absoluteUri, $userName, $sharedSecret, $syncToken); |
|
58 | - } catch (ClientExceptionInterface $ex) { |
|
59 | - if ($ex->getCode() === Http::STATUS_UNAUTHORIZED) { |
|
60 | - // remote server revoked access to the address book, remove it |
|
61 | - $this->backend->deleteAddressBook($addressBookId); |
|
62 | - $this->logger->error('Authorization failed, remove address book: ' . $url, ['app' => 'dav']); |
|
63 | - throw $ex; |
|
64 | - } |
|
65 | - $this->logger->error('Client exception:', ['app' => 'dav', 'exception' => $ex]); |
|
66 | - throw $ex; |
|
67 | - } |
|
68 | - |
|
69 | - // 3. apply changes |
|
70 | - // TODO: use multi-get for download |
|
71 | - foreach ($response['response'] as $resource => $status) { |
|
72 | - $cardUri = basename($resource); |
|
73 | - if (isset($status[200])) { |
|
74 | - $absoluteUrl = $this->prepareUri($url, $resource); |
|
75 | - $vCard = $this->download($absoluteUrl, $userName, $sharedSecret); |
|
76 | - $this->atomic(function () use ($addressBookId, $cardUri, $vCard): void { |
|
77 | - $existingCard = $this->backend->getCard($addressBookId, $cardUri); |
|
78 | - if ($existingCard === false) { |
|
79 | - $this->backend->createCard($addressBookId, $cardUri, $vCard); |
|
80 | - } else { |
|
81 | - $this->backend->updateCard($addressBookId, $cardUri, $vCard); |
|
82 | - } |
|
83 | - }, $this->dbConnection); |
|
84 | - } else { |
|
85 | - $this->backend->deleteCard($addressBookId, $cardUri); |
|
86 | - } |
|
87 | - } |
|
88 | - |
|
89 | - return [ |
|
90 | - $response['token'], |
|
91 | - $response['truncated'], |
|
92 | - ]; |
|
93 | - } |
|
94 | - |
|
95 | - /** |
|
96 | - * @throws \Sabre\DAV\Exception\BadRequest |
|
97 | - */ |
|
98 | - public function ensureSystemAddressBookExists(string $principal, string $uri, array $properties): ?array { |
|
99 | - try { |
|
100 | - return $this->atomic(function () use ($principal, $uri, $properties) { |
|
101 | - $book = $this->backend->getAddressBooksByUri($principal, $uri); |
|
102 | - if (!is_null($book)) { |
|
103 | - return $book; |
|
104 | - } |
|
105 | - $this->backend->createAddressBook($principal, $uri, $properties); |
|
106 | - |
|
107 | - return $this->backend->getAddressBooksByUri($principal, $uri); |
|
108 | - }, $this->dbConnection); |
|
109 | - } catch (Exception $e) { |
|
110 | - // READ COMMITTED doesn't prevent a nonrepeatable read above, so |
|
111 | - // two processes might create an address book here. Ignore our |
|
112 | - // failure and continue loading the entry written by the other process |
|
113 | - if ($e->getReason() !== Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) { |
|
114 | - throw $e; |
|
115 | - } |
|
116 | - |
|
117 | - // If this fails we might have hit a replication node that does not |
|
118 | - // have the row written in the other process. |
|
119 | - // TODO: find an elegant way to handle this |
|
120 | - $ab = $this->backend->getAddressBooksByUri($principal, $uri); |
|
121 | - if ($ab === null) { |
|
122 | - throw new Exception('Could not create system address book', $e->getCode(), $e); |
|
123 | - } |
|
124 | - return $ab; |
|
125 | - } |
|
126 | - } |
|
127 | - |
|
128 | - public function ensureLocalSystemAddressBookExists(): ?array { |
|
129 | - return $this->ensureSystemAddressBookExists('principals/system/system', 'system', [ |
|
130 | - '{' . Plugin::NS_CARDDAV . '}addressbook-description' => 'System addressbook which holds all users of this instance' |
|
131 | - ]); |
|
132 | - } |
|
133 | - |
|
134 | - /** |
|
135 | - * @param IUser $user |
|
136 | - */ |
|
137 | - public function updateUser(IUser $user): void { |
|
138 | - $systemAddressBook = $this->getLocalSystemAddressBook(); |
|
139 | - $addressBookId = $systemAddressBook['id']; |
|
140 | - |
|
141 | - $cardId = self::getCardUri($user); |
|
142 | - if ($user->isEnabled()) { |
|
143 | - $this->atomic(function () use ($addressBookId, $cardId, $user): void { |
|
144 | - $card = $this->backend->getCard($addressBookId, $cardId); |
|
145 | - if ($card === false) { |
|
146 | - $vCard = $this->converter->createCardFromUser($user); |
|
147 | - if ($vCard !== null) { |
|
148 | - $this->backend->createCard($addressBookId, $cardId, $vCard->serialize(), false); |
|
149 | - } |
|
150 | - } else { |
|
151 | - $vCard = $this->converter->createCardFromUser($user); |
|
152 | - if (is_null($vCard)) { |
|
153 | - $this->backend->deleteCard($addressBookId, $cardId); |
|
154 | - } else { |
|
155 | - $this->backend->updateCard($addressBookId, $cardId, $vCard->serialize()); |
|
156 | - } |
|
157 | - } |
|
158 | - }, $this->dbConnection); |
|
159 | - } else { |
|
160 | - $this->backend->deleteCard($addressBookId, $cardId); |
|
161 | - } |
|
162 | - } |
|
163 | - |
|
164 | - /** |
|
165 | - * @param IUser|string $userOrCardId |
|
166 | - */ |
|
167 | - public function deleteUser($userOrCardId) { |
|
168 | - $systemAddressBook = $this->getLocalSystemAddressBook(); |
|
169 | - if ($userOrCardId instanceof IUser) { |
|
170 | - $userOrCardId = self::getCardUri($userOrCardId); |
|
171 | - } |
|
172 | - $this->backend->deleteCard($systemAddressBook['id'], $userOrCardId); |
|
173 | - } |
|
174 | - |
|
175 | - /** |
|
176 | - * @return array|null |
|
177 | - */ |
|
178 | - public function getLocalSystemAddressBook() { |
|
179 | - if (is_null($this->localSystemAddressBook)) { |
|
180 | - $this->localSystemAddressBook = $this->ensureLocalSystemAddressBookExists(); |
|
181 | - } |
|
182 | - |
|
183 | - return $this->localSystemAddressBook; |
|
184 | - } |
|
185 | - |
|
186 | - /** |
|
187 | - * @return void |
|
188 | - */ |
|
189 | - public function syncInstance(?\Closure $progressCallback = null) { |
|
190 | - $systemAddressBook = $this->getLocalSystemAddressBook(); |
|
191 | - $this->userManager->callForAllUsers(function ($user) use ($systemAddressBook, $progressCallback): void { |
|
192 | - $this->updateUser($user); |
|
193 | - if (!is_null($progressCallback)) { |
|
194 | - $progressCallback(); |
|
195 | - } |
|
196 | - }); |
|
197 | - |
|
198 | - // remove no longer existing |
|
199 | - $allCards = $this->backend->getCards($systemAddressBook['id']); |
|
200 | - foreach ($allCards as $card) { |
|
201 | - $vCard = Reader::read($card['carddata']); |
|
202 | - $uid = $vCard->UID->getValue(); |
|
203 | - // load backend and see if user exists |
|
204 | - if (!$this->userManager->userExists($uid)) { |
|
205 | - $this->deleteUser($card['uri']); |
|
206 | - } |
|
207 | - } |
|
208 | - } |
|
209 | - |
|
210 | - /** |
|
211 | - * @param IUser $user |
|
212 | - * @return string |
|
213 | - */ |
|
214 | - public static function getCardUri(IUser $user): string { |
|
215 | - return $user->getBackendClassName() . ':' . $user->getUID() . '.vcf'; |
|
216 | - } |
|
27 | + use TTransactional; |
|
28 | + private ?array $localSystemAddressBook = null; |
|
29 | + protected string $certPath; |
|
30 | + |
|
31 | + public function __construct( |
|
32 | + IClientService $clientService, |
|
33 | + IConfig $config, |
|
34 | + private CardDavBackend $backend, |
|
35 | + private IUserManager $userManager, |
|
36 | + private IDBConnection $dbConnection, |
|
37 | + private LoggerInterface $logger, |
|
38 | + private Converter $converter, |
|
39 | + ) { |
|
40 | + parent::__construct($clientService, $config); |
|
41 | + |
|
42 | + $this->certPath = ''; |
|
43 | + } |
|
44 | + |
|
45 | + /** |
|
46 | + * @psalm-return list{0: ?string, 1: boolean} |
|
47 | + * @throws \Exception |
|
48 | + */ |
|
49 | + public function syncRemoteAddressBook(string $url, string $userName, string $addressBookUrl, string $sharedSecret, ?string $syncToken, string $targetBookHash, string $targetPrincipal, array $targetProperties): array { |
|
50 | + // 1. create addressbook |
|
51 | + $book = $this->ensureSystemAddressBookExists($targetPrincipal, $targetBookHash, $targetProperties); |
|
52 | + $addressBookId = $book['id']; |
|
53 | + |
|
54 | + // 2. query changes |
|
55 | + try { |
|
56 | + $absoluteUri = $this->prepareUri($url, $addressBookUrl); |
|
57 | + $response = $this->requestSyncReport($absoluteUri, $userName, $sharedSecret, $syncToken); |
|
58 | + } catch (ClientExceptionInterface $ex) { |
|
59 | + if ($ex->getCode() === Http::STATUS_UNAUTHORIZED) { |
|
60 | + // remote server revoked access to the address book, remove it |
|
61 | + $this->backend->deleteAddressBook($addressBookId); |
|
62 | + $this->logger->error('Authorization failed, remove address book: ' . $url, ['app' => 'dav']); |
|
63 | + throw $ex; |
|
64 | + } |
|
65 | + $this->logger->error('Client exception:', ['app' => 'dav', 'exception' => $ex]); |
|
66 | + throw $ex; |
|
67 | + } |
|
68 | + |
|
69 | + // 3. apply changes |
|
70 | + // TODO: use multi-get for download |
|
71 | + foreach ($response['response'] as $resource => $status) { |
|
72 | + $cardUri = basename($resource); |
|
73 | + if (isset($status[200])) { |
|
74 | + $absoluteUrl = $this->prepareUri($url, $resource); |
|
75 | + $vCard = $this->download($absoluteUrl, $userName, $sharedSecret); |
|
76 | + $this->atomic(function () use ($addressBookId, $cardUri, $vCard): void { |
|
77 | + $existingCard = $this->backend->getCard($addressBookId, $cardUri); |
|
78 | + if ($existingCard === false) { |
|
79 | + $this->backend->createCard($addressBookId, $cardUri, $vCard); |
|
80 | + } else { |
|
81 | + $this->backend->updateCard($addressBookId, $cardUri, $vCard); |
|
82 | + } |
|
83 | + }, $this->dbConnection); |
|
84 | + } else { |
|
85 | + $this->backend->deleteCard($addressBookId, $cardUri); |
|
86 | + } |
|
87 | + } |
|
88 | + |
|
89 | + return [ |
|
90 | + $response['token'], |
|
91 | + $response['truncated'], |
|
92 | + ]; |
|
93 | + } |
|
94 | + |
|
95 | + /** |
|
96 | + * @throws \Sabre\DAV\Exception\BadRequest |
|
97 | + */ |
|
98 | + public function ensureSystemAddressBookExists(string $principal, string $uri, array $properties): ?array { |
|
99 | + try { |
|
100 | + return $this->atomic(function () use ($principal, $uri, $properties) { |
|
101 | + $book = $this->backend->getAddressBooksByUri($principal, $uri); |
|
102 | + if (!is_null($book)) { |
|
103 | + return $book; |
|
104 | + } |
|
105 | + $this->backend->createAddressBook($principal, $uri, $properties); |
|
106 | + |
|
107 | + return $this->backend->getAddressBooksByUri($principal, $uri); |
|
108 | + }, $this->dbConnection); |
|
109 | + } catch (Exception $e) { |
|
110 | + // READ COMMITTED doesn't prevent a nonrepeatable read above, so |
|
111 | + // two processes might create an address book here. Ignore our |
|
112 | + // failure and continue loading the entry written by the other process |
|
113 | + if ($e->getReason() !== Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) { |
|
114 | + throw $e; |
|
115 | + } |
|
116 | + |
|
117 | + // If this fails we might have hit a replication node that does not |
|
118 | + // have the row written in the other process. |
|
119 | + // TODO: find an elegant way to handle this |
|
120 | + $ab = $this->backend->getAddressBooksByUri($principal, $uri); |
|
121 | + if ($ab === null) { |
|
122 | + throw new Exception('Could not create system address book', $e->getCode(), $e); |
|
123 | + } |
|
124 | + return $ab; |
|
125 | + } |
|
126 | + } |
|
127 | + |
|
128 | + public function ensureLocalSystemAddressBookExists(): ?array { |
|
129 | + return $this->ensureSystemAddressBookExists('principals/system/system', 'system', [ |
|
130 | + '{' . Plugin::NS_CARDDAV . '}addressbook-description' => 'System addressbook which holds all users of this instance' |
|
131 | + ]); |
|
132 | + } |
|
133 | + |
|
134 | + /** |
|
135 | + * @param IUser $user |
|
136 | + */ |
|
137 | + public function updateUser(IUser $user): void { |
|
138 | + $systemAddressBook = $this->getLocalSystemAddressBook(); |
|
139 | + $addressBookId = $systemAddressBook['id']; |
|
140 | + |
|
141 | + $cardId = self::getCardUri($user); |
|
142 | + if ($user->isEnabled()) { |
|
143 | + $this->atomic(function () use ($addressBookId, $cardId, $user): void { |
|
144 | + $card = $this->backend->getCard($addressBookId, $cardId); |
|
145 | + if ($card === false) { |
|
146 | + $vCard = $this->converter->createCardFromUser($user); |
|
147 | + if ($vCard !== null) { |
|
148 | + $this->backend->createCard($addressBookId, $cardId, $vCard->serialize(), false); |
|
149 | + } |
|
150 | + } else { |
|
151 | + $vCard = $this->converter->createCardFromUser($user); |
|
152 | + if (is_null($vCard)) { |
|
153 | + $this->backend->deleteCard($addressBookId, $cardId); |
|
154 | + } else { |
|
155 | + $this->backend->updateCard($addressBookId, $cardId, $vCard->serialize()); |
|
156 | + } |
|
157 | + } |
|
158 | + }, $this->dbConnection); |
|
159 | + } else { |
|
160 | + $this->backend->deleteCard($addressBookId, $cardId); |
|
161 | + } |
|
162 | + } |
|
163 | + |
|
164 | + /** |
|
165 | + * @param IUser|string $userOrCardId |
|
166 | + */ |
|
167 | + public function deleteUser($userOrCardId) { |
|
168 | + $systemAddressBook = $this->getLocalSystemAddressBook(); |
|
169 | + if ($userOrCardId instanceof IUser) { |
|
170 | + $userOrCardId = self::getCardUri($userOrCardId); |
|
171 | + } |
|
172 | + $this->backend->deleteCard($systemAddressBook['id'], $userOrCardId); |
|
173 | + } |
|
174 | + |
|
175 | + /** |
|
176 | + * @return array|null |
|
177 | + */ |
|
178 | + public function getLocalSystemAddressBook() { |
|
179 | + if (is_null($this->localSystemAddressBook)) { |
|
180 | + $this->localSystemAddressBook = $this->ensureLocalSystemAddressBookExists(); |
|
181 | + } |
|
182 | + |
|
183 | + return $this->localSystemAddressBook; |
|
184 | + } |
|
185 | + |
|
186 | + /** |
|
187 | + * @return void |
|
188 | + */ |
|
189 | + public function syncInstance(?\Closure $progressCallback = null) { |
|
190 | + $systemAddressBook = $this->getLocalSystemAddressBook(); |
|
191 | + $this->userManager->callForAllUsers(function ($user) use ($systemAddressBook, $progressCallback): void { |
|
192 | + $this->updateUser($user); |
|
193 | + if (!is_null($progressCallback)) { |
|
194 | + $progressCallback(); |
|
195 | + } |
|
196 | + }); |
|
197 | + |
|
198 | + // remove no longer existing |
|
199 | + $allCards = $this->backend->getCards($systemAddressBook['id']); |
|
200 | + foreach ($allCards as $card) { |
|
201 | + $vCard = Reader::read($card['carddata']); |
|
202 | + $uid = $vCard->UID->getValue(); |
|
203 | + // load backend and see if user exists |
|
204 | + if (!$this->userManager->userExists($uid)) { |
|
205 | + $this->deleteUser($card['uri']); |
|
206 | + } |
|
207 | + } |
|
208 | + } |
|
209 | + |
|
210 | + /** |
|
211 | + * @param IUser $user |
|
212 | + * @return string |
|
213 | + */ |
|
214 | + public static function getCardUri(IUser $user): string { |
|
215 | + return $user->getBackendClassName() . ':' . $user->getUID() . '.vcf'; |
|
216 | + } |
|
217 | 217 | } |
@@ -59,7 +59,7 @@ discard block |
||
59 | 59 | if ($ex->getCode() === Http::STATUS_UNAUTHORIZED) { |
60 | 60 | // remote server revoked access to the address book, remove it |
61 | 61 | $this->backend->deleteAddressBook($addressBookId); |
62 | - $this->logger->error('Authorization failed, remove address book: ' . $url, ['app' => 'dav']); |
|
62 | + $this->logger->error('Authorization failed, remove address book: '.$url, ['app' => 'dav']); |
|
63 | 63 | throw $ex; |
64 | 64 | } |
65 | 65 | $this->logger->error('Client exception:', ['app' => 'dav', 'exception' => $ex]); |
@@ -73,7 +73,7 @@ discard block |
||
73 | 73 | if (isset($status[200])) { |
74 | 74 | $absoluteUrl = $this->prepareUri($url, $resource); |
75 | 75 | $vCard = $this->download($absoluteUrl, $userName, $sharedSecret); |
76 | - $this->atomic(function () use ($addressBookId, $cardUri, $vCard): void { |
|
76 | + $this->atomic(function() use ($addressBookId, $cardUri, $vCard): void { |
|
77 | 77 | $existingCard = $this->backend->getCard($addressBookId, $cardUri); |
78 | 78 | if ($existingCard === false) { |
79 | 79 | $this->backend->createCard($addressBookId, $cardUri, $vCard); |
@@ -97,7 +97,7 @@ discard block |
||
97 | 97 | */ |
98 | 98 | public function ensureSystemAddressBookExists(string $principal, string $uri, array $properties): ?array { |
99 | 99 | try { |
100 | - return $this->atomic(function () use ($principal, $uri, $properties) { |
|
100 | + return $this->atomic(function() use ($principal, $uri, $properties) { |
|
101 | 101 | $book = $this->backend->getAddressBooksByUri($principal, $uri); |
102 | 102 | if (!is_null($book)) { |
103 | 103 | return $book; |
@@ -127,7 +127,7 @@ discard block |
||
127 | 127 | |
128 | 128 | public function ensureLocalSystemAddressBookExists(): ?array { |
129 | 129 | return $this->ensureSystemAddressBookExists('principals/system/system', 'system', [ |
130 | - '{' . Plugin::NS_CARDDAV . '}addressbook-description' => 'System addressbook which holds all users of this instance' |
|
130 | + '{'.Plugin::NS_CARDDAV.'}addressbook-description' => 'System addressbook which holds all users of this instance' |
|
131 | 131 | ]); |
132 | 132 | } |
133 | 133 | |
@@ -140,7 +140,7 @@ discard block |
||
140 | 140 | |
141 | 141 | $cardId = self::getCardUri($user); |
142 | 142 | if ($user->isEnabled()) { |
143 | - $this->atomic(function () use ($addressBookId, $cardId, $user): void { |
|
143 | + $this->atomic(function() use ($addressBookId, $cardId, $user): void { |
|
144 | 144 | $card = $this->backend->getCard($addressBookId, $cardId); |
145 | 145 | if ($card === false) { |
146 | 146 | $vCard = $this->converter->createCardFromUser($user); |
@@ -188,7 +188,7 @@ discard block |
||
188 | 188 | */ |
189 | 189 | public function syncInstance(?\Closure $progressCallback = null) { |
190 | 190 | $systemAddressBook = $this->getLocalSystemAddressBook(); |
191 | - $this->userManager->callForAllUsers(function ($user) use ($systemAddressBook, $progressCallback): void { |
|
191 | + $this->userManager->callForAllUsers(function($user) use ($systemAddressBook, $progressCallback): void { |
|
192 | 192 | $this->updateUser($user); |
193 | 193 | if (!is_null($progressCallback)) { |
194 | 194 | $progressCallback(); |
@@ -212,6 +212,6 @@ discard block |
||
212 | 212 | * @return string |
213 | 213 | */ |
214 | 214 | public static function getCardUri(IUser $user): string { |
215 | - return $user->getBackendClassName() . ':' . $user->getUID() . '.vcf'; |
|
215 | + return $user->getBackendClassName().':'.$user->getUID().'.vcf'; |
|
216 | 216 | } |
217 | 217 | } |
@@ -49,170 +49,170 @@ |
||
49 | 49 | use Sabre\DAV\SimpleCollection; |
50 | 50 | |
51 | 51 | class RootCollection extends SimpleCollection { |
52 | - public function __construct() { |
|
53 | - $l10n = \OC::$server->getL10N('dav'); |
|
54 | - $random = Server::get(ISecureRandom::class); |
|
55 | - $logger = Server::get(LoggerInterface::class); |
|
56 | - $userManager = Server::get(IUserManager::class); |
|
57 | - $userSession = Server::get(IUserSession::class); |
|
58 | - $groupManager = Server::get(IGroupManager::class); |
|
59 | - $shareManager = Server::get(\OCP\Share\IManager::class); |
|
60 | - $db = Server::get(IDBConnection::class); |
|
61 | - $dispatcher = Server::get(IEventDispatcher::class); |
|
62 | - $config = Server::get(IConfig::class); |
|
63 | - $proxyMapper = Server::get(ProxyMapper::class); |
|
64 | - $rootFolder = Server::get(IRootFolder::class); |
|
65 | - $federatedCalendarFactory = Server::get(FederatedCalendarFactory::class); |
|
66 | - |
|
67 | - $userPrincipalBackend = new Principal( |
|
68 | - $userManager, |
|
69 | - $groupManager, |
|
70 | - Server::get(IAccountManager::class), |
|
71 | - $shareManager, |
|
72 | - Server::get(IUserSession::class), |
|
73 | - Server::get(IAppManager::class), |
|
74 | - $proxyMapper, |
|
75 | - Server::get(KnownUserService::class), |
|
76 | - Server::get(IConfig::class), |
|
77 | - \OC::$server->getL10NFactory() |
|
78 | - ); |
|
79 | - |
|
80 | - $groupPrincipalBackend = new GroupPrincipalBackend($groupManager, $userSession, $shareManager, $config); |
|
81 | - $calendarResourcePrincipalBackend = new ResourcePrincipalBackend($db, $userSession, $groupManager, $logger, $proxyMapper); |
|
82 | - $calendarRoomPrincipalBackend = new RoomPrincipalBackend($db, $userSession, $groupManager, $logger, $proxyMapper); |
|
83 | - $remoteUserPrincipalBackend = Server::get(RemoteUserPrincipalBackend::class); |
|
84 | - // as soon as debug mode is enabled we allow listing of principals |
|
85 | - $disableListing = !$config->getSystemValue('debug', false); |
|
86 | - |
|
87 | - // setup the first level of the dav tree |
|
88 | - $userPrincipals = new Collection($userPrincipalBackend, 'principals/users'); |
|
89 | - $userPrincipals->disableListing = $disableListing; |
|
90 | - $groupPrincipals = new Collection($groupPrincipalBackend, 'principals/groups'); |
|
91 | - $groupPrincipals->disableListing = $disableListing; |
|
92 | - $systemPrincipals = new Collection(new SystemPrincipalBackend(), 'principals/system'); |
|
93 | - $systemPrincipals->disableListing = $disableListing; |
|
94 | - $calendarResourcePrincipals = new Collection($calendarResourcePrincipalBackend, 'principals/calendar-resources'); |
|
95 | - $calendarRoomPrincipals = new Collection($calendarRoomPrincipalBackend, 'principals/calendar-rooms'); |
|
96 | - $remoteUserPrincipals = new Collection($remoteUserPrincipalBackend, RemoteUserPrincipalBackend::PRINCIPAL_PREFIX); |
|
97 | - $calendarSharingBackend = Server::get(Backend::class); |
|
98 | - |
|
99 | - $filesCollection = new Files\RootCollection($userPrincipalBackend, 'principals/users'); |
|
100 | - $filesCollection->disableListing = $disableListing; |
|
101 | - $caldavBackend = new CalDavBackend( |
|
102 | - $db, |
|
103 | - $userPrincipalBackend, |
|
104 | - $userManager, |
|
105 | - $random, |
|
106 | - $logger, |
|
107 | - $dispatcher, |
|
108 | - $config, |
|
109 | - $calendarSharingBackend, |
|
110 | - Server::get(FederatedCalendarMapper::class), |
|
111 | - false, |
|
112 | - ); |
|
113 | - $userCalendarRoot = new CalendarRoot($userPrincipalBackend, $caldavBackend, 'principals/users', $logger, $l10n, $config, $federatedCalendarFactory); |
|
114 | - $userCalendarRoot->disableListing = $disableListing; |
|
115 | - |
|
116 | - $remoteUserCalendarRoot = new CalendarRoot($remoteUserPrincipalBackend, $caldavBackend, RemoteUserPrincipalBackend::PRINCIPAL_PREFIX, $logger, $l10n, $config, $federatedCalendarFactory); |
|
117 | - $remoteUserCalendarRoot->disableListing = $disableListing; |
|
118 | - |
|
119 | - $resourceCalendarRoot = new CalendarRoot($calendarResourcePrincipalBackend, $caldavBackend, 'principals/calendar-resources', $logger, $l10n, $config, $federatedCalendarFactory); |
|
120 | - $resourceCalendarRoot->disableListing = $disableListing; |
|
121 | - $roomCalendarRoot = new CalendarRoot($calendarRoomPrincipalBackend, $caldavBackend, 'principals/calendar-rooms', $logger, $l10n, $config, $federatedCalendarFactory); |
|
122 | - $roomCalendarRoot->disableListing = $disableListing; |
|
123 | - |
|
124 | - $publicCalendarRoot = new PublicCalendarRoot($caldavBackend, $l10n, $config, $logger); |
|
125 | - |
|
126 | - $systemTagCollection = Server::get(SystemTagsByIdCollection::class); |
|
127 | - $systemTagRelationsCollection = new SystemTagsRelationsCollection( |
|
128 | - Server::get(ISystemTagManager::class), |
|
129 | - Server::get(ISystemTagObjectMapper::class), |
|
130 | - Server::get(IUserSession::class), |
|
131 | - $groupManager, |
|
132 | - $dispatcher, |
|
133 | - $rootFolder, |
|
134 | - ); |
|
135 | - $systemTagInUseCollection = Server::get(SystemTagsInUseCollection::class); |
|
136 | - $commentsCollection = new Comments\RootCollection( |
|
137 | - Server::get(ICommentsManager::class), |
|
138 | - $userManager, |
|
139 | - Server::get(IUserSession::class), |
|
140 | - $dispatcher, |
|
141 | - $logger |
|
142 | - ); |
|
143 | - |
|
144 | - $contactsSharingBackend = Server::get(\OCA\DAV\CardDAV\Sharing\Backend::class); |
|
145 | - $config = Server::get(IConfig::class); |
|
146 | - |
|
147 | - $pluginManager = new PluginManager(\OC::$server, Server::get(IAppManager::class)); |
|
148 | - $usersCardDavBackend = new CardDavBackend( |
|
149 | - $db, |
|
150 | - $userPrincipalBackend, |
|
151 | - $userManager, |
|
152 | - $dispatcher, |
|
153 | - $contactsSharingBackend, |
|
154 | - $config |
|
155 | - ); |
|
156 | - $usersAddressBookRoot = new AddressBookRoot($userPrincipalBackend, $usersCardDavBackend, $pluginManager, $userSession->getUser(), $groupManager, 'principals/users'); |
|
157 | - $usersAddressBookRoot->disableListing = $disableListing; |
|
158 | - |
|
159 | - $systemCardDavBackend = new CardDavBackend( |
|
160 | - $db, |
|
161 | - $userPrincipalBackend, |
|
162 | - $userManager, |
|
163 | - $dispatcher, |
|
164 | - $contactsSharingBackend, |
|
165 | - $config |
|
166 | - ); |
|
167 | - $systemAddressBookRoot = new AddressBookRoot(new SystemPrincipalBackend(), $systemCardDavBackend, $pluginManager, $userSession->getUser(), $groupManager, 'principals/system'); |
|
168 | - $systemAddressBookRoot->disableListing = $disableListing; |
|
169 | - |
|
170 | - $uploadCollection = new Upload\RootCollection( |
|
171 | - $userPrincipalBackend, |
|
172 | - 'principals/users', |
|
173 | - Server::get(CleanupService::class), |
|
174 | - $rootFolder, |
|
175 | - $userSession, |
|
176 | - $shareManager, |
|
177 | - ); |
|
178 | - $uploadCollection->disableListing = $disableListing; |
|
179 | - |
|
180 | - $avatarCollection = new Avatars\RootCollection($userPrincipalBackend, 'principals/users'); |
|
181 | - $avatarCollection->disableListing = $disableListing; |
|
182 | - |
|
183 | - $appleProvisioning = new AppleProvisioningNode( |
|
184 | - Server::get(ITimeFactory::class)); |
|
185 | - |
|
186 | - $children = [ |
|
187 | - new SimpleCollection('principals', [ |
|
188 | - $userPrincipals, |
|
189 | - $groupPrincipals, |
|
190 | - $systemPrincipals, |
|
191 | - $calendarResourcePrincipals, |
|
192 | - $calendarRoomPrincipals, |
|
193 | - $remoteUserPrincipals]), |
|
194 | - $filesCollection, |
|
195 | - $userCalendarRoot, |
|
196 | - $remoteUserCalendarRoot, |
|
197 | - new SimpleCollection('system-calendars', [ |
|
198 | - $resourceCalendarRoot, |
|
199 | - $roomCalendarRoot, |
|
200 | - ]), |
|
201 | - $publicCalendarRoot, |
|
202 | - new SimpleCollection('addressbooks', [ |
|
203 | - $usersAddressBookRoot, |
|
204 | - $systemAddressBookRoot]), |
|
205 | - $systemTagCollection, |
|
206 | - $systemTagRelationsCollection, |
|
207 | - $systemTagInUseCollection, |
|
208 | - $commentsCollection, |
|
209 | - $uploadCollection, |
|
210 | - $avatarCollection, |
|
211 | - new SimpleCollection('provisioning', [ |
|
212 | - $appleProvisioning |
|
213 | - ]) |
|
214 | - ]; |
|
215 | - |
|
216 | - parent::__construct('root', $children); |
|
217 | - } |
|
52 | + public function __construct() { |
|
53 | + $l10n = \OC::$server->getL10N('dav'); |
|
54 | + $random = Server::get(ISecureRandom::class); |
|
55 | + $logger = Server::get(LoggerInterface::class); |
|
56 | + $userManager = Server::get(IUserManager::class); |
|
57 | + $userSession = Server::get(IUserSession::class); |
|
58 | + $groupManager = Server::get(IGroupManager::class); |
|
59 | + $shareManager = Server::get(\OCP\Share\IManager::class); |
|
60 | + $db = Server::get(IDBConnection::class); |
|
61 | + $dispatcher = Server::get(IEventDispatcher::class); |
|
62 | + $config = Server::get(IConfig::class); |
|
63 | + $proxyMapper = Server::get(ProxyMapper::class); |
|
64 | + $rootFolder = Server::get(IRootFolder::class); |
|
65 | + $federatedCalendarFactory = Server::get(FederatedCalendarFactory::class); |
|
66 | + |
|
67 | + $userPrincipalBackend = new Principal( |
|
68 | + $userManager, |
|
69 | + $groupManager, |
|
70 | + Server::get(IAccountManager::class), |
|
71 | + $shareManager, |
|
72 | + Server::get(IUserSession::class), |
|
73 | + Server::get(IAppManager::class), |
|
74 | + $proxyMapper, |
|
75 | + Server::get(KnownUserService::class), |
|
76 | + Server::get(IConfig::class), |
|
77 | + \OC::$server->getL10NFactory() |
|
78 | + ); |
|
79 | + |
|
80 | + $groupPrincipalBackend = new GroupPrincipalBackend($groupManager, $userSession, $shareManager, $config); |
|
81 | + $calendarResourcePrincipalBackend = new ResourcePrincipalBackend($db, $userSession, $groupManager, $logger, $proxyMapper); |
|
82 | + $calendarRoomPrincipalBackend = new RoomPrincipalBackend($db, $userSession, $groupManager, $logger, $proxyMapper); |
|
83 | + $remoteUserPrincipalBackend = Server::get(RemoteUserPrincipalBackend::class); |
|
84 | + // as soon as debug mode is enabled we allow listing of principals |
|
85 | + $disableListing = !$config->getSystemValue('debug', false); |
|
86 | + |
|
87 | + // setup the first level of the dav tree |
|
88 | + $userPrincipals = new Collection($userPrincipalBackend, 'principals/users'); |
|
89 | + $userPrincipals->disableListing = $disableListing; |
|
90 | + $groupPrincipals = new Collection($groupPrincipalBackend, 'principals/groups'); |
|
91 | + $groupPrincipals->disableListing = $disableListing; |
|
92 | + $systemPrincipals = new Collection(new SystemPrincipalBackend(), 'principals/system'); |
|
93 | + $systemPrincipals->disableListing = $disableListing; |
|
94 | + $calendarResourcePrincipals = new Collection($calendarResourcePrincipalBackend, 'principals/calendar-resources'); |
|
95 | + $calendarRoomPrincipals = new Collection($calendarRoomPrincipalBackend, 'principals/calendar-rooms'); |
|
96 | + $remoteUserPrincipals = new Collection($remoteUserPrincipalBackend, RemoteUserPrincipalBackend::PRINCIPAL_PREFIX); |
|
97 | + $calendarSharingBackend = Server::get(Backend::class); |
|
98 | + |
|
99 | + $filesCollection = new Files\RootCollection($userPrincipalBackend, 'principals/users'); |
|
100 | + $filesCollection->disableListing = $disableListing; |
|
101 | + $caldavBackend = new CalDavBackend( |
|
102 | + $db, |
|
103 | + $userPrincipalBackend, |
|
104 | + $userManager, |
|
105 | + $random, |
|
106 | + $logger, |
|
107 | + $dispatcher, |
|
108 | + $config, |
|
109 | + $calendarSharingBackend, |
|
110 | + Server::get(FederatedCalendarMapper::class), |
|
111 | + false, |
|
112 | + ); |
|
113 | + $userCalendarRoot = new CalendarRoot($userPrincipalBackend, $caldavBackend, 'principals/users', $logger, $l10n, $config, $federatedCalendarFactory); |
|
114 | + $userCalendarRoot->disableListing = $disableListing; |
|
115 | + |
|
116 | + $remoteUserCalendarRoot = new CalendarRoot($remoteUserPrincipalBackend, $caldavBackend, RemoteUserPrincipalBackend::PRINCIPAL_PREFIX, $logger, $l10n, $config, $federatedCalendarFactory); |
|
117 | + $remoteUserCalendarRoot->disableListing = $disableListing; |
|
118 | + |
|
119 | + $resourceCalendarRoot = new CalendarRoot($calendarResourcePrincipalBackend, $caldavBackend, 'principals/calendar-resources', $logger, $l10n, $config, $federatedCalendarFactory); |
|
120 | + $resourceCalendarRoot->disableListing = $disableListing; |
|
121 | + $roomCalendarRoot = new CalendarRoot($calendarRoomPrincipalBackend, $caldavBackend, 'principals/calendar-rooms', $logger, $l10n, $config, $federatedCalendarFactory); |
|
122 | + $roomCalendarRoot->disableListing = $disableListing; |
|
123 | + |
|
124 | + $publicCalendarRoot = new PublicCalendarRoot($caldavBackend, $l10n, $config, $logger); |
|
125 | + |
|
126 | + $systemTagCollection = Server::get(SystemTagsByIdCollection::class); |
|
127 | + $systemTagRelationsCollection = new SystemTagsRelationsCollection( |
|
128 | + Server::get(ISystemTagManager::class), |
|
129 | + Server::get(ISystemTagObjectMapper::class), |
|
130 | + Server::get(IUserSession::class), |
|
131 | + $groupManager, |
|
132 | + $dispatcher, |
|
133 | + $rootFolder, |
|
134 | + ); |
|
135 | + $systemTagInUseCollection = Server::get(SystemTagsInUseCollection::class); |
|
136 | + $commentsCollection = new Comments\RootCollection( |
|
137 | + Server::get(ICommentsManager::class), |
|
138 | + $userManager, |
|
139 | + Server::get(IUserSession::class), |
|
140 | + $dispatcher, |
|
141 | + $logger |
|
142 | + ); |
|
143 | + |
|
144 | + $contactsSharingBackend = Server::get(\OCA\DAV\CardDAV\Sharing\Backend::class); |
|
145 | + $config = Server::get(IConfig::class); |
|
146 | + |
|
147 | + $pluginManager = new PluginManager(\OC::$server, Server::get(IAppManager::class)); |
|
148 | + $usersCardDavBackend = new CardDavBackend( |
|
149 | + $db, |
|
150 | + $userPrincipalBackend, |
|
151 | + $userManager, |
|
152 | + $dispatcher, |
|
153 | + $contactsSharingBackend, |
|
154 | + $config |
|
155 | + ); |
|
156 | + $usersAddressBookRoot = new AddressBookRoot($userPrincipalBackend, $usersCardDavBackend, $pluginManager, $userSession->getUser(), $groupManager, 'principals/users'); |
|
157 | + $usersAddressBookRoot->disableListing = $disableListing; |
|
158 | + |
|
159 | + $systemCardDavBackend = new CardDavBackend( |
|
160 | + $db, |
|
161 | + $userPrincipalBackend, |
|
162 | + $userManager, |
|
163 | + $dispatcher, |
|
164 | + $contactsSharingBackend, |
|
165 | + $config |
|
166 | + ); |
|
167 | + $systemAddressBookRoot = new AddressBookRoot(new SystemPrincipalBackend(), $systemCardDavBackend, $pluginManager, $userSession->getUser(), $groupManager, 'principals/system'); |
|
168 | + $systemAddressBookRoot->disableListing = $disableListing; |
|
169 | + |
|
170 | + $uploadCollection = new Upload\RootCollection( |
|
171 | + $userPrincipalBackend, |
|
172 | + 'principals/users', |
|
173 | + Server::get(CleanupService::class), |
|
174 | + $rootFolder, |
|
175 | + $userSession, |
|
176 | + $shareManager, |
|
177 | + ); |
|
178 | + $uploadCollection->disableListing = $disableListing; |
|
179 | + |
|
180 | + $avatarCollection = new Avatars\RootCollection($userPrincipalBackend, 'principals/users'); |
|
181 | + $avatarCollection->disableListing = $disableListing; |
|
182 | + |
|
183 | + $appleProvisioning = new AppleProvisioningNode( |
|
184 | + Server::get(ITimeFactory::class)); |
|
185 | + |
|
186 | + $children = [ |
|
187 | + new SimpleCollection('principals', [ |
|
188 | + $userPrincipals, |
|
189 | + $groupPrincipals, |
|
190 | + $systemPrincipals, |
|
191 | + $calendarResourcePrincipals, |
|
192 | + $calendarRoomPrincipals, |
|
193 | + $remoteUserPrincipals]), |
|
194 | + $filesCollection, |
|
195 | + $userCalendarRoot, |
|
196 | + $remoteUserCalendarRoot, |
|
197 | + new SimpleCollection('system-calendars', [ |
|
198 | + $resourceCalendarRoot, |
|
199 | + $roomCalendarRoot, |
|
200 | + ]), |
|
201 | + $publicCalendarRoot, |
|
202 | + new SimpleCollection('addressbooks', [ |
|
203 | + $usersAddressBookRoot, |
|
204 | + $systemAddressBookRoot]), |
|
205 | + $systemTagCollection, |
|
206 | + $systemTagRelationsCollection, |
|
207 | + $systemTagInUseCollection, |
|
208 | + $commentsCollection, |
|
209 | + $uploadCollection, |
|
210 | + $avatarCollection, |
|
211 | + new SimpleCollection('provisioning', [ |
|
212 | + $appleProvisioning |
|
213 | + ]) |
|
214 | + ]; |
|
215 | + |
|
216 | + parent::__construct('root', $children); |
|
217 | + } |
|
218 | 218 | } |