From 92c431e856028b0585d30ac54bc2808a2ec49b51 Mon Sep 17 00:00:00 2001 From: Jonathan Treffler Date: Thu, 31 Oct 2024 17:29:15 +0100 Subject: [PATCH] added resource members --- appinfo/info.xml | 2 + lib/Command/BaseCommand.php | 18 ++-- .../ListOrganizationFolders.php | 2 +- lib/Command/Resource/ListResources.php | 2 +- .../ResourceMember/CreateResourceMember.php | 48 +++++++++ .../ResourceMember/ListResourceMembers.php | 35 +++++++ lib/Db/FolderResource.php | 2 +- lib/Db/ResourceMember.php | 50 ++++++++++ lib/Db/ResourceMemberMapper.php | 49 ++++++++++ lib/Enum/FromNameEnum.php | 16 ++- lib/Interface/TableSerializable.php | 2 +- lib/Model/OrganizationFolder.php | 2 +- lib/Service/ResourceMemberService.php | 97 +++++++++++++++++++ lib/Service/ResourceService.php | 6 +- 14 files changed, 311 insertions(+), 20 deletions(-) create mode 100644 lib/Command/ResourceMember/CreateResourceMember.php create mode 100644 lib/Command/ResourceMember/ListResourceMembers.php create mode 100644 lib/Db/ResourceMember.php create mode 100644 lib/Db/ResourceMemberMapper.php create mode 100644 lib/Service/ResourceMemberService.php diff --git a/appinfo/info.xml b/appinfo/info.xml index f58e3af..606c70d 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -23,5 +23,7 @@ OCA\OrganizationFolders\Command\OrganizationFolder\CreateOrganizationFolder OCA\OrganizationFolders\Command\Resource\CreateResource OCA\OrganizationFolders\Command\Resource\ListResources + OCA\OrganizationFolders\Command\ResourceMember\CreateResourceMember + OCA\OrganizationFolders\Command\ResourceMember\ListResourceMembers \ No newline at end of file diff --git a/lib/Command/BaseCommand.php b/lib/Command/BaseCommand.php index 424ec56..756f99c 100644 --- a/lib/Command/BaseCommand.php +++ b/lib/Command/BaseCommand.php @@ -8,6 +8,7 @@ use OCP\IDateTimeFormatter; use OCA\OrganizationFolders\Model\OrganizationFolder; use OCA\OrganizationFolders\Service\OrganizationFolderService; use OCA\OrganizationFolders\Service\ResourceService; +use OCA\OrganizationFolders\Service\ResourceMemberService; use OCA\OrganizationFolders\Interface\TableSerializable; abstract class BaseCommand extends Base { @@ -16,19 +17,20 @@ abstract class BaseCommand extends Base { private readonly IDateTimeFormatter $dateTimeFormatter, protected readonly OrganizationFolderService $organizationFolderService, protected ResourceService $resourceService, + protected ResourceMemberService $resourceMemberService, ) { parent::__construct(); } - protected function formatTableSerializable(TableSerializable $serializable): array { - return $serializable->tableSerialize(); + protected function formatTableSerializable(TableSerializable $serializable, ?array $params = null): array { + return $serializable->tableSerialize($params); } - protected function formatOrganizationFolders(array $organizationFolders) { - return array_map($this->formatTableSerializable(...), $organizationFolders); - } - - protected function formatResources(array $resources): array { - return array_map($this->formatTableSerializable(...), $resources); + protected function formatTableSerializables(array $serializables, ?array $params = null): array { + $result = []; + foreach($serializables as $serializable) { + $result[] = $serializable->tableSerialize($params); + } + return $result; } } diff --git a/lib/Command/OrganizationFolder/ListOrganizationFolders.php b/lib/Command/OrganizationFolder/ListOrganizationFolders.php index 65b82d3..1355c86 100644 --- a/lib/Command/OrganizationFolder/ListOrganizationFolders.php +++ b/lib/Command/OrganizationFolder/ListOrganizationFolders.php @@ -21,7 +21,7 @@ class ListOrganizationFolders extends BaseCommand { try { $organizationFolderGroupfolders = $this->organizationFolderService->getAll(); - $this->writeTableInOutputFormat($input, $output, $this->formatOrganizationFolders($organizationFolderGroupfolders)); + $this->writeTableInOutputFormat($input, $output, $this->formatTableSerializables($organizationFolderGroupfolders)); return 0; } catch (Exception $e) { $output->writeln("Exception \"{$e->getMessage()}\" at {$e->getFile()} line {$e->getLine()}"); diff --git a/lib/Command/Resource/ListResources.php b/lib/Command/Resource/ListResources.php index cf75ab1..4a0fe01 100644 --- a/lib/Command/Resource/ListResources.php +++ b/lib/Command/Resource/ListResources.php @@ -27,7 +27,7 @@ class ListResources extends BaseCommand { $resources = $this->resourceService->findAll($organizationFolderId, $parentResourceId); - $this->writeTableInOutputFormat($input, $output, $this->formatResources($resources)); + $this->writeTableInOutputFormat($input, $output, $this->formatTableSerializables($resources)); return 0; } catch (Exception $e) { $output->writeln("Exception \"{$e->getMessage()}\" at {$e->getFile()} line {$e->getLine()}"); diff --git a/lib/Command/ResourceMember/CreateResourceMember.php b/lib/Command/ResourceMember/CreateResourceMember.php new file mode 100644 index 0000000..1a99853 --- /dev/null +++ b/lib/Command/ResourceMember/CreateResourceMember.php @@ -0,0 +1,48 @@ +setName('organization-folders:create-resource-member') + ->setDescription('Create a new member of resource') + ->addOption('resource-id', null, InputOption::VALUE_REQUIRED, 'Id of resource to create member of') + ->addOption('permission-level', null, InputOption::VALUE_REQUIRED, 'Permissions level of member (valid values: MEMBER, MANAGER)') + ->addOption('type', null, InputOption::VALUE_REQUIRED, 'Type of principal (valid values: USER, GROUP, ROLE)') + ->addOption('principal', null, InputOption::VALUE_OPTIONAL, 'For type user: "[user_id]", for group: "[group_name]", for role: "[organization_provider_id]:[role_id]"'); + + parent::configure(); + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + $resourceId = $input->getOption('resource-id'); + $permissionLevel = MemberPermissionLevel::fromNameOrValue($input->getOption('permission-level')); + $type = MemberType::fromNameOrValue($input->getOption('type')); + $principal = $input->getOption('principal'); + + try { + $resource = $this->resourceMemberService->create( + resourceId: $resourceId, + permissionLevel: $permissionLevel, + type: $type, + principal: $principal, + ); + + $this->writeTableInOutputFormat($input, $output, [$this->formatTableSerializable($resource)]); + return 0; + } catch (Exception $e) { + $output->writeln("Exception \"{$e->getMessage()}\" at {$e->getFile()} line {$e->getLine()}"); + return 1; + } + } +} diff --git a/lib/Command/ResourceMember/ListResourceMembers.php b/lib/Command/ResourceMember/ListResourceMembers.php new file mode 100644 index 0000000..0a81c5b --- /dev/null +++ b/lib/Command/ResourceMember/ListResourceMembers.php @@ -0,0 +1,35 @@ +setName('organization-folders:list-resource-members') + ->addArgument('resource-id', InputArgument::REQUIRED, 'Id of Resource') + ->setDescription('List all members of resource.'); + + parent::configure(); + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + try { + $resourceId = $input->getArgument('resource-id'); + + $members = $this->resourceMemberService->findAll($resourceId); + + $this->writeTableInOutputFormat($input, $output, $this->formatTableSerializables($members)); + return 0; + } catch (Exception $e) { + $output->writeln("Exception \"{$e->getMessage()}\" at {$e->getFile()} line {$e->getLine()}"); + return 1; + } + } +} diff --git a/lib/Db/FolderResource.php b/lib/Db/FolderResource.php index 0ccb8c3..0725351 100644 --- a/lib/Db/FolderResource.php +++ b/lib/Db/FolderResource.php @@ -48,7 +48,7 @@ class FolderResource extends Resource { ]; } - public function tableSerialize(): array { + public function tableSerialize(?array $params = null): array { return [ 'Id' => $this->id, 'Name' => $this->name, diff --git a/lib/Db/ResourceMember.php b/lib/Db/ResourceMember.php new file mode 100644 index 0000000..b3a61bb --- /dev/null +++ b/lib/Db/ResourceMember.php @@ -0,0 +1,50 @@ +addType('resourceId','integer'); + $this->addType('permissionLevel','integer'); + $this->addType('type','integer'); + $this->addType('createdTimestamp','integer'); + $this->addType('lastUpdatedTimestamp','integer'); + } + + public function jsonSerialize(): array { + return [ + 'resourceId' => $this->resourceId, + 'permissionLevel' => $this->permissionLevel, + 'type' => $this->type, + 'principal' => $this->principal, + 'createdTimestamp' => $this->createdTimestamp, + 'lastUpdatedTimestamp' => $this->lastUpdatedTimestamp, + ]; + } + + public function tableSerialize(?array $params = null): array { + return [ + 'Resource Id' => $this->resourceId, + 'Permission Level' => MemberPermissionLevel::from($this->permissionLevel)->name, + 'Type' => MemberType::from($this->type)->name, + 'Principal' => $this->principal, + 'Created' => $this->createdTimestamp, + 'LastUpdated' => $this->lastUpdatedTimestamp, + ]; + } +} diff --git a/lib/Db/ResourceMemberMapper.php b/lib/Db/ResourceMemberMapper.php new file mode 100644 index 0000000..05be516 --- /dev/null +++ b/lib/Db/ResourceMemberMapper.php @@ -0,0 +1,49 @@ +db->getQueryBuilder(); + + $qb->select('*') + ->from(self::RESOURCE_MEMBERS_TABLE) + ->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT))); + + return $this->findEntity($qb); + } + + /** + * @param int $resourceId + * @return array + */ + public function findAll(int $resourceId): array { + /* @var $qb IQueryBuilder */ + $qb = $this->db->getQueryBuilder(); + + $qb->select('*') + ->from(self::RESOURCE_MEMBERS_TABLE) + ->where($qb->expr()->eq('resource_id', $qb->createNamedParameter($resourceId, IQueryBuilder::PARAM_INT))); + + return $this->findEntities($qb); + } +} \ No newline at end of file diff --git a/lib/Enum/FromNameEnum.php b/lib/Enum/FromNameEnum.php index 1cccdd7..807fba2 100644 --- a/lib/Enum/FromNameEnum.php +++ b/lib/Enum/FromNameEnum.php @@ -3,12 +3,20 @@ namespace OCA\OrganizationFolders\Enum; trait FromNameEnum { - public static function fromName(string $name): string { - foreach (self::cases() as $status) { - if( $name === $status->name ){ - return $status->value; + public static function fromName(string $name) { + foreach(self::cases() as $status) { + if($name === $status->name){ + return $status; } } throw new \ValueError("$name is not a valid value for enum " . self::class ); } + + public static function fromNameOrValue(int|string $scalar) { + if(gettype($scalar) == "integer") { + return self::tryFrom($scalar); + } else { + return self::fromName($scalar); + } + } } \ No newline at end of file diff --git a/lib/Interface/TableSerializable.php b/lib/Interface/TableSerializable.php index ac4a26f..759c674 100644 --- a/lib/Interface/TableSerializable.php +++ b/lib/Interface/TableSerializable.php @@ -7,5 +7,5 @@ interface TableSerializable { * Serializes the object to a dict array to be rendered into a occ command output table * @return array */ - function tableSerialize(); + function tableSerialize(?array $params = null); } \ No newline at end of file diff --git a/lib/Model/OrganizationFolder.php b/lib/Model/OrganizationFolder.php index 8e0e495..2422441 100644 --- a/lib/Model/OrganizationFolder.php +++ b/lib/Model/OrganizationFolder.php @@ -33,7 +33,7 @@ class OrganizationFolder implements JsonSerializable, TableSerializable { ]; } - public function tableSerialize(): array { + public function tableSerialize(?array $params = null): array { return [ 'Id' => $this->id, 'Name' => $this->name, diff --git a/lib/Service/ResourceMemberService.php b/lib/Service/ResourceMemberService.php new file mode 100644 index 0000000..f1e8aa1 --- /dev/null +++ b/lib/Service/ResourceMemberService.php @@ -0,0 +1,97 @@ +mapper->findAll($resourceId); + } + + private function handleException(Exception $e): void { + if ($e instanceof DoesNotExistException || + $e instanceof MultipleObjectsReturnedException) { + throw new ResourceMemberNotFound($e->getMessage()); + } else { + throw $e; + } + } + + public function find(int $id): ResourceMember { + try { + return $this->mapper->find($id); + } catch (Exception $e) { + $this->handleException($e); + } + } + + public function create( + int $resourceId, + MemberPermissionLevel $permissionLevel, + MemberType $type, + string $principal + ): ResourceMember { + $member = new ResourceMember(); + $member->setResourceId($resourceId); + $member->setPermissionLevel($permissionLevel->value); + $member->setType($type->value); + $member->setPrincipal($principal); + $member->setCreatedTimestamp(time()); + $member->setLastUpdatedTimestamp(time()); + + return $this->mapper->insert($member); + } + + public function update(int $id, ?MemberPermissionLevel $permissionLevel = null, ?MemberType $type = null, ?string $principal = null): ResourceMember { + try { + $member = $this->mapper->find($id); + + if(isset($permissionLevel)) { + $member->setPermissionLevel($permissionLevel->value); + } + + if(isset($type)) { + $member->setType($type->value); + } + + if(isset($principal)) { + $member->setPrincipal($principal); + } + + if(count($member->getUpdatedFields()) > 0) { + $member->setLastUpdatedTimestamp(time()); + } + + return $this->mapper->update($member); + } catch (Exception $e) { + $this->handleException($e); + } + } + + public function delete(int $id): ResourceMember { + try { + $member = $this->mapper->find($id); + $this->mapper->delete($member); + return $member; + } catch (Exception $e) { + $this->handleException($e); + } + } +} \ No newline at end of file diff --git a/lib/Service/ResourceService.php b/lib/Service/ResourceService.php index 10c15da..2cf2a97 100644 --- a/lib/Service/ResourceService.php +++ b/lib/Service/ResourceService.php @@ -20,8 +20,8 @@ class ResourceService { ) { } - public function findAll(int $groupfolderId, int $parentResourceId = null) { - return $this->mapper->findAll($groupfolderId, $parentResourceId); + public function findAll(int $organizationFolderId, int $parentResourceId = null) { + return $this->mapper->findAll($organizationFolderId, $parentResourceId); } private function handleException(Exception $e, int $id): void { @@ -60,7 +60,7 @@ class ResourceService { } if(!$this->mapper->existsWithName($organizationFolderId, $parentResource, $name)) { - $resource->setGroupFolderId($organizationFolderId); + $resource->setOrganizationFolderId($organizationFolderId); $resource->setName($name); $resource->setParentResource($parentResource); $resource->setActive($active);