diff --git a/appinfo/routes.php b/appinfo/routes.php index 05a0aafce..20176eb57 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -128,6 +128,7 @@ ['name' => 'Context#show', 'url' => '/api/2/contexts/{contextId}', 'verb' => 'GET'], ['name' => 'Context#create', 'url' => '/api/2/contexts', 'verb' => 'POST'], ['name' => 'Context#update', 'url' => '/api/2/contexts/{contextId}', 'verb' => 'PUT'], + ['name' => 'Context#transfer', 'url' => '/api/2/contexts/{contextId}/transfer', 'verb' => 'PUT'], ['name' => 'Context#addNode', 'url' => '/api/2/contexts/{contextId}/nodes', 'verb' => 'POST'], ['name' => 'Context#removeNode', 'url' => '/api/2/contexts/{contextId}/nodes/{nodeRelId}', 'verb' => 'DELETE'], ['name' => 'Context#updateContentOrder', 'url' => '/api/2/contexts/{contextId}/pages/{pageId}', 'verb' => 'PUT'], diff --git a/lib/Controller/ContextController.php b/lib/Controller/ContextController.php index 8f749ffdd..efd70cb40 100644 --- a/lib/Controller/ContextController.php +++ b/lib/Controller/ContextController.php @@ -113,6 +113,25 @@ public function update(int $contextId, ?string $name, ?string $iconName, ?string } } + /** + * @NoAdminRequired + * @CanManageContext + * + * @psalm-param int<0, max> $contextId + * @psalm-param int<0, 0> $newOwnerType + */ + public function transfer(int $contextId, string $newOwnerId, int $newOwnerType = 0): DataResponse { + try { + return new DataResponse($this->contextService->transfer($contextId, $newOwnerId, $newOwnerType)->jsonSerialize()); + } catch (Exception|MultipleObjectsReturnedException $e) { + return $this->handleError($e); + } catch (DoesNotExistException $e) { + return $this->handleNotFoundError(new NotFoundError($e->getMessage(), $e->getCode(), $e)); + } catch (BadRequestError $e) { + return $this->handleBadRequestError($e); + } + } + /** * @NoAdminRequired * @CanManageNode diff --git a/lib/Service/ContextService.php b/lib/Service/ContextService.php index 43dbdc6f1..2d4f7b358 100644 --- a/lib/Service/ContextService.php +++ b/lib/Service/ContextService.php @@ -14,11 +14,15 @@ use OCA\Tables\Db\PageContent; use OCA\Tables\Db\PageContentMapper; use OCA\Tables\Db\PageMapper; +use OCA\Tables\Errors\BadRequestError; use OCA\Tables\Errors\InternalError; use OCA\Tables\Errors\PermissionError; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\MultipleObjectsReturnedException; use OCP\DB\Exception; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\IUserManager; +use OCP\Log\Audit\CriticalActionPerformedEvent; use Psr\Log\LoggerInterface; class ContextService { @@ -30,6 +34,8 @@ class ContextService { private PageMapper $pageMapper; private PageContentMapper $pageContentMapper; private PermissionsService $permissionsService; + private IUserManager $userManager; + private IEventDispatcher $eventDispatcher; public function __construct( ContextMapper $contextMapper, @@ -38,6 +44,8 @@ public function __construct( PageContentMapper $pageContentMapper, LoggerInterface $logger, PermissionsService $permissionsService, + IUserManager $userManager, + IEventDispatcher $eventDispatcher, bool $isCLI, ) { $this->contextMapper = $contextMapper; @@ -47,6 +55,8 @@ public function __construct( $this->pageMapper = $pageMapper; $this->pageContentMapper = $pageContentMapper; $this->permissionsService = $permissionsService; + $this->userManager = $userManager; + $this->eventDispatcher = $eventDispatcher; } /** @@ -126,6 +136,41 @@ public function update(int $contextId, ?string $name, ?string $iconName, ?string return $this->contextMapper->update($context); } + /** + * @throws MultipleObjectsReturnedException + * @throws DoesNotExistException + * @throws Exception + * @throws BadRequestError + */ + public function transfer(int $contextId, string $newOwnerId, int $newOwnerType): Context { + $context = $this->contextMapper->findById($contextId); + + // the owner type check can be dropped as soon as NC 29 is the lowest supported version, + // as the int range as defined in the Controller will be enforced by the Http/Dispatcher. + if ($newOwnerType !== Application::OWNER_TYPE_USER) { + throw new BadRequestError('Unsupported owner type'); + } + + if (!$this->userManager->userExists($newOwnerId)) { + throw new BadRequestError('User does not exist'); + } + + $context->setOwnerId($newOwnerId); + $context->setOwnerType($newOwnerType); + + $context = $this->contextMapper->update($context); + + $auditEvent = new CriticalActionPerformedEvent( + sprintf('Tables application with ID %d was transferred to user %s', + $contextId, $newOwnerId, + ) + ); + + $this->eventDispatcher->dispatchTyped($auditEvent); + + return $context; + } + /** * @throws MultipleObjectsReturnedException * @throws DoesNotExistException