Skip to content

Commit a36c56e

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

File tree

8 files changed

+242
-45
lines changed

8 files changed

+242
-45
lines changed

lib/Helper/CircleHelper.php

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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+
?CirclesManager $circlesManager = null
33+
) {
34+
$this->logger = $logger;
35+
$this->circlesEnabled = $appManager->isEnabledForUser('circles');
36+
if ($this->circlesEnabled) {
37+
try {
38+
$this->circlesManager = $circlesManager ?? Server::get(CirclesManager::class);
39+
} catch (Throwable $e) {
40+
$this->logger->warning('Failed to get CirclesManager: ' . $e->getMessage());
41+
$this->circlesManager = null;
42+
$this->circlesEnabled = false;
43+
}
44+
} else {
45+
$this->circlesManager = null;
46+
}
47+
}
48+
49+
public function isCirclesEnabled(): bool {
50+
return $this->circlesEnabled;
51+
}
52+
53+
public function getCircleDisplayName(string $circleId, string $userId): string {
54+
if (!$this->circlesEnabled) {
55+
return $circleId;
56+
}
57+
58+
try {
59+
$federatedUser = $this->circlesManager->getFederatedUser($userId, Member::TYPE_USER);
60+
$this->circlesManager->startSession($federatedUser);
61+
62+
$circle = $this->circlesManager->getCircle($circleId);
63+
return $circle ? ($circle->getDisplayName() ?: $circleId) : $circleId;
64+
} catch (Throwable $e) {
65+
$this->logger->warning('Failed to get circle display name: ' . $e->getMessage(), [
66+
'circleId' => $circleId,
67+
'userId' => $userId
68+
]);
69+
return $circleId;
70+
}
71+
}
72+
73+
public function getUserCircles(string $userId): array {
74+
if (!$this->circlesEnabled) {
75+
return [];
76+
}
77+
78+
try {
79+
$federatedUser = $this->circlesManager->getFederatedUser($userId, Member::TYPE_USER);
80+
$this->circlesManager->startSession($federatedUser);
81+
$probe = new CircleProbe();
82+
$probe->mustBeMember();
83+
return $this->circlesManager->getCircles($probe);
84+
} catch (Throwable $e) {
85+
$this->logger->warning('Failed to get user circles: ' . $e->getMessage());
86+
return [];
87+
}
88+
}
89+
}

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,

lib/Service/ShareService.php

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424
use OCA\Tables\Errors\InternalError;
2525
use OCA\Tables\Errors\NotFoundError;
2626
use OCA\Tables\Errors\PermissionError;
27+
use OCA\Tables\Helper\CircleHelper;
2728
use OCA\Tables\Helper\GroupHelper;
2829
use OCA\Tables\Helper\UserHelper;
29-
3030
use OCA\Tables\Model\Permissions;
3131
use OCA\Tables\ResponseDefinitions;
3232
use OCP\AppFramework\Db\DoesNotExistException;
@@ -35,9 +35,11 @@
3535
use OCP\DB\Exception;
3636
use OCP\IDBConnection;
3737
use Psr\Log\LoggerInterface;
38+
use Throwable;
3839

