File indexing completed on 2024-05-19 05:00:39

0001 /*
0002  * SPDX-FileCopyrightText: 2017 Elvis Angelaccio <elvis.angelaccio@kde.org>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-or-later
0005  *
0006  */
0007 
0008 #include "kaccountsmanager.h"
0009 #include "gdrivedebug.h"
0010 #include "gdrivehelper.h"
0011 
0012 #include <Accounts/Manager>
0013 #include <Accounts/Provider>
0014 #include <KAccounts/Core>
0015 #include <KAccounts/GetCredentialsJob>
0016 #include <KGAPI/Account>
0017 
0018 #include <QProcess>
0019 #include <QStandardPaths>
0020 
0021 using namespace KGAPI2;
0022 
0023 KAccountsManager::KAccountsManager()
0024 {
0025     loadAccounts();
0026 }
0027 
0028 KAccountsManager::~KAccountsManager()
0029 {
0030 }
0031 
0032 AccountPtr KAccountsManager::account(const QString &accountName)
0033 {
0034     const auto accounts = m_accounts.values();
0035     for (const auto &account : accounts) {
0036         if (account->accountName() == accountName) {
0037             return account;
0038         }
0039     }
0040 
0041     return AccountPtr(new Account());
0042 }
0043 
0044 AccountPtr KAccountsManager::createAccount()
0045 {
0046     if (QStandardPaths::findExecutable(QStringLiteral("kcmshell6")).isEmpty()) {
0047         return AccountPtr(new Account());
0048     }
0049 
0050     const auto oldAccounts = accounts();
0051 
0052     QProcess process;
0053     process.start(QStringLiteral("kcmshell6"), {QStringLiteral("kcm_kaccounts")});
0054     qCDebug(GDRIVE) << "Waiting for kcmshell process...";
0055     if (process.waitForFinished(-1)) {
0056         loadAccounts();
0057     }
0058 
0059     const auto newAccounts = accounts();
0060     for (const auto &accountName : newAccounts) {
0061         if (oldAccounts.contains(accountName)) {
0062             continue;
0063         }
0064 
0065         // The KCM allows to add more than one account, but we can return only one from here.
0066         // So we just return the first new account in the set.
0067         qCDebug(GDRIVE) << "New account successfully created:" << accountName;
0068         return account(accountName);
0069     }
0070 
0071     // No accounts at all or no new account(s).
0072     qCDebug(GDRIVE) << "No new account created.";
0073     return AccountPtr(new Account());
0074 }
0075 
0076 AccountPtr KAccountsManager::refreshAccount(const AccountPtr &account)
0077 {
0078     const QString accountName = account->accountName();
0079     for (auto it = m_accounts.constBegin(); it != m_accounts.constEnd(); ++it) {
0080         if (it.value()->accountName() != accountName) {
0081             continue;
0082         }
0083 
0084         const auto id = it.key();
0085         qCDebug(GDRIVE) << "Refreshing" << accountName;
0086         auto gapiAccount = getAccountCredentials(id, accountName);
0087         m_accounts.insert(id, gapiAccount);
0088         return gapiAccount;
0089     }
0090 
0091     return {};
0092 }
0093 
0094 void KAccountsManager::removeAccount(const QString &accountName)
0095 {
0096     if (!accounts().contains(accountName)) {
0097         return;
0098     }
0099 
0100     for (auto it = m_accounts.constBegin(); it != m_accounts.constEnd(); ++it) {
0101         if (it.value()->accountName() != accountName) {
0102             continue;
0103         }
0104 
0105         auto manager = KAccounts::accountsManager();
0106         auto account = Accounts::Account::fromId(manager, it.key());
0107         Q_ASSERT(account->displayName() == accountName);
0108         qCDebug(GDRIVE) << "Going to remove account:" << account->displayName();
0109         account->selectService(manager->service(QStringLiteral("google-drive")));
0110         account->setEnabled(false);
0111         account->sync();
0112         return;
0113     }
0114 }
0115 
0116 QSet<QString> KAccountsManager::accounts()
0117 {
0118     auto accountNames = QSet<QString>();
0119 
0120     const auto accounts = m_accounts.values();
0121     for (const auto &account : accounts) {
0122         accountNames << account->accountName();
0123     }
0124 
0125     return accountNames;
0126 }
0127 
0128 void KAccountsManager::loadAccounts()
0129 {
0130     m_accounts.clear();
0131 
0132     auto manager = KAccounts::accountsManager();
0133     const auto enabledIDs = manager->accountListEnabled();
0134     for (const auto id : enabledIDs) {
0135         auto account = manager->account(id);
0136         if (account->providerName() != QLatin1String("google")) {
0137             continue;
0138         }
0139         qCDebug(GDRIVE) << "Found google-provided account:" << account->displayName();
0140         const auto services = account->enabledServices();
0141         for (const auto &service : services) {
0142             if (service.name() != QLatin1String("google-drive")) {
0143                 continue;
0144             }
0145             qCDebug(GDRIVE) << account->displayName() << "supports gdrive!";
0146 
0147             auto gapiAccount = getAccountCredentials(id, account->displayName());
0148             m_accounts.insert(id, gapiAccount);
0149         }
0150     }
0151 }
0152 
0153 AccountPtr KAccountsManager::getAccountCredentials(Accounts::AccountId id, const QString &displayName)
0154 {
0155     auto job = new KAccounts::GetCredentialsJob(id, nullptr);
0156     job->exec();
0157     if (job->error()) {
0158         qCWarning(GDRIVE) << "GetCredentialsJob failed:" << job->errorString();
0159     }
0160 
0161     auto gapiAccount = AccountPtr(new Account(displayName,
0162                                               job->credentialsData().value(QStringLiteral("AccessToken")).toString(),
0163                                               job->credentialsData().value(QStringLiteral("RefreshToken")).toString()));
0164 
0165     const auto scopes = job->credentialsData().value(QStringLiteral("Scope")).toStringList();
0166     for (const auto &scope : scopes) {
0167         gapiAccount->addScope(QUrl::fromUserInput(scope));
0168     }
0169 
0170     qCDebug(GDRIVE) << "Got account credentials for:" << gapiAccount->accountName() << ", accessToken:" << GDriveHelper::elideToken(gapiAccount->accessToken())
0171                     << ", refreshToken:" << GDriveHelper::elideToken(gapiAccount->refreshToken());
0172 
0173     return gapiAccount;
0174 }