diff --git a/apps/cloud_federation_api/lib/Config.php b/apps/cloud_federation_api/lib/Config.php index 8611b7cef9c97..2ddff29c1cb6b 100644 --- a/apps/cloud_federation_api/lib/Config.php +++ b/apps/cloud_federation_api/lib/Config.php @@ -49,8 +49,15 @@ public function __construct(ICloudFederationProviderManager $cloudFederationProv */ public function getSupportedShareTypes($resourceType) { try { - $provider = $this->cloudFederationProviderManager->getCloudFederationProvider($resourceType); - return $provider->getSupportedShareTypes(); + $supportedShareTypes = []; + $cloudFederationProviders = $this->cloudFederationProviderManager->getAllCloudFederationProviders(); + foreach ($cloudFederationProviders as $providerWrapper) { + if ($providerWrapper['resourceType'] === $resourceType) { + $providerSupportedShareTypes = $providerWrapper['provider']->getSupportedShareTypes(); + $supportedShareTypes = array_merge($supportedShareTypes, $providerSupportedShareTypes); + } + } + return array_unique($supportedShareTypes); } catch (\Exception $e) { return []; } diff --git a/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php b/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php index ef77f2fa317de..14011aae775ec 100644 --- a/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php +++ b/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php @@ -5,6 +5,7 @@ * @author Bjoern Schiessle * @author Christoph Wurst * @author Roeland Jago Douma + * @author Sandro Mesterheide * * @license GNU AGPL version 3 or any later version * @@ -177,6 +178,10 @@ public function addShare($shareWith, $name, $description, $providerId, $owner, $ } } + if ($shareType === 'federation') { + // Allow creation of pending shares by federation provider + } + // if no explicit display name is given, we use the uid as display name $ownerDisplayName = $ownerDisplayName === null ? $owner : $ownerDisplayName; $sharedByDisplayName = $sharedByDisplayName === null ? $sharedBy : $sharedByDisplayName; @@ -188,7 +193,7 @@ public function addShare($shareWith, $name, $description, $providerId, $owner, $ } try { - $provider = $this->cloudFederationProviderManager->getCloudFederationProvider($resourceType); + $provider = $this->cloudFederationProviderManager->getCloudFederationProvider($resourceType, $shareType); $share = $this->factory->getCloudFederationShare($shareWith, $name, $description, $providerId, $owner, $ownerDisplayName, $sharedBy, $sharedByDisplayName, '', $shareType, $resourceType); $share->setProtocol($protocol); $provider->shareReceived($share); @@ -249,7 +254,7 @@ public function receiveNotification($notificationType, $resourceType, $providerI } try { - $provider = $this->cloudFederationProviderManager->getCloudFederationProvider($resourceType); + $provider = $this->cloudFederationProviderManager->getCloudFederationProvider($resourceType, $notification['shareType']); $result = $provider->notificationReceived($notificationType, $providerId, $notification); } catch (ProviderDoesNotExistsException $e) { return new JSONResponse( diff --git a/apps/files_sharing/composer/composer/autoload_classmap.php b/apps/files_sharing/composer/composer/autoload_classmap.php index 50cbfe40d8aae..bdc359e316be6 100644 --- a/apps/files_sharing/composer/composer/autoload_classmap.php +++ b/apps/files_sharing/composer/composer/autoload_classmap.php @@ -71,6 +71,7 @@ 'OCA\\Files_Sharing\\Migration\\Version22000Date20210216084241' => $baseDir . '/../lib/Migration/Version22000Date20210216084241.php', 'OCA\\Files_Sharing\\Migration\\Version24000Date20220208195521' => $baseDir . '/../lib/Migration/Version24000Date20220208195521.php', 'OCA\\Files_Sharing\\Migration\\Version24000Date20220404142216' => $baseDir . '/../lib/Migration/Version24000Date20220404142216.php', + 'OCA\\Files_Sharing\\Migration\\Version26000Date20230117143027' => $baseDir . '/../lib/Migration/Version26000Date20230117143027.php', 'OCA\\Files_Sharing\\MountProvider' => $baseDir . '/../lib/MountProvider.php', 'OCA\\Files_Sharing\\Notification\\Listener' => $baseDir . '/../lib/Notification/Listener.php', 'OCA\\Files_Sharing\\Notification\\Notifier' => $baseDir . '/../lib/Notification/Notifier.php', diff --git a/apps/files_sharing/composer/composer/autoload_static.php b/apps/files_sharing/composer/composer/autoload_static.php index 4ba0fd52421a0..554dcc9d8fe98 100644 --- a/apps/files_sharing/composer/composer/autoload_static.php +++ b/apps/files_sharing/composer/composer/autoload_static.php @@ -86,6 +86,7 @@ class ComposerStaticInitFiles_Sharing 'OCA\\Files_Sharing\\Migration\\Version22000Date20210216084241' => __DIR__ . '/..' . '/../lib/Migration/Version22000Date20210216084241.php', 'OCA\\Files_Sharing\\Migration\\Version24000Date20220208195521' => __DIR__ . '/..' . '/../lib/Migration/Version24000Date20220208195521.php', 'OCA\\Files_Sharing\\Migration\\Version24000Date20220404142216' => __DIR__ . '/..' . '/../lib/Migration/Version24000Date20220404142216.php', + 'OCA\\Files_Sharing\\Migration\\Version26000Date20230117143027' => __DIR__ . '/..' . '/../lib/Migration/Version26000Date20230117143027.php', 'OCA\\Files_Sharing\\MountProvider' => __DIR__ . '/..' . '/../lib/MountProvider.php', 'OCA\\Files_Sharing\\Notification\\Listener' => __DIR__ . '/..' . '/../lib/Notification/Listener.php', 'OCA\\Files_Sharing\\Notification\\Notifier' => __DIR__ . '/..' . '/../lib/Notification/Notifier.php', diff --git a/apps/files_sharing/lib/Controller/ShareAPIController.php b/apps/files_sharing/lib/Controller/ShareAPIController.php index ab318a81fc232..d7eee224cc6a0 100644 --- a/apps/files_sharing/lib/Controller/ShareAPIController.php +++ b/apps/files_sharing/lib/Controller/ShareAPIController.php @@ -23,6 +23,7 @@ * @author Richard Steinmetz * @author Robin Appelman * @author Roeland Jago Douma + * @author Sandro Mesterheide * @author Valdnet <47037905+Valdnet@users.noreply.github.com> * @author Vincent Petry * @author waleczny @@ -320,7 +321,15 @@ protected function formatShare(IShare $share, Node $recipientNode = null): array $result = array_merge($result, $this->getDeckShareHelper()->formatShare($share)); } catch (QueryException $e) { } - } + } elseif ($share->getShareType() === IShare::TYPE_FEDERATED_GROUP) { + $group = $this->groupManager->get($share->getSharedWith()); + $result['share_with'] = $share->getSharedWith(); + $result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith(); + try { + $result = array_merge($result, $this->getFederatedGroupShareHelper()->formatShare($share)); + } catch (QueryException $e) { + } + } $result['mail_send'] = $share->getMailSend() ? 1 : 0; @@ -648,7 +657,7 @@ public function createShare( throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD')); } } - } elseif ($shareType === IShare::TYPE_REMOTE_GROUP) { + } elseif ($shareType === IShare::TYPE_REMOTE_GROUP || $shareType === IShare::TYPE_FEDERATED_GROUP) { if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) { throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$node->getPath(), $shareType])); } @@ -1609,6 +1618,16 @@ private function getShareById(string $id): IShare { if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) { throw new ShareNotFound(); } + + try { + if ($this->shareManager->shareProviderExists(IShare::TYPE_FEDERATED_GROUP)) { + $share = $this->shareManager->getShareById('ocFederatedGroupShare:' . $id, $this->currentUser); + return $share; + } + } catch (ShareNotFound $e) { + // Do nothing, just try the other share type + } + $share = $this->shareManager->getShareById('ocFederatedSharing:' . $id, $this->currentUser); return $share; @@ -1669,6 +1688,23 @@ private function getDeckShareHelper() { return $this->serverContainer->get('\OCA\Deck\Sharing\ShareAPIHelper'); } + /** + * Returns the helper of ShareAPIHelper for federated group shares. + * + * If the VO federation application is not enabled or the helper is not available + * a QueryException is thrown instead. + * + * @return \OCA\VO_Federation\Sharing\ShareAPIHelper + * @throws QueryException + */ + private function getFederatedGroupShareHelper() { + if (!$this->appManager->isEnabledForUser('vo_federation')) { + throw new QueryException(); + } + + return $this->serverContainer->get('\OCA\VO_Federation\Sharing\ShareAPIHelper'); + } + /** * @param string $viewer * @param Node $node @@ -1710,6 +1746,12 @@ private function getSharesFromNode(string $viewer, $node, bool $reShares): array $federatedShares = $this->shareManager->getSharesBy( $this->currentUser, IShare::TYPE_REMOTE_GROUP, $node, $reShares, -1, 0 ); + if ($this->shareManager->shareProviderExists(IShare::TYPE_FEDERATED_GROUP)) { + $federatedGroupShares = $this->shareManager->getSharesBy( + $this->currentUser, IShare::TYPE_FEDERATED_GROUP, $node, $reShares, -1, 0 + ); + $federatedShares = array_merge($federatedShares, $federatedGroupShares); + } $shares = array_merge($shares, $federatedShares); } @@ -1840,18 +1882,18 @@ private function getAllShares(?Node $path = null, bool $reshares = false) { $deckShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_DECK, $path, $reshares, -1, 0); // FEDERATION + $federatedShares = []; if ($this->shareManager->outgoingServer2ServerSharesAllowed()) { - $federatedShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_REMOTE, $path, $reshares, -1, 0); - } else { - $federatedShares = []; + $remoteShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_REMOTE, $path, $reshares, -1, 0); + $federatedShares = array_merge($federatedShares, $remoteShares); } if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) { - $federatedGroupShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_REMOTE_GROUP, $path, $reshares, -1, 0); - } else { - $federatedGroupShares = []; + $remoteGroupShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_REMOTE_GROUP, $path, $reshares, -1, 0); + $federatedGroupShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_FEDERATED_GROUP, $path, $reshares, -1, 0); + $federatedShares = array_merge($federatedShares, $remoteGroupShares, $federatedGroupShares); } - return array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares, $deckShares, $federatedShares, $federatedGroupShares); + return array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares, $deckShares, $federatedShares); } diff --git a/apps/files_sharing/lib/Controller/ShareesAPIController.php b/apps/files_sharing/lib/Controller/ShareesAPIController.php index 00e63ccb7b019..e6a93cdad216b 100644 --- a/apps/files_sharing/lib/Controller/ShareesAPIController.php +++ b/apps/files_sharing/lib/Controller/ShareesAPIController.php @@ -19,6 +19,7 @@ * @author Morris Jobke * @author Robin Appelman * @author Roeland Jago Douma + * @author Sandro Mesterheide * * @license AGPL-3.0 * @@ -82,6 +83,7 @@ class ShareesAPIController extends OCSController { 'groups' => [], 'remotes' => [], 'remote_groups' => [], + 'federated_groups' => [], 'emails' => [], 'circles' => [], 'rooms' => [], @@ -91,6 +93,7 @@ class ShareesAPIController extends OCSController { 'groups' => [], 'remotes' => [], 'remote_groups' => [], + 'federated_groups' => [], 'emails' => [], 'lookup' => [], 'circles' => [], @@ -178,6 +181,10 @@ public function search(string $search = '', string $itemType = null, int $page = if ($this->isRemoteGroupSharingAllowed($itemType)) { $shareTypes[] = IShare::TYPE_REMOTE_GROUP; + + if ($this->shareManager->shareProviderExists(IShare::TYPE_FEDERATED_GROUP)) { + $shareTypes[] = IShare::TYPE_FEDERATED_GROUP; + } } if ($this->shareManager->shareProviderExists(IShare::TYPE_EMAIL)) { @@ -284,6 +291,7 @@ private function sortShareesByFrequency(array $sharees): array { IShare::TYPE_GROUP => 'groups', IShare::TYPE_REMOTE => 'remotes', IShare::TYPE_REMOTE_GROUP => 'remote_groups', + IShare::TYPE_FEDERATED_GROUP => 'federated_groups', IShare::TYPE_EMAIL => 'emails', ]; @@ -356,6 +364,10 @@ public function findRecommended(string $itemType = null, $shareType = null): Dat if ($this->isRemoteGroupSharingAllowed($itemType)) { $shareTypes[] = IShare::TYPE_REMOTE_GROUP; + + if ($this->shareManager->shareProviderExists(IShare::TYPE_FEDERATED_GROUP)) { + $shareTypes[] = IShare::TYPE_FEDERATED_GROUP; + } } if ($this->shareManager->shareProviderExists(IShare::TYPE_EMAIL)) { diff --git a/apps/files_sharing/lib/Migration/Version26000Date20230117143027.php b/apps/files_sharing/lib/Migration/Version26000Date20230117143027.php new file mode 100644 index 0000000000000..c1c2cb65254df --- /dev/null +++ b/apps/files_sharing/lib/Migration/Version26000Date20230117143027.php @@ -0,0 +1,72 @@ + + * + * @author Sandro Mesterheide + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Files_Sharing\Migration; + +use Closure; +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +/** + * Auto-generated migration step: Please modify to your needs! + */ +class Version26000Date20230117143027 extends SimpleMigrationStep { + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $table = $schema->getTable('share_external'); + $changed = false; + + $column = $table->getColumn('user'); + if ($column->getLength() < 255) { + $column->setLength(255); + $changed = true; + } + + if (!$table->hasColumn('remote_share_type')) { + $table->addColumn('remote_share_type', Types::INTEGER, [ + 'notnull' => false, + 'length' => 4, + ]); + $changed = true; + } + + if ($changed) { + return $schema; + } + + return null; + } +} diff --git a/apps/files_sharing/src/components/SharingEntry.vue b/apps/files_sharing/src/components/SharingEntry.vue index b4549112964ae..5c4694e3a6c3c 100644 --- a/apps/files_sharing/src/components/SharingEntry.vue +++ b/apps/files_sharing/src/components/SharingEntry.vue @@ -183,6 +183,8 @@ export default { title += ` (${t('files_sharing', 'remote group')})` } else if (this.share.type === this.SHARE_TYPES.SHARE_TYPE_GUEST) { title += ` (${t('files_sharing', 'guest')})` + } else if (this.share.type === this.SHARE_TYPES.SHARE_TYPE_FEDERATED_GROUP) { + title += ` (${t('files_sharing', 'federated group')})` } return title }, diff --git a/apps/files_sharing/src/components/SharingInput.vue b/apps/files_sharing/src/components/SharingInput.vue index 46c495d8279cc..1a0592ffcc1e0 100644 --- a/apps/files_sharing/src/components/SharingInput.vue +++ b/apps/files_sharing/src/components/SharingInput.vue @@ -187,6 +187,7 @@ export default { this.SHARE_TYPES.SHARE_TYPE_ROOM, this.SHARE_TYPES.SHARE_TYPE_GUEST, this.SHARE_TYPES.SHARE_TYPE_DECK, + this.SHARE_TYPES.SHARE_TYPE_FEDERATED_GROUP, ] if (OC.getCapabilities().files_sharing.public.enabled === true) { @@ -413,6 +414,11 @@ export default { icon: 'icon-deck', iconTitle: t('files_sharing', 'Deck board'), } + case this.SHARE_TYPES.SHARE_TYPE_FEDERATED_GROUP: + return { + icon: 'icon-organization', + iconTitle: t('files_sharing', 'Virtual organization'), + } default: return {} } diff --git a/apps/files_sharing/src/mixins/ShareTypes.js b/apps/files_sharing/src/mixins/ShareTypes.js index 8b85f63f4563f..80dbe626e3de5 100644 --- a/apps/files_sharing/src/mixins/ShareTypes.js +++ b/apps/files_sharing/src/mixins/ShareTypes.js @@ -26,7 +26,10 @@ import { Type as ShareTypes } from '@nextcloud/sharing' export default { data() { return { - SHARE_TYPES: ShareTypes, + SHARE_TYPES: { + ...ShareTypes, + SHARE_TYPE_FEDERATED_GROUP: 14 + } } }, } diff --git a/core/img/actions/organization.svg b/core/img/actions/organization.svg new file mode 100644 index 0000000000000..c936c713cdbf5 --- /dev/null +++ b/core/img/actions/organization.svg @@ -0,0 +1,16 @@ + + + + + diff --git a/core/src/icons.js b/core/src/icons.js index 3cd685dce8c86..aa63aaea0fc9f 100644 --- a/core/src/icons.js +++ b/core/src/icons.js @@ -71,6 +71,7 @@ const icons = { 'menu': path.join(__dirname, '../img', 'actions', 'menu.svg'), 'more': path.join(__dirname, '../img', 'actions', 'more.svg'), 'music': path.join(__dirname, '../img', 'places', 'music.svg'), + 'organization': path.join(__dirname, '../img', 'actions', 'organization.svg'), 'password': path.join(__dirname, '../img', 'actions', 'password.svg'), 'pause': path.join(__dirname, '../img', 'actions', 'pause.svg'), 'phone': path.join(__dirname, '../img', 'clients', 'phone.svg'), diff --git a/lib/private/Federation/CloudFederationProviderManager.php b/lib/private/Federation/CloudFederationProviderManager.php index b11c4060ab4f2..c7685cd78b1f4 100644 --- a/lib/private/Federation/CloudFederationProviderManager.php +++ b/lib/private/Federation/CloudFederationProviderManager.php @@ -4,6 +4,7 @@ * * @author Bjoern Schiessle * @author Christoph Wurst + * @author Sandro Mesterheide * * @license GNU AGPL version 3 or any later version * @@ -88,26 +89,27 @@ public function __construct(IAppManager $appManager, * @param callable $callback */ public function addCloudFederationProvider($resourceType, $displayName, callable $callback) { - $this->cloudFederationProvider[$resourceType] = [ + $provider = call_user_func($callback); + $this->cloudFederationProvider[$provider::class] = [ 'resourceType' => $resourceType, 'displayName' => $displayName, - 'callback' => $callback, + 'provider' => $provider, ]; } /** * remove cloud federation provider * - * @param string $providerId + * @param string $providerClass */ - public function removeCloudFederationProvider($providerId) { - unset($this->cloudFederationProvider[$providerId]); + public function removeCloudFederationProvider($providerClass) { + unset($this->cloudFederationProvider[$providerClass]); } /** * get a list of all cloudFederationProviders * - * @return array [resourceType => ['resourceType' => $resourceType, 'displayName' => $displayName, 'callback' => callback]] + * @return array [providerClass => ['resourceType' => $resourceType, 'displayName' => $displayName, 'provider' => ICloudFederationProvider]] */ public function getAllCloudFederationProviders() { return $this->cloudFederationProvider; @@ -117,15 +119,20 @@ public function getAllCloudFederationProviders() { * get a specific cloud federation provider * * @param string $resourceType + * @param string|null $shareType * @return ICloudFederationProvider * @throws ProviderDoesNotExistsException */ - public function getCloudFederationProvider($resourceType) { - if (isset($this->cloudFederationProvider[$resourceType])) { - return call_user_func($this->cloudFederationProvider[$resourceType]['callback']); - } else { - throw new ProviderDoesNotExistsException($resourceType); - } + public function getCloudFederationProvider($resourceType, $shareType = null) { + foreach ($this->cloudFederationProvider as $providerWrapper) { + $provider = $providerWrapper['provider']; + if ($providerWrapper['resourceType'] === $resourceType) { + if (is_null($shareType) || in_array($shareType, $provider->getSupportedShareTypes())) { + return $provider; + } + } + } + throw new ProviderDoesNotExistsException($resourceType, $shareType); } public function sendShare(ICloudFederationShare $share) { diff --git a/lib/private/Federation/CloudFederationShare.php b/lib/private/Federation/CloudFederationShare.php index 0f79ba521eab6..63387b0350202 100644 --- a/lib/private/Federation/CloudFederationShare.php +++ b/lib/private/Federation/CloudFederationShare.php @@ -4,6 +4,7 @@ * * @author Bjoern Schiessle * @author Joas Schilling + * @author Sandro Mesterheide * * @license GNU AGPL version 3 or any later version * @@ -198,7 +199,7 @@ public function setProtocol(array $protocol) { } /** - * share type (group or user) + * share type (group, user or federation) * * @param string $shareType * @@ -207,6 +208,9 @@ public function setProtocol(array $protocol) { public function setShareType($shareType) { if ($shareType === 'group' || $shareType === IShare::TYPE_REMOTE_GROUP) { $this->share['shareType'] = 'group'; + } else if ($shareType === 'federation' || $shareType === IShare::TYPE_FEDERATED_GROUP) { + // OCM proposel, currently only supported by Nextcloud + $this->share['shareType'] = 'federation'; } else { $this->share['shareType'] = 'user'; } diff --git a/lib/private/Share/Constants.php b/lib/private/Share/Constants.php index 03c4c2ba828ec..75332cc97d382 100644 --- a/lib/private/Share/Constants.php +++ b/lib/private/Share/Constants.php @@ -74,6 +74,9 @@ class Constants { public const SHARE_TYPE_DECK = 12; // const SHARE_TYPE_DECK_USER = 13; // Internal type used by DeckShareProvider + // Relied on by appinfo XML schema collaboration plugin share-type attribute + public const SHARE_TYPE_FEDERATED_GROUP = 14; + public const FORMAT_NONE = -1; public const FORMAT_STATUSES = -2; public const FORMAT_SOURCES = -3; // ToDo Check if it is still in use otherwise remove it diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php index 7fd99545668b1..a5a5b9e61a718 100644 --- a/lib/private/Share20/Manager.php +++ b/lib/private/Share20/Manager.php @@ -20,6 +20,7 @@ * @author Robin Appelman * @author Roeland Jago Douma * @author Samuel + * @author Sandro Mesterheide * @author szaimen * @author Valdnet <47037905+Valdnet@users.noreply.github.com> * @author Vincent Petry @@ -237,6 +238,10 @@ protected function generalCreateChecks(IShare $share) { if ($share->getSharedWith() === null) { throw new \InvalidArgumentException('SharedWith should not be empty'); } + } elseif ($share->getShareType() === IShare::TYPE_FEDERATED_GROUP) { + if ($share->getSharedWith() === null) { + throw new \InvalidArgumentException('SharedWith should not be empty'); + } } elseif ($share->getShareType() === IShare::TYPE_CIRCLE) { $circle = \OCA\Circles\Api\v1\Circles::detailsCircle($share->getSharedWith()); if ($circle === null) { @@ -378,7 +383,9 @@ protected function generalCreateChecks(IShare $share) { * @throws \Exception */ protected function validateExpirationDateInternal(IShare $share) { - $isRemote = $share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP; + $isRemote = $share->getShareType() === IShare::TYPE_REMOTE + || $share->getShareType() === IShare::TYPE_REMOTE_GROUP + || $share->getShareType() === IShare::TYPE_FEDERATED_GROUP; $expirationDate = $share->getExpirationDate(); @@ -759,6 +766,9 @@ public function createShare(IShare $share) { } elseif ($share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP) { //Verify the expiration date $share = $this->validateExpirationDateInternal($share); + } elseif ($share->getShareType() === IShare::TYPE_FEDERATED_GROUP) { + //Verify the expiration date + $share = $this->validateExpirationDateInternal($share); } elseif ($share->getShareType() === IShare::TYPE_LINK || $share->getShareType() === IShare::TYPE_EMAIL) { $this->linkCreateChecks($share); @@ -1041,7 +1051,9 @@ public function updateShare(IShare $share) { $this->validateExpirationDateLink($share); $expirationDateUpdated = true; } - } elseif ($share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP) { + } elseif ($share->getShareType() === IShare::TYPE_REMOTE + || $share->getShareType() === IShare::TYPE_REMOTE_GROUP + || $share->getShareType() === IShare::TYPE_FEDERATED_GROUP) { if ($share->getExpirationDate() != $originalShare->getExpirationDate()) { //Verify the expiration date $this->validateExpirationDateInternal($share); @@ -1504,6 +1516,16 @@ public function getShareByToken($token) { } } + // If it is not a link share try to fetch a federated group share by token + if ($share === null && $this->shareProviderExists(IShare::TYPE_FEDERATED_GROUP)) { + try { + $provider = $this->factory->getProviderForType(IShare::TYPE_FEDERATED_GROUP); + $share = $provider->getShareByToken($token); + } catch (ProviderException $e) { + } catch (ShareNotFound $e) { + } + } + // If it is not a link share try to fetch a mail share by token if ($share === null && $this->shareProviderExists(IShare::TYPE_EMAIL)) { try { diff --git a/lib/private/Share20/ProviderFactory.php b/lib/private/Share20/ProviderFactory.php index 16f9a17ee4229..eb3befebfa93d 100644 --- a/lib/private/Share20/ProviderFactory.php +++ b/lib/private/Share20/ProviderFactory.php @@ -15,6 +15,7 @@ * @author Robin Appelman * @author Roeland Jago Douma * @author Samuel + * @author Sandro Mesterheide * * @license AGPL-3.0 * @@ -70,6 +71,8 @@ class ProviderFactory implements IProviderFactory { private $circlesAreNotAvailable = false; /** @var \OCA\Talk\Share\RoomShareProvider */ private $roomShareProvider = null; + /** @var \OCA\VO_Federation\FederatedGroupShareProvider */ + private $federatedGroupShareProvider = null; private $registeredShareProviders = []; @@ -274,6 +277,31 @@ protected function getRoomShareProvider() { return $this->roomShareProvider; } + /** + * Create the federated group share provider + * + * @return FederatedGroupShareProvider + */ + protected function getFederatedGroupShareProvider() { + if ($this->federatedGroupShareProvider === null) { + /* + * Check if the app is enabled + */ + $appManager = $this->serverContainer->getAppManager(); + if (!$appManager->isEnabledForUser('vo_federation')) { + return null; + } + + try { + $this->federatedGroupShareProvider = $this->serverContainer->query('\OCA\VO_Federation\FederatedGroupShareProvider'); + } catch (\OCP\AppFramework\QueryException $e) { + return null; + } + } + + return $this->federatedGroupShareProvider; + } + /** * @inheritdoc */ @@ -293,6 +321,8 @@ public function getProvider($id) { $provider = $this->getShareByCircleProvider(); } elseif ($id === 'ocRoomShare') { $provider = $this->getRoomShareProvider(); + } elseif ($id === 'ocFederatedGroupShare') { + $provider = $this->getFederatedGroupShareProvider(); } foreach ($this->registeredShareProviders as $shareProvider) { @@ -340,6 +370,8 @@ public function getProviderForType($shareType) { $provider = $this->getRoomShareProvider(); } elseif ($shareType === IShare::TYPE_DECK) { $provider = $this->getProvider('deck'); + } elseif ($shareType === IShare::TYPE_FEDERATED_GROUP) { + $provider = $this->getFederatedGroupShareProvider(); } @@ -364,6 +396,10 @@ public function getAllProviders() { if ($roomShare !== null) { $shares[] = $roomShare; } + $federatedGroupShare = $this->getFederatedGroupShareProvider(); + if ($federatedGroupShare !== null) { + $shares[] = $federatedGroupShare; + } foreach ($this->registeredShareProviders as $shareProvider) { try { diff --git a/lib/public/Federation/Exceptions/ProviderDoesNotExistsException.php b/lib/public/Federation/Exceptions/ProviderDoesNotExistsException.php index 849209da22d44..d9ca7ee8f761b 100644 --- a/lib/public/Federation/Exceptions/ProviderDoesNotExistsException.php +++ b/lib/public/Federation/Exceptions/ProviderDoesNotExistsException.php @@ -36,12 +36,13 @@ class ProviderDoesNotExistsException extends HintException { * * @since 14.0.0 * - * @param string $providerId cloud federation provider ID + * @param string $resourceId cloud federation resourceId + * @param string|null $shareId cloud federation shareId */ - public function __construct($providerId) { + public function __construct($resourceId, $shareId) { $l = \OC::$server->getL10N('federation'); - $message = 'Cloud Federation Provider with ID: "' . $providerId . '" does not exist.'; - $hint = $l->t('Cloud Federation Provider with ID: "%s" does not exist.', [$providerId]); + $message = 'Cloud Federation Provider with resourceId: "' . $resourceId . '" and shareId: "' . $shareId . '" does not exist.'; + $hint = $l->t('Cloud Federation Provider with resourceId: "%s" and shareId: "%s" does not exist.', [$resourceId, $shareId]); parent::__construct($message, $hint); } } diff --git a/lib/public/Federation/ICloudFederationProviderManager.php b/lib/public/Federation/ICloudFederationProviderManager.php index 7272653b14de4..6e76223169bac 100644 --- a/lib/public/Federation/ICloudFederationProviderManager.php +++ b/lib/public/Federation/ICloudFederationProviderManager.php @@ -47,18 +47,18 @@ public function addCloudFederationProvider($resourceType, $displayName, callable /** * remove cloud federation provider * - * @param string $resourceType + * @param string $providerClass * - * @since 14.0.0 + * @since 26.0.0 */ - public function removeCloudFederationProvider($resourceType); + public function removeCloudFederationProvider($providerClass); /** * get a list of all cloudFederationProviders * - * @return array [resourceType => ['resourceType' => $resourceType, 'displayName' => $displayName, 'callback' => callback]] + * @return array [providerClass => ['resourceType' => $resourceType, 'displayName' => $displayName, 'provider' => ICloudFederationProvider]] * - * @since 14.0.0 + * @since 26.0.0 */ public function getAllCloudFederationProviders(); @@ -66,12 +66,13 @@ public function getAllCloudFederationProviders(); * get a specific cloud federation provider * * @param string $resourceType + * @param string|null $shareType * @return ICloudFederationProvider * @throws Exceptions\ProviderDoesNotExistsException * * @since 14.0.0 */ - public function getCloudFederationProvider($resourceType); + public function getCloudFederationProvider($resourceType, $shareType = null); /** * send federated share diff --git a/lib/public/Federation/ICloudFederationShare.php b/lib/public/Federation/ICloudFederationShare.php index c2a4ca29e11c7..9e6783eba223e 100644 --- a/lib/public/Federation/ICloudFederationShare.php +++ b/lib/public/Federation/ICloudFederationShare.php @@ -219,7 +219,7 @@ public function getSharedBy(); public function getSharedByDisplayName(); /** - * get share type (group or user) + * get share type (group, user or federation) * * @return string * diff --git a/lib/public/Share/IShare.php b/lib/public/Share/IShare.php index f8f75be4c419a..9849bbe471a52 100644 --- a/lib/public/Share/IShare.php +++ b/lib/public/Share/IShare.php @@ -117,6 +117,12 @@ interface IShare { */ public const TYPE_DECK_USER = 13; + /** + * Extension to remote group share + * @since 26.0.0 + */ + public const TYPE_FEDERATED_GROUP = 14; + /** * @since 18.0.0 */