Skip to content

Commit d23b15e

Browse files
ylebremichielbdejong
authored andcommitted
Adding dynamic share providers.
Signed-off-by: Michiel de Jong <michiel@unhosted.org>
1 parent 1ea252f commit d23b15e

File tree

7 files changed

+178
-26
lines changed

7 files changed

+178
-26
lines changed

apps/files_sharing/lib/Controller/ShareAPIController.php

Lines changed: 80 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ class ShareAPIController extends OCSController {
113113
/** @var IPreview */
114114
private $previewManager;
115115

116+
private $dynamicShareTypes;
117+
116118
/**
117119
* Share20OCS constructor.
118120
*
@@ -161,6 +163,33 @@ public function __construct(
161163
$this->serverContainer = $serverContainer;
162164
$this->userStatusManager = $userStatusManager;
163165
$this->previewManager = $previewManager;
166+
$this->dynamicShareTypes = [];
167+
// FIXME: Move this line into the sciencemesh app:
168+
$this->registerHelper(IShare::TYPE_SCIENCEMESH, 'sciencemesh', '\OCA\ScienceMesh\ShareProvider\ShareAPIHelper');
169+
}
170+
171+
public function registerHelper($shareType, $identifier, $helperClassName) {
172+
$this->dynamicShareTypes[$shareType] = [
173+
"identifier" => $identifier,
174+
"helperClass" => $helperClassName
175+
];
176+
}
177+
178+
private function haveHelperFor($shareType) {
179+
return isset($this->dynamicShareTypes[$shareType]);
180+
}
181+
182+
private function getIdentifierFor($shareType) {
183+
return $this->dynamicShareTypes[$shareType]["identifier"];
184+
}
185+
186+
private function getHelperFor($shareType) {
187+
$identifier = $this->getIdentifierFor($shareType);
188+
if (!$this->appManager->isEnabledForUser($identifier)) {
189+
throw new QueryException();
190+
}
191+
192+
return $this->serverContainer->get($this->dynamicShareTypes[$shareType]["helperClass"]);
164193
}
165194

166195
/**
@@ -318,6 +347,14 @@ protected function formatShare(IShare $share, Node $recipientNode = null): array
318347
$result = array_merge($result, $this->getDeckShareHelper()->formatShare($share));
319348
} catch (QueryException $e) {
320349
}
350+
} elseif ($this->haveHelperFor($share->getShareType())) {
351+
$result['share_with'] = $share->getSharedWith();
352+
$result['share_with_displayname'] = '';
353+
354+
try {
355+
$result = array_merge($result, $this->getHelperFor($share->getShareType())->formatShare($share));
356+
} catch (QueryException $e) {
357+
}
321358
}
322359

323360

@@ -663,6 +700,12 @@ public function createShare(
663700
} catch (QueryException $e) {
664701
throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$node->getPath()]));
665702
}
703+
} elseif ($this->haveHelperFor($shareType)) {
704+
try {
705+
$this->getHelperFor($shareType)->createShare($share, $shareWith, $permissions, $expireDate);
706+
} catch (QueryException $e) {
707+
throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support this type of shares', [$node->getPath()]));
708+
}
666709
} else {
667710
throw new OCSBadRequestException($this->l->t('Unknown share type'));
668711
}
@@ -1568,6 +1611,17 @@ private function getShareById(string $id): IShare {
15681611
// Do nothing, just try the other share type
15691612
}
15701613

1614+
foreach ($this->dynamicShareTypes as $shareType => $details) {
1615+
try {
1616+
if ($this->shareManager->shareProviderExists($shareType)) {
1617+
$share = $this->shareManager->getShareById($details["identifier"] . ":" . $id, $this->currentUser);
1618+
return $share;
1619+
}
1620+
} catch (ShareNotFound $e) {
1621+
// Do nothing, just try the other share type
1622+
}
1623+
}
1624+
15711625
if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
15721626
throw new ShareNotFound();
15731627
}
@@ -1631,14 +1685,7 @@ private function getDeckShareHelper() {
16311685
return $this->serverContainer->get('\OCA\Deck\Sharing\ShareAPIHelper');
16321686
}
16331687

1634-
/**
1635-
* @param string $viewer
1636-
* @param Node $node
1637-
* @param bool $reShares
1638-
*
1639-
* @return IShare[]
1640-
*/
1641-
private function getSharesFromNode(string $viewer, $node, bool $reShares): array {
1688+
private function getProvidersExceptOutgoing() {
16421689
$providers = [
16431690
IShare::TYPE_USER,
16441691
IShare::TYPE_GROUP,
@@ -1648,6 +1695,23 @@ private function getSharesFromNode(string $viewer, $node, bool $reShares): array
16481695
IShare::TYPE_ROOM,
16491696
IShare::TYPE_DECK
16501697
];
1698+
foreach ($this->dynamicShareTypes as $shareType => $details) {
1699+
if ($this->shareManager->shareProviderExists($shareType)) {
1700+
array_push($providers, $shareType);
1701+
}
1702+
}
1703+
return $providers;
1704+
}
1705+
1706+
/**
1707+
* @param string $viewer
1708+
* @param Node $node
1709+
* @param bool $reShares
1710+
*
1711+
* @return IShare[]
1712+
*/
1713+
private function getSharesFromNode(string $viewer, $node, bool $reShares): array {
1714+
$providers = $this->getProvidersExceptOutgoing();
16511715

16521716
// Should we assume that the (currentUser) viewer is the owner of the node !?
16531717
$shares = [];
@@ -1785,21 +1849,13 @@ private function shareProviderResharingRights(string $userId, IShare $share, $no
17851849
* @return IShare[]
17861850
*/
17871851
private function getAllShares(?Node $path = null, bool $reshares = false) {
1788-
// Get all shares
1789-
$userShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_USER, $path, $reshares, -1, 0);
1790-
$groupShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_GROUP, $path, $reshares, -1, 0);
1791-
$linkShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_LINK, $path, $reshares, -1, 0);
1792-
1793-
// EMAIL SHARES
1794-
$mailShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_EMAIL, $path, $reshares, -1, 0);
1795-
1796-
// CIRCLE SHARES
1797-
$circleShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_CIRCLE, $path, $reshares, -1, 0);
1798-
1799-
// TALK SHARES
1800-
$roomShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_ROOM, $path, $reshares, -1, 0);
1801-
1802-
$deckShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_DECK, $path, $reshares, -1, 0);
1852+
$providers = $this->getProvidersExceptOutgoing();
1853+
$shares = [];
1854+
foreach ($providers as $provider) {
1855+
$providerShares =
1856+
$this->shareManager->getSharesBy($this->currentUser, $provider, $path, $reshares, -1, 0);
1857+
$shares = array_merge($shares, $providerShares);
1858+
}
18031859

