diff --git a/autotests/roomtest.cpp b/autotests/roomtest.cpp index add849fb..4d11737b 100644 --- a/autotests/roomtest.cpp +++ b/autotests/roomtest.cpp @@ -1,384 +1,381 @@ /* Copyright (c) 2017-2019 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 "roomtest.h" #include "room.h" #include "ruqola_autotest_helper.h" #include "model/usersforroommodel.h" #include "model/usersforroomfilterproxymodel.h" #include "model/filesforroomfilterproxymodel.h" #include "model/filesforroommodel.h" #include "model/discussionsfilterproxymodel.h" #include "model/discussionsmodel.h" #include "model/threadsfilterproxymodel.h" #include "model/threadsmodel.h" #include #include #include QTEST_GUILESS_MAIN(RoomTest) RoomTest::RoomTest(QObject *parent) : QObject(parent) { } void RoomTest::shouldHaveDefaultValue() { Room input(nullptr); QVERIFY(input.usersModelForRoom()); QVERIFY(input.usersModelForRoomProxyModel()); - QVERIFY(input.filesModelForRoom()); - QVERIFY(input.filesForRoomFilterProxyModel()); QVERIFY(input.threadsModelForRoom()); QVERIFY(input.threadsModelForRoomFilterProxyModel()); QCOMPARE(input.threadsModelForRoomFilterProxyModel()->sourceModel(), input.threadsModelForRoom()); QVERIFY(input.discussionsModelForRoom()); QVERIFY(input.discussionsModelForRoomFilterProxyModel()); QCOMPARE(input.discussionsModelForRoomFilterProxyModel()->sourceModel(), input.discussionsModelForRoom()); - QCOMPARE(input.filesForRoomFilterProxyModel()->sourceModel(), input.filesModelForRoom()); QCOMPARE(input.usersModelForRoomProxyModel()->sourceModel(), input.usersModelForRoom()); QVERIFY(input.messageModel()); QVERIFY(input.inputMessage().isEmpty()); QVERIFY(input.description().isEmpty()); QVERIFY(input.announcement().isEmpty()); QVERIFY(!input.readOnly()); //Add more QCOMPARE(input.userMentions(), 0); QCOMPARE(input.unread(), 0); QCOMPARE(input.blocked(), false); QCOMPARE(input.blocker(), false); QVERIFY(input.roles().isEmpty()); QVERIFY(!input.archived()); QVERIFY(input.name().isEmpty()); QVERIFY(input.ignoredUsers().isEmpty()); QVERIFY(input.e2EKey().isEmpty()); QVERIFY(input.e2eKeyId().isEmpty()); QVERIFY(!input.encrypted()); QVERIFY(!input.alert()); QVERIFY(!input.readOnly()); QVERIFY(!input.joinCodeRequired()); QVERIFY(!input.wasInitialized()); QVERIFY(input.rolesForRooms().isEmpty()); QVERIFY(input.parentRid().isEmpty()); QVERIFY(!input.broadcast()); QVERIFY(input.fName().isEmpty()); } //TODO add notification, userMentions too void RoomTest::shouldSerialized() { Room input(nullptr); input.setRoomId(QStringLiteral("foo")); input.setChannelType(QStringLiteral("p")); input.setName(QStringLiteral("d")); input.setAnnouncement(QStringLiteral("AA")); input.setRoomCreatorUserName(QStringLiteral("pp")); input.setRoomCreatorUserId(QStringLiteral("sdfsdfs")); input.setTopic(QStringLiteral("topic")); input.setMutedUsers(QStringList{QStringLiteral("mutedUsers"), QStringLiteral("muted2")}); input.setJitsiTimeout(55); input.setReadOnly(true); input.setUnread(66); input.setSelected(true); input.setFavorite(true); input.setAlert(true); input.setOpen(true); input.setBlocker(true); input.setBlocked(true); input.setArchived(true); input.setDescription(QStringLiteral("dd")); input.setUserMentions(3); input.setRoles({QStringLiteral("foo"), QStringLiteral("bla")}); input.setIgnoredUsers({QStringLiteral("gg"), QStringLiteral("gg2")}); input.setJoinCodeRequired(true); const QByteArray ba = Room::serialize(&input); //qDebug() << QJsonObject(QJsonDocument::fromBinaryData(ba).object()); Room *output = Room::fromJSon(QJsonObject(QJsonDocument::fromBinaryData(ba).object())); //qDebug() << "after" << QJsonObject(QJsonDocument::fromBinaryData(Room::serialize(output)).object()); QVERIFY(input.isEqual(*output)); delete output; } void RoomTest::shouldEmitSignals() { Room input(nullptr); QSignalSpy spyNameChanged(&input, &Room::nameChanged); QSignalSpy spyannouncementChanged(&input, &Room::announcementChanged); QSignalSpy spytopicChanged(&input, &Room::topicChanged); QSignalSpy spyfavoriteChanged(&input, &Room::favoriteChanged); QSignalSpy spyalertChanged(&input, &Room::alertChanged); QSignalSpy spyreadOnlyChanged(&input, &Room::readOnlyChanged); QSignalSpy spyunreadChanged(&input, &Room::unreadChanged); QSignalSpy spyblockerChanged(&input, &Room::blockerChanged); QSignalSpy spyarchivedChanged(&input, &Room::archivedChanged); QSignalSpy spydescriptionChanged(&input, &Room::descriptionChanged); QSignalSpy spyblockedChanged(&input, &Room::blockedChanged); QSignalSpy spyrolesChanged(&input, &Room::rolesChanged); QSignalSpy spyignoredUsersChanged(&input, &Room::ignoredUsersChanged); QSignalSpy spymutedUsersChanged(&input, &Room::mutedUsersChanged); QSignalSpy spyencryptedChanged(&input, &Room::encryptedChanged); QSignalSpy spyjoinCodeRequiredChanged(&input, &Room::joinCodeRequiredChanged); QSignalSpy spychannelTypeChanged(&input, &Room::channelTypeChanged); QSignalSpy spyparentRidChanged(&input, &Room::parentRidChanged); input.setRoomId(QStringLiteral("foo")); input.setChannelType(QStringLiteral("p")); input.setName(QStringLiteral("d")); input.setAnnouncement(QStringLiteral("AA")); input.setRoomCreatorUserName(QStringLiteral("pp")); input.setRoomCreatorUserId(QStringLiteral("sdfsdfs")); input.setTopic(QStringLiteral("topic")); input.setMutedUsers(QStringList{QStringLiteral("mutedUsers"), QStringLiteral("muted2")}); input.setJitsiTimeout(55); input.setReadOnly(true); input.setUnread(66); input.setSelected(true); input.setFavorite(true); input.setAlert(true); input.setOpen(true); input.setBlocker(true); input.setBlocked(true); input.setArchived(true); input.setEncrypted(true); input.setJoinCodeRequired(true); input.setDescription(QStringLiteral("ddd")); input.setRoles({QStringLiteral("bla"), QStringLiteral("blu")}); input.setIgnoredUsers({QStringLiteral("bla"), QStringLiteral("blu3")}); input.setParentRid(QStringLiteral("bla")); QCOMPARE(spyNameChanged.count(), 1); QCOMPARE(spyannouncementChanged.count(), 1); QCOMPARE(spytopicChanged.count(), 1); QCOMPARE(spyfavoriteChanged.count(), 1); QCOMPARE(spyalertChanged.count(), 1); QCOMPARE(spyreadOnlyChanged.count(), 1); QCOMPARE(spyunreadChanged.count(), 1); QCOMPARE(spyblockerChanged.count(), 1); QCOMPARE(spyarchivedChanged.count(), 1); QCOMPARE(spyblockedChanged.count(), 1); QCOMPARE(spydescriptionChanged.count(), 1); QCOMPARE(spyrolesChanged.count(), 1); QCOMPARE(spyignoredUsersChanged.count(), 1); QCOMPARE(spymutedUsersChanged.count(), 1); QCOMPARE(spyencryptedChanged.count(), 1); QCOMPARE(spyjoinCodeRequiredChanged.count(), 1); QCOMPARE(spychannelTypeChanged.count(), 1); QCOMPARE(spyparentRidChanged.count(), 1); } void RoomTest::shouldChangeInputMessage() { Room input(nullptr); QString inputMsg = QStringLiteral("Foo"); input.setInputMessage(inputMsg); QCOMPARE(input.inputMessage(), inputMsg); inputMsg = QString(); input.setInputMessage(inputMsg); QCOMPARE(input.inputMessage(), inputMsg); inputMsg = QStringLiteral("foo"); input.setInputMessage(inputMsg); QCOMPARE(input.inputMessage(), inputMsg); } void RoomTest::shouldParseRoom_data() { QTest::addColumn("fileName"); //Missing _updatedAt/ts/_id/groupMentions/ls/roles (implement roles ! ) QTest::newRow("notification-room") << QStringLiteral("notification-room"); QTest::newRow("unread-usermentions-room") << QStringLiteral("unread-usermentions-room"); QTest::newRow("muted-users") << QStringLiteral("muted-users"); QTest::newRow("userignored-room") << QStringLiteral("userignored-room"); } void RoomTest::shouldParseRoom() { QFETCH(QString, fileName); const QString originalJsonFile = QLatin1String(RUQOLA_DATA_DIR) + QStringLiteral("/room/") + fileName + QStringLiteral(".json"); QFile f(originalJsonFile); QVERIFY(f.open(QIODevice::ReadOnly)); const QByteArray content = f.readAll(); f.close(); const QJsonDocument doc = QJsonDocument::fromJson(content); const QJsonObject fields = doc.object(); Room r; r.parseSubscriptionRoom(fields); //qDebug() << " fields"<("fileNameinit"); QTest::addColumn("fileNameupdate"); //Missing _updatedAt/ts/_id/groupMentions/ls/roles (implement roles ! ) QTest::newRow("notification-roomupdate") << QStringLiteral("notification-room") << (QStringList() <("fileNameinit"); QTest::addColumn("UpdateRoomfileNames"); QTest::addColumn("UpdateSubscriptionFileNames"); //Missing _updatedAt/ts/_id/groupMentions/ls/roles (implement roles ! ) QTest::newRow("notification-roomupdate") << QStringLiteral("notification-room") << (QStringList() << QStringLiteral("notification-roomupdate1")) << (QStringList() << QStringLiteral("notification-roomsubscription1")); QTest::newRow("room-blocked") << QStringLiteral("room-blocked") << (QStringList() << QStringLiteral("room-blockedupdate1")) << QStringList(); QTest::newRow("room-encryption") << QStringLiteral("room-encryption") << (QStringList() << QStringLiteral("room-encryptionupdate1")) << QStringList(); QTest::newRow("room-broadcasted") << QStringLiteral("room-broadcasted") << (QStringList() << QStringLiteral("room-broadcastedupdate1")) << QStringList(); } void RoomTest::shouldParseRoomAndUpdateSubscription() { QFETCH(QString, fileNameinit); QFETCH(QStringList, UpdateRoomfileNames); QFETCH(QStringList, UpdateSubscriptionFileNames); const QString originalJsonFile = QLatin1String(RUQOLA_DATA_DIR) + QStringLiteral("/room-updated/") + fileNameinit + QStringLiteral(".json"); QFile f(originalJsonFile); QVERIFY(f.open(QIODevice::ReadOnly)); const QByteArray content = f.readAll(); f.close(); const QJsonDocument doc = QJsonDocument::fromJson(content); const QJsonObject fields = doc.object(); Room r; r.parseSubscriptionRoom(fields); for (const QString &updateFile : UpdateRoomfileNames) { const QString originalUpdateJsonFile = QLatin1String(RUQOLA_DATA_DIR) + QStringLiteral("/room-update-subscription/") + updateFile + QStringLiteral(".json"); QFile f(originalUpdateJsonFile); QVERIFY(f.open(QIODevice::ReadOnly)); const QByteArray content = f.readAll(); f.close(); const QJsonDocument doc = QJsonDocument::fromJson(content); const QJsonObject fields = doc.object(); r.parseUpdateRoom(fields); } for (const QString &updateFile : UpdateSubscriptionFileNames) { const QString originalUpdateJsonFile = QLatin1String(RUQOLA_DATA_DIR) + QStringLiteral("/room-update-subscription/") + updateFile + QStringLiteral(".json"); QFile f(originalUpdateJsonFile); QVERIFY(f.open(QIODevice::ReadOnly)); const QByteArray content = f.readAll(); f.close(); const QJsonDocument doc = QJsonDocument::fromJson(content); const QJsonObject fields = doc.object(); r.updateSubscriptionRoom(fields); } //qDebug() << " fields"< * Copyright (c) 2017-2019 Montel Laurent * * 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 . * */ import QtQuick 2.9 import QtQuick.Window 2.2 import QtQuick.Dialogs 1.2 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.5 as QQC2 import KDE.Ruqola.RuqolaUtils 1.0 import KDE.Ruqola.Ruqola 1.0 import KDE.Ruqola.DDPClient 1.0 import KDE.Ruqola.RoomFilterProxyModel 1.0 import org.kde.kirigami 2.7 as Kirigami import KDE.Ruqola.DebugCategory 1.0 import KDE.Ruqola.Channel 1.0 import KDE.Ruqola.AccountManager 1.0 Kirigami.ApplicationWindow { id: appid readonly property int margin: 11 property string selectedRoomID: ""; property QtObject selectedRoom property QtObject messageModel property QtObject userModel property QtObject filesModel property QtObject threadsModel property QtObject discussionsModel property QtObject accountManager: Ruqola.accountManager() property QtObject accountManagerModel: accountManager.rocketChatAccountModel() property QtObject rocketChatAccount: accountManager.firstAccount() property QtObject inputCompleterModel: rocketChatAccount.inputCompleterModel() property QtObject searchMessageModel: rocketChatAccount.searchMessageFilterProxyModel() property QtObject emojiModel: rocketChatAccount.emoticonModel() property string userInputMessageText: ""; width: Kirigami.Units.gridUnit * 55 height: Kirigami.Units.gridUnit * 40 title: i18n("Ruqola") function switchToRoom(roomID) { if (roomID === selectedRoomID) { return; } //TODO remove duplicate code !!!! appid.rocketChatAccount.switchingToRoom(roomID) appid.rocketChatAccount.setUserCurrentMessage(appid.userInputMessageText, selectedRoomID) appid.selectedRoomID = roomID; appid.messageModel = appid.rocketChatAccount.messageModelForRoom(roomID) appid.selectedRoom = appid.rocketChatAccount.getRoomWrapper(roomID) appid.userModel = appid.rocketChatAccount.usersForRoomFilterProxyModel(roomID) - appid.filesModel = appid.rocketChatAccount.filesForRoomFilterProxyModel(roomID) + appid.filesModel = appid.rocketChatAccount.filesForRoomFilterProxyModel() appid.threadsModel = appid.rocketChatAccount.threadsFilterProxyModel(roomID) appid.discussionsModel = appid.rocketChatAccount.discussionsFilterProxyModel(roomID) } pageStack.globalToolBar.style: Kirigami.ApplicationHeaderStyle.None pageStack.initialPage: [roomsComponent, mainComponent] pageStack.visible: rocketChatAccount.loginStatus === DDPClient.LoggedIn globalDrawer: Kirigami.GlobalDrawer { drawerOpen: false handleVisible: true resetMenuOnTriggered: true topContent: [ QQC2.Label { text: rocketChatAccount.userName === "" ? "" : i18n("Hello, %1", rocketChatAccount.userName) } ] actions: [ Kirigami.Action { text: i18n("About") iconName: ":/icons/systray.png" onTriggered: { aboutDataDialog.open() } }, Kirigami.Action { text: i18n("Report a Bug") iconName: "tools-report-bug" onTriggered: { Qt.openUrlExternally("https://bugs.kde.org/report.cgi"); } }, Kirigami.Action { text: i18n("Configure Account") iconName: "settings-configure" onTriggered: { configureServerList.visible = true pageStack.visible = false } }, Kirigami.Action { text: i18n("Handbook") iconName: "system-help" onTriggered: { rocketChatAccount.openDocumentation(); } }, Kirigami.Action { separator: true }, Kirigami.Action { text: i18n("Log out") iconName: "system-log-out" onTriggered: { rocketChatAccount.logOut(); appid.globalDrawer.drawerOpen = false; } }, Kirigami.Action { separator: true }, Kirigami.Action { shortcut: StandardKey.Quit text: i18n("Quit") iconName: "application-exit" onTriggered: { Qt.quit(); } } ] } ConfigureServerList { id: configureServerList accountModel: accountManagerModel visible: false onCloseConfigureServer: { configureServerList.visible = false pageStack.visible = true } } LoginPage { id: loginTab rcAccount: rocketChatAccount } AboutDialog { id: aboutDataDialog applicationData: Ruqola.applicationData() onOpenurl: { RuqolaUtils.openUrl(link); } } PrivateChannelInfoDialog { id: privateChannelInfoDialog onBlockUser: { rocketChatAccount.blockUser(rid, block) } } NotificationOptionsDialog { id: notificationsDialog rid: (appid && appid.selectedRoomID) ? appid.selectedRoomID : "" onModifyNotificationsSetting: { rocketChatAccount.changeNotificationsSettings(roomId, type, newVal) } } ChannelInfoDialog { id: channelInfoDialog channelName: (appid && appid.selectedRoomID) ? appid.selectedRoomID : "" onDeleteRoom: { rocketChatAccount.eraseRoom(roomId, appid.selectedRoom.channelType) } onModifyChannelSetting: { rocketChatAccount.changeChannelSettings(roomId, type, newVal, channelType) } } LeaveChannelDialog { id: leaveChannelDialog onLeaveChannel: { rocketChatAccount.leaveRoom(roomId, channelType) } } AddUserDialog { id: addUserDialog completerModel: rocketChatAccount.userCompleterFilterModelProxy() onSearchUserName: { rocketChatAccount.userAutocomplete(pattern, ""); } onAddUser: { rocketChatAccount.addUserToRoom(userId, rid, channelType) } } ShowSearchMessageDialog { id: searchMessageDialog searchMessageModel: appid.searchMessageModel onSearchMessage: { rocketChatAccount.messageSearch(pattern, rid) } onClosed: { rocketChatAccount.clearSearchModel() } onGoToMessage: { console.log("Show history to message: " + messageId) } } JobErrorMessageDialog { id: jobErrorMessageDialog } CreateNewChannelDialog { id: createNewChannelDialog onCreateNewChannel: { rocketChatAccount.createNewChannel(name, readOnly, privateRoom, usernames, encryptedRoom, password, broadcast); } } ServerInfoDialog { id: serverinfodialog } SearchChannelDialog { id: searchChannelDialog searchChannelModel: rocketChatAccount.searchChannelFilterProxyModel() onSearchChannel: { rocketChatAccount.channelAndPrivateAutocomplete(pattern); } onOpenChannel: { if (channeltype === Channel.Room) { rocketChatAccount.openChannel(channelid) } else if (channeltype === Channel.PrivateChannel) { if (rocketChatAccount.userName !== channelid) { rocketChatAccount.openDirectChannel(channelid) } } else { console.log(RuqolaDebugCategorySingleton.category, "Unknown open channel type : " + channeltype + " channelid : " + channelid + " channelname : " + channelname) } } } TakeVideoMessageDialog { id: takeVideoMessage rcAccount: rocketChatAccount } QQC2.BusyIndicator { id: busy anchors.centerIn: parent visible: rocketChatAccount.loginStatus === DDPClient.LoggingIn } RoomsComponent { id: roomsComponent } MainComponent { id: mainComponent } ChannelPasswordDialog { id: channelPasswordDialog onJoinRoom: { rocketChatAccount.joinRoom(roomId, password) } } Connections { target: rocketChatAccount onMissingChannelPassword: { channelPasswordDialog.roomId = roomId channelPasswordDialog.visible = true } onJobFailed: { jobErrorMessageDialog.jobMessageError = message jobErrorMessageDialog.open() } } onClosing: { Qt.quit(); } function toggleShow() { if (visible) { hide(); } else { show(); raise(); requestActivate(); } } Component.onCompleted: { systrayIcon.activateRequested.connect(toggleShow); } } diff --git a/src/ruqolacore/ddpapi/ddpclient.cpp b/src/ruqolacore/ddpapi/ddpclient.cpp index 1d4c49c6..6f218536 100644 --- a/src/ruqolacore/ddpapi/ddpclient.cpp +++ b/src/ruqolacore/ddpapi/ddpclient.cpp @@ -1,946 +1,947 @@ /* * Copyright 2016 Riccardo Iaconelli * Copyright (C) 2017-2019 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 "ddpclient.h" #include "restapirequest.h" #include "utils.h" #include "ruqola_ddpapi_debug.h" #include "ruqola_ddpapi_command_debug.h" #include "rocketchatmessage.h" #include "ruqolawebsocket.h" #include "rocketchataccount.h" #include "messagequeue.h" #include "ruqolalogger.h" #include "rocketchatbackend.h" #include "plugins/pluginauthenticationinterface.h" #include #include #include #include namespace RuqolaTestWebSocket { LIBRUQOLACORE_EXPORT AbstractWebSocket *_k_ruqola_webSocket = nullptr; } void user_ignore(const QJsonObject &root, RocketChatAccount *account) { if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("User Ignore:") + QJsonDocument(root).toJson()); } } void block_user(const QJsonObject &root, RocketChatAccount *account) { if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Block User:") + QJsonDocument(root).toJson()); } } void unblock_user(const QJsonObject &root, RocketChatAccount *account) { if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("UnBlock User:") + QJsonDocument(root).toJson()); } } void message_search(const QJsonObject &root, RocketChatAccount *account) { if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Search Message:") + QJsonDocument(root).toJson()); } const QJsonObject obj = root.value(QLatin1String("result")).toObject(); account->displaySearchedMessage(obj); } void input_user_channel_autocomplete(const QJsonObject &root, RocketChatAccount *account) { if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Input channel/User autocomplete:") + QJsonDocument(root).toJson()); } const QJsonObject obj = root.value(QLatin1String("result")).toObject(); account->inputTextCompleter(obj); } void process_backlog(const QJsonObject &root, RocketChatAccount *account) { const QJsonObject obj = root.value(QLatin1String("result")).toObject(); //qCDebug(RUQOLA_DDPAPI_LOG) << obj.value(QLatin1String("messages")).toArray().size(); account->rocketChatBackend()->processIncomingMessages(obj.value(QLatin1String("messages")).toArray()); } void add_user_to_room(const QJsonObject &root, RocketChatAccount *account) { if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Add User To Room:") + QJsonDocument(root).toJson()); } } void star_message(const QJsonObject &root, RocketChatAccount *account) { if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Star message:") + QJsonDocument(root).toJson()); } } void change_notifications_settings(const QJsonObject &root, RocketChatAccount *account) { if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Change Notifications Settings:") + QJsonDocument(root).toJson()); } } void change_room_settings(const QJsonObject &root, RocketChatAccount *account) { if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Change Room Settings:") + QJsonDocument(root).toJson()); } } void erase_room(const QJsonObject &root, RocketChatAccount *account) { if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Delete Room:") + QJsonDocument(root).toJson()); } qDebug()<< "void erase_room(const QJsonObject &root, RocketChatAccount *account)"<ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Delete Message:") + QJsonDocument(root).toJson()); } } void channel_and_private_autocomplete(const QJsonObject &root, RocketChatAccount *account) { const QJsonObject obj = root.value(QLatin1String("result")).toObject(); account->loadAutoCompleteChannel(obj); if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Channel And Private AutoComplete:") + QJsonDocument(root).toJson()); } } void create_jitsi_conf_call(const QJsonObject &root, RocketChatAccount *account) { if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Create Jitsi Conf Call:") + QJsonDocument(root).toJson()); } } void open_direct_channel(const QJsonObject &root, RocketChatAccount *account) { const QJsonObject obj = root.value(QLatin1String("result")).toObject(); if (!obj.isEmpty()) { const QString rid = obj.value(QLatin1String("rid")).toString(); if (!rid.isEmpty()) { account->ddp()->subscribeRoomMessage(rid); } } if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Open Direct channel:") + QJsonDocument(root).toJson()); } } void join_room(const QJsonObject &obj, RocketChatAccount *account) { if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Join Room :") + QJsonDocument(obj).toJson()); } } void change_default_status(const QJsonObject &obj, RocketChatAccount *account) { if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Change Default Status :") + QJsonDocument(obj).toJson()); } } void list_emoji_custom(const QJsonObject &obj, RocketChatAccount *account) { account->loadEmoji(obj); //qDebug() << " list emoji custom " << obj[QLatin1String("result")].toArray(); if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Load Emoji Custom :") + QJsonDocument(obj).toJson()); } } void empty_callback(const QJsonObject &obj, RocketChatAccount *account) { if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Empty call back :") + QJsonDocument(obj).toJson()); } else { qCWarning(RUQOLA_DDPAPI_LOG) << "empty_callback "<< obj; } } void create_channel(const QJsonObject &root, RocketChatAccount *account) { const QJsonObject obj = root.value(QLatin1String("result")).toObject(); if (!obj.isEmpty()) { const QString rid = obj.value(QLatin1String("rid")).toString(); if (!rid.isEmpty()) { account->joinRoom(rid); } if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("create Channel :") + QJsonDocument(root).toJson()); } } } DDPClient::DDPClient(RocketChatAccount *account, QObject *parent) : QObject(parent) , m_uid(1) , m_loginJob(0) , m_loginStatus(NotConnected) , m_connected(false) , m_attemptedPasswordLogin(false) , m_attemptedTokenLogin(false) , mRocketChatMessage(new RocketChatMessage) , mRocketChatAccount(account) { } DDPClient::~DDPClient() { mWebSocket->close(); //Don't delete socket when we use specific socket. if (!RuqolaTestWebSocket::_k_ruqola_webSocket) { delete mWebSocket; mWebSocket = nullptr; } delete mRocketChatMessage; mRocketChatMessage = nullptr; } void DDPClient::setServerUrl(const QString &url) { mUrl = url; } void DDPClient::initializeWebSocket() { mWebSocket->ignoreSslErrors(); connect(mWebSocket, &AbstractWebSocket::connected, this, &DDPClient::onWSConnected); connect(mWebSocket, &AbstractWebSocket::textMessageReceived, this, &DDPClient::onTextMessageReceived); connect(mWebSocket, &AbstractWebSocket::disconnected, this, &DDPClient::onWSclosed); connect(mWebSocket, &AbstractWebSocket::sslErrors, this, &DDPClient::onSslErrors); } void DDPClient::start() { if (!mWebSocket) { if (!RuqolaTestWebSocket::_k_ruqola_webSocket) { mWebSocket = new RuqolaWebSocket(this); } else { mWebSocket = RuqolaTestWebSocket::_k_ruqola_webSocket; } initializeWebSocket(); } connect(mRocketChatAccount, &RocketChatAccount::serverUrlChanged, this, &DDPClient::onServerURLChange); if (!mUrl.isEmpty()) { const QUrl serverUrl = adaptUrl(mUrl); if (!serverUrl.isValid()) { setLoginStatus(LoginFailed); } else { mWebSocket->openUrl(serverUrl); qCDebug(RUQOLA_DDPAPI_LOG) << "Trying to connect to URL" << serverUrl; } } else { qCDebug(RUQOLA_DDPAPI_LOG) << "url is empty"; } } void DDPClient::setLoginJobId(quint64 jobid) { m_loginJob = jobid; } QUrl DDPClient::adaptUrl(const QString &url) { return Utils::generateServerUrl(url); } void DDPClient::onServerURLChange() { if (mRocketChatAccount->settings()->serverUrl() != mUrl || !mWebSocket->isValid()) { if (mWebSocket->isValid()) { mWebSocket->flush(); mWebSocket->close(); } mUrl = mRocketChatAccount->settings()->serverUrl(); mWebSocket->openUrl(adaptUrl(mUrl)); connect(mWebSocket, &AbstractWebSocket::connected, this, &DDPClient::onWSConnected); qCDebug(RUQOLA_DDPAPI_LOG) << "Reconnecting" << mUrl; } } DDPClient::LoginStatus DDPClient::loginStatus() const { return m_loginStatus; } void DDPClient::setLoginStatus(DDPClient::LoginStatus l) { qCDebug(RUQOLA_DDPAPI_LOG) << "Setting login status to" << l; m_loginStatus = l; Q_EMIT loginStatusChanged(); // reset flags if (l == LoginFailed) { m_attemptedPasswordLogin = false; m_attemptedTokenLogin = false; } } bool DDPClient::isConnected() const { return m_connected; } bool DDPClient::isLoggedIn() const { return m_loginStatus == LoggedIn; } QString DDPClient::cachePath() const { return QStandardPaths::writableLocation(QStandardPaths::CacheLocation); } QQueue > DDPClient::messageQueue() const { return m_messageQueue; } quint64 DDPClient::leaveRoom(const QString &roomID) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->leaveRoom(roomID, m_uid); return method(result, empty_callback, DDPClient::Persistent); } quint64 DDPClient::hideRoom(const QString &roomID) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->hideRoom(roomID, m_uid); return method(result, empty_callback, DDPClient::Persistent); } quint64 DDPClient::toggleFavorite(const QString &roomID, bool favorite) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->toggleFavorite(roomID, favorite, m_uid); return method(result, empty_callback, DDPClient::Persistent); } quint64 DDPClient::createChannel(const QString &name, const QStringList &userList, bool readOnly) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->createChannel(name, userList, readOnly, m_uid); return method(result, create_channel, DDPClient::Persistent); } quint64 DDPClient::setRoomName(const QString &roomId, const QString &name) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->setRoomName(roomId, name, m_uid); return method(result, change_room_settings, DDPClient::Persistent); } quint64 DDPClient::setRoomTopic(const QString &roomId, const QString &topic) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->setRoomTopic(roomId, topic, m_uid); return method(result, change_room_settings, DDPClient::Persistent); } quint64 DDPClient::setRoomType(const QString &roomId, bool privateChannel) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->setRoomType(roomId, privateChannel, m_uid); return method(result, change_room_settings, DDPClient::Persistent); } quint64 DDPClient::setRoomEncrypted(const QString &roomId, bool encrypted) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->setRoomEncrypted(roomId, encrypted, m_uid); return method(result, change_room_settings, DDPClient::Persistent); } quint64 DDPClient::setRoomDescription(const QString &roomId, const QString &description) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->setRoomDescription(roomId, description, m_uid); return method(result, change_room_settings, DDPClient::Persistent); } quint64 DDPClient::archiveRoom(const QString &roomId) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->archiveRoom(roomId, m_uid); return method(result, change_room_settings, DDPClient::Persistent); } quint64 DDPClient::setRoomIsReadOnly(const QString &roomId, bool readOnly) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->setRoomIsReadOnly(roomId, readOnly, m_uid); return method(result, change_room_settings, DDPClient::Persistent); } quint64 DDPClient::setRoomAnnouncement(const QString &roomId, const QString &announcement) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->setRoomAnnouncement(roomId, announcement, m_uid); return method(result, change_room_settings, DDPClient::Persistent); } quint64 DDPClient::disableNotifications(const QString &roomId, bool disabled) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->disableNotifications(roomId, disabled, m_uid); return method(result, change_notifications_settings, DDPClient::Persistent); } quint64 DDPClient::hideUnreadStatus(const QString &roomId, bool disabled) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->hideUnreadStatus(roomId, disabled, m_uid); return method(result, change_notifications_settings, DDPClient::Persistent); } quint64 DDPClient::audioNotifications(const QString &roomId, const QString &value) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->audioNotifications(roomId, value, m_uid); return method(result, change_notifications_settings, DDPClient::Persistent); } quint64 DDPClient::mobilePushNotifications(const QString &roomId, const QString &value) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->mobilePushNotifications(roomId, value, m_uid); return method(result, change_notifications_settings, DDPClient::Persistent); } quint64 DDPClient::desktopNotifications(const QString &roomId, const QString &value) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->desktopNotifications(roomId, value, m_uid); return method(result, change_notifications_settings, DDPClient::Persistent); } quint64 DDPClient::emailNotifications(const QString &roomId, const QString &value) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->emailNotifications(roomId, value, m_uid); return method(result, change_notifications_settings, DDPClient::Persistent); } quint64 DDPClient::unreadAlert(const QString &roomId, const QString &value) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->unreadAlert(roomId, value, m_uid); return method(result, change_notifications_settings, DDPClient::Persistent); } void DDPClient::subscribeRoomMessage(const QString &roomId) { QJsonArray params; params.append(QJsonValue(roomId)); subscribe(QStringLiteral("stream-room-messages"), params); const QJsonArray params2{ QJsonValue(QStringLiteral("%1/%2").arg(roomId).arg(QStringLiteral("deleteMessage"))), true }; subscribe(QStringLiteral("stream-notify-room"), params2); const QJsonArray params3{ QJsonValue(QStringLiteral("%1/%2").arg(roomId).arg(QStringLiteral("typing"))), true }; subscribe(QStringLiteral("stream-notify-room"), params3); } quint64 DDPClient::eraseRoom(const QString &roomID) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->eraseRoom(roomID, m_uid); return method(result, erase_room, DDPClient::Persistent); } quint64 DDPClient::openDirectChannel(const QString &userId) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->openDirectChannel(userId, m_uid); return method(result, open_direct_channel, DDPClient::Persistent); } quint64 DDPClient::setReaction(const QString &emoji, const QString &messageId) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->setReaction(emoji, messageId, m_uid); return method(result, empty_callback, DDPClient::Persistent); } quint64 DDPClient::createPrivateGroup(const QString &name, const QStringList &userList) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->createPrivateGroup(name, userList, m_uid); return method(result, empty_callback, DDPClient::Persistent); } quint64 DDPClient::deleteMessage(const QString &messageId) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->deleteMessage(messageId, m_uid); return method(result, delete_message, DDPClient::Persistent); } quint64 DDPClient::deleteFileMessage(const QString &roomId, const QString &fileid, const QString &channelType) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->deleteFileMessage(fileid, m_uid); std::function callback = [ roomId, channelType ](const QJsonObject &root, RocketChatAccount *account) { if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Delete Attachment File:") + QJsonDocument(root).toJson()); } else { qCDebug(RUQOLA_DDPAPI_LOG) << " parse users for room" << roomId; } account->roomFiles(roomId, channelType); }; return method(result, callback, DDPClient::Persistent); } quint64 DDPClient::joinRoom(const QString &roomId, const QString &joinCode) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->joinRoom(roomId, joinCode, m_uid); return method(result, join_room, DDPClient::Persistent); } quint64 DDPClient::setDefaultStatus(User::PresenceStatus status) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->setDefaultStatus(status, m_uid); return method(result, change_default_status, DDPClient::Persistent); } quint64 DDPClient::listEmojiCustom() { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->listEmojiCustom(m_uid); return method(result, list_emoji_custom, DDPClient::Persistent); } quint64 DDPClient::userAutocomplete(const QString &pattern, const QString &exception) { const quint64 subscribeId = m_uid; const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->userAutocomplete(pattern, exception, subscribeId); std::function callback = [=](const QJsonObject &root, RocketChatAccount *account) { if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("User AutoComplete:") + QJsonDocument(root).toJson()); } else { qCDebug(RUQOLA_DDPAPI_LOG) << " User AutoComplete" << root; } account->insertCompleterUsers(); const RocketChatMessage::RocketChatMessageResult resultUnsubscribe = mRocketChatMessage->unsubscribe(subscribeId); std::function callbackUnsubscribeAutoComplete = [=](const QJsonObject &root, RocketChatAccount *account) { if (account->ruqolaLogger()) { account->ruqolaLogger()-> dataReceived(QByteArrayLiteral( "Unsubscribe AutoComplete:") + QJsonDocument(root).toJson()); } else { qDebug() << " Unsubscribe AutoComplete" << root; qCDebug(RUQOLA_DDPAPI_LOG) << " Unsubscribe AutoComplete" << root; } }; method(resultUnsubscribe, callbackUnsubscribeAutoComplete, DDPClient::Persistent); }; return method(result, callback, DDPClient::Persistent); } quint64 DDPClient::channelAndPrivateAutocomplete(const QString &pattern, const QString &exception) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->channelAndPrivateAutocomplete(pattern, exception, m_uid); return method(result, channel_and_private_autocomplete, DDPClient::Persistent); } quint64 DDPClient::getUsersOfRoom(const QString &roomId, bool showAll) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->getUsersOfRoom(roomId, showAll, m_uid); std::function callback = [ roomId ](const QJsonObject &root, RocketChatAccount *account) { if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Get Users of Room:") + QJsonDocument(root).toJson()); } else { qCDebug(RUQOLA_DDPAPI_LOG) << " parse users for room" << roomId; } account->parseUsersForRooms(root, roomId); }; return method(result, callback, DDPClient::Persistent); } +#if 0 quint64 DDPClient::roomFiles(const QString &roomId) { const quint64 subscribeId = m_uid; const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->roomFiles(roomId, subscribeId); std::function callback = [=](const QJsonObject &root, RocketChatAccount *account) { if (account->ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Room File done:") + QJsonDocument(root).toJson()); } else { qDebug() << "Room Files " << root; qCDebug(RUQOLA_DDPAPI_LOG) << " Room Files" << root; } account->insertFilesList(roomId); const RocketChatMessage::RocketChatMessageResult resultUnsubscribe = mRocketChatMessage->unsubscribe(subscribeId); std::function callbackUnsubscribeAutoComplete = [=](const QJsonObject &root, RocketChatAccount *account) { if (account->ruqolaLogger()) { account->ruqolaLogger()-> dataReceived(QByteArrayLiteral( "Unsubscribe room files:") + QJsonDocument(root).toJson()); } else { qDebug() << " Unsubscribe room files" << root; qCDebug(RUQOLA_DDPAPI_LOG) << " Unsubscribe room files" << root; } }; method(resultUnsubscribe, callbackUnsubscribeAutoComplete, DDPClient::Persistent); }; return method(result, callback, DDPClient::Persistent); } - +#endif quint64 DDPClient::createJitsiConfCall(const QString &roomId) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->createJitsiConfCall(roomId, m_uid); return method(result, create_jitsi_conf_call, DDPClient::Persistent); } quint64 DDPClient::clearUnreadMessages(const QString &roomID) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->readMessages(roomID, m_uid); return method(result, empty_callback, DDPClient::Persistent); } quint64 DDPClient::inputChannelAutocomplete(const QString &pattern, const QString &exceptions) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->inputChannelAutocomplete(pattern, exceptions, m_uid); return method(result, input_user_channel_autocomplete, DDPClient::Persistent); } quint64 DDPClient::inputUserAutocomplete(const QString &pattern, const QString &exceptions) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->inputUserAutocomplete(pattern, exceptions, m_uid); return method(result, input_user_channel_autocomplete, DDPClient::Persistent); } quint64 DDPClient::loginProvider(const QString &credentialToken, const QString &credentialSecret) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->loginProvider(credentialToken, credentialSecret, m_uid); return method(result, empty_callback, DDPClient::Ephemeral); } quint64 DDPClient::login(const QString &username, const QString &password) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->login(username, password, m_uid); return method(result, empty_callback, DDPClient::Ephemeral); } quint64 DDPClient::addUserToRoom(const QString &username, const QString &roomId) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->addUserToRoom(username, roomId, m_uid); return method(result, add_user_to_room, DDPClient::Persistent); } quint64 DDPClient::starMessage(const QString &messageId, const QString &rid, bool starred) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->starMessage(messageId, rid, starred, m_uid); return method(result, star_message, DDPClient::Persistent); } quint64 DDPClient::messageSearch(const QString &rid, const QString &pattern) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->messageSearch(rid, pattern, m_uid); return method(result, message_search, DDPClient::Persistent); } quint64 DDPClient::unBlockUser(const QString &rid, const QString &userId) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->unblockUser(rid, userId, m_uid); return method(result, unblock_user, DDPClient::Persistent); } quint64 DDPClient::blockUser(const QString &rid, const QString &userId) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->blockUser(rid, userId, m_uid); return method(result, block_user, DDPClient::Persistent); } quint64 DDPClient::informTypingStatus(const QString &roomId, bool typing, const QString &userName) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->informTypingStatus(roomId, userName, typing, m_uid); qint64 bytes = mWebSocket->sendTextMessage(result.result); if (bytes < result.result.length()) { qCDebug(RUQOLA_DDPAPI_LOG) << "ERROR! I couldn't send all of my message. This is a bug! (try again)"; qCDebug(RUQOLA_DDPAPI_LOG) << mWebSocket->isValid() << mWebSocket->error() << mWebSocket->requestUrl(); } else { qCDebug(RUQOLA_DDPAPI_COMMAND_LOG) << "Successfully sent " << result.result; } const quint64 value = m_uid; m_uid++; return value; } quint64 DDPClient::ignoreUser(const QString &roomId, const QString &userId, bool ignore) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->ignoreUser(roomId, userId, ignore, m_uid); return method(result, user_ignore, DDPClient::Persistent); } quint64 DDPClient::method(const RocketChatMessage::RocketChatMessageResult &result, std::function callback, DDPClient::MessageType messageType) { qint64 bytes = mWebSocket->sendTextMessage(result.result); if (bytes < result.result.length()) { qCDebug(RUQOLA_DDPAPI_COMMAND_LOG) << "ERROR! I couldn't send all of my message. This is a bug! (try again)"; qCDebug(RUQOLA_DDPAPI_COMMAND_LOG) << mWebSocket->isValid() << mWebSocket->error() << mWebSocket->requestUrl(); if (messageType == DDPClient::Persistent) { m_messageQueue.enqueue(qMakePair(result.method, result.jsonDocument)); mRocketChatAccount->messageQueue()->processQueue(); } } else { qCDebug(RUQOLA_DDPAPI_COMMAND_LOG) << "Successfully sent " << result.result; } m_callbackHash[m_uid] = callback; const quint64 value = m_uid; m_uid++; return value; } quint64 DDPClient::method(const QString &m, const QJsonDocument ¶ms, DDPClient::MessageType messageType) { return method(m, params, empty_callback, messageType); } quint64 DDPClient::method(const QString &method, const QJsonDocument ¶ms, std::function callback, DDPClient::MessageType messageType) { const RocketChatMessage::RocketChatMessageResult result = mRocketChatMessage->generateMethod(method, params, m_uid); qint64 bytes = mWebSocket->sendTextMessage(result.result); if (bytes < result.result.length()) { qCDebug(RUQOLA_DDPAPI_COMMAND_LOG) << "ERROR! I couldn't send all of my message. This is a bug! (try again)"; qCDebug(RUQOLA_DDPAPI_COMMAND_LOG) << mWebSocket->isValid() << mWebSocket->error() << mWebSocket->requestUrl(); if (messageType == DDPClient::Persistent) { m_messageQueue.enqueue(qMakePair(result.method, result.jsonDocument)); mRocketChatAccount->messageQueue()->processQueue(); } } else { qCDebug(RUQOLA_DDPAPI_COMMAND_LOG) << "Successfully sent " << result.result; } m_callbackHash[m_uid] = callback; const quint64 uidCurrent = m_uid; m_uid++; return uidCurrent; } void DDPClient::subscribe(const QString &collection, const QJsonArray ¶ms) { QJsonObject json; json[QStringLiteral("msg")] = QStringLiteral("sub"); json[QStringLiteral("id")] = QString::number(m_uid); json[QStringLiteral("name")] = collection; QJsonArray newParams = params; if (mRocketChatAccount->needAdaptNewSubscriptionRC60()) { QJsonArray args; QJsonObject obj; obj[QStringLiteral("useCollection")] = false; obj[QStringLiteral("args")] = args; newParams.append(obj); } json[QStringLiteral("params")] = newParams; qint64 bytes = mWebSocket->sendTextMessage(QString::fromUtf8(QJsonDocument(json).toJson(QJsonDocument::Compact))); if (bytes < json.length()) { qCDebug(RUQOLA_DDPAPI_LOG) << "ERROR! I couldn't send all of my message. This is a bug! (try again)"; qCDebug(RUQOLA_DDPAPI_LOG) << mWebSocket->isValid() << mWebSocket->error() << mWebSocket->requestUrl(); } else { qCDebug(RUQOLA_DDPAPI_COMMAND_LOG) << "Successfully sent " << json; } m_uid++; } void DDPClient::onTextMessageReceived(const QString &message) { QJsonDocument response = QJsonDocument::fromJson(message.toUtf8()); if (!response.isNull() && response.isObject()) { QJsonObject root = response.object(); const QString messageType = root.value(QLatin1String("msg")).toString(); if (messageType == QLatin1String("updated")) { //nothing to do. qCDebug(RUQOLA_DDPAPI_LOG) << " message updated ! not implemented yet" << response; } else if (messageType == QLatin1String("result")) { quint64 id = root.value(QLatin1String("id")).toString().toULongLong(); if (m_callbackHash.contains(id)) { std::function callback = m_callbackHash.take(id); callback(root, mRocketChatAccount); } Q_EMIT result(id, QJsonDocument(root.value(QLatin1String("result")).toObject())); if (id == m_loginJob) { if (root.value(QLatin1String("error")).toObject().value(QLatin1String("error")).toInt() == 403) { qCDebug(RUQOLA_DDPAPI_LOG) << "Wrong password or token expired"; login(); // Let's keep trying to log in } else { const QString token = root.value(QLatin1String("result")).toObject().value(QLatin1String("token")).toString(); mRocketChatAccount->settings()->setAuthToken(token); mRocketChatAccount->restApi()->setAuthToken(token); mRocketChatAccount->restApi()->setUserId(root.value(QLatin1String("id")).toString()); setLoginStatus(DDPClient::LoggedIn); } } } else if (messageType == QLatin1String("connected")) { //qCDebug(RUQOLA_DDPAPI_LOG) << "Connected"; qDebug() << "Connected"; m_connected = true; setLoginStatus(DDPClient::LoggingIn); Q_EMIT connectedChanged(); } else if (messageType == QLatin1String("error")) { qWarning() << "ERROR!!" << message; } else if (messageType == QLatin1String("ping")) { qCDebug(RUQOLA_DDPAPI_LOG) << "Ping - Pong"; pong(); } else if (messageType == QLatin1String("added")) { qCDebug(RUQOLA_DDPAPI_LOG) << "ADDING element" <settings()->password().isEmpty()) { // If we have a password and we couldn't log in, let's stop here if (m_attemptedPasswordLogin) { setLoginStatus(LoginFailed); return; } m_attemptedPasswordLogin = true; //m_loginJob = login(mRocketChatAccount->settings()->userName(), mRocketChatAccount->settings()->password()); mRocketChatAccount->defaultAuthenticationInterface()->login(); } else if (!mRocketChatAccount->settings()->authToken().isEmpty() && !m_attemptedTokenLogin) { m_attemptedPasswordLogin = true; QJsonObject json; json[QStringLiteral("resume")] = mRocketChatAccount->settings()->authToken(); m_loginJob = method(QStringLiteral("login"), QJsonDocument(json)); } else { setLoginStatus(LoginFailed); } } void DDPClient::onWSConnected() { qCDebug(RUQOLA_DDPAPI_LOG) << "Websocket connected at URL" << mUrl; QJsonArray supportedVersions; supportedVersions.append(QLatin1String("1")); QJsonObject protocol; protocol[QStringLiteral("msg")] = QStringLiteral("connect"); protocol[QStringLiteral("version")] = QStringLiteral("1"); protocol[QStringLiteral("support")] = supportedVersions; QByteArray serialize = QJsonDocument(protocol).toJson(QJsonDocument::Compact); qint64 bytes = mWebSocket->sendTextMessage(QString::fromUtf8(serialize)); if (bytes < serialize.length()) { qCDebug(RUQOLA_DDPAPI_COMMAND_LOG) << "onWSConnected: ERROR! I couldn't send all of my message. This is a bug! (try again)"; qCDebug(RUQOLA_DDPAPI_COMMAND_LOG) << mWebSocket->isValid() << mWebSocket->error() << mWebSocket->requestUrl(); } else { qCDebug(RUQOLA_DDPAPI_COMMAND_LOG) << "Successfully sent " << serialize; } } void DDPClient::onSslErrors(const QList &errors) { qCDebug(RUQOLA_DDPAPI_LOG) << "SSL error" << errors.count(); for (const QSslError &err : errors) { qCDebug(RUQOLA_DDPAPI_LOG) << "error ssl type:" << err.errorString(); } mWebSocket->ignoreSslErrors(); } void DDPClient::onWSclosed() { if (mWebSocket->closeCode() != QWebSocketProtocol::CloseCodeNormal) { qCDebug(RUQOLA_DDPAPI_LOG) << "WebSocket CLOSED" << mWebSocket->closeReason() << mWebSocket->error() << mWebSocket->closeCode(); } setLoginStatus(NotConnected); } void DDPClient::pong() { QJsonObject pong; pong[QStringLiteral("msg")] = QStringLiteral("pong"); mWebSocket->sendBinaryMessage(QJsonDocument(pong).toJson(QJsonDocument::Compact)); } void DDPClient::executeSubsCallBack(const QJsonObject &root) { const QJsonArray subs = root[QStringLiteral("subs")].toArray(); if (!subs.isEmpty()) { const quint64 id = subs.at(0).toString().toULongLong(); if (m_callbackHash.contains(id)) { std::function callback = m_callbackHash.take(id); callback(root, mRocketChatAccount); } } else { qCWarning(RUQOLA_DDPAPI_LOG) << "Problem with subs json " << root; } } diff --git a/src/ruqolacore/ddpapi/ddpclient.h b/src/ruqolacore/ddpapi/ddpclient.h index 34a7b942..5a4eeec8 100644 --- a/src/ruqolacore/ddpapi/ddpclient.h +++ b/src/ruqolacore/ddpapi/ddpclient.h @@ -1,255 +1,255 @@ /* * 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 DDPCLIENT_H #define DDPCLIENT_H #include "rocketchatmessage.h" #include "libruqolacore_export.h" #include #include #include class QJsonObject; class QJsonDocument; class RocketChatMessage; class AbstractWebSocket; class RocketChatAccount; class LIBRUQOLACORE_EXPORT DDPClient : public QObject { Q_OBJECT public: enum LoginStatus { NotConnected, LoggingIn, LoggedIn, LoginFailed, LoggedOut }; Q_ENUM(LoginStatus) enum MessageType { Persistent, Ephemeral }; explicit DDPClient(RocketChatAccount *account = nullptr, QObject *parent = nullptr); ~DDPClient(); /** * @brief Call a method with name @param method and parameters @param params and @param messageType with an empty callback * * @param method The name of the method to call Rocket.Chat API for * @param params The parameters * @param messageType The type of message * @return unsigned int, the ID of the called method */ quint64 method(const QString &method, const QJsonDocument ¶ms, DDPClient::MessageType messageType = DDPClient::Ephemeral); /** * @brief Send message over network * * @param method The name of the method to call Rocket.Chat API for * @param params The parameters * @param callback The pointer to callback function * @param messageType The type of message * @return unsigned int, the ID of the called method */ quint64 method(const QString &method, const QJsonDocument ¶ms, std::function callback, DDPClient::MessageType messageType = DDPClient::Ephemeral); quint64 method(const RocketChatMessage::RocketChatMessageResult &result, std::function callback, DDPClient::MessageType messageType = DDPClient::Ephemeral); /** * @brief Subscribes to a collection with name @param collection and parameters @param params * * @param collection The name of the collection * @param params The parameters */ void subscribe(const QString &collection, const QJsonArray ¶ms); /** * @brief Calls method to log in the user with valid username and password */ Q_INVOKABLE void login(); /** * @brief Closes the websocket connection */ void logOut(); /** * @brief Check whether websocket is connected at url * * @return true if connected, else false */ Q_REQUIRED_RESULT bool isConnected() const; /** * @brief Check whether user is logged in * * @return true if user is logged in, else false */ Q_REQUIRED_RESULT bool isLoggedIn() const; /** * @brief Reconnects the websocket to new url */ void onServerURLChange(); /** * @brief Returns the queue used to cache unsent messages * *@return QQueue>, The m_messageQueue object */ Q_REQUIRED_RESULT QQueue > messageQueue() const; /** * @brief Returns standard cache path * *@def QString path */ Q_REQUIRED_RESULT QString cachePath() const; Q_REQUIRED_RESULT quint64 leaveRoom(const QString &roomID); Q_REQUIRED_RESULT quint64 hideRoom(const QString &roomID); Q_REQUIRED_RESULT quint64 clearUnreadMessages(const QString &roomID); Q_REQUIRED_RESULT quint64 informTypingStatus(const QString &room, bool typing, const QString &userName); void setServerUrl(const QString &url); void start(); void setLoginJobId(quint64 jobid); Q_REQUIRED_RESULT LoginStatus loginStatus() const; Q_REQUIRED_RESULT quint64 toggleFavorite(const QString &roomID, bool favorite); Q_REQUIRED_RESULT quint64 createChannel(const QString &name, const QStringList &userList, bool readOnly); Q_REQUIRED_RESULT quint64 createPrivateGroup(const QString &name, const QStringList &userList); Q_REQUIRED_RESULT quint64 joinRoom(const QString &roomId, const QString &joinCode); Q_REQUIRED_RESULT quint64 openDirectChannel(const QString &userId); void subscribeRoomMessage(const QString &roomId); Q_REQUIRED_RESULT quint64 setDefaultStatus(User::PresenceStatus status); Q_REQUIRED_RESULT quint64 listEmojiCustom(); Q_REQUIRED_RESULT quint64 createJitsiConfCall(const QString &roomId); Q_REQUIRED_RESULT quint64 userAutocomplete(const QString &pattern, const QString &exception); Q_REQUIRED_RESULT quint64 deleteMessage(const QString &messageId); Q_REQUIRED_RESULT quint64 eraseRoom(const QString &roomID); Q_REQUIRED_RESULT quint64 setRoomName(const QString &roomId, const QString &name); Q_REQUIRED_RESULT quint64 setRoomTopic(const QString &roomId, const QString &topic); Q_REQUIRED_RESULT quint64 setRoomDescription(const QString &roomId, const QString &description); Q_REQUIRED_RESULT quint64 setRoomAnnouncement(const QString &roomId, const QString &announcement); Q_REQUIRED_RESULT quint64 starMessage(const QString &messageId, const QString &rid, bool starred); Q_REQUIRED_RESULT quint64 setRoomIsReadOnly(const QString &roomId, bool readOnly); Q_REQUIRED_RESULT quint64 archiveRoom(const QString &roomId); Q_REQUIRED_RESULT quint64 setReaction(const QString &emoji, const QString &messageId); Q_REQUIRED_RESULT quint64 getUsersOfRoom(const QString &roomId, bool showAll); Q_REQUIRED_RESULT quint64 loadHistory(const QJsonArray ¶ms); Q_REQUIRED_RESULT quint64 channelAndPrivateAutocomplete(const QString &pattern, const QString &exception); - Q_REQUIRED_RESULT quint64 roomFiles(const QString &roomId); + //Q_REQUIRED_RESULT quint64 roomFiles(const QString &roomId); Q_REQUIRED_RESULT quint64 addUserToRoom(const QString &userId, const QString &roomId); Q_REQUIRED_RESULT quint64 inputChannelAutocomplete(const QString &pattern, const QString &exceptions); Q_REQUIRED_RESULT quint64 inputUserAutocomplete(const QString &pattern, const QString &exceptions); Q_REQUIRED_RESULT quint64 login(const QString &username, const QString &password); Q_REQUIRED_RESULT quint64 loginProvider(const QString &credentialToken, const QString &credentialSecret); Q_REQUIRED_RESULT quint64 messageSearch(const QString &rid, const QString &pattern); Q_REQUIRED_RESULT quint64 unBlockUser(const QString &rid, const QString &userId); Q_REQUIRED_RESULT quint64 blockUser(const QString &rid, const QString &userId); Q_REQUIRED_RESULT quint64 disableNotifications(const QString &roomId, bool disabled); Q_REQUIRED_RESULT quint64 hideUnreadStatus(const QString &roomId, bool disabled); Q_REQUIRED_RESULT quint64 audioNotifications(const QString &roomId, const QString &value); Q_REQUIRED_RESULT quint64 mobilePushNotifications(const QString &roomId, const QString &value); Q_REQUIRED_RESULT quint64 desktopNotifications(const QString &roomId, const QString &value); Q_REQUIRED_RESULT quint64 emailNotifications(const QString &roomId, const QString &value); Q_REQUIRED_RESULT quint64 unreadAlert(const QString &roomId, const QString &value); Q_REQUIRED_RESULT quint64 deleteFileMessage(const QString &roomId, const QString &fileid, const QString &channelType); Q_REQUIRED_RESULT quint64 setRoomType(const QString &roomId, bool privateChannel); Q_REQUIRED_RESULT quint64 ignoreUser(const QString &roomId, const QString &userId, bool ignore); Q_REQUIRED_RESULT quint64 setRoomEncrypted(const QString &roomId, bool encrypted); Q_SIGNALS: void connectedChanged(); void loginStatusChanged(); void disconnected(); void added(const QJsonObject &item); void changed(const QJsonObject &item); void removed(const QJsonObject &item); /** * @brief Emitted whenever a result is received * * @param id The ID received in the method() call * @param result The response sent by server */ void result(quint64 id, const QJsonDocument &result); private Q_SLOTS: void onWSConnected(); void onTextMessageReceived(const QString &message); void onWSclosed(); void onSslErrors(const QList &errors); private: Q_DISABLE_COPY(DDPClient) void initializeWebSocket(); QUrl adaptUrl(const QString &url); void setLoginStatus(LoginStatus l); void pong(); void executeSubsCallBack(const QJsonObject &root); QString mUrl; AbstractWebSocket *mWebSocket = nullptr; /** * @brief Unique message ID for each message sent over network */ quint64 m_uid = 0; /** * @brief Stores callback function associated with each message * * @def QHash unsigned messageID and std::function pointer to callback */ QHash > m_callbackHash; quint64 m_loginJob = 0; LoginStatus m_loginStatus; bool m_connected = false; bool m_attemptedPasswordLogin = false; bool m_attemptedTokenLogin = false; /** * @brief Abstract queue for all requests regarding network management * * @def QPair QString method and QJsonDocument params */ QQueue > m_messageQueue; friend class Ruqola; RocketChatMessage *mRocketChatMessage = nullptr; RocketChatAccount *mRocketChatAccount = nullptr; }; #endif // DDPCLIENT_H diff --git a/src/ruqolacore/model/roommodel.cpp b/src/ruqolacore/model/roommodel.cpp index 548661d7..4cc51a42 100644 --- a/src/ruqolacore/model/roommodel.cpp +++ b/src/ruqolacore/model/roommodel.cpp @@ -1,604 +1,580 @@ /* * 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 "roommodel.h" #include "ruqola_debug.h" #include "rocketchataccount.h" #include "usersforroommodel.h" #include "threadsmodel.h" #include "discussionsmodel.h" #include "roomwrapper.h" #include #include #include #include #include RoomModel::RoomModel(RocketChatAccount *account, QObject *parent) : QAbstractListModel(parent) , mRocketChatAccount(account) { } RoomModel::~RoomModel() { #if 0 if (mRocketChatAccount && mRocketChatAccount->settings()) { const QString cachePath = mRocketChatAccount->settings()->cacheBasePath(); if (cachePath.isEmpty()) { qCWarning(RUQOLA_LOG) << " Cache Path is not defined"; return; } QDir cacheDir(cachePath); if (!cacheDir.exists(cacheDir.path())) { cacheDir.mkpath(cacheDir.path()); } QFile f(cacheDir.absoluteFilePath(QStringLiteral("rooms"))); if (f.open(QIODevice::WriteOnly)) { QDataStream out(&f); for (Room *m : qAsConst(mRoomsList)) { qCDebug(RUQOLA_LOG) << " save cache for room " << m->name(); const QByteArray ms = Room::serialize(m); out.writeBytes(ms.constData(), ms.size()); } } } #endif qDeleteAll(mRoomsList); } void RoomModel::clear() { if (!mRoomsList.isEmpty()) { beginRemoveRows(QModelIndex(), 0, rowCount() - 1); qDeleteAll(mRoomsList); mRoomsList.clear(); endRemoveRows(); } } Room *RoomModel::findRoom(const QString &roomID) const { for (Room *r : qAsConst(mRoomsList)) { if (r->roomId() == roomID) { return r; } } return nullptr; } RoomWrapper *RoomModel::findRoomWrapper(const QString &roomID) const { for (Room *r : qAsConst(mRoomsList)) { if (r->roomId() == roomID) { RoomWrapper *wrapper = new RoomWrapper(r); return wrapper; } } return nullptr; } // Clear data and refill it with data in the cache, if there is void RoomModel::reset() { clear(); if (!mRocketChatAccount) { return; } if (mRocketChatAccount->settings()->cacheBasePath().isEmpty()) { return; } //Laurent disable cache for the moment /* QDir cacheDir(Ruqola::self()->cacheBasePath()); // load cache if (cacheDir.exists(cacheDir.path())) { QFile f(cacheDir.absoluteFilePath(QStringLiteral("rooms"))); if (f.open(QIODevice::ReadOnly)) { QDataStream in(&f); while (!f.atEnd()) { char *byteArray; quint32 length; in.readBytes(byteArray, length); QByteArray arr = QByteArray::fromRawData(byteArray, length); Room m = Room::fromJSon(QJsonDocument::fromBinaryData(arr).object()); qDebug() <<" Load from cache room name: " << m.name; addRoom(m.id, m.name, m.selected); } } qCDebug(RUQOLA_LOG) << "Cache Loaded"; } */ } QHash RoomModel::roleNames() const { QHash roles; roles[RoomName] = QByteArrayLiteral("name"); roles[RoomFName] = QByteArrayLiteral("fname"); roles[RoomID] = QByteArrayLiteral("room_id"); roles[RoomSelected] = QByteArrayLiteral("selected"); roles[RoomUnread] = QByteArrayLiteral("unread"); roles[RoomType] = QByteArrayLiteral("type"); roles[RoomOwnerUserName] = QByteArrayLiteral("username"); roles[RoomOwnerUserID] = QByteArrayLiteral("userID"); roles[RoomTopic] = QByteArrayLiteral("topic"); roles[RoomMutedUsers] = QByteArrayLiteral("mutedUsers"); roles[RoomJitsiTimeout] = QByteArrayLiteral("jitsiTimeout"); roles[RoomRo] = QByteArrayLiteral("readOnly"); roles[RoomAnnouncement] = QByteArrayLiteral("announcement"); roles[RoomOpen] = QByteArrayLiteral("open"); roles[RoomAlert] = QByteArrayLiteral("alert"); roles[RoomOrder] = QByteArrayLiteral("roomorder"); roles[RoomFavorite] = QByteArrayLiteral("favorite"); roles[RoomSection] = QByteArrayLiteral("sectionname"); roles[RoomIcon] = QByteArrayLiteral("channelicon"); roles[RoomUserMentions] = QByteArrayLiteral("userMentions"); return roles; } int RoomModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return mRoomsList.size(); } QVariant RoomModel::data(const QModelIndex &index, int role) const { if (index.row() < 0 || index.row() >= mRoomsList.count()) { return QVariant(); } Room *r = mRoomsList.at(index.row()); switch (role) { case RoomModel::RoomName: return r->name(); case RoomModel::RoomFName: return r->displayFName(); case RoomModel::RoomID: return r->roomId(); case RoomModel::RoomSelected: return r->selected(); case RoomModel::RoomType: return r->channelType(); case RoomModel::RoomOwnerUserID: return r->roomCreatorUserId(); case RoomModel::RoomOwnerUserName: return r->roomOwnerUserName(); case RoomModel::RoomTopic: return r->topic(); case RoomModel::RoomMutedUsers: return r->mutedUsers(); case RoomModel::RoomJitsiTimeout: return r->jitsiTimeout(); case RoomModel::RoomRo: return r->readOnly(); case RoomModel::RoomAnnouncement: return r->announcement(); case RoomModel::RoomUnread: return r->unread(); case RoomModel::RoomOpen: return r->open(); case RoomModel::RoomAlert: return r->alert(); case RoomModel::RoomFavorite: return r->favorite(); case RoomModel::RoomSection: return sectionName(r); case RoomModel::RoomOrder: return order(r); case RoomModel::RoomIcon: return icon(r); case RoomModel::RoomOtr: //TODO implement it. return {}; case RoomModel::RoomUserMentions: return r->userMentions(); case RoomModel::RoomIgnoredUsers: return r->ignoredUsers(); } return {}; } void RoomModel::addRoom(const QString &roomID, const QString &roomName, bool selected) { if (roomID.isEmpty() || roomName.isEmpty()) { qCDebug(RUQOLA_LOG) << " Impossible to add a room"; return; } qCDebug(RUQOLA_LOG) << "Adding room : roomId: " << roomID << " room Name " << roomName << " isSelected : " << selected; Room *r = createNewRoom(); r->setRoomId(roomID); r->setName(roomName); r->setSelected(selected); addRoom(r); } Room *RoomModel::createNewRoom() { Room *r = new Room(mRocketChatAccount); connect(r, &Room::alertChanged, this, &RoomModel::needToUpdateNotification); connect(r, &Room::unreadChanged, this, &RoomModel::needToUpdateNotification); return r; } void RoomModel::getUnreadAlertFromAccount(bool &hasAlert, int &nbUnread) { for (int i = 0; i < mRoomsList.count(); ++i) { if (mRoomsList.at(i)->open()) { if (mRoomsList.at(i)->alert()) { hasAlert = true; } nbUnread += mRoomsList.at(i)->unread(); } } } void RoomModel::updateSubscriptionRoom(const QJsonObject &roomData) { //TODO fix me! //Use "_id" QString rId = roomData.value(QLatin1String("rid")).toString(); if (rId.isEmpty()) { rId = roomData.value(QLatin1String("_id")).toString(); } if (!rId.isEmpty()) { const int roomCount = mRoomsList.size(); for (int i = 0; i < roomCount; ++i) { if (mRoomsList.at(i)->roomId() == rId) { qCDebug(RUQOLA_LOG) << " void RoomModel::updateSubscriptionRoom(const QJsonArray &array) room found"; Room *room = mRoomsList.at(i); room->updateSubscriptionRoom(roomData); Q_EMIT dataChanged(createIndex(i, 0), createIndex(i, 0)); break; } } } else { //qCWarning(RUQOLA_LOG) << "RoomModel::updateRoom incorrect jsonobject "<< roomData; qWarning() << "RoomModel::updateSubscriptionRoom incorrect jsonobject "<< roomData; } } QString RoomModel::insertRoom(const QJsonObject &room) { Room *r = createNewRoom(); r->parseInsertRoom(room); qCDebug(RUQOLA_LOG) << "Inserting room" << r->name() << r->roomId() << r->topic(); addRoom(r); return r->roomId(); } Room *RoomModel::addRoom(const QJsonObject &room) { Room *r = createNewRoom(); r->parseSubscriptionRoom(room); qCDebug(RUQOLA_LOG) << "Adding room subscription" << r->name() << r->roomId() << r->topic(); addRoom(r); return r; } void RoomModel::addRoom(Room *room) { qCDebug(RUQOLA_LOG) << " void RoomModel::addRoom(const Room &room)"<name(); int roomCount = mRoomsList.count(); for (int i = 0; i < roomCount; ++i) { if (mRoomsList.at(i)->roomId() == room->roomId()) { delete mRoomsList.takeAt(i); break; } } roomCount = mRoomsList.count(); beginInsertRows(QModelIndex(), roomCount, roomCount); qCDebug(RUQOLA_LOG) << "Inserting room at position" <roomId() == id) { beginRemoveRows(QModelIndex(), i, i); mRoomsList.remove(i); endRemoveRows(); break; } } } else if (actionName == QStringLiteral("inserted")) { qCDebug(RUQOLA_LOG) << "INSERT ROOM name " << roomData.value(QLatin1String("name")) << " rid " << roomData.value(QLatin1String("rid")); //TODO fix me! addRoom(roomData); //addRoom(roomData.value(QLatin1String("rid")).toString(), roomData.value(QLatin1String("name")).toString(), false); } else if (actionName == QStringLiteral("updated")) { //qCDebug(RUQOLA_LOG) << "UPDATE ROOM name " << roomData.value(QLatin1String("name")).toString() << " rid " << roomData.value(QLatin1String("rid")) << " roomData " << roomData; qDebug() << "UPDATE ROOM name " << roomData.value(QLatin1String("name")).toString() << " rid " << roomData.value(QLatin1String("rid")) << " roomData " << roomData; updateSubscriptionRoom(roomData); } else if (actionName == QStringLiteral("changed")) { //qDebug() << "CHANGED ROOM name " << roomData.value(QLatin1String("name")).toString() << " rid " << roomData.value(QLatin1String("rid")) << " roomData " << roomData; qCDebug(RUQOLA_LOG) << "CHANGED ROOM name " << roomData.value(QLatin1String("name")).toString() << " rid " << roomData.value(QLatin1String("rid")) << " roomData " << roomData; qCDebug(RUQOLA_LOG) << "RoomModel::updateSubscription Not implementer changed room yet" << array; updateRoom(roomData); } else { qCDebug(RUQOLA_LOG) << "RoomModel::updateSubscription Undefined type" << actionName; } } void RoomModel::updateRoom(const QJsonObject &roomData) { qCDebug(RUQOLA_LOG) << " void RoomModel::updateRoom(const QJsonObject &roomData)"; //TODO fix me! //Use "_id" QString rId = roomData.value(QLatin1String("rid")).toString(); if (rId.isEmpty()) { rId = roomData.value(QLatin1String("_id")).toString(); } if (!rId.isEmpty()) { const int roomCount = mRoomsList.size(); for (int i = 0; i < roomCount; ++i) { if (mRoomsList.at(i)->roomId() == rId) { qCDebug(RUQOLA_LOG) << " void RoomModel::updateRoom(const QJsonArray &array) room found"; Room *room = mRoomsList.at(i); room->parseUpdateRoom(roomData); Q_EMIT dataChanged(createIndex(i, 0), createIndex(i, 0)); break; } } } else { //qCWarning(RUQOLA_LOG) << "RoomModel::updateRoom incorrect jsonobject "<< roomData; qWarning() << "RoomModel::updateRoom incorrect jsonobject "<< roomData; } } void RoomModel::userStatusChanged(const User &user) { const int roomCount = mRoomsList.count(); for (int i = 0; i < roomCount; ++i) { Room *room = mRoomsList.at(i); if (room->name() == user.userName()) { const QModelIndex idx = createIndex(i, 0); Q_EMIT dataChanged(idx, idx); } room->usersModelForRoom()->userStatusChanged(user); } } UsersForRoomModel *RoomModel::usersModelForRoom(const QString &roomId) const { const int roomCount = mRoomsList.count(); for (int i = 0; i < roomCount; ++i) { Room *room = mRoomsList.at(i); if (room->roomId() == roomId) { return room->usersModelForRoom(); } } qCWarning(RUQOLA_LOG) << " Users model for room undefined !"; return nullptr; } UsersForRoomFilterProxyModel *RoomModel::usersForRoomFilterProxyModel(const QString &roomId) const { const int roomCount = mRoomsList.count(); for (int i = 0; i < roomCount; ++i) { Room *room = mRoomsList.at(i); if (room->roomId() == roomId) { return room->usersModelForRoomProxyModel(); } } return {}; } -FilesForRoomFilterProxyModel *RoomModel::filesForRoomFilterProxyModel(const QString &roomId) const -{ - const int roomCount = mRoomsList.count(); - for (int i = 0; i < roomCount; ++i) { - Room *room = mRoomsList.at(i); - if (room->roomId() == roomId) { - return room->filesForRoomFilterProxyModel(); - } - } - return {}; -} - MessageModel *RoomModel::messageModel(const QString &roomId) const { const int roomCount = mRoomsList.count(); for (int i = 0; i < roomCount; ++i) { Room *room = mRoomsList.at(i); if (room->roomId() == roomId) { return room->messageModel(); } } return {}; } -FilesForRoomModel *RoomModel::filesModelForRoom(const QString &roomId) const -{ - const int roomCount = mRoomsList.count(); - for (int i = 0; i < roomCount; ++i) { - Room *room = mRoomsList.at(i); - if (room->roomId() == roomId) { - return room->filesModelForRoom(); - } - } - return {}; -} - DiscussionsModel *RoomModel::discussionsModelForRoom(const QString &roomId) const { const int roomCount = mRoomsList.count(); for (int i = 0; i < roomCount; ++i) { Room *room = mRoomsList.at(i); if (room->roomId() == roomId) { return room->discussionsModelForRoom(); } } return {}; } DiscussionsFilterProxyModel *RoomModel::discussionsModelForRoomProxyModel(const QString &roomId) const { const int roomCount = mRoomsList.count(); for (int i = 0; i < roomCount; ++i) { Room *room = mRoomsList.at(i); if (room->roomId() == roomId) { return room->discussionsModelForRoomFilterProxyModel(); } } return {}; } ThreadsModel *RoomModel::threadsModelForRoom(const QString &roomId) const { const int roomCount = mRoomsList.count(); for (int i = 0; i < roomCount; ++i) { Room *room = mRoomsList.at(i); if (room->roomId() == roomId) { return room->threadsModelForRoom(); } } return {}; } ThreadsFilterProxyModel *RoomModel::threadsModelForRoomProxyModel(const QString &roomId) const { const int roomCount = mRoomsList.count(); for (int i = 0; i < roomCount; ++i) { Room *room = mRoomsList.at(i); if (room->roomId() == roomId) { return room->threadsModelForRoomFilterProxyModel(); } } return {}; } QString RoomModel::inputMessage(const QString &roomId) const { const int roomCount = mRoomsList.count(); for (int i = 0; i < roomCount; ++i) { Room *room = mRoomsList.at(i); if (room->roomId() == roomId) { return room->inputMessage(); } } return {}; } void RoomModel::setInputMessage(const QString &roomId, const QString &inputMessage) { const int roomCount = mRoomsList.count(); for (int i = 0; i < roomCount; ++i) { Room *room = mRoomsList.at(i); if (room->roomId() == roomId) { room->setInputMessage(inputMessage); return; } } } QString RoomModel::sectionName(Room *r) const { QString str; if (r->favorite()) { str = i18n("Favorites"); } else { const QString channelTypeStr = r->channelType(); if (channelTypeStr == QLatin1String("p")) { if (r->parentRid().isEmpty()) { str = i18n("Rooms"); } else { str = i18n("Discussions"); } } else if (channelTypeStr == QLatin1String("c")) { str = i18n("Rooms"); } else if (channelTypeStr == QLatin1String("d")) { str = i18n("Private Message"); } } return str; } int RoomModel::order(Room *r) const { int order = 0; //First item are favorites channels if (!r->favorite()) { order += 10; } const QString channelTypeStr = r->channelType(); if (channelTypeStr == QLatin1String("c")) { order += 1; } else if (channelTypeStr == QLatin1String("d")) { order += 2; } else if (channelTypeStr == QLatin1String("p")) { if (r->parentRid().isEmpty()) { order += 1; } else { order += 4; } } else { qCDebug(RUQOLA_LOG) << r->name() << "has unhandled channel type" << channelTypeStr; order += 5; } return order; } QIcon RoomModel::icon(Room *r) const { if (r->channelType() == QLatin1String("c")) { if (r->unread() > 0 || r->alert()) { return QIcon::fromTheme(QStringLiteral("irc-channel-active")); } else { return QIcon::fromTheme(QStringLiteral("irc-channel-inactive")); } } else if (r->channelType() == QLatin1String("d")) { const QString userStatusIconFileName = mRocketChatAccount ? mRocketChatAccount->userStatusIconFileName(r->name()) : QString(); if (userStatusIconFileName.isEmpty()) { return QIcon::fromTheme(QStringLiteral("user-available")); } else { return QIcon::fromTheme(userStatusIconFileName); } } else if (r->channelType() == QLatin1String("p")) { return QIcon::fromTheme(QStringLiteral("lock")); } return {}; } diff --git a/src/ruqolacore/model/roommodel.h b/src/ruqolacore/model/roommodel.h index d61e01dd..dcc06270 100644 --- a/src/ruqolacore/model/roommodel.h +++ b/src/ruqolacore/model/roommodel.h @@ -1,147 +1,141 @@ /* * 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 ROOMMODEL_H #define ROOMMODEL_H #include "libruqolacore_export.h" #include "room.h" #include "user.h" #include #include class RoomWrapper; class RocketChatAccount; -class FilesForRoomModel; -class FilesForRoomFilterProxyModel; class MessageModel; class ThreadsModel; class DiscussionsModel; class ThreadsFilterProxyModel; class LIBRUQOLACORE_EXPORT RoomModel : public QAbstractListModel { Q_OBJECT public: enum RoomRoles { RoomName = Qt::UserRole + 1, RoomFName, RoomSelected, RoomID, RoomUnread, RoomType, RoomOwnerUserName, //created by UserName RoomOwnerUserID, RoomTopic, RoomMutedUsers, RoomJitsiTimeout, RoomRo, RoomAnnouncement, RoomOpen, RoomAlert, RoomOrder, RoomFavorite, RoomSection, RoomIcon, RoomOtr, RoomUserMentions, RoomIgnoredUsers, }; Q_ENUM(RoomRoles) explicit RoomModel(RocketChatAccount *account = nullptr, QObject *parent = nullptr); ~RoomModel() override; Q_REQUIRED_RESULT int rowCount(const QModelIndex &parent = QModelIndex()) const override; Q_REQUIRED_RESULT QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; /** * @brief Constructs room object from @param roomID and @param roomName and @param selected, then calls @method addRoom * * @param roomID The unique room ID * @param roomName The name of the room * @param selected True if room if @param roomID is selected, else false */ Q_INVOKABLE void addRoom(const QString &roomID, const QString &roomName, bool selected = false); /** * @brief Finds a room with @param roomID in m_roomsList * * @param roomID The ID of the room to find * @return RoomWrapper Pointer, The pointer to room with @param roomID in m_roomsList, if exists. Else return a new RoomWrapper object */ RoomWrapper *findRoomWrapper(const QString &roomID) const; //Clear data and refill it with data in the cache, if there is void reset(); void clear(); void updateSubscription(const QJsonArray &array); void updateRoom(const QJsonObject &array); Room *addRoom(const QJsonObject &room); /** * @brief Adds a room to m_roomsList with @param room * * @param room The room to be added */ void addRoom(Room *room); void removeRoom(const QString &roomId); void getUnreadAlertFromAccount(bool &hasAlert, int &nbUnread); void userStatusChanged(const User &user); UsersForRoomModel *usersModelForRoom(const QString &roomId) const; UsersForRoomFilterProxyModel *usersForRoomFilterProxyModel(const QString &roomId) const; - FilesForRoomModel *filesModelForRoom(const QString &roomId) const; - - FilesForRoomFilterProxyModel *filesForRoomFilterProxyModel(const QString &roomId) const; - MessageModel *messageModel(const QString &roomId) const; Q_REQUIRED_RESULT QHash roleNames() const override; Q_REQUIRED_RESULT QString inputMessage(const QString &roomId) const; void setInputMessage(const QString &roomId, const QString &inputMessage); Q_REQUIRED_RESULT Room *findRoom(const QString &roomID) const; void updateSubscriptionRoom(const QJsonObject &room); Q_REQUIRED_RESULT QString insertRoom(const QJsonObject &room); DiscussionsModel *discussionsModelForRoom(const QString &roomId) const; DiscussionsFilterProxyModel *discussionsModelForRoomProxyModel(const QString &roomId) const; ThreadsModel *threadsModelForRoom(const QString &roomId) const; ThreadsFilterProxyModel *threadsModelForRoomProxyModel(const QString &roomId) const; Q_SIGNALS: void needToUpdateNotification(); private: Q_DISABLE_COPY(RoomModel) Room *createNewRoom(); QIcon icon(Room *r) const; int order(Room *r) const; QString sectionName(Room *r) const; RocketChatAccount *mRocketChatAccount = nullptr; QVector mRoomsList; }; #endif // ROOMMODEL_H diff --git a/src/ruqolacore/rocketchataccount.cpp b/src/ruqolacore/rocketchataccount.cpp index 05950f71..4d01d33c 100644 --- a/src/ruqolacore/rocketchataccount.cpp +++ b/src/ruqolacore/rocketchataccount.cpp @@ -1,1520 +1,1514 @@ /* Copyright (c) 2017-2019 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 "emoticons/emojimanager.h" #include "model/emoticonmodel.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 "model/discussionsmodel.h" #include "model/threadsmodel.h" +#include "model/filesforroomfilterproxymodel.h" #include "managerdatapaths.h" #include "authenticationmanager.h" #include "ddpapi/ddpclient.h" #include "discussions.h" #include "receivetypingnotificationmanager.h" #include "restapirequest.h" #include "serverconfiginfo.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()); mEmoticonModel->setEmoticons(mEmojiManager->unicodeEmojiList()); 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); + mFilesModelForRoom = new FilesForRoomModel(this, this); + mFilesModelForRoom->setObjectName(QStringLiteral("filesmodelforrooms")); + mFilesForRoomFilterProxyModel = new FilesForRoomFilterProxyModel(this); + mFilesForRoomFilterProxyModel->setObjectName(QStringLiteral("filesforroomfiltermodelproxy")); + mFilesForRoomFilterProxyModel->setSourceModel(mFilesModelForRoom); + + mStatusModel = new StatusModel(this); mRoomModel = new RoomModel(this, 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, this); //TODO fix mem leak ! 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 +FilesForRoomFilterProxyModel *RocketChatAccount::filesForRoomFilterProxyModel() const { - return mRoomModel->filesForRoomFilterProxyModel(roomId); + return mFilesForRoomFilterProxyModel; } 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); } DiscussionsFilterProxyModel *RocketChatAccount::discussionsFilterProxyModel(const QString &roomId) const { return mRoomModel->discussionsModelForRoomProxyModel(roomId); } ThreadsFilterProxyModel *RocketChatAccount::threadsFilterProxyModel(const QString &roomId) const { return mRoomModel->threadsModelForRoomProxyModel(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) { restApi()->postMessage(roomID, message); } void RocketChatAccount::updateMessage(const QString &roomID, const QString &messageId, const QString &message) { restApi()->updateMessage(roomID, messageId, message); } 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); connect(mRestApi, &RocketChatRestApi::RestApiRequest::setChannelJoinDone, this, &RocketChatAccount::setChannelJoinDone); connect(mRestApi, &RocketChatRestApi::RestApiRequest::missingChannelPassword, this, &RocketChatAccount::missingChannelPassword); connect(mRestApi, &RocketChatRestApi::RestApiRequest::loadEmojiCustomDone, this, &RocketChatAccount::loadEmojiRestApi); connect(mRestApi, &RocketChatRestApi::RestApiRequest::openArchivedRoom, this, &RocketChatAccount::openArchivedRoom); connect(mRestApi, &RocketChatRestApi::RestApiRequest::channelMembersDone, this, &RocketChatAccount::parseUsersForRooms); connect(mRestApi, &RocketChatRestApi::RestApiRequest::channelFilesDone, this, &RocketChatAccount::slotChannelFilesDone); connect(mRestApi, &RocketChatRestApi::RestApiRequest::channelRolesDone, this, &RocketChatAccount::slotChannelRolesDone); connect(mRestApi, &RocketChatRestApi::RestApiRequest::searchMessageDone, this, &RocketChatAccount::slotSearchMessages); connect(mRestApi, &RocketChatRestApi::RestApiRequest::failed, this, &RocketChatAccount::jobFailed); connect(mRestApi, &RocketChatRestApi::RestApiRequest::spotlightDone, this, &RocketChatAccount::slotSplotLightDone); connect(mRestApi, &RocketChatRestApi::RestApiRequest::getThreadMessagesDone, this, &RocketChatAccount::slotGetThreadMessagesDone); connect(mRestApi, &RocketChatRestApi::RestApiRequest::getThreadsDone, this, &RocketChatAccount::slotGetThreadsListDone); connect(mRestApi, &RocketChatRestApi::RestApiRequest::getDiscussionsDone, this, &RocketChatAccount::slotGetDiscussionsListDone); connect(mRestApi, &RocketChatRestApi::RestApiRequest::channelGetAllUserMentionsDone, this, &RocketChatAccount::slotGetAllUserMentionsDone); mRestApi->setServerUrl(mSettings->serverUrl()); mRestApi->setRestApiLogger(mRuqolaLogger); } return mRestApi; } void RocketChatAccount::leaveRoom(const QString &roomId, const QString &channelType) { 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; } } void RocketChatAccount::hideRoom(const QString &roomId, const QString &channelType) { restApi()->closeChannel(roomId, channelType); } 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); if (mSettings) { mDdp->setServerUrl(mSettings->serverUrl()); } mDdp->start(); } return mDdp; } bool RocketChatAccount::editingMode() const { return mEditingMode; } 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) { restApi()->markAsRead(roomId); } void RocketChatAccount::changeFavorite(const QString &roomId, bool checked) { if (mRuqolaServerConfig->hasAtLeastVersion(0, 64, 0)) { restApi()->markAsFavorite(roomId, checked); } else { ddp()->toggleFavorite(roomId, checked); } } void RocketChatAccount::openChannel(const QString &url) { //qCDebug(RUQOLA_LOG) << " void RocketChatAccount::openChannel(const QString &url)"<channelJoin(url, QString()); //TODO search correct room + select it. } void RocketChatAccount::setChannelJoinDone(const QString &roomId) { ddp()->subscribeRoomMessage(roomId); } void RocketChatAccount::openArchivedRoom(const QString &roomId) { //TODO } 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) { if (channelType == QStringLiteral("c")) { restApi()->channelDelete(roomId); } else if (channelType == QStringLiteral("p")) { restApi()->groupDelete(roomId); } else { qCWarning(RUQOLA_LOG) << " unsupport delete for type " << channelType; } } void RocketChatAccount::openDirectChannel(const QString &username) { //TODO verify username vs userId #ifdef USE_REASTAPI_JOB restApi()->openDirectMessage(username); #else ddp()->openDirectChannel(username); #endif } void RocketChatAccount::createNewChannel(const QString &name, bool readOnly, bool privateRoom, const QString &userNames, bool encryptedRoom, const QString &password, bool broadcast) { //TODO use encryted room //TODO use broadcast if (!name.trimmed().isEmpty()) { const QStringList lstUsers = userNames.split(QLatin1Char(','), QString::SkipEmptyParts); if (privateRoom) { //TODO add password ??? restApi()->createGroups(name, readOnly, lstUsers); } else { restApi()->createChannels(name, readOnly, lstUsers, password); } } else { qCDebug(RUQOLA_LOG) << "Channel name can't be empty"; } } void RocketChatAccount::joinRoom(const QString &roomId, const QString &joinCode) { restApi()->channelJoin(roomId, joinCode); } void RocketChatAccount::channelAndPrivateAutocomplete(const QString &pattern) { //TODO use restapi if (pattern.isEmpty()) { searchChannelModel()->clear(); } else { //Use restapi //Avoid to show own user #ifdef USE_REASTAPI_JOB restApi()->searchRoomUser(pattern); #else const QString addUserNameToException = userName(); ddp()->channelAndPrivateAutocomplete(pattern, addUserNameToException); #endif } } void RocketChatAccount::listEmojiCustom() { if (mRuqolaServerConfig->hasAtLeastVersion(0, 63, 0)) { restApi()->listEmojiCustom(); } else { ddp()->listEmojiCustom(); } } void RocketChatAccount::setDefaultStatus(User::PresenceStatus status) { //Not implemented yet //TODO use restapi if (statusModel()->currentUserStatus() != status) { ddp()->setDefaultStatus(status); } } void RocketChatAccount::changeDefaultStatus(int index) { setDefaultStatus(mStatusModel->status(index)); } void RocketChatAccount::loadEmojiRestApi(const QJsonObject &obj) { mEmojiManager->loadCustomEmoji(obj, true); } void RocketChatAccount::loadEmoji(const QJsonObject &obj) { mEmojiManager->loadCustomEmoji(obj, false); } void RocketChatAccount::deleteMessage(const QString &messageId, const QString &roomId) { restApi()->deleteMessage(roomId, messageId); } -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::membersInRoom(const QString &roomId, const QString &roomType) { restApi()->membersInRoom(roomId, roomType); } void RocketChatAccount::parseUsersForRooms(const QJsonObject &obj, const QString &roomId) { UsersForRoomModel *usersModelForRoom = roomModel()->usersModelForRoom(roomId); if (usersModelForRoom) { usersModelForRoom->parseUsersForRooms(obj, mUserModel, true); } else { qCWarning(RUQOLA_LOG) << " Impossible to find room " << roomId; } } void RocketChatAccount::loadAutoCompleteChannel(const QJsonObject &obj) { mSearchChannelModel->parseChannels(obj); } void RocketChatAccount::roomFiles(const QString &roomId, const QString &channelType) { restApi()->filesInRoom(roomId, channelType); } QVector RocketChatAccount::parseFilesInChannel(const QJsonObject &obj) { //TODO add autotests QVector files; const QJsonArray filesArray = obj.value(QLatin1String("files")).toArray(); files.reserve(filesArray.count()); 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; } EmoticonModel *RocketChatAccount::emoticonModel() const { return mEmoticonModel; } void RocketChatAccount::setEmoticonModel(EmoticonModel *emoticonModel) { mEmoticonModel = emoticonModel; } ReceiveTypingNotificationManager *RocketChatAccount::receiveTypingNotificationManager() const { return mReceiveTypingNotificationManager; } void RocketChatAccount::slotChannelRolesDone(const QJsonObject &obj, const QString &roomId) { Room *room = mRoomModel->findRoom(roomId); if (room) { Roles r; r.parseRole(obj); room->setRolesForRooms(r); } else { qCWarning(RUQOLA_LOG) << " Impossible to find room " << roomId; } } void RocketChatAccount::slotGetThreadMessagesDone(const QJsonObject &obj, const QString &threadMessageId) { } void RocketChatAccount::slotGetDiscussionsListDone(const QJsonObject &obj, const QString &roomId) { Room *room = mRoomModel->findRoom(roomId); if (room) { Discussions discussions; discussions.parseDiscussions(obj); room->discussionsModelForRoom()->setDiscussions(discussions); } else { qCWarning(RUQOLA_LOG) << " Impossible to find room " << roomId; } } void RocketChatAccount::slotGetAllUserMentionsDone(const QJsonObject &obj, const QString &roomId) { //TODO parse mentions } void RocketChatAccount::slotGetThreadsListDone(const QJsonObject &obj, const QString &roomId) { Room *room = mRoomModel->findRoom(roomId); if (room) { Threads threads; threads.parseThreads(obj); room->threadsModelForRoom()->setThreads(threads); } else { qCWarning(RUQOLA_LOG) << " Impossible to find room " << roomId; } } void RocketChatAccount::slotSplotLightDone(const QJsonObject &obj) { qDebug() << " void RocketChatAccount::slotSplotLightDone(const QJsonObject &obj)"< files = parseFilesInChannel(obj); - FilesForRoomModel *filesForRoomModel = roomModel()->filesModelForRoom(roomId); - if (filesForRoomModel) { - filesForRoomModel->setFiles(files); - } else { - qCWarning(RUQOLA_LOG) << " Impossible to find room " << roomId; - } + mFilesModelForRoom->setFiles(files); } void RocketChatAccount::createJitsiConfCall(const QString &roomId) { //TODO use restapi ddp()->createJitsiConfCall(roomId); joinJitsiConfCall(roomId); } void RocketChatAccount::addUserToRoom(const QString &userId, const QString &roomId, const QString &channelType) { if (channelType == QStringLiteral("c")) { restApi()->addUserInChannel(roomId, userId); } else if (channelType == QStringLiteral("p")) { restApi()->addUserInGroup(roomId, userId); } } void RocketChatAccount::clearSearchModel() { mSearchMessageModel->clear(); } void RocketChatAccount::messageSearch(const QString &pattern, const QString &rid) { if (pattern.isEmpty()) { clearSearchModel(); } else { restApi()->searchMessages(rid, pattern); } } void RocketChatAccount::slotSearchMessages(const QJsonObject &obj) { mSearchMessageModel->parseResult(obj, true); } void RocketChatAccount::starMessage(const QString &messageId, bool starred) { restApi()->starMessage(messageId, starred); } void RocketChatAccount::pinMessage(const QString &messageId, bool pinned) { restApi()->pinMessage(messageId, pinned); } 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: if (channelType == QStringLiteral("c")) { restApi()->changeChannelAnnouncement(roomId, newValue.toString()); } else if (channelType == QStringLiteral("p")) { //FOR the moment we can't change group announcement with restapi if (mRuqolaServerConfig->hasAtLeastVersion(0, 70, 0)) { restApi()->changeGroupsAnnouncement(roomId, newValue.toString()); } else { ddp()->setRoomAnnouncement(roomId, newValue.toString()); } } else { qCWarning(RUQOLA_LOG) << " unsupport change announcement for type " << channelType; } break; case Description: 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; } break; case Name: if (channelType == QStringLiteral("c")) { restApi()->changeChannelName(roomId, newValue.toString()); } else if (channelType == QStringLiteral("p")) { restApi()->changeGroupName(roomId, newValue.toString()); } else { qCWarning(RUQOLA_LOG) << " unsupport change name for type " << channelType; } break; case Topic: if (channelType == QStringLiteral("c")) { restApi()->changeChannelTopic(roomId, newValue.toString()); } else if (channelType == QStringLiteral("p")) { restApi()->changeGroupsTopic(roomId, newValue.toString()); } else { //TODO : change topic in direct channel qCWarning(RUQOLA_LOG) << " unsupport change topic for type " << channelType; } break; case ReadOnly: if (channelType == QStringLiteral("c")) { restApi()->changeChannelReadOnly(roomId, newValue.toBool()); } else if (channelType == QStringLiteral("p")) { restApi()->changeGroupsReadOnly(roomId, newValue.toBool()); } else { qCWarning(RUQOLA_LOG) << " unsupport change readonly for type " << channelType; } break; case Archive: if (channelType == QStringLiteral("c")) { restApi()->archiveChannel(roomId); } else if (channelType == QStringLiteral("p")) { restApi()->archiveGroups(roomId); } else { qCWarning(RUQOLA_LOG) << " unsupport archiving for type " << channelType; } break; case RoomType: if (channelType == QStringLiteral("c")) { restApi()->setChannelType(roomId, channelType); } else if (channelType == QStringLiteral("p")) { restApi()->setGroupType(roomId, channelType); } else { qCWarning(RUQOLA_LOG) << " unsupport roomtype for type " << channelType; } break; case Encrypted: if (channelType == QStringLiteral("c")) { restApi()->changeChannelEncrypted(roomId, newValue.toBool()); } else if (channelType == QStringLiteral("p")) { restApi()->changeGroupsEncrypted(roomId, newValue.toBool()); } else { qCWarning(RUQOLA_LOG) << " unsupport encrypted mode for type " << channelType; } break; } } void RocketChatAccount::reportMessage(const QString &messageId, const QString &message) { if (mRuqolaServerConfig->hasAtLeastVersion(0, 64, 0)) { restApi()->reportMessage(messageId, message); } else { qCWarning(RUQOLA_LOG) << " RocketChatAccount::reportMessage is not supported before server 0.64"; } } void RocketChatAccount::getThreadMessages(const QString &threadMessageId) { if (mRuqolaServerConfig->hasAtLeastVersion(1, 0, 0)) { restApi()->getThreadMessages(threadMessageId); } else { qCWarning(RUQOLA_LOG) << " RocketChatAccount::getThreadMessages is not supported before server 1.0.0"; } } void RocketChatAccount::changeNotificationsSettings(const QString &roomId, RocketChatAccount::NotificationOptionsType notificationsType, const QVariant &newValue) { 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; case MuteGroupMentions: restApi()->muteGroupMentions(roomId, newValue.toBool()); break; case DesktopDurationNotifications: restApi()->desktopDurationNotifications(roomId, newValue.toInt()); break; case DesktopSoundNotifications: restApi()->desktopSoundNotifications(roomId, newValue.toString()); break; } } 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_Enabled")) { mRuqolaServerConfig->setJitsiEnabled(value.toBool()); } 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 if (id == QLatin1String("E2E_Enable")) { mRuqolaServerConfig->setEncryptionEnabled(value.toBool()); } else if (id == QLatin1String("Message_AllowPinning")) { mRuqolaServerConfig->setAllowMessagePinningEnabled(value.toBool()); } else if (id == QLatin1String("Message_AllowSnippeting")) { mRuqolaServerConfig->setAllowMessageSnippetingEnabled(value.toBool()); } else if (id == QLatin1String("Message_AllowStarring")) { mRuqolaServerConfig->setAllowMessageStarringEnabled(value.toBool()); } else if (id == QLatin1String("Message_AllowDeleting")) { mRuqolaServerConfig->setAllowMessageDeletingEnabled(value.toBool()); } else if (id == QLatin1String("Threads_enabled")) { mRuqolaServerConfig->setThreadsEnabled(value.toBool()); } else if (id == QLatin1String("Discussion_enabled")) { mRuqolaServerConfig->setDiscussionEnabled(value.toBool()); } 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::encryptedEnabled() const { return mRuqolaServerConfig->encryptionEnabled(); } bool RocketChatAccount::allowMessagePinningEnabled() const { return mRuqolaServerConfig->allowMessagePinningEnabled(); } bool RocketChatAccount::allowMessageSnippetingEnabled() const { return mRuqolaServerConfig->allowMessageSnippetingEnabled(); } bool RocketChatAccount::allowMessageStarringEnabled() const { return mRuqolaServerConfig->allowMessageStarringEnabled(); } bool RocketChatAccount::allowMessageDeletingEnabled() const { return mRuqolaServerConfig->allowMessageDeletingEnabled(); } bool RocketChatAccount::threadsEnabled() const { return mRuqolaServerConfig->threadsEnabled(); } bool RocketChatAccount::discussionEnabled() const { return mRuqolaServerConfig->discussionEnabled(); } QString RocketChatAccount::serverVersionStr() const { return mRuqolaServerConfig->serverVersionStr(); } ServerConfigInfo *RocketChatAccount::serverConfigInfo() const { return mServerConfigInfo; } bool RocketChatAccount::jitsiEnabled() const { return mRuqolaServerConfig->jitsiEnabled(); } void RocketChatAccount::groupInfo(const QString &roomId) { restApi()->groupInfo(roomId); } void RocketChatAccount::switchEditingMode(bool b) { if (mEditingMode != b) { mEditingMode = b; Q_EMIT editingModeChanged(); } } void RocketChatAccount::kickUser(const QString &roomId, const QString &userId, const QString &channelType) { if (channelType == QStringLiteral("c")) { restApi()->channelKick(roomId, userId); } else if (channelType == QStringLiteral("p")) { restApi()->groupKick(roomId, userId); } else { qCWarning(RUQOLA_LOG) << " unsupport kickUser room for type " << channelType; } } void RocketChatAccount::rolesInRoom(const QString &roomId, const QString &channelType) { if (channelType == QStringLiteral("c")) { restApi()->getChannelRoles(roomId); } else if (channelType == QStringLiteral("p")) { restApi()->getGroupRoles(roomId); } else { qCWarning(RUQOLA_LOG) << " unsupport get roles room for type " << channelType; } } void RocketChatAccount::switchingToRoom(const QString &roomID) { clearTypingNotification(); checkInitializedRoom(roomID); } void RocketChatAccount::changeRoles(const QString &roomId, const QString &userId, const QString &channelType, RocketChatAccount::RoleType roleType) { if (channelType == QStringLiteral("c")) { switch (roleType) { case RocketChatAccount::AddOwner: restApi()->channelAddOwner(roomId, userId); break; case RocketChatAccount::AddLeader: if (mRuqolaServerConfig->hasAtLeastVersion(0, 75, 0)) { restApi()->channelAddLeader(roomId, userId); } else { qCWarning(RUQOLA_LOG) << " RocketChatAccount::AddLeader is not supported before server 0.75"; } break; case RocketChatAccount::AddModerator: restApi()->channelAddModerator(roomId, userId); break; case RocketChatAccount::RemoveOwner: restApi()->channelRemoveOwner(roomId, userId); break; case RocketChatAccount::RemoveLeader: if (mRuqolaServerConfig->hasAtLeastVersion(0, 75, 0)) { restApi()->channelRemoveLeader(roomId, userId); } else { qCWarning(RUQOLA_LOG) << " RocketChatAccount::RemoveLeader is not supported before server 0.75"; } break; case RocketChatAccount::RemoveModerator: restApi()->channelRemoveModerator(roomId, userId); break; } } else if (channelType == QStringLiteral("p")) { switch (roleType) { case RocketChatAccount::AddOwner: restApi()->groupAddOwner(roomId, userId); break; case RocketChatAccount::AddLeader: restApi()->groupAddLeader(roomId, userId); break; case RocketChatAccount::AddModerator: restApi()->groupAddModerator(roomId, userId); break; case RocketChatAccount::RemoveOwner: restApi()->groupRemoveOwner(roomId, userId); break; case RocketChatAccount::RemoveLeader: restApi()->groupRemoveLeader(roomId, userId); break; case RocketChatAccount::RemoveModerator: restApi()->groupRemoveModerator(roomId, userId); break; } } else { qCWarning(RUQOLA_LOG) << " unsupport changeRoles room for type " << channelType; } } void RocketChatAccount::channelInfo(const QString &roomId) { restApi()->channelInfo(roomId); } 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) { restApi()->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::clearTypingNotification() { mReceiveTypingNotificationManager->clearTypingNotification(); } void RocketChatAccount::checkInitializedRoom(const QString &roomId) { Room *r = mRoomModel->findRoom(roomId); if (r && !r->wasInitialized()) { r->setWasInitialized(true); ddp()->subscribeRoomMessage(roomId); if (!r->archived()) { membersInRoom(r->roomId(), r->channelType()); rolesInRoom(r->roomId(), r->channelType()); } loadHistory(r->roomId(), QString(), true /*initial loading*/); } } void RocketChatAccount::openDocumentation() { QDesktopServices::openUrl(QUrl(QStringLiteral("help:/"))); } void RocketChatAccount::channelGetAllUserMentions(const QString &roomId) { restApi()->channelGetAllUserMentions(roomId); } void RocketChatAccount::rolesChanged(const QJsonArray &contents) { for (int i = 0; i < contents.count(); ++i) { const QJsonObject obj = contents.at(i).toObject(); const QString scope = obj[QLatin1String("scope")].toString(); Room *room = mRoomModel->findRoom(scope); if (room) { room->updateRoles(obj); } } } void RocketChatAccount::createDiscussion(const QString &parentRoomId, const QString &discussionName, const QString &replyMessage, const QString &messageId) { restApi()->createDiscussion(parentRoomId, discussionName, replyMessage, messageId); } void RocketChatAccount::threadsInRoom(const QString &roomId) { if (mRuqolaServerConfig->hasAtLeastVersion(1, 0, 0)) { restApi()->getThreadsList(roomId); } else { qCWarning(RUQOLA_LOG) << " RocketChatAccount::threadsInRoom is not supported before server 1.0.0"; } } void RocketChatAccount::discussionsInRoom(const QString &roomId) { if (mRuqolaServerConfig->hasAtLeastVersion(1, 0, 0)) { restApi()->getDiscussions(roomId); } else { qCWarning(RUQOLA_LOG) << " RocketChatAccount::discussionsInRoom is not supported before server 1.0.0"; } } diff --git a/src/ruqolacore/rocketchataccount.h b/src/ruqolacore/rocketchataccount.h index c2dca758..35f841ad 100644 --- a/src/ruqolacore/rocketchataccount.h +++ b/src/ruqolacore/rocketchataccount.h @@ -1,390 +1,392 @@ /* Copyright (c) 2017-2019 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 #include "rocketchataccountsettings.h" #include "libruqola_private_export.h" #include "authenticationinfo.h" #include "file.h" class TypingNotification; class UsersModel; class RoomModel; class RoomWrapper; class MessageModel; class DDPClient; class MessageQueue; class RocketChatBackend; class RoomFilterProxyModel; class RuqolaLogger; class RuqolaServerConfig; class UserCompleterModel; class UserCompleterFilterProxyModel; class StatusModel; class RocketChatCache; class EmojiManager; class OtrManager; class UsersForRoomFilterProxyModel; class UsersForRoomModel; class FilesForRoomFilterProxyModel; class SearchChannelModel; class SearchChannelFilterProxyModel; class LoginMethodModel; class InputCompleterModel; class InputTextManager; class PluginAuthenticationInterface; class Room; class SearchMessageModel; class SearchMessageFilterProxyModel; class DiscussionsFilterProxyModel; class ThreadsFilterProxyModel; class ServerConfigInfo; class ReceiveTypingNotificationManager; class EmoticonModel; +class FilesForRoomModel; namespace RocketChatRestApi { class RestApiRequest; } class LIBRUQOLACORE_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 READ password WRITE setPassword NOTIFY passwordChanged) Q_PROPERTY(DDPClient::LoginStatus loginStatus READ loginStatus NOTIFY loginStatusChanged) Q_PROPERTY(bool editingMode READ editingMode NOTIFY editingModeChanged) public: explicit RocketChatAccount(const QString &accountName = QString(), QObject *parent = nullptr); ~RocketChatAccount(); enum RoomInfoType { Announcement, Description, Name, Topic, ReadOnly, Archive, RoomType, Encrypted, }; Q_ENUM(RoomInfoType) enum NotificationOptionsType { DisableNotifications, HideUnreadStatus, AudioNotifications, DesktopNotifications, DesktopDurationNotifications, DesktopSoundNotifications, EmailNotifications, MobilePushNotifications, UnreadAlert, MuteGroupMentions }; Q_ENUM(NotificationOptionsType) enum RoleType { AddOwner, AddLeader, AddModerator, RemoveOwner, RemoveLeader, RemoveModerator }; Q_ENUM(RoleType) Q_INVOKABLE UsersModel *usersModel() const; Q_INVOKABLE RoomModel *roomModel() const; Q_INVOKABLE RoomFilterProxyModel *roomFilterProxyModel() const; Q_INVOKABLE UsersForRoomFilterProxyModel *usersForRoomFilterProxyModel(const QString &roomId) const; Q_INVOKABLE RoomWrapper *getRoomWrapper(const QString &roomId); Q_INVOKABLE MessageModel *messageModelForRoom(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, const QString &channelType); Q_INVOKABLE void hideRoom(const QString &roomId, const QString &channelType = QString()); Q_INVOKABLE void tryLogin(); Q_INVOKABLE void logOut(); Q_INVOKABLE void clearUnreadMessages(const QString &roomId); Q_INVOKABLE void changeFavorite(const QString &roomId, bool checked); Q_INVOKABLE void sendMessage(const QString &roomID, const QString &message); Q_INVOKABLE void updateMessage(const QString &roomID, const QString &messageId, const QString &message); 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, bool encryptedRoom, const QString &password, bool broadcast); 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, const QString &roomId); Q_INVOKABLE void userAutocomplete(const QString &searchText, const QString &exception); Q_INVOKABLE void eraseRoom(const QString &roomId, const QString &channelType); Q_INVOKABLE void changeChannelSettings(const QString &roomId, RocketChatAccount::RoomInfoType infoType, const QVariant &newValue, const QString &channelType = QString()); Q_INVOKABLE void changeNotificationsSettings(const QString &roomId, RocketChatAccount::NotificationOptionsType notificationsType, 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, bool starred); Q_INVOKABLE void pinMessage(const QString &messageId, bool pinned); Q_INVOKABLE void uploadFile(const QString &roomId, const QString &description, const QString &messageText, const QUrl &fileUrl); Q_INVOKABLE QString serverUrl() const; Q_INVOKABLE QString avatarUrl(const QString &userId); Q_INVOKABLE StatusModel *statusModel() const; Q_INVOKABLE Q_REQUIRED_RESULT QUrl attachmentUrl(const QString &url); Q_INVOKABLE void loadHistory(const QString &roomID, const QString &channelType = QString(), bool initial = false); Q_INVOKABLE Q_REQUIRED_RESULT bool allowEditingMessages() const; Q_INVOKABLE Q_REQUIRED_RESULT bool otrEnabled() const; Q_INVOKABLE void channelAndPrivateAutocomplete(const QString &pattern); Q_INVOKABLE UserCompleterFilterProxyModel *userCompleterFilterModelProxy() const; Q_INVOKABLE void roomFiles(const QString &roomId, const QString &channelType = QString()); - Q_INVOKABLE FilesForRoomFilterProxyModel *filesForRoomFilterProxyModel(const QString &roomId) const; + Q_INVOKABLE FilesForRoomFilterProxyModel *filesForRoomFilterProxyModel() const; Q_INVOKABLE void addUserToRoom(const QString &username, const QString &roomId, const QString &channelType); Q_INVOKABLE SearchChannelFilterProxyModel *searchChannelFilterProxyModel() const; Q_INVOKABLE InputCompleterModel *inputCompleterModel() const; Q_INVOKABLE LoginMethodModel *loginMethodModel() const; Q_INVOKABLE Room *getRoom(const QString &roomId); Q_INVOKABLE DiscussionsFilterProxyModel *discussionsFilterProxyModel(const QString &roomId) const; Q_INVOKABLE ThreadsFilterProxyModel *threadsFilterProxyModel(const QString &roomId) const; Q_INVOKABLE void changeDefaultAuthentication(int index); Q_INVOKABLE void messageSearch(const QString &pattern, const QString &rid); Q_INVOKABLE SearchMessageFilterProxyModel *searchMessageFilterProxyModel() const; Q_INVOKABLE void setInputTextChanged(const QString &str, int position); Q_INVOKABLE QString replaceWord(const QString &newWord, const QString &str, int position); Q_INVOKABLE void blockUser(const QString &userId, bool block); Q_INVOKABLE QString avatarUrlFromDirectChannel(const QString &rid); Q_INVOKABLE void deleteFileMessage(const QString &roomId, const QString &fileId, const QString &channelType); Q_INVOKABLE void openDocumentation(); Q_INVOKABLE void clearSearchModel(); Q_INVOKABLE void reactOnMessage(const QString &messageId, const QString &emoji, bool shouldReact); Q_INVOKABLE void ignoreUser(const QString &rid, const QString &userId, bool ignore); Q_INVOKABLE ReceiveTypingNotificationManager *receiveTypingNotificationManager() const; Q_INVOKABLE Q_REQUIRED_RESULT bool encryptedEnabled() const; Q_INVOKABLE Q_REQUIRED_RESULT QString serverVersionStr() const; Q_INVOKABLE Q_REQUIRED_RESULT ServerConfigInfo *serverConfigInfo() const; Q_INVOKABLE Q_REQUIRED_RESULT bool jitsiEnabled() const; Q_INVOKABLE Q_REQUIRED_RESULT bool allowMessagePinningEnabled() const; Q_INVOKABLE Q_REQUIRED_RESULT bool allowMessageSnippetingEnabled() const; Q_INVOKABLE Q_REQUIRED_RESULT bool allowMessageStarringEnabled() const; Q_INVOKABLE Q_REQUIRED_RESULT bool allowMessageDeletingEnabled() const; Q_INVOKABLE void channelInfo(const QString &roomId); Q_INVOKABLE void groupInfo(const QString &roomId); Q_INVOKABLE void channelGetAllUserMentions(const QString &roomId); Q_INVOKABLE void switchEditingMode(bool b); Q_INVOKABLE void kickUser(const QString &rid, const QString &userId, const QString &channelType); Q_INVOKABLE void changeRoles(const QString &rid, const QString &userId, const QString &channelType, RocketChatAccount::RoleType roleType); Q_INVOKABLE void rolesInRoom(const QString &roomId, const QString &channelType); Q_INVOKABLE void switchingToRoom(const QString &roomID); Q_INVOKABLE void reportMessage(const QString &messageId, const QString &message); Q_INVOKABLE void getThreadMessages(const QString &threadMessageId); Q_INVOKABLE void createDiscussion(const QString &parentRoomName, const QString &discussionName, const QString &replyMessage, const QString &messageId); Q_INVOKABLE Q_REQUIRED_RESULT bool threadsEnabled() const; Q_INVOKABLE Q_REQUIRED_RESULT bool discussionEnabled() const; Q_INVOKABLE void threadsInRoom(const QString &roomId); Q_INVOKABLE void discussionsInRoom(const QString &roomId); SearchChannelModel *searchChannelModel() const; UserCompleterModel *userCompleterModel() const; RocketChatAccountSettings *settings() const; DDPClient *ddp(); bool editingMode() const; DDPClient::LoginStatus loginStatus(); RocketChatRestApi::RestApiRequest *restApi(); //Make it private in future void slotInformTypingStatus(const QString &room, bool typing); MessageQueue *messageQueue() const; RocketChatBackend *rocketChatBackend() const; RuqolaLogger *ruqolaLogger() const; void loadEmoji(const QJsonObject &obj); void parsePublicSettings(const QJsonObject &obj); RuqolaServerConfig *ruqolaServerConfig() const; void setUserName(const QString &username); Q_REQUIRED_RESULT QString userName() const; void setAccountName(const QString &servername); Q_REQUIRED_RESULT QString accountName() const; void setUserID(const QString &userID); Q_REQUIRED_RESULT QString userID() const; void setPassword(const QString &password); Q_REQUIRED_RESULT QString password() const; void setAuthToken(const QString &token); Q_REQUIRED_RESULT QString authToken() const; void setServerUrl(const QString &serverUrl); void sendNotification(const QJsonArray &contents); void parseOtr(const QJsonArray &contents); void setServerVersion(const QString &version); Q_REQUIRED_RESULT bool needAdaptNewSubscriptionRC60() const; EmojiManager *emojiManager() const; Q_REQUIRED_RESULT QString userStatusIconFileName(const QString &id); void membersInRoom(const QString &roomId, const QString &roomType); void parseUsersForRooms(const QJsonObject &obj, const QString &roomId); void loadAutoCompleteChannel(const QJsonObject &obj); void insertCompleterUsers(); - void insertFilesList(const QString &roomId); void inputChannelAutocomplete(const QString &pattern, const QString &exceptions); void inputUserAutocomplete(const QString &pattern, const QString &exceptions); void inputTextCompleter(const QJsonObject &obj); PluginAuthenticationInterface *defaultAuthenticationInterface() const; SearchMessageModel *searchMessageModel() const; void displaySearchedMessage(const QJsonObject &obj); void updateUser(const QJsonObject &object); void removeSettings(); void rolesChanged(const QJsonArray &contents); Q_INVOKABLE EmoticonModel *emoticonModel() const; void setEmoticonModel(EmoticonModel *emoticonModel); Q_SIGNALS: void connectedChanged(); void accountNameChanged(); void userNameChanged(); void userIDChanged(); void passwordChanged(); void serverUrlChanged(); void loginStatusChanged(); void logoutDone(const QString &accountname); void added(const QJsonObject &item); void changed(const QJsonObject &item); void removed(const QJsonObject &item); void notification(const QString &title, const QString &message, const QPixmap &pixmap); void fileDownloaded(const QString &filePath, const QUrl &cacheImageUrl); void updateNotification(bool hasAlert, int nbUnread, const QString &accountName); void missingChannelPassword(const QString &roomId); void editingModeChanged(); void jobFailed(const QString &message); private: Q_DISABLE_COPY(RocketChatAccount) void slotChannelFilesDone(const QJsonObject &obj, const QString &roomId); void slotChannelRolesDone(const QJsonObject &obj, const QString &roomId); void slotSplotLightDone(const QJsonObject &obj); void slotGetThreadMessagesDone(const QJsonObject &obj, const QString &threadMessageId); void slotGetThreadsListDone(const QJsonObject &obj, const QString &roomId); void slotGetDiscussionsListDone(const QJsonObject &obj, const QString &roomId); void slotGetAllUserMentionsDone(const QJsonObject &obj, const QString &roomId); void loadEmojiRestApi(const QJsonObject &obj); void slotSearchMessages(const QJsonObject &obj); void slotNeedToUpdateNotification(); void insertAvatarUrl(const QString &userId, const QString &url); void loadSettings(const QString &accountFileName); void clearModels(); void fillOauthModel(); void initializeAuthenticationPlugins(); void setDefaultAuthentication(AuthenticationManager::OauthType type); void userStatusChanged(const User &user); void setChannelJoinDone(const QString &roomId); void openArchivedRoom(const QString &roomId); void checkInitializedRoom(const QString &roomId); void clearTypingNotification(); QVector parseFilesInChannel(const QJsonObject &obj); PluginAuthenticationInterface *mDefaultAuthenticationInterface = nullptr; QHash mLstPluginAuthenticationInterface; QVector mLstInfos; RocketChatAccountSettings *mSettings = nullptr; EmojiManager *mEmojiManager = nullptr; TypingNotification *mTypingNotification = nullptr; UsersModel *mUserModel = nullptr; RoomModel *mRoomModel = nullptr; RoomFilterProxyModel *mRoomFilterProxyModel = nullptr; DDPClient *mDdp = nullptr; RocketChatRestApi::RestApiRequest *mRestApi = nullptr; MessageQueue *mMessageQueue = nullptr; RocketChatBackend *mRocketChatBackend = nullptr; RuqolaLogger *mRuqolaLogger = nullptr; RuqolaServerConfig *mRuqolaServerConfig = nullptr; UserCompleterModel *mUserCompleterModel = nullptr; UserCompleterFilterProxyModel *mUserCompleterFilterModelProxy = nullptr; StatusModel *mStatusModel = nullptr; RocketChatCache *mCache = nullptr; OtrManager *mOtrManager = nullptr; SearchChannelModel *mSearchChannelModel = nullptr; SearchChannelFilterProxyModel *mSearchChannelFilterProxyModel = nullptr; LoginMethodModel *mLoginMethodModel = nullptr; InputTextManager *mInputTextManager = nullptr; SearchMessageModel *mSearchMessageModel = nullptr; SearchMessageFilterProxyModel *mSearchMessageFilterProxyModel = nullptr; ReceiveTypingNotificationManager *mReceiveTypingNotificationManager = nullptr; ServerConfigInfo *mServerConfigInfo = nullptr; + FilesForRoomModel *mFilesModelForRoom = nullptr; + FilesForRoomFilterProxyModel *mFilesForRoomFilterProxyModel = nullptr; EmoticonModel *mEmoticonModel = nullptr; bool mEditingMode = false; }; #endif // ROCKETCHATACCOUNT_H diff --git a/src/ruqolacore/room.cpp b/src/ruqolacore/room.cpp index 98ac350e..a8b523fd 100644 --- a/src/ruqolacore/room.cpp +++ b/src/ruqolacore/room.cpp @@ -1,1161 +1,1144 @@ /* * Copyright 2016 Riccardo Iaconelli * Copyright 2017-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 "notificationoptionswrapper.h" #include "room.h" #include "utils.h" #include "ruqola_debug.h" #include "model/usersforroommodel.h" #include "model/usersforroomfilterproxymodel.h" -#include "model/filesforroommodel.h" -#include "model/filesforroomfilterproxymodel.h" #include "model/messagemodel.h" #include "model/threadsmodel.h" #include "model/threadsfilterproxymodel.h" #include "model/discussionsmodel.h" #include "model/discussionsfilterproxymodel.h" #include #include #include Room::Room(RocketChatAccount *account, QObject *parent) : QObject(parent) , mRocketChatAccount(account) { mUsersModelForRoom = new UsersForRoomModel(this); mUsersModelForRoom->setObjectName(QStringLiteral("usersforroommodel")); mUsersModelForRoomProxyModel = new UsersForRoomFilterProxyModel(this); mUsersModelForRoomProxyModel->setObjectName(QStringLiteral("usersforroommodelproxymodel")); mUsersModelForRoomProxyModel->setSourceModel(mUsersModelForRoom); - mFilesModelForRoom = new FilesForRoomModel(mRocketChatAccount, this); - mFilesModelForRoom->setObjectName(QStringLiteral("filesmodelforrooms")); - mFilesForRoomFilterProxyModel = new FilesForRoomFilterProxyModel(this); - mFilesForRoomFilterProxyModel->setObjectName(QStringLiteral("filesforroomfiltermodelproxy")); - mFilesForRoomFilterProxyModel->setSourceModel(mFilesModelForRoom); - mMessageModel = new MessageModel(QString(), mRocketChatAccount, this, this); mThreadsModel = new ThreadsModel(this); mThreadsModel->setObjectName(QStringLiteral("threadsmodel")); mThreadsFilterProxyModel = new ThreadsFilterProxyModel(this); mThreadsFilterProxyModel->setObjectName(QStringLiteral("threadsfiltermodelproxy")); mThreadsFilterProxyModel->setSourceModel(mThreadsModel); mDiscussionsModel = new DiscussionsModel(this); mDiscussionsModel->setObjectName(QStringLiteral("discussionsmodel")); mDiscussionsFilterProxyModel = new DiscussionsFilterProxyModel(this); mDiscussionsFilterProxyModel->setObjectName(QStringLiteral("discussionsfilterproxymodel")); mDiscussionsFilterProxyModel->setSourceModel(mDiscussionsModel); //TODO necessary to define mChannelType } bool Room::operator==(const Room &other) const { //qDebug() << " other.id"< we need to clear it. setRoomCreatorUserId(QString()); setRoomCreatorUserName(QString()); } if (json.contains(QLatin1String("prid"))) { setParentRid(json[QStringLiteral("prid")].toString()); } } bool Room::selected() const { return mSelected; } void Room::setSelected(bool selected) { if (mSelected != selected) { mSelected = selected; //Add signal otherwise it's not necessary to check value } } int Room::unread() const { return mUnread; } void Room::setUnread(int unread) { if (mUnread != unread) { mUnread = unread; Q_EMIT unreadChanged(); } } qint64 Room::jitsiTimeout() const { return mJitsiTimeout; } void Room::setJitsiTimeout(const qint64 &jitsiTimeout) { if (mJitsiTimeout != jitsiTimeout) { mJitsiTimeout = jitsiTimeout; Q_EMIT jitsiTimeoutChanged(); } } QStringList Room::mutedUsers() const { return mMutedUsers; } void Room::setMutedUsers(const QStringList &mutedUsers) { if (mMutedUsers != mutedUsers) { mMutedUsers = mutedUsers; Q_EMIT mutedUsersChanged(); } } QString Room::roomCreatorUserId() const { return mRoomCreateUserId; } void Room::setRoomCreatorUserId(const QString &userId) { mRoomCreateUserId = userId; } QString Room::roomOwnerUserName() const { return mRoomCreatorUserName; } void Room::setRoomCreatorUserName(const QString &userName) { mRoomCreatorUserName = userName; } QString Room::roomId() const { return mRoomId; } void Room::setRoomId(const QString &id) { if (mRoomId != id) { mRoomId = id; mMessageModel->setRoomID(id); } } bool Room::alert() const { return mAlert; } void Room::setBlocker(bool block) { if (mBlocker != block) { mBlocker = block; Q_EMIT blockerChanged(); } } bool Room::blocker() const { return mBlocker; } void Room::setAlert(bool alert) { if (mAlert != alert) { mAlert = alert; Q_EMIT alertChanged(); } } bool Room::open() const { return mOpen; } void Room::setOpen(bool open) { if (mOpen != open) { mOpen = open; Q_EMIT openChanged(); } } bool Room::readOnly() const { return mReadOnly; } void Room::setReadOnly(bool readOnly) { if (mReadOnly != readOnly) { mReadOnly = readOnly; Q_EMIT readOnlyChanged(); } } QString Room::topic() const { return mTopic; } void Room::setTopic(const QString &topic) { if (mTopic != topic) { mTopic = topic; Q_EMIT topicChanged(); } } bool Room::favorite() const { return mFavorite; } void Room::setFavorite(bool favorite) { if (mFavorite != favorite) { mFavorite = favorite; Q_EMIT favoriteChanged(); } } QString Room::channelType() const { return mChannelType; } void Room::setChannelType(const QString &channelType) { if (mChannelType != channelType) { mChannelType = channelType; Q_EMIT channelTypeChanged(); } } QString Room::markdownAnnouncement() const { return Utils::markdownToRichText(mAnnouncement); } QString Room::announcement() const { return mAnnouncement; } void Room::setAnnouncement(const QString &announcement) { if (mAnnouncement != announcement) { mAnnouncement = announcement; Q_EMIT announcementChanged(); } } void Room::setName(const QString &name) { if (mName != name) { mName = name; Q_EMIT nameChanged(); } } void Room::parseInsertRoom(const QJsonObject &json) { QString roomID = json.value(QLatin1String("_id")).toString(); setRoomId(roomID); setName(json[QStringLiteral("name")].toString()); setFName(json[QStringLiteral("fname")].toString()); setJitsiTimeout(Utils::parseDate(QStringLiteral("jitsiTimeout"), json)); //topic/announcement/description is not part of update subscription const QString roomType = json.value(QLatin1String("t")).toString(); setChannelType(roomType); const QJsonValue favoriteValue = json.value(QLatin1String("f")); if (!favoriteValue.isUndefined()) { setFavorite(favoriteValue.toBool()); } setReadOnly(json[QStringLiteral("ro")].toBool()); if (json.contains(QLatin1String("userMentions"))) { setUserMentions(json[QStringLiteral("userMentions")].toInt()); } if (json.contains(QLatin1String("announcement"))) { setAnnouncement(json[QStringLiteral("announcement")].toString()); } if (json.contains(QLatin1String("description"))) { setDescription(json[QStringLiteral("description")].toString()); } setUpdatedAt(Utils::parseDate(QStringLiteral("_updatedAt"), json)); setUnread(json[QStringLiteral("unread")].toInt()); setOpen(json[QStringLiteral("open")].toBool()); setAlert(json[QStringLiteral("alert")].toBool()); const QJsonValue blockerValue = json.value(QLatin1String("blocker")); if (!blockerValue.isUndefined()) { setBlocker(blockerValue.toBool()); } else { setBlocker(false); } //setE2eKeyId(json[QStringLiteral("e2eKeyId")].toString()); setE2EKey(json[QStringLiteral("E2EKey")].toString()); if (json.contains(QLatin1String("encrypted"))) { setEncrypted(json[QStringLiteral("encrypted")].toBool()); } else { setEncrypted(false); } //Blocked ??? const QJsonValue archivedValue = json.value(QLatin1String("archived")); if (!archivedValue.isUndefined()) { setArchived(archivedValue.toBool()); } else { setArchived(false); } parseCommonData(json); const QJsonValue ownerValue = json.value(QLatin1String("u")); if (!ownerValue.isUndefined()) { const QJsonObject objOwner = ownerValue.toObject(); setRoomCreatorUserId(objOwner.value(QLatin1String("_id")).toString()); setRoomCreatorUserName(objOwner.value(QLatin1String("username")).toString()); } else { //When room is initialized we are the owner. When we update room we have the real //owner and if it's empty => we need to clear it. setRoomCreatorUserId(QString()); setRoomCreatorUserName(QString()); } //qDebug() << " *thus" << *this; mNotificationOptions.parseNotificationOptions(json); } qint64 Room::lastSeeAt() const { return mLastSeeAt; } void Room::setLastSeeAt(qint64 lastSeeAt) { mLastSeeAt = lastSeeAt; //Add signal otherwise it's not necessary to check value } bool Room::blocked() const { return mBlocked; } void Room::setBlocked(bool blocked) { if (mBlocked != blocked) { mBlocked = blocked; Q_EMIT blockedChanged(); } } QStringList Room::roles() const { return mRoles; } void Room::setRoles(const QStringList &roles) { if (mRoles != roles) { mRoles = roles; Q_EMIT rolesChanged(); } } QStringList Room::ignoredUsers() const { return mIgnoredUsers; } void Room::setIgnoredUsers(const QStringList &ignoredUsers) { if (mIgnoredUsers != ignoredUsers) { mIgnoredUsers = ignoredUsers; Q_EMIT ignoredUsersChanged(); } } void Room::parseSubscriptionRoom(const QJsonObject &json) { QString roomID = json.value(QLatin1String("rid")).toString(); if (roomID.isEmpty()) { roomID = json.value(QLatin1String("_id")).toString(); } setRoomId(roomID); setName(json[QStringLiteral("name")].toString()); setFName(json[QStringLiteral("fname")].toString()); setJitsiTimeout(Utils::parseDate(QStringLiteral("jitsiTimeout"), json)); //topic/announcement/description is not part of update subscription const QString roomType = json.value(QLatin1String("t")).toString(); setChannelType(roomType); const QJsonValue favoriteValue = json.value(QLatin1String("f")); if (!favoriteValue.isUndefined()) { setFavorite(favoriteValue.toBool()); } setE2EKey(json[QStringLiteral("E2EKey")].toString()); setReadOnly(json[QStringLiteral("ro")].toBool()); setUpdatedAt(Utils::parseDate(QStringLiteral("_updatedAt"), json)); setUnread(json[QStringLiteral("unread")].toInt()); setUserMentions(json[QStringLiteral("userMentions")].toInt()); setOpen(json[QStringLiteral("open")].toBool()); setAlert(json[QStringLiteral("alert")].toBool()); const QJsonValue blockerValue = json.value(QLatin1String("blocker")); if (!blockerValue.isUndefined()) { setBlocker(blockerValue.toBool()); } else { setBlocker(false); } //TODO e2ekey //TODO blocked ? const QJsonValue archivedValue = json.value(QLatin1String("archived")); if (!archivedValue.isUndefined()) { setArchived(archivedValue.toBool()); } else { setArchived(false); } parseCommonData(json); // const QJsonValue ownerValue = json.value(QLatin1String("u")); // if (!ownerValue.isUndefined()) { // const QJsonObject objOwner = ownerValue.toObject(); // setRoomCreatorUserId(objOwner.value(QLatin1String("_id")).toString()); // setRoomCreatorUserName(objOwner.value(QLatin1String("username")).toString()); // } else { // //When room is initialized we are the owner. When we update room we have the real // //owner and if it's empty => we need to clear it. // setRoomCreatorUserId(QString()); // setRoomCreatorUserName(QString()); // } //qDebug() << " *thus" << *this; mNotificationOptions.parseNotificationOptions(json); //TODO add muted } void Room::parseCommonData(const QJsonObject &json) { const QJsonArray mutedArray = json.value(QLatin1String("muted")).toArray(); QStringList lst; lst.reserve(mutedArray.count()); for (int i = 0; i < mutedArray.count(); ++i) { lst << mutedArray.at(i).toString(); } setMutedUsers(lst); const QJsonArray ignoredArray = json.value(QLatin1String("ignored")).toArray(); QStringList lstIgnored; lstIgnored.reserve(ignoredArray.count()); for (int i = 0; i < ignoredArray.count(); ++i) { lstIgnored << ignoredArray.at(i).toString(); } setIgnoredUsers(lstIgnored); const QJsonArray rolesArray = json.value(QLatin1String("roles")).toArray(); QStringList lstRoles; lstRoles.reserve(rolesArray.count()); for (int i = 0; i < rolesArray.count(); ++i) { lstRoles << rolesArray.at(i).toString(); } setRoles(lstRoles); } QString Room::displayFName() const { if (mFName.isEmpty()) { return mName; } return mFName; } QString Room::fName() const { return mFName; } void Room::setFName(const QString &value) { if (mFName != value) { mFName = value; Q_EMIT fnameChanged(); } } bool Room::isDiscussionRoom() const { return !mParentRid.isEmpty(); } QString Room::parentRid() const { return mParentRid; } void Room::setParentRid(const QString &parentRid) { if (mParentRid != parentRid) { mParentRid = parentRid; Q_EMIT parentRidChanged(); } } bool Room::broadcast() const { return mBroadcast; } void Room::setBroadcast(bool broadcast) { if (mBroadcast != broadcast) { mBroadcast = broadcast; Q_EMIT broadcastChanged(); } } Roles Room::rolesForRooms() const { return mRolesForRooms; } void Room::setRolesForRooms(const Roles &rolesForRooms) { mRolesForRooms = rolesForRooms; } QStringList Room::rolesForUserId(const QString &userId) { QStringList lstRoles; const Role r = mRolesForRooms.findRoleByUserId(userId); if (r.isValid()) { if (r.isOwner()) { lstRoles.append(i18n("Owner")); } if (r.isLeader()) { lstRoles.append(i18n("Leader")); } if (r.isModerator()) { lstRoles.append(i18n("Moderator")); } } return lstRoles; } bool Room::wasInitialized() const { return mWasInitialized; } void Room::setWasInitialized(bool wasInitialized) { mWasInitialized = wasInitialized; } bool Room::joinCodeRequired() const { return mJoinCodeRequired; } void Room::setJoinCodeRequired(bool joinCodeRequired) { if (mJoinCodeRequired != joinCodeRequired) { mJoinCodeRequired = joinCodeRequired; Q_EMIT joinCodeRequiredChanged(); } } QString Room::e2eKeyId() const { return mE2eKeyId; } void Room::setE2eKeyId(const QString &e2eKeyId) { if (mE2eKeyId != e2eKeyId) { mE2eKeyId = e2eKeyId; Q_EMIT encryptionKeyIdChanged(); } } QString Room::e2EKey() const { return mE2EKey; } void Room::setE2EKey(const QString &e2EKey) { if (mE2EKey != e2EKey) { mE2EKey = e2EKey; Q_EMIT encryptionKeyChanged(); } } bool Room::encrypted() const { return mEncrypted; } void Room::setEncrypted(bool encrypted) { if (mEncrypted != encrypted) { mEncrypted = encrypted; Q_EMIT encryptedChanged(); } } Room *Room::fromJSon(const QJsonObject &o) { //FIXME Room *r = new Room(nullptr); r->setRoomId(o[QStringLiteral("rid")].toString()); r->setChannelType(o[QStringLiteral("t")].toString()); r->setName(o[QStringLiteral("name")].toString()); r->setFName(o[QStringLiteral("fname")].toString()); r->setRoomCreatorUserName(o[QStringLiteral("roomCreatorUserName")].toString()); r->setRoomCreatorUserId(o[QStringLiteral("roomCreatorUserID")].toString()); r->setTopic(o[QStringLiteral("topic")].toString()); r->setJitsiTimeout(static_cast(o[QStringLiteral("jitsiTimeout")].toDouble())); r->setReadOnly(o[QStringLiteral("ro")].toBool()); r->setUnread(o[QStringLiteral("unread")].toInt(0)); r->setUserMentions(o[QStringLiteral("userMentions")].toInt(0)); r->setAnnouncement(o[QStringLiteral("announcement")].toString()); r->setSelected(o[QStringLiteral("selected")].toBool()); r->setFavorite(o[QStringLiteral("favorite")].toBool()); r->setAlert(o[QStringLiteral("alert")].toBool()); r->setOpen(o[QStringLiteral("open")].toBool()); r->setArchived(o[QStringLiteral("archived")].toBool()); r->setDescription(o[QStringLiteral("description")].toString()); r->setBlocker(o[QStringLiteral("blocker")].toBool()); r->setBlocked(o[QStringLiteral("blocked")].toBool()); r->setEncrypted(o[QStringLiteral("encrypted")].toBool()); r->setBroadcast(o[QStringLiteral("broadcast")].toBool()); r->setE2EKey(o[QStringLiteral("e2ekey")].toString()); r->setE2eKeyId(o[QStringLiteral("e2ekeyid")].toString()); r->setJoinCodeRequired(o[QStringLiteral("joinCodeRequired")].toBool()); r->setUpdatedAt(static_cast(o[QStringLiteral("updatedAt")].toDouble())); r->setLastSeeAt(static_cast(o[QStringLiteral("lastSeeAt")].toDouble())); const QJsonArray mutedArray = o.value(QLatin1String("mutedUsers")).toArray(); QStringList lst; lst.reserve(mutedArray.count()); for (int i = 0; i < mutedArray.count(); ++i) { lst <setMutedUsers(lst); const QJsonArray ignoredArray = o.value(QLatin1String("ignored")).toArray(); QStringList lstIgnored; const int ignoredArrayCount = ignoredArray.count(); lstIgnored.reserve(ignoredArrayCount); for (int i = 0; i < ignoredArrayCount; ++i) { lstIgnored <setIgnoredUsers(lstIgnored); const QJsonArray rolesArray = o.value(QLatin1String("roles")).toArray(); QStringList lstRoles; lstRoles.reserve(rolesArray.count()); for (int i = 0; i < rolesArray.count(); ++i) { lstRoles <setRoles(lstRoles); const QJsonObject notificationsObj = o.value(QLatin1String("notifications")).toObject(); const NotificationOptions notifications = NotificationOptions::fromJSon(notificationsObj); r->setNotificationOptions(notifications); //TODO add parent RID return r; } QByteArray Room::serialize(Room *r, bool toBinary) { QJsonDocument d; QJsonObject o; //todo add timestamp o[QStringLiteral("rid")] = r->roomId(); o[QStringLiteral("t")] = r->channelType(); o[QStringLiteral("name")] = r->name(); o[QStringLiteral("fname")] = r->fName(); o[QStringLiteral("roomCreatorUserName")] = r->roomOwnerUserName(); o[QStringLiteral("roomCreatorUserID")] = r->roomCreatorUserId(); if (!r->topic().isEmpty()) { o[QStringLiteral("topic")] = r->topic(); } o[QStringLiteral("jitsiTimeout")] = r->jitsiTimeout(); o[QStringLiteral("updatedAt")] = r->updatedAt(); o[QStringLiteral("lastSeeAt")] = r->lastSeeAt(); o[QStringLiteral("ro")] = r->readOnly(); o[QStringLiteral("unread")] = r->unread(); if (!r->announcement().isEmpty()) { o[QStringLiteral("announcement")] = r->announcement(); } o[QStringLiteral("selected")] = r->selected(); o[QStringLiteral("favorite")] = r->favorite(); o[QStringLiteral("alert")] = r->alert(); o[QStringLiteral("open")] = r->open(); o[QStringLiteral("blocker")] = r->blocker(); o[QStringLiteral("blocked")] = r->blocked(); o[QStringLiteral("encrypted")] = r->encrypted(); o[QStringLiteral("archived")] = r->archived(); o[QStringLiteral("broadcast")] = r->broadcast(); if (r->joinCodeRequired()) { o[QStringLiteral("joinCodeRequired")] = true; } if (!r->e2EKey().isEmpty()) { o[QStringLiteral("e2ekey")] = r->e2EKey(); } if (!r->e2eKeyId().isEmpty()) { o[QStringLiteral("e2ekeyid")] = r->e2eKeyId(); } if (!r->description().isEmpty()) { o[QStringLiteral("description")] = r->description(); } o[QStringLiteral("userMentions")] = r->userMentions(); if (!r->mutedUsers().isEmpty()) { QJsonArray array; const int nbMuted = r->mutedUsers().count(); for (int i = 0; i < nbMuted; ++i) { array.append(r->mutedUsers().at(i)); } o[QStringLiteral("mutedUsers")] = array; } if (!r->ignoredUsers().isEmpty()) { QJsonArray array; const int nbIgnoredUsers = r->ignoredUsers().count(); for (int i = 0; i < nbIgnoredUsers; ++i) { array.append(r->ignoredUsers().at(i)); } o[QStringLiteral("ignored")] = array; } if (!r->roles().isEmpty()) { QJsonArray array; const int nbRoles = r->roles().count(); for (int i = 0; i < nbRoles; ++i) { array.append(r->roles().at(i)); } o[QStringLiteral("roles")] = array; } o[QStringLiteral("notifications")] = NotificationOptions::serialize(r->notificationOptions()); d.setObject(o); if (toBinary) { return d.toBinaryData(); } return d.toJson(QJsonDocument::Indented); } UsersForRoomModel *Room::usersModelForRoom() const { return mUsersModelForRoom; } UsersForRoomFilterProxyModel *Room::usersModelForRoomProxyModel() const { return mUsersModelForRoomProxyModel; } -FilesForRoomModel *Room::filesModelForRoom() const -{ - return mFilesModelForRoom; -} - -FilesForRoomFilterProxyModel *Room::filesForRoomFilterProxyModel() const -{ - return mFilesForRoomFilterProxyModel; -} DiscussionsFilterProxyModel *Room::discussionsModelForRoomFilterProxyModel() const { return mDiscussionsFilterProxyModel; } DiscussionsModel *Room::discussionsModelForRoom() const { return mDiscussionsModel; } ThreadsFilterProxyModel *Room::threadsModelForRoomFilterProxyModel() const { return mThreadsFilterProxyModel; } ThreadsModel *Room::threadsModelForRoom() const { return mThreadsModel; } MessageModel *Room::messageModel() const { return mMessageModel; } QString Room::inputMessage() const { return mInputMessage; } void Room::setInputMessage(const QString &inputMessage) { mInputMessage = inputMessage; } bool Room::archived() const { return mArchived; } void Room::setArchived(bool archived) { if (mArchived != archived) { mArchived = archived; Q_EMIT archivedChanged(); } } QString Room::description() const { return mDescription; } void Room::setDescription(const QString &description) { if (mDescription != description) { mDescription = description; Q_EMIT descriptionChanged(); } } bool Room::encryptedEnabled() const { if (mRocketChatAccount) { return mRocketChatAccount->encryptedEnabled(); } return false; } bool Room::userIsIgnored(const QString &userId) { return mIgnoredUsers.contains(userId); } QString Room::roomMessageInfo() const { if (mReadOnly && !canChangeRoles()) { return i18n("Channel is read only."); } if (mBlocker) { return i18n("You have blocked this channel."); } if (mBlocked) { return i18n("Channel was blocked."); } return QString(); } bool Room::canChangeRoles() const { return mRoles.contains(QStringLiteral("owner")); } bool Room::userHasOwnerRole(const QString &userId) const { Role r = mRolesForRooms.findRoleByUserId(userId); if (r.isValid()) { return r.isOwner(); } return false; } bool Room::userHasLeaderRole(const QString &userId) const { Role r = mRolesForRooms.findRoleByUserId(userId); if (r.isValid()) { return r.isLeader(); } return false; } bool Room::userHasModeratorRole(const QString &userId) const { Role r = mRolesForRooms.findRoleByUserId(userId); if (r.isValid()) { return r.isModerator(); } return false; } void Room::updateRoles(const QJsonObject &obj) { mRolesForRooms.updateRoles(obj); } diff --git a/src/ruqolacore/room.h b/src/ruqolacore/room.h index 98413f04..61fcf035 100644 --- a/src/ruqolacore/room.h +++ b/src/ruqolacore/room.h @@ -1,361 +1,357 @@ /* * Copyright 2016 Riccardo Iaconelli * Copyright 2017-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 . * */ #ifndef ROOM_H #define ROOM_H #include #include #include "notificationoptions.h" #include "roles.h" #include "libruqola_private_export.h" class UsersForRoomModel; class UsersForRoomFilterProxyModel; -class FilesForRoomModel; -class FilesForRoomFilterProxyModel; class MessageModel; class RocketChatAccount; class NotificationOptionsWrapper; class ThreadsModel; class ThreadsFilterProxyModel; class DiscussionsModel; class DiscussionsFilterProxyModel; class LIBRUQOLACORE_TESTS_EXPORT Room : public QObject { Q_OBJECT Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) Q_PROPERTY(QString fname READ fName WRITE setFName NOTIFY fnameChanged) Q_PROPERTY(QString announcement READ announcement WRITE setAnnouncement NOTIFY announcementChanged) Q_PROPERTY(QString topic READ topic WRITE setTopic NOTIFY topicChanged) Q_PROPERTY(bool favorite READ favorite WRITE setFavorite NOTIFY favoriteChanged) Q_PROPERTY(bool readOnly READ readOnly WRITE setReadOnly NOTIFY readOnlyChanged) Q_PROPERTY(bool alert READ alert WRITE setAlert NOTIFY alertChanged) Q_PROPERTY(bool blocker READ blocker WRITE setBlocker NOTIFY blockerChanged) Q_PROPERTY(bool archived READ archived WRITE setArchived NOTIFY archivedChanged) Q_PROPERTY(bool blocked READ blocked WRITE setBlocked NOTIFY blockedChanged) Q_PROPERTY(bool open READ open WRITE setOpen NOTIFY openChanged) Q_PROPERTY(bool encrypted READ encrypted WRITE setEncrypted NOTIFY encryptedChanged) Q_PROPERTY(bool broadcast READ broadcast WRITE setBroadcast NOTIFY broadcastChanged) Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY descriptionChanged) Q_PROPERTY(QStringList roles READ roles WRITE setRoles NOTIFY rolesChanged) Q_PROPERTY(QString e2eKeyId READ e2eKeyId WRITE setE2eKeyId NOTIFY encryptionKeyIdChanged) Q_PROPERTY(bool joinCodeRequired READ joinCodeRequired WRITE setJoinCodeRequired NOTIFY joinCodeRequiredChanged) Q_PROPERTY(QString channelType READ channelType WRITE setChannelType NOTIFY channelTypeChanged) Q_PROPERTY(bool wasInitialized READ wasInitialized CONSTANT) public: explicit Room(RocketChatAccount *account = nullptr, QObject *parent = nullptr); // To be used in ID find: message ID Q_REQUIRED_RESULT bool operator==(const Room &other) const; //we can't use operator== as it tests only id. We need it for autotest Q_REQUIRED_RESULT bool isEqual(const Room &other) const; Q_REQUIRED_RESULT QString roomOwnerUserName() const; void setRoomCreatorUserName(const QString &userName); Q_REQUIRED_RESULT QString roomCreatorUserId() const; void setRoomCreatorUserId(const QString &userId); Q_REQUIRED_RESULT QStringList mutedUsers() const; void setMutedUsers(const QStringList &mutedUsers); Q_REQUIRED_RESULT qint64 jitsiTimeout() const; void setJitsiTimeout(const qint64 &jitsiTimeout); Q_REQUIRED_RESULT int unread() const; void setUnread(int unread); Q_REQUIRED_RESULT bool selected() const; void setSelected(bool selected); /** * @brief Return room name * * @return QString, The name of the room */ Q_REQUIRED_RESULT QString name() const; void setName(const QString &name); Q_REQUIRED_RESULT QString displayRoomName() const; Q_REQUIRED_RESULT QString announcement() const; void setAnnouncement(const QString &announcement); Q_REQUIRED_RESULT QString channelType() const; void setChannelType(const QString &channelType); Q_REQUIRED_RESULT bool favorite() const; void setFavorite(bool favorite); QString topic() const; void setTopic(const QString &topic); Q_REQUIRED_RESULT bool readOnly() const; void setReadOnly(bool readOnly); Q_REQUIRED_RESULT bool open() const; void setOpen(bool open); Q_REQUIRED_RESULT bool alert() const; void setAlert(bool alert); Q_REQUIRED_RESULT QString roomId() const; void setRoomId(const QString &id); void setBlocker(bool alert); Q_REQUIRED_RESULT bool blocker() const; void parseSubscriptionRoom(const QJsonObject &json); void parseUpdateRoom(const QJsonObject &json); /** * @brief Constructs Room object from QJsonObject (cache) * * @param source The Json containing room attributes * @return Room object, The room constructed from Json */ static Room *fromJSon(const QJsonObject &source); /** * @brief Constructs QBytearray from Room object * * @param message The Room object * @return QByteArray, The Json containing room attributes */ static QByteArray serialize(Room *r, bool toBinary = true); UsersForRoomModel *usersModelForRoom() const; UsersForRoomFilterProxyModel *usersModelForRoomProxyModel() const; - FilesForRoomModel *filesModelForRoom() const; - FilesForRoomFilterProxyModel *filesForRoomFilterProxyModel() const; - DiscussionsFilterProxyModel *discussionsModelForRoomFilterProxyModel() const; DiscussionsModel *discussionsModelForRoom() const; ThreadsModel *threadsModelForRoom() const; ThreadsFilterProxyModel *threadsModelForRoomFilterProxyModel() const; MessageModel *messageModel() const; Q_REQUIRED_RESULT QString inputMessage() const; void setInputMessage(const QString &inputMessage); Q_REQUIRED_RESULT bool archived() const; void setArchived(bool archived); QString description() const; void setDescription(const QString &description); Q_REQUIRED_RESULT bool encryptedEnabled() const; Q_REQUIRED_RESULT bool canBeModify() const; Q_REQUIRED_RESULT NotificationOptions notificationOptions() const; void setNotificationOptions(const NotificationOptions ¬ificationOptions); Q_REQUIRED_RESULT int userMentions() const; void setUserMentions(int userMentions); void updateSubscriptionRoom(const QJsonObject &json); Q_REQUIRED_RESULT qint64 updatedAt() const; void setUpdatedAt(qint64 updatedAt); void parseInsertRoom(const QJsonObject &json); Q_REQUIRED_RESULT qint64 lastSeeAt() const; void setLastSeeAt(qint64 lastSeeAt); Q_REQUIRED_RESULT bool blocked() const; void setBlocked(bool blocked); Q_REQUIRED_RESULT QStringList roles() const; void setRoles(const QStringList &roles); Q_REQUIRED_RESULT QStringList ignoredUsers() const; void setIgnoredUsers(const QStringList &ignoredUsers); Q_REQUIRED_RESULT bool encrypted() const; void setEncrypted(bool encrypted); Q_REQUIRED_RESULT bool userIsIgnored(const QString &userId); Q_REQUIRED_RESULT QString markdownAnnouncement() const; Q_REQUIRED_RESULT QString roomMessageInfo() const; Q_REQUIRED_RESULT QString e2EKey() const; void setE2EKey(const QString &e2EKey); Q_REQUIRED_RESULT QString e2eKeyId() const; void setE2eKeyId(const QString &e2eKeyId); NotificationOptionsWrapper *getNotificationWrapper(); Q_REQUIRED_RESULT bool joinCodeRequired() const; void setJoinCodeRequired(bool joinCodeRequired); Q_REQUIRED_RESULT bool wasInitialized() const; void setWasInitialized(bool wasInitialized); Q_REQUIRED_RESULT Roles rolesForRooms() const; void setRolesForRooms(const Roles &rolesForRooms); Q_REQUIRED_RESULT QStringList rolesForUserId(const QString &userId); Q_REQUIRED_RESULT bool canChangeRoles() const; Q_REQUIRED_RESULT bool userHasOwnerRole(const QString &userId) const; Q_REQUIRED_RESULT bool userHasLeaderRole(const QString &userId) const; Q_REQUIRED_RESULT bool userHasModeratorRole(const QString &userId) const; void updateRoles(const QJsonObject &obj); Q_REQUIRED_RESULT bool broadcast() const; void setBroadcast(bool broadcast); Q_REQUIRED_RESULT QString parentRid() const; void setParentRid(const QString &parentRid); Q_REQUIRED_RESULT QString fName() const; void setFName(const QString &value); Q_REQUIRED_RESULT QString displayFName() const; Q_REQUIRED_RESULT bool isDiscussionRoom() const; Q_SIGNALS: void nameChanged(); void fnameChanged(); void announcementChanged(); void topicChanged(); void favoriteChanged(); void alertChanged(); void readOnlyChanged(); void unreadChanged(); void openChanged(); void encryptedChanged(); void encryptionKeyChanged(); void encryptionKeyIdChanged(); //Blocker we blocked the channel void blockerChanged(); //Blocked the channel was blocked void blockedChanged(); void archivedChanged(); void descriptionChanged(); void rolesChanged(); void mutedUsersChanged(); void ignoredUsersChanged(); void jitsiTimeoutChanged(); void joinCodeRequiredChanged(); void channelTypeChanged(); void broadcastChanged(); void parentRidChanged(); private: Q_DISABLE_COPY(Room) void parseCommonData(const QJsonObject &json); //Room Object Fields NotificationOptions mNotificationOptions; // muted - collection of muted users by its usernames QStringList mMutedUsers; QStringList mIgnoredUsers; //Roles QStringList mRoles; QString mInputMessage; // _id QString mRoomId; // t (can take values "d" , "c" or "p" or "l") QString mChannelType; // Parent Rid when we have a discussion. QString mParentRid; // name QString mName; QString mFName; // Announcement QString mAnnouncement; // u QString mRoomCreatorUserName; QString mRoomCreateUserId; // topic QString mTopic; QString mDescription; // jitsiTimeout qint64 mJitsiTimeout = -1; qint64 mUpdatedAt = -1; qint64 mLastSeeAt = -1; //Encryption Key QString mE2EKey; QString mE2eKeyId; //Roles In Room Roles mRolesForRooms; //quint64 ? int mUnread = 0; int mUserMentions = 0; int mThreadCount = 0; // ro - read-only chat or not bool mReadOnly = false; bool mSelected = false; bool mFavorite = false; //We can hide it or not. bool mOpen = false; bool mAlert = false; bool mBlocker = false; bool mArchived = false; bool mBlocked = false; bool mEncrypted = false; bool mJoinCodeRequired = false; bool mWasInitialized = false; bool mBroadcast = false; - UsersForRoomModel *mUsersModelForRoom = nullptr; - UsersForRoomFilterProxyModel *mUsersModelForRoomProxyModel = nullptr; - FilesForRoomModel *mFilesModelForRoom = nullptr; - FilesForRoomFilterProxyModel *mFilesForRoomFilterProxyModel = nullptr; ThreadsModel *mThreadsModel = nullptr; ThreadsFilterProxyModel *mThreadsFilterProxyModel = nullptr; DiscussionsFilterProxyModel *mDiscussionsFilterProxyModel = nullptr; DiscussionsModel *mDiscussionsModel = nullptr; + + + + UsersForRoomModel *mUsersModelForRoom = nullptr; + UsersForRoomFilterProxyModel *mUsersModelForRoomProxyModel = nullptr; MessageModel *mMessageModel = nullptr; RocketChatAccount *mRocketChatAccount = nullptr; }; LIBRUQOLACORE_EXPORT QDebug operator <<(QDebug d, const Room &t); #endif // ROOM_H