File indexing completed on 2024-04-28 04:55:46

0001 /*
0002     This file is part of Choqok, the KDE micro-blogging client
0003 
0004     SPDX-FileCopyrightText: 2013 Andrea Scarpino <scarpino@kde.org>
0005 
0006     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0007 */
0008 
0009 #include "pumpioeditaccountwidget.h"
0010 
0011 #include <QCheckBox>
0012 #include <QInputDialog>
0013 #include <QJsonDocument>
0014 #include <QEventLoop>
0015 #include <QPushButton>
0016 #include <QUrl>
0017 
0018 #include <KIO/AccessManager>
0019 #include <KIO/StoredTransferJob>
0020 #include <KMessageBox>
0021 
0022 #include "choqoktools.h"
0023 #include "accountmanager.h"
0024 
0025 #include "pumpioaccount.h"
0026 #include "pumpiodebug.h"
0027 #include "pumpiomicroblog.h"
0028 #include "pumpiooauth.h"
0029 
0030 PumpIOEditAccountWidget::PumpIOEditAccountWidget(PumpIOMicroBlog *microblog,
0031         PumpIOAccount *account,
0032         QWidget *parent):
0033     ChoqokEditAccountWidget(account, parent)
0034     , m_account(account)
0035 {
0036     setupUi(this);
0037 
0038     connect(kcfg_authorize, &QPushButton::clicked, this, &PumpIOEditAccountWidget::authorizeUser);
0039 
0040     if (m_account) {
0041         kcfg_alias->setText(m_account->alias());
0042         kcfg_webfingerid->setText(m_account->webfingerID());
0043         setAuthenticated(!m_account->token().isEmpty() && !m_account->tokenSecret().isEmpty());
0044     } else {
0045         setAuthenticated(false);
0046         QString newAccountAlias = microblog->serviceName();
0047         const QString servName = newAccountAlias;
0048         int counter = 1;
0049         while (Choqok::AccountManager::self()->findAccount(newAccountAlias)) {
0050             newAccountAlias = QStringLiteral("%1%2").arg(servName).arg(counter);
0051             counter++;
0052         }
0053         m_account = new PumpIOAccount(microblog, newAccountAlias);
0054         setAccount(m_account);
0055         kcfg_alias->setText(newAccountAlias);
0056     }
0057 
0058     loadTimelinesTable();
0059 }
0060 
0061 PumpIOEditAccountWidget::~PumpIOEditAccountWidget()
0062 {
0063 }
0064 
0065 Choqok::Account *PumpIOEditAccountWidget::apply()
0066 {
0067     m_account->setAlias(kcfg_alias->text());
0068     m_account->setUsername(kcfg_webfingerid->text().split(QLatin1Char('@'))[0]);
0069     m_account->setToken(m_account->oAuth()->token());
0070     m_account->setTokenSecret(m_account->oAuth()->tokenSecret());
0071     m_account->writeConfig();
0072     saveTimelinesTable();
0073     return m_account;
0074 }
0075 
0076 void PumpIOEditAccountWidget::authorizeUser()
0077 {
0078     qCDebug(CHOQOK);
0079     if (kcfg_webfingerid->text().isEmpty() || !kcfg_webfingerid->text().contains(QLatin1Char('@'))) {
0080         return;
0081     }
0082     if (m_account->consumerKey().isEmpty() || m_account->consumerSecret().isEmpty()) {
0083         registerClient();
0084     }
0085 
0086     m_account->oAuth()->grant();
0087 
0088     connect(m_account->oAuth(), &QAbstractOAuth::authorizeWithBrowser, &Choqok::openUrl);
0089     connect(m_account->oAuth(), &QAbstractOAuth::statusChanged, this, &PumpIOEditAccountWidget::getPinCode);
0090 }
0091 
0092 void PumpIOEditAccountWidget::getPinCode()
0093 {
0094     isAuthenticated = false;
0095     if (m_account->oAuth()->status() == QAbstractOAuth::Status::TemporaryCredentialsReceived) {
0096         QString verifier = QInputDialog::getText(this, i18n("PIN"),
0097                            i18n("Enter the verifier code received from %1", m_account->host()));
0098         if (verifier.isEmpty()) {
0099             return;
0100         }
0101 
0102         m_account->oAuth()->continueGrantWithVerifier(verifier);
0103     } else if (m_account->oAuth()->status() == QAbstractOAuth::Status::Granted) {
0104         setAuthenticated(true);
0105         KMessageBox::information(this, i18n("Choqok is authorized successfully."), i18n("Authorized"));
0106     } else {
0107         KMessageBox::detailedError(this, i18n("Authorization Error"), i18n("OAuth authorization error"));
0108     }
0109 }
0110 
0111 bool PumpIOEditAccountWidget::validateData()
0112 {
0113     if (kcfg_alias->text().isEmpty() || kcfg_webfingerid->text().isEmpty() ||
0114             !kcfg_webfingerid->text().contains(QLatin1Char('@')) ||
0115             !isAuthenticated) {
0116         return false;
0117     } else {
0118         return true;
0119     }
0120 }
0121 
0122 void PumpIOEditAccountWidget::setAuthenticated(bool authenticated)
0123 {
0124     isAuthenticated = authenticated;
0125     if (authenticated) {
0126         kcfg_authorize->setIcon(QIcon::fromTheme(QLatin1String("object-unlocked")));
0127         kcfg_authenticateLed->on();
0128         kcfg_authenticateStatus->setText(i18n("Authenticated"));
0129     } else {
0130         kcfg_authorize->setIcon(QIcon::fromTheme(QLatin1String("object-locked")));
0131         kcfg_authenticateLed->off();
0132         kcfg_authenticateStatus->setText(i18n("Not Authenticated"));
0133     }
0134 }
0135 
0136 void PumpIOEditAccountWidget::loadTimelinesTable()
0137 {
0138     for (const QString &timeline: m_account->microblog()->timelineNames()) {
0139         int newRow = timelinesTable->rowCount();
0140         timelinesTable->insertRow(newRow);
0141         timelinesTable->setItem(newRow, 0, new QTableWidgetItem(timeline));
0142 
0143         QCheckBox *enable = new QCheckBox(timelinesTable);
0144         enable->setChecked(m_account->timelineNames().contains(timeline));
0145         timelinesTable->setCellWidget(newRow, 1, enable);
0146     }
0147 }
0148 
0149 void PumpIOEditAccountWidget::registerClient()
0150 {
0151     if (kcfg_webfingerid->text().contains(QLatin1Char('@'))) {
0152         m_account->setHost(QLatin1String("https://") + kcfg_webfingerid->text().split(QLatin1Char('@'))[1]);
0153 
0154         m_account->oAuth()->setTemporaryCredentialsUrl(QUrl(m_account->host() + QLatin1String("/oauth/request_token")));
0155         m_account->oAuth()->setAuthorizationUrl(QUrl(m_account->host() + QLatin1String("/oauth/authorize")));
0156         m_account->oAuth()->setTokenCredentialsUrl(QUrl(m_account->host() + QLatin1String("/oauth/access_token")));
0157 
0158         QUrl url(m_account->host() + QLatin1String("/api/client/register"));
0159         QByteArray data("{"
0160                         " \"type\": \"client_associate\", "
0161                         " \"application_type\": \"native\", "
0162                         " \"application_name\": \"Choqok\" "
0163                         "}");
0164         KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo);
0165         if (!job) {
0166             qCDebug(CHOQOK) << "Cannot create an http POST request!";
0167             return;
0168         }
0169         job->addMetaData(QLatin1String("content-type"), QLatin1String("Content-Type: application/json"));
0170         QEventLoop loop;
0171         connect(job, &KIO::StoredTransferJob::result, &loop, &QEventLoop::quit);
0172         job->start();
0173         loop.exec();
0174 
0175         if (job->error()) {
0176             qCDebug(CHOQOK) << "An error occurred in Job";
0177             return;
0178         } else {
0179             KIO::StoredTransferJob *stj = qobject_cast<KIO::StoredTransferJob *>(job);
0180 
0181             const QJsonDocument json = QJsonDocument::fromJson(stj->data());
0182             if (!json.isNull()) {
0183                 const QVariantMap result = json.toVariant().toMap();
0184                 m_account->setConsumerKey(result[QLatin1String("client_id")].toString());
0185                 m_account->setConsumerSecret(result[QLatin1String("client_secret")].toString());
0186                 m_account->oAuth()->setClientIdentifier(m_account->consumerKey());
0187                 m_account->oAuth()->setClientSharedSecret(m_account->consumerSecret());
0188             } else {
0189                 qCDebug(CHOQOK) << "Cannot parse JSON reply";
0190             }
0191         }
0192     } else {
0193         qCDebug(CHOQOK) << "webfingerID is not valid";
0194     }
0195 }
0196 
0197 void PumpIOEditAccountWidget::saveTimelinesTable()
0198 {
0199     QStringList timelines;
0200     for (int i = 0; i < timelinesTable->rowCount(); ++i) {
0201         QCheckBox *enable = qobject_cast<QCheckBox *>(timelinesTable->cellWidget(i, 1));
0202         if (enable && enable->isChecked()) {
0203             timelines.append(timelinesTable->item(i, 0)->text());
0204         }
0205     }
0206     m_account->setTimelineNames(timelines);
0207 }
0208 
0209 #include "moc_pumpioeditaccountwidget.cpp"