18041860
// FEDERATION
18051861
if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
@@ -1813,7 +1869,7 @@ private function getAllShares(?Node $path = null, bool $reshares = false) {
18131869
$federatedGroupShares = [];
18141870
}
18151871

1816-
return array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares, $deckShares, $federatedShares, $federatedGroupShares);
1872+
return array_merge($shares, $federatedShares, $federatedGroupShares);
18171873
}
18181874

18191875

apps/files_sharing/tests/Controller/ShareAPIControllerTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,10 +199,10 @@ public function testDeleteShareShareNotFound() {
199199
$this->expectExceptionMessage('Wrong share ID, share doesn\'t exist');
200200

201201
$this->shareManager
202-
->expects($this->exactly(6))
202+
->expects($this->exactly(7))
203203
->method('getShareById')
204204
->willReturnCallback(function ($id) {
205-
if ($id === 'ocinternal:42' || $id === 'ocRoomShare:42' || $id === 'ocFederatedSharing:42' || $id === 'ocCircleShare:42' || $id === 'ocMailShare:42' || $id === 'deck:42') {
205+
if ($id === 'ocinternal:42' || $id === 'ocRoomShare:42' || $id === 'ocFederatedSharing:42' || $id === 'ocCircleShare:42' || $id === 'ocMailShare:42' || $id === 'deck:42' || $id === 'sciencemesh:42') {
206206
throw new \OCP\Share\Exceptions\ShareNotFound();
207207
} else {
208208
throw new \Exception();

lib/private/Share20/Manager.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ protected function generalCreateChecks(IShare $share) {
245245
}
246246
} elseif ($share->getShareType() === IShare::TYPE_ROOM) {
247247
} elseif ($share->getShareType() === IShare::TYPE_DECK) {
248+
} else if ($this->factory->getProviderForType($share->getShareType())) {
248249
} else {
249250
// We cannot handle other types yet
250251
throw new \InvalidArgumentException('unknown share type');

lib/private/Share20/ProviderFactory.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,20 @@ public function getProviderForType($shareType) {
325325
$provider = $this->getRoomShareProvider();
326326
} elseif ($shareType === IShare::TYPE_DECK) {
327327
$provider = $this->getProvider('deck');
328+
} else {
329+
// try to autodetect in the registered providers;
330+
foreach ($this->registeredShareProviders as $shareProvider) {
331+
/** @var IShareProvider $instance */
332+
$instance = $this->serverContainer->get($shareProvider);
333+
334+
// not all instances will have the isShareTypeSupported function;
335+
if (method_exists($instance, "isShareTypeSupported")) {
336+
if ($instance->isShareTypeSupported($shareType)) {
337+
$provider = $this->getProvider($instance->identifier());
338+
break;
339+
}
340+
}
341+
}
328342
}
329343

330344

lib/public/Share/IShare.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ interface IShare {
116116
*/
117117
public const TYPE_DECK_USER = 13;
118118

119+
/**
120+
* @since ?
121+
*/
122+
public const TYPE_SCIENCEMESH = 1000;
123+
119124
/**
120125
* @since 18.0.0
121126
*/

tests/lib/Share20/ManagerTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4663,6 +4663,9 @@ public function getProvider($id) {
46634663
* @return IShareProvider
46644664
*/
46654665
public function getProviderForType($shareType) {
4666+
if ($shareType == -1) {
4667+
return null;
4668+
}
46664669
return $this->provider;
46674670
}
46684671

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
/**
3+
* @author Michiel de Jong <michiel@unhosted.org>
4+
*
5+
* @copyright Copyright (c) 2022, Nextcloud, Inc.
6+
* @license AGPL-3.0
7+
*
8+
* This code is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Affero General Public License, version 3,
10+
* as published by the Free Software Foundation.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU Affero General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Affero General Public License, version 3,
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>
19+
*
20+
*/
21+
22+
namespace Test\Share20;
23+
24+
use OCP\IServerContainer;
25+
26+
const EXAMPLE_SHARE_TYPE = 123;
27+
const UNKNOWN_SHARE_TYPE = 456;
28+
29+
class ExampleProvider {
30+
public function isShareTypeSupported($shareType) {
31+
return ($shareType == EXAMPLE_SHARE_TYPE);
32+
}
33+
public function identifier() {
34+
return "example";
35+
}
36+
}
37+
38+
/**
39+
* Class ProviderFactoryTest
40+
*
41+
* @package Test\Share20
42+
*/
43+
class ProviderFactoryTest extends \Test\TestCase {
44+
45+
/** @var \OCP\IServerContainer|\PHPUnit\Framework\MockObject\MockObject */
46+
protected $serverContainer;
47+
/** @var \OCP\Share20\ProviderFactory */
48+
protected $factory;
49+
50+
/** @var ExampleProvider */
51+
protected $dynamicProvider;
52+
53+
protected function setUp(): void {
54+
$this->dynamicProvider = new ExampleProvider();
55+
$this->serverContainer = $this->createMock(IServerContainer::class);
56+
$this->serverContainer->method('get')
57+
->with(ExampleProvider::class)
58+
->willReturn($this->dynamicProvider);
59+
$this->factory = new \OC\Share20\ProviderFactory($this->serverContainer);
60+
$this->factory->registerProvider(ExampleProvider::class);
61+
}
62+
63+
64+
public function testDynamicProvider() {
65+
$provider = $this->factory->getProviderForType(EXAMPLE_SHARE_TYPE);
66+
$this->assertEquals($provider, $this->dynamicProvider);
67+
}
68+
69+
public function testUnknownType() {
70+
$this->expectExceptionMessage('No share provider for share type 456');
71+
$provider = $this->factory->getProviderForType(UNKNOWN_SHARE_TYPE);
72+
}
73+
}

0 commit comments

Comments
 (0)