Skip to content

Commit a6da886

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

File tree

8 files changed

+183
-44
lines changed

8 files changed

+183
-44
lines changed

lib/Helper/CircleHelper.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/**
4+
* SPDX-FileCopyrightText: 2023 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 Psr\Log\LoggerInterface;
12+
13+
/**
14+
* @psalm-suppress UndefinedClass
15+
*/
16+
class CircleHelper {
17+
private LoggerInterface $logger;
18+
private CirclesManager $circlesManager;
19+
20+
/**
21+
* @psalm-suppress UndefinedClass
22+
*/
23+
public function __construct(LoggerInterface $logger, CirclesManager $circlesManager) {
24+
$this->logger = $logger;
25+
$this->circlesManager = $circlesManager;
26+
}
27+
28+
public function getCircleDisplayName(string $circleId): string {
29+
$this->circlesManager->startSuperSession();
30+
$circle = $this->circlesManager->getCircle($circleId);
31+
32+
if ($circle) {
33+
return $circle->getDisplayName() ?: $circleId;
34+
}
35+
36+
$this->logger->info('no circle given, will return circleId');
37+
38+
return $circleId;
39+
}
40+
}

lib/Helper/UserHelper.php

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,40 @@
77

88
namespace OCA\Tables\Helper;
99

10+
use OCA\Circles\CirclesManager;
11+
use OCA\Circles\Exceptions\InitiatorNotFoundException;
12+
use OCA\Circles\Exceptions\RequestBuilderException;
13+
use OCA\Circles\Model\Circle;
1014
use OCA\Tables\Errors\InternalError;
1115
use OCP\IGroup;
1216
use OCP\IGroupManager;
1317
use OCP\IUser;
1418
use OCP\IUserManager;
1519
use Psr\Log\LoggerInterface;
1620

