Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Direct editing API to allow file editing using a one-time token #17625

Merged
merged 9 commits into from
Nov 28, 2019
3 changes: 2 additions & 1 deletion apps/files/appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<name>Files</name>
<summary>File Management</summary>
<description>File Management</description>
<version>1.13.0</version>
<version>1.13.1</version>
<licence>agpl</licence>
<author>Robin Appelman</author>
<author>Vincent Petry</author>
Expand All @@ -26,6 +26,7 @@
<job>OCA\Files\BackgroundJob\ScanFiles</job>
<job>OCA\Files\BackgroundJob\DeleteOrphanedItems</job>
<job>OCA\Files\BackgroundJob\CleanupFileLocks</job>
<job>OCA\Files\BackgroundJob\CleanupDirectEditingTokens</job>
</background-jobs>

<commands>
Expand Down
27 changes: 27 additions & 0 deletions apps/files/appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,33 @@
'url' => '/api/v1/quickaccess/get/NodeType',
'verb' => 'GET',
],
[
'name' => 'DirectEditingView#edit',
'url' => '/directEditing/{token}',
'verb' => 'GET'
],
],
'ocs' => [
[
'name' => 'DirectEditing#info',
'url' => '/api/v1/directEditing',
'verb' => 'GET'
],
[
'name' => 'DirectEditing#templates',
'url' => '/api/v1/directEditing/templates/{editorId}/{creatorId}',
'verb' => 'GET'
],
[
'name' => 'DirectEditing#open',
'url' => '/api/v1/directEditing/open',
'verb' => 'POST'
],
[
'name' => 'DirectEditing#create',
'url' => '/api/v1/directEditing/create',
'verb' => 'POST'
],
]
]
);
Expand Down
4 changes: 4 additions & 0 deletions apps/files/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
'OCA\\Files\\Activity\\Settings\\FileRestored' => $baseDir . '/../lib/Activity/Settings/FileRestored.php',
'OCA\\Files\\App' => $baseDir . '/../lib/App.php',
'OCA\\Files\\AppInfo\\Application' => $baseDir . '/../lib/AppInfo/Application.php',
'OCA\\Files\\BackgroundJob\\CleanupDirectEditingTokens' => $baseDir . '/../lib/BackgroundJob/CleanupDirectEditingTokens.php',
'OCA\\Files\\BackgroundJob\\CleanupFileLocks' => $baseDir . '/../lib/BackgroundJob/CleanupFileLocks.php',
'OCA\\Files\\BackgroundJob\\DeleteOrphanedItems' => $baseDir . '/../lib/BackgroundJob/DeleteOrphanedItems.php',
'OCA\\Files\\BackgroundJob\\ScanFiles' => $baseDir . '/../lib/BackgroundJob/ScanFiles.php',
Expand All @@ -31,12 +32,15 @@
'OCA\\Files\\Command\\TransferOwnership' => $baseDir . '/../lib/Command/TransferOwnership.php',
'OCA\\Files\\Controller\\AjaxController' => $baseDir . '/../lib/Controller/AjaxController.php',
'OCA\\Files\\Controller\\ApiController' => $baseDir . '/../lib/Controller/ApiController.php',
'OCA\\Files\\Controller\\DirectEditingController' => $baseDir . '/../lib/Controller/DirectEditingController.php',
'OCA\\Files\\Controller\\DirectEditingViewController' => $baseDir . '/../lib/Controller/DirectEditingViewController.php',
'OCA\\Files\\Controller\\ViewController' => $baseDir . '/../lib/Controller/ViewController.php',
'OCA\\Files\\Event\\LoadAdditionalScriptsEvent' => $baseDir . '/../lib/Event/LoadAdditionalScriptsEvent.php',
'OCA\\Files\\Event\\LoadSidebar' => $baseDir . '/../lib/Event/LoadSidebar.php',
'OCA\\Files\\Exception\\TransferOwnershipException' => $baseDir . '/../lib/Exception/TransferOwnershipException.php',
'OCA\\Files\\Helper' => $baseDir . '/../lib/Helper.php',
'OCA\\Files\\Listener\\LegacyLoadAdditionalScriptsAdapter' => $baseDir . '/../lib/Listener/LegacyLoadAdditionalScriptsAdapter.php',
'OCA\\Files\\Service\\DirectEditingService' => $baseDir . '/../lib/Service/DirectEditingService.php',
'OCA\\Files\\Service\\OwnershipTransferService' => $baseDir . '/../lib/Service/OwnershipTransferService.php',
'OCA\\Files\\Service\\TagService' => $baseDir . '/../lib/Service/TagService.php',
);
4 changes: 4 additions & 0 deletions apps/files/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class ComposerStaticInitFiles
'OCA\\Files\\Activity\\Settings\\FileRestored' => __DIR__ . '/..' . '/../lib/Activity/Settings/FileRestored.php',
'OCA\\Files\\App' => __DIR__ . '/..' . '/../lib/App.php',
'OCA\\Files\\AppInfo\\Application' => __DIR__ . '/..' . '/../lib/AppInfo/Application.php',
'OCA\\Files\\BackgroundJob\\CleanupDirectEditingTokens' => __DIR__ . '/..' . '/../lib/BackgroundJob/CleanupDirectEditingTokens.php',
'OCA\\Files\\BackgroundJob\\CleanupFileLocks' => __DIR__ . '/..' . '/../lib/BackgroundJob/CleanupFileLocks.php',
'OCA\\Files\\BackgroundJob\\DeleteOrphanedItems' => __DIR__ . '/..' . '/../lib/BackgroundJob/DeleteOrphanedItems.php',
'OCA\\Files\\BackgroundJob\\ScanFiles' => __DIR__ . '/..' . '/../lib/BackgroundJob/ScanFiles.php',
Expand All @@ -46,12 +47,15 @@ class ComposerStaticInitFiles
'OCA\\Files\\Command\\TransferOwnership' => __DIR__ . '/..' . '/../lib/Command/TransferOwnership.php',
'OCA\\Files\\Controller\\AjaxController' => __DIR__ . '/..' . '/../lib/Controller/AjaxController.php',
'OCA\\Files\\Controller\\ApiController' => __DIR__ . '/..' . '/../lib/Controller/ApiController.php',
'OCA\\Files\\Controller\\DirectEditingController' => __DIR__ . '/..' . '/../lib/Controller/DirectEditingController.php',
'OCA\\Files\\Controller\\DirectEditingViewController' => __DIR__ . '/..' . '/../lib/Controller/DirectEditingViewController.php',
'OCA\\Files\\Controller\\ViewController' => __DIR__ . '/..' . '/../lib/Controller/ViewController.php',
'OCA\\Files\\Event\\LoadAdditionalScriptsEvent' => __DIR__ . '/..' . '/../lib/Event/LoadAdditionalScriptsEvent.php',
'OCA\\Files\\Event\\LoadSidebar' => __DIR__ . '/..' . '/../lib/Event/LoadSidebar.php',
'OCA\\Files\\Exception\\TransferOwnershipException' => __DIR__ . '/..' . '/../lib/Exception/TransferOwnershipException.php',
'OCA\\Files\\Helper' => __DIR__ . '/..' . '/../lib/Helper.php',
'OCA\\Files\\Listener\\LegacyLoadAdditionalScriptsAdapter' => __DIR__ . '/..' . '/../lib/Listener/LegacyLoadAdditionalScriptsAdapter.php',
'OCA\\Files\\Service\\DirectEditingService' => __DIR__ . '/..' . '/../lib/Service/DirectEditingService.php',
'OCA\\Files\\Service\\OwnershipTransferService' => __DIR__ . '/..' . '/../lib/Service/OwnershipTransferService.php',
'OCA\\Files\\Service\\TagService' => __DIR__ . '/..' . '/../lib/Service/TagService.php',
);
Expand Down
31 changes: 31 additions & 0 deletions apps/files/lib/BackgroundJob/CleanupDirectEditingTokens.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace OCA\Files\BackgroundJob;

