Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
0f10e42
Implement persisent major version workflow for versions
JammingBen Sep 2, 2022
7ede572
adjust after rebase
mrow4a Dec 2, 2022
6c0fcfc
rollback to preview current logic and add handling for displaying cur…
mrow4a Dec 3, 2022
fd8c511
add dav implementation for exposing current version
mrow4a Dec 5, 2022
6d9370d
cleanup handling for current version
mrow4a Dec 6, 2022
afff63c
add handling for restored files
mrow4a Dec 9, 2022
e9a394c
add publish workflow
mrow4a Dec 11, 2022
f4f6e9e
add new config for versions metadata
mrow4a Dec 11, 2022
0e5e827
rebase and linting
mrow4a Dec 11, 2022
6352ade
phan fixes
mrow4a Dec 11, 2022
73e4831
add expiry prevention for persistent versions
mrow4a Dec 14, 2022
1062c29
fix tests
mrow4a Dec 14, 2022
80e9cc7
version restore should do copy instead of move
mrow4a Jan 1, 2023
f158c27
revert logic to expose version restore tag
mrow4a Jan 1, 2023
859cce2
add warning on disabling the feature
mrow4a Jan 1, 2023
f4460e6
minor version restore fixes
mrow4a Jan 2, 2023
55dd496
make sure change is backwards compatible
mrow4a Jan 2, 2023
c1576d5
add changelog
mrow4a Jan 2, 2023
7ee858a
fix javascript tests
mrow4a Jan 2, 2023
ee41917
adjust versioning unit tests
mrow4a Jan 2, 2023
b4a2bad
copy should preserve mtime
mrow4a Jan 3, 2023
d5e1e51
add tests for version tags
mrow4a Jan 3, 2023
68c3bb1
add publish version tests
mrow4a Jan 4, 2023
45e0c19
update changelog
mrow4a Jan 4, 2023
4be3b9d
adjust for tests
mrow4a Jan 4, 2023
fea3774
adjust versioning acceptance tests
mrow4a Jan 7, 2023
038435f
review fixes
mrow4a Jan 15, 2023
768a5a8
adjust to new acceptance tests
mrow4a Jan 22, 2023
495a1ef
avoid moving of checkboxes
mrow4a Feb 3, 2023
a36fb61
adjust for reviews
mrow4a Feb 10, 2023
81e3c8b
minor fixes
mrow4a Feb 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 8 additions & 10 deletions apps/dav/lib/Meta/MetaFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/**
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
* @copyright Copyright (c) 2017, ownCloud GmbH
* @copyright Copyright (c) 2022, ownCloud GmbH
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
Expand All @@ -26,6 +26,7 @@
use OCA\DAV\Files\IProvidesAdditionalHeaders;
use OCA\DAV\Files\IFileNode;
use OCP\Files\IProvidesVersionAuthor;
use OCP\Files\IProvidesVersionTag;
use OCP\Files\Node;
use Sabre\DAV\File;

Expand Down Expand Up @@ -128,24 +129,21 @@ public function getNode() {
}

/**
* @return string
* @inheritdoc
*/
public function getVersionAuthor() : string {
public function getVersionEditedBy() : string {
if ($this->file instanceof IProvidesVersionAuthor) {
return $this->file->getEditedBy();
}
return '';
}

/**
* @return string
* @inheritdoc
*/
public function getVersionAuthorName() : string {
if ($this->file instanceof IProvidesVersionAuthor) {
$uid = $this->file->getEditedBy();
$manager = \OC::$server->getUserManager();
$user = $manager->get($uid);
return $user !== null ? $user->getDisplayName() : '';
public function getVersionTag() : string {
if ($this->file instanceof IProvidesVersionTag) {
return $this->file->getVersionTag();
}
return '';
}
Expand Down
22 changes: 22 additions & 0 deletions apps/dav/lib/Meta/MetaFolder.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
use OCP\Files\File;
use OCP\Files\Folder;
use OCP\Files\Node;
use OCP\Files\IProvidesVersionAuthor;
use OCP\Files\IProvidesVersionTag;
use Sabre\DAV\Collection;

/**
Expand Down Expand Up @@ -71,4 +73,24 @@ private function nodeFactory(Node $node) {
}
throw new \InvalidArgumentException();
}

/**
* @inheritdoc
*/
public function getVersionEditedBy() : string {
if ($this->folder instanceof IProvidesVersionAuthor) {
return $this->folder->getEditedBy();
}
return '';
}

/**
* @inheritdoc
*/
public function getVersionTag() : string {
if ($this->folder instanceof IProvidesVersionTag) {
return $this->folder->getVersionTag();
}
return '';
}
}
36 changes: 32 additions & 4 deletions apps/dav/lib/Meta/MetaPlugin.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?php
/**
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Jannik Stehle <jstehle@owncloud.com>
* @author Piotr Mrowczynski <piotr@owncloud.com>
*
* @copyright Copyright (c) 2019, ownCloud GmbH
* @license AGPL-3.0
Expand Down Expand Up @@ -33,7 +35,9 @@ class MetaPlugin extends ServerPlugin {
public const PATH_FOR_FILEID_PROPERTYNAME = '{http://owncloud.org/ns}meta-path-for-user';

public const VERSION_EDITED_BY_PROPERTYNAME = '{http://owncloud.org/ns}meta-version-edited-by';
public const VERSION_EDITED_BY_PROPERTYNAME_NAME = '{http://owncloud.org/ns}meta-version-edited-by-name';
public const VERSION_EDITED_BY_NAME_PROPERTYNAME = '{http://owncloud.org/ns}meta-version-edited-by-name';
public const VERSION_TAG_PROPERTYNAME = '{http://owncloud.org/ns}meta-version-tag';

/**
* Reference to main server object
*
Expand Down Expand Up @@ -98,12 +102,36 @@ public function handleGetProperties(PropFind $propFind, INode $node) {
$file = \current($files);
return $baseFolder->getRelativePath($file->getPath());
});
$propFind->handle(self::VERSION_EDITED_BY_PROPERTYNAME, function () use ($node) {
return $node->getVersionEditedBy();
});
$propFind->handle(self::VERSION_EDITED_BY_NAME_PROPERTYNAME, function () use ($node) {
$versionEditedBy = $node->getVersionEditedBy();
if (!$versionEditedBy) {
return '';
}
$manager = \OC::$server->getUserManager(); // FIXME: not so good
$user = $manager->get($versionEditedBy);
return $user !== null ? $user->getDisplayName() : '';
});
$propFind->handle(self::VERSION_TAG_PROPERTYNAME, function () use ($node) {
return $node->getVersionTag();
});
} elseif ($node instanceof MetaFile) {
$propFind->handle(self::VERSION_EDITED_BY_PROPERTYNAME, function () use ($node) {
return $node->getVersionAuthor();
return $node->getVersionEditedBy();
});
$propFind->handle(self::VERSION_EDITED_BY_NAME_PROPERTYNAME, function () use ($node) {
$versionEditedBy = $node->getVersionEditedBy();
if (!$versionEditedBy) {
return '';
}
$manager = \OC::$server->getUserManager(); // FIXME: not so good
Comment thread
mrow4a marked this conversation as resolved.
$user = $manager->get($versionEditedBy);
return $user !== null ? $user->getDisplayName() : '';
});
$propFind->handle(self::VERSION_EDITED_BY_PROPERTYNAME_NAME, function () use ($node) {
return $node->getVersionAuthorName();
$propFind->handle(self::VERSION_TAG_PROPERTYNAME, function () use ($node) {
return $node->getVersionTag();
});
}
}
Expand Down
44 changes: 33 additions & 11 deletions apps/files_trashbin/lib/Trashbin.php
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ private static function retainVersions($filename, $owner, $ownerPath, $timestamp

// Temporary
$config = \OC::$server->getConfig();
$metaEnabled = $config->getSystemValue('file_storage.save_version_author', false) === true;
$metaEnabled = ($config->getSystemValue('file_storage.save_version_metadata', false) === true);
/** @var MetaStorage|null $metaStorage */
$metaStorage = null;

Expand All @@ -413,35 +413,50 @@ private static function retainVersions($filename, $owner, $ownerPath, $timestamp
$src = $owner . '/files_versions/' . $ownerPath;
$dst = $owner . '/files_trashbin/versions/' . \basename($ownerPath) . '.d' . $timestamp;
self::copy_recursive($src, $dst, $rootView);
if ($metaEnabled) {
Comment thread
mrow4a marked this conversation as resolved.
$metaStorage->copyRecursiveMetaDataFiles('/files_versions/' . $ownerPath, $owner, '/files_trashbin/versions/' . \basename($ownerPath) . '.d' . $timestamp, $owner);
}
}
if (!$forceCopy) {
$src = '/files_versions/' . $ownerPath;
$dst ='/files_trashbin/versions/' . $filename . '.d' . $timestamp;
self::move($rootView, "$owner$src", "$user$dst");
if ($metaEnabled) {
$metaStorage->renameOrCopy('rename', $src . MetaStorage::VERSION_FILE_EXT, $owner, $dst . MetaStorage::VERSION_FILE_EXT, $user);
}
}
} elseif ($versions = \OCA\Files_Versions\Storage::getVersions($owner, $ownerPath)) {
// NOTE: move logic for versions metadata to versions storage (including current version logic for parent file)

// copy version root metadata
if ($metaEnabled) {
if ($owner !== $user || $forceCopy) {
$src = '/files_versions/' . $ownerPath . MetaStorage::CURRENT_FILE_PREFIX . MetaStorage::VERSION_FILE_EXT;
$dst = '/files_trashbin/versions/' . \basename($ownerPath) . MetaStorage::CURRENT_FILE_PREFIX . '.d' . $timestamp . MetaStorage::VERSION_FILE_EXT ;
$metaStorage->renameOrCopy('copy', $src, $owner, $dst, $owner);
}
if (!$forceCopy) {
$src = '/files_versions/' . $ownerPath . MetaStorage::CURRENT_FILE_PREFIX . MetaStorage::VERSION_FILE_EXT;
$dst = '/files_trashbin/versions/' . $filename . MetaStorage::CURRENT_FILE_PREFIX . '.d' . $timestamp . MetaStorage::VERSION_FILE_EXT;
$metaStorage->renameOrCopy('rename', $src, $owner, $dst, $user);
}
Comment thread
mrow4a marked this conversation as resolved.
}

foreach ($versions as $v) {
if ($owner !== $user || $forceCopy) {
// copy version data
$src = '/files_versions' . $v['path'] . '.v' . $v['version'];
$dst = '/files_trashbin/versions/' . $v['name'] . '.v' . $v['version'] . '.d' . $timestamp;
self::copy($rootView, "$owner$src", "$owner$dst");

// copy version metadata
if ($metaEnabled) {
$metaStorage->renameOrCopy('copy', $src . MetaStorage::VERSION_FILE_EXT, $owner, $dst . MetaStorage::VERSION_FILE_EXT, $owner);
}
}
if (!$forceCopy) {
// copy version data
$src = '/files_versions' . $v['path'] . '.v' . $v['version'];
$dst = '/files_trashbin/versions/' . $filename . '.v' . $v['version'] . '.d' . $timestamp;
self::move($rootView, "$owner$src", "$user$dst");

// copy version metadata
if ($metaEnabled) {
$metaStorage->renameOrCopy('rename', $src . MetaStorage::VERSION_FILE_EXT, $owner, $dst . MetaStorage::VERSION_FILE_EXT, $user);
;
}
}
}
Expand Down Expand Up @@ -580,7 +595,7 @@ public static function restore($filename, $targetLocation = null) {
\OCP\Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', ['filePath' => Filesystem::normalizePath('/' . $targetLocation),
'trashPath' => Filesystem::normalizePath($filename)]);

self::restoreVersions($view, $filename, $targetLocation);
self::restoreVersionsFromTrashbin($view, $filename, $targetLocation);

if ($timestamp) {
$query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=? AND `id`=? AND `timestamp`=?');
Expand All @@ -602,7 +617,7 @@ public static function restore($filename, $targetLocation = null) {
* @param string $location location where the file will be restored
* @return false|null
*/
private static function restoreVersions(View $view, $filename, $targetLocation) {
private static function restoreVersionsFromTrashbin(View $view, $filename, $targetLocation) {
if (\OCP\App::isEnabled('files_versions')) {
$user = User::getUser();
$rootView = new View('/');
Expand All @@ -618,7 +633,7 @@ private static function restoreVersions(View $view, $filename, $targetLocation)

// Temporary
$config = \OC::$server->getConfig();
$metaEnabled = $config->getSystemValue('file_storage.save_version_author', false) === true;
$metaEnabled = ($config->getSystemValue('file_storage.save_version_metadata', false) === true);
/** @var MetaStorage|null $metaStorage */
$metaStorage = null;

Expand All @@ -642,6 +657,13 @@ private static function restoreVersions(View $view, $filename, $targetLocation)
$filenameOnlyWithoutTimestamp = $filenameOnly;
$dirAndFilename = "{$dir}/{$filenameOnly}";
}

if ($metaEnabled && $timestamp) {
$src = '/files_trashbin/versions/' . $dirAndFilename . MetaStorage::CURRENT_FILE_PREFIX . '.d' . $timestamp;
$dst = '/files_versions/' . $ownerPath . MetaStorage::CURRENT_FILE_PREFIX;
$metaStorage->renameOrCopy('rename', $src . MetaStorage::VERSION_FILE_EXT, $user, $dst . MetaStorage::VERSION_FILE_EXT, $owner);
}

$versions = self::getVersionsFromTrash($filenameOnlyWithoutTimestamp, $timestamp, $user);
foreach ($versions as $v) {
if ($timestamp) {
Expand Down
36 changes: 36 additions & 0 deletions apps/files_versions/appinfo/routes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php
/**
* @author Jannik Stehle <jstehle@owncloud.com>
*
* @copyright Copyright (c) 2022, ownCloud GmbH
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* 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, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

$application = new \OCA\Files_Versions\AppInfo\Application();

$application->registerRoutes(
// @phan-suppress-next-line PhanUndeclaredThis
$this,
[
'routes' => [
[
'name' => 'Version#publishVersion',
'url' => '/publish-version',
'verb' => 'POST'
]
]
]
);
38 changes: 36 additions & 2 deletions apps/files_versions/css/versions.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
.versionsTabView li {
width: 100%;
cursor: default;
height: 56px;
height: 60px;
float: left;
border-bottom: 1px solid rgba(100,100,100,.1);
}
Expand Down Expand Up @@ -34,9 +34,13 @@

.versionsTabView .preview-container {
display: inline-block;
vertical-align: top;
vertical-align: top;
text-align: center;
}

.versionsTabView .preview-container {
padding: 5px;
}
.versionsTabView img {
cursor: pointer;
padding-right: 4px;
Expand All @@ -47,17 +51,31 @@
background-size: 32px;
width: 32px;
height: 32px;
display: block;
margin: 0 auto;
}

.versionsTabView .version-container {
display: inline-block;
margin-top: 5px;
}

.versionsTabView .versiondate {
min-width: 100px;
vertical-align: super;
}

.versionsTabView .versionstatus {
vertical-align: super;
}

/* FIXME: we need to find better solution for this ref. https://github.com/owncloud/core/pull/40531#issuecomment-1420926550 */
@media(max-width: 1200px) {
.versionsTabView .versionstatus {
display: none;
}
}

.versionsTabView .version-details {
text-align: left;
}
Expand All @@ -66,8 +84,24 @@
padding: 0 10px;
}

.versionsTabView .action-container {
display: inline;
}

.versionsTabView .revertVersion {
cursor: pointer;
float: right;
margin-right: -10px;
}

.versionsTabView .publishVersion {
cursor: pointer;
float: right;
margin-right: -10px;
}
.versionsTabView .current-version .version-headline {
font-weight: bold;
}
.versionsTabView .current-version {
background: #f8f8f8;
}
Loading