Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.drone.yml2
-rw-r--r--apps/dav/lib/Connector/Sabre/Directory.php6
-rw-r--r--apps/dav/lib/DAV/CustomPropertiesBackend.php22
-rw-r--r--apps/dav/lib/UserMigration/CalendarMigrator.php25
-rw-r--r--apps/dav/lib/UserMigration/ContactsMigrator.php22
-rw-r--r--apps/files_sharing/lib/AppInfo/Application.php3
-rw-r--r--apps/files_sharing/lib/Cache.php29
-rw-r--r--apps/files_sharing/lib/MountProvider.php11
-rw-r--r--apps/files_sharing/lib/SharedMount.php22
-rw-r--r--apps/files_sharing/lib/SharedStorage.php19
-rw-r--r--apps/files_sharing/tests/MountProviderTest.php7
-rw-r--r--apps/files_sharing/tests/TestCase.php2
-rw-r--r--core/Migrations/Version24000Date20220202150027.php (renamed from core/Migrations/Version240000Date20220202150027.php)2
-rw-r--r--core/Migrations/Version24000Date20220404230027.php (renamed from core/Migrations/Version240000Date20220404230027.php)4
-rw-r--r--core/Migrations/Version24000Date20220425072957.php53
-rw-r--r--cron.php2
-rw-r--r--lib/composer/composer/autoload_classmap.php7
-rw-r--r--lib/composer/composer/autoload_static.php7
-rw-r--r--lib/private/BackgroundJob/JobList.php2
-rw-r--r--lib/private/Files/Config/MountProviderCollection.php4
-rw-r--r--lib/private/Files/Node/Root.php4
-rw-r--r--lib/private/Files/SetupManager.php27
-rw-r--r--lib/private/Files/Storage/Local.php6
-rw-r--r--lib/private/Files/View.php22
-rw-r--r--lib/private/Metadata/FileEventListener.php23
-rw-r--r--lib/private/Metadata/FileMetadata.php2
-rw-r--r--lib/private/User/DisplayNameCache.php85
-rw-r--r--lib/private/User/LazyUser.php149
-rw-r--r--lib/private/legacy/OC_Helper.php35
-rw-r--r--tests/lib/BackgroundJob/DummyJobList.php2
-rw-r--r--tests/lib/Files/Node/RootTest.php4
31 files changed, 518 insertions, 92 deletions
diff --git a/.drone.yml b/.drone.yml
index 79cd295210e..e3ee9ca6ce9 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -1214,7 +1214,7 @@ steps:
commands:
# JavaScript files are not used in integration tests so it is not needed to
# build them.
- - git clone --depth 1 https://github.com/nextcloud/spreed apps/spreed
+ - git clone --depth 1 --branch stable24 https://github.com/nextcloud/spreed apps/spreed
- name: integration-sharing-v1-video-verification
image: ghcr.io/nextcloud/continuous-integration-integration-php7.4:latest
commands:
diff --git a/apps/dav/lib/Connector/Sabre/Directory.php b/apps/dav/lib/Connector/Sabre/Directory.php
index 9e0b89596cd..ed98b5050f8 100644
--- a/apps/dav/lib/Connector/Sabre/Directory.php
+++ b/apps/dav/lib/Connector/Sabre/Directory.php
@@ -47,6 +47,7 @@ use OCP\Files\NotPermittedException;
use OCP\Files\StorageNotAvailableException;
use OCP\Lock\ILockingProvider;
use OCP\Lock\LockedException;
+use Psr\Log\LoggerInterface;
use Sabre\DAV\Exception\BadRequest;
use Sabre\DAV\Exception\Locked;
use Sabre\DAV\Exception\NotFound;
@@ -331,6 +332,8 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node implements \Sabre\DAV\ICol
* @return array
*/
public function getQuotaInfo() {
+ /** @var LoggerInterface $logger */
+ $logger = \OC::$server->get(LoggerInterface::class);
if ($this->quotaInfo) {
return $this->quotaInfo;
}
@@ -347,10 +350,13 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node implements \Sabre\DAV\ICol
];
return $this->quotaInfo;
} catch (\OCP\Files\NotFoundException $e) {
+ $logger->warning("error while getting quota into", ['exception' => $e]);
return [0, 0];
} catch (\OCP\Files\StorageNotAvailableException $e) {
+ $logger->warning("error while getting quota into", ['exception' => $e]);
return [0, 0];
} catch (NotPermittedException $e) {
+ $logger->warning("error while getting quota into", ['exception' => $e]);
return [0, 0];
}
}
diff --git a/apps/dav/lib/DAV/CustomPropertiesBackend.php b/apps/dav/lib/DAV/CustomPropertiesBackend.php
index 5f512995ce8..acee65cd00d 100644
--- a/apps/dav/lib/DAV/CustomPropertiesBackend.php
+++ b/apps/dav/lib/DAV/CustomPropertiesBackend.php
@@ -54,6 +54,28 @@ class CustomPropertiesBackend implements BackendInterface {
'{http://owncloud.org/ns}dDC',
'{http://owncloud.org/ns}size',
'{http://nextcloud.org/ns}is-encrypted',
+
+ // Currently, returning null from any propfind handler would still trigger the backend,
+ // so we add all known Nextcloud custom properties in here to avoid that
+
+ // text app
+ '{http://nextcloud.org/ns}rich-workspace',
+ '{http://nextcloud.org/ns}rich-workspace-file',
+ // groupfolders
+ '{http://nextcloud.org/ns}acl-enabled',
+ '{http://nextcloud.org/ns}acl-can-manage',
+ '{http://nextcloud.org/ns}acl-list',
+ '{http://nextcloud.org/ns}inherited-acl-list',
+ '{http://nextcloud.org/ns}group-folder-id',
+ // files_lock
+ '{http://nextcloud.org/ns}lock',
+ '{http://nextcloud.org/ns}lock-owner-type',
+ '{http://nextcloud.org/ns}lock-owner',
+ '{http://nextcloud.org/ns}lock-owner-displayname',
+ '{http://nextcloud.org/ns}lock-owner-editor',
+ '{http://nextcloud.org/ns}lock-time',
+ '{http://nextcloud.org/ns}lock-timeout',
+ '{http://nextcloud.org/ns}lock-token',
];
/**
diff --git a/apps/dav/lib/UserMigration/CalendarMigrator.php b/apps/dav/lib/UserMigration/CalendarMigrator.php
index d94e3ec109e..015ce6faa86 100644
--- a/apps/dav/lib/UserMigration/CalendarMigrator.php
+++ b/apps/dav/lib/UserMigration/CalendarMigrator.php
@@ -108,14 +108,7 @@ class CalendarMigrator implements IMigrator {
*/
private function getCalendarExportData(IUser $user, ICalendar $calendar, OutputInterface $output): array {
$userId = $user->getUID();
- $calendarId = $calendar->getKey();
- $calendarInfo = $this->calDavBackend->getCalendarById($calendarId);
-
- if (empty($calendarInfo)) {
- throw new CalendarMigratorException("Invalid info for calendar ID $calendarId");
- }
-
- $uri = $calendarInfo['uri'];
+ $uri = $calendar->getUri();
$path = CalDAVPlugin::CALENDAR_ROOT . "/$userId/$uri";
/**
@@ -227,12 +220,12 @@ class CalendarMigrator implements IMigrator {
try {
/**
- * @var string $name
- * @var VCalendar $vCalendar
- */
+ * @var string $name
+ * @var VCalendar $vCalendar
+ */
foreach ($calendarExports as ['name' => $name, 'vCalendar' => $vCalendar]) {
- // Set filename to sanitized calendar name appended with the date
- $filename = preg_replace('/[^a-zA-Z0-9-_ ]/um', '', $name) . '_' . date('Y-m-d') . CalendarMigrator::FILENAME_EXT;
+ // Set filename to sanitized calendar name
+ $filename = preg_replace('/[^a-z0-9-_]/iu', '', $name) . CalendarMigrator::FILENAME_EXT;
$exportPath = CalendarMigrator::EXPORT_ROOT . $filename;
$exportDestination->addFileContents($exportPath, $vCalendar->serialize());
@@ -445,11 +438,11 @@ class CalendarMigrator implements IMigrator {
throw new CalendarMigratorException("Invalid calendar data contained in \"$importPath\"");
}
- $splitFilename = explode('_', $filename, 2);
+ $splitFilename = explode('.', $filename, 2);
if (count($splitFilename) !== 2) {
- throw new CalendarMigratorException("Invalid filename \"$filename\", expected filename of the format \"<calendar_name>_YYYY-MM-DD" . CalendarMigrator::FILENAME_EXT . '"');
+ throw new CalendarMigratorException("Invalid filename \"$filename\", expected filename of the format \"<calendar_name>" . CalendarMigrator::FILENAME_EXT . '"');
}
- [$initialCalendarUri, $suffix] = $splitFilename;
+ [$initialCalendarUri, $ext] = $splitFilename;
try {
$this->importCalendar(
diff --git a/apps/dav/lib/UserMigration/ContactsMigrator.php b/apps/dav/lib/UserMigration/ContactsMigrator.php
index 065ef05ceea..aed41e5c82f 100644
--- a/apps/dav/lib/UserMigration/ContactsMigrator.php
+++ b/apps/dav/lib/UserMigration/ContactsMigrator.php
@@ -168,7 +168,7 @@ class ContactsMigrator implements IMigrator {
}
$existingAddressBookUris = array_map(
- fn (array $addressBookInfo) => $addressBookInfo['uri'],
+ fn (array $addressBookInfo): string => $addressBookInfo['uri'],
$this->cardDavBackend->getAddressBooksForUser($principalUri),
);
@@ -207,14 +207,14 @@ class ContactsMigrator implements IMigrator {
try {
/**
- * @var string $name
- * @var string $displayName
- * @var ?string $description
- * @var VCard[] $vCards
- */
+ * @var string $name
+ * @var string $displayName
+ * @var ?string $description
+ * @var VCard[] $vCards
+ */
foreach ($addressBookExports as ['name' => $name, 'displayName' => $displayName, 'description' => $description, 'vCards' => $vCards]) {
- // Set filename to sanitized address book name appended with the date
- $basename = preg_replace('/[^a-zA-Z0-9-_ ]/um', '', $name) . '_' . date('Y-m-d');
+ // Set filename to sanitized address book name
+ $basename = preg_replace('/[^a-z0-9-_]/iu', '', $name);
$exportPath = ContactsMigrator::PATH_ROOT . $basename . '.' . ContactsMigrator::FILENAME_EXT;
$metadataExportPath = ContactsMigrator::PATH_ROOT . $basename . '.' . ContactsMigrator::METADATA_EXT;
@@ -340,11 +340,11 @@ class ContactsMigrator implements IMigrator {
$vCards[] = $vCard;
}
- $splitFilename = explode('_', $addressBookFilename, 2);
+ $splitFilename = explode('.', $addressBookFilename, 2);
if (count($splitFilename) !== 2) {
- throw new ContactsMigratorException("Invalid filename \"$addressBookFilename\", expected filename of the format \"<address_book_name>_YYYY-MM-DD." . ContactsMigrator::FILENAME_EXT . '"');
+ throw new ContactsMigratorException("Invalid filename \"$addressBookFilename\", expected filename of the format \"<address_book_name>." . ContactsMigrator::FILENAME_EXT . '"');
}
- [$initialAddressBookUri, $suffix] = $splitFilename;
+ [$initialAddressBookUri, $ext] = $splitFilename;
/** @var array{displayName: string, description?: string} $metadata */
$metadata = json_decode($importSource->getFileContents($metadataImportPath), true, 512, JSON_THROW_ON_ERROR);
diff --git a/apps/files_sharing/lib/AppInfo/Application.php b/apps/files_sharing/lib/AppInfo/Application.php
index befd1532d02..2539247b561 100644
--- a/apps/files_sharing/lib/AppInfo/Application.php
+++ b/apps/files_sharing/lib/AppInfo/Application.php
@@ -30,6 +30,7 @@
namespace OCA\Files_Sharing\AppInfo;
use OC\Share\Share;
+use OC\User\DisplayNameCache;
use OCA\Files_Sharing\Capabilities;
use OCA\Files_Sharing\Event\BeforeTemplateRenderedEvent;
use OCA\Files_Sharing\External\Manager;
@@ -65,6 +66,7 @@ use OCP\IUserSession;
use OCP\L10N\IFactory;
use OCP\Share\Events\ShareCreatedEvent;
use OCP\Share\IManager;
+use OCP\User\Events\UserChangedEvent;
use OCP\Util;
use Psr\Container\ContainerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@@ -98,6 +100,7 @@ class Application extends App implements IBootstrap {
$context->registerCapability(Capabilities::class);
$context->registerNotifierService(Notifier::class);
+ $context->registerEventListener(UserChangedEvent::class, DisplayNameCache::class);
}
public function boot(IBootContext $context): void {
diff --git a/apps/files_sharing/lib/Cache.php b/apps/files_sharing/lib/Cache.php
index 8729426221b..d245727b138 100644
--- a/apps/files_sharing/lib/Cache.php
+++ b/apps/files_sharing/lib/Cache.php
@@ -33,6 +33,7 @@ use OC\Files\Cache\Wrapper\CacheJail;
use OC\Files\Search\SearchBinaryOperator;
use OC\Files\Search\SearchComparison;
use OC\Files\Storage\Wrapper\Jail;
+use OC\User\DisplayNameCache;
use OCP\Files\Cache\ICacheEntry;
use OCP\Files\Search\ISearchBinaryOperator;
use OCP\Files\Search\ISearchComparison;
@@ -46,27 +47,22 @@ use OCP\IUserManager;
* don't use this class directly if you need to get metadata, use \OC\Files\Filesystem::getFileInfo instead
*/
class Cache extends CacheJail {
- /** @var \OCA\Files_Sharing\SharedStorage */
+ /** @var SharedStorage */
private $storage;
- /** @var ICacheEntry */
- private $sourceRootInfo;
- /** @var IUserManager */
- private $userManager;
-
- private $rootUnchanged = true;
-
- private $ownerDisplayName;
-
+ private ICacheEntry $sourceRootInfo;
+ private bool $rootUnchanged = true;
+ private ?string $ownerDisplayName = null;
private $numericId;
+ private DisplayNameCache $displayNameCache;
/**
- * @param \OCA\Files_Sharing\SharedStorage $storage
+ * @param SharedStorage $storage
*/
- public function __construct($storage, ICacheEntry $sourceRootInfo, IUserManager $userManager) {
+ public function __construct($storage, ICacheEntry $sourceRootInfo, DisplayNameCache $displayNameCache) {
$this->storage = $storage;
$this->sourceRootInfo = $sourceRootInfo;
- $this->userManager = $userManager;
$this->numericId = $sourceRootInfo->getStorageId();
+ $this->displayNameCache = $displayNameCache;
parent::__construct(
null,
@@ -173,12 +169,7 @@ class Cache extends CacheJail {
private function getOwnerDisplayName() {
if (!$this->ownerDisplayName) {
$uid = $this->storage->getOwner('');
- $user = $this->userManager->get($uid);
- if ($user) {
- $this->ownerDisplayName = $user->getDisplayName();
- } else {
- $this->ownerDisplayName = $uid;
- }
+ $this->ownerDisplayName = $this->displayNameCache->getDisplayName($uid);
}
return $this->ownerDisplayName;
}
diff --git a/apps/files_sharing/lib/MountProvider.php b/apps/files_sharing/lib/MountProvider.php
index 27edf5074e1..bfb40387622 100644
--- a/apps/files_sharing/lib/MountProvider.php
+++ b/apps/files_sharing/lib/MountProvider.php
@@ -34,6 +34,7 @@ use OCA\Files_Sharing\Event\ShareMountedEvent;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Config\IMountProvider;
use OCP\Files\Storage\IStorageFactory;
+use OCP\ICacheFactory;
use OCP\IConfig;
use OCP\ILogger;
use OCP\IUser;
@@ -59,6 +60,9 @@ class MountProvider implements IMountProvider {
/** @var IEventDispatcher */
protected $eventDispatcher;
+ /** @var ICacheFactory */
+ protected $cacheFactory;
+
/**
* @param \OCP\IConfig $config
* @param IManager $shareManager
@@ -68,12 +72,14 @@ class MountProvider implements IMountProvider {
IConfig $config,
IManager $shareManager,
ILogger $logger,
- IEventDispatcher $eventDispatcher
+ IEventDispatcher $eventDispatcher,
+ ICacheFactory $cacheFactory
) {
$this->config = $config;
$this->shareManager = $shareManager;
$this->logger = $logger;
$this->eventDispatcher = $eventDispatcher;
+ $this->cacheFactory = $cacheFactory;
}
@@ -136,7 +142,8 @@ class MountProvider implements IMountProvider {
$view,
$foldersExistCache,
$this->eventDispatcher,
- $user
+ $user,
+ $this->cacheFactory->createLocal('share-valid-mountpoint')
);
$event = new ShareMountedEvent($mount);
diff --git a/apps/files_sharing/lib/SharedMount.php b/apps/files_sharing/lib/SharedMount.php
index 60361e25fd0..398da5eaf23 100644
--- a/apps/files_sharing/lib/SharedMount.php
+++ b/apps/files_sharing/lib/SharedMount.php
@@ -26,6 +26,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
+
namespace OCA\Files_Sharing;
use OC\Cache\CappedMemoryCache;
@@ -36,6 +37,7 @@ use OC\Files\View;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Events\InvalidateMountCacheEvent;
use OCP\Files\Storage\IStorageFactory;
+use OCP\ICache;
use OCP\IUser;
use OCP\Share\Events\VerifyMountPointEvent;
@@ -63,6 +65,8 @@ class SharedMount extends MountPoint implements MoveableMount {
private IEventDispatcher $eventDispatcher;
+ private ICache $cache;
+
public function __construct(
$storage,
array $mountpoints,
@@ -71,11 +75,13 @@ class SharedMount extends MountPoint implements MoveableMount {
View $recipientView,
CappedMemoryCache $folderExistCache,
IEventDispatcher $eventDispatcher,
- IUser $user
+ IUser $user,
+ ICache $cache
) {
$this->user = $user;
$this->recipientView = $recipientView;
$this->eventDispatcher = $eventDispatcher;
+ $this->cache = $cache;
$this->superShare = $arguments['superShare'];
$this->groupedShares = $arguments['groupedShares'];
@@ -92,7 +98,17 @@ class SharedMount extends MountPoint implements MoveableMount {
* @param SharedMount[] $mountpoints
* @return string
*/
- private function verifyMountPoint(\OCP\Share\IShare $share, array $mountpoints, CappedMemoryCache $folderExistCache) {
+ private function verifyMountPoint(
+ \OCP\Share\IShare $share,
+ array $mountpoints,
+ CappedMemoryCache $folderExistCache
+ ) {
+ $cacheKey = $this->user->getUID() . '/' . $share->getTarget();
+ $cached = $this->cache->get($cacheKey);
+ if ($cached !== null) {
+ return $cached;
+ }
+
$mountPoint = basename($share->getTarget());
$parent = dirname($share->getTarget());
@@ -120,6 +136,8 @@ class SharedMount extends MountPoint implements MoveableMount {
$this->updateFileTarget($newMountPoint, $share);
}
+ $this->cache->set($cacheKey, $newMountPoint, 60 * 60);
+
return $newMountPoint;
}
diff --git a/apps/files_sharing/lib/SharedStorage.php b/apps/files_sharing/lib/SharedStorage.php
index 6a342f0bdbf..37f1c12a2e4 100644
--- a/apps/files_sharing/lib/SharedStorage.php
+++ b/apps/files_sharing/lib/SharedStorage.php
@@ -35,7 +35,12 @@ namespace OCA\Files_Sharing;
use OC\Files\Cache\FailedCache;
use OC\Files\Cache\NullWatcher;
use OC\Files\Cache\Watcher;
+use OC\Files\ObjectStore\HomeObjectStoreStorage;
+use OC\Files\Storage\Common;
+use OC\Files\Storage\Home;
+use OC\User\DisplayNameCache;
use OCP\Files\Folder;
+use OCP\Files\IHomeStorage;
use OCP\Files\Node;
use OC\Files\Storage\FailedStorage;
use OC\Files\Storage\Wrapper\PermissionsMask;
@@ -47,7 +52,6 @@ use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
use OCP\Files\Storage\IDisableEncryptionStorage;
use OCP\Files\Storage\IStorage;
-use OCP\IUserManager;
use OCP\Lock\ILockingProvider;
use OCP\Share\IShare;
@@ -182,10 +186,17 @@ class SharedStorage extends \OC\Files\Storage\Wrapper\Jail implements ISharedSto
* @inheritdoc
*/
public function instanceOfStorage($class): bool {
- if ($class === '\OC\Files\Storage\Common') {
+ if ($class === '\OC\Files\Storage\Common' || $class == Common::class) {
return true;
}
- if (in_array($class, ['\OC\Files\Storage\Home', '\OC\Files\ObjectStore\HomeObjectStoreStorage', '\OCP\Files\IHomeStorage'])) {
+ if (in_array($class, [
+ '\OC\Files\Storage\Home',
+ '\OC\Files\ObjectStore\HomeObjectStoreStorage',
+ '\OCP\Files\IHomeStorage',
+ Home::class,
+ HomeObjectStoreStorage::class,
+ IHomeStorage::class
+ ])) {
return false;
}
return parent::instanceOfStorage($class);
@@ -405,7 +416,7 @@ class SharedStorage extends \OC\Files\Storage\Wrapper\Jail implements ISharedSto
$this->cache = new \OCA\Files_Sharing\Cache(
$storage,
$sourceRoot,
- \OC::$server->get(IUserManager::class)
+ \OC::$server->get(DisplayNameCache::class)
);
return $this->cache;
}
diff --git a/apps/files_sharing/tests/MountProviderTest.php b/apps/files_sharing/tests/MountProviderTest.php
index 756c6f95d42..00ae847eaac 100644
--- a/apps/files_sharing/tests/MountProviderTest.php
+++ b/apps/files_sharing/tests/MountProviderTest.php
@@ -29,10 +29,12 @@
*/
namespace OCA\Files_Sharing\Tests;
+use OC\Memcache\NullCache;
use OCA\Files_Sharing\MountProvider;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\IRootFolder;
use OCP\Files\Storage\IStorageFactory;
+use OCP\ICacheFactory;
use OCP\IConfig;
use OCP\ILogger;
use OCP\IUser;
@@ -72,8 +74,11 @@ class MountProviderTest extends \Test\TestCase {
$this->shareManager = $this->getMockBuilder(IManager::class)->getMock();
$this->logger = $this->getMockBuilder(ILogger::class)->getMock();
$eventDispatcher = $this->createMock(IEventDispatcher::class);
+ $cacheFactory = $this->createMock(ICacheFactory::class);
+ $cacheFactory->method('createLocal')
+ ->willReturn(new NullCache());
- $this->provider = new MountProvider($this->config, $this->shareManager, $this->logger, $eventDispatcher);
+ $this->provider = new MountProvider($this->config, $this->shareManager, $this->logger, $eventDispatcher, $cacheFactory);
}
private function makeMockShare($id, $nodeId, $owner = 'user2', $target = null, $permissions = 31) {
diff --git a/apps/files_sharing/tests/TestCase.php b/apps/files_sharing/tests/TestCase.php
index bb1e3125ab2..234ea2c69c8 100644
--- a/apps/files_sharing/tests/TestCase.php
+++ b/apps/files_sharing/tests/TestCase.php
@@ -39,6 +39,7 @@ use OCA\Files_Sharing\MountProvider;
use OCP\Files\Config\IMountProviderCollection;
use OCP\Share\IShare;
use Test\Traits\MountProviderTrait;
+use OC\User\DisplayNameCache;
/**
* Class TestCase
@@ -116,6 +117,7 @@ abstract class TestCase extends \Test\TestCase {
protected function setUp(): void {
parent::setUp();
+ \OC::$server->get(DisplayNameCache::class)->clear();
//login as user1
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
diff --git a/core/Migrations/Version240000Date20220202150027.php b/core/Migrations/Version24000Date20220202150027.php
index b13afa67d1e..76a3ae8c73c 100644
--- a/core/Migrations/Version240000Date20220202150027.php
+++ b/core/Migrations/Version24000Date20220202150027.php
@@ -13,7 +13,7 @@ use OCP\Migration\SimpleMigrationStep;
/**
* Auto-generated migration step: Please modify to your needs!
*/
-class Version240000Date20220202150027 extends SimpleMigrationStep {
+class Version24000Date20220202150027 extends SimpleMigrationStep {
/**
* @param IOutput $output
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
diff --git a/core/Migrations/Version240000Date20220404230027.php b/core/Migrations/Version24000Date20220404230027.php
index f45f8d5b500..a650fcb7021 100644
--- a/core/Migrations/Version240000Date20220404230027.php
+++ b/core/Migrations/Version24000Date20220404230027.php
@@ -30,9 +30,9 @@ use OCP\Migration\SimpleMigrationStep;
/**
* Add oc_file_metadata table
- * @see OC\Metadata\FileMetadata
+ * @see \OC\Metadata\FileMetadata
*/
-class Version240000Date20220404230027 extends SimpleMigrationStep {
+class Version24000Date20220404230027 extends SimpleMigrationStep {
/**
* @param IOutput $output
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
diff --git a/core/Migrations/Version24000Date20220425072957.php b/core/Migrations/Version24000Date20220425072957.php
new file mode 100644
index 00000000000..87d62873c6b
--- /dev/null
+++ b/core/Migrations/Version24000Date20220425072957.php
@@ -0,0 +1,53 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2022 Joas Schilling <coding@schilljs.com>
+ *
+ * @author Joas Schilling <coding@schilljs.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * 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 OC\Core\Migrations;
+
+use Closure;
+use OCP\DB\ISchemaWrapper;
+use OCP\Migration\IOutput;
+use OCP\Migration\SimpleMigrationStep;
+
+class Version24000Date20220425072957 extends SimpleMigrationStep {
+ /**
+ * @param IOutput $output
+ * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+ * @param array $options
+ * @return null|ISchemaWrapper
+ */
+ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
+ /** @var ISchemaWrapper $schema */
+ $schema = $schemaClosure();
+
+ $table = $schema->getTable('mounts');
+ if (!$table->hasIndex('mount_user_storage')) {
+ $table->addIndex(['storage_id', 'user_id'], 'mount_user_storage');
+ return $schema;
+ }
+
+ return null;
+ }
+}
diff --git a/cron.php b/cron.php
index 5095a2c7574..a58ef2c206f 100644
--- a/cron.php
+++ b/cron.php
@@ -147,6 +147,7 @@ try {
break;
}
+ $logger->debug('CLI cron call has selected job with ID ' . strval($job->getId()), ['app' => 'cron']);
$job->execute($jobList, $logger);
// clean up after unclean jobs
\OC_Util::tearDownFS();
@@ -169,6 +170,7 @@ try {
$jobList = \OC::$server->getJobList();
$job = $jobList->getNext();
if ($job != null) {
+ $logger->debug('WebCron call has selected job with ID ' . strval($job->getId()), ['app' => 'cron']);
$job->execute($jobList, $logger);
$jobList->setLastJob($job);
}
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 685fae9bef1..2c962b0fc6d 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -1020,14 +1020,15 @@ return array(
'OC\\Core\\Migrations\\Version23000Date20210930122352' => $baseDir . '/core/Migrations/Version23000Date20210930122352.php',
'OC\\Core\\Migrations\\Version23000Date20211203110726' => $baseDir . '/core/Migrations/Version23000Date20211203110726.php',
'OC\\Core\\Migrations\\Version23000Date20211213203940' => $baseDir . '/core/Migrations/Version23000Date20211213203940.php',
- 'OC\\Core\\Migrations\\Version240000Date20220202150027' => $baseDir . '/core/Migrations/Version240000Date20220202150027.php',
- 'OC\\Core\\Migrations\\Version240000Date20220404230027' => $baseDir . '/core/Migrations/Version240000Date20220404230027.php',
'OC\\Core\\Migrations\\Version24000Date20211210141942' => $baseDir . '/core/Migrations/Version24000Date20211210141942.php',
'OC\\Core\\Migrations\\Version24000Date20211213081506' => $baseDir . '/core/Migrations/Version24000Date20211213081506.php',
'OC\\Core\\Migrations\\Version24000Date20211213081604' => $baseDir . '/core/Migrations/Version24000Date20211213081604.php',
'OC\\Core\\Migrations\\Version24000Date20211222112246' => $baseDir . '/core/Migrations/Version24000Date20211222112246.php',
'OC\\Core\\Migrations\\Version24000Date20211230140012' => $baseDir . '/core/Migrations/Version24000Date20211230140012.php',
'OC\\Core\\Migrations\\Version24000Date20220131153041' => $baseDir . '/core/Migrations/Version24000Date20220131153041.php',
+ 'OC\\Core\\Migrations\\Version24000Date20220202150027' => $baseDir . '/core/Migrations/Version24000Date20220202150027.php',
+ 'OC\\Core\\Migrations\\Version24000Date20220404230027' => $baseDir . '/core/Migrations/Version24000Date20220404230027.php',
+ 'OC\\Core\\Migrations\\Version24000Date20220425072957' => $baseDir . '/core/Migrations/Version24000Date20220425072957.php',
'OC\\Core\\Notification\\CoreNotifier' => $baseDir . '/core/Notification/CoreNotifier.php',
'OC\\Core\\Service\\LoginFlowV2Service' => $baseDir . '/core/Service/LoginFlowV2Service.php',
'OC\\DB\\Adapter' => $baseDir . '/lib/private/DB/Adapter.php',
@@ -1540,6 +1541,8 @@ return array(
'OC\\UserStatus\\Manager' => $baseDir . '/lib/private/UserStatus/Manager.php',
'OC\\User\\Backend' => $baseDir . '/lib/private/User/Backend.php',
'OC\\User\\Database' => $baseDir . '/lib/private/User/Database.php',
+ 'OC\\User\\DisplayNameCache' => $baseDir . '/lib/private/User/DisplayNameCache.php',
+ 'OC\\User\\LazyUser' => $baseDir . '/lib/private/User/LazyUser.php',
'OC\\User\\LoginException' => $baseDir . '/lib/private/User/LoginException.php',
'OC\\User\\Manager' => $baseDir . '/lib/private/User/Manager.php',
'OC\\User\\NoUserException' => $baseDir . '/lib/private/User/NoUserException.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 7e778d73b83..da591ab0c0f 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -1049,14 +1049,15 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Core\\Migrations\\Version23000Date20210930122352' => __DIR__ . '/../../..' . '/core/Migrations/Version23000Date20210930122352.php',
'OC\\Core\\Migrations\\Version23000Date20211203110726' => __DIR__ . '/../../..' . '/core/Migrations/Version23000Date20211203110726.php',
'OC\\Core\\Migrations\\Version23000Date20211213203940' => __DIR__ . '/../../..' . '/core/Migrations/Version23000Date20211213203940.php',
- 'OC\\Core\\Migrations\\Version240000Date20220202150027' => __DIR__ . '/../../..' . '/core/Migrations/Version240000Date20220202150027.php',
- 'OC\\Core\\Migrations\\Version240000Date20220404230027' => __DIR__ . '/../../..' . '/core/Migrations/Version240000Date20220404230027.php',
'OC\\Core\\Migrations\\Version24000Date20211210141942' => __DIR__ . '/../../..' . '/core/Migrations/Version24000Date20211210141942.php',
'OC\\Core\\Migrations\\Version24000Date20211213081506' => __DIR__ . '/../../..' . '/core/Migrations/Version24000Date20211213081506.php',
'OC\\Core\\Migrations\\Version24000Date20211213081604' => __DIR__ . '/../../..' . '/core/Migrations/Version24000Date20211213081604.php',
'OC\\Core\\Migrations\\Version24000Date20211222112246' => __DIR__ . '/../../..' . '/core/Migrations/Version24000Date20211222112246.php',
'OC\\Core\\Migrations\\Version24000Date20211230140012' => __DIR__ . '/../../..' . '/core/Migrations/Version24000Date20211230140012.php',
'OC\\Core\\Migrations\\Version24000Date20220131153041' => __DIR__ . '/../../..' . '/core/Migrations/Version24000Date20220131153041.php',
+ 'OC\\Core\\Migrations\\Version24000Date20220202150027' => __DIR__ . '/../../..' . '/core/Migrations/Version24000Date20220202150027.php',
+ 'OC\\Core\\Migrations\\Version24000Date20220404230027' => __DIR__ . '/../../..' . '/core/Migrations/Version24000Date20220404230027.php',
+ 'OC\\Core\\Migrations\\Version24000Date20220425072957' => __DIR__ . '/../../..' . '/core/Migrations/Version24000Date20220425072957.php',
'OC\\Core\\Notification\\CoreNotifier' => __DIR__ . '/../../..' . '/core/Notification/CoreNotifier.php',
'OC\\Core\\Service\\LoginFlowV2Service' => __DIR__ . '/../../..' . '/core/Service/LoginFlowV2Service.php',
'OC\\DB\\Adapter' => __DIR__ . '/../../..' . '/lib/private/DB/Adapter.php',
@@ -1569,6 +1570,8 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\UserStatus\\Manager' => __DIR__ . '/../../..' . '/lib/private/UserStatus/Manager.php',
'OC\\User\\Backend' => __DIR__ . '/../../..' . '/lib/private/User/Backend.php',
'OC\\User\\Database' => __DIR__ . '/../../..' . '/lib/private/User/Database.php',
+ 'OC\\User\\DisplayNameCache' => __DIR__ . '/../../..' . '/lib/private/User/DisplayNameCache.php',
+ 'OC\\User\\LazyUser' => __DIR__ . '/../../..' . '/lib/private/User/LazyUser.php',
'OC\\User\\LoginException' => __DIR__ . '/../../..' . '/lib/private/User/LoginException.php',
'OC\\User\\Manager' => __DIR__ . '/../../..' . '/lib/private/User/Manager.php',
'OC\\User\\NoUserException' => __DIR__ . '/../../..' . '/lib/private/User/NoUserException.php',
diff --git a/lib/private/BackgroundJob/JobList.php b/lib/private/BackgroundJob/JobList.php
index 21af79c4686..fe65a1879bc 100644
--- a/lib/private/BackgroundJob/JobList.php
+++ b/lib/private/BackgroundJob/JobList.php
@@ -203,7 +203,7 @@ class JobList implements IJobList {
* @param bool $onlyTimeSensitive
* @return IJob|null
*/
- public function getNext(bool $onlyTimeSensitive = true): ?IJob {
+ public function getNext(bool $onlyTimeSensitive = false): ?IJob {
$query = $this->connection->getQueryBuilder();
$query->select('*')
->from('jobs')
diff --git a/lib/private/Files/Config/MountProviderCollection.php b/lib/private/Files/Config/MountProviderCollection.php
index 334fce15d9e..0e08d9d0e83 100644
--- a/lib/private/Files/Config/MountProviderCollection.php
+++ b/lib/private/Files/Config/MountProviderCollection.php
@@ -234,4 +234,8 @@ class MountProviderCollection implements IMountProviderCollection, Emitter {
$this->homeProviders = [];
$this->rootProviders = [];
}
+
+ public function getProviders(): array {
+ return $this->providers;
+ }
}
diff --git a/lib/private/Files/Node/Root.php b/lib/private/Files/Node/Root.php
index 8b599ddfd75..6dd65a4291d 100644
--- a/lib/private/Files/Node/Root.php
+++ b/lib/private/Files/Node/Root.php
@@ -365,6 +365,7 @@ class Root extends Folder implements IRootFolder {
$userObject = $this->userManager->get($userId);
if (is_null($userObject)) {
+ $e = new NoUserException('Backends provided no user object');
$this->logger->error(
sprintf(
'Backends provided no user object for %s',
@@ -372,9 +373,10 @@ class Root extends Folder implements IRootFolder {
),
[
'app' => 'files',
+ 'exception' => $e,
]
);
- throw new NoUserException('Backends provided no user object');
+ throw $e;
}
$userId = $userObject->getUID();
diff --git a/lib/private/Files/SetupManager.php b/lib/private/Files/SetupManager.php
index e0575ea92a5..9fb7b030e1d 100644
--- a/lib/private/Files/SetupManager.php
+++ b/lib/private/Files/SetupManager.php
@@ -81,6 +81,7 @@ class SetupManager {
private LoggerInterface $logger;
private IConfig $config;
private bool $listeningForProviders;
+ private array $fullSetupRequired = [];
public function __construct(
IEventLogger $eventLogger,
@@ -202,6 +203,8 @@ class SetupManager {
$this->setupUserMountProviders[$user->getUID()] = [];
}
+ $previouslySetupProviders = $this->setupUserMountProviders[$user->getUID()];
+
$this->setupForUserWith($user, function () use ($user) {
$this->mountProviderCollection->addMountForUser($user, $this->mountManager, function (
IMountProvider $provider
@@ -209,7 +212,7 @@ class SetupManager {
return !in_array(get_class($provider), $this->setupUserMountProviders[$user->getUID()]);
});
});
- $this->afterUserFullySetup($user);
+ $this->afterUserFullySetup($user, $previouslySetupProviders);
}
/**
@@ -257,17 +260,25 @@ class SetupManager {
/**
* Final housekeeping after a user has been fully setup
*/
- private function afterUserFullySetup(IUser $user): void {
+ private function afterUserFullySetup(IUser $user, array $previouslySetupProviders): void {
$userRoot = '/' . $user->getUID() . '/';
$mounts = $this->mountManager->getAll();
$mounts = array_filter($mounts, function (IMountPoint $mount) use ($userRoot) {
return strpos($mount->getMountPoint(), $userRoot) === 0;
});
- $this->userMountCache->registerMounts($user, $mounts);
+ $allProviders = array_map(function (IMountProvider $provider) {
+ return get_class($provider);
+ }, $this->mountProviderCollection->getProviders());
+ $newProviders = array_diff($allProviders, $previouslySetupProviders);
+ $mounts = array_filter($mounts, function (IMountPoint $mount) use ($previouslySetupProviders) {
+ return !in_array($mount->getMountProvider(), $previouslySetupProviders);
+ });
+ $this->userMountCache->registerMounts($user, $mounts, $newProviders);
$cacheDuration = $this->config->getSystemValueInt('fs_mount_cache_duration', 5 * 60);
if ($cacheDuration > 0) {
$this->cache->set($user->getUID(), true, $cacheDuration);
+ $this->fullSetupRequired[$user->getUID()] = false;
}
}
@@ -333,7 +344,9 @@ class SetupManager {
* @return IUser|null
*/
private function getUserForPath(string $path) {
- if (substr_count($path, '/') < 2) {
+ if (strpos($path, '/__groupfolders') === 0) {
+ return null;
+ } elseif (substr_count($path, '/') < 2) {
if ($user = $this->userSession->getUser()) {
return $user;
} else {
@@ -434,7 +447,10 @@ class SetupManager {
// we perform a "cached" setup only after having done the full setup recently
// this is also used to trigger a full setup after handling events that are likely
// to change the available mounts
- return !$this->cache->get($user->getUID());
+ if (!isset($this->fullSetupRequired[$user->getUID()])) {
+ $this->fullSetupRequired[$user->getUID()] = !$this->cache->get($user->getUID());
+ }
+ return $this->fullSetupRequired[$user->getUID()];
}
/**
@@ -489,6 +505,7 @@ class SetupManager {
$this->setupUsers = [];
$this->setupUsersComplete = [];
$this->setupUserMountProviders = [];
+ $this->fullSetupRequired = [];
$this->rootSetup = false;
$this->mountManager->clear();
$this->eventDispatcher->dispatchTyped(new FilesystemTornDownEvent());
diff --git a/lib/private/Files/Storage/Local.php b/lib/private/Files/Storage/Local.php
index 34ab9a5fc97..d637b3d194f 100644
--- a/lib/private/Files/Storage/Local.php
+++ b/lib/private/Files/Storage/Local.php
@@ -173,7 +173,11 @@ class Local extends \OC\Files\Storage\Common {
* @inheritdoc
*/
public function getMetaData($path) {
- $stat = $this->stat($path);
+ try {
+ $stat = $this->stat($path);
+ } catch (ForbiddenException $e) {
+ return null;
+ }
if (!$stat) {
return null;
}
diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php
index 30dc5518be8..c209c8594f7 100644
--- a/lib/private/Files/View.php
+++ b/lib/private/Files/View.php
@@ -49,6 +49,8 @@ namespace OC\Files;
use Icewind\Streams\CallbackWrapper;
use OC\Files\Mount\MoveableMount;
use OC\Files\Storage\Storage;
+use OC\User\DisplayNameCache;
+use OC\User\LazyUser;
use OC\User\User;
use OCA\Files_Sharing\SharedMount;
use OCP\Constants;
@@ -102,6 +104,8 @@ class View {
/** @var \OCP\ILogger */
private $logger;
+ private DisplayNameCache $displayNameCache;
+
/**
* @param string $root
* @throws \Exception If $root contains an invalid path
@@ -118,6 +122,7 @@ class View {
$this->lockingProvider = \OC::$server->getLockingProvider();
$this->lockingEnabled = !($this->lockingProvider instanceof \OC\Lock\NoopLockingProvider);
$this->userManager = \OC::$server->getUserManager();
+ $this->displayNameCache = \OC::$server->get(DisplayNameCache::class);
$this->logger = \OC::$server->getLogger();
}
@@ -1312,15 +1317,10 @@ class View {
/**
* @param string $ownerId
- * @return \OC\User\User
+ * @return IUser
*/
- private function getUserObjectForOwner($ownerId) {
- $owner = $this->userManager->get($ownerId);
- if ($owner instanceof IUser) {
- return $owner;
- } else {
- return new User($ownerId, null, \OC::$server->getEventDispatcher());
- }
+ private function getUserObjectForOwner(string $ownerId) {
+ return new LazyUser($ownerId, $this->displayNameCache, $this->userManager);
}
/**
@@ -1517,10 +1517,8 @@ class View {
if ($pos = strpos($relativePath, '/')) {
//mountpoint inside subfolder add size to the correct folder
$entryName = substr($relativePath, 0, $pos);
- foreach ($files as &$entry) {
- if ($entry->getName() === $entryName) {
- $entry->addSubEntry($rootEntry, $mountPoint);
- }
+ if (isset($files[$entryName])) {
+ $files[$entryName]->addSubEntry($rootEntry, $mountPoint);
}
} else { //mountpoint in this folder, add an entry for it
$rootEntry['name'] = $relativePath;
diff --git a/lib/private/Metadata/FileEventListener.php b/lib/private/Metadata/FileEventListener.php
index fdec891c6e2..6d41ccdef30 100644
--- a/lib/private/Metadata/FileEventListener.php
+++ b/lib/private/Metadata/FileEventListener.php
@@ -31,12 +31,15 @@ use OCP\Files\File;
use OCP\Files\Node;
use OCP\Files\NotFoundException;
use OCP\Files\FileInfo;
+use Psr\Log\LoggerInterface;
class FileEventListener implements IEventListener {
private IMetadataManager $manager;
+ private LoggerInterface $logger;
- public function __construct(IMetadataManager $manager) {
+ public function __construct(IMetadataManager $manager, LoggerInterface $logger) {
$this->manager = $manager;
+ $this->logger = $logger;
}
private function shouldExtractMetadata(Node $node): bool {
@@ -52,13 +55,31 @@ class FileEventListener implements IEventListener {
}
$path = $node->getPath();
+ return $this->isCorrectPath($path);
+ }
+
+ private function isCorrectPath(string $path): bool {
// TODO make this more dynamic, we have the same issue in other places
return !str_starts_with($path, 'appdata_') && !str_starts_with($path, 'files_versions/') && !str_starts_with($path, 'files_trashbin/');
}
public function handle(Event $event): void {
if ($event instanceof NodeRemovedFromCache) {
+ if (!$this->isCorrectPath($event->getPath())) {
+ // Don't listen to paths for which we don't extract metadata
+ return;
+ }
$view = Filesystem::getView();
+ if (!$view) {
+ // Should not happen since a scan in the user folder should setup
+ // the file system.
+ $e = new \Exception(); // don't trigger, just get backtrace
+ $this->logger->error('Detecting deletion of a file with possible metadata but file system setup is not setup', [
+ 'exception' => $e,
+ 'app' => 'metadata'
+ ]);
+ return;
+ }
$info = $view->getFileInfo($event->getPath());
if ($info && $info->getType() === FileInfo::TYPE_FILE) {
$this->manager->clearMetadata($info->getId());
diff --git a/lib/private/Metadata/FileMetadata.php b/lib/private/Metadata/FileMetadata.php
index c53f5d7f619..7d1db21cf39 100644
--- a/lib/private/Metadata/FileMetadata.php
+++ b/lib/private/Metadata/FileMetadata.php
@@ -30,7 +30,7 @@ use OCP\DB\Types;
* @method void setGroupName(string $groupName)
* @method string getMetadata()
* @method void setMetadata(array $metadata)
- * @see OC\Core\Migrations\Version240000Date20220404230027
+ * @see \OC\Core\Migrations\Version240000Date20220404230027
*/
class FileMetadata extends Entity {
protected ?string $groupName = null;
diff --git a/lib/private/User/DisplayNameCache.php b/lib/private/User/DisplayNameCache.php
new file mode 100644
index 00000000000..22a79863e49
--- /dev/null
+++ b/lib/private/User/DisplayNameCache.php
@@ -0,0 +1,85 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright 2022 Carl Schwan <carl@carlschwan.eu>
+ * @license 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 OC\User;
+
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\ICache;
+use OCP\ICacheFactory;
+use OCP\IUserManager;
+use OCP\User\Events\UserChangedEvent;
+
+/**
+ * Class that cache the relation UserId -> Display name
+ *
+ * This saves fetching the user from a user backend and later on fetching
+ * their preferences. It's generally not an issue if this data is slightly
+ * outdated.
+ */
+class DisplayNameCache implements IEventListener {
+ private array $cache = [];
+ private ICache $memCache;
+ private IUserManager $userManager;
+
+ public function __construct(ICacheFactory $cacheFactory, IUserManager $userManager) {
+ $this->memCache = $cacheFactory->createDistributed('displayNameMappingCache');
+ $this->userManager = $userManager;
+ }
+
+ public function getDisplayName(string $userId) {
+ if (isset($this->cache[$userId])) {
+ return $this->cache[$userId];
+ }
+ $displayName = $this->memCache->get($userId);
+ if ($displayName) {
+ $this->cache[$userId] = $displayName;
+ return $displayName;
+ }
+
+ $user = $this->userManager->get($userId);
+ if ($user) {
+ $displayName = $user->getDisplayName();
+ } else {
+ $displayName = $userId;
+ }
+ $this->cache[$userId] = $displayName;
+ $this->memCache->set($userId, $displayName, 60 * 10); // 10 minutes
+
+ return $displayName;
+ }
+
+ public function clear(): void {
+ $this->cache = [];
+ $this->memCache->clear();
+ }
+
+ public function handle(Event $event): void {
+ if ($event instanceof UserChangedEvent && $event->getFeature() === 'displayName') {
+ $userId = $event->getUser()->getUID();
+ $newDisplayName = $event->getValue();
+ $this->cache[$userId] = $newDisplayName;
+ $this->memCache->set($userId, $newDisplayName, 60 * 10); // 10 minutes
+ }
+ }
+}
diff --git a/lib/private/User/LazyUser.php b/lib/private/User/LazyUser.php
new file mode 100644
index 00000000000..8b98b112731
--- /dev/null
+++ b/lib/private/User/LazyUser.php
@@ -0,0 +1,149 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2022 Robin Appelman <robin@icewind.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * 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 OC\User;
+
+use OCP\IUser;
+use OCP\IUserManager;
+
+class LazyUser implements IUser {
+ private ?IUser $user = null;
+ private DisplayNameCache $displayNameCache;
+ private string $uid;
+ private IUserManager $userManager;
+
+ public function __construct(string $uid, DisplayNameCache $displayNameCache, IUserManager $userManager) {
+ $this->displayNameCache = $displayNameCache;
+ $this->uid = $uid;
+ $this->userManager = $userManager;
+ }
+
+ private function getUser(): IUser {
+ if ($this->user === null) {
+ $this->user = $this->userManager->get($this->uid);
+ }
+ /** @var IUser */
+ $user = $this->user;
+ return $user;
+ }
+
+ public function getUID() {
+ return $this->uid;
+ }
+
+ public function getDisplayName() {
+ return $this->displayNameCache->getDisplayName($this->uid);
+ }
+
+ public function setDisplayName($displayName) {
+ return $this->getUser()->setDisplayName($displayName);
+ }
+
+ public function getLastLogin() {
+ return $this->getUser()->getLastLogin();
+ }
+
+ public function updateLastLoginTimestamp() {
+ return $this->getUser()->updateLastLoginTimestamp();
+ }
+
+ public function delete() {
+ return $this->getUser()->delete();
+ }
+
+ public function setPassword($password, $recoveryPassword = null) {
+ return $this->getUser()->setPassword($password, $recoveryPassword);
+ }
+
+ public function getHome() {
+ return $this->getUser()->getHome();
+ }
+
+ public function getBackendClassName() {
+ return $this->getUser()->getBackendClassName();
+ }
+
+ public function getBackend() {
+ return $this->getUser()->getBackend();
+ }
+
+ public function canChangeAvatar() {
+ return $this->getUser()->canChangeAvatar();
+ }
+
+ public function canChangePassword() {
+ return $this->getUser()->canChangePassword();
+ }
+
+ public function canChangeDisplayName() {
+ return $this->getUser()->canChangeDisplayName();
+ }
+
+ public function isEnabled() {
+ return $this->getUser()->isEnabled();
+ }
+
+ public function setEnabled(bool $enabled = true) {
+ return $this->getUser()->setEnabled($enabled);
+ }
+
+ public function getEMailAddress() {
+ return $this->getUser()->getEMailAddress();
+ }
+
+ public function getSystemEMailAddress(): ?string {
+ return $this->getUser()->getSystemEMailAddress();
+ }
+
+ public function getPrimaryEMailAddress(): ?string {
+ return $this->getUser()->getPrimaryEMailAddress();
+ }
+
+ public function getAvatarImage($size) {
+ return $this->getUser()->getAvatarImage($size);
+ }
+
+ public function getCloudId() {
+ return $this->getUser()->getCloudId();
+ }
+
+ public function setEMailAddress($mailAddress) {
+ $this->getUser()->setEMailAddress($mailAddress);
+ }
+
+ public function setSystemEMailAddress(string $mailAddress): void {
+ $this->getUser()->setSystemEMailAddress($mailAddress);
+ }
+
+ public function setPrimaryEMailAddress(string $mailAddress): void {
+ $this->getUser()->setPrimaryEMailAddress($mailAddress);
+ }
+
+ public function getQuota() {
+ return $this->getUser()->getQuota();
+ }
+
+ public function setQuota($quota) {
+ $this->getUser()->setQuota($quota);
+ }
+}
diff --git a/lib/private/legacy/OC_Helper.php b/lib/private/legacy/OC_Helper.php
index 547ffef8607..0d1903007c2 100644
--- a/lib/private/legacy/OC_Helper.php
+++ b/lib/private/legacy/OC_Helper.php
@@ -44,8 +44,11 @@
*
*/
use bantu\IniGetWrapper\IniGetWrapper;
+use OC\Files\Filesystem;
use OCP\Files\Mount\IMountPoint;
+use OCP\ICacheFactory;
use OCP\IUser;
+use Psr\Log\LoggerInterface;
use Symfony\Component\Process\ExecutableFinder;
/**
@@ -486,9 +489,20 @@ class OC_Helper {
* @throws \OCP\Files\NotFoundException
*/
public static function getStorageInfo($path, $rootInfo = null, $includeMountPoints = true) {
+ /** @var ICacheFactory $cacheFactory */
+ $cacheFactory = \OC::$server->get(ICacheFactory::class);
+ $memcache = $cacheFactory->createLocal('storage_info');
+
// return storage info without adding mount points
$includeExtStorage = \OC::$server->getSystemConfig()->getValue('quota_include_external_storage', false);
+ $fullPath = Filesystem::getView()->getAbsolutePath($path);
+ $cacheKey = $fullPath. '::' . ($includeMountPoints ? 'include' : 'exclude');
+ $cached = $memcache->get($cacheKey);
+ if ($cached) {
+ return $cached;
+ }
+
if (!$rootInfo) {
$rootInfo = \OC\Files\Filesystem::getFileInfo($path, $includeExtStorage ? 'ext' : false);
}
@@ -505,7 +519,6 @@ class OC_Helper {
$sourceStorage = $storage;
if ($storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
$includeExtStorage = false;
- $sourceStorage = $storage->getSourceStorage();
$internalPath = $storage->getUnjailedPath($rootInfo->getInternalPath());
} else {
$internalPath = $rootInfo->getInternalPath();
@@ -531,7 +544,19 @@ class OC_Helper {
/** @var \OC\Files\Storage\Wrapper\Quota $storage */
$quota = $sourceStorage->getQuota();
}
- $free = $sourceStorage->free_space($internalPath);
+ try {
+ $free = $sourceStorage->free_space($internalPath);
+ } catch (\Exception $e) {
+ if ($path === "") {
+ throw $e;
+ }
+ /** @var LoggerInterface $logger */
+ $logger = \OC::$server->get(LoggerInterface::class);
+ $logger->warning("Error while getting quota info, using root quota", ['exception' => $e]);
+ $rootInfo = self::getStorageInfo("");
+ $memcache->set($cacheKey, $rootInfo, 5 * 60);
+ return $rootInfo;
+ }
if ($free >= 0) {
$total = $free + $used;
} else {
@@ -559,7 +584,7 @@ class OC_Helper {
[,,,$mountPoint] = explode('/', $mount->getMountPoint(), 4);
}
- return [
+ $info = [
'free' => $free,
'used' => $used,
'quota' => $quota,
@@ -570,6 +595,10 @@ class OC_Helper {
'mountType' => $mount->getMountType(),
'mountPoint' => trim($mountPoint, '/'),
];
+
+ $memcache->set($cacheKey, $info, 5 * 60);
+
+ return $info;
}
/**
diff --git a/tests/lib/BackgroundJob/DummyJobList.php b/tests/lib/BackgroundJob/DummyJobList.php
index ec06203a477..0751409f62c 100644
--- a/tests/lib/BackgroundJob/DummyJobList.php
+++ b/tests/lib/BackgroundJob/DummyJobList.php
@@ -78,7 +78,7 @@ class DummyJobList extends \OC\BackgroundJob\JobList {
* @param bool $onlyTimeSensitive
* @return IJob|null
*/
- public function getNext(bool $onlyTimeSensitive = true): ?IJob {
+ public function getNext(bool $onlyTimeSensitive = false): ?IJob {
if (count($this->jobs) > 0) {
if ($this->last < (count($this->jobs) - 1)) {
$i = $this->last + 1;
diff --git a/tests/lib/Files/Node/RootTest.php b/tests/lib/Files/Node/RootTest.php
index fe151d70dc3..ee86eab5675 100644
--- a/tests/lib/Files/Node/RootTest.php
+++ b/tests/lib/Files/Node/RootTest.php
@@ -232,9 +232,7 @@ class RootTest extends \Test\TestCase {
->method('error')
->with(
'Backends provided no user object for NotExistingUser',
- [
- 'app' => 'files',
- ]
+ $this->anything()
);
$root->getUserFolder('NotExistingUser');