use OC\BackgroundJob\TimedJob;
use OCP\DirectEditing\IManager;

class CleanupDirectEditingTokens extends TimedJob {

private const INTERVAL_MINUTES = 15 * 60;

/**
* @var IManager
*/
private $manager;

public function __construct(IManager $manager) {
$this->interval = self::INTERVAL_MINUTES;
$this->manager = $manager;
}

/**
* Makes the background job do its work
*
* @param array $argument unused argument
* @throws \Exception
*/
public function run($argument) {
$this->manager->cleanup();
}
}
25 changes: 24 additions & 1 deletion apps/files/lib/Capabilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,42 @@

namespace OCA\Files;

use OC\DirectEditing\Manager;
use OCA\Files\Service\DirectEditingService;
use OCP\Capabilities\ICapability;
use OCP\DirectEditing\ACreateEmpty;
use OCP\DirectEditing\ACreateFromTemplate;
use OCP\DirectEditing\IEditor;
use OCP\DirectEditing\RegisterDirectEditorEvent;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IConfig;
use OCP\IURLGenerator;

/**
* Class Capabilities
*
* @package OCA\Files
*/
class Capabilities implements ICapability {

/** @var IConfig */
protected $config;

/** @var DirectEditingService */
protected $directEditingService;

/** @var IURLGenerator */
private $urlGenerator;

/**
* Capabilities constructor.
*
* @param IConfig $config
*/
public function __construct(IConfig $config) {
public function __construct(IConfig $config, DirectEditingService $directEditingService, IURLGenerator $urlGenerator) {
$this->config = $config;
$this->directEditingService = $directEditingService;
$this->urlGenerator = $urlGenerator;
}

/**
Expand All @@ -56,7 +73,13 @@ public function getCapabilities() {
'files' => [
'bigfilechunking' => true,
'blacklisted_files' => $this->config->getSystemValue('blacklisted_files', ['.htaccess']),
'directEditing' => [
'url' => $this->urlGenerator->linkToOCSRouteAbsolute('files.DirectEditing.info'),
'etag' => $this->directEditingService->getDirectEditingETag()
]
],
];
}


}
128 changes: 128 additions & 0 deletions apps/files/lib/Controller/DirectEditingController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<?php
/**
* @copyright Copyright (c) 2019 Julius Härtl <[email protected]>
*
* @author Julius Härtl <[email protected]>
*
* @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\ACreateEmpty;
use OCP\DirectEditing\ACreateFromTemplate;
use OCP\DirectEditing\IEditor;
use OCP\DirectEditing\IManager;
use OCP\DirectEditing\RegisterDirectEditorEvent;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\ILogger;
use OCP\IRequest;
use OCP\IURLGenerator;

class DirectEditingController extends OCSController {

/** @var IEventDispatcher */
private $eventDispatcher;

/** @var IManager */
private $directEditingManager;

/** @var IURLGenerator */
private $urlGenerator;

/** @var ILogger */
private $logger;

/** @var DirectEditingService */
private $directEditingService;

public function __construct($appName, IRequest $request, $corsMethods, $corsAllowedHeaders, $corsMaxAge,
IEventDispatcher $eventDispatcher, IURLGenerator $urlGenerator, IManager $manager, DirectEditingService $directEditingService, ILogger $logger) {
parent::__construct($appName, $request, $corsMethods, $corsAllowedHeaders, $corsMaxAge);

$this->eventDispatcher = $eventDispatcher;
$this->directEditingManager = $manager;
$this->directEditingService = $directEditingService;
$this->logger = $logger;
$this->urlGenerator = $urlGenerator;
}

/**
* @NoAdminRequired
*/
public function info(): DataResponse {
$response = new DataResponse($this->directEditingService->getDirectEditingCapabilitites());
$response->setETag($this->directEditingService->getDirectEditingETag());
return $response;
}

/**
* @NoAdminRequired
*/
public function create(string $path, string $editorId, string $creatorId, string $templateId = null): DataResponse {
$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->logException($e, ['message' => 'Exception when creating a new file through direct editing']);
return new DataResponse('Failed to create file', Http::STATUS_FORBIDDEN);
}
}

/**
* @NoAdminRequired
*/
public function open(int $fileId, string $editorId = null): DataResponse {
$this->eventDispatcher->dispatchTyped(new RegisterDirectEditorEvent($this->directEditingManager));

try {
$token = $this->directEditingManager->open($fileId, $editorId);
return new DataResponse([
'url' => $this->urlGenerator->linkToRouteAbsolute('files.DirectEditingView.edit', ['token' => $token])
]);
} catch (Exception $e) {
$this->logger->logException($e, ['message' => 'Exception when opening a file through direct editing']);
return new DataResponse('Failed to open file', Http::STATUS_FORBIDDEN);
}
}



/**
* @NoAdminRequired
*/
public function templates(string $editorId, string $creatorId): DataResponse {
$this->eventDispatcher->dispatchTyped(new RegisterDirectEditorEvent($this->directEditingManager));

try {
return new DataResponse($this->directEditingManager->getTemplates($editorId, $creatorId));
} catch (Exception $e) {
$this->logger->logException($e);
return new DataResponse('Failed to open file', Http::STATUS_INTERNAL_SERVER_ERROR);
}
}
}
72 changes: 72 additions & 0 deletions apps/files/lib/Controller/DirectEditingViewController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php
/**
* @copyright Copyright (c) 2019 Julius Härtl <[email protected]>
*
* @author Julius Härtl <[email protected]>
*
* @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\NotFoundResponse;
use OCP\AppFramework\Http\Response;
use OCP\DirectEditing\IManager;
use OCP\DirectEditing\RegisterDirectEditorEvent;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\ILogger;
use OCP\IRequest;

class DirectEditingViewController extends Controller {

/** @var IEventDispatcher */
private $eventDispatcher;

/** @var IManager */
private $directEditingManager;

/** @var ILogger */
private $logger;

public function __construct($appName, IRequest $request, IEventDispatcher $eventDispatcher, IManager $manager, ILogger $logger) {
parent::__construct($appName, $request);

$this->eventDispatcher = $eventDispatcher;
$this->directEditingManager = $manager;
$this->logger = $logger;
}

/**
* @PublicPage
* @NoCSRFRequired
*
* @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->logException($e);
return new NotFoundResponse();
}
}
}
Loading