File indexing completed on 2024-04-14 15:03:53

0001 /*
0002  * SPDX-FileCopyrightText: 2016 Riccardo Iaconelli <riccardo@kde.org>
0003  * SPDX-FileCopyrightText: 2017-2024 Laurent Montel <montel@kde.org>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.0-or-later
0006  *
0007  */
0008 
0009 #include "room.h"
0010 #include "model/messagesmodel.h"
0011 #include "model/usersforroommodel.h"
0012 #include "rocketchataccount.h"
0013 #include "ruqola_debug.h"
0014 #include "textconverter.h"
0015 
0016 #include <KLocalizedString>
0017 
0018 #include <QCborValue>
0019 #include <QJsonArray>
0020 #include <QJsonDocument>
0021 
0022 Room::Room(RocketChatAccount *account, QObject *parent)
0023     : QObject(parent)
0024     , mUsersModelForRoom(new UsersForRoomModel(this))
0025     , mRocketChatAccount(account)
0026 {
0027     mUsersModelForRoom->setObjectName(QStringLiteral("usersforroommodel"));
0028     mMessageModel = new MessagesModel(QString(), mRocketChatAccount, this, this);
0029 }
0030 
0031 Room::~Room() = default;
0032 
0033 Room::RoomType Room::roomTypeFromString(const QString &type)
0034 {
0035     if (type == QLatin1String("p")) {
0036         return Room::RoomType::Private;
0037     } else if (type == QLatin1String("c")) {
0038         return Room::RoomType::Channel;
0039     } else if (type == QLatin1String("d")) {
0040         return Room::RoomType::Direct;
0041     } else {
0042         return Room::RoomType::Unknown;
0043     }
0044 }
0045 
0046 QString Room::roomFromRoomType(Room::RoomType type)
0047 {
0048     switch (type) {
0049     case Room::RoomType::Private:
0050         return QStringLiteral("p");
0051     case Room::RoomType::Channel:
0052         return QStringLiteral("c");
0053     case Room::RoomType::Direct:
0054         return QStringLiteral("d");
0055     case Room::RoomType::Unknown:
0056         qCDebug(RUQOLA_LOG) << "void Room::roomFromRoomType : unknown type";
0057         return {};
0058     }
0059     return {};
0060 }
0061 
0062 bool Room::operator==(const Room &other) const
0063 {
0064     // qDebug() << " other.id"<<other.id << " id " << id;
0065     return other.mRoomId == roomId();
0066 }
0067 
0068 bool Room::isEqual(const Room &other) const
0069 {
0070     return (mRoomId == other.roomId()) && (mChannelType == other.channelType()) && (mName == other.name()) && (mAnnouncement == other.announcement())
0071         && (mRoomCreatorUserName == other.roomOwnerUserName()) && (mRoomCreateUserId == other.roomCreatorUserId()) && (mTopic == other.topic())
0072         && (mMutedUsers == other.mutedUsers()) && (mJitsiTimeout == other.jitsiTimeout()) && (mReadOnly == other.readOnly()) && (mUnread == other.unread())
0073         && (mSelected == other.selected()) && (mFavorite == other.favorite()) && (mOpen == other.open()) && (mBlocker == other.blocker())
0074         && (mArchived == other.archived()) && (mDescription == other.description()) && (mUserMentions == other.userMentions())
0075         && (mNotificationOptions == other.notificationOptions()) && (mUpdatedAt == other.updatedAt()) && (mLastSeenAt == other.lastSeenAt())
0076         && (mBlocked == other.blocked()) && (mRoles == other.roles()) && (mIgnoredUsers == other.ignoredUsers()) && (mEncrypted == other.encrypted())
0077         && (mE2EKey == other.e2EKey()) && (mE2eKeyId == other.e2eKeyId()) && (mJoinCodeRequired == other.joinCodeRequired())
0078         && (mBroadcast == other.broadcast()) && (mParentRid == other.parentRid()) && (mFName == other.fName()) && (mAutoTranslate == other.autoTranslate())
0079         && (mAutotranslateLanguage == other.autoTranslateLanguage()) && (mDirectChannelUserId == other.directChannelUserId())
0080         && (mDisplaySystemMessageType == other.displaySystemMessageTypes()) && (mAvatarETag == other.avatarETag()) && (mUids == other.uids())
0081         && (mUserNames == other.userNames()) && (mHighlightsWord == other.highlightsWord()) && (mRetentionInfo == other.retentionInfo())
0082         && (mTeamInfo == other.teamInfo()) && (mLastMessageAt == other.lastMessageAt());
0083 }
0084 
0085 QString Room::displayRoomName() const
0086 {
0087     const QString displayName = mFName.isEmpty() ? mName : mFName;
0088     if (channelType() == RoomType::Direct) {
0089         return QLatin1Char('@') + displayName;
0090     } else {
0091         return QLatin1Char('#') + displayName;
0092     }
0093 }
0094 
0095 QString Room::name() const
0096 {
0097     return mName;
0098 }
0099 
0100 QDebug operator<<(QDebug d, const Room &t)
0101 {
0102     d << "id :" << t.roomId();
0103     d << "type :" << t.channelType();
0104     d << "name :" << t.name();
0105     d << "mAnnouncement :" << t.announcement();
0106     d << "roomCreaterUserName :" << t.roomOwnerUserName();
0107     d << "roomCreaterUserID :" << t.roomCreatorUserId();
0108     d << "topic :" << t.topic();
0109     d << "mutedUsers :" << t.mutedUsers();
0110     d << "jitsiTimeout :" << t.jitsiTimeout();
0111     d << "ro :" << t.readOnly();
0112     d << "unread :" << t.unread();
0113     d << "selected :" << t.selected();
0114     d << "favorite :" << t.favorite();
0115     d << "open :" << t.open();
0116     d << "blocker: " << t.blocker();
0117     d << "archived: " << t.archived();
0118     d << "description: " << t.description();
0119     d << "userMentions: " << t.userMentions();
0120     d << "notifications: " << t.notificationOptions();
0121     d << "UpdatedAt: " << t.updatedAt();
0122     d << "LastSeenAt: " << t.lastSeenAt();
0123     d << "LastMessageAt: " << t.lastMessageAt();
0124     d << "blocked: " << t.blocked();
0125     d << "roles: " << t.roles();
0126     d << "ignoredUsers: " << t.ignoredUsers();
0127     d << "encrypted room: " << t.encrypted();
0128     d << "E2E keys: " << t.e2EKey();
0129     d << "mE2eKeyId: " << t.e2eKeyId();
0130     d << "mJoinCodeRequired: " << t.joinCodeRequired();
0131     d << "broadcast: " << t.broadcast();
0132     d << "ParentRid: " << t.parentRid();
0133     d << "Fname: " << t.fName();
0134     d << "autotranslate " << t.autoTranslate();
0135     d << "autotranslateLanguage " << t.autoTranslateLanguage();
0136     d << "directChannelUserId " << t.directChannelUserId();
0137     d << "DisplaySystemMessageType " << t.displaySystemMessageTypes();
0138     d << "AvatarEtag " << t.avatarETag();
0139     d << "uids " << t.uids();
0140     d << "usernames " << t.userNames();
0141     d << "highlightsWord " << t.highlightsWord();
0142     d << "RetentionInfo " << t.retentionInfo();
0143     d << "TeamInfo " << t.teamInfo();
0144     d << "Number Of messages in room " << t.numberMessages();
0145     return d;
0146 }
0147 
0148 bool Room::canBeModify() const
0149 {
0150     if (mRocketChatAccount) {
0151         return mRoles.contains(QLatin1String("owner"));
0152     }
0153     return false;
0154 }
0155 
0156 NotificationOptions Room::notificationOptions() const
0157 {
0158     return mNotificationOptions;
0159 }
0160 
0161 void Room::setNotificationOptions(const NotificationOptions &notificationOptions)
0162 {
0163     if (mNotificationOptions != notificationOptions) {
0164         mNotificationOptions = notificationOptions;
0165         Q_EMIT notificationOptionsChanged();
0166     }
0167 }
0168 
0169 int Room::userMentions() const
0170 {
0171     return mUserMentions;
0172 }
0173 
0174 void Room::setUserMentions(int userMentions)
0175 {
0176     mUserMentions = userMentions;
0177     // Send needAttention only if we have alert.
0178     if (mUserMentions > 0) {
0179         Q_EMIT needAttention();
0180     }
0181 }
0182 
0183 void Room::updateSubscriptionRoom(const QJsonObject &json)
0184 {
0185     parseSubscriptionRoom(json);
0186 }
0187 
0188 qint64 Room::updatedAt() const
0189 {
0190     return mUpdatedAt;
0191 }
0192 
0193 void Room::setUpdatedAt(qint64 updatedAt)
0194 {
0195     mUpdatedAt = updatedAt;
0196 }
0197 
0198 void Room::parseUpdateRoom(const QJsonObject &json)
0199 {
0200     qCDebug(RUQOLA_LOG) << "void Room::parseUpdateRoom(const QJsonObject &json)" << json;
0201     if (json.contains(QLatin1String("rid"))) {
0202         setRoomId(json.value(QLatin1String("rid")).toString());
0203     }
0204     setJitsiTimeout(Utils::parseDate(QStringLiteral("jitsiTimeout"), json));
0205     if (json.contains(QLatin1String("alert"))) {
0206         setAlert(json[QLatin1String("alert")].toBool());
0207     }
0208     if (json.contains(QLatin1String("f"))) {
0209         setFavorite(json[QLatin1String("f")].toBool());
0210     }
0211 
0212     if (json.contains(QLatin1String("unread"))) {
0213         setUnread(json[QLatin1String("unread")].toInt());
0214     }
0215     if (json.contains(QLatin1String("userMentions"))) {
0216         setUserMentions(json[QLatin1String("userMentions")].toInt());
0217     }
0218     if (json.contains(QLatin1String("announcement"))) {
0219         setAnnouncement(json[QLatin1String("announcement")].toString());
0220     }
0221     if (json.contains(QLatin1String("description"))) {
0222         setDescription(json[QLatin1String("description")].toString());
0223     }
0224     if (json.contains(QLatin1String("open"))) {
0225         setOpen(json[QLatin1String("open")].toBool());
0226     }
0227     if (json.contains(QLatin1String("topic"))) {
0228         setTopic(json[QLatin1String("topic")].toString());
0229     }
0230     if (json.contains(QLatin1String("name"))) {
0231         setName(json[QLatin1String("name")].toString());
0232     }
0233     if (json.contains(QLatin1String("joinCodeRequired"))) {
0234         setJoinCodeRequired(json[QLatin1String("joinCodeRequired")].toBool());
0235     } else {
0236         setJoinCodeRequired(false);
0237     }
0238 
0239     if (json.contains(QLatin1String("fname"))) {
0240         setFName(json[QLatin1String("fname")].toString());
0241     }
0242     if (json.contains(QLatin1String("autoTranslateLanguage"))) {
0243         setAutoTranslateLanguage(json[QLatin1String("autoTranslateLanguage")].toString());
0244     }
0245     if (json.contains(QLatin1String("autoTranslate"))) {
0246         setAutoTranslate(json[QLatin1String("autoTranslate")].toBool());
0247     }
0248     if (json.contains(QLatin1String("archived"))) {
0249         setArchived(json[QLatin1String("archived")].toBool());
0250     } else {
0251         setArchived(false);
0252     }
0253     if (json.contains(QLatin1String("blocker"))) {
0254         setBlocker(json[QLatin1String("blocker")].toBool());
0255     } else {
0256         setBlocker(false);
0257     }
0258     if (json.contains(QLatin1String("blocked"))) {
0259         setBlocked(json[QLatin1String("blocked")].toBool());
0260     } else {
0261         setBlocked(false);
0262     }
0263 
0264     if (json.contains(QLatin1String("encrypted"))) {
0265         setEncrypted(json[QLatin1String("encrypted")].toBool());
0266     } else {
0267         setEncrypted(false);
0268     }
0269     // TODO verify it. add autotest
0270     if (json.contains(QLatin1String("broadcast"))) {
0271         setBroadcast(json[QLatin1String("broadcast")].toBool());
0272     } else {
0273         setBroadcast(false);
0274     }
0275     setReadOnly(json[QLatin1String("ro")].toBool());
0276     const qint64 result = Utils::parseDate(QStringLiteral("ls"), json);
0277     if (result != -1) {
0278         setLastSeenAt(result);
0279     }
0280     const qint64 lm = Utils::parseDate(QStringLiteral("lm"), json);
0281     if (lm != -1) {
0282         setLastMessageAt(lm);
0283     }
0284 
0285     if (json.contains(QLatin1String("msgs"))) {
0286         mNumberMessages = json[QLatin1String("msgs")].toInt();
0287     }
0288 
0289     const QJsonArray highlightsWordArray = json.value(QLatin1String("userHighlights")).toArray();
0290     QStringList lstHighlightsWord;
0291     const int highlightsWordArrayCount = highlightsWordArray.count();
0292     lstHighlightsWord.reserve(highlightsWordArrayCount);
0293     for (int i = 0; i < highlightsWordArrayCount; ++i) {
0294         lstHighlightsWord << highlightsWordArray.at(i).toString();
0295     }
0296     setHighlightsWord(lstHighlightsWord);
0297 
0298     if (json.contains(QLatin1String("ignored"))) {
0299         const QJsonArray ignoredArray = json.value(QLatin1String("ignored")).toArray();
0300         QStringList lstIgnored;
0301         const int ignoredArrayCount = ignoredArray.count();
0302         lstIgnored.reserve(ignoredArrayCount);
0303         for (int i = 0; i < ignoredArrayCount; ++i) {
0304             lstIgnored << ignoredArray.at(i).toString();
0305         }
0306         setIgnoredUsers(lstIgnored);
0307     }
0308 
0309     // TODO muted ????
0310     // TODO E2EKey
0311     setE2eKeyId(json[QLatin1String("e2eKeyId")].toString());
0312 
0313     const QJsonValue ownerValue = json.value(QLatin1String("u"));
0314     if (!ownerValue.isUndefined()) {
0315         const QJsonObject objOwner = ownerValue.toObject();
0316         setRoomCreatorUserId(objOwner.value(QLatin1String("_id")).toString());
0317         setRoomCreatorUserName(objOwner.value(QLatin1String("username")).toString());
0318     } else {
0319         // When room is initialized we are the owner. When we update room we have the real
0320         // owner and if it's empty => we need to clear it.
0321         setRoomCreatorUserId(QString());
0322         setRoomCreatorUserName(QString());
0323     }
0324     if (json.contains(QLatin1String("prid"))) {
0325         setParentRid(json[QLatin1String("prid")].toString());
0326     }
0327     if (json.contains(QLatin1String("uids"))) {
0328         const QJsonArray &uidsArray = json[QLatin1String("uids")].toArray();
0329         const auto &u0 = uidsArray[0].toString();
0330         const auto &u1 = uidsArray[1].toString();
0331         setDirectChannelUserId((u0 == mRocketChatAccount->userId()) ? u1 : u0);
0332 
0333         QStringList lstUids;
0334         lstUids.reserve(uidsArray.count());
0335         for (int i = 0; i < uidsArray.count(); ++i) {
0336             lstUids << uidsArray.at(i).toString();
0337         }
0338         setUids(lstUids);
0339     }
0340 
0341     const QJsonArray userNamesArray = json.value(QLatin1String("usernames")).toArray();
0342     QStringList lstUserNames;
0343     const int nbUserNamesArray = userNamesArray.count();
0344     lstUserNames.reserve(nbUserNamesArray);
0345     for (int i = 0; i < nbUserNamesArray; ++i) {
0346         lstUserNames << userNamesArray.at(i).toString();
0347     }
0348     setUserNames(lstUserNames);
0349 
0350     setAvatarETag(json.value(QLatin1String("avatarETag")).toString());
0351     parseDisplaySystemMessage(json);
0352     parseRetentionInfo(json);
0353     parseTeamInfo(json);
0354 }
0355 
0356 void Room::parseTeamInfo(const QJsonObject &json)
0357 {
0358     TeamInfo info;
0359     info.parseTeamInfo(json);
0360     setTeamInfo(std::move(info));
0361 }
0362 
0363 qint64 Room::numberMessages() const
0364 {
0365     return mNumberMessages;
0366 }
0367 
0368 void Room::setNumberMessages(qint64 newNumberMessages)
0369 {
0370     mNumberMessages = newNumberMessages;
0371 }
0372 
0373 bool Room::selected() const
0374 {
0375     return mSelected;
0376 }
0377 
0378 void Room::setSelected(bool selected)
0379 {
0380     if (mSelected != selected) {
0381         mSelected = selected;
0382         // Add signal otherwise it's not necessary to check value
0383     }
0384 }
0385 
0386 bool Room::hideBadgeForMention() const
0387 {
0388     return mNotificationOptions.hideMentionStatus();
0389 }
0390 
0391 bool Room::hideUnreadStatus() const
0392 {
0393     return mNotificationOptions.hideUnreadStatus();
0394 }
0395 
0396 int Room::unread() const
0397 {
0398     return mUnread;
0399 }
0400 
0401 void Room::setUnread(int unread)
0402 {
0403     if (mUnread != unread) {
0404         mUnread = unread;
0405         Q_EMIT unreadChanged();
0406     }
0407     if (channelType() != RoomType::Channel) { // TODO verify it
0408         if (mUnread > 0) {
0409             Q_EMIT needAttention();
0410         }
0411     }
0412 }
0413 
0414 qint64 Room::jitsiTimeout() const
0415 {
0416     return mJitsiTimeout;
0417 }
0418 
0419 void Room::setJitsiTimeout(qint64 jitsiTimeout)
0420 {
0421     if (mJitsiTimeout != jitsiTimeout) {
0422         mJitsiTimeout = jitsiTimeout;
0423         Q_EMIT jitsiTimeoutChanged();
0424     }
0425 }
0426 
0427 QStringList Room::mutedUsers() const
0428 {
0429     return mMutedUsers;
0430 }
0431 
0432 void Room::setMutedUsers(const QStringList &mutedUsers)
0433 {
0434     if (mMutedUsers != mutedUsers) {
0435         mMutedUsers = mutedUsers;
0436         Q_EMIT mutedUsersChanged();
0437     }
0438 }
0439 
0440 QString Room::roomCreatorUserId() const
0441 {
0442     return mRoomCreateUserId;
0443 }
0444 
0445 void Room::setRoomCreatorUserId(const QString &userId)
0446 {
0447     mRoomCreateUserId = userId;
0448 }
0449 
0450 QString Room::roomOwnerUserName() const
0451 {
0452     return mRoomCreatorUserName;
0453 }
0454 
0455 void Room::setRoomCreatorUserName(const QString &userName)
0456 {
0457     mRoomCreatorUserName = userName;
0458 }
0459 
0460 QString Room::roomId() const
0461 {
0462     return mRoomId;
0463 }
0464 
0465 void Room::setRoomId(const QString &id)
0466 {
0467     if (mRoomId != id) {
0468         mRoomId = id;
0469         mMessageModel->setRoomId(id);
0470     }
0471 }
0472 
0473 bool Room::alert() const
0474 {
0475     return mAlert;
0476 }
0477 
0478 void Room::setBlocker(bool block)
0479 {
0480     if (mBlocker != block) {
0481         mBlocker = block;
0482         Q_EMIT blockerChanged();
0483     }
0484 }
0485 
0486 bool Room::blocker() const
0487 {
0488     return mBlocker;
0489 }
0490 
0491 void Room::setAlert(bool alert)
0492 {
0493     if (mAlert != alert) {
0494         mAlert = alert;
0495         Q_EMIT alertChanged();
0496     }
0497 }
0498 
0499 bool Room::open() const
0500 {
0501     return mOpen;
0502 }
0503 
0504 void Room::setOpen(bool open)
0505 {
0506     if (mOpen != open) {
0507         mOpen = open;
0508         Q_EMIT openChanged();
0509     }
0510 }
0511 
0512 bool Room::readOnly() const
0513 {
0514     return mReadOnly;
0515 }
0516 
0517 void Room::setReadOnly(bool readOnly)
0518 {
0519     if (mReadOnly != readOnly) {
0520         mReadOnly = readOnly;
0521         Q_EMIT readOnlyChanged();
0522     }
0523 }
0524 
0525 QString Room::topic() const
0526 {
0527     return mTopic;
0528 }
0529 
0530 QString Room::displayTopic() const
0531 {
0532     if (mTopic.isEmpty()) {
0533         return {};
0534     }
0535     auto emojiManager = mRocketChatAccount ? mRocketChatAccount->emojiManager() : nullptr;
0536     auto messageCache = mRocketChatAccount ? mRocketChatAccount->messageCache() : nullptr;
0537     QString needUpdateMessageId;
0538     const TextConverter::ConvertMessageTextSettings settings(mTopic, {}, {}, {}, emojiManager, messageCache, {}, {});
0539     int recursiveIndex = 0;
0540     return TextConverter::convertMessageText(settings, needUpdateMessageId, recursiveIndex);
0541 }
0542 
0543 void Room::setTopic(const QString &topic)
0544 {
0545     if (mTopic != topic) {
0546         mTopic = topic;
0547         Q_EMIT topicChanged();
0548     }
0549 }
0550 
0551 bool Room::favorite() const
0552 {
0553     return mFavorite;
0554 }
0555 
0556 void Room::setFavorite(bool favorite)
0557 {
0558     if (mFavorite != favorite) {
0559         mFavorite = favorite;
0560         Q_EMIT favoriteChanged();
0561     }
0562 }
0563 
0564 Room::RoomType Room::channelType() const
0565 {
0566     return mChannelType;
0567 }
0568 
0569 void Room::setChannelType(RoomType channelType)
0570 {
0571     if (mChannelType != channelType) {
0572         mChannelType = channelType;
0573         Q_EMIT channelTypeChanged();
0574     }
0575 }
0576 
0577 QString Room::announcement() const
0578 {
0579     return mAnnouncement;
0580 }
0581 
0582 QString Room::displayAnnouncement() const
0583 {
0584     if (mAnnouncement.isEmpty()) {
0585         return {};
0586     }
0587     auto emojiManager = mRocketChatAccount ? mRocketChatAccount->emojiManager() : nullptr;
0588     auto messageCache = mRocketChatAccount ? mRocketChatAccount->messageCache() : nullptr;
0589     QString needUpdateMessageId;
0590     const TextConverter::ConvertMessageTextSettings settings(mAnnouncement, {}, {}, {}, emojiManager, messageCache, {}, {});
0591     int recursiveIndex = 0;
0592     return TextConverter::convertMessageText(settings, needUpdateMessageId, recursiveIndex);
0593 }
0594 
0595 void Room::setAnnouncement(const QString &announcement)
0596 {
0597     if (mAnnouncement != announcement) {
0598         mAnnouncement = announcement;
0599         Q_EMIT announcementChanged();
0600     }
0601 }
0602 
0603 void Room::setName(const QString &name)
0604 {
0605     if (mName != name) {
0606         mName = name;
0607         Q_EMIT nameChanged();
0608     }
0609 }
0610 
0611 void Room::parseInsertRoom(const QJsonObject &json)
0612 {
0613     const QString roomID = json.value(QLatin1String("_id")).toString();
0614     // qDebug() << " json " << json;
0615     setRoomId(roomID);
0616     setName(json[QLatin1String("name")].toString());
0617     setFName(json[QLatin1String("fname")].toString());
0618     setAutoTranslateLanguage(json[QLatin1String("autoTranslateLanguage")].toString());
0619     setAutoTranslate(json[QLatin1String("autoTranslate")].toBool());
0620     setJitsiTimeout(Utils::parseDate(QStringLiteral("jitsiTimeout"), json));
0621     // topic/announcement/description is not part of update subscription
0622     const QString roomType = json.value(QLatin1String("t")).toString();
0623     setChannelType(Room::roomTypeFromString(roomType));
0624     const QJsonValue favoriteValue = json.value(QLatin1String("f"));
0625     if (!favoriteValue.isUndefined()) {
0626         setFavorite(favoriteValue.toBool());
0627     }
0628     setReadOnly(json[QLatin1String("ro")].toBool());
0629     if (json.contains(QLatin1String("userMentions"))) {
0630         setUserMentions(json[QLatin1String("userMentions")].toInt());
0631     }
0632     if (json.contains(QLatin1String("announcement"))) {
0633         setAnnouncement(json[QLatin1String("announcement")].toString());
0634     }
0635     if (json.contains(QLatin1String("description"))) {
0636         setDescription(json[QLatin1String("description")].toString());
0637     }
0638     setUpdatedAt(Utils::parseDate(QStringLiteral("_updatedAt"), json));
0639     setLastSeenAt(Utils::parseDate(QStringLiteral("ls"), json));
0640     setLastMessageAt(Utils::parseDate(QStringLiteral("lm"), json));
0641     setUnread(json[QLatin1String("unread")].toInt());
0642     setOpen(json[QLatin1String("open")].toBool());
0643     setAlert(json[QLatin1String("alert")].toBool());
0644     const QJsonValue blockerValue = json.value(QLatin1String("blocker"));
0645     if (!blockerValue.isUndefined()) {
0646         setBlocker(blockerValue.toBool());
0647     } else {
0648         setBlocker(false);
0649     }
0650 
0651     // setE2eKeyId(json[QLatin1String("e2eKeyId")].toString());
0652     setE2EKey(json[QLatin1String("E2EKey")].toString());
0653 
0654     if (json.contains(QLatin1String("encrypted"))) {
0655         setEncrypted(json[QLatin1String("encrypted")].toBool());
0656     } else {
0657         setEncrypted(false);
0658     }
0659 
0660     // Blocked ???
0661     const QJsonValue archivedValue = json.value(QLatin1String("archived"));
0662     if (!archivedValue.isUndefined()) {
0663         setArchived(archivedValue.toBool());
0664     } else {
0665         setArchived(false);
0666     }
0667 
0668     parseCommonData(json);
0669     parseDisplaySystemMessage(json);
0670 
0671     const QJsonValue ownerValue = json.value(QLatin1String("u"));
0672     if (!ownerValue.isUndefined()) {
0673         const QJsonObject objOwner = ownerValue.toObject();
0674         setRoomCreatorUserId(objOwner.value(QLatin1String("_id")).toString());
0675         setRoomCreatorUserName(objOwner.value(QLatin1String("username")).toString());
0676     } else {
0677         // When room is initialized we are the owner. When we update room we have the real
0678         // owner and if it's empty => we need to clear it.
0679         setRoomCreatorUserId(QString());
0680         setRoomCreatorUserName(QString());
0681     }
0682     // qDebug() << " *thus" << *this;
0683     mNotificationOptions.parseNotificationOptions(json);
0684     parseTeamInfo(json);
0685 }
0686 
0687 qint64 Room::lastSeenAt() const
0688 {
0689     return mLastSeenAt;
0690 }
0691 
0692 void Room::setLastSeenAt(qint64 lastSeenAt)
0693 {
0694     if (mLastSeenAt != lastSeenAt) {
0695         mLastSeenAt = lastSeenAt;
0696         Q_EMIT lastSeenChanged();
0697     }
0698 }
0699 
0700 qint64 Room::lastMessageAt() const
0701 {
0702     return mLastMessageAt;
0703 }
0704 
0705 void Room::setLastMessageAt(qint64 lastMessageAt)
0706 {
0707     if (mLastMessageAt != lastMessageAt) {
0708         mLastMessageAt = lastMessageAt;
0709         Q_EMIT lastMessageAtChanged();
0710     }
0711 }
0712 
0713 bool Room::blocked() const
0714 {
0715     return mBlocked;
0716 }
0717 
0718 void Room::setBlocked(bool blocked)
0719 {
0720     if (mBlocked != blocked) {
0721         mBlocked = blocked;
0722         Q_EMIT blockedChanged();
0723     }
0724 }
0725 
0726 QStringList Room::roles() const
0727 {
0728     return mRoles;
0729 }
0730 
0731 void Room::setRoles(const QStringList &roles)
0732 {
0733     if (mRoles != roles) {
0734         mRoles = roles;
0735         Q_EMIT rolesChanged();
0736     }
0737 }
0738 
0739 QStringList Room::ignoredUsers() const
0740 {
0741     return mIgnoredUsers;
0742 }
0743 
0744 void Room::setIgnoredUsers(const QStringList &ignoredUsers)
0745 {
0746     if (mIgnoredUsers != ignoredUsers) {
0747         mIgnoredUsers = ignoredUsers;
0748         Q_EMIT ignoredUsersChanged();
0749     }
0750 }
0751 
0752 void Room::parseSubscriptionRoom(const QJsonObject &json)
0753 {
0754     QString roomID = json.value(QLatin1String("rid")).toString();
0755     if (roomID.isEmpty()) {
0756         roomID = json.value(QLatin1String("_id")).toString();
0757     }
0758     setRoomId(roomID);
0759     setName(json[QLatin1String("name")].toString());
0760     setFName(json[QLatin1String("fname")].toString());
0761     setAutoTranslateLanguage(json[QLatin1String("autoTranslateLanguage")].toString());
0762     setAutoTranslate(json[QLatin1String("autoTranslate")].toBool());
0763     setJitsiTimeout(Utils::parseDate(QStringLiteral("jitsiTimeout"), json));
0764     // topic/announcement/description is not part of update subscription
0765     const QString roomType = json.value(QLatin1String("t")).toString();
0766     setChannelType(Room::roomTypeFromString(roomType));
0767     const QJsonValue favoriteValue = json.value(QLatin1String("f"));
0768     if (!favoriteValue.isUndefined()) {
0769         setFavorite(favoriteValue.toBool());
0770     }
0771     setE2EKey(json[QLatin1String("E2EKey")].toString());
0772     setReadOnly(json[QLatin1String("ro")].toBool());
0773 
0774     setUpdatedAt(Utils::parseDate(QStringLiteral("_updatedAt"), json));
0775     setLastSeenAt(Utils::parseDate(QStringLiteral("ls"), json));
0776     setUnread(json[QLatin1String("unread")].toInt());
0777     setUserMentions(json[QLatin1String("userMentions")].toInt());
0778     setOpen(json[QLatin1String("open")].toBool());
0779     setAlert(json[QLatin1String("alert")].toBool());
0780     const QJsonValue blockerValue = json.value(QLatin1String("blocker"));
0781     if (!blockerValue.isUndefined()) {
0782         setBlocker(blockerValue.toBool());
0783     } else {
0784         setBlocker(false);
0785     }
0786     // TODO e2ekey
0787     // TODO blocked ?
0788     const QJsonValue archivedValue = json.value(QLatin1String("archived"));
0789     if (!archivedValue.isUndefined()) {
0790         setArchived(archivedValue.toBool());
0791     } else {
0792         setArchived(false);
0793     }
0794 
0795     parseCommonData(json);
0796     parseDisplaySystemMessage(json);
0797 
0798     //    const QJsonValue ownerValue = json.value(QLatin1String("u"));
0799     //    if (!ownerValue.isUndefined()) {
0800     //        const QJsonObject objOwner = ownerValue.toObject();
0801     //        setRoomCreatorUserId(objOwner.value(QLatin1String("_id")).toString());
0802     //        setRoomCreatorUserName(objOwner.value(QLatin1String("username")).toString());
0803     //    } else {
0804     //        //When room is initialized we are the owner. When we update room we have the real
0805     //        //owner and if it's empty => we need to clear it.
0806     //        setRoomCreatorUserId(QString());
0807     //        setRoomCreatorUserName(QString());
0808     //    }
0809     // qDebug() << " *thus" << *this;
0810     mNotificationOptions.parseNotificationOptions(json);
0811     parseRetentionInfo(json);
0812     // parseTeamInfo(json);
0813     // TODO add muted
0814 }
0815 
0816 void Room::parseRetentionInfo(const QJsonObject &json)
0817 {
0818     const QJsonValue retentionValue = json.value(QLatin1String("retention"));
0819     if (!retentionValue.isUndefined()) {
0820         mRetentionInfo.parseRetentionInfo(retentionValue.toObject());
0821     }
0822 }
0823 
0824 Room::TeamRoomInfo Room::teamRoomInfo() const
0825 {
0826     if (mRocketChatAccount) {
0827         if (!mTeamInfo.mainTeam() && !mTeamInfo.teamId().isEmpty()) {
0828             return mRocketChatAccount->roomFromTeamId(mTeamInfo.teamId());
0829         }
0830     }
0831     return {};
0832 }
0833 
0834 TeamInfo Room::teamInfo() const
0835 {
0836     return mTeamInfo;
0837 }
0838 
0839 void Room::setTeamInfo(const TeamInfo &teamInfo)
0840 {
0841     if (mTeamInfo != teamInfo) {
0842         mTeamInfo = teamInfo;
0843         Q_EMIT teamInfoChanged();
0844     }
0845 }
0846 
0847 void Room::parseDisplaySystemMessage(const QJsonObject &json)
0848 {
0849     const QJsonArray sysMessArray = json.value(QLatin1String("sysMes")).toArray();
0850     QStringList lst;
0851     const auto sysMessArrayCount{sysMessArray.count()};
0852     lst.reserve(sysMessArrayCount);
0853     for (auto i = 0; i < sysMessArrayCount; ++i) {
0854         lst << sysMessArray.at(i).toString();
0855     }
0856     setDisplaySystemMessageTypes(lst);
0857 }
0858 
0859 RetentionInfo Room::retentionInfo() const
0860 {
0861     return mRetentionInfo;
0862 }
0863 
0864 void Room::setRetentionInfo(RetentionInfo retentionInfo)
0865 {
0866     if (mRetentionInfo != retentionInfo) {
0867         mRetentionInfo = retentionInfo;
0868         Q_EMIT retentionInfoChanged();
0869     }
0870 }
0871 
0872 QStringList Room::highlightsWord() const
0873 {
0874     return mHighlightsWord;
0875 }
0876 
0877 void Room::setHighlightsWord(const QStringList &highlightsWord)
0878 {
0879     if (mHighlightsWord != highlightsWord) {
0880         mHighlightsWord = highlightsWord;
0881         Q_EMIT highlightsWordChanged();
0882     }
0883 }
0884 
0885 QStringList Room::userNames() const
0886 {
0887     return mUserNames;
0888 }
0889 
0890 void Room::setUserNames(const QStringList &userNames)
0891 {
0892     if (mUserNames != userNames) {
0893         mUserNames = userNames;
0894         Q_EMIT userNamesChanged();
0895     }
0896 }
0897 
0898 QStringList Room::uids() const
0899 {
0900     return mUids;
0901 }
0902 
0903 void Room::setUids(const QStringList &uids)
0904 {
0905     if (mUids != uids) {
0906         mUids = uids;
0907         mCurrentAvatarInfo = {};
0908         Q_EMIT uidsChanged();
0909     }
0910 }
0911 
0912 Utils::AvatarInfo Room::avatarInfo() const
0913 {
0914     if (mCurrentAvatarInfo.isValid()) {
0915         return mCurrentAvatarInfo;
0916     }
0917     // TODO direct channel or group channel
0918     Utils::AvatarInfo info;
0919     info.etag = mAvatarETag;
0920     // Group => uids >= 3
0921     if (mUids.count() > 2) {
0922         QString identifier;
0923         for (const QString &username : mUserNames) {
0924             identifier.append(username);
0925         }
0926         identifier.prepend(QString::number(mUids.count()));
0927         info.avatarType = Utils::AvatarType::User;
0928         info.identifier = identifier;
0929     } else if (mUids.count() == 2) {
0930         info.avatarType = Utils::AvatarType::User;
0931         if (mRocketChatAccount) {
0932             QString otherUserName;
0933             for (const QString &userName : mUserNames) {
0934                 if (userName != mRocketChatAccount->userName()) {
0935                     otherUserName = userName;
0936                 }
0937             }
0938             info.identifier = otherUserName;
0939         }
0940     } else {
0941         info.avatarType = Utils::AvatarType::Room;
0942         info.identifier = mRoomId;
0943     }
0944     mCurrentAvatarInfo = info;
0945     return mCurrentAvatarInfo;
0946 }
0947 
0948 QString Room::avatarETag() const
0949 {
0950     return mAvatarETag;
0951 }
0952 
0953 void Room::setAvatarETag(const QString &avatarETag)
0954 {
0955     if (mAvatarETag != avatarETag) {
0956         mAvatarETag = avatarETag;
0957         mCurrentAvatarInfo = {};
0958         Q_EMIT avatarETagChanged();
0959     }
0960 }
0961 
0962 ChannelCounterInfo Room::channelCounterInfo() const
0963 {
0964     return mChannelCounterInfo;
0965 }
0966 
0967 void Room::setChannelCounterInfo(const ChannelCounterInfo &channelCounterInfo)
0968 {
0969     if (mChannelCounterInfo != channelCounterInfo) {
0970         mChannelCounterInfo = channelCounterInfo;
0971         Q_EMIT channelCounterInfoChanged();
0972     }
0973 }
0974 
0975 void Room::newMessageAdded()
0976 {
0977     if (mChannelCounterInfo.isValid()) {
0978         if (mChannelCounterInfo.unreadMessages() > 0) {
0979             const auto unreadMessageCount = mChannelCounterInfo.unreadMessages() + 1;
0980             mChannelCounterInfo.setUnreadMessages(unreadMessageCount);
0981             Q_EMIT channelCounterInfoChanged();
0982             // qDebug() << " mChannelCounterInfo " << mChannelCounterInfo;
0983         }
0984     }
0985 }
0986 
0987 void Room::parseCommonData(const QJsonObject &json)
0988 {
0989     const QJsonArray mutedArray = json.value(QLatin1String("muted")).toArray();
0990     QStringList lst;
0991     lst.reserve(mutedArray.count());
0992     for (int i = 0; i < mutedArray.count(); ++i) {
0993         lst << mutedArray.at(i).toString();
0994     }
0995     setMutedUsers(lst);
0996 
0997     const QJsonArray ignoredArray = json.value(QLatin1String("ignored")).toArray();
0998     QStringList lstIgnored;
0999     lstIgnored.reserve(ignoredArray.count());
1000     for (int i = 0; i < ignoredArray.count(); ++i) {
1001         lstIgnored << ignoredArray.at(i).toString();
1002     }
1003     setIgnoredUsers(lstIgnored);
1004 
1005     const QJsonArray rolesArray = json.value(QLatin1String("roles")).toArray();
1006     QStringList lstRoles;
1007     lstRoles.reserve(rolesArray.count());
1008     for (int i = 0; i < rolesArray.count(); ++i) {
1009         lstRoles << rolesArray.at(i).toString();
1010     }
1011     setRoles(lstRoles);
1012 
1013     // FIXME.
1014     const QJsonArray highlightsWordArray = json.value(QLatin1String("userHighlights")).toArray();
1015     QStringList lstHighlightsWord;
1016     const int highlightsWordArrayCount = highlightsWordArray.count();
1017     lstHighlightsWord.reserve(highlightsWordArrayCount);
1018     for (int i = 0; i < highlightsWordArrayCount; ++i) {
1019         lstHighlightsWord << highlightsWordArray.at(i).toString();
1020     }
1021     setHighlightsWord(lstHighlightsWord);
1022 }
1023 
1024 QStringList Room::displaySystemMessageTypes() const
1025 {
1026     return mDisplaySystemMessageType;
1027 }
1028 
1029 void Room::setDisplaySystemMessageTypes(const QStringList &systemMessageType)
1030 {
1031     if (mDisplaySystemMessageType != systemMessageType) {
1032         mDisplaySystemMessageType = systemMessageType;
1033         Q_EMIT displaySystemMessageTypesChanged();
1034     }
1035 }
1036 
1037 bool Room::autoTranslate() const
1038 {
1039     return mAutoTranslate;
1040 }
1041 
1042 void Room::setAutoTranslate(bool autoTranslate)
1043 {
1044     if (mAutoTranslate != autoTranslate) {
1045         mAutoTranslate = autoTranslate;
1046         Q_EMIT autoTranslateChanged();
1047     }
1048 }
1049 
1050 QString Room::autoTranslateLanguage() const
1051 {
1052     return mAutotranslateLanguage;
1053 }
1054 
1055 void Room::setAutoTranslateLanguage(const QString &autotranslateLanguage)
1056 {
1057     if (mAutotranslateLanguage != autotranslateLanguage) {
1058         mAutotranslateLanguage = autotranslateLanguage;
1059         Q_EMIT autoTranslateLanguageChanged();
1060     }
1061 }
1062 
1063 QString Room::displayFName() const
1064 {
1065     if (mFName.isEmpty()) { // Fallback to name if fname is empty
1066         return mName;
1067     }
1068     return mFName;
1069 }
1070 
1071 QString Room::fName() const
1072 {
1073     return mFName;
1074 }
1075 
1076 void Room::setFName(const QString &value)
1077 {
1078     if (mFName != value) {
1079         mFName = value;
1080         Q_EMIT fnameChanged();
1081     }
1082 }
1083 
1084 bool Room::isDiscussionRoom() const
1085 {
1086     return !mParentRid.isEmpty();
1087 }
1088 
1089 QString Room::parentRid() const
1090 {
1091     return mParentRid;
1092 }
1093 
1094 void Room::setParentRid(const QString &parentRid)
1095 {
1096     if (mParentRid != parentRid) {
1097         mParentRid = parentRid;
1098         Q_EMIT parentRidChanged();
1099     }
1100 }
1101 
1102 bool Room::broadcast() const
1103 {
1104     return mBroadcast;
1105 }
1106 
1107 void Room::setBroadcast(bool broadcast)
1108 {
1109     if (mBroadcast != broadcast) {
1110         mBroadcast = broadcast;
1111         Q_EMIT broadcastChanged();
1112     }
1113 }
1114 
1115 Roles Room::rolesForRooms() const
1116 {
1117     return mRolesForRooms;
1118 }
1119 
1120 void Room::setRolesForRooms(const Roles &rolesForRooms)
1121 {
1122     mRolesForRooms = rolesForRooms;
1123 }
1124 
1125 bool Room::hasPermission(const QString &permission) const
1126 {
1127     if (mRocketChatAccount) {
1128         const QStringList permissionRoles = mRocketChatAccount->permissions(permission);
1129         for (const QString &role : permissionRoles) {
1130             if (mRoles.contains(role)) {
1131                 return true;
1132             }
1133         }
1134     }
1135     return false;
1136 }
1137 
1138 bool Room::allowToPinMessage() const
1139 {
1140     return hasPermission(QStringLiteral("pin-message"));
1141 }
1142 
1143 QStringList Room::rolesForUserId(const QString &userId)
1144 {
1145     QStringList lstRoles;
1146     const Role r = mRolesForRooms.findRoleByUserId(userId);
1147     // qDebug() << " mRolesForRooms" << mRolesForRooms;
1148     if (r.isValid()) {
1149         if (r.isOwner()) {
1150             lstRoles.append(i18n("Owner"));
1151         }
1152         if (r.isLeader()) {
1153             lstRoles.append(i18n("Leader"));
1154         }
1155         if (r.isModerator()) {
1156             lstRoles.append(i18n("Moderator"));
1157         }
1158     }
1159     return lstRoles;
1160 }
1161 
1162 bool Room::wasInitialized() const
1163 {
1164     return mWasInitialized;
1165 }
1166 
1167 void Room::setWasInitialized(bool wasInitialized)
1168 {
1169     mWasInitialized = wasInitialized;
1170 }
1171 
1172 bool Room::joinCodeRequired() const
1173 {
1174     return mJoinCodeRequired;
1175 }
1176 
1177 void Room::setJoinCodeRequired(bool joinCodeRequired)
1178 {
1179     if (mJoinCodeRequired != joinCodeRequired) {
1180         mJoinCodeRequired = joinCodeRequired;
1181         Q_EMIT joinCodeRequiredChanged();
1182     }
1183 }
1184 
1185 QString Room::e2eKeyId() const
1186 {
1187     return mE2eKeyId;
1188 }
1189 
1190 void Room::setE2eKeyId(const QString &e2eKeyId)
1191 {
1192     if (mE2eKeyId != e2eKeyId) {
1193         mE2eKeyId = e2eKeyId;
1194         Q_EMIT encryptionKeyIdChanged();
1195     }
1196 }
1197 
1198 QString Room::e2EKey() const
1199 {
1200     return mE2EKey;
1201 }
1202 
1203 void Room::setE2EKey(const QString &e2EKey)
1204 {
1205     if (mE2EKey != e2EKey) {
1206         mE2EKey = e2EKey;
1207         Q_EMIT encryptionKeyChanged();
1208     }
1209 }
1210 
1211 bool Room::encrypted() const
1212 {
1213     return mEncrypted;
1214 }
1215 
1216 void Room::setEncrypted(bool encrypted)
1217 {
1218     if (mEncrypted != encrypted) {
1219         mEncrypted = encrypted;
1220         Q_EMIT encryptedChanged();
1221     }
1222 }
1223 
1224 void Room::deserialize(Room *r, const QJsonObject &o)
1225 {
1226     r->setRoomId(o[QLatin1String("rid")].toString());
1227     r->setChannelType(Room::roomTypeFromString(o[QLatin1String("t")].toString()));
1228     r->setName(o[QLatin1String("name")].toString());
1229     r->setFName(o[QLatin1String("fname")].toString());
1230     r->setAutoTranslateLanguage(o[QLatin1String("autoTranslateLanguage")].toString());
1231     r->setAutoTranslate(o[QLatin1String("autoTranslate")].toBool());
1232     r->setRoomCreatorUserName(o[QLatin1String("roomCreatorUserName")].toString());
1233     r->setRoomCreatorUserId(o[QLatin1String("roomCreatorUserID")].toString());
1234     r->setTopic(o[QLatin1String("topic")].toString());
1235     r->setJitsiTimeout(static_cast<qint64>(o[QLatin1String("jitsiTimeout")].toDouble()));
1236     r->setReadOnly(o[QLatin1String("ro")].toBool());
1237     r->setUnread(o[QLatin1String("unread")].toInt(0));
1238     r->setUserMentions(o[QLatin1String("userMentions")].toInt(0));
1239     r->setAnnouncement(o[QLatin1String("announcement")].toString());
1240     r->setSelected(o[QLatin1String("selected")].toBool());
1241     r->setFavorite(o[QLatin1String("favorite")].toBool());
1242     r->setAlert(o[QLatin1String("alert")].toBool());
1243     r->setOpen(o[QLatin1String("open")].toBool());
1244     r->setArchived(o[QLatin1String("archived")].toBool());
1245     r->setDescription(o[QLatin1String("description")].toString());
1246     r->setBlocker(o[QLatin1String("blocker")].toBool());
1247     r->setBlocked(o[QLatin1String("blocked")].toBool());
1248     r->setEncrypted(o[QLatin1String("encrypted")].toBool());
1249     r->setBroadcast(o[QLatin1String("broadcast")].toBool());
1250     r->setE2EKey(o[QLatin1String("e2ekey")].toString());
1251     r->setE2eKeyId(o[QLatin1String("e2ekeyid")].toString());
1252     r->setJoinCodeRequired(o[QLatin1String("joinCodeRequired")].toBool());
1253     r->setUpdatedAt(static_cast<qint64>(o[QLatin1String("updatedAt")].toDouble()));
1254     r->setLastSeenAt(static_cast<qint64>(o[QLatin1String("lastSeenAt")].toDouble()));
1255     r->setNumberMessages(static_cast<qint64>(o[QLatin1String("msgs")].toInt()));
1256     const QJsonArray mutedArray = o.value(QLatin1String("mutedUsers")).toArray();
1257     QStringList lst;
1258     const auto nbMutedElement{mutedArray.count()};
1259     lst.reserve(nbMutedElement);
1260     for (int i = 0; i < nbMutedElement; ++i) {
1261         lst << mutedArray.at(i).toString();
1262     }
1263     r->setMutedUsers(lst);
1264 
1265     const QJsonArray systemMessagesArray = o.value(QLatin1String("systemMessages")).toArray();
1266     lst.clear();
1267     const auto nbSystemMessagesCount{systemMessagesArray.count()};
1268     lst.reserve(nbSystemMessagesCount);
1269     for (int i = 0; i < nbSystemMessagesCount; ++i) {
1270         lst << systemMessagesArray.at(i).toString();
1271     }
1272     r->setDisplaySystemMessageTypes(lst);
1273 
1274     const QJsonArray ignoredArray = o.value(QLatin1String("ignored")).toArray();
1275     QStringList lstIgnored;
1276     const auto ignoredArrayCount{ignoredArray.count()};
1277     lstIgnored.reserve(ignoredArrayCount);
1278     for (int i = 0; i < ignoredArrayCount; ++i) {
1279         lstIgnored << ignoredArray.at(i).toString();
1280     }
1281     r->setIgnoredUsers(lstIgnored);
1282 
1283     const QJsonArray highlightsWordArray = o.value(QLatin1String("userHighlights")).toArray();
1284     QStringList lstHighlightsWord;
1285     const auto highlightsWordArrayCount{highlightsWordArray.count()};
1286     lstHighlightsWord.reserve(highlightsWordArrayCount);
1287     for (int i = 0; i < highlightsWordArrayCount; ++i) {
1288         lstHighlightsWord << highlightsWordArray.at(i).toString();
1289     }
1290     r->setHighlightsWord(lstHighlightsWord);
1291     const QJsonArray rolesArray = o.value(QLatin1String("roles")).toArray();
1292     QStringList lstRoles;
1293     const auto rolesCount{rolesArray.count()};
1294 
1295     lstRoles.reserve(rolesCount);
1296     for (int i = 0; i < rolesCount; ++i) {
1297         lstRoles << rolesArray.at(i).toString();
1298     }
1299     r->setRoles(lstRoles);
1300 
1301     const QJsonObject notificationsObj = o.value(QLatin1String("notifications")).toObject();
1302     const NotificationOptions notifications = NotificationOptions::deserialize(notificationsObj);
1303     r->setNotificationOptions(notifications);
1304 
1305     r->setDirectChannelUserId(o[QLatin1String("directChannelUserId")].toString());
1306 
1307     r->setAvatarETag(o[QLatin1String("avatarETag")].toString());
1308 
1309     const QJsonArray uidsArray = o.value(QLatin1String("uids")).toArray();
1310     QStringList lstUids;
1311     const auto uidsArrayCount{uidsArray.count()};
1312     lstUids.reserve(uidsArrayCount);
1313     for (int i = 0; i < uidsArrayCount; ++i) {
1314         lstUids << uidsArray.at(i).toString();
1315     }
1316     r->setUids(lstUids);
1317     const QJsonObject retentionObj = o.value(QLatin1String("retention")).toObject();
1318     const RetentionInfo retention = RetentionInfo::deserialize(retentionObj);
1319     r->setRetentionInfo(retention);
1320     const TeamInfo teaminfo = TeamInfo::deserialize(o);
1321     r->setTeamInfo(teaminfo);
1322 
1323     r->setParentRid(o[QLatin1String("prid")].toString());
1324 
1325     const QJsonArray userNamesArray = o.value(QLatin1String("usernames")).toArray();
1326     QStringList lstUserNames;
1327     const int nbUserNamesArray = userNamesArray.count();
1328     lstUserNames.reserve(nbUserNamesArray);
1329     for (int i = 0; i < nbUserNamesArray; ++i) {
1330         lstUserNames << userNamesArray.at(i).toString();
1331     }
1332     r->setUserNames(lstUserNames);
1333 }
1334 
1335 // For autotest only
1336 std::unique_ptr<Room> Room::deserialize(const QJsonObject &o)
1337 {
1338     auto r = std::make_unique<Room>(nullptr);
1339     deserialize(r.get(), o);
1340     return r;
1341 }
1342 
1343 QByteArray Room::serialize(Room *r, bool toBinary)
1344 {
1345     QJsonDocument d;
1346     QJsonObject o;
1347 
1348     // todo add timestamp
1349 
1350     o[QLatin1String("rid")] = r->roomId();
1351     o[QLatin1String("t")] = Room::roomFromRoomType(r->channelType());
1352     o[QLatin1String("name")] = r->name();
1353     o[QLatin1String("fname")] = r->fName();
1354     o[QLatin1String("roomCreatorUserName")] = r->roomOwnerUserName();
1355     o[QLatin1String("roomCreatorUserID")] = r->roomCreatorUserId();
1356     if (r->numberMessages() > 0) {
1357         o[QLatin1String("msgs")] = r->numberMessages();
1358     }
1359     if (!r->topic().isEmpty()) {
1360         o[QLatin1String("topic")] = r->topic();
1361     }
1362     if (!r->autoTranslateLanguage().isEmpty()) {
1363         o[QLatin1String("autoTranslateLanguage")] = r->autoTranslateLanguage();
1364     }
1365     if (r->autoTranslate()) {
1366         o[QLatin1String("autoTranslate")] = r->autoTranslate();
1367     }
1368     o[QLatin1String("jitsiTimeout")] = r->jitsiTimeout();
1369     o[QLatin1String("updatedAt")] = r->updatedAt();
1370     o[QLatin1String("lastSeenAt")] = r->lastSeenAt();
1371     o[QLatin1String("ro")] = r->readOnly();
1372     o[QLatin1String("unread")] = r->unread();
1373     if (!r->announcement().isEmpty()) {
1374         o[QLatin1String("announcement")] = r->announcement();
1375     }
1376     o[QLatin1String("selected")] = r->selected();
1377     o[QLatin1String("favorite")] = r->favorite();
1378     o[QLatin1String("alert")] = r->alert();
1379     o[QLatin1String("open")] = r->open();
1380     o[QLatin1String("blocker")] = r->blocker();
1381     o[QLatin1String("blocked")] = r->blocked();
1382     o[QLatin1String("encrypted")] = r->encrypted();
1383     o[QLatin1String("archived")] = r->archived();
1384     o[QLatin1String("broadcast")] = r->broadcast();
1385     if (r->joinCodeRequired()) {
1386         o[QLatin1String("joinCodeRequired")] = true;
1387     }
1388     if (!r->e2EKey().isEmpty()) {
1389         o[QLatin1String("e2ekey")] = r->e2EKey();
1390     }
1391     if (!r->e2eKeyId().isEmpty()) {
1392         o[QLatin1String("e2ekeyid")] = r->e2eKeyId();
1393     }
1394 
1395     if (!r->description().isEmpty()) {
1396         o[QLatin1String("description")] = r->description();
1397     }
1398     o[QLatin1String("userMentions")] = r->userMentions();
1399 
1400     if (!r->mutedUsers().isEmpty()) {
1401         QJsonArray array;
1402         const int nbMuted = r->mutedUsers().count();
1403         for (int i = 0; i < nbMuted; ++i) {
1404             array.append(r->mutedUsers().at(i));
1405         }
1406         o[QLatin1String("mutedUsers")] = array;
1407     }
1408 
1409     if (!r->ignoredUsers().isEmpty()) {
1410         QJsonArray array;
1411         const int nbIgnoredUsers = r->ignoredUsers().count();
1412         for (int i = 0; i < nbIgnoredUsers; ++i) {
1413             array.append(r->ignoredUsers().at(i));
1414         }
1415         o[QLatin1String("ignored")] = array;
1416     }
1417 
1418     if (!r->roles().isEmpty()) {
1419         QJsonArray array;
1420         const int nbRoles = r->roles().count();
1421         for (int i = 0; i < nbRoles; ++i) {
1422             array.append(r->roles().at(i));
1423         }
1424         o[QLatin1String("roles")] = array;
1425     }
1426 
1427     o[QLatin1String("notifications")] = NotificationOptions::serialize(r->notificationOptions());
1428 
1429     if (!r->directChannelUserId().isEmpty()) {
1430         o[QLatin1String("directChannelUserId")] = r->directChannelUserId();
1431     }
1432 
1433     if (!r->displaySystemMessageTypes().isEmpty()) {
1434         QJsonArray array;
1435         const int nbDisplaySystemMessageType = r->displaySystemMessageTypes().count();
1436         for (int i = 0; i < nbDisplaySystemMessageType; ++i) {
1437             array.append(r->displaySystemMessageTypes().at(i));
1438         }
1439         o[QLatin1String("systemMessages")] = array;
1440     }
1441 
1442     if (!r->highlightsWord().isEmpty()) {
1443         QJsonArray array;
1444         const int nbHighlightsWord = r->highlightsWord().count();
1445         for (int i = 0; i < nbHighlightsWord; ++i) {
1446             array.append(r->highlightsWord().at(i));
1447         }
1448         o[QLatin1String("userHighlights")] = array;
1449     }
1450 
1451     if (!r->avatarETag().isEmpty()) {
1452         o[QLatin1String("avatarETag")] = r->avatarETag();
1453     }
1454     if (!r->uids().isEmpty()) {
1455         o[QLatin1String("uids")] = QJsonArray::fromStringList(r->uids());
1456     }
1457 
1458     if (r->retentionInfo().isNotDefault()) {
1459         o[QLatin1String("retention")] = RetentionInfo::serialize(r->retentionInfo());
1460     }
1461     if (r->teamInfo().isValid()) {
1462         TeamInfo::serialize(r->teamInfo(), o);
1463     }
1464     if (!r->parentRid().isEmpty()) {
1465         o[QLatin1String("prid")] = r->parentRid();
1466     }
1467 
1468     if (!r->userNames().isEmpty()) {
1469         QJsonArray array;
1470         const int nbUserNames = r->userNames().count();
1471         for (int i = 0; i < nbUserNames; ++i) {
1472             array.append(r->userNames().at(i));
1473         }
1474         o[QLatin1String("usernames")] = array;
1475     }
1476 
1477     if (toBinary) {
1478         return QCborValue::fromJsonValue(o).toCbor();
1479     }
1480     d.setObject(o);
1481     return d.toJson(QJsonDocument::Indented);
1482 }
1483 
1484 UsersForRoomModel *Room::usersModelForRoom() const
1485 {
1486     return mUsersModelForRoom;
1487 }
1488 
1489 MessagesModel *Room::messageModel() const
1490 {
1491     return mMessageModel;
1492 }
1493 
1494 QString Room::inputMessage() const
1495 {
1496     return mInputMessage;
1497 }
1498 
1499 void Room::setInputMessage(const QString &inputMessage)
1500 {
1501     mInputMessage = inputMessage;
1502 }
1503 
1504 bool Room::archived() const
1505 {
1506     return mArchived;
1507 }
1508 
1509 void Room::setArchived(bool archived)
1510 {
1511     if (mArchived != archived) {
1512         mArchived = archived;
1513         Q_EMIT archivedChanged();
1514     }
1515 }
1516 
1517 QString Room::description() const
1518 {
1519     return mDescription;
1520 }
1521 
1522 void Room::setDescription(const QString &description)
1523 {
1524     if (mDescription != description) {
1525         mDescription = description;
1526         Q_EMIT descriptionChanged();
1527     }
1528 }
1529 
1530 bool Room::encryptedEnabled() const
1531 {
1532     if (mRocketChatAccount) {
1533         return mRocketChatAccount->encryptionEnabled();
1534     }
1535     return false;
1536 }
1537 
1538 bool Room::userIsIgnored(const QString &userId)
1539 {
1540     return mIgnoredUsers.contains(userId);
1541 }
1542 
1543 bool Room::roomIsBlocked() const
1544 {
1545     return ((mReadOnly && !canChangeRoles()) || mArchived) || mBlocker || mBlocked;
1546 }
1547 
1548 QString Room::roomMessageInfo() const
1549 {
1550     if ((mReadOnly && !canChangeRoles()) || mArchived) {
1551         return i18n("Channel is read only.");
1552     }
1553     if (mBlocker) {
1554         return i18n("You have blocked this channel.");
1555     }
1556     if (mBlocked) {
1557         return i18n("Channel was blocked.");
1558     }
1559     return {};
1560 }
1561 
1562 bool Room::canChangeRoles() const
1563 {
1564     return mRoles.contains(QStringLiteral("owner"));
1565 }
1566 
1567 bool Room::userHasOwnerRole(const QString &userId) const
1568 {
1569     const Role r = mRolesForRooms.findRoleByUserId(userId);
1570     if (r.isValid()) {
1571         return r.isOwner();
1572     }
1573     return false;
1574 }
1575 
1576 bool Room::userHasLeaderRole(const QString &userId) const
1577 {
1578     const Role r = mRolesForRooms.findRoleByUserId(userId);
1579     if (r.isValid()) {
1580         return r.isLeader();
1581     }
1582     return false;
1583 }
1584 
1585 bool Room::userHasModeratorRole(const QString &userId) const
1586 {
1587     const Role r = mRolesForRooms.findRoleByUserId(userId);
1588     if (r.isValid()) {
1589         return r.isModerator();
1590     }
1591     return false;
1592 }
1593 
1594 void Room::updateRoles(const QJsonObject &obj)
1595 {
1596     mRolesForRooms.updateRoles(obj);
1597 }
1598 
1599 QString Room::directChannelUserId() const
1600 {
1601     return mDirectChannelUserId;
1602 }
1603 
1604 void Room::setDirectChannelUserId(const QString &uid)
1605 {
1606     if (mDirectChannelUserId != uid) {
1607         mDirectChannelUserId = uid;
1608         Q_EMIT directChannelUserIdChanged();
1609     }
1610 }
1611 
1612 #include "moc_room.cpp"