diff --git a/appinfo/database.xml b/appinfo/database.xml index 3d0eead9..722fc1ee 100644 --- a/appinfo/database.xml +++ b/appinfo/database.xml @@ -305,6 +305,14 @@ 4 The unique ID of the file authorized + + version + integer + true + 0 + 4 + Authorized version, if any, of given fileid + path text diff --git a/controller/documentcontroller.php b/controller/documentcontroller.php index e5f49d76..61d92d2e 100644 --- a/controller/documentcontroller.php +++ b/controller/documentcontroller.php @@ -346,10 +346,19 @@ class DocumentController extends Controller { * Only for authenticated users! */ public function wopiGetToken($fileId){ - \OC::$server->getLogger()->debug('Generating WOPI Token for file {fileId}.', [ 'app' => $this->appName, 'fileId' => $fileId ]); + $arr = explode('_', $fileId, 2); + $version = '0'; + if (count($arr) == 2) { + $fileId = $arr[0]; + $version = $arr[1]; + } + + \OC::$server->getLogger()->debug('Generating WOPI Token for file {fileId}, version {version}.', [ 'app' => $this->appName, 'fileId' => $fileId, 'version' => $version ]); + + $row = new Db\Wopi(); - $token = $row->generateFileToken($fileId); + $token = $row->generateFileToken($fileId, $version); // Return the token. return array( @@ -367,12 +376,19 @@ class DocumentController extends Controller { public function wopiCheckFileInfo($fileId){ $token = $this->request->getParam('access_token'); - \OC::$server->getLogger()->debug('Getting info about file {fileId} by token {token}.', [ 'app' => $this->appName, 'fileId' => $fileId, 'token' => $token ]); + $arr = explode('_', $fileId, 2); + $version = '0'; + if (count($arr) == 2) { + $fileId = $arr[0]; + $version = $arr[1]; + } + + \OC::$server->getLogger()->debug('Getting info about file {fileId}, version {version} by token {token}.', [ 'app' => $this->appName, 'fileId' => $fileId, 'version' => $version, 'token' => $token ]); $row = new Db\Wopi(); $row->loadBy('token', $token); - $res = $row->getPathForToken($fileId, $token); + $res = $row->getPathForToken($fileId, $version, $token); if ($res == false || http_response_code() != 200) { return false; @@ -389,6 +405,7 @@ class DocumentController extends Controller { return array( 'BaseFileName' => $baseFileName, 'Size' => $size, + 'Version' => $version //'DownloadUrl' => '', //'FileUrl' => '', ); @@ -404,13 +421,51 @@ class DocumentController extends Controller { public function wopiGetFile($fileId){ $token = $this->request->getParam('access_token'); - \OC::$server->getLogger()->debug('Getting contents of file {fileId} by token {token}.', [ 'app' => $this->appName, 'fileId' => $fileId, 'token' => $token ]); + $arr = explode('_', $fileId, 2); + $version = '0'; + if (count($arr) == 2) { + $fileId = $arr[0]; + $version = $arr[1]; + } + + \OC::$server->getLogger()->debug('Getting contents of file {fileId}, version {version} by token {token}.', [ 'app' => $this->appName, 'fileId' => $fileId, 'version' => $version, 'token' => $token ]); $row = new Db\Wopi(); $row->loadBy('token', $token); //TODO: Support X-WOPIMaxExpectedSize header. - $res = $row->getPathForToken($fileId, $token); + $res = $row->getPathForToken($fileId, $version, $token); + + // If some previous version is requested, fetch it from Files_Version app + if ($version !== '0') { + \OCP\JSON::checkAppEnabled('files_versions'); + + // Login as this user + $editorid = $res['editor']; + $users = \OC::$server->getUserManager()->search($editorid, 1, 0); + if (count($users) > 0) + { + $user = array_shift($users); + if (strcasecmp($user->getUID(),$editorid) === 0) + { + \OC::$server->getUserSession()->setUser($user); + } + } + + \OCP\JSON::checkLoggedIn(); + + // Setup the FS + \OC_Util::tearDownFS(); + \OC_Util::setupFS($editorid, '/' . $editorid . '/files'); + + list($owner_uid, $filename) = \OCA\Files_Versions\Storage::getUidAndFilename($res['path']); + $versionName = '/files_versions/' . $filename . '.v' . $version; + + \OC_Util::tearDownFS(); + + return new DownloadResponse($this->request, $owner_uid, $versionName); + } + return new DownloadResponse($this->request, $res['owner'], '/files' . $res['path']); } @@ -424,12 +479,27 @@ class DocumentController extends Controller { public function wopiPutFile($fileId){ $token = $this->request->getParam('access_token'); - \OC::$server->getLogger()->debug('Putting contents of file {fileId} by token {token}.', [ 'app' => $this->appName, 'fileId' => $fileId, 'token' => $token ]); + $arr = explode('_', $fileId, 2); + $version = '0'; + if (count($arr) == 2) { + $fileId = $arr[0]; + $version = $arr[1]; + } + + // Changing a previous version of the file is not possible + // Ignore WOPI put if such a request is encountered + if ($version !== '0') { + return array( + 'status' => 'success' + ); + } + + \OC::$server->getLogger()->debug('Putting contents of file {fileId}, version {version} by token {token}.', [ 'app' => $this->appName, 'fileId' => $fileId, 'version' => $version, 'token' => $token ]); $row = new Db\Wopi(); $row->loadBy('token', $token); - $res = $row->getPathForToken($fileId, $token); + $res = $row->getPathForToken($fileId, $version, $token); // Log-in as the user to regiser the change under her name. $editorid = $res['editor']; @@ -525,7 +595,7 @@ class DocumentController extends Controller { * Get file information about single document with fileId */ public function get($fileId){ - $documents = array(); + $documents = array(); $documents[0] = Storage::getDocumentById($fileId); return $this->prepareDocuments($documents); diff --git a/css/style.css b/css/style.css index ccdcad83..51c7cecf 100644 --- a/css/style.css +++ b/css/style.css @@ -180,6 +180,72 @@ bottom: 0; } +#revViewerContainer{ + position: absolute; + width: 85%; + z-index: 600; + background-color: #ddd !important; + top: 45px; + bottom: 0; +} + +#revPanelContainer{ + position: absolute; + width: 15%; + z-index: 600; + background-color: #efefef !important; + right: 0; + top: 45px; + bottom: 0; + box-sizing: border-box; + overflow: auto; +} + +/* Title */ +#revPanelHeader{ + height: 69px; + border-bottom: 1px solid #ddd; + margin: 0 0; + box-sizing: border-box; + padding-left: 15px; + padding-top: 15px; +} + +#revPanelHeader h2{ + margin: 0 0; +} + +.loleaflet-font{ + font-family: "Segoe UI", Tahoma, Arial, Helvetica, sans-serif !important; +} + +#revisionsContainer{ + list-style: none; +} + +#revisionsContainer li{ + width: 100%; + cursor: default; + height: 45px; + float: left; + border-bottom: 1px solid #ddd; + box-sizing: border-box; + padding: 10px 0; +} + +#revisionsContainer a{ + padding-left: 15px; +} + +#revisionsContainer li:hover, #revisionsContainer li.active{ + background-color: rgba(0, 0, 0, 0.1); +} + +#show-more-versions{ + width: 100%; + padding: 10px; +} + #documents-overlay, #documents-overlay-below{ position: fixed; top: 45px; @@ -189,7 +255,7 @@ filter:alpha(opacity=60); opacity: .6; z-index: 1000; - background-color: #fff; + background-color: #fff; } #documents-overlay-below{ diff --git a/js/documents.js b/js/documents.js index b24d12cf..c81b27ff 100644 --- a/js/documents.js +++ b/js/documents.js @@ -180,7 +180,8 @@ $.widget('oc.documentOverlay', { }); var documentsMain = { - isEditormode : false, + isEditorMode : false, + isViewerMode: false, isGuest : false, memberId : false, esId : false, @@ -199,13 +200,174 @@ var documentsMain = { container : '
' + '
', + viewContainer: '
' + + '
' + + '
', + + revHistoryContainerTemplate: '
' + + '
' + + '

Revision History

' + + '{{filename}}' + + '
' + + '
' + + '
    ' + + '
    ' + + '' + + '
    ', + + revHistoryItemTemplate: '
  • ' + + '' + + '{{formattedTimestamp}}' + + '' + + '
  • ', + /* Previous window title */ mainTitle : '', + /* Number of revisions already loaded */ + revisionsStart: 0, init : function(){ documentsMain.UI.mainTitle = $('title').text(); }, + showViewer: function(fileId, title){ + // remove previous viewer, if open, and set a new one + if (documentsMain.isViewerMode) { + $('#revViewer').remove(); + $('#revViewerContainer').prepend($('
    ')); + } + + $.get(OC.generateUrl('apps/richdocuments/wopi/token/{fileId}', { fileId: fileId }), + function (result) { + // WOPISrc - URL that loolwsd will access (ie. pointing to ownCloud) + var wopiurl = window.location.protocol + '//' + window.location.host + OC.generateUrl('apps/richdocuments/wopi/files/{file_id}', {file_id: fileId}); + var wopisrc = encodeURIComponent(wopiurl); + + // urlsrc - the URL from discovery xml that we access for the particular + // document; we add various parameters to that. + // The discovery is available at + // https://:9980/hosting/discovery + var urlsrc = $('li[data-id='+ fileId.replace(/_.*/, '') +']>a').attr('urlsrc') + + "WOPISrc=" + wopisrc + + "&title=" + encodeURIComponent(title) + + "&closebutton=1" + + "&permission=readonly"; + + // access_token - must be passed via a form post + var access_token = encodeURIComponent(result.token); + + // form to post the access token for WOPISrc + var form = '
    ' + + '
    '; + + // iframe that contains the Collabora Online Viewer + var frame = '