145 lines
4.8 KiB
PHP
145 lines
4.8 KiB
PHP
|
<?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);
|
||
|
}
|
||
|
}
|