added DiffTaskResultService, including revert logic

This commit is contained in:
Jonathan Treffler 2024-01-24 20:57:47 +01:00 committed by root
parent 5b6470a53b
commit a0e91fbf7b
3 changed files with 163 additions and 0 deletions

View file

@ -0,0 +1,9 @@
<?php
namespace OCA\GroupfolderFilesystemSnapshots\Exceptions;
class AlreadyRevertedException extends \RuntimeException {
public function __construct(string $message = 'Diff task result has already been reverted.') {
parent::__construct($message);
}
}

View file

@ -0,0 +1,9 @@
<?php
namespace OCA\GroupfolderFilesystemSnapshots\Exceptions;
class ChangesMadeSinceDiffException extends \RuntimeException {
public function __construct(string $message = 'Conflicting changes have been made to the files, since the restore process started') {
parent::__construct($message);
}
}

View file

@ -0,0 +1,145 @@
<?php
namespace OCA\GroupfolderFilesystemSnapshots\Service;
use Exception;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCA\GroupfolderFilesystemSnapshots\Exceptions\NotFoundException;
use OCA\GroupfolderFilesystemSnapshots\Exceptions\AlreadyRevertedException;
use OCA\GroupfolderFilesystemSnapshots\Exceptions\ChangesMadeSinceDiffException;
use OCA\GroupfolderFilesystemSnapshots\Db\DiffTaskResult;
use OCA\GroupfolderFilesystemSnapshots\Db\DiffTaskResultMapper;
use OCA\GroupfolderFilesystemSnapshots\Db\DiffTaskMapper;
use OCA\GroupfolderFilesystemSnapshots\Manager\PathManager;
class DiffTaskResultService {
private DiffTaskResultMapper $mapper;
private DiffTaskMapper $diffTaskMapper;
private PathManager $pathManager;
public function __construct(DiffTaskResultMapper $mapper, DiffTaskMapper $diffTaskMapper, PathManager $pathManager){
$this->mapper = $mapper;
$this->diffTaskMapper = $diffTaskMapper;
$this->pathManager = $pathManager;
}
/**
* @return DiffTaskResult[]
*/
public function findAll(int $taskId): array {
return $this->mapper->findAll($taskId);
}
/**
* @return never
*/
private function handleException ($e, $criteria) {
if ($e instanceof DoesNotExistException ||
$e instanceof MultipleObjectsReturnedException) {
throw new NotFoundException($e->getMessage(), $criteria);
} else {
throw $e;
}
}
public function find(int $id): DiffTaskResult {
try {
return $this->mapper->find($id);
} catch(Exception $e) {
$this->handleException($e, ["id" => $id]);
}
}
public function revert(int $id, string $userId) {
$diffTaskResult = $this->find($id);
if($diffTaskResult->getReverted()) {
throw new AlreadyRevertedException;
}
$taskId = $diffTaskResult->getTaskId();
$diffTask = $this->diffTaskMapper->find($taskId, $userId);
$snapshotPath = $this->pathManager->getGroupFolderSnapshotDirectory($diffTask->getGroupfolderId(), $diffTask->getRelativePath(), $diffTask->getSnapshotId());
$gruenerFolder = $this->pathManager->getGroupfolderMountById($diffTask->getGroupfolderId())->get($diffTask->getRelativePath());
switch($diffTaskResult->getType()) {
case "CREATION":
$currentFile = $this->getSubfolderMustExist($gruenerFolder, $diffTaskResult->getCurrentPath());
$currentFile->delete();
break;
case "RENAME":
$currentFile = $this->getSubfolderMustExist($gruenerFolder, $diffTaskResult->getCurrentPath());
$beforeDirectory = $this->getOrCreateSubdirectoryByFilepath($gruenerFolder, $diffTaskResult->getBeforePath());
$currentFile->move($beforeDirectory->getPath() . DIRECTORY_SEPARATOR . basename($diffTaskResult->getBeforePath()));
break;
case "DELETION":
$beforeFileFilesystemPath = $snapshotPath . DIRECTORY_SEPARATOR . $diffTaskResult->getBeforePath();
$beforeDirectory = $this->getOrCreateSubdirectoryByFilepath($gruenerFolder, $diffTaskResult->getBeforePath());
$restoredFile = $beforeDirectory->newFile(basename($diffTaskResult->getBeforePath()));
$this->copyFilesystemFileToNextcloudFile($beforeFileFilesystemPath, $restoredFile);
break;
case "EDIT":
$currentFile = $this->getSubfolderMustExist($gruenerFolder, $diffTaskResult->getCurrentPath());
$beforeFileFilesystemPath = $snapshotPath . DIRECTORY_SEPARATOR . $diffTaskResult->getBeforePath();
$this->copyFilesystemFileToNextcloudFile($beforeFileFilesystemPath, $currentFile);
break;
default:
throw new \Exception;
}
return $this->mapper->markReverted($id);
}
private function getSubfolderMustExist(\OCP\Files\Folder $parent, string $path) {
if($parent->nodeExists($path)) {
return $parent->get($path);
} else {
throw new ChangesMadeSinceDiffException;
}
}
private function getOrCreateSubdirectoryByFilepath(\OCP\Files\Folder $parent, string $filepath) {
$pathSplit = explode('/', trim($filepath, '/'));
array_pop($pathSplit);
$beforeDirectory = $parent;
foreach($pathSplit as $subdir) {
if($beforeDirectory->nodeExists($subdir)) {
$temp = $beforeDirectory->get($subdir);
if($temp instanceof \OCP\Files\Folder) {
$beforeDirectory = $temp;
} else {
throw new ChangesMadeSinceDiffException;
}
} else {
$beforeDirectory = $beforeDirectory->newFolder($subdir);
}
}
return $beforeDirectory;
}
private function copyFilesystemFileToNextcloudFile(string $filesystemPath, \OCP\Files\File $nextcloudFile) {
$snapshotFileStream = fopen($filesystemPath, 'r');
$snapshotFileMtime = filemtime($filesystemPath);
$restoredFileStream = $nextcloudFile->fopen('w');
stream_copy_to_stream($snapshotFileStream, $restoredFileStream);
fclose($snapshotFileStream);
fclose($restoredFileStream);
$nextcloudFile->touch($snapshotFileMtime);
}
}