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