[Libreoffice-commits] online.git: loleaflet/src test/Makefile.am test/UnitWOPIRenameFile.cpp test/WopiTestServer.hpp wsd/ClientSession.cpp wsd/DocumentBroker.cpp wsd/DocumentBroker.hpp wsd/Storage.cpp wsd/Storage.hpp
Libreoffice Gerrit user
logerrit at kemper.freedesktop.org
Mon May 13 19:30:37 UTC 2019
loleaflet/src/control/Control.Toolbar.js | 10 +++
loleaflet/src/control/Toolbar.js | 8 ++
loleaflet/src/core/Socket.js | 5 +
loleaflet/src/errormessages.js | 3 -
loleaflet/src/map/handler/Map.WOPI.js | 4 +
test/Makefile.am | 6 +-
test/UnitWOPIRenameFile.cpp | 90 +++++++++++++++++++++++++++++++
test/WopiTestServer.hpp | 25 ++++++--
wsd/ClientSession.cpp | 18 +++++-
wsd/DocumentBroker.cpp | 33 ++++++++---
wsd/DocumentBroker.hpp | 4 -
wsd/Storage.cpp | 40 ++++++++-----
wsd/Storage.hpp | 20 +++++-
13 files changed, 224 insertions(+), 42 deletions(-)
New commits:
commit 0dbf9bcf27155fa846977bdf0b8e990e0bc07211
Author: merttumer <mert.tumer at collabora.com>
AuthorDate: Tue Apr 30 17:21:44 2019 +0300
Commit: merttumer <mert.tumer at collabora.com>
CommitDate: Mon May 13 22:29:40 2019 +0300
Added RenameFile Support for WOPI
This patch concerns rename file operation when the integration
supports it
Signed-off-by: merttumer <mert.tumer at collabora.com>
Change-Id: Ibb4f615b91dda2491bfcd4d4738198d69eca4e6f
Reviewed-on: https://gerrit.libreoffice.org/71587
Reviewed-by: Jan Holesovsky <kendy at collabora.com>
Tested-by: Jan Holesovsky <kendy at collabora.com>
Signed-off-by: merttumer <mert.tumer at collabora.com>
diff --git a/loleaflet/src/control/Control.Toolbar.js b/loleaflet/src/control/Control.Toolbar.js
index 287a1598d..14a762315 100644
--- a/loleaflet/src/control/Control.Toolbar.js
+++ b/loleaflet/src/control/Control.Toolbar.js
@@ -1151,7 +1151,15 @@ function onSearchKeyDown(e) {
function documentNameConfirm() {
var value = $('#document-name-input').val();
if (value !== null && value != '' && value != map['wopi'].BaseFileName) {
- map.saveAs(value);
+ if (map['wopi'].UserCanRename && map['wopi'].SupportsRename) {
+ // file name must be without the extension
+ if (value.lastIndexOf('.') > 0)
+ value = value.substr(0, value.lastIndexOf('.'));
+ map.renameFile(value);
+ } else {
+ // saveAs for rename
+ map.saveAs(value);
+ }
}
map._onGotFocus();
}
diff --git a/loleaflet/src/control/Toolbar.js b/loleaflet/src/control/Toolbar.js
index 3258e8b10..f75c0ae31 100644
--- a/loleaflet/src/control/Toolbar.js
+++ b/loleaflet/src/control/Toolbar.js
@@ -107,6 +107,14 @@ L.Map.include({
'options=' + options);
},
+ renameFile: function (filename) {
+ if (!filename) {
+ return;
+ }
+ this.showBusy(_('Renaming...'), false);
+ this._socket.sendMessage('renamefile filename=' + encodeURIComponent(filename));
+ },
+
applyStyle: function (style, familyName) {
if (!style || !familyName) {
this.fire('error', {cmd: 'setStyle', kind: 'incorrectparam'});
diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js
index 7f45eb73a..3a3d8f269 100644
--- a/loleaflet/src/core/Socket.js
+++ b/loleaflet/src/core/Socket.js
@@ -433,6 +433,9 @@ L.Socket = L.Class.extend({
else if (command.errorKind === 'savefailed') {
storageError = errorMessages.storage.savefailed;
}
+ else if (command.errorKind === 'renamefailed') {
+ storageError = errorMessages.storage.renamefailed;
+ }
else if (command.errorKind === 'saveunauthorized') {
storageError = errorMessages.storage.saveunauthorized;
}
@@ -628,7 +631,7 @@ L.Socket = L.Class.extend({
', last: ' + (command.rendercount - this._map._docLayer._debugRenderCount));
this._map._docLayer._debugRenderCount = command.rendercount;
}
- else if (textMsg.startsWith('saveas:')) {
+ else if (textMsg.startsWith('saveas:') || textMsg.startsWith('renamefile:')) {
this._map.hideBusy();
if (command !== undefined && command.url !== undefined && command.url !== '') {
this.close();
diff --git a/loleaflet/src/errormessages.js b/loleaflet/src/errormessages.js
index b4b04838f..7e790c833 100644
--- a/loleaflet/src/errormessages.js
+++ b/loleaflet/src/errormessages.js
@@ -28,7 +28,8 @@ errorMessages.storage = {
loadfailed: _('Failed to read document from storage. Please contact your storage server (%storageserver) administrator.'),
savediskfull: _('Save failed due to no disk space left on storage server. Document will now be read-only. Please contact the server (%storageserver) administrator to continue editing.'),
saveunauthorized: _('Document cannot be saved due to expired or invalid access token.'),
- savefailed: _('Document cannot be saved. Check your permissions or contact the storage server administrator.')
+ savefailed: _('Document cannot be saved. Check your permissions or contact the storage server administrator.'),
+ renamefailed: _('Document cannot be renamed. Check your permissions or contact the storage server administrator.')
};
if (typeof window !== 'undefined') {
diff --git a/loleaflet/src/map/handler/Map.WOPI.js b/loleaflet/src/map/handler/Map.WOPI.js
index cf0bf7013..ff9200086 100644
--- a/loleaflet/src/map/handler/Map.WOPI.js
+++ b/loleaflet/src/map/handler/Map.WOPI.js
@@ -24,6 +24,8 @@ L.Map.WOPI = L.Handler.extend({
EnableShare: false,
HideUserList: null,
CallPythonScriptSource: null,
+ SupportsRename: false,
+ UserCanRename: false,
_appLoadedConditions: {
docloaded: false,
@@ -79,6 +81,8 @@ L.Map.WOPI = L.Handler.extend({
this.DisableInactiveMessages = !!wopiInfo['DisableInactiveMessages'];
this.UserCanNotWriteRelative = !!wopiInfo['UserCanNotWriteRelative'];
this.EnableInsertRemoteImage = !!wopiInfo['EnableInsertRemoteImage'];
+ this.SupportsRename = !!wopiInfo['SupportsRename'];
+ this.UserCanRename = !!wopiInfo['UserCanRename'];
this.EnableShare = !!wopiInfo['EnableShare'];
if (wopiInfo['HideUserList'])
this.HideUserList = wopiInfo['HideUserList'].split(',');
diff --git a/test/Makefile.am b/test/Makefile.am
index bd107629e..0432955ae 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -20,7 +20,7 @@ noinst_LTLIBRARIES = \
unit-fuzz.la unit-oob.la unit-oauth.la \
unit-wopi.la unit-wopi-saveas.la \
unit-wopi-ownertermination.la unit-wopi-versionrestore.la \
- unit-wopi-documentconflict.la
+ unit-wopi-documentconflict.la unit_wopi_renamefile.la
MAGIC_TO_FORCE_SHLIB_CREATION = -rpath /dummy
@@ -110,6 +110,8 @@ unit_wopi_versionrestore_la_SOURCES = UnitWOPIVersionRestore.cpp
unit_wopi_versionrestore_la_LIBADD = $(CPPUNIT_LIBS)
unit_wopi_documentconflict_la_SOURCES = UnitWOPIDocumentConflict.cpp
unit_wopi_documentconflict_la_LIBADD = $(CPPUNIT_LIBS)
+unit_wopi_renamefile_la_SOURCES = UnitWOPIRenameFile.cpp
+unit_wopi_renamefile_la_LIBADD = $(CPPUNIT_LIBS)
if HAVE_LO_PATH
SYSTEM_STAMP = @SYSTEMPLATE_PATH@/system_stamp
@@ -128,7 +130,7 @@ check-local:
TESTS = unit-typing.la unit-convert.la unit-prefork.la unit-tilecache.la \
unit-timeout.la unit-oauth.la unit-wopi.la unit-wopi-saveas.la \
unit-wopi-ownertermination.la unit-wopi-versionrestore.la \
- unit-wopi-documentconflict.la
+ unit-wopi-documentconflict.la unit_wopi_renamefile.la
# TESTS = unit-client.la
# TESTS += unit-admin.la
# TESTS += unit-storage.la
diff --git a/test/UnitWOPIRenameFile.cpp b/test/UnitWOPIRenameFile.cpp
new file mode 100644
index 000000000..04d1fc6d6
--- /dev/null
+++ b/test/UnitWOPIRenameFile.cpp
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <config.h>
+
+#include <WopiTestServer.hpp>
+#include <Log.hpp>
+#include <Unit.hpp>
+#include <UnitHTTP.hpp>
+#include <helpers.hpp>
+#include <Poco/Net/HTTPRequest.h>
+#include <Poco/Util/LayeredConfiguration.h>
+
+class UnitWOPIRenameFile : public WopiTestServer
+{
+ enum class Phase
+ {
+ Load,
+ RenameFile,
+ Polling
+ } _phase;
+
+public:
+ UnitWOPIRenameFile() :
+ _phase(Phase::Load)
+ {
+ }
+
+ void assertRenameFileRequest(const Poco::Net::HTTPRequest& request) override
+ {
+ // spec says UTF-7...
+ CPPUNIT_ASSERT_EQUAL(std::string("hello"), request.get("X-WOPI-RequestedName"));
+ }
+
+ bool filterSendMessage(const char* data, const size_t len, const WSOpCode /* code */, const bool /* flush */, int& /*unitReturn*/) override
+ {
+ const std::string message(data, len);
+
+ const std::string expected("renamefile: filename=hello");
+ if (message.find(expected) == 0)
+ {
+ // successfully exit the test if we also got the outgoing message
+ // notifying about saving the file
+ exitTest(TestResult::Ok);
+ }
+
+ return false;
+ }
+
+ void invokeTest() override
+ {
+ constexpr char testName[] = "UnitWOPIRenameFile";
+
+ switch (_phase)
+ {
+ case Phase::Load:
+ {
+ initWebsocket("/wopi/files/0?access_token=anything");
+
+ helpers::sendTextFrame(*_ws->getLOOLWebSocket(), "load url=" + _wopiSrc, testName);
+ _phase = Phase::RenameFile;
+ break;
+ }
+ case Phase::RenameFile:
+ {
+ helpers::sendTextFrame(*_ws->getLOOLWebSocket(), "renamefile filename=hello", testName);
+ _phase = Phase::Polling;
+ break;
+ }
+ case Phase::Polling:
+ {
+ // just wait for the results
+ break;
+ }
+ }
+ }
+};
+
+UnitBase *unit_create_wsd(void)
+{
+ return new UnitWOPIRenameFile();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/test/WopiTestServer.hpp b/test/WopiTestServer.hpp
index ea5659912..237957ba2 100644
--- a/test/WopiTestServer.hpp
+++ b/test/WopiTestServer.hpp
@@ -92,6 +92,10 @@ public:
{
}
+ virtual void assertRenameFileRequest(const Poco::Net::HTTPRequest& /*request*/)
+ {
+ }
+
protected:
/// Here we act as a WOPI server, so that we have a server that responds to
/// the wopi requests without additional expensive setup.
@@ -166,13 +170,22 @@ protected:
else if (request.getMethod() == "POST" && (uriReq.getPath() == "/wopi/files/0" || uriReq.getPath() == "/wopi/files/1"))
{
LOG_INF("Fake wopi host request, handling PutRelativeFile: " << uriReq.getPath());
-
- CPPUNIT_ASSERT_EQUAL(std::string("PUT_RELATIVE"), request.get("X-WOPI-Override"));
-
- assertPutRelativeFileRequest(request);
-
std::string wopiURL = helpers::getTestServerURI() + "/something wopi/files/1?access_token=anything";
- std::string content = "{ \"Name\":\"hello world%1.pdf\", \"Url\":\"" + wopiURL + "\" }";
+ std::string content;
+
+ if(request.get("X-WOPI-Override") == std::string("PUT_RELATIVE"))
+ {
+ CPPUNIT_ASSERT_EQUAL(std::string("PUT_RELATIVE"), request.get("X-WOPI-Override"));
+ assertPutRelativeFileRequest(request);
+ content = "{ \"Name\":\"hello world%1.pdf\", \"Url\":\"" + wopiURL + "\" }";
+ }
+ else
+ {
+ // rename file; response should be the file name without the url and the extension
+ CPPUNIT_ASSERT_EQUAL(std::string("RENAME_FILE"), request.get("X-WOPI-Override"));
+ assertRenameFileRequest(request);
+ content = "{ \"Name\":\"hello\", \"Url\":\"" + wopiURL + "\" }";
+ }
std::ostringstream oss;
oss << "HTTP/1.1 200 OK\r\n"
diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp
index ad5d4b97a..2146cedfe 100644
--- a/wsd/ClientSession.cpp
+++ b/wsd/ClientSession.cpp
@@ -178,7 +178,8 @@ bool ClientSession::_handleInput(const char *buffer, int length)
tokens[0] != "uploadsigneddocument" &&
tokens[0] != "exportsignanduploaddocument" &&
tokens[0] != "rendershapeselection" &&
- tokens[0] != "removesession")
+ tokens[0] != "removesession" &&
+ tokens[0] != "renamefile")
{
sendTextFrame("error: cmd=" + tokens[0] + " kind=unknown");
return false;
@@ -369,6 +370,19 @@ bool ClientSession::_handleInput(const char *buffer, int length)
docBroker->broadcastMessage(firstLine);
docBroker->removeSession(sessionId);
}
+ else if (tokens[0] == "renamefile") {
+ std::string encodedWopiFilename;
+ if (!getTokenString(tokens[1], "filename", encodedWopiFilename))
+ {
+ LOG_ERR("Bad syntax for: " << firstLine);
+ sendTextFrame("error: cmd=renamefile kind=syntax");
+ return false;
+ }
+ std::string wopiFilename;
+ Poco::URI::decode(encodedWopiFilename, wopiFilename);
+ docBroker->saveAsToStorage(getId(), "", wopiFilename, true);
+ return true;
+ }
else
{
if (tokens[0] == "key")
@@ -826,7 +840,7 @@ bool ClientSession::handleKitToClientMessage(const char* buffer, const int lengt
{
// this also sends the saveas: result
LOG_TRC("Save-as path: " << resultURL.getPath());
- docBroker->saveAsToStorage(getId(), resultURL.getPath(), wopiFilename);
+ docBroker->saveAsToStorage(getId(), resultURL.getPath(), wopiFilename, false);
}
else
sendTextFrame("error: cmd=storage kind=savefailed");
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index 4b0390ce9..e3b42e8c3 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -561,6 +561,8 @@ bool DocumentBroker::load(const std::shared_ptr<ClientSession>& session, const s
wopiInfo->set("EnableInsertRemoteImage", wopifileinfo->getEnableInsertRemoteImage());
wopiInfo->set("EnableShare", wopifileinfo->getEnableShare());
wopiInfo->set("HideUserList", wopifileinfo->getHideUserList());
+ wopiInfo->set("SupportsRename", wopifileinfo->getSupportsRename());
+ wopiInfo->set("UserCanRename", wopifileinfo->getUserCanRename());
if (wopifileinfo->getHideChangeTrackingControls() != WopiStorage::WOPIFileInfo::TriState::Unset)
wopiInfo->set("HideChangeTrackingControls", wopifileinfo->getHideChangeTrackingControls() == WopiStorage::WOPIFileInfo::TriState::True);
@@ -791,16 +793,16 @@ bool DocumentBroker::saveToStorage(const std::string& sessionId,
return res;
}
-bool DocumentBroker::saveAsToStorage(const std::string& sessionId, const std::string& saveAsPath, const std::string& saveAsFilename)
+bool DocumentBroker::saveAsToStorage(const std::string& sessionId, const std::string& saveAsPath, const std::string& saveAsFilename, const bool isRename)
{
assertCorrectThread();
- return saveToStorageInternal(sessionId, true, "", saveAsPath, saveAsFilename);
+ return saveToStorageInternal(sessionId, true, "", saveAsPath, saveAsFilename, isRename);
}
bool DocumentBroker::saveToStorageInternal(const std::string& sessionId,
bool success, const std::string& result,
- const std::string& saveAsPath, const std::string& saveAsFilename)
+ const std::string& saveAsPath, const std::string& saveAsFilename, const bool isRename)
{
assertCorrectThread();
@@ -813,7 +815,7 @@ bool DocumentBroker::saveToStorageInternal(const std::string& sessionId,
// notify the waiting thread, if any.
LOG_TRC("Saving to storage docKey [" << _docKey << "] for session [" << sessionId <<
"]. Success: " << success << ", result: " << result);
- if (!success && result == "unmodified")
+ if (!success && result == "unmodified" && !isRename)
{
LOG_DBG("Save skipped as document [" << _docKey << "] was not modified.");
_lastSaveTime = std::chrono::steady_clock::now();
@@ -850,7 +852,7 @@ bool DocumentBroker::saveToStorageInternal(const std::string& sessionId,
// If the file timestamp hasn't changed, skip saving.
const Poco::Timestamp newFileModifiedTime = Poco::File(_storage->getRootFilePath()).getLastModified();
- if (!isSaveAs && newFileModifiedTime == _lastFileModifiedTime)
+ if (!isSaveAs && newFileModifiedTime == _lastFileModifiedTime && !isRename)
{
// Nothing to do.
LOG_DBG("Skipping unnecessary saving to URI [" << uriAnonym << "] with docKey [" << _docKey <<
@@ -862,10 +864,10 @@ bool DocumentBroker::saveToStorageInternal(const std::string& sessionId,
LOG_DBG("Persisting [" << _docKey << "] after saving to URI [" << uriAnonym << "].");
assert(_storage && _tileCache);
- StorageBase::SaveResult storageSaveResult = _storage->saveLocalFileToStorage(auth, saveAsPath, saveAsFilename);
+ StorageBase::SaveResult storageSaveResult = _storage->saveLocalFileToStorage(auth, saveAsPath, saveAsFilename, isRename);
if (storageSaveResult.getResult() == StorageBase::SaveResult::OK)
{
- if (!isSaveAs)
+ if (!isSaveAs && !isRename)
{
// Saved and stored; update flags.
setModified(false);
@@ -884,6 +886,19 @@ bool DocumentBroker::saveToStorageInternal(const std::string& sessionId,
// Resume polling.
_poll->wakeup();
}
+ else if (isRename)
+ {
+ // encode the name
+ const std::string filename = storageSaveResult.getSaveAsName();
+ const std::string url = Poco::URI(storageSaveResult.getSaveAsUrl()).toString();
+ std::string encodedName;
+ Poco::URI::encode(filename, "", encodedName);
+ const std::string filenameAnonym = LOOLWSD::anonymizeUrl(filename);
+
+ std::ostringstream oss;
+ oss << "renamefile: " << "filename=" << encodedName << " url=" << url;
+ broadcastMessage(oss.str());
+ }
else
{
// normalize the url (mainly to " " -> "%20")
@@ -931,7 +946,9 @@ bool DocumentBroker::saveToStorageInternal(const std::string& sessionId,
{
//TODO: Should we notify all clients?
LOG_ERR("Failed to save docKey [" << _docKey << "] to URI [" << uriAnonym << "]. Notifying client.");
- it->second->sendTextFrame("error: cmd=storage kind=savefailed");
+ std::ostringstream oss;
+ oss << "error: cmd=storage kind=" << (isRename ? "renamefailed" : "savefailed");
+ it->second->sendTextFrame(oss.str());
}
else if (storageSaveResult.getResult() == StorageBase::SaveResult::DOC_CHANGED)
{
diff --git a/wsd/DocumentBroker.hpp b/wsd/DocumentBroker.hpp
index 5fd4cef48..0642599c2 100644
--- a/wsd/DocumentBroker.hpp
+++ b/wsd/DocumentBroker.hpp
@@ -246,7 +246,7 @@ public:
/// Save As the document to Storage.
/// @param saveAsPath Absolute path to the jailed file.
- bool saveAsToStorage(const std::string& sesionId, const std::string& saveAsPath, const std::string& saveAsFilename);
+ bool saveAsToStorage(const std::string& sesionId, const std::string& saveAsPath, const std::string& saveAsFilename, const bool isRename);
bool isModified() const { return _isModified; }
void setModified(const bool value);
@@ -368,7 +368,7 @@ private:
void terminateChild(const std::string& closeReason);
/// Saves the doc to the storage.
- bool saveToStorageInternal(const std::string& sesionId, bool success, const std::string& result = "", const std::string& saveAsPath = std::string(), const std::string& saveAsFilename = std::string());
+ bool saveToStorageInternal(const std::string& sesionId, bool success, const std::string& result = "", const std::string& saveAsPath = std::string(), const std::string& saveAsFilename = std::string(), const bool isRename = false);
/// True iff a save is in progress (requested but not completed).
bool isSaving() const { return _lastSaveResponseTime < _lastSaveRequestTime; }
diff --git a/wsd/Storage.cpp b/wsd/Storage.cpp
index 9d97cc1b6..d29bbaa63 100644
--- a/wsd/Storage.cpp
+++ b/wsd/Storage.cpp
@@ -336,7 +336,7 @@ std::string LocalStorage::loadStorageFileToLocal(const Authorization& /*auth*/)
}
-StorageBase::SaveResult LocalStorage::saveLocalFileToStorage(const Authorization& /*auth*/, const std::string& /*saveAsPath*/, const std::string& /*saveAsFilename*/)
+StorageBase::SaveResult LocalStorage::saveLocalFileToStorage(const Authorization& /*auth*/, const std::string& /*saveAsPath*/, const std::string& /*saveAsFilename*/, bool /*isRename*/)
{
try
{
@@ -499,6 +499,8 @@ std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const Au
bool userCanNotWriteRelative = true;
bool enableInsertRemoteImage = false;
bool enableShare = false;
+ bool supportsRename = false;
+ bool userCanRename = false;
std::string hideUserList("false");
WOPIFileInfo::TriState disableChangeTrackingRecord = WOPIFileInfo::TriState::Unset;
WOPIFileInfo::TriState disableChangeTrackingShow = WOPIFileInfo::TriState::Unset;
@@ -585,6 +587,8 @@ std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const Au
JsonUtil::findJSONValue(object, "EnableInsertRemoteImage", enableInsertRemoteImage);
JsonUtil::findJSONValue(object, "EnableShare", enableShare);
JsonUtil::findJSONValue(object, "HideUserList", hideUserList);
+ JsonUtil::findJSONValue(object, "SupportsRename", supportsRename);
+ JsonUtil::findJSONValue(object, "UserCanRename", userCanRename);
bool booleanFlag = false;
if (JsonUtil::findJSONValue(object, "DisableChangeTrackingRecord", booleanFlag))
disableChangeTrackingRecord = (booleanFlag ? WOPIFileInfo::TriState::True : WOPIFileInfo::TriState::False);
@@ -614,7 +618,7 @@ std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const Au
enableOwnerTermination, disablePrint, disableExport, disableCopy,
disableInactiveMessages, userCanNotWriteRelative, enableInsertRemoteImage, enableShare,
hideUserList, disableChangeTrackingShow, disableChangeTrackingRecord,
- hideChangeTrackingControls, callDuration}));
+ hideChangeTrackingControls, supportsRename, userCanRename, callDuration}));
}
/// uri format: http://server/<...>/wopi*/files/<id>/content
@@ -692,7 +696,7 @@ std::string WopiStorage::loadStorageFileToLocal(const Authorization& auth)
return "";
}
-StorageBase::SaveResult WopiStorage::saveLocalFileToStorage(const Authorization& auth, const std::string& saveAsPath, const std::string& saveAsFilename)
+StorageBase::SaveResult WopiStorage::saveLocalFileToStorage(const Authorization& auth, const std::string& saveAsPath, const std::string& saveAsFilename, const bool isRename)
{
// TODO: Check if this URI has write permission (canWrite = true)
@@ -703,7 +707,7 @@ StorageBase::SaveResult WopiStorage::saveLocalFileToStorage(const Authorization&
const size_t size = getFileSize(filePath);
Poco::URI uriObject(getUri());
- uriObject.setPath(isSaveAs? uriObject.getPath(): uriObject.getPath() + "/contents");
+ uriObject.setPath(isSaveAs || isRename? uriObject.getPath(): uriObject.getPath() + "/contents");
auth.authorizeURI(uriObject);
const std::string uriAnonym = LOOLWSD::anonymizeUrl(uriObject.toString());
@@ -718,7 +722,7 @@ StorageBase::SaveResult WopiStorage::saveLocalFileToStorage(const Authorization&
request.set("User-Agent", WOPI_AGENT_STRING);
auth.authorizeRequest(request);
- if (!isSaveAs)
+ if (!isSaveAs && !isRename)
{
// normal save
request.set("X-WOPI-Override", "PUT");
@@ -736,9 +740,6 @@ StorageBase::SaveResult WopiStorage::saveLocalFileToStorage(const Authorization&
}
else
{
- // save as
- request.set("X-WOPI-Override", "PUT_RELATIVE");
-
// the suggested target has to be in UTF-7; default to extension
// only when the conversion fails
std::string suggestedTarget = "." + Poco::Path(saveAsFilename).getExtension();
@@ -766,9 +767,19 @@ StorageBase::SaveResult WopiStorage::saveLocalFileToStorage(const Authorization&
}
}
- request.set("X-WOPI-SuggestedTarget", suggestedTarget);
-
- request.set("X-WOPI-Size", std::to_string(size));
+ if (isRename)
+ {
+ // rename file
+ request.set("X-WOPI-Override", "RENAME_FILE");
+ request.set("X-WOPI-RequestedName", suggestedTarget);
+ }
+ else
+ {
+ // save as
+ request.set("X-WOPI-Override", "PUT_RELATIVE");
+ request.set("X-WOPI-Size", std::to_string(size));
+ request.set("X-WOPI-SuggestedTarget", suggestedTarget);
+ }
}
request.setContentType("application/octet-stream");
@@ -786,7 +797,7 @@ StorageBase::SaveResult WopiStorage::saveLocalFileToStorage(const Authorization&
Poco::StreamCopier::copyStream(rs, oss);
std::string responseString = oss.str();
- const std::string wopiLog(isSaveAs ? "WOPI::PutRelativeFile" : "WOPI::PutFile");
+ const std::string wopiLog(isSaveAs ? "WOPI::PutRelativeFile" : (isRename ? "WOPI::RenameFile":"WOPI::PutFile"));
if (Log::infoEnabled())
{
@@ -834,7 +845,7 @@ StorageBase::SaveResult WopiStorage::saveLocalFileToStorage(const Authorization&
LOG_TRC(wopiLog << " returns LastModifiedTime [" << lastModifiedTime << "].");
getFileInfo().setModifiedTime(iso8601ToTimestamp(lastModifiedTime, "LastModifiedTime"));
- if (isSaveAs)
+ if (isSaveAs || isRename)
{
const std::string name = JsonUtil::getJSONValue<std::string>(object, "Name");
LOG_TRC(wopiLog << " returns Name [" << LOOLWSD::anonymizeUrl(name) << "].");
@@ -844,7 +855,6 @@ StorageBase::SaveResult WopiStorage::saveLocalFileToStorage(const Authorization&
saveResult.setSaveAsResult(name, url);
}
-
// Reset the force save flag now, if any, since we are done saving
// Next saves shouldn't be saved forcefully unless commanded
forceSave(false);
@@ -897,7 +907,7 @@ std::string WebDAVStorage::loadStorageFileToLocal(const Authorization& /*auth*/)
return getUri().toString();
}
-StorageBase::SaveResult WebDAVStorage::saveLocalFileToStorage(const Authorization& /*auth*/, const std::string& /*saveAsPath*/, const std::string& /*saveAsFilename*/)
+StorageBase::SaveResult WebDAVStorage::saveLocalFileToStorage(const Authorization& /*auth*/, const std::string& /*saveAsPath*/, const std::string& /*saveAsFilename*/, bool /*isRename*/)
{
// TODO: implement webdav PUT.
return StorageBase::SaveResult(StorageBase::SaveResult::OK);
diff --git a/wsd/Storage.hpp b/wsd/Storage.hpp
index bf228721a..02539b8f1 100644
--- a/wsd/Storage.hpp
+++ b/wsd/Storage.hpp
@@ -193,7 +193,7 @@ public:
/// Writes the contents of the file back to the source.
/// @param savedFile When the operation was saveAs, this is the path to the file that was saved.
- virtual SaveResult saveLocalFileToStorage(const Authorization& auth, const std::string& saveAsPath, const std::string& saveAsFilename) = 0;
+ virtual SaveResult saveLocalFileToStorage(const Authorization& auth, const std::string& saveAsPath, const std::string& saveAsFilename, const bool isRename) = 0;
static size_t getFileSize(const std::string& filename);
@@ -274,7 +274,7 @@ public:
std::string loadStorageFileToLocal(const Authorization& auth) override;
- SaveResult saveLocalFileToStorage(const Authorization& auth, const std::string& saveAsPath, const std::string& saveAsFilename) override;
+ SaveResult saveLocalFileToStorage(const Authorization& auth, const std::string& saveAsPath, const std::string& saveAsFilename, const bool isRename) override;
private:
/// True if the jailed file is not linked but copied.
@@ -329,6 +329,8 @@ public:
const TriState disableChangeTrackingShow,
const TriState disableChangeTrackingRecord,
const TriState hideChangeTrackingControls,
+ const bool supportsRename,
+ const bool userCanRename,
const std::chrono::duration<double> callDuration)
: _userId(userid),
_obfuscatedUserId(obfuscatedUserId),
@@ -352,6 +354,8 @@ public:
_disableChangeTrackingShow(disableChangeTrackingShow),
_disableChangeTrackingRecord(disableChangeTrackingRecord),
_hideChangeTrackingControls(hideChangeTrackingControls),
+ _supportsRename(supportsRename),
+ _userCanRename(userCanRename),
_callDuration(callDuration)
{
_userExtraInfo = userExtraInfo;
@@ -397,6 +401,10 @@ public:
bool getEnableShare() const { return _enableShare; }
+ bool getSupportsRename() const { return _supportsRename; }
+
+ bool getUserCanRename() const { return _userCanRename; }
+
std::string& getHideUserList() { return _hideUserList; }
TriState getDisableChangeTrackingShow() const { return _disableChangeTrackingShow; }
@@ -456,6 +464,10 @@ public:
TriState _disableChangeTrackingRecord;
/// If we should hide change-tracking commands for this user.
TriState _hideChangeTrackingControls;
+ /// If WOPI host supports rename
+ bool _supportsRename;
+ /// If user is allowed to rename the document
+ bool _userCanRename;
/// Time it took to call WOPI's CheckFileInfo
std::chrono::duration<double> _callDuration;
@@ -470,7 +482,7 @@ public:
/// uri format: http://server/<...>/wopi*/files/<id>/content
std::string loadStorageFileToLocal(const Authorization& auth) override;
- SaveResult saveLocalFileToStorage(const Authorization& auth, const std::string& saveAsPath, const std::string& saveAsFilename) override;
+ SaveResult saveLocalFileToStorage(const Authorization& auth, const std::string& saveAsPath, const std::string& saveAsFilename, const bool isRename) override;
/// Total time taken for making WOPI calls during load
std::chrono::duration<double> getWopiLoadDuration() const { return _wopiLoadDuration; }
@@ -500,7 +512,7 @@ public:
std::string loadStorageFileToLocal(const Authorization& auth) override;
- SaveResult saveLocalFileToStorage(const Authorization& auth, const std::string& saveAsPath, const std::string& saveAsFilename) override;
+ SaveResult saveLocalFileToStorage(const Authorization& auth, const std::string& saveAsPath, const std::string& saveAsFilename, const bool isRename) override;
private:
std::unique_ptr<AuthBase> _authAgent;
More information about the Libreoffice-commits
mailing list