1<?php
2/**
3 * @copyright Copyright (c) 2016, ownCloud, Inc.
4 *
5 * @author Christoph Wurst <christoph@winzerhof-wurst.at>
6 * @author Joas Schilling <coding@schilljs.com>
7 * @author Morris Jobke <hey@morrisjobke.de>
8 * @author Roeland Jago Douma <roeland@famdouma.nl>
9 * @author Vincent Petry <vincent@nextcloud.com>
10 *
11 * @license AGPL-3.0
12 *
13 * This code is free software: you can redistribute it and/or modify
14 * it under the terms of the GNU Affero General Public License, version 3,
15 * as published by the Free Software Foundation.
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, version 3,
23 * along with this program. If not, see <http://www.gnu.org/licenses/>
24 *
25 */
26namespace OCA\DAV\SystemTag;
27
28use OCP\IUser;
29use OCP\SystemTag\ISystemTag;
30use OCP\SystemTag\ISystemTagManager;
31use OCP\SystemTag\ISystemTagObjectMapper;
32use OCP\SystemTag\TagNotFoundException;
33use Sabre\DAV\Exception\BadRequest;
34use Sabre\DAV\Exception\Forbidden;
35use Sabre\DAV\Exception\NotFound;
36use Sabre\DAV\Exception\PreconditionFailed;
37use Sabre\DAV\ICollection;
38
39/**
40 * Collection containing tags by object id
41 */
42class SystemTagsObjectMappingCollection implements ICollection {
43
44	/**
45	 * @var string
46	 */
47	private $objectId;
48
49	/**
50	 * @var string
51	 */
52	private $objectType;
53
54	/**
55	 * @var ISystemTagManager
56	 */
57	private $tagManager;
58
59	/**
60	 * @var ISystemTagObjectMapper
61	 */
62	private $tagMapper;
63
64	/**
65	 * User
66	 *
67	 * @var IUser
68	 */
69	private $user;
70
71
72	/**
73	 * Constructor
74	 *
75	 * @param string $objectId object id
76	 * @param string $objectType object type
77	 * @param IUser $user user
78	 * @param ISystemTagManager $tagManager tag manager
79	 * @param ISystemTagObjectMapper $tagMapper tag mapper
80	 */
81	public function __construct(
82		$objectId,
83		$objectType,
84		IUser $user,
85		ISystemTagManager $tagManager,
86		ISystemTagObjectMapper $tagMapper
87	) {
88		$this->tagManager = $tagManager;
89		$this->tagMapper = $tagMapper;
90		$this->objectId = $objectId;
91		$this->objectType = $objectType;
92		$this->user = $user;
93	}
94
95	public function createFile($name, $data = null) {
96		$tagId = $name;
97		try {
98			$tags = $this->tagManager->getTagsByIds([$tagId]);
99			$tag = current($tags);
100			if (!$this->tagManager->canUserSeeTag($tag, $this->user)) {
101				throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign');
102			}
103			if (!$this->tagManager->canUserAssignTag($tag, $this->user)) {
104				throw new Forbidden('No permission to assign tag ' . $tagId);
105			}
106
107			$this->tagMapper->assignTags($this->objectId, $this->objectType, $tagId);
108		} catch (TagNotFoundException $e) {
109			throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign');
110		}
111	}
112
113	public function createDirectory($name) {
114		throw new Forbidden('Permission denied to create collections');
115	}
116
117	public function getChild($tagName) {
118		try {
119			if ($this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagName, true)) {
120				$tag = $this->tagManager->getTagsByIds([$tagName]);
121				$tag = current($tag);
122				if ($this->tagManager->canUserSeeTag($tag, $this->user)) {
123					return $this->makeNode($tag);
124				}
125			}
126			throw new NotFound('Tag with id ' . $tagName . ' not present for object ' . $this->objectId);
127		} catch (\InvalidArgumentException $e) {
128			throw new BadRequest('Invalid tag id', 0, $e);
129		} catch (TagNotFoundException $e) {
130			throw new NotFound('Tag with id ' . $tagName . ' not found', 0, $e);
131		}
132	}
133
134	public function getChildren() {
135		$tagIds = current($this->tagMapper->getTagIdsForObjects([$this->objectId], $this->objectType));
136		if (empty($tagIds)) {
137			return [];
138		}
139		$tags = $this->tagManager->getTagsByIds($tagIds);
140
141		// filter out non-visible tags
142		$tags = array_filter($tags, function ($tag) {
143			return $this->tagManager->canUserSeeTag($tag, $this->user);
144		});
145
146		return array_values(array_map(function ($tag) {
147			return $this->makeNode($tag);
148		}, $tags));
149	}
150
151	public function childExists($tagId) {
152		try {
153			$result = $this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true);
154
155			if ($result) {
156				$tags = $this->tagManager->getTagsByIds([$tagId]);
157				$tag = current($tags);
158				if (!$this->tagManager->canUserSeeTag($tag, $this->user)) {
159					return false;
160				}
161			}
162
163			return $result;
164		} catch (\InvalidArgumentException $e) {
165			throw new BadRequest('Invalid tag id', 0, $e);
166		} catch (TagNotFoundException $e) {
167			return false;
168		}
169	}
170
171	public function delete() {
172		throw new Forbidden('Permission denied to delete this collection');
173	}
174
175	public function getName() {
176		return $this->objectId;
177	}
178
179	public function setName($name) {
180		throw new Forbidden('Permission denied to rename this collection');
181	}
182
183	/**
184	 * Returns the last modification time, as a unix timestamp
185	 *
186	 * @return int
187	 */
188	public function getLastModified() {
189		return null;
190	}
191
192	/**
193	 * Create a sabre node for the mapping of the
194	 * given system tag to the collection's object
195	 *
196	 * @param ISystemTag $tag
197	 *
198	 * @return SystemTagMappingNode
199	 */
200	private function makeNode(ISystemTag $tag) {
201		return new SystemTagMappingNode(
202			$tag,
203			$this->objectId,
204			$this->objectType,
205			$this->user,
206			$this->tagManager,
207			$this->tagMapper
208		);
209	}
210}
211