migrate therinaldos.com data
Build & Deploy to DigitalOcean Space / build (push) Failing after 2m38s

This commit is contained in:
2024-05-05 15:50:45 -04:00
commit ef1ff240d4
23182 changed files with 3801898 additions and 0 deletions
@@ -0,0 +1,408 @@
<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author Felix Nüsse <Felix.nuesse@t-online.de>
* @author fnuesse <felix.nuesse@t-online.de>
* @author fnuesse <fnuesse@techfak.uni-bielefeld.de>
* @author Joas Schilling <coding@schilljs.com>
* @author John Molakvoæ <skjnldsv@protonmail.com>
* @author Julius Härtl <jus@bitgrid.net>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Max Kovalenko <mxss1998@yandex.ru>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Nina Pypchenko <22447785+nina-py@users.noreply.github.com>
* @author Richard Steinmetz <richard@steinmetz.cloud>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Tobias Kaminsky <tobias@kaminsky.me>
* @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Files\Controller;
use OC\Files\Node\Node;
use OCA\Files\Service\TagService;
use OCA\Files\Service\UserConfig;
use OCA\Files\Service\ViewConfig;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\OpenAPI;
use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Http\FileDisplayResponse;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Http\StreamResponse;
use OCP\Files\File;
use OCP\Files\Folder;
use OCP\Files\NotFoundException;
use OCP\IConfig;
use OCP\IPreview;
use OCP\IRequest;
use OCP\IUserSession;
use OCP\Share\IManager;
use OCP\Share\IShare;
/**
* @package OCA\Files\Controller
*/
class ApiController extends Controller {
private TagService $tagService;
private IManager $shareManager;
private IPreview $previewManager;
private IUserSession $userSession;
private IConfig $config;
private ?Folder $userFolder;
private UserConfig $userConfig;
private ViewConfig $viewConfig;
public function __construct(string $appName,
IRequest $request,
IUserSession $userSession,
TagService $tagService,
IPreview $previewManager,
IManager $shareManager,
IConfig $config,
?Folder $userFolder,
UserConfig $userConfig,
ViewConfig $viewConfig) {
parent::__construct($appName, $request);
$this->userSession = $userSession;
$this->tagService = $tagService;
$this->previewManager = $previewManager;
$this->shareManager = $shareManager;
$this->config = $config;
$this->userFolder = $userFolder;
$this->userConfig = $userConfig;
$this->viewConfig = $viewConfig;
}
/**
* Gets a thumbnail of the specified file
*
* @since API version 1.0
*
* @NoAdminRequired
* @NoCSRFRequired
* @StrictCookieRequired
*
* @param int $x Width of the thumbnail
* @param int $y Height of the thumbnail
* @param string $file URL-encoded filename
* @return FileDisplayResponse<Http::STATUS_OK, array{Content-Type: string}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_NOT_FOUND, array{message?: string}, array{}>
*
* 200: Thumbnail returned
* 400: Getting thumbnail is not possible
* 404: File not found
*/
public function getThumbnail($x, $y, $file) {
if ($x < 1 || $y < 1) {
return new DataResponse(['message' => 'Requested size must be numeric and a positive value.'], Http::STATUS_BAD_REQUEST);
}
try {
$file = $this->userFolder->get($file);
if ($file instanceof Folder) {
throw new NotFoundException();
}
/** @var File $file */
$preview = $this->previewManager->getPreview($file, $x, $y, true);
return new FileDisplayResponse($preview, Http::STATUS_OK, ['Content-Type' => $preview->getMimeType()]);
} catch (NotFoundException $e) {
return new DataResponse(['message' => 'File not found.'], Http::STATUS_NOT_FOUND);
} catch (\Exception $e) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
}
/**
* Updates the info of the specified file path
* The passed tags are absolute, which means they will
* replace the actual tag selection.
*
* @NoAdminRequired
*
* @param string $path path
* @param array|string $tags array of tags
* @return DataResponse
*/
public function updateFileTags($path, $tags = null) {
$result = [];
// if tags specified or empty array, update tags
if (!is_null($tags)) {
try {
$this->tagService->updateFileTags($path, $tags);
} catch (\OCP\Files\NotFoundException $e) {
return new DataResponse([
'message' => $e->getMessage()
], Http::STATUS_NOT_FOUND);
} catch (\OCP\Files\StorageNotAvailableException $e) {
return new DataResponse([
'message' => $e->getMessage()
], Http::STATUS_SERVICE_UNAVAILABLE);
} catch (\Exception $e) {
return new DataResponse([
'message' => $e->getMessage()
], Http::STATUS_NOT_FOUND);
}
$result['tags'] = $tags;
}
return new DataResponse($result);
}
/**
* @param \OCP\Files\Node[] $nodes
* @return array
*/
private function formatNodes(array $nodes) {
$shareTypesForNodes = $this->getShareTypesForNodes($nodes);
return array_values(array_map(function (Node $node) use ($shareTypesForNodes) {
$shareTypes = $shareTypesForNodes[$node->getId()] ?? [];
$file = \OCA\Files\Helper::formatFileInfo($node->getFileInfo());
$file['hasPreview'] = $this->previewManager->isAvailable($node);
$parts = explode('/', dirname($node->getPath()), 4);
if (isset($parts[3])) {
$file['path'] = '/' . $parts[3];
} else {
$file['path'] = '/';
}
if (!empty($shareTypes)) {
$file['shareTypes'] = $shareTypes;
}
return $file;
}, $nodes));
}
/**
* Get the share types for each node
*
* @param \OCP\Files\Node[] $nodes
* @return array<int, int[]> list of share types for each fileid
*/
private function getShareTypesForNodes(array $nodes): array {
$userId = $this->userSession->getUser()->getUID();
$requestedShareTypes = [
IShare::TYPE_USER,
IShare::TYPE_GROUP,
IShare::TYPE_LINK,
IShare::TYPE_REMOTE,
IShare::TYPE_EMAIL,
IShare::TYPE_ROOM,
IShare::TYPE_DECK,
IShare::TYPE_SCIENCEMESH,
];
$shareTypes = [];
$nodeIds = array_map(function (Node $node) {
return $node->getId();
}, $nodes);
foreach ($requestedShareTypes as $shareType) {
$nodesLeft = array_combine($nodeIds, array_fill(0, count($nodeIds), true));
$offset = 0;
// fetch shares until we've either found shares for all nodes or there are no more shares left
while (count($nodesLeft) > 0) {
$shares = $this->shareManager->getSharesBy($userId, $shareType, null, false, 100, $offset);
foreach ($shares as $share) {
$fileId = $share->getNodeId();
if (isset($nodesLeft[$fileId])) {
if (!isset($shareTypes[$fileId])) {
$shareTypes[$fileId] = [];
}
$shareTypes[$fileId][] = $shareType;
unset($nodesLeft[$fileId]);
}
}
if (count($shares) < 100) {
break;
} else {
$offset += count($shares);
}
}
}
return $shareTypes;
}
/**
* Returns a list of recently modified files.
*
* @NoAdminRequired
*
* @return DataResponse
*/
public function getRecentFiles() {
$nodes = $this->userFolder->getRecent(100);
$files = $this->formatNodes($nodes);
return new DataResponse(['files' => $files]);
}
/**
* Returns the current logged-in user's storage stats.
*
* @NoAdminRequired
*
* @param ?string $dir the directory to get the storage stats from
* @return JSONResponse
*/
public function getStorageStats($dir = '/'): JSONResponse {
$storageInfo = \OC_Helper::getStorageInfo($dir ?: '/');
return new JSONResponse(['message' => 'ok', 'data' => $storageInfo]);
}
/**
* Set a user view config
*
* @NoAdminRequired
*
* @param string $view
* @param string $key
* @param string|bool $value
* @return JSONResponse
*/
public function setViewConfig(string $view, string $key, $value): JSONResponse {
try {
$this->viewConfig->setConfig($view, $key, (string)$value);
} catch (\InvalidArgumentException $e) {
return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_BAD_REQUEST);
}
return new JSONResponse(['message' => 'ok', 'data' => $this->viewConfig->getConfig($view)]);
}
/**
* Get the user view config
*
* @NoAdminRequired
*
* @return JSONResponse
*/
public function getViewConfigs(): JSONResponse {
return new JSONResponse(['message' => 'ok', 'data' => $this->viewConfig->getConfigs()]);
}
/**
* Set a user config
*
* @NoAdminRequired
*
* @param string $key
* @param string|bool $value
* @return JSONResponse
*/
public function setConfig(string $key, $value): JSONResponse {
try {
$this->userConfig->setConfig($key, (string)$value);
} catch (\InvalidArgumentException $e) {
return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_BAD_REQUEST);
}
return new JSONResponse(['message' => 'ok', 'data' => ['key' => $key, 'value' => $value]]);
}
/**
* Get the user config
*
* @NoAdminRequired
*
* @return JSONResponse
*/
public function getConfigs(): JSONResponse {
return new JSONResponse(['message' => 'ok', 'data' => $this->userConfig->getConfigs()]);
}
/**
* Toggle default for showing/hiding hidden files
*
* @NoAdminRequired
*
* @param bool $value
* @return Response
* @throws \OCP\PreConditionNotMetException
*/
public function showHiddenFiles(bool $value): Response {
$this->config->setUserValue($this->userSession->getUser()->getUID(), 'files', 'show_hidden', $value ? '1' : '0');
return new Response();
}
/**
* Toggle default for cropping preview images
*
* @NoAdminRequired
*
* @param bool $value
* @return Response
* @throws \OCP\PreConditionNotMetException
*/
public function cropImagePreviews(bool $value): Response {
$this->config->setUserValue($this->userSession->getUser()->getUID(), 'files', 'crop_image_previews', $value ? '1' : '0');
return new Response();
}
/**
* Toggle default for files grid view
*
* @NoAdminRequired
*
* @param bool $show
* @return Response
* @throws \OCP\PreConditionNotMetException
*/
public function showGridView(bool $show): Response {
$this->config->setUserValue($this->userSession->getUser()->getUID(), 'files', 'show_grid', $show ? '1' : '0');
return new Response();
}
/**
* Get default settings for the grid view
*
* @NoAdminRequired
*/
public function getGridView() {
$status = $this->config->getUserValue($this->userSession->getUser()->getUID(), 'files', 'show_grid', '0') === '1';
return new JSONResponse(['gridview' => $status]);
}
/**
* @NoAdminRequired
* @NoCSRFRequired
* @PublicPage
*/
#[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]
public function serviceWorker(): StreamResponse {
$response = new StreamResponse(__DIR__ . '/../../../../dist/preview-service-worker.js');
$response->setHeaders([
'Content-Type' => 'application/javascript',
'Service-Worker-Allowed' => '/'
]);
$policy = new ContentSecurityPolicy();
$policy->addAllowedWorkerSrcDomain("'self'");
$policy->addAllowedScriptDomain("'self'");
$policy->addAllowedConnectDomain("'self'");
$response->setContentSecurityPolicy($policy);
return $response;
}
}
@@ -0,0 +1,172 @@
<?php
/**
* @copyright Copyright (c) 2019 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
*
* @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 OCA\Files\Controller;
use Exception;
use OCA\Files\Service\DirectEditingService;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\DirectEditing\IManager;
use OCP\DirectEditing\RegisterDirectEditorEvent;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IRequest;
use OCP\IURLGenerator;
use Psr\Log\LoggerInterface;
class DirectEditingController extends OCSController {
public function __construct(
string $appName,
IRequest $request,
string $corsMethods,
string $corsAllowedHeaders,
int $corsMaxAge,
private IEventDispatcher $eventDispatcher,
private IURLGenerator $urlGenerator,
private IManager $directEditingManager,
private DirectEditingService $directEditingService,
private LoggerInterface $logger
) {
parent::__construct($appName, $request, $corsMethods, $corsAllowedHeaders, $corsMaxAge);
}
/**
* @NoAdminRequired
*
* Get the direct editing capabilities
* @return DataResponse<Http::STATUS_OK, array{editors: array<string, array{id: string, name: string, mimetypes: string[], optionalMimetypes: string[], secure: bool}>, creators: array<string, array{id: string, editor: string, name: string, extension: string, templates: bool, mimetypes: string[]}>}, array{}>
*
* 200: Direct editing capabilities returned
*/
public function info(): DataResponse {
$response = new DataResponse($this->directEditingService->getDirectEditingCapabilitites());
$response->setETag($this->directEditingService->getDirectEditingETag());
return $response;
}
/**
* @NoAdminRequired
*
* Create a file for direct editing
*
* @param string $path Path of the file
* @param string $editorId ID of the editor
* @param string $creatorId ID of the creator
* @param ?string $templateId ID of the template
*
* @return DataResponse<Http::STATUS_OK, array{url: string}, array{}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_INTERNAL_SERVER_ERROR, array{message: string}, array{}>
*
* 200: URL for direct editing returned
* 403: Opening file is not allowed
*/
public function create(string $path, string $editorId, string $creatorId, string $templateId = null): DataResponse {
if (!$this->directEditingManager->isEnabled()) {
return new DataResponse(['message' => 'Direct editing is not enabled'], Http::STATUS_INTERNAL_SERVER_ERROR);
}
$this->eventDispatcher->dispatchTyped(new RegisterDirectEditorEvent($this->directEditingManager));
try {
$token = $this->directEditingManager->create($path, $editorId, $creatorId, $templateId);
return new DataResponse([
'url' => $this->urlGenerator->linkToRouteAbsolute('files.DirectEditingView.edit', ['token' => $token])
]);
} catch (Exception $e) {
$this->logger->error(
'Exception when creating a new file through direct editing',
[
'exception' => $e
],
);
return new DataResponse(['message' => 'Failed to create file: ' . $e->getMessage()], Http::STATUS_FORBIDDEN);
}
}
/**
* @NoAdminRequired
*
* Open a file for direct editing
*
* @param string $path Path of the file
* @param ?string $editorId ID of the editor
* @param ?int $fileId ID of the file
*
* @return DataResponse<Http::STATUS_OK, array{url: string}, array{}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_INTERNAL_SERVER_ERROR, array{message: string}, array{}>
*
* 200: URL for direct editing returned
* 403: Opening file is not allowed
*/
public function open(string $path, string $editorId = null, ?int $fileId = null): DataResponse {
if (!$this->directEditingManager->isEnabled()) {
return new DataResponse(['message' => 'Direct editing is not enabled'], Http::STATUS_INTERNAL_SERVER_ERROR);
}
$this->eventDispatcher->dispatchTyped(new RegisterDirectEditorEvent($this->directEditingManager));
try {
$token = $this->directEditingManager->open($path, $editorId, $fileId);
return new DataResponse([
'url' => $this->urlGenerator->linkToRouteAbsolute('files.DirectEditingView.edit', ['token' => $token])
]);
} catch (Exception $e) {
$this->logger->error(
'Exception when opening a file through direct editing',
[
'exception' => $e
],
);
return new DataResponse(['message' => 'Failed to open file: ' . $e->getMessage()], Http::STATUS_FORBIDDEN);
}
}
/**
* @NoAdminRequired
*
* Get the templates for direct editing
*
* @param string $editorId ID of the editor
* @param string $creatorId ID of the creator
*
* @return DataResponse<Http::STATUS_OK, array{templates: array<string, array{id: string, title: string, preview: ?string, extension: string, mimetype: string}>}, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR, array{message: string}, array{}>
*
* 200: Templates returned
*/
public function templates(string $editorId, string $creatorId): DataResponse {
if (!$this->directEditingManager->isEnabled()) {
return new DataResponse(['message' => 'Direct editing is not enabled'], Http::STATUS_INTERNAL_SERVER_ERROR);
}
$this->eventDispatcher->dispatchTyped(new RegisterDirectEditorEvent($this->directEditingManager));
try {
return new DataResponse($this->directEditingManager->getTemplates($editorId, $creatorId));
} catch (Exception $e) {
$this->logger->error(
$e->getMessage(),
[
'exception' => $e
],
);
return new DataResponse(['message' => 'Failed to obtain template list: ' . $e->getMessage()], Http::STATUS_INTERNAL_SERVER_ERROR);
}
}
}
@@ -0,0 +1,65 @@
<?php
/**
* @copyright Copyright (c) 2019 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
*
* @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 OCA\Files\Controller;
use Exception;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\OpenAPI;
use OCP\AppFramework\Http\NotFoundResponse;
use OCP\AppFramework\Http\Response;
use OCP\DirectEditing\IManager;
use OCP\DirectEditing\RegisterDirectEditorEvent;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IRequest;
use Psr\Log\LoggerInterface;
#[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]
class DirectEditingViewController extends Controller {
public function __construct(
$appName,
IRequest $request,
private IEventDispatcher $eventDispatcher,
private IManager $directEditingManager,
private LoggerInterface $logger,
) {
parent::__construct($appName, $request);
}
/**
* @PublicPage
* @NoCSRFRequired
* @UseSession
*
* @param string $token
* @return Response
*/
public function edit(string $token): Response {
$this->eventDispatcher->dispatchTyped(new RegisterDirectEditorEvent($this->directEditingManager));
try {
return $this->directEditingManager->edit($token);
} catch (Exception $e) {
$this->logger->error($e->getMessage(), ['exception' => $e]);
return new NotFoundResponse();
}
}
}
@@ -0,0 +1,156 @@
<?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 OCA\Files\Controller;
use OCA\Files\Db\OpenLocalEditor;
use OCA\Files\Db\OpenLocalEditorMapper;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\DB\Exception;
use OCP\IRequest;
use OCP\Security\ISecureRandom;
use Psr\Log\LoggerInterface;
class OpenLocalEditorController extends OCSController {
public const TOKEN_LENGTH = 128;
public const TOKEN_DURATION = 600; // 10 Minutes
public const TOKEN_RETRIES = 50;
protected ITimeFactory $timeFactory;
protected OpenLocalEditorMapper $mapper;
protected ISecureRandom $secureRandom;
protected LoggerInterface $logger;
protected ?string $userId;
public function __construct(
string $appName,
IRequest $request,
ITimeFactory $timeFactory,
OpenLocalEditorMapper $mapper,
ISecureRandom $secureRandom,
LoggerInterface $logger,
?string $userId
) {
parent::__construct($appName, $request);
$this->timeFactory = $timeFactory;
$this->mapper = $mapper;
$this->secureRandom = $secureRandom;
$this->logger = $logger;
$this->userId = $userId;
}
/**
* @NoAdminRequired
* @UserRateThrottle(limit=10, period=120)
*
* Create a local editor
*
* @param string $path Path of the file
*
* @return DataResponse<Http::STATUS_OK, array{userId: ?string, pathHash: string, expirationTime: int, token: string}, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR, array<empty>, array{}>
*
* 200: Local editor returned
*/
public function create(string $path): DataResponse {
$pathHash = sha1($path);
$entity = new OpenLocalEditor();
$entity->setUserId($this->userId);
$entity->setPathHash($pathHash);
$entity->setExpirationTime($this->timeFactory->getTime() + self::TOKEN_DURATION); // Expire in 10 minutes
for ($i = 1; $i <= self::TOKEN_RETRIES; $i++) {
$token = $this->secureRandom->generate(self::TOKEN_LENGTH, ISecureRandom::CHAR_ALPHANUMERIC);
$entity->setToken($token);
try {
$this->mapper->insert($entity);
return new DataResponse([
'userId' => $this->userId,
'pathHash' => $pathHash,
'expirationTime' => $entity->getExpirationTime(),
'token' => $entity->getToken(),
]);
} catch (Exception $e) {
if ($e->getCode() !== Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) {
// Only retry on unique constraint violation
throw $e;
}
}
}
$this->logger->error('Giving up after ' . self::TOKEN_RETRIES . ' retries to generate a unique local editor token for path hash: ' . $pathHash);
return new DataResponse([], Http::STATUS_INTERNAL_SERVER_ERROR);
}
/**
* @NoAdminRequired
* @BruteForceProtection(action=openLocalEditor)
*
* Validate a local editor
*
* @param string $path Path of the file
* @param string $token Token of the local editor
*
* @return DataResponse<Http::STATUS_OK, array{userId: string, pathHash: string, expirationTime: int, token: string}, array{}>|DataResponse<Http::STATUS_NOT_FOUND, array<empty>, array{}>
*
* 200: Local editor validated successfully
* 404: Local editor not found
*/
public function validate(string $path, string $token): DataResponse {
$pathHash = sha1($path);
try {
$entity = $this->mapper->verifyToken($this->userId, $pathHash, $token);
} catch (DoesNotExistException $e) {
$response = new DataResponse([], Http::STATUS_NOT_FOUND);
$response->throttle(['userId' => $this->userId, 'pathHash' => $pathHash]);
return $response;
}
$this->mapper->delete($entity);
if ($entity->getExpirationTime() <= $this->timeFactory->getTime()) {
$response = new DataResponse([], Http::STATUS_NOT_FOUND);
$response->throttle(['userId' => $this->userId, 'pathHash' => $pathHash]);
return $response;
}
return new DataResponse([
'userId' => $this->userId,
'pathHash' => $pathHash,
'expirationTime' => $entity->getExpirationTime(),
'token' => $entity->getToken(),
]);
}
}
@@ -0,0 +1,111 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2021 Julius Härtl <jus@bitgrid.net>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
* @author Julius Härtl <jus@bitgrid.net>
*
* @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 OCA\Files\Controller;
use OCA\Files\ResponseDefinitions;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSForbiddenException;
use OCP\AppFramework\OCSController;
use OCP\Files\GenericFileException;
use OCP\Files\Template\ITemplateManager;
use OCP\Files\Template\TemplateFileCreator;
use OCP\IRequest;
/**
* @psalm-import-type FilesTemplateFile from ResponseDefinitions
* @psalm-import-type FilesTemplateFileCreator from ResponseDefinitions
*/
class TemplateController extends OCSController {
protected $templateManager;
public function __construct($appName, IRequest $request, ITemplateManager $templateManager) {
parent::__construct($appName, $request);
$this->templateManager = $templateManager;
}
/**
* @NoAdminRequired
*
* List the available templates
*
* @return DataResponse<Http::STATUS_OK, array<FilesTemplateFileCreator>, array{}>
*
* 200: Available templates returned
*/
public function list(): DataResponse {
return new DataResponse($this->templateManager->listTemplates());
}
/**
* @NoAdminRequired
*
* Create a template
*
* @param string $filePath Path of the file
* @param string $templatePath Name of the template
* @param string $templateType Type of the template
*
* @return DataResponse<Http::STATUS_OK, FilesTemplateFile, array{}>
* @throws OCSForbiddenException Creating template is not allowed
*
* 200: Template created successfully
*/
public function create(string $filePath, string $templatePath = '', string $templateType = 'user'): DataResponse {
try {
return new DataResponse($this->templateManager->createFromTemplate($filePath, $templatePath, $templateType));
} catch (GenericFileException $e) {
throw new OCSForbiddenException($e->getMessage());
}
}
/**
* @NoAdminRequired
*
* Initialize the template directory
*
* @param string $templatePath Path of the template directory
* @param bool $copySystemTemplates Whether to copy the system templates to the template directory
*
* @return DataResponse<Http::STATUS_OK, array{template_path: string, templates: FilesTemplateFileCreator[]}, array{}>
* @throws OCSForbiddenException Initializing the template directory is not allowed
*
* 200: Template directory initialized successfully
*/
public function path(string $templatePath = '', bool $copySystemTemplates = false) {
try {
/** @var string $templatePath */
$templatePath = $this->templateManager->initializeTemplateDirectory($templatePath, null, $copySystemTemplates);
return new DataResponse([
'template_path' => $templatePath,
'templates' => array_map(fn (TemplateFileCreator $creator) => $creator->jsonSerialize(), $this->templateManager->listCreators()),
]);
} catch (\Exception $e) {
throw new OCSForbiddenException($e->getMessage());
}
}
}
@@ -0,0 +1,227 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Julius Härtl <jus@bitgrid.net>
* @author Roeland Jago Douma <roeland@famdouma.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 OCA\Files\Controller;
use OCA\Files\BackgroundJob\TransferOwnership;
use OCA\Files\Db\TransferOwnership as TransferOwnershipEntity;
use OCA\Files\Db\TransferOwnershipMapper;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\IJobList;
use OCP\Files\IHomeStorage;
use OCP\Files\IRootFolder;
use OCP\IRequest;
use OCP\IUserManager;
use OCP\Notification\IManager as NotificationManager;
class TransferOwnershipController extends OCSController {
/** @var string */
private $userId;
/** @var NotificationManager */
private $notificationManager;
/** @var ITimeFactory */
private $timeFactory;
/** @var IJobList */
private $jobList;
/** @var TransferOwnershipMapper */
private $mapper;
/** @var IUserManager */
private $userManager;
/** @var IRootFolder */
private $rootFolder;
public function __construct(string $appName,
IRequest $request,
string $userId,
NotificationManager $notificationManager,
ITimeFactory $timeFactory,
IJobList $jobList,
TransferOwnershipMapper $mapper,
IUserManager $userManager,
IRootFolder $rootFolder) {
parent::__construct($appName, $request);
$this->userId = $userId;
$this->notificationManager = $notificationManager;
$this->timeFactory = $timeFactory;
$this->jobList = $jobList;
$this->mapper = $mapper;
$this->userManager = $userManager;
$this->rootFolder = $rootFolder;
}
/**
* @NoAdminRequired
*
* Transfer the ownership to another user
*
* @param string $recipient Username of the recipient
* @param string $path Path of the file
*
* @return DataResponse<Http::STATUS_OK|Http::STATUS_BAD_REQUEST|Http::STATUS_FORBIDDEN, array<empty>, array{}>
*
* 200: Ownership transferred successfully
* 400: Transferring ownership is not possible
* 403: Transferring ownership is not allowed
*/
public function transfer(string $recipient, string $path): DataResponse {
$recipientUser = $this->userManager->get($recipient);
if ($recipientUser === null) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
$userRoot = $this->rootFolder->getUserFolder($this->userId);
try {
$node = $userRoot->get($path);
} catch (\Exception $e) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
if ($node->getOwner()->getUID() !== $this->userId || !$node->getStorage()->instanceOfStorage(IHomeStorage::class)) {
return new DataResponse([], Http::STATUS_FORBIDDEN);
}
$transferOwnership = new TransferOwnershipEntity();
$transferOwnership->setSourceUser($this->userId);
$transferOwnership->setTargetUser($recipient);
$transferOwnership->setFileId($node->getId());
$transferOwnership->setNodeName($node->getName());
$transferOwnership = $this->mapper->insert($transferOwnership);
$notification = $this->notificationManager->createNotification();
$notification->setUser($recipient)
->setApp($this->appName)
->setDateTime($this->timeFactory->getDateTime())
->setSubject('transferownershipRequest', [
'sourceUser' => $this->userId,
'targetUser' => $recipient,
'nodeName' => $node->getName(),
])
->setObject('transfer', (string)$transferOwnership->getId());
$this->notificationManager->notify($notification);
return new DataResponse([]);
}
/**
* @NoAdminRequired
*
* Accept an ownership transfer
*
* @param int $id ID of the ownership transfer
*
* @return DataResponse<Http::STATUS_OK|Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, array<empty>, array{}>
*
* 200: Ownership transfer accepted successfully
* 403: Accepting ownership transfer is not allowed
* 404: Ownership transfer not found
*/
public function accept(int $id): DataResponse {
try {
$transferOwnership = $this->mapper->getById($id);
} catch (DoesNotExistException $e) {
return new DataResponse([], Http::STATUS_NOT_FOUND);
}
if ($transferOwnership->getTargetUser() !== $this->userId) {
return new DataResponse([], Http::STATUS_FORBIDDEN);
}
$notification = $this->notificationManager->createNotification();
$notification->setApp('files')
->setObject('transfer', (string)$id);
$this->notificationManager->markProcessed($notification);
$newTransferOwnership = new TransferOwnershipEntity();
$newTransferOwnership->setNodeName($transferOwnership->getNodeName());
$newTransferOwnership->setFileId($transferOwnership->getFileId());
$newTransferOwnership->setSourceUser($transferOwnership->getSourceUser());
$newTransferOwnership->setTargetUser($transferOwnership->getTargetUser());
$this->mapper->insert($newTransferOwnership);
$this->jobList->add(TransferOwnership::class, [
'id' => $newTransferOwnership->getId(),
]);
return new DataResponse([], Http::STATUS_OK);
}
/**
* @NoAdminRequired
*
* Reject an ownership transfer
*
* @param int $id ID of the ownership transfer
*
* @return DataResponse<Http::STATUS_OK|Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, array<empty>, array{}>
*
* 200: Ownership transfer rejected successfully
* 403: Rejecting ownership transfer is not allowed
* 404: Ownership transfer not found
*/
public function reject(int $id): DataResponse {
try {
$transferOwnership = $this->mapper->getById($id);
} catch (DoesNotExistException $e) {
return new DataResponse([], Http::STATUS_NOT_FOUND);
}
if ($transferOwnership->getTargetUser() !== $this->userId) {
return new DataResponse([], Http::STATUS_FORBIDDEN);
}
$notification = $this->notificationManager->createNotification();
$notification->setApp('files')
->setObject('transfer', (string)$id);
$this->notificationManager->markProcessed($notification);
$notification = $this->notificationManager->createNotification();
$notification->setUser($transferOwnership->getSourceUser())
->setApp($this->appName)
->setDateTime($this->timeFactory->getDateTime())
->setSubject('transferownershipRequestDenied', [
'sourceUser' => $transferOwnership->getSourceUser(),
'targetUser' => $transferOwnership->getTargetUser(),
'nodeName' => $transferOwnership->getNodeName()
])
->setObject('transfer', (string)$transferOwnership->getId());
$this->notificationManager->notify($notification);
$this->mapper->delete($transferOwnership);
return new DataResponse([], Http::STATUS_OK);
}
}
@@ -0,0 +1,424 @@
<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author fnuesse <felix.nuesse@t-online.de>
* @author fnuesse <fnuesse@techfak.uni-bielefeld.de>
* @author Joas Schilling <coding@schilljs.com>
* @author John Molakvoæ <skjnldsv@protonmail.com>
* @author Julius Härtl <jus@bitgrid.net>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Max Kovalenko <mxss1998@yandex.ru>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Nina Pypchenko <22447785+nina-py@users.noreply.github.com>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Files\Controller;
use OCA\Files\Activity\Helper;
use OCA\Files\AppInfo\Application;
use OCA\Files\Event\LoadAdditionalScriptsEvent;
use OCA\Files\Event\LoadSidebar;
use OCA\Files\Service\UserConfig;
use OCA\Files\Service\ViewConfig;
use OCA\Viewer\Event\LoadViewer;
use OCP\App\IAppManager;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\OpenAPI;
use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Services\IInitialState;
use OCP\Collaboration\Resources\LoadAdditionalScriptsEvent as ResourcesLoadAdditionalScriptsEvent;
use OCP\Constants;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Folder;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
use OCP\Files\Template\ITemplateManager;
use OCP\IConfig;
use OCP\IL10N;
use OCP\IRequest;
use OCP\IURLGenerator;
use OCP\IUserSession;
use OCP\Share\IManager;
/**
* @package OCA\Files\Controller
*/
#[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]
class ViewController extends Controller {
private IURLGenerator $urlGenerator;
private IL10N $l10n;
private IConfig $config;
private IEventDispatcher $eventDispatcher;
private IUserSession $userSession;
private IAppManager $appManager;
private IRootFolder $rootFolder;
private Helper $activityHelper;
private IInitialState $initialState;
private ITemplateManager $templateManager;
private IManager $shareManager;
private UserConfig $userConfig;
private ViewConfig $viewConfig;
public function __construct(string $appName,
IRequest $request,
IURLGenerator $urlGenerator,
IL10N $l10n,
IConfig $config,
IEventDispatcher $eventDispatcher,
IUserSession $userSession,
IAppManager $appManager,
IRootFolder $rootFolder,
Helper $activityHelper,
IInitialState $initialState,
ITemplateManager $templateManager,
IManager $shareManager,
UserConfig $userConfig,
ViewConfig $viewConfig
) {
parent::__construct($appName, $request);
$this->urlGenerator = $urlGenerator;
$this->l10n = $l10n;
$this->config = $config;
$this->eventDispatcher = $eventDispatcher;
$this->userSession = $userSession;
$this->appManager = $appManager;
$this->rootFolder = $rootFolder;
$this->activityHelper = $activityHelper;
$this->initialState = $initialState;
$this->templateManager = $templateManager;
$this->shareManager = $shareManager;
$this->userConfig = $userConfig;
$this->viewConfig = $viewConfig;
}
/**
* @param string $appName
* @param string $scriptName
* @return string
*/
protected function renderScript($appName, $scriptName) {
$content = '';
$appPath = \OC_App::getAppPath($appName);
$scriptPath = $appPath . '/' . $scriptName;
if (file_exists($scriptPath)) {
// TODO: sanitize path / script name ?
ob_start();
include $scriptPath;
$content = ob_get_contents();
@ob_end_clean();
}
return $content;
}
/**
* FIXME: Replace with non static code
*
* @return array
* @throws \OCP\Files\NotFoundException
*/
protected function getStorageInfo(string $dir = '/') {
$rootInfo = \OC\Files\Filesystem::getFileInfo('/', false);
return \OC_Helper::getStorageInfo($dir, $rootInfo ?: null);
}
/**
* @NoCSRFRequired
* @NoAdminRequired
*
* @param string $fileid
* @return TemplateResponse|RedirectResponse
*/
public function showFile(string $fileid = null): Response {
if (!$fileid) {
return new RedirectResponse($this->urlGenerator->linkToRoute('files.view.index'));
}
// This is the entry point from the `/f/{fileid}` URL which is hardcoded in the server.
try {
return $this->redirectToFile((int) $fileid);
} catch (NotFoundException $e) {
return new RedirectResponse($this->urlGenerator->linkToRoute('files.view.index', ['fileNotFound' => true]));
}
}
/**
* @NoCSRFRequired
* @NoAdminRequired
* @UseSession
*
* @param string $dir
* @param string $view
* @param string $fileid
* @param bool $fileNotFound
* @return TemplateResponse|RedirectResponse
*/
public function indexView($dir = '', $view = '', $fileid = null, $fileNotFound = false) {
return $this->index($dir, $view, $fileid, $fileNotFound);
}
/**
* @NoCSRFRequired
* @NoAdminRequired
* @UseSession
*
* @param string $dir
* @param string $view
* @param string $fileid
* @param bool $fileNotFound
* @return TemplateResponse|RedirectResponse
*/
public function indexViewFileid($dir = '', $view = '', $fileid = null, $fileNotFound = false) {
return $this->index($dir, $view, $fileid, $fileNotFound);
}
/**
* @NoCSRFRequired
* @NoAdminRequired
* @UseSession
*
* @param string $dir
* @param string $view
* @param string $fileid
* @param bool $fileNotFound
* @return TemplateResponse|RedirectResponse
*/
public function index($dir = '', $view = '', $fileid = null, $fileNotFound = false) {
if ($fileid !== null && $view !== 'trashbin') {
try {
return $this->redirectToFileIfInTrashbin((int) $fileid);
} catch (NotFoundException $e) {
}
}
// Load the files we need
\OCP\Util::addInitScript('files', 'init');
\OCP\Util::addStyle('files', 'merged');
\OCP\Util::addScript('files', 'main');
$userId = $this->userSession->getUser()->getUID();
// Get all the user favorites to create a submenu
try {
$userFolder = $this->rootFolder->getUserFolder($userId);
$favElements = $this->activityHelper->getFavoriteNodes($userId, true);
$favElements = array_map(fn (Folder $node) => [
'fileid' => $node->getId(),
'path' => $userFolder->getRelativePath($node->getPath()),
], $favElements);
} catch (\RuntimeException $e) {
$favElements = [];
}
// If the file doesn't exists in the folder and
// exists in only one occurrence, redirect to that file
// in the correct folder
if ($fileid && $dir !== '') {
$baseFolder = $this->rootFolder->getUserFolder($userId);
$nodes = $baseFolder->getById((int) $fileid);
if (!empty($nodes)) {
$nodePath = $baseFolder->getRelativePath($nodes[0]->getPath());
$relativePath = $nodePath ? dirname($nodePath) : '';
// If the requested path does not contain the file id
// or if the requested path is not the file id itself
if (count($nodes) === 1 && $relativePath !== $dir && $nodePath !== $dir) {
return $this->redirectToFile((int) $fileid);
}
} else { // fileid does not exist anywhere
$fileNotFound = true;
}
}
try {
// If view is files, we use the directory, otherwise we use the root storage
$storageInfo = $this->getStorageInfo(($view === 'files' && $dir) ? $dir : '/');
} catch(\Exception $e) {
$storageInfo = $this->getStorageInfo();
}
$this->initialState->provideInitialState('storageStats', $storageInfo);
$this->initialState->provideInitialState('config', $this->userConfig->getConfigs());
$this->initialState->provideInitialState('viewConfigs', $this->viewConfig->getConfigs());
$this->initialState->provideInitialState('favoriteFolders', $favElements);
// File sorting user config
$filesSortingConfig = json_decode($this->config->getUserValue($userId, 'files', 'files_sorting_configs', '{}'), true);
$this->initialState->provideInitialState('filesSortingConfig', $filesSortingConfig);
// Forbidden file characters
/** @var string[] */
$forbiddenCharacters = $this->config->getSystemValue('forbidden_chars', []);
$this->initialState->provideInitialState('forbiddenCharacters', Constants::FILENAME_INVALID_CHARS . implode('', $forbiddenCharacters));
$event = new LoadAdditionalScriptsEvent();
$this->eventDispatcher->dispatchTyped($event);
$this->eventDispatcher->dispatchTyped(new ResourcesLoadAdditionalScriptsEvent());
$this->eventDispatcher->dispatchTyped(new LoadSidebar());
// Load Viewer scripts
if (class_exists(LoadViewer::class)) {
$this->eventDispatcher->dispatchTyped(new LoadViewer());
}
$this->initialState->provideInitialState('templates_path', $this->templateManager->hasTemplateDirectory() ? $this->templateManager->getTemplatePath() : false);
$this->initialState->provideInitialState('templates', $this->templateManager->listCreators());
$response = new TemplateResponse(
Application::APP_ID,
'index',
);
$policy = new ContentSecurityPolicy();
$policy->addAllowedFrameDomain('\'self\'');
// Allow preview service worker
$policy->addAllowedWorkerSrcDomain('\'self\'');
$response->setContentSecurityPolicy($policy);
$this->provideInitialState($dir, $fileid);
return $response;
}
/**
* Add openFileInfo in initialState.
* @param string $dir - the ?dir= URL param
* @param string $fileid - the fileid URL param
* @return void
*/
private function provideInitialState(string $dir, ?string $fileid): void {
if ($fileid === null) {
return;
}
$user = $this->userSession->getUser();
if ($user === null) {
return;
}
$uid = $user->getUID();
$userFolder = $this->rootFolder->getUserFolder($uid);
$nodes = $userFolder->getById((int) $fileid);
$node = array_shift($nodes);
if ($node === null) {
return;
}
// properly format full path and make sure
// we're relative to the user home folder
$isRoot = $node === $userFolder;
$path = $userFolder->getRelativePath($node->getPath());
$directory = $userFolder->getRelativePath($node->getParent()->getPath());
// Prevent opening a file from another folder.
if ($dir !== $directory) {
return;
}
$this->initialState->provideInitialState(
'openFileInfo', [
'id' => $node->getId(),
'name' => $isRoot ? '' : $node->getName(),
'path' => $path,
'directory' => $directory,
'mime' => $node->getMimetype(),
'type' => $node->getType(),
'permissions' => $node->getPermissions(),
]
);
}
/**
* Redirects to the trashbin file list and highlight the given file id
*
* @param int $fileId file id to show
* @return RedirectResponse redirect response or not found response
* @throws NotFoundException
*/
private function redirectToFileIfInTrashbin($fileId): RedirectResponse {
$uid = $this->userSession->getUser()->getUID();
$baseFolder = $this->rootFolder->getUserFolder($uid);
$nodes = $baseFolder->getById($fileId);
$params = [];
if (empty($nodes) && $this->appManager->isEnabledForUser('files_trashbin')) {
/** @var Folder */
$baseFolder = $this->rootFolder->get($uid . '/files_trashbin/files/');
$nodes = $baseFolder->getById($fileId);
$params['view'] = 'trashbin';
if (!empty($nodes)) {
$node = current($nodes);
$params['fileid'] = $fileId;
if ($node instanceof Folder) {
// set the full path to enter the folder
$params['dir'] = $baseFolder->getRelativePath($node->getPath());
} else {
// set parent path as dir
$params['dir'] = $baseFolder->getRelativePath($node->getParent()->getPath());
}
return new RedirectResponse($this->urlGenerator->linkToRoute('files.view.indexViewFileid', $params));
}
}
throw new NotFoundException();
}
/**
* Redirects to the file list and highlight the given file id
*
* @param int $fileId file id to show
* @return RedirectResponse redirect response or not found response
* @throws NotFoundException
*/
private function redirectToFile(int $fileId) {
$uid = $this->userSession->getUser()->getUID();
$baseFolder = $this->rootFolder->getUserFolder($uid);
$nodes = $baseFolder->getById($fileId);
$params = ['view' => 'files'];
try {
$this->redirectToFileIfInTrashbin($fileId);
} catch (NotFoundException $e) {
}
if (!empty($nodes)) {
$node = current($nodes);
$params['fileid'] = $fileId;
if ($node instanceof Folder) {
// set the full path to enter the folder
$params['dir'] = $baseFolder->getRelativePath($node->getPath());
} else {
// set parent path as dir
$params['dir'] = $baseFolder->getRelativePath($node->getParent()->getPath());
}
return new RedirectResponse($this->urlGenerator->linkToRoute('files.view.indexViewFileid', $params));
}
throw new NotFoundException();
}
}