Merge pull request #44049 from nextcloud/feat/show-name-of-user-in-versions

feat: show the id of last author in versions metadata
pull/44138/head
Eduardo Morales 3 months ago committed by GitHub
commit f99b820cd0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -21,6 +21,7 @@ return array(
'OCA\\Files_Versions\\Listener\\FileEventsListener' => $baseDir . '/../lib/Listener/FileEventsListener.php',
'OCA\\Files_Versions\\Listener\\LoadAdditionalListener' => $baseDir . '/../lib/Listener/LoadAdditionalListener.php',
'OCA\\Files_Versions\\Listener\\LoadSidebarListener' => $baseDir . '/../lib/Listener/LoadSidebarListener.php',
'OCA\\Files_Versions\\Listener\\MetadataFileEvents' => $baseDir . '/../lib/Listener/MetadataFileEvents.php',
'OCA\\Files_Versions\\Migration\\Version1020Date20221114144058' => $baseDir . '/../lib/Migration/Version1020Date20221114144058.php',
'OCA\\Files_Versions\\Sabre\\Plugin' => $baseDir . '/../lib/Sabre/Plugin.php',
'OCA\\Files_Versions\\Sabre\\RestoreFolder' => $baseDir . '/../lib/Sabre/RestoreFolder.php',
@ -32,6 +33,8 @@ return array(
'OCA\\Files_Versions\\Storage' => $baseDir . '/../lib/Storage.php',
'OCA\\Files_Versions\\Versions\\BackendNotFoundException' => $baseDir . '/../lib/Versions/BackendNotFoundException.php',
'OCA\\Files_Versions\\Versions\\IDeletableVersionBackend' => $baseDir . '/../lib/Versions/IDeletableVersionBackend.php',
'OCA\\Files_Versions\\Versions\\IMetadataVersion' => $baseDir . '/../lib/Versions/IMetadataVersion.php',
'OCA\\Files_Versions\\Versions\\IMetadataVersionBackend' => $baseDir . '/../lib/Versions/IMetadataVersionBackend.php',
'OCA\\Files_Versions\\Versions\\INameableVersion' => $baseDir . '/../lib/Versions/INameableVersion.php',
'OCA\\Files_Versions\\Versions\\INameableVersionBackend' => $baseDir . '/../lib/Versions/INameableVersionBackend.php',
'OCA\\Files_Versions\\Versions\\INeedSyncVersionBackend' => $baseDir . '/../lib/Versions/INeedSyncVersionBackend.php',

@ -36,6 +36,7 @@ class ComposerStaticInitFiles_Versions
'OCA\\Files_Versions\\Listener\\FileEventsListener' => __DIR__ . '/..' . '/../lib/Listener/FileEventsListener.php',
'OCA\\Files_Versions\\Listener\\LoadAdditionalListener' => __DIR__ . '/..' . '/../lib/Listener/LoadAdditionalListener.php',
'OCA\\Files_Versions\\Listener\\LoadSidebarListener' => __DIR__ . '/..' . '/../lib/Listener/LoadSidebarListener.php',
'OCA\\Files_Versions\\Listener\\MetadataFileEvents' => __DIR__ . '/..' . '/../lib/Listener/MetadataFileEvents.php',
'OCA\\Files_Versions\\Migration\\Version1020Date20221114144058' => __DIR__ . '/..' . '/../lib/Migration/Version1020Date20221114144058.php',
'OCA\\Files_Versions\\Sabre\\Plugin' => __DIR__ . '/..' . '/../lib/Sabre/Plugin.php',
'OCA\\Files_Versions\\Sabre\\RestoreFolder' => __DIR__ . '/..' . '/../lib/Sabre/RestoreFolder.php',
@ -47,6 +48,8 @@ class ComposerStaticInitFiles_Versions
'OCA\\Files_Versions\\Storage' => __DIR__ . '/..' . '/../lib/Storage.php',
'OCA\\Files_Versions\\Versions\\BackendNotFoundException' => __DIR__ . '/..' . '/../lib/Versions/BackendNotFoundException.php',
'OCA\\Files_Versions\\Versions\\IDeletableVersionBackend' => __DIR__ . '/..' . '/../lib/Versions/IDeletableVersionBackend.php',
'OCA\\Files_Versions\\Versions\\IMetadataVersion' => __DIR__ . '/..' . '/../lib/Versions/IMetadataVersion.php',
'OCA\\Files_Versions\\Versions\\IMetadataVersionBackend' => __DIR__ . '/..' . '/../lib/Versions/IMetadataVersionBackend.php',
'OCA\\Files_Versions\\Versions\\INameableVersion' => __DIR__ . '/..' . '/../lib/Versions/INameableVersion.php',
'OCA\\Files_Versions\\Versions\\INameableVersionBackend' => __DIR__ . '/..' . '/../lib/Versions/INameableVersionBackend.php',
'OCA\\Files_Versions\\Versions\\INeedSyncVersionBackend' => __DIR__ . '/..' . '/../lib/Versions/INeedSyncVersionBackend.php',

@ -3,7 +3,7 @@
'name' => '__root__',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => 'a820e3d036741ad1194361eca11bc1cbcdda0a47',
'reference' => '84930a207a8d5f0ef32320796fe188892b63fa19',
'type' => 'library',
'install_path' => __DIR__ . '/../',
'aliases' => array(),
@ -13,7 +13,7 @@
'__root__' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => 'a820e3d036741ad1194361eca11bc1cbcdda0a47',
'reference' => '84930a207a8d5f0ef32320796fe188892b63fa19',
'type' => 'library',
'install_path' => __DIR__ . '/../',
'aliases' => array(),

@ -36,6 +36,7 @@ use OCA\Files_Versions\Capabilities;
use OCA\Files_Versions\Listener\FileEventsListener;
use OCA\Files_Versions\Listener\LoadAdditionalListener;
use OCA\Files_Versions\Listener\LoadSidebarListener;
use OCA\Files_Versions\Listener\MetadataFileEvents;
use OCA\Files_Versions\Versions\IVersionManager;
use OCA\Files_Versions\Versions\VersionManager;
use OCP\Accounts\IAccountManager;
@ -119,6 +120,8 @@ class Application extends App implements IBootstrap {
$context->registerEventListener(NodeCopiedEvent::class, FileEventsListener::class);
$context->registerEventListener(BeforeNodeRenamedEvent::class, FileEventsListener::class);
$context->registerEventListener(BeforeNodeCopiedEvent::class, FileEventsListener::class);
$context->registerEventListener(NodeWrittenEvent::class, MetadataFileEvents::class);
}
public function boot(IBootContext $context): void {

@ -78,4 +78,23 @@ class VersionEntity extends Entity implements JsonSerializable {
$this->metadata['label'] = $label;
$this->markFieldUpdated('metadata');
}
/**
* @abstract given a key, return the value associated with the key in the metadata column
* if nothing is found, we return an empty string
* @param string $key key associated with the value
*/
public function getMetadataValue(string $key): ?string {
return $this->metadata[$key] ?? null;
}
/**
* @abstract sets a key value pair in the metadata column
* @param string $key key associated with the value
* @param string $value value associated with the key
*/
public function setMetadataValue(string $key, string $value): void {
$this->metadata[$key] = $value;
$this->markFieldUpdated('metadata');
}
}

@ -85,7 +85,7 @@ class VersionsMapper extends QBMapper {
->executeStatement();
}
public function deleteAllVersionsForUser(int $storageId, string $path = null): void {
public function deleteAllVersionsForUser(int $storageId, ?string $path = null): void {
$fileIdsGenerator = $this->getFileIdsGenerator($storageId, $path);
$versionEntitiesDeleteQuery = $this->db->getQueryBuilder();

@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
/**
* @author Eduardo Morales emoral435@gmail.com>
*
* @license GNU AGPL-3.0-or-later
*
* 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/>
*
*/
namespace OCA\Files_Versions\Listener;
use OC\Files\Node\Folder;
use OCA\Files_Versions\Versions\IMetadataVersionBackend;
use OCA\Files_Versions\Versions\IVersionManager;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Files\Events\Node\NodeWrittenEvent;
use OCP\Files\Node;
use OCP\IUserSession;
/** @template-implements IEventListener<NodeWrittenEvent> */
class MetadataFileEvents implements IEventListener {
public function __construct(
private IVersionManager $versionManager,
private IUserSession $userSession,
) {
}
/**
* @abstract handles events from a nodes version being changed
* @param Event $event the event that triggered this listener to activate
*/
public function handle(Event $event): void {
if ($event instanceof NodeWrittenEvent) {
$this->post_write_hook($event->getNode());
}
}
/**
* @abstract handles the NodeWrittenEvent, and sets the metadata for the associated node
* @param Node $node the node that is currently being written
*/
public function post_write_hook(Node $node): void {
$user = $this->userSession->getUser();
// Do not handle folders or users that we cannot get metadata from
if ($node instanceof Folder || is_null($user)) {
return;
}
// check if our version manager supports setting the metadata
if ($this->versionManager instanceof IMetadataVersionBackend) {
$author = $user->getUID();
$this->versionManager->setMetadataValue($node, 'author', $author);
}
}
}

@ -44,6 +44,8 @@ class Plugin extends ServerPlugin {
public const VERSION_LABEL = '{http://nextcloud.org/ns}version-label';
public const VERSION_AUTHOR = '{http://nextcloud.org/ns}version-author'; // dav property for author
public function __construct(
private IRequest $request,
private IPreview $previewManager,
@ -93,6 +95,7 @@ class Plugin extends ServerPlugin {
public function propFind(PropFind $propFind, INode $node): void {
if ($node instanceof VersionFile) {
$propFind->handle(self::VERSION_LABEL, fn () => $node->getLabel());
$propFind->handle(self::VERSION_AUTHOR, fn () => $node->getMetadataValue("author"));
$propFind->handle(FilesPlugin::HAS_PREVIEW_PROPERTYNAME, fn () => $this->previewManager->isMimeSupported($node->getContentType()));
}
}

@ -27,6 +27,7 @@ declare(strict_types=1);
namespace OCA\Files_Versions\Sabre;
use OCA\Files_Versions\Versions\IDeletableVersionBackend;
use OCA\Files_Versions\Versions\IMetadataVersion;
use OCA\Files_Versions\Versions\INameableVersion;
use OCA\Files_Versions\Versions\INameableVersionBackend;
use OCA\Files_Versions\Versions\IVersion;
@ -109,6 +110,13 @@ class VersionFile implements IFile {
}
}
public function getMetadataValue(string $key): ?string {
if ($this->version instanceof IMetadataVersion) {
return $this->version->getMetadataValue($key);
}
return null;
}
public function getLastModified(): int {
return $this->version->getTimestamp();
}

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2024 Eduardo Morales <emoral435@gmail.com>
*
* @license GNU AGPL-3.0-or-later
*
* 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\Files_Versions\Versions;
/**
* This interface allows for just direct accessing of the metadata column JSON
* @since 29.0.0
*/
interface IMetadataVersion {
/**
* retrieves the metadata value from our $key param
*
* @param string $key the key for the json value of the metadata column
* @since 29.0.0
*/
public function getMetadataValue(string $key): ?string;
}

@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2024 Eduardo Morales <emoral435@gmail.com>
*
* @license GNU AGPL-3.0-or-later
*
* 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\Files_Versions\Versions;
use OCP\Files\Node;
/**
* This interface edits the metadata column of a node.
* Each column of the metadata has a key => value mapping.
* @since 29.0.0
*/
interface IMetadataVersionBackend {
/**
* Sets a key value pair in the metadata column corresponding to the node's version.
*
* @param Node $node the node that triggered the Metadata event listener, aka, the file version
* @param string $key the key for the json value of the metadata column
* @param string $value the value that corresponds to the key in the metadata column
* @since 29.0.0
*/
public function setMetadataValue(Node $node, string $key, string $value): void;
/**
* Retrieves a corresponding value from the metadata column using the key.
*
* @param Node $node the node that triggered the Metadata event listener, aka, the file version
* @param string $key the key for the json value of the metadata column
* @since 29.0.0
*/
public function getMetadataValue(Node $node, string $key): ?string;
}

@ -24,12 +24,13 @@ declare(strict_types=1);
namespace OCA\Files_Versions\Versions;
/**
* @deprecated 29.0.0
* @since 26.0.0
*/
interface INameableVersion {
/**
* Get the user created label
*
* @deprecated 29.0.0
* @return string
* @since 26.0.0
*/

@ -24,12 +24,13 @@ declare(strict_types=1);
namespace OCA\Files_Versions\Versions;
/**
* @deprecated 29.0.0
* @since 26.0.0
*/
interface INameableVersionBackend {
/**
* Set the label for a version.
*
* @deprecated 29.0.0
* @since 26.0.0
*/
public function setVersionLabel(IVersion $version, string $label): void;

@ -39,13 +39,14 @@ use OCP\Files\FileInfo;
use OCP\Files\Folder;
use OCP\Files\IMimeTypeLoader;
use OCP\Files\IRootFolder;
use OCP\Files\Node;
use OCP\Files\NotFoundException;
use OCP\Files\Storage\IStorage;
use OCP\IUser;
use OCP\IUserManager;
use OCP\IUserSession;
class LegacyVersionsBackend implements IVersionBackend, INameableVersionBackend, IDeletableVersionBackend, INeedSyncVersionBackend {
class LegacyVersionsBackend implements IVersionBackend, INameableVersionBackend, IDeletableVersionBackend, INeedSyncVersionBackend, IMetadataVersionBackend {
private IRootFolder $rootFolder;
private IUserManager $userManager;
private VersionsMapper $versionsMapper;
@ -312,4 +313,33 @@ class LegacyVersionsBackend implements IVersionBackend, INameableVersionBackend,
return ($sourceFile->getPermissions() & $permissions) === $permissions;
}
public function setMetadataValue(Node $node, string $key, string $value): void {
// Do not handle folders.
if ($node instanceof File) {
try {
$versionEntity = $this->versionsMapper->findVersionForFileId($node->getId(), $node->getMTime());
} catch (\Exception $e) {
throw $e; // the version does not exist or too many versions exist
}
$currentMetadata = $versionEntity->getMetadata() ?? [];
$currentMetadata[$key] = $value;
$versionEntity->setMetadata($currentMetadata);
$this->versionsMapper->update($versionEntity);
}
}
public function getMetadataValue(Node $node, string $key): ?string {
try {
$versionEntity = $this->versionsMapper->findVersionForFileId($node->getId(), $node->getMTime());
return $versionEntity->getMetadataValue($key);
} catch (\InvalidArgumentException $e) {
// we tried to find a version or key that doesn't exist
return null;
}
}
}

@ -26,9 +26,10 @@ declare(strict_types=1);
namespace OCA\Files_Versions\Versions;
use OCP\Files\FileInfo;
use OCP\Files\Node;
use OCP\IUser;
class Version implements IVersion, INameableVersion {
class Version implements IVersion, INameableVersion, IMetadataVersion {
/** @var int */
private $timestamp;
@ -121,4 +122,11 @@ class Version implements IVersion, INameableVersion {
public function getUser(): IUser {
return $this->user;
}
public function getMetadataValue(string $key): ?string {
if ($this->backend instanceof IMetadataVersionBackend && $this->sourceFileInfo instanceof Node) {
return $this->backend->getMetadataValue($this->sourceFileInfo, "author");
}
return null;
}
}

@ -31,11 +31,12 @@ use OCP\Files\IRootFolder;
use OCP\Files\Lock\ILock;
use OCP\Files\Lock\ILockManager;
use OCP\Files\Lock\LockContext;
use OCP\Files\Node;
use OCP\Files\Storage\IStorage;
use OCP\IUser;
use OCP\Lock\ManuallyLockedException;
class VersionManager implements IVersionManager, INameableVersionBackend, IDeletableVersionBackend, INeedSyncVersionBackend {
class VersionManager implements IVersionManager, INameableVersionBackend, IDeletableVersionBackend, INeedSyncVersionBackend, IMetadataVersionBackend {
/** @var (IVersionBackend[])[] */
private $backends = [];
@ -160,6 +161,21 @@ class VersionManager implements IVersionManager, INameableVersionBackend, IDelet
}
}
public function setMetadataValue(Node $node, string $key, string $value): void {
$backend = $this->getBackendForStorage($node->getStorage());
if ($backend instanceof IMetadataVersionBackend) {
$backend->setMetadataValue($node, $key, $value);
}
}
public function getMetadataValue(Node $node, string $key): ?string {
$backend = $this->getBackendForStorage($node->getStorage());
if ($backend instanceof IMetadataVersionBackend) {
return $backend->getMetadataValue($node, $key);
}
return null;
}
/**
* Catch ManuallyLockedException and retry in app context if possible.
*
@ -184,7 +200,7 @@ class VersionManager implements IVersionManager, INameableVersionBackend, IDelet
return $callback();
} catch (ManuallyLockedException $e) {
$owner = (string) $e->getOwner();
$appsThatHandleUpdates = array("text", "richdocuments");
$appsThatHandleUpdates = ["text", "richdocuments"];
if (!in_array($owner, $appsThatHandleUpdates)) {
throw $e;
}

@ -31,6 +31,7 @@ export default `<?xml version="1.0"?>
<d:getlastmodified />
<d:getetag />
<nc:version-label />
<nc:version-author />
<nc:has-preview />
</d:prop>
</d:propfind>`

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -17,6 +17,10 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\' => 3,
'OCP\\' => 4,
),
'B' =>
array (
'Bamarni\\Composer\\Bin\\' => 21,
),
);
public static $prefixDirsPsr4 = array (
@ -32,6 +36,10 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
array (
0 => __DIR__ . '/../../..' . '/lib/public',
),
'Bamarni\\Composer\\Bin\\' =>
array (
0 => __DIR__ . '/..' . '/bamarni/composer-bin-plugin/src',
),
);
public static $fallbackDirsPsr4 = array (

Loading…
Cancel
Save