From 69b530a44230028c278bda94984b7aaacd22a8a1 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Fri, 14 Sep 2018 12:34:24 +0200 Subject: [PATCH 01/53] Basic implementation of resource and collection handling Signed-off-by: Joas Schilling --- .../Version15000Date20180917092725.php | 76 +++++++++ .../Collaboration/Resources/Collection.php | 155 ++++++++++++++++++ .../Collaboration/Resources/Manager.php | 58 +++++++ .../Collaboration/Resources/Resource.php | 91 ++++++++++ .../Collaboration/Resources/ICollection.php | 52 ++++++ .../Collaboration/Resources/IManager.php | 45 +++++ .../Collaboration/Resources/IProvider.php | 27 +++ .../Collaboration/Resources/IResource.php | 48 ++++++ .../Resources/ResourceException.php | 27 +++ 9 files changed, 579 insertions(+) create mode 100644 core/Migrations/Version15000Date20180917092725.php create mode 100644 lib/private/Collaboration/Resources/Collection.php create mode 100644 lib/private/Collaboration/Resources/Manager.php create mode 100644 lib/private/Collaboration/Resources/Resource.php create mode 100644 lib/public/Collaboration/Resources/ICollection.php create mode 100644 lib/public/Collaboration/Resources/IManager.php create mode 100644 lib/public/Collaboration/Resources/IProvider.php create mode 100644 lib/public/Collaboration/Resources/IResource.php create mode 100644 lib/public/Collaboration/Resources/ResourceException.php diff --git a/core/Migrations/Version15000Date20180917092725.php b/core/Migrations/Version15000Date20180917092725.php new file mode 100644 index 0000000000..9dbc5efced --- /dev/null +++ b/core/Migrations/Version15000Date20180917092725.php @@ -0,0 +1,76 @@ + + * + * @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 OC\Core\Migrations; + +use Closure; +use Doctrine\DBAL\Types\Type; +use OCP\DB\ISchemaWrapper; +use OCP\Migration\SimpleMigrationStep; +use OCP\Migration\IOutput; + +class Version15000Date20180917092725 extends SimpleMigrationStep { + + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + if (!$schema->hasTable('collres_collections')) { + $table = $schema->createTable('collres_collections'); + + $table->addColumn('id', Type::BIGINT, [ + 'autoincrement' => true, + 'notnull' => true, + ]); + + $table->setPrimaryKey(['id']); + } + + if (!$schema->hasTable('collres_resources')) { + $table = $schema->createTable('collres_resources'); + + $table->addColumn('collection_id', Type::BIGINT, [ + 'notnull' => true, + ]); + $table->addColumn('resource_type', Type::STRING, [ + 'notnull' => true, + 'length' => 64, + ]); + $table->addColumn('resource_id', Type::STRING, [ + 'notnull' => true, + 'length' => 64, + ]); + + $table->addUniqueIndex(['collection_id', 'resource_type', 'resource_id'], 'collres_unique_res'); + } + + return $schema; + } + +} diff --git a/lib/private/Collaboration/Resources/Collection.php b/lib/private/Collaboration/Resources/Collection.php new file mode 100644 index 0000000000..8509b4442d --- /dev/null +++ b/lib/private/Collaboration/Resources/Collection.php @@ -0,0 +1,155 @@ + + * + * @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 OC\Collaboration\Resources; + + +use Doctrine\DBAL\Exception\ConstraintViolationException; +use OCP\Collaboration\Resources\IManager; +use OCP\Collaboration\Resources\ResourceException; +use OCP\Collaboration\Resources\ICollection; +use OCP\Collaboration\Resources\IResource; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; + +class Collection implements ICollection { + + /** @var IManager */ + protected $manager; + + /** @var IDBConnection */ + protected $connection; + + /** @var int */ + protected $id; + + /** @var IResource[] */ + protected $resources; + + public function __construct(IManager $manager, IDBConnection $connection, int $id) { + $this->manager = $manager; + $this->connection = $connection; + $this->id = $id; + $this->resources = []; + } + + /** + * @return IResource[] + * @since 15.0.0 + */ + public function getResources(): array { + if (empty($this->resources)) { + $query = $this->connection->getQueryBuilder(); + $query->select('resource_type', 'resource_id') + ->from('collres_resources') + ->where($query->expr()->eq('collection_id', $query->createNamedParameter($this->id, IQueryBuilder::PARAM_INT))); + + $result = $query->execute(); + while ($row = $result->fetch()) { + $this->resources[] = $this->manager->getResource($row['resource_type'], $row['resource_id']); + } + $result->closeCursor(); + } + + return $this->resources; + } + + /** + * Adds a resource to a collection + * + * @param IResource $resource + * @throws ResourceException when the resource is already part of the collection + * @since 15.0.0 + */ + public function addResource(IResource $resource) { + array_map(function(IResource $r) use ($resource) { + if ($this->isSameResource($r, $resource)) { + throw new ResourceException('Already part of the collection'); + } + }, $this->resources); + + $this->resources[] = $resource; + + if ($this->id === 0) { + $this->makeCollectionPersistent(); + } + + $query = $this->connection->getQueryBuilder(); + $query->insert('collres_resources') + ->values([ + 'collection_id' => $query->createNamedParameter($this->id, IQueryBuilder::PARAM_INT), + 'resource_type' => $query->createNamedParameter($resource->getType()), + 'resource_id' => $query->createNamedParameter($resource->getId()), + ]); + + try { + $query->execute(); + } catch (ConstraintViolationException $e) { + throw new ResourceException('Already part of the collection'); + } + } + + /** + * Removes a resource from a collection + * + * @param IResource $resource + * @since 15.0.0 + */ + public function removeResource(IResource $resource) { + $this->resources = array_filter($this->resources, function(IResource $r) use ($resource) { + return !$this->isSameResource($r, $resource); + }); + + $query = $this->connection->getQueryBuilder(); + $query->delete('collres_resources') + ->where($query->expr()->eq('collection_id', $query->createNamedParameter($this->id, IQueryBuilder::PARAM_INT))) + ->andWhere($query->expr()->eq('resource_type', $query->createNamedParameter($resource->getType()))) + ->andWhere($query->expr()->eq('resource_id', $query->createNamedParameter($resource->getId()))); + $query->execute(); + + if (empty($this->resources)) { + $this->makeCollectionUnsteady(); + } + } + + protected function isSameResource(IResource $resource1, IResource $resource2): bool { + return $resource1->getType() === $resource2->getType() && + $resource1->getId() === $resource2->getId(); + } + + protected function makeCollectionPersistent() { + $query = $this->connection->getQueryBuilder(); + $query->insert('collres_collections'); + $query->execute(); + + $this->id = $query->getLastInsertId(); + } + + protected function makeCollectionUnsteady() { + $query = $this->connection->getQueryBuilder(); + $query->delete('collres_collections') + ->where($query->expr()->eq('id', $query->createNamedParameter($this->id, IQueryBuilder::PARAM_INT))); + $query->execute(); + + $this->id = 0; + } +} diff --git a/lib/private/Collaboration/Resources/Manager.php b/lib/private/Collaboration/Resources/Manager.php new file mode 100644 index 0000000000..e36c4ab1d3 --- /dev/null +++ b/lib/private/Collaboration/Resources/Manager.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 OC\Collaboration\Resources; + + +use OCP\Collaboration\Resources\ICollection; +use OCP\Collaboration\Resources\IManager; +use OCP\Collaboration\Resources\IResource; +use OCP\IDBConnection; + +class Manager implements IManager { + + /** @var IDBConnection */ + protected $connection; + + public function __construct(IDBConnection $connection) { + $this->connection = $connection; + } + + /** + * @param int $id + * @return ICollection + * @since 15.0.0 + */ + public function getCollection(int $id): ICollection { + return new Collection($this, $this->connection, $id); + } + + /** + * @param string $type + * @param string $id + * @return IResource + * @since 15.0.0 + */ + public function getResource(string $type, string $id): IResource { + return new Resource($this, $this->connection, $type, $id); + } +} diff --git a/lib/private/Collaboration/Resources/Resource.php b/lib/private/Collaboration/Resources/Resource.php new file mode 100644 index 0000000000..f82ceff559 --- /dev/null +++ b/lib/private/Collaboration/Resources/Resource.php @@ -0,0 +1,91 @@ + + * + * @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 OC\Collaboration\Resources; + + +use OCP\Collaboration\Resources\ICollection; +use OCP\Collaboration\Resources\IManager; +use OCP\Collaboration\Resources\IResource; +use OCP\IDBConnection; + +class Resource implements IResource { + + /** @var IManager */ + protected $manager; + + /** @var IDBConnection */ + protected $connection; + + /** @var string */ + protected $type; + + /** @var string */ + protected $id; + + public function __construct(IManager $manager, IDBConnection $connection, string $type, string $id) { + $this->manager = $manager; + $this->connection = $connection; + $this->type = $type; + $this->id = $id; + } + + /** + * @return string + * @since 15.0.0 + */ + public function getType(): string { + return $this->type; + } + + /** + * @return string + * @since 15.0.0 + */ + public function getId(): string { + return $this->id; + } + + /** + * @param IResource $resource + * @return ICollection[] + * @since 15.0.0 + */ + public function getCollections(IResource $resource): array { + $collections = []; + + $query = $this->connection->getQueryBuilder(); + + $query->select('collection_id') + ->from('collres_resources') + ->where($query->expr()->eq('resource_type', $query->createNamedParameter($resource->getType()))) + ->andWhere($query->expr()->eq('resource_id', $query->createNamedParameter($resource->getId()))); + + $result = $query->execute(); + while ($row = $result->fetch()) { + $collections[] = $this->manager->getCollection((int) $row['collection_id']); + } + $result->closeCursor(); + + return $collections; + } +} diff --git a/lib/public/Collaboration/Resources/ICollection.php b/lib/public/Collaboration/Resources/ICollection.php new file mode 100644 index 0000000000..408ec67401 --- /dev/null +++ b/lib/public/Collaboration/Resources/ICollection.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 OCP\Collaboration\Resources; + +/** + * @since 15.0.0 + */ +interface ICollection { + + /** + * @return IResource[] + * @since 15.0.0 + */ + public function getResources(): array; + + /** + * Adds a resource to a collection + * + * @param IResource $resource + * @throws ResourceException when the resource is already part of the collection + * @since 15.0.0 + */ + public function addResource(IResource $resource); + + /** + * Removes a resource from a collection + * + * @param IResource $resource + * @since 15.0.0 + */ + public function removeResource(IResource $resource); +} diff --git a/lib/public/Collaboration/Resources/IManager.php b/lib/public/Collaboration/Resources/IManager.php new file mode 100644 index 0000000000..9a7fda28bb --- /dev/null +++ b/lib/public/Collaboration/Resources/IManager.php @@ -0,0 +1,45 @@ + + * + * @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 OCP\Collaboration\Resources; + +/** + * @since 15.0.0 + */ +interface IManager extends IProvider { + + /** + * @param int $id + * @return ICollection + * @since 15.0.0 + */ + public function getCollection(int $id): ICollection; + + /** + * @param string $type + * @param string $id + * @return IResource + * @since 15.0.0 + */ + public function getResource(string $type, string $id): IResource; + +} diff --git a/lib/public/Collaboration/Resources/IProvider.php b/lib/public/Collaboration/Resources/IProvider.php new file mode 100644 index 0000000000..06e2a6a81e --- /dev/null +++ b/lib/public/Collaboration/Resources/IProvider.php @@ -0,0 +1,27 @@ + + * + * @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 OCP\Collaboration\Resources; + + +interface IProvider { + +} diff --git a/lib/public/Collaboration/Resources/IResource.php b/lib/public/Collaboration/Resources/IResource.php new file mode 100644 index 0000000000..42631bc27a --- /dev/null +++ b/lib/public/Collaboration/Resources/IResource.php @@ -0,0 +1,48 @@ + + * + * @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 OCP\Collaboration\Resources; + +/** + * @since 15.0.0 + */ +interface IResource { + + /** + * @return string + * @since 15.0.0 + */ + public function getType(): string; + + /** + * @return string + * @since 15.0.0 + */ + public function getId(): string; + + /** + * @param IResource $resource + * @return ICollection[] + * @since 15.0.0 + */ + public function getCollections(IResource $resource): array; +} diff --git a/lib/public/Collaboration/Resources/ResourceException.php b/lib/public/Collaboration/Resources/ResourceException.php new file mode 100644 index 0000000000..f31b2031a8 --- /dev/null +++ b/lib/public/Collaboration/Resources/ResourceException.php @@ -0,0 +1,27 @@ + + * + * @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 OCP\Collaboration\Resources; + + +class ResourceException extends \RuntimeException { + +} From 65a9ab47ea233701b559d08d89e36649a3d5a30b Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Tue, 16 Oct 2018 17:48:16 +0200 Subject: [PATCH 02/53] Add a controller with the most important methods Signed-off-by: Joas Schilling --- .../CollaborationResourcesController.php | 163 ++++++++++++++++++ core/routes.php | 5 + .../Collaboration/Resources/Resource.php | 7 +- .../Resources/CollectionException.php | 28 +++ .../Collaboration/Resources/IProvider.php | 1 + .../Collaboration/Resources/IResource.php | 3 +- .../Resources/ResourceException.php | 1 + 7 files changed, 202 insertions(+), 6 deletions(-) create mode 100644 core/Controller/CollaborationResourcesController.php create mode 100644 lib/public/Collaboration/Resources/CollectionException.php diff --git a/core/Controller/CollaborationResourcesController.php b/core/Controller/CollaborationResourcesController.php new file mode 100644 index 0000000000..b56d67d845 --- /dev/null +++ b/core/Controller/CollaborationResourcesController.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 OC\Core\Controller; + +use OCP\AppFramework\Http; +use OCP\AppFramework\OCSController; +use OCP\AppFramework\Http\DataResponse; +use OCP\Collaboration\Resources\CollectionException; +use OCP\Collaboration\Resources\ICollection; +use OCP\Collaboration\Resources\IManager; +use OCP\Collaboration\Resources\IResource; +use OCP\Collaboration\Resources\ResourceException; +use OCP\IRequest; + +class CollaborationResourcesController extends OCSController { + /** @var IManager */ + private $manager; + + public function __construct( + $appName, + IRequest $request, + IManager $manager + ) { + parent::__construct($appName, $request); + + $this->manager = $manager; + } + + /** + * @param int $collectionId + * @return ICollection + * @throws CollectionException when the collection was not found for the user + */ + protected function getCollection(int $collectionId): ICollection { + $collection = $this->manager->getCollection($collectionId); + + if (false) { // TODO auth checking + throw new CollectionException('Not found'); + } + + return $collection; + } + + /** + * @NoAdminRequired + * + * @param int $collectionId + * @return DataResponse + */ + public function listCollection(int $collectionId): DataResponse { + try { + $collection = $this->getCollection($collectionId); + } catch (CollectionException $e) { + return new DataResponse([], Http::STATUS_NOT_FOUND); + } + + return new DataResponse($this->prepareCollection($collection)); + } + + /** + * @NoAdminRequired + * + * @param int $collectionId + * @param string $resourceType + * @param string $resourceId + * @return DataResponse + */ + public function addResource(int $collectionId, string $resourceType, string $resourceId): DataResponse { + try { + $collection = $this->getCollection($collectionId); + } catch (CollectionException $e) { + return new DataResponse([], Http::STATUS_NOT_FOUND); + } + + try { + $resource = $this->manager->getResource($resourceType, $resourceId); + } catch (ResourceException $e) { + return new DataResponse([], Http::STATUS_NOT_FOUND); + } + + try { + $collection->addResource($resource); + } catch (ResourceException $e) { + } + + return new DataResponse($this->prepareCollection($collection)); + } + + /** + * @NoAdminRequired + * + * @param int $collectionId + * @param string $resourceType + * @param string $resourceId + * @return DataResponse + */ + public function removeResource(int $collectionId, string $resourceType, string $resourceId): DataResponse { + try { + $collection = $this->getCollection($collectionId); + } catch (CollectionException $e) { + return new DataResponse([], Http::STATUS_NOT_FOUND); + } + + try { + $resource = $this->manager->getResource($resourceType, $resourceId); + } catch (CollectionException $e) { + return new DataResponse([], Http::STATUS_NOT_FOUND); + } + + $collection->removeResource($resource); + + return new DataResponse($this->prepareCollection($collection)); + } + + /** + * @NoAdminRequired + * + * @param string $resourceType + * @param string $resourceId + * @return DataResponse + */ + public function getCollectionsByResource(string $resourceType, string $resourceId): DataResponse { + try { + // TODO auth checking + $resource = $this->manager->getResource($resourceType, $resourceId); + } catch (CollectionException $e) { + return new DataResponse([], Http::STATUS_NOT_FOUND); + } + + return new DataResponse(array_map([$this, 'prepareCollection'], $resource->getCollections())); + } + + protected function prepareCollection(ICollection $collection): array { + return array_map([$this, 'prepareResources'], $collection->getResources()); + } + + protected function prepareResources(IResource $resource): array { + return [ + 'type' => $resource->getType(), + 'id' => $resource->getId() + ]; + } +} diff --git a/core/routes.php b/core/routes.php index d79fea1ca2..7fcd576d32 100644 --- a/core/routes.php +++ b/core/routes.php @@ -90,6 +90,11 @@ $application->registerRoutes($this, [ ['root' => '/core', 'name' => 'WhatsNew#get', 'url' => '/whatsnew', 'verb' => 'GET'], ['root' => '/core', 'name' => 'WhatsNew#dismiss', 'url' => '/whatsnew', 'verb' => 'POST'], ['root' => '/core', 'name' => 'AppPassword#getAppPassword', 'url' => '/getapppassword', 'verb' => 'GET'], + + ['root' => '/collaboration', 'name' => 'CollaborationResources#listCollection', 'url' => '/resources/collections/{collectionId}', 'verb' => 'GET'], + ['root' => '/collaboration', 'name' => 'CollaborationResources#addResource', 'url' => '/resources/collections/{collectionId}', 'verb' => 'POST'], + ['root' => '/collaboration', 'name' => 'CollaborationResources#removeResource', 'url' => '/resources/collections/{collectionId}', 'verb' => 'DELETE'], + ['root' => '/collaboration', 'name' => 'CollaborationResources#getCollectionsByResource', 'url' => '/resources/{resourceType}/{resourceId}', 'verb' => 'GET'], ], ]); diff --git a/lib/private/Collaboration/Resources/Resource.php b/lib/private/Collaboration/Resources/Resource.php index f82ceff559..0eda8ba55c 100644 --- a/lib/private/Collaboration/Resources/Resource.php +++ b/lib/private/Collaboration/Resources/Resource.php @@ -66,19 +66,18 @@ class Resource implements IResource { } /** - * @param IResource $resource * @return ICollection[] * @since 15.0.0 */ - public function getCollections(IResource $resource): array { + public function getCollections(): array { $collections = []; $query = $this->connection->getQueryBuilder(); $query->select('collection_id') ->from('collres_resources') - ->where($query->expr()->eq('resource_type', $query->createNamedParameter($resource->getType()))) - ->andWhere($query->expr()->eq('resource_id', $query->createNamedParameter($resource->getId()))); + ->where($query->expr()->eq('resource_type', $query->createNamedParameter($this->getType()))) + ->andWhere($query->expr()->eq('resource_id', $query->createNamedParameter($this->getId()))); $result = $query->execute(); while ($row = $result->fetch()) { diff --git a/lib/public/Collaboration/Resources/CollectionException.php b/lib/public/Collaboration/Resources/CollectionException.php new file mode 100644 index 0000000000..f5130d37d6 --- /dev/null +++ b/lib/public/Collaboration/Resources/CollectionException.php @@ -0,0 +1,28 @@ + + * + * @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 OCP\Collaboration\Resources; + + +class CollectionException extends \RuntimeException { + +} diff --git a/lib/public/Collaboration/Resources/IProvider.php b/lib/public/Collaboration/Resources/IProvider.php index 06e2a6a81e..eac92733de 100644 --- a/lib/public/Collaboration/Resources/IProvider.php +++ b/lib/public/Collaboration/Resources/IProvider.php @@ -1,4 +1,5 @@ * diff --git a/lib/public/Collaboration/Resources/IResource.php b/lib/public/Collaboration/Resources/IResource.php index 42631bc27a..9f8628c0d4 100644 --- a/lib/public/Collaboration/Resources/IResource.php +++ b/lib/public/Collaboration/Resources/IResource.php @@ -40,9 +40,8 @@ interface IResource { public function getId(): string; /** - * @param IResource $resource * @return ICollection[] * @since 15.0.0 */ - public function getCollections(IResource $resource): array; + public function getCollections(): array; } diff --git a/lib/public/Collaboration/Resources/ResourceException.php b/lib/public/Collaboration/Resources/ResourceException.php index f31b2031a8..d03264bcef 100644 --- a/lib/public/Collaboration/Resources/ResourceException.php +++ b/lib/public/Collaboration/Resources/ResourceException.php @@ -1,4 +1,5 @@ * From 136d2c39ac72f837a3ea9a3f698be963fefb69a3 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 17 Oct 2018 20:03:44 +0200 Subject: [PATCH 03/53] Provider functionality Signed-off-by: Joas Schilling --- .../CollaborationResourcesController.php | 21 ++++++-- .../Collaboration/Resources/Collection.php | 18 +++++++ .../Collaboration/Resources/Manager.php | 50 +++++++++++++++++++ .../Collaboration/Resources/Resource.php | 28 +++++++++++ .../Collaboration/Resources/ICollection.php | 11 ++++ .../Collaboration/Resources/IProvider.php | 20 ++++++++ .../Collaboration/Resources/IResource.php | 17 +++++++ 7 files changed, 160 insertions(+), 5 deletions(-) diff --git a/core/Controller/CollaborationResourcesController.php b/core/Controller/CollaborationResourcesController.php index b56d67d845..bd8c8442ae 100644 --- a/core/Controller/CollaborationResourcesController.php +++ b/core/Controller/CollaborationResourcesController.php @@ -31,19 +31,26 @@ use OCP\Collaboration\Resources\IManager; use OCP\Collaboration\Resources\IResource; use OCP\Collaboration\Resources\ResourceException; use OCP\IRequest; +use OCP\IUserSession; class CollaborationResourcesController extends OCSController { + /** @var IManager */ private $manager; + /** @var IUserSession */ + private $userSession; + public function __construct( - $appName, + string $appName, IRequest $request, - IManager $manager + IManager $manager, + IUserSession $userSession ) { parent::__construct($appName, $request); $this->manager = $manager; + $this->userSession = $userSession; } /** @@ -54,7 +61,7 @@ class CollaborationResourcesController extends OCSController { protected function getCollection(int $collectionId): ICollection { $collection = $this->manager->getCollection($collectionId); - if (false) { // TODO auth checking + if (!$collection->canAccess($this->userSession->getUser())) { throw new CollectionException('Not found'); } @@ -141,12 +148,15 @@ class CollaborationResourcesController extends OCSController { */ public function getCollectionsByResource(string $resourceType, string $resourceId): DataResponse { try { - // TODO auth checking $resource = $this->manager->getResource($resourceType, $resourceId); } catch (CollectionException $e) { return new DataResponse([], Http::STATUS_NOT_FOUND); } + if (!$resource->canAccess($this->userSession->getUser())) { + return new DataResponse([], Http::STATUS_NOT_FOUND); + } + return new DataResponse(array_map([$this, 'prepareCollection'], $resource->getCollections())); } @@ -157,7 +167,8 @@ class CollaborationResourcesController extends OCSController { protected function prepareResources(IResource $resource): array { return [ 'type' => $resource->getType(), - 'id' => $resource->getId() + 'id' => $resource->getId(), + 'name' => $resource->getName(), ]; } } diff --git a/lib/private/Collaboration/Resources/Collection.php b/lib/private/Collaboration/Resources/Collection.php index 8509b4442d..e89f62c051 100644 --- a/lib/private/Collaboration/Resources/Collection.php +++ b/lib/private/Collaboration/Resources/Collection.php @@ -30,6 +30,7 @@ use OCP\Collaboration\Resources\ICollection; use OCP\Collaboration\Resources\IResource; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; +use OCP\IUser; class Collection implements ICollection { @@ -131,6 +132,23 @@ class Collection implements ICollection { } } + /** + * Can a user/guest access the collection + * + * @param IUser $user + * @return bool + * @since 15.0.0 + */ + public function canAccess(IUser $user = null): bool { + foreach ($this->getResources() as $resource) { + if ($resource->canAccess($user)) { + return true; + } + } + + return false; + } + protected function isSameResource(IResource $resource1, IResource $resource2): bool { return $resource1->getType() === $resource2->getType() && $resource1->getId() === $resource2->getId(); diff --git a/lib/private/Collaboration/Resources/Manager.php b/lib/private/Collaboration/Resources/Manager.php index e36c4ab1d3..8302d4a100 100644 --- a/lib/private/Collaboration/Resources/Manager.php +++ b/lib/private/Collaboration/Resources/Manager.php @@ -25,8 +25,11 @@ namespace OC\Collaboration\Resources; use OCP\Collaboration\Resources\ICollection; use OCP\Collaboration\Resources\IManager; +use OCP\Collaboration\Resources\IProvider; use OCP\Collaboration\Resources\IResource; +use OCP\Collaboration\Resources\ResourceException; use OCP\IDBConnection; +use OCP\IUser; class Manager implements IManager { @@ -55,4 +58,51 @@ class Manager implements IManager { public function getResource(string $type, string $id): IResource { return new Resource($this, $this->connection, $type, $id); } + + /** + * @return IProvider[] + * @since 15.0.0 + */ + public function getProviders(): array { + return []; + } + + /** + * Get the display name of a resource + * + * @param IResource $resource + * @return string + * @since 15.0.0 + */ + public function getName(IResource $resource): string { + foreach ($this->getProviders() as $provider) { + try { + return $provider->getName($resource); + } catch (ResourceException $e) { + } + } + + return ''; + } + + /** + * Can a user/guest access the collection + * + * @param IResource $resource + * @param IUser $user + * @return bool + * @since 15.0.0 + */ + public function canAccess(IResource $resource, IUser $user = null): bool { + foreach ($this->getProviders() as $provider) { + try { + if ($provider->canAccess($resource, $user)) { + return true; + } + } catch (ResourceException $e) { + } + } + + return false; + } } diff --git a/lib/private/Collaboration/Resources/Resource.php b/lib/private/Collaboration/Resources/Resource.php index 0eda8ba55c..144af6d358 100644 --- a/lib/private/Collaboration/Resources/Resource.php +++ b/lib/private/Collaboration/Resources/Resource.php @@ -26,7 +26,9 @@ namespace OC\Collaboration\Resources; use OCP\Collaboration\Resources\ICollection; use OCP\Collaboration\Resources\IManager; use OCP\Collaboration\Resources\IResource; +use OCP\Collaboration\Resources\ResourceException; use OCP\IDBConnection; +use OCP\IUser; class Resource implements IResource { @@ -42,6 +44,9 @@ class Resource implements IResource { /** @var string */ protected $id; + /** @var string|null */ + protected $name; + public function __construct(IManager $manager, IDBConnection $connection, string $type, string $id) { $this->manager = $manager; $this->connection = $connection; @@ -65,6 +70,29 @@ class Resource implements IResource { return $this->id; } + /** + * @return string + * @since 15.0.0 + */ + public function getName(): string { + if ($this->name === null) { + $this->name = $this->manager->getName($this); + } + + return $this->name; + } + + /** + * Can a user/guest access the resource + * + * @param IUser $user + * @return bool + * @since 15.0.0 + */ + public function canAccess(IUser $user = null): bool { + return $this->manager->canAccess($this, $user); + } + /** * @return ICollection[] * @since 15.0.0 diff --git a/lib/public/Collaboration/Resources/ICollection.php b/lib/public/Collaboration/Resources/ICollection.php index 408ec67401..0859ee3397 100644 --- a/lib/public/Collaboration/Resources/ICollection.php +++ b/lib/public/Collaboration/Resources/ICollection.php @@ -22,6 +22,8 @@ declare(strict_types=1); namespace OCP\Collaboration\Resources; +use OCP\IUser; + /** * @since 15.0.0 */ @@ -49,4 +51,13 @@ interface ICollection { * @since 15.0.0 */ public function removeResource(IResource $resource); + + /** + * Can a user/guest access the collection + * + * @param IUser $user + * @return bool + * @since 15.0.0 + */ + public function canAccess(IUser $user = null): bool; } diff --git a/lib/public/Collaboration/Resources/IProvider.php b/lib/public/Collaboration/Resources/IProvider.php index eac92733de..bf33811300 100644 --- a/lib/public/Collaboration/Resources/IProvider.php +++ b/lib/public/Collaboration/Resources/IProvider.php @@ -22,7 +22,27 @@ declare(strict_types=1); namespace OCP\Collaboration\Resources; +use OCP\IUser; interface IProvider { + /** + * Get the display name of a resource + * + * @param IResource $resource + * @return string + * @since 15.0.0 + */ + public function getName(IResource $resource): string; + + /** + * Can a user/guest access the collection + * + * @param IResource $resource + * @param IUser $user + * @return bool + * @since 15.0.0 + */ + public function canAccess(IResource $resource, IUser $user = null): bool; + } diff --git a/lib/public/Collaboration/Resources/IResource.php b/lib/public/Collaboration/Resources/IResource.php index 9f8628c0d4..242ad9432d 100644 --- a/lib/public/Collaboration/Resources/IResource.php +++ b/lib/public/Collaboration/Resources/IResource.php @@ -22,6 +22,8 @@ declare(strict_types=1); namespace OCP\Collaboration\Resources; +use OCP\IUser; + /** * @since 15.0.0 */ @@ -39,6 +41,21 @@ interface IResource { */ public function getId(): string; + /** + * @return string + * @since 15.0.0 + */ + public function getName(): string; + + /** + * Can a user/guest access the resource + * + * @param IUser $user + * @return bool + * @since 15.0.0 + */ + public function canAccess(IUser $user = null): bool; + /** * @return ICollection[] * @since 15.0.0 From 5dfc56e925309d637be6f5a69cc16d0baaf20d03 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 18 Oct 2018 13:00:25 +0200 Subject: [PATCH 04/53] Allow to create collections Signed-off-by: Joas Schilling --- .../CollaborationResourcesController.php | 34 ++++++++++++++++++- core/routes.php | 1 + .../Collaboration/Resources/Manager.php | 8 +++++ .../Collaboration/Resources/ICollection.php | 6 ++++ .../Collaboration/Resources/IManager.php | 6 ++++ 5 files changed, 54 insertions(+), 1 deletion(-) diff --git a/core/Controller/CollaborationResourcesController.php b/core/Controller/CollaborationResourcesController.php index bd8c8442ae..453a6405e5 100644 --- a/core/Controller/CollaborationResourcesController.php +++ b/core/Controller/CollaborationResourcesController.php @@ -160,8 +160,40 @@ class CollaborationResourcesController extends OCSController { return new DataResponse(array_map([$this, 'prepareCollection'], $resource->getCollections())); } + /** + * @NoAdminRequired + * + * @param string $baseResourceType + * @param string $baseResourceId + * @param string $resourceType + * @param string $resourceId + * @return DataResponse + */ + public function createCollectionOnResource(string $baseResourceType, string $baseResourceId, string $resourceType, string $resourceId): DataResponse { + try { + $baseResource = $this->manager->getResource($baseResourceType, $baseResourceId); + $resource = $this->manager->getResource($resourceType, $resourceId); + } catch (CollectionException $e) { + return new DataResponse([], Http::STATUS_NOT_FOUND); + } + + if (!$baseResource->canAccess($this->userSession->getUser()) || + !$resource->canAccess($this->userSession->getUser())) { + return new DataResponse([], Http::STATUS_NOT_FOUND); + } + + $collection = $this->manager->newCollection(); + $collection->addResource($baseResource); + $collection->addResource($resource); + + return new DataResponse($this->prepareCollection($collection)); + } + protected function prepareCollection(ICollection $collection): array { - return array_map([$this, 'prepareResources'], $collection->getResources()); + return [ + 'id' => $collection->getId(), + 'resources' => array_map([$this, 'prepareResources'], $collection->getResources()), + ]; } protected function prepareResources(IResource $resource): array { diff --git a/core/routes.php b/core/routes.php index 7fcd576d32..079f99d265 100644 --- a/core/routes.php +++ b/core/routes.php @@ -95,6 +95,7 @@ $application->registerRoutes($this, [ ['root' => '/collaboration', 'name' => 'CollaborationResources#addResource', 'url' => '/resources/collections/{collectionId}', 'verb' => 'POST'], ['root' => '/collaboration', 'name' => 'CollaborationResources#removeResource', 'url' => '/resources/collections/{collectionId}', 'verb' => 'DELETE'], ['root' => '/collaboration', 'name' => 'CollaborationResources#getCollectionsByResource', 'url' => '/resources/{resourceType}/{resourceId}', 'verb' => 'GET'], + ['root' => '/collaboration', 'name' => 'CollaborationResources#createCollectionOnResource', 'url' => '/resources/{baseResourceType}/{baseResourceId}', 'verb' => 'POST'], ], ]); diff --git a/lib/private/Collaboration/Resources/Manager.php b/lib/private/Collaboration/Resources/Manager.php index 8302d4a100..c091f5c580 100644 --- a/lib/private/Collaboration/Resources/Manager.php +++ b/lib/private/Collaboration/Resources/Manager.php @@ -49,6 +49,14 @@ class Manager implements IManager { return new Collection($this, $this->connection, $id); } + /** + * @return ICollection + * @since 15.0.0 + */ + public function newCollection(): ICollection { + return new Collection($this, $this->connection, 0); + } + /** * @param string $type * @param string $id diff --git a/lib/public/Collaboration/Resources/ICollection.php b/lib/public/Collaboration/Resources/ICollection.php index 0859ee3397..1f503d8083 100644 --- a/lib/public/Collaboration/Resources/ICollection.php +++ b/lib/public/Collaboration/Resources/ICollection.php @@ -29,6 +29,12 @@ use OCP\IUser; */ interface ICollection { + /** + * @return int + * @since 15.0.0 + */ + public function getId(): int; + /** * @return IResource[] * @since 15.0.0 diff --git a/lib/public/Collaboration/Resources/IManager.php b/lib/public/Collaboration/Resources/IManager.php index 9a7fda28bb..abccfd2eed 100644 --- a/lib/public/Collaboration/Resources/IManager.php +++ b/lib/public/Collaboration/Resources/IManager.php @@ -34,6 +34,12 @@ interface IManager extends IProvider { */ public function getCollection(int $id): ICollection; + /** + * @return ICollection + * @since 15.0.0 + */ + public function newCollection(): ICollection; + /** * @param string $type * @param string $id From 702dcfb72848b36921a310188aa019d810668ebc Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 24 Oct 2018 14:25:35 +0200 Subject: [PATCH 05/53] Make names mandatory Signed-off-by: Joas Schilling --- .../composer/composer/autoload_classmap.php | 1 + .../composer/composer/autoload_static.php | 1 + .../Resources/ResourceProvider.php | 83 +++++++++++++++++++ .../CollaborationResourcesController.php | 17 ++-- .../Version15000Date20180917092725.php | 4 + lib/composer/composer/autoload_classmap.php | 11 +++ lib/composer/composer/autoload_static.php | 11 +++ .../DependencyInjection/DIContainer.php | 1 + .../Collaboration/Resources/Collection.php | 43 ++++++---- .../Collaboration/Resources/Manager.php | 31 ++++++- .../Collaboration/Resources/Resource.php | 7 +- .../Collaboration/Resources/ICollection.php | 6 ++ .../Collaboration/Resources/IManager.php | 4 +- 13 files changed, 191 insertions(+), 29 deletions(-) create mode 100644 apps/files/lib/Collaboration/Resources/ResourceProvider.php diff --git a/apps/files/composer/composer/autoload_classmap.php b/apps/files/composer/composer/autoload_classmap.php index 3fe29a5dd5..fe4477635c 100644 --- a/apps/files/composer/composer/autoload_classmap.php +++ b/apps/files/composer/composer/autoload_classmap.php @@ -23,6 +23,7 @@ return array( 'OCA\\Files\\BackgroundJob\\DeleteOrphanedItems' => $baseDir . '/../lib/BackgroundJob/DeleteOrphanedItems.php', 'OCA\\Files\\BackgroundJob\\ScanFiles' => $baseDir . '/../lib/BackgroundJob/ScanFiles.php', 'OCA\\Files\\Capabilities' => $baseDir . '/../lib/Capabilities.php', + 'OCA\\Files\\Collaboration\\Resources\\ResourceProvider' => $baseDir . '/../lib/Collaboration/Resources/ResourceProvider.php', 'OCA\\Files\\Command\\DeleteOrphanedFiles' => $baseDir . '/../lib/Command/DeleteOrphanedFiles.php', 'OCA\\Files\\Command\\Scan' => $baseDir . '/../lib/Command/Scan.php', 'OCA\\Files\\Command\\ScanAppData' => $baseDir . '/../lib/Command/ScanAppData.php', diff --git a/apps/files/composer/composer/autoload_static.php b/apps/files/composer/composer/autoload_static.php index 7dd1508383..9da1be7be0 100644 --- a/apps/files/composer/composer/autoload_static.php +++ b/apps/files/composer/composer/autoload_static.php @@ -38,6 +38,7 @@ class ComposerStaticInitFiles 'OCA\\Files\\BackgroundJob\\DeleteOrphanedItems' => __DIR__ . '/..' . '/../lib/BackgroundJob/DeleteOrphanedItems.php', 'OCA\\Files\\BackgroundJob\\ScanFiles' => __DIR__ . '/..' . '/../lib/BackgroundJob/ScanFiles.php', 'OCA\\Files\\Capabilities' => __DIR__ . '/..' . '/../lib/Capabilities.php', + 'OCA\\Files\\Collaboration\\Resources\\ResourceProvider' => __DIR__ . '/..' . '/../lib/Collaboration/Resources/ResourceProvider.php', 'OCA\\Files\\Command\\DeleteOrphanedFiles' => __DIR__ . '/..' . '/../lib/Command/DeleteOrphanedFiles.php', 'OCA\\Files\\Command\\Scan' => __DIR__ . '/..' . '/../lib/Command/Scan.php', 'OCA\\Files\\Command\\ScanAppData' => __DIR__ . '/..' . '/../lib/Command/ScanAppData.php', diff --git a/apps/files/lib/Collaboration/Resources/ResourceProvider.php b/apps/files/lib/Collaboration/Resources/ResourceProvider.php new file mode 100644 index 0000000000..6d9b1b5978 --- /dev/null +++ b/apps/files/lib/Collaboration/Resources/ResourceProvider.php @@ -0,0 +1,83 @@ + + * + * @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\Files\Collaboration\Resources; + + +use OCP\Collaboration\Resources\IProvider; +use OCP\Collaboration\Resources\IResource; +use OCP\Files\IRootFolder; +use OCP\IUser; + +class ResourceProvider implements IProvider { + + /** @var IRootFolder */ + protected $rootFolder; + + /** @var array */ + protected $nodes = []; + + public function __construct(IRootFolder $rootFolder) { + $this->rootFolder = $rootFolder; + } + + /** + * Get the display name of a resource + * + * @param IResource $resource + * @return string + * @since 15.0.0 + */ + public function getName(IResource $resource): string { + if (isset($this->nodes[(int) $resource->getId()])) { + return $this->nodes[(int) $resource->getId()]->getPath(); + } + return ''; + } + + /** + * Can a user/guest access the collection + * + * @param IResource $resource + * @param IUser $user + * @return bool + * @since 15.0.0 + */ + public function canAccess(IResource $resource, IUser $user = null): bool { + if ($resource->getType() !== 'files') { + return false; + } + + if (!$user instanceof IUser) { + return false; + } + + $userFolder = $this->rootFolder->getUserFolder($user->getUID()); + $nodes = $userFolder->getById((int) $resource->getId()); + + if (!empty($nodes)) { + $this->nodes[(int) $resource->getId()] = array_shift($nodes); + return true; + } + + return false; + } +} diff --git a/core/Controller/CollaborationResourcesController.php b/core/Controller/CollaborationResourcesController.php index 453a6405e5..e9fc7b1ac7 100644 --- a/core/Controller/CollaborationResourcesController.php +++ b/core/Controller/CollaborationResourcesController.php @@ -163,27 +163,27 @@ class CollaborationResourcesController extends OCSController { /** * @NoAdminRequired * - * @param string $baseResourceType - * @param string $baseResourceId * @param string $resourceType * @param string $resourceId + * @param string $name * @return DataResponse */ - public function createCollectionOnResource(string $baseResourceType, string $baseResourceId, string $resourceType, string $resourceId): DataResponse { + public function createCollectionOnResource(string $resourceType, string $resourceId, string $name): DataResponse { + if (!isset($name[0]) || isset($name[64])) { + return new DataResponse([], Http::STATUS_BAD_REQUEST); + } + try { - $baseResource = $this->manager->getResource($baseResourceType, $baseResourceId); $resource = $this->manager->getResource($resourceType, $resourceId); } catch (CollectionException $e) { return new DataResponse([], Http::STATUS_NOT_FOUND); } - if (!$baseResource->canAccess($this->userSession->getUser()) || - !$resource->canAccess($this->userSession->getUser())) { + if (!$resource->canAccess($this->userSession->getUser())) { return new DataResponse([], Http::STATUS_NOT_FOUND); } - $collection = $this->manager->newCollection(); - $collection->addResource($baseResource); + $collection = $this->manager->newCollection($name); $collection->addResource($resource); return new DataResponse($this->prepareCollection($collection)); @@ -192,6 +192,7 @@ class CollaborationResourcesController extends OCSController { protected function prepareCollection(ICollection $collection): array { return [ 'id' => $collection->getId(), + 'name' => $collection->getName(), 'resources' => array_map([$this, 'prepareResources'], $collection->getResources()), ]; } diff --git a/core/Migrations/Version15000Date20180917092725.php b/core/Migrations/Version15000Date20180917092725.php index 9dbc5efced..1bcc638274 100644 --- a/core/Migrations/Version15000Date20180917092725.php +++ b/core/Migrations/Version15000Date20180917092725.php @@ -48,6 +48,10 @@ class Version15000Date20180917092725 extends SimpleMigrationStep { 'autoincrement' => true, 'notnull' => true, ]); + $table->addColumn('name', Type::STRING, [ + 'notnull' => true, + 'length' => 64, + ]); $table->setPrimaryKey(['id']); } diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index e1f5e2b8c9..af347b1ea9 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -112,6 +112,12 @@ return array( 'OCP\\Collaboration\\Collaborators\\ISearchPlugin' => $baseDir . '/lib/public/Collaboration/Collaborators/ISearchPlugin.php', 'OCP\\Collaboration\\Collaborators\\ISearchResult' => $baseDir . '/lib/public/Collaboration/Collaborators/ISearchResult.php', 'OCP\\Collaboration\\Collaborators\\SearchResultType' => $baseDir . '/lib/public/Collaboration/Collaborators/SearchResultType.php', + 'OCP\\Collaboration\\Resources\\CollectionException' => $baseDir . '/lib/public/Collaboration/Resources/CollectionException.php', + 'OCP\\Collaboration\\Resources\\ICollection' => $baseDir . '/lib/public/Collaboration/Resources/ICollection.php', + 'OCP\\Collaboration\\Resources\\IManager' => $baseDir . '/lib/public/Collaboration/Resources/IManager.php', + 'OCP\\Collaboration\\Resources\\IProvider' => $baseDir . '/lib/public/Collaboration/Resources/IProvider.php', + 'OCP\\Collaboration\\Resources\\IResource' => $baseDir . '/lib/public/Collaboration/Resources/IResource.php', + 'OCP\\Collaboration\\Resources\\ResourceException' => $baseDir . '/lib/public/Collaboration/Resources/ResourceException.php', 'OCP\\Command\\IBus' => $baseDir . '/lib/public/Command/IBus.php', 'OCP\\Command\\ICommand' => $baseDir . '/lib/public/Command/ICommand.php', 'OCP\\Comments\\CommentsEntityEvent' => $baseDir . '/lib/public/Comments/CommentsEntityEvent.php', @@ -544,6 +550,9 @@ return array( 'OC\\Collaboration\\Collaborators\\Search' => $baseDir . '/lib/private/Collaboration/Collaborators/Search.php', 'OC\\Collaboration\\Collaborators\\SearchResult' => $baseDir . '/lib/private/Collaboration/Collaborators/SearchResult.php', 'OC\\Collaboration\\Collaborators\\UserPlugin' => $baseDir . '/lib/private/Collaboration/Collaborators/UserPlugin.php', + 'OC\\Collaboration\\Resources\\Collection' => $baseDir . '/lib/private/Collaboration/Resources/Collection.php', + 'OC\\Collaboration\\Resources\\Manager' => $baseDir . '/lib/private/Collaboration/Resources/Manager.php', + 'OC\\Collaboration\\Resources\\Resource' => $baseDir . '/lib/private/Collaboration/Resources/Resource.php', 'OC\\Color' => $baseDir . '/lib/private/Color.php', 'OC\\Command\\AsyncBus' => $baseDir . '/lib/private/Command/AsyncBus.php', 'OC\\Command\\CallableJob' => $baseDir . '/lib/private/Command/CallableJob.php', @@ -659,6 +668,7 @@ return array( 'OC\\Core\\Controller\\CSRFTokenController' => $baseDir . '/core/Controller/CSRFTokenController.php', 'OC\\Core\\Controller\\ClientFlowLoginController' => $baseDir . '/core/Controller/ClientFlowLoginController.php', 'OC\\Core\\Controller\\ClientFlowLoginV2Controller' => $baseDir . '/core/Controller/ClientFlowLoginV2Controller.php', + 'OC\\Core\\Controller\\CollaborationResourcesController' => $baseDir . '/core/Controller/CollaborationResourcesController.php', 'OC\\Core\\Controller\\ContactsMenuController' => $baseDir . '/core/Controller/ContactsMenuController.php', 'OC\\Core\\Controller\\CssController' => $baseDir . '/core/Controller/CssController.php', 'OC\\Core\\Controller\\GuestAvatarController' => $baseDir . '/core/Controller/GuestAvatarController.php', @@ -695,6 +705,7 @@ return array( 'OC\\Core\\Migrations\\Version14000Date20180626223656' => $baseDir . '/core/Migrations/Version14000Date20180626223656.php', 'OC\\Core\\Migrations\\Version14000Date20180710092004' => $baseDir . '/core/Migrations/Version14000Date20180710092004.php', 'OC\\Core\\Migrations\\Version14000Date20180712153140' => $baseDir . '/core/Migrations/Version14000Date20180712153140.php', + 'OC\\Core\\Migrations\\Version15000Date20180917092725' => $baseDir . '/core/Migrations/Version15000Date20180917092725.php', 'OC\\Core\\Migrations\\Version15000Date20180926101451' => $baseDir . '/core/Migrations/Version15000Date20180926101451.php', 'OC\\Core\\Migrations\\Version15000Date20181015062942' => $baseDir . '/core/Migrations/Version15000Date20181015062942.php', 'OC\\Core\\Migrations\\Version15000Date20181029084625' => $baseDir . '/core/Migrations/Version15000Date20181029084625.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 3f7132316a..9238ad7875 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -142,6 +142,12 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OCP\\Collaboration\\Collaborators\\ISearchPlugin' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Collaborators/ISearchPlugin.php', 'OCP\\Collaboration\\Collaborators\\ISearchResult' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Collaborators/ISearchResult.php', 'OCP\\Collaboration\\Collaborators\\SearchResultType' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Collaborators/SearchResultType.php', + 'OCP\\Collaboration\\Resources\\CollectionException' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Resources/CollectionException.php', + 'OCP\\Collaboration\\Resources\\ICollection' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Resources/ICollection.php', + 'OCP\\Collaboration\\Resources\\IManager' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Resources/IManager.php', + 'OCP\\Collaboration\\Resources\\IProvider' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Resources/IProvider.php', + 'OCP\\Collaboration\\Resources\\IResource' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Resources/IResource.php', + 'OCP\\Collaboration\\Resources\\ResourceException' => __DIR__ . '/../../..' . '/lib/public/Collaboration/Resources/ResourceException.php', 'OCP\\Command\\IBus' => __DIR__ . '/../../..' . '/lib/public/Command/IBus.php', 'OCP\\Command\\ICommand' => __DIR__ . '/../../..' . '/lib/public/Command/ICommand.php', 'OCP\\Comments\\CommentsEntityEvent' => __DIR__ . '/../../..' . '/lib/public/Comments/CommentsEntityEvent.php', @@ -574,6 +580,9 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Collaboration\\Collaborators\\Search' => __DIR__ . '/../../..' . '/lib/private/Collaboration/Collaborators/Search.php', 'OC\\Collaboration\\Collaborators\\SearchResult' => __DIR__ . '/../../..' . '/lib/private/Collaboration/Collaborators/SearchResult.php', 'OC\\Collaboration\\Collaborators\\UserPlugin' => __DIR__ . '/../../..' . '/lib/private/Collaboration/Collaborators/UserPlugin.php', + 'OC\\Collaboration\\Resources\\Collection' => __DIR__ . '/../../..' . '/lib/private/Collaboration/Resources/Collection.php', + 'OC\\Collaboration\\Resources\\Manager' => __DIR__ . '/../../..' . '/lib/private/Collaboration/Resources/Manager.php', + 'OC\\Collaboration\\Resources\\Resource' => __DIR__ . '/../../..' . '/lib/private/Collaboration/Resources/Resource.php', 'OC\\Color' => __DIR__ . '/../../..' . '/lib/private/Color.php', 'OC\\Command\\AsyncBus' => __DIR__ . '/../../..' . '/lib/private/Command/AsyncBus.php', 'OC\\Command\\CallableJob' => __DIR__ . '/../../..' . '/lib/private/Command/CallableJob.php', @@ -689,6 +698,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Core\\Controller\\CSRFTokenController' => __DIR__ . '/../../..' . '/core/Controller/CSRFTokenController.php', 'OC\\Core\\Controller\\ClientFlowLoginController' => __DIR__ . '/../../..' . '/core/Controller/ClientFlowLoginController.php', 'OC\\Core\\Controller\\ClientFlowLoginV2Controller' => __DIR__ . '/../../..' . '/core/Controller/ClientFlowLoginV2Controller.php', + 'OC\\Core\\Controller\\CollaborationResourcesController' => __DIR__ . '/../../..' . '/core/Controller/CollaborationResourcesController.php', 'OC\\Core\\Controller\\ContactsMenuController' => __DIR__ . '/../../..' . '/core/Controller/ContactsMenuController.php', 'OC\\Core\\Controller\\CssController' => __DIR__ . '/../../..' . '/core/Controller/CssController.php', 'OC\\Core\\Controller\\GuestAvatarController' => __DIR__ . '/../../..' . '/core/Controller/GuestAvatarController.php', @@ -725,6 +735,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Core\\Migrations\\Version14000Date20180626223656' => __DIR__ . '/../../..' . '/core/Migrations/Version14000Date20180626223656.php', 'OC\\Core\\Migrations\\Version14000Date20180710092004' => __DIR__ . '/../../..' . '/core/Migrations/Version14000Date20180710092004.php', 'OC\\Core\\Migrations\\Version14000Date20180712153140' => __DIR__ . '/../../..' . '/core/Migrations/Version14000Date20180712153140.php', + 'OC\\Core\\Migrations\\Version15000Date20180917092725' => __DIR__ . '/../../..' . '/core/Migrations/Version15000Date20180917092725.php', 'OC\\Core\\Migrations\\Version15000Date20180926101451' => __DIR__ . '/../../..' . '/core/Migrations/Version15000Date20180926101451.php', 'OC\\Core\\Migrations\\Version15000Date20181015062942' => __DIR__ . '/../../..' . '/core/Migrations/Version15000Date20181015062942.php', 'OC\\Core\\Migrations\\Version15000Date20181029084625' => __DIR__ . '/../../..' . '/core/Migrations/Version15000Date20181029084625.php', diff --git a/lib/private/AppFramework/DependencyInjection/DIContainer.php b/lib/private/AppFramework/DependencyInjection/DIContainer.php index bb63adf398..fc16521cf3 100644 --- a/lib/private/AppFramework/DependencyInjection/DIContainer.php +++ b/lib/private/AppFramework/DependencyInjection/DIContainer.php @@ -283,6 +283,7 @@ class DIContainer extends SimpleContainer implements IAppContainer { return $dispatcher; }); + $this->registerAlias(\OCP\Collaboration\Resources\IManager::class, OC\Collaboration\Resources\Manager::class); } /** diff --git a/lib/private/Collaboration/Resources/Collection.php b/lib/private/Collaboration/Resources/Collection.php index e89f62c051..54c009b917 100644 --- a/lib/private/Collaboration/Resources/Collection.php +++ b/lib/private/Collaboration/Resources/Collection.php @@ -43,16 +43,41 @@ class Collection implements ICollection { /** @var int */ protected $id; + /** @var string */ + protected $name; + /** @var IResource[] */ protected $resources; - public function __construct(IManager $manager, IDBConnection $connection, int $id) { + public function __construct( + IManager $manager, + IDBConnection $connection, + int $id, + string $name + ) { $this->manager = $manager; $this->connection = $connection; $this->id = $id; + $this->name = $name; $this->resources = []; } + /** + * @return int + * @since 15.0.0 + */ + public function getId(): int { + return $this->id; + } + + /** + * @return string + * @since 15.0.0 + */ + public function getName(): string { + return $this->name; + } + /** * @return IResource[] * @since 15.0.0 @@ -90,10 +115,6 @@ class Collection implements ICollection { $this->resources[] = $resource; - if ($this->id === 0) { - $this->makeCollectionPersistent(); - } - $query = $this->connection->getQueryBuilder(); $query->insert('collres_resources') ->values([ @@ -128,7 +149,7 @@ class Collection implements ICollection { $query->execute(); if (empty($this->resources)) { - $this->makeCollectionUnsteady(); + $this->removeCollection(); } } @@ -154,15 +175,7 @@ class Collection implements ICollection { $resource1->getId() === $resource2->getId(); } - protected function makeCollectionPersistent() { - $query = $this->connection->getQueryBuilder(); - $query->insert('collres_collections'); - $query->execute(); - - $this->id = $query->getLastInsertId(); - } - - protected function makeCollectionUnsteady() { + protected function removeCollection() { $query = $this->connection->getQueryBuilder(); $query->delete('collres_collections') ->where($query->expr()->eq('id', $query->createNamedParameter($this->id, IQueryBuilder::PARAM_INT))); diff --git a/lib/private/Collaboration/Resources/Manager.php b/lib/private/Collaboration/Resources/Manager.php index c091f5c580..18301e0f2f 100644 --- a/lib/private/Collaboration/Resources/Manager.php +++ b/lib/private/Collaboration/Resources/Manager.php @@ -23,11 +23,14 @@ declare(strict_types=1); namespace OC\Collaboration\Resources; +use OCA\Files\Collaboration\Resources\ResourceProvider; +use OCP\Collaboration\Resources\CollectionException; use OCP\Collaboration\Resources\ICollection; use OCP\Collaboration\Resources\IManager; use OCP\Collaboration\Resources\IProvider; use OCP\Collaboration\Resources\IResource; use OCP\Collaboration\Resources\ResourceException; +use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; use OCP\IUser; @@ -43,18 +46,36 @@ class Manager implements IManager { /** * @param int $id * @return ICollection + * @throws CollectionException when the collection could not be found * @since 15.0.0 */ public function getCollection(int $id): ICollection { - return new Collection($this, $this->connection, $id); + $query = $this->connection->getQueryBuilder(); + $query->select('*') + ->from('collres_collections') + ->where($query->expr()->eq('id', $query->createNamedParameter($id, IQueryBuilder::PARAM_INT))); + $result = $query->execute(); + $row = $result->fetch(); + $result->closeCursor(); + + if (!$row) { + throw new CollectionException('Collection not found'); + } + + return new Collection($this, $this->connection, (int) $row['id'], (string) $row['name']); } /** + * @param string $name * @return ICollection * @since 15.0.0 */ - public function newCollection(): ICollection { - return new Collection($this, $this->connection, 0); + public function newCollection(string $name): ICollection { + $query = $this->connection->getQueryBuilder(); + $query->insert('collres_collections'); + $query->execute(); + + return new Collection($this, $this->connection, $query->getLastInsertId(), $name); } /** @@ -72,7 +93,9 @@ class Manager implements IManager { * @since 15.0.0 */ public function getProviders(): array { - return []; + return [ + \OC::$server->query(ResourceProvider::class) // FIXME + ]; } /** diff --git a/lib/private/Collaboration/Resources/Resource.php b/lib/private/Collaboration/Resources/Resource.php index 144af6d358..3013f1f5c4 100644 --- a/lib/private/Collaboration/Resources/Resource.php +++ b/lib/private/Collaboration/Resources/Resource.php @@ -47,7 +47,12 @@ class Resource implements IResource { /** @var string|null */ protected $name; - public function __construct(IManager $manager, IDBConnection $connection, string $type, string $id) { + public function __construct( + IManager $manager, + IDBConnection $connection, + string $type, + string $id + ) { $this->manager = $manager; $this->connection = $connection; $this->type = $type; diff --git a/lib/public/Collaboration/Resources/ICollection.php b/lib/public/Collaboration/Resources/ICollection.php index 1f503d8083..d586446649 100644 --- a/lib/public/Collaboration/Resources/ICollection.php +++ b/lib/public/Collaboration/Resources/ICollection.php @@ -35,6 +35,12 @@ interface ICollection { */ public function getId(): int; + /** + * @return string + * @since 15.0.0 + */ + public function getName(): string; + /** * @return IResource[] * @since 15.0.0 diff --git a/lib/public/Collaboration/Resources/IManager.php b/lib/public/Collaboration/Resources/IManager.php index abccfd2eed..dd1c970af7 100644 --- a/lib/public/Collaboration/Resources/IManager.php +++ b/lib/public/Collaboration/Resources/IManager.php @@ -30,15 +30,17 @@ interface IManager extends IProvider { /** * @param int $id * @return ICollection + * @throws CollectionException when the collection could not be found * @since 15.0.0 */ public function getCollection(int $id): ICollection; /** + * @param string $name * @return ICollection * @since 15.0.0 */ - public function newCollection(): ICollection; + public function newCollection(string $name): ICollection; /** * @param string $type From ab4b293854bf627c1d5dafcd7218e36cb3580bad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Mon, 29 Oct 2018 11:18:38 +0100 Subject: [PATCH 06/53] Insert new collection into database MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/private/Collaboration/Resources/Manager.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/private/Collaboration/Resources/Manager.php b/lib/private/Collaboration/Resources/Manager.php index 18301e0f2f..82a14f47d9 100644 --- a/lib/private/Collaboration/Resources/Manager.php +++ b/lib/private/Collaboration/Resources/Manager.php @@ -72,7 +72,10 @@ class Manager implements IManager { */ public function newCollection(string $name): ICollection { $query = $this->connection->getQueryBuilder(); - $query->insert('collres_collections'); + $query->insert('collres_collections') + ->values([ + 'name' => $query->createNamedParameter($name), + ]); $query->execute(); return new Collection($this, $this->connection, $query->getLastInsertId(), $name); From d6aae4317ddb64356cd633121fd858482839fb7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Thu, 17 Jan 2019 12:56:18 +0100 Subject: [PATCH 07/53] Move files_sharing to webpack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- apps/files_sharing/.babelrc.js | 13 +++++++ apps/files_sharing/list.php | 3 +- apps/files_sharing/package.json | 35 ++++++++++++++++++ apps/files_sharing/src/files_sharing.js | 16 +++++++++ apps/files_sharing/src/sharetabview.js | 2 ++ apps/files_sharing/webpack.common.js | 47 +++++++++++++++++++++++++ apps/files_sharing/webpack.dev.js | 12 +++++++ apps/files_sharing/webpack.prod.js | 7 ++++ 8 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 apps/files_sharing/.babelrc.js create mode 100644 apps/files_sharing/package.json create mode 100644 apps/files_sharing/src/files_sharing.js create mode 100644 apps/files_sharing/webpack.common.js create mode 100644 apps/files_sharing/webpack.dev.js create mode 100644 apps/files_sharing/webpack.prod.js diff --git a/apps/files_sharing/.babelrc.js b/apps/files_sharing/.babelrc.js new file mode 100644 index 0000000000..137b266162 --- /dev/null +++ b/apps/files_sharing/.babelrc.js @@ -0,0 +1,13 @@ +module.exports = { + presets: [ + [ + '@babel/preset-env', + { + targets: { + browsers: ['last 2 versions', 'ie >= 11'] + } + } + ] + ], + plugins: ['@babel/plugin-syntax-dynamic-import'] +} diff --git a/apps/files_sharing/list.php b/apps/files_sharing/list.php index 9eed10f8d2..1866c73b68 100644 --- a/apps/files_sharing/list.php +++ b/apps/files_sharing/list.php @@ -32,7 +32,6 @@ $tmpl = new OCP\Template('files_sharing', 'list', ''); // gridview not available for ie $tmpl->assign('showgridview', $showgridview && !$isIE); -OCP\Util::addScript('files_sharing', 'app'); -OCP\Util::addScript('files_sharing', 'sharedfilelist'); +OCP\Util::addScript('files_sharing', 'dist/files_sharing'); $tmpl->printPage(); diff --git a/apps/files_sharing/package.json b/apps/files_sharing/package.json new file mode 100644 index 0000000000..9aa194cbae --- /dev/null +++ b/apps/files_sharing/package.json @@ -0,0 +1,35 @@ +{ + "name": "files_sharing", + "version": "1.0.0", + "description": "File sharing in Nextcloud", + "main": "files_sharing.js", + "directories": { + "lib": "lib", + "test": "tests" + }, + "scripts": { + "build": "webpack --progress --hide-modules --config webpack.prod.js", + "dev": "webpack --progress --watch --config webpack.dev.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "AGPL-3.0-or-later", + "dependencies": { + "nextcloud-axios": "^0.1.3", + "nextcloud-vue": "^0.5.0", + "vue": "^2.5.17" + }, + "devDependencies": { + "@babel/core": "^7.1.0", + "@babel/plugin-syntax-dynamic-import": "^7.2.0", + "babel-loader": "^8.0.2", + "css-loader": "^2.1.0", + "node-sass": "^4.11.0", + "sass-loader": "^7.1.0", + "vue-loader": "^15.4.2", + "vue-template-compiler": "^2.5.17", + "webpack": "^4.20.0", + "webpack-cli": "^3.1.1", + "webpack-merge": "^4.1.4" + } +} diff --git a/apps/files_sharing/src/files_sharing.js b/apps/files_sharing/src/files_sharing.js new file mode 100644 index 0000000000..c31c8c6e20 --- /dev/null +++ b/apps/files_sharing/src/files_sharing.js @@ -0,0 +1,16 @@ +// CSP config for webpack dynamic chunk loading +// eslint-disable-next-line +__webpack_nonce__ = btoa(OC.requestToken) + +// Correct the root of the app for chunk loading +// OC.linkTo matches the apps folders +// eslint-disable-next-line +__webpack_public_path__ = OC.linkTo('files_sharing', 'js/dist/') + +import '../js/app' +import '../js/sharedfilelist' +import '../js/sharetabview' +import '../js/share' +import '../js/sharebreadcrumbview' + +window.OCA.Sharing = OCA.Sharing diff --git a/apps/files_sharing/src/sharetabview.js b/apps/files_sharing/src/sharetabview.js index 9b1176dbb9..4ac09ff9f7 100644 --- a/apps/files_sharing/src/sharetabview.js +++ b/apps/files_sharing/src/sharetabview.js @@ -14,6 +14,7 @@ var TEMPLATE = '
' + '
' + + '
' + '
'; /** @@ -81,6 +82,7 @@ this._dialog.model.on('change', function() { self.trigger('sharesChanged', shareModel); }); + } else { this.$el.empty(); // TODO: render placeholder text? diff --git a/apps/files_sharing/webpack.common.js b/apps/files_sharing/webpack.common.js new file mode 100644 index 0000000000..9479459286 --- /dev/null +++ b/apps/files_sharing/webpack.common.js @@ -0,0 +1,47 @@ +const path = require('path'); +const { VueLoaderPlugin } = require('vue-loader'); + +module.exports = { + entry: path.join(__dirname, 'src', 'files_sharing.js'), + output: { + path: path.resolve(__dirname, 'js/dist'), + publicPath: '/js/dist/', + filename: 'files_sharing.js', + chunkFilename: 'files_sharing.[name].js' +}, + module: { + rules: [ + { + test: /\.css$/, + use: ['vue-style-loader', 'css-loader'] + }, + { + test: /\.scss$/, + use: ['vue-style-loader', 'css-loader', 'sass-loader'] + }, + { + test: /\.vue$/, + loader: 'vue-loader' + }, + { + test: /\.js$/, + loader: 'babel-loader', + exclude: /node_modules/ + }, + { + test: /\.(png|jpg|gif|svg)$/, + loader: 'file-loader', + options: { + name: '[name].[ext]?[hash]' + } + } + ] + }, + plugins: [new VueLoaderPlugin()], + resolve: { + alias: { + vue$: 'vue/dist/vue.runtime.esm.js', + }, + extensions: ['*', '.js', '.vue', '.json'] + } +}; diff --git a/apps/files_sharing/webpack.dev.js b/apps/files_sharing/webpack.dev.js new file mode 100644 index 0000000000..0c569e7f61 --- /dev/null +++ b/apps/files_sharing/webpack.dev.js @@ -0,0 +1,12 @@ +const merge = require('webpack-merge'); +const common = require('./webpack.common.js'); + +module.exports = merge(common, { + mode: 'development', + devServer: { + historyApiFallback: true, + noInfo: true, + overlay: true + }, + devtool: '#source-map', +}) diff --git a/apps/files_sharing/webpack.prod.js b/apps/files_sharing/webpack.prod.js new file mode 100644 index 0000000000..f081567bd6 --- /dev/null +++ b/apps/files_sharing/webpack.prod.js @@ -0,0 +1,7 @@ +const merge = require('webpack-merge') +const common = require('./webpack.common.js') + +module.exports = merge(common, { + mode: 'production', + devtool: '#source-map' +}) From 322f7c3c85ff22dd791d15b2fe959f1230e25e43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Thu, 17 Jan 2019 13:11:16 +0100 Subject: [PATCH 08/53] Add vue app for collaboration resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl Add js api for resources Signed-off-by: Julius Härtl More frontend work Signed-off-by: Julius Härtl --- .../src/collaborationresources.js | 108 ++++++++++ .../src/components/CollectionListItem.vue | 158 +++++++++++++++ .../files_sharing/src/services/collections.js | 59 ++++++ apps/files_sharing/src/sharetabview.js | 12 ++ .../src/views/CollaborationView.vue | 184 ++++++++++++++++++ 5 files changed, 521 insertions(+) create mode 100644 apps/files_sharing/src/collaborationresources.js create mode 100644 apps/files_sharing/src/components/CollectionListItem.vue create mode 100644 apps/files_sharing/src/services/collections.js create mode 100644 apps/files_sharing/src/views/CollaborationView.vue diff --git a/apps/files_sharing/src/collaborationresources.js b/apps/files_sharing/src/collaborationresources.js new file mode 100644 index 0000000000..3b0a12c5b2 --- /dev/null +++ b/apps/files_sharing/src/collaborationresources.js @@ -0,0 +1,108 @@ +/* + * @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 { PopoverMenu } from 'nextcloud-vue' +import ClickOutside from 'vue-click-outside' +import { VTooltip } from 'v-tooltip' + +Vue.prototype.t = t; + +Vue.component('PopoverMenu', PopoverMenu) +Vue.directive('ClickOutside', ClickOutside) +Vue.directive('Tooltip', VTooltip) + +import View from './views/CollaborationView' + +let selectAction = {}; +let icons = {}; +let types = {}; + +window.Collaboration = { + /** + * + * @param type + * @param {callback} selectCallback should return a promise + */ + registerType(type, typeDefinition) { + types[type] = typeDefinition; + }, + trigger(type) { + return types[type].action() + }, + getTypes() { + return Object.keys(types); + }, + getIcon(type) { + return types[type].icon; + }, + getLabel(type) { + return t('files_sharing', 'Link to a {label}', { label: types[type].typeString || type }, 1) + }, + getLink(type, id) { + /* TODO: Allow action to be executed instead of href as well */ + return types[type].link(id); + } +} + +window.Collaboration.registerType('files', { + action: () => { + return new Promise((resolve, reject) => { + OC.dialogs.filepicker('Link to a file', function (f) { + const client = OC.Files.getClient(); + client.getFileInfo(f).then((status, fileInfo) => { + resolve(fileInfo.id) + }, () => { + reject() + }) + }, false); + }) + }, + link: (id) => OC.generateUrl('/f/') + id, + icon: 'nav-icon-files', + /** used in "Link to a {typeString}" */ + typeString: 'file' +}); + +/* TODO: temporary data for testing */ +window.Collaboration.registerType('calendar', { + action: () => { + return new Promise((resolve, reject) => { + var id = window.prompt("calendar id", "1"); + resolve(id); + }) + }, + icon: 'icon-calendar-dark', + typeName: 'calendar', +}); +window.Collaboration.registerType('contact', { + action: () => { + return new Promise((resolve, reject) => { + var id = window.prompt("contacts id", "1"); + resolve(id); + }) + }, + icon: 'icon-contacts-dark', + typeName: 'contact', +}); + +export { Vue, View } diff --git a/apps/files_sharing/src/components/CollectionListItem.vue b/apps/files_sharing/src/components/CollectionListItem.vue new file mode 100644 index 0000000000..8819497ca6 --- /dev/null +++ b/apps/files_sharing/src/components/CollectionListItem.vue @@ -0,0 +1,158 @@ + + + + + + + diff --git a/apps/files_sharing/src/services/collections.js b/apps/files_sharing/src/services/collections.js new file mode 100644 index 0000000000..bd45b8f3c3 --- /dev/null +++ b/apps/files_sharing/src/services/collections.js @@ -0,0 +1,59 @@ +/* + * @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 axios from 'nextcloud-axios'; + +class Service { + constructor() { + this.service = axios.create(); + } + + listCollection(collectionId) { + return this.service.get(`/collaboration/resources/collections/${collectionId}`) + } + + addResource(collectionId, resource) { + return this.service.post(`/collaboration/resources/collections/${collectionId}`) + } + + removeResource() { + return this.service.post(`/collaboration/resources/collections/${collectionId}`) + } + + createCollectionOnResource(resourceType, resourceId) { + return this.service.post(`/collaboration/resources/${resourceType}/${resourceId}`) + } + + getCollectionByResource(resourceType, resourceId) { + return this.service.get(`/collaboration/resources/${resourceType}/${resourceId}`) + } + + getProviders() { + + } + + search() { + + } +} + +export default new Service; diff --git a/apps/files_sharing/src/sharetabview.js b/apps/files_sharing/src/sharetabview.js index 4ac09ff9f7..8f8a655b00 100644 --- a/apps/files_sharing/src/sharetabview.js +++ b/apps/files_sharing/src/sharetabview.js @@ -83,6 +83,18 @@ self.trigger('sharesChanged', shareModel); }); + import('./../src/collaborationresources').then((Resources) => { + var vm = new Resources.Vue({ + el: '#collaborationResources', + render: h => h(Resources.View), + data: { + model: this.model.toJSON() + }, + }); + this.model.on('change', () => { vm.data = this.model.toJSON() }) + + }) + } else { this.$el.empty(); // TODO: render placeholder text? diff --git a/apps/files_sharing/src/views/CollaborationView.vue b/apps/files_sharing/src/views/CollaborationView.vue new file mode 100644 index 0000000000..e5431ba580 --- /dev/null +++ b/apps/files_sharing/src/views/CollaborationView.vue @@ -0,0 +1,184 @@ + + + + + + From a72a6d73a3c07f41756f77c57829fecbaa42d6ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Tue, 22 Jan 2019 13:11:49 +0100 Subject: [PATCH 09/53] Adjust parameter names on createCollectionOnResource MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- core/Controller/CollaborationResourcesController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/Controller/CollaborationResourcesController.php b/core/Controller/CollaborationResourcesController.php index e9fc7b1ac7..ea21f0c584 100644 --- a/core/Controller/CollaborationResourcesController.php +++ b/core/Controller/CollaborationResourcesController.php @@ -168,13 +168,13 @@ class CollaborationResourcesController extends OCSController { * @param string $name * @return DataResponse */ - public function createCollectionOnResource(string $resourceType, string $resourceId, string $name): DataResponse { + public function createCollectionOnResource(string $baseResourceType, string $baseResourceId, string $name): DataResponse { if (!isset($name[0]) || isset($name[64])) { return new DataResponse([], Http::STATUS_BAD_REQUEST); } try { - $resource = $this->manager->getResource($resourceType, $resourceId); + $resource = $this->manager->getResource($baseResourceType, $baseResourceId); } catch (CollectionException $e) { return new DataResponse([], Http::STATUS_NOT_FOUND); } From 7a4b2db2a7a624081de2d9264129358857f2b6e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Mon, 22 Oct 2018 14:58:16 +0200 Subject: [PATCH 10/53] Add javascript API for collaboration resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- core/js/core.json | 3 +- core/src/OCP/collaboration.js | 163 ++++++++++++++++++++++++++++++++++ core/src/OCP/index.js | 2 + 3 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 core/src/OCP/collaboration.js diff --git a/core/js/core.json b/core/js/core.json index 5bf6512d6a..ae2e9a87a9 100644 --- a/core/js/core.json +++ b/core/js/core.json @@ -26,6 +26,7 @@ "systemtags/systemtagmodel.js", "systemtags/systemtagscollection.js", "systemtags/systemtagsmappingcollection.js", - "systemtags/systemtagsinputfield.js" + "systemtags/systemtagsinputfield.js", + "collaboration.js" ] } diff --git a/core/src/OCP/collaboration.js b/core/src/OCP/collaboration.js new file mode 100644 index 0000000000..a4b0fc24e6 --- /dev/null +++ b/core/src/OCP/collaboration.js @@ -0,0 +1,163 @@ +/* + * @copyright Copyright (c) 2018 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 . + * + */ + +let resourceSelectHandlers = {}; + +export default { + + /** + * @class + * @param resourceType + * @param resourceId + * @constructor + */ + Resource: function(resourceType, resourceId) { + this.resourceType = '' + resourceType; + this.resourceId = '' + resourceId; + }, + + /** + * @class + * @param id + * @param name + * @constructor + */ + Collection: function(id, name) { + this.id = '' + id; + this.name = '' + name; + this.resources = []; + }, + + /** + * + * @param resourceType + * @param title + * @param selectorCallback + */ + registerResourceSelector: function(resourceType, title, selectorCallback) { + if (!this.resourceSelectHandlers.hasOwnProperty(resourceType)) { + this.resourceSelectHandlers[resourceType] = { + title: title, + callback: selectorCallback + }; + } + }, + + getResourceTypes: function() { + return this.resourceSelectHandlers; + }, + + /** + * Select a resource for a given type + * + * @param resourceType + * @param successCallback + * @param abortCallback + */ + selectResource: function (resourceType, successCallback, abortCallback) { + this.resourceSelectHandlers[resourceType].callback(successCallback, abortCallback); + }, + + getCollectionsByResource: function(resourceType, resourceId) { + // TODO: to implement + }, + + /** + * Create a new collection from two resources + * + * @param name + * @param resource1 + * @param resource2 + * @param successCallback + * @param errorCallback + */ + createCollection: function (name, resource1, resource2, successCallback, errorCallback) { + var self = this; + this.createCollectionOnResource(name, resource1, function (collection) { + self.addResource(collection, resource2, function (collection) { + successCallback(collection); + }) + }); + }, + + /** + * + * @param name + * @param resource1 + * @param successCallback + * @param errorCallback + */ + createCollectionOnResource: function (name, resource1, successCallback, errorCallback) { + var data = { + name: name, + resourceType: resource1.resourceType, + resourceId: ''+resource1.resourceId, + }; + var request = new XMLHttpRequest(); + request.open('POST', OC.linkToOCS('collaboration/resources/' + data.resourceType, 2) + data.resourceId + '?format=json', true); + request.setRequestHeader('Content-Type', 'application/json; charset=UTF-8'); + request.setRequestHeader('oc_requesttoken', OC.requestToken); + request.setRequestHeader('OCS-APIRequest', true); + request.onreadystatechange = function () { + if(request.readyState === 4 && request.status === 200) { + var result = JSON.parse(request.responseText); + var collection = new OCP.Collaboration.Collection(result.ocs.data.id, result.ocs.data.name); + collection.resources.push(resource1); + successCallback(collection); + } + }; + request.send(JSON.stringify(data)); + }, + + /** + * Add a resource to a collection + * + * @param {OCP.Collaboration.Collection} collection + * @param resource + * @param successCallback + * @param resource + */ + addResource: function (collection, resource, successCallback) { + var data = { + resourceType: resource.resourceType, + resourceId: '' + resource.resourceId, + }; + var request = new XMLHttpRequest(); + request.open('POST', OC.linkToOCS('collaboration/resources/collections', 2) + collection.id + '?format=json', true); + request.setRequestHeader('Content-Type', 'application/json; charset=UTF-8'); + request.setRequestHeader('oc_requesttoken', OC.requestToken); + request.setRequestHeader('OCS-APIRequest', true); + request.onreadystatechange = function () { + if(request.readyState === 4 && request.status === 200) { + var result = JSON.parse(request.responseText); + collection.resources.push(resource); + successCallback(collection); + } + }; + request.send(JSON.stringify(data)); + }, + + removeResource: function(collection, resource) { + // TODO: to implement + } + +}; diff --git a/core/src/OCP/index.js b/core/src/OCP/index.js index aa3650b061..6794531836 100644 --- a/core/src/OCP/index.js +++ b/core/src/OCP/index.js @@ -5,6 +5,7 @@ import * as AppConfig from './appconfig' import * as Comments from './comments' import * as InitialState from './initialstate' import Loader from './loader' +import Collaboration from './collaboration' import * as WhatsNew from './whatsnew' /** @namespace OCP */ @@ -14,4 +15,5 @@ export default { InitialState, Loader, WhatsNew, + Collaboration }; From 51057c539feace8381ab83310b307749fec60f91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Wed, 23 Jan 2019 16:34:11 +0100 Subject: [PATCH 11/53] Use proper public javascript methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- .../src/collaborationresources.js | 58 +++---------------- .../src/components/CollectionListItem.vue | 17 +++--- apps/files_sharing/src/files_sharing.js | 19 ++++++ .../src/views/CollaborationView.vue | 18 +++--- 4 files changed, 47 insertions(+), 65 deletions(-) diff --git a/apps/files_sharing/src/collaborationresources.js b/apps/files_sharing/src/collaborationresources.js index 3b0a12c5b2..0370c367bb 100644 --- a/apps/files_sharing/src/collaborationresources.js +++ b/apps/files_sharing/src/collaborationresources.js @@ -36,55 +36,10 @@ import View from './views/CollaborationView' let selectAction = {}; let icons = {}; let types = {}; - -window.Collaboration = { - /** - * - * @param type - * @param {callback} selectCallback should return a promise - */ - registerType(type, typeDefinition) { - types[type] = typeDefinition; - }, - trigger(type) { - return types[type].action() - }, - getTypes() { - return Object.keys(types); - }, - getIcon(type) { - return types[type].icon; - }, - getLabel(type) { - return t('files_sharing', 'Link to a {label}', { label: types[type].typeString || type }, 1) - }, - getLink(type, id) { - /* TODO: Allow action to be executed instead of href as well */ - return types[type].link(id); - } -} - -window.Collaboration.registerType('files', { - action: () => { - return new Promise((resolve, reject) => { - OC.dialogs.filepicker('Link to a file', function (f) { - const client = OC.Files.getClient(); - client.getFileInfo(f).then((status, fileInfo) => { - resolve(fileInfo.id) - }, () => { - reject() - }) - }, false); - }) - }, - link: (id) => OC.generateUrl('/f/') + id, - icon: 'nav-icon-files', - /** used in "Link to a {typeString}" */ - typeString: 'file' -}); +console.log('register types'); /* TODO: temporary data for testing */ -window.Collaboration.registerType('calendar', { +window.OCP.Collaboration.registerType('calendar', { action: () => { return new Promise((resolve, reject) => { var id = window.prompt("calendar id", "1"); @@ -92,9 +47,10 @@ window.Collaboration.registerType('calendar', { }) }, icon: 'icon-calendar-dark', - typeName: 'calendar', + typeString: 'calendar', + link: (id) => '#' + id, }); -window.Collaboration.registerType('contact', { +window.OCP.Collaboration.registerType('contact', { action: () => { return new Promise((resolve, reject) => { var id = window.prompt("contacts id", "1"); @@ -102,7 +58,9 @@ window.Collaboration.registerType('contact', { }) }, icon: 'icon-contacts-dark', - typeName: 'contact', + link: (id) => '#' + id, + /** used in "Link to a {typeString}" */ + typeString: 'contact' }); export { Vue, View } diff --git a/apps/files_sharing/src/components/CollectionListItem.vue b/apps/files_sharing/src/components/CollectionListItem.vue index 8819497ca6..aebab670ac 100644 --- a/apps/files_sharing/src/components/CollectionListItem.vue +++ b/apps/files_sharing/src/components/CollectionListItem.vue @@ -24,11 +24,12 @@
  • {{ collection.name }} -
    - - - -
    + +
    + +
    +
    +