Skip to content

Commit 1f12051

Browse files
committed
share with teams
Signed-off-by: Hoang Pham <hoangmaths96@gmail.com>
1 parent 8e4104c commit 1f12051

File tree

17 files changed

+354
-60
lines changed

17 files changed

+354
-60
lines changed

lib/Capabilities.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
namespace OCA\Tables;
88

9+
use OCA\Tables\Helper\CircleHelper;
910
use OCP\App\IAppManager;
1011
use OCP\Capabilities\ICapability;
1112
use OCP\IConfig;
@@ -18,18 +19,23 @@
1819
*/
1920
class Capabilities implements ICapability {
2021
private IAppManager $appManager;
22+
2123
private LoggerInterface $logger;
24+
2225
private IConfig $config;
2326

24-
public function __construct(IAppManager $appManager, LoggerInterface $logger, IConfig $config) {
27+
private CircleHelper $circleHelper;
28+
29+
public function __construct(IAppManager $appManager, LoggerInterface $logger, IConfig $config, CircleHelper $circleHelper) {
2530
$this->appManager = $appManager;
2631
$this->logger = $logger;
2732
$this->config = $config;
33+
$this->circleHelper = $circleHelper;
2834
}
2935

3036
/**
3137
*
32-
* @return array{tables: array{enabled: bool, version: string, apiVersions: string[], features: string[], column_types: string[]}}
38+
* @return array{tables: array{enabled: bool, version: string, apiVersions: string[], features: string[], isCirclesEnabled: bool, column_types: string[]}}
3339
*
3440
* @inheritDoc
3541
*/
@@ -52,6 +58,7 @@ public function getCapabilities(): array {
5258
'favorite',
5359
'archive',
5460
],
61+
'isCirclesEnabled' => $this->circleHelper->isCirclesEnabled(),
5562
'column_types' => [
5663
'text-line',
5764
$textColumnVariant,

lib/Db/Share.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class Share extends Entity implements JsonSerializable {
4949

5050
protected ?string $receiver = null;
5151
protected ?string $receiverDisplayName = null;
52-
protected ?string $receiverType = null; // user, group
52+
protected ?string $receiverType = null; // user, group, circle
5353
protected ?int $nodeId = null;
5454
protected ?string $nodeType = null;
5555
protected ?bool $permissionRead = null;

lib/Db/ShareMapper.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,16 +102,21 @@ public function findAllSharesFor(string $nodeType, string $receiver, string $use
102102
* @param string $nodeType
103103
* @param int $nodeId
104104
* @param string $sender
105+
* @param array<string> $excluded receiver types to exclude from results
105106
* @return array
106107
* @throws Exception
107108
*/
108-
public function findAllSharesForNode(string $nodeType, int $nodeId, string $sender): array {
109-
// TODO filter for sender...
109+
public function findAllSharesForNode(string $nodeType, int $nodeId, string $sender, array $excluded = []): array {
110110
$qb = $this->db->getQueryBuilder();
111111
$qb->select('*')
112112
->from($this->table)
113113
->andWhere($qb->expr()->eq('node_type', $qb->createNamedParameter($nodeType, IQueryBuilder::PARAM_STR)))
114114
->andWhere($qb->expr()->eq('node_id', $qb->createNamedParameter($nodeId, IQueryBuilder::PARAM_INT)));
115+
116+
if (!empty($excluded)) {
117+
$qb->andWhere($qb->expr()->notIn('receiver_type', $qb->createNamedParameter($excluded, IQueryBuilder::PARAM_STR_ARRAY)));
118+
}
119+
115120
return $this->findEntities($qb);
116121
}
117122

lib/Helper/CircleHelper.php

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
/**
4+
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
5+
* SPDX-License-Identifier: AGPL-3.0-or-later
6+
*/
7+
8+
namespace OCA\Tables\Helper;
9+
10+
use OCA\Circles\CirclesManager;
11+
use OCA\Circles\Model\Member;
12+
use OCA\Circles\Model\Probes\CircleProbe;
13+
use OCP\App\IAppManager;
14+
use OCP\Server;
15+
use Psr\Log\LoggerInterface;
16+
use Throwable;
17+
18+
/**
19+
* @psalm-suppress UndefinedClass
20+
*/
21+
class CircleHelper {
22+
private LoggerInterface $logger;
23+
private bool $circlesEnabled;
24+
private ?CirclesManager $circlesManager;
25+
26+
/**
27+
* @psalm-suppress UndefinedClass
28+
*/
29+
public function __construct(
30+
LoggerInterface $logger,
31+
IAppManager $appManager
32+
) {
33+
$this->logger = $logger;
34+
$this->circlesEnabled = $appManager->isEnabledForUser('circles');
35+
$this->circlesManager = null;
36+
37+
if ($this->circlesEnabled) {
38+
try {
39+
$this->circlesManager = Server::get(CirclesManager::class);
40+
} catch (Throwable $e) {
41+
$this->logger->warning('Failed to get CirclesManager: ' . $e->getMessage());
42+
$this->circlesEnabled = false;
43+
}
44+
}
45+
}
46+
47+
public function isCirclesEnabled(): bool {
48+
return $this->circlesEnabled;
49+
}
50+
51+
public function getCircleDisplayName(string $circleId, string $userId): string {
52+
if (!$this->circlesEnabled) {
53+
return $circleId;
54+
}
55+
56+
try {
57+
$federatedUser = $this->circlesManager->getFederatedUser($userId, Member::TYPE_USER);
58+
$this->circlesManager->startSession($federatedUser);
59+
60+
$circle = $this->circlesManager->getCircle($circleId);
61+
return $circle ? ($circle->getDisplayName() ?: $circleId) : $circleId;
62+
} catch (Throwable $e) {
63+
$this->logger->warning('Failed to get circle display name: ' . $e->getMessage(), [
64+
'circleId' => $circleId,
65+
'userId' => $userId
66+
]);
67+
return $circleId;
68+
}
69+
}
70+
71+
public function getUserCircles(string $userId): array {
72+
if (!$this->circlesEnabled) {
73+
return [];
74+
}
75+
76+
try {
77+
$federatedUser = $this->circlesManager->getFederatedUser($userId, Member::TYPE_USER);
78+
$this->circlesManager->startSession($federatedUser);
79+
$probe = new CircleProbe();
80+
$probe->mustBeMember();
81+
return $this->circlesManager->getCircles($probe);
82+
} catch (Throwable $e) {
83+
$this->logger->warning('Failed to get user circles: ' . $e->getMessage());
84+
return [];
85+
}
86+
}
87+
}

lib/Helper/UserHelper.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,26 @@
1414
use OCP\IUserManager;
1515
use Psr\Log\LoggerInterface;
1616

17+
/**
18+
* @psalm-suppress UndefinedClass
19+
* @psalm-suppress UndefinedDocblockClass
20+
*/
1721
class UserHelper {
1822
private IUserManager $userManager;
1923

2024
private LoggerInterface $logger;
25+
2126
private IGroupManager $groupManager;
2227

28+
/**
29+
* @psalm-suppress UndefinedClass
30+
*/
2331
public function __construct(IUserManager $userManager, LoggerInterface $logger, IGroupManager $groupManager) {
2432
$this->userManager = $userManager;
2533
$this->logger = $logger;
2634
$this->groupManager = $groupManager;
2735
}
36+
2837
public function getUserDisplayName(string $userId): string {
2938
try {
3039
$user = $this->getUser($userId);

lib/Service/PermissionsService.php

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,19 @@
1818
use OCA\Tables\Db\ViewMapper;
1919
use OCA\Tables\Errors\InternalError;
2020
use OCA\Tables\Errors\NotFoundError;
21+
use OCA\Tables\Helper\CircleHelper;
2122
use OCA\Tables\Helper\ConversionHelper;
2223
use OCA\Tables\Helper\UserHelper;
2324
use OCA\Tables\Model\Permissions;
2425
use OCP\AppFramework\Db\DoesNotExistException;
2526
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
2627
use OCP\DB\Exception;
2728
use Psr\Log\LoggerInterface;
29+
use Throwable;
2830

31+
/**
32+
* @psalm-suppress UndefinedDocblockClass
33+
*/
2934
class PermissionsService {
3035
private TableMapper $tableMapper;
3136

@@ -35,11 +40,14 @@ class PermissionsService {
3540

3641
private UserHelper $userHelper;
3742

43+
private CircleHelper $circleHelper;
44+
3845
protected LoggerInterface $logger;
3946

4047
protected ?string $userId = null;
4148

4249
protected bool $isCli = false;
50+
4351
private ContextMapper $contextMapper;
4452

4553
public function __construct(
@@ -50,6 +58,7 @@ public function __construct(
5058
ShareMapper $shareMapper,
5159
ContextMapper $contextMapper,
5260
UserHelper $userHelper,
61+
CircleHelper $circleHelper,
5362
bool $isCLI
5463
) {
5564
$this->tableMapper = $tableMapper;
@@ -60,6 +69,7 @@ public function __construct(
6069
$this->userId = $userId;
6170
$this->isCli = $isCLI;
6271
$this->contextMapper = $contextMapper;
72+
$this->circleHelper = $circleHelper;
6373
}
6474

6575

@@ -420,6 +430,7 @@ public function canReadShare(Share $share, ?string $userId = null): bool {
420430
* @param int $elementId
421431
* @param 'table'|'view' $elementType
422432
* @param string $userId
433+
* @return Permissions
423434
* @throws NotFoundError
424435
*/
425436
public function getSharedPermissionsIfSharedWithMe(int $elementId, string $elementType, string $userId): Permissions {
@@ -436,16 +447,40 @@ public function getSharedPermissionsIfSharedWithMe(int $elementId, string $eleme
436447
$this->logger->warning('Exception occurred: '.$e->getMessage().' Permission denied.');
437448
return new Permissions();
438449
}
439-
$additionalShares = [];
450+
$groupShares = [];
440451
foreach ($userGroups as $userGroup) {
441452
try {
442-
$additionalShares[] = $this->shareMapper->findAllSharesForNodeFor($elementType, $elementId, $userGroup->getGid(), 'group');
453+
$groupShares[] = $this->shareMapper->findAllSharesForNodeFor($elementType, $elementId, $userGroup->getGid(), 'group');
443454
} catch (Exception $e) {
444455
$this->logger->warning('Exception occurred: '.$e->getMessage().' Permission denied.');
445456
return new Permissions();
446457
}
447458
}
448-
$shares = array_merge($shares, ...$additionalShares);
459+
460+
$shares = array_merge($shares, ...$groupShares);
461+
462+
if ($this->circleHelper->isCirclesEnabled()) {
463+
$circleShares = [];
464+
465+
try {
466+
$userCircles = $this->circleHelper->getUserCircles($userId);
467+
} catch (Throwable $e) {
468+
$this->logger->warning('Exception occurred: ' . $e->getMessage() . ' Permission denied.');
469+
return new Permissions();
470+
}
471+
472+
foreach ($userCircles as $userCircle) {
473+
try {
474+
$circleShares[] = $this->shareMapper->findAllSharesForNodeFor($elementType, $elementId, $userCircle->getSingleId(), 'circle');
475+
} catch (Exception $e) {
476+
$this->logger->warning('Exception occurred: ' . $e->getMessage() . ' Permission denied.');
477+
return new Permissions();
478+
}
479+
}
480+
481+
$shares = array_merge($shares, ...$circleShares);
482+
}
483+
449484
if (count($shares) > 0) {
450485
$read = array_reduce($shares, function ($carry, $share) {
451486
return $carry || ($share->getPermissionRead());
@@ -520,7 +555,7 @@ private function hasPermission(int $existingPermissions, string $permissionName)
520555
$constantName = 'PERMISSION_' . strtoupper($permissionName);
521556
try {
522557
$permissionBit = constant(Application::class . "::$constantName");
523-
} catch (\Throwable $t) {
558+
} catch (Throwable $t) {
524559
$this->logger->error('Unexpected permission string {permission}', [
525560
'app' => Application::APP_ID,
526561
'permission' => $permissionName,

0 commit comments

Comments
 (0)