diff --git a/src/ruqolacore/rocketchataccount.cpp b/src/ruqolacore/rocketchataccount.cpp index 3cd7beb4..029f19a0 100644 --- a/src/ruqolacore/rocketchataccount.cpp +++ b/src/ruqolacore/rocketchataccount.cpp @@ -1,1257 +1,1255 @@ /* Copyright (c) 2017-2018 Montel Laurent This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License or ( at your option ) version 3 or, at the discretion of KDE e.V. ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "model/messagemodel.h" #include "rocketchataccount.h" #include "model/roommodel.h" #include "roomwrapper.h" #include "typingnotification.h" #include "model/usersmodel.h" #include "ruqola_debug.h" #include "ruqola.h" #include "messagequeue.h" #include "rocketchatbackend.h" #include "model/roomfilterproxymodel.h" #include "ruqolalogger.h" #include "ruqolaserverconfig.h" #include "model/usercompletermodel.h" #include "model/usercompleterfilterproxymodel.h" #include "model/statusmodel.h" #include "utils.h" #include "rocketchatcache.h" #include "emojimanager.h" #include "otrmanager.h" #include "inputtextmanager.h" #include "model/usersforroommodel.h" #include "model/filesforroommodel.h" #include "model/searchchannelfilterproxymodel.h" #include "model/searchchannelmodel.h" #include "model/loginmethodmodel.h" #include "model/inputcompletermodel.h" #include "model/searchmessagemodel.h" #include "model/searchmessagefilterproxymodel.h" #include "managerdatapaths.h" #include "authenticationmanager.h" #include "ddpapi/ddpclient.h" #include "receivetypingnotificationmanager.h" #include "restapirequest.h" #include #include #include #include #include #define USE_REASTAPI_JOB 1 RocketChatAccount::RocketChatAccount(const QString &accountFileName, QObject *parent) : QObject(parent) { qCDebug(RUQOLA_LOG) << " RocketChatAccount::RocketChatAccount(const QString &accountFileName, QObject *parent)"<setServerUrl(mSettings->serverUrl()); mOtrManager = new OtrManager(this); mRoomFilterProxyModel = new RoomFilterProxyModel(this); mUserCompleterModel = new UserCompleterModel(this); mUserCompleterFilterModelProxy = new UserCompleterFilterProxyModel(this); mUserCompleterFilterModelProxy->setSourceModel(mUserCompleterModel); mSearchChannelModel = new SearchChannelModel(this); mSearchChannelFilterProxyModel = new SearchChannelFilterProxyModel(this); mSearchChannelFilterProxyModel->setSourceModel(mSearchChannelModel); mSearchMessageModel = new SearchMessageModel(this); mSearchMessageFilterProxyModel = new SearchMessageFilterProxyModel(this); mSearchMessageFilterProxyModel->setSourceModel(mSearchMessageModel); mStatusModel = new StatusModel(this); mRoomModel = new RoomModel(this); connect(mRoomModel, &RoomModel::needToUpdateNotification, this, &RocketChatAccount::slotNeedToUpdateNotification); mRoomFilterProxyModel->setSourceModel(mRoomModel); mUserModel = new UsersModel(this); connect(mUserModel, &UsersModel::userStatusChanged, this, &RocketChatAccount::userStatusChanged); mMessageQueue = new MessageQueue(this); mTypingNotification = new TypingNotification(this); mCache = new RocketChatCache(this, this); connect(mCache, &RocketChatCache::fileDownloaded, this, &RocketChatAccount::fileDownloaded); connect(mTypingNotification, &TypingNotification::informTypingStatus, this, &RocketChatAccount::slotInformTypingStatus); QTimer::singleShot(0, this, &RocketChatAccount::clearModels); } RocketChatAccount::~RocketChatAccount() { delete mCache; mCache = nullptr; delete mRuqolaServerConfig; delete mRuqolaLogger; } void RocketChatAccount::removeSettings() { mSettings->removeSettings(); } void RocketChatAccount::loadSettings(const QString &accountFileName) { delete mSettings; mSettings = new RocketChatAccountSettings(accountFileName, this); connect(mSettings, &RocketChatAccountSettings::serverURLChanged, this, &RocketChatAccount::serverUrlChanged); connect(mSettings, &RocketChatAccountSettings::userIDChanged, this, &RocketChatAccount::userIDChanged); connect(mSettings, &RocketChatAccountSettings::userNameChanged, this, &RocketChatAccount::userNameChanged); connect(mSettings, &RocketChatAccountSettings::passwordChanged, this, &RocketChatAccount::passwordChanged); } void RocketChatAccount::slotNeedToUpdateNotification() { bool hasAlert = false; int nbUnread = 0; mRoomModel->getUnreadAlertFromAccount(hasAlert, nbUnread); Q_EMIT updateNotification(hasAlert, nbUnread, accountName()); } void RocketChatAccount::clearModels() { // Clear rooms data and refill it with data in the cache, if there is mRoomModel->reset(); mMessageQueue->loadCache(); //Try to send queue message mMessageQueue->processQueue(); } SearchChannelFilterProxyModel *RocketChatAccount::searchChannelFilterProxyModel() const { return mSearchChannelFilterProxyModel; } SearchChannelModel *RocketChatAccount::searchChannelModel() const { return mSearchChannelModel; } UserCompleterModel *RocketChatAccount::userCompleterModel() const { return mUserCompleterModel; } UserCompleterFilterProxyModel *RocketChatAccount::userCompleterFilterModelProxy() const { return mUserCompleterFilterModelProxy; } EmojiManager *RocketChatAccount::emojiManager() const { return mEmojiManager; } QString RocketChatAccount::userStatusIconFileName(const QString &name) { return mUserModel->userStatusIconFileName(name); } StatusModel *RocketChatAccount::statusModel() const { return mStatusModel; } RuqolaServerConfig *RocketChatAccount::ruqolaServerConfig() const { return mRuqolaServerConfig; } RuqolaLogger *RocketChatAccount::ruqolaLogger() const { return mRuqolaLogger; } RoomFilterProxyModel *RocketChatAccount::roomFilterProxyModel() const { return mRoomFilterProxyModel; } UsersForRoomFilterProxyModel *RocketChatAccount::usersForRoomFilterProxyModel(const QString &roomId) const { return mRoomModel->usersForRoomFilterProxyModel(roomId); } FilesForRoomFilterProxyModel *RocketChatAccount::filesForRoomFilterProxyModel(const QString &roomId) const { return mRoomModel->filesForRoomFilterProxyModel(roomId); } RocketChatBackend *RocketChatAccount::rocketChatBackend() const { return mRocketChatBackend; } MessageQueue *RocketChatAccount::messageQueue() const { return mMessageQueue; } RocketChatAccountSettings *RocketChatAccount::settings() const { return mSettings; } void RocketChatAccount::slotInformTypingStatus(const QString &room, bool typing) { ddp()->informTypingStatus(room, typing, mSettings->userName()); } RoomModel *RocketChatAccount::roomModel() const { return mRoomModel; } UsersModel *RocketChatAccount::usersModel() const { return mUserModel; } Room *RocketChatAccount::getRoom(const QString &roomId) { return mRoomModel->findRoom(roomId); } RoomWrapper *RocketChatAccount::getRoomWrapper(const QString &roomId) { return mRoomModel->findRoomWrapper(roomId); } MessageModel *RocketChatAccount::messageModelForRoom(const QString &roomID) { return mRoomModel->messageModel(roomID); } QString RocketChatAccount::getUserCurrentMessage(const QString &roomId) { return mRoomModel->inputMessage(roomId); } void RocketChatAccount::setUserCurrentMessage(const QString &message, const QString &roomId) { mRoomModel->setInputMessage(roomId, message); } void RocketChatAccount::setInputTextChanged(const QString &str, int position) { mInputTextManager->setInputTextChanged(str, position); } QString RocketChatAccount::replaceWord(const QString &newWord, const QString &str, int position) { return mInputTextManager->replaceWord(newWord, str, position); } void RocketChatAccount::textEditing(const QString &roomId, const QString &str) { mTypingNotification->setText(roomId, str); } void RocketChatAccount::reactOnMessage(const QString &messageId, const QString &emoji, bool shouldReact) { restApi()->reactOnMessage(messageId, emoji, shouldReact); } void RocketChatAccount::sendMessage(const QString &roomID, const QString &message) { #ifdef USE_REASTAPI_JOB restApi()->postMessage(roomID, message); #else QJsonObject json; json[QStringLiteral("rid")] = roomID; json[QStringLiteral("msg")] = message; ddp()->method(QStringLiteral("sendMessage"), QJsonDocument(json), DDPClient::Persistent); #endif } void RocketChatAccount::updateMessage(const QString &roomID, const QString &messageId, const QString &message) { #ifdef USE_REASTAPI_JOB restApi()->updateMessage(roomID, messageId, message); #else QJsonObject json; json[QStringLiteral("rid")] = roomID; json[QStringLiteral("msg")] = message; json[QStringLiteral("_id")] = messageId; ddp()->method(QStringLiteral("updateMessage"), QJsonDocument(json), DDPClient::Persistent); #endif } QString RocketChatAccount::avatarUrlFromDirectChannel(const QString &rid) { return mCache->avatarUrl(Utils::userIdFromDirectChannel(rid, userID())); } void RocketChatAccount::deleteFileMessage(const QString &roomId, const QString &fileId, const QString &channelType) { ddp()->deleteFileMessage(roomId, fileId, channelType); } QString RocketChatAccount::avatarUrl(const QString &userId) { return mCache->avatarUrl(userId); } void RocketChatAccount::insertAvatarUrl(const QString &userId, const QString &url) { mCache->insertAvatarUrl(userId, url); } RocketChatRestApi::RestApiRequest *RocketChatAccount::restApi() { if (!mRestApi) { mRestApi = new RocketChatRestApi::RestApiRequest(this); mRestApi->setServerUrl(mSettings->serverUrl()); mRestApi->setRestApiLogger(mRuqolaLogger); } return mRestApi; } void RocketChatAccount::leaveRoom(const QString &roomId, const QString &channelType) { #ifdef USE_REASTAPI_JOB if (channelType == QStringLiteral("c")) { restApi()->leaveChannel(roomId); } else if (channelType == QStringLiteral("p")) { restApi()->leaveGroups(roomId); } else { qCWarning(RUQOLA_LOG) << " unsupport leave room for type " << channelType; } #else Q_UNUSED(channelType) ddp()->leaveRoom(roomId); #endif } void RocketChatAccount::hideRoom(const QString &roomId, const QString &channelType) { #ifdef USE_REASTAPI_JOB_NOTSUPPORTED_YET if (channelType == QStringLiteral("c")) { restApi()->leaveChannel(roomId); } else if (channelType == QStringLiteral("p")) { restApi()->leaveGroups(roomId); } else if (channelType == QStringLiteral("d")) { } else { qCWarning(RUQOLA_LOG) << " unsupport hide room for type " << channelType; } restApi()->closeChannel(roomId, channelType); #else Q_UNUSED(channelType) ddp()->hideRoom(roomId); #endif } DDPClient *RocketChatAccount::ddp() { if (!mDdp) { mDdp = new DDPClient(this, this); connect(mDdp, &DDPClient::loginStatusChanged, this, &RocketChatAccount::loginStatusChanged); connect(mDdp, &DDPClient::connectedChanged, this, &RocketChatAccount::connectedChanged); connect(mDdp, &DDPClient::changed, this, &RocketChatAccount::changed); connect(mDdp, &DDPClient::added, this, &RocketChatAccount::added); connect(mDdp, &DDPClient::removed, this, &RocketChatAccount::removed); mDdp->setServerUrl(mSettings->serverUrl()); mDdp->start(); } return mDdp; } DDPClient::LoginStatus RocketChatAccount::loginStatus() { if (mDdp) { return ddp()->loginStatus(); } else { return DDPClient::LoggedOut; } } void RocketChatAccount::tryLogin() { qCDebug(RUQOLA_LOG) << "Attempting login" << mSettings->userName() << "on" << mSettings->serverUrl(); delete mDdp; mDdp = nullptr; // This creates a new ddp() object. // DDP will automatically try to connect and login. ddp(); // In the meantime, load cache... mRoomModel->reset(); } void RocketChatAccount::logOut() { mSettings->logout(); mRoomModel->clear(); #ifdef USE_REASTAPI_JOB restApi()->logout(); #else QJsonObject user; user[QStringLiteral("username")] = mSettings->userName(); QJsonObject json; json[QStringLiteral("user")] = user; ddp()->method(QStringLiteral("logout"), QJsonDocument(json)); #endif delete mDdp; mDdp = nullptr; Q_EMIT logoutDone(accountName()); Q_EMIT loginStatusChanged(); qCDebug(RUQOLA_LOG) << "Successfully logged out!"; } void RocketChatAccount::clearUnreadMessages(const QString &roomId) { #ifdef USE_REASTAPI_JOB restApi()->markAsRead(roomId); #else //TODO don't send message when we don't have unread message ddp()->clearUnreadMessages(roomId); #endif } void RocketChatAccount::changeFavorite(const QString &roomId, bool checked) { #ifdef USE_REASTAPI_JOB if (mRuqolaServerConfig->hasAtLeastVersion(0, 64, 0)) { restApi()->markAsFavorite(roomId, checked); } else { ddp()->toggleFavorite(roomId, checked); } #else ddp()->toggleFavorite(roomId, checked); #endif } void RocketChatAccount::openChannel(const QString &url) { //TODO use restapi qCDebug(RUQOLA_LOG) << " void RocketChatAccount::openChannel(const QString &url)"<joinRoom(url, QString()); //TODO search correct room + select it. } void RocketChatAccount::joinJitsiConfCall(const QString &roomId) { qCDebug(RUQOLA_LOG) << " void RocketChatAccount::joinJitsiConfCall(const QString &roomId)"<uniqueId() + roomId).toUtf8(), QCryptographicHash::Md5).toHex()); #if defined(Q_OS_IOS) || defined(Q_OS_ANDROID) const QString scheme = "org.jitsi.meet://"; #else const QString scheme = QStringLiteral("https://"); #endif const QString url = scheme + mRuqolaServerConfig->jitsiMeetUrl() + QLatin1Char('/') + mRuqolaServerConfig->jitsiMeetPrefix() + hash; const QUrl clickedUrl = QUrl::fromUserInput(url); QDesktopServices::openUrl(clickedUrl); } void RocketChatAccount::eraseRoom(const QString &roomId, const QString &channelType) { #ifdef USE_REASTAPI_JOB_NOT_SUPPORTED_YET restApi()->closeChannel(roomId, channelType); #else Q_UNUSED(channelType); ddp()->eraseRoom(roomId); #endif } void RocketChatAccount::openDirectChannel(const QString &username) { #ifdef USE_REASTAPI_JOB restApi()->createDirectMessage(username); #else ddp()->openDirectChannel(username); #endif } void RocketChatAccount::createNewChannel(const QString &name, bool readOnly, bool privateRoom, const QString &userNames) { if (!name.trimmed().isEmpty()) { const QStringList lstUsers = userNames.split(QLatin1Char(','), QString::SkipEmptyParts); #ifdef USE_REASTAPI_JOB if (privateRoom) { restApi()->createGroups(name, readOnly, lstUsers); } else { restApi()->createChannels(name, readOnly, lstUsers); } #else if (privateRoom) { ddp()->createPrivateGroup(name, lstUsers); } else { ddp()->createChannel(name, lstUsers, readOnly); } #endif } else { qCDebug(RUQOLA_LOG) << "Channel name can't be empty"; } } void RocketChatAccount::joinRoom(const QString &roomId, const QString &joinCode) { //TODO use restapi ddp()->joinRoom(roomId, joinCode); ddp()->subscribeRoomMessage(roomId); } void RocketChatAccount::channelAndPrivateAutocomplete(const QString &pattern) { //TODO use restapi if (pattern.isEmpty()) { searchChannelModel()->clear(); } else { //Avoid to show own user const QString addUserNameToException = userName(); ddp()->channelAndPrivateAutocomplete(pattern, addUserNameToException); } } void RocketChatAccount::listEmojiCustom() { #ifdef USE_REASTAPI_JOB if (mRuqolaServerConfig->hasAtLeastVersion(0, 63, 0)) { #ifdef USE_REASTAPI_JOB restApi()->listEmojiCustom(); connect(restApi(), &RocketChatRestApi::RestApiRequest::loadEmojiCustomDone, this, &RocketChatAccount::loadEmojiRestApi, Qt::UniqueConnection); #else ddp()->listEmojiCustom(); #endif } else { ddp()->listEmojiCustom(); } #else ddp()->listEmojiCustom(); #endif } void RocketChatAccount::setDefaultStatus(User::PresenceStatus status) { //Not implemented yet //TODO use restapi ddp()->setDefaultStatus(status); } void RocketChatAccount::changeDefaultStatus(int index) { setDefaultStatus(mStatusModel->status(index)); } void RocketChatAccount::loadEmojiRestApi(const QJsonObject &obj) { mEmojiManager->loadEmoji(obj, true); } void RocketChatAccount::loadEmoji(const QJsonObject &obj) { mEmojiManager->loadEmoji(obj, false); } void RocketChatAccount::deleteMessage(const QString &messageId, const QString &roomId) { #ifdef USE_REASTAPI_JOB restApi()->deleteMessage(roomId, messageId); #else Q_UNUSED(roomId); ddp()->deleteMessage(messageId); #endif } void RocketChatAccount::insertFilesList(const QString &roomId) { FilesForRoomModel *filesForRoomModel = roomModel()->filesModelForRoom(roomId); if (filesForRoomModel) { filesForRoomModel->setFiles(rocketChatBackend()->files()); } else { qCWarning(RUQOLA_LOG) << " Impossible to find room " << roomId; } } void RocketChatAccount::insertCompleterUsers() { userCompleterModel()->insertUsers(rocketChatBackend()->users()); } void RocketChatAccount::userAutocomplete(const QString &searchText, const QString &exception) { //Clear before to create new search userCompleterModel()->clear(); rocketChatBackend()->clearUsersList(); if (!searchText.isEmpty()) { //Avoid to show own user QString addUserNameToException; if (exception.isEmpty()) { addUserNameToException = userName(); } else { addUserNameToException = exception + QLatin1Char(',') + userName(); } //TODO use restapi ddp()->userAutocomplete(searchText, addUserNameToException); } } void RocketChatAccount::getUsersOfRoom(const QString &roomId) { //TODO use restapi ddp()->getUsersOfRoom(roomId, true); } void RocketChatAccount::parseUsersForRooms(const QString &roomId, const QJsonObject &root) { UsersForRoomModel *usersModelForRoom = roomModel()->usersModelForRoom(roomId); if (usersModelForRoom) { usersModelForRoom->parseUsersForRooms(root, mUserModel); } else { qCWarning(RUQOLA_LOG) << " Impossible to find room " << roomId; } } void RocketChatAccount::loadAutoCompleteChannel(const QJsonObject &obj) { mSearchChannelModel->parseChannels(obj); } UsersForRoomModel *RocketChatAccount::usersModelForRoom(const QString &roomId) const { return mRoomModel->usersModelForRoom(roomId); } void RocketChatAccount::roomFiles(const QString &roomId, const QString &channelType) { #ifdef USE_REASTAPI_JOB connect(restApi(), &RocketChatRestApi::RestApiRequest::channelFilesDone, this, &RocketChatAccount::slotChannelFilesDone, Qt::UniqueConnection); restApi()->filesInRoom(roomId, channelType); #else Q_UNUSED(channelType); rocketChatBackend()->clearFilesList(); ddp()->roomFiles(roomId); #endif } QVector RocketChatAccount::parseFilesInChannel(const QJsonObject &obj) { //TODO add autotests QVector files; const QJsonArray filesArray = obj.value(QLatin1String("files")).toArray(); for (int i = 0; i < filesArray.count(); ++i) { QJsonObject fileObj = filesArray.at(i).toObject(); File f; f.parseFile(fileObj, true); files.append(f); } return files; } ReceiveTypingNotificationManager *RocketChatAccount::receiveTypingNotificationManager() const { return mReceiveTypingNotificationManager; } void RocketChatAccount::slotChannelFilesDone(const QJsonObject &obj, const QString &roomId) { const QVector files = parseFilesInChannel(obj); FilesForRoomModel *filesForRoomModel = roomModel()->filesModelForRoom(roomId); if (filesForRoomModel) { filesForRoomModel->setFiles(files); } else { qCWarning(RUQOLA_LOG) << " Impossible to find room " << roomId; } } void RocketChatAccount::createJitsiConfCall(const QString &roomId) { //TODO use restapi ddp()->createJitsiConfCall(roomId); joinJitsiConfCall(roomId); } void RocketChatAccount::addUserToRoom(const QString &username, const QString &roomId, const QString &channelType) { #ifdef USE_REASTAPI_JOB_IMPOSSIBLE_YET restApi()->addUserInChannel(roomId, username); restApi()->addUserInGroup(roomId, username); #else Q_UNUSED(channelType); ddp()->addUserToRoom(username, roomId); #endif } void RocketChatAccount::clearSearchModel() { mSearchMessageModel->clear(); } void RocketChatAccount::messageSearch(const QString &pattern, const QString &rid) { if (pattern.isEmpty()) { clearSearchModel(); } else { #ifdef USE_REASTAPI_JOB connect(restApi(), &RocketChatRestApi::RestApiRequest::searchMessageDone, this, &RocketChatAccount::slotSearchMessages); restApi()->searchMessages(rid, pattern); #else ddp()->messageSearch(rid, pattern); #endif } } void RocketChatAccount::slotSearchMessages(const QJsonObject &obj) { mSearchMessageModel->parseResult(obj, true); } void RocketChatAccount::starMessage(const QString &messageId, const QString &rid, bool starred) { #ifdef USE_REASTAPI_JOB Q_UNUSED(rid); restApi()->starMessage(messageId, starred); #else ddp()->starMessage(messageId, rid, starred); #endif } void RocketChatAccount::uploadFile(const QString &roomId, const QString &description, const QString &messageText, const QUrl &fileUrl) { restApi()->uploadFile(roomId, description, messageText, fileUrl); } void RocketChatAccount::changeChannelSettings(const QString &roomId, RocketChatAccount::RoomInfoType infoType, const QVariant &newValue, const QString &channelType) { switch (infoType) { case Announcement: #ifdef USE_REASTAPI_JOB if (channelType == QStringLiteral("c")) { restApi()->changeChannelAnnouncement(roomId, newValue.toString()); } else if (channelType == QStringLiteral("p")) { #ifdef USE_RESTAPI_NO_IMPLEMENTED_YET //FOR the moment we can't change group announcement with restapi //restApi()->changeGroupsAnnouncement(roomId, newValue.toString()); #else ddp()->setRoomAnnouncement(roomId, newValue.toString()); #endif } else { qCWarning(RUQOLA_LOG) << " unsupport change announcement for type " << channelType; } #else ddp()->setRoomAnnouncement(roomId, newValue.toString()); #endif break; case Description: #ifdef USE_REASTAPI_JOB if (channelType == QStringLiteral("c")) { restApi()->changeChannelDescription(roomId, newValue.toString()); } else if (channelType == QStringLiteral("p")) { restApi()->changeGroupsDescription(roomId, newValue.toString()); } else { qCWarning(RUQOLA_LOG) << " unsupport change description for type " << channelType; } #else ddp()->setRoomDescription(roomId, newValue.toString()); #endif break; case Name: ddp()->setRoomName(roomId, newValue.toString()); break; case Topic: #ifdef USE_REASTAPI_JOB if (channelType == QStringLiteral("c")) { restApi()->changeChannelTopic(roomId, newValue.toString()); } else if (channelType == QStringLiteral("p")) { restApi()->changeGroupsTopic(roomId, newValue.toString()); } else { qCWarning(RUQOLA_LOG) << " unsupport change topic for type " << channelType; } #else ddp()->setRoomTopic(roomId, newValue.toString()); #endif break; case ReadOnly: ddp()->setRoomIsReadOnly(roomId, newValue.toBool()); break; case Archive: #ifdef USE_REASTAPI_JOB if (channelType == QStringLiteral("c")) { restApi()->archiveChannel(roomId); } else if (channelType == QStringLiteral("p")) { restApi()->archiveGroups(roomId); } else { qCWarning(RUQOLA_LOG) << " unsupport archiving for type " << channelType; } #else //No argument here. ddp()->archiveRoom(roomId); #endif break; case RoomType: ddp()->setRoomType(roomId, newValue.toBool()); break; } } void RocketChatAccount::changeNotificationsSettings(const QString &roomId, RocketChatAccount::NotificationOptionsType notificationsType, const QVariant &newValue) { #ifdef USE_REASTAPI_JOB switch (notificationsType) { case DisableNotifications: restApi()->disableNotifications(roomId, newValue.toBool()); break; case HideUnreadStatus: restApi()->hideUnreadStatus(roomId, newValue.toBool()); break; case AudioNotifications: restApi()->audioNotifications(roomId, newValue.toString()); break; case DesktopNotifications: restApi()->desktopNotifications(roomId, newValue.toString()); break; case EmailNotifications: restApi()->emailNotifications(roomId, newValue.toString()); break; case MobilePushNotifications: restApi()->mobilePushNotifications(roomId, newValue.toString()); break; case UnreadAlert: restApi()->unreadAlert(roomId, newValue.toString()); break; } #else switch (notificationsType) { case DisableNotifications: ddp()->disableNotifications(roomId, newValue.toBool()); break; case HideUnreadStatus: ddp()->hideUnreadStatus(roomId, newValue.toBool()); break; case AudioNotifications: ddp()->audioNotifications(roomId, newValue.toString()); break; case DesktopNotifications: ddp()->desktopNotifications(roomId, newValue.toString()); break; case EmailNotifications: ddp()->emailNotifications(roomId, newValue.toString()); break; case MobilePushNotifications: ddp()->mobilePushNotifications(roomId, newValue.toString()); break; case UnreadAlert: ddp()->unreadAlert(roomId, newValue.toString()); break; } #endif } void RocketChatAccount::parsePublicSettings(const QJsonObject &obj) { QJsonArray configs = obj.value(QLatin1String("result")).toArray(); for (QJsonValueRef currentConfig : configs) { QJsonObject currentConfObject = currentConfig.toObject(); const QString id = currentConfObject[QStringLiteral("_id")].toString(); const QVariant value = currentConfObject[QStringLiteral("value")].toVariant(); if (id == QLatin1String("uniqueID")) { mRuqolaServerConfig->setUniqueId(value.toString()); } else if (id == QLatin1String("Jitsi_Domain")) { mRuqolaServerConfig->setJitsiMeetUrl(value.toString()); } else if (id == QLatin1String("Jitsi_URL_Room_Prefix")) { mRuqolaServerConfig->setJitsiMeetPrefix(value.toString()); } else if (id == QLatin1String("FileUpload_Storage_Type")) { mRuqolaServerConfig->setFileUploadStorageType(value.toString()); } else if (id == QLatin1String("Message_AllowEditing")) { mRuqolaServerConfig->setAllowMessageEditing(value.toBool()); } else if (id == QLatin1String("Message_AllowEditing_BlockEditInMinutes")) { mRuqolaServerConfig->setBlockEditingMessageInMinutes(value.toInt()); } else if (id == QLatin1String("OTR_Enable")) { mRuqolaServerConfig->setOtrEnabled(value.toBool()); } else if (id.contains(QRegularExpression(QStringLiteral("^Accounts_OAuth_\\w+")))) { if (value.toBool()) { mRuqolaServerConfig->addOauthService(id); } } else if (id == QLatin1String("Site_Url")) { mRuqolaServerConfig->setSiteUrl(value.toString()); } else if (id == QLatin1String("Site_Name")) { mRuqolaServerConfig->setSiteName(value.toString()); } else { qCDebug(RUQOLA_LOG) << "Other public settings id " << id << value; } } fillOauthModel(); } void RocketChatAccount::fillOauthModel() { QVector fillModel; for (int i = 0, total = mLstInfos.count(); i < total; ++i) { if (mRuqolaServerConfig->canShowOauthService(mLstInfos.at(i).oauthType())) { fillModel.append(mLstInfos.at(i)); } } mLoginMethodModel->setAuthenticationInfos(fillModel); } void RocketChatAccount::changeDefaultAuthentication(int index) { setDefaultAuthentication(mLoginMethodModel->loginType(index)); } void RocketChatAccount::setDefaultAuthentication(AuthenticationManager::OauthType type) { PluginAuthenticationInterface *interface = mLstPluginAuthenticationInterface.value(type); if (interface) { mDefaultAuthenticationInterface = interface; } else { qCWarning(RUQOLA_LOG) << "No interface defined for " << type; } } SearchMessageFilterProxyModel *RocketChatAccount::searchMessageFilterProxyModel() const { return mSearchMessageFilterProxyModel; } SearchMessageModel *RocketChatAccount::searchMessageModel() const { return mSearchMessageModel; } void RocketChatAccount::initializeAuthenticationPlugins() { //TODO change it when we change server //Clean up at the end. const QVector lstPlugins = AuthenticationManager::self()->pluginsList(); qCDebug(RUQOLA_LOG) <<" void RocketChatAccount::initializeAuthenticationPlugins()" << lstPlugins.count(); mLstPluginAuthenticationInterface.clear(); mLstInfos.clear(); for (PluginAuthentication *abstractPlugin : lstPlugins) { AuthenticationInfo info; info.setIconName(abstractPlugin->iconName()); info.setName(abstractPlugin->name()); info.setOauthType(abstractPlugin->type()); if (info.isValid()) { mLstInfos.append(info); } PluginAuthenticationInterface *interface = abstractPlugin->createInterface(this); interface->setAccount(this); mRuqolaServerConfig->addRuqolaAuthenticationSupport(abstractPlugin->type()); mLstPluginAuthenticationInterface.insert(abstractPlugin->type(), interface); //For the moment initialize default interface if (abstractPlugin->type() == AuthenticationManager::OauthType::Password) { mDefaultAuthenticationInterface = interface; } qCDebug(RUQOLA_LOG) << " plugin type " << abstractPlugin->type(); } //TODO fill ??? or store QVector } PluginAuthenticationInterface *RocketChatAccount::defaultAuthenticationInterface() const { return mDefaultAuthenticationInterface; } InputCompleterModel *RocketChatAccount::inputCompleterModel() const { return mInputTextManager->inputCompleterModel(); } LoginMethodModel *RocketChatAccount::loginMethodModel() const { return mLoginMethodModel; } QString RocketChatAccount::authToken() const { return settings()->authToken(); } QString RocketChatAccount::userName() const { return settings()->userName(); } void RocketChatAccount::setAccountName(const QString &accountname) { //Initialize new account room ManagerDataPaths::self()->initializeAccountPath(accountname); //qDebug() << "void RocketChatAccount::setAccountName(const QString &servername)"<accountConfigFileName(accountname)); settings()->setAccountName(accountname); } QString RocketChatAccount::accountName() const { return settings()->accountName(); } QString RocketChatAccount::userID() const { return settings()->userId(); } QString RocketChatAccount::password() const { return settings()->password(); } void RocketChatAccount::setAuthToken(const QString &token) { settings()->setAuthToken(token); } void RocketChatAccount::setPassword(const QString &password) { settings()->setPassword(password); } void RocketChatAccount::setUserName(const QString &username) { settings()->setUserName(username); } void RocketChatAccount::setUserID(const QString &userID) { settings()->setUserId(userID); } QString RocketChatAccount::serverUrl() const { return settings()->serverUrl(); } void RocketChatAccount::setServerUrl(const QString &serverURL) { settings()->setServerUrl(serverURL); restApi()->setServerUrl(serverURL); mEmojiManager->setServerUrl(serverURL); } QString RocketChatAccount::recordingVideoPath() const { return mCache->recordingVideoPath(accountName()); } QString RocketChatAccount::recordingImagePath() const { return mCache->recordingImagePath(accountName()); } void RocketChatAccount::downloadFile(const QString &downloadFileUrl, const QUrl &localFile) { mCache->downloadFile(downloadFileUrl, localFile, false); } QUrl RocketChatAccount::attachmentUrl(const QString &url) { return mCache->attachmentUrl(url); } void RocketChatAccount::loadHistory(const QString &roomID, const QString &channelType, bool initial) { //TODO port to restapi Q_UNUSED(channelType); MessageModel *roomModel = messageModelForRoom(roomID); if (roomModel) { //TODO add autotest for it ! QJsonArray params; params.append(QJsonValue(roomID)); // Load history const qint64 endDateTime = roomModel->lastTimestamp(); if (initial || roomModel->isEmpty()) { params.append(QJsonValue(QJsonValue::Null)); params.append(QJsonValue(50)); // Max number of messages to load; QJsonObject dateObject; //qDebug() << "roomModel->lastTimestamp()" << roomModel->lastTimestamp() << " ROOMID " << roomID; dateObject[QStringLiteral("$date")] = QJsonValue(endDateTime); params.append(dateObject); } else { const qint64 startDateTime = roomModel->generateNewStartTimeStamp(endDateTime); QJsonObject dateObjectEnd; dateObjectEnd[QStringLiteral("$date")] = QJsonValue(endDateTime); //qDebug() << " QDATE TIME END" << QDateTime::fromMSecsSinceEpoch(endDateTime) << " START " << QDateTime::fromMSecsSinceEpoch(startDateTime) << " ROOMID" << roomID; params.append(dateObjectEnd); params.append(QJsonValue(50)); // Max number of messages to load; QJsonObject dateObjectStart; //qDebug() << "roomModel->lastTimestamp()" << roomModel->lastTimestamp() << " ROOMID " << roomID; dateObjectStart[QStringLiteral("$date")] = QJsonValue(startDateTime); params.append(dateObjectStart); } ddp()->loadHistory(params); } else { qCWarning(RUQOLA_LOG) << "Room is not found " << roomID; } } void RocketChatAccount::setServerVersion(const QString &version) { qCDebug(RUQOLA_LOG) << " void RocketChatAccount::setServerVersion(const QString &version)" << version; mRuqolaServerConfig->setServerVersion(version); } bool RocketChatAccount::needAdaptNewSubscriptionRC60() const { return mRuqolaServerConfig->needAdaptNewSubscriptionRC60(); } bool RocketChatAccount::otrEnabled() const { return mRuqolaServerConfig->otrEnabled(); } bool RocketChatAccount::allowEditingMessages() const { return mRuqolaServerConfig->allowMessageEditing(); } void RocketChatAccount::parseOtr(const QJsonArray &contents) { const Otr t = mOtrManager->parseOtr(contents); qDebug() << " void RocketChatAccount::parseOtr(const QJsonArray &contents)"<avatarUrlFromCacheOnly(sender); //qDebug() << " iconFileName"<inputChannelAutocomplete(pattern, exceptions); } void RocketChatAccount::inputUserAutocomplete(const QString &pattern, const QString &exceptions) { ddp()->inputUserAutocomplete(pattern, exceptions); } void RocketChatAccount::inputTextCompleter(const QJsonObject &obj) { mInputTextManager->inputTextCompleter(obj); } void RocketChatAccount::displaySearchedMessage(const QJsonObject &obj) { mSearchMessageModel->parseResult(obj); } void RocketChatAccount::updateUser(const QJsonObject &object) { mUserModel->updateUser(object); } void RocketChatAccount::userStatusChanged(const User &user) { //qDebug() << " void RocketChatAccount::userStatusChanged(const User &user)"<setCurrentPresenceStatus(Utils::presenceStatusFromString(user.status())); } mRoomModel->userStatusChanged(user); } void RocketChatAccount::ignoreUser(const QString &rid, const QString &userId, bool ignore) { - qDebug() << " void RocketChatAccount::ignoreUser(const QString &rid, const QString &userId, bool ignore)"<ignoreUser(rid, userId, ignore); } void RocketChatAccount::blockUser(const QString &rid, bool block) { //TODO use restapi if (rid.isEmpty()) { qCWarning(RUQOLA_LOG) << " void RocketChatAccount::blockUser EMPTY rid ! block " << block; } else { //qDebug() << " void RocketChatAccount::blockUser userId " << userId << " block " << block << " rid " << rid << " own userdId" << userID(); const QString userId = Utils::userIdFromDirectChannel(rid, userID()); if (block) { ddp()->blockUser(rid, userId); } else { ddp()->unBlockUser(rid, userId); } } } void RocketChatAccount::initializeRoom(const QString &roomId, bool loadInitialHistory) { - //TODO use restapi ddp()->subscribeRoomMessage(roomId); getUsersOfRoom(roomId); if (loadInitialHistory) { //Load history //TODO fix me use channeltype! loadHistory(roomId, QString(), true /*initial loading*/); } } void RocketChatAccount::openDocumentation() { QDesktopServices::openUrl(QUrl(QStringLiteral("help:/"))); } diff --git a/src/ruqolacore/rocketchatbackend.cpp b/src/ruqolacore/rocketchatbackend.cpp index 77d15532..b50b917c 100644 --- a/src/ruqolacore/rocketchatbackend.cpp +++ b/src/ruqolacore/rocketchatbackend.cpp @@ -1,640 +1,646 @@ /* * Copyright 2016 Riccardo Iaconelli * Copyright 2018 Laurent Montel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "rocketchataccount.h" #include "rocketchatbackend.h" #include "model/usercompletermodel.h" #include "ruqola_debug.h" #include "ruqola_message_debug.h" #include "ddpapi/ddpclient.h" #include "restapirequest.h" #include "user.h" #include "model/usersmodel.h" #include "ruqolalogger.h" #include "model/messagemodel.h" #include "receivetypingnotificationmanager.h" #include "file.h" #include "user.h" #include #include void process_publicsettings(const QJsonObject &obj, RocketChatAccount *account) { account->parsePublicSettings(obj); //qCDebug(RUQOLA_LOG) << " configs"<ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Public Settings:") + QJsonDocument(obj).toJson()); } } void rooms_parsing(const QJsonObject &root, RocketChatAccount *account) { const QJsonObject obj = root.value(QLatin1String("result")).toObject(); RoomModel *model = account->roomModel(); //qDebug() << " doc " << doc; QJsonArray removed = obj.value(QLatin1String("remove")).toArray(); //qDebug() << " rooms_parsing: room removed *************************************************" << removed; const QJsonArray updated = obj.value(QLatin1String("update")).toArray(); //qDebug() << " rooms_parsing: updated *******************************************************: "<< updated; for (int i = 0; i < updated.size(); i++) { QJsonObject roomJson = updated.at(i).toObject(); const QString roomType = roomJson.value(QLatin1String("t")).toString(); if (account->ruqolaLogger()) { QJsonDocument d; d.setObject(roomJson); account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Rooms:") + d.toJson()); } if (roomType == QLatin1String("c") //Chat || roomType == QLatin1String("p") /*Private chat*/) { // let's be extra safe around crashes if (account->loginStatus() == DDPClient::LoggedIn) { model->updateRoom(roomJson); } } } } void getsubscription_parsing(const QJsonObject &root, RocketChatAccount *account) { const QJsonObject obj = root.value(QLatin1String("result")).toObject(); RoomModel *model = account->roomModel(); //qDebug() << " doc " << doc; const QJsonArray removed = obj.value(QLatin1String("remove")).toArray(); qDebug() << " room removed " << removed; //TODO implement it. const QJsonArray updated = obj.value(QLatin1String("update")).toArray(); //qDebug() << " updated : "<< updated; for (int i = 0; i < updated.size(); i++) { QJsonObject room = updated.at(i).toObject(); const QString roomType = room.value(QLatin1String("t")).toString(); if (account->ruqolaLogger()) { QJsonDocument d; d.setObject(room); account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Rooms subscriptions:") + d.toJson()); } if (roomType == QLatin1String("c") //Chat || roomType == QLatin1String("p") /*Private chat*/ || roomType == QLatin1String("d")) { //Direct chat) { // let's be extra safe around crashes if (account->loginStatus() == DDPClient::LoggedIn) { Room *r = model->addRoom(room); account->initializeRoom(r->roomId(), r->open()); } } else if (roomType == QLatin1String("l")) { //Live chat qCDebug(RUQOLA_LOG) << "Live Chat not implemented yet"; } } //We need to load all room after get subscription to update parameters QJsonObject params; params[QStringLiteral("$date")] = QJsonValue(0); // get ALL rooms we've ever seen account->ddp()->method(QStringLiteral("rooms/get"), QJsonDocument(params), rooms_parsing); //TODO ? account->listEmojiCustom(); //Force set online. account->ddp()->setDefaultStatus(User::PresenceStatus::PresenceOnline); } RocketChatBackend::RocketChatBackend(RocketChatAccount *account, QObject *parent) : QObject(parent) , mRocketChatAccount(account) { connect(mRocketChatAccount, &RocketChatAccount::loginStatusChanged, this, &RocketChatBackend::slotLoginStatusChanged); connect(mRocketChatAccount, &RocketChatAccount::userIDChanged, this, &RocketChatBackend::slotUserIDChanged); connect(mRocketChatAccount, &RocketChatAccount::changed, this, &RocketChatBackend::slotChanged); connect(mRocketChatAccount, &RocketChatAccount::added, this, &RocketChatBackend::slotAdded); connect(mRocketChatAccount, &RocketChatAccount::removed, this, &RocketChatBackend::slotRemoved); connect(mRocketChatAccount, &RocketChatAccount::connectedChanged, this, &RocketChatBackend::slotConnectedChanged); } RocketChatBackend::~RocketChatBackend() { } void RocketChatBackend::slotConnectedChanged() { mRocketChatAccount->restApi()->serverInfo(); connect(mRocketChatAccount->restApi(), &RocketChatRestApi::RestApiRequest::getServerInfoDone, this, &RocketChatBackend::parseServerVersionDone, Qt::UniqueConnection); mRocketChatAccount->ddp()->method(QStringLiteral("public-settings/get"), QJsonDocument(), process_publicsettings); } void RocketChatBackend::processIncomingMessages(const QJsonArray &messages) { for (const QJsonValue &v : messages) { QJsonObject o = v.toObject(); if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(o); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("Message:") + d.toJson()); } else { qCDebug(RUQOLA_MESSAGE_LOG) <<" new message: " << o; } Message m; m.parseMessage(o); //qDebug() << " roomId"<messageModelForRoom(m.roomId())) { messageModel->addMessage(m); } else { qCWarning(RUQOLA_MESSAGE_LOG) << " MessageModel is empty for :" << m.roomId() << " It's a bug for sure."; } } } void RocketChatBackend::parseOwnInfoDown(const QJsonObject &replyObject) { //Move code in rocketchataccount directly ? //qDebug() << "replyJson " << replyJson; User user; user.setUserId(replyObject.value(QLatin1String("_id")).toString()); user.setUserName(replyObject.value(QLatin1String("username")).toString()); user.setStatus(replyObject.value(QLatin1String("status")).toString()); if (user.isValid()) { mRocketChatAccount->usersModel()->addUser(user); } else { qCWarning(RUQOLA_LOG) << " Error during parsing user" << replyObject; } } void RocketChatBackend::slotLoginStatusChanged() { if (mRocketChatAccount->loginStatus() == DDPClient::LoggedIn) { connect(mRocketChatAccount->restApi(), &RocketChatRestApi::RestApiRequest::getOwnInfoDone, this, &RocketChatBackend::parseOwnInfoDown, Qt::UniqueConnection); QJsonObject params; params[QStringLiteral("$date")] = QJsonValue(0); // get ALL rooms we've ever seen std::function subscription_callback = [=](const QJsonObject &obj, RocketChatAccount *account) { getsubscription_parsing(obj, account); }; mRocketChatAccount->ddp()->method(QStringLiteral("subscriptions/get"), QJsonDocument(params), subscription_callback); mRocketChatAccount->restApi()->setAuthToken(mRocketChatAccount->settings()->authToken()); mRocketChatAccount->restApi()->setUserId(mRocketChatAccount->settings()->userId()); mRocketChatAccount->restApi()->getPrivateSettings(); mRocketChatAccount->restApi()->getOwnInfo(); } } void RocketChatBackend::parseServerVersionDone(const QString &version) { qCDebug(RUQOLA_LOG) << " void RocketChatBackend::parseServerVersionDone(const QString &version)******************" << version; mRocketChatAccount->setServerVersion(version); mRocketChatAccount->ddp()->login(); } QVector RocketChatBackend::files() const { return mFiles; } QVector RocketChatBackend::users() const { return mUsers; } void RocketChatBackend::slotRemoved(const QJsonObject &object) { const QString collection = object.value(QLatin1String("collection")).toString(); if (collection == QLatin1String("users")) { const QString id = object.value(QLatin1String("id")).toString(); mRocketChatAccount->usersModel()->removeUser(id); if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("users: Removed user:") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "USER REMOVED VALUE" << object; } } else { qCDebug(RUQOLA_LOG) << " Other collection type removed " << collection << " object "<settings()->userName()) { mRocketChatAccount->settings()->setUserId(object[QStringLiteral("id")].toString()); qCDebug(RUQOLA_LOG) << "User id set to " << mRocketChatAccount->settings()->userId(); } else { //TODO add current user ? me ? User user; user.parseUser(object); if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("users: Add User:") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "USER ADDED VALUE" << object; } mRocketChatAccount->usersModel()->addUser(user); } qCDebug(RUQOLA_LOG) << "NEW USER ADDED: " << username << fields; } else if (collection == QLatin1String("rooms")) { qCDebug(RUQOLA_LOG) << "NEW ROOMS ADDED: " << object; } else if (collection == QLatin1String("stream-notify-user")) { qCDebug(RUQOLA_LOG) << "stream-notify-user: " << object; } else if (collection == QLatin1String("stream-notify-all")) { qCDebug(RUQOLA_LOG) << "stream-notify-user: " << object; //TODO verify that all is ok ! } else if (collection == QLatin1String("autocompleteRecords")) { if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("autocompleteRecords: Add User:") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "AutoCompleteRecords VALUE" << object; } User user; user.parseUser(object); mUsers.append(user); } else if (collection == QLatin1String("room_files")) { if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("room_files: Add Files:") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "room_files VALUE" << object; } File file; file.parseFile(object); mFiles.append(file); } else if (collection == QLatin1String("stream-notify-room")) { //TODO qCDebug(RUQOLA_LOG) << "stream-notify-room not implemented: "<< object; } else { qCDebug(RUQOLA_LOG) << "Unknown added element: "<< object; } } void RocketChatBackend::slotChanged(const QJsonObject &object) { //qDebug() << " void RocketChatBackend::onChanged(const QJsonObject &object)"<ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("users: User Changed:") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "USER CHANGED" << object; } mRocketChatAccount->updateUser(object); } else if (collection == QLatin1String("rooms")) { if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("rooms: Room Changed:") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "ROOMS CHANGED: " << object; } } else if (collection == QLatin1String("stream-notify-user")) { QJsonObject fields = object.value(QLatin1String("fields")).toObject(); const QString eventname = fields.value(QLatin1String("eventName")).toString(); const QJsonArray contents = fields.value(QLatin1String("args")).toArray(); qCDebug(RUQOLA_LOG) << " EVENT " << eventname << " contents " << contents << fields.value(QLatin1String("args")).toArray().toVariantList(); if (eventname.endsWith(QLatin1String("/subscriptions-changed"))) { RoomModel *model = mRocketChatAccount->roomModel(); model->updateSubscription(contents); if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(fields); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("stream-notify-user: subscriptions-changed:") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "stream-notify-user: subscriptions-changed " << object; } } else if (eventname.endsWith(QLatin1String("/rooms-changed"))) { RoomModel *model = mRocketChatAccount->roomModel(); //qDebug() << " EVENT " << eventname << " contents " << contents << fields.value(QLatin1String("args")).toArray().toVariantList(); const QJsonArray lst = fields.value(QLatin1String("args")).toArray(); const QString actionName = lst[0].toString(); if (actionName == QLatin1String("updated")) { qDebug() << " Update room " << lst; const QJsonObject roomData = lst[1].toObject(); model->updateRoom(roomData); } else if (actionName == QLatin1String("inserted")) { qDebug() << " insert new Room !!!!!" << lst; const QJsonObject roomData = lst[1].toObject(); const QString rid = model->insertRoom(roomData); qDebug() << "rid " << rid; mRocketChatAccount->initializeRoom(rid); } else if (actionName == QLatin1String("removed")) { qDebug() << "Remove channel" << lst; const QJsonObject roomData = lst[1].toObject(); //TODO use rid model->removeRoom(QString()); } else { qWarning() << "rooms-changed invalid actionName " << actionName; } if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("stream-notify-user: Room Changed:") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "ROOMS CHANGED: " << object; } } else if (eventname.endsWith(QLatin1String("/notification"))) { if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("stream-notify-user: notification:") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "NOTIFICATION: " << object; } mRocketChatAccount->sendNotification(contents); } else if (eventname.endsWith(QLatin1String("/webrtc"))) { if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("stream-notify-user: webrtc: ") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "WEBRTC CHANGED: " << object; } qCWarning(RUQOLA_LOG) << "stream-notify-user : WEBRTC ? " << eventname << " contents " << contents; } else if (eventname.endsWith(QLatin1String("/otr"))) { if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("stream-notify-user: otr: ") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "OTR CHANGED: " << object; } mRocketChatAccount->parseOtr(contents); qCWarning(RUQOLA_LOG) << "stream-notify-user : OTR ? " << eventname << " contents " << contents; } else if (eventname.endsWith(QLatin1String("/message"))) { if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("stream-notify-user: message: ") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "stream-notify-user : Message: " << object; } const QJsonArray lst = fields.value(QLatin1String("args")).toArray(); const QJsonObject roomData = lst[0].toObject(); QString roomId = roomData.value(QLatin1String("rid")).toString(); if (!roomId.isEmpty()) { MessageModel *messageModel = mRocketChatAccount->messageModelForRoom(roomId); Message m; m.parseMessage(roomData); //m.setMessageType(Message::System); //TODO add special element!See roomData QJsonObject({"_id":"u9xnnzaBQoQithsxP","msg":"You have been muted and cannot speak in this room","rid":"Dic5wZD4Zu9ze5gk3","ts":{"$date":1534166745895}}) messageModel->addMessage(m); } else { qCWarning(RUQOLA_LOG) << "stream-notify-user : Message: ROOMID is empty "; } qCWarning(RUQOLA_LOG) << "stream-notify-user : Message " << eventname << " contents " << contents; } else { if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("stream-notify-user: Unknown event: ") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "Unknown change: " << object; } qCWarning(RUQOLA_LOG) << "stream-notify-user : message event " << eventname << " contents " << contents; } } else if (collection == QLatin1String("stream-notify-room")) { qCDebug(RUQOLA_LOG) << " stream-notify-room " << collection << " object "<ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("stream-notify-room: DeleteMessage:") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "Delete message" << object; } //Move code in rocketChatAccount ? QString roomId = eventname; roomId.remove(QStringLiteral("/deleteMessage")); MessageModel *messageModel = mRocketChatAccount->messageModelForRoom(roomId); if (messageModel) { messageModel->deleteMessage(contents.at(0).toObject()[QStringLiteral("_id")].toString()); } else { qCWarning(RUQOLA_MESSAGE_LOG) << " MessageModel is empty for :" << roomId << " It's a bug for sure."; } } else if (eventname.endsWith(QLatin1String("/typing"))) { if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("stream-notify-room: typing:") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "typing message" << object; } QString roomId = eventname; roomId.remove(QStringLiteral("/typing")); //TODO Perhaps not necessary to convert to variantlist. Need to investigate qCWarning(RUQOLA_LOG) << "stream-notify-room: typing event ? " << eventname << " content " << contents.toVariantList(); const QString typingUserName = contents.toVariantList().at(0).toString(); if (typingUserName != mRocketChatAccount->settings()->userName()) { const bool status = contents.toVariantList().at(1).toBool(); mRocketChatAccount->receiveTypingNotificationManager()->insertTypingNotification(roomId, typingUserName, status); } } else { - qCWarning(RUQOLA_LOG) << "stream-notify-room: Unknown event ? " << eventname; + if (mRocketChatAccount->ruqolaLogger()) { + QJsonDocument d; + d.setObject(object); + mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("stream-notify-room: Unknown event ?") + d.toJson()); + } else { + qCWarning(RUQOLA_LOG) << "stream-notify-room: Unknown event ? " << eventname; + } } } else { qCDebug(RUQOLA_LOG) << " Other collection type changed " << collection << " object "<settings()->userId() }; { //Subscribe notification. QJsonArray params; params.append(QJsonValue(QStringLiteral("%1/%2").arg(userId).arg(QStringLiteral("notification")))); mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-user"), params); } { //Subscribe room-changed. QJsonArray params; params.append(QJsonValue(QStringLiteral("%1/%2").arg(userId).arg(QStringLiteral("rooms-changed")))); mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-user"), params); } { //Subscribe subscriptions-changed QJsonArray params; params.append(QJsonValue(QStringLiteral("%1/%2").arg(userId).arg(QStringLiteral("subscriptions-changed")))); mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-user"), params); } { //Subscribe message QJsonArray params; params.append(QJsonValue(QStringLiteral("%1/%2").arg(userId).arg(QStringLiteral("message")))); mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-user"), params); } { //Subscribe message QJsonArray params; params.append(QJsonValue(QStringLiteral("%1/%2").arg(userId).arg(QStringLiteral("otr")))); mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-user"), params); } { //Subscribe message QJsonArray params; params.append(QJsonValue(QStringLiteral("%1/%2").arg(userId).arg(QStringLiteral("webrtc")))); mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-user"), params); } { //Subscribe activeUsers QJsonArray params; params.append(QJsonValue(params)); mRocketChatAccount->ddp()->subscribe(QStringLiteral("activeUsers"), params); } { //Subscribe users in room ? //TODO verify it. QJsonArray params; params.append(QJsonValue(QStringLiteral("%1/%2").arg(userId).arg(QStringLiteral("webrtc")))); mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-room-users"), params); } //stream-notify-all { const QJsonArray params{ QJsonValue(QStringLiteral("updateAvatar")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-all"), params); } { const QJsonArray params{ QJsonValue(QStringLiteral("roles-change")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-all"), params); } { const QJsonArray params{ QJsonValue(QStringLiteral("updateEmojiCustom")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-all"), params); } { const QJsonArray params{ QJsonValue(QStringLiteral("deleteEmojiCustom")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-all"), params); } { const QJsonArray params{ QJsonValue(QStringLiteral("public-settings-changed")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-all"), params); } { const QJsonArray params{ QJsonValue(QStringLiteral("permissions-changed")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-all"), params); } //stream-notify-logged { const QJsonArray params{ QJsonValue(QStringLiteral("updateEmojiCustom")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-logged"), params); } //stream-notify-logged { const QJsonArray params{ QJsonValue(QStringLiteral("deleteEmojiCustom")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-logged"), params); } //stream-notify-logged { const QJsonArray params{ QJsonValue(QStringLiteral("deleteEmojiCustom")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-logged"), params); } //stream-notify-logged { const QJsonArray params{ QJsonValue(QStringLiteral("updateAvatar")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-logged"), params); } }