diff --git a/src/rocketchataccount.cpp b/src/rocketchataccount.cpp index 7b2c8f3d..245ffbcb 100644 --- a/src/rocketchataccount.cpp +++ b/src/rocketchataccount.cpp @@ -1,610 +1,618 @@ /* 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 "messagemodel.h" #include "rocketchataccount.h" #include "roommodel.h" #include "roomwrapper.h" #include "typingnotification.h" #include "usersmodel.h" #include "ruqola_debug.h" #include "ruqola.h" #include "messagequeue.h" #include "rocketchatbackend.h" #include "usersforroommodel.h" #include "roomfilterproxymodel.h" #include "ruqolalogger.h" #include "ruqolaserverconfig.h" #include "usercompletermodel.h" #include "statusmodel.h" #include "utils.h" #include "rocketchatcache.h" #include "ddpapi/ddpclient.h" #include "restapi/restapirequest.h" #include #include #include #include RocketChatAccount::RocketChatAccount(const QString &accountFileName, QObject *parent) : QObject(parent) { //create an uniq file for each account if (!qEnvironmentVariableIsEmpty("RUQOLA_LOGFILE")) { mRuqolaLogger = new RuqolaLogger; } mRuqolaServerConfig = new RuqolaServerConfig; //TODO add account name. mSettings = new RocketChatAccountSettings(accountFileName, this); connect(mSettings, &RocketChatAccountSettings::loginStatusChanged, this, &RocketChatAccount::loginStatusChanged); connect(mSettings, &RocketChatAccountSettings::serverURLChanged, this, &RocketChatAccount::serverUrlChanged); connect(mSettings, &RocketChatAccountSettings::userIDChanged, this, &RocketChatAccount::userIDChanged); connect(mSettings, &RocketChatAccountSettings::userNameChanged, this, &RocketChatAccount::userNameChanged); mRocketChatBackend = new RocketChatBackend(this, this); - connect(mRocketChatBackend, &RocketChatBackend::notification, this, &RocketChatAccount::notification); loadSettings(); mRoomFilterProxyModel = new RoomFilterProxyModel(this); mUserCompleterModel = new UserCompleterModel(this); mStatusModel = new StatusModel(this); mRoomModel = new RoomModel(this); connect(mRoomModel, &RoomModel::needToUpdateNotification, this, &RocketChatAccount::slotNeedToUpdateNotification); mRoomFilterProxyModel->setSourceModel(mRoomModel); mUserModel = new UsersModel(this); 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; qDeleteAll(mUsersForRoomModels); qDeleteAll(mMessageModels); delete mRuqolaServerConfig; delete mRuqolaLogger; } 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(); } StatusModel *RocketChatAccount::statusModel() const { return mStatusModel; } UserCompleterModel *RocketChatAccount::userCompleterModel() const { return mUserCompleterModel; } RuqolaServerConfig *RocketChatAccount::ruqolaServerConfig() const { return mRuqolaServerConfig; } RuqolaLogger *RocketChatAccount::ruqolaLogger() const { return mRuqolaLogger; } RoomFilterProxyModel *RocketChatAccount::roomFilterProxyModel() const { return mRoomFilterProxyModel; } RocketChatBackend *RocketChatAccount::rocketChatBackend() const { return mRocketChatBackend; } void RocketChatAccount::loadSettings() { mSettings->loadSettings(); } 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; } RoomWrapper *RocketChatAccount::getRoom(const QString &roomId) { return mRoomModel->findRoom(roomId); } MessageModel *RocketChatAccount::getMessageModelForRoom(const QString &roomID) { if (MessageModel *model = mMessageModels.value(roomID)) { return model; } else { mMessageModels[roomID] = new MessageModel(roomID, this, this); return mMessageModels[roomID]; } } UsersForRoomModel *RocketChatAccount::getUsersForRoomModel(const QString &roomId) { UsersForRoomModel *model = nullptr; if ((model = mUsersForRoomModels.value(roomId))) { return model; } else { model = new UsersForRoomModel(this); model->setCurrentRoomId(roomId); mUsersForRoomModels[roomId] = model; return model; } } QString RocketChatAccount::getUserCurrentMessage(const QString &roomId) { return mUserCurrentMessage.value(roomId); } void RocketChatAccount::setUserCurrentMessage(const QString &message, const QString &roomId) { if (mUserCurrentMessage.contains(roomId)) { if (!message.trimmed().isEmpty()) { mUserCurrentMessage[roomId] = message; } else { mUserCurrentMessage.remove(roomId); } } else { if (!message.trimmed().isEmpty()) { mUserCurrentMessage.insert(roomId, message); } } } void RocketChatAccount::textEditing(const QString &roomId, const QString &str) { mTypingNotification->setText(roomId, str); } void RocketChatAccount::sendMessage(const QString &roomID, const QString &message) { QJsonObject json; json[QStringLiteral("rid")] = roomID; json[QStringLiteral("msg")] = message; ddp()->method(QStringLiteral("sendMessage"), QJsonDocument(json), DDPClient::Persistent); } void RocketChatAccount::updateMessage(const QString &roomID, const QString &messageId, const QString &message) { QJsonObject json; json[QStringLiteral("rid")] = roomID; json[QStringLiteral("msg")] = message; json[QStringLiteral("_id")] = messageId; ddp()->method(QStringLiteral("updateMessage"), QJsonDocument(json), DDPClient::Persistent); } QString RocketChatAccount::avatarUrl(const QString &userId) { return mCache->avatarUrl(userId); } void RocketChatAccount::insertAvatarUrl(const QString &userId, const QString &url) { mCache->insertAvatarUrl(userId, url); } RestApiRequest *RocketChatAccount::restApi() { if (!mRestApi) { mRestApi = new RestApiRequest(this); mRestApi->setServerUrl(mSettings->serverUrl()); } return mRestApi; } void RocketChatAccount::leaveRoom(const QString &roomId) { ddp()->leaveRoom(roomId); } void RocketChatAccount::hideRoom(const QString &roomId) { ddp()->hideRoom(roomId); } DDPClient *RocketChatAccount::ddp() { if (!mDdp) { mDdp = new DDPClient(this, this); connect(mDdp, &DDPClient::loginStatusChanged, this, &RocketChatAccount::loginStatusChanged); connect(mDdp, &DDPClient::changed, this, &RocketChatAccount::changed); connect(mDdp, &DDPClient::added, this, &RocketChatAccount::added); 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(); // Reset model views foreach (const QString &key, mMessageModels.keys()) { MessageModel *m = mMessageModels.take(key); delete m; } 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(); foreach (const QString &key, mMessageModels.keys()) { MessageModel *m = mMessageModels.take(key); delete m; } mRoomModel->clear(); QJsonObject user; user[QStringLiteral("username")] = mSettings->userName(); QJsonObject json; json[QStringLiteral("user")] = user; ddp()->method(QStringLiteral("logout"), QJsonDocument(json)); delete mDdp; mDdp = nullptr; Q_EMIT loginStatusChanged(); qCDebug(RUQOLA_LOG) << "Successfully logged out!"; } void RocketChatAccount::clearUnreadMessages(const QString &roomId) { ddp()->clearUnreadMessages(roomId); } void RocketChatAccount::changeFavorite(const QString &roomId, bool checked) { ddp()->toggleFavorite(roomId, checked); } void RocketChatAccount::openChannel(const QString &url) { qCDebug(RUQOLA_LOG) << " void RocketChatAccount::openChannel(const QString &url)"<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) { ddp()->eraseRoom(roomId); } void RocketChatAccount::openDirectChannel(const QString &username) { ddp()->openDirectChannel(username); } void RocketChatAccount::createNewChannel(const QString &name, bool readOnly, bool privateRoom, const QString &userNames) { const QStringList lstUsers = userNames.split(QLatin1Char(','), QString::SkipEmptyParts); if (privateRoom) { ddp()->createPrivateGroup(name, lstUsers); } else { ddp()->createChannel(name, lstUsers, readOnly); } } void RocketChatAccount::joinRoom(const QString &roomId, const QString &joinCode) { ddp()->joinRoom(roomId, joinCode); ddp()->subscribeRoomMessage(roomId); } void RocketChatAccount::listEmojiCustom() { ddp()->listEmojiCustom(); } void RocketChatAccount::setDefaultStatus(User::PresenceStatus status) { ddp()->setDefaultStatus(status); } void RocketChatAccount::changeDefaultStatus(int index) { setDefaultStatus(mStatusModel->status(index)); } void RocketChatAccount::loadEmoji() { mEmojiList.clear(); //TODO } void RocketChatAccount::deleteMessage(const QString &messageId) { ddp()->deleteMessage(messageId); } void RocketChatAccount::userAutocomplete(const QString &searchText, const QString &exception) { ddp()->userAutocomplete(searchText, exception); } void RocketChatAccount::createJitsiConfCall(const QString &roomId) { ddp()->createJitsiConfCall(roomId); joinJitsiConfCall(roomId); } void RocketChatAccount::starMessage(const QString &messageId, const QString &rid, bool starred) { ddp()->starMessage(messageId, rid, starred); } void RocketChatAccount::uploadFile(const QString &description, const QUrl &fileUrl) { qDebug() << " void RocketChatAccount::uploadFile(const QString &description, const QUrl &fileUrl)"<setRoomAnnouncement(roomId, newValue.toString()); break; case Description: ddp()->setRoomDescription(roomId, newValue.toString()); break; case Name: ddp()->setRoomName(roomId, newValue.toString()); break; case Topic: ddp()->setRoomTopic(roomId, newValue.toString()); break; case ReadOnly: ddp()->setRoomIsReadOnly(roomId, newValue.toBool()); break; case Archive: //No argument here. ddp()->archiveRoom(roomId); break; } } void RocketChatAccount::parsePublicSettings(const QJsonObject &obj) { QJsonArray configs = obj.value(QLatin1String("result")).toArray(); for (const QJsonValueRef ¤tConfig : 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 { qCDebug(RUQOLA_LOG) << "Other public settings id " << id << value; } } } QString RocketChatAccount::authToken() const { return settings()->authToken(); } QString RocketChatAccount::userName() const { return settings()->userName(); } void RocketChatAccount::setAccountName(const QString &servername) { settings()->setAccountName(servername); } 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); } 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); } QUrl RocketChatAccount::attachmentUrl(const QString &url) { return mCache->attachmentUrl(url); } void RocketChatAccount::loadHistory(const QString &roomID, bool initial) { MessageModel *roomModel = getMessageModelForRoom(roomID); if (roomModel) { QJsonArray params; params.append(QJsonValue(roomID)); // Load history const qint64 endDateTime = roomModel->lastTimestamp(); if (initial) { params.append(QJsonValue(QJsonValue::Null)); } else { const qint64 startDateTime = roomModel->generateNewStartTimeStamp(endDateTime); QJsonObject dateObject; dateObject[QStringLiteral("$date")] = QJsonValue(startDateTime); //qDebug() << " QDATE TIME END" << QDateTime::fromMSecsSinceEpoch(endDateTime) << " START " << QDateTime::fromMSecsSinceEpoch(startDateTime); params.append(dateObject); } 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); ddp()->loadHistory(params); } else { qCWarning(RUQOLA_LOG) << "Room is not found " << roomID; } } bool RocketChatAccount::allowEditingMessages() const { return mRuqolaServerConfig->allowMessageEditing(); } + +void RocketChatAccount::sendNotification(const QJsonArray &contents) +{ + qDebug() << "void RocketChatAccount::sendNotification(const QJsonArray &contents) " << contents; + const QJsonObject obj = contents.at(0).toObject(); + const QString message = obj[QStringLiteral("text")].toString(); + const QString title = obj[QStringLiteral("title")].toString(); + Q_EMIT notification(title, message); +} diff --git a/src/rocketchataccount.h b/src/rocketchataccount.h index d190b7c6..fe55aff7 100644 --- a/src/rocketchataccount.h +++ b/src/rocketchataccount.h @@ -1,199 +1,202 @@ /* 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. */ #ifndef ROCKETCHATACCOUNT_H #define ROCKETCHATACCOUNT_H #include #include #include "rocketchataccountsettings.h" #include "libruqola_private_export.h" #include "emoji.h" class TypingNotification; class UsersModel; class RoomModel; class RoomWrapper; class MessageModel; class DDPClient; class RestApiRequest; class MessageQueue; class RocketChatBackend; class UsersForRoomModel; class RoomFilterProxyModel; class RuqolaLogger; class RuqolaServerConfig; class UserCompleterModel; class StatusModel; class RocketChatCache; class LIBRUQOLACORE_TESTS_EXPORT RocketChatAccount : public QObject { Q_OBJECT Q_PROPERTY(QString userName READ userName WRITE setUserName NOTIFY userNameChanged) Q_PROPERTY(QString userID READ userID WRITE setUserID NOTIFY userIDChanged) Q_PROPERTY(QString serverUrl READ serverUrl WRITE setServerUrl NOTIFY serverUrlChanged) Q_PROPERTY(QString accountName READ accountName WRITE setAccountName NOTIFY accountNameChanged) Q_PROPERTY(QString password WRITE setPassword) Q_PROPERTY(DDPClient::LoginStatus loginStatus READ loginStatus NOTIFY loginStatusChanged) public: explicit RocketChatAccount(const QString &accountName = QString(), QObject *parent = nullptr); ~RocketChatAccount(); enum RoomInfoType { Announcement, Description, Name, Topic, ReadOnly, Archive }; Q_ENUM(RoomInfoType) RocketChatAccountSettings *settings() const; Q_INVOKABLE UsersModel *usersModel() const; Q_INVOKABLE RoomModel *roomModel() const; Q_INVOKABLE RoomFilterProxyModel *roomFilterProxyModel() const; Q_INVOKABLE RoomWrapper *getRoom(const QString &roomId); Q_INVOKABLE MessageModel *getMessageModelForRoom(const QString &roomID); Q_INVOKABLE UsersForRoomModel *getUsersForRoomModel(const QString &roomId); Q_INVOKABLE QString getUserCurrentMessage(const QString &roomId); Q_INVOKABLE void setUserCurrentMessage(const QString &message, const QString &roomId); Q_INVOKABLE void textEditing(const QString &roomId, const QString &str); Q_INVOKABLE void leaveRoom(const QString &roomId); Q_INVOKABLE void hideRoom(const QString &roomId); Q_INVOKABLE void tryLogin(); Q_INVOKABLE void logOut(); Q_INVOKABLE void clearUnreadMessages(const QString &roomId); Q_INVOKABLE void changeFavorite(const QString &roomId, bool checked); DDPClient *ddp(); DDPClient::LoginStatus loginStatus(); RestApiRequest *restApi(); //Make it private in future void slotInformTypingStatus(const QString &room, bool typing); Q_INVOKABLE void sendMessage(const QString &roomID, const QString &message); Q_INVOKABLE void updateMessage(const QString &roomID, const QString &messageId, const QString &message); MessageQueue *messageQueue() const; RocketChatBackend *rocketChatBackend() const; RuqolaLogger *ruqolaLogger() const; Q_INVOKABLE void openChannel(const QString &url); Q_INVOKABLE void joinJitsiConfCall(const QString &roomId); Q_INVOKABLE void createNewChannel(const QString &name, bool readOnly, bool privateRoom, const QString &userNames); Q_INVOKABLE void joinRoom(const QString &roomId, const QString &joinCode = QString()); Q_INVOKABLE void openDirectChannel(const QString &username); Q_INVOKABLE void listEmojiCustom(); Q_INVOKABLE void setDefaultStatus(User::PresenceStatus status); Q_INVOKABLE void changeDefaultStatus(int index); Q_INVOKABLE void createJitsiConfCall(const QString &roomId); Q_INVOKABLE void deleteMessage(const QString &messageId); Q_INVOKABLE void userAutocomplete(const QString &searchText, const QString &exception); Q_INVOKABLE void eraseRoom(const QString &roomId); Q_INVOKABLE void changeChannelSettings(const QString &roomId, RocketChatAccount::RoomInfoType infoType, const QVariant &newValue); Q_INVOKABLE QString recordingVideoPath() const; Q_INVOKABLE QString recordingImagePath() const; Q_INVOKABLE void downloadFile(const QString &downloadFileUrl, const QUrl &localFile); Q_INVOKABLE void starMessage(const QString &messageId, const QString &rid, bool starred); Q_INVOKABLE void uploadFile(const QString &description, const QUrl &fileUrl); void loadEmoji(); void parsePublicSettings(const QJsonObject &obj); RuqolaServerConfig *ruqolaServerConfig() const; void setUserName(const QString &username); QString userName() const; void setAccountName(const QString &servername); QString accountName() const; void setUserID(const QString &userID); QString userID() const; void setPassword(const QString &password); QString password() const; void setAuthToken(const QString &token); QString authToken() const; Q_INVOKABLE QString serverUrl() const; void setServerUrl(const QString &serverUrl); UserCompleterModel *userCompleterModel() const; Q_INVOKABLE QString avatarUrl(const QString &userId); Q_INVOKABLE StatusModel *statusModel() const; Q_INVOKABLE QUrl attachmentUrl(const QString &url); Q_INVOKABLE void loadHistory(const QString &roomID, bool initial = false); Q_INVOKABLE bool allowEditingMessages() const; + + void sendNotification(const QJsonArray &contents); + Q_SIGNALS: void accountNameChanged(); void userNameChanged(); void userIDChanged(); void serverUrlChanged(); void loginStatusChanged(); void added(const QJsonObject &item); void changed(const QJsonObject &item); void notification(const QString &title, const QString &message); void fileDownloaded(const QString &filePath, const QUrl &cacheImageUrl); void updateNotification(bool hasAlert, int nbUnread, const QString &accountName); private: Q_DISABLE_COPY(RocketChatAccount) void slotNeedToUpdateNotification(); void insertAvatarUrl(const QString &userId, const QString &url); void loadSettings(); void clearModels(); RocketChatAccountSettings *mSettings = nullptr; //room, messagemodel QHash mMessageModels; QHash mUsersForRoomModels; QHash mUserCurrentMessage; QVector mEmojiList; TypingNotification *mTypingNotification = nullptr; UsersModel *mUserModel = nullptr; RoomModel *mRoomModel = nullptr; RoomFilterProxyModel *mRoomFilterProxyModel = nullptr; DDPClient *mDdp = nullptr; RestApiRequest *mRestApi = nullptr; MessageQueue *mMessageQueue = nullptr; RocketChatBackend *mRocketChatBackend = nullptr; RuqolaLogger *mRuqolaLogger = nullptr; RuqolaServerConfig *mRuqolaServerConfig = nullptr; UserCompleterModel *mUserCompleterModel = nullptr; StatusModel *mStatusModel = nullptr; RocketChatCache *mCache = nullptr; }; #endif // ROCKETCHATACCOUNT_H diff --git a/src/rocketchatbackend.cpp b/src/rocketchatbackend.cpp index 5632bb13..2878dc60 100644 --- a/src/rocketchatbackend.cpp +++ b/src/rocketchatbackend.cpp @@ -1,418 +1,412 @@ /* * Copyright 2016 Riccardo Iaconelli * * 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 "ruqola_debug.h" #include "ddpapi/ddpclient.h" #include "restapi/restapirequest.h" #include "user.h" #include "usersmodel.h" #include "ruqolalogger.h" #include "messagemodel.h" #include "user.h" #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) { Room r; r.parseRoom(roomJson); qCDebug(RUQOLA_LOG) << "Adding room" << r.id() << r.topic() << r.announcement(); model->updateRoom(r.name(), r.id(), r.topic(), r.announcement(), r.readOnly()); } } } } 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) { const QString roomID = room.value(QLatin1String("rid")).toString(); // let's be extra safe around crashes if (account->loginStatus() == DDPClient::LoggedIn) { model->addRoom(room); } account->ddp()->subscribeRoomMessage(roomID); //Load history account->loadHistory(roomID, true /*initial loading*/); } 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); account->ddp()->method(QStringLiteral("public-settings/get"), QJsonDocument(), process_publicsettings); //TODO ? account->ddp()->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::onLoginStatusChanged); connect(mRocketChatAccount, &RocketChatAccount::userIDChanged, this, &RocketChatBackend::onUserIDChanged); connect(mRocketChatAccount, &RocketChatAccount::changed, this, &RocketChatBackend::onChanged); connect(mRocketChatAccount, &RocketChatAccount::added, this, &RocketChatBackend::onAdded); } RocketChatBackend::~RocketChatBackend() { } 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_LOG) <<" new message: " << o; } Message m; m.parseMessage(o); //qDebug() << " roomId"<getMessageModelForRoom(m.roomId())->addMessage(m); } } void RocketChatBackend::onLoginStatusChanged() { if (mRocketChatAccount->loginStatus() == DDPClient::LoggedIn) { // qCDebug(RUQOLA_LOG) << "GETTING LIST OF ROOMS"; 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()->channelList(); } } void RocketChatBackend::onAdded(const QJsonObject &object) { QString collection = object.value(QLatin1String("collection")).toString(); if (collection == QLatin1String("stream-room-messages")) { qCDebug(RUQOLA_LOG) << "stream-room-messages : " << object; } else if (collection == QLatin1String("users")) { const QJsonObject fields = object.value(QLatin1String("fields")).toObject(); const QString username = fields.value(QLatin1String("username")).toString(); if (username == mRocketChatAccount->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 = new User; user->parseUser(object); qCDebug(RUQOLA_LOG) << " USER ADDED VALUE " << user; 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 ! } } void RocketChatBackend::onChanged(const QJsonObject &object) { //qDebug() << " void RocketChatBackend::onChanged(const QJsonObject &object)"<usersModel(); model->updateUser(object); if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("users: User Changed:") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "USER CHANGED" << 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(); model->updateRoom(fields); 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"))) { - const QJsonObject obj = contents.at(0).toObject(); - const QString message = obj[QStringLiteral("text")].toString(); - const QString title = obj[QStringLiteral("title")].toString(); - //const QString sender = obj[QStringLiteral("sender")].toString(); - //TODO add autotest for notification too - qDebug() << " contents" << contents; - Q_EMIT notification(title, message); + mRocketChatAccount->sendNotification(contents); } else if (eventname.endsWith(QLatin1String("/webrtc"))) { qCWarning(RUQOLA_LOG) << "stream-notify-user : WEBRTC ? " << eventname << " contents " << contents; } else if (eventname.endsWith(QLatin1String("/otr"))) { qCWarning(RUQOLA_LOG) << "stream-notify-user : OTR ? " << eventname << " contents " << contents; } else { qCWarning(RUQOLA_LOG) << "stream-notify-user : Unknown 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->getMessageModelForRoom(roomId); messageModel->deleteMessage(contents.at(0).toObject()[QStringLiteral("_id")].toString()); //qDebug() << " message id " << contents.at(0).toObject()[QStringLiteral("_id")].toString(); } else { qCWarning(RUQOLA_LOG) << "stream-notify-room: Unknown event ? " << eventname; } } else { qCDebug(RUQOLA_LOG) << " Other collection type " << 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); } //stream-notify-all { const QJsonArray params{ QJsonValue(QStringLiteral("updateAvatar")), { true } }; //params.append(QJsonValue(params)); qDebug() << " updateAvatar"<ddp()->subscribe(QStringLiteral("stream-notify-all"), params); } { const QJsonArray params{ QJsonValue(QStringLiteral("roles-change")), { true } }; //params.append(QJsonValue(params)); qDebug() << " roles-change"<ddp()->subscribe(QStringLiteral("stream-notify-all"), params); } { const QJsonArray params{ QJsonValue(QStringLiteral("updateEmojiCustom")), { true } }; //params.append(QJsonValue(params)); qDebug() << " updateEmojiCustom"<ddp()->subscribe(QStringLiteral("stream-notify-all"), params); } { const QJsonArray params{ QJsonValue(QStringLiteral("deleteEmojiCustom")), { true } }; //params.append(QJsonValue(params)); qDebug() << " deleteEmojiCustom"<ddp()->subscribe(QStringLiteral("stream-notify-all"), params); } { const QJsonArray params{ QJsonValue(QStringLiteral("public-settings-changed")), { true } }; //params.append(QJsonValue(params)); qDebug() << " public-settings-changed"<ddp()->subscribe(QStringLiteral("stream-notify-all"), params); } { const QJsonArray params{ QJsonValue(QStringLiteral("permissions-changed")), { true } }; //params.append(QJsonValue(params)); qDebug() << " permissions-changed"<ddp()->subscribe(QStringLiteral("stream-notify-all"), params); } } diff --git a/src/rocketchatbackend.h b/src/rocketchatbackend.h index 7788a06d..17be8502 100644 --- a/src/rocketchatbackend.h +++ b/src/rocketchatbackend.h @@ -1,59 +1,56 @@ /* * Copyright 2016 Riccardo Iaconelli * * 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 . * */ #ifndef ROCKETCHATBACKEND_H #define ROCKETCHATBACKEND_H #include "libruqolacore_export.h" #include #include #include "roommodel.h" class RocketChatAccount; class LIBRUQOLACORE_EXPORT RocketChatBackend : public QObject { Q_OBJECT public: explicit RocketChatBackend(RocketChatAccount *account, QObject *parent = nullptr); ~RocketChatBackend(); /** * @brief Adds incoming message from server to appropriate room * * @param messages The Json containing the message */ void processIncomingMessages(const QJsonArray &messages); -Q_SIGNALS: - void notification(const QString &title, const QString &message); - private: Q_DISABLE_COPY(RocketChatBackend) void onAdded(const QJsonObject &object); void onChanged(const QJsonObject &object); void onLoginStatusChanged(); void onUserIDChanged(); RocketChatAccount *mRocketChatAccount = nullptr; }; #endif // ROCKETCHATBACKEND_H