From 6118b747155d24e21357393e3ada8b03802aff19 Mon Sep 17 00:00:00 2001 From: zak39 Date: Wed, 11 Dec 2024 17:44:20 +0100 Subject: [PATCH 01/19] chore: Declare workspace as DAV type in the info.xml WorkSpace must be considered as dav types, in order to boot on dav requests. by @smarinier. --- appinfo/info.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/appinfo/info.xml b/appinfo/info.xml index 360fca2c7..1da127464 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -25,6 +25,10 @@ Create Groupfolders with delegated management + + + + Date: Wed, 11 Dec 2024 17:45:10 +0100 Subject: [PATCH 02/19] feat(php): Create a backend group for the added groups by @smarinier. --- lib/AppInfo/Application.php | 14 ++- lib/Group/GroupBackend.php | 182 ++++++++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 lib/Group/GroupBackend.php diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 216b74427..8ef493e64 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -22,6 +22,8 @@ namespace OCA\Workspace\AppInfo; +use OCA\Workspace\Db\SpaceMapper; +use OCA\Workspace\Group\GroupBackend; use OCA\Workspace\Middleware\IsGeneralManagerMiddleware; use OCA\Workspace\Middleware\IsSpaceAdminMiddleware; use OCA\Workspace\Middleware\WorkspaceAccessControlMiddleware; @@ -32,6 +34,7 @@ use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\AppFramework\Utility\IControllerMethodReflector; +use OCP\IGroupManager; use OCP\IRequest; use OCP\IURLGenerator; @@ -43,6 +46,7 @@ public function __construct(array $urlParams = []) { } public function register(IRegistrationContext $context): void { + $context->registerService(WorkspaceAccessControlMiddleware::class, function ($c) { return new WorkspaceAccessControlMiddleware( $c->query(IURLGenerator::class), @@ -75,6 +79,14 @@ public function register(IRegistrationContext $context): void { } public function boot(IBootContext $context): void { - } + // Unexplained BUG with autoload. Keep this line + $context->getAppContainer()->query(SpaceMapper::class); + $context->injectFn(function ( + IGroupManager $groupManager, + GroupBackend $groupBackend, + ) { + $groupManager->addBackend($groupBackend); + }); + } } diff --git a/lib/Group/GroupBackend.php b/lib/Group/GroupBackend.php new file mode 100644 index 000000000..da8c2f86e --- /dev/null +++ b/lib/Group/GroupBackend.php @@ -0,0 +1,182 @@ + + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Workspace\Group; + +use OCA\Workspace\Service\Group\ConnectedGroupsService; +use OCP\Group\Backend\ABackend; +use OCP\Group\Backend\ICountUsersBackend; +use OCP\Group\Backend\INamedBackend; +use OCP\GroupInterface; +use OCP\IGroupManager; +use OCP\IUserManager; + +class GroupBackend extends ABackend implements GroupInterface, INamedBackend, ICountUsersBackend { + + private bool $avoidRecurse_users; + private bool $avoidRecurse_groups; + + /** + * @param IGroupManager $groupManager parent group manager + */ + public function __construct( + protected IGroupManager $groupManager, + protected IUserManager $userManager, + private ConnectedGroupsService $connectedGroups, + ) { + $this->avoidRecurse_users = $this->avoidRecurse_groups = false; + } + + /** + * is user in group? + * @param string $uid uid of the user + * @param string $gid gid of the group + * @return bool + * + * Checks whether the user is member of a group or not. + */ + public function inGroup($uid, $gid) { + // not backend responsability + return false; + } + + /** + * Get all groups a user belongs to + * @param string $uid Name of the user + * @return string[] an array of group names + * + * This function fetches all groups a user belongs to. It does not check + * if the user exists at all. + */ + public function getUserGroups($uid) { + if ($this->avoidRecurse_groups) { + return []; + } + + $avoid = $this->avoidRecurse_groups; + $this->avoidRecurse_groups = true; + $user = $this->userManager->get($uid); + if ($user) { + $groupIds = $this->groupManager->getUserGroupIds($user); + } else { + $groupIds = []; + } + $this->avoidRecurse_groups = $avoid; + if (empty($groupIds)) { + return []; + } + $userGroups = []; + foreach ($groupIds as $gid) { + $connectedGids = $this->connectedGroups->getConnectedSpaceToGroupIds($gid); + if ($connectedGids !== null) { + $userGroups = array_merge($userGroups, $connectedGids); + } + } + + return $userGroups; + } + + /** + * get a list of all groups + * @param string $search + * @param int $limit + * @param int $offset + * @return array an array of group names + * @since 4.5.0 + * + * Returns a list with all groups + */ + public function getGroups($search = '', $limit = -1, $offset = 0) { + return []; // return all virtual groups + } + + /** + * check if a group exists + * @param string $gid + * @return bool + */ + public function groupExists($gid) { + // @note : need to implement, but this backend doesn't manage existence of connected groups + return $this->connectedGroups->hasConnectedGroups($gid); + } + + /** + * get a list of all users in a group + * @param string $gid + * @param string $search + * @param int $limit + * @param int $offset + * @return string[] an array of user ids + */ + public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) { + if ($this->avoidRecurse_users) { + return []; + } + + $groups = $this->connectedGroups->getConnectedGroupsToSpaceGroup($gid); + if ($groups === null) { + return []; + } + + $users = []; + $avoid = $this->avoidRecurse_users; + $this->avoidRecurse_users = true; + foreach ($groups as $group) { + if (!is_null($group)) { + foreach ($group->getUsers() as $user) { + $users[] = $user->getUID(); + }; + } + } + $this->avoidRecurse_users = $avoid; + return $users; + } + + public function getBackendName(): string { + return 'WorkspaceGroupBackend'; + } + + + public function countUsersInGroup(string $gid, string $search = ''): int { + + $users = $this->usersInGroup($gid); + if (!is_array($users)) { + return 0; + } + + // get database users first + $group = $this->groupManager->get($gid); + $this->avoidRecurse_users = true; + $usersDb = $group->getUsers(); + $this->avoidRecurse_users = false; + + $nbUsers = 0; + foreach ($users as $userId) { + if (!isset($usersDb[$userId])) { + $usersDb[$userId] = true; + $nbUsers ++; + } + } + return $nbUsers; + } +}; From bfef0357333d3715dfbf8feeab3bebd8baf2729a Mon Sep 17 00:00:00 2001 From: zak39 Date: Wed, 11 Dec 2024 17:46:26 +0100 Subject: [PATCH 03/19] feat(php): Add the ability to add groups in workspaces We can add connected groups (or added groups) to workspaces. These groups can be LDAP or local, and when we add a connected group, we also add its users. In this feature, we return a slug of a gid. This slug handles special characters, making it more suitable for rendering in the browser's URL. --- lib/Controller/ConnectedGroupController.php | 167 +++++++++++++++++++ lib/Controller/GroupController.php | 69 +++++++- lib/Controller/WorkspaceController.php | 74 ++++++-- lib/Db/ConnectedGroup.php | 54 ++++++ lib/Db/GroupFoldersGroupsMapper.php | 60 ++++++- lib/Group/AddedGroups/AddedGroups.php | 52 ++++++ lib/Group/Admin/AdminGroup.php | 23 ++- lib/Group/SubGroups/SubGroup.php | 58 +++++++ lib/Group/User/UserGroup.php | 11 +- lib/Helper/GroupfolderHelper.php | 15 ++ lib/Service/Group/ConnectedGroupsService.php | 163 ++++++++++++++++++ lib/Service/Group/GroupFormatter.php | 19 ++- lib/Service/Slugger.php | 24 +++ lib/Service/User/UserFormatter.php | 10 +- lib/Service/UserService.php | 18 +- lib/Service/WorkspaceService.php | 33 ++-- lib/Space/SpaceManager.php | 64 ++++++- 17 files changed, 861 insertions(+), 53 deletions(-) create mode 100644 lib/Controller/ConnectedGroupController.php create mode 100644 lib/Db/ConnectedGroup.php create mode 100644 lib/Group/AddedGroups/AddedGroups.php create mode 100644 lib/Group/SubGroups/SubGroup.php create mode 100644 lib/Service/Group/ConnectedGroupsService.php create mode 100644 lib/Service/Slugger.php diff --git a/lib/Controller/ConnectedGroupController.php b/lib/Controller/ConnectedGroupController.php new file mode 100644 index 000000000..ab56ba6c9 --- /dev/null +++ b/lib/Controller/ConnectedGroupController.php @@ -0,0 +1,167 @@ +groupManager->groupExists($gid)) { + $message = sprintf('The group %s does not exist', $gid); + + $this->logger->error($message); + + return new JSONResponse( + [ + 'message' => $message, + 'success' => false + ], + Http::STATUS_NOT_FOUND + ); + } + + $group = $this->groupManager->get($gid); + + if (str_starts_with($group->getGID(), 'SPACE-')) { + $message = sprintf('The group %s cannot be added, as it is already a workspace group', $gid); + + $this->logger->error($message); + + return new JSONResponse( + [ + 'message' => $message, + 'success' => false + ], + Http::STATUS_NOT_FOUND + ); + } + + $space = $this->spaceMapper->find($spaceId); + + $this->folderHelper->addApplicableGroup( + $space->getGroupfolderId(), + $group->getGid(), + ); + + + foreach ($group->getUsers() as $user) { + $users[$user->getUID()] = $this->userService->formatUser( + $user, + $this->spaceManager->get($spaceId), + 'user' + ); + }; + + foreach ($users as &$user) { + if (array_key_exists('groups', $user)) { + array_push($user['groups'], 'SPACE-U-' . $space->getSpaceId()); + } + } + + $message = sprintf('The %s group is added to the %s workspace.', $group->getGID(), $space->getSpaceName()); + + $this->logger->info($message); + + return new JSONResponse([ + 'message' => sprintf('The %s group is added to the %s workspace.', $group->getGID(), $space->getSpaceName()), + 'success' => true, + 'users' => $users, + 'slug' => Slugger::slugger($gid), + ]); + } + + /** + * Remove a group connected to a workspace/groupfolder. + * + * @NoAdminRequired + * @SpaceAdminRequired + */ + public function removeGroup(int $spaceId, string $gid) { + if (!$this->groupManager->groupExists($gid)) { + $message = sprintf('The group %s does not exist', $gid); + + $this->logger->error($message); + + return new JSONResponse( + [ + 'message' => $message, + 'success' => false + ], + Http::STATUS_NOT_FOUND + ); + } + + $group = $this->groupManager->get($gid); + + if (str_starts_with($group->getGID(), 'SPACE-')) { + + $message = sprintf('The %s group is not authorized to remove.', $gid); + + $this->logger->error($message); + + return new JSONResponse( + [ + 'message' => $message, + 'success' => false + ], + Http::STATUS_NOT_FOUND + ); + } + + $space = $this->spaceMapper->find($spaceId); + + $this->folderHelper->removeApplicableGroup( + $space->getGroupfolderId(), + $group->getGID() + ); + + $message = sprintf('The group %s is removed from the workspace %s', $group->getGID(), $space->getSpaceName()); + + $this->logger->info($message); + + return new JSONResponse([ + 'message' => sprintf('The group %s is removed from the workspace %s', $group->getGID(), $space->getSpaceName()), + 'success' => true + ]); + } +} diff --git a/lib/Controller/GroupController.php b/lib/Controller/GroupController.php index 00648cb95..edff39474 100644 --- a/lib/Controller/GroupController.php +++ b/lib/Controller/GroupController.php @@ -31,16 +31,21 @@ use OCA\Workspace\Service\Group\ManagersWorkspace; use OCA\Workspace\Service\Group\UserGroup; use OCA\Workspace\Service\Group\WorkspaceManagerGroup; +use OCA\Workspace\Service\Slugger; use OCA\Workspace\Service\User\UserFormatter; use OCA\Workspace\Service\User\UserWorkspace; use OCA\Workspace\Service\UserService; +use OCA\Workspace\Share\Group\GroupMembersOnlyChecker; +use OCA\Workspace\Share\Group\ShareMembersOnlyFilter; use OCA\Workspace\Space\SpaceManager; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\JSONResponse; +use OCP\Collaboration\Collaborators\ISearch; use OCP\IGroupManager; use OCP\IRequest; use OCP\IUserManager; +use OCP\Share\IShare; use Psr\Log\LoggerInterface; class GroupController extends Controller { @@ -52,12 +57,15 @@ class GroupController extends Controller { public function __construct( private GroupsWorkspaceService $groupsWorkspace, private IGroupManager $groupManager, - private LoggerInterface $logger, private SpaceManager $spaceManager, private IUserManager $userManager, + private ISearch $collaboratorSearch, + private LoggerInterface $logger, private UserFormatter $userFormatter, private UserService $userService, private UserWorkspace $userWorkspace, + private GroupMembersOnlyChecker $groupMembersOnlyChecker, + private ShareMembersOnlyFilter $shareMembersOnlyFilter, ) { } @@ -96,7 +104,10 @@ public function create(array $data = []): JSONResponse { return new JSONResponse([ 'group' => [ 'gid' => $NCGroup->getGID(), - 'displayName' => $NCGroup->getDisplayName() + 'displayName' => $NCGroup->getDisplayName(), + 'types' => $NCGroup->getBackendNames(), + 'usersCount' => 0, + 'slug' => Slugger::slugger($NCGroup->getGID()) ] ]); } @@ -429,4 +440,58 @@ public function transferUsersToGroups(string $spaceId, 'users' => (object)$users ], Http::STATUS_OK); } + + /** + * @NoAdminRequired + * + * @param string $pattern The pattern to search + * @param bool $ignoreSpaces (not require) Ignore the workspace groups + * @param array $groupsPresents are groups already present + */ + public function search(string $pattern, ?bool $ignoreSpaces = null, array $groupsPresents = []): JSONResponse { + + [$groups] = $this->collaboratorSearch->search( + $pattern, + [ + IShare::TYPE_GROUP + ], + false, + 200, + 0 + ); + + $groupsSearching = array_map( + fn ($group) => $group['value']['shareWith'], + $groups['groups'] + ); + + $groupsExact = []; + if (!empty($groups['exact']['groups'])) { + $groupsExact[] = $groups['exact']['groups'][0]['value']['shareWith']; + } + + $groups = array_merge($groupsSearching, $groupsExact); + + $groups = array_map(fn ($group) => $this->groupManager->get($group), $groups); + + if (!is_null($ignoreSpaces) && (bool)$ignoreSpaces) { + $groups = array_filter($groups, function ($group) { + $gid = $group->getGID(); + + return !str_starts_with($gid, WorkspaceManagerGroup::getPrefix()) + && !str_starts_with($gid, UserGroup::getPrefix()) + && !str_starts_with($gid, 'SPACE-G') + && $gid !== ManagersWorkspace::GENERAL_MANAGER + && $gid !== ManagersWorkspace::WORKSPACES_MANAGERS; + }); + } + + $groups = array_filter($groups, fn ($group) => !in_array($group->getGID(), $groupsPresents)); + + $groupsFormatted = GroupFormatter::formatGroups($groups); + + uksort($groupsFormatted, 'strcasecmp'); + + return new JSONResponse($groupsFormatted); + } } diff --git a/lib/Controller/WorkspaceController.php b/lib/Controller/WorkspaceController.php index c0fb0b96a..9af769741 100644 --- a/lib/Controller/WorkspaceController.php +++ b/lib/Controller/WorkspaceController.php @@ -25,18 +25,19 @@ namespace OCA\Workspace\Controller; -use OCA\Workspace\Db\Space; use OCA\Workspace\Db\SpaceMapper; use OCA\Workspace\Exceptions\BadRequestException; use OCA\Workspace\Folder\RootFolder; use OCA\Workspace\Group\Admin\AdminGroup; use OCA\Workspace\Group\Admin\AdminUserGroup; use OCA\Workspace\Helper\GroupfolderHelper; +use OCA\Workspace\Service\Group\ConnectedGroupsService; use OCA\Workspace\Service\Group\GroupFormatter; use OCA\Workspace\Service\Group\ManagersWorkspace; use OCA\Workspace\Service\Group\UserGroup; use OCA\Workspace\Service\Group\WorkspaceManagerGroup; use OCA\Workspace\Service\SpaceService; +use OCA\Workspace\Service\User\UserFormatter; use OCA\Workspace\Service\UserService; use OCA\Workspace\Service\Workspace\WorkspaceCheckService; use OCA\Workspace\Service\WorkspaceService; @@ -62,12 +63,14 @@ public function __construct( private SpaceMapper $spaceMapper, private SpaceService $spaceService, private UserService $userService, + private ConnectedGroupsService $connectedGroups, private WorkspaceCheckService $workspaceCheck, private WorkspaceService $workspaceService, private UserGroup $userGroup, + private UserFormatter $userFormatter, private WorkspaceManagerGroup $workspaceManagerGroup, private SpaceManager $spaceManager, - public $AppName + public $AppName, ) { parent::__construct($AppName, $request); } @@ -109,20 +112,10 @@ public function createWorkspace(string $spaceName): JSONResponse { * */ public function destroy(int $spaceId): JSONResponse { - $this->logger->debug('Removing GE users from the WorkspacesManagers group if needed.'); - foreach ($this->adminGroup->getUsers($spaceId) as $user) { - if ($this->userService->canRemoveWorkspaceManagers($user)) { - $this->adminUserGroup->removeUser($user); - } - } - - // Removes all workspaces groups $space = $this->spaceManager->get($spaceId); $groups = []; - $this->logger->debug('Removing workspaces groups.'); foreach (array_keys($space['groups']) as $group) { $groups[] = $group; - $this->groupManager->get($group)->delete(); } $this->spaceManager->remove($spaceId); @@ -181,9 +174,47 @@ public function findAll(): JSONResponse { $groups[] = $group; } + $gids = array_keys($space['groups'] ?? []); + $groups = []; + + $gids = array_filter($gids, fn ($gid) => str_starts_with($gid, 'SPACE-')); + + $space['users'] = []; + foreach ($gids as $gid) { + $group = $this->groupManager->get($gid); + if (is_null($group)) { + $this->logger->warning( + "Be careful, the $gid group is not exist in the oc_groups table." + . " But, it's present in the oc_group_folders_groups table." + . 'It necessary to recreate it with the occ command.' + ); + continue; + } + $groups[] = $group; + + if (str_starts_with($gid, 'SPACE-U-')) { + $space['userCount'] = $group->count(); + } + + if (str_starts_with($gid, 'SPACE-GE')) { + $users = $group->getUsers(); + $space['users'] = $this->userFormatter->formatUsers($users, $folderInfo, (string)$space['id']); + } + + $space['users'] = (object)$space['users']; + } + + $addedGroups = []; + foreach ($gids as $gid) { + $addedToGroup = $this->connectedGroups->getConnectedGroupsToSpaceGroup($gid); + if ($addedToGroup !== null) { + $addedGroups = array_merge($addedGroups, $addedToGroup); + } + } + $space['groups'] = GroupFormatter::formatGroups($groups); - $space['users'] = $this->workspaceService->addUsersInfo($space); - + $space['added_groups'] = (object)GroupFormatter::formatGroups($addedGroups); + $spaces[] = $space; } // We only want to return those workspaces for which the connected user is a manager @@ -198,6 +229,21 @@ public function findAll(): JSONResponse { return new JSONResponse($spaces); } + /** + * @NoAdminRequired + */ + public function getUsers(int $spaceId): JSONResponse { + + $space = $this->spaceMapper->find($spaceId); + + $groupfolder = $this->folderHelper->getFolder($space->getGroupfolderId(), $this->rootFolder->getRootFolderStorageId()); + + $workspace = array_merge($groupfolder, $space->jsonSerialize()); + $users = $this->workspaceService->addUsersInfo($workspace); + + return new JSONResponse($users); + } + /** * @NoAdminRequired * @param string|array $workspace diff --git a/lib/Db/ConnectedGroup.php b/lib/Db/ConnectedGroup.php new file mode 100644 index 000000000..27ad9879e --- /dev/null +++ b/lib/Db/ConnectedGroup.php @@ -0,0 +1,54 @@ + + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Workspace\Db; + +use JsonSerializable; + +use OCP\AppFramework\Db\Entity; + +class ConnectedGroup extends Entity implements JsonSerializable { + + /** + * @var integer + */ + protected $spaceId; + + /** + * @var string + */ + protected $gid; + + public function __construct() { + $this->addType('space_id', 'integer'); + $this->addType('gid', 'string'); + } + + public function jsonSerialize(): array { + return [ + 'space_id' => (int)$this->getSpaceId(), + 'gid' => $this->getGid(), + ]; + } +} diff --git a/lib/Db/GroupFoldersGroupsMapper.php b/lib/Db/GroupFoldersGroupsMapper.php index 9f7635eb7..f671533e6 100644 --- a/lib/Db/GroupFoldersGroupsMapper.php +++ b/lib/Db/GroupFoldersGroupsMapper.php @@ -32,19 +32,20 @@ class GroupFoldersGroupsMapper extends QBMapper { public function __construct(IDBConnection $db) { $this->db = $db; + $this->entityClass = ConnectedGroup::class; } /** * @return array [ - * [ - * 'space_name' => 'Space01', - * 'group_id' => 'Mars-9', - * ], - * [ - * 'space_name' => 'Space02', - * 'group_id' => 'Moon-10', - * ], - * ] + * [ + * 'space_name' => 'Space01', + * 'group_id' => 'Mars-9', + * ], + * [ + * 'space_name' => 'Space02', + * 'group_id' => 'Moon-10', + * ], + * ] */ public function getSpacenamesGroupIds() { $qb = $this->db->getQueryBuilder(); @@ -65,4 +66,45 @@ public function getSpacenamesGroupIds() { return $qb->executeQuery()->fetchAll(); } + + + /** + * @return array + */ + public function findAllAddedGroups() : array { + $qb = $this->db->getQueryBuilder(); + $query = $qb + ->select([ 'space_id', 'group_id as gid' ]) + ->from('group_folders_groups', 'gf_groups') + ->innerJoin( + 'gf_groups', + 'work_spaces', + 'ws', + $qb->expr()->eq( + 'ws.groupfolder_id', + 'gf_groups.folder_id' + ) + ) + ->where('group_id not like :wmGroup') // G and GE + ->andWhere('group_id not like :uGroup') + ->setParameter('wmGroup', 'SPACE-G%') + ->setParameter('uGroup', 'SPACE-U%'); + + return $this->findEntities($query); + } + + public function isUserConnectedGroup(string $uid): mixed { + $qb = $this->db->getQueryBuilder(); + + $query = $qb + ->select('*') + ->from('group_user') + ->where('uid = :uid') + ->setParameter('uid', $uid) + ; + + $res = $query->executeQuery(); + + return $res->fetch(); + } } diff --git a/lib/Group/AddedGroups/AddedGroups.php b/lib/Group/AddedGroups/AddedGroups.php new file mode 100644 index 000000000..8a7204b1f --- /dev/null +++ b/lib/Group/AddedGroups/AddedGroups.php @@ -0,0 +1,52 @@ + + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Workspace\Group\AddedGroups; + +use OCA\Workspace\Service\Group\ConnectedGroupsService; +use OCA\Workspace\Service\Group\GroupFormatter; + +class AddedGroups { + + public function __construct( + private ConnectedGroupsService $connectedGroupsService, + ) { + } + + public function get(array $gids): array { + $addedGroups = []; + foreach ($gids as $gid) { + $addedToGroup = $this->connectedGroupsService->getConnectedGroupsToSpaceGroup($gid); + if ($addedToGroup !== null) { + $addedGroups = array_merge($addedGroups, $addedToGroup); + } + } + + return $addedGroups; + } + + public function getGroupsFormatted(array $gids): array { + return GroupFormatter::formatGroups($this->get($gids)); + } +} diff --git a/lib/Group/Admin/AdminGroup.php b/lib/Group/Admin/AdminGroup.php index fd24df5a0..35730c08b 100644 --- a/lib/Group/Admin/AdminGroup.php +++ b/lib/Group/Admin/AdminGroup.php @@ -24,6 +24,8 @@ namespace OCA\Workspace\Group\Admin; +use OCA\Workspace\Db\Space; +use OCA\Workspace\Service\User\UserFormatter; use OCP\IGroupManager; use OCP\IUser; use Psr\Log\LoggerInterface; @@ -34,20 +36,28 @@ class AdminGroup { public const GID_PREFIX = 'SPACE-GE-'; - public function __construct(private AdminUserGroup $adminUserGroup, + public function __construct( + private AdminUserGroup $adminUserGroup, private AdminGroupManager $adminGroupManager, private LoggerInterface $logger, - private IGroupManager $groupManager) { + private UserFormatter $userFormatter, + private IGroupManager $groupManager, + ) { } - public function addUser(IUser $user, string $gid): bool { - $group = $this->adminGroupManager->get($gid); + public function addUser(IUser $user, int $spaceId): bool { + $group = $this->adminGroupManager->get(self::GID_PREFIX . $spaceId); $group->addUser($user); $this->adminUserGroup->addUser($user); return true; } + public function removeUser(IUser $user, int $spaceId): void { + $group = $this->groupManager->get(self::GID_PREFIX . $spaceId); + $group->removeUser($user); + } + /** * @return IUser[] */ @@ -55,4 +65,9 @@ public function getUsers(int $spaceId): array { $group = $this->groupManager->get(self::GID_PREFIX . $spaceId); return $group->getUsers(); } + + public function getUsersFormatted(mixed $folderInfo, Space $space): array { + $users = $this->getUsers($space->getSpaceId()); + return $this->userFormatter->formatUsers($users, $folderInfo, (string)$space->getSpaceId()); + } } diff --git a/lib/Group/SubGroups/SubGroup.php b/lib/Group/SubGroups/SubGroup.php new file mode 100644 index 000000000..ad820ec26 --- /dev/null +++ b/lib/Group/SubGroups/SubGroup.php @@ -0,0 +1,58 @@ + + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Workspace\Group\SubGroups; + +use OCA\Workspace\Service\Group\GroupFormatter; +use OCP\IGroupManager; +use Psr\Log\LoggerInterface; + +class SubGroup { + public function __construct( + private IGroupManager $groupManager, + private LoggerInterface $logger, + ) { + } + + public function get(array $gids): array { + $groups = []; + foreach ($gids as $gid) { + $group = $this->groupManager->get($gid); + if (is_null($group)) { + $this->logger->warning( + "Be careful, the $gid group is not exist in the oc_groups table." + . " But, it's present in the oc_group_folders_groups table." + . 'It necessary to recreate it with the occ command.' + ); + continue; + } + $groups[] = $group; + } + return $groups; + } + + public function getGroupsFormatted(array $gids): array { + return GroupFormatter::formatGroups($this->get($gids)); + } +} diff --git a/lib/Group/User/UserGroup.php b/lib/Group/User/UserGroup.php index 8e4f90b02..4ca57fab8 100644 --- a/lib/Group/User/UserGroup.php +++ b/lib/Group/User/UserGroup.php @@ -24,6 +24,7 @@ namespace OCA\Workspace\Group\User; +use OCP\IGroupManager; use OCP\IUser; /** @@ -32,7 +33,10 @@ class UserGroup { public const GID_PREFIX = 'SPACE-U-'; - public function __construct(private UserGroupManager $userGroupManager) { + public function __construct( + private UserGroupManager $userGroupManager, + private IGroupManager $groupManager, + ) { } public function addUser(IUser $user, string $gid): bool { @@ -41,4 +45,9 @@ public function addUser(IUser $user, string $gid): bool { return true; } + + public function count(int $spaceId): int { + $usersGroup = $this->groupManager->get($this::GID_PREFIX . $spaceId); + return $usersGroup->count(); + } } diff --git a/lib/Helper/GroupfolderHelper.php b/lib/Helper/GroupfolderHelper.php index 2f42cafc7..0bf1b22a5 100644 --- a/lib/Helper/GroupfolderHelper.php +++ b/lib/Helper/GroupfolderHelper.php @@ -81,6 +81,21 @@ public function addApplicableGroup(int $id, string $group): void { } } + /** + * Remove a group from a groupfolder. + * + * @param integer $id is the folderId of the groupfolder. + * @param string $gid correspond to the gid of group already present in groupfolder. + * @return void + */ + public function removeApplicableGroup(int $id, string $gid): void { + try { + $this->folderManager->removeApplicableGroup($id, $gid); + } catch (\Exception $e) { + throw new GroupFolderFunctionException($e->getMessage() . 'Impossible to use the removeApplicableGroup from FolderManager.'); + } + } + public function setManageACL(int $folderId, string $type, string $id, bool $manageAcl): void { try { $this->folderManager->setManageACL($folderId, $type, $id, $manageAcl); diff --git a/lib/Service/Group/ConnectedGroupsService.php b/lib/Service/Group/ConnectedGroupsService.php new file mode 100644 index 000000000..e4893cd76 --- /dev/null +++ b/lib/Service/Group/ConnectedGroupsService.php @@ -0,0 +1,163 @@ + + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Workspace\Service\Group; + +use OCA\Workspace\Db\ConnectedGroup; +use OCA\Workspace\Db\GroupFoldersGroupsMapper; +use OCA\Workspace\Db\Space; +use OCA\Workspace\Db\SpaceMapper; +use OCP\IGroup; +use OCP\IGroupManager; + +class ConnectedGroupsService { + + + private ?array $linkedSpaceGroups = null; + private array $linkedGroupsWSGroups = []; + + public function __construct( + private IGroupManager $groupManager, + private GroupFoldersGroupsMapper $mapper, + private SpaceMapper $spaceMapper, + ) { + } + + private function getLinkedSpaceGroups(): array { + if ($this->linkedSpaceGroups === null) { + $this->initLinkedSpaceGroups(); + } + return $this->linkedSpaceGroups; + } + + private function initLinkedSpaceGroups(): void { + $connectedGroups = $this->mapper->findAllAddedGroups(); + + if (empty($connectedGroups)) { + $this->linkedSpaceGroups = []; + return; + } + + $data = []; + foreach ($connectedGroups as $connectedGroup) { + $gid = 'SPACE-U-' . $connectedGroup->getSpaceId(); + $linked_gid = $connectedGroup->getGid(); + $data[$gid][] = $linked_gid; + $this->linkedGroupsWSGroups[$linked_gid][] = $gid; + } + + $this->linkedSpaceGroups = $data; + } + + /** + * @param string $gid + * @param array $spaceGids + * @return bool + */ + public function isConnectedToWorkspace(string $gid, array $spaceGids) : bool { + $linkedSpaceGroups = $this->getLinkedSpaceGroups(); + + foreach ($spaceGids as $spaceGid) { + if (isset($linkedSpaceGroups[$spaceGid])) { + return in_array($gid, $linkedSpaceGroups[$spaceGid]); + } + } + return false; + } + + /** + * @param string $gid + * @return array|null + */ + public function getConnectedSpaceToGroupIds(string $gid): ?array { + if ($this->linkedSpaceGroups === null) { + $this->initLinkedSpaceGroups(); + } + if (isset($this->linkedGroupsWSGroups[$gid])) { + return $this->linkedGroupsWSGroups[$gid]; + } + return null; + } + + /** + * @param string $spaceGid + * @return array|null + */ + public function getConnectedGroupsToSpaceGroup(string $spaceGid): ?array { + $linkedSpaceGroups = $this->getLinkedSpaceGroups(); + + if (!isset($linkedSpaceGroups[$spaceGid])) { + return null; + } + $groups = []; + foreach ($linkedSpaceGroups[$spaceGid] as $gid) { + $groups[] = $this->groupManager->get($gid); + } + return $groups; + } + + /** + * @param string $gid + * @param ?string $gidUserGroup - Specify the gid user group + * @return bool + */ + public function hasConnectedGroups(string $gid, ?string $gidUserGroup = null) : bool { + + $linkedSpaceGroups = $this->getLinkedSpaceGroups(); + + if (empty($linkedSpaceGroups)) { + return false; + } + + if (!is_null($gidUserGroup)) { + $values = $linkedSpaceGroups[$gidUserGroup]; + if (!is_null($values)) { + return in_array($gid, $values); + } + return false; + } + + return isset($linkedSpaceGroups[$gid]); + } + + /** + * @deprecated don't use this function + * @todo delete this function + */ + public function add(IGroup $group, Space $space): bool { + /* + $connectedGroup = new ConnectedGroup(); + $connectedGroup->setSpaceId($space->getSpaceId()); + $connectedGroup->setGid($group->getGid()); + + $this->mapper->insert($connectedGroup); + */ + return true; + } + + public function isUserConnectedGroup(string $uid): bool { + $res = $this->mapper->isUserConnectedGroup($uid); + return empty($res); + } +} diff --git a/lib/Service/Group/GroupFormatter.php b/lib/Service/Group/GroupFormatter.php index 4295a068e..fda2d5eca 100644 --- a/lib/Service/Group/GroupFormatter.php +++ b/lib/Service/Group/GroupFormatter.php @@ -24,19 +24,36 @@ namespace OCA\Workspace\Service\Group; +use OCA\Workspace\Service\Slugger; use OCP\IGroup; class GroupFormatter { /** * @param IGroup[] $groups + * @return array [ + * 'gid' => string, + * 'displayName' => string, + * 'types' => string[], + * 'is_ldap' => boolean + * ] */ public static function formatGroups(array $groups): array { $groupsFormat = []; foreach ($groups as $group) { + + $backendnames = $group->getBackendNames(); + $backendnames = array_map( + fn ($backendname) => strtoupper($backendname), + $backendnames + ); + $groupsFormat[$group->getGID()] = [ 'gid' => $group->getGID(), - 'displayName' => $group->getDisplayName() + 'displayName' => $group->getDisplayName(), + 'types' => $group->getBackendNames(), + 'usersCount' => $group->count(), + 'slug' => Slugger::slugger($group->getGID()) ]; } diff --git a/lib/Service/Slugger.php b/lib/Service/Slugger.php new file mode 100644 index 000000000..a232a0bed --- /dev/null +++ b/lib/Service/Slugger.php @@ -0,0 +1,24 @@ + $user->getEmailAddress(), 'subtitle' => $user->getEmailAddress(), 'groups' => $this->groupsWorkspace->getGroupsUserFromGroupfolder($user, $groupfolder, $spaceId), + 'is_connected' => $this->connectedGroupsService->isUserConnectedGroup($user->getUID()), + 'profile' => $this->urlGenerator->linkToRouteAbsolute('core.ProfilePage.index', ['targetUserId' => $user->getUID()]), 'role' => $role ]; } diff --git a/lib/Service/UserService.php b/lib/Service/UserService.php index 9948d9366..fa07a390c 100644 --- a/lib/Service/UserService.php +++ b/lib/Service/UserService.php @@ -25,9 +25,11 @@ namespace OCA\Workspace\Service; +use OCA\Workspace\Service\Group\ConnectedGroupsService; use OCA\Workspace\Service\Group\ManagersWorkspace; use OCA\Workspace\Service\Group\WorkspaceManagerGroup; use OCP\IGroupManager; +use OCP\IURLGenerator; use OCP\IUser; use OCP\IUserSession; use Psr\Log\LoggerInterface; @@ -36,7 +38,9 @@ class UserService { public function __construct( private IGroupManager $groupManager, private IUserSession $userSession, - private LoggerInterface $logger + private LoggerInterface $logger, + private ConnectedGroupsService $connectedGroups, + private IURLGenerator $urlGenerator, ) { } @@ -55,7 +59,8 @@ public function __construct( * @return array|null * */ - public function formatUser(IUser $user, array $space, string $role): array|null { + + public function formatUser(IUser $user, array $space, string $role): ?array { if (is_null($user)) { return null; } @@ -72,19 +77,20 @@ public function formatUser(IUser $user, array $space, string $role): array|null } foreach ($this->groupManager->getUserGroups($user) as $group) { - if (in_array($group->getGID(), array_keys($space['groups']))) { + if (in_array($group->getGID(), array_keys($space['groups'])) || $this->connectedGroups->isConnectedToWorkspace($group->getGID(), array_keys($space['groups']))) { array_push($groups, $group->getGID()); } } - // Returns a user that is valid for the frontend return [ 'uid' => $user->getUID(), 'name' => $user->getDisplayName(), 'email' => $user->getEmailAddress(), 'subtitle' => $user->getEmailAddress(), 'groups' => $groups, - 'role' => $role + 'role' => $role, + 'is_connected' => $this->connectedGroups->isUserConnectedGroup($user->getUID()), + 'profile' => $this->urlGenerator->linkToRouteAbsolute('core.ProfilePage.index', ['targetUserId' => $user->getUID()]) ]; } @@ -148,7 +154,7 @@ public function canRemoveWorkspaceManagers(IUser $user): bool { fn ($group) => str_starts_with($group->getGID(), 'SPACE-GE') ); - $canRemove = count($allManagersGroups) > 0 && count($allManagersGroups) <= 1 ? true : false; + $canRemove = count($allManagersGroups) >= 0 && count($allManagersGroups) <= 1 ? true : false; if (!$canRemove) { $this->logger->debug('User is still manager of other workspaces, will not remove it from the ' . ManagersWorkspace::WORKSPACES_MANAGERS . ' group.'); diff --git a/lib/Service/WorkspaceService.php b/lib/Service/WorkspaceService.php index 108d658df..45704b8b2 100644 --- a/lib/Service/WorkspaceService.php +++ b/lib/Service/WorkspaceService.php @@ -26,6 +26,8 @@ namespace OCA\Workspace\Service; use OCA\Workspace\Db\SpaceMapper; +use OCA\Workspace\Service\Group\ConnectedGroupsService; +use OCA\Workspace\Service\Group\GroupFormatter; use OCA\Workspace\Service\Group\UserGroup; use OCA\Workspace\Service\Group\WorkspaceManagerGroup; use OCA\Workspace\Share\Group\GroupMembersOnlyChecker; @@ -46,7 +48,8 @@ public function __construct( private SpaceMapper $spaceMapper, private UserService $userService, private ShareMembersOnlyFilter $shareMembersFilter, - private GroupMembersOnlyChecker $memberGroupOnlyChecker + private GroupMembersOnlyChecker $memberGroupOnlyChecker, + private ConnectedGroupsService $connectedGroups, ) { } @@ -177,11 +180,13 @@ public function addUsersInfo(string|array $workspace): \stdClass { $group = $this->groupManager->get(WorkspaceManagerGroup::get($workspace['id'])); if (!is_null($group)) { foreach ($group->getUsers() as $user) { - $users[$user->getUID()] = $this->userService->formatUser($user, $workspace, 'wm'); + if (isset($users[$user->getUID()])) { + $users[$user->getUID()] = $this->userService->formatUser($user, $workspace, 'wm'); + } }; } - return (object) $users; + return (object)$users; } /** @@ -193,15 +198,23 @@ public function addUsersInfo(string|array $workspace): \stdClass { * */ public function addGroupsInfo(array|string $workspace): array { - $groups = []; + if (!isset($workspace['groups'])) { + return $workspace; + } + $groups = array_map( + fn ($gid) => $this->groupManager->get($gid), + array_keys($workspace['groups']) + ); + $addedGroups = []; foreach (array_keys($workspace['groups']) as $gid) { - $NCGroup = $this->groupManager->get($gid); - $groups[$gid] = [ - 'gid' => $NCGroup->getGID(), - 'displayName' => $NCGroup->getDisplayName() - ]; + $addedToGroup = $this->connectedGroups->getConnectedGroupsToSpaceGroup($gid); + if ($addedToGroup !== null) { + $addedGroups = array_merge($addedGroups, $addedToGroup); + } } - $workspace['groups'] = $groups; + + $workspace['groups'] = GroupFormatter::formatGroups($groups); + $workspace['added_groups'] = GroupFormatter::formatGroups($addedGroups); return $workspace; } diff --git a/lib/Space/SpaceManager.php b/lib/Space/SpaceManager.php index 14c67d8d5..5303cfc66 100644 --- a/lib/Space/SpaceManager.php +++ b/lib/Space/SpaceManager.php @@ -30,13 +30,23 @@ use OCA\Workspace\Exceptions\CreateWorkspaceException; use OCA\Workspace\Exceptions\WorkspaceNameExistException; use OCA\Workspace\Folder\RootFolder; +use OCA\Workspace\Group\AddedGroups\AddedGroups; +use OCA\Workspace\Group\Admin\AdminGroup; +use OCA\Workspace\Group\Admin\AdminUserGroup; +use OCA\Workspace\Group\SubGroups\SubGroup; +use OCA\Workspace\Group\User\UserGroup as UserWorkspaceGroup; use OCA\Workspace\Helper\GroupfolderHelper; use OCA\Workspace\Service\ColorCode; +use OCA\Workspace\Service\Group\ConnectedGroupsService; use OCA\Workspace\Service\Group\GroupFormatter; use OCA\Workspace\Service\Group\UserGroup; use OCA\Workspace\Service\Group\WorkspaceManagerGroup; +use OCA\Workspace\Service\User\UserFormatter; +use OCA\Workspace\Service\UserService; use OCA\Workspace\Service\Workspace\WorkspaceCheckService; use OCP\AppFramework\Http; +use OCP\IGroupManager; +use Psr\Log\LoggerInterface; class SpaceManager { public function __construct( @@ -44,7 +54,17 @@ public function __construct( private RootFolder $rootFolder, private WorkspaceCheckService $workspaceCheck, private UserGroup $userGroup, + private AdminGroup $adminGroup, + private AdminUserGroup $adminUserGroup, + private AddedGroups $addedGroups, + private SubGroup $subGroup, + private UserWorkspaceGroup $userWorkspaceGroup, private SpaceMapper $spaceMapper, + private ConnectedGroupsService $connectedGroupsService, + private LoggerInterface $logger, + private UserFormatter $userFormatter, + private UserService $userService, + private IGroupManager $groupManager, private WorkspaceManagerGroup $workspaceManagerGroup, private ColorCode $colorCode, ) { @@ -123,17 +143,36 @@ public function create(string $spacename): array { 'quota' => $groupfolder['quota'], 'size' => $groupfolder['size'], 'acl' => $groupfolder['acl'], - 'manage' => $groupfolder['manage'] + 'manage' => $groupfolder['manage'], + 'userCount' => 0 ]; } public function get(int $spaceId): array { - $space = $this->spaceMapper->find($spaceId)->jsonSerialize(); - $workspace = array_merge( - $this->folderHelper->getFolder($space['groupfolder_id'], $this->rootFolder->getRootFolderStorageId()), - $space + $space = $this->spaceMapper->find($spaceId); + $groupfolder = $this->folderHelper->getFolder($space->getSpaceId(), $this->rootFolder->getRootFolderStorageId()); + + $workspace = array_merge($space->jsonSerialize(), $groupfolder); + + $folderInfo = $this->folderHelper->getFolder( + $workspace['groupfolder_id'], + $this->rootFolder->getRootFolderStorageId() ); + $workspace = ($folderInfo !== false) ? array_merge( + $folderInfo, + $workspace + ) : $workspace; + + $gids = array_keys($workspace['groups'] ?? []); + + $gids = array_filter($gids, fn ($gid) => str_starts_with($gid, 'SPACE-')); + + $workspace['userCount'] = $this->userWorkspaceGroup->count($space->getSpaceId()); + + $workspace['users'] = $this->adminGroup->getUsersFormatted($folderInfo, $space); + $workspace['groups'] = $this->subGroup->getGroupsFormatted($gids); + $workspace['added_groups'] = (object)$this->addedGroups->getGroupsFormatted($gids); return $workspace; } @@ -153,6 +192,21 @@ private function deleteBlankSpaceName(string $spaceName): string { public function remove(string $spaceId): void { $space = $this->get($spaceId); + + foreach ($this->adminGroup->getUsers($spaceId) as $user) { + if ($this->userService->canRemoveWorkspaceManagers($user)) { + $this->logger->debug('Remove user ' . $user->getUID() . ' from the Workspace Manager group in ' . $space['name']); + $this->adminUserGroup->removeUser($user); + } + } + + $groups = []; + $this->logger->debug('Removing workspace groups.'); + foreach (array_keys($space['groups']) as $group) { + $groups[] = $group; + $this->groupManager->get($group)->delete(); + } + $folderId = $space['groupfolder_id']; $this->folderHelper->removeFolder($folderId); } From 8f73fc423a818c70dde9e24db201994566a3dd3d Mon Sep 17 00:00:00 2001 From: zak39 Date: Wed, 11 Dec 2024 17:47:02 +0100 Subject: [PATCH 04/19] refactor(middleware): Retrieve spaceId from request in IsSpaceAdminMiddleware Retrieve the spaceId from the request if it is provided by the data from the controllers and check whether it is null or not. --- lib/Middleware/IsSpaceAdminMiddleware.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/Middleware/IsSpaceAdminMiddleware.php b/lib/Middleware/IsSpaceAdminMiddleware.php index 4759e778a..ffc840246 100644 --- a/lib/Middleware/IsSpaceAdminMiddleware.php +++ b/lib/Middleware/IsSpaceAdminMiddleware.php @@ -47,8 +47,15 @@ public function __construct( public function beforeController($controller, $methodName): void { if ($this->reflector->hasAnnotation('SpaceAdminRequired')) { $spaceId = $this->request->getParam('spaceId'); + if ($spaceId === null) { + $data = $this->request->getParam('data'); + $spaceId = $data ? $data['spaceId'] : null; + } + if ($spaceId === null) { + throw new AccessDeniedException(); + } $space = $this->spaceService->find($spaceId); - if (!$this->userService->isSpaceManagerOfSpace($space->jsonSerialize()) && !$this->userService->isUserGeneralAdmin()) { + if ($spaceId === null || $space === null || (!$this->userService->isSpaceManagerOfSpace($space->jsonSerialize()) && !$this->userService->isUserGeneralAdmin())) { throw new AccessDeniedException(); } } From f206389749a232c40a32b8981ce9f3e4d5ca9341 Mon Sep 17 00:00:00 2001 From: zak39 Date: Wed, 11 Dec 2024 17:48:11 +0100 Subject: [PATCH 05/19] feat(route): Create routes for added groups --- appinfo/routes.php | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/appinfo/routes.php b/appinfo/routes.php index ffa6e3dab..335b1e4ff 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -38,6 +38,21 @@ 'url' => '/', 'verb' => 'GET', ], + [ + 'name' => 'connectedGroup#addConnectedGroup', + 'url' => '/spaces/{spaceId}/connected-group', + 'verb' => 'POST' + ], + [ + 'name' => 'connectedGroup#getConnectedGroupsFromSpaceId', + 'url' => '/spaces/{spaceId}/connected-group', + 'verb' => 'GET' + ], + [ + 'name' => 'connectedGroup#getConnectedGroups', + 'url' => '/connected-group', + 'verb' => 'GET' + ], [ 'name' => 'workspace#addGroupsInfo', 'url' => '/api/workspace/formatGroups', @@ -77,6 +92,16 @@ 'url' => '/workspaces', 'verb' => 'GET' ], + [ + 'name' => 'connectedGroup#addGroup', + 'url' => '/spaces/{spaceId}/connected-groups/{gid}', + 'verb' => 'POST', + ], + [ + 'name' => 'connectedGroup#removeGroup', + 'url' => '/spaces/{spaceId}/connected-groups/{gid}', + 'verb' => 'DELETE' + ], [ 'name' => 'workspace#findAll', 'url' => '/spaces', @@ -117,6 +142,11 @@ 'url' => '/api/group/{gid}', 'verb' => 'PATCH', ], + [ + 'name' => 'group#search', + 'url' => '/groups', + 'verb' => 'GET', + ], [ 'name' => 'group#addUser', /** @@ -147,6 +177,11 @@ 'url' => '/api/group/delUser/{spaceId}', 'verb' => 'PATCH', ], + [ + 'name' => 'workspace#getUsers', + 'url' => '/spaces/{spaceId}/users', + 'verb' => 'GET', + ], [ 'name' => 'group#removeUserFromWorkspace', 'url' => '/spaces/{spaceId}/users/{user}/groups', From f00501312ac6937e5c84463f2a8ae20b6a90a200 Mon Sep 17 00:00:00 2001 From: zak39 Date: Wed, 11 Dec 2024 17:48:33 +0100 Subject: [PATCH 06/19] l10n: Translate new sentences for added groups --- l10n/cs.js | 2 +- l10n/cs.json | 2 +- l10n/en.js | 23 ++++++++++++++++++++--- l10n/fr.js | 22 +++++++++++++++++++++- l10n/fr.json | 21 ++++++++++++++++++--- 5 files changed, 61 insertions(+), 9 deletions(-) diff --git a/l10n/cs.js b/l10n/cs.js index d95022a80..7622a1b5d 100644 --- a/l10n/cs.js +++ b/l10n/cs.js @@ -9,7 +9,7 @@ OC.L10N.register( 'Error': 'Chyba', 'Please specify a name.': 'Zadejte název.', 'Caution, users highlighted in red are not yet member of this workspace. They will be automaticaly added.': 'Upozornění – červeně označení uživatelé ještě nejsou členy tohoto pracovního prostoru. Budou automaticky přidáni.', - 'Create group': 'Vytvořit skupinu', + 'Create a workspace group': 'Vytvořit skupinu', 'Delete space': 'Smazat prac. prostor', 'Delete user': 'Odebrat uživatele', 'Error 403': 'Chyba 403', diff --git a/l10n/cs.json b/l10n/cs.json index 2e1e67d6d..e2b6a20d5 100644 --- a/l10n/cs.json +++ b/l10n/cs.json @@ -7,7 +7,7 @@ "Error": "Chyba", "Please specify a name.": "Zadejte název.", "Caution, users highlighted in red are not yet member of this workspace. They will be automaticaly added.": "Upozornění – červeně označení uživatelé ještě nejsou členy tohoto pracovního prostoru. Budou automaticky přidáni.", - "Create group": "Vytvořit skupinu", + "Create a workspace group": "Vytvořit skupinu", "Delete space": "Smazat prac. prostor", "Delete user": "Odebrat uživatele", "Error 403": "Chyba 403", diff --git a/l10n/en.js b/l10n/en.js index cb120cfe1..eac3a9499 100644 --- a/l10n/en.js +++ b/l10n/en.js @@ -3,7 +3,9 @@ OC.L10N.register( { 'Workspace': 'Workspace', 'Are you sure you want to delete the {space} workspace ?': 'Are you sure you want to delete the {space} workspace ?', + 'Add': 'Add', 'Add users': 'Add users', + 'Add a group': 'Add a group', 'All spaces': 'All Workspaces', 'Administrators': 'General manager', 'admin': 'Workspace manager', @@ -15,7 +17,8 @@ OC.L10N.register( 'Unknown error': 'Unknown error', 'Error in file format': 'Error in file format', 'Caution, users highlighted in red are not yet member of this workspace. They will be automaticaly added.': 'Caution, users highlighted in red are not yet member of this workspace. They will be automaticaly added.', - 'Create group': 'Create group', + 'Create a workspace group': 'Create a workspace group', + 'Add a group': 'Add a group', 'Delete space': 'Delete Workspace', 'Search users': 'Search users', 'Delete user': 'Remove user', @@ -24,6 +27,7 @@ OC.L10N.register( 'Error in the table header': 'Error in the table header', 'The content of your file is invalid. Two columns are required, with the following header names and values:
- "user": the user\'s username or e-mail address
- "role": the user\'s role ("u" or "user" for a user and "wm" for a workspace manager)': 'The content of your file is invalid. Two columns are required, with the following header names and values:
- "user": the user\'s username or e-mail address
- "role": the user\'s role ("u" or "user" for a user and "wm" for a workspace manager)', 'This group already exists. Please, change the name': 'This group already exists. Please, change the name', + 'Remove conntected group': 'Remove conntected group', 'You aren\'t allowed to access into this application !': 'You aren\'t allowed to access into this application !', 'Only the following values are allowed: %1$s

- "wm": to define the user as a workspace manager.
- "u" or "user": to define the user as a simple user.

Check the role for these users:
%2$s': 'Only the following values are allowed: %1$s

- "wm": to define the user as a workspace manager.
- "u" or "user": to define the user as a simple user.

Check the role for these users:
%2$s', 'Error in CSV file content': 'Error in CSV file content', @@ -32,10 +36,12 @@ OC.L10N.register( 'Your CSV file must use a comma (",") as separator': 'Your CSV file must use a comma (",") as separator', 'Email': 'Emails', 'Groups': 'Groups', + 'remove group from selection': 'remove group from selection', + 'No group selected': 'No group selected', 'Duplication of groups': 'Duplication of groups', 'or': 'or', 'The group already exists.': 'The group already exists.', - 'Make administrator': 'Assign as Workspace manager', + 'Make administrator': 'Assign as WM', 'Error to rename space': 'Error to rename space', 'The space name already exist. We cannot rename with this name.': 'The space name already exist. We cannot rename with this name.', 'User doesn\'t exist': 'User doesn\'t exist', @@ -53,7 +59,7 @@ OC.L10N.register( 'Select groupfolders to convert in workspace': 'Select groupfolders to convert in workspace', 'Convert in spaces': 'Convert in spaces', 'The name space must be defined.': 'The name space must be defined.', - 'Remove admin rights': 'Remove workspace manager rights', + 'Remove admin rights': 'Remove WM rights', 'Remove user from selection': 'Remove user from selection', 'There is a problem to add group to groupfolder. The group is deleted.': 'There is a problem to add group to groupfolder. The group is deleted.', 'Rename space': 'Rename Workspace', @@ -71,6 +77,7 @@ OC.L10N.register( 'Remove from group': 'Remove from group', 'Workspace name': 'Workspace name', 'No users': 'No users', + 'Start typing text to search for groups': 'Start typing text to search for groups', 'Group name': 'Group name', 'Space name': 'Space name', 'Your Workspace name must not contain the following characters: [ ~ < > { } | ; . : , ! ? \' @ # $ + ( ) % \\\\ ^ = / & * ]': 'Your Workspace name must not contain the following characters: [ ~ < > { } | ; . : , ! ? \' @ # $ + ( ) % \\ ^ = / & * ]', @@ -85,6 +92,11 @@ OC.L10N.register( 'unlimited': 'unlimited', 'You may only specify "unlimited" or a number followed by "TB", "GB", "MB", or "KB" (eg: "5GB") as quota': 'Vous devez spécifier le terme "unlimited" ou un nombre suivi de "TB", "GB", "MB" ou "KB" (exemple: "5GB") comme quota.', 'This space or groupfolder already exist. Please, input another space.\nIf "toto" space exist, you cannot create the "tOTo" space.\nMake sure you the groupfolder doesn\'t exist.': 'This space or groupfolder already exist. Please, input another space.\nIf "toto" space exist, you cannot create the "tOTo" space.\nMake sure you the groupfolder doesn\'t exist.', + 'Please, note that once {groupname} group has been removed, its users will lose access to the {spacename} workspace': 'Please, note that once {groupname} group has been removed, its users will lose access to the {spacename} workspace', + 'Please note that after deleting the {groupname} group, its users will retain access to the {spacename} workspace': 'Please note that after deleting the {groupname} group, its users will retain access to the {spacename} workspace', + 'Confirm': 'Confirm', + 'Workspace groups': 'Workspace groups', + 'Added groups': 'Added groups', 'A network error occured while trying to create group {group}
The error is: {error}': 'A network error occured while trying to create group {group}
The error is: {error}', 'A network error occured while trying to add user {user_name} to workspaces.
The error is: {error}': 'A network error occured while trying to add user {user_name} to workspaces.
The error is: {error}', 'An error occured while trying to retrieve workspaces.
The error is: {error}': 'An error occured while trying to retrieve workspaces.
The error is: {error}', @@ -104,5 +116,10 @@ OC.L10N.register( 'Something went wrong. Couldn\'t open the file.': 'Something went wrong. Couldn\'t open the file.', 'Upload new files': 'Upload new files', 'Choose from Files': 'Choose from Files', + 'Warning, after removal of group {groupname}, its users will lose access to the nouveaux espaces workspace, with the exception of:

- Workspace Managers (WM-nouveaux espaces)
- users who are members of Groupe Workspace (prefixed G-)
- users who are members of another Added Group
- users manually added from the Workspace nouveaux espaces': 'Warning, after removal of group {groupname}, its users will lose access to the nouveaux espaces workspace, with the exception of:

- Workspace Managers (WM-nouveaux espaces)
- users who are members of Groupe Workspace (prefixed G-)
- users who are members of another Added Group
- users manually added from the Workspace nouveaux espaces', + 'Wrong file extension. Must be .csv.': 'Wrong file extension. Must be .csv.', + 'Add users from csv file': 'Ajouter à partir du fichier csv', + 'Import csv from Files': 'Importer csv à partir de Files', + 'View Profile': 'View Profile' }, 'nplurals=2; plural=(n > 1)') diff --git a/l10n/fr.js b/l10n/fr.js index 69ad85262..00d6802c1 100644 --- a/l10n/fr.js +++ b/l10n/fr.js @@ -4,12 +4,15 @@ OC.L10N.register( 'Workspace': 'Espace de travail', 'Are you sure you want to delete the {space} workspace ?': 'Êtes vous sûr de vouloir supprimer l\'espace de travail {space} ?', 'Add': 'Ajouter', + 'Add users': 'Ajouter un utilisateur', + 'Add a group': 'Ajouter un groupe', 'All spaces': 'Tous les espaces de travail', 'Administrators': 'Gestionnaires généraux', 'admin': "Gestionnaire d'espace", 'The content of your file is invalid. Two columns are required, with the following header names and values:
- "user": the user\'s username or e-mail address
- "role": the user\'s role ("u" or "user" for a user and "wm" for a workspace manager)': 'Le contenu de votre fichier est invalide. L\'en-tête ne contient pas les valeurs souhaitées.
Deux colonnes sont requises, avec les noms d\'en-têtes et valeurs suivantes :
- "user" : le nom d\'utilisateur ou l\'adresse e-mail de l\'utilisateur
- "role" : le rôle de l\'utilisateur ("u" ou "user" pour un utilisateur et "wm" pour un gestionnaire d\'espace)', 'Group name': 'Nom du groupe', 'Space name': 'Nom de l\'espace de travail', + 'Add a group': 'Ajouter un groupe', 'Cancel': 'Annuler', 'Unknown error': 'Erreur inconnue', 'You csv file must follow this structure:': 'Votre fichier csv doit respecter cette structure :', @@ -23,12 +26,17 @@ OC.L10N.register( 'or': 'ou', 'Create group': 'Créer un groupe', 'Error in CSV file content': 'Erreur dans le contenu du fichier CSV', + 'remove group from selection': 'retirer le groupe de la sélection', + 'Create a workspace group': 'Créer un groupe workspace', 'Duplication of groups': 'Duplication des groupes', 'Invalid separator for CSV file': 'Séparateur incorrect pour le fichier CSV', 'Your CSV file must use a comma (",") as separator': 'Votre fichier CSV doit utiliser une virgule (",") comme séparateur.', 'The group already exists.': 'Le groupe existe déjà.', 'Delete space': "Supprimer l'espace de travail", 'Delete user': "Retirer de l'espace de travail", + 'Please, note that once {groupname} group has been removed, its users will lose access to the {spacename} workspace': 'Attention, après le retrait du groupe {groupname}, ses utilisateurs perdront l\'accès à l\'espace de travail {spacename}', + 'Please note that after deleting the {groupname} group, its users will retain access to the {spacename} workspace': 'Attention, après la suppression du groupe {groupname}, ses utilisateurs conserveront l\'accès à l\'espace de travail {spacename}', + 'Confirm': 'Confirmer', 'Email': 'Email', 'User doesn\'t exist': 'Des utilisateurs n\'existent pas', 'Only the following values are allowed: %1$s

- "wm": to define the user as a workspace manager.
- "u" or "user": to define the user as a simple user.

Check the role for these users:
%2$s': 'Seule les valeurs suivantes sont autorisées pour le champs "role": %1$s

- "wm": pour définir le rôle de gestionnaire d\'espace.
- "u" ou "user": pour définir le rôle d\'utilisateur.

Veuillez vérifier les rôles utilisateurs suivants:
%2$s', @@ -36,6 +44,7 @@ OC.L10N.register( 'Error: unknown users': 'Erreur: utilisateurs non reconnus', '- %1$s has the %2$s role': '- %1$s a le rôle %2$s', 'The users of this CSV file are unknown and can not be imported. Check the following users and repeat the process:
': 'Les utilisateurs de ce fichier CSV ne sont pas reconnus et ne peuvent pas être importés. Veuillez vérifier les utilisateurs suivants et répéter l\'opération :
', + 'Remove conntected group': 'Retirer le groupe', 'Settings': 'Paramètres', 'This group already exists. Please, change the name': 'Ce groupe existe déjà. Changez le nom, s\'il vous plaît.', 'Groups': 'Groupes', @@ -75,6 +84,7 @@ OC.L10N.register( 'Rename space': "Renommer l'espace de travail", 'Rename group': 'Renommer le groupe', 'Delete group': 'Supprimer le groupe', + 'No group selected': 'Aucun groupe selectionné', 'Role': 'Rôle', 'WM': 'WM', 'Error 403': 'Erreur 403', @@ -90,6 +100,9 @@ OC.L10N.register( 'There are no users in this space/group yet': 'Il n\'y a pas encore d\'utilisateur dans cet espace de travail', 'Start typing to lookup users': 'Commencez à saisir du texte pour rechercher des utilisateurs', 'remove users from selection': 'retirer l\'utilisateur de la sélection', + 'Start typing text to search for groups': 'Commencez à saisir du texte pour rechercher des groupes', + 'Workspace groups': 'Groupes d\'espace de travail', + 'Added groups': 'Groupes ajoutés', 'Workspace name': "Nom de l'espace de travail", 'Error - Duplicate space name': 'Erreur - Duplication de nom de l\'espace de travail', 'Error - This workspace name already exists': 'Erreur - Ce nom d\'espace de travail existe déjà', @@ -103,6 +116,13 @@ OC.L10N.register( 'Invalid file format. Table header doesn\'t contain any of the following values:
{values}': 'Format de fichier est invalide. L\'en-tête du tableau ne contient aucune des valeurs suivantes :
{values}', 'Something went wrong. Couldn\'t open the file.': 'Quelque chose s\'est mal passé. Impossible d\'ouvrir le fichier.', 'Upload new files': 'Téléverser de nouveaux fichiers', - 'Choose from Files': 'Choisir depuis Fichiers' + 'Choose from Files': 'Choisir depuis Fichiers', + 'Wrong file extension. Must be .csv.': 'Mauvais format de fichier. Doit être .csv.', + 'Warning, after removal of group {groupname}, its users will lose access to the nouveaux espaces workspace, with the exception of:

- Workspace Managers (WM-nouveaux espaces)
- users who are members of Groupe Workspace (prefixed G-)
- users who are members of another Added Group
- users manually added from the Workspace nouveaux espaces': 'Attention, après le retrait du groupe {groupname}, les membres de ce groupe perdront l\'accès à l\'espace de travail nouveaux espaces, à l\'exception :

- des Gestionnaires d\'Espaces (WM-nouveaux espaces)
- des utilisateurs embres d\'un Groupe Workspace (préfixé G-)
- des utilisateurs membres d\'un autre Groupe Ajouté
- des utilisateurs ajoutés manuellement depuis l\'espace de travail nouveaux espaces', + 'Invalid file format. Table header doesn\'t contain any of the following values:
{values}': 'Format de fichier est invalide. L\'en-tête du tableau ne contient aucune des valeurs suivantes :
{values}', + 'Something went wrong. Couldn\'t open a file.': 'Quelque chose s\'est mal passé. Impossible d\'ouvrir un fichier.', + 'Add users from csv file': 'Ajouter à partir du fichier csv', + 'Import csv from Files': 'Importer csv à partir de Files', + 'View Profile': 'Voir le profil' }, "nplurals=2; plural=(n > 1)"); diff --git a/l10n/fr.json b/l10n/fr.json index f659f07ba..3489527c5 100644 --- a/l10n/fr.json +++ b/l10n/fr.json @@ -2,26 +2,32 @@ "Workspace": "Espace de travail", "Are you sure you want to delete the {space} workspace ?": "Êtes vous sûr de vouloir supprimer l'espace de travail {space} ?", "Add": "Ajouter", + "Add users": "Ajouter des utilisateurs", + "Add a group": "Ajouter un groupe", "All spaces": "Tous les espaces de travail", "Administrators" : "Gestionnaires généraux", "admin" : "Gestionnaire d'espace", "Cancel": "Annuler", "Caution, users highlighted in red are not yet member of this workspace. They will be automaticaly added.": "Attention, les utilisateurs surlignés en rouge ne sont pas encore membres de l'espace. Ils seront ajoutés automatiquement à ce dernier", - "Create group": "Créer un groupe", + "Create a workspace group": "Créer un groupe workspace", "Delete space" : "Supprimer l'espace de travail", "Duplication of groups": "Duplication des groupes", "The group already exists.": "Le groupe existe déjà.", "Unknown error": "Erreur inconnue", "Delete user" : "Supprimer de l'espace de travail", "Group name": "Nom du groupe", + "Remove conntected group": "Retirer le groupe", + "Please, note that once {groupname} group has been removed, its users will lose access to the {spacename} workspace": "Attention, après le retrait du groupe {groupname}, ses utilisateurs perdront l'accès à l'espace de travail {spacename}", + "Please note that after deleting the {groupname} group, its users will retain access to the {spacename} workspace": "Attention, après la suppression du groupe {groupname}, ses utilisateurs conserveront l'accès à l'espace de travail {spacename}", + "remove group from selection": "retirer le groupe de la sélection", "Space name": "Nom de l'espace de travail", "Import a .csv file": "Importer un fichier .csv", "Error in file format": "Erreur dans le format de fichier", "Search users": "Rechercher des utilisateurs", "Groups": "Groupes", "Error in the table header": "Erreur dans l'en-tête", - "Search users": "Rechercher des utilisateurs", "The content of your file is invalid. Two columns are required, with the following header names and values:
- \"user\": the user's username or e-mail address
- \"role\": the user's role (\"u\" or \"user\" for a user and \"wm\" for a workspace manager)": "Le contenu de votre fichier est invalide.
Deux colonnes sont requises, avec les noms d'en-têtes et valeurs suivantes :
- \"user\" : le nom d'utilisateur ou l'adresse e-mail de l'utilisateur
- \"role\" : le rôle de l'utilisateur (\"u\" ou \"user\" pour un utilisateur et \"wm\" pour un gestionnaire d'espace)", + "Confirm": "Confirmer", "Make administrator" : "Assigner en tant que WM", "New space" : "Créer un espace de travail", "Settings": "Paramètres", @@ -72,6 +78,7 @@ "Network error occured while trying to change the role of user {user}.
The error is: {error}": "Une erreur réseau s'est produite lors de modification du rôle de l'utilisateur {user}.
L'erreur est: {error}", "An error occured while trying to update the workspace's quota.
The error is: {error}": "Une erreur s'est produite lors de mise à jour du quota de l'espace de travail.
L'erreur est: {error}", "Network error occured while trying to update the workspace's quota.
The error is: {error}": "Une erreur réseau s'est produite lors de mise à jour du quota de l'espace de travail.
L'erreur est: {error}", + "No group selected": "Aucun groupe selectionné", "return to home": "retourner à l'accueil", "Rename group": "Renommer le groupe", "Delete group": "Supprimer le groupe", @@ -81,14 +88,19 @@ "Space administrators" : "Gestionnaires d'espace de travail", "Users" : "Utilisateurs", "user" : "utilisateur", + "Start typing text to search for groups": "Commencez à saisir du texte pour rechercher des groupes", "Workspace name" : "Nom de l'espace de travail", "Remove from group": "Retirer du groupe", "No users": "Pas d'utilisateur", "Add users": "Ajouter des utilisateurs", "Your Workspace name must not contain the following characters: [ ~ < > { } | ; . : , ! ? ' @ # $ + ( ) % \\\\ ^ = / & * ]": "Le nom de votre Espace de travail ne doit pas contenir les caractères suivants : [ ~ < > { } | ; . : , ! ? ' @ # $ + ( ) % \\\\ ^ = / & * ]", + "Add a group": "Ajouter un groupe", "No spaces": "Aucun espace de travail", "You have not yet created any workspace": "Vous n'avez pas encore créé d'espace de travail", "unlimited": "unlimited", + "Workspace groups": "Groupes d'espace de travail", + "Added groups": "Groupes ajoutés", + "Warning, after removal of group {groupname}, its users will lose access to the nouveaux espaces workspace, with the exception of:

- Workspace Managers (WM-nouveaux espaces)
- users who are members of Groupe Workspace (prefixed G-)
- users who are members of another Added Group
- users manually added from the Workspace nouveaux espaces": "Attention, après le retrait du groupe {groupname}, les membres de ce groupe perdront l'accès à l'espace de travail nouveaux espaces, à l'exception :

- des Gestionnaires d'Espaces (WM-nouveaux espaces)
- des utilisateurs embres d'un Groupe Workspace (préfixé G-)
- des utilisateurs membres d'un autre Groupe Ajouté
- des utilisateurs ajoutés manuellement depuis l'espace de travail nouveaux espaces", "You may only specify \"unlimited\" or a number followed by \"TB\", \"GB\", \"MB\", or \"KB\" (eg: \"5GB\") as quota": "Vous devez spécifier le terme \"unlimited\" ou un nombre suivi de \"TB\", \"GB\", \"MB\" ou \"KB\" (exemple: \"5GB\") comme quota.", "There are no users in this space/group yet": "Il n'y a pas encore d'utilisateur dans cet espace de travail", "Start typing to lookup users": "Commencez à saisir du texte pour rechercher des utilisateurs", @@ -97,7 +109,10 @@ "Invalid file format. Table header doesn't contain any of the following values:
{values}": "Format de fichier est invalide. L'en-tête du tableau ne contient aucune des valeurs suivantes :
{values}", "Something went wrong. Couldn't open the file.": "Quelque chose s'est mal passé. Impossible d'ouvrir le fichier.", "Upload new files": "Téléverser de nouveaux fichiers", - "Choose from Files": "Choisir depuis Fichiers" + "Choose from Files": "Choisir depuis Fichiers", + "Add users from csv file": "Ajouter à partir du fichier csv", + "Import csv from Files": "Importer csv à partir de Files", + "View Profile": "Voir le profil" }, "pluralForm" : "nplurals=2; plural=(n > 1);" } From a28c2727162ee053ecbd8761307cadea06d7b010 Mon Sep 17 00:00:00 2001 From: zak39 Date: Wed, 11 Dec 2024 17:49:01 +0100 Subject: [PATCH 07/19] style: Add a new icon for the added group --- css/workspace-style.css | 6 ++++++ img/added_group_black.svg | 9 +++++++++ 2 files changed, 15 insertions(+) create mode 100644 img/added_group_black.svg diff --git a/css/workspace-style.css b/css/workspace-style.css index cc269767c..a1d2e6eea 100644 --- a/css/workspace-style.css +++ b/css/workspace-style.css @@ -92,3 +92,9 @@ .workspace-sidebar .icon-collapse { visibility: visible !important; } + +.icon-added-group, .icon-added-group-dark { + background-image: url('../img/added_group_black.svg'); + min-width: 42px; + min-height: 42px; +} diff --git a/img/added_group_black.svg b/img/added_group_black.svg new file mode 100644 index 000000000..267d7cfca --- /dev/null +++ b/img/added_group_black.svg @@ -0,0 +1,9 @@ + + + Added Group + + + + + + From ed1183ed9b68573905367cc81ac802f8368124db Mon Sep 17 00:00:00 2001 From: zak39 Date: Wed, 11 Dec 2024 17:49:57 +0100 Subject: [PATCH 08/19] feat: Render the added groups on the fron-end --- src/AlertRemoveGroup.vue | 71 ++++++++ src/GroupDetails.vue | 114 +++++++++++-- src/GroupMenuItem.vue | 22 ++- src/LeftSidebar.vue | 3 +- src/LoadingUsers.vue | 45 +++++ src/MenuItemSelector.vue | 86 ++++++++++ src/RemoveSpace.vue | 97 ++++++----- src/SelectConnectedGroups.vue | 250 ++++++++++++++++++++++++++++ src/SpaceDetails.vue | 38 ++++- src/SpaceMenuItem.vue | 114 +++++++++++-- src/SpaceTable.vue | 3 + src/UserTable.vue | 135 +++++++++++---- src/WorkspaceContent.vue | 17 +- src/router.js | 2 +- src/services/groupfoldersService.js | 3 +- src/services/spaceService.js | 11 ++ src/store/actions.js | 128 +++++++++++++- src/store/getters.js | 36 +++- src/store/index.js | 2 + src/store/mutations.js | 74 +++++++- 20 files changed, 1119 insertions(+), 132 deletions(-) create mode 100644 src/AlertRemoveGroup.vue create mode 100644 src/LoadingUsers.vue create mode 100644 src/MenuItemSelector.vue create mode 100644 src/SelectConnectedGroups.vue diff --git a/src/AlertRemoveGroup.vue b/src/AlertRemoveGroup.vue new file mode 100644 index 000000000..ce472acd0 --- /dev/null +++ b/src/AlertRemoveGroup.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/src/GroupDetails.vue b/src/GroupDetails.vue index c5fc36b4d..d3c9d3543 100644 --- a/src/GroupDetails.vue +++ b/src/GroupDetails.vue @@ -21,16 +21,16 @@ --> diff --git a/src/LeftSidebar.vue b/src/LeftSidebar.vue index 575925169..1e9775b46 100644 --- a/src/LeftSidebar.vue +++ b/src/LeftSidebar.vue @@ -26,7 +26,7 @@ :title="t('workspace', 'New space')" @new-item="createSpace" /> diff --git a/src/SpaceTable.vue b/src/SpaceTable.vue index ea2e42107..0a4b5aa31 100644 --- a/src/SpaceTable.vue +++ b/src/SpaceTable.vue @@ -104,6 +104,9 @@ export default { this.$router.push({ path: `/workspace/${name}`, }) + + const space = this.$store.state.spaces[this.$route.params.space] + this.$store.dispatch('loadUsers', { space }) }, }, } diff --git a/src/UserTable.vue b/src/UserTable.vue index a22f252dd..da5106ab5 100644 --- a/src/UserTable.vue +++ b/src/UserTable.vue @@ -60,32 +60,44 @@ {{ user.groups.map(group => $store.getters.groupName($route.params.space, group)).join(', ') }} - + @@ -96,6 +108,7 @@ {{ t('workspace', 'There are no users in this space/group yet') }} + @@ -105,6 +118,9 @@ import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js' import NcAvatar from '@nextcloud/vue/dist/Components/NcAvatar.js' import NcEmptyContent from '@nextcloud/vue/dist/Components/NcEmptyContent.js' import UserGroup from './services/Groups/UserGroup.js' +import AccountCog from 'vue-material-design-icons/AccountCog.vue' +import Close from 'vue-material-design-icons/Close.vue' +import ManagerGroup from './services/Groups/ManagerGroup.js' export default { name: 'UserTable', @@ -113,6 +129,8 @@ export default { NcActions, NcActionButton, NcEmptyContent, + AccountCog, + Close, }, data() { return { @@ -125,8 +143,8 @@ export default { users() { let result = [] const space = this.$store.state.spaces[this.$route.params.space] - const group = this.$route.params.group - if (this.$route.params.group !== undefined) { + const group = decodeURIComponent(this.$route.params.slug) + if (this.$route.params.slug !== undefined) { // We are showing a group's users, so we have to filter the users result = Object.values(space.users) .filter((user) => user.groups.includes(group)) @@ -146,6 +164,9 @@ export default { } }) }, + isAddedGroup() { + return this.$store.getters.isSpaceAddedGroup(this.$route.params.space, decodeURIComponent(this.$route.params.slug)) + }, }, methods: { sortGroups(groups) { @@ -181,27 +202,81 @@ export default { // Removes a user from a workspace deleteUser(user) { const space = this.$store.state.spaces[this.$route.params.space] + const gid = decodeURIComponent(decodeURIComponent(this.$route.params.slug)) this.$store.dispatch('removeUserFromWorkspace', { name: this.$route.params.space, gid: UserGroup.getGid(space), user, }) + this.$store.dispatch('decrementGroupUserCount', { + spaceName: this.$route.params.space, + gid: UserGroup.getGid(space) + }) + if (user.role === 'admin') { + this.$store.dispatch('decrementGroupUserCount', { + spaceName: this.$route.params.space, + gid: ManagerGroup.getGid(space) + }) + } + if (gid !== undefined && gid.startsWith('SPACE-G-')) { + this.$store.dispatch('decrementGroupUserCount', { + spaceName: this.$route.params.space, + gid + }) + } + this.$store.dispatch('decrementSpaceUserCount', { + spaceName: this.$route.params.space, + }) }, // Makes user an admin or a simple user toggleUserRole(user) { + const name = this.$route.params.space + const space = this.$store.state.spaces[name] this.$store.dispatch('toggleUserRole', { - name: this.$route.params.space, + name, user, }) + if (user.is_connected) { + this.$store.commit('TOGGLE_USER_CONNECTED', { name, user }) + this.$store.dispatch('addUserToGroup', { + name, + gid: UserGroup.getGid(space), + user, + }) + } }, // Removes a user from a group removeFromGroup(user) { + const gid = decodeURIComponent(this.$route.params.slug) + const space = this.$store.state.spaces[this.$route.params.space] this.$store.dispatch('removeUserFromGroup', { name: this.$route.params.space, - gid: this.$route.params.group, + gid, user, }) + this.$store.dispatch('decrementGroupUserCount', { + spaceName: this.$route.params.space, + gid + }) + if (gid.startsWith('SPACE-GE')) { + this.$store.dispatch('decrementGroupUserCount', { + spaceName: this.$route.params.space, + gid: ManagerGroup.getGid(space) + }) + } + if (gid.startsWith('SPACE-U')) { + this.$store.dispatch('decrementGroupUserCount', { + spaceName: this.$route.params.space, + gid: UserGroup.getGid(space) + }) + this.$store.dispatch('decrementSpaceUserCount', { + spaceName: this.$route.params.space, + }) + } }, + viewProfile(user) { + window.location.href = user.profile + } }, } diff --git a/src/WorkspaceContent.vue b/src/WorkspaceContent.vue index a40b69c78..93b86fba0 100644 --- a/src/WorkspaceContent.vue +++ b/src/WorkspaceContent.vue @@ -22,12 +22,10 @@ - @@ -154,11 +153,11 @@ export default { } return result.sort((firstUser, secondUser) => { - const roleFirstUser = this.$store.getters.isSpaceAdmin(firstUser, this.$route.params.space) ? 'admin' : 'user' - const roleSecondUser = this.$store.getters.isSpaceAdmin(secondUser, this.$route.params.space) ? 'admin' : 'user' + const roleFirstUser = this.$store.getters.isSpaceAdmin(firstUser, this.$route.params.space) ? 'wm' : 'user' + const roleSecondUser = this.$store.getters.isSpaceAdmin(secondUser, this.$route.params.space) ? 'wm' : 'user' if (roleFirstUser !== roleSecondUser) { // display admins first - return roleFirstUser === 'admin' ? -1 : 1 + return roleFirstUser === 'wm' ? -1 : 1 } else { return firstUser.name.localeCompare(secondUser.name) } @@ -212,7 +211,7 @@ export default { spaceName: this.$route.params.space, gid: UserGroup.getGid(space) }) - if (user.role === 'admin') { + if (user.role === 'wm') { this.$store.dispatch('decrementGroupUserCount', { spaceName: this.$route.params.space, gid: ManagerGroup.getGid(space) diff --git a/src/store/actions.js b/src/store/actions.js index 64a11cbe5..58dbf9ae2 100644 --- a/src/store/actions.js +++ b/src/store/actions.js @@ -297,7 +297,7 @@ export default { context.commit('CHANGE_USER_ROLE', { spaceName: space.name, user, - role: 'admin', + role: 'wm', }) } const spaceId = space.id From 604b5c675feef881a4719e53603f3bd73806abec Mon Sep 17 00:00:00 2001 From: zak39 Date: Mon, 16 Dec 2024 16:53:59 +0100 Subject: [PATCH 14/19] fix(vue): Use $route.params.slug instead of $route.params.group --- src/AddUsersTabs.vue | 4 ++-- src/ButtonUploadLocalFile.vue | 4 ++-- src/ButtonUploadShareFiles.vue | 4 ++-- src/MultiSelectUsers.vue | 5 +++-- src/UserCard.vue | 3 ++- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/AddUsersTabs.vue b/src/AddUsersTabs.vue index 2e743a59e..d68c7a281 100644 --- a/src/AddUsersTabs.vue +++ b/src/AddUsersTabs.vue @@ -70,13 +70,13 @@ -

diff --git a/src/ButtonUploadLocalFile.vue b/src/ButtonUploadLocalFile.vue index 0c3bc002f..eaa141cfa 100644 --- a/src/ButtonUploadLocalFile.vue +++ b/src/ButtonUploadLocalFile.vue @@ -96,14 +96,14 @@ export default { // When adding users to a space, show only those users who are not already member of the space filterAlreadyPresentUsers(recvUsers) { let users = [] - if (this.$route.params.group === undefined) { + if (this.$route.params.slug === undefined) { const space = this.$store.state.spaces[this.$route.params.space] users = recvUsers.filter(user => { return (!(user.uid in space.users)) }, space) } else { users = recvUsers.filter(user => { - return (!(user.groups.includes(this.$route.params.group))) + return (!(user.groups.includes(decodeURIComponent(decodeURIComponent(this.$route.params.slug))))) }) } // Filters user that are already selected diff --git a/src/ButtonUploadShareFiles.vue b/src/ButtonUploadShareFiles.vue index 81b8bc38e..57bec05d1 100644 --- a/src/ButtonUploadShareFiles.vue +++ b/src/ButtonUploadShareFiles.vue @@ -88,14 +88,14 @@ export default { // When adding users to a space, show only those users who are not already member of the space filterAlreadyPresentUsers(recvUsers) { let users = [] - if (this.$route.params.group === undefined) { + if (this.$route.params.slug === undefined) { const space = this.$store.state.spaces[this.$route.params.space] users = recvUsers.filter(user => { return (!(user.uid in space.users)) }, space) } else { users = recvUsers.filter(user => { - return (!(user.groups.includes(this.$route.params.group))) + return (!(user.groups.includes(decodeURIComponent(decodeURIComponent(this.$route.params.slug))))) }) } // Filters user that are already selected diff --git a/src/MultiSelectUsers.vue b/src/MultiSelectUsers.vue index ab8f47c34..e7b6f52c6 100644 --- a/src/MultiSelectUsers.vue +++ b/src/MultiSelectUsers.vue @@ -110,14 +110,15 @@ export default { // When adding users to a space, show only those users who are not already member of the space filterAlreadyPresentUsers(recvUsers) { let users = [] - if (this.$route.params.group === undefined) { + const group = this.$route.params.slug + if (group === undefined) { const space = this.$store.state.spaces[this.$route.params.space] users = recvUsers.filter(user => { return (!(user.uid in space.users)) }, space) } else { users = recvUsers.filter(user => { - return (!(user.groups.includes(this.$route.params.group))) + return (!(user.groups.includes(group))) }) } // Filters user that are already selected diff --git a/src/UserCard.vue b/src/UserCard.vue index fa026885a..603ac1186 100644 --- a/src/UserCard.vue +++ b/src/UserCard.vue @@ -29,10 +29,11 @@

-
+
{{ t('workspace', 'WM') }} From 584eb5188b4d1abc94b98bf756528c29747136dc Mon Sep 17 00:00:00 2001 From: zak39 Date: Mon, 16 Dec 2024 17:03:32 +0100 Subject: [PATCH 15/19] fix: Add 'added_groups' key when creating a workspace --- lib/Space/SpaceManager.php | 1 + src/LeftSidebar.vue | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/Space/SpaceManager.php b/lib/Space/SpaceManager.php index 5303cfc66..c2d72ebed 100644 --- a/lib/Space/SpaceManager.php +++ b/lib/Space/SpaceManager.php @@ -140,6 +140,7 @@ public function create(string $spacename): array { $newSpaceManagerGroup, $newSpaceUsersGroup ]), + 'added_groups' => (object)[], 'quota' => $groupfolder['quota'], 'size' => $groupfolder['size'], 'acl' => $groupfolder['acl'], diff --git a/src/LeftSidebar.vue b/src/LeftSidebar.vue index 1e9775b46..d53bd33fa 100644 --- a/src/LeftSidebar.vue +++ b/src/LeftSidebar.vue @@ -95,6 +95,7 @@ export default { this.$store.commit('addSpace', { color: workspace.color, groups: workspace.groups, + added_groups: workspace.added_groups, isOpen: false, id: workspace.id_space, groupfolderId: workspace.folder_id, From f3c1be837f71f7cef3d6610c625dd6efd7a3430d Mon Sep 17 00:00:00 2001 From: zak39 Date: Mon, 16 Dec 2024 17:04:53 +0100 Subject: [PATCH 16/19] refactor: Add is_connected and profile keys when formatting a user --- lib/Users/UserFormatter.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/Users/UserFormatter.php b/lib/Users/UserFormatter.php index 2374c724e..39e58c9af 100644 --- a/lib/Users/UserFormatter.php +++ b/lib/Users/UserFormatter.php @@ -2,11 +2,17 @@ namespace OCA\Workspace\Users; +use OCA\Workspace\Service\Group\ConnectedGroupsService; use OCP\IGroupManager; +use OCP\IURLGenerator; use OCP\IUser; class UserFormatter { - public function __construct(private IGroupManager $groupManager) { + public function __construct( + private IGroupManager $groupManager, + private ConnectedGroupsService $connectedGroupsService, + private IURLGenerator $urlGenerator + ) { } /** @@ -32,6 +38,8 @@ public function formatUser(IUser $user, array $space, string $role): array { 'email' => $user->getEmailAddress(), 'subtitle' => $user->getEmailAddress(), 'groups' => $groups, + 'is_connected' => $this->connectedGroupsService->isUserConnectedGroup($user->getUID()), + 'profile' => $this->urlGenerator->linkToRouteAbsolute('core.ProfilePage.index', ['targetUserId' => $user->getUID()]), 'role' => $role ]; } From 4347f80707be1448244460b855dc83bff67ff7bd Mon Sep 17 00:00:00 2001 From: zak39 Date: Mon, 16 Dec 2024 17:28:14 +0100 Subject: [PATCH 17/19] style: run composer cs:fix --- lib/Space/SpaceManager.php | 2 +- lib/Users/UserFormatter.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Space/SpaceManager.php b/lib/Space/SpaceManager.php index c2d72ebed..6dcbe735d 100644 --- a/lib/Space/SpaceManager.php +++ b/lib/Space/SpaceManager.php @@ -140,7 +140,7 @@ public function create(string $spacename): array { $newSpaceManagerGroup, $newSpaceUsersGroup ]), - 'added_groups' => (object)[], + 'added_groups' => (object)[], 'quota' => $groupfolder['quota'], 'size' => $groupfolder['size'], 'acl' => $groupfolder['acl'], diff --git a/lib/Users/UserFormatter.php b/lib/Users/UserFormatter.php index 39e58c9af..97696596c 100644 --- a/lib/Users/UserFormatter.php +++ b/lib/Users/UserFormatter.php @@ -9,10 +9,10 @@ class UserFormatter { public function __construct( - private IGroupManager $groupManager, - private ConnectedGroupsService $connectedGroupsService, - private IURLGenerator $urlGenerator - ) { + private IGroupManager $groupManager, + private ConnectedGroupsService $connectedGroupsService, + private IURLGenerator $urlGenerator, + ) { } /** From 3c5103b5750d9140d4dbc97c16aa80a7e157ab9d Mon Sep 17 00:00:00 2001 From: zak39 Date: Mon, 16 Dec 2024 17:28:59 +0100 Subject: [PATCH 18/19] style(vue,js): Run eslint --ext .js,.vue src --fix --- src/AddUsersTabs.vue | 20 ++--- src/AlertRemoveGroup.vue | 12 +-- src/ButtonUploadLocalFile.vue | 2 +- src/GroupDetails.vue | 21 +++-- src/GroupMenuItem.vue | 8 +- src/LeftSidebar.vue | 4 +- src/LoadingUsers.vue | 12 +-- src/MenuItemSelector.vue | 2 +- src/MultiSelectUsers.vue | 2 +- src/RemoveSpace.vue | 36 ++++----- src/SelectConnectedGroups.vue | 8 +- src/SpaceDetails.vue | 8 +- src/SpaceMenuItem.vue | 10 +-- src/UserTable.vue | 90 +++++++++++----------- src/WorkspaceContent.vue | 6 +- src/services/groupfoldersService.js | 2 +- src/services/spaceService.js | 9 +++ src/store/actions.js | 12 +-- src/store/mutations.js | 6 +- src/tests/unit/groupfoldersService.test.js | 14 ++-- src/tests/unit/store.test.js | 8 +- src/tests/unit/workspaceContent.test.js | 6 +- 22 files changed, 155 insertions(+), 143 deletions(-) diff --git a/src/AddUsersTabs.vue b/src/AddUsersTabs.vue index d68c7a281..818770c65 100644 --- a/src/AddUsersTabs.vue +++ b/src/AddUsersTabs.vue @@ -191,7 +191,7 @@ export default { } }) }, - addUserFromWorkspace(user, space) { + addUserFromWorkspace(user, space) { let gid = '' if (user.role === 'wm') { gid = ManagerGroup.getGid(space) @@ -205,7 +205,7 @@ export default { }) this.$store.dispatch('incrementGroupUserCount', { spaceName: this.$route.params.space, - gid + gid, }) this.$store.dispatch('incrementSpaceUserCount', { spaceName: this.$route.params.space, @@ -213,14 +213,14 @@ export default { if (user.role === 'wm') { this.$store.dispatch('incrementGroupUserCount', { spaceName: this.$route.params.space, - gid: UserGroup.getGid(space) + gid: UserGroup.getGid(space), }) } }, addExistingUserFromSubgroup(user) { this.$store.dispatch('incrementGroupUserCount', { spaceName: this.$route.params.space, - gid: decodeURIComponent(decodeURIComponent(this.$route.params.slug)) + gid: decodeURIComponent(decodeURIComponent(this.$route.params.slug)), }) this.$store.dispatch('addUserToGroup', { name: this.$route.params.space, @@ -236,14 +236,14 @@ export default { }) this.$store.dispatch('incrementGroupUserCount', { spaceName: this.$route.params.space, - gid: decodeURIComponent(decodeURIComponent(this.$route.params.slug)) + gid: decodeURIComponent(decodeURIComponent(this.$route.params.slug)), }) this.$store.dispatch('incrementSpaceUserCount', { spaceName: this.$route.params.space, }) this.$store.dispatch('incrementGroupUserCount', { spaceName: this.$route.params.space, - gid: UserGroup.getGid(space) + gid: UserGroup.getGid(space), }) if (user.role === 'wm') { this.$store.dispatch('addUserToGroup', { @@ -253,7 +253,7 @@ export default { }) this.$store.dispatch('incrementGroupUserCount', { spaceName: this.$route.params.space, - gid: ManagerGroup.getGid(space) + gid: ManagerGroup.getGid(space), }) } }, @@ -266,7 +266,7 @@ export default { }) this.$store.dispatch('incrementGroupUserCount', { spaceName: this.$route.params.space, - gid: decodeURIComponent(decodeURIComponent(this.$route.params.slug)) + gid: decodeURIComponent(decodeURIComponent(this.$route.params.slug)), }) if (usersBackup.includes(user.uid)) { return @@ -281,7 +281,7 @@ export default { }) this.$store.dispatch('incrementGroupUserCount', { spaceName: this.$route.params.space, - gid: UserGroup.getGid(space) + gid: UserGroup.getGid(space), }) }, addUserFromUserGroup(user) { @@ -292,7 +292,7 @@ export default { }) this.$store.dispatch('incrementGroupUserCount', { spaceName: this.$route.params.space, - gid: decodeURIComponent(decodeURIComponent(this.$route.params.slug)) + gid: decodeURIComponent(decodeURIComponent(this.$route.params.slug)), }) this.$store.dispatch('incrementSpaceUserCount', { spaceName: this.$route.params.space, diff --git a/src/AlertRemoveGroup.vue b/src/AlertRemoveGroup.vue index ce472acd0..89555355d 100644 --- a/src/AlertRemoveGroup.vue +++ b/src/AlertRemoveGroup.vue @@ -3,13 +3,13 @@ size="normal">
-

+

+ @click="cancel()"> @@ -17,7 +17,7 @@ + @click="removeGroup()"> @@ -37,7 +37,7 @@ export default { components: { NcButton, NcNoteCard, - NcModal + NcModal, }, props: { message: { @@ -51,8 +51,8 @@ export default { }, removeGroup() { this.$emit('remove-group') - } - } + }, + }, } diff --git a/src/ButtonUploadLocalFile.vue b/src/ButtonUploadLocalFile.vue index eaa141cfa..c4238490c 100644 --- a/src/ButtonUploadLocalFile.vue +++ b/src/ButtonUploadLocalFile.vue @@ -70,7 +70,7 @@ export default { try { const users = await this.$store.dispatch('addUsersFromCSV', { formData: bodyFormData, - spaceId: space.id + spaceId: space.id, }) let usersToDisplay = this.filterAlreadyPresentUsers(users) usersToDisplay = this.addSubtitleToUsers(usersToDisplay) diff --git a/src/GroupDetails.vue b/src/GroupDetails.vue index d3c9d3543..87ccf94cf 100644 --- a/src/GroupDetails.vue +++ b/src/GroupDetails.vue @@ -76,7 +76,7 @@ @cancel="closeConnectedGroupModal" @remove-group="removeConnectedGroup" />
@@ -92,7 +92,6 @@ import NcModal from '@nextcloud/vue/dist/Components/NcModal.js' import AddUsersTabs from './AddUsersTabs.vue' import UserGroup from './services/Groups/UserGroup.js' import UserTable from './UserTable.vue' -import ManagerGroup from './services/Groups/ManagerGroup.js' export default { name: 'GroupDetails', @@ -118,11 +117,11 @@ export default { isAddedGroup() { return this.$store.getters.isSpaceAddedGroup(this.$route.params.space, decodeURIComponent(this.$route.params.slug)) }, - connectedGroupMessage() { - const text = t('workspace', 'Warning, after removal of group :{groupname}', { groupname: 'aaaa'}) - console.debug('text', text) - return 'Warning, after removal of group :aaaa' - }, + connectedGroupMessage() { + const text = t('workspace', 'Warning, after removal of group :{groupname}', { groupname: 'aaaa' }) + console.debug('text', text) + return 'Warning, after removal of group :aaaa' + }, }, mounted() { const space = this.$store.state.spaces[this.$route.params.space] @@ -163,19 +162,19 @@ export default { this.$store.dispatch('substractionSpaceUserCount', { spaceName: space.name, - usersCount + usersCount, }) this.$store.dispatch('substractionGroupUserCount', { spaceName: space.name, gid: UserGroup.getGid(space), - usersCount + usersCount, }) this.$store.dispatch('removeConnectedGroup', { spaceId: space.id, gid, - name: space.name + name: space.name, }) Object.keys(space.users).forEach(key => { @@ -185,7 +184,7 @@ export default { this.$store.commit('removeUserFromWorkspace', { name: space.name, user: space.users[key] }) } else { this.$store.commit('removeUserFromGroup', { name: space.name, gid, user: space.users[key] }) - } + } } }) diff --git a/src/GroupMenuItem.vue b/src/GroupMenuItem.vue index 78ff58cc1..83bb250a9 100644 --- a/src/GroupMenuItem.vue +++ b/src/GroupMenuItem.vue @@ -19,9 +19,6 @@ export default { NcAppNavigationItem, NcCounterBubble, }, - beforeMount() { - console.debug('Voici le groupe', this.group) - }, props: { group: { type: Object, @@ -40,7 +37,10 @@ export default { type: Number, required: true, default: 0, - } + }, + }, + beforeMount() { + console.debug('Voici le groupe', this.group) }, } diff --git a/src/LeftSidebar.vue b/src/LeftSidebar.vue index d53bd33fa..1a795ac6a 100644 --- a/src/LeftSidebar.vue +++ b/src/LeftSidebar.vue @@ -95,14 +95,14 @@ export default { this.$store.commit('addSpace', { color: workspace.color, groups: workspace.groups, - added_groups: workspace.added_groups, + added_groups: workspace.added_groups, isOpen: false, id: workspace.id_space, groupfolderId: workspace.folder_id, name, quota: t('workspace', 'unlimited'), users: {}, - userCount: workspace.userCount + userCount: workspace.userCount, }) this.$router.push({ path: `/workspace/${name}`, diff --git a/src/LoadingUsers.vue b/src/LoadingUsers.vue index ae7e54bff..5bb1550c0 100644 --- a/src/LoadingUsers.vue +++ b/src/LoadingUsers.vue @@ -4,7 +4,7 @@ - @@ -132,7 +136,7 @@ export default { NcActionButton, NcActionInput, NcColorPicker, - NcModal, + NcModal, NcMultiselect, SelectConnectedGroups, RemoveSpace, diff --git a/src/SpaceMenuItem.vue b/src/SpaceMenuItem.vue index 826e158d3..43c566681 100644 --- a/src/SpaceMenuItem.vue +++ b/src/SpaceMenuItem.vue @@ -25,8 +25,8 @@ :allow-collapse="true" :open="$route.params.space === spaceName" :name="spaceName" - @click="loadUsers(spaceName)" - :to="{path: `/workspace/${spaceName}`}"> + :to="{path: `/workspace/${spaceName}`}" + @click="loadUsers(spaceName)"> {{ $store.getters.getSpaceUserCount(spaceName) }} @@ -67,11 +67,11 @@ - {{ t('workspace', 'Add a group')}} + {{ t('workspace', 'Add a group') }} - + diff --git a/src/UserTable.vue b/src/UserTable.vue index 3b8b0c846..6d1e10f06 100644 --- a/src/UserTable.vue +++ b/src/UserTable.vue @@ -60,44 +60,44 @@ {{ user.groups.map(group => $store.getters.groupName($route.params.space, group)).join(', ') }} - + @@ -209,18 +209,18 @@ export default { }) this.$store.dispatch('decrementGroupUserCount', { spaceName: this.$route.params.space, - gid: UserGroup.getGid(space) + gid: UserGroup.getGid(space), }) if (user.role === 'wm') { this.$store.dispatch('decrementGroupUserCount', { spaceName: this.$route.params.space, - gid: ManagerGroup.getGid(space) + gid: ManagerGroup.getGid(space), }) } if (gid !== undefined && gid.startsWith('SPACE-G-')) { this.$store.dispatch('decrementGroupUserCount', { spaceName: this.$route.params.space, - gid + gid, }) } this.$store.dispatch('decrementSpaceUserCount', { @@ -255,18 +255,18 @@ export default { }) this.$store.dispatch('decrementGroupUserCount', { spaceName: this.$route.params.space, - gid + gid, }) if (gid.startsWith('SPACE-GE')) { this.$store.dispatch('decrementGroupUserCount', { spaceName: this.$route.params.space, - gid: ManagerGroup.getGid(space) + gid: ManagerGroup.getGid(space), }) } if (gid.startsWith('SPACE-U')) { this.$store.dispatch('decrementGroupUserCount', { spaceName: this.$route.params.space, - gid: UserGroup.getGid(space) + gid: UserGroup.getGid(space), }) this.$store.dispatch('decrementSpaceUserCount', { spaceName: this.$route.params.space, @@ -275,7 +275,7 @@ export default { }, viewProfile(user) { window.location.href = user.profile - } + }, }, } diff --git a/src/WorkspaceContent.vue b/src/WorkspaceContent.vue index 93b86fba0..42c7ab6df 100644 --- a/src/WorkspaceContent.vue +++ b/src/WorkspaceContent.vue @@ -23,9 +23,9 @@
- - - + + +
diff --git a/src/services/groupfoldersService.js b/src/services/groupfoldersService.js index 47a2c656f..0f148896f 100644 --- a/src/services/groupfoldersService.js +++ b/src/services/groupfoldersService.js @@ -296,7 +296,7 @@ export function rename(workspace, newSpaceName) { { workspace, newSpaceName, - spaceId: workspace.id + spaceId: workspace.id, }) .then(resp => { // If space is updated... diff --git a/src/services/spaceService.js b/src/services/spaceService.js index 581a86af9..0a7336a8a 100644 --- a/src/services/spaceService.js +++ b/src/services/spaceService.js @@ -58,6 +58,10 @@ export function createSpace(spaceName, vueInstance = undefined) { return result } +/** + * + * @param spaceId + */ export function getUsers(spaceId) { const result = axios.get(generateUrl(`/apps/workspace/spaces/${spaceId}/users`)) .then(resp => { @@ -155,6 +159,11 @@ export function removeWorkspace(spaceId) { return result } +/** + * + * @param spaceId + * @param newSpaceName + */ export function renameSpace(spaceId, newSpaceName) { const respFormat = { data: {}, diff --git a/src/store/actions.js b/src/store/actions.js index 58dbf9ae2..cda480baf 100644 --- a/src/store/actions.js +++ b/src/store/actions.js @@ -113,7 +113,7 @@ export default { gid, displayName, }, - spaceId: space.id + spaceId: space.id, }) .then((resp) => { addGroupToWorkspace(space.id, resp.data.group.gid) @@ -122,8 +122,8 @@ export default { name, gid, displayName, - types: resp.data.group.types, - slug: resp.data.group.slug + types: resp.data.group.types, + slug: resp.data.group.slug, }) // Navigates to the g roup's details page context.state.spaces[name].isOpen = true @@ -281,7 +281,7 @@ export default { user.groups.splice(user.groups.indexOf(ManagerGroup.getGid(space)), 1) context.commit('DECREMENT_GROUP_USER_COUNT', { spaceName: space.name, - gid: ManagerGroup.getGid(space) + gid: ManagerGroup.getGid(space), }) context.commit('CHANGE_USER_ROLE', { spaceName: space.name, @@ -292,7 +292,7 @@ export default { user.groups.push(ManagerGroup.getGid(space)) context.commit('INCREMENT_GROUP_USER_COUNT', { spaceName: space.name, - gid: ManagerGroup.getGid(space) + gid: ManagerGroup.getGid(space), }) context.commit('CHANGE_USER_ROLE', { spaceName: space.name, @@ -467,7 +467,7 @@ export default { context.commit('SET_NO_USERS', ({ activated: false })) context.commit('UPDATE_USERS', { space, - users + users, }) } }) diff --git a/src/store/mutations.js b/src/store/mutations.js index ec24fed46..4e4f3b4e7 100644 --- a/src/store/mutations.js +++ b/src/store/mutations.js @@ -89,7 +89,7 @@ export default { gid, displayName, usersCount: 0, - slug + slug, } VueSet(state.spaces, name, space) sortSpaces(state) @@ -266,9 +266,9 @@ export default { VueSet(state.groupfolders, groupfolder.mount_point, groupfolder) sortGroupfolders(state) }, - TOGGLE_USER_CONNECTED(state, { name, user }) { + TOGGLE_USER_CONNECTED(state, { name, user }) { const space = state.spaces[name] space.users[user.uid].is_connected = !space.users[user.uid].is_connected VueSet(state.spaces, name, space) - }, + }, } diff --git a/src/tests/unit/groupfoldersService.test.js b/src/tests/unit/groupfoldersService.test.js index e899a0c82..ad4d047fb 100644 --- a/src/tests/unit/groupfoldersService.test.js +++ b/src/tests/unit/groupfoldersService.test.js @@ -293,16 +293,16 @@ describe('destroy', () => { { http: { statuscode: 200, - message: 'The space is deleted.' + message: 'The space is deleted.', }, - data: { + data: { name: 'foobar', groups: ['SPACE-WM-1', 'SPACE-U-1'], - space_id: 1, - groupfolder_id: 1, - state: 'delete' - } - } + space_id: 1, + groupfolder_id: 1, + state: 'delete', + }, + }, ) axios.delete.mockResolvedValue({ status: 200, data: { ocs: { meta: { status: 'ok' } } } }) diff --git a/src/tests/unit/store.test.js b/src/tests/unit/store.test.js index aa5687aac..039b4a4cb 100644 --- a/src/tests/unit/store.test.js +++ b/src/tests/unit/store.test.js @@ -81,15 +81,15 @@ describe('Vuex store tests', () => { mutations.addGroupToSpace(state, { name: 'test-space', gid: 'test-group', - slug: 'test-group', - usersCount: 0, + slug: 'test-group', + usersCount: 0, }) expect(state.spaces['test-space'].groups['test-group']).toEqual({ gid: 'test-group', displayName: 'test-group', - slug: 'test-group', - usersCount: 0, + slug: 'test-group', + usersCount: 0, }) }) diff --git a/src/tests/unit/workspaceContent.test.js b/src/tests/unit/workspaceContent.test.js index 32340b20d..6509a6862 100644 --- a/src/tests/unit/workspaceContent.test.js +++ b/src/tests/unit/workspaceContent.test.js @@ -125,10 +125,10 @@ describe('Creating spaces with different entries', () => { { type: 'group', id: 'SPACE-GE-421', - displayname: 'WM-Sri_Lanka' - } + displayname: 'WM-Sri_Lanka', + }, ], - statuscode: 201 + statuscode: 201, }, }) From 3b4a8e0ad897558ae067cc99696716bf798f3e07 Mon Sep 17 00:00:00 2001 From: zak39 Date: Mon, 16 Dec 2024 17:56:28 +0100 Subject: [PATCH 19/19] test(php): Add 'added_groups' key when creating a workspace --- tests/Unit/Space/SpaceManagerTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Unit/Space/SpaceManagerTest.php b/tests/Unit/Space/SpaceManagerTest.php index aa5f975a8..d04cff72c 100644 --- a/tests/Unit/Space/SpaceManagerTest.php +++ b/tests/Unit/Space/SpaceManagerTest.php @@ -262,6 +262,7 @@ public function testArrayAfterCreatedTheEspace01Workspace(): void { 'slug' => 'SPACE-U-1' ], ], + 'added_groups' => (object)[], 'quota' => -3, 'size' => 0, 'acl' => true,