parent
2c9761c73a
commit
c7813bfdaf
@ -0,0 +1,97 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
/** |
||||
* @copyright Copyright (c) 2024 Julius Härtl <jus@bitgrid.net> |
||||
* |
||||
* @author Julius Härtl <jus@bitgrid.net> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
*/ |
||||
|
||||
namespace OC\Core\Controller; |
||||
|
||||
use OCA\Core\ResponseDefinitions; |
||||
use OCP\AppFramework\Http; |
||||
use OCP\AppFramework\Http\Attribute\ApiRoute; |
||||
use OCP\AppFramework\Http\Attribute\NoAdminRequired; |
||||
use OCP\AppFramework\Http\DataResponse; |
||||
use OCP\IRequest; |
||||
use OCP\Teams\ITeamManager; |
||||
use OCP\Teams\Team; |
||||
|
||||
/** |
||||
* @psalm-import-type CoreTeamResource from ResponseDefinitions |
||||
* @psalm-import-type CoreTeam from ResponseDefinitions |
||||
* @property $userId string |
||||
*/ |
||||
class TeamsApiController extends \OCP\AppFramework\OCSController { |
||||
public function __construct( |
||||
string $appName, |
||||
IRequest $request, |
||||
private ITeamManager $teamManager, |
||||
private ?string $userId, |
||||
) { |
||||
parent::__construct($appName, $request); |
||||
} |
||||
|
||||
/** |
||||
* Get all resources of a team |
||||
* |
||||
* @param string $teamId Unique id of the team |
||||
* @return DataResponse<Http::STATUS_OK, array{resources: CoreTeamResource[]}, array{}> |
||||
* |
||||
* 200: Resources returned |
||||
*/ |
||||
#[NoAdminRequired] |
||||
#[ApiRoute(verb: 'GET', url: '/{teamId}/resources', root: '/teams')] |
||||
public function resolveOne(string $teamId): DataResponse { |
||||
/** |
||||
* @var CoreTeamResource[] $resolvedResources |
||||
* @psalm-suppress PossiblyNullArgument The route is limited to logged-in users |
||||
*/ |
||||
$resolvedResources = $this->teamManager->getSharedWith($teamId, $this->userId); |
||||
|
||||
return new DataResponse(['resources' => $resolvedResources]); |
||||
} |
||||
|
||||
/** |
||||
* Get all teams of a resource |
||||
* |
||||
* @param string $providerId Identifier of the provider (e.g. deck, talk, collectives) |
||||
* @param string $resourceId Unique id of the resource to list teams for (e.g. deck board id) |
||||
* @return DataResponse<Http::STATUS_OK, array{teams: CoreTeam[]}, array{}> |
||||
* |
||||
* 200: Teams returned |
||||
*/ |
||||
#[NoAdminRequired] |
||||
#[ApiRoute(verb: 'GET', url: '/resources/{providerId}/{resourceId}', root: '/teams')] |
||||
public function listTeams(string $providerId, string $resourceId): DataResponse { |
||||
/** @psalm-suppress PossiblyNullArgument The route is limited to logged-in users */ |
||||
$teams = $this->teamManager->getTeamsForResource($providerId, $resourceId, $this->userId); |
||||
/** @var CoreTeam[] $teams */ |
||||
$teams = array_map(function (Team $team) { |
||||
$response = $team->jsonSerialize(); |
||||
/** @psalm-suppress PossiblyNullArgument The route is limited to logged in users */ |
||||
$response['resources'] = $this->teamManager->getSharedWith($team->getId(), $this->userId); |
||||
return $response; |
||||
}, $teams); |
||||
|
||||
return new DataResponse([ |
||||
'teams' => $teams, |
||||
]); |
||||
} |
||||
} |
||||
@ -1,5 +1,68 @@ |
||||
{ |
||||
"packages": [], |
||||
"dev": false, |
||||
"dev-package-names": [] |
||||
"packages": [ |
||||
{ |
||||
"name": "bamarni/composer-bin-plugin", |
||||
"version": "1.8.2", |
||||
"version_normalized": "1.8.2.0", |
||||
"source": { |
||||
"type": "git", |
||||
"url": "https://github.com/bamarni/composer-bin-plugin.git", |
||||
"reference": "92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880" |
||||
}, |
||||
"dist": { |
||||
"type": "zip", |
||||
"url": "https://api.github.com/repos/bamarni/composer-bin-plugin/zipball/92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880", |
||||
"reference": "92fd7b1e6e9cdae19b0d57369d8ad31a37b6a880", |
||||
"shasum": "" |
||||
}, |
||||
"require": { |
||||
"composer-plugin-api": "^2.0", |
||||
"php": "^7.2.5 || ^8.0" |
||||
}, |
||||
"require-dev": { |
||||
"composer/composer": "^2.0", |
||||
"ext-json": "*", |
||||
"phpstan/extension-installer": "^1.1", |
||||
"phpstan/phpstan": "^1.8", |
||||
"phpstan/phpstan-phpunit": "^1.1", |
||||
"phpunit/phpunit": "^8.5 || ^9.5", |
||||
"symfony/console": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", |
||||
"symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", |
||||
"symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0" |
||||
}, |
||||
"time": "2022-10-31T08:38:03+00:00", |
||||
"type": "composer-plugin", |
||||
"extra": { |
||||
"class": "Bamarni\\Composer\\Bin\\BamarniBinPlugin" |
||||
}, |
||||
"installation-source": "dist", |
||||
"autoload": { |
||||
"psr-4": { |
||||
"Bamarni\\Composer\\Bin\\": "src" |
||||
} |
||||
}, |
||||
"notification-url": "https://packagist.org/downloads/", |
||||
"license": [ |
||||
"MIT" |
||||
], |
||||
"description": "No conflicts for your bin dependencies", |
||||
"keywords": [ |
||||
"composer", |
||||
"conflict", |
||||
"dependency", |
||||
"executable", |
||||
"isolation", |
||||
"tool" |
||||
], |
||||
"support": { |
||||
"issues": "https://github.com/bamarni/composer-bin-plugin/issues", |
||||
"source": "https://github.com/bamarni/composer-bin-plugin/tree/1.8.2" |
||||
}, |
||||
"install-path": "../bamarni/composer-bin-plugin" |
||||
} |
||||
], |
||||
"dev": true, |
||||
"dev-package-names": [ |
||||
"bamarni/composer-bin-plugin" |
||||
] |
||||
} |
||||
|
||||
@ -0,0 +1,119 @@ |
||||
<?php |
||||
/** |
||||
* @copyright Copyright (c) 2024 Julius Härtl <jus@bitgrid.net> |
||||
* |
||||
* @author Julius Härtl <jus@bitgrid.net> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
*/ |
||||
|
||||
namespace OC\Teams; |
||||
|
||||
use OC\AppFramework\Bootstrap\Coordinator; |
||||
use OCA\Circles\CirclesManager; |
||||
use OCA\Circles\Exceptions\CircleNotFoundException; |
||||
use OCA\Circles\Model\Circle; |
||||
use OCA\Circles\Model\Member; |
||||
use OCP\IURLGenerator; |
||||
use OCP\Server; |
||||
use OCP\Teams\ITeamManager; |
||||
use OCP\Teams\ITeamResourceProvider; |
||||
use OCP\Teams\Team; |
||||
use Psr\Container\ContainerExceptionInterface; |
||||
use Psr\Container\NotFoundExceptionInterface; |
||||
|
||||
class TeamManager implements ITeamManager { |
||||
|
||||
/** @var ?ITeamResourceProvider[] */ |
||||
private ?array $providers = null; |
||||
|
||||
public function __construct( |
||||
private Coordinator $bootContext, |
||||
private IURLGenerator $urlGenerator, |
||||
private ?CirclesManager $circlesManager, |
||||
) { |
||||
} |
||||
|
||||
public function hasTeamSupport(): bool { |
||||
return $this->circlesManager !== null; |
||||
} |
||||
|
||||
public function getProviders(): array { |
||||
if ($this->providers !== null) { |
||||
return $this->providers; |
||||
} |
||||
|
||||
$this->providers = []; |
||||
foreach ($this->bootContext->getRegistrationContext()->getTeamResourceProviders() as $providerRegistration) { |
||||
try { |
||||
/** @var ITeamResourceProvider $provider */ |
||||
$provider = Server::get($providerRegistration->getService()); |
||||
$this->providers[$provider->getId()] = $provider; |
||||
} catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) { |
||||
} |
||||
} |
||||
return $this->providers; |
||||
} |
||||
|
||||
public function getProvider(string $providerId): ITeamResourceProvider { |
||||
$providers = $this->getProviders(); |
||||
if (isset($providers[$providerId])) { |
||||
return $providers[$providerId]; |
||||
} |
||||
|
||||
throw new \RuntimeException('No provider found for id ' .$providerId); |
||||
} |
||||
|
||||
public function getSharedWith(string $teamId, string $userId): array { |
||||
if ($this->getTeam($teamId, $userId) === null) { |
||||
return []; |
||||
} |
||||
|
||||
$resources = []; |
||||
|
||||
foreach ($this->getProviders() as $provider) { |
||||
array_push($resources, ...$provider->getSharedWith($teamId)); |
||||
} |
||||
|
||||
return $resources; |
||||
} |
||||
|
||||
public function getTeamsForResource(string $providerId, string $resourceId, string $userId): array { |
||||
$provider = $this->getProvider($providerId); |
||||
return array_values(array_filter(array_map(function ($teamId) use ($userId) { |
||||
$team = $this->getTeam($teamId, $userId); |
||||
if ($team === null) { |
||||
return null; |
||||
} |
||||
|
||||
return new Team( |
||||
$teamId, |
||||
$team->getDisplayName(), |
||||
$this->urlGenerator->linkToRouteAbsolute('contacts.contacts.directcircle', ['singleId' => $teamId]), |
||||
); |
||||
}, $provider->getTeamsForResource($resourceId)))); |
||||
} |
||||
|
||||
private function getTeam(string $teamId, string $userId): ?Circle { |
||||
try { |
||||
$federatedUser = $this->circlesManager->getFederatedUser($userId, Member::TYPE_USER); |
||||
$this->circlesManager->startSession($federatedUser); |
||||
return $this->circlesManager->getCircle($teamId); |
||||
} catch (CircleNotFoundException) { |
||||
return null; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,58 @@ |
||||
<?php |
||||
/** |
||||
* @copyright Copyright (c) 2024 Julius Härtl <jus@bitgrid.net> |
||||
* |
||||
* @author Julius Härtl <jus@bitgrid.net> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
*/ |
||||
|
||||
namespace OCP\Teams; |
||||
|
||||
/** |
||||
* @since 29.0.0 |
||||
*/ |
||||
interface ITeamManager { |
||||
/** |
||||
* Get all providers that have registered as a team resource provider |
||||
* |
||||
* @return ITeamResourceProvider[] |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function getProviders(): array; |
||||
|
||||
/** |
||||
* Get a specific team resource provider by its id |
||||
* |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function getProvider(string $providerId): ITeamResourceProvider; |
||||
|
||||
/** |
||||
* Returns all team resources for a given team and user |
||||
* |
||||
* @return TeamResource[] |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function getSharedWith(string $teamId, string $userId): array; |
||||
|
||||
/** |
||||
* Returns all teams for a given resource and user |
||||
* |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function getTeamsForResource(string $providerId, string $resourceId, string $userId): array; |
||||
} |
||||
@ -0,0 +1,76 @@ |
||||
<?php |
||||
/** |
||||
* @copyright Copyright (c) 2024 Julius Härtl <jus@bitgrid.net> |
||||
* |
||||
* @author Julius Härtl <jus@bitgrid.net> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
*/ |
||||
|
||||
namespace OCP\Teams; |
||||
|
||||
/** |
||||
* Implement a provider of resources that are shared or owned by a team |
||||
* |
||||
* @since 29.0.0 |
||||
*/ |
||||
interface ITeamResourceProvider { |
||||
|
||||
/** |
||||
* Unique identifier used to identify the provider (app id) |
||||
* |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function getId(): string; |
||||
|
||||
/** |
||||
* User visible name of the provider (app name) |
||||
* |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function getName(): string; |
||||
|
||||
/** |
||||
* Svg icon to show next to the provider (app icon) |
||||
* |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function getIconSvg(): string; |
||||
|
||||
/** |
||||
* Return all resources that are shared to the given team id for the current provider |
||||
* |
||||
* @param string $teamId |
||||
* @return TeamResource[] |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function getSharedWith(string $teamId): array; |
||||
|
||||
/** |
||||
* Check if a resource is shared with the given team |
||||
* |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function isSharedWithTeam(string $teamId, string $resourceId): bool; |
||||
|
||||
/** |
||||
* Return team ids that a resource is shared with or owned by |
||||
* |
||||
* @return string[] |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function getTeamsForResource(string $resourceId): array; |
||||
} |
||||
@ -0,0 +1,73 @@ |
||||
<?php |
||||
/** |
||||
* @copyright Copyright (c) 2024 Julius Härtl <jus@bitgrid.net> |
||||
* |
||||
* @author Julius Härtl <jus@bitgrid.net> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
*/ |
||||
|
||||
namespace OCP\Teams; |
||||
|
||||
/** |
||||
* Simple abstraction to represent a team in the public API |
||||
* |
||||
* In the backend a team is a circle identified by the circles singleId |
||||
* |
||||
* @since 29.0.0 |
||||
*/ |
||||
class Team implements \JsonSerializable { |
||||
|
||||
/** |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function __construct(private string $teamId, private string $displayName, private ?string $link) { |
||||
} |
||||
|
||||
/** |
||||
* Unique identifier of the team (singleId of the circle) |
||||
* |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function getId(): string { |
||||
return $this->teamId; |
||||
} |
||||
|
||||
/** |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function getDisplayName(): string { |
||||
return $this->displayName; |
||||
} |
||||
|
||||
/** |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function getLink(): ?string { |
||||
return $this->link; |
||||
} |
||||
|
||||
/** |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function jsonSerialize(): array { |
||||
return [ |
||||
'teamId' => $this->teamId, |
||||
'displayName' => $this->displayName, |
||||
'link' => $this->link, |
||||
]; |
||||
} |
||||
} |
||||
@ -0,0 +1,129 @@ |
||||
<?php |
||||
/** |
||||
* @copyright Copyright (c) 2024 Julius Härtl <jus@bitgrid.net> |
||||
* |
||||
* @author Julius Härtl <jus@bitgrid.net> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
*/ |
||||
|
||||
namespace OCP\Teams; |
||||
|
||||
/** |
||||
* @since 29.0.0 |
||||
*/ |
||||
class TeamResource implements \JsonSerializable { |
||||
/** |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function __construct( |
||||
private ITeamResourceProvider $teamResourceProvider, |
||||
private string $resourceId, |
||||
private string $label, |
||||
private string $url, |
||||
private ?string $iconSvg = null, |
||||
private ?string $iconURL = null, |
||||
private ?string $iconEmoji = null, |
||||
) { |
||||
} |
||||
|
||||
/** |
||||
* Returns the provider details for the current resource |
||||
* |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function getProvider(): ITeamResourceProvider { |
||||
return $this->teamResourceProvider; |
||||
} |
||||
|
||||
/** |
||||
* Unique id of the resource (e.g. primary key id) |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function getId(): string { |
||||
return $this->resourceId; |
||||
} |
||||
|
||||
/** |
||||
* User visible label when listing resources |
||||
* |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function getLabel(): string { |
||||
return $this->label; |
||||
} |
||||
|
||||
/** |
||||
* Absolute url to navigate the user to the resource |
||||
* |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function getUrl(): string { |
||||
return $this->url; |
||||
} |
||||
|
||||
/** |
||||
* Svg icon to show next to the name for the resource |
||||
* |
||||
* From all icons the first one returning not null will be picked in order: iconEmoji, iconSvg, iconUrl |
||||
* |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function getIconSvg(): ?string { |
||||
return $this->iconSvg; |
||||
} |
||||
|
||||
/** |
||||
* Image url of the icon to show next to the name for the resource |
||||
* |
||||
* From all icons the first one returning not null will be picked in order: iconEmoji, iconSvg, iconUrl |
||||
* |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function getIconURL(): ?string { |
||||
return $this->iconURL; |
||||
} |
||||
|
||||
/** |
||||
* Emoji show next to the name for the resource |
||||
* |
||||
* From all icons the first one returning not null will be picked in order: iconEmoji, iconSvg, iconUrl |
||||
* |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function getIconEmoji(): ?string { |
||||
return $this->iconEmoji; |
||||
} |
||||
|
||||
/** |
||||
* @since 29.0.0 |
||||
*/ |
||||
public function jsonSerialize(): array { |
||||
return [ |
||||
'id' => $this->resourceId, |
||||
'label' => $this->label, |
||||
'url' => $this->url, |
||||
'iconSvg' => $this->iconSvg, |
||||
'iconURL' => $this->iconURL, |
||||
'iconEmoji' => $this->iconEmoji, |
||||
'provider' => [ |
||||
'id' => $this->teamResourceProvider->getId(), |
||||
'name' => $this->teamResourceProvider->getName(), |
||||
'icon' => $this->teamResourceProvider->getIconSvg(), |
||||
] |
||||
]; |
||||
} |
||||
} |
||||
Loading…
Reference in new issue