Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/text.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJulius Härtl <jus@bitgrid.net>2019-05-14 10:34:30 +0300
committerJulius Härtl <jus@bitgrid.net>2019-05-14 10:34:30 +0300
commitfe6272f411f502b5734f74270f62fed17a0a8156 (patch)
treea518a1d6b1ffb0def71ea30d72502909dc858cf2 /lib
parentfd1e342338fbf6007ccbcd4fc2a34cdf8c8b2140 (diff)
Add public endpoints
Signed-off-by: Julius Härtl <jus@bitgrid.net>
Diffstat (limited to 'lib')
-rw-r--r--lib/Controller/PublicSessionController.php74
-rw-r--r--lib/Controller/SessionController.php103
-rw-r--r--lib/Service/ApiService.php121
-rw-r--r--lib/Service/DocumentService.php146
-rw-r--r--lib/Service/SessionService.php2
5 files changed, 317 insertions, 129 deletions
diff --git a/lib/Controller/PublicSessionController.php b/lib/Controller/PublicSessionController.php
index 446b02fde..ee5b446fc 100644
--- a/lib/Controller/PublicSessionController.php
+++ b/lib/Controller/PublicSessionController.php
@@ -26,26 +26,80 @@ declare(strict_types=1);
namespace OCA\Text\Controller;
-use OCP\AppFramework\Controller;
+use OCA\Text\Service\ApiService;
+use OCP\AppFramework\Http\Response;
+use OCP\AppFramework\PublicShareController;
+use OCP\ISession;
+use OCP\Share\Exceptions\ShareNotFound;
+use OCP\Share\IManager as ShareManager;
use OCP\AppFramework\Http\DataResponse;
-use OCP\AppFramework\Http\FileDisplayResponse;
-use OCP\Files\IRootFolder;
-use OCP\ICacheFactory;
use OCP\IRequest;
-use OCP\ITempManager;
-use OCP\Security\ISecureRandom;
+use OCP\Share\IShare;
-class PublicSessionController extends SessionController {
+class PublicSessionController extends PublicShareController {
+
+ /** @var ShareManager */
+ private $shareManager;
+
+ /** @var IShare */
+ private $share;
+
+ /** @var ApiService */
+ private $apiService;
+
+ public function __construct(string $appName, IRequest $request, ISession $session, ShareManager $shareManager, ApiService $apiService) {
+ parent::__construct($appName, $request, $session);
+ $this->shareManager = $shareManager;
+ $this->apiService = $apiService;
+ }
+
+ protected function getPasswordHash(): string {
+ return $this->share->getPassword();
+ }
+
+ public function isValidToken(): bool {
+ try {
+ $this->share = $this->shareManager->getShareByToken($this->getToken());
+ return true;
+ } catch (ShareNotFound $e) {
+ return false;
+ }
+ }
+
+ protected function isPasswordProtected(): bool {
+ return $this->share->getPassword() !== null;
+ }
/**
- * TODO: maybe set guestUserId in middleware
+ * @NoAdminRequired
+ * @PublicPage
*/
+ public function create(string $token, string $file = null): DataResponse {
+ return $this->apiService->create(null, $file, $token);
+ }
+
+ /**
+ * @NoAdminRequired
+ * @PublicPage
+ */
+ public function fetch(int $documentId, string $sessionId, string $sessionToken): Response {
+ return $this->apiService->fetch($documentId, $sessionId, $sessionToken);
+ }
+
+ /**
+ * @NoAdminRequired
+ * @PublicPage
+ */
+ public function push(int $documentId, int $sessionId, string $sessionToken, int $version, array $steps): DataResponse {
+ return $this->apiService->push($documentId, $sessionId, $sessionToken, $version, $steps);
+ }
/**
+ * @NoAdminRequired
* @PublicPage
*/
- public function push($transaction): DataResponse {
- parent::push($transaction);
+ public function sync(string $token, int $documentId, int $sessionId, string $sessionToken, int $version = 0, string $autosaveContent = null, bool $force = false, bool $manualSave = false): DataResponse {
+ return $this->apiService->sync($documentId, $sessionId, $sessionToken, $version, $autosaveContent, $force, $manualSave, $token);
}
}
diff --git a/lib/Controller/SessionController.php b/lib/Controller/SessionController.php
index 58a2dd7d4..aff55f0bc 100644
--- a/lib/Controller/SessionController.php
+++ b/lib/Controller/SessionController.php
@@ -4,124 +4,57 @@ declare(strict_types=1);
namespace OCA\Text\Controller;
-use OC\Files\Node\File;
-use OCA\Text\Service\DocumentService;
-use OCA\Text\Service\SessionService;
-use OCA\Text\VersionMismatchException;
+use OCA\Text\Service\ApiService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\DataResponse;
-use OCP\AppFramework\Http\FileDisplayResponse;
-use OCP\AppFramework\Http\NotFoundResponse;
-use OCP\Files\IRootFolder;
-use OCP\Files\NotFoundException;
-use OCP\ICacheFactory;
+use OCP\AppFramework\Http\Response;
use OCP\IRequest;
-use OCP\ITempManager;
-use OCP\Security\ISecureRandom;
-use OCA\Text\DocumentSaveConflictException;
class SessionController extends Controller {
- private $cache;
- private $sessionService;
- private $documentService;
+ /**
+ * @var ApiService
+ */
+ private $apiService;
- public function __construct(string $appName, IRequest $request, ICacheFactory $cacheFactory, SessionService $sessionService, DocumentService $documentService) {
+ public function __construct(string $appName, IRequest $request, ApiService $apiService) {
parent::__construct($appName, $request);
-
- $this->cache = $cacheFactory->createDistributed('textSession');
- $this->sessionService = $sessionService;
- $this->documentService = $documentService;
+ $this->apiService = $apiService;
}
/**
- * Initialize the session as a client so it can use the other methods
- *
- * @NoCSRFRequired
* @NoAdminRequired
*/
- public function create($file) {
- $document = $this->documentService->createDocumentByPath($file);
- $session = $this->sessionService->initSession($document->getId());
- return new DataResponse([
- 'document' => $document,
- 'session' => $session
- ]);
+ public function create(int $fileId = null, string $file = null): DataResponse {
+ return $this->apiService->create($fileId, $file);
}
/**
- *
- *
- * @NoCSRFRequired
* @NoAdminRequired
*/
- public function fetch($documentId, $sessionId, $token) {
- if ($this->sessionService->isValidSession($documentId, $sessionId, $token)) {
- $this->sessionService->removeInactiveSessions($documentId);
- $file = $this->documentService->getBaseFile($documentId);
- return new FileDisplayResponse($file);
- }
- return new NotFoundResponse();
+ public function fetch(int $documentId, int $sessionId, string $sessionToken): Response {
+ return $this->apiService->fetch($documentId, $sessionId, $sessionToken);
}
/**
- * Close existing session when quiting the client gracefully
- * This reduces some cleanup work if used by the client
- *
- * @NoCSRFRequired
* @NoAdminRequired
*/
- public function close($documentId, $sessionId, $token): DataResponse {
- // TODO: To implement
- return new DataResponse([]);
+ public function close(int $documentId, int $sessionId, string $sessionToken): DataResponse {
+ return $this->apiService->close($documentId, $sessionId, $sessionToken);
}
/**
- * Client tries to commit a set of transactions to the document
- *
- * @NoCSRFRequired
* @NoAdminRequired
*/
- public function push($documentId, $sessionId, $token, $version, $steps): DataResponse {
- if ($this->sessionService->isValidSession($documentId, $sessionId, $token)) {
- try {
- $steps = $this->documentService->addStep($documentId, $sessionId, $steps, $version);
- } catch (VersionMismatchException $e) {
- return new DataResponse($e->getMessage(), $e->getStatus());
- }
- return new DataResponse($steps);
- }
- return new DataResponse([], 500);
+ public function push(int $documentId, int $sessionId, string $sessionToken, int $version, array $steps): DataResponse {
+ return $this->apiService->push($documentId, $sessionId, $sessionToken, $version, $steps);
}
/**
- * Eventsource based handler
- *
- * @NoCSRFRequired
* @NoAdminRequired
- * @PublicPage
*/
- public function sync($documentId, $sessionId, $token, $version = 0, $autosaveContent = null, bool $force = false, bool $manualSave = false): DataResponse {
- if (!$this->sessionService->isValidSession($documentId, $sessionId, $token)) {
- return new DataResponse([], 500);
- }
- if ($version === $this->cache->get('document-version-'.$documentId)) {
- return new DataResponse(['steps' => []]);
- }
- try {
- $document = $this->documentService->autosave($documentId, $version, $autosaveContent, $force, $manualSave);
- } catch (DocumentSaveConflictException $e) {
- /** @var File $file */
- $file = $this->documentService->getFile($documentId);
- return new DataResponse([
- 'outsideChange' => $file->getContent()
- ], 409);
- }
- return new DataResponse([
- 'steps' => $this->documentService->getSteps($documentId, $version),
- 'sessions' => $this->sessionService->getActiveSessions($documentId),
- 'document' => $document
- ]);
+ public function sync(int $documentId, int $sessionId, string $sessionToken, int $version = 0, string $autosaveContent = null, bool $force = false, bool $manualSave = false): DataResponse {
+ return $this->apiService->sync($documentId, $sessionId, $sessionToken, $version, $autosaveContent, $force, $manualSave);
}
}
diff --git a/lib/Service/ApiService.php b/lib/Service/ApiService.php
new file mode 100644
index 000000000..07ea15e8f
--- /dev/null
+++ b/lib/Service/ApiService.php
@@ -0,0 +1,121 @@
+<?php
+/**
+ * @copyright Copyright (c) 2019 Julius Härtl <jus@bitgrid.net>
+ *
+ * @author Julius Härtl <jus@bitgrid.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Text\Service;
+
+
+use OCA\Text\DocumentSaveConflictException;
+use OCA\Text\VersionMismatchException;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\Http\FileDisplayResponse;
+use OCP\AppFramework\Http\NotFoundResponse;
+use OCP\Files\NotFoundException;
+use OCP\ICacheFactory;
+use OCP\IRequest;
+
+class ApiService {
+
+ protected $cache;
+ protected $sessionService;
+ protected $documentService;
+
+ public function __construct(string $appName, IRequest $request, ICacheFactory $cacheFactory, SessionService $sessionService, DocumentService $documentService) {
+ $this->cache = $cacheFactory->createDistributed('textSession');
+ $this->sessionService = $sessionService;
+ $this->documentService = $documentService;
+ }
+
+ public function create($fileId = null, $file = null, $token = null): DataResponse {
+ try {
+ if ($token) {
+ $document = $this->documentService->createDocumentByShareToken($token, $file);
+ } else if ($fileId) {
+ $document = $this->documentService->createDocumentByFileId($fileId);
+ } else if ($file) {
+ $document = $this->documentService->createDocumentByPath($file);
+ } else {
+ return new DataResponse('No valid file argument provided', 500);
+ }
+ } catch (\Exception $e) {
+ return new DataResponse($e->getMessage(), 500);
+ }
+ $session = $this->sessionService->initSession($document->getId());
+ return new DataResponse([
+ 'document' => $document,
+ 'session' => $session
+ ]);
+ }
+
+ public function fetch($documentId, $sessionId, $sessionToken) {
+ if ($this->sessionService->isValidSession($documentId, $sessionId, $sessionToken)) {
+ $this->sessionService->removeInactiveSessions($documentId);
+ try {
+ $file = $this->documentService->getBaseFile($documentId);
+ } catch (NotFoundException $e) {
+ return new NotFoundResponse();
+ }
+ return new FileDisplayResponse($file);
+ }
+ return new NotFoundResponse();
+ }
+
+ public function close($documentId, $sessionId, $sessionToken): DataResponse {
+ // TODO: To implement
+ return new DataResponse([]);
+ }
+
+ public function push($documentId, $sessionId, $sessionToken, $version, $steps): DataResponse {
+ if ($this->sessionService->isValidSession($documentId, $sessionId, $sessionToken)) {
+ try {
+ $steps = $this->documentService->addStep($documentId, $sessionId, $steps, $version);
+ } catch (VersionMismatchException $e) {
+ return new DataResponse($e->getMessage(), $e->getStatus());
+ }
+ return new DataResponse($steps);
+ }
+ return new DataResponse([], 500);
+ }
+
+ public function sync($documentId, $sessionId, $sessionToken, $version = 0, $autosaveContent = null, bool $force = false, bool $manualSave = false, $token = null): DataResponse {
+ if (!$this->sessionService->isValidSession($documentId, $sessionId, $sessionToken)) {
+ return new DataResponse([], 500);
+ }
+ if ($version === $this->cache->get('document-version-'.$documentId)) {
+ return new DataResponse(['steps' => []]);
+ }
+ try {
+ $document = $this->documentService->autosave($documentId, $version, $autosaveContent, $force, $manualSave, $token);
+ } catch (DocumentSaveConflictException $e) {
+ /** @var \OC\Files\Node\File $file */
+ $file = $this->documentService->getFileByShareToken($token);
+ return new DataResponse([
+ 'outsideChange' => $file->getContent()
+ ], 409);
+ }
+ return new DataResponse([
+ 'steps' => $this->documentService->getSteps($documentId, $version),
+ 'sessions' => $this->sessionService->getActiveSessions($documentId),
+ 'document' => $document
+ ]);
+ }
+}
diff --git a/lib/Service/DocumentService.php b/lib/Service/DocumentService.php
index 2ccc588ae..af9570610 100644
--- a/lib/Service/DocumentService.php
+++ b/lib/Service/DocumentService.php
@@ -23,42 +23,73 @@
namespace OCA\Text\Service;
-use http\Exception\InvalidArgumentException;
+use \InvalidArgumentException;
use function json_encode;
use OC\Files\Node\File;
use OCA\Text\Db\Document;
use OCA\Text\Db\DocumentMapper;
-use OCA\Text\Db\SessionMapper;
use OCA\Text\Db\Step;
use OCA\Text\Db\StepMapper;
use OCA\Text\DocumentSaveConflictException;
use OCA\Text\VersionMismatchException;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\Entity;
+use OCP\Constants;
+use OCP\Files\Folder;
+use OCP\Files\GenericFileException;
use OCP\Files\IAppData;
use OCP\Files\InvalidPathException;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\ICache;
use OCP\ICacheFactory;
use OCP\ILogger;
-use OCP\Lock\ILockingProvider;
+use OCP\Share\Exceptions\ShareNotFound;
+use OCP\Share\IManager as ShareManager;
class DocumentService {
/**
* Delay to wait for between autosave versions
*/
- const AUTOSAVE_MINIMUM_DELAY = 60;
+ public const AUTOSAVE_MINIMUM_DELAY = 60;
- private $sessionMapper;
+ /**
+ * @var string|null
+ */
private $userId;
+ /**
+ * @var DocumentMapper
+ */
private $documentMapper;
+ /**
+ * @var ILogger
+ */
private $logger;
+ /**
+ * @var ShareManager
+ */
+ private $shareManager;
+ /**
+ * @var StepMapper
+ */
+ private $stepMapper;
+ /**
+ * @var IRootFolder
+ */
+ private $rootFolder;
+ /**
+ * @var ICache
+ */
+ private $cache;
+ /**
+ * @var IAppData
+ */
+ private $appData;
- public function __construct(SessionMapper $sessionMapper, DocumentMapper $documentMapper, StepMapper $stepMapper, IAppData $appData, $userId, IRootFolder $rootFolder, ICacheFactory $cacheFactory, ILogger $logger) {
- $this->sessionMapper = $sessionMapper;
+ public function __construct(DocumentMapper $documentMapper, StepMapper $stepMapper, IAppData $appData, $userId, IRootFolder $rootFolder, ICacheFactory $cacheFactory, ILogger $logger, ShareManager $shareManager) {
$this->documentMapper = $documentMapper;
$this->stepMapper = $stepMapper;
$this->userId = $userId;
@@ -66,7 +97,7 @@ class DocumentService {
$this->rootFolder = $rootFolder;
$this->cache = $cacheFactory->createDistributed('text');
$this->logger = $logger;
-
+ $this->shareManager = $shareManager;
try {
$this->appData->getFolder('documents');
} catch (NotFoundException $e) {
@@ -94,30 +125,26 @@ class DocumentService {
* @throws InvalidPathException
* @throws NotPermittedException
*/
- public function getDocumentById($fileId) {
- return $this->createDocument($this->getFile($fileId));
+ public function createDocumentByFileId($fileId) {
+ $file = $this->getFileById($fileId);
+ return $this->createDocument($file);
}
- public function getFile($fileId) {
- /** @var File $file */
- return $this->rootFolder->getUserFolder($this->userId)->getById($fileId)[0];
+ /**
+ * @param $shareToken
+ * @param null $filePath
+ * @return Entity
+ * @throws InvalidPathException
+ * @throws NotFoundException
+ * @throws NotPermittedException
+ */
+ public function createDocumentByShareToken($shareToken, $filePath = null) {
+ $file = $this->getFileByShareToken($shareToken, $filePath);
+ return $this->createDocument($file);
}
- public function getFileForShare($token) {
-
- $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
- $originalSharePath = $userFolder->getRelativePath($share->getNode()->getPath());
- // Single file share
- if ($share->getNode() instanceof \OCP\Files\File) {
- // Single file download
- return $share->getNode();
- }
-
- return null;
- }
-
/**
* @param File $file
* @return Entity
@@ -125,7 +152,7 @@ class DocumentService {
* @throws InvalidPathException
* @throws NotPermittedException
*/
- protected function createDocument(File $file) {
+ protected function createDocument(File $file): Document {
try {
$document = $this->documentMapper->find($file->getFileInfo()->getId());
@@ -174,7 +201,7 @@ class DocumentService {
* @return ISimpleFile
* @throws NotFoundException
*/
- public function getBaseFile($document) {
+ public function getBaseFile($document): ISimpleFile {
return $this->appData->getFolder('documents')->getFile($document);
}
@@ -187,7 +214,7 @@ class DocumentService {
* @throws DoesNotExistException
* @throws VersionMismatchException
*/
- public function addStep($documentId, $sessionId, $steps, $version) {
+ public function addStep($documentId, $sessionId, $steps, $version): array {
// TODO check cache
$document = $this->documentMapper->find($documentId);
if ($version !== $document->getCurrentVersion()) {
@@ -200,7 +227,7 @@ class DocumentService {
$newVersion = $document->getCurrentVersion() + count($steps);
$document->setCurrentVersion($newVersion);
$this->documentMapper->update($document);
- $step = new Step($stepsJson);
+ $step = new Step();
$step->setData($stepsJson);
$step->setSessionId($sessionId);
$step->setDocumentId($documentId);
@@ -222,20 +249,27 @@ class DocumentService {
* @param $autoaveDocument
* @param bool $force
* @param bool $manualSave
+ * @param null $token
* @return Document
* @throws DocumentSaveConflictException
* @throws DoesNotExistException
+ * @throws GenericFileException
* @throws InvalidPathException
* @throws NotFoundException
* @throws NotPermittedException
- * @throws \OCP\Files\GenericFileException
+ * @throws ShareNotFound
*/
- public function autosave($documentId, $version, $autoaveDocument, $force = false, $manualSave = false) {
+ public function autosave($documentId, $version, $autoaveDocument, $force = false, $manualSave = false, $token = null): Document {
/** @var Document $document */
$document = $this->documentMapper->find($documentId);
/** @var File $file */
- $file = $this->rootFolder->getUserFolder($this->userId)->getById($documentId)[0];
+ if (!$token) {
+ $file = $this->rootFolder->getUserFolder($this->userId)->getById($documentId)[0];
+ } else {
+ $share = $this->shareManager->getShareByToken($token);
+ $file = $share->getNode();
+ }
$lastMTime = $document->getLastSavedVersionTime();
if ($lastMTime > 0 && $file->getEtag() !== $document->getLastSavedVersionEtag() && $force === false) {
@@ -278,4 +312,50 @@ class DocumentService {
}
}
+ public function getFileById($fileId) {
+ /** @var File $file */
+ return $this->rootFolder->getUserFolder($this->userId)->getById($fileId)[0];
+ }
+
+ /**
+ * @param $shareToken
+ * @param null|string $path
+ * @return \OCP\Files\File|Folder|\OCP\Files\Node
+ * @throws NotFoundException
+ */
+ public function getFileByShareToken($shareToken, $path = null) {
+ try {
+ $share = $this->shareManager->getShareByToken($shareToken);
+
+ } catch (ShareNotFound $e) {
+ throw new NotFoundException();
+ }
+
+ $node = $share->getNode();
+ if ($node instanceof \OCP\Files\File) {
+ return $node;
+ }
+ if ($node instanceof Folder) {
+ return $node->get($path);
+ }
+ throw new \InvalidArgumentException('No proper share data');
+ }
+
+ /**
+ * @param $shareToken
+ * @return void
+ * @throws NotFoundException
+ */
+ public function checkSharePermissions($shareToken, $permission = Constants::PERMISSION_READ): void {
+ try {
+ $share = $this->shareManager->getShareByToken($shareToken);
+ } catch (ShareNotFound $e) {
+ throw new NotFoundException();
+ }
+
+ if (($share->getPermissions() & $permission) === 0) {
+ throw new NotFoundException();
+ }
+ }
+
}
diff --git a/lib/Service/SessionService.php b/lib/Service/SessionService.php
index 94bc145ad..c46a1fef4 100644
--- a/lib/Service/SessionService.php
+++ b/lib/Service/SessionService.php
@@ -46,7 +46,7 @@ class SessionService {
$this->sessionMapper = $sessionMapper;
$this->secureRandom = $secureRandom;
$this->timeFactory = $timeFactory;
- $this->userId = $userId;
+ $this->userId = $userId ?? 'Guest';
}
public function initSession($documentId): Session {