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-04-23 13:00:59 +0300
committerJulius Härtl <jus@bitgrid.net>2019-04-23 13:00:59 +0300
commit2660b7fee51fe87c375307891e4a8abb98c07a69 (patch)
tree0be402f081d029bdc6a82bd80e8df0b7add65ce6 /lib
parent1bdb0ff3eaa0f8a874bbf306ca5fe8a45f8e6ff4 (diff)
Add first file handling
Signed-off-by: Julius Härtl <jus@bitgrid.net>
Diffstat (limited to 'lib')
-rw-r--r--lib/Controller/SessionController.php19
-rw-r--r--lib/Db/Document.php13
-rw-r--r--lib/Db/StepMapper.php8
-rw-r--r--lib/DocumentSaveConflictException.php29
-rw-r--r--lib/Service/DocumentService.php76
-rw-r--r--lib/Service/SessionService.php1
6 files changed, 129 insertions, 17 deletions
diff --git a/lib/Controller/SessionController.php b/lib/Controller/SessionController.php
index 7416bd5c3..2347d953c 100644
--- a/lib/Controller/SessionController.php
+++ b/lib/Controller/SessionController.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace OCA\Text\Controller;
+use OC\Files\Node\File;
use OCA\Text\Service\DocumentService;
use OCA\Text\Service\SessionService;
use OCP\AppFramework\Controller;
@@ -16,6 +17,7 @@ use OCP\ICacheFactory;
use OCP\IRequest;
use OCP\ITempManager;
use OCP\Security\ISecureRandom;
+use OCA\Text\DocumentSaveConflictException;
class SessionController extends Controller {
@@ -97,13 +99,26 @@ class SessionController extends Controller {
* @NoCSRFRequired
* @NoAdminRequired
*/
- public function sync($documentId, $version = 0): DataResponse {
+ public function sync($documentId, $sessionId, $token, $version = 0, $autosaveContent = null): 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);
+ } 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)
+ 'sessions' => $this->sessionService->getActiveSessions($documentId),
+ 'document' => $document
]);
}
diff --git a/lib/Db/Document.php b/lib/Db/Document.php
index 3155eac73..5c1e30c06 100644
--- a/lib/Db/Document.php
+++ b/lib/Db/Document.php
@@ -26,18 +26,29 @@ namespace OCA\Text\Db;
use OCP\AppFramework\Db\Entity;
-class Document extends Entity {
+class Document extends Entity implements \JsonSerializable {
public $id;
protected $currentVersion = 0;
protected $lastSavedVersion = 0;
protected $initialVersion = 0;
+ protected $lastSavedVersionTime = 0;
public function __construct() {
$this->addType('id', 'integer');
$this->addType('currentVersion', 'integer');
$this->addType('lastSavedVersion', 'integer');
+ $this->addType('lastSavedVersionTime', 'integer');
$this->addType('initialVersion', 'integer');
}
+ public function jsonSerialize() {
+ return [
+ 'id' => $this->id,
+ 'currentVersion' => $this->currentVersion,
+ 'lastSavedVersion' => $this->lastSavedVersion,
+ 'lastSavedVersionTime' => $this->lastSavedVersionTime,
+ ];
+ }
+
}
diff --git a/lib/Db/StepMapper.php b/lib/Db/StepMapper.php
index d8b370592..847409750 100644
--- a/lib/Db/StepMapper.php
+++ b/lib/Db/StepMapper.php
@@ -45,4 +45,12 @@ class StepMapper extends QBMapper {
return $this->findEntities($qb);
}
+
+ public function deleteAll($documentId) {
+ /* @var $qb IQueryBuilder */
+ $qb = $this->db->getQueryBuilder();
+ $qb->delete($this->getTableName())
+ ->where($qb->expr()->eq('document_id', $qb->createNamedParameter($documentId)))
+ ->execute();
+ }
}
diff --git a/lib/DocumentSaveConflictException.php b/lib/DocumentSaveConflictException.php
new file mode 100644
index 000000000..927c90a6a
--- /dev/null
+++ b/lib/DocumentSaveConflictException.php
@@ -0,0 +1,29 @@
+<?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;
+
+
+class DocumentSaveConflictException extends \Exception {
+
+}
diff --git a/lib/Service/DocumentService.php b/lib/Service/DocumentService.php
index 77c67557a..e68bfebd5 100644
--- a/lib/Service/DocumentService.php
+++ b/lib/Service/DocumentService.php
@@ -29,15 +29,21 @@ 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 OCP\AppFramework\Db\DoesNotExistException;
use OCP\Files\IAppData;
use OCP\Files\InvalidPathException;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
+use OCP\Files\NotPermittedException;
use OCP\ICacheFactory;
class DocumentService {
+ /**
+ * Delay to wait for between autosave versions
+ */
+ const AUTOSAVE_MINIMUM_DELAY = 10;
private $sessionMapper;
private $userId;
@@ -80,9 +86,12 @@ class DocumentService {
* @throws \OCP\Files\NotPermittedException
*/
public function getDocumentById($fileId) {
+ return $this->createDocument($this->getFile($fileId));
+ }
+
+ public function getFile($fileId) {
/** @var File $file */
- $file = $this->rootFolder->getUserFolder($this->userId)->getById($fileId);
- return $this->createDocument($file);
+ return $this->rootFolder->getUserFolder($this->userId)->getById($fileId)[0];
}
/**
@@ -93,24 +102,23 @@ class DocumentService {
* @throws \OCP\Files\NotPermittedException
*/
protected function createDocument(File $file) {
- /* remove this after debugging */
- try {
- $documentBaseFile = $this->appData->getFolder('documents')->getFile($file->getFileInfo()->getId());
- } catch (NotFoundException $e) {
- $documentBaseFile = $this->appData->getFolder('documents')->newFile($file->getFileInfo()->getId());
- }
- $documentBaseFile->putContent($file->fopen('r'));
- /** endremove */
-
try {
$document = $this->documentMapper->find($file->getFileInfo()->getId());
+
+ // TODO: do not hard reset if changed from outside since this will throw away possible steps
+ // TODO: Only do this when no sessions active, otherise we need to resolve the conflict differently
+ $lastMTime = $document->getLastSavedVersionTime();
+ if ($file->getMTime() > $lastMTime && $lastMTime > 0) {
+ $this->resetDocument($document->getId());
+ throw new NotFoundException();
+ }
+
return $document;
} catch (DoesNotExistException $e) {
} catch (InvalidPathException $e) {
} catch (NotFoundException $e) {
}
- // TODO: lock file
- // TODO: unlock after saving
+
try {
$documentBaseFile = $this->appData->getFolder('documents')->getFile($file->getFileInfo()->getId());
} catch (NotFoundException $e) {
@@ -122,6 +130,7 @@ class DocumentService {
$document->setId($file->getFileInfo()->getId());
$document->setCurrentVersion(0);
$document->setLastSavedVersion(0);
+ $document->setLastSavedVersionTime($file->getFileInfo()->getMtime());
$document = $this->documentMapper->insert($document);
$this->cache->set('document-version-'.$document->getId(), 0);
return $document;
@@ -155,7 +164,6 @@ class DocumentService {
$document->setCurrentVersion($newVersion);
$this->documentMapper->update($document);
$this->cache->set('document-version-'.$document->getId(), $newVersion);
- // TODO write version to cache for quicker checking
// TODO write steps to cache for quicker reading
return $steps;
}
@@ -164,4 +172,44 @@ class DocumentService {
return $this->stepMapper->find($documentId, $lastVersion);
}
+ public function autosave($documentId, $version, $autoaveDocument, $force = false, $manualSave = false) {
+ /** @var Document $document */
+ $document = $this->documentMapper->find($documentId);
+ $lastMTime = $document->getLastSavedVersionTime();
+ /** @var File $file */
+ $file = $this->rootFolder->getUserFolder($this->userId)->getById($documentId)[0];
+ if ($file->getMTime() > $lastMTime && $lastMTime > 0 && $force === false) {
+ throw new DocumentSaveConflictException('File changed in the meantime from outside');
+ }
+ // TODO: check for etag rather than mtime
+ // Do not save if version already saved
+ if ($version === (string)$document->getLastSavedVersion()) {
+ return null;
+ }
+ // Only save once every AUTOSAVE_MINIMUM_DELAY seconds
+ if ($file->getMTime() === $lastMTime && $lastMTime > time()- self::AUTOSAVE_MINIMUM_DELAY && $manualSave === false) {
+ return null;
+ }
+ $file->putContent($autoaveDocument);
+ $document->setLastSavedVersion($version);
+ $document->setLastSavedVersionTime(time());
+ $this->documentMapper->update($document);
+ return $document;
+ }
+
+ public function resetDocument($documentId) {
+ $this->stepMapper->deleteAll($documentId);
+ try {
+ $document = $this->documentMapper->find($documentId);
+ $this->documentMapper->delete($document);
+ } catch (DoesNotExistException $e) {
+ }
+
+ try {
+ $this->appData->getFolder('documents')->getFile($documentId)->delete();
+ } catch (NotFoundException $e) {
+ } catch (NotPermittedException $e) {
+ }
+ }
+
}
diff --git a/lib/Service/SessionService.php b/lib/Service/SessionService.php
index 748baf2f5..94bc145ad 100644
--- a/lib/Service/SessionService.php
+++ b/lib/Service/SessionService.php
@@ -95,6 +95,7 @@ class SessionService {
} catch (DoesNotExistException $e) {
return false;
}
+ // TODO: move to cache
$session->setLastContact($this->timeFactory->getTime());
$this->sessionMapper->update($session);
return true;