Skip to content

Commit

Permalink
Merge pull request #974 from nextcloud/enh/frontend-api
Browse files Browse the repository at this point in the history
  • Loading branch information
juliushaertl committed Oct 13, 2020
2 parents 2443a5d + cbaffd2 commit 30fba11
Show file tree
Hide file tree
Showing 16 changed files with 726 additions and 294 deletions.
9 changes: 8 additions & 1 deletion css/viewer.scss
Expand Up @@ -124,8 +124,15 @@
padding-left: 12px;
}

#currentVersion li {
#currentVersion li,
#lastSavedVersion li {
border-bottom: 1px solid rgba(100,100,100,.1);

.version-container .downloadVersion {
display: flex;
flex-direction: column;
margin-left: 12px;
}
}

@import 'templatePicker';
151 changes: 151 additions & 0 deletions docs/frontend-integration.md
@@ -0,0 +1,151 @@
## Frontend integration API

### Configuration

The Collabora configuration for creating new files with their mietype and extension per file type is exposed to `OCA.RichDocuments.config.create`.

```json
{
"create": {
"document": {
"extension": "odt",
"mime": "application/vnd.oasis.opendocument.text"
},
"spreadsheet": {
"extension": "ods",
"mime": "application/vnd.oasis.opendocument.spreadsheet"
},
"presentation": {
"extension": "odp",
"mime": "application/vnd.oasis.opendocument.presentation"
}
}
}
```

### Open viewer


The following two methods are exposed in order to manually trigger the Collabora viewer opening a file:

#### Open an existing file

`OCA.RichDocuments.open(params)` will open the Collabora view for an existing file.

Params requires the following properties:
- fileId: (string) internal file id
- path: (string) full path to the file
- fileModel: (OCA.Files.FileInfoModel) model of the file that will be opened
- fileList: (object) optional file list object


```javascript
OCA.RichDocuments.open({
fileId: 1234,
path: '/path/to/file.odt',
fileModel: new OCA.Files.FileInfoModel({...})
fileList: FileList
})
```

#### Create a new file from a template

`OCA.RichDocuments.openWithTemplate(params)` provides a method to open a Collabora view for a file that should be created from a template. Calling this method requires the file to be already present on the filesytem and shown in the file list.

Params requires the following properties:
- fileId: (string) internal file id
- path: (string) full path to the file
- templateId: (string) file id of the template
- fileModel: (OCA.Files.FileInfoModel) model of the file that will be opened
- fileList: (object) optional file list object

```javascript
OCA.RichDocuments.openWithTemplate({
fileId: -1,
path: '/path/to/file.odt,
templateId: templateId,
fileModel: new OCA.Files.FileInfoModel({...})
})
```
Changes to the fileModel should be propagated by triggering a backbone `change` event:
```javascript
window.OCA.RichDocuments.FilesAppIntegration.registerHandler('actionFavorite', (filesAppIntegration) => {
// custom logic here
// make sure to trigger a change on the file info model object like this:
filesAppIntegration.getFileModel().trigger('change', newFileModel)
return true
})
```
### Handlers
Handlers provide a way to hook into the files app integration in order to inject custom behaviour during certain actions.
The return value indicates if the default behavour should be blocked (true) or still be executed (false).
The following handlers are currently supported:
- initAfterReady: will be called once the Collabora frame has been loaded
- close: will be called after the Collabora view has been closed
- saveAs: will be called on a save_as response by collabora
- share: will be called before the default share action is triggered
- rename: will be called before the default rename action is triggered (the new filename is available as a property of the filesAppIntegration parameter)
- showRevHistory: will be called before the default show revision history action is triggered
- insertGraphic: will be called when an image from the Nextcloud storage should be inserted
- Arguments
- insertFileFromPath(path): Callback to trigger the actual inserting of the graphic from an absolute file path
In addition, the following handlers can be used to overwrite the handling of file actions that are rendered in the Nextcloud header bar:
- actionDetails
- actionDownload
- actionFavorite
The filesAppIntegration parameter can be used to extract the current context of the edited file. The following properties are available for that:
- fileName
- fileId
The callback function of each handler will be called with the following parameters:
- filesAppIntegration: current instance of the filesAppIntegration object
- arguments (optional): see list of supported handlers for details
The following code shows an example on how to register the different handlers:
```javascript
(function() {
OCA.RichDocuments.FilesAppIntegration.registerHandler('initAfterReady', (filesAppIntegration) => {
console.debug('called initAfterReady', filesAppIntegration)
return false
})
OCA.RichDocuments.FilesAppIntegration.registerHandler('close', (filesAppIntegration) => {
console.debug('called close', filesAppIntegration)
return false
})
OCA.RichDocuments.FilesAppIntegration.registerHandler('share', (filesAppIntegration) => {
console.debug('called share', filesAppIntegration)
return false
})
OCA.RichDocuments.FilesAppIntegration.registerHandler('rename', (filesAppIntegration) => {
console.debug('called rename', filesAppIntegration)
return false
})
OCA.RichDocuments.FilesAppIntegration.registerHandler('showRevHistory', (filesAppIntegration) => {
console.debug('called showRevHistory', filesAppIntegration)
return false
})
OCA.RichDocuments.FilesAppIntegration.registerHandler('insertGraphic', (filesAppIntegration, { insertFileFromPath }) => {
const path = prompt('Enter a file path', '')
insertFileFromPath(path)
return true
})
})()
```
17 changes: 14 additions & 3 deletions lib/Controller/DocumentController.php
Expand Up @@ -11,6 +11,7 @@

