aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files_sharing/lib/External/Scanner.php
blob: 2b0741b4b966c3e43f3c1e6f6adb578a13ee0e8a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?php
/**
 * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors
 * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
 * SPDX-License-Identifier: AGPL-3.0-only
 */
namespace OCA\Files_Sharing\External;

use OC\Files\Cache\CacheEntry;
use OC\ForbiddenException;
use OCP\Files\NotFoundException;
use OCP\Files\StorageInvalidException;
use OCP\Files\StorageNotAvailableException;

class Scanner extends \OC\Files\Cache\Scanner {
	/** @var Storage */
	protected $storage;

	public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $lock = true) {
		// Disable locking for federated shares
		parent::scan($path, $recursive, $reuse, false);
	}

	/**
	 * Scan a single file and store it in the cache.
	 * If an exception happened while accessing the external storage,
	 * the storage will be checked for availability and removed
	 * if it is not available any more.
	 *
	 * @param string $file file to scan
	 * @param int $reuseExisting
	 * @param int $parentId
	 * @param CacheEntry|array|null|false $cacheData existing data in the cache for the file to be scanned
	 * @param bool $lock set to false to disable getting an additional read lock during scanning
	 * @param array|null $data the metadata for the file, as returned by the storage
	 * @return array|null an array of metadata of the scanned file
	 */
	public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null, $lock = true, $data = null) {
		try {
			return parent::scanFile($file, $reuseExisting, $parentId, $cacheData, $lock, $data);
		} catch (ForbiddenException $e) {
			$this->storage->checkStorageAvailability();
		} catch (NotFoundException $e) {
			// if the storage isn't found, the call to
			// checkStorageAvailable() will verify it and remove it
			// if appropriate
			$this->storage->checkStorageAvailability();
		} catch (StorageInvalidException $e) {
			$this->storage->checkStorageAvailability();
		} catch (StorageNotAvailableException $e) {
			$this->storage->checkStorageAvailability();
		}
	}
}
s="p">; use OCP\Comments\IComment; use OCP\Comments\ICommentsManager; 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 ICommentsManager */ protected $commentsManager; /** @var \Sabre\DAV\Server $server */ private $server; /** @var \OCP\IUserSession */ protected $userSession; /** * Comments plugin * * @param ICommentsManager $commentsManager * @param IUserSession $userSession */ public function __construct(ICommentsManager $commentsManager, IUserSession $userSession) { $this->commentsManager = $commentsManager; $this->userSession = $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) { $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(201); 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(207); $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 (\OCP\Comments\MessageTooLongException $e) { $msg = 'Message exceeds allowed character limit of '; throw new BadRequest($msg . \OCP\Comments\IComment::MAX_MESSAGE_LENGTH, 0, $e); } } }