Completed
Push — master ( 830834...005b3d )
by Thomas
10:38
created

CommentsPlugin::getSupportedReportSet()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Arthur Schiwon <[email protected]>
4
 * @author Joas Schilling <[email protected]>
5
 * @author Vincent Petry <[email protected]>
6
 *
7
 * @copyright Copyright (c) 2016, ownCloud GmbH.
8
 * @license AGPL-3.0
9
 *
10
 * This code is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Affero General Public License, version 3,
12
 * as published by the Free Software Foundation.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License, version 3,
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
21
 *
22
 */
23
24
namespace OCA\DAV\Comments;
25
26
use OCP\Comments\IComment;
27
use OCP\Comments\ICommentsManager;
28
use OCP\IUserSession;
29
use Sabre\DAV\Exception\BadRequest;
30
use Sabre\DAV\Exception\ReportNotSupported;
31
use Sabre\DAV\Exception\UnsupportedMediaType;
32
use Sabre\DAV\Exception\NotFound;
33
use Sabre\DAV\Server;
34
use Sabre\DAV\ServerPlugin;
35
use Sabre\DAV\Xml\Element\Response;
36
use Sabre\DAV\Xml\Response\MultiStatus;
37
use Sabre\HTTP\RequestInterface;
38
use Sabre\HTTP\ResponseInterface;
39
use Sabre\Xml\Writer;
40
41
/**
42
 * Sabre plugin to handle comments:
43
 */
