diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index cd90ae35e..c3fccb411 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -187,6 +187,7 @@ class Application extends App { /** @var IManager $resourceManager */ $resourceManager = $this->getContainer()->query(IManager::class); $resourceManager->registerResourceProvider(\OCA\Deck\Collaboration\Resources\ResourceProvider::class); + $resourceManager->registerResourceProvider(\OCA\Deck\Collaboration\Resources\ResourceProviderCard::class); \OC::$server->getEventDispatcher()->addListener('\OCP\Collaboration\Resources::loadAdditionalScripts', function () { \OCP\Util::addScript('deck', 'collections'); }); diff --git a/lib/Collaboration/Resources/ResourceProviderCard.php b/lib/Collaboration/Resources/ResourceProviderCard.php new file mode 100644 index 000000000..8211919d8 --- /dev/null +++ b/lib/Collaboration/Resources/ResourceProviderCard.php @@ -0,0 +1,133 @@ + + * + * @author Julius Härtl + * + * @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\Deck\Collaboration\Resources; + + +use OCA\Deck\Db\Acl; +use OCA\Deck\Db\Board; +use OCA\Deck\Db\BoardMapper; +use OCA\Deck\Service\PermissionService; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\AppFramework\QueryException; +use OCP\Collaboration\Resources\IManager; +use OCP\Collaboration\Resources\IProvider; +use OCP\Collaboration\Resources\IResource; +use OCP\Collaboration\Resources\ResourceException; +use OCP\IUser; + +class ResourceProviderCard implements IProvider { + + const RESOURCE_TYPE = 'deck-card'; + + private $boardMapper; + private $permissionService; + + /** @var array */ + protected $nodes = []; + + public function __construct(BoardMapper $boardMapper, PermissionService $permissionService) { + $this->boardMapper = $boardMapper; + $this->permissionService = $permissionService; + } + + /** + * Get the type of a resource + * + * @param IResource $resource + * @return string + * @since 15.0.0 + */ + public function getType(): string { + return self::RESOURCE_TYPE; + } + + /** + * Get the rich object data of a resource + * + * @param IResource $resource + * @return array + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @since 16.0.0 + */ + public function getResourceRichObject(IResource $resource): array { + $board = $this->getBoard($resource); + $link = \OC::$server->getURLGenerator()->linkToRoute('deck.page.index') . '#!/board/' . $resource->getId(); + + return [ + 'type' => self::RESOURCE_TYPE, + 'id' => $resource->getId(), + 'name' => $board->getTitle(), + 'link' => $link, + 'iconUrl' => \OC::$server->getURLGenerator()->imagePath('deck', 'deck-dark.svg') + ]; + + } + + /** + * Can a user/guest access the collection + * + * @param IResource $resource + * @param IUser|null $user + * @return bool + * @since 16.0.0 + */ + public function canAccessResource(IResource $resource, ?IUser $user): bool { + if ($resource->getType() !== self::RESOURCE_TYPE || !$user instanceof IUser) { + return false; + } + $board = $this->getBoard($resource); + if ($board === null) { + return false; + } + if ($board->getOwner() === $user->getUID()) { + return true; + } + return $this->permissionService->userCan($board->getAcl(), Acl::PERMISSION_READ, $user->getUID()); + } + + private function getBoard(IResource $resource) { + try { + return $this->boardMapper->find($resource->getId(), false, true); + } catch (DoesNotExistException $e) { + } catch (MultipleObjectsReturnedException $e) { + return null; + } + } + + public function invalidateAccessCache($boardId = null) { + try { + /** @var IManager $resourceManager */ + $resourceManager = \OC::$server->query(IManager::class); + } catch (QueryException $e) { + } + if ($boardId !== null) { + $resource = $resourceManager->getResourceForUser(self::RESOURCE_TYPE, (string)$boardId, null); + $resourceManager->invalidateAccessCacheForResource($resource); + } else { + $resourceManager->invalidateAccessCacheForProvider($this); + } + } +} diff --git a/src/CardSelector.vue b/src/CardSelector.vue new file mode 100644 index 000000000..34bbc618c --- /dev/null +++ b/src/CardSelector.vue @@ -0,0 +1,119 @@ + + + + + + + diff --git a/src/init-collections-card.js b/src/init-collections-card.js new file mode 100644 index 000000000..1a004d6c4 --- /dev/null +++ b/src/init-collections-card.js @@ -0,0 +1,67 @@ +/* + * @copyright Copyright (c) 2019 Julius Härtl + * + * @author Julius Härtl + * + * @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 . + * + */ + +import Vue from 'vue' +import CardSelector from './CardSelector' +import './../css/collections.css' + +'use strict' + +/* global __webpack_nonce__ __webpack_public_path__ OC t n */ +// eslint-disable-next-line +__webpack_nonce__ = btoa(OC.requestToken); +// eslint-disable-next-line +__webpack_public_path__ = OC.linkTo('deck', 'js/'); + +Vue.prototype.t = t +Vue.prototype.n = n +Vue.prototype.OC = OC; + +((function(OCP) { + + OCP.Collaboration.registerType('deck-card', { + action: () => { + return new Promise((resolve, reject) => { + const container = document.createElement('div') + container.id = 'deck-board-select' + const body = document.getElementById('body-user') + body.append(container) + const ComponentVM = new Vue({ + render: h => h(CardSelector) + }) + ComponentVM.$mount(container) + ComponentVM.$root.$on('close', () => { + ComponentVM.$el.remove() + ComponentVM.$destroy() + reject() + }) + ComponentVM.$root.$on('select', (id) => { + resolve(id) + ComponentVM.$el.remove() + ComponentVM.$destroy() + }) + }) + }, + typeString: t('deck', 'Link to a card'), + typeIconClass: 'icon-deck' + }) +})(window.OCP)) diff --git a/webpack.common.js b/webpack.common.js index eb9cee08d..f1246d860 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -5,6 +5,7 @@ module.exports = { entry: { deck: path.join(__dirname, 'src', 'main.js'), collections: path.join(__dirname, 'src', 'init-collections.js'), + collectionscard: path.join(__dirname, 'src', 'init-collections-card.js'), }, output: { filename: '[name].js',