File indexing completed on 2025-02-16 07:48:52
0001 /* 0002 SPDX-FileCopyrightText: 2017-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "rocketchataccount.h" 0008 #include "accountroomsettings.h" 0009 0010 #include "attachments/fileattachments.h" 0011 #include "authenticationmanager.h" 0012 #include "autotranslate/getsupportedlanguagesjob.h" 0013 #include "commands/listcommandsjob.h" 0014 #include "config-ruqola.h" 0015 #include "customemojiiconmanager.h" 0016 #include "downloadappslanguages/downloadappslanguagesmanager.h" 0017 #include "emoticons/emojimanager.h" 0018 #include "encryption/e2ekeymanager.h" 0019 #include "managerdatapaths.h" 0020 #include "messagequeue.h" 0021 #include "previewurlcachemanager.h" 0022 0023 #include "model/autotranslatelanguagesmodel.h" 0024 #include "model/commandsmodel.h" 0025 #include "model/commonmessagefilterproxymodel.h" 0026 #include "model/commonmessagesmodel.h" 0027 #include "model/discussionsfilterproxymodel.h" 0028 #include "model/discussionsmodel.h" 0029 #include "model/emoticonmodel.h" 0030 #include "model/filesforroomfilterproxymodel.h" 0031 #include "model/filesforroommodel.h" 0032 #include "model/listmessagesfilterproxymodel.h" 0033 #include "model/messagesmodel.h" 0034 #include "model/statusmodel.h" 0035 #include "model/threadmessagemodel.h" 0036 #include "model/usercompleterfilterproxymodel.h" 0037 #include "model/usercompletermodel.h" 0038 #include "model/usersforroommodel.h" 0039 #include "model/usersmodel.h" 0040 #include "otr/otrmanager.h" 0041 #include "rocketchatbackend.h" 0042 #include "rocketchatcache.h" 0043 #include "ruqola.h" 0044 #include "ruqola_debug.h" 0045 #include "ruqola_notification_debug.h" 0046 #include "ruqola_reconnect_core_debug.h" 0047 #include "ruqola_typing_notification_debug.h" 0048 #include "ruqolaglobalconfig.h" 0049 #include "ruqolalogger.h" 0050 #include "typingnotification.h" 0051 #include <TextEmoticonsCore/UnicodeEmoticonManager> 0052 0053 #include "channelcounterinfo.h" 0054 #include "connection.h" 0055 #include "ddpapi/ddpclient.h" 0056 #include "directmessage/opendmjob.h" 0057 #include "discussions/discussions.h" 0058 #include "emoji/loademojicustomjob.h" 0059 #include "license/licensesisenterprisejob.h" 0060 #include "listmessages.h" 0061 #include "localdatabase/localdatabasemanager.h" 0062 #include "localdatabase/localdatabaseutils.h" 0063 #include "managechannels.h" 0064 #include "managelocaldatabase.h" 0065 #include "messagecache.h" 0066 #include "misc/roleslistjob.h" 0067 #include "receivetypingnotificationmanager.h" 0068 #include "ruqola_thread_message_debug.h" 0069 #include "uploadfilemanager.h" 0070 #include "videoconference/videoconferencemanager.h" 0071 #include "videoconference/videoconferencemessageinfomanager.h" 0072 0073 #include "channelgroupbasejob.h" 0074 #include <KLocalizedString> 0075 #include <KNotification> 0076 #include <QDesktopServices> 0077 #include <QJsonArray> 0078 #include <QTimer> 0079 #include <TextEmoticonsCore/EmojiModel> 0080 #include <TextEmoticonsCore/EmojiModelManager> 0081 0082 #if HAVE_NETWORKMANAGER 0083 #include <NetworkManagerQt/Manager> 0084 #endif 0085 0086 #if HAVE_SOLID 0087 #include <Solid/Power> 0088 #endif 0089 0090 #include "plugins/pluginauthentication.h" 0091 #include "plugins/pluginauthenticationinterface.h" 0092 0093 #include "away/awaymanager.h" 0094 #include "customsound/customsoundsmanager.h" 0095 #include "model/switchchannelhistorymodel.h" 0096 #include "users/setstatusjob.h" 0097 #include "users/usersautocompletejob.h" 0098 0099 RocketChatAccount::RocketChatAccount(const QString &accountFileName, QObject *parent) 0100 : QObject(parent) 0101 , mAccountRoomSettings(new AccountRoomSettings) 0102 , mUserModel(new UsersModel(this)) 0103 , mRoomModel(new RoomModel(this, this)) 0104 , mRuqolaServerConfig(new RuqolaServerConfig) 0105 , mUserCompleterModel(new UserCompleterModel(this)) 0106 , mStatusModel(new StatusModel(this)) 0107 , mOtrManager(new OtrManager(this, this)) 0108 , mInputTextManager(new InputTextManager(this, this)) 0109 , mInputThreadMessageTextManager(new InputTextManager(this, this)) 0110 , mReceiveTypingNotificationManager(new ReceiveTypingNotificationManager(this)) 0111 , mDiscussionsModel(new DiscussionsModel(this)) 0112 , mCommandsModel(new CommandsModel(this)) 0113 , mAutoTranslateLanguagesModel(new AutotranslateLanguagesModel(this)) 0114 , mDownloadAppsLanguagesManager(new DownloadAppsLanguagesManager(this)) 0115 , mMessageCache(new MessageCache(this, this)) 0116 , mManageChannels(new ManageChannels(this, this)) 0117 , mCustomSoundManager(new CustomSoundsManager(this)) 0118 , mAwayManager(new AwayManager(this, this)) 0119 , mSwitchChannelHistoryModel(new SwitchChannelHistoryModel(this)) 0120 , mUploadFileManager(new UploadFileManager(this, this)) 0121 , mVideoConferenceManager(new VideoConferenceManager(this, this)) 0122 , mVideoConferenceMessageInfoManager(new VideoConferenceMessageInfoManager(this, this)) 0123 , mLocalDatabaseManager(std::make_unique<LocalDatabaseManager>()) 0124 , mManageLoadHistory(new ManageLocalDatabase(this, this)) 0125 , mPreviewUrlCacheManager(new PreviewUrlCacheManager(this, this)) 0126 , mE2eKeyManager(new E2eKeyManager(this, this)) 0127 { 0128 qCDebug(RUQOLA_LOG) << " RocketChatAccount::RocketChatAccount(const QString &accountFileName, QObject *parent)" << accountFileName; 0129 // create an unique file for each account 0130 loadSettings(accountFileName); 0131 #if 0 // Disable it otherwise autotests failed 0132 if (!mSettings->isValid()) { 0133 return; 0134 } 0135 #endif 0136 if (!qEnvironmentVariableIsEmpty("RUQOLA_LOGFILE")) { 0137 mRuqolaLogger = new RuqolaLogger(mSettings->accountName()); 0138 } 0139 0140 mServerConfigInfo = new ServerConfigInfo(this, this); 0141 // Create it before loading settings 0142 0143 mInputTextManager->setObjectName(QStringLiteral("mInputTextManager")); 0144 connect(mInputTextManager, 0145 &InputTextManager::completionRequested, 0146 this, 0147 [this](const QString &roomId, const QString &pattern, const QString &exceptions, InputTextManager::CompletionForType type) { 0148 inputAutocomplete(roomId, pattern, exceptions, type, false); 0149 }); 0150 0151 mInputThreadMessageTextManager->setObjectName(QStringLiteral("mInputThreadMessageTextManager")); 0152 connect(mInputThreadMessageTextManager, 0153 &InputTextManager::completionRequested, 0154 this, 0155 [this](const QString &roomId, const QString &pattern, const QString &exceptions, InputTextManager::CompletionForType type) { 0156 inputAutocomplete(roomId, pattern, exceptions, type, true); 0157 }); 0158 0159 initializeAuthenticationPlugins(); 0160 0161 mRocketChatBackend = new RocketChatBackend(this, this); 0162 0163 // Load list of unicode emoticon 0164 TextEmoticonsCore::UnicodeEmoticonManager::self(); 0165 0166 // After loadSettings 0167 mEmojiManager = new EmojiManager(this, this); 0168 mEmojiManager->setServerUrl(mSettings->serverUrl()); 0169 connect(mEmojiManager, &EmojiManager::customEmojiChanged, this, &RocketChatAccount::updateCustomEmojiList); 0170 0171 mEmoticonModel = new EmoticonModel(this, this); 0172 mEmoticonModel->setUnicodeEmoticons(mEmojiManager->unicodeEmojiList()); 0173 mInputTextManager->setEmoticonModel(mEmoticonModel); 0174 mInputThreadMessageTextManager->setEmoticonModel(mEmoticonModel); 0175 0176 mUserCompleterFilterModelProxy = new UserCompleterFilterProxyModel(this); 0177 mUserCompleterFilterModelProxy->setSourceModel(mUserCompleterModel); 0178 0179 mSearchMessageModel = new CommonMessagesModel(this, this); 0180 mSearchMessageFilterProxyModel = new CommonMessageFilterProxyModel(mSearchMessageModel, this); 0181 0182 mFilesModelForRoom = new FilesForRoomModel(this, this); 0183 mFilesModelForRoom->setObjectName(QStringLiteral("filesmodelforrooms")); 0184 mFilesForRoomFilterProxyModel = new FilesForRoomFilterProxyModel(mFilesModelForRoom, this); 0185 mFilesForRoomFilterProxyModel->setObjectName(QStringLiteral("filesforroomfiltermodelproxy")); 0186 0187 mDiscussionsModel->setObjectName(QStringLiteral("discussionsmodel")); 0188 mDiscussionsFilterProxyModel = new DiscussionsFilterProxyModel(mDiscussionsModel, this); 0189 mDiscussionsFilterProxyModel->setObjectName(QStringLiteral("discussionsfilterproxymodel")); 0190 0191 mThreadMessageModel = new ThreadMessageModel(this, this); 0192 mThreadMessageModel->setObjectName(QStringLiteral("threadmessagemodel")); 0193 0194 mListMessageModel = new ListMessagesModel(QString(), this, nullptr, this); 0195 mListMessageModel->setObjectName(QStringLiteral("listmessagemodel")); 0196 0197 mListMessagesFilterProxyModel = new ListMessagesFilterProxyModel(mListMessageModel, this); 0198 mListMessagesFilterProxyModel->setObjectName(QStringLiteral("listmessagesfiltermodelproxy")); 0199 0200 mAutoTranslateLanguagesModel->setObjectName(QStringLiteral("autotranslatelanguagesmodel")); 0201 0202 connect(mRoomModel, &RoomModel::needToUpdateNotification, this, &RocketChatAccount::slotNeedToUpdateNotification); 0203 connect(mRoomModel, &RoomModel::roomNeedAttention, this, &RocketChatAccount::slotRoomNeedAttention); 0204 connect(mRoomModel, &RoomModel::roomRemoved, this, &RocketChatAccount::roomRemoved); 0205 0206 mMessageQueue = new MessageQueue(this, this); 0207 mTypingNotification = new TypingNotification(this); 0208 mCache = new RocketChatCache(this, this); 0209 0210 connect(mDownloadAppsLanguagesManager, &DownloadAppsLanguagesManager::fileLanguagesParseSuccess, this, &RocketChatAccount::slotFileLanguagedParsed); 0211 connect(mDownloadAppsLanguagesManager, &DownloadAppsLanguagesManager::fileLanguagesParseFailed, this, &RocketChatAccount::slotFileLanguagedParsed); 0212 0213 connect(mCache, &RocketChatCache::fileDownloaded, this, &RocketChatAccount::fileDownloaded); 0214 connect(mTypingNotification, &TypingNotification::informTypingStatus, this, &RocketChatAccount::slotInformTypingStatus); 0215 connect(this, &RocketChatAccount::customUserStatusChanged, this, &RocketChatAccount::slotUpdateCustomUserStatus); 0216 QTimer::singleShot(0, this, &RocketChatAccount::clearModels); 0217 0218 #if HAVE_SOLID 0219 connect(Solid::Power::self(), &Solid::Power::resumeFromSuspend, this, &RocketChatAccount::slotReconnectToServer); 0220 #endif 0221 0222 #if HAVE_NETWORKMANAGER 0223 connect(NetworkManager::notifier(), &NetworkManager::Notifier::primaryConnectionChanged, this, [=](const QString &uni) { 0224 // If there is a new network connection, log out and back. The uni is "/" when the last primary connection 0225 // was closed. Do not log out to keep the messages visible. Login only if we were logged in at this point. 0226 if (uni != QLatin1String("/") && mDdp) { 0227 qCDebug(RUQOLA_RECONNECT_LOG) << "Reconnect and logout : " << accountName(); 0228 logOut(); 0229 slotReconnectToServer(); 0230 } 0231 }); 0232 #endif 0233 connect(mManageChannels, &ManageChannels::selectRoomByRoomIdRequested, this, &RocketChatAccount::selectRoomByRoomIdRequested); 0234 connect(mManageChannels, &ManageChannels::selectRoomByRoomNameRequested, this, &RocketChatAccount::selectRoomByRoomNameRequested); 0235 connect(mManageChannels, &ManageChannels::missingChannelPassword, this, &RocketChatAccount::missingChannelPassword); 0236 connect(mManageChannels, &ManageChannels::openArchivedRoom, this, &RocketChatAccount::openArchivedRoom); 0237 connect(&mRolesManager, &RolesManager::rolesChanged, this, &RocketChatAccount::rolesUpdated); 0238 connect(mCustomSoundManager, &CustomSoundsManager::customSoundRemoved, this, &RocketChatAccount::customSoundRemoved); 0239 connect(mCustomSoundManager, &CustomSoundsManager::customSoundAdded, this, &RocketChatAccount::customSoundAdded); 0240 connect(mCustomSoundManager, &CustomSoundsManager::customSoundUpdated, this, &RocketChatAccount::customSoundUpdated); 0241 connect(mAwayManager, &AwayManager::awayChanged, this, &RocketChatAccount::slotAwayStatusChanged); 0242 0243 mPreviewUrlCacheManager->setCachePath(ManagerDataPaths::self()->path(ManagerDataPaths::PreviewUrl, accountName())); 0244 } 0245 0246 RocketChatAccount::~RocketChatAccount() 0247 { 0248 delete mCache; 0249 mCache = nullptr; 0250 0251 delete mRuqolaServerConfig; 0252 delete mRuqolaLogger; 0253 delete mAccountRoomSettings; 0254 } 0255 0256 void RocketChatAccount::reconnectToServer() 0257 { 0258 slotReconnectToServer(); 0259 } 0260 0261 Room::TeamRoomInfo RocketChatAccount::roomFromTeamId(const QString &teamId) const 0262 { 0263 return mRoomModel->roomFromTeamId(teamId); 0264 } 0265 0266 void RocketChatAccount::removeSettings() 0267 { 0268 mSettings->removeSettings(); 0269 } 0270 0271 void RocketChatAccount::loadSettings(const QString &accountFileName) 0272 { 0273 delete mSettings; 0274 mSettings = new RocketChatAccountSettings(accountFileName, this); 0275 if (mSettings->isValid()) { 0276 connect(mSettings, &RocketChatAccountSettings::serverURLChanged, this, &RocketChatAccount::serverUrlChanged); 0277 connect(mSettings, &RocketChatAccountSettings::userIdChanged, this, &RocketChatAccount::userIdChanged); 0278 connect(mSettings, &RocketChatAccountSettings::userNameChanged, this, &RocketChatAccount::userNameChanged); 0279 connect(mSettings, &RocketChatAccountSettings::passwordChanged, this, &RocketChatAccount::passwordChanged); 0280 } 0281 } 0282 0283 void RocketChatAccount::slotRoomNeedAttention() 0284 { 0285 qCDebug(RUQOLA_NOTIFICATION_LOG) << " emit alert" 0286 << " account name: " << accountName(); 0287 Q_EMIT roomNeedAttention(); 0288 } 0289 0290 void RocketChatAccount::setOwnUserPreferences(const OwnUserPreferences &ownUserPreferences) 0291 { 0292 mOwnUser.setOwnUserPreferences(ownUserPreferences); 0293 } 0294 0295 OwnUser RocketChatAccount::ownUser() const 0296 { 0297 return mOwnUser; 0298 } 0299 0300 void RocketChatAccount::cleanChannelHistory(const RocketChatRestApi::RoomsCleanHistoryJob::CleanHistoryInfo &info) 0301 { 0302 restApi()->cleanChannelHistory(info); 0303 } 0304 0305 void RocketChatAccount::slotNeedToUpdateNotification() 0306 { 0307 bool hasAlert = false; 0308 int nbUnread = 0; 0309 mRoomModel->getUnreadAlertFromAccount(hasAlert, nbUnread); 0310 Q_EMIT updateNotification(hasAlert, nbUnread, accountName()); 0311 } 0312 0313 void RocketChatAccount::clearModels() 0314 { 0315 // Clear rooms data and refill it with data in the cache, if there is 0316 mRoomModel->reset(); 0317 0318 mMessageQueue->loadCache(); 0319 // Try to send queue message 0320 mMessageQueue->processQueue(); 0321 } 0322 0323 UserCompleterModel *RocketChatAccount::userCompleterModel() const 0324 { 0325 return mUserCompleterModel; 0326 } 0327 0328 UserCompleterFilterProxyModel *RocketChatAccount::userCompleterFilterProxyModel() const 0329 { 0330 return mUserCompleterFilterModelProxy; 0331 } 0332 0333 EmojiManager *RocketChatAccount::emojiManager() const 0334 { 0335 return mEmojiManager; 0336 } 0337 0338 QString RocketChatAccount::userStatusStr(const QString &name) 0339 { 0340 return mUserModel->userStatusStr(name); 0341 } 0342 0343 QString RocketChatAccount::userStatusIconFileName(const QString &name) 0344 { 0345 return mUserModel->userStatusIconFileName(name); 0346 } 0347 0348 bool RocketChatAccount::userIsOffline(const QString &name) 0349 { 0350 return mUserModel->userIsOffline(name); 0351 } 0352 0353 StatusModel *RocketChatAccount::statusModel() const 0354 { 0355 return mStatusModel; 0356 } 0357 0358 RuqolaServerConfig *RocketChatAccount::ruqolaServerConfig() const 0359 { 0360 return mRuqolaServerConfig; 0361 } 0362 0363 RuqolaLogger *RocketChatAccount::ruqolaLogger() const 0364 { 0365 return mRuqolaLogger; 0366 } 0367 0368 UsersForRoomModel *RocketChatAccount::usersModelForRoom(const QString &roomId) const 0369 { 0370 return mRoomModel->usersModelForRoom(roomId); 0371 } 0372 0373 FilesForRoomFilterProxyModel *RocketChatAccount::filesForRoomFilterProxyModel() const 0374 { 0375 return mFilesForRoomFilterProxyModel; 0376 } 0377 0378 RocketChatBackend *RocketChatAccount::rocketChatBackend() const 0379 { 0380 return mRocketChatBackend; 0381 } 0382 0383 MessageQueue *RocketChatAccount::messageQueue() const 0384 { 0385 return mMessageQueue; 0386 } 0387 0388 RocketChatAccountSettings *RocketChatAccount::settings() const 0389 { 0390 return mSettings; 0391 } 0392 0393 void RocketChatAccount::slotInformTypingStatus(const QString &room, bool typing) 0394 { 0395 qCDebug(RUQOLA_TYPING_NOTIFICATION_LOG) << " slotInformTypingStatus room " << room << " typing " << typing; 0396 ddp()->informTypingStatus(room, typing, mSettings->userName()); 0397 } 0398 0399 RoomModel *RocketChatAccount::roomModel() const 0400 { 0401 return mRoomModel; 0402 } 0403 0404 UsersModel *RocketChatAccount::usersModel() const 0405 { 0406 return mUserModel; 0407 } 0408 0409 Room *RocketChatAccount::room(const QString &roomId) 0410 { 0411 return mRoomModel->findRoom(roomId); 0412 } 0413 0414 DiscussionsFilterProxyModel *RocketChatAccount::discussionsFilterProxyModel() const 0415 { 0416 return mDiscussionsFilterProxyModel; 0417 } 0418 0419 MessagesModel *RocketChatAccount::messageModelForRoom(const QString &roomID) 0420 { 0421 return mRoomModel->messageModel(roomID); 0422 } 0423 0424 void RocketChatAccount::changeShowOriginalMessage(const QString &roomId, const QString &messageId, bool showOriginal) 0425 { 0426 MessagesModel *model = mRoomModel->messageModel(roomId); 0427 if (model) { 0428 model->changeShowOriginalMessage(messageId, showOriginal); 0429 } else { 0430 qCWarning(RUQOLA_LOG) << "impossible to find room: " << roomId; 0431 } 0432 } 0433 0434 QString RocketChatAccount::getUserCurrentMessage(const QString &roomId) 0435 { 0436 return mRoomModel->inputMessage(roomId); 0437 } 0438 0439 void RocketChatAccount::setUserCurrentMessage(const QString &message, const QString &roomId) 0440 { 0441 mRoomModel->setInputMessage(roomId, message); 0442 } 0443 0444 void RocketChatAccount::textEditing(const QString &roomId, bool clearNotification) 0445 { 0446 mTypingNotification->textNotificationChanged(roomId, clearNotification); 0447 } 0448 0449 void RocketChatAccount::reactOnMessage(const QString &messageId, const QString &emoji, bool shouldReact) 0450 { 0451 if (emoji.startsWith(QLatin1Char(':')) && emoji.endsWith(QLatin1Char(':'))) { 0452 restApi()->reactOnMessage(messageId, emoji, shouldReact); 0453 } else { 0454 restApi()->reactOnMessage(messageId, mEmojiManager->normalizedReactionEmoji(emoji), shouldReact); 0455 } 0456 } 0457 0458 void RocketChatAccount::sendMessage(const QString &roomID, const QString &message) 0459 { 0460 restApi()->postMessage(roomID, message); 0461 markRoomAsRead(roomID); 0462 } 0463 0464 void RocketChatAccount::updateMessage(const QString &roomID, const QString &messageId, const QString &message) 0465 { 0466 restApi()->updateMessage(roomID, messageId, message); 0467 } 0468 0469 void RocketChatAccount::replyOnThread(const QString &roomID, const QString &threadMessageId, const QString &message) 0470 { 0471 restApi()->sendMessage(roomID, message, QString(), threadMessageId); 0472 } 0473 0474 void RocketChatAccount::deleteFileMessage(const QString &roomId, const QString &fileId, Room::RoomType channelType) 0475 { 0476 ddp()->deleteFileMessage(roomId, fileId, channelType); 0477 } 0478 0479 QString RocketChatAccount::avatarUrl(const Utils::AvatarInfo &info) 0480 { 0481 return mCache->avatarUrl(info); 0482 } 0483 0484 void RocketChatAccount::insertAvatarUrl(const QString &userId, const QUrl &url) 0485 { 0486 mCache->insertAvatarUrl(userId, url); 0487 } 0488 0489 RocketChatRestApi::Connection *RocketChatAccount::restApi() 0490 { 0491 if (!mRestApi) { 0492 mRestApi = new RocketChatRestApi::Connection(this); 0493 connect(mRestApi, &RocketChatRestApi::Connection::channelMembersDone, this, &RocketChatAccount::parseUsersForRooms); 0494 connect(mRestApi, &RocketChatRestApi::Connection::channelFilesDone, this, &RocketChatAccount::slotChannelFilesDone); 0495 connect(mRestApi, &RocketChatRestApi::Connection::channelRolesDone, this, &RocketChatAccount::slotChannelGroupRolesDone); 0496 connect(mRestApi, &RocketChatRestApi::Connection::groupRolesDone, this, &RocketChatAccount::slotChannelGroupRolesDone); 0497 connect(mRestApi, &RocketChatRestApi::Connection::searchMessageDone, this, &RocketChatAccount::slotSearchMessages); 0498 connect(mRestApi, &RocketChatRestApi::Connection::failed, this, &RocketChatAccount::slotJobFailed); 0499 connect(mRestApi, &RocketChatRestApi::Connection::getThreadMessagesDone, this, &RocketChatAccount::slotGetThreadMessagesDone); 0500 connect(mRestApi, &RocketChatRestApi::Connection::getDiscussionsDone, this, &RocketChatAccount::slotGetDiscussionsListDone); 0501 connect(mRestApi, &RocketChatRestApi::Connection::markAsReadDone, this, &RocketChatAccount::slotMarkAsReadDone); 0502 connect(mRestApi, &RocketChatRestApi::Connection::postMessageDone, this, &RocketChatAccount::slotPostMessageDone); 0503 connect(mRestApi, &RocketChatRestApi::Connection::updateMessageFailed, this, &RocketChatAccount::updateMessageFailed); 0504 0505 connect(mRestApi, &RocketChatRestApi::Connection::getThreadsDone, this, [this](const QJsonObject &obj, const QString &roomId, bool onlyUnread) { 0506 slotGetListMessagesDone(obj, 0507 roomId, 0508 onlyUnread ? ListMessagesModel::ListMessageType::UnreadThreadsMessages 0509 : ListMessagesModel::ListMessageType::ThreadsMessages); 0510 }); 0511 connect(mRestApi, &RocketChatRestApi::Connection::getMentionedMessagesDone, this, [this](const QJsonObject &obj, const QString &roomId) { 0512 slotGetListMessagesDone(obj, roomId, ListMessagesModel::ListMessageType::MentionsMessages); 0513 }); 0514 connect(mRestApi, &RocketChatRestApi::Connection::getPinnedMessagesDone, this, [this](const QJsonObject &obj, const QString &roomId) { 0515 slotGetListMessagesDone(obj, roomId, ListMessagesModel::ListMessageType::PinnedMessages); 0516 }); 0517 connect(mRestApi, &RocketChatRestApi::Connection::getStarredMessagesDone, this, [this](const QJsonObject &obj, const QString &roomId) { 0518 slotGetListMessagesDone(obj, roomId, ListMessagesModel::ListMessageType::StarredMessages); 0519 }); 0520 0521 connect(mRestApi, &RocketChatRestApi::Connection::usersPresenceDone, this, &RocketChatAccount::slotUsersPresenceDone); 0522 connect(mRestApi, &RocketChatRestApi::Connection::usersAutocompleteDone, this, &RocketChatAccount::slotUserAutoCompleterDone); 0523 connect(mRestApi, &RocketChatRestApi::Connection::registerUserDone, this, &RocketChatAccount::slotRegisterUserDone); 0524 connect(mRestApi, &RocketChatRestApi::Connection::channelGetCountersDone, this, &RocketChatAccount::slotChannelGetCountersDone); 0525 connect(mRestApi, &RocketChatRestApi::Connection::customUserStatusDone, this, &RocketChatAccount::slotCustomUserStatusDone); 0526 connect(mRestApi, &RocketChatRestApi::Connection::permissionListAllDone, this, &RocketChatAccount::slotPermissionListAllDone); 0527 connect(mRestApi, &RocketChatRestApi::Connection::usersSetPreferencesDone, this, &RocketChatAccount::slotUsersSetPreferencesDone); 0528 connect(mRestApi, &RocketChatRestApi::Connection::networkSessionFailedError, this, [this]() { 0529 qCDebug(RUQOLA_RECONNECT_LOG) << "networkSessionFailedError Reconnect and logout : " << accountName(); 0530 logOut(); 0531 slotReconnectToServer(); 0532 }); 0533 0534 mRestApi->setServerUrl(mSettings->serverUrl()); 0535 mRestApi->setRestApiLogger(mRuqolaLogger); 0536 mCache->setRestApiConnection(mRestApi); 0537 } 0538 return mRestApi; 0539 } 0540 0541 void RocketChatAccount::slotJobFailed(const QString &str) 0542 { 0543 Q_EMIT jobFailed(str, accountName()); 0544 } 0545 0546 const BannerInfos &RocketChatAccount::bannerInfos() const 0547 { 0548 return mBannerInfos; 0549 } 0550 0551 UploadFileManager *RocketChatAccount::uploadFileManager() const 0552 { 0553 return mUploadFileManager; 0554 } 0555 0556 int RocketChatAccount::messageMaximumAllowedSize() const 0557 { 0558 return mRuqolaServerConfig->messageMaximumAllowedSize(); 0559 } 0560 0561 bool RocketChatAccount::previewEmbed() const 0562 { 0563 return mRuqolaServerConfig->previewEmbed(); 0564 } 0565 0566 bool RocketChatAccount::messageAllowConvertLongMessagesToAttachment() const 0567 { 0568 return mRuqolaServerConfig->messageAllowConvertLongMessagesToAttachment(); 0569 } 0570 0571 bool RocketChatAccount::useRealName() const 0572 { 0573 return mRuqolaServerConfig->useRealName(); 0574 } 0575 0576 SwitchChannelHistoryModel *RocketChatAccount::switchChannelHistoryModel() const 0577 { 0578 return mSwitchChannelHistoryModel; 0579 } 0580 0581 const QStringList &RocketChatAccount::searchListCompletion() const 0582 { 0583 return mSearchListCompletion; 0584 } 0585 0586 void RocketChatAccount::setSearchListCompletion(const QStringList &newSearchListCompletion) 0587 { 0588 mSearchListCompletion = newSearchListCompletion; 0589 } 0590 0591 void RocketChatAccount::leaveRoom(const QString &identifier, Room::RoomType channelType) 0592 { 0593 switch (channelType) { 0594 case Room::RoomType::Private: 0595 restApi()->leaveGroups(identifier); 0596 break; 0597 case Room::RoomType::Channel: 0598 restApi()->leaveChannel(identifier); 0599 break; 0600 case Room::RoomType::Direct: 0601 case Room::RoomType::Unknown: 0602 qCWarning(RUQOLA_LOG) << " unsupported leave room for type " << channelType; 0603 break; 0604 } 0605 } 0606 0607 void RocketChatAccount::hideRoom(const QString &roomId, Room::RoomType channelType) 0608 { 0609 restApi()->closeChannel(roomId, Room::roomFromRoomType(channelType)); 0610 } 0611 0612 DDPClient *RocketChatAccount::ddp() 0613 { 0614 if (!mDdp) { 0615 mDdp = new DDPClient(this, this); 0616 connect(mDdp->authenticationManager(), &DDPAuthenticationManager::loginStatusChanged, this, &RocketChatAccount::slotLoginStatusChanged); 0617 connect(mDdp, &DDPClient::connectedChanged, this, &RocketChatAccount::connectedChanged); 0618 connect(mDdp, &DDPClient::changed, this, &RocketChatAccount::changed); 0619 connect(mDdp, &DDPClient::added, this, &RocketChatAccount::added); 0620 connect(mDdp, &DDPClient::removed, this, &RocketChatAccount::removed); 0621 connect(mDdp, &DDPClient::socketError, this, &RocketChatAccount::socketError); 0622 connect(mDdp, &DDPClient::disconnectedByServer, this, &RocketChatAccount::slotReconnectToServer); 0623 connect(mDdp, &DDPClient::wsClosedSocketError, this, &RocketChatAccount::wsClosedSocketError); 0624 0625 if (mSettings) { 0626 mDdp->setServerUrl(mSettings->serverUrl()); 0627 } 0628 mDdp->start(); 0629 } 0630 return mDdp; 0631 } 0632 0633 bool RocketChatAccount::editingMode() const 0634 { 0635 return mEditingMode; 0636 } 0637 0638 DDPAuthenticationManager::LoginStatus RocketChatAccount::loginStatus() 0639 { 0640 // TODO: DDP API should exist as soon as the hostname is known 0641 if (mDdp) { 0642 return ddp()->authenticationManager()->loginStatus(); 0643 } else { 0644 return DDPAuthenticationManager::LoggedOut; 0645 } 0646 } 0647 0648 void RocketChatAccount::tryLogin() 0649 { 0650 qCDebug(RUQOLA_LOG) << "Attempting login" << mSettings->userName() << "on" << mSettings->serverUrl(); 0651 0652 // ddp() creates a new DDPClient object if it doesn't exist. 0653 ddp()->enqueueLogin(); 0654 0655 // In the meantime, load cache... 0656 mRoomModel->reset(); 0657 } 0658 0659 void RocketChatAccount::logOut() 0660 { 0661 mSettings->logout(); 0662 mRoomModel->clear(); 0663 if (mDdp) { 0664 mDdp->authenticationManager()->logout(); 0665 delete mDdp; 0666 mDdp = nullptr; 0667 } 0668 delete mRestApi; 0669 mRestApi = nullptr; 0670 } 0671 0672 void RocketChatAccount::clearAllUnreadMessages() 0673 { 0674 for (int roomIdx = 0, nRooms = mRoomModel->rowCount(); roomIdx < nRooms; ++roomIdx) { 0675 const auto roomModelIndex = mRoomModel->index(roomIdx); 0676 const auto roomId = roomModelIndex.data(RoomModel::RoomId).toString(); 0677 const bool roomHasAlert = roomModelIndex.data(RoomModel::RoomAlert).toBool(); 0678 if (roomHasAlert) { 0679 markRoomAsRead(roomId); 0680 } 0681 } 0682 } 0683 0684 void RocketChatAccount::markRoomAsRead(const QString &roomId) 0685 { 0686 mMarkUnreadThreadsAsReadOnNextReply = true; 0687 restApi()->markRoomAsRead(roomId); 0688 if (threadsEnabled()) { 0689 getListMessages(roomId, ListMessagesModel::UnreadThreadsMessages); 0690 } 0691 } 0692 0693 void RocketChatAccount::changeFavorite(const QString &roomId, bool checked) 0694 { 0695 restApi()->markAsFavorite(roomId, checked); 0696 } 0697 0698 void RocketChatAccount::openPrivateGroup(const QString &roomId, ChannelTypeInfo typeInfo) 0699 { 0700 mManageChannels->openPrivateGroup(roomId, typeInfo); 0701 } 0702 0703 void RocketChatAccount::openChannel(const QString &roomId, ChannelTypeInfo typeInfo) 0704 { 0705 mManageChannels->openChannel(roomId, typeInfo); 0706 } 0707 0708 void RocketChatAccount::openArchivedRoom(const RocketChatRestApi::ChannelGroupBaseJob::ChannelGroupInfo &channelInfo) 0709 { 0710 // TODO 0711 } 0712 0713 void RocketChatAccount::joinJitsiConfCall(const QString &roomId) 0714 { 0715 qCDebug(RUQOLA_LOG) << " void RocketChatAccount::joinJitsiConfCall(const QString &roomId)" << roomId; 0716 // const QString hash = QString::fromLatin1(QCryptographicHash::hash((mRuqolaServerConfig->uniqueId() + roomId).toUtf8(), QCryptographicHash::Md5).toHex()); 0717 const QString hash = mRuqolaServerConfig->uniqueId() + roomId; 0718 #if defined(Q_OS_IOS) 0719 const QString scheme = QStringLiteral("org.jitsi.meet://"); 0720 #else 0721 const QString scheme = QStringLiteral("https://"); 0722 #endif 0723 const QString url = scheme + mRuqolaServerConfig->jitsiMeetUrl() + QLatin1Char('/') + mRuqolaServerConfig->jitsiMeetPrefix() + hash; 0724 const QUrl clickedUrl = QUrl::fromUserInput(url); 0725 QDesktopServices::openUrl(clickedUrl); 0726 } 0727 0728 void RocketChatAccount::eraseRoom(const QString &roomId, Room::RoomType channelType) 0729 { 0730 switch (channelType) { 0731 case Room::RoomType::Private: 0732 restApi()->groupDelete(roomId); 0733 break; 0734 case Room::RoomType::Channel: 0735 restApi()->channelDelete(roomId); 0736 break; 0737 case Room::RoomType::Direct: 0738 case Room::RoomType::Unknown: 0739 qCWarning(RUQOLA_LOG) << " unsupported delete for type " << channelType; 0740 break; 0741 } 0742 } 0743 0744 void RocketChatAccount::openDirectChannel(const QString &roomId) 0745 { 0746 if (hasPermission(QStringLiteral("create-d"))) { 0747 auto job = new RocketChatRestApi::OpenDmJob(this); 0748 job->setDirectUserId(roomId); 0749 restApi()->initializeRestApiJob(job); 0750 // TODO ???? 0751 // connect(job, &RocketChatRestApi::OpenDmJob::openDmDone, this, &RolesManager::parseRoles); 0752 if (!job->start()) { 0753 qCWarning(RUQOLA_LOG) << "Impossible to start OpenDmJob job"; 0754 } 0755 qDebug() << "Open direct conversation channel with" << roomId; 0756 } 0757 } 0758 0759 void RocketChatAccount::createNewChannel(const RocketChatRestApi::CreateChannelTeamInfo &info) 0760 { 0761 if (!info.name.trimmed().isEmpty()) { 0762 if (info.privateChannel) { 0763 restApi()->createGroups(info); 0764 } else { 0765 restApi()->createChannels(info); 0766 } 0767 } else { 0768 qCDebug(RUQOLA_LOG) << "Channel name can't be empty"; 0769 } 0770 } 0771 0772 void RocketChatAccount::joinDiscussion(const QString &roomId, const QString &joinCode) 0773 { 0774 ddp()->joinRoom(roomId, joinCode); 0775 } 0776 0777 void RocketChatAccount::joinRoom(const QString &roomId, const QString &joinCode) 0778 { 0779 RocketChatRestApi::ChannelGroupBaseJob::ChannelGroupInfo info; 0780 info.channelGroupInfoType = RocketChatRestApi::ChannelGroupBaseJob::ChannelGroupInfoType::Identifier; 0781 info.identifier = roomId; 0782 mManageChannels->channelJoin(info, joinCode); 0783 } 0784 0785 void RocketChatAccount::listEmojiCustom() 0786 { 0787 auto job = new RocketChatRestApi::LoadEmojiCustomJob(this); 0788 restApi()->initializeRestApiJob(job); 0789 connect(job, &RocketChatRestApi::LoadEmojiCustomJob::loadEmojiCustomDone, this, &RocketChatAccount::loadEmoji); 0790 if (!job->start()) { 0791 qCWarning(RUQOLA_LOG) << "Impossible to start listEmojiCustom job"; 0792 } 0793 } 0794 0795 void RocketChatAccount::setDefaultStatus(User::PresenceStatus status, const QString &messageStatus) 0796 { 0797 RocketChatRestApi::SetStatusJob::StatusType type = RocketChatRestApi::SetStatusJob::Unknown; 0798 switch (status) { 0799 case User::PresenceStatus::PresenceOnline: 0800 type = RocketChatRestApi::SetStatusJob::OnLine; 0801 break; 0802 case User::PresenceStatus::PresenceBusy: 0803 type = RocketChatRestApi::SetStatusJob::Busy; 0804 break; 0805 case User::PresenceStatus::PresenceAway: 0806 type = RocketChatRestApi::SetStatusJob::Away; 0807 break; 0808 case User::PresenceStatus::PresenceOffline: 0809 type = RocketChatRestApi::SetStatusJob::Offline; 0810 break; 0811 case User::PresenceStatus::Unknown: 0812 type = RocketChatRestApi::SetStatusJob::Unknown; 0813 break; 0814 } 0815 mPresenceStatus = status; 0816 // qDebug() << "RocketChatAccount::setDefaultStatus " << messageStatus; 0817 restApi()->setUserStatus(userId(), type, messageStatus); 0818 } 0819 0820 QList<TextEmoticonsCore::CustomEmoji> RocketChatAccount::customEmojies() const 0821 { 0822 QList<TextEmoticonsCore::CustomEmoji> mCustomEmojies; 0823 const auto customEmojiList = mEmojiManager->customEmojiList(); 0824 for (const auto &emoji : customEmojiList) { 0825 TextEmoticonsCore::CustomEmoji custom; 0826 custom.setIdentifier(emoji.emojiIdentifier()); 0827 custom.setIsAnimatedEmoji(emoji.isAnimatedImage()); 0828 mCustomEmojies.append(std::move(custom)); 0829 } 0830 return mCustomEmojies; 0831 } 0832 0833 void RocketChatAccount::loadEmoji(const QJsonObject &obj) 0834 { 0835 mEmojiManager->loadCustomEmoji(obj); 0836 updateCustomEmojiList(false); 0837 } 0838 0839 void RocketChatAccount::updateCustomEmojiList(bool fetchListCustom) 0840 { 0841 if (fetchListCustom) { 0842 listEmojiCustom(); 0843 } else { 0844 const auto customEmojiList = mEmojiManager->customEmojiList(); 0845 mEmoticonModel->setCustomEmojiList(customEmojiList); 0846 if (Ruqola::self()->customEmojiIconManager()->currentRocketChatAccount() == this) { 0847 TextEmoticonsCore::EmojiModelManager::self()->emojiModel()->setCustomEmojiList(customEmojies()); 0848 } 0849 } 0850 } 0851 0852 OtrManager *RocketChatAccount::otrManager() const 0853 { 0854 return mOtrManager; 0855 } 0856 0857 void RocketChatAccount::deleteMessage(const QString &messageId, const QString &roomId) 0858 { 0859 restApi()->deleteMessage(roomId, messageId); 0860 } 0861 0862 void RocketChatAccount::insertCompleterUsers() 0863 { 0864 userCompleterModel()->addUsers(rocketChatBackend()->users()); 0865 } 0866 0867 void RocketChatAccount::userAutocomplete(const QString &searchText, const QString &exception) 0868 { 0869 userCompleterModel()->clear(); 0870 if (!searchText.isEmpty()) { 0871 RocketChatRestApi::UsersAutocompleteJob::UsersAutocompleterInfo info; 0872 info.pattern = searchText; 0873 info.exception = exception; 0874 restApi()->usersAutocomplete(info); 0875 } 0876 } 0877 0878 void RocketChatAccount::membersInRoom(const QString &roomId, Room::RoomType channelType) 0879 { 0880 // We call it first for initialize all member in rooms. 0881 // We need to clear it. It can be initialize by "/rooms-changed" signal 0882 UsersForRoomModel *usersModelForRoom = roomModel()->usersModelForRoom(roomId); 0883 if (usersModelForRoom) { 0884 if (usersModelForRoom->total() != 0) { 0885 usersModelForRoom->clear(); 0886 } 0887 usersModelForRoom->setLoadMoreUsersInProgress(true); 0888 } 0889 restApi()->membersInRoom(roomId, Room::roomFromRoomType(channelType)); 0890 } 0891 0892 void RocketChatAccount::updateUserInRoom(const QJsonObject &roomData) 0893 { 0894 const QString roomId = roomData.value(QStringLiteral("_id")).toString(); 0895 UsersForRoomModel *usersModelForRoom = roomModel()->usersModelForRoom(roomId); 0896 if (usersModelForRoom) { 0897 const int numberOfUsers = roomData.value(QStringLiteral("usersCount")).toInt(); 0898 if (usersModelForRoom->total() != numberOfUsers) { 0899 if (!usersModelForRoom->loadMoreUsersInProgress()) { 0900 usersModelForRoom->clear(); 0901 usersModelForRoom->setLoadMoreUsersInProgress(true); 0902 const QString channelType = roomData.value(QStringLiteral("t")).toString(); 0903 restApi()->membersInRoom(roomId, channelType, 0, qMin(50, usersModelForRoom->offset())); 0904 } 0905 } 0906 } 0907 } 0908 0909 void RocketChatAccount::parseUsersForRooms(const QJsonObject &obj, const RocketChatRestApi::ChannelGroupBaseJob::ChannelGroupInfo &channelInfo) 0910 { 0911 // FIXME channelInfo 0912 const QString channelInfoIdentifier = channelInfo.identifier; 0913 UsersForRoomModel *usersModelForRoom = roomModel()->usersModelForRoom(channelInfoIdentifier); 0914 if (usersModelForRoom) { 0915 usersModelForRoom->parseUsersForRooms(obj, mUserModel, true); 0916 usersModelForRoom->setLoadMoreUsersInProgress(false); 0917 } else { 0918 qCWarning(RUQOLA_LOG) << " Impossible to find room " << channelInfoIdentifier; 0919 } 0920 } 0921 0922 void RocketChatAccount::roomFiles(const QString &roomId, Room::RoomType channelType) 0923 { 0924 mFilesModelForRoom->initialize(); 0925 restApi()->filesInRoom(roomId, Room::roomFromRoomType(channelType)); 0926 } 0927 0928 MessagesModel *RocketChatAccount::threadMessageModel() const 0929 { 0930 return mThreadMessageModel; 0931 } 0932 0933 DiscussionsModel *RocketChatAccount::discussionsModel() const 0934 { 0935 return mDiscussionsModel; 0936 } 0937 0938 FilesForRoomModel *RocketChatAccount::filesModelForRoom() const 0939 { 0940 return mFilesModelForRoom; 0941 } 0942 0943 EmoticonModel *RocketChatAccount::emoticonModel() const 0944 { 0945 return mEmoticonModel; 0946 } 0947 0948 CommandsModel *RocketChatAccount::commandsModel() const 0949 { 0950 return mCommandsModel; 0951 } 0952 0953 ReceiveTypingNotificationManager *RocketChatAccount::receiveTypingNotificationManager() const 0954 { 0955 return mReceiveTypingNotificationManager; 0956 } 0957 0958 void RocketChatAccount::slotChannelGroupRolesDone(const QJsonObject &obj, const RocketChatRestApi::ChannelGroupBaseJob::ChannelGroupInfo &channelInfo) 0959 { 0960 Room *room = mRoomModel->findRoom(channelInfo.identifier); 0961 if (room) { 0962 Roles r; 0963 r.parseRole(obj); 0964 room->setRolesForRooms(r); 0965 // qDebug() << " r " << r << " room " << room->name() << " obj" << obj; 0966 } else { 0967 qCWarning(RUQOLA_LOG) << " Impossible to find room " << channelInfo.identifier; 0968 } 0969 } 0970 0971 void RocketChatAccount::slotGetThreadMessagesDone(const QJsonObject &obj, const QString &threadMessageId) 0972 { 0973 if (mThreadMessageModel->threadMessageId() != threadMessageId) { 0974 mThreadMessageModel->setThreadMessageId(threadMessageId); 0975 mThreadMessageModel->parseThreadMessages(obj); 0976 } else { 0977 mThreadMessageModel->loadMoreThreadMessages(obj); 0978 } 0979 } 0980 0981 void RocketChatAccount::slotGetDiscussionsListDone(const QJsonObject &obj, const QString &roomId) 0982 { 0983 if (mDiscussionsModel->roomId() != roomId) { 0984 mDiscussionsModel->parseDiscussions(obj, roomId); 0985 } else { 0986 mDiscussionsModel->addMoreDiscussions(obj); 0987 } 0988 mDiscussionsModel->setLoadMoreDiscussionsInProgress(false); 0989 } 0990 0991 void RocketChatAccount::slotGetListMessagesDone(const QJsonObject &obj, const QString &roomId, ListMessagesModel::ListMessageType type) 0992 { 0993 if (mMarkUnreadThreadsAsReadOnNextReply && type == ListMessagesModel::UnreadThreadsMessages) { 0994 qCDebug(RUQOLA_THREAD_MESSAGE_LOG) << "Obj" << obj << "roomId:" << roomId; 0995 mMarkUnreadThreadsAsReadOnNextReply = false; 0996 0997 ListMessages messages; 0998 messages.parseMessages(obj, QStringLiteral("threads")); 0999 const auto listMessages = messages.listMessages(); 1000 for (const auto &msg : listMessages) { 1001 QJsonObject params; 1002 params.insert(QStringLiteral("tmid"), msg.messageId()); 1003 mDdp->method(QStringLiteral("getThreadMessages"), QJsonDocument(params), [](const QJsonObject &reply, RocketChatAccount *account) { 1004 // don't trigger warning about unhandled replies 1005 Q_UNUSED(reply) 1006 Q_UNUSED(account) 1007 }); 1008 } 1009 return; 1010 } 1011 1012 if (mListMessageModel->roomId() != roomId || mListMessageModel->listMessageType() != type) { 1013 mListMessageModel->setRoomId(roomId); 1014 mListMessageModel->setListMessageType(type); 1015 mListMessageModel->parseListMessages(obj); 1016 } else { 1017 mListMessageModel->loadMoreListMessages(obj); 1018 } 1019 mListMessageModel->setLoadMoreListMessagesInProgress(false); 1020 } 1021 1022 void RocketChatAccount::slotUserAutoCompleterDone(const QJsonObject &obj) 1023 { 1024 const QVector<User> users = User::parseUsersList(obj, roleInfo()); 1025 mUserCompleterModel->addUsers(users); 1026 } 1027 1028 User::PresenceStatus RocketChatAccount::presenceStatus() const 1029 { 1030 return mPresenceStatus; 1031 } 1032 1033 AccountRoomSettings *RocketChatAccount::accountRoomSettings() const 1034 { 1035 return mAccountRoomSettings; 1036 } 1037 1038 ListMessagesFilterProxyModel *RocketChatAccount::listMessagesFilterProxyModel() const 1039 { 1040 return mListMessagesFilterProxyModel; 1041 } 1042 1043 ListMessagesModel *RocketChatAccount::listMessageModel() const 1044 { 1045 return mListMessageModel; 1046 } 1047 1048 void RocketChatAccount::slotChannelFilesDone(const QJsonObject &obj, const RocketChatRestApi::ChannelGroupBaseJob::ChannelGroupInfo &channelInfo) 1049 { 1050 // TODO fixme channelinfo 1051 // qDebug() << " slotChannelFilesDone(const QJsonObject &obj, const QString &roomId)" << roomId << " obj " << obj; 1052 if (mFilesModelForRoom->roomId() != channelInfo.identifier) { 1053 mFilesModelForRoom->parseFileAttachments(obj, channelInfo.identifier); 1054 } else { 1055 mFilesModelForRoom->addMoreFileAttachments(obj); 1056 } 1057 mFilesModelForRoom->setLoadMoreFilesInProgress(false); 1058 } 1059 1060 void RocketChatAccount::loadMoreUsersInRoom(const QString &roomId, Room::RoomType channelType) 1061 { 1062 UsersForRoomModel *usersModelForRoom = roomModel()->usersModelForRoom(roomId); 1063 const int offset = usersModelForRoom->usersCount(); 1064 if (offset < usersModelForRoom->total()) { 1065 usersModelForRoom->setLoadMoreUsersInProgress(true); 1066 restApi()->membersInRoom(roomId, Room::roomFromRoomType(channelType), offset, qMin(50, usersModelForRoom->total() - offset)); 1067 } 1068 } 1069 1070 void RocketChatAccount::getMentionsMessages(const QString &roomId) 1071 { 1072 mListMessageModel->clear(); 1073 mListMessageModel->setRoomId(roomId); 1074 mListMessageModel->setLoadMoreListMessagesInProgress(true); 1075 restApi()->getMentionedMessages(roomId); 1076 } 1077 1078 void RocketChatAccount::getPinnedMessages(const QString &roomId) 1079 { 1080 mListMessageModel->clear(); 1081 mListMessageModel->setLoadMoreListMessagesInProgress(true); 1082 mListMessageModel->setRoomId(roomId); 1083 restApi()->getPinnedMessages(roomId); 1084 } 1085 1086 void RocketChatAccount::getStarredMessages(const QString &roomId) 1087 { 1088 mListMessageModel->clear(); 1089 mListMessageModel->setRoomId(roomId); 1090 mListMessageModel->setLoadMoreListMessagesInProgress(true); 1091 restApi()->getStarredMessages(roomId); 1092 } 1093 1094 void RocketChatAccount::loadMoreFileAttachments(const QString &roomId, Room::RoomType channelType) 1095 { 1096 if (!mFilesModelForRoom->loadMoreFilesInProgress()) { 1097 const int offset = mFilesModelForRoom->fileAttachments()->filesCount(); 1098 if (offset < mFilesModelForRoom->fileAttachments()->total()) { 1099 mFilesModelForRoom->setLoadMoreFilesInProgress(true); 1100 restApi()->filesInRoom(roomId, Room::roomFromRoomType(channelType), offset, qMin(50, mFilesModelForRoom->fileAttachments()->total() - offset)); 1101 } 1102 } 1103 } 1104 1105 void RocketChatAccount::loadMoreDiscussions(const QString &roomId) 1106 { 1107 if (!mDiscussionsModel->loadMoreDiscussionsInProgress()) { 1108 const int offset = mDiscussionsModel->discussions()->discussionsCount(); 1109 if (offset < mDiscussionsModel->discussions()->total()) { 1110 mDiscussionsModel->setLoadMoreDiscussionsInProgress(true); 1111 restApi()->getDiscussions(roomId, offset, qMin(50, mDiscussionsModel->discussions()->total() - offset)); 1112 } 1113 } 1114 } 1115 1116 void RocketChatAccount::updateThreadMessageList(const Message &m) 1117 { 1118 if (mThreadMessageModel->threadMessageId() == m.threadMessageId()) { 1119 mThreadMessageModel->addMessages({m}); 1120 } 1121 } 1122 1123 void RocketChatAccount::getListMessages(const QString &roomId, ListMessagesModel::ListMessageType type) 1124 { 1125 mListMessageModel->setListMessageType(type); 1126 mListMessageModel->setLoadMoreListMessagesInProgress(true); 1127 switch (type) { 1128 case ListMessagesModel::Unknown: 1129 qCWarning(RUQOLA_LOG) << " Error when using getListMessages"; 1130 break; 1131 case ListMessagesModel::StarredMessages: 1132 getStarredMessages(roomId); 1133 break; 1134 case ListMessagesModel::PinnedMessages: 1135 getPinnedMessages(roomId); 1136 break; 1137 case ListMessagesModel::MentionsMessages: 1138 getMentionsMessages(roomId); 1139 break; 1140 case ListMessagesModel::ThreadsMessages: 1141 threadsInRoom(roomId, false); 1142 break; 1143 case ListMessagesModel::UnreadThreadsMessages: 1144 threadsInRoom(roomId, true); 1145 break; 1146 } 1147 } 1148 1149 void RocketChatAccount::setNameChanged(const QJsonArray &array) 1150 { 1151 qCWarning(RUQOLA_LOG) << "Need to implement: Users:NameChanged :" << array << " account name " << accountName(); 1152 // QJsonArray([{"_id":"Z5TPBsWrmjAWCKGBC","name":"LifeLine","username":"LifeLine-GM"}]) 1153 for (int i = 0; i < array.count(); ++i) { 1154 const QJsonObject obj = array.at(i).toObject(); 1155 const QString id = obj[QLatin1String("_id")].toString(); 1156 const QString name = obj[QLatin1String("name")].toString(); 1157 const QString username = obj[QLatin1String("username")].toString(); 1158 // TODO 1159 } 1160 } 1161 1162 void RocketChatAccount::setOwnStatus(const User &user) 1163 { 1164 userStatusChanged(user); 1165 } 1166 1167 void RocketChatAccount::setUserStatusChanged(const QJsonArray &array) 1168 { 1169 // qDebug() << "Account Name : " << accountName() << " status changed: " << array << " array " << array.count() << " array" << array.toVariantList(); 1170 const auto list = array.toVariantList(); 1171 for (const auto &var : list) { 1172 const auto userListArguments = var.toJsonArray().toVariantList(); 1173 User user; 1174 user.parseUser(userListArguments); 1175 if (user.isValid()) { 1176 userStatusChanged(user); 1177 // qDebug() << " user status changed " << user; 1178 } 1179 } 1180 } 1181 1182 void RocketChatAccount::setShowRoomAvatar(bool checked) 1183 { 1184 RocketChatRestApi::UsersSetPreferencesJob::UsersSetPreferencesInfo info; 1185 info.userId = userId(); 1186 info.sidebarDisplayAvatar = RocketChatRestApi::UsersSetPreferencesJob::UsersSetPreferencesInfo::convertToState(checked); 1187 setUserPreferences(std::move(info)); 1188 } 1189 1190 void RocketChatAccount::setShowFavoriteRoom(bool checked) 1191 { 1192 RocketChatRestApi::UsersSetPreferencesJob::UsersSetPreferencesInfo info; 1193 info.userId = userId(); 1194 info.sidebarShowFavorites = RocketChatRestApi::UsersSetPreferencesJob::UsersSetPreferencesInfo::convertToState(checked); 1195 setUserPreferences(std::move(info)); 1196 } 1197 1198 void RocketChatAccount::loadMoreListMessages(const QString &roomId) 1199 { 1200 if (!mListMessageModel->loadMoreListMessagesInProgress()) { 1201 const int offset = mListMessageModel->rowCount(); 1202 if (offset < mListMessageModel->total()) { 1203 mListMessageModel->setLoadMoreListMessagesInProgress(true); 1204 switch (mListMessageModel->listMessageType()) { 1205 case ListMessagesModel::Unknown: 1206 qCWarning(RUQOLA_LOG) << " Error when using loadMoreListMessages"; 1207 break; 1208 case ListMessagesModel::StarredMessages: 1209 restApi()->getStarredMessages(roomId, offset, qMin(50, mListMessageModel->total() - offset)); 1210 break; 1211 case ListMessagesModel::PinnedMessages: 1212 restApi()->getPinnedMessages(roomId, offset, qMin(50, mListMessageModel->total() - offset)); 1213 break; 1214 case ListMessagesModel::MentionsMessages: 1215 restApi()->getMentionedMessages(roomId, offset, qMin(50, mListMessageModel->total() - offset)); 1216 break; 1217 case ListMessagesModel::ThreadsMessages: 1218 restApi()->getThreadsList(roomId, false, offset, qMin(50, mListMessageModel->total() - offset)); 1219 break; 1220 case ListMessagesModel::UnreadThreadsMessages: 1221 restApi()->getThreadsList(roomId, true, offset, qMin(50, mListMessageModel->total() - offset)); 1222 break; 1223 } 1224 } 1225 } 1226 } 1227 1228 void RocketChatAccount::loadThreadMessagesHistory(const QString &threadMessageId) 1229 { 1230 restApi()->getThreadMessages(threadMessageId); 1231 } 1232 1233 void RocketChatAccount::createJitsiConfCall(const QString &roomId) 1234 { 1235 // TODO use restapi 1236 ddp()->createJitsiConfCall(roomId); 1237 joinJitsiConfCall(roomId); 1238 } 1239 1240 void RocketChatAccount::addUserToRoom(const QString &userId, const QString &roomId, Room::RoomType channelType) 1241 { 1242 switch (channelType) { 1243 case Room::RoomType::Private: 1244 restApi()->addUserInGroup(roomId, userId); 1245 break; 1246 case Room::RoomType::Channel: 1247 restApi()->addUserInChannel(roomId, userId); 1248 break; 1249 case Room::RoomType::Direct: 1250 case Room::RoomType::Unknown: 1251 break; 1252 } 1253 } 1254 1255 void RocketChatAccount::clearSearchModel() 1256 { 1257 mSearchMessageModel->clearModel(); 1258 } 1259 1260 void RocketChatAccount::messageSearch(const QString &pattern, const QString &rid, bool userRegularExpression) 1261 { 1262 if (pattern.isEmpty()) { 1263 clearSearchModel(); 1264 } else { 1265 mSearchMessageModel->setLoadCommonMessagesInProgress(true); 1266 restApi()->searchMessages(rid, pattern, userRegularExpression); 1267 } 1268 } 1269 1270 InputTextManager *RocketChatAccount::inputTextManager() const 1271 { 1272 return mInputTextManager; 1273 } 1274 1275 InputTextManager *RocketChatAccount::inputThreadMessageTextManager() const 1276 { 1277 return mInputThreadMessageTextManager; 1278 } 1279 1280 void RocketChatAccount::slotSearchMessages(const QJsonObject &obj) 1281 { 1282 mSearchMessageModel->setLoadCommonMessagesInProgress(false); 1283 mSearchMessageModel->parse(obj); 1284 } 1285 1286 void RocketChatAccount::starMessage(const QString &messageId, bool starred) 1287 { 1288 restApi()->starMessage(messageId, starred); 1289 } 1290 1291 void RocketChatAccount::pinMessage(const QString &messageId, bool pinned) 1292 { 1293 restApi()->pinMessage(messageId, pinned); 1294 } 1295 1296 void RocketChatAccount::reportMessage(const QString &messageId, const QString &message) 1297 { 1298 restApi()->reportMessage(messageId, message); 1299 } 1300 1301 void RocketChatAccount::getThreadMessages(const QString &threadMessageId, const Message &message) 1302 { 1303 // mListMessageModel->clear(); 1304 mThreadMessageModel->setPreviewMessage(message); 1305 restApi()->getThreadMessages(threadMessageId); 1306 } 1307 1308 void RocketChatAccount::changeNotificationsSettings(const QString &roomId, 1309 RocketChatAccount::NotificationOptionsType notificationsType, 1310 const QVariant &newValue) 1311 { 1312 switch (notificationsType) { 1313 case DisableNotifications: 1314 restApi()->disableNotifications(roomId, newValue.toBool()); 1315 break; 1316 case HideUnreadStatus: 1317 restApi()->hideUnreadStatus(roomId, newValue.toBool()); 1318 break; 1319 case DesktopNotifications: 1320 restApi()->desktopNotifications(roomId, newValue.toString()); 1321 break; 1322 case EmailNotifications: 1323 restApi()->emailNotifications(roomId, newValue.toString()); 1324 break; 1325 case MobilePushNotifications: 1326 restApi()->mobilePushNotifications(roomId, newValue.toString()); 1327 break; 1328 case UnreadAlert: 1329 restApi()->unreadAlert(roomId, newValue.toString()); 1330 break; 1331 case MuteGroupMentions: 1332 restApi()->muteGroupMentions(roomId, newValue.toBool()); 1333 break; 1334 case DesktopDurationNotifications: 1335 restApi()->desktopDurationNotifications(roomId, newValue.toInt()); 1336 break; 1337 case DesktopSoundNotifications: 1338 restApi()->desktopSoundNotifications(roomId, newValue.toString()); 1339 break; 1340 case HideMentionStatus: 1341 restApi()->hideMentionStatus(roomId, newValue.toBool()); 1342 break; 1343 } 1344 } 1345 1346 void RocketChatAccount::parseCustomSounds(const QJsonArray &obj) 1347 { 1348 customSoundManager()->parseCustomSounds(obj); 1349 } 1350 1351 void RocketChatAccount::parsePublicSettings(const QJsonObject &obj, bool update) 1352 { 1353 mRuqolaServerConfig->parsePublicSettings(obj, update); 1354 parsePublicSettings(); 1355 mPreviewUrlCacheManager->setEmbedCacheExpirationDays(mRuqolaServerConfig->embedCacheExpirationDays()); 1356 } 1357 1358 void RocketChatAccount::parsePublicSettings() 1359 { 1360 if (!accountName().isEmpty()) { 1361 localDatabaseManager()->updateAccount(accountName(), mRuqolaServerConfig->serialize(false), LocalDatabaseUtils::currentTimeStamp()); 1362 } 1363 1364 fillAuthenticationModel(); 1365 // Download logo/favicon if possible 1366 (void)faviconLogoUrlFromLocalCache(mRuqolaServerConfig->logoUrl().url); 1367 (void)faviconLogoUrlFromLocalCache(mRuqolaServerConfig->faviconUrl().url); 1368 1369 Q_EMIT publicSettingChanged(); 1370 } 1371 1372 void RocketChatAccount::fillAuthenticationModel() 1373 { 1374 QVector<AuthenticationInfo> fillModel; 1375 // qDebug() << " before " << mLstInfos; 1376 for (int i = 0, total = mAuthenticationMethodInfos.count(); i < total; ++i) { 1377 if (mRuqolaServerConfig->canShowAuthMethod(mAuthenticationMethodInfos.at(i).oauthType())) { 1378 fillModel.append(mAuthenticationMethodInfos.at(i)); 1379 } 1380 } 1381 // qDebug() << "void RocketChatAccount::fillAuthenticationModel() " << fillModel; 1382 mAccountAvailableAuthenticationMethodInfos = fillModel; 1383 } 1384 1385 void RocketChatAccount::changeDefaultAuthentication(int index) 1386 { 1387 setDefaultAuthentication(mAccountAvailableAuthenticationMethodInfos.at(index).oauthType()); 1388 } 1389 1390 QVector<AuthenticationInfo> RocketChatAccount::authenticationMethodInfos() const 1391 { 1392 return mAccountAvailableAuthenticationMethodInfos; 1393 } 1394 1395 void RocketChatAccount::setDefaultAuthentication(AuthenticationManager::AuthMethodType type) 1396 { 1397 PluginAuthenticationInterface *interface = mLstPluginAuthenticationInterface.value(type); 1398 if (interface) { 1399 mDefaultAuthenticationInterface = interface; 1400 } else { 1401 qCWarning(RUQOLA_LOG) << "No interface defined for " << type; 1402 } 1403 } 1404 1405 CommonMessageFilterProxyModel *RocketChatAccount::searchMessageFilterProxyModel() const 1406 { 1407 return mSearchMessageFilterProxyModel; 1408 } 1409 1410 CommonMessagesModel *RocketChatAccount::searchMessageModel() const 1411 { 1412 return mSearchMessageModel; 1413 } 1414 1415 void RocketChatAccount::initializeAuthenticationPlugins() 1416 { 1417 // TODO change it when we change server 1418 // Clean up at the end. 1419 const QVector<PluginAuthentication *> lstPlugins = AuthenticationManager::self()->pluginsList(); 1420 qCDebug(RUQOLA_LOG) << " void RocketChatAccount::initializeAuthenticationPlugins()" << lstPlugins.count(); 1421 if (lstPlugins.isEmpty()) { 1422 qCWarning(RUQOLA_LOG) << " No plugins loaded. Please verify your installation."; 1423 ddp()->authenticationManager()->setLoginStatus(DDPAuthenticationManager::FailedToLoginPluginProblem); 1424 return; 1425 } 1426 mLstPluginAuthenticationInterface.clear(); 1427 1428 mAuthenticationMethodInfos.clear(); 1429 for (PluginAuthentication *abstractPlugin : lstPlugins) { 1430 AuthenticationInfo info; 1431 info.setIconName(abstractPlugin->iconName()); 1432 info.setName(abstractPlugin->name()); 1433 info.setOauthType(abstractPlugin->type()); 1434 if (info.isValid()) { 1435 mAuthenticationMethodInfos.append(std::move(info)); 1436 } 1437 1438 PluginAuthenticationInterface *interface = abstractPlugin->createInterface(this); 1439 interface->setAccount(this); 1440 mRuqolaServerConfig->addRuqolaAuthenticationSupport(abstractPlugin->type()); 1441 mLstPluginAuthenticationInterface.insert(abstractPlugin->type(), interface); 1442 // For the moment initialize default interface 1443 if (abstractPlugin->type() == AuthenticationManager::AuthMethodType::Password) { 1444 mDefaultAuthenticationInterface = interface; 1445 } 1446 qCDebug(RUQOLA_LOG) << " plugin type " << abstractPlugin->type(); 1447 } 1448 // TODO fill ??? or store QVector<AuthenticationInfo> 1449 } 1450 1451 PluginAuthenticationInterface *RocketChatAccount::defaultAuthenticationInterface() const 1452 { 1453 return mDefaultAuthenticationInterface; 1454 } 1455 1456 QString RocketChatAccount::authToken() const 1457 { 1458 return settings()->authToken(); 1459 } 1460 1461 QString RocketChatAccount::userName() const 1462 { 1463 return settings()->userName(); 1464 } 1465 1466 void RocketChatAccount::setAccountName(const QString &accountname) 1467 { 1468 // Initialize new account room 1469 // qDebug() << "void RocketChatAccount::setAccountName(const QString &accountname)"<<accountname; 1470 loadSettings(ManagerDataPaths::self()->accountConfigFileName(accountname)); 1471 settings()->setAccountName(accountname); 1472 } 1473 1474 QString RocketChatAccount::accountName() const 1475 { 1476 return settings()->accountName(); 1477 } 1478 1479 QString RocketChatAccount::displayName() const 1480 { 1481 return settings()->displayName(); 1482 } 1483 1484 void RocketChatAccount::addUpdateEmojiCustomList(const QJsonArray &replyArray) 1485 { 1486 mEmojiManager->addUpdateEmojiCustomList(replyArray); 1487 } 1488 1489 void RocketChatAccount::deleteEmojiCustom(const QJsonArray &replyArray) 1490 { 1491 mEmojiManager->deleteEmojiCustom(replyArray); 1492 } 1493 1494 void RocketChatAccount::privateSettingsUpdated(const QJsonArray &replyArray) 1495 { 1496 mRuqolaServerConfig->privateSettingsUpdated(replyArray); 1497 localDatabaseManager()->updateAccount(accountName(), mRuqolaServerConfig->serialize(false), LocalDatabaseUtils::currentTimeStamp()); 1498 Q_EMIT privateSettingsChanged(); 1499 mPreviewUrlCacheManager->setEmbedCacheExpirationDays(mRuqolaServerConfig->embedCacheExpirationDays()); 1500 } 1501 1502 void RocketChatAccount::permissionUpdated(const QJsonArray &replyArray) 1503 { 1504 if (mPermissionManager.updatePermission(replyArray)) { 1505 Q_EMIT permissionChanged(); 1506 } 1507 // TODO stockage roles! Load it before permission! 1508 // QJsonObject({"args":["updated",{"_id":"access-mailer","_updatedAt":{"$date":1634569746270},"roles":["admin","vFXCWG9trXLti6xQm"]}],"eventName":"permissions-changed"}) 1509 } 1510 1511 const QVector<RoleInfo> &RocketChatAccount::roleInfo() const 1512 { 1513 return mRolesManager.roleInfo(); 1514 } 1515 1516 void RocketChatAccount::deleteCustomSound(const QJsonArray &replyArray) 1517 { 1518 mCustomSoundManager->deleteCustomSounds(replyArray); 1519 } 1520 1521 void RocketChatAccount::updateRoles(const QJsonArray &contents) 1522 { 1523 mRolesManager.updateRoles(contents); 1524 } 1525 1526 void RocketChatAccount::addStdoutInfo(const QJsonArray &contents) 1527 { 1528 const auto count{contents.count()}; 1529 for (auto i = 0; i < count; ++i) { 1530 const QJsonObject obj = contents.at(i).toObject(); 1531 const QString infoStr = obj[QLatin1String("string")].toString(); 1532 // qDebug() << " infoStr " << infoStr; 1533 Q_EMIT insertStdOutInfo(infoStr); 1534 } 1535 } 1536 1537 void RocketChatAccount::updateCustomSound(const QJsonArray &replyArray) 1538 { 1539 mCustomSoundManager->updateCustomSounds(replyArray); 1540 } 1541 1542 void RocketChatAccount::deleteUser(const QJsonArray &replyArray) 1543 { 1544 qDebug() << " void RocketChatAccount::deleteUser(const QJsonObject &replyObject)" << replyArray; 1545 } 1546 1547 void RocketChatAccount::deleteCustomUserStatus(const QJsonArray &replyArray) 1548 { 1549 qDebug() << " void RocketChatAccount::deleteCustomUserStatus(const QJsonObject &replyObject)" << replyArray; 1550 mCustomUserStatuses.deleteCustomUserStatuses(replyArray); 1551 Q_EMIT customUserStatusChanged(); 1552 } 1553 1554 void RocketChatAccount::updateCustomUserStatus(const QJsonArray &replyArray) 1555 { 1556 mCustomUserStatuses.updateCustomUserStatues(replyArray); 1557 Q_EMIT customUserStatusChanged(); 1558 qDebug() << " void RocketChatAccount::updateCustomUserStatus(const QJsonObject &replyObject)" << replyArray; 1559 } 1560 1561 void RocketChatAccount::setDisplayName(const QString &displayName) 1562 { 1563 settings()->setDisplayName(displayName); 1564 } 1565 1566 QString RocketChatAccount::userId() const 1567 { 1568 return settings()->userId(); 1569 } 1570 1571 QString RocketChatAccount::password() const 1572 { 1573 return settings()->password(); 1574 } 1575 1576 QString RocketChatAccount::twoFactorAuthenticationCode() const 1577 { 1578 return settings()->twoFactorAuthenticationCode(); 1579 } 1580 1581 void RocketChatAccount::setAuthToken(const QString &token) 1582 { 1583 settings()->setAuthToken(token); 1584 } 1585 1586 void RocketChatAccount::setPassword(const QString &password) 1587 { 1588 settings()->setPassword(password); 1589 } 1590 1591 void RocketChatAccount::setTwoFactorAuthenticationCode(const QString &twoFactorAuthenticationCode) 1592 { 1593 settings()->setTwoFactorAuthenticationCode(twoFactorAuthenticationCode); 1594 } 1595 1596 void RocketChatAccount::setAccountEnabled(bool enabled) 1597 { 1598 settings()->setAccountEnabled(enabled); 1599 } 1600 1601 void RocketChatAccount::setUserName(const QString &username) 1602 { 1603 settings()->setUserName(username); 1604 } 1605 1606 bool RocketChatAccount::accountEnabled() const 1607 { 1608 return settings()->accountEnabled(); 1609 } 1610 1611 void RocketChatAccount::setUserId(const QString &userID) 1612 { 1613 settings()->setUserId(userID); 1614 } 1615 1616 QString RocketChatAccount::serverUrl() const 1617 { 1618 return settings()->serverUrl(); 1619 } 1620 1621 void RocketChatAccount::setServerUrl(const QString &serverURL) 1622 { 1623 settings()->setServerUrl(serverURL); 1624 restApi()->setServerUrl(serverURL); 1625 mEmojiManager->setServerUrl(serverURL); 1626 } 1627 1628 QUrl RocketChatAccount::urlForLink(const QString &link) const 1629 { 1630 if (link.startsWith(QLatin1String("https:")) || link.startsWith(QLatin1String("http:"))) { 1631 return QUrl(link); 1632 } 1633 QString tmpUrl = settings()->serverUrl(); 1634 if (!tmpUrl.startsWith(QLatin1String("https://"))) { 1635 tmpUrl = QLatin1String("https://") + tmpUrl; 1636 } 1637 if (!link.startsWith(QLatin1Char('/'))) { 1638 tmpUrl += QLatin1Char('/'); 1639 } 1640 const QUrl downloadFileUrl = QUrl::fromUserInput(tmpUrl + link); 1641 return downloadFileUrl; 1642 } 1643 1644 QString RocketChatAccount::recordingVideoPath() const 1645 { 1646 return mCache->recordingVideoPath(accountName()); 1647 } 1648 1649 QString RocketChatAccount::recordingImagePath() const 1650 { 1651 return mCache->recordingImagePath(accountName()); 1652 } 1653 1654 void RocketChatAccount::downloadFile(const QString &downloadFileUrl, const QUrl &localFile) 1655 { 1656 mCache->downloadFile(downloadFileUrl, localFile); 1657 } 1658 1659 QUrl RocketChatAccount::avatarUrlFromLocalCache(const QString &url) 1660 { 1661 return mCache->avatarUrlFromLocalCache(url); 1662 } 1663 1664 QUrl RocketChatAccount::faviconLogoUrlFromLocalCache(const QString &url) 1665 { 1666 return mCache->faviconLogoUrlFromLocalCache(url); 1667 } 1668 1669 QUrl RocketChatAccount::previewUrlFromLocalCache(const QString &url) 1670 { 1671 return mCache->previewUrlFromLocalCache(url); 1672 } 1673 1674 QUrl RocketChatAccount::attachmentUrlFromLocalCache(const QString &url) 1675 { 1676 return mCache->attachmentUrlFromLocalCache(url); 1677 } 1678 1679 bool RocketChatAccount::attachmentIsInLocalCache(const QString &url) 1680 { 1681 return mCache->attachmentIsInLocalCache(url); 1682 } 1683 1684 void RocketChatAccount::loadHistory(const QString &roomID, bool initial, qint64 timeStamp) 1685 { 1686 MessagesModel *roomModel = messageModelForRoom(roomID); 1687 if (roomModel) { 1688 Room *room = mRoomModel->findRoom(roomID); 1689 // qDebug() << " room->numberMessages() " << room->numberMessages() << " roomModel->rowCount() " << roomModel->rowCount(); 1690 if (!initial && (room->numberMessages() == roomModel->rowCount())) { 1691 return; 1692 } 1693 ManageLocalDatabase::ManageLoadHistoryInfo info; 1694 info.roomModel = roomModel; 1695 info.roomId = roomID; 1696 info.initial = initial; 1697 info.timeStamp = timeStamp; 1698 info.roomName = room->displayFName(); 1699 info.lastSeenAt = room->lastSeenAt(); 1700 mManageLoadHistory->loadMessagesHistory(info); 1701 } else { 1702 qCWarning(RUQOLA_LOG) << "Room is not found " << roomID; 1703 } 1704 } 1705 1706 void RocketChatAccount::loadAccountSettings() 1707 { 1708 mManageLoadHistory->loadAccountSettings(); 1709 } 1710 1711 void RocketChatAccount::setServerVersion(const QString &version) 1712 { 1713 qCDebug(RUQOLA_LOG) << " void RocketChatAccount::setServerVersion(const QString &version)" << version; 1714 mRuqolaServerConfig->setServerVersion(version); 1715 Q_EMIT serverVersionChanged(); 1716 } 1717 1718 QString RocketChatAccount::serverVersion() const 1719 { 1720 return mRuqolaServerConfig->serverVersion(); 1721 } 1722 1723 bool RocketChatAccount::needAdaptNewSubscriptionRC60() const 1724 { 1725 return mRuqolaServerConfig->needAdaptNewSubscriptionRC60(); 1726 } 1727 1728 bool RocketChatAccount::otrEnabled() const 1729 { 1730 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::OtrEnabled; 1731 } 1732 1733 bool RocketChatAccount::allowProfileChange() const 1734 { 1735 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::AllowUserProfileChange; 1736 } 1737 1738 void RocketChatAccount::enable2FaEmailJob(bool enable) 1739 { 1740 restApi()->enable2FaEmailJob(enable); 1741 } 1742 1743 bool RocketChatAccount::allowMessagePinningEnabled() const 1744 { 1745 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::AllowMessagePinning; 1746 } 1747 1748 bool RocketChatAccount::allowMessageStarringEnabled() const 1749 { 1750 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::AllowMessageStarring; 1751 } 1752 1753 bool RocketChatAccount::allowMessageDeletingEnabled() const 1754 { 1755 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::AllowMessageDeleting; 1756 } 1757 1758 bool RocketChatAccount::threadsEnabled() const 1759 { 1760 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::ThreadsEnabled; 1761 } 1762 1763 bool RocketChatAccount::autoTranslateEnabled() const 1764 { 1765 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::AutoTranslateEnabled; 1766 } 1767 1768 bool RocketChatAccount::encryptionEnabled() const 1769 { 1770 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::EncryptionEnabled; 1771 } 1772 1773 bool RocketChatAccount::twoFactorAuthenticationEnabled() const 1774 { 1775 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::TwoFactorAuthenticationEnabled; 1776 } 1777 1778 bool RocketChatAccount::twoFactorAuthenticationByEmailEnabled() const 1779 { 1780 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::TwoFactorAuthenticationByEmailEnabled; 1781 } 1782 1783 bool RocketChatAccount::twoFactorAuthenticationEnforcePasswordFallback() const 1784 { 1785 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::TwoFactorAuthenticationEnforcePasswordFallback; 1786 } 1787 1788 bool RocketChatAccount::twoFactorAuthenticationByTOTPEnabled() const 1789 { 1790 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::TwoFactorAuthenticationByTOTPEnabled; 1791 } 1792 1793 bool RocketChatAccount::broadCastEnabled() const 1794 { 1795 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::BroadCastEnabled; 1796 } 1797 1798 bool RocketChatAccount::registrationFormEnabled() const 1799 { 1800 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::RegistrationFormEnabled; 1801 } 1802 1803 bool RocketChatAccount::allowDeleteOwnAccount() const 1804 { 1805 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::AllowDeleteOwnAccount; 1806 } 1807 1808 bool RocketChatAccount::discussionEnabled() const 1809 { 1810 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::DiscussionEnabled; 1811 } 1812 1813 bool RocketChatAccount::allowAvatarChanged() const 1814 { 1815 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::AllowUserAvatarChange; 1816 } 1817 1818 bool RocketChatAccount::audioRecorderEnabled() const 1819 { 1820 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::AudioRecorderEnabled; 1821 } 1822 1823 bool RocketChatAccount::videoRecorderEnabled() const 1824 { 1825 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::VideoRecorderEnabled; 1826 } 1827 1828 bool RocketChatAccount::teamEnabled() const 1829 { 1830 return hasPermission(QStringLiteral("create-team")); 1831 } 1832 1833 bool RocketChatAccount::ldapEnabled() const 1834 { 1835 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::LdapEnabled; 1836 } 1837 1838 ServerConfigInfo *RocketChatAccount::serverConfigInfo() const 1839 { 1840 return mServerConfigInfo; 1841 } 1842 1843 bool RocketChatAccount::jitsiEnabled() const 1844 { 1845 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::JitsiEnabled; 1846 } 1847 1848 void RocketChatAccount::groupInfo(const QString &roomId) 1849 { 1850 restApi()->groupInfo(roomId); 1851 } 1852 1853 void RocketChatAccount::switchEditingMode(bool b) 1854 { 1855 if (mEditingMode != b) { 1856 mEditingMode = b; 1857 Q_EMIT editingModeChanged(); 1858 } 1859 } 1860 1861 void RocketChatAccount::setSortUnreadOnTop(bool checked) 1862 { 1863 RocketChatRestApi::UsersSetPreferencesJob::UsersSetPreferencesInfo info; 1864 info.userId = userId(); 1865 info.sidebarShowUnread = RocketChatRestApi::UsersSetPreferencesJob::UsersSetPreferencesInfo::convertToState(checked); 1866 setUserPreferences(std::move(info)); 1867 } 1868 1869 bool RocketChatAccount::sortUnreadOnTop() const 1870 { 1871 return ownUser().ownUserPreferences().showUnread(); 1872 } 1873 1874 bool RocketChatAccount::sortFavoriteChannels() const 1875 { 1876 return ownUser().ownUserPreferences().showFavorite(); 1877 } 1878 1879 void RocketChatAccount::setRoomListSortOrder(OwnUserPreferences::RoomListSortOrder roomListSortOrder) 1880 { 1881 RocketChatRestApi::UsersSetPreferencesJob::UsersSetPreferencesInfo info; 1882 info.userId = userId(); 1883 switch (roomListSortOrder) { 1884 case OwnUserPreferences::RoomListSortOrder::ByLastMessage: 1885 info.sidebarSortby = QStringLiteral("activity"); 1886 break; 1887 case OwnUserPreferences::RoomListSortOrder::Alphabetically: 1888 info.sidebarSortby = QStringLiteral("alphabetical"); 1889 break; 1890 case OwnUserPreferences::RoomListSortOrder::Unknown: 1891 qCWarning(RUQOLA_LOG) << " OwnUserPreferences::RoomListSortOrder::Unknown is a bug"; 1892 return; 1893 } 1894 setUserPreferences(std::move(info)); 1895 } 1896 1897 OwnUserPreferences::RoomListSortOrder RocketChatAccount::roomListSortOrder() const 1898 { 1899 return ownUser().ownUserPreferences().roomListSortOrder(); 1900 } 1901 1902 void RocketChatAccount::kickUser(const QString &roomId, const QString &userId, Room::RoomType channelType) 1903 { 1904 switch (channelType) { 1905 case Room::RoomType::Private: 1906 restApi()->groupKick(roomId, userId); 1907 break; 1908 case Room::RoomType::Channel: 1909 restApi()->channelKick(roomId, userId); 1910 break; 1911 case Room::RoomType::Direct: 1912 break; 1913 case Room::RoomType::Unknown: 1914 qCWarning(RUQOLA_LOG) << " unsupported kickUser room for type " << channelType; 1915 break; 1916 } 1917 } 1918 1919 void RocketChatAccount::rolesInRoom(const QString &roomId, Room::RoomType channelType) 1920 { 1921 switch (channelType) { 1922 case Room::RoomType::Private: 1923 restApi()->getGroupRoles(roomId); 1924 break; 1925 case Room::RoomType::Channel: 1926 restApi()->getChannelRoles(roomId); 1927 break; 1928 case Room::RoomType::Direct: 1929 break; 1930 case Room::RoomType::Unknown: 1931 qCWarning(RUQOLA_LOG) << " unsupported get roles room for type " << channelType; 1932 break; 1933 } 1934 } 1935 1936 void RocketChatAccount::switchingToRoom(const QString &roomID) 1937 { 1938 clearTypingNotification(); 1939 checkInitializedRoom(roomID); 1940 } 1941 1942 void RocketChatAccount::changeRoles(const QString &roomId, const QString &userId, Room::RoomType channelType, RocketChatAccount::RoleType roleType) 1943 { 1944 switch (channelType) { 1945 case Room::RoomType::Private: 1946 switch (roleType) { 1947 case RocketChatAccount::AddOwner: 1948 restApi()->groupAddOwner(roomId, userId); 1949 break; 1950 case RocketChatAccount::AddLeader: 1951 restApi()->groupAddLeader(roomId, userId); 1952 break; 1953 case RocketChatAccount::AddModerator: 1954 restApi()->groupAddModerator(roomId, userId); 1955 break; 1956 case RocketChatAccount::RemoveOwner: 1957 restApi()->groupRemoveOwner(roomId, userId); 1958 break; 1959 case RocketChatAccount::RemoveLeader: 1960 restApi()->groupRemoveLeader(roomId, userId); 1961 break; 1962 case RocketChatAccount::RemoveModerator: 1963 restApi()->groupRemoveModerator(roomId, userId); 1964 break; 1965 } 1966 1967 break; 1968 case Room::RoomType::Channel: 1969 switch (roleType) { 1970 case RocketChatAccount::AddOwner: 1971 restApi()->channelAddOwner(roomId, userId); 1972 break; 1973 case RocketChatAccount::AddLeader: 1974 restApi()->channelAddLeader(roomId, userId); 1975 break; 1976 case RocketChatAccount::AddModerator: 1977 restApi()->channelAddModerator(roomId, userId); 1978 break; 1979 case RocketChatAccount::RemoveOwner: 1980 restApi()->channelRemoveOwner(roomId, userId); 1981 break; 1982 case RocketChatAccount::RemoveLeader: 1983 restApi()->channelRemoveLeader(roomId, userId); 1984 break; 1985 case RocketChatAccount::RemoveModerator: 1986 restApi()->channelRemoveModerator(roomId, userId); 1987 break; 1988 } 1989 1990 break; 1991 case Room::RoomType::Direct: 1992 case Room::RoomType::Unknown: 1993 qCWarning(RUQOLA_LOG) << " unsupported changeRoles room for type " << channelType; 1994 break; 1995 } 1996 } 1997 1998 void RocketChatAccount::channelInfo(const QString &roomId) 1999 { 2000 restApi()->channelInfo(roomId); 2001 } 2002 2003 bool RocketChatAccount::allowEditingMessages() const 2004 { 2005 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::AllowEditingMessage; 2006 } 2007 2008 bool RocketChatAccount::uploadFileEnabled() const 2009 { 2010 return mRuqolaServerConfig->serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::UploadFileEnabled; 2011 } 2012 2013 bool RocketChatAccount::isMessageEditable(const Message &message) const 2014 { 2015 if (!allowEditingMessages()) { 2016 return false; 2017 } 2018 if (hasPermission(QStringLiteral("edit-message"))) { 2019 return true; 2020 } 2021 if (message.userId() != userId()) { 2022 return false; 2023 } 2024 if (ruqolaServerConfig()->blockEditingMessageInMinutes() == 0) { 2025 return true; 2026 } 2027 constexpr int minute = 60 * 1000; 2028 return (message.timeStamp() + ruqolaServerConfig()->blockEditingMessageInMinutes() * minute) > QDateTime::currentMSecsSinceEpoch(); 2029 } 2030 2031 bool RocketChatAccount::isMessageDeletable(const Message &message) const 2032 { 2033 if (!allowMessageDeletingEnabled()) { 2034 return false; 2035 } 2036 if (hasPermission(QStringLiteral("force-delete-message"))) { 2037 return true; 2038 } 2039 if (hasPermission(QStringLiteral("delete-message"))) { 2040 return true; 2041 } 2042 if (message.userId() != userId()) { 2043 return false; 2044 } 2045 if (ruqolaServerConfig()->blockDeletingMessageInMinutes() == 0) { // TODO verify it 2046 return true; 2047 } 2048 constexpr int minutes = 60 * 1000; 2049 return (message.timeStamp() + ruqolaServerConfig()->blockDeletingMessageInMinutes() * minutes) > QDateTime::currentMSecsSinceEpoch(); 2050 } 2051 2052 void RocketChatAccount::parseVideoConference(const QJsonArray &contents) 2053 { 2054 qDebug() << " RocketChatAccount::parseVideoConference(const QJsonArray &contents) " << contents; 2055 mVideoConferenceManager->parseVideoConference(contents); 2056 } 2057 2058 void RocketChatAccount::parseOtr(const QJsonArray &contents) 2059 { 2060 qDebug() << " void RocketChatAccount::parseOtr(const QJsonArray &contents)" << contents << " account name" << accountName(); 2061 mOtrManager->parseOtr(contents); 2062 } 2063 2064 void RocketChatAccount::sendNotification(const QJsonArray &contents) 2065 { 2066 // Conference call 2067 // NOTIFICATION: QJsonObject({"collection":"stream-notify-user","fields": 2068 // {"args":[{"payload":{"_id":"vD3CXNB2oK5uB8nDT","message":{"msg":"","t":"videoconf"}, 2069 // "rid":"YbwG4T2uB3wZSZSKBxkNpoB3T98EEPCj2K","sender":{"_id":"YbwG4T2uB3wZSZSKB", 2070 // "name":"laurent","username":"laurent-montel"},"type":"d"},"text":"","title":"laurent"}], 2071 // "eventName":"xkNpoB3T98EEPCj2K/notification"},"id":"id","msg":"changed"}) 2072 2073 NotificationInfo info; 2074 info.setAccountName(accountName()); 2075 info.setDateTime(QDateTime::currentDateTime().toString()); 2076 info.parseNotification(contents); 2077 if (!info.isValid()) { 2078 qCWarning(RUQOLA_LOG) << " Info is invalid ! " << contents; 2079 } else { 2080 switch (info.notificationType()) { 2081 case NotificationInfo::StandardMessage: { 2082 const QString iconFileName = mCache->avatarUrlFromCacheOnly(info.senderUserName()); 2083 // qDebug() << " iconFileName" << iconFileName << " sender " << info.senderId() << " info.senderUserName() " << info.senderUserName(); 2084 QPixmap pix; 2085 if (!iconFileName.isEmpty()) { 2086 const QUrl url = QUrl::fromLocalFile(iconFileName); 2087 // qDebug() << "url.toLocalFile()" << url.toLocalFile(); 2088 const bool loaded = pix.load(url.toLocalFile().remove(QStringLiteral("file://")), "JPEG"); 2089 // qDebug() << " load pixmap : " << loaded; 2090 // qDebug() << " pix " << pix.isNull(); 2091 Q_UNUSED(loaded) 2092 info.setPixmap(pix); 2093 } 2094 break; 2095 } 2096 case NotificationInfo::ConferenceCall: { 2097 // Nothing 2098 break; 2099 } 2100 } 2101 2102 Q_EMIT notification(info); 2103 } 2104 } 2105 2106 void RocketChatAccount::inputAutocomplete(const QString &roomId, 2107 const QString &pattern, 2108 const QString &exceptions, 2109 InputTextManager::CompletionForType type, 2110 bool threadDialog) 2111 { 2112 // TODO look at for restapi support. 2113 switch (type) { 2114 case InputTextManager::CompletionForType::Channel: 2115 ddp()->inputChannelAutocomplete(roomId, pattern, exceptions, threadDialog); 2116 break; 2117 case InputTextManager::CompletionForType::User: 2118 ddp()->inputUserAutocomplete(roomId, pattern, exceptions, threadDialog); 2119 break; 2120 default: 2121 break; 2122 } 2123 } 2124 2125 AutotranslateLanguagesModel *RocketChatAccount::autoTranslateLanguagesModel() const 2126 { 2127 return mAutoTranslateLanguagesModel; 2128 } 2129 2130 void RocketChatAccount::updateUser(const QJsonObject &object) 2131 { 2132 mUserModel->updateUser(object); 2133 } 2134 2135 void RocketChatAccount::userStatusChanged(const User &user) 2136 { 2137 if (user.userId() == userId()) { 2138 mPresenceStatus = user.status(); 2139 statusModel()->setCurrentPresenceStatus(mPresenceStatus); 2140 statusModel()->setCustomText(user.statusText()); 2141 Q_EMIT userStatusUpdated(mPresenceStatus, user.statusText(), accountName()); 2142 } 2143 mUserModel->addUser(user); 2144 mRoomModel->userStatusChanged(user); 2145 } 2146 2147 void RocketChatAccount::ignoreUser(const QString &rid, const QString &userId, bool ignore) 2148 { 2149 restApi()->ignoreUser(rid, userId, ignore); 2150 } 2151 2152 void RocketChatAccount::blockUser(const QString &rid, bool block) 2153 { 2154 // TODO use restapi 2155 if (rid.isEmpty()) { 2156 qCWarning(RUQOLA_LOG) << " void RocketChatAccount::blockUser EMPTY rid ! block " << block; 2157 } else { 2158 // qDebug() << " void RocketChatAccount::blockUser userId " << userId << " block " << block << " rid " << rid << " own userdId" << userID(); 2159 2160 const QString userIdFromDirectChannel = Utils::userIdFromDirectChannel(rid, userId()); 2161 if (block) { 2162 ddp()->blockUser(rid, userIdFromDirectChannel); 2163 } else { 2164 ddp()->unBlockUser(rid, userIdFromDirectChannel); 2165 } 2166 } 2167 } 2168 2169 void RocketChatAccount::clearTypingNotification() 2170 { 2171 mReceiveTypingNotificationManager->clearTypingNotification(); 2172 } 2173 2174 void RocketChatAccount::checkInitializedRoom(const QString &roomId) 2175 { 2176 Room *r = mRoomModel->findRoom(roomId); 2177 if (r && !r->wasInitialized()) { 2178 r->setWasInitialized(true); 2179 ddp()->subscribeRoomMessage(roomId); 2180 if (!r->archived()) { 2181 membersInRoom(r->roomId(), r->channelType()); 2182 rolesInRoom(r->roomId(), r->channelType()); 2183 if (r->channelType() == Room::RoomType::Channel) { 2184 restApi()->getChannelsCounter(r->roomId()); 2185 } 2186 } 2187 loadHistory(r->roomId(), true /*initial loading*/); 2188 } else if (!r) { 2189 qWarning() << " Room " << roomId << " was no found! Need to open it"; 2190 // openDirectChannel(roomId); 2191 } 2192 QMetaObject::invokeMethod(this, &RocketChatAccount::switchedRooms, Qt::QueuedConnection); 2193 } 2194 2195 void RocketChatAccount::openDocumentation() 2196 { 2197 QDesktopServices::openUrl(QUrl(QStringLiteral("help:/"))); 2198 } 2199 2200 void RocketChatAccount::updateAvatarCache(const Utils::AvatarInfo &info) 2201 { 2202 mCache->updateAvatar(info); 2203 } 2204 2205 void RocketChatAccount::avatarChanged(const QJsonArray &contents) 2206 { 2207 // qDebug() << " void RocketChatAccount::avatarChanged(const QJsonArray &contents)*******************" << contents; 2208 for (int i = 0; i < contents.count(); ++i) { 2209 const QJsonObject obj = contents.at(i).toObject(); 2210 if (obj.contains(QLatin1String("username"))) { 2211 const QString userName = obj[QLatin1String("username")].toString(); 2212 Utils::AvatarInfo info; 2213 info.avatarType = Utils::AvatarType::User; 2214 info.identifier = userName; 2215 Q_EMIT avatarWasChanged(info); 2216 } else if (obj.contains(QLatin1String("rid"))) { 2217 const QString roomId = obj[QLatin1String("rid")].toString(); 2218 const QString etag = obj[QLatin1String("etag")].toString(); 2219 qDebug() << "need to update room avatar " << accountName() << "room" << roomId << "etag " << etag; 2220 Utils::AvatarInfo info; 2221 info.avatarType = Utils::AvatarType::Room; 2222 info.etag = etag; // Etag 2223 info.identifier = roomId; // roomId 2224 Q_EMIT avatarWasChanged(info); 2225 } else { 2226 qWarning() << "avatar changed but missing roomId or userId. It seems to be a regression in RC? " << contents; 2227 } 2228 } 2229 2230 // TODO parse "QJsonObject({"args":[{"username":"foo"}],"eventName":"updateAvatar"})" 2231 } 2232 2233 void RocketChatAccount::rolesChanged(const QJsonArray &contents) 2234 { 2235 // TODO verify this code when role change. It seems weird. 2236 for (int i = 0; i < contents.count(); ++i) { 2237 const QJsonObject obj = contents.at(i).toObject(); 2238 const QString scope = obj[QLatin1String("scope")].toString(); 2239 Room *room = mRoomModel->findRoom(scope); 2240 if (room) { 2241 room->updateRoles(obj); 2242 } else { 2243 qWarning() << " Impossible to find room associate to " << scope << contents; 2244 } 2245 } 2246 } 2247 2248 void RocketChatAccount::createDiscussion(const QString &parentRoomId, 2249 const QString &discussionName, 2250 const QString &replyMessage, 2251 const QString &messageId, 2252 const QStringList &users) 2253 { 2254 restApi()->createDiscussion(parentRoomId, discussionName, replyMessage, messageId, users); 2255 } 2256 2257 void RocketChatAccount::threadsInRoom(const QString &roomId, bool onlyUnread) 2258 { 2259 if (threadsEnabled()) { 2260 mListMessageModel->clear(); 2261 mListMessageModel->setRoomId(roomId); 2262 restApi()->getThreadsList(roomId, onlyUnread); 2263 } 2264 } 2265 2266 void RocketChatAccount::discussionsInRoom(const QString &roomId) 2267 { 2268 mDiscussionsModel->initialize(); 2269 mDiscussionsModel->setLoadMoreDiscussionsInProgress(true); 2270 restApi()->getDiscussions(roomId); 2271 } 2272 2273 void RocketChatAccount::followMessage(const QString &messageId, bool follow) 2274 { 2275 if (follow) { 2276 restApi()->followMessage(messageId); 2277 } else { 2278 restApi()->unFollowMessage(messageId); 2279 } 2280 } 2281 2282 void RocketChatAccount::getSupportedLanguages() 2283 { 2284 if (autoTranslateEnabled()) { 2285 bool needTargetLanguage = false; 2286 if (ruqolaServerConfig()->hasAtLeastVersion(5, 1, 0)) { 2287 needTargetLanguage = true; 2288 } 2289 auto job = new RocketChatRestApi::GetSupportedLanguagesJob(this); 2290 job->setNeedTargetLanguage(needTargetLanguage); 2291 restApi()->initializeRestApiJob(job); 2292 connect(job, &RocketChatRestApi::GetSupportedLanguagesJob::getSupportedLanguagesDone, this, &RocketChatAccount::slotGetSupportedLanguagesDone); 2293 if (!job->start()) { 2294 qCDebug(RUQOLA_LOG) << "Impossible to start getSupportedLanguagesMessages"; 2295 } 2296 } else { 2297 qCWarning(RUQOLA_LOG) << " RocketChatAccount::getSupportedLanguages is not supported before server 2.0.0"; 2298 } 2299 } 2300 2301 void RocketChatAccount::slotGetSupportedLanguagesDone(const QJsonObject &obj) 2302 { 2303 mAutoTranslateLanguagesModel->parseLanguages(obj); 2304 } 2305 2306 void RocketChatAccount::autoTranslateSaveLanguageSettings(const QString &roomId, const QString &language) 2307 { 2308 restApi()->autoTranslateSaveLanguageSettings(roomId, language); 2309 } 2310 2311 void RocketChatAccount::autoTranslateSaveAutoTranslateSettings(const QString &roomId, bool autoTranslate) 2312 { 2313 restApi()->autoTranslateSaveAutoTranslateSettings(roomId, autoTranslate); 2314 } 2315 2316 void RocketChatAccount::slotUsersPresenceDone(const QJsonObject &obj) 2317 { 2318 // qDebug() << " void RocketChatAccount::slotUsersPresenceDone(const QJsonObject &obj)" << obj; 2319 const auto lst = obj.value(QStringLiteral("users")).toArray(); 2320 for (const auto &var : lst) { 2321 const QJsonObject userJson = var.toObject(); 2322 User user; 2323 user.parseUserRestApi(userJson, roleInfo()); 2324 if (user.isValid()) { 2325 userStatusChanged(user); 2326 } 2327 } 2328 } 2329 2330 void RocketChatAccount::slotReconnectToServer() 2331 { 2332 // This happens when we didn't react to pings for a while 2333 // (e.g. while stopped in gdb, or if network went down for a bit) 2334 // Let's try connecting in again 2335 QTimer::singleShot(mDelayReconnect, this, [this]() { 2336 qCDebug(RUQOLA_RECONNECT_LOG) << "Attempting to reconnect after the server disconnected us: " << accountName(); 2337 if (mDelayReconnect == 100) { 2338 mDelayReconnect = 1000; 2339 } else { 2340 mDelayReconnect *= 2; 2341 } 2342 Q_EMIT displayReconnectWidget(mDelayReconnect / 1000); 2343 tryLogin(); 2344 }); 2345 } 2346 2347 void RocketChatAccount::usersPresence() 2348 { 2349 restApi()->usersPresence(); 2350 } 2351 2352 void RocketChatAccount::customUsersStatus() 2353 { 2354 restApi()->customUserStatus(); 2355 } 2356 2357 void RocketChatAccount::initializeAccount() 2358 { 2359 listEmojiCustom(); 2360 2361 // load when necessary 2362 usersPresence(); 2363 // Force set online. 2364 // TODO don't reset message status ! 2365 if (RuqolaGlobalConfig::self()->setOnlineAccounts()) { 2366 ddp()->setDefaultStatus(User::PresenceStatus::PresenceOnline); 2367 } 2368 // Initialize sounds 2369 mCustomSoundManager->initializeDefaultSounds(); 2370 ddp()->listCustomSounds(); 2371 customUsersStatus(); 2372 slotLoadRoles(); 2373 if (mRuqolaServerConfig->hasAtLeastVersion(5, 0, 0)) { 2374 checkLicenses(); 2375 } 2376 2377 Q_EMIT accountInitialized(); 2378 } 2379 2380 void RocketChatAccount::checkLicenses() 2381 { 2382 auto job = new RocketChatRestApi::LicensesIsEnterpriseJob(this); 2383 restApi()->initializeRestApiJob(job); 2384 connect(job, &RocketChatRestApi::LicensesIsEnterpriseJob::licensesIsEnterpriseDone, this, [this](bool isEnterprise) { 2385 mRuqolaServerConfig->setHasEnterpriseSupport(isEnterprise); 2386 if (isEnterprise) { 2387 ddp()->licenseGetModules(); 2388 } 2389 }); 2390 if (!job->start()) { 2391 qCWarning(RUQOLA_LOG) << "Impossible to start LicensesIsEnterpriseJob job"; 2392 } 2393 } 2394 2395 LocalDatabaseManager *RocketChatAccount::localDatabaseManager() const 2396 { 2397 return mLocalDatabaseManager.get(); 2398 } 2399 2400 VideoConferenceMessageInfoManager *RocketChatAccount::videoConferenceMessageInfoManager() const 2401 { 2402 return mVideoConferenceMessageInfoManager; 2403 } 2404 2405 VideoConferenceManager *RocketChatAccount::videoConferenceManager() const 2406 { 2407 return mVideoConferenceManager; 2408 } 2409 2410 void RocketChatAccount::downloadAppsLanguages() 2411 { 2412 mDownloadAppsLanguagesManager->setServerVersion(mServerConfigInfo->serverVersionStr()); 2413 mDownloadAppsLanguagesManager->setAccountName(mSettings->accountName()); 2414 mDownloadAppsLanguagesManager->parse(mSettings->serverUrl()); 2415 } 2416 2417 void RocketChatAccount::slotFileLanguagedParsed() 2418 { 2419 // We need mDownloadAppsLanguagesManager result for updating command 2420 getListCommands(); 2421 } 2422 2423 void RocketChatAccount::getListCommands() 2424 { 2425 auto job = new RocketChatRestApi::ListCommandsJob(this); 2426 restApi()->initializeRestApiJob(job); 2427 connect(job, &RocketChatRestApi::ListCommandsJob::listCommandsDone, this, &RocketChatAccount::slotListCommandDone); 2428 if (!job->start()) { 2429 qCDebug(RUQOLA_LOG) << "Impossible to start ListPermissionsJob job"; 2430 } 2431 } 2432 2433 void RocketChatAccount::slotListCommandDone(const QJsonObject &obj) 2434 { 2435 Commands commands; 2436 commands.setDownloadManager(mDownloadAppsLanguagesManager); 2437 commands.parseCommands(obj); 2438 if (!mCommandsModel->commands().isEmpty()) { // Don't show command listview if we already have command (for example when we logout/login) 2439 QSignalBlocker blockSignal(mCommandsModel); 2440 mCommandsModel->setCommands(commands); 2441 } else { 2442 // Initialize it after loading otherwise we will see listview at startup 2443 mCommandsModel->setCommands(commands); 2444 mInputTextManager->setCommandModel(mCommandsModel); 2445 mInputThreadMessageTextManager->setCommandModel(mCommandsModel); 2446 } 2447 // qCDebug(RUQOLA_COMMANDS_LOG) << "accountname " << accountName() << "\nslotListCommandDone " << obj; 2448 } 2449 2450 bool RocketChatAccount::runCommand(const QString &msg, const QString &roomId, const QString &tmid) 2451 { 2452 const RocketChatRestApi::RunCommandJob::RunCommandInfo info = RocketChatRestApi::RunCommandJob::parseString(msg, roomId, tmid); 2453 if (info.isValid()) { 2454 runCommand(info); 2455 return true; 2456 } 2457 return false; 2458 } 2459 2460 void RocketChatAccount::runCommand(const RocketChatRestApi::RunCommandJob::RunCommandInfo &runCommandInfo) 2461 { 2462 restApi()->runCommand(runCommandInfo); 2463 } 2464 2465 User RocketChatAccount::fullUserInfo(const QString &userName) const 2466 { 2467 return mUserModel->fullUserInfo(userName); 2468 } 2469 2470 void RocketChatAccount::markMessageAsUnReadFrom(const QString &messageId) 2471 { 2472 restApi()->markMessageAsUnReadFrom(messageId); 2473 } 2474 2475 void RocketChatAccount::markRoomAsUnRead(const QString &roomId) 2476 { 2477 restApi()->markRoomAsUnRead(roomId); 2478 } 2479 2480 void RocketChatAccount::slotLoginStatusChanged() 2481 { 2482 if (loginStatus() == DDPAuthenticationManager::LoggedOut) { 2483 Q_EMIT logoutDone(accountName()); 2484 qCDebug(RUQOLA_LOG) << "Successfully logged out!"; 2485 } else if (loginStatus() == DDPAuthenticationManager::LoggedIn) { 2486 // Reset it. 2487 mDelayReconnect = 100; 2488 } else if (loginStatus() == DDPAuthenticationManager::LoginFailedInvalidUserOrPassword) { 2489 // clear auth token to refresh it with the next login 2490 setAuthToken({}); 2491 } 2492 Q_EMIT loginStatusChanged(); 2493 } 2494 2495 void RocketChatAccount::sendUserEmailCode() 2496 { 2497 restApi()->sendUserEmailCode(userName()); 2498 } 2499 2500 void RocketChatAccount::requestNewPassword(const QString &email) 2501 { 2502 restApi()->forgotPassword(email); 2503 } 2504 2505 void RocketChatAccount::registerNewUser(const RocketChatRestApi::RegisterUserJob::RegisterUserInfo &userInfo) 2506 { 2507 restApi()->registerNewUser(userInfo); 2508 } 2509 2510 void RocketChatAccount::deleteOwnAccount(const QString &password) 2511 { 2512 restApi()->deleteOwnAccount(password); 2513 } 2514 2515 bool RocketChatAccount::allowEmailChange() const 2516 { 2517 return serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::AllowEmailChange; 2518 } 2519 2520 bool RocketChatAccount::allowPasswordChange() const 2521 { 2522 return serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::AllowPasswordChange; 2523 } 2524 2525 bool RocketChatAccount::allowPasswordReset() const 2526 { 2527 return serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::AllowPasswordReset; 2528 } 2529 2530 bool RocketChatAccount::allowUsernameChange() const 2531 { 2532 return serverConfigFeatureTypes() & RuqolaServerConfig::ServerConfigFeatureType::AllowUsernameChange; 2533 } 2534 2535 void RocketChatAccount::slotRegisterUserDone() 2536 { 2537 Q_EMIT registerUserSuccess(); 2538 } 2539 2540 void RocketChatAccount::updateOwnBasicInfo(const RocketChatRestApi::UsersUpdateOwnBasicInfoJob::UpdateOwnBasicInfo &info) 2541 { 2542 restApi()->updateOwnBasicInfo(info); 2543 } 2544 2545 RuqolaServerConfig::ServerConfigFeatureTypes RocketChatAccount::serverConfigFeatureTypes() const 2546 { 2547 return mRuqolaServerConfig->serverConfigFeatureTypes(); 2548 } 2549 2550 void RocketChatAccount::parseOwnInfoDone(const QJsonObject &replyObject) 2551 { 2552 mOwnUser.parseOwnUserInfo(replyObject); 2553 mAwayManager->updateSettings(); 2554 mBannerInfos.parseBannerInfos(replyObject); 2555 const User user = mOwnUser.user(); 2556 // qDebug() << " USER " << user; 2557 if (user.isValid()) { 2558 usersModel()->addUser(user); 2559 if (!RuqolaGlobalConfig::self()->setOnlineAccounts()) { 2560 // Need to update own status. 2561 setOwnStatus(user); 2562 } 2563 } else { 2564 qCWarning(RUQOLA_LOG) << " Error during parsing user" << replyObject; 2565 } 2566 downloadAppsLanguages(); 2567 Q_EMIT bannerInfoChanged(); 2568 Q_EMIT ownInfoChanged(); 2569 Q_EMIT ownUserPreferencesChanged(); 2570 } 2571 2572 bool RocketChatAccount::isAdministrator() const 2573 { 2574 return mOwnUser.isAdministrator(); 2575 } 2576 2577 void RocketChatAccount::slotChannelGetCountersDone(const QJsonObject &obj, const RocketChatRestApi::ChannelGroupBaseJob::ChannelGroupInfo &channelInfo) 2578 { 2579 Room *room = mRoomModel->findRoom(channelInfo.identifier); 2580 if (room) { 2581 ChannelCounterInfo info; 2582 info.parseCounterInfo(obj); 2583 room->setChannelCounterInfo(info); 2584 } 2585 } 2586 2587 void RocketChatAccount::slotMarkAsReadDone(const QString &roomId) 2588 { 2589 Room *room = this->room(roomId); 2590 if (room) { 2591 room->setChannelCounterInfo({}); 2592 } 2593 } 2594 2595 void RocketChatAccount::logoutFromOtherLocation() 2596 { 2597 restApi()->removeOtherTokens(); 2598 } 2599 2600 void RocketChatAccount::createDirectMessages(const QStringList &usernames) 2601 { 2602 restApi()->createDirectMessage(usernames); 2603 } 2604 2605 void RocketChatAccount::slotCustomUserStatusDone(const QJsonObject &customList) 2606 { 2607 mCustomUserStatuses.parseCustomUserStatuses(customList); 2608 // qDebug() << "customList " << mCustomUserStatuses; 2609 Q_EMIT customUserStatusChanged(); 2610 } 2611 2612 CustomUserStatuses RocketChatAccount::customUserStatuses() const 2613 { 2614 return mCustomUserStatuses; 2615 } 2616 2617 void RocketChatAccount::removeCustomUserStatus(const QString &customUserStatusId) 2618 { 2619 restApi()->deleteCustomUserStatus(customUserStatusId); 2620 } 2621 2622 void RocketChatAccount::updateCustomUserStatus(const RocketChatRestApi::CustomUserStatusUpdateJob::StatusUpdateInfo &statusUpdateInfo) 2623 { 2624 restApi()->updateCustomUserStatus(statusUpdateInfo); 2625 } 2626 2627 void RocketChatAccount::createCustomUserStatus(const RocketChatRestApi::CustomUserStatusCreateJob::StatusCreateInfo &statusCreateInfo) 2628 { 2629 restApi()->createCustomUserStatus(statusCreateInfo); 2630 } 2631 2632 void RocketChatAccount::slotPostMessageDone(const QJsonObject &replyObject) 2633 { 2634 // qDebug() << "replyObject " << replyObject; 2635 const QJsonObject roomInfo = replyObject[QLatin1String("message")].toObject(); 2636 addMessage(roomInfo, true, true); 2637 } 2638 2639 void RocketChatAccount::updateUserData(const QJsonArray &contents) 2640 { 2641 qDebug() << " void RocketChatAccount::updateUserData(const QJsonArray &contents)" << contents; 2642 for (const auto &array : contents) { 2643 const QJsonObject updateJson = array[QLatin1String("diff")].toObject(); 2644 const QStringList keys = updateJson.keys(); 2645 OwnUserPreferences ownUserPreferences = mOwnUser.ownUserPreferences(); 2646 for (const QString &key : keys) { 2647 if (key == QLatin1String("settings.preferences.highlights")) { 2648 const QJsonArray highlightsArray = updateJson.value(key).toArray(); 2649 ownUserPreferences.updateHighlightWords(highlightsArray); 2650 mOwnUser.setOwnUserPreferences(ownUserPreferences); 2651 Q_EMIT needUpdateMessageView(); 2652 } else if (key == QLatin1String("settings.preferences.enableAutoAway")) { 2653 ownUserPreferences.setEnableAutoAway(updateJson.value(key).toBool()); 2654 mOwnUser.setOwnUserPreferences(ownUserPreferences); 2655 } else if (key == QLatin1String("settings.preferences.convertAsciiEmoji")) { 2656 ownUserPreferences.setConvertAsciiEmoji(updateJson.value(key).toBool()); 2657 mOwnUser.setOwnUserPreferences(ownUserPreferences); 2658 Q_EMIT needUpdateMessageView(); 2659 } else if (key == QLatin1String("settings.preferences.hideRoles")) { 2660 ownUserPreferences.setHideRoles(updateJson.value(key).toBool()); 2661 mOwnUser.setOwnUserPreferences(ownUserPreferences); 2662 Q_EMIT needUpdateMessageView(); 2663 } else if (key == QLatin1String("settings.preferences.displayAvatars")) { 2664 ownUserPreferences.setDisplayAvatars(updateJson.value(key).toBool()); 2665 mOwnUser.setOwnUserPreferences(ownUserPreferences); 2666 Q_EMIT needUpdateMessageView(); 2667 } else if (key == QLatin1String("settings.preferences.sidebarViewMode")) { // Channel List view mode 2668 // TODO 2669 } else if (key == QLatin1String("settings.preferences.sidebarShowUnread")) { 2670 ownUserPreferences.setShowUnread(updateJson.value(key).toBool()); 2671 mOwnUser.setOwnUserPreferences(ownUserPreferences); 2672 Q_EMIT ownUserPreferencesChanged(); 2673 } else if (key == QLatin1String("settings.preferences.sidebarDisplayAvatar")) { // Avatar in channel list view 2674 ownUserPreferences.setShowRoomAvatar(updateJson.value(key).toBool()); 2675 mOwnUser.setOwnUserPreferences(ownUserPreferences); 2676 Q_EMIT ownUserPreferencesChanged(); 2677 } else if (key == QLatin1String("settings.preferences.sidebarShowFavorites")) { 2678 ownUserPreferences.setShowFavorite(updateJson.value(key).toBool()); 2679 mOwnUser.setOwnUserPreferences(ownUserPreferences); 2680 Q_EMIT ownUserPreferencesChanged(); 2681 } else if (key == QLatin1String("settings.preferences.sidebarSortby")) { 2682 const QString value = updateJson.value(key).toString(); 2683 if (value == QLatin1String("activity")) { 2684 ownUserPreferences.setRoomListSortOrder(OwnUserPreferences::RoomListSortOrder::ByLastMessage); 2685 } else if (value == QLatin1String("alphabetical")) { 2686 ownUserPreferences.setRoomListSortOrder(OwnUserPreferences::RoomListSortOrder::Alphabetically); 2687 } else { 2688 qCWarning(RUQOLA_LOG) << "Sortby is not defined ? " << value; 2689 } 2690 mOwnUser.setOwnUserPreferences(ownUserPreferences); 2691 Q_EMIT ownUserPreferencesChanged(); 2692 } else { 2693 const static QRegularExpression bannerRegularExpression(QStringLiteral("banners.(.*).read")); 2694 QRegularExpressionMatch rmatch; 2695 if (key.contains(bannerRegularExpression, &rmatch)) { 2696 if (rmatch.hasMatch()) { 2697 const QString bannerName = rmatch.captured(1); 2698 const bool result = updateJson.value(key).toBool(); 2699 mBannerInfos.updateBannerReadInfo(bannerName, result); 2700 } 2701 } 2702 } 2703 } 2704 } 2705 // QJsonArray([{"diff":{"_updatedAt":{"$date":1639552419120},"avatarETag":"MCGFkLtBKkhb5GXBj","avatarOrigin":"rest"},"type":"updated","unset":{}}]) 2706 // QJsonArray([{"diff":{"_updatedAt":{"$date":1639552237550}},"type":"updated","unset":{"avatarETag":1,"avatarOrigin":1}}]) 2707 // QJsonArray([{"diff":{"_updatedAt":{"$date":1639552298748},"nickname":"ss"},"type":"updated","unset":{}}]) 2708 // QJsonArray([{"diff":{"_updatedAt":{"$date":1639552390152}},"type":"updated","unset":{"nickname":1}}]) 2709 // TODO 2710 } 2711 2712 void RocketChatAccount::addMessage(const QJsonObject &replyObject, bool useRestApi, bool temporaryMessage) 2713 { 2714 const QString roomId = replyObject.value(QLatin1String("rid")).toString(); 2715 if (!roomId.isEmpty()) { 2716 MessagesModel *messageModel = messageModelForRoom(roomId); 2717 if (!messageModel) { 2718 qCWarning(RUQOLA_LOG) << "Unexpected null message model."; 2719 return; 2720 } 2721 Message m(emojiManager()); 2722 m.parseMessage(replyObject, useRestApi); 2723 m.setMessageType(Message::MessageType::Information); 2724 m.setPendingMessage(temporaryMessage); 2725 if (!m.threadMessageId().isEmpty()) { 2726 // qDebug() << " It's a thread message id ****************************" << m.threadMessageId(); 2727 updateThreadMessageList(m); 2728 } 2729 // m.setMessageType(Message::System); 2730 // TODO add special element!See roomData QJsonObject({"_id":"u9xnnzaBQoQithsxP","msg":"You have been muted and cannot speak in this 2731 // room","rid":"Dic5wZD4Zu9ze5gk3","ts":{"$date":1534166745895}}) 2732 // Temporary => we don't add it in database 2733 messageModel->addMessages({m}); 2734 } else { 2735 qCWarning(RUQOLA_LOG) << "stream-notify-user : Message: ROOMID is empty "; 2736 } 2737 } 2738 2739 OwnUserPreferences RocketChatAccount::ownUserPreferences() const 2740 { 2741 return ownUser().ownUserPreferences(); 2742 } 2743 2744 QStringList RocketChatAccount::highlightWords() const 2745 { 2746 return ownUser().ownUserPreferences().highlightWords(); 2747 } 2748 2749 void RocketChatAccount::resetAvatar() 2750 { 2751 RocketChatRestApi::UserBaseJob::UserInfo info; 2752 info.userInfoType = RocketChatRestApi::UserBaseJob::UserInfoType::UserId; 2753 info.userIdentifier = userId(); 2754 restApi()->resetAvatar(info); 2755 // TODO update avatar when we reset it. 2756 } 2757 2758 void RocketChatAccount::setAvatarUrl(const QString &url) 2759 { 2760 RocketChatRestApi::UserBaseJob::UserInfo userInfo; 2761 userInfo.userInfoType = RocketChatRestApi::UserBaseJob::UserInfoType::UserId; 2762 userInfo.userIdentifier = userId(); 2763 RocketChatRestApi::SetAvatarJob::SetAvatarInfo avatarInfo; 2764 avatarInfo.mAvatarUrl = url; 2765 restApi()->setAvatar(userInfo, avatarInfo); 2766 } 2767 2768 void RocketChatAccount::setImageUrl(const QUrl &url) 2769 { 2770 RocketChatRestApi::UserBaseJob::UserInfo userInfo; 2771 userInfo.userInfoType = RocketChatRestApi::UserBaseJob::UserInfoType::UserId; 2772 userInfo.userIdentifier = userId(); 2773 RocketChatRestApi::SetAvatarJob::SetAvatarInfo avatarInfo; 2774 avatarInfo.mImageUrl = url; 2775 restApi()->setAvatar(userInfo, avatarInfo); 2776 } 2777 2778 void RocketChatAccount::exportMessages(const RocketChatRestApi::RoomsExportJob::RoomsExportInfo &info) 2779 { 2780 auto job = new RocketChatRestApi::RoomsExportJob(this); 2781 job->setRoomExportInfo(info); 2782 restApi()->initializeRestApiJob(job); 2783 connect(job, &RocketChatRestApi::RoomsExportJob::roomExportDone, this, &RocketChatAccount::slotRoomExportDone); 2784 if (!job->start()) { 2785 qCDebug(RUQOLA_LOG) << "Impossible to start RoomsExportJob"; 2786 } 2787 } 2788 2789 void RocketChatAccount::slotRoomExportDone() 2790 { 2791 auto notification = new KNotification(QStringLiteral("export-message"), KNotification::CloseOnTimeout); 2792 notification->setTitle(i18n("Export Messages")); 2793 notification->setText(i18n("Your email has been queued for sending.")); 2794 notification->sendEvent(); 2795 } 2796 2797 void RocketChatAccount::slotPermissionListAllDone(const QJsonObject &replyObject) 2798 { 2799 // qDebug() << accountName() << " replyObject " << replyObject; 2800 mPermissionManager.parsePermissions(replyObject); 2801 Q_EMIT permissionChanged(); 2802 // We can't load until permission loaded. 2803 if (hasAutotranslateSupport()) { 2804 getSupportedLanguages(); 2805 } 2806 } 2807 2808 QStringList RocketChatAccount::permissions(const QString &permissionId) const 2809 { 2810 return mPermissionManager.roles(permissionId); 2811 } 2812 2813 QStringList RocketChatAccount::ownUserPermission() const 2814 { 2815 return mOwnUser.roles(); 2816 } 2817 2818 bool RocketChatAccount::hasPermission(const QString &permissionId) const 2819 { 2820 const QStringList ownUserRoles{mOwnUser.roles()}; 2821 const QStringList permissionRoles{mPermissionManager.roles(permissionId)}; 2822 if (permissionRoles.isEmpty()) { // Check if we don't have stored permissionId in permission manager 2823 if (!mPermissionManager.contains(permissionId)) { 2824 qCWarning(RUQOLA_LOG) << "permissionId not loaded during setup:" << permissionId; 2825 } 2826 } 2827 for (const QString &role : permissionRoles) { 2828 if (ownUserRoles.contains(role)) { 2829 return true; 2830 } 2831 } 2832 return false; 2833 } 2834 2835 void RocketChatAccount::setUserPreferences(const RocketChatRestApi::UsersSetPreferencesJob::UsersSetPreferencesInfo &info) 2836 { 2837 restApi()->setUserPreferences(info); 2838 } 2839 2840 void RocketChatAccount::slotUsersSetPreferencesDone(const QJsonObject &replyObject) 2841 { 2842 // qDebug() << " void RocketChatAccount::slotUsersSetPreferencesDone(const QJsonObject &replyObject)" << replyObject; 2843 const QJsonObject user = replyObject.value(QLatin1String("user")).toObject(); 2844 if (user.value(QLatin1String("_id")).toString() == userId()) { 2845 OwnUserPreferences ownUserPreferences; 2846 ownUserPreferences.parsePreferences(user.value(QLatin1String("settings")).toObject().value(QLatin1String("preferences")).toObject()); 2847 mOwnUser.setOwnUserPreferences(ownUserPreferences); 2848 Q_EMIT ownUserPreferencesChanged(); 2849 } 2850 } 2851 2852 bool RocketChatAccount::hasAutotranslateSupport() const 2853 { 2854 return autoTranslateEnabled() && hasPermission(QStringLiteral("auto-translate")); 2855 } 2856 2857 MessageCache *RocketChatAccount::messageCache() const 2858 { 2859 return mMessageCache; 2860 } 2861 2862 void RocketChatAccount::slotUpdateCustomUserStatus() 2863 { 2864 mStatusModel->updateCustomStatus(mCustomUserStatuses.customUserses()); 2865 Q_EMIT customStatusChanged(); 2866 } 2867 2868 bool RocketChatAccount::hideRoles() const 2869 { 2870 return ownUser().ownUserPreferences().hideRoles(); 2871 } 2872 2873 bool RocketChatAccount::displayAvatars() const 2874 { 2875 return ownUser().ownUserPreferences().displayAvatars(); 2876 } 2877 2878 void RocketChatAccount::slotLoadRoles() 2879 { 2880 // First load list of roles. 2881 auto job = new RocketChatRestApi::RolesListJob(this); 2882 restApi()->initializeRestApiJob(job); 2883 connect(job, &RocketChatRestApi::RolesListJob::rolesListDone, &mRolesManager, &RolesManager::parseRoles); 2884 if (!job->start()) { 2885 qCWarning(RUQOLA_LOG) << "Impossible to start RolesListJob job"; 2886 } 2887 } 2888 2889 CustomSoundsManager *RocketChatAccount::customSoundManager() const 2890 { 2891 return mCustomSoundManager; 2892 } 2893 2894 void RocketChatAccount::slotAwayStatusChanged(bool away) 2895 { 2896 restApi()->setUserStatus(userId(), away ? RocketChatRestApi::SetStatusJob::Away : RocketChatRestApi::SetStatusJob::OnLine, {}); 2897 qCDebug(RUQOLA_LOG) << "RocketChatAccount::slotAwayStatusChanged " << away; 2898 } 2899 2900 void RocketChatAccount::generate2FaTotp(const QJsonObject &obj) 2901 { 2902 // qDebug() << "RocketChatAccount::generate2FaTotp " << obj; 2903 const QString secret = obj.value(QStringLiteral("secret")).toString(); 2904 const QString url = obj.value(QStringLiteral("url")).toString(); 2905 Q_EMIT totpResult(secret, url); 2906 } 2907 2908 void RocketChatAccount::totpDisabledVerify(const QJsonObject &root) 2909 { 2910 const int result = root.value(QStringLiteral("result")).toInt(); 2911 Q_EMIT disabledTotpValid(result == 1); 2912 } 2913 2914 void RocketChatAccount::totpVerify(const QJsonObject &obj) 2915 { 2916 if (obj.isEmpty()) { 2917 Q_EMIT totpInvalid(); 2918 } else { 2919 // qDebug() << "totpValid " << obj; 2920 QStringList lstCodes; 2921 const QJsonArray codes = obj.value(QStringLiteral("codes")).toArray(); 2922 const auto nbCodes{codes.count()}; 2923 lstCodes.reserve(nbCodes); 2924 for (auto i = 0; i < nbCodes; ++i) { 2925 lstCodes.append(codes.at(i).toString()); 2926 } 2927 Q_EMIT totpValid(lstCodes); 2928 } 2929 } 2930 2931 void RocketChatAccount::setOauthAppAdded(const QJsonObject &obj) 2932 { 2933 // TODO return error 2934 Q_EMIT oauthAppAdded(obj); 2935 } 2936 2937 void RocketChatAccount::setOauthAppUpdated(const QJsonObject &obj) 2938 { 2939 // TODO return error 2940 Q_EMIT oauthAppUpdated(obj); 2941 } 2942 2943 bool RocketChatAccount::hasLicense(const QString &name) 2944 { 2945 return mLicensesManager.hasLicense(name); 2946 } 2947 2948 void RocketChatAccount::parseLicenses(const QJsonArray &replyArray) 2949 { 2950 mLicensesManager.parseLicenses(replyArray); 2951 } 2952 2953 void RocketChatAccount::addMessageToDataBase(const QString &roomName, const Message &message) 2954 { 2955 mLocalDatabaseManager->addMessage(accountName(), roomName, message); 2956 } 2957 2958 void RocketChatAccount::deleteMessageFromDatabase(const QString &roomName, const QString &messageId) 2959 { 2960 mLocalDatabaseManager->deleteMessage(accountName(), roomName, messageId); 2961 } 2962 2963 // Only for debugging permissions. (debug mode) 2964 QVector<Permission> RocketChatAccount::permissions() const 2965 { 2966 return mPermissionManager.permissions(); 2967 } 2968 2969 #include "moc_rocketchataccount.cpp"