0
0
Fork 0
mirror of https://github.com/nextcloud/server.git synced 2025-02-06 01:20:16 +00:00
nextcloud_server/apps/dav/lib/Comments/CommentsPlugin.php
Git'Fellow 36d6b0f1e6 refactor: Use Http framework where possible
Signed-off-by: Git'Fellow <12234510+solracsf@users.noreply.github.com>
2024-12-14 11:23:29 +01:00

232 lines
6.6 KiB
PHP

<?php
/**
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
* SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCA\DAV\Comments;
use OCP\AppFramework\Http;
use OCP\Comments\IComment;
use OCP\Comments\ICommentsManager;
use OCP\Comments\MessageTooLongException;
use OCP\IUserSession;
use Sabre\DAV\Exception\BadRequest;
use Sabre\DAV\Exception\NotFound;
use Sabre\DAV\Exception\ReportNotSupported;
use Sabre\DAV\Exception\UnsupportedMediaType;
use Sabre\DAV\Server;
use Sabre\DAV\ServerPlugin;
use Sabre\DAV\Xml\Element\Response;
use Sabre\DAV\Xml\Response\MultiStatus;
use Sabre\HTTP\RequestInterface;
use Sabre\HTTP\ResponseInterface;
use Sabre\Xml\Writer;
/**
* Sabre plugin to handle comments:
*/
class CommentsPlugin extends ServerPlugin {
// namespace
public const NS_OWNCLOUD = 'http://owncloud.org/ns';
public const REPORT_NAME = '{http://owncloud.org/ns}filter-comments';
public const REPORT_PARAM_LIMIT = '{http://owncloud.org/ns}limit';
public const REPORT_PARAM_OFFSET = '{http://owncloud.org/ns}offset';
public const REPORT_PARAM_TIMESTAMP = '{http://owncloud.org/ns}datetime';
/** @var \Sabre\DAV\Server $server */
private $server;
/**
* Comments plugin
*
* @param ICommentsManager $commentsManager
* @param IUserSession $userSession
*/
public function __construct(
protected ICommentsManager $commentsManager,
protected IUserSession $userSession,
) {
}
/**
* This initializes the plugin.
*
* This function is called by Sabre\DAV\Server, after
* addPlugin is called.
*
* This method should set up the required event subscriptions.
*
* @param Server $server
* @return void
*/
public function initialize(Server $server) {
$this->server = $server;
if (!str_starts_with($this->server->getRequestUri(), 'comments/')) {
return;
}
$this->server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc';
$this->server->xml->classMap['DateTime'] = function (Writer $writer, \DateTime $value): void {
$writer->write(\Sabre\HTTP\toDate($value));
};
$this->server->on('report', [$this, 'onReport']);
$this->server->on('method:POST', [$this, 'httpPost']);
}
/**
* POST operation on Comments collections
*
* @param RequestInterface $request request object
* @param ResponseInterface $response response object
* @return null|false
*/
public function httpPost(RequestInterface $request, ResponseInterface $response) {
$path = $request->getPath();
$node = $this->server->tree->getNodeForPath($path);
if (!$node instanceof EntityCollection) {
return null;
}
$data = $request->getBodyAsString();
$comment = $this->createComment(
$node->getName(),
$node->getId(),
$data,
$request->getHeader('Content-Type')
);
// update read marker for the current user/poster to avoid
// having their own comments marked as unread
$node->setReadMarker(null);
$url = rtrim($request->getUrl(), '/') . '/' . urlencode($comment->getId());
$response->setHeader('Content-Location', $url);
// created
$response->setStatus(Http::STATUS_CREATED);
return false;
}
/**
* Returns a list of reports this plugin supports.
*
* This will be used in the {DAV:}supported-report-set property.
*
* @param string $uri
* @return array
*/
public function getSupportedReportSet($uri) {
return [self::REPORT_NAME];
}
/**
* REPORT operations to look for comments
*
* @param string $reportName
* @param array $report
* @param string $uri
* @return bool
* @throws NotFound
* @throws ReportNotSupported
*/
public function onReport($reportName, $report, $uri) {
$node = $this->server->tree->getNodeForPath($uri);
if (!$node instanceof EntityCollection || $reportName !== self::REPORT_NAME) {
throw new ReportNotSupported();
}
$args = ['limit' => 0, 'offset' => 0, 'datetime' => null];
$acceptableParameters = [
$this::REPORT_PARAM_LIMIT,
$this::REPORT_PARAM_OFFSET,
$this::REPORT_PARAM_TIMESTAMP
];
$ns = '{' . $this::NS_OWNCLOUD . '}';
foreach ($report as $parameter) {
if (!in_array($parameter['name'], $acceptableParameters) || empty($parameter['value'])) {
continue;
}
$args[str_replace($ns, '', $parameter['name'])] = $parameter['value'];
}
if (!is_null($args['datetime'])) {
$args['datetime'] = new \DateTime((string)$args['datetime']);
}
$results = $node->findChildren($args['limit'], $args['offset'], $args['datetime']);
$responses = [];
foreach ($results as $node) {
$nodePath = $this->server->getRequestUri() . '/' . $node->comment->getId();
$resultSet = $this->server->getPropertiesForPath($nodePath, CommentNode::getPropertyNames());
if (isset($resultSet[0]) && isset($resultSet[0][200])) {
$responses[] = new Response(
$this->server->getBaseUri() . $nodePath,
[200 => $resultSet[0][200]],
'200'
);
}
}
$xml = $this->server->xml->write(
'{DAV:}multistatus',
new MultiStatus($responses)
);
$this->server->httpResponse->setStatus(Http::STATUS_MULTI_STATUS);
$this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
$this->server->httpResponse->setBody($xml);
return false;
}
/**
* Creates a new comment
*
* @param string $objectType e.g. "files"
* @param string $objectId e.g. the file id
* @param string $data JSON encoded string containing the properties of the tag to create
* @param string $contentType content type of the data
* @return IComment newly created comment
*
* @throws BadRequest if a field was missing
* @throws UnsupportedMediaType if the content type is not supported
*/
private function createComment($objectType, $objectId, $data, $contentType = 'application/json') {
if (explode(';', $contentType)[0] === 'application/json') {
$data = json_decode($data, true, 512, JSON_THROW_ON_ERROR);
} else {
throw new UnsupportedMediaType();
}
$actorType = $data['actorType'];
$actorId = null;
if ($actorType === 'users') {
$user = $this->userSession->getUser();
if (!is_null($user)) {
$actorId = $user->getUID();
}
}
if (is_null($actorId)) {
throw new BadRequest('Invalid actor "' . $actorType . '"');
}
try {
$comment = $this->commentsManager->create($actorType, $actorId, $objectType, $objectId);
$comment->setMessage($data['message']);
$comment->setVerb($data['verb']);
$this->commentsManager->save($comment);
return $comment;
} catch (\InvalidArgumentException $e) {
throw new BadRequest('Invalid input values', 0, $e);
} catch (MessageTooLongException $e) {
$msg = 'Message exceeds allowed character limit of ';
throw new BadRequest($msg . IComment::MAX_MESSAGE_LENGTH, 0, $e);
}
}
}