diff options
author | Marcel Klehr <mklehr@gmx.net> | 2022-03-13 18:34:35 +0300 |
---|---|---|
committer | Marcel Klehr <mklehr@gmx.net> | 2022-03-13 18:34:35 +0300 |
commit | 74fb4510f6fb8318e805dae72738deb621124668 (patch) | |
tree | 28d37cf3296c34f5f20f644609c8b28046563aa9 | |
parent | ddeb5fc9535a1393022528b351e36f2bd2309341 (diff) |
Projects: Add bookmarks foldersfeature/projects
remove bookmark picker from collections.js for now as we don't have a picker, yet.
Signed-off-by: Marcel Klehr <mklehr@gmx.net>
-rw-r--r-- | lib/AppInfo/Application.php | 2 | ||||
-rw-r--r-- | lib/Collaboration/Resources/FolderResourceProvider.php | 90 | ||||
-rw-r--r-- | lib/Db/FolderMapper.php | 4 | ||||
-rw-r--r-- | src/collections.js | 100 | ||||
-rw-r--r-- | src/components/FolderPicker.vue | 7 | ||||
-rw-r--r-- | src/components/FolderPickerDialog.vue | 3 | ||||
-rw-r--r-- | src/components/SidebarBookmark.vue | 3 | ||||
-rw-r--r-- | src/components/SidebarFolder.vue | 21 |
8 files changed, 155 insertions, 75 deletions
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 0555ffea..312db322 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -11,6 +11,7 @@ namespace OCA\Bookmarks\AppInfo; use Closure; use OC\EventDispatcher\SymfonyAdapter; use OCA\Bookmarks\Activity\ActivityPublisher; +use OCA\Bookmarks\Collaboration\Resources\FolderResourceProvider; use OCA\Bookmarks\Collaboration\Resources\ResourceProvider; use OCA\Bookmarks\Dashboard\Frequent; use OCA\Bookmarks\Dashboard\Recent; @@ -95,6 +96,7 @@ class Application extends App implements IBootstrap { protected function registerCollaborationResources(IProviderManager $resourceManager, SymfonyAdapter $symfonyAdapter): void { $resourceManager->registerResourceProvider(ResourceProvider::class); + $resourceManager->registerResourceProvider(FolderResourceProvider::class); $symfonyAdapter->addListener('\OCP\Collaboration\Resources::loadAdditionalScripts', static function () { Util::addScript('bookmarks', 'bookmarks-collections'); diff --git a/lib/Collaboration/Resources/FolderResourceProvider.php b/lib/Collaboration/Resources/FolderResourceProvider.php new file mode 100644 index 00000000..1ffc1a2c --- /dev/null +++ b/lib/Collaboration/Resources/FolderResourceProvider.php @@ -0,0 +1,90 @@ +<?php +/* + * Copyright (c) 2022. The Nextcloud Bookmarks contributors. + * + * This file is licensed under the Affero General Public License version 3 or later. See the COPYING file. + */ + +namespace OCA\Bookmarks\Collaboration\Resources; + +use OCA\Bookmarks\Db\Folder; +use OCA\Bookmarks\Db\FolderMapper; +use OCA\Bookmarks\Service\Authorizer; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\Collaboration\Resources\IProvider; +use OCP\Collaboration\Resources\IResource; +use OCP\IURLGenerator; +use OCP\IUser; + +class FolderResourceProvider implements IProvider { + public const RESOURCE_TYPE = 'bookmarks-folder'; + /** + * @var IURLGenerator + */ + private $url; + /** + * @var Authorizer + */ + private $authorizer; + /** + * @var FolderMapper + */ + private $folderMapper; + + public function __construct(IURLGenerator $url, Authorizer $authorizer, FolderMapper $folderMapper) { + $this->url = $url; + $this->authorizer = $authorizer; + $this->folderMapper = $folderMapper; + } + + /** + * @inheritDoc + */ + public function getType(): string { + return self::RESOURCE_TYPE; + } + + /** + * @inheritDoc + */ + public function getResourceRichObject(IResource $resource): array { + $folder = $this->getFolder($resource); + $favicon = $this->url->imagePath('bookmarks', 'bookmarks-black.svg'); + $resourceUrl = $this->url->linkToRouteAbsolute('bookmarks.web_view.indexfolder', ['folder' => $folder->getId()]); + + return [ + 'type' => self::RESOURCE_TYPE, + 'id' => $resource->getId(), + 'name' => $folder->getTitle(), + 'link' => $resourceUrl, + 'iconUrl' => $favicon, + ]; + } + + /** + * @inheritDoc + */ + public function canAccessResource(IResource $resource, ?IUser $user): bool { + if ($resource->getType() !== self::RESOURCE_TYPE || !($user instanceof IUser)) { + return false; + } + $folder = $this->getFolder($resource); + if ($folder === null) { + return false; + } + if ($folder->getUserId() === $user->getUID()) { + return true; + } + $permissions = $this->authorizer->getUserPermissionsForFolder($user->getUID(), $folder->getId()); + return Authorizer::hasPermission(Authorizer::PERM_READ, $permissions); + } + + private function getFolder(IResource $resource) : ?Folder { + try { + return $this->folderMapper->find((int) $resource->getId()); + } catch (MultipleObjectsReturnedException|DoesNotExistException $e) { + return null; + } + } +} diff --git a/lib/Db/FolderMapper.php b/lib/Db/FolderMapper.php index 99c93719..14ad59b6 100644 --- a/lib/Db/FolderMapper.php +++ b/lib/Db/FolderMapper.php @@ -59,11 +59,11 @@ class FolderMapper extends QBMapper { /** * @param int $id - * @return Entity + * @return Folder * @throws DoesNotExistException if not found * @throws MultipleObjectsReturnedException if more than one result */ - public function find(int $id): Entity { + public function find(int $id): Folder { $qb = $this->db->getQueryBuilder(); $qb ->select('*') diff --git a/src/collections.js b/src/collections.js index c81d16f8..83504404 100644 --- a/src/collections.js +++ b/src/collections.js @@ -6,70 +6,46 @@ import Vue from 'vue' import FolderPickerDialog from './components/FolderPickerDialog' +import { Store } from 'vuex' +import deepClone from 'clone-deep' +import store, { actions } from './store' +import AppGlobal from './mixins/AppGlobal' +import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip' -// eslint-disable-next-line no-unexpected-multiline -(function(OCP, OC) { +// eslint-disable-next-line +__webpack_nonce__ = btoa(OC.requestToken) +// eslint-disable-next-line +__webpack_public_path__ = OC.linkTo('bookmarks', 'js/') - // eslint-disable-next-line - __webpack_nonce__ = btoa(OC.requestToken) - // eslint-disable-next-line - __webpack_public_path__ = OC.linkTo('bookmarks', 'js/') +Vue.mixin(AppGlobal) +Vue.directive('tooltip', Tooltip) - Vue.prototype.t = t - Vue.prototype.n = n - Vue.prototype.OC = OC - - OCP.Collaboration.registerType('bookmarks', { - action: () => { - return new Promise((resolve, reject) => { - const container = document.createElement('div') - container.id = 'bookmarks-bookmark-select' - const body = document.getElementById('body-user') - body.appendChild(container) - const ComponentVM = new Vue({ - render: h => h(FolderPickerDialog), - }) - ComponentVM.$mount(container) - ComponentVM.$root.$on('close', () => { - ComponentVM.$el.remove() - ComponentVM.$destroy() - reject(new Error('User cancelled resource selection')) - }) - ComponentVM.$root.$on('select', (id) => { - resolve(id) - ComponentVM.$el.remove() - ComponentVM.$destroy() - }) +OCP.Collaboration.registerType('bookmarks-folder', { + action: () => { + return new Promise((resolve, reject) => { + const container = document.createElement('div') + container.id = 'bookmarks-bookmark-folder-select' + const body = document.getElementById('body-user') + body.appendChild(container) + const ComponentVM = new Vue({ + render: h => h(FolderPickerDialog), + store: new Store(deepClone(store)), }) - }, - typeString: t('bookmarks', 'Link to a bookmark'), - typeIconClass: 'icon-favorite', - }) - - OCP.Collaboration.registerType('bookmarks::folder', { - action: () => { - return new Promise((resolve, reject) => { - const container = document.createElement('div') - container.id = 'bookmarks-bookmark-folder-select' - const body = document.getElementById('body-user') - body.appendChild(container) - const ComponentVM = new Vue({ - render: h => h(FolderPickerDialog), - }) - ComponentVM.$mount(container) - ComponentVM.$root.$on('close', () => { - ComponentVM.$el.remove() - ComponentVM.$destroy() - reject(new Error('User cancelled resource selection')) - }) - ComponentVM.$root.$on('select', (id) => { - resolve(id) - ComponentVM.$el.remove() - ComponentVM.$destroy() - }) + ComponentVM.$store.dispatch(actions.LOAD_FOLDERS, true) + ComponentVM.$mount(container) + window.bookmarksPicker = ComponentVM + ComponentVM.$root.$on('close', () => { + ComponentVM.$el.remove() + ComponentVM.$destroy() + reject(new Error('User cancelled resource selection')) + }) + ComponentVM.$root.$on('select', (id) => { + resolve(id) + ComponentVM.$el.remove() + ComponentVM.$destroy() }) - }, - typeString: t('bookmarks', 'Link to a bookmark folder'), - typeIconClass: 'icon-favorite', - }) -})(window.OCP, window.OC) + }) + }, + typeString: t('bookmarks', 'Link to a bookmark folder'), + typeIconClass: 'icon-favorite', +}) diff --git a/src/components/FolderPicker.vue b/src/components/FolderPicker.vue index b35c3f62..709496a9 100644 --- a/src/components/FolderPicker.vue +++ b/src/components/FolderPicker.vue @@ -105,12 +105,7 @@ export default { .currentfolder h2 { margin: 0; -} - -.currentfolder h2 .material-design-icon { - position: relative; - top: 5px; - margin: 0 15px; + display: flex; } .treefolder__title .material-design-icon { diff --git a/src/components/FolderPickerDialog.vue b/src/components/FolderPickerDialog.vue index 33010ac5..0afb9e4d 100644 --- a/src/components/FolderPickerDialog.vue +++ b/src/components/FolderPickerDialog.vue @@ -39,11 +39,12 @@ export default { created() {}, methods: { onSelect(folderId) { + this.$root.$emit('select', folderId) this.$emit('input', folderId) - this.$emit('select', folderId) this.$emit('close') }, onClose() { + this.$root.$emit('close') this.$emit('close') }, }, diff --git a/src/components/SidebarBookmark.vue b/src/components/SidebarBookmark.vue index 8523e9a6..a0d411eb 100644 --- a/src/components/SidebarBookmark.vue +++ b/src/components/SidebarBookmark.vue @@ -95,7 +95,8 @@ <a class="button" :href="archivedFile" target="_blank"><span class="icon-files-dark" /> {{ t('bookmarks', 'Open file location') }}</a> </div> </AppSidebarTab> - <AppSidebarTab id="bookmark-projects" + <AppSidebarTab v-if="!isPublic" + id="bookmark-projects" :name="t('bookmarks', 'Projects')" icon="icon-projects" :order="1"> diff --git a/src/components/SidebarFolder.vue b/src/components/SidebarFolder.vue index fb4afad8..6a7d2e8c 100644 --- a/src/components/SidebarFolder.vue +++ b/src/components/SidebarFolder.vue @@ -11,7 +11,10 @@ :title="folder.title" :active.sync="activeTab" @close="onClose"> - <AppSidebarTab id="folder-details" :name="t('bookmarks', 'Details')" icon="icon-info"> + <AppSidebarTab id="folder-details" + :name="t('bookmarks', 'Details')" + icon="icon-info" + :order="0"> <h3>{{ t('bookmarks', 'Owner') }}</h3> <UserBubble :user="folder.userId" :display-name="folder.userId" /> <h3>{{ t('bookmarks', 'Bookmarks') }}</h3> @@ -20,7 +23,8 @@ <AppSidebarTab v-if="isSharable" id="folder-sharing" :name="t('bookmarks', 'Sharing')" - icon="icon-shared"> + icon="icon-shared" + :order="1"> <div class="participant-select"> <figure :class="{'icon-user': true, 'share__avatar': true }" /> <Multiselect v-model="participant" @@ -108,6 +112,16 @@ </div> </div> </AppSidebarTab> + <AppSidebarTab v-if="!isPublic" + id="bookmark-projects" + :name="t('bookmarks', 'Projects')" + icon="icon-projects" + :order="2"> + <CollectionList v-if="folder" + :id="''+folder.id" + :name="folder.title" + type="bookmarks-folder" /> + </AppSidebarTab> </AppSidebar> </template> <script> @@ -128,10 +142,11 @@ import { actions, mutations } from '../store/' import EyeIcon from 'vue-material-design-icons/Eye' import PencilIcon from 'vue-material-design-icons/Pencil' import ShareAllIcon from 'vue-material-design-icons/ShareAll' +import { CollectionList } from 'nextcloud-vue-collections' export default { name: 'SidebarFolder', - components: { AppSidebar, AppSidebarTab, Avatar, Multiselect, ActionButton, ActionCheckbox, Actions, UserBubble, ActionSeparator, EyeIcon, PencilIcon, ShareAllIcon }, + components: { AppSidebar, AppSidebarTab, Avatar, Multiselect, ActionButton, ActionCheckbox, Actions, UserBubble, ActionSeparator, EyeIcon, PencilIcon, ShareAllIcon, CollectionList }, data() { return { participantSearchResults: [], |