44
class CommentsPlugin extends ServerPlugin {
45
	// namespace
46
	const NS_OWNCLOUD = 'http://owncloud.org/ns';
47
48
	const REPORT_NAME            = '{http://owncloud.org/ns}filter-comments';
49
	const REPORT_PARAM_LIMIT     = '{http://owncloud.org/ns}limit';
50
	const REPORT_PARAM_OFFSET    = '{http://owncloud.org/ns}offset';
51
	const REPORT_PARAM_TIMESTAMP = '{http://owncloud.org/ns}datetime';
52
53
	/** @var ICommentsManager  */
54
	protected $commentsManager;
55
56
	/** @var \Sabre\DAV\Server $server */
57
	private $server;
58
59
	/** @var  \OCP\IUserSession */
60
	protected $userSession;
61
62
	/**
63
	 * Comments plugin
64
	 *
65
	 * @param ICommentsManager $commentsManager
66
	 * @param IUserSession $userSession
67
	 */
68
	public function __construct(ICommentsManager $commentsManager, IUserSession $userSession) {
69
		$this->commentsManager = $commentsManager;
70
		$this->userSession = $userSession;
71
	}
72
73
	/**
74
	 * This initializes the plugin.
75
	 *
76
	 * This function is called by Sabre\DAV\Server, after
77
	 * addPlugin is called.
78
	 *
79
	 * This method should set up the required event subscriptions.
80
	 *
81
	 * @param Server $server
82
	 * @return void
83
	 */
84
	function initialize(Server $server) {
85
		$this->server = $server;
86
		if(strpos($this->server->getRequestUri(), 'comments/') !== 0) {
87
			return;
88
		}
89
90
		$this->server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc';
91
92
		$this->server->xml->classMap['DateTime'] = function(Writer $writer, \DateTime $value) {
93
			$writer->write(\Sabre\HTTP\toDate($value));
94
		};
95
96
		$this->server->on('report', [$this, 'onReport']);
97
		$this->server->on('method:POST', [$this, 'httpPost']);
98
	}
99
100
	/**
101
	 * POST operation on Comments collections
102
	 *
103
	 * @param RequestInterface $request request object
104
	 * @param ResponseInterface $response response object
105
	 * @return null|false
106
	 */
107
	public function httpPost(RequestInterface $request, ResponseInterface $response) {
108
		$path = $request->getPath();
109
		$node = $this->server->tree->getNodeForPath($path);
110
		if (!$node instanceof EntityCollection) {
111
			return null;
112
		}
113
114
		$data = $request->getBodyAsString();
115
		$comment = $this->createComment(
116
			$node->getName(),
117
			$node->getId(),
118
			$data,
119
			$request->getHeader('Content-Type')
120
		);
121
122
		// update read marker for the current user/poster to avoid
123
		// having their own comments marked as unread
124
		$node->setReadMarker(null);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a object<DateTime>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
125
126
		$url = rtrim($request->getUrl(), '/') . '/' . urlencode($comment->getId());
127
128
		$response->setHeader('Content-Location', $url);
129
130
		// created
131
		$response->setStatus(201);
132
		return false;
133
	}
134
135
	/**
136
	 * Returns a list of reports this plugin supports.
137
	 *
138
	 * This will be used in the {DAV:}supported-report-set property.
139
	 *
140
	 * @param string $uri
141
	 * @return array
142
	 */
143
	public function getSupportedReportSet($uri) {
144
		return [self::REPORT_NAME];
145
	}
146
147
	/**
148
	 * REPORT operations to look for comments
149
	 *
150
	 * @param string $reportName
151
	 * @param [] $report
0 ignored issues
show
Documentation introduced by
The doc-type [] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
152
	 * @param string $uri
153
	 * @return bool
154
	 * @throws NotFound
155
	 * @throws ReportNotSupported
156
	 */
157
	public function onReport($reportName, $report, $uri) {
158
		$node = $this->server->tree->getNodeForPath($uri);
159
		if(!$node instanceof EntityCollection || $reportName !== self::REPORT_NAME) {
160
			throw new ReportNotSupported();
161
		}
162
		$args = ['limit' => 0, 'offset' => 0, 'datetime' => null];
163
		$acceptableParameters = [
164
			$this::REPORT_PARAM_LIMIT,
165
			$this::REPORT_PARAM_OFFSET,
166
			$this::REPORT_PARAM_TIMESTAMP
167
		];
168
		$ns = '{' . $this::NS_OWNCLOUD . '}';
169
		foreach($report as $parameter) {
170
			if(!in_array($parameter['name'], $acceptableParameters) || empty($parameter['value'])) {
171
				continue;
172
			}
173
			$args[str_replace($ns, '', $parameter['name'])] = $parameter['value'];
174
		}
175
176 View Code Duplication
		if(!is_null($args['datetime'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
177
			$args['datetime'] = new \DateTime($args['datetime']);
178
		}
179
180
		$results = $node->findChildren($args['limit'], $args['offset'], $args['datetime']);
181
182
		$responses = [];
183
		foreach($results as $node) {
184
			$nodePath = $this->server->getRequestUri() . '/' . $node->comment->getId();
185
			$resultSet = $this->server->getPropertiesForPath($nodePath, CommentNode::getPropertyNames());
186
			if(isset($resultSet[0]) && isset($resultSet[0][200])) {
187
				$responses[] = new Response(
188
					$this->server->getBaseUri() . $nodePath,
189
					[200 => $resultSet[0][200]],
190
					200
191
				);
192
			}
193
194
		}
195
196
		$xml = $this->server->xml->write(
197
			'{DAV:}multistatus',
198
			new MultiStatus($responses)
199
		);
200
201
		$this->server->httpResponse->setStatus(207);
202
		$this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
203
		$this->server->httpResponse->setBody($xml);
204
205
		return false;
206
	}
207
208
	/**
209
	 * Creates a new comment
210
	 *
211
	 * @param string $objectType e.g. "files"
212
	 * @param string $objectId e.g. the file id
213
	 * @param string $data JSON encoded string containing the properties of the tag to create
214
	 * @param string $contentType content type of the data
215
	 * @return IComment newly created comment
216
	 *
217
	 * @throws BadRequest if a field was missing
218
	 * @throws UnsupportedMediaType if the content type is not supported
219
	 */
220
	private function createComment($objectType, $objectId, $data, $contentType = 'application/json') {
221 View Code Duplication
		if (explode(';', $contentType)[0] === 'application/json') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
222
			$data = json_decode($data, true);
223
		} else {
224
			throw new UnsupportedMediaType();
225
		}
226
227
		$actorType = $data['actorType'];
228
		$actorId = null;
229
		if($actorType === 'users') {
230
			$user = $this->userSession->getUser();
231
			if(!is_null($user)) {
232
				$actorId = $user->getUID();
233
			}
234
		}
235
		if(is_null($actorId)) {
236
			throw new BadRequest('Invalid actor "' .  $actorType .'"');
237
		}
238
239
		try {
240
			$comment = $this->commentsManager->create($actorType, $actorId, $objectType, $objectId);
241
			$comment->setMessage($data['message']);
242
			$comment->setVerb($data['verb']);
243
			$this->commentsManager->save($comment);
244
			return $comment;
245
		} catch (\InvalidArgumentException $e) {
246
			throw new BadRequest('Invalid input values', 0, $e);
247
		} catch (\OCP\Comments\MessageTooLongException $e) {
248
			$msg = 'Message exceeds allowed character limit of ';
249
			throw new BadRequest($msg . \OCP\Comments\IComment::MAX_MESSAGE_LENGTH, 0,	$e);
250
		}
251
	}
252
253
254
255
}
256