Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[stable31] include circles to acl #3589

Merged
merged 5 commits into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/ACL/UserMapping/IUserMapping.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
namespace OCA\GroupFolders\ACL\UserMapping;

interface IUserMapping {
/** @return 'user'|'group'|'dummy' */
/** @return 'user'|'group'|'dummy'|'circle' */
public function getType(): string;

public function getId(): string;

public function getDisplayName(): string;

public function getKey(): string;
}
9 changes: 9 additions & 0 deletions lib/ACL/UserMapping/IUserMappingManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,13 @@ interface IUserMappingManager {
public function getMappingsForUser(IUser $user, bool $userAssignable = true): array;

public function mappingFromId(string $type, string $id): ?IUserMapping;

/**
* Check if a user is a member of one of the provided user mappings
*
* @param IUser $user
* @param IUserMapping[] $mappings
* @return bool
*/
public function userInMappings(IUser $user, array $mappings): bool;
}
6 changes: 5 additions & 1 deletion lib/ACL/UserMapping/UserMapping.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class UserMapping implements IUserMapping {
private string $displayName;

/**
* @param 'user'|'group'|'dummy' $type
* @param 'user'|'group'|'dummy'|'circle' $type
*/
public function __construct(
private string $type,
Expand All @@ -33,4 +33,8 @@ public function getId(): string {
public function getDisplayName(): string {
return $this->displayName;
}

public function getKey(): string {
return $this->getType() . ':' . $this->getId();
}
}
108 changes: 101 additions & 7 deletions lib/ACL/UserMapping/UserMappingManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,128 @@

namespace OCA\GroupFolders\ACL\UserMapping;

use OCA\Circles\CirclesManager;
use OCA\Circles\Exceptions\CircleNotFoundException;
use OCA\Circles\Model\Circle;
use OCA\Circles\Model\Probes\CircleProbe;
use OCP\AutoloadNotAllowedException;
use OCP\IGroup;
use OCP\IGroupManager;
use OCP\IUser;
use OCP\IUserManager;
use OCP\Server;
use Psr\Container\ContainerExceptionInterface;
use Psr\Log\LoggerInterface;

class UserMappingManager implements IUserMappingManager {
public function __construct(
private IGroupManager $groupManager,
private IUserManager $userManager,
private LoggerInterface $logger,
) {
}

public function getMappingsForUser(IUser $user, bool $userAssignable = true): array {
$groupMappings = array_values(array_map(fn (IGroup $group): UserMapping => new UserMapping('group', $group->getGID(), $group->getDisplayName()), $this->groupManager->getUserGroups($user)));
$circleMappings = array_values(array_map(fn (Circle $circle): UserMapping => new UserMapping('circle', $circle->getSingleId(), $circle->getDisplayName()), $this->getUserCircles($user->getUID())));

return array_merge([
new UserMapping('user', $user->getUID(), $user->getDisplayName()),
], $groupMappings);
], $groupMappings, $circleMappings);
}

public function mappingFromId(string $type, string $id): ?IUserMapping {
$mappingObject = ($type === 'group' ? $this->groupManager : $this->userManager)->get($id);
if ($mappingObject) {
$displayName = $mappingObject->getDisplayName();
/** @var 'user'|'group' $type */
return new UserMapping($type, $id, $displayName);
} else {
switch ($type) {
case 'group':
$displayName = $this->groupManager->get($id)?->getDisplayName();
break;
case 'user':
$displayName = $this->userManager->get($id)?->getDisplayName();
break;
case 'circle':
$displayName = $this->getCircle($id)?->getDisplayName();
break;
default:
return null;
}
if ($displayName === null) {
return null;
}

return new UserMapping($type, $id, $displayName);
}



/**
* returns the Circle from its single Id, or NULL if not available
*/
private function getCircle(string $groupId): ?Circle {
$circlesManager = $this->getCirclesManager();
if ($circlesManager === null) {
return null;
}

$circlesManager->startSuperSession();
$probe = new CircleProbe();
$probe->includeSystemCircles();
$probe->includeSingleCircles();
try {
return $circlesManager->getCircle($groupId, $probe);
} catch (CircleNotFoundException) {
} catch (\Exception $e) {
$this->logger->warning('', ['exception' => $e]);
} finally {
$circlesManager->stopSession();
}

return null;
}

/**
* returns list of circles a user is member of
*/
private function getUserCircles(string $userId): array {
$circlesManager = $this->getCirclesManager();
if ($circlesManager === null) {
return [];
}

$circlesManager->startSession($circlesManager->getLocalFederatedUser($userId));
try {
return $circlesManager->probeCircles();
} catch (\Exception $e) {
$this->logger->warning('', ['exception' => $e]);
} finally {
$circlesManager->stopSession();
}

return [];
}

public function getCirclesManager(): ?CirclesManager {
try {
return Server::get(CirclesManager::class);
} catch (ContainerExceptionInterface|AutoloadNotAllowedException) {
return null;
}
}

public function userInMappings(IUser $user, array $mappings): bool {
foreach ($mappings as $mapping) {
if ($mapping->getType() === 'user' && $mapping->getId() === $user->getUID()) {
return true;
}
}

$mappingKeys = array_map(fn (IUserMapping $mapping) => $mapping->getKey(), $mappings);

$userMappings = $this->getMappingsForUser($user);
foreach ($userMappings as $userMapping) {
if (in_array($userMapping->getKey(), $mappingKeys, true)) {
return true;
}
}
return false;
}
}
2 changes: 1 addition & 1 deletion lib/Command/ListCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}, array_keys($folder['groups']), array_values($folder['groups']));
$folder['groups'] = implode("\n", $groupStrings);
$folder['acl'] = $folder['acl'] ? 'Enabled' : 'Disabled';
$manageStrings = array_map(fn (array $manage): string => $manage['id'] . ' (' . $manage['type'] . ')', $folder['manage']);
$manageStrings = array_map(fn (array $manage): string => $manage['displayname'] . ' (' . $manage['type'] . ')', $folder['manage']);
$folder['manage'] = implode("\n", $manageStrings);

return $folder;
Expand Down
8 changes: 5 additions & 3 deletions lib/Controller/FolderController.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

/**
* @psalm-import-type GroupFoldersGroup from ResponseDefinitions
* @psalm-import-type GroupFoldersCircle from ResponseDefinitions
* @psalm-import-type GroupFoldersUser from ResponseDefinitions
* @psalm-import-type GroupFoldersFolder from ResponseDefinitions
* @psalm-import-type InternalFolderOut from FolderManager
Expand Down Expand Up @@ -474,16 +475,15 @@ private function folderDataForXML(array $data): array {
*
* @param int $id The ID of the Groupfolder
* @param string $search String to search by
* @return DataResponse<Http::STATUS_OK, array{users: list<GroupFoldersUser>, groups: list<GroupFoldersGroup>}, array{}>
* @return DataResponse<Http::STATUS_OK, array{users: list<GroupFoldersUser>, groups: list<GroupFoldersGroup>, circles: list<GroupFoldersCircle>}, array{}>
* @throws OCSForbiddenException Not allowed to search
*
* 200: ACL Mappings returned
*/
#[NoAdminRequired]
#[FrontpageRoute(verb: 'GET', url: '/folders/{id}/search')]
public function aclMappingSearch(int $id, string $search = ''): DataResponse {
$users = [];
$groups = [];
$users = $groups = $circles = [];

if ($this->user === null) {
throw new OCSForbiddenException();
Expand All @@ -492,11 +492,13 @@ public function aclMappingSearch(int $id, string $search = ''): DataResponse {
if ($this->manager->canManageACL($id, $this->user) === true) {
$groups = $this->manager->searchGroups($id, $search);
$users = $this->manager->searchUsers($id, $search);
$circles = $this->manager->searchCircles($id, $search);
}

return new DataResponse([
'users' => $users,
'groups' => $groups,
'circles' => $circles
]);
}
}
Loading
Loading