namespace OCA\Richdocuments\Controller;

use OCA\Richdocuments\Events\BeforeFederationRedirectEvent;
use OCA\Richdocuments\Service\FederationService;
use OCA\Richdocuments\TokenManager;
use \OCP\AppFramework\Controller;
Expand Down Expand Up @@ -193,11 +194,21 @@ public function open($fileId) {
$remoteCollabora = $this->federationService->getRemoteCollaboraURL($remote);
if ($remoteCollabora !== '') {
$absolute = $item->getParent()->getPath();
$relative = $folder->getRelativePath($absolute);
$url = '/index.php/apps/files?dir=' . $relative .
'&richdocuments_open=' . $item->getName() .
$relativeFolderPath = $folder->getRelativePath($absolute);
$relativeFilePath = $folder->getRelativePath($item->getPath());
$url = '/index.php/apps/files/?dir=' . $relativeFolderPath .
'&richdocuments_open=' . $relativeFilePath .
'&richdocuments_fileId=' . $fileId .
'&richdocuments_remote_access=' . $remote;

$event = new BeforeFederationRedirectEvent(
$item, $relative, $remote
);
$eventDispatcher = \OC::$server->getEventDispatcher();
$eventDispatcher->dispatch(BeforeFederationRedirectEvent::class, $event);
if ($event->getRedirectUrl()) {
$url = $event->getRedirectUrl();
}
return new RedirectResponse($url);
}
$this->logger->warning('Failed to connect to remote collabora instance for ' . $fileId);
Expand Down
4 changes: 3 additions & 1 deletion lib/Controller/FederationController.php
Expand Up @@ -62,9 +62,11 @@ public function __construct(
* @NoCSRFRequired
*/
public function index() {
return new DataResponse([
$response = new DataResponse([
'wopi_url' => $this->config->getAppValue('richdocuments', 'wopi_url')
]);
$response->setHeaders(['X-Frame-Options' => 'ALLOW']);
return $response;
}

/**
Expand Down
9 changes: 5 additions & 4 deletions lib/Controller/WopiController.php
Expand Up @@ -161,6 +161,7 @@ public function checkFileInfo($fileId, $access_token) {
$guestUserId = 'Guest-' . \OC::$server->getSecureRandom()->generate(8);
$user = $this->userManager->get($wopi->getEditorUid());
$userDisplayName = $user !== null && !$isPublic ? $user->getDisplayName() : $wopi->getGuestDisplayname();
$isVersion = $version !== '0';
$response = [
'BaseFileName' => $file->getName(),
'Size' => $file->getSize(),
Expand All @@ -174,10 +175,10 @@ public function checkFileInfo($fileId, $access_token) {
'UserCanNotWriteRelative' => \OC::$server->getEncryptionManager()->isEnabled() || $isPublic,
'PostMessageOrigin' => $wopi->getServerHost(),
'LastModifiedTime' => Helper::toISO8601($file->getMTime()),
'SupportsRename' => true,
'UserCanRename' => !$isPublic,
'SupportsRename' => !$isVersion,
'UserCanRename' => !$isPublic && !$isVersion,
'EnableInsertRemoteImage' => true,
'EnableShare' => true,
'EnableShare' => $file->isShareable() && !$isVersion,
'HideUserList' => 'desktop',
'DisablePrint' => $wopi->getHideDownload(),
'DisableExport' => $wopi->getHideDownload(),
Expand Down Expand Up @@ -392,7 +393,7 @@ public function putFile($fileId,
}

// Set the user to register the change under his name
$this->userScopeService->setUserScope($wopi->getEditorUid());
$this->userScopeService->setUserScope($wopi->getUserForFileAccess());
$this->userScopeService->setFilesystemScope($isPutRelative ? $wopi->getEditorUid() : $wopi->getUserForFileAccess());

try {
Expand Down
46 changes: 46 additions & 0 deletions lib/Events/BeforeFederationRedirectEvent.php
@@ -0,0 +1,46 @@
<?php

namespace OCA\Richdocuments\Events;


use OCP\Files\Node;
use Symfony\Component\EventDispatcher\Event;

class BeforeFederationRedirectEvent extends Event {

/** @var Node */
private $node;
/** @var string */
private $relativePath;
/** @var string|null */
private $redirectUrl = null;
/** @var string */
private $remote;

public function __construct($node, $relativePath, $remote) {
$this->node = $node;
$this->relativePath = $relativePath;
$this->remote = $remote;
}

public function getRelativePath() {
return $this->relativePath;
}

public function getNode() {
return $this->node;
}

public function getRemote() {
return $this->remote;
}

public function setRedirectUrl($redirectUrl) {
$this->redirectUrl = $redirectUrl;
}

public function getRedirectUrl() {
return $this->redirectUrl;
}

}
8 changes: 6 additions & 2 deletions lib/Service/FederationService.php
Expand Up @@ -60,10 +60,14 @@ public function __construct(ICacheFactory $cacheFactory, IClientService $clientS
} catch (QueryException $e) {}
}

/**
* @param $remote
* @return string
* @throws \Exception
*/
public function getRemoteCollaboraURL($remote) {
if ($this->trustedServers === null || !$this->trustedServers->isTrustedServer($remote)) {
$this->logger->info('Unable to determine collabora URL of remote server ' . $remote . ' - Remote is not a trusted server');
return '';
throw new \Exception('Unable to determine collabora URL of remote server ' . $remote . ' - Remote is not a trusted server');
}
if ($remoteCollabora = $this->cache->get('richdocuments_remote/' . $remote)) {
return $remoteCollabora;
Expand Down
6 changes: 5 additions & 1 deletion src/document.js
Expand Up @@ -266,6 +266,10 @@ const documentsMain = {
PostMessages.sendWOPIPostMessage('loolframe', 'Hide_Menu_Item', { id: 'shareas' })
}

if (Config.get('userId') === null) {
PostMessages.sendWOPIPostMessage('loolframe', 'Hide_Menu_Item', { id: 'insertgraphicremote' })
}

break
case 'Failed':
// Loading failed but editor shows the error
Expand Down Expand Up @@ -395,7 +399,7 @@ const documentsMain = {
t('richdocuments', 'Save As'),
function(result, value) {
if (result === true && value) {
PostMessages.sendWOPIPostMessage('loolframe', 'Action_SaveAs', { 'Filename': value })
PostMessages.sendWOPIPostMessage('loolframe', 'Action_SaveAs', { Filename: value, Notify: true })
}
},
true,
Expand Down

0 comments on commit 30fba11

Please sign in to comment.