aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private')
-rw-r--r--lib/private/App/AppManager.php21
-rw-r--r--lib/private/App/AppStore/AppNotFoundException.php13
-rw-r--r--lib/private/AppConfig.php9
-rw-r--r--lib/private/AppFramework/Bootstrap/Coordinator.php12
-rw-r--r--lib/private/AppFramework/Services/AppConfig.php4
-rw-r--r--lib/private/Files/Cache/Storage.php1
-rw-r--r--lib/private/Files/Node/Folder.php8
-rw-r--r--lib/private/Files/Node/LazyFolder.php4
-rw-r--r--lib/private/Files/ObjectStore/ObjectStoreStorage.php6
-rw-r--r--lib/private/Installer.php9
-rw-r--r--lib/private/Notification/Manager.php4
-rw-r--r--lib/private/PreviewManager.php16
-rw-r--r--lib/private/Route/CachingRouter.php100
-rw-r--r--lib/private/Route/Route.php10
-rw-r--r--lib/private/Route/Router.php46
-rw-r--r--lib/private/Server.php4
-rw-r--r--lib/private/TemplateLayout.php2
-rw-r--r--lib/private/URLGenerator.php6
-rw-r--r--lib/private/legacy/OC_App.php2
19 files changed, 228 insertions, 49 deletions
diff --git a/lib/private/App/AppManager.php b/lib/private/App/AppManager.php
index f6494fa946d..4223d09e3dc 100644
--- a/lib/private/App/AppManager.php
+++ b/lib/private/App/AppManager.php
@@ -18,6 +18,7 @@ use OCP\Collaboration\AutoComplete\IManager as IAutoCompleteManager;
use OCP\Collaboration\Collaborators\ISearch as ICollaboratorSearch;
use OCP\Diagnostics\IEventLogger;
use OCP\EventDispatcher\IEventDispatcher;
+use OCP\IAppConfig;
use OCP\ICacheFactory;
use OCP\IConfig;
use OCP\IGroup;
@@ -134,7 +135,8 @@ class AppManager implements IAppManager {
*/
private function getEnabledAppsValues(): array {
if (!$this->enabledAppsCache) {
- $values = $this->getAppConfig()->getValues(false, 'enabled');
+ /** @var array<string,string> */
+ $values = $this->getAppConfig()->searchValues('enabled', false, IAppConfig::VALUE_STRING);
$alwaysEnabledApps = $this->getAlwaysEnabledApps();
foreach ($alwaysEnabledApps as $appId) {
@@ -545,11 +547,16 @@ class AppManager implements IAppManager {
* @param string $appId
* @param bool $forceEnable
* @throws AppPathNotFoundException
+ * @throws \InvalidArgumentException if the application is not installed yet
*/
public function enableApp(string $appId, bool $forceEnable = false): void {
// Check if app exists
$this->getAppPath($appId);
+ if ($this->config->getAppValue($appId, 'installed_version', '') === '') {
+ throw new \InvalidArgumentException("$appId is not installed, cannot be enabled.");
+ }
+
if ($forceEnable) {
$this->overwriteNextcloudRequirement($appId);
}
@@ -596,6 +603,10 @@ class AppManager implements IAppManager {
throw new \InvalidArgumentException("$appId can't be enabled for groups.");
}
+ if ($this->config->getAppValue($appId, 'installed_version', '') === '') {
+ throw new \InvalidArgumentException("$appId is not installed, cannot be enabled.");
+ }
+
if ($forceEnable) {
$this->overwriteNextcloudRequirement($appId);
}
@@ -775,8 +786,8 @@ class AppManager implements IAppManager {
*
* @return array<string, string>
*/
- public function getAppInstalledVersions(): array {
- return $this->getAppConfig()->getAppInstalledVersions();
+ public function getAppInstalledVersions(bool $onlyEnabled = false): array {
+ return $this->getAppConfig()->getAppInstalledVersions($onlyEnabled);
}
/**
@@ -812,6 +823,10 @@ class AppManager implements IAppManager {
}
private function isAlwaysEnabled(string $appId): bool {
+ if ($appId === 'core') {
+ return true;
+ }
+
$alwaysEnabled = $this->getAlwaysEnabledApps();
return in_array($appId, $alwaysEnabled, true);
}
diff --git a/lib/private/App/AppStore/AppNotFoundException.php b/lib/private/App/AppStore/AppNotFoundException.php
new file mode 100644
index 00000000000..79ceebb4423
--- /dev/null
+++ b/lib/private/App/AppStore/AppNotFoundException.php
@@ -0,0 +1,13 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OC\App\AppStore;
+
+class AppNotFoundException extends \Exception {
+}
diff --git a/lib/private/AppConfig.php b/lib/private/AppConfig.php
index a8a6f689ffa..adbfc58978b 100644
--- a/lib/private/AppConfig.php
+++ b/lib/private/AppConfig.php
@@ -1670,11 +1670,18 @@ class AppConfig implements IAppConfig {
*
* @return array<string, string>
*/
- public function getAppInstalledVersions(): array {
+ public function getAppInstalledVersions(bool $onlyEnabled = false): array {
if ($this->appVersionsCache === null) {
/** @var array<string, string> */
$this->appVersionsCache = $this->searchValues('installed_version', false, IAppConfig::VALUE_STRING);
}
+ if ($onlyEnabled) {
+ return array_filter(
+ $this->appVersionsCache,
+ fn (string $app): bool => $this->getValueString($app, 'enabled', 'no') !== 'no',
+ ARRAY_FILTER_USE_KEY
+ );
+ }
return $this->appVersionsCache;
}
}
diff --git a/lib/private/AppFramework/Bootstrap/Coordinator.php b/lib/private/AppFramework/Bootstrap/Coordinator.php
index 4e613703dec..190244051d3 100644
--- a/lib/private/AppFramework/Bootstrap/Coordinator.php
+++ b/lib/private/AppFramework/Bootstrap/Coordinator.php
@@ -20,6 +20,7 @@ use OCP\Dashboard\IManager;
use OCP\Diagnostics\IEventLogger;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IServerContainer;
+use Psr\Container\ContainerExceptionInterface;
use Psr\Log\LoggerInterface;
use Throwable;
use function class_exists;
@@ -69,19 +70,24 @@ class Coordinator {
*/
try {
$path = $this->appManager->getAppPath($appId);
+ OC_App::registerAutoloading($appId, $path);
} catch (AppPathNotFoundException) {
// Ignore
continue;
}
- OC_App::registerAutoloading($appId, $path);
$this->eventLogger->end("bootstrap:register_app:$appId:autoloader");
/*
* Next we check if there is an application class, and it implements
* the \OCP\AppFramework\Bootstrap\IBootstrap interface
*/
- $appNameSpace = App::buildAppNamespace($appId);
+ if ($appId === 'core') {
+ $appNameSpace = 'OC\\Core';
+ } else {
+ $appNameSpace = App::buildAppNamespace($appId);
+ }
$applicationClassName = $appNameSpace . '\\AppInfo\\Application';
+
try {
if (class_exists($applicationClassName) && is_a($applicationClassName, IBootstrap::class, true)) {
$this->eventLogger->start("bootstrap:register_app:$appId:application", "Load `Application` instance for $appId");
@@ -89,7 +95,7 @@ class Coordinator {
/** @var IBootstrap&App $application */
$application = $this->serverContainer->query($applicationClassName);
$apps[$appId] = $application;
- } catch (QueryException $e) {
+ } catch (ContainerExceptionInterface $e) {
// Weird, but ok
$this->eventLogger->end("bootstrap:register_app:$appId");
continue;
diff --git a/lib/private/AppFramework/Services/AppConfig.php b/lib/private/AppFramework/Services/AppConfig.php
index 77c5ea4de0c..04d97738483 100644
--- a/lib/private/AppFramework/Services/AppConfig.php
+++ b/lib/private/AppFramework/Services/AppConfig.php
@@ -343,7 +343,7 @@ class AppConfig implements IAppConfig {
*
* @return array<string, string>
*/
- public function getAppInstalledVersions(): array {
- return $this->appConfig->getAppInstalledVersions();
+ public function getAppInstalledVersions(bool $onlyEnabled = false): array {
+ return $this->appConfig->getAppInstalledVersions($onlyEnabled);
}
}
diff --git a/lib/private/Files/Cache/Storage.php b/lib/private/Files/Cache/Storage.php
index 2b49e65f0b4..1a3bda58e6a 100644
--- a/lib/private/Files/Cache/Storage.php
+++ b/lib/private/Files/Cache/Storage.php
@@ -213,6 +213,7 @@ class Storage {
$query = $db->getQueryBuilder();
$query->delete('filecache')
->where($query->expr()->in('storage', $query->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY)));
+ $query->runAcrossAllShards();
$query->executeStatement();
$query = $db->getQueryBuilder();
diff --git a/lib/private/Files/Node/Folder.php b/lib/private/Files/Node/Folder.php
index 16365948031..c41838fd6b0 100644
--- a/lib/private/Files/Node/Folder.php
+++ b/lib/private/Files/Node/Folder.php
@@ -460,4 +460,12 @@ class Folder extends Node implements \OCP\Files\Folder {
return $this->search($query);
}
+
+ public function verifyPath($fileName, $readonly = false): void {
+ $this->view->verifyPath(
+ $this->getPath(),
+ $fileName,
+ $readonly,
+ );
+ }
}
diff --git a/lib/private/Files/Node/LazyFolder.php b/lib/private/Files/Node/LazyFolder.php
index 5879748d951..37b1efa0fad 100644
--- a/lib/private/Files/Node/LazyFolder.php
+++ b/lib/private/Files/Node/LazyFolder.php
@@ -561,4 +561,8 @@ class LazyFolder implements Folder {
public function getMetadata(): array {
return $this->data['metadata'] ?? $this->__call(__FUNCTION__, func_get_args());
}
+
+ public function verifyPath($fileName, $readonly = false): void {
+ $this->__call(__FUNCTION__, func_get_args());
+ }
}
diff --git a/lib/private/Files/ObjectStore/ObjectStoreStorage.php b/lib/private/Files/ObjectStore/ObjectStoreStorage.php
index ebe87399ab4..36b1a7a1c95 100644
--- a/lib/private/Files/ObjectStore/ObjectStoreStorage.php
+++ b/lib/private/Files/ObjectStore/ObjectStoreStorage.php
@@ -67,7 +67,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
$this->logger = \OCP\Server::get(LoggerInterface::class);
}
- public function mkdir(string $path, bool $force = false): bool {
+ public function mkdir(string $path, bool $force = false, array $metadata = []): bool {
$path = $this->normalizePath($path);
if (!$force && $this->file_exists($path)) {
$this->logger->warning("Tried to create an object store folder that already exists: $path");
@@ -77,7 +77,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
$mTime = time();
$data = [
'mimetype' => 'httpd/unix-directory',
- 'size' => 0,
+ 'size' => $metadata['size'] ?? 0,
'mtime' => $mTime,
'storage_mtime' => $mTime,
'permissions' => \OCP\Constants::PERMISSION_ALL,
@@ -709,7 +709,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
if ($cache->inCache($to)) {
$cache->remove($to);
}
- $this->mkdir($to);
+ $this->mkdir($to, false, ['size' => $sourceEntry->getSize()]);
foreach ($sourceCache->getFolderContentsById($sourceEntry->getId()) as $child) {
$this->copyInner($sourceCache, $child, $to . '/' . $child->getName());
diff --git a/lib/private/Installer.php b/lib/private/Installer.php
index f32b0e5919a..3bbef3252f4 100644
--- a/lib/private/Installer.php
+++ b/lib/private/Installer.php
@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace OC;
use Doctrine\DBAL\Exception\TableExistsException;
+use OC\App\AppStore\AppNotFoundException;
use OC\App\AppStore\Bundles\Bundle;
use OC\App\AppStore\Fetcher\AppFetcher;
use OC\AppFramework\Bootstrap\Coordinator;
@@ -174,6 +175,7 @@ class Installer {
* @param string $appId
* @param bool [$allowUnstable]
*
+ * @throws AppNotFoundException If the app is not found on the appstore
* @throws \Exception If the installation was not successful
*/
public function downloadApp(string $appId, bool $allowUnstable = false): void {
@@ -341,6 +343,9 @@ class Installer {
// otherwise we just copy the outer directory
$this->copyRecursive($extractDir, $baseDir);
Files::rmdirr($extractDir);
+ if (function_exists('opcache_reset')) {
+ opcache_reset();
+ }
return;
}
// Signature does not match
@@ -353,9 +358,9 @@ class Installer {
}
}
- throw new \Exception(
+ throw new AppNotFoundException(
sprintf(
- 'Could not download app %s',
+ 'Could not download app %s, it was not found on the appstore',
$appId
)
);
diff --git a/lib/private/Notification/Manager.php b/lib/private/Notification/Manager.php
index b75e52deacb..8c457db8beb 100644
--- a/lib/private/Notification/Manager.php
+++ b/lib/private/Notification/Manager.php
@@ -217,7 +217,9 @@ class Manager implements IManager {
* @since 8.2.0
*/
public function hasNotifiers(): bool {
- return !empty($this->notifiers) || !empty($this->notifierClasses);
+ return !empty($this->notifiers)
+ || !empty($this->notifierClasses)
+ || (!$this->parsedRegistrationContext && !empty($this->coordinator->getRegistrationContext()->getNotifierServices()));
}
/**
diff --git a/lib/private/PreviewManager.php b/lib/private/PreviewManager.php
index fa62a7b0257..0bb0280406c 100644
--- a/lib/private/PreviewManager.php
+++ b/lib/private/PreviewManager.php
@@ -154,7 +154,7 @@ class PreviewManager implements IPreview {
$mimeType = null,
bool $cacheResult = true,
): ISimpleFile {
- $this->throwIfPreviewsDisabled($file);
+ $this->throwIfPreviewsDisabled($file, $mimeType);
$previewConcurrency = $this->getGenerator()->getNumConcurrentPreviews('preview_concurrency_all');
$sem = Generator::guardWithSemaphore(Generator::SEMAPHORE_ID_ALL, $previewConcurrency);
try {
@@ -178,7 +178,7 @@ class PreviewManager implements IPreview {
* @since 19.0.0
*/
public function generatePreviews(File $file, array $specifications, $mimeType = null) {
- $this->throwIfPreviewsDisabled($file);
+ $this->throwIfPreviewsDisabled($file, $mimeType);
return $this->getGenerator()->generatePreviews($file, $specifications, $mimeType);
}
@@ -213,13 +213,15 @@ class PreviewManager implements IPreview {
/**
* Check if a preview can be generated for a file
*/
- public function isAvailable(\OCP\Files\FileInfo $file): bool {
+ public function isAvailable(\OCP\Files\FileInfo $file, ?string $mimeType = null): bool {
if (!$this->enablePreviews) {
return false;
}
+ $fileMimeType = $mimeType ?? $file->getMimeType();
+
$this->registerCoreProviders();
- if (!$this->isMimeSupported($file->getMimetype())) {
+ if (!$this->isMimeSupported($fileMimeType)) {
return false;
}
@@ -229,7 +231,7 @@ class PreviewManager implements IPreview {
}
foreach ($this->providers as $supportedMimeType => $providers) {
- if (preg_match($supportedMimeType, $file->getMimetype())) {
+ if (preg_match($supportedMimeType, $fileMimeType)) {
foreach ($providers as $providerClosure) {
$provider = $this->helper->getProvider($providerClosure);
if (!($provider instanceof IProviderV2)) {
@@ -455,8 +457,8 @@ class PreviewManager implements IPreview {
/**
* @throws NotFoundException if preview generation is disabled
*/
- private function throwIfPreviewsDisabled(File $file): void {
- if (!$this->isAvailable($file)) {
+ private function throwIfPreviewsDisabled(File $file, ?string $mimeType = null): void {
+ if (!$this->isAvailable($file, $mimeType)) {
throw new NotFoundException('Previews disabled');
}
}
diff --git a/lib/private/Route/CachingRouter.php b/lib/private/Route/CachingRouter.php
index 7dd26827d3c..dbd5ef02603 100644
--- a/lib/private/Route/CachingRouter.php
+++ b/lib/private/Route/CachingRouter.php
@@ -15,10 +15,16 @@ use OCP\IConfig;
use OCP\IRequest;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
+use Symfony\Component\Routing\Exception\ResourceNotFoundException;
+use Symfony\Component\Routing\Matcher\CompiledUrlMatcher;
+use Symfony\Component\Routing\Matcher\Dumper\CompiledUrlMatcherDumper;
+use Symfony\Component\Routing\RouteCollection;
class CachingRouter extends Router {
protected ICache $cache;
+ protected array $legacyCreatedRoutes = [];
+
public function __construct(
ICacheFactory $cacheFactory,
LoggerInterface $logger,
@@ -54,4 +60,98 @@ class CachingRouter extends Router {
return $url;
}
}
+
+ private function serializeRouteCollection(RouteCollection $collection): array {
+ $dumper = new CompiledUrlMatcherDumper($collection);
+ return $dumper->getCompiledRoutes();
+ }
+
+ /**
+ * Find the route matching $url
+ *
+ * @param string $url The url to find
+ * @throws \Exception
+ * @return array
+ */
+ public function findMatchingRoute(string $url): array {
+ $this->eventLogger->start('cacheroute:match', 'Match route');
+ $key = $this->context->getHost() . '#' . $this->context->getBaseUrl() . '#rootCollection';
+ $cachedRoutes = $this->cache->get($key);
+ if (!$cachedRoutes) {
+ parent::loadRoutes();
+ $cachedRoutes = $this->serializeRouteCollection($this->root);
+ $this->cache->set($key, $cachedRoutes, 3600);
+ }
+ $matcher = new CompiledUrlMatcher($cachedRoutes, $this->context);
+ $this->eventLogger->start('cacheroute:url:match', 'Symfony URL match call');
+ try {
+ $parameters = $matcher->match($url);
+ } catch (ResourceNotFoundException $e) {
+ if (!str_ends_with($url, '/')) {
+ // We allow links to apps/files? for backwards compatibility reasons
+ // However, since Symfony does not allow empty route names, the route
+ // we need to match is '/', so we need to append the '/' here.
+ try {
+ $parameters = $matcher->match($url . '/');
+ } catch (ResourceNotFoundException $newException) {
+ // If we still didn't match a route, we throw the original exception
+ throw $e;
+ }
+ } else {
+ throw $e;
+ }
+ }
+ $this->eventLogger->end('cacheroute:url:match');
+
+ $this->eventLogger->end('cacheroute:match');
+ return $parameters;
+ }
+
+ /**
+ * @param array{action:mixed, ...} $parameters
+ */
+ protected function callLegacyActionRoute(array $parameters): void {
+ /*
+ * Closures cannot be serialized to cache, so for legacy routes calling an action we have to include the routes.php file again
+ */
+ $app = $parameters['app'];
+ $this->useCollection($app);
+ parent::requireRouteFile($parameters['route-file'], $app);
+ $collection = $this->getCollection($app);
+ $parameters['action'] = $collection->get($parameters['_route'])?->getDefault('action');
+ parent::callLegacyActionRoute($parameters);
+ }
+
+ /**
+ * Create a \OC\Route\Route.
+ * Deprecated
+ *
+ * @param string $name Name of the route to create.
+ * @param string $pattern The pattern to match
+ * @param array $defaults An array of default parameter values
+ * @param array $requirements An array of requirements for parameters (regexes)
+ */
+ public function create($name, $pattern, array $defaults = [], array $requirements = []): Route {
+ $this->legacyCreatedRoutes[] = $name;
+ return parent::create($name, $pattern, $defaults, $requirements);
+ }
+
+ /**
+ * Require a routes.php file
+ */
+ protected function requireRouteFile(string $file, string $appName): void {
+ $this->legacyCreatedRoutes = [];
+ parent::requireRouteFile($file, $appName);
+ foreach ($this->legacyCreatedRoutes as $routeName) {
+ $route = $this->collection?->get($routeName);
+ if ($route === null) {
+ /* Should never happen */
+ throw new \Exception("Could not find route $routeName");
+ }
+ if ($route->hasDefault('action')) {
+ $route->setDefault('route-file', $file);
+ $route->setDefault('app', $appName);
+ }
+ }
+ }
}
diff --git a/lib/private/Route/Route.php b/lib/private/Route/Route.php
index ab5a1f6b59a..08231649e76 100644
--- a/lib/private/Route/Route.php
+++ b/lib/private/Route/Route.php
@@ -124,15 +124,9 @@ class Route extends SymfonyRoute implements IRoute {
* The action to execute when this route matches, includes a file like
* it is called directly
* @param string $file
- * @return void
*/
public function actionInclude($file) {
- $function = function ($param) use ($file) {
- unset($param['_route']);
- $_GET = array_merge($_GET, $param);
- unset($param);
- require_once "$file";
- } ;
- $this->action($function);
+ $this->setDefault('file', $file);
+ return $this;
}
}
diff --git a/lib/private/Route/Router.php b/lib/private/Route/Router.php
index 376852a1b6e..02f371e808a 100644
--- a/lib/private/Route/Router.php
+++ b/lib/private/Route/Router.php
@@ -82,7 +82,7 @@ class Router implements IRouter {
public function getRoutingFiles() {
if ($this->routingFiles === null) {
$this->routingFiles = [];
- foreach (\OC_APP::getEnabledApps() as $app) {
+ foreach ($this->appManager->getEnabledApps() as $app) {
try {
$appPath = $this->appManager->getAppPath($app);
$file = $appPath . '/appinfo/routes.php';
@@ -117,7 +117,7 @@ class Router implements IRouter {
$routingFiles = $this->getRoutingFiles();
$this->eventLogger->start('route:load:attributes', 'Loading Routes from attributes');
- foreach (\OC_App::getEnabledApps() as $enabledApp) {
+ foreach ($this->appManager->getEnabledApps() as $enabledApp) {
$this->loadAttributeRoutes($enabledApp);
}
$this->eventLogger->end('route:load:attributes');
@@ -312,17 +312,11 @@ class Router implements IRouter {
$application = $this->getApplicationClass($caller[0]);
\OC\AppFramework\App::main($caller[1], $caller[2], $application->getContainer(), $parameters);
} elseif (isset($parameters['action'])) {
- $action = $parameters['action'];
- if (!is_callable($action)) {
- throw new \Exception('not a callable action');
- }
- unset($parameters['action']);
- unset($parameters['caller']);
- $this->eventLogger->start('route:run:call', 'Run callable route');
- call_user_func($action, $parameters);
- $this->eventLogger->end('route:run:call');
+ $this->logger->warning('Deprecated action route used', ['parameters' => $parameters]);
+ $this->callLegacyActionRoute($parameters);
} elseif (isset($parameters['file'])) {
- include $parameters['file'];
+ $this->logger->debug('Deprecated file route used', ['parameters' => $parameters]);
+ $this->includeLegacyFileRoute($parameters);
} else {
throw new \Exception('no action available');
}
@@ -330,6 +324,32 @@ class Router implements IRouter {
}
/**
+ * @param array{file:mixed, ...} $parameters
+ */
+ protected function includeLegacyFileRoute(array $parameters): void {
+ $param = $parameters;
+ unset($param['_route']);
+ $_GET = array_merge($_GET, $param);
+ unset($param);
+ require_once $parameters['file'];
+ }
+
+ /**
+ * @param array{action:mixed, ...} $parameters
+ */
+ protected function callLegacyActionRoute(array $parameters): void {
+ $action = $parameters['action'];
+ if (!is_callable($action)) {
+ throw new \Exception('not a callable action');
+ }
+ unset($parameters['action']);
+ unset($parameters['caller']);
+ $this->eventLogger->start('route:run:call', 'Run callable route');
+ call_user_func($action, $parameters);
+ $this->eventLogger->end('route:run:call');
+ }
+
+ /**
* Get the url generator
*
* @return \Symfony\Component\Routing\Generator\UrlGenerator
@@ -492,7 +512,7 @@ class Router implements IRouter {
* @param string $file the route file location to include
* @param string $appName
*/
- private function requireRouteFile($file, $appName) {
+ protected function requireRouteFile(string $file, string $appName): void {
$this->setupRoutes(include $file, $appName);
}
diff --git a/lib/private/Server.php b/lib/private/Server.php
index bf07ee355ea..83eb95cd671 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -605,7 +605,7 @@ class Server extends ServerContainer implements IServerContainer {
$prefixClosure = function () use ($logQuery, $serverVersion): ?string {
if (!$logQuery) {
try {
- $v = \OCP\Server::get(IAppConfig::class)->getAppInstalledVersions();
+ $v = \OCP\Server::get(IAppConfig::class)->getAppInstalledVersions(true);
} catch (\Doctrine\DBAL\Exception $e) {
// Database service probably unavailable
// Probably related to https://github.com/nextcloud/server/issues/37424
@@ -620,7 +620,7 @@ class Server extends ServerContainer implements IServerContainer {
];
}
$v['core'] = implode(',', $serverVersion->getVersion());
- $version = implode(',', $v);
+ $version = implode(',', array_keys($v)) . implode(',', $v);
$instanceId = \OC_Util::getInstanceId();
$path = \OC::$SERVERROOT;
return md5($instanceId . '-' . $version . '-' . $path);
diff --git a/lib/private/TemplateLayout.php b/lib/private/TemplateLayout.php
index caffbfceefa..cfc387d2164 100644
--- a/lib/private/TemplateLayout.php
+++ b/lib/private/TemplateLayout.php
@@ -201,7 +201,7 @@ class TemplateLayout {
if ($this->config->getSystemValueBool('installed', false)) {
if (empty(self::$versionHash)) {
- $v = $this->appManager->getAppInstalledVersions();
+ $v = $this->appManager->getAppInstalledVersions(true);
$v['core'] = implode('.', $this->serverVersion->getVersion());
self::$versionHash = substr(md5(implode(',', $v)), 0, 8);
}
diff --git a/lib/private/URLGenerator.php b/lib/private/URLGenerator.php
index c78ecac0903..1a2978b84d7 100644
--- a/lib/private/URLGenerator.php
+++ b/lib/private/URLGenerator.php
@@ -189,14 +189,14 @@ class URLGenerator implements IURLGenerator {
$basename = substr(basename($file), 0, -4);
try {
- $appPath = $this->getAppManager()->getAppPath($appName);
- } catch (AppPathNotFoundException $e) {
if ($appName === 'core' || $appName === '') {
$appName = 'core';
$appPath = false;
} else {
- throw new RuntimeException('image not found: image: ' . $file . ' webroot: ' . \OC::$WEBROOT . ' serverroot: ' . \OC::$SERVERROOT);
+ $appPath = $this->getAppManager()->getAppPath($appName);
}
+ } catch (AppPathNotFoundException $e) {
+ throw new RuntimeException('image not found: image: ' . $file . ' webroot: ' . \OC::$WEBROOT . ' serverroot: ' . \OC::$SERVERROOT);
}
// Check if the app is in the app folder
diff --git a/lib/private/legacy/OC_App.php b/lib/private/legacy/OC_App.php
index abac0d2635e..4f0fff8884e 100644
--- a/lib/private/legacy/OC_App.php
+++ b/lib/private/legacy/OC_App.php
@@ -316,6 +316,8 @@ class OC_App {
$appId = self::cleanAppId($appId);
if ($appId === '') {
return false;
+ } elseif ($appId === 'core') {
+ return __DIR__ . '/../../../core';
}
if (($dir = self::findAppInDirectories($appId, $refreshAppPath)) != false) {