Compare commits
46 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
93f8b0da47 | ||
|
3eba8b7644 | ||
|
909053b299 | ||
|
29d587293d | ||
|
9d2563d545 | ||
|
3a8a629d10 | ||
|
d76740bc75 | ||
|
5855b7de9e | ||
|
9d4cff8f97 | ||
|
ba25db2b4d | ||
|
fc24ac3319 | ||
|
bbefee2e4f | ||
|
49a73108e9 | ||
|
32755343ed | ||
|
2c1dd44651 | ||
|
57f6a5ba32 | ||
|
654c8e988d | ||
|
257e9f2020 | ||
|
9afe6fb69c | ||
|
c99ec2d615 | ||
|
0a4c5816ee | ||
|
6b112402f9 | ||
|
b44c4da9a5 | ||
|
f74a7b7f4a | ||
|
cc5fb99cb4 | ||
|
d4e0ac2387 | ||
|
586c925bb1 | ||
|
5e42ea1dab | ||
|
d6c90226b9 | ||
|
6925e4f2f6 | ||
|
bd68097a92 | ||
|
2385b70915 | ||
|
b1e51782fc | ||
|
ff1ee24c46 | ||
|
ff7aa2d5e8 | ||
|
472a22ef21 | ||
|
c21c029fa4 | ||
|
7e4c59e360 | ||
|
ad61db1158 | ||
|
6b629b2c67 | ||
|
f790f640b1 | ||
|
674a6cb384 | ||
|
df0c7cce94 | ||
|
1cc5e43106 | ||
|
f74b0b3018 | ||
|
bf72f5b01d |
45
CHANGELOG.md
45
CHANGELOG.md
@ -1,3 +1,46 @@
|
||||
**1.11.34**
|
||||
- Bug: Fix editing publicly shared documents
|
||||
- Bug: Delete creator/last modifier name from document templates
|
||||
|
||||
**1.11.33**
|
||||
- Feature: Restore 'Enable edit for specific groups' feature, fixes #66
|
||||
- Feature: Only edit textfiles with Collabora Online, when texteditorapp is disabled
|
||||
- Feature: Include support for X-LOOL-WOPI-Timestamp
|
||||
- Bug: Undefined variable 'owneruid'
|
||||
|
||||
**1.11.32**
|
||||
- Bug: Show Display Name of user, not its uid in userlist
|
||||
- Bug: Do not throw exception when user not found. It might be a public link share.
|
||||
- Bug: Use the file owner from the share object, if available. Fixes #85.
|
||||
- Bug: Shorter db index name. Fixes #54.
|
||||
|
||||
**1.11.31**
|
||||
- Bug: Guard encryption support
|
||||
|
||||
**1.11.30**
|
||||
- Feature: Support opening encrypted files
|
||||
- Bug: Respect OOXML settings again
|
||||
- Bug: Register the change under user’s name when saving the document
|
||||
|
||||
**1.11.29**
|
||||
- Bug: Fix undefined instanceId
|
||||
|
||||
**1.11.28**
|
||||
- Bug: Allow full screen
|
||||
- Updated screenshots
|
||||
|
||||
**1.11.27**
|
||||
- Bug: Fix revision history
|
||||
|
||||
**1.1.25.1**
|
||||
- Bug: Fix height for revision history viewer
|
||||
- Bug: Set the correct language tag expected by JS
|
||||
- Bug: Replace trailing slash of WOPI URL
|
||||
- Bug: Try opening readonly documents too
|
||||
- Bug: Fix revision history
|
||||
- Feature: Add rtf and txt as supported file formats
|
||||
- Feature: Support for multitenancy installations of LibreOffice Online
|
||||
|
||||
**1.1.24**
|
||||
- Bug: Fix undefined PHP notices
|
||||
- Security: Properly check for password on password protected shares
|
||||
- Security: Properly check for password on password protected shares
|
||||
|
@ -121,7 +121,7 @@
|
||||
</field>
|
||||
|
||||
<index>
|
||||
<name>richdocuments_wopi_token_idx</name>
|
||||
<name>rd_wopi_token_idx</name>
|
||||
<unique>true</unique>
|
||||
<field>
|
||||
<name>token</name>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<description>Collabora Online allows you to to work with all kinds of office documents directly in your browser. This application requires Collabora Cloudsuite to be installed on one of your servers, please read the documentation to learn more about that.</description>
|
||||
<summary>Edit office documents directly in your browser.</summary>
|
||||
<licence>AGPL</licence>
|
||||
<version>1.1.24</version>
|
||||
<version>1.11.34</version>
|
||||
<author>Collabora Productivity based on work of Frank Karlitschek, Victor Dubiniuk</author>
|
||||
<bugs>https://github.com/nextcloud/richdocuments/issues</bugs>
|
||||
<repository type="git">https://github.com/nextcloud/richdocuments.git</repository>
|
||||
@ -22,7 +22,6 @@
|
||||
<prevent_group_restriction/>
|
||||
</types>
|
||||
<screenshot>https://nextcloud.com/wp-content/themes/next/assets/img/features/collabora-document.png</screenshot>
|
||||
<screenshot>https://nextcloud.com/wp-content/themes/next/assets/img/features/collabora-app.png</screenshot>
|
||||
<screenshot>https://nextcloud.com/wp-content/themes/next/assets/img/features/collabora-presentation.png</screenshot>
|
||||
<screenshot>https://nextcloud.com/wp-content/themes/next/assets/img/features/collabora-spreadsheet.png</screenshot>
|
||||
<settings>
|
||||
|
@ -25,5 +25,6 @@ return [
|
||||
|
||||
//settings
|
||||
['name' => 'settings#setSettings', 'url' => 'ajax/admin.php', 'verb' => 'POST'],
|
||||
['name' => 'settings#getSettings', 'url' => 'ajax/settings.php', 'verb' => 'GET'],
|
||||
]
|
||||
];
|
||||
|
Binary file not shown.
Binary file not shown.
@ -133,7 +133,7 @@
|
||||
width: 100%;
|
||||
z-index: 600;
|
||||
background-color: #ddd !important;
|
||||
top: 45px;
|
||||
top: 0px;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
@ -149,7 +149,7 @@
|
||||
z-index: 600;
|
||||
background-color: #efefef !important;
|
||||
right: 0;
|
||||
top: 45px;
|
||||
top: 0px;
|
||||
bottom: 0;
|
||||
box-sizing: border-box;
|
||||
overflow-x: hidden;
|
||||
|
46
js/admin.js
46
js/admin.js
@ -4,7 +4,7 @@ var documentsSettings = {
|
||||
save : function() {
|
||||
$('#wopi_apply').attr('disabled', true);
|
||||
var data = {
|
||||
wopi_url : $('#wopi_url').val()
|
||||
wopi_url : $('#wopi_url').val().replace(/\/$/, '')
|
||||
};
|
||||
|
||||
OC.msg.startAction('#documents-admin-msg', t('richdocuments', 'Saving...'));
|
||||
@ -15,6 +15,17 @@ var documentsSettings = {
|
||||
);
|
||||
},
|
||||
|
||||
saveGroups: function(groups) {
|
||||
var data = {
|
||||
'edit_groups': groups
|
||||
};
|
||||
|
||||
$.post(
|
||||
OC.filePath('richdocuments', 'ajax', 'admin.php'),
|
||||
data
|
||||
);
|
||||
},
|
||||
|
||||
saveDocFormat: function(format) {
|
||||
$.post(
|
||||
OC.filePath('richdocuments', 'ajax', 'admin.php'),
|
||||
@ -27,7 +38,19 @@ var documentsSettings = {
|
||||
OC.msg.finishedAction('#documents-admin-msg', response);
|
||||
},
|
||||
|
||||
initEditGroups: function() {
|
||||
var groups = $('#edit_group_select').val();
|
||||
if (groups !== '') {
|
||||
OC.Settings.setupGroupsSelect($('#edit_group_select'));
|
||||
$('.edit-groups-enable').attr('checked', 'checked');
|
||||
} else {
|
||||
$('.edit-groups-enable').attr('checked', null);
|
||||
}
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
documentsSettings.initEditGroups();
|
||||
|
||||
$('#wopi_apply').on('click', documentsSettings.save);
|
||||
|
||||
$(document).on('change', '.doc-format-ooxml', function() {
|
||||
@ -35,6 +58,27 @@ var documentsSettings = {
|
||||
documentsSettings.saveDocFormat(ooxml ? 'ooxml' : 'odf');
|
||||
});
|
||||
|
||||
$(document).on('change', '#edit_group_select', function() {
|
||||
var element = $(this).parent().find('input.edit-groups-enable');
|
||||
var groups = $(this).val();
|
||||
documentsSettings.saveGroups(groups);
|
||||
});
|
||||
|
||||
$(document).on('change', '.edit-groups-enable', function() {
|
||||
var $select = $(this).parent().find('#edit_group_select');
|
||||
$select.val('');
|
||||
|
||||
if (this.checked) {
|
||||
OC.Settings.setupGroupsSelect($select, {
|
||||
placeholder: t('core', 'All')
|
||||
});
|
||||
} else {
|
||||
$select.select2('destroy');
|
||||
}
|
||||
|
||||
$select.change();
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -72,7 +72,6 @@ var documentsMain = {
|
||||
loadErrorHint : '',
|
||||
renderComplete: false, // false till page is rendered with all required data about the document(s)
|
||||
toolbar : '<div id="ocToolbar"><div id="ocToolbarInside"></div><span id="toolbar" class="claro"></span></div>',
|
||||
returnToDir : null, // directory where we started from in the 'Files' app
|
||||
|
||||
UI : {
|
||||
/* Editor wrapper HTML */
|
||||
@ -129,7 +128,7 @@ var documentsMain = {
|
||||
var urlsrc = documentsMain.urlsrc +
|
||||
"WOPISrc=" + wopisrc +
|
||||
"&title=" + encodeURIComponent(title) +
|
||||
"&lang=" + OC.getLocale() +
|
||||
"&lang=" + OC.getLocale().replace('_', '-') + // loleaflet expects a BCP47 language tag syntax
|
||||
"&permission=readonly";
|
||||
|
||||
// access_token - must be passed via a form post
|
||||
@ -163,7 +162,6 @@ var documentsMain = {
|
||||
if (version === 0) {
|
||||
formattedTimestamp = t('richdocuments', 'Latest revision');
|
||||
downloadUrl = OC.generateUrl('apps/files/download'+ documentPath);
|
||||
fileId = fileId.replace(/_.*/, '');
|
||||
} else {
|
||||
downloadUrl = OC.generateUrl('apps/files_versions/download.php?file={file}&revision={revision}',
|
||||
{file: documentPath, revision: version});
|
||||
@ -268,12 +266,8 @@ var documentsMain = {
|
||||
documentsMain.UI.notify(t('richdocuments', 'Failed to revert the document to older version'));
|
||||
}
|
||||
|
||||
// generate file id with returnToDir information in it, if any
|
||||
var fileid = e.currentTarget.parentElement.dataset.fileid.replace(/_.*/, '') +
|
||||
(documentsMain.returnToDir ? '_' + documentsMain.returnToDir : '');
|
||||
|
||||
// load the file again, it should get reverted now
|
||||
window.location = OC.generateUrl('apps/richdocuments/index#{fileid}', {fileid: fileid});
|
||||
window.location = OC.generateUrl('apps/richdocuments/index#{fileid}', {fileid: e.currentTarget.parentElement.dataset.fileid});
|
||||
window.location.reload();
|
||||
documentsMain.overlay.documentOverlay('hide');
|
||||
}
|
||||
@ -320,7 +314,7 @@ var documentsMain = {
|
||||
var urlsrc = documentsMain.urlsrc +
|
||||
"WOPISrc=" + wopisrc +
|
||||
"&title=" + encodeURIComponent(title) +
|
||||
"&lang=" + OC.getLocale() +
|
||||
"&lang=" + OC.getLocale().replace('_', '-') + // loleaflet expects a BCP47 language tag syntax
|
||||
"&closebutton=1" +
|
||||
"&revisionhistory=1";
|
||||
if (!documentsMain.canEdit || action === "view") {
|
||||
@ -426,11 +420,6 @@ var documentsMain = {
|
||||
// Does anything indicate that we need to autostart a session?
|
||||
fileId = getURLParameter('fileid').replace(/^\W*/, '');
|
||||
|
||||
if (fileId.indexOf('_') >= 0) {
|
||||
documentsMain.returnToDir = unescape(fileId.replace(/^[^_]*_/, ''));
|
||||
fileId = fileId.replace(/_.*/, '');
|
||||
}
|
||||
|
||||
documentsMain.show(fileId);
|
||||
|
||||
if (fileId) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* globals FileList, OCA.Files.fileActions, oc_debug */
|
||||
var odfViewer = {
|
||||
isDocuments : false,
|
||||
supportedMimesReadWrite: [
|
||||
supportedMimes: [
|
||||
'application/vnd.oasis.opendocument.text',
|
||||
'application/vnd.oasis.opendocument.spreadsheet',
|
||||
'application/vnd.oasis.opendocument.graphics',
|
||||
@ -12,6 +12,8 @@ var odfViewer = {
|
||||
'application/vnd.wordperfect',
|
||||
'application/msonenote',
|
||||
'application/msword',
|
||||
'application/rtf',
|
||||
'text/rtf',
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
|
||||
'application/vnd.ms-word.document.macroEnabled.12',
|
||||
@ -35,34 +37,19 @@ var odfViewer = {
|
||||
|
||||
register : function() {
|
||||
var i,
|
||||
mimeReadOnly,
|
||||
mimeReadWrite;
|
||||
mime;
|
||||
|
||||
for (i = 0; i < odfViewer.supportedMimesReadWrite.length; ++i) {
|
||||
mimeReadOnly = odfViewer.supportedMimesReadWrite[i];
|
||||
OCA.Files.fileActions.register(mimeReadOnly, 'View', OC.PERMISSION_READ, '', odfViewer.onEdit);
|
||||
OCA.Files.fileActions.setDefault(mimeReadOnly, 'View');
|
||||
}
|
||||
for (i = 0; i < odfViewer.supportedMimesReadWrite.length; ++i) {
|
||||
mimeReadWrite = odfViewer.supportedMimesReadWrite[i];
|
||||
for (i = 0; i < odfViewer.supportedMimes.length; ++i) {
|
||||
mime = odfViewer.supportedMimes[i];
|
||||
OCA.Files.fileActions.register(
|
||||
mimeReadWrite,
|
||||
mime,
|
||||
'Edit',
|
||||
OC.PERMISSION_UPDATE,
|
||||
OC.PERMISSION_UPDATE | OC.PERMISSION_READ,
|
||||
OC.imagePath('core', 'actions/rename'),
|
||||
odfViewer.onEdit,
|
||||
t('richdocuments', 'Edit')
|
||||
);
|
||||
OCA.Files.fileActions.register(
|
||||
mimeReadWrite,
|
||||
'View',
|
||||
OC.PERMISSION_READ,
|
||||
OC.imagePath('core', 'actions/rename'),
|
||||
odfViewer.onEdit,
|
||||
t('richdocuments', 'View')
|
||||
);
|
||||
OCA.Files.fileActions.setDefault(mimeReadWrite, 'View');
|
||||
OCA.Files.fileActions.setDefault(mimeReadWrite, 'Edit');
|
||||
OCA.Files.fileActions.setDefault(mime, 'Edit');
|
||||
}
|
||||
},
|
||||
|
||||
@ -79,17 +66,17 @@ var odfViewer = {
|
||||
var viewer;
|
||||
if($('#isPublic').val() === '1') {
|
||||
viewer = OC.generateUrl(
|
||||
'apps/richdocuments/public?shareToken={shareToken}&fileName={fileName}&requesttoken={requesttoken}',
|
||||
'apps/richdocuments/public?shareToken={shareToken}&fileName={fileName}&requesttoken={requesttoken}&fileId={fileId}',
|
||||
{
|
||||
shareToken: $('#sharingToken').val(),
|
||||
fileName: fileName,
|
||||
dir: fileDir,
|
||||
fileId: fileId,
|
||||
requesttoken: OC.requestToken
|
||||
}
|
||||
);
|
||||
} else {
|
||||
viewer = OC.generateUrl(
|
||||
'apps/richdocuments/index?fileId={fileId}_{dir}&requesttoken={requesttoken}',
|
||||
'apps/richdocuments/index?fileId={fileId}&requesttoken={requesttoken}',
|
||||
{
|
||||
fileId: fileId,
|
||||
dir: fileDir,
|
||||
@ -102,7 +89,7 @@ var odfViewer = {
|
||||
FileList.setViewerMode(true);
|
||||
}
|
||||
|
||||
var $iframe = $('<iframe id="richdocumentsframe" style="width:100%;height:100%;display:block;position:absolute;top:0;" src="'+viewer+'" />');
|
||||
var $iframe = $('<iframe id="richdocumentsframe" allowfullscreen style="width:100%;height:100%;display:block;position:absolute;top:0;z-index:5;" src="'+viewer+'" />');
|
||||
if ($('#isPublic').val()) {
|
||||
// force the preview to adjust its height
|
||||
$('#preview').append($iframe).css({height: '100%'});
|
||||
@ -122,7 +109,6 @@ var odfViewer = {
|
||||
$('#app-content').append($iframe);
|
||||
},
|
||||
|
||||
|
||||
onClose: function() {
|
||||
if(typeof FileList !== "undefined") {
|
||||
FileList.setViewerMode(false);
|
||||
@ -131,8 +117,8 @@ var odfViewer = {
|
||||
$('#richdocumentsframe').remove();
|
||||
},
|
||||
|
||||
registerFilesMenu: function() {
|
||||
var ooxml = false;
|
||||
registerFilesMenu: function(response) {
|
||||
var ooxml = response.doc_format === 'ooxml';
|
||||
|
||||
var docExt, spreadsheetExt, presentationExt;
|
||||
var docMime, spreadsheetMime, presentationMime;
|
||||
@ -219,15 +205,28 @@ $(document).ready(function() {
|
||||
&& typeof OCA.Files !== 'undefined'
|
||||
&& typeof OCA.Files.fileActions !== 'undefined'
|
||||
) {
|
||||
// check if texteditor app is enabled and loaded...
|
||||
if (_.isUndefined(OCA.Files_Texteditor)) {
|
||||
// it is not, so we do open text files with this app too.
|
||||
odfViewer.supportedMimes.push('text/plain');
|
||||
}
|
||||
|
||||
// notice: when changing 'supportedMimes' interactively (e.g. dev console),
|
||||
// register() needs to be re-run to re-register the fileActions.
|
||||
odfViewer.register();
|
||||
odfViewer.registerFilesMenu();
|
||||
|
||||
$.get(
|
||||
OC.filePath('richdocuments', 'ajax', 'settings.php'),
|
||||
{},
|
||||
odfViewer.registerFilesMenu
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// FIXME: Hack for single public file view since it is not attached to the fileslist
|
||||
$(document).ready(function(){
|
||||
// FIXME: FIlter compatible mime types
|
||||
if ($('#isPublic').val() && odfViewer.supportedMimesReadWrite.indexOf($('#mimetype').val()) !== -1) {
|
||||
// FIXME: Filter compatible mime types
|
||||
if ($('#isPublic').val() && odfViewer.supportedMimes.indexOf($('#mimetype').val()) !== -1) {
|
||||
odfViewer.onEdit($('#filename').val());
|
||||
}
|
||||
});
|
||||
@ -244,4 +243,4 @@ $(document).ready(function() {
|
||||
$('#content').removeClass('loading');
|
||||
}
|
||||
}, false);
|
||||
});
|
||||
});
|
||||
|
@ -104,12 +104,24 @@ class DocumentController extends Controller {
|
||||
$params = [
|
||||
'permissions' => $item->getPermissions(),
|
||||
'title' => $item->getName(),
|
||||
'fileId' => $item->getId(),
|
||||
'fileId' => $item->getId() . '_' . $this->settings->getSystemValue('instanceid'),
|
||||
'token' => $token,
|
||||
'urlsrc' => $urlSrc,
|
||||
'path' => '/',
|
||||
'path' => $folder->getRelativePath($item->getPath()),
|
||||
'instanceId' => $this->settings->getSystemValue('instanceid'),
|
||||
];
|
||||
|
||||
$encryptionManager = \OC::$server->getEncryptionManager();
|
||||
if ($encryptionManager->isEnabled())
|
||||
{
|
||||
// Update the current file to be accessible with system public shared key
|
||||
$owner = $item->getOwner()->getUID();
|
||||
$absPath = '/' . $owner . '/' . $item->getInternalPath();
|
||||
$accessList = \OC::$server->getEncryptionFilesHelper()->getAccessList($absPath);
|
||||
$accessList['public'] = true;
|
||||
$encryptionManager->getEncryptionModule()->update($absPath, $owner, $accessList);
|
||||
}
|
||||
|
||||
$response = new TemplateResponse('richdocuments', 'documents', $params, 'empty');
|
||||
$policy = new ContentSecurityPolicy();
|
||||
$policy->addAllowedFrameDomain($this->appConfig->getAppValue('wopi_url'));
|
||||
@ -130,7 +142,7 @@ class DocumentController extends Controller {
|
||||
* @return TemplateResponse
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function publicPage($shareToken, $fileName) {
|
||||
public function publicPage($shareToken, $fileName, $fileId) {
|
||||
try {
|
||||
$share = $this->shareManager->getShareByToken($shareToken);
|
||||
// not authenticated ?
|
||||
@ -144,7 +156,7 @@ class DocumentController extends Controller {
|
||||
|
||||
$node = $share->getNode();
|
||||
if($node instanceof Folder) {
|
||||
$item = $node->get($fileName);
|
||||
$item = $node->getById($fileId)[0];
|
||||
} else {
|
||||
$item = $node;
|
||||
}
|
||||
@ -153,10 +165,11 @@ class DocumentController extends Controller {
|
||||
$params = [
|
||||
'permissions' => $share->getPermissions(),
|
||||
'title' => $item->getName(),
|
||||
'fileId' => $item->getId(),
|
||||
'fileId' => $item->getId() . '_' . $this->settings->getSystemValue('instanceid'),
|
||||
'token' => $token,
|
||||
'urlsrc' => $urlSrc,
|
||||
'path' => '/',
|
||||
'instanceId' => $this->settings->getSystemValue('instanceid'),
|
||||
];
|
||||
|
||||
$response = new TemplateResponse('richdocuments', 'documents', $params, 'empty');
|
||||
@ -231,12 +244,13 @@ class DocumentController extends Controller {
|
||||
if ($content && $view->file_put_contents($path, $content)) {
|
||||
$info = $view->getFileInfo($path);
|
||||
$ret = $this->wopiParser->getUrlSrc($mimetype);
|
||||
$lolang = strtolower(str_replace('_', '-', $this->settings->getUserValue($this->uid, 'core', 'lang', 'en')));
|
||||
$response = array(
|
||||
'status' => 'success',
|
||||
'fileid' => $info['fileid'],
|
||||
'fileid' => $info['fileid'] . '_' . $this->settings->getSystemValue('instanceid'),
|
||||
'urlsrc' => $ret['urlsrc'],
|
||||
'action' => $ret['action'],
|
||||
'lolang' => $this->settings->getUserValue($this->uid, 'core', 'lang', 'en'),
|
||||
'lolang' => $lolang,
|
||||
'data' => \OCA\Files\Helper::formatFileInfo($info)
|
||||
);
|
||||
} else {
|
||||
|
@ -45,12 +45,27 @@ class SettingsController extends Controller{
|
||||
$this->discoveryManager = $discoveryManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
*
|
||||
* @return JSONResponse
|
||||
*/
|
||||
public function getSettings() {
|
||||
return new JSONResponse([
|
||||
'wopi_url' => $this->appConfig->getAppValue('wopi_url'),
|
||||
'edit_groups' => $this->appConfig->getAppValue('edit_groups'),
|
||||
'doc_format' => $this->appConfig->getAppValue('doc_format'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $wopi_url
|
||||
* @param string $edit_groups
|
||||
* @param string $doc_format
|
||||
* @return JSONResponse
|
||||
*/
|
||||
public function setSettings($wopi_url,
|
||||
$edit_groups,
|
||||
$doc_format){
|
||||
$message = $this->l10n->t('Saved');
|
||||
|
||||
@ -63,6 +78,10 @@ class SettingsController extends Controller{
|
||||
}
|
||||
}
|
||||
|
||||
if ($edit_groups !== null){
|
||||
$this->appConfig->setAppValue('edit_groups', $edit_groups);
|
||||
}
|
||||
|
||||
if ($doc_format !== null) {
|
||||
$this->appConfig->setAppValue('doc_format', $doc_format);
|
||||
}
|
||||
|
@ -21,7 +21,9 @@
|
||||
|
||||
namespace OCA\Richdocuments\Controller;
|
||||
|
||||
use OC\Files\View;
|
||||
use OCA\Richdocuments\Db\Wopi;
|
||||
use OCA\Richdocuments\Helper;
|
||||
use OCA\Richdocuments\WOPI\Parser;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http;
|
||||
@ -35,32 +37,22 @@ use OCP\AppFramework\Http\StreamResponse;
|
||||
class WopiController extends Controller {
|
||||
/** @var IRootFolder */
|
||||
private $rootFolder;
|
||||
/** @var string */
|
||||
private $userId;
|
||||
/** @var IUserManager */
|
||||
private $userManager;
|
||||
/** @var Parser */
|
||||
private $wopiParser;
|
||||
|
||||
// Signifies LOOL that document has been changed externally in this storage
|
||||
const LOOL_STATUS_DOC_CHANGED = 1010;
|
||||
|
||||
/**
|
||||
* @param string $appName
|
||||
* @param IRequest $request
|
||||
* @param IRootFolder $rootFolder
|
||||
* @param string $UserId
|
||||
* @param IUserManager $userManager
|
||||
* @param Parser $wopiParser
|
||||
*/
|
||||
public function __construct($appName,
|
||||
$UserId,
|
||||
IRequest $request,
|
||||
IRootFolder $rootFolder,
|
||||
IUserManager $userManager,
|
||||
Parser $wopiParser) {
|
||||
IRootFolder $rootFolder) {
|
||||
parent::__construct($appName, $request);
|
||||
$this->rootFolder = $rootFolder;
|
||||
$this->userId = $UserId;
|
||||
$this->userManager = $userManager;
|
||||
$this->wopiParser = $wopiParser;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,16 +68,9 @@ class WopiController extends Controller {
|
||||
public function checkFileInfo($fileId) {
|
||||
$token = $this->request->getParam('access_token');
|
||||
|
||||
$arr = explode('_', $fileId, 2);
|
||||
$version = '0';
|
||||
if (count($arr) === 2) {
|
||||
list($fileId, $version) = $arr;
|
||||
}
|
||||
|
||||
$row = new Wopi();
|
||||
$row->loadBy('token', $token);
|
||||
|
||||
$res = $row->getPathForToken($fileId, $version, $token);
|
||||
list($fileId, , $version) = Helper::parseFileId($fileId);
|
||||
$db = new Wopi();
|
||||
$res = $db->getPathForToken($fileId, $token);
|
||||
if ($res === false) {
|
||||
return new JSONResponse([], Http::STATUS_FORBIDDEN);
|
||||
}
|
||||
@ -110,9 +95,10 @@ class WopiController extends Controller {
|
||||
'Version' => $version,
|
||||
'UserId' => $res['editor'] !== '' ? $res['editor'] : 'Guest user',
|
||||
'OwnerId' => $res['owner'],
|
||||
'UserFriendlyName' => $res['editor'] !== '' ? $res['editor'] : 'Guest user',
|
||||
'UserFriendlyName' => $res['editor'] !== '' ? \OC_User::getDisplayName($res['editor']) : 'Guest user',
|
||||
'UserCanWrite' => $res['canwrite'] ? true : false,
|
||||
'PostMessageOrigin' => $res['server_host'],
|
||||
'LastModifiedTime' => Helper::toISO8601($file->getMtime())
|
||||
]
|
||||
);
|
||||
}
|
||||
@ -130,22 +116,32 @@ class WopiController extends Controller {
|
||||
*/
|
||||
public function getFile($fileId,
|
||||
$access_token) {
|
||||
$arr = explode('_', $fileId, 2);
|
||||
$version = '0';
|
||||
if (count($arr) === 2) {
|
||||
list($fileId, $version) = $arr;
|
||||
}
|
||||
|
||||
list($fileId, , $version) = Helper::parseFileId($fileId);
|
||||
$row = new Wopi();
|
||||
$row->loadBy('token', $access_token);
|
||||
|
||||
$res = $row->getPathForToken($fileId, $version, $access_token);
|
||||
|
||||
$res = $row->getPathForToken($fileId, $access_token);
|
||||
try {
|
||||
/** @var File $file */
|
||||
$userFolder = $this->rootFolder->getUserFolder($res['owner']);
|
||||
$file = $userFolder->getById($fileId)[0];
|
||||
$response = new StreamResponse($file->fopen('rb'));
|
||||
\OC_User::setIncognitoMode(true);
|
||||
if ($version !== '0')
|
||||
{
|
||||
$view = new View('/' . $res['owner'] . '/files');
|
||||
$relPath = $view->getRelativePath($file->getPath());
|
||||
$versionPath = '/files_versions/' . $relPath . '.v' . $version;
|
||||
$view = new View('/' . $res['owner']);
|
||||
if ($view->file_exists($versionPath)){
|
||||
$response = new StreamResponse($view->fopen($versionPath, 'rb'));
|
||||
}
|
||||
else {
|
||||
$response->setStatus(Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$response = new StreamResponse($file->fopen('rb'));
|
||||
}
|
||||
$response->addHeader('Content-Disposition', 'attachment');
|
||||
$response->addHeader('Content-Type', 'application/octet-stream');
|
||||
return $response;
|
||||
@ -165,28 +161,48 @@ class WopiController extends Controller {
|
||||
* @param string $access_token
|
||||
* @return JSONResponse
|
||||
*/
|
||||
public function putFile($fileId, $access_token) {
|
||||
$arr = explode('_', $fileId, 2);
|
||||
$version = '0';
|
||||
if (count($arr) === 2) {
|
||||
list($fileId, $version) = $arr;
|
||||
}
|
||||
public function putFile($fileId,
|
||||
$access_token) {
|
||||
list($fileId, , $version) = Helper::parseFileId($fileId);
|
||||
|
||||
$row = new Wopi();
|
||||
$row->loadBy('token', $access_token);
|
||||
|
||||
$res = $row->getPathForToken($fileId, $version, $access_token);
|
||||
$res = $row->getPathForToken($fileId, $access_token);
|
||||
if (!$res['canwrite']) {
|
||||
return new JSONResponse([], Http::STATUS_FORBIDDEN);
|
||||
}
|
||||
|
||||
|
||||
|
||||
try {
|
||||
/** @var File $file */
|
||||
$userFolder = $this->rootFolder->getUserFolder($res['owner']);
|
||||
$file = $userFolder->getById($fileId)[0];
|
||||
|
||||
$wopiHeaderTime = $this->request->getHeader('X-LOOL-WOPI-Timestamp');
|
||||
if (!is_null($wopiHeaderTime) && $wopiHeaderTime != Helper::toISO8601($file->getMTime())) {
|
||||
\OC::$server->getLogger()->debug('Document timestamp mismatch ! WOPI client says mtime {headerTime} but storage says {storageTime}', [
|
||||
'headerTime' => $wopiHeaderTime,
|
||||
'storageTime' => Helper::toISO8601($file->getMtime())
|
||||
]);
|
||||
// Tell WOPI client about this conflict.
|
||||
return new JSONResponse(['LOOLStatusCode' => self::LOOL_STATUS_DOC_CHANGED], Http::STATUS_CONFLICT);
|
||||
}
|
||||
|
||||
$content = fopen('php://input', 'rb');
|
||||
// Setup the FS which is needed to emit hooks (versioning).
|
||||
\OC_Util::tearDownFS();
|
||||
\OC_Util::setupFS($res['owner']);
|
||||
|
||||
// Set the user to register the change under his name
|
||||
$editor = \OC::$server->getUserManager()->get($res['editor']);
|
||||
if (!is_null($editor)) {
|
||||
\OC::$server->getUserSession()->setUser($editor);
|
||||
}
|
||||
|
||||
$file->putContent($content);
|
||||
return new JSONResponse();
|
||||
return new JSONResponse(['LastModifiedTime' => Helper::toISO8601($file->getMtime())]);
|
||||
} catch (\Exception $e) {
|
||||
return new JSONResponse([], Http::STATUS_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
@ -49,8 +49,6 @@ class Admin implements ISettings {
|
||||
'wopi_url' => $this->config->getAppValue('richdocuments', 'wopi_url'),
|
||||
'edit_groups' => $this->config->getAppValue('richdocuments', 'edit_groups'),
|
||||
'doc_format' => $this->config->getAppValue('richdocuments', 'doc_format'),
|
||||
'test_wopi_url' => $this->config->getAppValue('richdocuments', 'test_wopi_url'),
|
||||
'test_server_groups' => $this->config->getAppValue('richdocuments', 'test_server_groups')
|
||||
],
|
||||
'blank'
|
||||
);
|
||||
|
@ -22,6 +22,7 @@
|
||||
namespace OCA\Richdocuments;
|
||||
|
||||
use OC\Share\Constants;
|
||||
use OCA\Richdocuments\Helper;
|
||||
use OCA\Richdocuments\Db\Wopi;
|
||||
use OCA\Richdocuments\WOPI\Parser;
|
||||
use OCP\Files\File;
|
||||
@ -49,11 +50,13 @@ class TokenManager {
|
||||
IManager $shareManager,
|
||||
IURLGenerator $urlGenerator,
|
||||
Parser $wopiParser,
|
||||
AppConfig $appConfig,
|
||||
$UserId) {
|
||||
$this->rootFolder = $rootFolder;
|
||||
$this->shareManager = $shareManager;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->wopiParser = $wopiParser;
|
||||
$this->appConfig = $appConfig;
|
||||
$this->userId = $UserId;
|
||||
}
|
||||
|
||||
@ -64,33 +67,49 @@ class TokenManager {
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getToken($fileId, $shareToken = null) {
|
||||
$arr = explode('_', $fileId, 2);
|
||||
$version = '0';
|
||||
if (count($arr) === 2) {
|
||||
list($fileId, $version) = $arr;
|
||||
}
|
||||
|
||||
list($fileId,, $version) = Helper::parseFileId($fileId);
|
||||
$owneruid = null;
|
||||
// if the user is not logged-in do use the sharers storage
|
||||
if($shareToken !== null) {
|
||||
/** @var File $file */
|
||||
$rootFolder = $this->rootFolder;
|
||||
$share = $this->shareManager->getShareByToken($shareToken);
|
||||
$updatable = (bool)($share->getPermissions() & \OCP\Constants::PERMISSION_UPDATE);
|
||||
$owneruid = $share->getShareOwner();
|
||||
} else {
|
||||
try {
|
||||
/** @var File $file */
|
||||
$rootFolder = $this->rootFolder->getUserFolder($this->userId);
|
||||
$updatable = $rootFolder->isUpdateable();
|
||||
// Check if the editor (user who is accessing) is in editable group
|
||||
// UserCanWrite only if
|
||||
// 1. No edit groups are set or
|
||||
// 2. if they are set, it is in one of the edit groups
|
||||
$editorUid = \OC::$server->getUserSession()->getUser()->getUID();
|
||||
$editGroups = array_filter(explode('|', $this->appConfig->getAppValue('edit_groups')));
|
||||
if ($updatable && count($editGroups) > 0) {
|
||||
$updatable = false;
|
||||
foreach($editGroups as $editGroup) {
|
||||
$editorGroup = \OC::$server->getGroupManager()->get($editGroup);
|
||||
if ($editorGroup !== null && sizeof($editorGroup->searchUsers($editorUid)) > 0) {
|
||||
$updatable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
/** @var File $file */
|
||||
$file = $rootFolder->getById($fileId)[0];
|
||||
|
||||
// If its a public share, use the owner from the share, otherwise check the file object
|
||||
if (is_null($owneruid)) {
|
||||
$owneruid = $file->getOwner()->getUID();
|
||||
}
|
||||
$row = new Wopi();
|
||||
$serverHost = $this->urlGenerator->getAbsoluteURL('/');//$this->request->getServerProtocol() . '://' . $this->request->getServerHost();
|
||||
$token = $row->generateFileToken($fileId, $file->getOwner()->getUID(), $this->userId, $version, (int)$updatable, $serverHost);
|
||||
$token = $row->generateFileToken($fileId, $owneruid, $this->userId, $version, (int)$updatable, $serverHost);
|
||||
|
||||
try {
|
||||
|
||||
@ -102,4 +121,4 @@ class TokenManager {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -56,12 +56,12 @@ class Wopi extends \OCA\Richdocuments\Db{
|
||||
* constructs and validates the path.
|
||||
* Returns the path, if valid, else false.
|
||||
*/
|
||||
public function getPathForToken($fileId, $version, $token){
|
||||
public function getPathForToken($fileId, $token){
|
||||
|
||||
$wopi = new Wopi();
|
||||
$row = $wopi->loadBy('token', $token)->getData();
|
||||
\OC::$server->getLogger()->debug('Loaded WOPI Token record: {row}.', [ 'row' => $row ]);
|
||||
if (count($row) == 0)
|
||||
if (count($row) === 0)
|
||||
{
|
||||
// Invalid token.
|
||||
http_response_code(401);
|
||||
@ -75,11 +75,6 @@ class Wopi extends \OCA\Richdocuments\Db{
|
||||
//$wopi->deleteBy('id', $row['id']);
|
||||
//return false;
|
||||
}
|
||||
if ($row['fileid'] != $fileId || $row['version'] != $version){
|
||||
// File unknown / user unauthorized (for the requested file).
|
||||
http_response_code(404);
|
||||
return false;
|
||||
}
|
||||
|
||||
return array(
|
||||
'owner' => $row['owner_uid'],
|
||||
|
@ -11,9 +11,53 @@
|
||||
|
||||
namespace OCA\Richdocuments;
|
||||
|
||||
use \DateTime;
|
||||
use \DateTimeZone;
|
||||
|
||||
class Helper {
|
||||
const APP_ID = 'richdocuments';
|
||||
|
||||
/**
|
||||
* @param string $fileId
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function parseFileId($fileId) {
|
||||
$arr = explode('_', $fileId);
|
||||
if (count($arr) === 1) {
|
||||
$fileId = $arr[0];
|
||||
$instanceId = '';
|
||||
$version = '0';
|
||||
} else if (count($arr) === 2) {
|
||||
list($fileId, $instanceId) = $arr;
|
||||
$version = '0';
|
||||
} else if (count($arr) === 3) {
|
||||
list($fileId, $instanceId, $version) = $arr;
|
||||
} else {
|
||||
throw new \Exception('$fileId has not the expected format');
|
||||
}
|
||||
|
||||
return [
|
||||
$fileId,
|
||||
$instanceId,
|
||||
$version,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* WOPI helper function to convert to ISO 8601 round-trip format.
|
||||
* @param integer $time Must be seconds since unix epoch
|
||||
*/
|
||||
public static function toISO8601($time)
|
||||
{
|
||||
// TODO: Be more precise and don't ignore milli, micro seconds ?
|
||||
$datetime = DateTime::createFromFormat('U', $time, new DateTimeZone('UTC'));
|
||||
if ($datetime)
|
||||
return $datetime->format('Y-m-d\TH:i:s.u\Z');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function getNewFileName($view, $path, $prepend = ' '){
|
||||
$fileNum = 1;
|
||||
|
||||
|
@ -9,7 +9,10 @@ script('richdocuments', 'admin');
|
||||
<br/><button type="button" id="wopi_apply"><?php p($l->t('Apply')) ?></button>
|
||||
<span id="documents-admin-msg" class="msg"></span>
|
||||
<br/>
|
||||
|
||||
<input type="checkbox" class="edit-groups-enable" id="edit_groups_enable-richdocuments" />
|
||||
<label for="edit_groups_enable-richdocuments"><?php p($l->t('Enable edit for specific groups')) ?></label>
|
||||
<input type="hidden" id="edit_group_select" value="<?php p($_['edit_groups'])?>" title="<?php p($l->t('All')); ?>" style="width: 200px">
|
||||
<br/>
|
||||
<input type="checkbox" class="doc-format-ooxml" id="doc_format_ooxml_enable-richdocuments" <?php p($_['doc_format'] === 'ooxml' ? 'checked' : '') ?> />
|
||||
<label for="doc_format_ooxml_enable-richdocuments"><?php p($l->t('Use OOXML by default for new files')) ?></label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -5,6 +5,7 @@
|
||||
var richdocuments_token = '<?php p($_['token']) ?>';
|
||||
var richdocuments_urlsrc = '<?php p($_['urlsrc']) ?>';
|
||||
var richdocuments_path = '<?php p($_['path']) ?>';
|
||||
var instanceId = '<?php p($_['instanceId']) ?>';
|
||||
</script>
|
||||
|
||||
<?php
|
||||
|
Loading…
x
Reference in New Issue
Block a user