-
+
pgsql
sqlite
mysql
diff --git a/krankerl.toml b/krankerl.toml
index eee1014..ecf3843 100644
--- a/krankerl.toml
+++ b/krankerl.toml
@@ -1,6 +1,6 @@
[package]
before_cmds = [
"composer install",
- "npm install",
+ "npm ci",
"npm run build",
]
diff --git a/l10n/.gitkeep b/l10n/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/l10n/de.js b/l10n/de.js
new file mode 100644
index 0000000..a94a64b
--- /dev/null
+++ b/l10n/de.js
@@ -0,0 +1,9 @@
+OC.L10N.register(
+ "groupfolder_filesystem_snapshots",
+ {
+ "Automated hourly backup" : "Stündliches automatisches Backup",
+ "Automated daily backup" : "Tägliches automatisches Backup",
+ "Automated weekly backup" : "Wöchentliches automatisches Backup",
+ "Automated monthly backup" : "Monatliches automatisches Backup"
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/l10n/de.json b/l10n/de.json
new file mode 100644
index 0000000..8ae274f
--- /dev/null
+++ b/l10n/de.json
@@ -0,0 +1,7 @@
+{ "translations": {
+ "Automated hourly backup" : "Stündliches automatisches Backup",
+ "Automated daily backup" : "Tägliches automatisches Backup",
+ "Automated weekly backup" : "Wöchentliches automatisches Backup",
+ "Automated monthly backup" : "Monatliches automatisches Backup"
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+}
\ No newline at end of file
diff --git a/l10n/de_DE.js b/l10n/de_DE.js
new file mode 100644
index 0000000..a94a64b
--- /dev/null
+++ b/l10n/de_DE.js
@@ -0,0 +1,9 @@
+OC.L10N.register(
+ "groupfolder_filesystem_snapshots",
+ {
+ "Automated hourly backup" : "Stündliches automatisches Backup",
+ "Automated daily backup" : "Tägliches automatisches Backup",
+ "Automated weekly backup" : "Wöchentliches automatisches Backup",
+ "Automated monthly backup" : "Monatliches automatisches Backup"
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/l10n/de_DE.json b/l10n/de_DE.json
new file mode 100644
index 0000000..8ae274f
--- /dev/null
+++ b/l10n/de_DE.json
@@ -0,0 +1,7 @@
+{ "translations": {
+ "Automated hourly backup" : "Stündliches automatisches Backup",
+ "Automated daily backup" : "Tägliches automatisches Backup",
+ "Automated weekly backup" : "Wöchentliches automatisches Backup",
+ "Automated monthly backup" : "Monatliches automatisches Backup"
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+}
\ No newline at end of file
diff --git a/lib/Controller/AdminSettingsController.php b/lib/Controller/AdminSettingsController.php
index 97302d0..399e08e 100644
--- a/lib/Controller/AdminSettingsController.php
+++ b/lib/Controller/AdminSettingsController.php
@@ -19,29 +19,29 @@ class AdminSettingsController extends Controller {
);
}
- /**
- * @return JSONResponse
- */
- public function index(): JSONResponse {
- return new JSONResponse($this->settingsService->getAppValues());
- }
+ /**
+ * @return JSONResponse
+ */
+ public function index(): JSONResponse {
+ return new JSONResponse($this->settingsService->getAppValues());
+ }
- /**
- * @param $key
- *
- * @return JSONResponse
- */
- public function show($key): JSONResponse {
- return new JSONResponse($this->settingsService->getAppValue($key));
- }
+ /**
+ * @param $key
+ *
+ * @return JSONResponse
+ */
+ public function show($key): JSONResponse {
+ return new JSONResponse($this->settingsService->getAppValue($key));
+ }
- /**
- * @param $key
- * @param $value
- *
- * @return JSONResponse
- */
- public function update($key, $value): JSONResponse {
+ /**
+ * @param $key
+ * @param $value
+ *
+ * @return JSONResponse
+ */
+ public function update($key, $value): JSONResponse {
return new JSONResponse($this->settingsService->setAppValue($key, $value));
- }
+ }
}
\ No newline at end of file
diff --git a/lib/Db/DiffTask.php b/lib/Db/DiffTask.php
index 0398287..7a5a8c4 100644
--- a/lib/Db/DiffTask.php
+++ b/lib/Db/DiffTask.php
@@ -7,25 +7,25 @@ use OCP\AppFramework\Db\Entity;
class DiffTask extends Entity implements JsonSerializable {
- protected $userId;
- protected $groupfolderId;
+ protected $userId;
+ protected $groupfolderId;
protected $relativePath;
- protected $snapshotId;
- protected $timestamp;
+ protected $snapshotId;
+ protected $timestamp;
- public function __construct() {
- $this->addType('id','integer');
- $this->addType('groupfolderId','integer');
- }
+ public function __construct() {
+ $this->addType('id','integer');
+ $this->addType('groupfolderId','integer');
+ }
- public function jsonSerialize() {
- return [
- 'id' => $this->id,
+ public function jsonSerialize() {
+ return [
+ 'id' => $this->id,
'userId' => $this->userId,
- 'groupfolderId' => $this->groupfolderId,
+ 'groupfolderId' => $this->groupfolderId,
'relativePath' => $this->relativePath,
- 'snapshotId' => $this->snapshotId,
- 'timestamp' => $this->timestamp,
- ];
- }
+ 'snapshotId' => $this->snapshotId,
+ 'timestamp' => $this->timestamp,
+ ];
+ }
}
\ No newline at end of file
diff --git a/lib/Db/DiffTaskMapper.php b/lib/Db/DiffTaskMapper.php
index b1811c6..86f0353 100644
--- a/lib/Db/DiffTaskMapper.php
+++ b/lib/Db/DiffTaskMapper.php
@@ -9,29 +9,29 @@ use OCP\AppFramework\Db\QBMapper;
*/
class DiffTaskMapper extends QBMapper {
- public function __construct(IDBConnection $db) {
- parent::__construct($db, 'groupfolder_snapshots_tasks', DiffTask::class);
- }
+ public function __construct(IDBConnection $db) {
+ parent::__construct($db, 'groupfolder_snapshots_tasks', DiffTask::class);
+ }
- public function find(int $id, string $userId) {
- $qb = $this->db->getQueryBuilder();
+ public function find(int $id, string $userId) {
+ $qb = $this->db->getQueryBuilder();
- $qb->select('*')
- ->from($this->getTableName())
- ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
- ->andWhere($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)));
+ $qb->select('*')
+ ->from($this->getTableName())
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
+ ->andWhere($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)));
- return $this->findEntity($qb);
- }
+ return $this->findEntity($qb);
+ }
- public function findAll(string $userId) {
- $qb = $this->db->getQueryBuilder();
+ public function findAll(string $userId) {
+ $qb = $this->db->getQueryBuilder();
- $qb->select('*')
- ->from($this->getTableName())
- ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)));
+ $qb->select('*')
+ ->from($this->getTableName())
+ ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)));
- return $this->findEntities($qb);
- }
+ return $this->findEntities($qb);
+ }
}
\ No newline at end of file
diff --git a/lib/Db/DiffTaskResult.php b/lib/Db/DiffTaskResult.php
index b6865a9..e16d63e 100644
--- a/lib/Db/DiffTaskResult.php
+++ b/lib/Db/DiffTaskResult.php
@@ -7,45 +7,49 @@ use OCP\AppFramework\Db\Entity;
class DiffTaskResult extends Entity implements JsonSerializable {
- protected $taskId;
- protected $timestamp;
- protected $type;
+ protected $taskId;
+ protected $timestamp;
+ protected $type;
- protected $beforeFileExists;
- protected $beforePath;
- protected $beforeSize;
+ protected $beforeFileExists;
+ protected $beforePath;
+ protected $beforeSize;
- protected $currentFileExists;
- protected $currentPath;
- protected $currentSize;
+ protected $currentFileExists;
+ protected $currentFileId;
+
+ protected $currentPath;
+ protected $currentSize;
protected $reverted;
- public function __construct() {
- $this->addType('id','integer');
- $this->addType('taskId','integer');
- $this->addType('beforeFileExists','boolean');
- $this->addType('beforeSize','integer');
- $this->addType('currentFileExists','boolean');
- $this->addType('currentSize','integer');
+ public function __construct() {
+ $this->addType('id','integer');
+ $this->addType('taskId','integer');
+ $this->addType('beforeFileExists','boolean');
+ $this->addType('beforeSize','integer');
+ $this->addType('currentFileExists','boolean');
+ $this->addType('currentFileId','integer');
+ $this->addType('currentSize','integer');
$this->addType('reverted','boolean');
- }
+ }
- public function jsonSerialize() {
- return [
- 'id' => $this->id,
- 'taskId' => $this->taskId,
- 'type' => $this->type,
- 'before' => [
- 'fileExists' => $this->beforeFileExists,
- 'path' => $this->beforePath,
- 'size' => $this->beforeSize,
- ],
- 'current' => [
- 'fileExists' => $this->currentFileExists,
- 'path' => $this->currentPath,
- 'size' => $this->currentSize,
+ public function jsonSerialize() {
+ return [
+ 'id' => $this->id,
+ 'taskId' => $this->taskId,
+ 'type' => $this->type,
+ 'before' => [
+ 'fileExists' => $this->beforeFileExists,
+ 'path' => $this->beforePath,
+ 'size' => $this->beforeSize,
+ ],
+ 'current' => [
+ 'fileExists' => $this->currentFileExists,
+ 'fileId' => $this->currentFileId,
+ 'path' => $this->currentPath,
+ 'size' => $this->currentSize,
],
'reverted' => $this->reverted,
- ];
- }
+ ];
+ }
}
\ No newline at end of file
diff --git a/lib/Db/DiffTaskResultMapper.php b/lib/Db/DiffTaskResultMapper.php
index 882a0e1..7ecbaf2 100644
--- a/lib/Db/DiffTaskResultMapper.php
+++ b/lib/Db/DiffTaskResultMapper.php
@@ -9,29 +9,29 @@ use OCP\AppFramework\Db\QBMapper;
*/
class DiffTaskResultMapper extends QBMapper {
- public function __construct(IDBConnection $db) {
- parent::__construct($db, 'groupfolder_snapshots_task_results', DiffTaskResult::class);
- }
+ public function __construct(IDBConnection $db) {
+ parent::__construct($db, 'groupfolder_snapshots_task_results', DiffTaskResult::class);
+ }
- public function find(int $id) {
- $qb = $this->db->getQueryBuilder();
+ public function find(int $id) {
+ $qb = $this->db->getQueryBuilder();
- $qb->select('*')
- ->from($this->getTableName())
- ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
+ $qb->select('*')
+ ->from($this->getTableName())
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
- return $this->findEntity($qb);
- }
+ return $this->findEntity($qb);
+ }
- public function findAll(int $taskId) {
- $qb = $this->db->getQueryBuilder();
+ public function findAll(int $taskId) {
+ $qb = $this->db->getQueryBuilder();
- $qb->select('*')
- ->from($this->getTableName())
- ->where($qb->expr()->eq('task_id', $qb->createNamedParameter($taskId)));
+ $qb->select('*')
+ ->from($this->getTableName())
+ ->where($qb->expr()->eq('task_id', $qb->createNamedParameter($taskId)));
- return $this->findEntities($qb);
- }
+ return $this->findEntities($qb);
+ }
public function markReverted(int $id) {
$taskResult = $this->find($id);
diff --git a/lib/Entity/Snapshot.php b/lib/Entity/Snapshot.php
index e571a7d..90a99fe 100644
--- a/lib/Entity/Snapshot.php
+++ b/lib/Entity/Snapshot.php
@@ -5,16 +5,30 @@ namespace OCA\GroupfolderFilesystemSnapshots\Entity;
use JsonSerializable;
class Snapshot implements JsonSerializable {
- /** @var string */
- private $id;
+ public function __construct(
+ private string $id,
+ private string $name,
+ private ?\DateTimeImmutable $createdTimestamp = null,
+ ) {
+ }
- public function __construct(string $id) {
- $this->id = $id;
- }
+ public function getId(): string {
+ return $this->id;
+ }
- public function jsonSerialize(): mixed {
+ public function getName(): string {
+ return $this->name;
+ }
+
+ public function getCreatedTimestamp(): ?\DateTimeImmutable {
+ return $this->createdTimestamp;
+ }
+
+ public function jsonSerialize(): mixed {
return [
- 'id' => $this->id
+ 'id' => $this->id,
+ 'name' => $this->name,
+ 'createdTimestamp' => $this->createdTimestamp?->getTimestamp(),
];
}
}
diff --git a/lib/Helpers/FileHelper.php b/lib/Helpers/FileHelper.php
index c987549..27b6992 100644
--- a/lib/Helpers/FileHelper.php
+++ b/lib/Helpers/FileHelper.php
@@ -3,34 +3,34 @@
namespace OCA\GroupfolderFilesystemSnapshots\Helpers;
class FileHelper {
- private static function seperateFilesFromFolders($parentDir, $items) {
- $files = [];
- $folders = [];
+ private static function seperateFilesFromFolders($parentDir, $items) {
+ $files = [];
+ $folders = [];
- foreach($items as $item) {
- if(is_dir($parentDir . DIRECTORY_SEPARATOR . $item)) {
- $folders[] = $item;
- } else {
- $files[] = $item;
- }
- }
+ foreach($items as $item) {
+ if(is_dir($parentDir . DIRECTORY_SEPARATOR . $item)) {
+ $folders[] = $item;
+ } else {
+ $files[] = $item;
+ }
+ }
- return array($files, $folders);
- }
+ return array($files, $folders);
+ }
- public static function getFilesAndFolders($dir) {
- $scan = array_diff(scandir($dir), array('..', '.'));
+ public static function getFilesAndFolders($dir) {
+ $scan = array_diff(scandir($dir), array('..', '.'));
- return self::seperateFilesFromFolders($dir, $scan);
- }
+ return self::seperateFilesFromFolders($dir, $scan);
+ }
- public static function getFilesizesOfFiles($prefix, array $files) {
- $result = array();
+ public static function getFilesizesOfFiles($prefix, array $files) {
+ $result = array();
- foreach($files as $index=>$file) {
- $result[$index] = filesize($prefix . DIRECTORY_SEPARATOR . $file);
- }
+ foreach($files as $index=>$file) {
+ $result[$index] = filesize($prefix . DIRECTORY_SEPARATOR . $file);
+ }
- return $result;
- }
+ return $result;
+ }
}
\ No newline at end of file
diff --git a/lib/Manager/PathManager.php b/lib/Manager/PathManager.php
index 7b8a6e9..d7f0234 100644
--- a/lib/Manager/PathManager.php
+++ b/lib/Manager/PathManager.php
@@ -70,12 +70,12 @@ class PathManager {
private function checkIfGroupfolderExists(int $groupfolderId): bool {
$storageId = $this->getRootFolderStorageId();
if ($storageId === null) {
- return "storage Id null";
+ return false;
}
$folder = $this->groupfolderFolderManager->getFolder($groupfolderId, $storageId);
if ($folder === false) {
- return "Folder does not exist";
+ return false;
}
return true;
diff --git a/lib/Manager/SnapshotManager.php b/lib/Manager/SnapshotManager.php
index a66def3..ac9594b 100644
--- a/lib/Manager/SnapshotManager.php
+++ b/lib/Manager/SnapshotManager.php
@@ -2,16 +2,21 @@
namespace OCA\GroupfolderFilesystemSnapshots\Manager;
-use OCA\GroupfolderFilesystemSnapshots\Manager\PathManager;
+use OCP\IL10N;
+use OCA\GroupfolderFilesystemSnapshots\Manager\PathManager;
+use OCA\GroupfolderFilesystemSnapshots\Service\SettingsService;
use OCA\GroupfolderFilesystemSnapshots\Entity\Snapshot;
class SnapshotManager {
- private PathManager $pathManager;
+ private string $snapshotNamingScheme = "";
-
- public function __construct(PathManager $pathManager){
- $this->pathManager = $pathManager;
+ public function __construct(
+ protected readonly IL10N $l10n,
+ private readonly PathManager $pathManager,
+ private readonly SettingsService $settingsService,
+ ){
+ $this->snapshotNamingScheme = $this->settingsService->getAppValue("snapshot_naming_scheme");
}
private function validSnapshotId(string $snapshotId) {
@@ -27,20 +32,94 @@ class SnapshotManager {
}
}
+ private function createSnapshotEntity(string $id): Snapshot {
+ if ($this->snapshotNamingScheme === "zfs-auto-snapshot" && str_starts_with($id, "zfs-auto-snap")) {
+ if (str_starts_with($id, "zfs-auto-snap_hourly-")) {
+ $name = $this->l10n->t("Automated hourly backup");
+ $datetimestring = str_replace("zfs-auto-snap_hourly-", "", $id);
+ } elseif (str_starts_with($id, "zfs-auto-snap_daily-")) {
+ $name = $this->l10n->t("Automated daily backup");
+ $datetimestring = str_replace("zfs-auto-snap_daily-", "", $id);
+ } elseif (str_starts_with($id, "zfs-auto-snap_weekly-")) {
+ $name = $this->l10n->t("Automated weekly backup");
+ $datetimestring = str_replace("zfs-auto-snap_weekly-", "", $id);
+ } elseif (str_starts_with($id, "zfs-auto-snap_monthly-")) {
+ $name = $this->l10n->t("Automated monthly backup");
+ $datetimestring = str_replace("zfs-auto-snap_monthly-", "", $id);
+ }
+
+ if(isset($datetimestring)) {
+ $datetimearray = explode("-", $datetimestring);
+ $timestring = array_pop($datetimearray);
+
+ $year = (int)$datetimearray[0];
+ $month = (int)$datetimearray[1];
+ $day = (int)$datetimearray[2];
+ $hour = (int)substr($timestring, 0, 2);
+ $minute = (int)substr($timestring, 2, 2);
+
+ $createdTimestamp = (new \DateTimeImmutable())
+ ->setDate($year, $month, $day)
+ ->setTime($hour, $minute);
+ }
+
+ return new Snapshot(
+ id: $id,
+ name: $name ?: $id,
+ createdTimestamp: $createdTimestamp,
+ );
+ } else {
+ return new Snapshot(
+ id: $id,
+ name: $id,
+ );
+ }
+ }
+
function get(string $snapshotId) {
if(self::snapshotExists($snapshotId)) {
- return new Snapshot($snapshotId);
+ return $this->createSnapshotEntity($snapshotId);
} else {
return false;
}
-
}
- function getAll() {
+ function getAll(): array {
+ $snapshots = [];
+
$iterator = new \FilesystemIterator($this->pathManager->getFilesystemSnapshotsPath());
- foreach ($iterator as $fileinfo) {
- if(!$fileinfo->isDir()) continue;
- yield new Snapshot($fileinfo->getFilename());
- }
+
+ foreach ($iterator as $fileinfo) {
+ if(!$fileinfo->isDir()) continue;
+ $snapshots[] = $this->createSnapshotEntity($fileinfo->getFilename());
+ }
+
+ return $snapshots;
}
+
+ function getAllGenerator(){
+ $iterator = new \FilesystemIterator($this->pathManager->getFilesystemSnapshotsPath());
+
+ foreach ($iterator as $fileinfo) {
+ if(!$fileinfo->isDir()) continue;
+ yield $this->createSnapshotEntity($fileinfo->getFilename());
+ }
+ }
+
+ /**
+ * @var $subPathFilter Only return snapshots that have this subfolder in the specified groupfolder
+ */
+ function getFilteredGenerator(int $groupfolderId, string $subDirectoryFilter) {
+ $iterator = new \FilesystemIterator($this->pathManager->getFilesystemSnapshotsPath());
+
+ $groupfolderSubdirectoryPath = $this->pathManager->getGroupFolderDirectory($groupfolderId, $subDirectoryFilter);
+
+ foreach ($iterator as $fileinfo) {
+ if(!$fileinfo->isDir()) continue;
+ $snapshotId = $fileinfo->getFilename();
+ $filterFullPath = $this->pathManager->convertToSnapshotPath($groupfolderSubdirectoryPath, $snapshotId);
+ if(!(is_dir($filterFullPath))) continue;
+ yield $this->createSnapshotEntity($snapshotId);
+ }
+ }
}
\ No newline at end of file
diff --git a/lib/Migration/Version140Date20250701164500.php b/lib/Migration/Version140Date20250701164500.php
new file mode 100644
index 0000000..bebdd12
--- /dev/null
+++ b/lib/Migration/Version140Date20250701164500.php
@@ -0,0 +1,33 @@
+getTable(self::RESULTS_TABLE);
+
+ if(!$table->hasColumn('current_file_id')) {
+ $table->addColumn('current_file_id', Types::BIGINT, [
+ 'notnull' => false,
+ ]);
+ }
+
+ return $schema;
+ }
+}
diff --git a/lib/RecursiveDiff.php b/lib/RecursiveDiff.php
index 98ed344..9196eee 100644
--- a/lib/RecursiveDiff.php
+++ b/lib/RecursiveDiff.php
@@ -5,227 +5,223 @@ namespace OCA\GroupfolderFilesystemSnapshots;
use OCA\GroupfolderFilesystemSnapshots\Helpers\FileHelper;
class RecursiveDiff {
+ private $scan1files = [];
+ private $scan1folders = [];
- public string $dir1;
- public string $dir2;
+ private $scan2files = [];
+ private $scan2folders = [];
- private $prefix;
+ private $subJobs = [];
- private $newResultCallback;
- private $progressCallback;
+ private $subJobProgress = [];
+ private $progress = 0;
- private $scan1files = [];
- private $scan1folders = [];
+ public function __construct(
+ public readonly string $dir1,
+ public readonly string $dir2,
+ private readonly string $prefix = "",
+ private readonly array $folderBlocklist = [],
+ private $newResultCallback,
+ private $progressCallback,
+ ){}
- private $scan2files = [];
- private $scan2folders = [];
+ public function scan() {
+ $scan_num_files = 0;
- private $subJobs = [];
+ if(file_exists($this->dir1) && is_dir($this->dir1)) {
+ [$this->scan1files, $this->scan1folders] = FileHelper::getFilesAndFolders($this->dir1);
+ }
+
+ if(file_exists($this->dir2) && is_dir($this->dir2)) {
+ [$this->scan2files, $this->scan2folders] = FileHelper::getFilesAndFolders($this->dir2);
+ }
- private $subJobProgress = [];
- private $progress = 0;
+ $scan_num_files += sizeof($this->scan1files);
+ $scan_num_files += sizeof($this->scan2files);
+
+ $allSubfolders = array_unique(array_merge($this->scan1folders, $this->scan2folders));
- public function __construct($dir1, $dir2, $prefix = "", $newResultCallback, $progressCallback){
- $this->dir1 = $dir1;
- $this->dir2 = $dir2;
- $this->prefix = $prefix;
+ foreach($allSubfolders as $key=>$folder) {
+ $subdir1 = $this->dir1 . DIRECTORY_SEPARATOR . $folder;
+ $subdir2 = $this->dir2 . DIRECTORY_SEPARATOR . $folder;
+ $subprefix = $this->prefix . DIRECTORY_SEPARATOR . $folder;
+ $subFolderBlocklist = $this->folderBlocklist[$folder] ?? [];
- $this->newResultCallback = $newResultCallback;
- $this->progressCallback = $progressCallback;
- }
+ if($subFolderBlocklist === true) {
+ continue;
+ }
+
+ $newJob = new RecursiveDiff($subdir1, $subdir2, $subprefix, $subFolderBlocklist, $this->newResultCallback, function($numDoneFiles) use ($key) {
+ $this->subJobProgress[$key] = $numDoneFiles;
- public function scan() {
- $scan_num_files = 0;
+ $this->updateProgress();
+ });
- if(file_exists($this->dir1) && is_dir($this->dir1)) {
- [$this->scan1files, $this->scan1folders] = FileHelper::getFilesAndFolders($this->dir1);
- }
-
- if(file_exists($this->dir2) && is_dir($this->dir2)) {
- [$this->scan2files, $this->scan2folders] = FileHelper::getFilesAndFolders($this->dir2);
- }
+ $this->subJobs[] = $newJob;
- $scan_num_files += sizeof($this->scan1files);
- $scan_num_files += sizeof($this->scan2files);
-
- $allSubfolders = array_unique(array_merge($this->scan1folders, $this->scan2folders));
+ $scan_num_files += $newJob->scan();
+ }
- foreach($allSubfolders as $key=>$folder) {
- $subdir1 = $this->dir1 . DIRECTORY_SEPARATOR . $folder;
- $subdir2 = $this->dir2 . DIRECTORY_SEPARATOR . $folder;
- $subprefix = $this->prefix . DIRECTORY_SEPARATOR . $folder;
-
- $newJob = new RecursiveDiff($subdir1, $subdir2, $subprefix, $this->newResultCallback, function($numDoneFiles) use ($key) {
- $this->subJobProgress[$key] = $numDoneFiles;
+ return $scan_num_files;
+ }
- $this->updateProgress();
- });
+ private function updateProgress() {
+ ($this->progressCallback)(array_sum($this->subJobProgress) + $this->progress);
+ }
- $this->subJobs[] = $newJob;
+ function diff() {
+ $diff = [];
- $scan_num_files += $newJob->scan();
- }
+ foreach($this->subJobs as $job) {
+ $result = $job->diff();
+ array_push($diff, ...$result);
+ }
- return $scan_num_files;
- }
+ $fileCreations = array_diff($this->scan2files, $this->scan1files);
+ $fileCreationsFilesizes = FileHelper::getFilesizesOfFiles($this->dir2, $fileCreations);
- private function updateProgress() {
- ($this->progressCallback)(array_sum($this->subJobProgress) + $this->progress);
- }
+ $fileDeletions = array_diff($this->scan1files, $this->scan2files);
+ $fileDeletionsFilesizes = FileHelper::getFilesizesOfFiles($this->dir1, $fileDeletions);
- function diff() {
- $diff = [];
+ $filePossibleEdits = array_intersect($this->scan1files, $this->scan2files);
- foreach($this->subJobs as $job) {
- $result = $job->diff();
- array_push($diff, ...$result);
- }
+ /*$diff[] = [
+ "type" => "DEBUG",
+ "prefix" => $this->prefix,
+ "fileCreations" => $fileCreations,
+ "fileCreationsFilesizes" => $fileCreationsFilesizes,
+ "fileDeletions" => $fileDeletions,
+ "fileDeletionsFilesizes" => $fileDeletionsFilesizes,
+ //"folderCreations" => $folderCreations,
+ //"folderDeletions" => $folderDeletions,
+ "allSubfolders" => $allSubfolders,
+ ];*/
- $fileCreations = array_diff($this->scan2files, $this->scan1files);
- $fileCreationsFilesizes = FileHelper::getFilesizesOfFiles($this->dir2, $fileCreations);
+ // search for creations and deletions, that are actually renames
+ foreach($fileCreations as $creationIndex=>$creation) {
+ $creationPath = $this->dir2 . DIRECTORY_SEPARATOR . $creation;
+ $creationSize = $fileCreationsFilesizes[$creationIndex];
+
+ $renameContenders = array_keys($fileDeletionsFilesizes, $creationSize);
- $fileDeletions = array_diff($this->scan1files, $this->scan2files);
- $fileDeletionsFilesizes = FileHelper::getFilesizesOfFiles($this->dir1, $fileDeletions);
+ if(sizeof($renameContenders) != 0) {
+ /*$diff[] = [
+ "type" => "DEBUG",
+ "comparing" => [
+ "creation" => $creationIndex,
+ "deletions" => $renameContenders,
+ ],
+ ];*/
- $filePossibleEdits = array_intersect($this->scan1files, $this->scan2files);
+ $creationSHA = sha1_file($creationPath);
+ foreach($renameContenders as $contender) {
+ $deletion = $fileDeletions[$contender];
+ $deletionPath = $this->dir1 . DIRECTORY_SEPARATOR . $deletion;
+ $deletionSHA = sha1_file($deletionPath);
- /*$diff[] = [
- "type" => "DEBUG",
- "prefix" => $this->prefix,
- "fileCreations" => $fileCreations,
- "fileCreationsFilesizes" => $fileCreationsFilesizes,
- "fileDeletions" => $fileDeletions,
- "fileDeletionsFilesizes" => $fileDeletionsFilesizes,
- //"folderCreations" => $folderCreations,
- //"folderDeletions" => $folderDeletions,
- "allSubfolders" => $allSubfolders,
- ];*/
+ if($deletionSHA == $creationSHA) {
+ ($this->newResultCallback)(
+ type: "RENAME",
+ beforeFileExists: True,
+ beforePath: $this->prefix . DIRECTORY_SEPARATOR . $deletion,
+ beforeSize: $creationSize,
+ currentFileExists: True,
+ currentPath: $this->prefix . DIRECTORY_SEPARATOR . $creation,
+ currentSize: $creationSize,
+ );
- // search for creations and deletions, that are actually renames
- foreach($fileCreations as $creationIndex=>$creation) {
- $creationPath = $this->dir2 . DIRECTORY_SEPARATOR . $creation;
- $creationSize = $fileCreationsFilesizes[$creationIndex];
-
- $renameContenders = array_keys($fileDeletionsFilesizes, $creationSize);
+ unset($fileCreations[$creationIndex]);
+ unset($fileDeletions[$contender]);
- if(sizeof($renameContenders) != 0) {
- /*$diff[] = [
- "type" => "DEBUG",
- "comparing" => [
- "creation" => $creationIndex,
- "deletions" => $renameContenders,
- ],
- ];*/
+ $this->progress += 2;
+ $this->updateProgress();
- $creationSHA = sha1_file($creationPath);
- foreach($renameContenders as $contender) {
- $deletion = $fileDeletions[$contender];
- $deletionPath = $this->dir1 . DIRECTORY_SEPARATOR . $deletion;
- $deletionSHA = sha1_file($deletionPath);
+ break;
+ }
+ }
+ }
+ }
- if($deletionSHA == $creationSHA) {
- ($this->newResultCallback)(
- type: "RENAME",
- beforeFileExists: True,
- beforePath: $this->prefix . DIRECTORY_SEPARATOR . $deletion,
- beforeSize: $creationSize,
- currentFileExists: True,
- currentPath: $this->prefix . DIRECTORY_SEPARATOR . $creation,
- currentSize: $creationSize,
- );
+ foreach($fileCreations as $index=>$creation) {
+ ($this->newResultCallback)(
+ type: "CREATION",
+ beforeFileExists: False,
+ beforePath: NULL,
+ beforeSize: NULL,
+ currentFileExists: True,
+ currentPath: $this->prefix . DIRECTORY_SEPARATOR . $creation,
+ currentSize: $fileCreationsFilesizes[$index],
+ );
- unset($fileCreations[$creationIndex]);
- unset($fileDeletions[$contender]);
+ $this->progress++;
+ $this->updateProgress();
+ }
- $this->progress += 2;
- $this->updateProgress();
+ foreach($fileDeletions as $index=>$deletion) {
+ ($this->newResultCallback)(
+ type: "DELETION",
+ beforeFileExists: True,
+ beforePath: $this->prefix . DIRECTORY_SEPARATOR . $deletion,
+ beforeSize: $fileDeletionsFilesizes[$index],
+ currentFileExists: False,
+ currentPath: NULL,
+ currentSize: NULL,
+ );
- break;
- }
- }
- }
- }
+ $this->progress++;
+ $this->updateProgress();
+ }
- foreach($fileCreations as $index=>$creation) {
- ($this->newResultCallback)(
- type: "CREATION",
- beforeFileExists: False,
- beforePath: NULL,
- beforeSize: NULL,
- currentFileExists: True,
- currentPath: $this->prefix . DIRECTORY_SEPARATOR . $creation,
- currentSize: $fileCreationsFilesizes[$index],
- );
+ foreach($filePossibleEdits as $possibleEdit) {
+ $file1 = $this->dir1 . DIRECTORY_SEPARATOR . $possibleEdit;
+ $file2 = $this->dir2 . DIRECTORY_SEPARATOR . $possibleEdit;
+ $file1Size = filesize($file1);
+ $file2Size = filesize($file2);
- $this->progress++;
- $this->updateProgress();
- }
+ $this->progress += 2;
+ $this->updateProgress();
- foreach($fileDeletions as $index=>$deletion) {
- ($this->newResultCallback)(
- type: "DELETION",
- beforeFileExists: True,
- beforePath: $this->prefix . DIRECTORY_SEPARATOR . $deletion,
- beforeSize: $fileDeletionsFilesizes[$index],
- currentFileExists: False,
- currentPath: NULL,
- currentSize: NULL,
- );
+ if(filemtime($file1) == filemtime($file2)) {
+ //not different because same mtime
+ continue;
+ } else {
+ // mtime different, but could just have gotten touched without modifications
+ if($file1Size == $file2Size) {
+ // if filesize is the same check for binary differences
+ $handle1 = fopen($file1, 'rb');
+ $handle2 = fopen($file2, 'rb');
- $this->progress++;
- $this->updateProgress();
- }
+ $filesdifferent = false;
- foreach($filePossibleEdits as $possibleEdit) {
- $file1 = $this->dir1 . DIRECTORY_SEPARATOR . $possibleEdit;
- $file2 = $this->dir2 . DIRECTORY_SEPARATOR . $possibleEdit;
- $file1Size = filesize($file1);
- $file2Size = filesize($file2);
+ while(!feof($handle1)) {
+ if(fread($handle1, 8192) != fread($handle2, 8192)) {
+ // files are different
+ $filesdifferent = true;
+ break;
+ }
+ }
- $this->progress += 2;
- $this->updateProgress();
+ fclose($handle1);
+ fclose($handle2);
- if(filemtime($file1) == filemtime($file2)) {
- //not different because same mtime
- continue;
- } else {
- // mtime different, but could just have gotten touched without modifications
- if($file1Size == $file2Size) {
- // if filesize is the same check for binary differences
- $handle1 = fopen($file1, 'rb');
- $handle2 = fopen($file2, 'rb');
+ if(!$filesdifferent) {
+ continue;
+ }
+ }
+ }
- $filesdifferent = false;
+
+ ($this->newResultCallback)(
+ type: "EDIT",
+ beforeFileExists: True,
+ beforePath: $this->prefix . DIRECTORY_SEPARATOR . $possibleEdit,
+ beforeSize: $file1Size,
+ currentFileExists: True,
+ currentPath: $this->prefix . DIRECTORY_SEPARATOR . $possibleEdit,
+ currentSize: $file2Size,
+ );
+ }
- while(!feof($handle1)) {
- if(fread($handle1, 8192) != fread($handle2, 8192)) {
- // files are different
- $filesdifferent = true;
- break;
- }
- }
-
- fclose($handle1);
- fclose($handle2);
-
- if(!$filesdifferent) {
- continue;
- }
- }
- }
-
-
- ($this->newResultCallback)(
- type: "EDIT",
- beforeFileExists: True,
- beforePath: $this->prefix . DIRECTORY_SEPARATOR . $possibleEdit,
- beforeSize: $file1Size,
- currentFileExists: True,
- currentPath: $this->prefix . DIRECTORY_SEPARATOR . $possibleEdit,
- currentSize: $file2Size,
- );
- }
-
- return $diff;
- }
+ return $diff;
+ }
}
\ No newline at end of file
diff --git a/lib/Sections/SnapshotsSection.php b/lib/Sections/SnapshotsSection.php
index ca5800e..75f6ac5 100644
--- a/lib/Sections/SnapshotsSection.php
+++ b/lib/Sections/SnapshotsSection.php
@@ -6,27 +6,27 @@ use OCP\IURLGenerator;
use OCP\Settings\IIconSection;
class SnapshotsSection implements IIconSection {
- private IL10N $l;
- private IURLGenerator $urlGenerator;
+ private IL10N $l;
+ private IURLGenerator $urlGenerator;
- public function __construct(IL10N $l, IURLGenerator $urlGenerator) {
- $this->l = $l;
- $this->urlGenerator = $urlGenerator;
- }
+ public function __construct(IL10N $l, IURLGenerator $urlGenerator) {
+ $this->l = $l;
+ $this->urlGenerator = $urlGenerator;
+ }
- public function getIcon(): string {
- return $this->urlGenerator->imagePath('core', 'actions/settings-dark.svg');
- }
+ public function getIcon(): string {
+ return $this->urlGenerator->imagePath('core', 'actions/settings-dark.svg');
+ }
- public function getID(): string {
- return 'groupfolder_filesystem_snapshots';
- }
+ public function getID(): string {
+ return 'groupfolder_filesystem_snapshots';
+ }
- public function getName(): string {
- return $this->l->t('Groupfolder Filesystem Snapshots');
- }
+ public function getName(): string {
+ return $this->l->t('Groupfolder Filesystem Snapshots');
+ }
- public function getPriority(): int {
- return 98;
- }
+ public function getPriority(): int {
+ return 98;
+ }
}
\ No newline at end of file
diff --git a/lib/Service/DiffTaskResultService.php b/lib/Service/DiffTaskResultService.php
index 399185b..ed2e750 100644
--- a/lib/Service/DiffTaskResultService.php
+++ b/lib/Service/DiffTaskResultService.php
@@ -58,7 +58,7 @@ class DiffTaskResultService {
$diffTaskResult = $this->find($id);
if($diffTaskResult->getReverted()) {
- throw new AlreadyRevertedException;
+ throw new AlreadyRevertedException();
}
$taskId = $diffTaskResult->getTaskId();
@@ -66,35 +66,35 @@ class DiffTaskResultService {
$snapshotPath = $this->pathManager->getGroupFolderSnapshotDirectory($diffTask->getGroupfolderId(), $diffTask->getRelativePath(), $diffTask->getSnapshotId());
- $gruenerFolder = $this->pathManager->getGroupfolderMountById($diffTask->getGroupfolderId())->get($diffTask->getRelativePath());
+ $parentFolder = $this->pathManager->getGroupfolderMountById($diffTask->getGroupfolderId())->get($diffTask->getRelativePath());
switch($diffTaskResult->getType()) {
case "CREATION":
- $currentFile = $this->getSubfolderMustExist($gruenerFolder, $diffTaskResult->getCurrentPath());
+ $currentFile = $this->getSubfolderMustExist($parentFolder, $diffTaskResult->getCurrentPath());
$currentFile->delete();
break;
case "RENAME":
- $currentFile = $this->getSubfolderMustExist($gruenerFolder, $diffTaskResult->getCurrentPath());
- $beforeDirectory = $this->getOrCreateSubdirectoryByFilepath($gruenerFolder, $diffTaskResult->getBeforePath());
+ $currentFile = $this->getSubfolderMustExist($parentFolder, $diffTaskResult->getCurrentPath());
+ $beforeDirectory = $this->getOrCreateSubdirectoryByFilepath($parentFolder, $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());
+ $beforeDirectory = $this->getOrCreateSubdirectoryByFilepath($parentFolder, $diffTaskResult->getBeforePath());
$restoredFile = $beforeDirectory->newFile(basename($diffTaskResult->getBeforePath()));
$this->copyFilesystemFileToNextcloudFile($beforeFileFilesystemPath, $restoredFile);
break;
case "EDIT":
- $currentFile = $this->getSubfolderMustExist($gruenerFolder, $diffTaskResult->getCurrentPath());
+ $currentFile = $this->getSubfolderMustExist($parentFolder, $diffTaskResult->getCurrentPath());
$beforeFileFilesystemPath = $snapshotPath . DIRECTORY_SEPARATOR . $diffTaskResult->getBeforePath();
$this->copyFilesystemFileToNextcloudFile($beforeFileFilesystemPath, $currentFile);
break;
default:
- throw new \Exception;
+ throw new Exception();
}
return $this->mapper->markReverted($id);
@@ -104,7 +104,7 @@ class DiffTaskResultService {
if($parent->nodeExists($path)) {
return $parent->get($path);
} else {
- throw new ChangesMadeSinceDiffException;
+ throw new ChangesMadeSinceDiffException();
}
}
@@ -119,7 +119,7 @@ class DiffTaskResultService {
if($temp instanceof \OCP\Files\Folder) {
$beforeDirectory = $temp;
} else {
- throw new ChangesMadeSinceDiffException;
+ throw new ChangesMadeSinceDiffException();
}
} else {
$beforeDirectory = $beforeDirectory->newFolder($subdir);
diff --git a/lib/Service/DiffTaskService.php b/lib/Service/DiffTaskService.php
index 16ebb46..0f789ec 100644
--- a/lib/Service/DiffTaskService.php
+++ b/lib/Service/DiffTaskService.php
@@ -58,7 +58,8 @@ class DiffTaskService {
}
}
- function create(string $relativePathInGroupfolder, int $groupfolderId, string $snapshotId, string $userId, Callable $progressCallback = null): ?DiffTask {
+ function create(string $relativePathInGroupfolder, int $groupfolderId, string $snapshotId, string $userId, array $folderBlocklist, Callable $progressCallback = null): ?DiffTask {
+ $parentNode = $this->pathManager->getGroupfolderMountById($groupfolderId)->get($relativePathInGroupfolder);
$snapshotPath = $this->pathManager->getGroupFolderSnapshotDirectory($groupfolderId, $relativePathInGroupfolder, $snapshotId);
$groupfolderPath = $this->pathManager->getGroupFolderDirectory($groupfolderId, $relativePathInGroupfolder);
@@ -80,16 +81,25 @@ class DiffTaskService {
$snapshotPath,
$groupfolderPath,
"",
- function(string $type, bool $beforeFileExists, ?string $beforePath, ?int $beforeSize, bool $currentFileExists, ?string $currentPath, ?int $currentSize) use ($task) {
+ $folderBlocklist,
+ function(string $type, bool $beforeFileExists, ?string $beforePath, ?int $beforeSize, bool $currentFileExists, ?string $currentPath, ?int $currentSize) use ($task, $parentNode) {
$newResult = new DiffTaskResult();
$newResult->setTaskId($task->getId());
$newResult->setType($type);
+
$newResult->setBeforeFileExists($beforeFileExists);
- $newResult->setBeforePath($beforePath);
- $newResult->setBeforeSize($beforeSize);
+ if($beforeFileExists) {
+ $newResult->setBeforePath($beforePath);
+ $newResult->setBeforeSize($beforeSize);
+ }
+
$newResult->setCurrentFileExists($currentFileExists);
- $newResult->setCurrentPath($currentPath);
- $newResult->setCurrentSize($currentSize);
+ if($currentFileExists) {
+ $newResult->setCurrentFileId($parentNode->get($currentPath)?->getId());
+ $newResult->setCurrentPath($currentPath);
+ $newResult->setCurrentSize($currentSize);
+ }
+
$newResult = $this->diffTaskResultMapper->insert($newResult);
},
function($numDoneFiles) use ($progressCallback, &$numFiles) {
@@ -97,8 +107,7 @@ class DiffTaskService {
($progressCallback)([
"overallFiles" => $numFiles,
"doneFiles" => $numDoneFiles,
- "progress" => number_format(($numDoneFiles / $numFiles),2),
- "progressPercent" => (number_format(($numDoneFiles / $numFiles),2) * 100) . "%",
+ "progress" => floor(($numDoneFiles / $numFiles) * 100) / 100,
]);
}
},
@@ -113,7 +122,6 @@ class DiffTaskService {
"overallFiles" => $numFiles,
"doneFiles" => $numFiles,
"progress" => 1.0,
- "progressPercent" => "100.00%",
"result" => $task,
]);
}
diff --git a/lib/Service/SettingsService.php b/lib/Service/SettingsService.php
index 9e9a56b..9846e84 100644
--- a/lib/Service/SettingsService.php
+++ b/lib/Service/SettingsService.php
@@ -9,7 +9,7 @@ use OCP\IConfig;
class SettingsService {
- private static array $VALID_APP_SETTINGS = ["filesystem_mountpoint_path", "filesystem_snapshots_path"];
+ private static array $VALID_APP_SETTINGS = ["filesystem_mountpoint_path", "filesystem_snapshots_path", "snapshot_naming_scheme"];
public function __construct(private IConfig $config) {
}
@@ -28,7 +28,7 @@ class SettingsService {
}
}
- public function setAppValue(string $key, string $value): string {
+ public function setAppValue(string $key, string $value): string {
if(in_array($key, self::$VALID_APP_SETTINGS)) {
if($value !== '') {
$this->config->setAppValue(Application::APP_ID, $key, $value);
@@ -38,5 +38,5 @@ class SettingsService {
return $value;
}
- }
+ }
}
\ No newline at end of file
diff --git a/lib/Settings/SnapshotsAdmin.php b/lib/Settings/SnapshotsAdmin.php
index 24bed92..848cb58 100644
--- a/lib/Settings/SnapshotsAdmin.php
+++ b/lib/Settings/SnapshotsAdmin.php
@@ -6,21 +6,21 @@ use OCP\Settings\ISettings;
class SnapshotsAdmin implements ISettings {
- public function __construct() {
- }
+ public function __construct() {
+ }
- /**
- * @return TemplateResponse
- */
- public function getForm() {
- return new TemplateResponse('groupfolder_filesystem_snapshots', 'settings/admin');
- }
+ /**
+ * @return TemplateResponse
+ */
+ public function getForm() {
+ return new TemplateResponse('groupfolder_filesystem_snapshots', 'settings/admin');
+ }
- public function getSection() {
- return 'groupfolder_filesystem_snapshots';
- }
+ public function getSection() {
+ return 'groupfolder_filesystem_snapshots';
+ }
- public function getPriority() {
- return 10;
- }
+ public function getPriority() {
+ return 10;
+ }
}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 0933a90..fcbb78f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,7 +22,7 @@
},
"engines": {
"node": "^16.0.0",
- "npm": "^11.0.0"
+ "npm": "^7.0.0 || ^8.0.0"
}
},
"node_modules/@ampproject/remapping": {
diff --git a/package.json b/package.json
index 6a214a6..f4c091a 100644
--- a/package.json
+++ b/package.json
@@ -31,7 +31,7 @@
],
"engines": {
"node": "^16.0.0",
- "npm": "^11.0.0"
+ "npm": "^7.0.0 || ^8.0.0"
},
"devDependencies": {
"@nextcloud/babel-config": "^1.2.0",
diff --git a/src/AdminSettings.vue b/src/AdminSettings.vue
index fd5a7a3..e605975 100644
--- a/src/AdminSettings.vue
+++ b/src/AdminSettings.vue
@@ -4,12 +4,13 @@
name="Groupfolder Filesystem Snapshots"
:limit-width="false">
- updateSetting(setting.id, newValue)"
@update:value="(newValue) => updateSetting(setting.id, newValue)" />
@@ -18,7 +19,7 @@