Collection.php 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright Copyright (c) 2018 Joas Schilling <coding@schilljs.com>
  5. *
  6. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  7. * @author Joas Schilling <coding@schilljs.com>
  8. * @author Roeland Jago Douma <roeland@famdouma.nl>
  9. *
  10. * @license GNU AGPL version 3 or any later version
  11. *
  12. * This program is free software: you can redistribute it and/or modify
  13. * it under the terms of the GNU Affero General Public License as
  14. * published by the Free Software Foundation, either version 3 of the
  15. * License, or (at your option) any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU Affero General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU Affero General Public License
  23. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  24. *
  25. */
  26. namespace OC\Collaboration\Resources;
  27. use Doctrine\DBAL\Exception\ConstraintViolationException;
  28. use OCP\Collaboration\Resources\ICollection;
  29. use OCP\Collaboration\Resources\IManager;
  30. use OCP\Collaboration\Resources\IResource;
  31. use OCP\Collaboration\Resources\ResourceException;
  32. use OCP\DB\QueryBuilder\IQueryBuilder;
  33. use OCP\IDBConnection;
  34. use OCP\IUser;
  35. class Collection implements ICollection {
  36. /** @var IManager|Manager */
  37. protected $manager;
  38. /** @var IDBConnection */
  39. protected $connection;
  40. /** @var int */
  41. protected $id;
  42. /** @var string */
  43. protected $name;
  44. /** @var IUser|null */
  45. protected $userForAccess;
  46. /** @var bool|null */
  47. protected $access;
  48. /** @var IResource[] */
  49. protected $resources;
  50. public function __construct(
  51. IManager $manager,
  52. IDBConnection $connection,
  53. int $id,
  54. string $name,
  55. ?IUser $userForAccess = null,
  56. ?bool $access = null
  57. ) {
  58. $this->manager = $manager;
  59. $this->connection = $connection;
  60. $this->id = $id;
  61. $this->name = $name;
  62. $this->userForAccess = $userForAccess;
  63. $this->access = $access;
  64. $this->resources = [];
  65. }
  66. /**
  67. * @return int
  68. * @since 16.0.0
  69. */
  70. public function getId(): int {
  71. return $this->id;
  72. }
  73. /**
  74. * @return string
  75. * @since 16.0.0
  76. */
  77. public function getName(): string {
  78. return $this->name;
  79. }
  80. /**
  81. * @param string $name
  82. * @since 16.0.0
  83. */
  84. public function setName(string $name): void {
  85. $query = $this->connection->getQueryBuilder();
  86. $query->update(Manager::TABLE_COLLECTIONS)
  87. ->set('name', $query->createNamedParameter($name))
  88. ->where($query->expr()->eq('id', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT)));
  89. $query->execute();
  90. $this->name = $name;
  91. }
  92. /**
  93. * @return IResource[]
  94. * @since 16.0.0
  95. */
  96. public function getResources(): array {
  97. if (empty($this->resources)) {
  98. $this->resources = $this->manager->getResourcesByCollectionForUser($this, $this->userForAccess);
  99. }
  100. return $this->resources;
  101. }
  102. /**
  103. * Adds a resource to a collection
  104. *
  105. * @param IResource $resource
  106. * @throws ResourceException when the resource is already part of the collection
  107. * @since 16.0.0
  108. */
  109. public function addResource(IResource $resource): void {
  110. array_map(function (IResource $r) use ($resource) {
  111. if ($this->isSameResource($r, $resource)) {
  112. throw new ResourceException('Already part of the collection');
  113. }
  114. }, $this->getResources());
  115. $this->resources[] = $resource;
  116. $query = $this->connection->getQueryBuilder();
  117. $query->insert(Manager::TABLE_RESOURCES)
  118. ->values([
  119. 'collection_id' => $query->createNamedParameter($this->id, IQueryBuilder::PARAM_INT),
  120. 'resource_type' => $query->createNamedParameter($resource->getType()),
  121. 'resource_id' => $query->createNamedParameter($resource->getId()),
  122. ]);
  123. try {
  124. $query->execute();
  125. } catch (ConstraintViolationException $e) {
  126. throw new ResourceException('Already part of the collection');
  127. }
  128. $this->manager->invalidateAccessCacheForCollection($this);
  129. }
  130. /**
  131. * Removes a resource from a collection
  132. *
  133. * @param IResource $resource
  134. * @since 16.0.0
  135. */
  136. public function removeResource(IResource $resource): void {
  137. $this->resources = array_filter($this->getResources(), function (IResource $r) use ($resource) {
  138. return !$this->isSameResource($r, $resource);
  139. });
  140. $query = $this->connection->getQueryBuilder();
  141. $query->delete(Manager::TABLE_RESOURCES)
  142. ->where($query->expr()->eq('collection_id', $query->createNamedParameter($this->id, IQueryBuilder::PARAM_INT)))
  143. ->andWhere($query->expr()->eq('resource_type', $query->createNamedParameter($resource->getType())))
  144. ->andWhere($query->expr()->eq('resource_id', $query->createNamedParameter($resource->getId())));
  145. $query->execute();
  146. if (empty($this->resources)) {
  147. $this->removeCollection();
  148. } else {
  149. $this->manager->invalidateAccessCacheForCollection($this);
  150. }
  151. }
  152. /**
  153. * Can a user/guest access the collection
  154. *
  155. * @param IUser|null $user
  156. * @return bool
  157. * @since 16.0.0
  158. */
  159. public function canAccess(?IUser $user): bool {
  160. if ($user instanceof IUser) {
  161. return $this->canUserAccess($user);
  162. }
  163. return $this->canGuestAccess();
  164. }
  165. protected function canUserAccess(IUser $user): bool {
  166. if (\is_bool($this->access) && $this->userForAccess instanceof IUser && $user->getUID() === $this->userForAccess->getUID()) {
  167. return $this->access;
  168. }
  169. $access = $this->manager->canAccessCollection($this, $user);
  170. if ($this->userForAccess instanceof IUser && $user->getUID() === $this->userForAccess->getUID()) {
  171. $this->access = $access;
  172. }
  173. return $access;
  174. }
  175. protected function canGuestAccess(): bool {
  176. if (\is_bool($this->access) && !$this->userForAccess instanceof IUser) {
  177. return $this->access;
  178. }
  179. $access = $this->manager->canAccessCollection($this, null);
  180. if (!$this->userForAccess instanceof IUser) {
  181. $this->access = $access;
  182. }
  183. return $access;
  184. }
  185. protected function isSameResource(IResource $resource1, IResource $resource2): bool {
  186. return $resource1->getType() === $resource2->getType() &&
  187. $resource1->getId() === $resource2->getId();
  188. }
  189. protected function removeCollection(): void {
  190. $query = $this->connection->getQueryBuilder();
  191. $query->delete(Manager::TABLE_COLLECTIONS)
  192. ->where($query->expr()->eq('id', $query->createNamedParameter($this->id, IQueryBuilder::PARAM_INT)));
  193. $query->execute();
  194. $this->manager->invalidateAccessCacheForCollection($this);
  195. $this->id = 0;
  196. }
  197. }