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