Compare commits

..

12 Commits

Author SHA1 Message Date
Julius Härtl 8d27561d96 debug: Some code paths for debugging
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-06-20 18:39:01 +02:00
Andy Scherzinger c3354e9c84 Merge pull request #45228 from smokris/heartbeat-route
fix(settings): define a 'heartbeat' route, so SecurityHeaders can handle redirected root
2024-06-18 17:29:30 +02:00
Côme Chilliet 5d744456f6 fix(tests): Strong type property $router in RouterTest
Co-authored-by: Kate <26026535+provokateurin@users.noreply.github.com>
Signed-off-by: Côme Chilliet <91878298+come-nc@users.noreply.github.com>
2024-06-18 16:33:31 +02:00
Richard Steinmetz 4e840fb17a Merge pull request #45945 from nextcloud/perf/upgrade-reset-steps
perf: Avoid reusing previous migration steps
2024-06-18 15:24:37 +02:00
John Molakvoæ ae4a64b724 Merge pull request #45889 from nextcloud/fix/noid/cypress-local-changes 2024-06-18 15:11:50 +02:00
John Molakvoæ 61df8fa3ea Merge pull request #45894 from nextcloud/test/cypress/changes-ci 2024-06-18 15:08:44 +02:00
Richard Steinmetz 250bb12572 Merge pull request #45866 from nextcloud/bug/45697/disable-previews-two
fix(preview): don't create folder structure when previews are disabled
2024-06-18 13:57:42 +02:00
Julius Härtl ea9f2361ae perf: Avoid reusing previous migration steps
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2024-06-18 11:55:08 +02:00
Daniel Kesselberg d270561ef8 fix(preview): don't create folder structure when previews are disabled
Signed-off-by: Daniel Kesselberg <mail@danielkesselberg.de>
2024-06-18 10:39:45 +02:00
Richard Steinmetz ead63a067e test(cypress): don't apply changes in CI
Signed-off-by: Richard Steinmetz <richard@steinmetz.cloud>
2024-06-16 06:22:13 +00:00
Marcel Müller a5ba81a250 fix(cypress): Check for local changes before trying to apply them
Signed-off-by: Marcel Müller <marcel-mueller@gmx.de>
2024-06-15 20:19:05 +02:00
Steve Mokris e5ec9d6a7b fix(settings): define a 'heartbeat' route, so SecurityHeaders can handle redirected root
Signed-off-by: Steve Mokris <steve@kosada.com>
2024-05-07 20:01:27 -04:00
16 changed files with 222 additions and 246 deletions
+6
View File
@@ -22,6 +22,7 @@ use OCP\Files\NotFoundException;
use OCP\IPreview;
use OCP\IRequest;
use OCP\Preview\IMimeIconProvider;
use Psr\Log\LoggerInterface;
class PreviewController extends Controller {
public function __construct(
@@ -141,6 +142,11 @@ class PreviewController extends Controller {
return new DataResponse([], Http::STATUS_FORBIDDEN);
}
if ($node->getId() <= 0) {
\OCP\Server::get(LoggerInterface::class)->error('Requested preview with invalid file id: ' . $node->getId());
return new DataResponse([], Http::STATUS_FORBIDDEN);
}
$storage = $node->getStorage();
if ($storage->instanceOfStorage(SharedStorage::class)) {
/** @var SharedStorage $storage */
+2
View File
@@ -13,3 +13,5 @@ declare(strict_types=1);
// Routing
$this->create('core_ajax_update', '/core/ajax/update.php')
->actionInclude('core/ajax/update.php');
$this->create('heartbeat', '/heartbeat')->get();
+4 -1
View File
@@ -94,7 +94,10 @@ export default defineConfig({
config.baseUrl = `http://${ip}/index.php`
await waitOnNextcloud(ip)
await configureNextcloud()
await applyChangesToNextcloud()
if (!process.env.CI) {
await applyChangesToNextcloud()
}
// IMPORTANT: return the config otherwise cypress-split will not work
return config
+20 -3
View File
@@ -9,7 +9,9 @@
import Docker from 'dockerode'
import waitOn from 'wait-on'
import tar from 'tar'
import path from 'path'
import { execSync } from 'child_process'
import { existsSync } from 'fs'
export const docker = new Docker()
@@ -129,7 +131,6 @@ export const configureNextcloud = async function() {
*/
export const applyChangesToNextcloud = async function() {
console.log('\nApply local changes to nextcloud...')
const container = docker.getContainer(CONTAINER_NAME)
const htmlPath = '/var/www/html'
const folderPaths = [
@@ -151,10 +152,26 @@ export const applyChangesToNextcloud = async function() {
'./version.php',
]
folderPaths.forEach((path) => {
console.log(`├─ Copying ${path}`)
let needToApplyChanges = false
folderPaths.forEach((folderPath) => {
const fullPath = path.join(htmlPath, folderPath)
if (existsSync(fullPath)) {
needToApplyChanges = true
console.log(`├─ Copying ${folderPath}`)
}
})
// Don't try to apply changes, when there are none. Otherwise we
// still execute the 'chown' command, which is not needed.
if (!needToApplyChanges) {
console.log('└─ No local changes found to apply')
return
}
const container = docker.getContainer(CONTAINER_NAME)
// Tar-streaming the above folders into the container
const serverTar = tar.c({ gzip: false }, folderPaths)
await container.putArchive(serverTar, {
+1 -1
View File
@@ -110,7 +110,7 @@ class CacheEntry implements ICacheEntry {
return $this->data['upload_time'] ?? null;
}
public function getData(): array {
public function getData() {
return $this->data;
}
@@ -1,111 +0,0 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2024 Robin Appelman <robin@icewind.nl>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Files\Cache;
use OC\FilesMetadata\FilesMetadataManager;
use OC\SystemConfig;
use OCP\Files\Cache\ICacheEntry;
use OCP\Files\IMimeTypeLoader;
use OCP\ICache;
use OCP\ICacheFactory;
use OCP\IDBConnection;
use Psr\Log\LoggerInterface;
/**
* Provides cached access to file metadata.
*
* Note that this does not include any logic for invalidation and should only be
* used in places where up to 5 minute outdated metadata is accepted
*/
class CachedFileAccess extends FileAccess {
const TTL = 5 * 60;
private ICache $cache;
public function __construct(
IDBConnection $connection,
SystemConfig $systemConfig,
LoggerInterface $logger,
FilesMetadataManager $metadataManager,
IMimeTypeLoader $mimeTypeLoader,
ICacheFactory $cacheFactory,
) {
parent::__construct($connection, $systemConfig, $logger, $metadataManager, $mimeTypeLoader);
$this->cache = $cacheFactory->createLocal('file_access::');
}
/**
* @param int[] $fileIds
* @return string
*/
private function getCacheKey(array $fileIds): string {
return md5(implode(',', $fileIds));
}
/**
* @param int[] $fileIds
* @return null|ICacheEntry[]
*/
private function getCachedByFileIds(array $fileIds): ?array {
$cached = $this->cache->get($this->getCacheKey($fileIds));
if (is_array($cached)) {
return array_map(function ($data) {
return new CacheEntry($data);
}, $cached);
} else {
return null;
}
}
/**
* @param ICacheEntry[] $results
* @return void
*/
private function cacheEntries(array $results): void {
$resultFileIds = array_map(function(ICacheEntry $result) {
return $result->getId();
}, $results);
$value = array_map(function(ICacheEntry $entry) {
return $entry->getData();
}, $results);
$this->cache->set($this->getCacheKey($resultFileIds), $value, self::TTL);
}
public function getByFileIdInStorage(int $fileId, int $storageId): ?CacheEntry {
$items = array_values($this->getByFileIdsInStorage([$fileId], $storageId));
return $items[0] ?? null;
}
public function getByFileId(int $fileId): ?CacheEntry {
$items = array_values($this->getByFileIds([$fileId]));
return $items[0] ?? null;
}
public function getByFileIds(array $fileIds): array {
$cached = $this->getCachedByFileIds($fileIds);
if ($cached) {
return $cached;
}
$result = parent::getByFileIds($fileIds);
$this->cacheEntries($result);
return $result;
}
public function getByFileIdsInStorage(array $fileIds, int $storageId): array {
$cached = $this->getCachedByFileIds($fileIds);
if ($cached) {
return $cached;
}
$result = parent::getByFileIdsInStorage($fileIds, $storageId);
$this->cacheEntries($result);
return $result;
}
}
@@ -493,7 +493,9 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
$stat['checksum'] = '';
$exists = $this->getCache()->inCache($path);
// if ($this->needsPartFile()) {
$uploadPath = $exists ? $path : $path . '.part';
// }
if ($exists) {
$fileId = $stat['fileid'];
@@ -554,7 +556,8 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
$this->getCache()->update($fileId, $stat);
} else {
if (!$this->validateWrites || $this->objectStore->objectExists($urn)) {
$this->getCache()->move($uploadPath, $path);
// Here we rename
// $this->getCache()->move($uploadPath, $path);
} else {
$this->getCache()->remove($uploadPath);
throw new \Exception("Object not found after writing (urn: $urn, path: $path)", 404);
+2
View File
@@ -1791,6 +1791,8 @@ class View {
* Get a fileinfo object for files that are ignored in the cache (part files)
*/
private function getPartFileInfo(string $path): \OC\Files\FileInfo {
// For S3 we could actually get the file info here already
// $storage->getCache()->get($internalPath);
$mount = $this->getMount($path);
$storage = $mount->getStorage();
$internalPath = $mount->getInternalPath($this->getAbsolutePath($path));
+17 -4
View File
@@ -50,6 +50,7 @@ class PreviewManager implements IPreview {
private IServerContainer $container;
private IBinaryFinder $binaryFinder;
private IMagickSupport $imagickSupport;
private bool $enablePreviews;
public function __construct(
IConfig $config,
@@ -73,6 +74,7 @@ class PreviewManager implements IPreview {
$this->container = $container;
$this->binaryFinder = $binaryFinder;
$this->imagickSupport = $imagickSupport;
$this->enablePreviews = $config->getSystemValueBool('enable_previews', true);
}
/**
@@ -86,7 +88,7 @@ class PreviewManager implements IPreview {
* @return void
*/
public function registerProvider($mimeTypeRegex, \Closure $callable): void {
if (!$this->config->getSystemValueBool('enable_previews', true)) {
if (!$this->enablePreviews) {
return;
}
@@ -101,7 +103,7 @@ class PreviewManager implements IPreview {
* Get all providers
*/
public function getProviders(): array {
if (!$this->config->getSystemValueBool('enable_previews', true)) {
if (!$this->enablePreviews) {
return [];
}
@@ -158,6 +160,7 @@ class PreviewManager implements IPreview {
* @since 11.0.0 - \InvalidArgumentException was added in 12.0.0
*/
public function getPreview(File $file, $width = -1, $height = -1, $crop = false, $mode = IPreview::MODE_FILL, $mimeType = null) {
$this->throwIfPreviewsDisabled();
$previewConcurrency = $this->getGenerator()->getNumConcurrentPreviews('preview_concurrency_all');
$sem = Generator::guardWithSemaphore(Generator::SEMAPHORE_ID_ALL, $previewConcurrency);
try {
@@ -181,6 +184,7 @@ class PreviewManager implements IPreview {
* @since 19.0.0
*/
public function generatePreviews(File $file, array $specifications, $mimeType = null) {
$this->throwIfPreviewsDisabled();
return $this->getGenerator()->generatePreviews($file, $specifications, $mimeType);
}
@@ -191,7 +195,7 @@ class PreviewManager implements IPreview {
* @return boolean
*/
public function isMimeSupported($mimeType = '*') {
if (!$this->config->getSystemValueBool('enable_previews', true)) {
if (!$this->enablePreviews) {
return false;
}
@@ -216,7 +220,7 @@ class PreviewManager implements IPreview {
* Check if a preview can be generated for a file
*/
public function isAvailable(\OCP\Files\FileInfo $file): bool {
if (!$this->config->getSystemValueBool('enable_previews', true)) {
if (!$this->enablePreviews) {
return false;
}
@@ -452,4 +456,13 @@ class PreviewManager implements IPreview {
});
}
}
/**
* @throws NotFoundException if preview generation is disabled
*/
private function throwIfPreviewsDisabled(): void {
if (!$this->enablePreviews) {
throw new NotFoundException('Previews disabled');
}
}
}
+2
View File
@@ -102,6 +102,8 @@ class Repair implements IOutput {
$this->dispatcher->dispatchTyped(new RepairErrorEvent($e->getMessage()));
}
}
$this->repairSteps = [];
}
/**
+113 -59
View File
@@ -5,13 +5,9 @@
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
* SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OC\Share20;
use OC\Files\Cache\Cache;
use OC\Files\Cache\CachedFileAccess;
use OC\Files\Cache\CacheEntry;
use OC\Files\Cache\FileAccess;
use OC\Share20\Exception\BackendError;
use OC\Share20\Exception\InvalidShare;
use OC\Share20\Exception\ProviderException;
@@ -45,21 +41,52 @@ class DefaultShareProvider implements IShareProvider {
// Special share type for user modified group shares
public const SHARE_TYPE_USERGROUP = 2;
private IDBConnection $dbConn;
/** @var IDBConnection */
private $dbConn;
/** @var IUserManager */
private $userManager;
/** @var IGroupManager */
private $groupManager;
/** @var IRootFolder */
private $rootFolder;
/** @var IMailer */
private $mailer;
/** @var Defaults */
private $defaults;
/** @var IFactory */
private $l10nFactory;
/** @var IURLGenerator */
private $urlGenerator;
private ITimeFactory $timeFactory;
public function __construct(
IDBConnection $connection,
private IUserManager $userManager,
private IGroupManager $groupManager,
private IRootFolder $rootFolder,
private IMailer $mailer,
private Defaults $defaults,
private IFactory $l10nFactory,
private IURLGenerator $urlGenerator,
private ITimeFactory $timeFactory,
private CachedFileAccess $cacheAccess,
IDBConnection $connection,
IUserManager $userManager,
IGroupManager $groupManager,
IRootFolder $rootFolder,
IMailer $mailer,
Defaults $defaults,
IFactory $l10nFactory,
IURLGenerator $urlGenerator,
ITimeFactory $timeFactory,
) {
$this->dbConn = $connection;
$this->userManager = $userManager;
$this->groupManager = $groupManager;
$this->rootFolder = $rootFolder;
$this->mailer = $mailer;
$this->defaults = $defaults;
$this->l10nFactory = $l10nFactory;
$this->urlGenerator = $urlGenerator;
$this->timeFactory = $timeFactory;
}
/**
@@ -604,7 +631,10 @@ class DefaultShareProvider implements IShareProvider {
}
$qb = $this->dbConn->getQueryBuilder();
$qb->select('s.*')
$qb->select('s.*',
'f.fileid', 'f.path', 'f.permissions AS f_permissions', 'f.storage', 'f.path_hash',
'f.parent AS f_parent', 'f.name', 'f.mimetype', 'f.mimepart', 'f.size', 'f.mtime', 'f.storage_mtime',
'f.encrypted', 'f.unencrypted_size', 'f.etag', 'f.checksum')
->from('share', 's')
->andWhere($qb->expr()->orX(
$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
@@ -631,17 +661,27 @@ class DefaultShareProvider implements IShareProvider {
);
}
$childFileIds = array_map(function (Node $node): int {
// todo? maybe get these from the oc_mounts table
$childMountNodes = array_filter($node->getDirectoryListing(), function (Node $node): bool {
return $node->getInternalPath() === '';
});
$childMountRootIds = array_map(function (Node $node): int {
return $node->getId();
}, $node->getDirectoryListing());
}, $childMountNodes);
$qb->andWhere($qb->expr()->in('s.file_source', $qb->createParameter('chunk')));
$qb->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
$qb->andWhere(
$qb->expr()->orX(
$qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())),
$qb->expr()->in('f.fileid', $qb->createParameter('chunk'))
)
);
$qb->orderBy('id');
$shares = [];
$chunks = array_chunk($childFileIds, 1000);
$chunks = array_chunk($childMountRootIds, 1000);
// Force the request to be run when there is 0 mount.
if (count($chunks) === 0) {
@@ -652,7 +692,7 @@ class DefaultShareProvider implements IShareProvider {
$qb->setParameter('chunk', $chunk, IQueryBuilder::PARAM_INT_ARRAY);
$cursor = $qb->executeQuery();
while ($data = $cursor->fetch()) {
$shares[$data['file_source']][] = $this->createShare($data);
$shares[$data['fileid']][] = $this->createShare($data);
}
$cursor->closeCursor();
}
@@ -751,7 +791,7 @@ class DefaultShareProvider implements IShareProvider {
// If the recipient is set for a group share resolve to that user
if ($recipientId !== null && $share->getShareType() === IShare::TYPE_GROUP) {
$share = $this->resolveGroupShares([(int)$share->getId() => $share], $recipientId)[0];
$share = $this->resolveGroupShares([(int) $share->getId() => $share], $recipientId)[0];
}
return $share;
@@ -794,9 +834,25 @@ class DefaultShareProvider implements IShareProvider {
* Returns whether the given database result can be interpreted as
* a share with accessible file (not trashed, not deleted)
*/
private function isAccessibleResult(CacheEntry $data) {
$path = $data->getPath();
return !(str_starts_with($path, 'files_trashbin/') || str_starts_with($path, '__groupfolders/trash/'));
private function isAccessibleResult($data) {
// exclude shares leading to deleted file entries
if ($data['fileid'] === null || $data['path'] === null) {
return false;
}
// exclude shares leading to trashbin on home storages
$pathSections = explode('/', $data['path'], 2);
// FIXME: would not detect rare md5'd home storage case properly
if ($pathSections[0] !== 'files'
&& (str_starts_with($data['storage_string_id'], 'home::') || str_starts_with($data['storage_string_id'], 'object::user'))) {
return false;
} elseif ($pathSections[0] === '__groupfolders'
&& str_starts_with($pathSections[1], 'trash/')
) {
// exclude shares leading to trashbin on group folders storages
return false;
}
return true;
}
/**
@@ -809,8 +865,15 @@ class DefaultShareProvider implements IShareProvider {
if ($shareType === IShare::TYPE_USER) {
//Get shares directly with this user
$qb = $this->dbConn->getQueryBuilder();
$qb->select('s.*')
->from('share', 's');
$qb->select('s.*',
'f.fileid', 'f.path', 'f.permissions AS f_permissions', 'f.storage', 'f.path_hash',
'f.parent AS f_parent', 'f.name', 'f.mimetype', 'f.mimepart', 'f.size', 'f.mtime', 'f.storage_mtime',
'f.encrypted', 'f.unencrypted_size', 'f.etag', 'f.checksum'
)
->selectAlias('st.id', 'storage_string_id')
->from('share', 's')
->leftJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'))
->leftJoin('f', 'storages', 'st', $qb->expr()->eq('f.storage', 'st.numeric_id'));
// Order by id
$qb->orderBy('s.id');
@@ -836,7 +899,14 @@ class DefaultShareProvider implements IShareProvider {
$cursor = $qb->execute();
while ($data = $cursor->fetch()) {
$shares[] = $this->createShare($data);
if ($data['fileid'] && $data['path'] === null) {
$data['path'] = (string) $data['path'];
$data['name'] = (string) $data['name'];
$data['checksum'] = (string) $data['checksum'];
}
if ($this->isAccessibleResult($data)) {
$shares[] = $this->createShare($data);
}
}
$cursor->closeCursor();
} elseif ($shareType === IShare::TYPE_GROUP) {
@@ -856,8 +926,15 @@ class DefaultShareProvider implements IShareProvider {
}
$qb = $this->dbConn->getQueryBuilder();
$qb->select('s.*')
$qb->select('s.*',
'f.fileid', 'f.path', 'f.permissions AS f_permissions', 'f.storage', 'f.path_hash',
'f.parent AS f_parent', 'f.name', 'f.mimetype', 'f.mimepart', 'f.size', 'f.mtime', 'f.storage_mtime',
'f.encrypted', 'f.unencrypted_size', 'f.etag', 'f.checksum'
)
->selectAlias('st.id', 'storage_string_id')
->from('share', 's')
->leftJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'))
->leftJoin('f', 'storages', 'st', $qb->expr()->eq('f.storage', 'st.numeric_id'))
->orderBy('s.id')
->setFirstResult(0);
@@ -890,8 +967,10 @@ class DefaultShareProvider implements IShareProvider {
continue;
}
$share = $this->createShare($data);
$shares2[$share->getId()] = $share;
if ($this->isAccessibleResult($data)) {
$share = $this->createShare($data);
$shares2[$share->getId()] = $share;
}
}
$cursor->closeCursor();
}
@@ -905,31 +984,7 @@ class DefaultShareProvider implements IShareProvider {
}
return $this->setNodes($shares);
}
/**
* @param IShare[] $shares
* @return IShare[]
*/
private function setNodes(array $shares): array {
$fileIds = array_map(function (IShare $share): int {
return $share->getNodeId();
}, $shares);
$files = $this->cacheAccess->getByFileIds($fileIds);
$sharesWithFiles = [];
foreach ($shares as $share) {
if (isset($files[$share->getNodeId()])) {
$cacheItem = $files[$share->getNodeId()];
if ($this->isAccessibleResult($cacheItem)) {
$share->setNodeCacheEntry($cacheItem);
$sharesWithFiles[] = $share;
}
}
}
return $sharesWithFiles;
return $shares;
}
/**
@@ -1298,15 +1353,14 @@ class DefaultShareProvider implements IShareProvider {
/**
* For each user the path with the fewest slashes is returned
*
* @param array $shares
* @return array
*/
protected function filterSharesOfUser(array $shares) {
// Group shares when the user has a share exception
foreach ($shares as $id => $share) {
$type = (int)$share['share_type'];
$permissions = (int)$share['permissions'];
$type = (int) $share['share_type'];
$permissions = (int) $share['permissions'];
if ($type === IShare::TYPE_USERGROUP) {
unset($shares[$share['parent']]);
+13 -1
View File
@@ -15,12 +15,14 @@ use OCA\FederatedFileSharing\TokenHandler;
use OCA\ShareByMail\Settings\SettingsManager;
use OCA\ShareByMail\ShareByMailProvider;
use OCA\Talk\Share\RoomShareProvider;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Defaults;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Federation\ICloudFederationFactory;
use OCP\Files\IRootFolder;
use OCP\Http\Client\IClientService;
use OCP\IServerContainer;
use OCP\L10N\IFactory;
use OCP\Mail\IMailer;
use OCP\Security\IHasher;
use OCP\Security\ISecureRandom;
@@ -75,7 +77,17 @@ class ProviderFactory implements IProviderFactory {
*/
protected function defaultShareProvider() {
if ($this->defaultProvider === null) {
$this->defaultProvider = $this->serverContainer->get(DefaultShareProvider::class);
$this->defaultProvider = new DefaultShareProvider(
$this->serverContainer->getDatabaseConnection(),
$this->serverContainer->getUserManager(),
$this->serverContainer->getGroupManager(),
$this->serverContainer->get(IRootFolder::class),
$this->serverContainer->get(IMailer::class),
$this->serverContainer->query(Defaults::class),
$this->serverContainer->get(IFactory::class),
$this->serverContainer->getURLGenerator(),
$this->serverContainer->query(ITimeFactory::class),
);
}
return $this->defaultProvider;
+5 -3
View File
@@ -19,8 +19,10 @@ use OCP\App\ManagerEvent;
use OCP\Authentication\IAlternativeLogin;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IAppConfig;
use OCP\Server;
use Psr\Container\ContainerExceptionInterface;
use Psr\Log\LoggerInterface;
use function OCP\Log\logger;
/**
* This class manages the apps. It allows them to register and integrate in the
@@ -777,16 +779,16 @@ class OC_App {
// load the app
self::loadApp($appId);
$dispatcher = \OC::$server->get(IEventDispatcher::class);
$dispatcher = Server::get(IEventDispatcher::class);
// load the steps
$r = \OCP\Server::get(Repair::class);
$r = Server::get(Repair::class);
foreach ($steps as $step) {
try {
$r->addStep($step);
} catch (Exception $ex) {
$dispatcher->dispatchTyped(new RepairErrorEvent($ex->getMessage()));
\OC::$server->getLogger()->logException($ex);
logger('core')->error('Failed to add app migration step ' . $step, ['exception' => $ex]);
}
}
// run the steps
-8
View File
@@ -161,12 +161,4 @@ interface ICacheEntry extends ArrayAccess {
* @since 25.0.0
*/
public function getUnencryptedSize(): int;
/**
* Get the cache data as array
*
* @return array
* @since 30.0.0
*/
public function getData(): array;
}
+14 -5
View File
@@ -25,7 +25,9 @@ use Test\TestCase;
* @package Test\Route
*/
class RouterTest extends TestCase {
public function testGenerateConsecutively(): void {
private Router $router;
protected function setUp(): void {
parent::setUp();
/** @var LoggerInterface $logger */
$logger = $this->createMock(LoggerInterface::class);
$logger->method('info')
@@ -34,7 +36,7 @@ class RouterTest extends TestCase {
$this->fail('Unexpected info log: '.(string)($data['exception'] ?? $message));
}
);
$router = new Router(
$this->router = new Router(
$logger,
$this->createMock(IRequest::class),
$this->createMock(IConfig::class),
@@ -42,13 +44,20 @@ class RouterTest extends TestCase {
$this->createMock(ContainerInterface::class),
$this->createMock(IAppManager::class),
);
}
$this->assertEquals('/index.php/apps/files/', $router->generate('files.view.index'));
public function testHeartbeat(): void {
$this->assertEquals('/index.php/heartbeat', $this->router->generate('heartbeat'));
}
public function testGenerateConsecutively(): void {
$this->assertEquals('/index.php/apps/files/', $this->router->generate('files.view.index'));
// the OCS route is the prefixed one for the AppFramework - see /ocs/v1.php for routing details
$this->assertEquals('/index.php/ocsapp/apps/dav/api/v1/direct', $router->generate('ocs.dav.direct.getUrl'));
$this->assertEquals('/index.php/ocsapp/apps/dav/api/v1/direct', $this->router->generate('ocs.dav.direct.getUrl'));
// test caching
$this->assertEquals('/index.php/apps/files/', $router->generate('files.view.index'));
$this->assertEquals('/index.php/apps/files/', $this->router->generate('files.view.index'));
}
}
+19 -49
View File
@@ -7,8 +7,6 @@
namespace Test\Share20;
use OC\Files\Cache\CacheEntry;
use OC\Files\Cache\FileAccess;
use OC\Share20\DefaultShareProvider;
use OC\Share20\ShareAttributes;
use OCP\AppFramework\Utility\ITimeFactory;
@@ -70,11 +68,6 @@ class DefaultShareProviderTest extends \Test\TestCase {
/** @var ITimeFactory|MockObject */
protected $timeFactory;
/** @var FileAccess|MockObject */
protected $cacheAccess;
/** @var array<int, CacheEntry> */
protected $cacheItems = [];
protected function setUp(): void {
$this->dbConn = \OC::$server->getDatabaseConnection();
$this->userManager = $this->createMock(IUserManager::class);
@@ -86,26 +79,6 @@ class DefaultShareProviderTest extends \Test\TestCase {
$this->defaults = $this->getMockBuilder(Defaults::class)->disableOriginalConstructor()->getMock();
$this->urlGenerator = $this->createMock(IURLGenerator::class);
$this->timeFactory = $this->createMock(ITimeFactory::class);
$this->cacheAccess = $this->createMock(FileAccess::class);
$this->cacheItems = [];
$this->cacheAccess->method('getByFileIds')->willReturnCallback(function (array $fileIds) {
$result = [];
foreach ($fileIds as $fileId) {
if (isset($this->cacheItems[$fileId])) {
$result[$fileId] = $this->cacheItems[$fileId];
}
}
return $result;
});
$this->cacheAccess->method('getByFileIdsInStorage')->willReturnCallback(function (array $fileIds, int $storageId) {
$result = [];
foreach ($fileIds as $fileId) {
if (isset($this->cacheItems[$fileId]) && $this->cacheItems[$fileId]->getStorageId() === $storageId) {
$result[$fileId] = $this->cacheItems[$fileId];
}
}
return $result;
});
$this->userManager->expects($this->any())->method('userExists')->willReturn(true);
$this->timeFactory->expects($this->any())->method('now')->willReturn(new \DateTimeImmutable("2023-05-04 00:00 Europe/Berlin"));
@@ -122,13 +95,13 @@ class DefaultShareProviderTest extends \Test\TestCase {
$this->defaults,
$this->l10nFactory,
$this->urlGenerator,
$this->timeFactory,
$this->cacheAccess,
$this->timeFactory
);
}
protected function tearDown(): void {
$this->dbConn->getQueryBuilder()->delete('share')->execute();
$this->dbConn->getQueryBuilder()->delete('filecache')->execute();
$this->dbConn->getQueryBuilder()->delete('storages')->execute();
}
@@ -483,8 +456,7 @@ class DefaultShareProviderTest extends \Test\TestCase {
$this->defaults,
$this->l10nFactory,
$this->urlGenerator,
$this->timeFactory,
$this->cacheAccess,
$this->timeFactory
])
->setMethods(['getShareById'])
->getMock();
@@ -579,8 +551,7 @@ class DefaultShareProviderTest extends \Test\TestCase {
$this->defaults,
$this->l10nFactory,
$this->urlGenerator,
$this->timeFactory,
$this->cacheAccess,
$this->timeFactory
])
->setMethods(['getShareById'])
->getMock();
@@ -935,15 +906,16 @@ class DefaultShareProviderTest extends \Test\TestCase {
}
private function createTestFileEntry($path, $storage = 1) {
$id = count($this->cacheItems);
$this->cacheItems[$id] = new CacheEntry([
'fileid' => $id,
'storage' => $storage,
'path' => $path,
'path_hash' => md5($path),
'name' => basename($path),
]);
return $id;
$qb = $this->dbConn->getQueryBuilder();
$qb->insert('filecache')
->values([
'storage' => $qb->expr()->literal($storage),
'path' => $qb->expr()->literal($path),
'path_hash' => $qb->expr()->literal(md5($path)),
'name' => $qb->expr()->literal(basename($path)),
]);
$this->assertEquals(1, $qb->execute());
return $qb->getLastInsertId();
}
public function storageAndFileNameProvider() {
@@ -952,6 +924,8 @@ class DefaultShareProviderTest extends \Test\TestCase {
['home::shareOwner', 'files/test.txt', 'files/test2.txt'],
// regular file on external storage
['smb::whatever', 'files/test.txt', 'files/test2.txt'],
// regular file on external storage in trashbin-like folder,
['smb::whatever', 'files_trashbin/files/test.txt', 'files_trashbin/files/test2.txt'],
];
}
@@ -1305,7 +1279,6 @@ class DefaultShareProviderTest extends \Test\TestCase {
$user = $this->createMock(IUser::class);
$user->method('getUID')->willReturn('sharedWith');
$user->method('getDisplayName')->willReturn('sharedWith');
$owner = $this->createMock(IUser::class);
$owner->method('getUID')->willReturn('shareOwner');
$initiator = $this->createMock(IUser::class);
@@ -2546,8 +2519,7 @@ class DefaultShareProviderTest extends \Test\TestCase {
$this->defaults,
$this->l10nFactory,
$this->urlGenerator,
$this->timeFactory,
$this->cacheAccess,
$this->timeFactory
);
$password = md5(time());
@@ -2645,8 +2617,7 @@ class DefaultShareProviderTest extends \Test\TestCase {
$this->defaults,
$this->l10nFactory,
$this->urlGenerator,
$this->timeFactory,
$this->cacheAccess,
$this->timeFactory
);
$u1 = $userManager->createUser('testShare1', 'test');
@@ -2742,8 +2713,7 @@ class DefaultShareProviderTest extends \Test\TestCase {
$this->defaults,
$this->l10nFactory,
$this->urlGenerator,
$this->timeFactory,
$this->cacheAccess,
$this->timeFactory
);
$u1 = $userManager->createUser('testShare1', 'test');