common/Session.cpp | 10 ++++++++-- common/Session.hpp | 3 +++ common/Util.cpp | 23 ++++++++++++++++++++++- common/Util.hpp | 3 +++ kit/ChildSession.cpp | 2 +- kit/ChildSession.hpp | 1 + kit/Kit.cpp | 11 +++++++---- kit/Kit.hpp | 28 +++++++++++++++++++++++++--- loleaflet/src/map/Map.js | 2 +- loleaflet/src/map/handler/Map.WOPI.js | 1 + wsd/ClientSession.cpp | 11 +++++++++-- wsd/ClientSession.hpp | 1 + wsd/DocumentBroker.cpp | 3 +++ wsd/Storage.cpp | 4 +++- wsd/Storage.hpp | 4 ++++ 15 files changed, 92 insertions(+), 15 deletions(-)
New commits: commit b001c6864810a6739e2c63ed7033410b6cc18cf5 Author: Ashod Nakashian <ashod.nakash...@collabora.co.uk> Date: Sun May 28 12:20:49 2017 -0400 wsd: support per-user links and commands userextrainfo is a json array that contains extra user-specific links. Currently 'avatar' is assumed to hold the image url for the user's avatar. 'mail' and other links can also be added. Change-Id: I37c4c68bfa0b7ee659e017b4867dcb8cf5c2ca2f Reviewed-on: https://gerrit.libreoffice.org/38120 Reviewed-by: Ashod Nakashian <ashnak...@gmail.com> Tested-by: Ashod Nakashian <ashnak...@gmail.com> (cherry picked from commit da2d3cbc92bf76f0d29b67eab493f2f350d1b63c) Reviewed-on: https://gerrit.libreoffice.org/38138 Reviewed-by: Jan Holesovsky <ke...@collabora.com> Tested-by: Jan Holesovsky <ke...@collabora.com> diff --git a/common/Session.cpp b/common/Session.cpp index 2b99ec79..a1cded5f 100644 --- a/common/Session.cpp +++ b/common/Session.cpp @@ -99,16 +99,22 @@ void Session::parseDocOptions(const std::vector<std::string>& tokens, int& part, } else if (tokens[i].find("authorid=") == 0) { - std::string userId = tokens[i].substr(strlen("authorid=")); + const std::string userId = tokens[i].substr(strlen("authorid=")); Poco::URI::decode(userId, _userId); ++offset; } else if (tokens[i].find("author=") == 0) { - std::string userName = tokens[i].substr(strlen("author=")); + const std::string userName = tokens[i].substr(strlen("author=")); Poco::URI::decode(userName, _userName); ++offset; } + else if (tokens[i].find("authorextrainfo=") == 0) + { + const std::string userExtraInfo= tokens[i].substr(strlen("authorextrainfo=")); + Poco::URI::decode(userExtraInfo, _userExtraInfo); + ++offset; + } else if (tokens[i].find("readonly=") == 0) { _isReadOnly = tokens[i].substr(strlen("readonly=")) != "0"; diff --git a/common/Session.hpp b/common/Session.hpp index b67466e3..63872c08 100644 --- a/common/Session.hpp +++ b/common/Session.hpp @@ -152,6 +152,9 @@ protected: /// Name of the user to whom the session belongs to std::string _userName; + /// Extra info per user, mostly mail, avatar, links, etc. + std::string _userExtraInfo; + /// Language for the document based on what the user has in the UI. std::string _lang; }; diff --git a/common/Util.cpp b/common/Util.cpp index 23a74c6f..b3bcb354 100644 --- a/common/Util.cpp +++ b/common/Util.cpp @@ -39,6 +39,9 @@ #include <Poco/ConsoleChannel.h> #include <Poco/Exception.h> #include <Poco/Format.h> +#include <Poco/JSON/JSON.h> +#include <Poco/JSON/Object.h> +#include <Poco/JSON/Parser.h> #include <Poco/Net/WebSocket.h> #include <Poco/Process.h> #include <Poco/RandomStream.h> @@ -334,7 +337,25 @@ namespace Util std::string UniqueId() { static std::atomic_int counter(0); - return std::to_string(Poco::Process::id()) + "/" + std::to_string(counter++); + return std::to_string(Poco::Process::id()) + '/' + std::to_string(counter++); + } + + std::map<std::string, std::string> JsonToMap(const std::string& jsonString) + { + Poco::JSON::Parser parser; + const auto result = parser.parse(jsonString); + const auto& json = result.extract<Poco::JSON::Object::Ptr>(); + + std::vector<std::string> names; + json->getNames(names); + + std::map<std::string, std::string> map; + for (const auto& name : names) + { + map[name] = json->get(name).toString(); + } + + return map; } } diff --git a/common/Util.hpp b/common/Util.hpp index 22173634..93f25cf0 100644 --- a/common/Util.hpp +++ b/common/Util.hpp @@ -121,6 +121,9 @@ namespace Util /// Return a string that is unique across processes and calls. std::string UniqueId(); + // Extract all json entries into a map. + std::map<std::string, std::string> JsonToMap(const std::string& jsonString); + /// Trim spaces from the left. Just spaces. inline std::string& ltrim(std::string& s) { diff --git a/kit/ChildSession.cpp b/kit/ChildSession.cpp index d68bcf59..4fd77800 100644 --- a/kit/ChildSession.cpp +++ b/kit/ChildSession.cpp @@ -477,7 +477,7 @@ void insertUserNames(const std::map<int, UserInfo>& viewInfo, std::string& json) int viewId = action->getValue<int>("viewId"); auto it = viewInfo.find(viewId); if (it != viewInfo.end()) - action->set("userName", Poco::Dynamic::Var(it->second.username)); + action->set("userName", Poco::Dynamic::Var(it->second.Username)); } } } diff --git a/kit/ChildSession.hpp b/kit/ChildSession.hpp index 703df776..7faef0ed 100644 --- a/kit/ChildSession.hpp +++ b/kit/ChildSession.hpp @@ -138,6 +138,7 @@ public: void setViewId(const int viewId) { _viewId = viewId; } const std::string& getViewUserId() const { return _userId; } const std::string& getViewUserName() const { return _userName; } + const std::string& getViewUserExtraInfo() const { return _userExtraInfo; } void loKitCallback(const int type, const std::string& payload); diff --git a/kit/Kit.cpp b/kit/Kit.cpp index 304a62e5..5415c760 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -1074,10 +1074,12 @@ private: } else { - oss << "\"userid\":\"" << itView->second.userid << "\","; - const auto username = itView->second.username; + oss << "\"userid\":\"" << itView->second.UserId << "\","; + const auto username = itView->second.Username; oss << "\"username\":\"" << username << "\","; - const auto readonly = itView->second.isReadOnly; + if (!itView->second.UserExtraInfo.empty()) + oss << itView->second.UserExtraInfo << ','; + const auto readonly = itView->second.IsReadOnly; oss << "\"readonly\":\"" << readonly << "\","; const auto it = viewColorsMap.find(username); if (it != viewColorsMap.end()) @@ -1248,7 +1250,8 @@ private: const int viewId = _loKitDocument->getView(); session->setViewId(viewId); - _sessionUserInfo[viewId] = UserInfo({session->getViewUserId(), session->getViewUserName(), session->isReadOnly()}); + _sessionUserInfo[viewId] = UserInfo(session->getViewUserId(), session->getViewUserName(), + session->getViewUserExtraInfo(), session->isReadOnly()); _viewIdToCallbackDescr.emplace(viewId, std::unique_ptr<CallbackDescriptor>(new CallbackDescriptor({ this, viewId }))); diff --git a/kit/Kit.hpp b/kit/Kit.hpp index f003e26a..bbaf1bba 100644 --- a/kit/Kit.hpp +++ b/kit/Kit.hpp @@ -9,6 +9,11 @@ #ifndef INCLUDED_LOOLKIT_HPP #define INCLUDED_LOOLKIT_HPP +#include <map> +#include <string> + +#include <common/Util.hpp> + void lokit_main(const std::string& childRoot, const std::string& jailId, const std::string& sysTemplate, @@ -37,9 +42,26 @@ struct CallbackDescriptor /// after any child session goes away struct UserInfo { - std::string userid; - std::string username; - bool isReadOnly; + UserInfo() + { + } + + UserInfo(const std::string& userId, + const std::string& username, + const std::string& userExtraInfo, + const bool readonly) : + UserId(userId), + Username(username), + IsReadOnly(readonly) + { + if (!userExtraInfo.empty()) + UserExtraInfo = "\"userextrainfo\":[" + userExtraInfo + ']'; + } + + std::string UserId; + std::string Username; + std::string UserExtraInfo; + bool IsReadOnly; }; /// Check the ForkCounter, and if non-zero, fork more of them accordingly. diff --git a/loleaflet/src/map/Map.js b/loleaflet/src/map/Map.js index 65575f0d..c809980e 100644 --- a/loleaflet/src/map/Map.js +++ b/loleaflet/src/map/Map.js @@ -160,7 +160,7 @@ L.Map = L.Evented.extend({ addView: function(viewInfo) { this._viewInfo[viewInfo.id] = viewInfo; - this.fire('postMessage', {msgId: 'View_Added', args: {ViewId: viewInfo.id, UserId: viewInfo.userid, UserName: viewInfo.username, Color: viewInfo.color, ReadOnly: viewInfo.readonly}}); + this.fire('postMessage', {msgId: 'View_Added', args: {ViewId: viewInfo.id, UserId: viewInfo.userid, UserName: viewInfo.username, UserExtraInfo: viewInfo.userextrainfo, Color: viewInfo.color, ReadOnly: viewInfo.readonly}}); // Fire last, otherwise not all events are handled correctly. this.fire('addview', {viewId: viewInfo.id, username: viewInfo.username, extraInfo: viewInfo.userextrainfo, readonly: this.isViewReadOnly(viewInfo.id)}); diff --git a/loleaflet/src/map/handler/Map.WOPI.js b/loleaflet/src/map/handler/Map.WOPI.js index 20d11a6f..fcb454ec 100644 --- a/loleaflet/src/map/handler/Map.WOPI.js +++ b/loleaflet/src/map/handler/Map.WOPI.js @@ -113,6 +113,7 @@ L.Map.WOPI = L.Handler.extend({ ViewId: viewInfoIdx, UserName: this._map._viewInfo[viewInfoIdx].username, UserId: this._map._viewInfo[viewInfoIdx].userid, + UserExtraInfo: this._map._viewInfo[viewInfoIdx].userextrainfo, Color: this._map._viewInfo[viewInfoIdx].color }); } diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp index 026b0513..a65959b8 100644 --- a/wsd/ClientSession.cpp +++ b/wsd/ClientSession.cpp @@ -259,11 +259,18 @@ bool ClientSession::loadDocument(const char* /*buffer*/, int /*length*/, { std::string encodedUserId; Poco::URI::encode(_userId, "", encodedUserId); - oss << " authorid=" + encodedUserId; + oss << " authorid=" << encodedUserId; std::string encodedUserName; Poco::URI::encode(_userName, "", encodedUserName); - oss << " author=" + encodedUserName; + oss << " author=" << encodedUserName; + } + + if (!_userExtraInfo.empty()) + { + std::string encodedUserExtraInfo; + Poco::URI::encode(_userExtraInfo, "", encodedUserExtraInfo); + oss << " authorextrainfo=" << encodedUserExtraInfo; } oss << " readonly=" << isReadOnly(); diff --git a/wsd/ClientSession.hpp b/wsd/ClientSession.hpp index 96f090d7..17fca2a7 100644 --- a/wsd/ClientSession.hpp +++ b/wsd/ClientSession.hpp @@ -45,6 +45,7 @@ public: const std::string getUserId() const { return _userId; } void setUserId(const std::string& userId) { _userId = userId; } void setUserName(const std::string& userName) { _userName = userName; } + void setUserExtraInfo(const std::string& userExtraInfo) { _userExtraInfo = userExtraInfo; } void setDocumentOwner(const bool documentOwner) { _isDocumentOwner = documentOwner; } bool isDocumentOwner() const { return _isDocumentOwner; } diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp index 1e4870e1..c04fa850 100644 --- a/wsd/DocumentBroker.cpp +++ b/wsd/DocumentBroker.cpp @@ -395,6 +395,7 @@ bool DocumentBroker::load(const std::shared_ptr<ClientSession>& session, const s // Call the storage specific fileinfo functions std::string userid, username; + std::string userExtraInfo; std::chrono::duration<double> getInfoCallDuration(0); WopiStorage* wopiStorage = dynamic_cast<WopiStorage*>(_storage.get()); if (wopiStorage != nullptr) @@ -402,6 +403,7 @@ bool DocumentBroker::load(const std::shared_ptr<ClientSession>& session, const s std::unique_ptr<WopiStorage::WOPIFileInfo> wopifileinfo = wopiStorage->getWOPIFileInfo(session->getAccessToken()); userid = wopifileinfo->_userid; username = wopifileinfo->_username; + userExtraInfo = wopifileinfo->_userExtraInfo; if (!wopifileinfo->_userCanWrite) { @@ -462,6 +464,7 @@ bool DocumentBroker::load(const std::shared_ptr<ClientSession>& session, const s LOG_DBG("Setting username [" << username << "] and userId [" << userid << "] for session [" << sessionId << "]"); session->setUserId(userid); session->setUserName(username); + session->setUserExtraInfo(userExtraInfo); // Basic file information was stored by the above getWOPIFileInfo() or getLocalFileInfo() calls const auto fileInfo = _storage->getFileInfo(); diff --git a/wsd/Storage.cpp b/wsd/Storage.cpp index 4e6e6567..f67513ef 100644 --- a/wsd/Storage.cpp +++ b/wsd/Storage.cpp @@ -483,6 +483,7 @@ std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const st std::string ownerId; std::string userId; std::string userName; + std::string userExtraInfo; bool canWrite = false; bool enableOwnerTermination = false; std::string postMessageOrigin; @@ -507,6 +508,7 @@ std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const st getWOPIValue(object, "OwnerId", ownerId); getWOPIValue(object, "UserId", userId); getWOPIValue(object, "UserFriendlyName", userName); + getWOPIValue(object, "UserExtraInfo", userExtraInfo); getWOPIValue(object, "UserCanWrite", canWrite); getWOPIValue(object, "PostMessageOrigin", postMessageOrigin); getWOPIValue(object, "HidePrintOption", hidePrintOption); @@ -548,7 +550,7 @@ std::unique_ptr<WopiStorage::WOPIFileInfo> WopiStorage::getWOPIFileInfo(const st _fileInfo = FileInfo({filename, ownerId, modifiedTime, size}); - return std::unique_ptr<WopiStorage::WOPIFileInfo>(new WOPIFileInfo({userId, userName, canWrite, postMessageOrigin, hidePrintOption, hideSaveOption, hideExportOption, enableOwnerTermination, disablePrint, disableExport, disableCopy, callDuration})); + return std::unique_ptr<WopiStorage::WOPIFileInfo>(new WOPIFileInfo({userId, userName, userExtraInfo, canWrite, postMessageOrigin, hidePrintOption, hideSaveOption, hideExportOption, enableOwnerTermination, disablePrint, disableExport, disableCopy, callDuration})); } /// uri format: http://server/<...>/wopi*/files/<id>/content diff --git a/wsd/Storage.hpp b/wsd/Storage.hpp index d0dff593..34b56de3 100644 --- a/wsd/Storage.hpp +++ b/wsd/Storage.hpp @@ -182,6 +182,7 @@ public: public: WOPIFileInfo(const std::string& userid, const std::string& username, + const std::string& userExtraInfo, const bool userCanWrite, const std::string& postMessageOrigin, const bool hidePrintOption, @@ -205,12 +206,15 @@ public: _disableCopy(disableCopy), _callDuration(callDuration) { + _userExtraInfo = userExtraInfo; } /// User id of the user accessing the file std::string _userid; /// Display Name of user accessing the file std::string _username; + /// Extra info per user, typically mail and other links, as json. + std::string _userExtraInfo; /// If user accessing the file has write permission bool _userCanWrite; /// WOPI Post message property _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits