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

0001 /*
0002     This file is part of Choqok, the KDE micro-blogging client
0003 
0004     SPDX-FileCopyrightText: 2017 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 "mastodoneditaccountwidget.h"
0010 
0011 #include <QCoreApplication>
0012 #include <QCheckBox>
0013 #include <QInputDialog>
0014 #include <QJsonDocument>
0015 #include <QEventLoop>
0016 #include <QPushButton>
0017 #include <QUrl>
0018 
0019 #include <KIO/AccessManager>
0020 #include <KIO/StoredTransferJob>
0021 #include <KMessageBox>
0022 
0023 #include "choqoktools.h"
0024 #include "accountmanager.h"
0025 
0026 #include "mastodonaccount.h"
0027 #include "mastodondebug.h"
0028 #include "mastodonmicroblog.h"
0029 #include "mastodonoauth.h"
0030 
0031 MastodonEditAccountWidget::MastodonEditAccountWidget(MastodonMicroBlog *microblog,
0032          MastodonAccount *account,
0033          QWidget *parent):
0034      ChoqokEditAccountWidget(account, parent)
0035      , m_account(account)
0036 {
0037     setupUi(this);
0038 
0039     connect(kcfg_authorize, &QPushButton::clicked, this, &MastodonEditAccountWidget::authorizeUser);
0040 
0041     if (m_account) {
0042         kcfg_alias->setText(m_account->alias());
0043         kcfg_acct->setText(m_account->username());
0044         setAuthenticated(!m_account->tokenSecret().isEmpty());
0045     } else {
0046         setAuthenticated(false);
0047         QString newAccountAlias = microblog->serviceName();
0048         const QString servName = newAccountAlias;
0049         int counter = 1;
0050         while (Choqok::AccountManager::self()->findAccount(newAccountAlias)) {
0051             newAccountAlias = QStringLiteral("%1%2").arg(servName).arg(counter);
0052             counter++;
0053         }
0054         m_account = new MastodonAccount(microblog, newAccountAlias);
0055         setAccount(m_account);
0056         kcfg_alias->setText(newAccountAlias);
0057     }
0058 
0059     loadTimelinesTable();
0060 }
0061 
0062 MastodonEditAccountWidget::~MastodonEditAccountWidget()
0063 {
0064 }
0065 
0066 Choqok::Account *MastodonEditAccountWidget::apply()
0067 {
0068     m_account->setAlias(kcfg_alias->text());
0069     m_account->setUsername(MastodonMicroBlog::userNameFromAcct(kcfg_acct->text()));
0070     m_account->setTokenSecret(m_account->oAuth()->token());
0071     m_account->writeConfig();
0072     saveTimelinesTable();
0073     return m_account;
0074 }
0075 
0076 void MastodonEditAccountWidget::authorizeUser()
0077 {
0078     qCDebug(CHOQOK);
0079     if (kcfg_acct->text().isEmpty() || !kcfg_acct->text().contains(QLatin1Char('@'))) {
0080         return;
0081     }
0082     if (m_account->consumerKey().isEmpty() || m_account->consumerSecret().isEmpty()) {
0083         registerClient();
0084     }
0085 
0086     connect(m_account->oAuth(), &QAbstractOAuth::authorizeWithBrowser, &Choqok::openUrl);
0087     connect(m_account->oAuth(), &QAbstractOAuth::statusChanged, this, &MastodonEditAccountWidget::gotToken);
0088 
0089     m_account->oAuth()->grant();
0090 
0091     QString verifier = QInputDialog::getText(this, i18n("Code"),
0092                        i18n("Enter the code received from %1", m_account->host()));
0093     if (verifier.isEmpty()) {
0094         return;
0095     }
0096 
0097     m_account->oAuth()->getToken(verifier);
0098 }
0099 
0100 void MastodonEditAccountWidget::gotToken()
0101 {
0102     isAuthenticated = false;
0103     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 MastodonEditAccountWidget::validateData()
0112 {
0113     if (kcfg_alias->text().isEmpty() || kcfg_acct->text().isEmpty() ||
0114             !kcfg_acct->text().contains(QLatin1Char('@')) ||
0115             !isAuthenticated) {
0116         return false;
0117     } else {
0118         return true;
0119     }
0120 }
0121 
0122 void MastodonEditAccountWidget::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 MastodonEditAccountWidget::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 MastodonEditAccountWidget::registerClient()
0150 {
0151     if (kcfg_acct->text().contains(QLatin1Char('@'))) {
0152         m_account->setUsername(MastodonMicroBlog::userNameFromAcct(kcfg_acct->text()));
0153         m_account->setHost(QLatin1String("https://") + MastodonMicroBlog::hostFromAcct(kcfg_acct->text()));
0154 
0155         m_account->oAuth()->setAccessTokenUrl(QUrl(m_account->host() + QLatin1String("/oauth/token")));
0156         m_account->oAuth()->setAuthorizationUrl(QUrl(m_account->host() + QLatin1String("/oauth/authorize")));
0157 
0158         QUrl url(m_account->host() + QLatin1String("/api/v1/apps"));
0159         QByteArray data;
0160         data += "client_name=" + QCoreApplication::applicationName().toLatin1();
0161         data += "&redirect_uris=" + QUrl::toPercentEncoding(QLatin1String("urn:ietf:wg:oauth:2.0:oob"));
0162         data += "&scopes=" + QUrl::toPercentEncoding(QLatin1String("read write follow"));
0163         data += "&website=" + QUrl::toPercentEncoding(QLatin1String("https://choqok.kde.org/"));
0164 
0165         KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo);
0166         if (!job) {
0167             qCDebug(CHOQOK) << "Cannot create an http POST request!";
0168             return;
0169         }
0170         job->addMetaData(QLatin1String("content-type"), QLatin1String("Content-Type: application/x-www-form-urlencoded"));
0171         QEventLoop loop;
0172         connect(job, &KIO::StoredTransferJob::result, &loop, &QEventLoop::quit);
0173         job->start();
0174         loop.exec();
0175 
0176         if (job->error()) {
0177             qCDebug(CHOQOK) << "An error occurred in Job";
0178             return;
0179         } else {
0180             KIO::StoredTransferJob *stj = qobject_cast<KIO::StoredTransferJob *>(job);
0181 
0182             const QJsonDocument json = QJsonDocument::fromJson(stj->data());
0183             if (!json.isNull()) {
0184                 const QVariantMap result = json.toVariant().toMap();
0185                 m_account->setConsumerKey(result[QLatin1String("client_id")].toString());
0186                 m_account->setConsumerSecret(result[QLatin1String("client_secret")].toString());
0187                 m_account->oAuth()->setClientIdentifier(m_account->consumerKey());
0188                 m_account->oAuth()->setClientIdentifierSharedKey(m_account->consumerSecret());
0189             } else {
0190                 qCDebug(CHOQOK) << "Cannot parse JSON reply";
0191             }
0192         }
0193     } else {
0194         qCDebug(CHOQOK) << "username is not valid";
0195     }
0196 }
0197 
0198 void MastodonEditAccountWidget::saveTimelinesTable()
0199 {
0200     QStringList timelines;
0201     for (int i = 0; i < timelinesTable->rowCount(); ++i) {
0202         QCheckBox *enable = qobject_cast<QCheckBox *>(timelinesTable->cellWidget(i, 1));
0203         if (enable && enable->isChecked()) {
0204             timelines.append(timelinesTable->item(i, 0)->text());
0205         }
0206     }
0207     //m_account->setTimelineNames(timelines);
0208 }
0209 
0210 #include "moc_mastodoneditaccountwidget.cpp"