From e27715de4798d73c31b6f6e07eefedfab809daa4 Mon Sep 17 00:00:00 2001 From: nfebe Date: Fri, 13 Dec 2024 16:11:11 +0100 Subject: [PATCH] wip: Add admin toggle to disable systemtag Signed-off-by: nfebe --- apps/dav/lib/SystemTag/SystemTagPlugin.php | 7 +- .../src/actions/sharingStatusAction.ts | 159 ++++++++++++++++++ apps/systemtags/src/components/SystemTags.vue | 5 + .../src/views/SystemTagsSection.vue | 3 + lib/composer/composer/autoload_classmap.php | 1 - lib/composer/composer/autoload_static.php | 1 - lib/private/SystemTag/ManagerFactory.php | 12 +- lib/private/SystemTag/SystemTagManager.php | 25 --- lib/public/SystemTag/ISystemTagManager.php | 12 -- 9 files changed, 172 insertions(+), 53 deletions(-) create mode 100644 apps/files_sharing/src/actions/sharingStatusAction.ts diff --git a/apps/dav/lib/SystemTag/SystemTagPlugin.php b/apps/dav/lib/SystemTag/SystemTagPlugin.php index 428e71d91f432..8305944cb0bcd 100644 --- a/apps/dav/lib/SystemTag/SystemTagPlugin.php +++ b/apps/dav/lib/SystemTag/SystemTagPlugin.php @@ -18,7 +18,6 @@ use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\ISystemTagObjectMapper; use OCP\SystemTag\TagAlreadyExistsException; -use OCP\SystemTag\TagCreationForbiddenException; use OCP\Util; use Sabre\DAV\Exception\BadRequest; use Sabre\DAV\Exception\Conflict; @@ -190,8 +189,6 @@ private function createTag($data, $contentType = 'application/json') { return $tag; } catch (TagAlreadyExistsException $e) { throw new Conflict('Tag already exists', 0, $e); - } catch (TagCreationForbiddenException $e) { - throw new Forbidden('You don’t have right to create tags', 0, $e); } } @@ -379,7 +376,7 @@ public function handleUpdateProperties($path, PropPatch $propPatch) { if (!$node instanceof SystemTagNode && !$node instanceof SystemTagObjectType) { return; } - + $propPatch->handle([self::OBJECTIDS_PROPERTYNAME], function ($props) use ($node) { if (!$node instanceof SystemTagObjectType) { return false; @@ -397,7 +394,7 @@ public function handleUpdateProperties($path, PropPatch $propPatch) { if (count($objectTypes) !== 1 || $objectTypes[0] !== $node->getName()) { throw new BadRequest('Invalid object-ids property. All object types must be of the same type: ' . $node->getName()); } - + $this->tagMapper->setObjectIdsForTag($node->getSystemTag()->getId(), $node->getName(), array_keys($objects)); } diff --git a/apps/files_sharing/src/actions/sharingStatusAction.ts b/apps/files_sharing/src/actions/sharingStatusAction.ts new file mode 100644 index 0000000000000..cebdd5172adab --- /dev/null +++ b/apps/files_sharing/src/actions/sharingStatusAction.ts @@ -0,0 +1,159 @@ +/** + * @copyright Copyright (c) 2023 John Molakvoæ + * + * @author John Molakvoæ + * + * @license AGPL-3.0-or-later + * + * 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 . + * + */ +import { Node, View, registerFileAction, FileAction, Permission } from '@nextcloud/files' +import { translate as t } from '@nextcloud/l10n' +import { Type } from '@nextcloud/sharing' + +import AccountGroupSvg from '@mdi/svg/svg/account-group.svg?raw' +import AccountPlusSvg from '@mdi/svg/svg/account-plus.svg?raw' +import LinkSvg from '@mdi/svg/svg/link.svg?raw' +import CircleSvg from '../../../../core/img/apps/circles.svg?raw' + +import { action as sidebarAction } from '../../../files/src/actions/sidebarAction' +import { generateUrl } from '@nextcloud/router' +import { getCurrentUser } from '@nextcloud/auth' + +import './sharingStatusAction.scss' + +const isDarkMode = window?.matchMedia?.('(prefers-color-scheme: dark)')?.matches === true + || document.querySelector('[data-themes*=dark]') !== null + +const generateAvatarSvg = (userId: string, isGuest = false) => { + console.debug("USER ID, is Guest", userId, isGuest) + const url = isDarkMode ? '/avatar/{userId}/32/dark' : '/avatar/{userId}/32' + const avatarUrl = generateUrl(isGuest ? url : url + '?guestFallback=true', { userId }) + return `` +} + +const isExternal = (node: Node) => { + return node.attributes.remote_id !== undefined +} + +export const action = new FileAction({ + id: 'sharing-status', + displayName(nodes: Node[]) { + const node = nodes[0] + const shareTypes = Object.values(node?.attributes?.['share-types'] || {}).flat() as number[] + const ownerId = node?.attributes?.['owner-id'] + + if (shareTypes.length > 0 + || (ownerId !== getCurrentUser()?.uid || isExternal(node))) { + return t('files_sharing', 'Shared') + } + + return '' + }, + + title(nodes: Node[]) { + const node = nodes[0] + const ownerId = node?.attributes?.['owner-id'] + const ownerDisplayName = node?.attributes?.['owner-display-name'] + + // Mixed share types + if (Array.isArray(node.attributes?.['share-types']) && node.attributes?.['share-types'].length > 1) { + return t('files_sharing', 'Shared multiple times with different people') + } + + if (ownerId && (ownerId !== getCurrentUser()?.uid || isExternal(node))) { + return t('files_sharing', 'Shared by {ownerDisplayName}', { ownerDisplayName }) + } + + return t('files_sharing', 'Show sharing options') + }, + + iconSvgInline(nodes: Node[]) { + const node = nodes[0] + console.debug("Node check", node) + const shareTypes = Object.values(node?.attributes?.['share-types'] || {}).flat() as number[] + + // Mixed share types + if (Array.isArray(node.attributes?.['share-types']) && node.attributes?.['share-types'].length > 1) { + return AccountPlusSvg + } + + // Link shares + if (shareTypes.includes(Type.SHARE_TYPE_LINK) + || shareTypes.includes(Type.SHARE_TYPE_EMAIL)) { + return LinkSvg + } + + // Group shares + if (shareTypes.includes(Type.SHARE_TYPE_GROUP) + || shareTypes.includes(Type.SHARE_TYPE_REMOTE_GROUP)) { + return AccountGroupSvg + } + + // Circle shares + if (shareTypes.includes(Type.SHARE_TYPE_CIRCLE)) { + return CircleSvg + } + + const ownerId = node?.attributes?.['owner-id'] + if (ownerId && (ownerId !== getCurrentUser()?.uid || isExternal(node))) { + console.debug("IS EXTERNAL", isExternal(node)) + console.debug("EXTENAL NODE", node) + return generateAvatarSvg(ownerId, true) + } + + return AccountPlusSvg + }, + + enabled(nodes: Node[]) { + if (nodes.length !== 1) { + return false + } + + const node = nodes[0] + const ownerId = node?.attributes?.['owner-id'] + const isMixed = Array.isArray(node.attributes?.['share-types']) + + // If the node is shared multiple times with + // different share types to the current user + if (isMixed) { + return true + } + + // If the node is shared by someone else + if (ownerId && (ownerId !== getCurrentUser()?.uid || isExternal(node))) { + return true + } + + return (node.permissions & Permission.SHARE) !== 0 + }, + + async exec(node: Node, view: View, dir: string) { + // You need read permissions to see the sidebar + if ((node.permissions & Permission.READ) !== 0) { + window.OCA?.Files?.Sidebar?.setActiveTab?.('sharing') + return sidebarAction.exec(node, view, dir) + } + return null + }, + + inline: () => true, + +}) + +registerFileAction(action) diff --git a/apps/systemtags/src/components/SystemTags.vue b/apps/systemtags/src/components/SystemTags.vue index 1f2b38bf10aaa..89c35b3347f8f 100644 --- a/apps/systemtags/src/components/SystemTags.vue +++ b/apps/systemtags/src/components/SystemTags.vue @@ -74,6 +74,7 @@ export default Vue.extend({ data() { return { + allowSystemTagCreationForNonAdmins: false, // obtain default value sortedTags: [] as TagWithId[], selectedTags: [] as TagWithId[], loadingTags: false, @@ -202,6 +203,10 @@ export default Vue.extend({ } this.loading = false }, + async onSystemTagCreationPermissionChange(checked) { + return checked + + } }, }) diff --git a/apps/systemtags/src/views/SystemTagsSection.vue b/apps/systemtags/src/views/SystemTagsSection.vue index 9745ab188afc2..345487f289046 100644 --- a/apps/systemtags/src/views/SystemTagsSection.vue +++ b/apps/systemtags/src/views/SystemTagsSection.vue @@ -6,6 +6,7 @@