21+
/**
22+
* @psalm-suppress UndefinedClass
23+
* @psalm-suppress UndefinedDocblockClass
24+
*/
1725
class UserHelper {
1826
private IUserManager $userManager;
1927

2028
private LoggerInterface $logger;
29+
2130
private IGroupManager $groupManager;
2231

23-
public function __construct(IUserManager $userManager, LoggerInterface $logger, IGroupManager $groupManager) {
32+
private CirclesManager $circlesManager;
33+
34+
/**
35+
* @psalm-suppress UndefinedClass
36+
*/
37+
public function __construct(IUserManager $userManager, LoggerInterface $logger, IGroupManager $groupManager, CirclesManager $circlesManager) {
2438
$this->userManager = $userManager;
2539
$this->logger = $logger;
2640
$this->groupManager = $groupManager;
41+
$this->circlesManager = $circlesManager;
2742
}
43+
2844
public function getUserDisplayName(string $userId): string {
2945
try {
3046
$user = $this->getUser($userId);
@@ -56,6 +72,17 @@ public function getGroupsForUser(string $userId): array {
5672
return $this->groupManager->getUserGroups($user);
5773
}
5874

75+
/**
76+
* @psalm-suppress UndefinedDocblockClass
77+
* @return Circle[]
78+
* @throws InitiatorNotFoundException
79+
* @throws RequestBuilderException
80+
*/
81+
public function getCircles(): array {
82+
$this->circlesManager->startSuperSession();
83+
return $this->circlesManager->probeCircles();
84+
}
85+
5986
/**
6087
* @param string $userId
6188
* @return array|null

lib/Service/PermissionsService.php

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@
2525
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
2626
use OCP\DB\Exception;
2727
use Psr\Log\LoggerInterface;
28+
use Throwable;
2829

30+
/**
31+
* @psalm-suppress UndefinedDocblockClass
32+
*/
2933
class PermissionsService {
3034
private TableMapper $tableMapper;
3135

@@ -420,6 +424,7 @@ public function canReadShare(Share $share, ?string $userId = null): bool {
420424
* @param int $elementId
421425
* @param 'table'|'view' $elementType
422426
* @param string $userId
427+
* @return Permissions
423428
* @throws NotFoundError
424429
*/
425430
public function getSharedPermissionsIfSharedWithMe(int $elementId, string $elementType, string $userId): Permissions {
@@ -436,16 +441,31 @@ public function getSharedPermissionsIfSharedWithMe(int $elementId, string $eleme
436441
$this->logger->warning('Exception occurred: '.$e->getMessage().' Permission denied.');
437442
return new Permissions();
438443
}
439-
$additionalShares = [];
444+
$groupShares = [];
440445
foreach ($userGroups as $userGroup) {
441446
try {
442-
$additionalShares[] = $this->shareMapper->findAllSharesForNodeFor($elementType, $elementId, $userGroup->getGid(), 'group');
447+
$groupShares[] = $this->shareMapper->findAllSharesForNodeFor($elementType, $elementId, $userGroup->getGid(), 'group');
448+
} catch (Exception $e) {
449+
$this->logger->warning('Exception occurred: '.$e->getMessage().' Permission denied.');
450+
return new Permissions();
451+
}
452+
}
453+
454+
try {
455+
$userCircles = $this->userHelper->getCircles();
456+
} catch (Throwable $e) {
457+
$this->logger->warning('Exception occurred: '.$e->getMessage().' Permission denied.');
458+
return new Permissions();
459+
}
460+
foreach ($userCircles as $userCircle) {
461+
try {
462+
$circleShares[] = $this->shareMapper->findAllSharesForNodeFor($elementType, $elementId, $userCircle->getSingleId(), 'circle');
443463
} catch (Exception $e) {
444464
$this->logger->warning('Exception occurred: '.$e->getMessage().' Permission denied.');
445465
return new Permissions();
446466
}
447467
}
448-
$shares = array_merge($shares, ...$additionalShares);
468+
$shares = array_merge($shares, ...$groupShares, ...$circleShares);
449469
if (count($shares) > 0) {
450470
$read = array_reduce($shares, function ($carry, $share) {
451471
return $carry || ($share->getPermissionRead());
@@ -520,7 +540,7 @@ private function hasPermission(int $existingPermissions, string $permissionName)
520540
$constantName = 'PERMISSION_' . strtoupper($permissionName);
521541
try {
522542
$permissionBit = constant(Application::class . "::$constantName");
523-
} catch (\Throwable $t) {
543+
} catch (Throwable $t) {
524544
$this->logger->error('Unexpected permission string {permission}', [
525545
'app' => Application::APP_ID,
526546
'permission' => $permissionName,

lib/Service/ShareService.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
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;
2930

@@ -38,6 +39,7 @@
3839

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

5355
protected GroupHelper $groupHelper;
56+
57+
protected CircleHelper $circleHelper;
5458
private ContextNavigationMapper $contextNavigationMapper;
5559
private IDBConnection $dbc;
5660

@@ -63,6 +67,7 @@ public function __construct(
6367
ViewMapper $viewMapper,
6468
UserHelper $userHelper,
6569
GroupHelper $groupHelper,
70+
CircleHelper $circleHelper,
6671
ContextNavigationMapper $contextNavigationMapper,
6772
IDBConnection $dbc,
6873
) {
@@ -72,6 +77,7 @@ public function __construct(
7277
$this->viewMapper = $viewMapper;
7378
$this->userHelper = $userHelper;
7479
$this->groupHelper = $groupHelper;
80+
$this->circleHelper = $circleHelper;
7581
$this->contextNavigationMapper = $contextNavigationMapper;
7682
$this->dbc = $dbc;
7783
}
@@ -163,6 +169,14 @@ private function findElementsSharedWithMe(string $elementType = 'table', ?string
163169
$shares = $this->mapper->findAllSharesFor($elementType, $userGroup->getGid(), $userId, 'group');
164170
$elementsSharedWithMe = array_merge($elementsSharedWithMe, $shares);
165171
}
172+
173+
// get all views or tables that are shared with me by circle
174+
$userCircles = $this->userHelper->getCircles();
175+
176+
foreach ($userCircles as $userCircle) {
177+
$shares = $this->mapper->findAllSharesFor($elementType, $userCircle->getSingleId(), $userId, 'circle');
178+
$elementsSharedWithMe = array_merge($elementsSharedWithMe, $shares);
179+
}
166180
} catch (Exception $e) {
167181
throw new InternalError($e->getMessage());
168182
}
@@ -398,6 +412,8 @@ private function addReceiverDisplayName(Share $share):Share {
398412
$share->setReceiverDisplayName($this->userHelper->getUserDisplayName($share->getReceiver()));
399413
} elseif ($share->getReceiverType() === 'group') {
400414
$share->setReceiverDisplayName($this->groupHelper->getGroupDisplayName($share->getReceiver()));
415+
} elseif ($share->getReceiverType() === 'circle') {
416+
$share->setReceiverDisplayName($this->circleHelper->getCircleDisplayName($share->getReceiver()));
401417
} else {
402418
$this->logger->info('can not use receiver type to get display name');
403419
$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) {

src/modules/sidebar/partials/ShareForm.vue

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
<div class="row space-B">
77
<h3>{{ t('tables', 'Share with accounts or groups') }}</h3>
88
<NcSelect id="ajax" style="width: 100%;" :clear-on-select="true" :hide-selected="true" :internal-search="false"
9-
:loading="loading" :options="options" :placeholder="t('tables', 'User or group name …')"
9+
:loading="loading" :options="options" :placeholder="t('tables', 'User, group or team …')"
1010
:preselect-first="true" :preserve-search="true" :searchable="true" :user-select="true"
11-
:get-option-key="(option) => option.key" :aria-label-combobox="t('tables', 'User or group name …')"
11+
:get-option-key="(option) => option.key" :aria-label-combobox="t('tables', 'User, group or team …')"
1212
label="displayName" @search="asyncFind" @input="addShare">
1313
<template #no-options>
1414
{{ t('tables', 'No recommendations. Start typing.') }}
@@ -51,6 +51,10 @@ export default {
5151
type: Boolean,
5252
default: true,
5353
},
54+
selectCircles: {
55+
type: Boolean,
56+
default: true,
57+
},
5458
},
5559
5660
computed: {
@@ -100,7 +104,7 @@ export default {
100104
101105
filterOutUnwantedItems(items) {
102106
const shareTypesList = this.getShareTypes()
103-
const shareTypes = { 0: 'user', 1: 'group' }
107+
const shareTypes = { 0: 'user', 1: 'group', 7: 'circle' }
104108
105109
// Filter out current user and sort
106110
items = items.filter((item) => !(item.shareType === this.SHARE_TYPES.SHARE_TYPE_USER && item.shareWith === this.currentUserId)).sort((a, b) => a.shareType - b.shareType)
@@ -113,13 +117,24 @@ export default {
113117
},
114118
115119
formatResult(result) {
120+
const isUser = result.source.startsWith('users')
121+
const isGroup = result.source.startsWith('groups')
122+
116123
return {
117124
shareWith: result.id,
118-
shareType: result.source.startsWith('users') ? this.SHARE_TYPES.SHARE_TYPE_USER : this.SHARE_TYPES.SHARE_TYPE_GROUP,
125+
shareType: isUser
126+
? this.SHARE_TYPES.SHARE_TYPE_USER
127+
: isGroup
128+
? this.SHARE_TYPES.SHARE_TYPE_GROUP
129+
: this.SHARE_TYPES.SHARE_TYPE_CIRCLE,
119130
user: result.id,
120-
isNoUser: !result.source.startsWith('users'),
131+
isNoUser: !isUser,
121132
displayName: result.label,
122-
icon: result.icon || result.source.startsWith('users') ? 'icon-user' : 'icon-group',
133+
icon: isUser
134+
? 'icon-user'
135+
: isGroup
136+
? 'icon-group'
137+
: 'icon-circles',
123138
key: result.source + '-' + result.id,
124139
}
125140
},
@@ -131,15 +146,21 @@ export default {
131146
* @return {object}
132147
*/
133148
formatRecommendations(result) {
149+
const isUser = result.value.shareType === this.SHARE_TYPES.SHARE_TYPE_USER
150+
const isGroup = result.value.shareType === this.SHARE_TYPES.SHARE_TYPE_GROUP
151+
134152
return {
135153
shareWith: result.value.shareWith,
136154
shareType: result.value.shareType,
137155
user: result.uuid || result.value.shareWith,
138-
isNoUser: result.value.shareType !== this.SHARE_TYPES.SHARE_TYPE_USER,
156+
isNoUser: !isUser,
139157
displayName: result.name || result.label,
140-
icon: result.value.shareType === this.SHARE_TYPES.SHARE_TYPE_USER ? 'icon-user' : 'icon-group',
141-
// Vue unique binding to render within Multiselect's AvatarSelectOption
142-
key: result.uuid || result.value.shareWith + '-' + result.value.shareType + '-' + result.name || result.label,
158+
icon: isUser
159+
? 'icon-user'
160+
: isGroup
161+
? 'icon-group'
162+
: 'icon-circle',
163+
key: result.uuid || result.value.shareWith + '-' + result.value.shareType + '-' + (result.name || result.label),
143164
}
144165
},
145166

0 commit comments

Comments
 (0)