File indexing completed on 2023-11-26 08:17:49

0001 /*
0002    SPDX-FileCopyrightText: 2018-2023 Laurent Montel <montel@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "accountmanager.h"
0008 #include "localdatabase/localdatabaseutils.h"
0009 #include "managerdatapaths.h"
0010 #include "notificationhistorymanager.h"
0011 #include "notifications/notifierjob.h"
0012 #include "parsemessageurlutils.h"
0013 #include "ruqola_debug.h"
0014 #include "ruqolaglobalconfig.h"
0015 #include <KLocalizedString>
0016 #include <QDir>
0017 #include <QDirIterator>
0018 #include <QSettings>
0019 
0020 AccountManager::AccountManager(QObject *parent)
0021     : QObject(parent)
0022     , mRocketChatAccountModel(new RocketChatAccountModel(this))
0023     , mRocketChatAccountProxyModel(new RocketChatAccountFilterProxyModel(this))
0024 {
0025     mRocketChatAccountProxyModel->setSourceModel(mRocketChatAccountModel);
0026     loadAccount();
0027 }
0028 
0029 AccountManager::~AccountManager() = default;
0030 
0031 int AccountManager::accountNumber() const
0032 {
0033     return mRocketChatAccountModel->accountNumber();
0034 }
0035 
0036 bool AccountManager::showMessage(const ParseMessageUrlUtils &parseUrl)
0037 {
0038     auto account = mRocketChatAccountModel->accountFromServerUrl(parseUrl.serverHost());
0039     if (account) {
0040         // const QString path{parseUrl.path()};
0041         const QString messageId = parseUrl.messageId();
0042         qCDebug(RUQOLA_LOG) << " parseUrl " << parseUrl;
0043         // https://<server url>/channel/python?msg=sn3gEQom7NcLxTg5h
0044         setCurrentAccount(account->accountName());
0045         // qDebug() << " account->accountName() : " << account->accountName();
0046         Q_EMIT mCurrentAccount->raiseWindow();
0047         Q_EMIT mCurrentAccount->selectChannelAndMessage(messageId, parseUrl.roomId(), parseUrl.roomIdType(), parseUrl.channelType());
0048         return true;
0049     }
0050     return false;
0051 }
0052 
0053 void AccountManager::openMessageUrl(const QString &messageUrl)
0054 {
0055     ParseMessageUrlUtils parseUrl;
0056     if (parseUrl.parseUrl(messageUrl)) {
0057         if (showMessage(parseUrl)) {
0058             return;
0059         }
0060     }
0061 
0062     Q_EMIT messageUrlNotFound(i18n("Server not found: %1", messageUrl));
0063     // TODO report error
0064 }
0065 
0066 void AccountManager::connectToAccount(RocketChatAccount *account)
0067 {
0068     connect(account, &RocketChatAccount::notification, this, [this, account](const NotificationInfo &info) {
0069         NotificationHistoryManager::self()->addNotification(info);
0070 
0071         switch (info.notificationType()) {
0072         case NotificationInfo::StandardMessage: {
0073             auto job = new NotifierJob;
0074             job->setInfo(info);
0075             connect(job, &NotifierJob::switchToAccountAndRoomName, this, &AccountManager::slotSwitchToAccountAndRoomName);
0076             connect(job, &NotifierJob::sendReply, this, [account](const QString &str, const QString &roomId, const QString &tmId) {
0077                 if (tmId.isEmpty()) {
0078                     account->sendMessage(roomId, str);
0079                 } else {
0080                     account->replyOnThread(roomId, tmId, str);
0081                 }
0082                 // qDebug() << " str" << str << " Room Name " << roomName;
0083             });
0084             job->start();
0085             break;
0086         }
0087         case NotificationInfo::ConferenceCall: {
0088             break;
0089         }
0090         }
0091     });
0092     connect(account, &RocketChatAccount::updateNotification, this, &AccountManager::updateNotification);
0093     connect(account, &RocketChatAccount::roomNeedAttention, this, &AccountManager::roomNeedAttention);
0094     connect(account, &RocketChatAccount::logoutDone, this, &AccountManager::logoutAccountDone);
0095 }
0096 
0097 void AccountManager::slotSwitchToAccountAndRoomName(const QString &accountName, const QString &roomName, const QString &channelType)
0098 {
0099     setCurrentAccount(accountName);
0100     QString linkRoom;
0101     if (channelType == QLatin1Char('c')) {
0102         linkRoom = QStringLiteral("ruqola:/room/%1").arg(roomName);
0103     } else {
0104         linkRoom = QStringLiteral("ruqola:/user/%1").arg(roomName);
0105     }
0106     Q_EMIT mCurrentAccount->raiseWindow();
0107     Q_EMIT mCurrentAccount->openLinkRequested(linkRoom);
0108 }
0109 
0110 void AccountManager::loadAccount()
0111 {
0112     qCDebug(RUQOLA_LOG) << " void AccountManager::loadAccount()" << ManagerDataPaths::self()->path(ManagerDataPaths::Config, QString());
0113     QDirIterator it(ManagerDataPaths::self()->path(ManagerDataPaths::Config, QString()),
0114                     QStringList() << QStringLiteral("ruqola.conf"),
0115                     QDir::AllEntries | QDir::NoSymLinks | QDir::NoDotAndDotDot,
0116                     QDirIterator::Subdirectories);
0117     QVector<RocketChatAccount *> lstAccounts;
0118     while (it.hasNext()) {
0119         const QString val = it.next();
0120         qCDebug(RUQOLA_LOG) << "Account found list.at(i)" << val;
0121         auto account = new RocketChatAccount(val);
0122         if (account->settings()->isValid()) {
0123             connectToAccount(account);
0124             lstAccounts.append(account);
0125         } else {
0126             account->deleteLater();
0127         }
0128     }
0129 
0130     // New account => empty list.
0131     if (lstAccounts.isEmpty()) {
0132         qCDebug(RUQOLA_LOG) << "Empty list. Create a default rocketchataccount";
0133         auto account = new RocketChatAccount();
0134         if (account->accountEnabled()) {
0135             connectToAccount(account);
0136         }
0137         lstAccounts.append(account);
0138     }
0139 
0140     mRocketChatAccountModel->setAccounts(lstAccounts);
0141 
0142     QSettings settings;
0143     const QString previousAccount = settings.value(QStringLiteral("currentAccount"), QString()).toString();
0144     if (previousAccount.isEmpty()) {
0145         // Use first one
0146         mCurrentAccount = mRocketChatAccountModel->account(0);
0147     } else {
0148         selectAccount(previousAccount);
0149         if (!mCurrentAccount) {
0150             // Use first one
0151             mCurrentAccount = mRocketChatAccountModel->account(0);
0152         }
0153     }
0154     mRocketChatAccountProxyModel->setAccountOrder(RuqolaGlobalConfig::self()->accountOrder());
0155 }
0156 
0157 RocketChatAccountFilterProxyModel *AccountManager::rocketChatAccountProxyModel() const
0158 {
0159     return mRocketChatAccountProxyModel;
0160 }
0161 
0162 RocketChatAccount *AccountManager::account() const
0163 {
0164     return mCurrentAccount;
0165 }
0166 
0167 void AccountManager::addAccount(const AccountManagerInfo &info)
0168 {
0169     // TODO verify if account exist or not ?
0170     auto account = new RocketChatAccount();
0171     account->setAccountName(info.accountName);
0172     account->setUserName(info.userName);
0173     account->setServerUrl(info.serverUrl);
0174     account->setAccountEnabled(info.enabled);
0175     account->setPassword(info.password);
0176     if (info.enabled) {
0177         connectToAccount(account);
0178     }
0179     addAccount(account);
0180 }
0181 
0182 void AccountManager::modifyAccount(const AccountManagerInfo &info)
0183 {
0184     RocketChatAccount *account = mRocketChatAccountModel->account(info.accountName);
0185     if (account) {
0186         account->setDisplayName(info.displayName);
0187         account->setUserName(info.userName);
0188         account->setServerUrl(info.serverUrl);
0189         account->setAccountEnabled(info.enabled);
0190         if (!info.enabled) {
0191             // TODO fixme
0192             // disconnect(account, &RocketChatAccount::notification, this, &AccountManager::notification);
0193             disconnect(account, &RocketChatAccount::updateNotification, this, &AccountManager::updateNotification);
0194             disconnect(account, &RocketChatAccount::logoutDone, this, &AccountManager::logoutAccountDone);
0195         }
0196     }
0197 }
0198 
0199 RocketChatAccount *AccountManager::accountFromName(const QString &accountName)
0200 {
0201     return mRocketChatAccountModel->account(accountName);
0202 }
0203 
0204 QStringList AccountManager::accountsName() const
0205 {
0206     return mRocketChatAccountModel->accountsName();
0207 }
0208 
0209 void AccountManager::addAccount(RocketChatAccount *account)
0210 {
0211     mRocketChatAccountModel->insertAccount(account);
0212 }
0213 
0214 void AccountManager::selectAccount(const QString &accountName)
0215 {
0216     RocketChatAccount *account = mRocketChatAccountModel->account(accountName);
0217     if (account) {
0218         mCurrentAccount = account;
0219     } else {
0220         qCWarning(RUQOLA_LOG) << "AccountName " << accountName << " is not found on system.";
0221     }
0222 }
0223 
0224 void AccountManager::setCurrentAccount(const QString &accountName)
0225 {
0226     RocketChatAccount *account = mRocketChatAccountModel->account(accountName);
0227     if (account) {
0228         if (mCurrentAccount != account) {
0229             QSettings settings;
0230             settings.setValue(QStringLiteral("currentAccount"), accountName);
0231             settings.sync();
0232             mCurrentAccount = account;
0233             Q_EMIT currentAccountChanged();
0234         }
0235     } else {
0236         qCWarning(RUQOLA_LOG) << "AccountName " << accountName << " is not found on system. Fallback to default one.";
0237     }
0238 }
0239 
0240 QString AccountManager::currentAccount() const
0241 {
0242     return mCurrentAccount ? mCurrentAccount->accountName() : QString();
0243 }
0244 
0245 void AccountManager::removeLogs(const QString &accountName)
0246 {
0247     const QString directory = LocalDatabaseUtils::localMessageLoggerPath() + accountName;
0248     removeDirectory(directory);
0249 }
0250 
0251 void AccountManager::removeDatabaseAccount(const QString &accountName)
0252 {
0253     const QString directory = LocalDatabaseUtils::localAccountDatabasePath() + accountName;
0254     removeDirectory(directory);
0255 }
0256 
0257 void AccountManager::removeDirectory(const QString &directory)
0258 {
0259     QDir dir(directory);
0260     if (dir.exists()) {
0261         if (!dir.removeRecursively()) {
0262             qCWarning(RUQOLA_LOG) << " Impossible to remove directory : " << directory;
0263         }
0264     }
0265 }
0266 
0267 void AccountManager::removeAccount(const QString &accountName, bool removeLogFiles)
0268 {
0269     auto account = mRocketChatAccountModel->removeAccount(accountName);
0270     if (mRocketChatAccountModel->accountNumber() > 0) {
0271         mCurrentAccount = mRocketChatAccountModel->account(0);
0272         removeDatabaseAccount(accountName);
0273         // TODO remove others files
0274         if (removeLogFiles) {
0275             removeLogs(accountName);
0276         }
0277     } else {
0278         // TODO create new dummy account !
0279     }
0280     Q_EMIT currentAccountChanged();
0281     if (account) {
0282         account->deleteLater();
0283     }
0284 }
0285 
0286 RocketChatAccountModel *AccountManager::rocketChatAccountModel() const
0287 {
0288     return mRocketChatAccountModel;
0289 }
0290 
0291 QStringList AccountManager::accountNamesSorted() const
0292 {
0293     QStringList lst;
0294     auto model = rocketChatAccountProxyModel();
0295     for (int i = 0; i < model->rowCount(); ++i) {
0296         const auto index = model->index(i, 0);
0297         auto account = index.data(RocketChatAccountModel::Account).value<RocketChatAccount *>();
0298         lst << account->displayName();
0299     }
0300     return lst;
0301 }
0302 
0303 #include "moc_accountmanager.cpp"