diff --git a/src/rocketchataccount.cpp b/src/rocketchataccount.cpp index 13dee239..0669339c 100644 --- a/src/rocketchataccount.cpp +++ b/src/rocketchataccount.cpp @@ -1,261 +1,256 @@ /* Copyright (c) 2017 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 "usermodel.h" #include "ruqola_debug.h" #include "ruqola.h" #include "messagequeue.h" #include "rocketchatbackend.h" +#include #include #include #include #include RocketChatAccount::RocketChatAccount(QObject *parent) : QObject(parent) { mSettings = new RocketChatAccountSettings(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); mRoomModel = new RoomModel(this); mUserModel = new UsersModel(this); mMessageQueue = new MessageQueue(this); mTypingNotification = new TypingNotification(this); connect(mTypingNotification, &TypingNotification::informTypingStatus, this, &RocketChatAccount::slotInformTypingStatus); loadSettings(); QTimer::singleShot(0, this, &RocketChatAccount::initialize); } RocketChatAccount::~RocketChatAccount() { } void RocketChatAccount::initialize() { // 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(); } 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::userModel() 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); return mMessageModels[roomID]; } } void RocketChatAccount::textEditing(const QString &roomId, const QString &str) { mTypingNotification->setText(roomId, str); } void RocketChatAccount::attachmentButtonClicked(const QString &roomId) { const QString fileName = QFileDialog::getOpenFileName(nullptr, - tr("Select one or more files to open"), + i18n("Select one or more files to open"), QDir::homePath(), - tr("Images (*.png *.jpeg *.jpg)")); + i18n("Images (*.png *.jpeg *.jpg)")); if (fileName.isEmpty()) { return; } qCDebug(RUQOLA_LOG) << "Selected Image " << fileName; QFile file(fileName); if (!file.open(QFile::ReadOnly)) { qCDebug(RUQOLA_LOG) << "Cannot open the selected file" << fileName; return; } const QString message = QString::fromLatin1(file.readAll().toBase64()); const QString roomID(roomId); const QString type(QStringLiteral("image")); sendMessage(roomID, message, type); } void RocketChatAccount::sendMessage(const QString &roomID, const QString &message, const QString &type) { QJsonObject json; json[QStringLiteral("rid")] = roomID; json[QStringLiteral("msg")] = message; json[QStringLiteral("type")] = type; ddp()->method(QStringLiteral("sendMessage"), QJsonDocument(json), DDPClient::Persistent); } RestApiRequest *RocketChatAccount::restApi() const { return mRestApi; } 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(); - //FIXME - //TODO we need to load it after ddp login done - restapi(); - restapi()->setPassword(mSettings->password()); - restapi()->login(); - // In the meantime, load cache... //if(Ruqola::self()->ddp()->isConnected() && Ruqola::self()->loginStatus() == DDPClient::LoggedIn) { 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!"; } diff --git a/src/rocketchatbackend.cpp b/src/rocketchatbackend.cpp index 948fb87c..42f8cdeb 100644 --- a/src/rocketchatbackend.cpp +++ b/src/rocketchatbackend.cpp @@ -1,265 +1,262 @@ /* * 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 #include "ruqola_debug.h" #include "ddpapi/ddpclient.h" #include "restapi/restapirequest.h" #include "ruqola.h" void process_backlog(const QJsonDocument &messages, RocketChatAccount *account) { qCDebug(RUQOLA_LOG) << messages.object().value(QStringLiteral("messages")).toArray().size(); account->rocketChatBackend()->processIncomingMessages(messages.object().value(QStringLiteral("messages")).toArray()); } void rooms_parsing(const QJsonDocument &doc, RocketChatAccount *account) { RoomModel *model = account->roomModel(); //qDebug() << " doc " << doc; QJsonArray removed = doc.object().value(QStringLiteral("remove")).toArray(); //qDebug() << " rooms_parsing: room removed *************************************************" << removed; const QJsonArray updated = doc.object().value(QStringLiteral("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(QStringLiteral("t")).toString(); 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.mAnnouncement; model->updateRoom(r.name, r.id, r.topic, r.mAnnouncement); } } } } void getsubscription_parsing(const QJsonDocument &doc, RocketChatAccount *account) { RoomModel *model = account->roomModel(); //qDebug() << " doc " << doc; QJsonArray removed = doc.object().value(QStringLiteral("remove")).toArray(); //qDebug() << " room removed " << removed; const QJsonArray updated = doc.object().value(QStringLiteral("update")).toArray(); //qDebug() << " updated : "<< updated; for (int i = 0; i < updated.size(); i++) { QJsonObject room = updated.at(i).toObject(); const QString roomType = room.value(QStringLiteral("t")).toString(); if (roomType == QLatin1String("c") //Chat || roomType == QLatin1String("p") /*Private chat*/ || roomType == QLatin1String("d")) { //Direct chat) { - QString roomID = room.value(QStringLiteral("rid")).toString(); + const QString roomID = room.value(QStringLiteral("rid")).toString(); MessageModel *roomModel = account->getMessageModelForRoom(roomID); // let's be extra safe around crashes if (account->loginStatus() == DDPClient::LoggedIn) { Room r; r.parseSubscriptionRoom(room); qCDebug(RUQOLA_LOG) << "Adding room subscription" << r.name << r.id << r.topic; model->addRoom(r); } QJsonArray params; params.append(QJsonValue(roomID)); account->ddp()->subscribe(QStringLiteral("stream-room-messages"), params); // Load history params.append(QJsonValue(QJsonValue::Null)); params.append(QJsonValue(50)); // Max number of messages to load; QJsonObject dateObject; dateObject[QStringLiteral("$date")] = QJsonValue(roomModel->lastTimestamp()); params.append(dateObject); account->ddp()->method(QStringLiteral("loadHistory"), QJsonDocument(params), process_backlog); } else if (roomType == QLatin1String("l")) { //Live chat qDebug() << "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); } -/* -void rooms_callback(const QJsonDocument &doc) -{ - rooms_parsing(doc); -} -*/ 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(); //qDebug() <<" o" << o; Message m; m.parseMessage(o); //qDebug() << " roomId"<getMessageModelForRoom(m.mRoomId)->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 QJsonDocument &doc, RocketChatAccount *account) { getsubscription_parsing(doc, 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(QStringLiteral("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(QStringLiteral("fields")).toObject(); const QString username = fields.value(QStringLiteral("username")).toString(); if (username == mRocketChatAccount->settings()->userName()) { mRocketChatAccount->settings()->setUserId(object[QStringLiteral("id")].toString()); qCDebug(RUQOLA_LOG) << "User id set to " << mRocketChatAccount->settings()->userId(); mRocketChatAccount->restapi()->setUserName(mRocketChatAccount->settings()->userName()); mRocketChatAccount->restapi()->setPassword(mRocketChatAccount->settings()->password()); mRocketChatAccount->restapi()->login(); } 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; } } void RocketChatBackend::onChanged(const QJsonObject &object) { qDebug() << " void RocketChatBackend::onChanged(const QJsonObject &object)"<roomModel(); model->updateSubscription(contents); } else if (eventname.endsWith(QStringLiteral("/rooms-changed"))) { qDebug() << "rooms-changed " << eventname; RoomModel *model = mRocketChatAccount->roomModel(); model->updateRoom(contents); } else if (eventname.endsWith(QStringLiteral("/notification"))) { const QString message = contents.at(0).toObject()[QStringLiteral("text")].toString(); const QString title = contents.at(0).toObject()[QStringLiteral("title")].toString(); Ruqola::self()->notification()->showMessage(title, message, QSystemTrayIcon::Information, 5000); } else { qCWarning(RUQOLA_LOG) << " Unknown event ? " << eventname; } qCDebug(RUQOLA_LOG) << "New notification" << fields; } else { qCDebug(RUQOLA_LOG) << " Other collection type " << collection; } } void RocketChatBackend::onUserIDChanged() { const QString userId{mRocketChatAccount->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 activeUsers QJsonArray params; params.append(QJsonValue(params)); mRocketChatAccount->ddp()->subscribe(QStringLiteral("activeUsers"), params); } //TODO stream-notify-all ? }