mirror of
https://github.com/verdigado/organization_folders.git
synced 2024-11-21 20:28:11 +01:00
added user-has-manager-permissions dav prop; added principal model and simplified the ACL code with it
This commit is contained in:
parent
72fbc9e20e
commit
8bfa9dfa29
11 changed files with 172 additions and 114 deletions
|
@ -14,14 +14,17 @@ use OCA\GroupFolders\Folder\FolderManager;
|
||||||
use OCA\GroupFolders\Mount\GroupMountPoint;
|
use OCA\GroupFolders\Mount\GroupMountPoint;
|
||||||
|
|
||||||
use OCA\OrganizationFolders\Service\ResourceService;
|
use OCA\OrganizationFolders\Service\ResourceService;
|
||||||
|
use OCA\OrganizationFolders\Security\AuthorizationService;
|
||||||
|
|
||||||
class PropFindPlugin extends ServerPlugin {
|
class PropFindPlugin extends ServerPlugin {
|
||||||
public const ORGANIZATION_FOLDER_ID_PROPERTYNAME = '{http://verdigado.com/ns}organization-folder-id';
|
public const ORGANIZATION_FOLDER_ID_PROPERTYNAME = '{http://verdigado.com/ns}organization-folder-id';
|
||||||
public const ORGANIZATION_FOLDER_RESOURCE_ID_PROPERTYNAME = '{http://verdigado.com/ns}organization-folder-resource-id';
|
public const ORGANIZATION_FOLDER_RESOURCE_ID_PROPERTYNAME = '{http://verdigado.com/ns}organization-folder-resource-id';
|
||||||
|
public const ORGANIZATION_FOLDER_RESOURCE_MANAGER_PERMISSIONS_PROPERTYNAME = '{http://verdigado.com/ns}organization-folder-resource-user-has-manager-permissions';
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private FolderManager $folderManager,
|
private FolderManager $folderManager,
|
||||||
private ResourceService $resourceService,
|
private ResourceService $resourceService,
|
||||||
|
private AuthorizationService $authorizationService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +44,7 @@ class PropFindPlugin extends ServerPlugin {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$propFind->handle(self::ORGANIZATION_FOLDER_ID_PROPERTYNAME, function () use ($fileInfo): int {
|
$propFind->handle(self::ORGANIZATION_FOLDER_ID_PROPERTYNAME, function () use ($fileInfo): int {
|
||||||
return $this->folderManager->getFolderByPath($fileInfo->getPath());
|
return $this->folderManager->getFolderByPath($fileInfo->getPath());
|
||||||
});
|
});
|
||||||
|
@ -52,5 +56,14 @@ class PropFindPlugin extends ServerPlugin {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$propFind->handle(self::ORGANIZATION_FOLDER_RESOURCE_MANAGER_PERMISSIONS_PROPERTYNAME, function () use ($node) {
|
||||||
|
try {
|
||||||
|
$resource = $this->resourceService->findByFileId($node->getId());
|
||||||
|
return $this->authorizationService->isGranted(["READ"], $resource) ? 'true' : 'false';
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -67,8 +67,13 @@ class ResourceMapper extends QBMapper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $organizationFolderId
|
* @param int $organizationFolderId
|
||||||
* @param int $parentResourceId
|
* @psalm-param int $organizationFolderId
|
||||||
|
* @param int|null $parentResourceId
|
||||||
|
* @psalm-param int|null $parentResourceId
|
||||||
|
* @param array $filters
|
||||||
|
* @psalm-param array $filters
|
||||||
* @return array
|
* @return array
|
||||||
|
* @psalm-return Resource[]
|
||||||
*/
|
*/
|
||||||
public function findAll(int $organizationFolderId, ?int $parentResourceId = null, array $filters = []): array {
|
public function findAll(int $organizationFolderId, ?int $parentResourceId = null, array $filters = []): array {
|
||||||
/* @var $qb IQueryBuilder */
|
/* @var $qb IQueryBuilder */
|
||||||
|
|
|
@ -8,31 +8,39 @@ use OCA\OrganizationFolders\Interface\TableSerializable;
|
||||||
use OCP\AppFramework\Db\Entity;
|
use OCP\AppFramework\Db\Entity;
|
||||||
|
|
||||||
use OCA\OrganizationFolders\Enum\MemberPermissionLevel;
|
use OCA\OrganizationFolders\Enum\MemberPermissionLevel;
|
||||||
use OCA\OrganizationFolders\Enum\MemberType;
|
use OCA\OrganizationFolders\Enum\PrincipalType;
|
||||||
|
use OCA\OrganizationFolders\Model\Principal;
|
||||||
|
|
||||||
class ResourceMember extends Entity implements JsonSerializable, TableSerializable {
|
class ResourceMember extends Entity implements JsonSerializable, TableSerializable {
|
||||||
protected $resourceId;
|
protected $resourceId;
|
||||||
protected $permissionLevel;
|
protected $permissionLevel;
|
||||||
protected $type;
|
protected $principalType;
|
||||||
protected $principal;
|
protected $principalId;
|
||||||
protected $createdTimestamp;
|
protected $createdTimestamp;
|
||||||
protected $lastUpdatedTimestamp;
|
protected $lastUpdatedTimestamp;
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
$this->addType('resourceId','integer');
|
$this->addType('resourceId','integer');
|
||||||
$this->addType('permissionLevel','integer');
|
$this->addType('permissionLevel','integer');
|
||||||
$this->addType('type','integer');
|
$this->addType('principalType','integer');
|
||||||
$this->addType('createdTimestamp','integer');
|
$this->addType('createdTimestamp','integer');
|
||||||
$this->addType('lastUpdatedTimestamp','integer');
|
$this->addType('lastUpdatedTimestamp','integer');
|
||||||
}
|
}
|
||||||
|
public function getPrincipal(): Principal {
|
||||||
|
return new Principal(PrincipalType::from($this->principalType), $this->principalId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPrincipal(Principal $principal) {
|
||||||
|
$this->setPrincipalType($principal->getType()->value);
|
||||||
|
$this->setPrincipalId($principal->getId());
|
||||||
|
}
|
||||||
|
|
||||||
public function jsonSerialize(): array {
|
public function jsonSerialize(): array {
|
||||||
return [
|
return [
|
||||||
'id' => $this->id,
|
'id' => $this->id,
|
||||||
'resourceId' => $this->resourceId,
|
'resourceId' => $this->resourceId,
|
||||||
'permissionLevel' => $this->permissionLevel,
|
'permissionLevel' => $this->permissionLevel,
|
||||||
'type' => $this->type,
|
'principal' => $this->getPrincipal(),
|
||||||
'principal' => $this->principal,
|
|
||||||
'createdTimestamp' => $this->createdTimestamp,
|
'createdTimestamp' => $this->createdTimestamp,
|
||||||
'lastUpdatedTimestamp' => $this->lastUpdatedTimestamp,
|
'lastUpdatedTimestamp' => $this->lastUpdatedTimestamp,
|
||||||
];
|
];
|
||||||
|
@ -43,29 +51,10 @@ class ResourceMember extends Entity implements JsonSerializable, TableSerializab
|
||||||
'Id' => $this->id,
|
'Id' => $this->id,
|
||||||
'Resource Id' => $this->resourceId,
|
'Resource Id' => $this->resourceId,
|
||||||
'Permission Level' => MemberPermissionLevel::from($this->permissionLevel)->name,
|
'Permission Level' => MemberPermissionLevel::from($this->permissionLevel)->name,
|
||||||
'Type' => MemberType::from($this->type)->name,
|
'Principal Type' => PrincipalType::from($this->principalType)->name,
|
||||||
'Principal' => $this->principal,
|
'Principal Id' => $this->principalId,
|
||||||
'Created' => $this->createdTimestamp,
|
'Created' => $this->createdTimestamp,
|
||||||
'LastUpdated' => $this->lastUpdatedTimestamp,
|
'LastUpdated' => $this->lastUpdatedTimestamp,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getParsedPrincipal() {
|
|
||||||
if($this->type === MemberType::USER->value) {
|
|
||||||
return [
|
|
||||||
"userId" => $this->principal,
|
|
||||||
];
|
|
||||||
} else if($this->type === MemberType::GROUP->value) {
|
|
||||||
return [
|
|
||||||
"groupId" => $this->principal,
|
|
||||||
];
|
|
||||||
} else if($this->type === MemberType::ROLE->value) {
|
|
||||||
[$organizationProviderId, $roleId] = explode(":", $this->principal, 2);
|
|
||||||
|
|
||||||
return [
|
|
||||||
"organizationProviderId" => $organizationProviderId,
|
|
||||||
"roleId" => $roleId,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,9 @@ class ResourceMemberMapper extends QBMapper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $resourceId
|
* @param int $resourceId
|
||||||
|
* @psalm-param int $resourceId
|
||||||
* @return array
|
* @return array
|
||||||
|
* @psalm-return ResourceMember[]
|
||||||
*/
|
*/
|
||||||
public function findAll(int $resourceId): array {
|
public function findAll(int $resourceId): array {
|
||||||
/* @var $qb IQueryBuilder */
|
/* @var $qb IQueryBuilder */
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace OCA\OrganizationFolders\Enum;
|
namespace OCA\OrganizationFolders\Enum;
|
||||||
|
|
||||||
enum MemberType: int {
|
enum PrincipalType: int {
|
||||||
use FromNameEnum;
|
use FromNameEnum;
|
||||||
|
|
||||||
case USER = 1;
|
case USER = 1;
|
|
@ -8,16 +8,22 @@ use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||||
use OCP\IDBConnection;
|
use OCP\IDBConnection;
|
||||||
|
|
||||||
use OCA\GroupFolders\ACL\Rule;
|
use OCA\GroupFolders\ACL\Rule;
|
||||||
|
use OCA\GroupFolders\ACL\UserMapping\IUserMapping;
|
||||||
use OCA\GroupFolders\ACL\UserMapping\IUserMappingManager;
|
use OCA\GroupFolders\ACL\UserMapping\IUserMappingManager;
|
||||||
use OCA\GroupFolders\ACL\RuleManager;
|
use OCA\GroupFolders\ACL\RuleManager;
|
||||||
use OCA\GroupFolders\Folder\FolderManager;
|
use OCA\GroupFolders\Folder\FolderManager;
|
||||||
|
|
||||||
|
use OCA\OrganizationFolders\OrganizationProvider\OrganizationProviderManager;
|
||||||
|
use OCA\OrganizationFolders\Model\Principal;
|
||||||
|
use OCA\OrganizationFolders\Enum\PrincipalType;
|
||||||
|
|
||||||
class ACLManager {
|
class ACLManager {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
protected IDBConnection $db,
|
protected IDBConnection $db,
|
||||||
protected FolderManager $folderManager,
|
protected FolderManager $folderManager,
|
||||||
protected IUserMappingManager $userMappingManager,
|
protected IUserMappingManager $userMappingManager,
|
||||||
protected RuleManager $ruleManager,
|
protected RuleManager $ruleManager,
|
||||||
|
protected OrganizationProviderManager $organizationProviderManager
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +54,38 @@ class ACLManager {
|
||||||
return array_map($this->createRuleEntityFromRow(...), $rows);
|
return array_map($this->createRuleEntityFromRow(...), $rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getMappingForPrincipal(Principal $principal): IUserMapping {
|
||||||
|
if($principal->getType() === PrincipalType::USER) {
|
||||||
|
return $this->userMappingManager->mappingFromId("user", $principal->getId());
|
||||||
|
} else if($principal->getType() === PrincipalType::GROUP) {
|
||||||
|
return $this->userMappingManager->mappingFromId("group", $principal->getId());
|
||||||
|
} else if($principal->getType() === PrincipalType::ROLE) {
|
||||||
|
[$organizationProviderId, $roleId] = explode(":", $principal->getId(), 2);
|
||||||
|
|
||||||
|
$organizationProvider = $this->organizationProviderManager->getOrganizationProvider($organizationProviderId);
|
||||||
|
$role = $organizationProvider->getRole($roleId);
|
||||||
|
|
||||||
|
return $this->userMappingManager->mappingFromId("group", $role->getMembersGroup());
|
||||||
|
} else {
|
||||||
|
throw new \Exception("invalid resource member type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createAclRuleForPrincipal(Principal $principal, int $fileId, int $mask, int $permissions): ?Rule {
|
||||||
|
$mapping = $this->getMappingForPrincipal($principal);
|
||||||
|
|
||||||
|
if(is_null($mapping)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Rule(
|
||||||
|
userMapping: $mapping,
|
||||||
|
fileId: $fileId,
|
||||||
|
mask: $mask,
|
||||||
|
permissions: $permissions,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
protected function ruleMappingComparison(Rule $rule1, Rule $rule2): int {
|
protected function ruleMappingComparison(Rule $rule1, Rule $rule2): int {
|
||||||
$mapping1 = $rule1->getUserMapping();
|
$mapping1 = $rule1->getUserMapping();
|
||||||
$mapping2 = $rule2->getUserMapping();
|
$mapping2 = $rule2->getUserMapping();
|
||||||
|
|
|
@ -42,13 +42,13 @@ class Version000000Date20241025120000 extends SimpleMigrationStep {
|
||||||
// 0: user
|
// 0: user
|
||||||
// 1: group
|
// 1: group
|
||||||
// 2: role
|
// 2: role
|
||||||
$table->addColumn('type', Types::INTEGER, [
|
$table->addColumn('principal_type', Types::INTEGER, [
|
||||||
'notnull' => true,
|
'notnull' => true,
|
||||||
]);
|
]);
|
||||||
// for type user: "[user_id]"
|
// for principal type user: "[user_id]"
|
||||||
// for type group: "[group_name]"
|
// for principal type group: "[group_name]"
|
||||||
// for type role: "[organization_provider_id]:[role_id]"
|
// for principal type role: "[organization_provider_id]:[role_id]"
|
||||||
$table->addColumn('principal', Types::STRING, [
|
$table->addColumn('principal_id', Types::STRING, [
|
||||||
'length' => 128,
|
'length' => 128,
|
||||||
'notnull' => true,
|
'notnull' => true,
|
||||||
]);
|
]);
|
||||||
|
|
29
lib/Model/Principal.php
Normal file
29
lib/Model/Principal.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\OrganizationFolders\Model;
|
||||||
|
|
||||||
|
use OCA\OrganizationFolders\Enum\PrincipalType;
|
||||||
|
|
||||||
|
class Principal implements \JsonSerializable {
|
||||||
|
public function __construct(
|
||||||
|
private PrincipalType $type,
|
||||||
|
private string $id,
|
||||||
|
) {
|
||||||
|
// check if id fits format
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType(): PrincipalType {
|
||||||
|
return $this->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getId(): string {
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jsonSerialize(): array {
|
||||||
|
return [
|
||||||
|
'type' => $this->type->value,
|
||||||
|
'id' => $this->id,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ use OCA\OrganizationFolders\Db\Resource;
|
||||||
use OCA\OrganizationFolders\Service\ResourceService;
|
use OCA\OrganizationFolders\Service\ResourceService;
|
||||||
use OCA\OrganizationFolders\Service\ResourceMemberService;
|
use OCA\OrganizationFolders\Service\ResourceMemberService;
|
||||||
use OCA\OrganizationFolders\Enum\MemberPermissionLevel;
|
use OCA\OrganizationFolders\Enum\MemberPermissionLevel;
|
||||||
use OCA\OrganizationFolders\Enum\MemberType;
|
use OCA\OrganizationFolders\Enum\PrincipalType;
|
||||||
use OCA\OrganizationFolders\OrganizationProvider\OrganizationProviderManager;
|
use OCA\OrganizationFolders\OrganizationProvider\OrganizationProviderManager;
|
||||||
|
|
||||||
class ResourceVoter extends Voter {
|
class ResourceVoter extends Voter {
|
||||||
|
@ -38,6 +38,7 @@ class ResourceVoter extends Voter {
|
||||||
'READ' => $this->isGranted($user, $resource),
|
'READ' => $this->isGranted($user, $resource),
|
||||||
'UPDATE' => $this->isGranted($user, $resource),
|
'UPDATE' => $this->isGranted($user, $resource),
|
||||||
'DELETE' => $this->isGranted($user, $resource),
|
'DELETE' => $this->isGranted($user, $resource),
|
||||||
|
'UPDATE_MEMBERS' => $this->isGranted($user, $resource),
|
||||||
default => throw new \LogicException('This code should not be reached!')
|
default => throw new \LogicException('This code should not be reached!')
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -59,19 +60,22 @@ class ResourceVoter extends Voter {
|
||||||
|
|
||||||
foreach($resourceMembers as $resourceMember) {
|
foreach($resourceMembers as $resourceMember) {
|
||||||
if($resourceMember->getPermissionLevel() === MemberPermissionLevel::MANAGER->value) {
|
if($resourceMember->getPermissionLevel() === MemberPermissionLevel::MANAGER->value) {
|
||||||
if($resourceMember->getType() === MemberType::USER->value) {
|
$principal = $resourceMember->getPrincipal();
|
||||||
if($resourceMember->getPrincipal() === $user->getUID()) {
|
|
||||||
|
if($principal->getType() === PrincipalType::USER) {
|
||||||
|
if($principal->getId() === $user->getUID()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if($resourceMember->getType() === MemberType::GROUP->value) {
|
} else if($principal->getType() === PrincipalType::GROUP) {
|
||||||
if($this->groupManager->isInGroup($user->getUID(), $resourceMember->getPrincipal())) {
|
if($this->groupManager->isInGroup($user->getUID(), $principal->getId())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if($resourceMember->getType() === MemberType::ROLE->value) {
|
} else if($principal->getType() === PrincipalType::ROLE) {
|
||||||
['organizationProviderId' => $organizationProviderId, 'roleId' => $roleId] = $resourceMember->getParsedPrincipal();
|
[$organizationProviderId, $roleId] = explode(":", $principal->getId(), 2);
|
||||||
|
|
||||||
$organizationProvider = $this->organizationProviderManager->getOrganizationProvider($organizationProviderId);
|
$organizationProvider = $this->organizationProviderManager->getOrganizationProvider($organizationProviderId);
|
||||||
$role = $organizationProvider->getRole($roleId);
|
$role = $organizationProvider->getRole($roleId);
|
||||||
|
|
||||||
if($this->groupManager->isInGroup($user->getUID(), $role->getMembersGroup())) {
|
if($this->groupManager->isInGroup($user->getUID(), $role->getMembersGroup())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ use OCA\OrganizationFolders\Db\ResourceMember;
|
||||||
use OCA\OrganizationFolders\Db\ResourceMemberMapper;
|
use OCA\OrganizationFolders\Db\ResourceMemberMapper;
|
||||||
|
|
||||||
use OCA\OrganizationFolders\Enum\MemberPermissionLevel;
|
use OCA\OrganizationFolders\Enum\MemberPermissionLevel;
|
||||||
use OCA\OrganizationFolders\Enum\MemberType;
|
use OCA\OrganizationFolders\Model\Principal;
|
||||||
|
|
||||||
class ResourceMemberService {
|
class ResourceMemberService {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
@ -23,6 +23,12 @@ class ResourceMemberService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $resourceId
|
||||||
|
* @psalm-param int $resourceId
|
||||||
|
* @return array
|
||||||
|
* @psalm-return ResourceMember[]
|
||||||
|
*/
|
||||||
public function findAll(int $resourceId): array {
|
public function findAll(int $resourceId): array {
|
||||||
return $this->mapper->findAll($resourceId);
|
return $this->mapper->findAll($resourceId);
|
||||||
}
|
}
|
||||||
|
@ -47,8 +53,7 @@ class ResourceMemberService {
|
||||||
public function create(
|
public function create(
|
||||||
int $resourceId,
|
int $resourceId,
|
||||||
MemberPermissionLevel $permissionLevel,
|
MemberPermissionLevel $permissionLevel,
|
||||||
MemberType $type,
|
Principal $principal,
|
||||||
string $principal
|
|
||||||
): ResourceMember {
|
): ResourceMember {
|
||||||
$resource = $this->resourceService->find($resourceId);
|
$resource = $this->resourceService->find($resourceId);
|
||||||
|
|
||||||
|
@ -56,10 +61,7 @@ class ResourceMemberService {
|
||||||
|
|
||||||
$member->setResourceId($resource->getId());
|
$member->setResourceId($resource->getId());
|
||||||
$member->setPermissionLevel($permissionLevel->value);
|
$member->setPermissionLevel($permissionLevel->value);
|
||||||
$member->setType($type->value);
|
$member->setPrincipal($principal);
|
||||||
|
|
||||||
// TODO: check if principal fits format
|
|
||||||
$member->setPrincipal($principal);
|
|
||||||
$member->setCreatedTimestamp(time());
|
$member->setCreatedTimestamp(time());
|
||||||
$member->setLastUpdatedTimestamp(time());
|
$member->setLastUpdatedTimestamp(time());
|
||||||
|
|
||||||
|
@ -70,7 +72,7 @@ class ResourceMemberService {
|
||||||
return $member;
|
return $member;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(int $id, ?MemberPermissionLevel $permissionLevel = null, ?MemberType $type = null, ?string $principal = null): ResourceMember {
|
public function update(int $id, ?MemberPermissionLevel $permissionLevel = null, ?Principal $principal = null): ResourceMember {
|
||||||
try {
|
try {
|
||||||
$member = $this->mapper->find($id);
|
$member = $this->mapper->find($id);
|
||||||
|
|
||||||
|
@ -78,12 +80,8 @@ class ResourceMemberService {
|
||||||
$member->setPermissionLevel($permissionLevel->value);
|
$member->setPermissionLevel($permissionLevel->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isset($type)) {
|
|
||||||
$member->setType($type->value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isset($principal)) {
|
if(isset($principal)) {
|
||||||
$member->setPrincipal($principal);
|
$member->setPrincipal($principal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(count($member->getUpdatedFields()) > 0) {
|
if(count($member->getUpdatedFields()) > 0) {
|
||||||
|
|
|
@ -16,8 +16,9 @@ use OCA\OrganizationFolders\Db\Resource;
|
||||||
use OCA\OrganizationFolders\Db\FolderResource;
|
use OCA\OrganizationFolders\Db\FolderResource;
|
||||||
use OCA\OrganizationFolders\Db\ResourceMapper;
|
use OCA\OrganizationFolders\Db\ResourceMapper;
|
||||||
use OCA\OrganizationFolders\Model\OrganizationFolder;
|
use OCA\OrganizationFolders\Model\OrganizationFolder;
|
||||||
|
use \OCA\OrganizationFolders\Model\Principal;
|
||||||
use OCA\OrganizationFolders\Enum\MemberPermissionLevel;
|
use OCA\OrganizationFolders\Enum\MemberPermissionLevel;
|
||||||
use OCA\OrganizationFolders\Enum\MemberType;
|
use OCA\OrganizationFolders\Enum\PrincipalType;
|
||||||
use OCA\OrganizationFolders\Errors\InvalidResourceType;
|
use OCA\OrganizationFolders\Errors\InvalidResourceType;
|
||||||
use OCA\OrganizationFolders\Errors\ResourceNotFound;
|
use OCA\OrganizationFolders\Errors\ResourceNotFound;
|
||||||
use OCA\OrganizationFolders\Errors\ResourceNameNotUnique;
|
use OCA\OrganizationFolders\Errors\ResourceNameNotUnique;
|
||||||
|
@ -37,7 +38,16 @@ class ResourceService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findAll(int $organizationFolderId, int $parentResourceId = null, array $filters = []) {
|
/**
|
||||||
|
* @param int $organizationFolderId
|
||||||
|
* @psalm-param int $organizationFolderId
|
||||||
|
* @param int|null $parentResourceId
|
||||||
|
* @psalm-param int|null $parentResourceId
|
||||||
|
* @param array $filters
|
||||||
|
* @psalm-param array $filters
|
||||||
|
* @psalm-return Resource[]
|
||||||
|
*/
|
||||||
|
public function findAll(int $organizationFolderId, ?int $parentResourceId = null, array $filters = []): array {
|
||||||
return $this->mapper->findAll($organizationFolderId, $parentResourceId, $filters);
|
return $this->mapper->findAll($organizationFolderId, $parentResourceId, $filters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +103,11 @@ class ResourceService {
|
||||||
$parentResource = $this->find($parentResourceId);
|
$parentResource = $this->find($parentResourceId);
|
||||||
|
|
||||||
if($parentResource->getOrganizationFolderId() === $organizationFolderId) {
|
if($parentResource->getOrganizationFolderId() === $organizationFolderId) {
|
||||||
$resource->setParentResource($parentResource->getId());
|
if($parentResource->getType() !== "folder") {
|
||||||
|
throw new Exception("Only folder resources can have sub-resources");
|
||||||
|
} else {
|
||||||
|
$resource->setParentResource($parentResource->getId());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Exception("Cannot create child-resource of parent in different organizationId");
|
throw new Exception("Cannot create child-resource of parent in different organizationId");
|
||||||
}
|
}
|
||||||
|
@ -136,7 +150,6 @@ class ResourceService {
|
||||||
int $id,
|
int $id,
|
||||||
|
|
||||||
?string $name = null,
|
?string $name = null,
|
||||||
?int $parentResource = null,
|
|
||||||
?bool $active = null,
|
?bool $active = null,
|
||||||
?bool $inheritManagers = null,
|
?bool $inheritManagers = null,
|
||||||
|
|
||||||
|
@ -146,10 +159,6 @@ class ResourceService {
|
||||||
): Resource {
|
): Resource {
|
||||||
$resource = $this->find($id);
|
$resource = $this->find($id);
|
||||||
|
|
||||||
if(isset($parentResource)) {
|
|
||||||
$resource->setParentResource($parentResource);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isset($name)) {
|
if(isset($name)) {
|
||||||
if($this->mapper->existsWithName($resource->getOrganizationFolderId(), $resource->getParentResource(), $name)) {
|
if($this->mapper->existsWithName($resource->getOrganizationFolderId(), $resource->getParentResource(), $name)) {
|
||||||
throw new ResourceNameNotUnique();
|
throw new ResourceNameNotUnique();
|
||||||
|
@ -206,10 +215,7 @@ class ResourceService {
|
||||||
|
|
||||||
$inheritingPrincipals = [];
|
$inheritingPrincipals = [];
|
||||||
foreach($inheritingGroups as $inheritingGroup) {
|
foreach($inheritingGroups as $inheritingGroup) {
|
||||||
$inheritingPrincipals[] = [
|
$inheritingPrincipals[] = new Principal(PrincipalType::GROUP, $inheritingGroup);
|
||||||
"type" => "group",
|
|
||||||
"groupId" => $inheritingGroup,
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->recursivelySetFolderResourceALCs($topLevelFolderResources, "", $inheritingPrincipals);
|
return $this->recursivelySetFolderResourceALCs($topLevelFolderResources, "", $inheritingPrincipals);
|
||||||
|
@ -222,8 +228,8 @@ class ResourceService {
|
||||||
* @psalm-param FolderResource[] $folderResources
|
* @psalm-param FolderResource[] $folderResources
|
||||||
* @param string $path
|
* @param string $path
|
||||||
* @psalm-param string $path
|
* @psalm-param string $path
|
||||||
* @param array $inheritingGroups
|
* @param array $inheritingPrincipals
|
||||||
* @psalm-param string[] $inheritingGroups
|
* @psalm-param Principal[] $inheritingPrincipals
|
||||||
*/
|
*/
|
||||||
public function recursivelySetFolderResourceALCs(array $folderResources, string $path, array $inheritingPrincipals) {
|
public function recursivelySetFolderResourceALCs(array $folderResources, string $path, array $inheritingPrincipals) {
|
||||||
foreach($folderResources as $folderResource) {
|
foreach($folderResources as $folderResource) {
|
||||||
|
@ -232,20 +238,16 @@ class ResourceService {
|
||||||
|
|
||||||
// inherit ACLs
|
// inherit ACLs
|
||||||
foreach($inheritingPrincipals as $inheritingPrincipal) {
|
foreach($inheritingPrincipals as $inheritingPrincipal) {
|
||||||
if($inheritingPrincipal["type"] === "group") {
|
$newACL = $this->aclManager->createAclRuleForPrincipal(
|
||||||
$acls[] = new Rule(
|
principal: $inheritingPrincipal,
|
||||||
userMapping: $this->userMappingManager->mappingFromId("group", $inheritingPrincipal["groupId"]),
|
fileId: $resourceFileId,
|
||||||
fileId: $resourceFileId,
|
mask: 31,
|
||||||
mask: 31,
|
permissions: $folderResource->getInheritedAclPermission(),
|
||||||
permissions: $folderResource->getInheritedAclPermission(),
|
);
|
||||||
);
|
|
||||||
} else if($inheritingPrincipal["type"] === "user") {
|
// if mapping for principal could not be created, skip creating rule for it
|
||||||
$acls[] = new Rule(
|
if(!is_null($newACL)) {
|
||||||
userMapping: $this->userMappingManager->mappingFromId("user", $inheritingPrincipal["userId"]),
|
$acls[] = $newACL;
|
||||||
fileId: $resourceFileId,
|
|
||||||
mask: 31,
|
|
||||||
permissions: $folderResource->getInheritedAclPermission(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,6 +262,7 @@ class ResourceService {
|
||||||
/** @var ResourceService */
|
/** @var ResourceService */
|
||||||
$resourceMemberService = $this->container->get(ResourceMemberService::class);
|
$resourceMemberService = $this->container->get(ResourceMemberService::class);
|
||||||
$resourceMembers = $resourceMemberService->findAll($folderResource->getId());
|
$resourceMembers = $resourceMemberService->findAll($folderResource->getId());
|
||||||
|
|
||||||
foreach($resourceMembers as $resourceMember) {
|
foreach($resourceMembers as $resourceMember) {
|
||||||
if($resourceMember->getPermissionLevel() === MemberPermissionLevel::MANAGER->value) {
|
if($resourceMember->getPermissionLevel() === MemberPermissionLevel::MANAGER->value) {
|
||||||
$resourceMemberPermissions = $folderResource->getManagersAclPermission();
|
$resourceMemberPermissions = $folderResource->getManagersAclPermission();
|
||||||
|
@ -270,43 +273,20 @@ class ResourceService {
|
||||||
}
|
}
|
||||||
|
|
||||||
if($resourceMemberPermissions !== 0) {
|
if($resourceMemberPermissions !== 0) {
|
||||||
if($resourceMember->getType() === MemberType::USER->value) {
|
$resourceMemberPrincipal = $resourceMember->getPrincipal();
|
||||||
$mapping = $this->userMappingManager->mappingFromId("user", $resourceMember->getPrincipal());
|
|
||||||
$nextInheritingPrincipals[] = [
|
|
||||||
"type" => "user",
|
|
||||||
"userId" => $resourceMember->getPrincipal(),
|
|
||||||
];
|
|
||||||
} else if($resourceMember->getType() === MemberType::GROUP->value) {
|
|
||||||
$mapping = $this->userMappingManager->mappingFromId("group", $resourceMember->getPrincipal());
|
|
||||||
$nextInheritingPrincipals[] = [
|
|
||||||
"type" => "group",
|
|
||||||
"groupId" => $resourceMember->getPrincipal(),
|
|
||||||
];
|
|
||||||
} else if($resourceMember->getType() === MemberType::ROLE->value) {
|
|
||||||
['organizationProviderId' => $organizationProviderId, 'roleId' => $roleId] = $resourceMember->getParsedPrincipal();
|
|
||||||
|
|
||||||
$organizationProvider = $this->organizationProviderManager->getOrganizationProvider($organizationProviderId);
|
$newACL = $this->aclManager->createAclRuleForPrincipal(
|
||||||
$role = $organizationProvider->getRole($roleId);
|
principal: $resourceMemberPrincipal,
|
||||||
$mapping = $this->userMappingManager->mappingFromId("group", $role->getMembersGroup());
|
|
||||||
$nextInheritingPrincipals[] = [
|
|
||||||
"type" => "group",
|
|
||||||
"groupId" => $role->getMembersGroup(),
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
throw new Exception("invalid resource member type");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_null($mapping)) {
|
|
||||||
// TODO: skip member instead of crashing
|
|
||||||
throw new Exception(message: "invalid mapping, likely non-existing group");
|
|
||||||
}
|
|
||||||
|
|
||||||
$acls[] = new Rule(
|
|
||||||
userMapping: $mapping,
|
|
||||||
fileId: $resourceFileId,
|
fileId: $resourceFileId,
|
||||||
mask: 31,
|
mask: 31,
|
||||||
permissions: $resourceMemberPermissions,
|
permissions: $resourceMemberPermissions,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// if mapping for principal could not be created, skip creating rule for it
|
||||||
|
if(!is_null($newACL)) {
|
||||||
|
$acls[] = $newACL;
|
||||||
|
$nextInheritingPrincipals[] = $resourceMemberPrincipal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue