Skip to content

Commit

Permalink
share with teams
Browse files Browse the repository at this point in the history
Signed-off-by: Hoang Pham <hoangmaths96@gmail.com>
  • Loading branch information
hweihwang committed Dec 13, 2024
1 parent 1a9f747 commit 68c2920
Show file tree
Hide file tree
Showing 17 changed files with 354 additions and 60 deletions.
11 changes: 9 additions & 2 deletions lib/Capabilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

namespace OCA\Tables;

use OCA\Tables\Helper\CircleHelper;
use OCP\App\IAppManager;
use OCP\Capabilities\ICapability;
use OCP\IConfig;
Expand All @@ -18,18 +19,23 @@
*/
class Capabilities implements ICapability {
private IAppManager $appManager;

private LoggerInterface $logger;

private IConfig $config;

public function __construct(IAppManager $appManager, LoggerInterface $logger, IConfig $config) {
private CircleHelper $circleHelper;

public function __construct(IAppManager $appManager, LoggerInterface $logger, IConfig $config, CircleHelper $circleHelper) {
$this->appManager = $appManager;
$this->logger = $logger;
$this->config = $config;
$this->circleHelper = $circleHelper;
}

/**
*
* @return array{tables: array{enabled: bool, version: string, apiVersions: string[], features: string[], column_types: string[]}}
* @return array{tables: array{enabled: bool, version: string, apiVersions: string[], features: string[], isCirclesEnabled: bool, column_types: string[]}}
*
* @inheritDoc
*/
Expand All @@ -52,6 +58,7 @@ public function getCapabilities(): array {
'favorite',
'archive',
],
'isCirclesEnabled' => $this->circleHelper->isCirclesEnabled(),
'column_types' => [
'text-line',
$textColumnVariant,
Expand Down
2 changes: 1 addition & 1 deletion lib/Db/Share.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class Share extends Entity implements JsonSerializable {

protected ?string $receiver = null;
protected ?string $receiverDisplayName = null;
protected ?string $receiverType = null; // user, group
protected ?string $receiverType = null; // user, group, circle
protected ?int $nodeId = null;
protected ?string $nodeType = null;
protected ?bool $permissionRead = null;
Expand Down
9 changes: 7 additions & 2 deletions lib/Db/ShareMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,16 +102,21 @@ public function findAllSharesFor(string $nodeType, string $receiver, string $use
* @param string $nodeType
* @param int $nodeId
* @param string $sender
* @param array<string> $excluded receiver types to exclude from results
* @return array
* @throws Exception
*/
public function findAllSharesForNode(string $nodeType, int $nodeId, string $sender): array {
// TODO filter for sender...
public function findAllSharesForNode(string $nodeType, int $nodeId, string $sender, array $excluded = []): array {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->table)
->andWhere($qb->expr()->eq('node_type', $qb->createNamedParameter($nodeType, IQueryBuilder::PARAM_STR)))
->andWhere($qb->expr()->eq('node_id', $qb->createNamedParameter($nodeId, IQueryBuilder::PARAM_INT)));

if (!empty($excluded)) {
$qb->andWhere($qb->expr()->notIn('receiver_type', $qb->createNamedParameter($excluded, IQueryBuilder::PARAM_STR_ARRAY)));
}

return $this->findEntities($qb);
}

Expand Down
87 changes: 87 additions & 0 deletions lib/Helper/CircleHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Tables\Helper;

use OCA\Circles\CirclesManager;
use OCA\Circles\Model\Member;
use OCA\Circles\Model\Probes\CircleProbe;
use OCP\App\IAppManager;
use OCP\Server;
use Psr\Log\LoggerInterface;
use Throwable;

/**
* @psalm-suppress UndefinedClass
*/
class CircleHelper {
private LoggerInterface $logger;
private bool $circlesEnabled;
private ?CirclesManager $circlesManager;

/**
* @psalm-suppress UndefinedClass
*/
public function __construct(
LoggerInterface $logger,
IAppManager $appManager
) {
$this->logger = $logger;
$this->circlesEnabled = $appManager->isEnabledForUser('circles');
$this->circlesManager = null;

if ($this->circlesEnabled) {
try {
$this->circlesManager = Server::get(CirclesManager::class);
} catch (Throwable $e) {
$this->logger->warning('Failed to get CirclesManager: ' . $e->getMessage());
$this->circlesEnabled = false;
}
}
}

public function isCirclesEnabled(): bool {
return $this->circlesEnabled;
}

public function getCircleDisplayName(string $circleId, string $userId): string {
if (!$this->circlesEnabled) {
return $circleId;
}

try {
$federatedUser = $this->circlesManager->getFederatedUser($userId, Member::TYPE_USER);
$this->circlesManager->startSession($federatedUser);

$circle = $this->circlesManager->getCircle($circleId);
return $circle ? ($circle->getDisplayName() ?: $circleId) : $circleId;
} catch (Throwable $e) {
$this->logger->warning('Failed to get circle display name: ' . $e->getMessage(), [
'circleId' => $circleId,
'userId' => $userId
]);
return $circleId;
}
}

public function getUserCircles(string $userId): array {
if (!$this->circlesEnabled) {
return [];
}

try {
$federatedUser = $this->circlesManager->getFederatedUser($userId, Member::TYPE_USER);
$this->circlesManager->startSession($federatedUser);
$probe = new CircleProbe();
$probe->mustBeMember();
return $this->circlesManager->getCircles($probe);
} catch (Throwable $e) {
$this->logger->warning('Failed to get user circles: ' . $e->getMessage());
return [];
}
}
}
9 changes: 9 additions & 0 deletions lib/Helper/UserHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,26 @@
use OCP\IUserManager;
use Psr\Log\LoggerInterface;

/**
* @psalm-suppress UndefinedClass
* @psalm-suppress UndefinedDocblockClass
*/
class UserHelper {
private IUserManager $userManager;

private LoggerInterface $logger;

private IGroupManager $groupManager;

/**
* @psalm-suppress UndefinedClass
*/
public function __construct(IUserManager $userManager, LoggerInterface $logger, IGroupManager $groupManager) {
$this->userManager = $userManager;
$this->logger = $logger;
$this->groupManager = $groupManager;
}

public function getUserDisplayName(string $userId): string {
try {
$user = $this->getUser($userId);
Expand Down
43 changes: 39 additions & 4 deletions lib/Service/PermissionsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,19 @@
use OCA\Tables\Db\ViewMapper;
use OCA\Tables\Errors\InternalError;
use OCA\Tables\Errors\NotFoundError;
use OCA\Tables\Helper\CircleHelper;
use OCA\Tables\Helper\ConversionHelper;
use OCA\Tables\Helper\UserHelper;
use OCA\Tables\Model\Permissions;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\DB\Exception;
use Psr\Log\LoggerInterface;
use Throwable;

/**
* @psalm-suppress UndefinedDocblockClass
*/
class PermissionsService {
private TableMapper $tableMapper;

Expand All @@ -35,11 +40,14 @@ class PermissionsService {

private UserHelper $userHelper;

private CircleHelper $circleHelper;

protected LoggerInterface $logger;

protected ?string $userId = null;

protected bool $isCli = false;

private ContextMapper $contextMapper;

public function __construct(
Expand All @@ -50,6 +58,7 @@ public function __construct(
ShareMapper $shareMapper,
ContextMapper $contextMapper,
UserHelper $userHelper,
CircleHelper $circleHelper,
bool $isCLI
) {
$this->tableMapper = $tableMapper;
Expand All @@ -60,6 +69,7 @@ public function __construct(
$this->userId = $userId;
$this->isCli = $isCLI;
$this->contextMapper = $contextMapper;
$this->circleHelper = $circleHelper;
}


Expand Down Expand Up @@ -420,6 +430,7 @@ public function canReadShare(Share $share, ?string $userId = null): bool {
* @param int $elementId
* @param 'table'|'view' $elementType
* @param string $userId
* @return Permissions
* @throws NotFoundError
*/
public function getSharedPermissionsIfSharedWithMe(int $elementId, string $elementType, string $userId): Permissions {
Expand All @@ -436,16 +447,40 @@ public function getSharedPermissionsIfSharedWithMe(int $elementId, string $eleme
$this->logger->warning('Exception occurred: '.$e->getMessage().' Permission denied.');
return new Permissions();
}
$additionalShares = [];
$groupShares = [];
foreach ($userGroups as $userGroup) {
try {
$additionalShares[] = $this->shareMapper->findAllSharesForNodeFor($elementType, $elementId, $userGroup->getGid(), 'group');
$groupShares[] = $this->shareMapper->findAllSharesForNodeFor($elementType, $elementId, $userGroup->getGid(), 'group');
} catch (Exception $e) {
$this->logger->warning('Exception occurred: '.$e->getMessage().' Permission denied.');
return new Permissions();
}
}
$shares = array_merge($shares, ...$additionalShares);

$shares = array_merge($shares, ...$groupShares);

if ($this->circleHelper->isCirclesEnabled()) {
$circleShares = [];

try {
$userCircles = $this->circleHelper->getUserCircles($userId);
} catch (Throwable $e) {
$this->logger->warning('Exception occurred: ' . $e->getMessage() . ' Permission denied.');
return new Permissions();
}

foreach ($userCircles as $userCircle) {
try {
$circleShares[] = $this->shareMapper->findAllSharesForNodeFor($elementType, $elementId, $userCircle->getSingleId(), 'circle');
} catch (Exception $e) {
$this->logger->warning('Exception occurred: ' . $e->getMessage() . ' Permission denied.');
return new Permissions();
}
}

$shares = array_merge($shares, ...$circleShares);
}

if (count($shares) > 0) {
$read = array_reduce($shares, function ($carry, $share) {
return $carry || ($share->getPermissionRead());
Expand Down Expand Up @@ -520,7 +555,7 @@ private function hasPermission(int $existingPermissions, string $permissionName)
$constantName = 'PERMISSION_' . strtoupper($permissionName);
try {
$permissionBit = constant(Application::class . "::$constantName");
} catch (\Throwable $t) {
} catch (Throwable $t) {
$this->logger->error('Unexpected permission string {permission}', [
'app' => Application::APP_ID,
'permission' => $permissionName,
Expand Down
Loading

0 comments on commit 68c2920

Please sign in to comment.