3940
/**
4041
* @psalm-import-type TablesShare from ResponseDefinitions
42+
* @psalm-suppress UndefinedDocblockClass
4143
*/
4244
class ShareService extends SuperService {
4345
use TTransactional;
@@ -51,7 +53,11 @@ class ShareService extends SuperService {
5153
protected UserHelper $userHelper;
5254

5355
protected GroupHelper $groupHelper;
56+
57+
protected CircleHelper $circleHelper;
58+
5459
private ContextNavigationMapper $contextNavigationMapper;
60+
5561
private IDBConnection $dbc;
5662

5763
public function __construct(
@@ -63,6 +69,7 @@ public function __construct(
6369
ViewMapper $viewMapper,
6470
UserHelper $userHelper,
6571
GroupHelper $groupHelper,
72+
CircleHelper $circleHelper,
6673
ContextNavigationMapper $contextNavigationMapper,
6774
IDBConnection $dbc,
6875
) {
@@ -72,6 +79,7 @@ public function __construct(
7279
$this->viewMapper = $viewMapper;
7380
$this->userHelper = $userHelper;
7481
$this->groupHelper = $groupHelper;
82+
$this->circleHelper = $circleHelper;
7583
$this->contextNavigationMapper = $contextNavigationMapper;
7684
$this->dbc = $dbc;
7785
}
@@ -163,7 +171,17 @@ private function findElementsSharedWithMe(string $elementType = 'table', ?string
163171
$shares = $this->mapper->findAllSharesFor($elementType, $userGroup->getGid(), $userId, 'group');
164172
$elementsSharedWithMe = array_merge($elementsSharedWithMe, $shares);
165173
}
166-
} catch (Exception $e) {
174+
175+
// get all views or tables that are shared with me by circle
176+
if ($this->circleHelper->isCirclesEnabled()) {
177+
$userCircles = $this->circleHelper->getUserCircles($userId);
178+
179+
foreach ($userCircles as $userCircle) {
180+
$shares = $this->mapper->findAllSharesFor($elementType, $userCircle->getSingleId(), $userId, 'circle');
181+
$elementsSharedWithMe = array_merge($elementsSharedWithMe, $shares);
182+
}
183+
}
184+
} catch (Throwable $e) {
167185
throw new InternalError($e->getMessage());
168186
}
169187
foreach ($elementsSharedWithMe as $share) {
@@ -398,6 +416,16 @@ private function addReceiverDisplayName(Share $share):Share {
398416
$share->setReceiverDisplayName($this->userHelper->getUserDisplayName($share->getReceiver()));
399417
} elseif ($share->getReceiverType() === 'group') {
400418
$share->setReceiverDisplayName($this->groupHelper->getGroupDisplayName($share->getReceiver()));
419+
} elseif ($share->getReceiverType() === 'circle') {
420+
if ($this->circleHelper->isCirclesEnabled()) {
421+
$share->setReceiverDisplayName($this->circleHelper->getCircleDisplayName($share->getReceiver(), $this->userId));
422+
} else {
423+
$this->logger->info(
424+
'Could not get display name for receiver type {type}',
425+
['type' => $share->getReceiverType()]
426+
);
427+
$share->setReceiverDisplayName($share->getReceiver());
428+
}
401429
} else {
402430
$this->logger->info('can not use receiver type to get display name');
403431
$share->setReceiverDisplayName($share->getReceiver());

src/modules/sidebar/mixins/shareAPI.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ import axios from '@nextcloud/axios'
66
import { generateUrl } from '@nextcloud/router'
77
import '@nextcloud/dialogs/style.css'
88
import displayError from '../../../shared/utils/displayError.js'
9+
import ShareTypes from '../../../shared/mixins/shareTypesMixin.js'
910

1011
export default {
12+
mixins: [ShareTypes],
13+
1114
methods: {
1215
async getSharedWithFromBE() {
1316
try {
@@ -32,7 +35,11 @@ export default {
3235
nodeType: this.isView ? 'view' : 'table',
3336
nodeId: this.activeElement.id,
3437
receiver: share.user,
35-
receiverType: (share.isNoUser) ? 'group' : 'user',
38+
receiverType: share.shareType === this.SHARE_TYPES.SHARE_TYPE_USER
39+
? 'user'
40+
: share.shareType === this.SHARE_TYPES.SHARE_TYPE_GROUP
41+
? 'group'
42+
: 'circle',
3643
permissionRead: true,
3744
permissionCreate: true,
3845
permissionUpdate: true,
@@ -45,8 +52,11 @@ export default {
4552
displayError(e, t('tables', 'Could not create share.'))
4653
return false
4754
}
48-
if (this.isView) await this.$store.dispatch('setViewHasShares', { viewId: this.activeElement.id, hasShares: true })
49-
else await this.$store.dispatch('setTableHasShares', { tableId: this.isView ? this.activeElement.tableId : this.activeElement.id, hasShares: true })
55+
if (this.isView) {
56+
await this.$store.dispatch('setViewHasShares', { viewId: this.activeElement.id, hasShares: true })
57+
} else {
58+
await this.$store.dispatch('setTableHasShares', { tableId: this.isView ? this.activeElement.tableId : this.activeElement.id, hasShares: true })
59+
}
5060
return true
5161
},
5262
async removeShareFromBE(shareId) {

0 commit comments

Comments
 (0)