diff --git a/src/core/autotests/usersforroomfilterproxymodeltest.cpp b/src/core/autotests/usersforroomfilterproxymodeltest.cpp index a59967bb..6db5b220 100644 --- a/src/core/autotests/usersforroomfilterproxymodeltest.cpp +++ b/src/core/autotests/usersforroomfilterproxymodeltest.cpp @@ -1,72 +1,72 @@ /* Copyright (c) 2018-2020 Laurent Montel 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 "usersforroomfilterproxymodeltest.h" #include "model/usersforroomfilterproxymodel.h" #include "model/usersforroommodel.h" #include QTEST_MAIN(UsersForRoomFilterProxyModelTest) UsersForRoomFilterProxyModelTest::UsersForRoomFilterProxyModelTest(QObject *parent) : QObject(parent) { } UsersForRoomFilterProxyModelTest::~UsersForRoomFilterProxyModelTest() { } void UsersForRoomFilterProxyModelTest::shouldHaveDefaultValues() { UsersForRoomFilterProxyModel proxy; UsersForRoomModel model; proxy.setSourceModel(&model); QCOMPARE(proxy.rowCount(), 0); QHash roles; roles[UsersForRoomModel::UserName] = QByteArrayLiteral("username"); roles[UsersForRoomModel::Name] = QByteArrayLiteral("name"); roles[UsersForRoomModel::UserId] = QByteArrayLiteral("userid"); roles[UsersForRoomModel::IconStatus] = QByteArrayLiteral("iconstatus"); roles[UsersForRoomModel::DisplayName] = QByteArrayLiteral("displayname"); QCOMPARE(proxy.roleNames(), roles); } void UsersForRoomFilterProxyModelTest::shouldAssignValue() { UsersForRoomFilterProxyModel proxy; UsersForRoomModel model; proxy.setSourceModel(&model); QCOMPARE(proxy.rowCount(), 0); - QVector users; + QVector users; for (int i = 0; i < 10; i++) { - User *user = new User; - user->setName(QStringLiteral("name%1").arg(i)); - user->setStatus(QStringLiteral("status%1").arg(i)); - user->setUserId(QStringLiteral("userId%1").arg(i)); - user->setUserName(QStringLiteral("username%1").arg(i)); + User user; + user.setName(QStringLiteral("name%1").arg(i)); + user.setStatus(QStringLiteral("status%1").arg(i)); + user.setUserId(QStringLiteral("userId%1").arg(i)); + user.setUserName(QStringLiteral("username%1").arg(i)); users.append(user); } model.setUsers(users); QCOMPARE(proxy.rowCount(), 10); QCOMPARE(model.rowCount(), 10); } diff --git a/src/core/autotests/usersforroommodeltest.cpp b/src/core/autotests/usersforroommodeltest.cpp index 066b6f4b..561c83ed 100644 --- a/src/core/autotests/usersforroommodeltest.cpp +++ b/src/core/autotests/usersforroommodeltest.cpp @@ -1,169 +1,169 @@ /* Copyright (c) 2018-2020 Laurent Montel 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 "usersforroommodeltest.h" #include "test_model_helpers.h" #include "model/usersforroommodel.h" #include #include #include #include QTEST_GUILESS_MAIN(UsersForRoomModelTest) UsersForRoomModelTest::UsersForRoomModelTest(QObject *parent) : QObject(parent) { } void UsersForRoomModelTest::shouldHaveDefaultValue() { UsersForRoomModel w; QSignalSpy rowInsertedSpy(&w, &UsersForRoomModel::rowsInserted); QSignalSpy rowABTInserted(&w, &UsersForRoomModel::rowsAboutToBeInserted); QCOMPARE(w.rowCount(), 0); QCOMPARE(rowInsertedSpy.count(), 0); QCOMPARE(rowABTInserted.count(), 0); QHash roles; roles[UsersForRoomModel::UserName] = QByteArrayLiteral("username"); roles[UsersForRoomModel::Name] = QByteArrayLiteral("name"); roles[UsersForRoomModel::UserId] = QByteArrayLiteral("userid"); roles[UsersForRoomModel::IconStatus] = QByteArrayLiteral("iconstatus"); roles[UsersForRoomModel::DisplayName] = QByteArrayLiteral("displayname"); QCOMPARE(w.roleNames(), roles); } void UsersForRoomModelTest::shouldAddValues() { UsersForRoomModel w; - QVector users; + QVector users; QSignalSpy rowInsertedSpy(&w, &UsersForRoomModel::rowsInserted); QSignalSpy rowABTInserted(&w, &UsersForRoomModel::rowsAboutToBeInserted); for (int i = 0; i < 10; i++) { - User *user = new User; - user->setName(QStringLiteral("name%1").arg(i)); - user->setStatus(QStringLiteral("status%1").arg(i)); - user->setUserId(QStringLiteral("userId%1").arg(i)); - user->setUserName(QStringLiteral("username%1").arg(i)); + User user; + user.setName(QStringLiteral("name%1").arg(i)); + user.setStatus(QStringLiteral("status%1").arg(i)); + user.setUserId(QStringLiteral("userId%1").arg(i)); + user.setUserName(QStringLiteral("username%1").arg(i)); users.append(user); } w.setUsers(users); QCOMPARE(w.rowCount(), 10); QCOMPARE(rowInsertedSpy.count(), 1); QCOMPARE(rowABTInserted.count(), 1); QCOMPARE(TestModelHelpers::rowSpyToText(rowInsertedSpy), QStringLiteral("0,9")); QCOMPARE(TestModelHelpers::rowSpyToText(rowABTInserted), QStringLiteral("0,9")); rowABTInserted.clear(); rowInsertedSpy.clear(); users.clear(); for (int i = 0; i < 3; ++i) { - User *user = new User; - user->setName(QStringLiteral("name%1").arg(i)); - user->setStatus(QStringLiteral("status%1").arg(i)); - user->setUserId(QStringLiteral("userId%1").arg(i)); - user->setUserName(QStringLiteral("username%1").arg(i)); + User user; + user.setName(QStringLiteral("name%1").arg(i)); + user.setStatus(QStringLiteral("status%1").arg(i)); + user.setUserId(QStringLiteral("userId%1").arg(i)); + user.setUserName(QStringLiteral("username%1").arg(i)); users.append(user); } w.clear(); w.setUsers(users); QCOMPARE(w.rowCount(), 3); QCOMPARE(rowInsertedSpy.count(), 1); QCOMPARE(rowABTInserted.count(), 1); QCOMPARE(TestModelHelpers::rowSpyToText(rowInsertedSpy), QStringLiteral("0,2")); QCOMPARE(TestModelHelpers::rowSpyToText(rowABTInserted), QStringLiteral("0,2")); rowABTInserted.clear(); rowInsertedSpy.clear(); users.clear(); w.clear(); w.setUsers(users); QCOMPARE(w.rowCount(), 0); QCOMPARE(rowInsertedSpy.count(), 0); QCOMPARE(rowABTInserted.count(), 0); QCOMPARE(TestModelHelpers::rowSpyToText(rowInsertedSpy), QString()); QCOMPARE(TestModelHelpers::rowSpyToText(rowABTInserted), QString()); } void UsersForRoomModelTest::shouldVerifyData() { UsersForRoomModel w; - QVector users; + QVector users; for (int i = 0; i < 10; i++) { - User *user = new User; - user->setName(QStringLiteral("name%1").arg(i)); - user->setStatus(QStringLiteral("online")); - user->setUserId(QStringLiteral("userId%1").arg(i)); - user->setUserName(QStringLiteral("username%1").arg(i)); + User user; + user.setName(QStringLiteral("name%1").arg(i)); + user.setStatus(QStringLiteral("online")); + user.setUserId(QStringLiteral("userId%1").arg(i)); + user.setUserName(QStringLiteral("username%1").arg(i)); users.append(user); } w.setUsers(users); QCOMPARE(w.rowCount(), 10); for (int i = 0; i < 10; ++i) { QCOMPARE(w.data(w.index(i), UsersForRoomModel::Name).toString(), QStringLiteral("name%1").arg(i)); QCOMPARE(w.data(w.index(i), UsersForRoomModel::IconStatus).toString(), QStringLiteral("user-online")); QCOMPARE(w.data(w.index(i), UsersForRoomModel::UserId).toString(), QStringLiteral("userId%1").arg(i)); QCOMPARE(w.data(w.index(i), UsersForRoomModel::UserName).toString(), QStringLiteral("username%1").arg(i)); } } void UsersForRoomModelTest::shouldParseUsers_data() { QTest::addColumn("filename"); QTest::addColumn("numberOfUsers"); QTest::addColumn("numberOfSignal"); QTest::addColumn("restApi"); QTest::newRow("oneuser") << QStringLiteral("oneuser.json") << 1 << 1 << false; QTest::newRow("severalusers") << QStringLiteral("severalusers.json") << 14 << 1 << false; QTest::newRow("severalusers1-restapi") << QStringLiteral("severalusers1-restapi.json") << 2 << 1 << true; } QJsonObject loadFile(const QString &file) { const QString originalJsonFile = QLatin1String(RUQOLA_DATA_DIR) + QLatin1String("/usersforroom/") + file; QFile f(originalJsonFile); if (!f.open(QIODevice::ReadOnly)) { qWarning() << " Unable to load file " << file; return {}; } const QByteArray content = f.readAll(); f.close(); const QJsonDocument doc = QJsonDocument::fromJson(content); const QJsonObject root = doc.object(); return root; } void UsersForRoomModelTest::shouldParseUsers() { QFETCH(QString, filename); QFETCH(int, numberOfUsers); QFETCH(int, numberOfSignal); QFETCH(bool, restApi); UsersForRoomModel w; QSignalSpy rowInsertedSpy(&w, &UsersForRoomModel::rowsInserted); QSignalSpy rowABTInserted(&w, &UsersForRoomModel::rowsAboutToBeInserted); w.parseUsersForRooms(loadFile(filename), nullptr, restApi); //We don't have userstatus model here QCOMPARE(rowInsertedSpy.count(), numberOfSignal); QCOMPARE(rowABTInserted.count(), numberOfSignal); QCOMPARE(w.rowCount(), numberOfUsers); } diff --git a/src/core/autotests/usertest.cpp b/src/core/autotests/usertest.cpp index 074d159e..af753a53 100644 --- a/src/core/autotests/usertest.cpp +++ b/src/core/autotests/usertest.cpp @@ -1,217 +1,217 @@ /* Copyright (c) 2017-2020 Laurent Montel 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 "usertest.h" #include "user.h" #include #include #include QTEST_GUILESS_MAIN(UserTest) UserTest::UserTest(QObject *parent) : QObject(parent) { } void UserTest::shouldHaveDefaultValue() { User u; QVERIFY(u.name().isEmpty()); QVERIFY(u.userId().isEmpty()); QCOMPARE(u.status(), QStringLiteral("offline")); QVERIFY(u.userName().isEmpty()); QVERIFY(!u.isValid()); } void UserTest::shouldBeValid() { User u; u.setName(QStringLiteral("foo")); QVERIFY(u.isValid()); User u2; u2.setUserId(QStringLiteral("bla")); QVERIFY(!u2.isValid()); User u3; u3.setUserName(QStringLiteral("dd")); QVERIFY(u3.isValid()); User u4; u4.setUserId(QStringLiteral("d")); u4.setUserName(QStringLiteral("dd")); u4.setName(QStringLiteral("foo")); QVERIFY(u4.isValid()); } void UserTest::shouldSetAndGetName() { User sampleUser; QString name = QStringLiteral("Maxwell"); sampleUser.setName(name); QCOMPARE(sampleUser.name(), name); name = QStringLiteral("Maxwell_NEW"); sampleUser.setName(name); QCOMPARE(sampleUser.name(), name); name = QStringLiteral("Maxwell_NEW"); sampleUser.setName(name); QCOMPARE(sampleUser.name(), name); } void UserTest::shouldSetAndGetUserId() { User sampleUser; QString Id = QStringLiteral("RA1511ECE"); sampleUser.setUserId(Id); QCOMPARE(sampleUser.userId(), Id); Id = QStringLiteral("RA1511ECE_NEW"); sampleUser.setUserId(Id); QCOMPARE(sampleUser.userId(), Id); Id = QStringLiteral("RA1511ECE_NEW"); sampleUser.setUserId(Id); QCOMPARE(sampleUser.userId(), Id); } void UserTest::shouldSetAndGetStatus() { User sampleUser; QString status = QStringLiteral("myStatus"); sampleUser.setStatus(status); QCOMPARE(sampleUser.status(), status); status = QStringLiteral("myStatus_NEW"); sampleUser.setStatus(status); QCOMPARE(sampleUser.status(), status); status = QStringLiteral("myStatus_NEW"); sampleUser.setStatus(status); QCOMPARE(sampleUser.status(), status); } void UserTest::shouldParseUser() { User sampleUser; QJsonObject object; QJsonObject fields; const QString name = QStringLiteral("Newton"); const QString status = QStringLiteral("Newton"); fields.insert(QStringLiteral("name"), QJsonValue(name)); fields.insert(QStringLiteral("status"), QJsonValue(status)); object.insert(QStringLiteral("id"), QJsonValue(QLatin1String("RA151100ECE"))); object.insert(QStringLiteral("fields"), fields); sampleUser.parseUser(object); QCOMPARE(sampleUser.name(), name); QCOMPARE(sampleUser.status(), status); sampleUser.parseUser(object); QCOMPARE(sampleUser.name(), name); QCOMPARE(sampleUser.status(), status); } void UserTest::checkEqualsAndUnequalsOperator() { User sampleuser, sampleuserOther; QString Id = QStringLiteral("RA151100ECE"); QString name = QStringLiteral("Robert Segwick"); QString status = QStringLiteral("myStaus"); sampleuser.setUserId(Id); sampleuser.setName(name); sampleuser.setStatus(status); QVERIFY(sampleuser != sampleuserOther); sampleuserOther.setUserId(Id); sampleuserOther.setName(name); sampleuserOther.setStatus(status); QVERIFY(sampleuser == sampleuserOther); sampleuserOther.setName(QStringLiteral("Robert Segwick_NEW")); QVERIFY(sampleuser != sampleuserOther); } //FIXME void UserTest::shouldParseJson_data() { // QTest::addColumn("fileName"); // QTest::addColumn("expectedUser"); // User *expected = new User; // expected->setName(QStringLiteral("Laurent M")); // expected->setStatus(QStringLiteral("away")); // expected->setUserId(QStringLiteral("yi2ucvqkdkxiTkyZ5")); // expected->setUserName(QStringLiteral("laurent")); // expected->setUtcOffset(1); // QTest::newRow("user1") << QStringLiteral("adduser") << *expected; } void UserTest::shouldParseJson() { // QFETCH(QString, fileName); // QFETCH(User*, expectedUser); // const QString originalJsonFile = QLatin1String(RUQOLA_DATA_DIR) + QLatin1String("/json/") + fileName + QLatin1String(".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(); -// User *user = new User; -// user->parseUser(fields); +// User user; +// user.parseUser(fields); // const bool equal = (*user == *expectedUser); // if (!equal) { // qDebug() << " current value " << user; // qDebug() << " expected value " << expectedUser; // } // QVERIFY(equal); // delete expectedUser; // delete user; } void UserTest::shouldGetStatusIcon_data() { QTest::addColumn("status"); QTest::addColumn("iconFileName"); QTest::newRow("online") << QStringLiteral("online") << QStringLiteral("user-online"); QTest::newRow("busy") << QStringLiteral("busy") << QStringLiteral("user-busy"); QTest::newRow("away") << QStringLiteral("away") << QStringLiteral("user-away"); QTest::newRow("offline") << QStringLiteral("offline") << QStringLiteral("user-offline"); QTest::newRow("unknown") << QStringLiteral("foo") << QStringLiteral("unknown"); QTest::newRow("unknown1") << QString() << QStringLiteral("unknown"); } void UserTest::shouldGetStatusIcon() { QFETCH(QString, status); QFETCH(QString, iconFileName); User user; user.setStatus(status); QCOMPARE(user.iconFromStatus(), iconFileName); } diff --git a/src/core/model/roommodel.cpp b/src/core/model/roommodel.cpp index a1745403..c27b7fb8 100644 --- a/src/core/model/roommodel.cpp +++ b/src/core/model/roommodel.cpp @@ -1,569 +1,569 @@ /* * 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 "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) { auto *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"); roles[RoomAutotranslateLanguage] = QByteArrayLiteral("autotranslateLanguage"); roles[RoomAutotranslate] = QByteArrayLiteral("autotranslate"); 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()); if (role == Qt::DisplayRole) { return r->displayFName(); } 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: case Qt::DecorationRole: return icon(r); case RoomModel::RoomOtr: //TODO implement it. return {}; case RoomModel::RoomUserMentions: return r->userMentions(); case RoomModel::RoomIgnoredUsers: return r->ignoredUsers(); case RoomModel::RoomAutotranslateLanguage: return r->autoTranslateLanguage(); } 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 == QLatin1String("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 == QLatin1String("updated")) { qCDebug(RUQOLA_LOG) << "UPDATE ROOM name " << roomData.value(QLatin1String("name")).toString() << " rid " << roomData.value(QLatin1String("rid")) << " roomData " << roomData; updateSubscriptionRoom(roomData); } else if (actionName == QLatin1String("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(User *user) +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()) { + 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 {}; } 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 {}; } 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 (mRocketChatAccount && mRocketChatAccount->sortUnreadOnTop() && (r->unread() > 0 || r->alert())) { if (channelTypeStr == QLatin1Char('p')) { if (r->parentRid().isEmpty()) { str = i18n("Unread Rooms"); } else { str = i18n("Unread Discussions"); } } else if (channelTypeStr == QLatin1Char('c')) { str = i18n("Unread Rooms"); } else if (channelTypeStr == QLatin1Char('d')) { str = i18n("Unread Private Messages"); } } else { if (channelTypeStr == QLatin1Char('p')) { if (r->parentRid().isEmpty()) { str = i18n("Rooms"); } else { str = i18n("Discussions"); } } else if (channelTypeStr == QLatin1Char('c')) { str = i18n("Rooms"); } else if (channelTypeStr == QLatin1Char('d')) { str = i18n("Private Messages"); } } } return str; } int RoomModel::order(Room *r) const { int order = 0; // Unread on top: push down everything that isn't unread if (mRocketChatAccount && mRocketChatAccount->sortUnreadOnTop() && r->unread() == 0 && !r->alert()) { order += 20; } // Then we have favorites channels, push down everything else if (!r->favorite()) { order += 10; } const QString channelTypeStr = r->channelType(); if (channelTypeStr == QLatin1Char('c')) { order += 1; } else if (channelTypeStr == QLatin1Char('d')) { order += 2; } else if (channelTypeStr == QLatin1Char('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() == QLatin1Char('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() == QLatin1Char('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() == QLatin1Char('p')) { return QIcon::fromTheme(QStringLiteral("lock")); } return {}; } QModelIndex RoomModel::indexForRoomName(const QString &roomName) const { for (int row = 0; row < rowCount(); ++row) { const QModelIndex modelIndex = index(row, 0); if (modelIndex.data(RoomModel::RoomName) == roomName) { return modelIndex; } } return {}; } diff --git a/src/core/model/roommodel.h b/src/core/model/roommodel.h index 762ae56f..e445096a 100644 --- a/src/core/model/roommodel.h +++ b/src/core/model/roommodel.h @@ -1,137 +1,137 @@ /* * 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 MessageModel; 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, RoomAutotranslateLanguage, RoomAutotranslate, }; 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 mRoomsList * * @param roomID The ID of the room to find * @return RoomWrapper Pointer, The pointer to room with @param roomID in mRoomsList, 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 mRoomsList 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(User *user); + void userStatusChanged(const User &user); UsersForRoomModel *usersModelForRoom(const QString &roomId) const; UsersForRoomFilterProxyModel *usersForRoomFilterProxyModel(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); Q_REQUIRED_RESULT QModelIndex indexForRoomName(const QString &roomName) 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/core/model/usersforroommodel.cpp b/src/core/model/usersforroommodel.cpp index d670159e..d11a7a65 100644 --- a/src/core/model/usersforroommodel.cpp +++ b/src/core/model/usersforroommodel.cpp @@ -1,254 +1,251 @@ /* Copyright (c) 2017-2020 Laurent Montel 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 "usersforroommodel.h" #include "usersmodel.h" #include "ruqola_debug.h" #include #include UsersForRoomModel::UsersForRoomModel(QObject *parent) : QAbstractListModel(parent) { } UsersForRoomModel::~UsersForRoomModel() { - qDeleteAll(mUsers); } void UsersForRoomModel::removeUser(const QString &userId) { //TODO verify if it } void UsersForRoomModel::addUser(const User &users) { //TODO verify if it } -void UsersForRoomModel::setUsers(const QVector &users) +void UsersForRoomModel::setUsers(const QVector &users) { if (mUsers.isEmpty()) { if (rowCount() != 0) { beginRemoveRows(QModelIndex(), 0, mUsers.count() - 1); - qDeleteAll(mUsers); mUsers.clear(); endRemoveRows(); } if (!users.isEmpty()) { beginInsertRows(QModelIndex(), 0, users.count() - 1); mUsers = users; endInsertRows(); } } else { const int numberOfElement = mUsers.count(); mUsers << users; beginInsertRows(QModelIndex(), numberOfElement, mUsers.count() - 1); endInsertRows(); } checkFullList(); } void UsersForRoomModel::clear() { if (!mUsers.isEmpty()) { beginRemoveRows(QModelIndex(), 0, mUsers.count() - 1); - qDeleteAll(mUsers); mUsers.clear(); endRemoveRows(); } } int UsersForRoomModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return mUsers.count(); } QVariant UsersForRoomModel::data(const QModelIndex &index, int role) const { if (index.row() < 0 || index.row() >= mUsers.count()) { return QVariant(); } - User *user = mUsers.at(index.row()); + const User &user = mUsers.at(index.row()); switch (role) { case DisplayName: - return generateDisplayName(*user); + return generateDisplayName(user); case UserName: - return user->userName(); + return user.userName(); case IconStatus: - return user->iconFromStatus(); + return user.iconFromStatus(); case UserId: - return user->userId(); + return user.userId(); case Name: - return user->name(); + return user.name(); } return {}; } QString UsersForRoomModel::generateDisplayName(const User &user) const { const QString displayName = QStringLiteral("%1").arg(user.userName().isEmpty() ? user.name() : user.userName()); return displayName; } void UsersForRoomModel::checkFullList() { setHasFullList(mUsers.count() == mTotal); } bool UsersForRoomModel::hasFullList() const { return mHasFullList; } void UsersForRoomModel::setHasFullList(bool hasFullList) { if (mHasFullList != hasFullList) { mHasFullList = hasFullList; Q_EMIT hasFullListChanged(); } } int UsersForRoomModel::usersCount() const { return mUsers.count(); } int UsersForRoomModel::offset() const { return mOffset; } void UsersForRoomModel::setOffset(int offset) { mOffset = offset; } int UsersForRoomModel::total() const { return mTotal; } void UsersForRoomModel::setTotal(int total) { mTotal = total; } QHash UsersForRoomModel::roleNames() const { QHash roles; roles[UserName] = QByteArrayLiteral("username"); roles[Name] = QByteArrayLiteral("name"); roles[UserId] = QByteArrayLiteral("userid"); roles[IconStatus] = QByteArrayLiteral("iconstatus"); roles[DisplayName] = QByteArrayLiteral("displayname"); return roles; } void UsersForRoomModel::parseUsersForRooms(const QJsonObject &root, UsersModel *model, bool restapi) { if (restapi) { mTotal = root[QLatin1String("total")].toInt(); mOffset = root[QLatin1String("offset")].toInt(); const QJsonArray members = root[QStringLiteral("members")].toArray(); - QVector users; + QVector users; users.reserve(members.count()); for (const QJsonValue ¤t : members) { if (current.type() == QJsonValue::Object) { const QJsonObject userObject = current.toObject(); const QString userName = userObject[QStringLiteral("username")].toString(); const QString name = userObject[QStringLiteral("name")].toString(); const QString id = userObject[QStringLiteral("_id")].toString(); const double utcOffset = userObject[QStringLiteral("utcOffset")].toDouble(); const QString status = userObject[QStringLiteral("status")].toString(); - QScopedPointer user(new User); - user->setName(name); - user->setUserName(userName); - user->setUserId(id); - user->setUtcOffset(utcOffset); - user->setStatus(status); - if (user->isValid()) { - users.append(user.take()); + User user; + user.setName(name); + user.setUserName(userName); + user.setUserId(id); + user.setUtcOffset(utcOffset); + user.setStatus(status); + if (user.isValid()) { + users.append(user); } else { - qCWarning(RUQOLA_LOG) << "Invalid user" << *user; + qCWarning(RUQOLA_LOG) << "Invalid user" << user; mTotal--; } } else { qCWarning(RUQOLA_LOG) << "Parse records: Error in users for rooms json" << root; } } setUsers(users); } else { const QJsonObject result = root[QLatin1String("result")].toObject(); if (!result.isEmpty()) { const QJsonArray records = result[QStringLiteral("records")].toArray(); mTotal = result[QLatin1String("total")].toInt(); mOffset = root[QLatin1String("offset")].toInt(); //TODO verify if a day we use no rest api - QVector users; + QVector users; users.reserve(records.count()); for (const QJsonValue ¤t : records) { if (current.type() == QJsonValue::Object) { const QJsonObject userObject = current.toObject(); const QString userName = userObject[QStringLiteral("username")].toString(); const QString name = userObject[QStringLiteral("name")].toString(); const QString id = userObject[QStringLiteral("_id")].toString(); - User *user = new User; - user->setName(name); - user->setUserName(userName); - user->setUserId(id); + User user; + user.setName(name); + user.setUserName(userName); + user.setUserId(id); if (model) { - user->setStatus(model->status(id)); + user.setStatus(model->status(id)); } //Add status! - if (user->isValid()) { + if (user.isValid()) { users.append(user); } else { - qCWarning(RUQOLA_LOG) << "Invalid user" << *user; + qCWarning(RUQOLA_LOG) << "Invalid user" << user; mTotal--; } } else { qCWarning(RUQOLA_LOG) << "Parse records: Error in users for rooms json" << root; } } setUsers(users); } else { qCWarning(RUQOLA_LOG) << "Error in users for rooms json" << root; } } } -void UsersForRoomModel::userStatusChanged(User *newuser) +void UsersForRoomModel::userStatusChanged(const User &newuser) { const int roomCount = mUsers.count(); for (int i = 0; i < roomCount; ++i) { - User *user = mUsers.at(i); - if (newuser->userId() == user->userId()) { - user->setStatus(newuser->status()); + User &user = mUsers[i]; + if (newuser.userId() == user.userId()) { + user.setStatus(newuser.status()); const QModelIndex idx = createIndex(i, 0); Q_EMIT dataChanged(idx, idx); } } } diff --git a/src/core/model/usersforroommodel.h b/src/core/model/usersforroommodel.h index 711583a9..cb94442a 100644 --- a/src/core/model/usersforroommodel.h +++ b/src/core/model/usersforroommodel.h @@ -1,81 +1,81 @@ /* Copyright (c) 2017-2020 Laurent Montel 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 USERSFORROOMMODEL_H #define USERSFORROOMMODEL_H #include "libruqolacore_export.h" #include "user.h" #include #include class UsersModel; class LIBRUQOLACORE_EXPORT UsersForRoomModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(bool hasFullList READ hasFullList WRITE setHasFullList NOTIFY hasFullListChanged) public: enum UsersForRoomRoles { UserName = Qt::UserRole + 1, UserId, Name, IconStatus, DisplayName }; Q_ENUM(UsersForRoomRoles) explicit UsersForRoomModel(QObject *parent = nullptr); ~UsersForRoomModel() override; - void setUsers(const QVector &users); + void setUsers(const QVector &users); void clear(); Q_INVOKABLE int rowCount(const QModelIndex &parent = {}) const override; Q_REQUIRED_RESULT QVariant data(const QModelIndex &index, int role) const override; void parseUsersForRooms(const QJsonObject &root, UsersModel *model, bool restapi); - void userStatusChanged(User *newuser); + void userStatusChanged(const User &newuser); void removeUser(const QString &userId); void addUser(const User &users); Q_REQUIRED_RESULT QHash roleNames() const override; Q_REQUIRED_RESULT int total() const; void setTotal(int total); Q_REQUIRED_RESULT int offset() const; void setOffset(int offset); Q_REQUIRED_RESULT bool hasFullList() const; void setHasFullList(bool hasFullList); Q_REQUIRED_RESULT int usersCount() const; Q_SIGNALS: void hasFullListChanged(); private: QString generateDisplayName(const User &user) const; void checkFullList(); - QVector mUsers; + QVector mUsers; int mTotal = 0; int mOffset = 0; bool mHasFullList = false; }; #endif // USERSFORROOMMODEL_H diff --git a/src/core/model/usersmodel.cpp b/src/core/model/usersmodel.cpp index 5043ce9f..020933b0 100644 --- a/src/core/model/usersmodel.cpp +++ b/src/core/model/usersmodel.cpp @@ -1,183 +1,181 @@ /* Copyright (c) 2017-2020 Laurent Montel 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 "usersmodel.h" #include "ruqola_debug.h" #include UsersModel::UsersModel(QObject *parent) : QAbstractListModel(parent) { } UsersModel::~UsersModel() { - qDeleteAll(mUsers); } int UsersModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return mUsers.size(); } QVariant UsersModel::data(const QModelIndex &index, int role) const { if (index.row() < 0 || index.row() >= mUsers.count()) { return QVariant(); } - const User *user = mUsers.at(index.row()); + const User &user = mUsers.at(index.row()); switch (role) { case UserName: - return user->name(); + return user.name(); case UserId: - return user->userId(); + return user.userId(); case UserStatus: - return user->status(); + return user.status(); case UserIcon: - return user->iconFromStatus(); + return user.iconFromStatus(); case UserStatusText: - return user->statusText(); + return user.statusText(); } return {}; } QString UsersModel::userStatusIconFileName(const QString &name) const { const int userCount = mUsers.count(); for (int i = 0; i < userCount; ++i) { - if (mUsers.at(i)->userName() == name) { - return mUsers.at(i)->iconFromStatus(); + if (mUsers.at(i).userName() == name) { + return mUsers.at(i).iconFromStatus(); } } //qCWarning(RUQOLA_LOG) << "User for name " << name << " not defined yet"; return QStringLiteral("user-offline"); } QString UsersModel::status(const QString &userId) const { const int userCount = mUsers.count(); for (int i = 0; i < userCount; ++i) { - if (mUsers.at(i)->userId() == userId) { - return mUsers.at(i)->status(); + if (mUsers.at(i).userId() == userId) { + return mUsers.at(i).status(); } } //Return offline as default; return QStringLiteral("offline"); } void UsersModel::removeUser(const QString &userId) { qCDebug(RUQOLA_LOG) << " User removed " << userId; const int userCount = mUsers.count(); for (int i = 0; i < userCount; ++i) { - if (mUsers.at(i)->userId() == userId) { - qCDebug(RUQOLA_LOG) << " User removed " << mUsers.at(i)->name(); + if (mUsers.at(i).userId() == userId) { + qCDebug(RUQOLA_LOG) << " User removed " << mUsers.at(i).name(); //Send info as it's disconnected. But don't remove it from list - User *user = mUsers.at(i); - user->setStatus(QStringLiteral("offline")); + User &user = mUsers[i]; + user.setStatus(QStringLiteral("offline")); const QModelIndex idx = createIndex(i, 0); Q_EMIT userStatusChanged(user); Q_EMIT dataChanged(idx, idx); break; } } } -void UsersModel::addUser(User *newuser) +void UsersModel::addUser(const User &newuser) { //It can be duplicate as we don't remove user from list when user is disconnected. Otherwise it will not sync with // user for room list qCDebug(RUQOLA_LOG) << " User added " << newuser; const int userCount = mUsers.count(); bool found = false; for (int i = 0; i < userCount; ++i) { - if (mUsers.at(i)->userId() == newuser->userId()) { + if (mUsers.at(i).userId() == newuser.userId()) { found = true; - User *user = mUsers.at(i); - user->setStatus(newuser->status()); + User &user = mUsers[i]; + user.setStatus(newuser.status()); const QModelIndex idx = createIndex(i, 0); Q_EMIT userStatusChanged(user); Q_EMIT dataChanged(idx, idx); - delete newuser; break; } } if (!found) { const int pos = mUsers.size(); beginInsertRows(QModelIndex(), pos, pos); mUsers.append(newuser); endInsertRows(); } } void UsersModel::updateUser(const QJsonObject &array) { const QString id = array.value(QLatin1String("id")).toString(); const int userCount = mUsers.count(); for (int i = 0; i < userCount; ++i) { - if (mUsers.at(i)->userId() == id) { - User *user = mUsers.at(i); + if (mUsers.at(i).userId() == id) { + User &user = mUsers[i]; const QJsonObject fields = array.value(QLatin1String("fields")).toObject(); const QString newStatus = fields.value(QLatin1String("status")).toString(); bool userDataChanged = false; if (!newStatus.isEmpty()) { - user->setStatus(newStatus); + user.setStatus(newStatus); const QModelIndex idx = createIndex(i, 0); Q_EMIT dataChanged(idx, idx); Q_EMIT userStatusChanged(user); userDataChanged = true; } const QString newName = fields.value(QLatin1String("name")).toString(); if (!newName.isEmpty()) { - user->setName(newName); + user.setName(newName); const QModelIndex idx = createIndex(i, 0); Q_EMIT dataChanged(idx, idx); Q_EMIT userNameChanged(user); userDataChanged = true; } const QString newuserName = fields.value(QLatin1String("username")).toString(); if (!newuserName.isEmpty()) { - user->setUserName(newuserName); + user.setUserName(newuserName); const QModelIndex idx = createIndex(i, 0); Q_EMIT dataChanged(idx, idx); Q_EMIT nameChanged(user); userDataChanged = true; } const QString statusMessage = fields.value(QLatin1String("statusText")).toString(); if (!statusMessage.isEmpty()) { - user->setStatusText(statusMessage); + user.setStatusText(statusMessage); const QModelIndex idx = createIndex(i, 0); Q_EMIT dataChanged(idx, idx); Q_EMIT statusMessageChanged(user); userDataChanged = true; } if (!userDataChanged) { qCWarning(RUQOLA_LOG) << " Unsupported yet user data modification " << array; } break; } } } diff --git a/src/core/model/usersmodel.h b/src/core/model/usersmodel.h index 3789163b..2da29c34 100644 --- a/src/core/model/usersmodel.h +++ b/src/core/model/usersmodel.h @@ -1,65 +1,65 @@ /* Copyright (c) 2017-2020 Laurent Montel 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 USERSMODEL_H #define USERSMODEL_H #include "libruqola_private_export.h" #include #include "user.h" class LIBRUQOLACORE_TESTS_EXPORT UsersModel : public QAbstractListModel { Q_OBJECT public: enum UserRoles { UserName = Qt::UserRole + 1, UserId, UserStatus, UserIcon, UserStatusText }; Q_ENUM(UserRoles) explicit UsersModel(QObject *parent = nullptr); ~UsersModel() 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; - void addUser(User *userFromUserId); + void addUser(const User &userFromUserId); void removeUser(const QString &userId); void updateUser(const QJsonObject &array); Q_REQUIRED_RESULT QString userStatusIconFileName(const QString &name) const; Q_REQUIRED_RESULT QString status(const QString &userId) const; Q_SIGNALS: - void userStatusChanged(User *user); - void userNameChanged(User *user); - void nameChanged(User *user); - void statusMessageChanged(User *user); + void userStatusChanged(const User &user); + void userNameChanged(const User &user); + void nameChanged(const User &user); + void statusMessageChanged(const User &user); private: Q_DISABLE_COPY(UsersModel) - QVector mUsers; + QVector mUsers; }; #endif // USERSMODEL_H diff --git a/src/core/rocketchataccount.cpp b/src/core/rocketchataccount.cpp index 212beea4..9fca5695 100644 --- a/src/core/rocketchataccount.cpp +++ b/src/core/rocketchataccount.cpp @@ -1,1956 +1,1956 @@ /* Copyright (c) 2017-2020 Laurent Montel 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 "fileattachments.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 "model/discussionsfilterproxymodel.h" #include "model/threadsfilterproxymodel.h" #include "model/listmessagesmodel.h" #include "model/threadmessagemodel.h" #include "model/listmessagesmodelfilterproxymodel.h" #include "model/autotranslatelanguagesmodel.h" #include "managerdatapaths.h" #include "authenticationmanager.h" #include "ddpapi/ddpclient.h" #include "discussions.h" #include "receivetypingnotificationmanager.h" #include "restapirequest.h" #include "serverconfiginfo.h" #include "listmessages.h" #include "threads.h" #include #include #include #include #include #include "users/setstatusjob.h" #include "users/usersautocompletejob.h" #define USE_REASTAPI_JOB 1 RocketChatAccount::RocketChatAccount(const QString &accountFileName, QObject *parent) : QObject(parent) { mAccountRoomSettings = new AccountRoomSettings; qCDebug(RUQOLA_LOG) << " RocketChatAccount::RocketChatAccount(const QString &accountFileName, QObject *parent)"<accountName()); } mServerConfigInfo = new ServerConfigInfo(this, this); //Create it before loading settings mLoginMethodModel = new LoginMethodModel(this); mInputTextManager = new InputTextManager(this); connect(mInputTextManager, &InputTextManager::inputCompleter, this, &RocketChatAccount::inputAutocomplete); mInputThreadMessageTextManager = new InputTextManager(this); connect(mInputThreadMessageTextManager, &InputTextManager::inputCompleter, this, &RocketChatAccount::inputThreadMessageAutocomplete); mRuqolaServerConfig = new RuqolaServerConfig; mReceiveTypingNotificationManager = new ReceiveTypingNotificationManager(this); initializeAuthenticationPlugins(); mRocketChatBackend = new RocketChatBackend(this, this); mEmoticonModel = new EmoticonModel(this); //After loadSettings mEmojiManager = new EmojiManager(this); mEmojiManager->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(QString(), this, nullptr, this); mSearchMessageFilterProxyModel = new SearchMessageFilterProxyModel(mSearchMessageModel, this); mFilesModelForRoom = new FilesForRoomModel(this, this); mFilesModelForRoom->setObjectName(QStringLiteral("filesmodelforrooms")); mFilesForRoomFilterProxyModel = new FilesForRoomFilterProxyModel(mFilesModelForRoom, this); mFilesForRoomFilterProxyModel->setObjectName(QStringLiteral("filesforroomfiltermodelproxy")); mDiscussionsModel = new DiscussionsModel(this); mDiscussionsModel->setObjectName(QStringLiteral("discussionsmodel")); mDiscussionsFilterProxyModel = new DiscussionsFilterProxyModel(mDiscussionsModel, this); mDiscussionsFilterProxyModel->setObjectName(QStringLiteral("discussionsfilterproxymodel")); mThreadsModel = new ThreadsModel(this); mThreadsModel->setObjectName(QStringLiteral("threadsmodel")); mThreadsFilterProxyModel = new ThreadsFilterProxyModel(mThreadsModel, this); mThreadsFilterProxyModel->setObjectName(QStringLiteral("threadsfiltermodelproxy")); mThreadMessageModel = new ThreadMessageModel(QString(), this, nullptr, this); mThreadMessageModel->setObjectName(QStringLiteral("threadmessagemodel")); mListMessageModel = new ListMessagesModel(QString(), this, nullptr, this); mListMessageModel->setObjectName(QStringLiteral("listmessagemodel")); mListMessagesFilterProxyModel = new ListMessagesModelFilterProxyModel(mListMessageModel, this); mListMessagesFilterProxyModel->setObjectName(QStringLiteral("listmessagesfiltermodelproxy")); mAutoTranslateLanguagesModel = new AutotranslateLanguagesModel(this); mAutoTranslateLanguagesModel->setObjectName(QStringLiteral("autotranslatelanguagesmodel")); 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; delete mAccountRoomSettings; } 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 { 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 { return mDiscussionsFilterProxyModel; } ThreadsFilterProxyModel *RocketChatAccount::threadsFilterProxyModel() const { return mThreadsFilterProxyModel; } RoomWrapper *RocketChatAccount::roomWrapper(const QString &roomId) { return mRoomModel->findRoomWrapper(roomId); } MessageModel *RocketChatAccount::messageModelForRoom(const QString &roomID) { return mRoomModel->messageModel(roomID); } void RocketChatAccount::changeDisplayAttachment(const QString &roomId, const QString &messageId, bool displayAttachment) { MessageModel *model = mRoomModel->messageModel(roomId); if (model) { model->changeDisplayAttachment(messageId, displayAttachment); } else { qCWarning(RUQOLA_LOG) << "impossible to find room: " << roomId; } //TODO } void RocketChatAccount::changeShowOriginalMessage(const QString &roomId, const QString &messageId, bool showOriginal) { MessageModel *model = mRoomModel->messageModel(roomId); if (model) { model->changeShowOriginalMessage(messageId, showOriginal); } else { qCWarning(RUQOLA_LOG) << "impossible to find room: " << roomId; } //TODO } 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::textEditing(const QString &roomId, bool clearNotification) { mTypingNotification->textNotificationChanged(roomId, clearNotification); } void RocketChatAccount::reactOnMessage(const QString &messageId, const QString &emoji, bool shouldReact) { restApi()->reactOnMessage(messageId, emoji, shouldReact); } void RocketChatAccount::replyToMessage(const QString &roomID, const QString &message, const QString &messageId) { restApi()->postMessage(roomID, message); } 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); } void RocketChatAccount::replyOnThread(const QString &roomID, const QString &threadMessageId, const QString &message) { restApi()->sendMessage(roomID, message, QString(), threadMessageId); } 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 QUrl &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::loadEmoji); 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, [this](const QJsonObject &obj, const QString &roomId) { slotGetListMessagesDone(obj, roomId, ListMessagesModel::ListMessageType::MentionsMessages); }); connect(mRestApi, &RocketChatRestApi::RestApiRequest::getPinnedMessagesDone, this, [this](const QJsonObject &obj, const QString &roomId) { slotGetListMessagesDone(obj, roomId, ListMessagesModel::ListMessageType::PinnedMessages); }); connect(mRestApi, &RocketChatRestApi::RestApiRequest::getSnippetedMessagesDone, this, [this](const QJsonObject &obj, const QString &roomId) { slotGetListMessagesDone(obj, roomId, ListMessagesModel::ListMessageType::SnipperedMessages); }); connect(mRestApi, &RocketChatRestApi::RestApiRequest::getStarredMessagesDone, this, [this](const QJsonObject &obj, const QString &roomId) { slotGetListMessagesDone(obj, roomId, ListMessagesModel::ListMessageType::StarredMessages); }); connect(mRestApi, &RocketChatRestApi::RestApiRequest::getSupportedLanguagesDone, this, &RocketChatAccount::slotGetSupportedLanguagesDone); connect(mRestApi, &RocketChatRestApi::RestApiRequest::usersPresenceDone, this, &RocketChatAccount::slotUsersPresenceDone); connect(mRestApi, &RocketChatRestApi::RestApiRequest::usersAutocompleteDone, this, &RocketChatAccount::slotUserAutoCompleterDone); connect(mRestApi, &RocketChatRestApi::RestApiRequest::roomsAutoCompleteChannelAndPrivateDone, this, &RocketChatAccount::slotRoomsAutoCompleteChannelAndPrivateDone); mRestApi->setServerUrl(mSettings->serverUrl()); mRestApi->setRestApiLogger(mRuqolaLogger); } return mRestApi; } void RocketChatAccount::leaveRoom(const QString &roomId, const QString &channelType) { if (channelType == QLatin1Char('c')) { restApi()->leaveChannel(roomId); } else if (channelType == QLatin1Char('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); connect(mDdp, &DDPClient::socketError, this, &RocketChatAccount::socketError); connect(mDdp, &DDPClient::disconnectedByServer, this, &RocketChatAccount::slotDisconnectedByServer); 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::clearAllUnreadMessages() { for (int roomIdx = 0, nRooms = mRoomModel->rowCount(); roomIdx < nRooms; ++roomIdx) { const auto roomModelIndex = mRoomModel->index(roomIdx); const auto roomId = roomModelIndex.data(RoomModel::RoomID).toString(); const bool roomHasAlert = roomModelIndex.data(RoomModel::RoomAlert).toBool(); if (roomHasAlert) { clearUnreadMessages(roomId); } } } void RocketChatAccount::clearUnreadMessages(const QString &roomId) { restApi()->markAsRead(roomId); } void RocketChatAccount::changeFavorite(const QString &roomId, bool checked) { restApi()->markAsFavorite(roomId, checked); } void RocketChatAccount::openChannel(const QString &url) { qCDebug(RUQOLA_LOG) << "opening channel" << url; restApi()->channelJoin(url, QString()); //TODO search correct room + select it. } void RocketChatAccount::setChannelJoinDone(const RocketChatRestApi::ChannelBaseJob::ChannelInfo &channelInfo) { //FIXME type of identifier ddp()->subscribeRoomMessage(channelInfo.channelInfoIdentifier); } void RocketChatAccount::openArchivedRoom(const RocketChatRestApi::ChannelBaseJob::ChannelInfo &channelInfo) { //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 = QStringLiteral("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 == QLatin1Char('c')) { restApi()->channelDelete(roomId); } else if (channelType == QLatin1Char('p')) { restApi()->groupDelete(roomId); } else { qCWarning(RUQOLA_LOG) << " unsupport delete for type " << channelType; } } void RocketChatAccount::openDirectChannel(const QString &username) { //Laurent for the moment I didn't find a restapi method for it //TODO verify username vs userId //#ifdef USE_REASTAPI_JOB // restApi()->openDirectMessage(username); //#else qDebug() << "Open direct conversation channel with" << username; 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 encrypted 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) { 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() { restApi()->listEmojiCustom(); } void RocketChatAccount::setDefaultStatus(User::PresenceStatus status, const QString &messageStatus) { #ifdef USE_REASTAPI_JOB RocketChatRestApi::SetStatusJob::StatusType type = RocketChatRestApi::SetStatusJob::Unknown; switch (status) { case User::PresenceStatus::PresenceOnline: type = RocketChatRestApi::SetStatusJob::OnLine; break; case User::PresenceStatus::PresenceBusy: type = RocketChatRestApi::SetStatusJob::Busy; break; case User::PresenceStatus::PresenceAway: type = RocketChatRestApi::SetStatusJob::Away; break; case User::PresenceStatus::PresenceOffline: type = RocketChatRestApi::SetStatusJob::Offline; break; case User::PresenceStatus::Unknown: type = RocketChatRestApi::SetStatusJob::Unknown; break; } restApi()->setUserStatus(userID(), type, messageStatus); #else Q_UNUSED(messageStatus); ddp()->setDefaultStatus(status); #endif } void RocketChatAccount::changeDefaultStatus(int index, const QString &messageStatus) { setDefaultStatus(mStatusModel->status(index), messageStatus); } void RocketChatAccount::loadEmoji(const QJsonObject &obj) { mEmojiManager->loadCustomEmoji(obj); } void RocketChatAccount::deleteMessage(const QString &messageId, const QString &roomId) { restApi()->deleteMessage(roomId, messageId); } void RocketChatAccount::insertCompleterUsers() { userCompleterModel()->insertUsers(rocketChatBackend()->users()); } void RocketChatAccount::userAutocomplete(const QString &searchText, const QString &exception) { userCompleterModel()->clear(); if (mRuqolaServerConfig->hasAtLeastVersion(2, 4, 0)) { if (!searchText.isEmpty()) { RocketChatRestApi::UsersAutocompleteJob::UsersAutocompleterInfo info; info.pattern = searchText; info.exception = exception; restApi()->usersAutocomplete(info); } } else { //Clear before to create new search rocketChatBackend()->clearUsersList(); if (!searchText.isEmpty()) { //Avoid to show own user QString addUserNameToException; if (exception.isEmpty()) { addUserNameToException = userName(); } else { addUserNameToException = exception + QLatin1Char(',') + userName(); } ddp()->userAutocomplete(searchText, addUserNameToException); } } } void RocketChatAccount::membersInRoom(const QString &roomId, const QString &roomType) { restApi()->membersInRoom(roomId, roomType); } void RocketChatAccount::parseUsersForRooms(const QJsonObject &obj, const RocketChatRestApi::ChannelBaseJob::ChannelInfo &channelInfo) { //FIXME channelInfo UsersForRoomModel *usersModelForRoom = roomModel()->usersModelForRoom(channelInfo.channelInfoIdentifier); if (usersModelForRoom) { usersModelForRoom->parseUsersForRooms(obj, mUserModel, true); } else { qCWarning(RUQOLA_LOG) << " Impossible to find room " << channelInfo.channelInfoIdentifier; } } void RocketChatAccount::loadAutoCompleteChannel(const QJsonObject &obj) { mSearchChannelModel->parseChannels(obj); } void RocketChatAccount::roomFiles(const QString &roomId, const QString &channelType) { mFilesModelForRoom->initialize(); restApi()->filesInRoom(roomId, channelType); } MessageModel *RocketChatAccount::threadMessageModel() const { return mThreadMessageModel; } ThreadsModel *RocketChatAccount::threadsModel() const { return mThreadsModel; } DiscussionsModel *RocketChatAccount::discussionsModel() const { return mDiscussionsModel; } FilesForRoomModel *RocketChatAccount::filesModelForRoom() const { return mFilesModelForRoom; } EmoticonModel *RocketChatAccount::emoticonModel() const { return mEmoticonModel; } ReceiveTypingNotificationManager *RocketChatAccount::receiveTypingNotificationManager() const { return mReceiveTypingNotificationManager; } void RocketChatAccount::slotChannelRolesDone(const QJsonObject &obj, const RocketChatRestApi::ChannelBaseJob::ChannelInfo &channelInfo) { Room *room = mRoomModel->findRoom(channelInfo.channelInfoIdentifier); if (room) { Roles r; r.parseRole(obj); room->setRolesForRooms(r); } else { qCWarning(RUQOLA_LOG) << " Impossible to find room " << channelInfo.channelInfoIdentifier; } } void RocketChatAccount::slotGetThreadMessagesDone(const QJsonObject &obj, const QString &threadMessageId) { if (mThreadMessageModel->threadMessageId() != threadMessageId) { mThreadMessageModel->setThreadMessageId(threadMessageId); mThreadMessageModel->parseThreadMessages(obj); } else { mThreadMessageModel->loadMoreThreadMessages(obj); } } void RocketChatAccount::slotGetDiscussionsListDone(const QJsonObject &obj, const QString &roomId) { if (mDiscussionsModel->roomId() != roomId) { mDiscussionsModel->parseDiscussions(obj, roomId); } else { mDiscussionsModel->addMoreDiscussions(obj); } mDiscussionsModel->setLoadMoreDiscussionsInProgress(false); } void RocketChatAccount::slotGetListMessagesDone(const QJsonObject &obj, const QString &roomId, ListMessagesModel::ListMessageType type) { if (mListMessageModel->roomId() != roomId || mListMessageModel->listMessageType() != type) { mListMessageModel->setRoomId(roomId); mListMessageModel->setListMessageType(type); mListMessageModel->parseListMessages(obj); } else { mListMessageModel->loadMoreListMessages(obj); } mListMessageModel->setLoadMoreListMessagesInProgress(false); } void RocketChatAccount::slotUserAutoCompleterDone(const QJsonObject &obj) { const QVector users = User::parseUsersList(obj); mUserCompleterModel->insertUsers(users); } void RocketChatAccount::slotRoomsAutoCompleteChannelAndPrivateDone(const QJsonObject &obj) { //TODO } AccountRoomSettings *RocketChatAccount::accountRoomSettings() const { return mAccountRoomSettings; } ListMessagesModelFilterProxyModel *RocketChatAccount::listMessagesFilterProxyModel() const { return mListMessagesFilterProxyModel; } ListMessagesModel *RocketChatAccount::listMessageModel() const { return mListMessageModel; } void RocketChatAccount::slotGetThreadsListDone(const QJsonObject &obj, const QString &roomId) { if (mThreadsModel->roomId() != roomId) { mThreadsModel->parseThreads(obj, roomId); } else { mThreadsModel->addMoreThreads(obj); } mThreadsModel->setLoadMoreThreadsInProgress(false); } void RocketChatAccount::slotSplotLightDone(const QJsonObject &obj) { //qDebug() << " void RocketChatAccount::slotSplotLightDone(const QJsonObject &obj)"<roomId() != channelInfo.channelInfoIdentifier) { mFilesModelForRoom->parseFileAttachments(obj, channelInfo.channelInfoIdentifier); } else { mFilesModelForRoom->addMoreFileAttachments(obj); } mFilesModelForRoom->setLoadMoreFilesInProgress(false); } void RocketChatAccount::loadMoreUsersInRoom(const QString &roomId, const QString &channelType) { UsersForRoomModel *usersModelForRoom = roomModel()->usersModelForRoom(roomId); const int offset = usersModelForRoom->usersCount(); if (offset < usersModelForRoom->total()) { restApi()->membersInRoom(roomId, channelType, offset, qMin(50, usersModelForRoom->total() - offset)); } } void RocketChatAccount::getMentionsMessages(const QString &roomId) { mListMessageModel->clear(); mListMessageModel->setRoomId(roomId); restApi()->channelGetAllUserMentions(roomId); } void RocketChatAccount::getPinnedMessages(const QString &roomId) { if (hasPinnedMessagesSupport()) { mListMessageModel->clear(); mListMessageModel->setRoomId(roomId); restApi()->getPinnedMessages(roomId); } else { qCWarning(RUQOLA_LOG) << " RocketChatAccount::getPinnedMessages is not supported before server 2.0.0"; } } bool RocketChatAccount::hasPinnedMessagesSupport() const { return mRuqolaServerConfig->hasAtLeastVersion(1, 4, 0); } bool RocketChatAccount::hasStarredMessagesSupport() const { return mRuqolaServerConfig->hasAtLeastVersion(2, 3, 0); } void RocketChatAccount::getStarredMessages(const QString &roomId) { if (hasStarredMessagesSupport()) { mListMessageModel->clear(); mListMessageModel->setRoomId(roomId); restApi()->getStarredMessages(roomId); } else { qCWarning(RUQOLA_LOG) << " RocketChatAccount::getStarredMessages is not supported before server 2.3.0"; } } bool RocketChatAccount::hasSnippetedMessagesSupport() const { return mRuqolaServerConfig->hasAtLeastVersion(2, 3, 0); } void RocketChatAccount::getSnippetedMessages(const QString &roomId) { if (hasSnippetedMessagesSupport()) { mListMessageModel->clear(); mListMessageModel->setRoomId(roomId); restApi()->getSnippetedMessages(roomId); } else { qCWarning(RUQOLA_LOG) << " RocketChatAccount::getSnippetedMessages is not supported before server 2.3.0"; } } void RocketChatAccount::loadMoreFileAttachments(const QString &roomId, const QString &channelType) { if (!mFilesModelForRoom->loadMoreFilesInProgress()) { const int offset = mFilesModelForRoom->fileAttachments()->filesCount(); if (offset < mFilesModelForRoom->fileAttachments()->total()) { mFilesModelForRoom->setLoadMoreFilesInProgress(true); restApi()->filesInRoom(roomId, channelType, offset, qMin(50, mFilesModelForRoom->fileAttachments()->total() - offset)); } } } void RocketChatAccount::loadMoreDiscussions(const QString &roomId) { if (!mDiscussionsModel->loadMoreDiscussionsInProgress()) { const int offset = mDiscussionsModel->discussions()->discussionsCount(); if (offset < mDiscussionsModel->discussions()->total()) { mDiscussionsModel->setLoadMoreDiscussionsInProgress(true); restApi()->getDiscussions(roomId, offset, qMin(50, mDiscussionsModel->discussions()->total() - offset)); } } } void RocketChatAccount::updateThreadMessageList(const Message &m) { if (mThreadMessageModel->threadMessageId() == m.threadMessageId()) { mThreadMessageModel->addMessage(m); } } void RocketChatAccount::loadMoreThreads(const QString &roomId) { if (!mThreadsModel->loadMoreThreadsInProgress()) { const int offset = mThreadsModel->threads()->threadsCount(); if (offset < mThreadsModel->threads()->total()) { restApi()->getThreadsList(roomId, offset, qMin(50, mThreadsModel->threads()->total() - offset)); } } } void RocketChatAccount::getListMessages(const QString &roomId, ListMessagesModel::ListMessageType type) { mListMessageModel->setListMessageType(type); switch (type) { case ListMessagesModel::Unknown: qCWarning(RUQOLA_LOG) << " Error when using getListMessages"; break; case ListMessagesModel::StarredMessages: if (hasStarredMessagesSupport()) { getStarredMessages(roomId); } break; case ListMessagesModel::SnipperedMessages: if (hasSnippetedMessagesSupport()) { getSnippetedMessages(roomId); } break; case ListMessagesModel::PinnedMessages: getPinnedMessages(roomId); break; case ListMessagesModel::MentionsMessages: getMentionsMessages(roomId); break; } } QUrl RocketChatAccount::urlForLink(const QString &link) const { return mCache->urlForLink(link); } void RocketChatAccount::loadMoreListMessages(const QString &roomId) { if (!mListMessageModel->loadMoreListMessagesInProgress()) { const int offset = mListMessageModel->rowCount(); if (offset < mListMessageModel->total()) { switch (mListMessageModel->listMessageType()) { case ListMessagesModel::Unknown: qCWarning(RUQOLA_LOG) << " Error when using loadMoreListMessages"; break; case ListMessagesModel::StarredMessages: if (hasStarredMessagesSupport()) { restApi()->getStarredMessages(roomId, offset, qMin(50, mListMessageModel->total() - offset)); } break; case ListMessagesModel::SnipperedMessages: if (hasSnippetedMessagesSupport()) { restApi()->getSnippetedMessages(roomId, offset, qMin(50, mListMessageModel->total() - offset)); } break; case ListMessagesModel::PinnedMessages: restApi()->getPinnedMessages(roomId, offset, qMin(50, mListMessageModel->total() - offset)); break; case ListMessagesModel::MentionsMessages: restApi()->channelGetAllUserMentions(roomId, offset, qMin(50, mListMessageModel->total() - offset)); break; } } } } void RocketChatAccount::loadThreadMessagesHistory(const QString &threadMessageId) { restApi()->getThreadMessages(threadMessageId); } 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 == QLatin1Char('c')) { restApi()->addUserInChannel(roomId, userId); } else if (channelType == QLatin1Char('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->parse(obj); } 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 == QLatin1Char('c')) { restApi()->changeChannelAnnouncement(roomId, newValue.toString()); } else if (channelType == QLatin1Char('p')) { restApi()->changeGroupsAnnouncement(roomId, newValue.toString()); } else { qCWarning(RUQOLA_LOG) << " unsupport change announcement for type " << channelType; } break; case Description: if (channelType == QLatin1Char('c')) { restApi()->changeChannelDescription(roomId, newValue.toString()); } else if (channelType == QLatin1Char('p')) { restApi()->changeGroupsDescription(roomId, newValue.toString()); } else { qCWarning(RUQOLA_LOG) << " unsupport change description for type " << channelType; } break; case Name: if (channelType == QLatin1Char('c')) { restApi()->changeChannelName(roomId, newValue.toString()); } else if (channelType == QLatin1Char('p')) { restApi()->changeGroupName(roomId, newValue.toString()); } else { qCWarning(RUQOLA_LOG) << " unsupport change name for type " << channelType; } break; case Topic: if (channelType == QLatin1Char('c')) { restApi()->changeChannelTopic(roomId, newValue.toString()); } else if (channelType == QLatin1Char('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 == QLatin1Char('c')) { restApi()->changeChannelReadOnly(roomId, newValue.toBool()); } else if (channelType == QLatin1Char('p')) { restApi()->changeGroupsReadOnly(roomId, newValue.toBool()); } else { qCWarning(RUQOLA_LOG) << " unsupport change readonly for type " << channelType; } break; case Archive: if (channelType == QLatin1Char('c')) { restApi()->archiveChannel(roomId, newValue.toBool()); } else if (channelType == QLatin1Char('p')) { restApi()->archiveGroups(roomId, newValue.toBool()); } else { qCWarning(RUQOLA_LOG) << " unsupport archiving for type " << channelType; } break; case RoomType: if (channelType == QLatin1Char('c')) { restApi()->setChannelType(roomId, newValue.toBool()); } else if (channelType == QLatin1Char('p')) { restApi()->setGroupType(roomId, newValue.toBool()); } else { qCWarning(RUQOLA_LOG) << " unsupport roomtype for type " << channelType; } break; case Encrypted: if (channelType == QLatin1Char('c')) { restApi()->changeChannelEncrypted(roomId, newValue.toBool()); } else if (channelType == QLatin1Char('p')) { restApi()->changeGroupsEncrypted(roomId, newValue.toBool()); } else { qCWarning(RUQOLA_LOG) << " unsupport encrypted mode for type " << channelType; } break; case Password: //FIXME channel type ??? //restApi()->setJoinCodeChannel(roomId, newValue.toString()); break; } } void RocketChatAccount::reportMessage(const QString &messageId, const QString &message) { restApi()->reportMessage(messageId, message); } void RocketChatAccount::getThreadMessages(const QString &threadMessageId) { mThreadMessageModel->clear(); restApi()->getThreadMessages(threadMessageId); } 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 if (id == QLatin1String("AutoTranslate_Enabled")) { mRuqolaServerConfig->setAutoTranslateEnabled(value.toBool()); } else if (id == QLatin1String("AutoTranslate_GoogleAPIKey")) { mRuqolaServerConfig->setAutoTranslateGoogleKey(value.toString()); } else { qCDebug(RUQOLA_LOG) << "Other public settings id " << id << value; } //TODO add Accounts_AllowUserStatusMessageChange when we will have a RestAPI method for it. } fillOauthModel(); Q_EMIT publicSettingChanged(); } 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(); if (lstPlugins.isEmpty()) { qCWarning(RUQOLA_LOG) <<" No plugins loaded. Please verify your installation."; } 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; } 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(); } QString RocketChatAccount::twoFactorAuthenticationCode() const { return settings()->twoFactorAuthenticationCode(); } void RocketChatAccount::setAuthToken(const QString &token) { settings()->setAuthToken(token); } void RocketChatAccount::setPassword(const QString &password) { settings()->setPassword(password); } void RocketChatAccount::setTwoFactorAuthenticationCode(const QString &twoFactorAuthenticationCode) { settings()->setTwoFactorAuthenticationCode(twoFactorAuthenticationCode); } void RocketChatAccount::setAccountEnabled(bool enabled) { settings()->setAccountEnabled(enabled); } void RocketChatAccount::setUserName(const QString &username) { settings()->setUserName(username); } bool RocketChatAccount::accountEnabled() const { return settings()->accountEnabled(); } 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); Q_EMIT serverVersionChanged(); } 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::autoTranslateEnabled() const { return mRuqolaServerConfig->autoTranslateEnabled(); } 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::setSortUnreadOnTop(bool b) { if (settings()->setShowUnreadOnTop(b)) { mRoomFilterProxyModel->invalidate(); Q_EMIT sortUnreadOnTopChanged(); } } bool RocketChatAccount::sortUnreadOnTop() const { return settings()->showUnreadOnTop(); } void RocketChatAccount::kickUser(const QString &roomId, const QString &userId, const QString &channelType) { if (channelType == QLatin1Char('c')) { restApi()->channelKick(roomId, userId); } else if (channelType == QLatin1Char('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 == QLatin1Char('c')) { restApi()->getChannelRoles(roomId); } else if (channelType == QLatin1Char('p')) { restApi()->getGroupRoles(roomId); } else if (channelType == QLatin1Char('d')) { //No a problem here. } 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 == QLatin1Char('c')) { switch (roleType) { case RocketChatAccount::AddOwner: restApi()->channelAddOwner(roomId, userId); break; case RocketChatAccount::AddLeader: restApi()->channelAddLeader(roomId, userId); break; case RocketChatAccount::AddModerator: restApi()->channelAddModerator(roomId, userId); break; case RocketChatAccount::RemoveOwner: restApi()->channelRemoveOwner(roomId, userId); break; case RocketChatAccount::RemoveLeader: restApi()->channelRemoveLeader(roomId, userId); break; case RocketChatAccount::RemoveModerator: restApi()->channelRemoveModerator(roomId, userId); break; } } else if (channelType == QLatin1Char('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) { qCWarning(RUQOLA_LOG) << " NOT IMPLEMENTED YET"; //const Otr t = mOtrManager->parseOtr(contents); //qDebug() << " void RocketChatAccount::parseOtr(const QJsonArray &contents)"<avatarUrlFromCacheOnly(sender); //qDebug() << " iconFileName"<inputChannelAutocomplete(pattern, exceptions); break; case InputTextManager::CompletionForType::User: ddp()->inputUserAutocomplete(pattern, exceptions); break; } } void RocketChatAccount::inputThreadMessageAutocomplete(const QString &pattern, const QString &exceptions, InputTextManager::CompletionForType type) { //qDebug() << " void RocketChatAccount::inputThreadMessageAutocomplete(const QString &pattern, const QString &exceptions, InputTextManager::CompletionForType type)" << pattern; switch (type) { case InputTextManager::CompletionForType::Channel: ddp()->inputChannelAutocomplete(pattern, exceptions); break; case InputTextManager::CompletionForType::User: ddp()->inputUserAutocomplete(pattern, exceptions); break; } } AutotranslateLanguagesModel *RocketChatAccount::autoTranslateLanguagesModel() const { return mAutoTranslateLanguagesModel; } void RocketChatAccount::updateUser(const QJsonObject &object) { mUserModel->updateUser(object); } -void RocketChatAccount::userStatusChanged(User *user) +void RocketChatAccount::userStatusChanged(const User &user) { - if (user->userId() == userID()) { - const User::PresenceStatus status = Utils::presenceStatusFromString(user->status()); + if (user.userId() == userID()) { + const User::PresenceStatus status = Utils::presenceStatusFromString(user.status()); statusModel()->setCurrentPresenceStatus(status); Q_EMIT userStatusUpdated(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*/); } else if (!r) { qWarning() << " Room " << roomId << " was no found! Need to open it"; //openDirectChannel(roomId); } QMetaObject::invokeMethod(this, &RocketChatAccount::switchedRooms, Qt::QueuedConnection); } void RocketChatAccount::openDocumentation() { QDesktopServices::openUrl(QUrl(QStringLiteral("help:/"))); } 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, const QStringList &users) { restApi()->createDiscussion(parentRoomId, discussionName, replyMessage, messageId, users); } void RocketChatAccount::threadsInRoom(const QString &roomId) { mThreadsModel->initialize(); restApi()->getThreadsList(roomId); } void RocketChatAccount::discussionsInRoom(const QString &roomId) { mDiscussionsModel->initialize(); restApi()->getDiscussions(roomId); } void RocketChatAccount::followMessage(const QString &messageId, bool follow) { if (follow) { restApi()->followMessage(messageId); } else { restApi()->unFollowMessage(messageId); } } void RocketChatAccount::getSupportedLanguages() { if (mRuqolaServerConfig->hasAtLeastVersion(1, 99, 0) && autoTranslateEnabled()) { restApi()->getSupportedLanguagesMessages(); } else { qCWarning(RUQOLA_LOG) << " RocketChatAccount::getSupportedLanguages is not supported before server 2.0.0"; } } void RocketChatAccount::slotGetSupportedLanguagesDone(const QJsonObject &obj) { mAutoTranslateLanguagesModel->parseLanguages(obj); } void RocketChatAccount::autoTranslateSaveLanguageSettings(const QString &roomId, const QString &language) { if (mRuqolaServerConfig->hasAtLeastVersion(1, 99, 0)) { restApi()->autoTranslateSaveLanguageSettings(roomId, language); } else { qCWarning(RUQOLA_LOG) << " RocketChatAccount::autoTranslateSaveLanguageSettings is not supported before server 2.0.0"; } } void RocketChatAccount::autoTranslateSaveAutoTranslateSettings(const QString &roomId, bool autoTranslate) { if (mRuqolaServerConfig->hasAtLeastVersion(1, 99, 0)) { restApi()->autoTranslateSaveAutoTranslateSettings(roomId, autoTranslate); } else { qCWarning(RUQOLA_LOG) << " RocketChatAccount::autoTranslateSaveLanguageSettings is not supported before server 2.0.0"; } } void RocketChatAccount::slotUsersPresenceDone(const QJsonObject &obj) { qDebug() << " void RocketChatAccount::slotUsersPresenceDone(const QJsonObject &obj)" << obj; } void RocketChatAccount::slotDisconnectedByServer() { //Laurent: disable it for the moment otherwise when we logout we are unable to add password in login page. Need to improve it first :) return; // This happens when we didn't react to pings for a while // (e.g. while stopped in gdb, or if network went down for a bit) // Let's try connecting in again // TODO: delay this more and more like RC+ ? QTimer::singleShot(100, this, [this]() { qCDebug(RUQOLA_LOG) << "Attempting to reconnect after the server disconnected us"; // Do the parts of logOut() that don't actually try talking to the server mRoomModel->clear(); delete mDdp; mDdp = nullptr; tryLogin(); }); } void RocketChatAccount::usersPresence() { restApi()->usersPresence(); } void RocketChatAccount::customUsersStatus() { if (mRuqolaServerConfig->hasAtLeastVersion(2, 4, 0)) { restApi()->customUserStatus(); } else { qCWarning(RUQOLA_LOG) << " RocketChatAccount::customUserStatus is not supported before server 2.4.0"; } } void RocketChatAccount::initializeAccount() { listEmojiCustom(); //load when necessary //account->usersPresence(); if (mRuqolaServerConfig->autoTranslateEnabled()) { getSupportedLanguages(); } //Force set online. //TODO don't reset message status ! ddp()->setDefaultStatus(User::PresenceStatus::PresenceOnline); //customUsersStatus(); Only for test } diff --git a/src/core/rocketchataccount.h b/src/core/rocketchataccount.h index 239a0095..6e0e04dc 100644 --- a/src/core/rocketchataccount.h +++ b/src/core/rocketchataccount.h @@ -1,510 +1,510 @@ /* Copyright (c) 2017-2020 Laurent Montel 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 #include #include "messages/message.h" #include "rocketchataccountsettings.h" #include "libruqolacore_export.h" #include "authenticationinfo.h" #include "file.h" #include "inputtextmanager.h" #include "accountroomsettings.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 FilesForRoomFilterProxyModel; class FilesForRoomModel; class SearchChannelModel; class SearchChannelFilterProxyModel; class LoginMethodModel; class InputTextManager; class PluginAuthenticationInterface; class Room; class SearchMessageModel; class SearchMessageFilterProxyModel; class ThreadsFilterProxyModel; class ServerConfigInfo; class ReceiveTypingNotificationManager; class EmoticonModel; class DiscussionsFilterProxyModel; class DiscussionsModel; class ThreadsModel; class ThreadMessageModel; class ListMessagesModel; class ListMessagesModelFilterProxyModel; class AutotranslateLanguagesModel; 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(QString twoFactorAuthenticationCode READ twoFactorAuthenticationCode WRITE setTwoFactorAuthenticationCode NOTIFY twoFactorAuthenticationCodeChanged) Q_PROPERTY(DDPClient::LoginStatus loginStatus READ loginStatus NOTIFY loginStatusChanged) Q_PROPERTY(bool editingMode READ editingMode NOTIFY editingModeChanged) Q_PROPERTY(bool sortUnreadOnTop READ sortUnreadOnTop NOTIFY sortUnreadOnTopChanged) Q_PROPERTY(bool autoTranslateEnabled READ autoTranslateEnabled CONSTANT) Q_PROPERTY(bool jitsiEnabled READ jitsiEnabled CONSTANT) Q_PROPERTY(bool encryptedEnabled READ encryptedEnabled CONSTANT) Q_PROPERTY(bool allowMessagePinningEnabled READ allowMessagePinningEnabled CONSTANT) Q_PROPERTY(bool allowMessageSnippetingEnabled READ allowMessageSnippetingEnabled CONSTANT) Q_PROPERTY(bool allowMessageStarringEnabled READ allowMessageStarringEnabled CONSTANT) Q_PROPERTY(bool allowMessageDeletingEnabled READ allowMessageDeletingEnabled CONSTANT) Q_PROPERTY(bool threadsEnabled READ threadsEnabled CONSTANT) Q_PROPERTY(bool discussionEnabled READ discussionEnabled CONSTANT) Q_PROPERTY(bool hasPinnedMessagesSupport READ hasPinnedMessagesSupport CONSTANT) Q_PROPERTY(bool hasSnippetedMessagesSupport READ hasSnippetedMessagesSupport CONSTANT) Q_PROPERTY(bool hasStarredMessagesSupport READ hasStarredMessagesSupport CONSTANT) Q_PROPERTY(bool allowEditingMessages READ allowEditingMessages CONSTANT) Q_PROPERTY(bool otrEnabled READ otrEnabled CONSTANT) Q_PROPERTY(ServerConfigInfo* serverConfigInfo READ serverConfigInfo CONSTANT) Q_PROPERTY(AutotranslateLanguagesModel* autoTranslateLanguagesModel READ autoTranslateLanguagesModel CONSTANT) Q_PROPERTY(QString recordingVideoPath READ recordingVideoPath CONSTANT) Q_PROPERTY(QString recordingImagePath READ recordingImagePath CONSTANT) Q_PROPERTY(LoginMethodModel* loginMethodModel READ loginMethodModel CONSTANT) Q_PROPERTY(StatusModel* statusModel READ statusModel CONSTANT) Q_PROPERTY(DiscussionsFilterProxyModel* discussionsFilterProxyModel READ discussionsFilterProxyModel CONSTANT) Q_PROPERTY(SearchChannelFilterProxyModel* searchChannelFilterProxyModel READ searchChannelFilterProxyModel CONSTANT) Q_PROPERTY(InputTextManager* inputTextManager READ inputTextManager CONSTANT) Q_PROPERTY(InputTextManager* inputThreadMessageTextManager READ inputThreadMessageTextManager CONSTANT) Q_PROPERTY(ThreadsFilterProxyModel* threadsFilterProxyModel READ threadsFilterProxyModel CONSTANT) Q_PROPERTY(MessageModel* threadMessageModel READ threadMessageModel CONSTANT) Q_PROPERTY(EmoticonModel* emoticonModel READ emoticonModel CONSTANT) Q_PROPERTY(FilesForRoomFilterProxyModel* filesForRoomFilterProxyModel READ filesForRoomFilterProxyModel CONSTANT) Q_PROPERTY(SearchMessageFilterProxyModel* searchMessageFilterProxyModel READ searchMessageFilterProxyModel CONSTANT) Q_PROPERTY(ListMessagesModelFilterProxyModel* listMessagesFilterProxyModel READ listMessagesFilterProxyModel CONSTANT) Q_PROPERTY(RoomFilterProxyModel* roomFilterProxyModel READ roomFilterProxyModel CONSTANT) Q_PROPERTY(UsersModel* usersModel READ usersModel CONSTANT) Q_PROPERTY(ReceiveTypingNotificationManager* receiveTypingNotificationManager READ receiveTypingNotificationManager CONSTANT) Q_PROPERTY(UserCompleterFilterProxyModel* userCompleterFilterModelProxy READ userCompleterFilterModelProxy CONSTANT) public: explicit RocketChatAccount(const QString &accountName = QString(), QObject *parent = nullptr); ~RocketChatAccount() override; enum RoomInfoType { Announcement, Description, Name, Topic, ReadOnly, Archive, RoomType, Encrypted, Password }; 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 Q_REQUIRED_RESULT QString getUserCurrentMessage(const QString &roomId); Q_INVOKABLE void setUserCurrentMessage(const QString &message, const QString &roomId); Q_INVOKABLE void textEditing(const QString &roomId, bool clearNotification); 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 clearAllUnreadMessages(); 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 replyOnThread(const QString &roomID, const QString &threadMessageId, 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 setDefaultStatus(User::PresenceStatus status, const QString &messageStatus); //Move to private no ? Q_INVOKABLE void changeDefaultStatus(int index, const QString &messageStatus); 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 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 Q_REQUIRED_RESULT QString avatarUrl(const QString &userId); 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 void channelAndPrivateAutocomplete(const QString &pattern); Q_INVOKABLE void roomFiles(const QString &roomId, const QString &channelType = QString()); Q_INVOKABLE void addUserToRoom(const QString &username, const QString &roomId, const QString &channelType); Q_INVOKABLE void changeDefaultAuthentication(int index); Q_INVOKABLE void messageSearch(const QString &pattern, const QString &rid); InputTextManager *inputTextManager() const { return mInputTextManager; } InputTextManager *inputThreadMessageTextManager() const { return mInputThreadMessageTextManager; } Q_INVOKABLE void blockUser(const QString &userId, bool block); Q_INVOKABLE Q_REQUIRED_RESULT 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 void channelInfo(const QString &roomId); Q_INVOKABLE void groupInfo(const QString &roomId); Q_INVOKABLE void switchEditingMode(bool b); Q_INVOKABLE void setSortUnreadOnTop(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, const QStringList &users = QStringList()); Q_INVOKABLE void threadsInRoom(const QString &roomId); Q_INVOKABLE void discussionsInRoom(const QString &roomId); Q_INVOKABLE void followMessage(const QString &messageId, bool follow); Q_INVOKABLE void replyToMessage(const QString &roomID, const QString &message, const QString &messageId); Q_INVOKABLE void loadMoreFileAttachments(const QString &roomId, const QString &channelType); Q_INVOKABLE void loadMoreDiscussions(const QString &roomId); Q_INVOKABLE void loadMoreThreads(const QString &roomId); Q_INVOKABLE void loadThreadMessagesHistory(const QString &roomId); Q_INVOKABLE void loadMoreUsersInRoom(const QString &roomId, const QString &channelType); Q_INVOKABLE void getPinnedMessages(const QString &roomId); Q_INVOKABLE void getStarredMessages(const QString &roomId); Q_INVOKABLE void getSnippetedMessages(const QString &roomId); Q_INVOKABLE void getMentionsMessages(const QString &roomId); Q_INVOKABLE void autoTranslateSaveLanguageSettings(const QString &roomId, const QString &language); Q_INVOKABLE void autoTranslateSaveAutoTranslateSettings(const QString &roomId, bool autoTranslate); Q_INVOKABLE UsersForRoomFilterProxyModel *usersForRoomFilterProxyModel(const QString &roomId) const; Q_INVOKABLE RoomWrapper *roomWrapper(const QString &roomId); Q_INVOKABLE MessageModel *messageModelForRoom(const QString &roomID); Q_INVOKABLE void changeDisplayAttachment(const QString &roomId, const QString &messageId, bool displayAttachment); Q_INVOKABLE void changeShowOriginalMessage(const QString &roomId, const QString &messageId, bool showOriginal); Q_INVOKABLE void loadMoreListMessages(const QString &roomId); Q_INVOKABLE void getListMessages(const QString &roomId, ListMessagesModel::ListMessageType type); QUrl urlForLink(const QString &link) const; SearchMessageFilterProxyModel *searchMessageFilterProxyModel() const; FilesForRoomFilterProxyModel *filesForRoomFilterProxyModel() const; ReceiveTypingNotificationManager *receiveTypingNotificationManager() const; UserCompleterFilterProxyModel *userCompleterFilterModelProxy() const; UsersModel *usersModel() const; RoomFilterProxyModel *roomFilterProxyModel() const; MessageModel *threadMessageModel() const; EmoticonModel *emoticonModel() const; SearchChannelFilterProxyModel *searchChannelFilterProxyModel() const; AutotranslateLanguagesModel *autoTranslateLanguagesModel() const; DiscussionsFilterProxyModel *discussionsFilterProxyModel() const; SearchChannelModel *searchChannelModel() const; UserCompleterModel *userCompleterModel() const; RocketChatAccountSettings *settings() const; ThreadsFilterProxyModel *threadsFilterProxyModel() const; DDPClient *ddp(); RoomModel *roomModel() const; LoginMethodModel *loginMethodModel() const; Q_REQUIRED_RESULT bool editingMode() const; Q_REQUIRED_RESULT QString serverVersionStr() const; Q_REQUIRED_RESULT bool sortUnreadOnTop() const; Q_REQUIRED_RESULT 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 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 setTwoFactorAuthenticationCode(const QString &twoFactorAuthenticationCode); Q_REQUIRED_RESULT QString twoFactorAuthenticationCode() 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 RocketChatRestApi::ChannelBaseJob::ChannelInfo &channelInfo); void loadAutoCompleteChannel(const QJsonObject &obj); void insertCompleterUsers(); PluginAuthenticationInterface *defaultAuthenticationInterface() const; SearchMessageModel *searchMessageModel() const; void updateUser(const QJsonObject &object); void removeSettings(); void rolesChanged(const QJsonArray &contents); FilesForRoomModel *filesModelForRoom() const; DiscussionsModel *discussionsModel() const; ThreadsModel *threadsModel() const; Q_REQUIRED_RESULT bool encryptedEnabled() const; void updateThreadMessageList(const Message &m); void initializeAccount(); Q_REQUIRED_RESULT bool allowEditingMessages() const; Q_REQUIRED_RESULT bool otrEnabled() const; ListMessagesModel *listMessageModel() const; ListMessagesModelFilterProxyModel *listMessagesFilterProxyModel() const; Q_REQUIRED_RESULT ServerConfigInfo *serverConfigInfo() const; Q_REQUIRED_RESULT QString serverUrl() const; Q_REQUIRED_RESULT StatusModel *statusModel() const; void customUsersStatus(); Q_REQUIRED_RESULT bool jitsiEnabled() const; Q_REQUIRED_RESULT bool allowMessagePinningEnabled() const; Q_REQUIRED_RESULT bool allowMessageSnippetingEnabled() const; Q_REQUIRED_RESULT bool allowMessageStarringEnabled() const; Q_REQUIRED_RESULT bool allowMessageDeletingEnabled() const; Q_REQUIRED_RESULT bool hasPinnedMessagesSupport() const; Q_REQUIRED_RESULT bool hasStarredMessagesSupport() const; Q_REQUIRED_RESULT bool hasSnippetedMessagesSupport() const; Q_REQUIRED_RESULT bool autoTranslateEnabled() const; Q_REQUIRED_RESULT bool threadsEnabled() const; Q_REQUIRED_RESULT bool discussionEnabled() const; Q_REQUIRED_RESULT QString recordingVideoPath() const; Q_REQUIRED_RESULT QString recordingImagePath() const; void setAccountEnabled(bool enabled); Q_REQUIRED_RESULT bool accountEnabled() const; void insertAvatarUrl(const QString &userId, const QUrl &url); Q_REQUIRED_RESULT AccountRoomSettings *accountRoomSettings() const; Q_SIGNALS: void connectedChanged(); void accountNameChanged(); void userNameChanged(); void userIDChanged(); void passwordChanged(); void twoFactorAuthenticationCodeChanged(); void serverUrlChanged(); void loginStatusChanged(); void socketError(QAbstractSocket::SocketError error, const QString &errorString); 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 RocketChatRestApi::ChannelBaseJob::ChannelInfo &channelInfo); void editingModeChanged(); void sortUnreadOnTopChanged(); void jobFailed(const QString &message); void switchedRooms(); void userStatusUpdated(User::PresenceStatus status); void publicSettingChanged(); void serverVersionChanged(); void openLinkRequested(const QString &link); private: Q_DISABLE_COPY(RocketChatAccount) Room *getRoom(const QString &roomId); void slotChannelFilesDone(const QJsonObject &obj, const RocketChatRestApi::ChannelBaseJob::ChannelInfo &channelInfo); void slotChannelRolesDone(const QJsonObject &obj, const RocketChatRestApi::ChannelBaseJob::ChannelInfo &channelInfo); 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 slotGetSupportedLanguagesDone(const QJsonObject &obj); void slotUsersPresenceDone(const QJsonObject &obj); void slotSocketError(QAbstractSocket::SocketError error, const QString &errorString); void slotDisconnectedByServer(); void loadEmoji(const QJsonObject &obj); void slotSearchMessages(const QJsonObject &obj); void slotNeedToUpdateNotification(); void loadSettings(const QString &accountFileName); void clearModels(); void fillOauthModel(); void initializeAuthenticationPlugins(); void setDefaultAuthentication(AuthenticationManager::OauthType type); - void userStatusChanged(User *user); + void userStatusChanged(const User &user); void setChannelJoinDone(const RocketChatRestApi::ChannelBaseJob::ChannelInfo &channelInfo); void openArchivedRoom(const RocketChatRestApi::ChannelBaseJob::ChannelInfo &channelInfo); void getSupportedLanguages(); void usersPresence(); void listEmojiCustom(); void checkInitializedRoom(const QString &roomId); void clearTypingNotification(); void inputAutocomplete(const QString &pattern, const QString &exceptions, InputTextManager::CompletionForType type); void inputThreadMessageAutocomplete(const QString &pattern, const QString &exceptions, InputTextManager::CompletionForType type); void slotGetListMessagesDone(const QJsonObject &obj, const QString &roomId, ListMessagesModel::ListMessageType type); void slotUserAutoCompleterDone(const QJsonObject &obj); void slotRoomsAutoCompleteChannelAndPrivateDone(const QJsonObject &obj); AccountRoomSettings *mAccountRoomSettings = nullptr; 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; InputTextManager *mInputThreadMessageTextManager = nullptr; SearchMessageModel *mSearchMessageModel = nullptr; SearchMessageFilterProxyModel *mSearchMessageFilterProxyModel = nullptr; ReceiveTypingNotificationManager *mReceiveTypingNotificationManager = nullptr; ServerConfigInfo *mServerConfigInfo = nullptr; FilesForRoomModel *mFilesModelForRoom = nullptr; FilesForRoomFilterProxyModel *mFilesForRoomFilterProxyModel = nullptr; DiscussionsFilterProxyModel *mDiscussionsFilterProxyModel = nullptr; DiscussionsModel *mDiscussionsModel = nullptr; ThreadsModel *mThreadsModel = nullptr; ThreadsFilterProxyModel *mThreadsFilterProxyModel = nullptr; EmoticonModel *mEmoticonModel = nullptr; ThreadMessageModel *mThreadMessageModel = nullptr; ListMessagesModel *mListMessageModel = nullptr; ListMessagesModelFilterProxyModel *mListMessagesFilterProxyModel = nullptr; AutotranslateLanguagesModel *mAutoTranslateLanguagesModel = nullptr; bool mEditingMode = false; }; #endif // ROCKETCHATACCOUNT_H diff --git a/src/core/rocketchatbackend.cpp b/src/core/rocketchatbackend.cpp index 7ff0cea5..738d0bc5 100644 --- a/src/core/rocketchatbackend.cpp +++ b/src/core/rocketchatbackend.cpp @@ -1,727 +1,727 @@ /* * Copyright 2016 Riccardo Iaconelli * Copyright 2018-2020 Laurent Montel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "rocketchataccount.h" #include "rocketchatbackend.h" #include "model/usercompletermodel.h" #include "ruqola_debug.h" #include "ruqola_message_debug.h" #include "ruqola_unknown_collectiontype_debug.h" #include "ddpapi/ddpclient.h" #include "restapirequest.h" #include "user.h" #include "model/usersmodel.h" #include "ruqolalogger.h" #include "model/messagemodel.h" #include "receivetypingnotificationmanager.h" #include "file.h" #include #include void process_publicsettings(const QJsonObject &obj, RocketChatAccount *account) { account->parsePublicSettings(obj); //qCDebug(RUQOLA_LOG) << " configs"<ruqolaLogger()) { account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Public Settings:") + QJsonDocument(obj).toJson()); } } void rooms_parsing(const QJsonObject &root, RocketChatAccount *account) { const QJsonObject obj = root.value(QLatin1String("result")).toObject(); RoomModel *model = account->roomModel(); //qDebug() << " doc " << doc; QJsonArray removed = obj.value(QLatin1String("remove")).toArray(); //qDebug() << " rooms_parsing: room removed *************************************************" << removed; const QJsonArray updated = obj.value(QLatin1String("update")).toArray(); //qDebug() << " rooms_parsing: updated *******************************************************: "<< updated; for (int i = 0; i < updated.size(); i++) { QJsonObject roomJson = updated.at(i).toObject(); const QString roomType = roomJson.value(QLatin1String("t")).toString(); if (account->ruqolaLogger()) { QJsonDocument d; d.setObject(roomJson); account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Rooms:") + d.toJson()); } if (roomType == QLatin1Char('c') //Chat || roomType == QLatin1Char('p') /*Private chat*/) { // let's be extra safe around crashes if (account->loginStatus() == DDPClient::LoggedIn) { model->updateRoom(roomJson); } } } } void getsubscription_parsing(const QJsonObject &root, RocketChatAccount *account) { const QJsonObject obj = root.value(QLatin1String("result")).toObject(); RoomModel *model = account->roomModel(); //qDebug() << " doc " << doc; const QJsonArray removed = obj.value(QLatin1String("remove")).toArray(); qDebug() << " room removed " << removed; //TODO implement it. const QJsonArray updated = obj.value(QLatin1String("update")).toArray(); //qDebug() << " updated : "<< updated; for (int i = 0; i < updated.size(); i++) { QJsonObject room = updated.at(i).toObject(); const QString roomType = room.value(QLatin1String("t")).toString(); if (account->ruqolaLogger()) { QJsonDocument d; d.setObject(room); account->ruqolaLogger()->dataReceived(QByteArrayLiteral("Rooms subscriptions:") + d.toJson()); } if (roomType == QLatin1Char('c') //Chat || roomType == QLatin1Char('p') /*Private chat*/ || roomType == QLatin1Char('d')) { //Direct chat) { // let's be extra safe around crashes if (account->loginStatus() == DDPClient::LoggedIn) { model->addRoom(room); } } else if (roomType == QLatin1Char('l')) { //Live chat qCDebug(RUQOLA_LOG) << "Live Chat not implemented yet"; } } //We need to load all room after get subscription to update parameters QJsonObject params; params[QStringLiteral("$date")] = QJsonValue(0); // get ALL rooms we've ever seen account->ddp()->method(QStringLiteral("rooms/get"), QJsonDocument(params), rooms_parsing); account->initializeAccount(); } RocketChatBackend::RocketChatBackend(RocketChatAccount *account, QObject *parent) : QObject(parent) , mRocketChatAccount(account) { connect(mRocketChatAccount, &RocketChatAccount::loginStatusChanged, this, &RocketChatBackend::slotLoginStatusChanged); connect(mRocketChatAccount, &RocketChatAccount::userIDChanged, this, &RocketChatBackend::slotUserIDChanged); connect(mRocketChatAccount, &RocketChatAccount::changed, this, &RocketChatBackend::slotChanged); connect(mRocketChatAccount, &RocketChatAccount::added, this, &RocketChatBackend::slotAdded); connect(mRocketChatAccount, &RocketChatAccount::removed, this, &RocketChatBackend::slotRemoved); connect(mRocketChatAccount, &RocketChatAccount::connectedChanged, this, &RocketChatBackend::slotConnectedChanged); } RocketChatBackend::~RocketChatBackend() { } void RocketChatBackend::slotConnectedChanged() { mRocketChatAccount->restApi()->serverInfo(false); connect(mRocketChatAccount->restApi(), &RocketChatRestApi::RestApiRequest::getServerInfoDone, this, &RocketChatBackend::parseServerVersionDone, Qt::UniqueConnection); connect(mRocketChatAccount->restApi(), &RocketChatRestApi::RestApiRequest::getServerInfoFailed, this, &RocketChatBackend::slotGetServerInfoFailed, Qt::UniqueConnection); mRocketChatAccount->ddp()->method(QStringLiteral("public-settings/get"), QJsonDocument(), process_publicsettings); } void RocketChatBackend::slotGetServerInfoFailed(bool useDeprecatedVersion) { if (!useDeprecatedVersion) { mRocketChatAccount->restApi()->serverInfo(true); } } void RocketChatBackend::processIncomingMessages(const QJsonArray &messages) { QMap > dispatcher; for (const QJsonValue &v : messages) { QJsonObject o = v.toObject(); if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(o); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("Message:") + d.toJson()); } else { qCDebug(RUQOLA_MESSAGE_LOG) <<" new message: " << o; } Message m(mRocketChatAccount->emojiManager()); m.parseMessage(o); //qDebug() << " roomId"<messageModelForRoom(m.roomId())) { if (!m.threadMessageId().isEmpty()) { mRocketChatAccount->updateThreadMessageList(m); } dispatcher[messageModel].append(std::move(m)); } else { qCWarning(RUQOLA_MESSAGE_LOG) << " MessageModel is empty for :" << m.roomId() << " It's a bug for sure."; } } for (auto it = dispatcher.cbegin(); it != dispatcher.cend(); ++it) { it.key()->addMessages(it.value()); } } void RocketChatBackend::parseOwnInfoDown(const QJsonObject &replyObject) { //Move code in rocketchataccount directly ? //qDebug() << "replyJson " << replyJson; - User *user = new User; - user->setUserId(replyObject.value(QLatin1String("_id")).toString()); - user->setUserName(replyObject.value(QLatin1String("username")).toString()); - user->setStatus(replyObject.value(QLatin1String("status")).toString()); - if (user->isValid()) { + User user; + user.setUserId(replyObject.value(QLatin1String("_id")).toString()); + user.setUserName(replyObject.value(QLatin1String("username")).toString()); + user.setStatus(replyObject.value(QLatin1String("status")).toString()); + if (user.isValid()) { mRocketChatAccount->usersModel()->addUser(user); } else { qCWarning(RUQOLA_LOG) << " Error during parsing user" << replyObject; } } void RocketChatBackend::slotLoginStatusChanged() { if (mRocketChatAccount->loginStatus() == DDPClient::LoggedIn) { connect(mRocketChatAccount->restApi(), &RocketChatRestApi::RestApiRequest::getOwnInfoDone, this, &RocketChatBackend::parseOwnInfoDown, Qt::UniqueConnection); QJsonObject params; params[QStringLiteral("$date")] = QJsonValue(0); // get ALL rooms we've ever seen std::function subscription_callback = [=](const QJsonObject &obj, RocketChatAccount *account) { getsubscription_parsing(obj, account); }; mRocketChatAccount->ddp()->method(QStringLiteral("subscriptions/get"), QJsonDocument(params), subscription_callback); mRocketChatAccount->restApi()->setAuthToken(mRocketChatAccount->settings()->authToken()); mRocketChatAccount->restApi()->setUserId(mRocketChatAccount->settings()->userId()); mRocketChatAccount->restApi()->getPrivateSettings(); mRocketChatAccount->restApi()->getOwnInfo(); } } void RocketChatBackend::parseServerVersionDone(const QString &version) { //qCDebug(RUQOLA_LOG) << " void RocketChatBackend::parseServerVersionDone(const QString &version)******************" << version; mRocketChatAccount->setServerVersion(version); mRocketChatAccount->ddp()->login(); } QVector RocketChatBackend::files() const { return mFiles; } QVector RocketChatBackend::users() const { return mUsers; } void RocketChatBackend::slotRemoved(const QJsonObject &object) { const QString collection = object.value(QLatin1String("collection")).toString(); if (collection == QLatin1String("users")) { const QString id = object.value(QLatin1String("id")).toString(); mRocketChatAccount->usersModel()->removeUser(id); if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("users: Removed user:") + d.toJson()); } else { qDebug() << "USER REMOVED VALUE" << object; } } else if (collection == QLatin1String("stream-notify-logged")) { qDebug() << "removed stream-notify-logged " << object; } else { qCDebug(RUQOLA_UNKNOWN_COLLECTIONTYPE_LOG) << " Other collection type removed " << collection << " object "<settings()->userName()) { mRocketChatAccount->settings()->setUserId(object[QStringLiteral("id")].toString()); qCDebug(RUQOLA_LOG) << "User id set to " << mRocketChatAccount->settings()->userId(); } else { //TODO add current user ? me ? - User *user = new User; - user->parseUser(object); + User user; + user.parseUser(object); if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("users: Add User:") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "USER ADDED VALUE" << object; } mRocketChatAccount->usersModel()->addUser(user); } qCDebug(RUQOLA_LOG) << "NEW USER ADDED: " << username << fields; } else if (collection == QLatin1String("rooms")) { qCDebug(RUQOLA_LOG) << "NEW ROOMS ADDED: " << object; } else if (collection == QLatin1String("stream-notify-user")) { qDebug() << "stream-notify-user: " << object; } else if (collection == QLatin1String("stream-notify-all")) { qCDebug(RUQOLA_UNKNOWN_COLLECTIONTYPE_LOG) << "stream-notify-user: " << object; //TODO verify that all is ok ! } else if (collection == QLatin1String("autocompleteRecords")) { if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("autocompleteRecords: Add User:") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "AutoCompleteRecords VALUE" << object; } User user; user.parseUser(object); mUsers.append(user); } else if (collection == QLatin1String("room_files")) { if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("room_files: Add Files:") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "room_files VALUE" << object; } File file; file.parseFile(object); mFiles.append(file); } else if (collection == QLatin1String("stream-notify-room")) { //TODO qCDebug(RUQOLA_UNKNOWN_COLLECTIONTYPE_LOG) << "stream-notify-room not implemented: "<< object; } else if (collection == QLatin1String("stream-notify-logged")) { qCDebug(RUQOLA_UNKNOWN_COLLECTIONTYPE_LOG) << "stream-notify-logged not implemented: "<< object; } else { qCDebug(RUQOLA_UNKNOWN_COLLECTIONTYPE_LOG) << "Unknown added element: "<< object; } } void RocketChatBackend::slotChanged(const QJsonObject &object) { const QString collection = object[QStringLiteral("collection")].toString(); if (collection == QLatin1String("stream-room-messages")) { const QJsonObject fields = object.value(QLatin1String("fields")).toObject(); const QJsonArray contents = fields.value(QLatin1String("args")).toArray(); processIncomingMessages(contents); } else if (collection == QLatin1String("users")) { if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("users: User Changed:") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "USER CHANGED" << object; } mRocketChatAccount->updateUser(object); } else if (collection == QLatin1String("rooms")) { if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("rooms: Room Changed:") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "ROOMS CHANGED: " << object; } } else if (collection == QLatin1String("stream-notify-user")) { QJsonObject fields = object.value(QLatin1String("fields")).toObject(); const QString eventname = fields.value(QLatin1String("eventName")).toString(); const QJsonArray contents = fields.value(QLatin1String("args")).toArray(); qCDebug(RUQOLA_LOG) << " EVENT " << eventname << " contents " << contents << fields.value(QLatin1String("args")).toArray().toVariantList(); if (eventname.endsWith(QLatin1String("/subscriptions-changed"))) { RoomModel *model = mRocketChatAccount->roomModel(); model->updateSubscription(contents); if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(fields); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("stream-notify-user: subscriptions-changed:") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "stream-notify-user: subscriptions-changed " << object; } } else if (eventname.endsWith(QLatin1String("/rooms-changed"))) { RoomModel *model = mRocketChatAccount->roomModel(); //qDebug() << " EVENT " << eventname << " contents " << contents << fields.value(QLatin1String("args")).toArray().toVariantList(); const QJsonArray lst = fields.value(QLatin1String("args")).toArray(); const QString actionName = lst[0].toString(); if (actionName == QLatin1String("updated")) { qCDebug(RUQOLA_LOG) << " Update room " << lst; const QJsonObject roomData = lst[1].toObject(); model->updateRoom(roomData); } else if (actionName == QLatin1String("inserted")) { qCDebug(RUQOLA_LOG) << "****************************************** insert new Room !!!!!" << lst; const QJsonObject roomData = lst[1].toObject(); model->insertRoom(roomData); } else if (actionName == QLatin1String("removed")) { qCDebug(RUQOLA_LOG) << "Remove channel" << lst; const QJsonObject roomData = lst[1].toObject(); //TODO use rid model->removeRoom(QString()); } else { qWarning() << "rooms-changed invalid actionName " << actionName; } if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("stream-notify-user: Room Changed:") + d.toJson()); } } else if (eventname.endsWith(QLatin1String("/notification"))) { if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("stream-notify-user: notification:") + d.toJson()); } else { qCDebug(RUQOLA_UNKNOWN_COLLECTIONTYPE_LOG) << "NOTIFICATION: " << object; } mRocketChatAccount->sendNotification(contents); } else if (eventname.endsWith(QLatin1String("/webrtc"))) { if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("stream-notify-user: webrtc: ") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "WEBRTC CHANGED: " << object; } qCWarning(RUQOLA_LOG) << "stream-notify-user : WEBRTC ? " << eventname << " contents " << contents; } else if (eventname.endsWith(QLatin1String("/otr"))) { if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("stream-notify-user: otr: ") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "OTR CHANGED: " << object; } mRocketChatAccount->parseOtr(contents); qCDebug(RUQOLA_UNKNOWN_COLLECTIONTYPE_LOG) << "stream-notify-user : OTR ? " << eventname << " contents " << contents; } else if (eventname.endsWith(QLatin1String("/message"))) { if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("stream-notify-user: message: ") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "stream-notify-user : Message: " << object; } const QJsonArray lst = fields.value(QLatin1String("args")).toArray(); const QJsonObject roomData = lst[0].toObject(); QString roomId = roomData.value(QLatin1String("rid")).toString(); if (!roomId.isEmpty()) { MessageModel *messageModel = mRocketChatAccount->messageModelForRoom(roomId); Message m(mRocketChatAccount->emojiManager()); m.parseMessage(roomData); if (!m.threadMessageId().isEmpty()) { qDebug() << " It's a thread message id ****************************" << m.threadMessageId(); mRocketChatAccount->updateThreadMessageList(m); } //m.setMessageType(Message::System); //TODO add special element!See roomData QJsonObject({"_id":"u9xnnzaBQoQithsxP","msg":"You have been muted and cannot speak in this room","rid":"Dic5wZD4Zu9ze5gk3","ts":{"$date":1534166745895}}) messageModel->addMessage(m); } else { qCWarning(RUQOLA_LOG) << "stream-notify-user : Message: ROOMID is empty "; } qCDebug(RUQOLA_LOG) << "stream-notify-user : Message " << eventname << " contents " << contents; } else { if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("stream-notify-user: Unknown event: ") + d.toJson()); } else { qCDebug(RUQOLA_UNKNOWN_COLLECTIONTYPE_LOG) << "Unknown change: " << object; } qCDebug(RUQOLA_LOG) << "stream-notify-user : message event " << eventname << " contents " << contents; } } else if (collection == QLatin1String("stream-notify-room")) { qCDebug(RUQOLA_LOG) << " stream-notify-room " << collection << " object "<ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("stream-notify-room: DeleteMessage:") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "Delete message" << object; } //Move code in rocketChatAccount ? QString roomId = eventname; roomId.remove(QStringLiteral("/deleteMessage")); MessageModel *messageModel = mRocketChatAccount->messageModelForRoom(roomId); if (messageModel) { messageModel->deleteMessage(contents.at(0).toObject()[QStringLiteral("_id")].toString()); } else { qCWarning(RUQOLA_MESSAGE_LOG) << " MessageModel is empty for :" << roomId << " It's a bug for sure."; } } else if (eventname.endsWith(QLatin1String("/typing"))) { if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("stream-notify-room: typing:") + d.toJson()); } else { qCDebug(RUQOLA_LOG) << "typing message" << object; } QString roomId = eventname; roomId.remove(QStringLiteral("/typing")); //TODO Perhaps not necessary to convert to variantlist. Need to investigate //qCWarning(RUQOLA_LOG) << "stream-notify-room: typing event ? " << eventname << " content " << contents.toVariantList(); const QString typingUserName = contents.toVariantList().at(0).toString(); if (typingUserName != mRocketChatAccount->settings()->userName()) { const bool status = contents.toVariantList().at(1).toBool(); mRocketChatAccount->receiveTypingNotificationManager()->insertTypingNotification(roomId, typingUserName, status); } } else { if (mRocketChatAccount->ruqolaLogger()) { QJsonDocument d; d.setObject(object); mRocketChatAccount->ruqolaLogger()->dataReceived(QByteArrayLiteral("stream-notify-room: Unknown event ?") + d.toJson()); } else { qCDebug(RUQOLA_UNKNOWN_COLLECTIONTYPE_LOG) << "stream-notify-room: Unknown event ? " << eventname; } } } else if (collection == QLatin1String("stream-notify-logged")) { QJsonObject fields = object.value(QLatin1String("fields")).toObject(); const QString eventname = fields.value(QLatin1String("eventName")).toString(); const QJsonArray contents = fields.value(QLatin1String("args")).toArray(); qCDebug(RUQOLA_LOG) << " EVENT " << eventname << " contents " << contents << fields.value(QLatin1String("args")).toArray().toVariantList(); if (eventname == QLatin1String("roles-change")) { mRocketChatAccount->rolesChanged(contents); } else if (eventname == QLatin1String("updateAvatar")) { //TODO update it. //Update list of avatar ! qCWarning(RUQOLA_LOG) << "Need to implement updateAvatar :" << fields; } else if (eventname == QLatin1String("updateEmojiCustom")) { qCWarning(RUQOLA_LOG) << "Need to implement updateEmojiCustom :" << fields; } else if (eventname == QLatin1String("Users:NameChanged")) { qCWarning(RUQOLA_LOG) << "Need to implement: Users:NameChanged :" << fields; } else if (eventname == QLatin1String("Users:Deleted")) { qCWarning(RUQOLA_LOG) << "Need to implement: Users:Deleted :" << fields; } else if (eventname == QLatin1String("deleteCustomUserStatus")) { qCWarning(RUQOLA_LOG) << "Need to implement: deleteCustomUserStatus :" << fields; } else if (eventname == QLatin1String("updateCustomUserStatus")) { qCWarning(RUQOLA_LOG) << "Need to implement: updateCustomUserStatus :" << fields; } else if (eventname == QLatin1String("user-status")) { qCWarning(RUQOLA_LOG) << "Need to implement: user-status :" << fields; } else { qWarning() << "stream-notify-logged not supported " << fields; } } else { qCDebug(RUQOLA_UNKNOWN_COLLECTIONTYPE_LOG) << " Other collection type changed " << collection << " object "<settings()->userId() }; { //Subscribe notification. QJsonArray params; params.append(QJsonValue(QStringLiteral("%1/%2").arg(userId, QStringLiteral("notification")))); mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-user"), params); } { //Subscribe room-changed. QJsonArray params; params.append(QJsonValue(QStringLiteral("%1/%2").arg(userId, QStringLiteral("rooms-changed")))); mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-user"), params); } { //Subscribe subscriptions-changed QJsonArray params; params.append(QJsonValue(QStringLiteral("%1/%2").arg(userId, QStringLiteral("subscriptions-changed")))); mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-user"), params); } { //Subscribe message QJsonArray params; params.append(QJsonValue(QStringLiteral("%1/%2").arg(userId, QStringLiteral("message")))); mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-user"), params); } { //Subscribe message QJsonArray params; params.append(QJsonValue(QStringLiteral("%1/%2").arg(userId, QStringLiteral("otr")))); mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-user"), params); } { //Subscribe message QJsonArray params; params.append(QJsonValue(QStringLiteral("%1/%2").arg(userId, QStringLiteral("webrtc")))); mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-user"), params); } { //Subscribe activeUsers QJsonArray params; params.append(QJsonValue(params)); mRocketChatAccount->ddp()->subscribe(QStringLiteral("activeUsers"), params); } { //Subscribe users in room ? //TODO verify it. QJsonArray params; params.append(QJsonValue(QStringLiteral("%1/%2").arg(userId, QStringLiteral("webrtc")))); mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-room-users"), params); } //stream-notify-all { const QJsonArray params{ QJsonValue(QStringLiteral("updateAvatar")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-all"), params); } { const QJsonArray params{ QJsonValue(QStringLiteral("roles-change")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-all"), params); } { const QJsonArray params{ QJsonValue(QStringLiteral("updateEmojiCustom")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-all"), params); } { const QJsonArray params{ QJsonValue(QStringLiteral("deleteEmojiCustom")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-all"), params); } { const QJsonArray params{ QJsonValue(QStringLiteral("public-settings-changed")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-all"), params); } { const QJsonArray params{ QJsonValue(QStringLiteral("permissions-changed")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-all"), params); } //stream-notify-logged { const QJsonArray params{ QJsonValue(QStringLiteral("updateEmojiCustom")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-logged"), params); } //stream-notify-logged { const QJsonArray params{ QJsonValue(QStringLiteral("deleteEmojiCustom")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-logged"), params); } //stream-notify-logged { const QJsonArray params{ QJsonValue(QStringLiteral("roles-change")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-logged"), params); } //stream-notify-logged { const QJsonArray params{ QJsonValue(QStringLiteral("updateAvatar")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-logged"), params); } //stream-notify-logged { const QJsonArray params{ QJsonValue(QStringLiteral("Users:NameChanged")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-logged"), params); } //stream-notify-logged { const QJsonArray params{ QJsonValue(QStringLiteral("Users:Deleted")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-logged"), params); } { const QJsonArray params{ QJsonValue(QStringLiteral("deleteCustomUserStatus")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-logged"), params); } { const QJsonArray params{ QJsonValue(QStringLiteral("updateCustomUserStatus")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-logged"), params); } { const QJsonArray params{ QJsonValue(QStringLiteral("user-status")), { true } }; mRocketChatAccount->ddp()->subscribe(QStringLiteral("stream-notify-logged"), params); } } diff --git a/src/core/user.h b/src/core/user.h index 2f4865af..51d6b960 100644 --- a/src/core/user.h +++ b/src/core/user.h @@ -1,83 +1,85 @@ /* Copyright (c) 2017-2020 Laurent Montel 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 USER_H #define USER_H #include #include #include "libruqolacore_export.h" class LIBRUQOLACORE_EXPORT User { Q_GADGET public: enum class PresenceStatus { PresenceOnline, PresenceBusy, PresenceAway, PresenceOffline, Unknown }; Q_ENUM(PresenceStatus) User(); ~User(); Q_REQUIRED_RESULT QString name() const; void setName(const QString &name); Q_REQUIRED_RESULT QString userId() const; void setUserId(const QString &userId); Q_REQUIRED_RESULT QString status() const; void setStatus(const QString &status); void parseUser(const QJsonObject &json); Q_REQUIRED_RESULT Q_INVOKABLE QString iconFromStatus() const; Q_REQUIRED_RESULT bool operator ==(const User &other) const; Q_REQUIRED_RESULT bool operator !=(const User &other) const; Q_REQUIRED_RESULT QString userName() const; void setUserName(const QString &userName); Q_REQUIRED_RESULT bool isValid() const; Q_REQUIRED_RESULT double utcOffset() const; void setUtcOffset(double utcOffset); Q_REQUIRED_RESULT QString statusText() const; void setStatusText(const QString &statusText); void parseUserRestApi(const QJsonObject &object); static Q_REQUIRED_RESULT QVector parseUsersList(const QJsonObject &object); private: QString mStatus = QStringLiteral("offline"); QString mUserId; QString mName; QString mUserName; QString mStatusText; double mUtcOffset = 0.0; }; +Q_DECLARE_METATYPE(User) +Q_DECLARE_TYPEINFO(User, Q_MOVABLE_TYPE); LIBRUQOLACORE_EXPORT QDebug operator <<(QDebug d, const User &t); #endif // USER_H