File indexing completed on 2024-05-05 04:39:54

0001 /*
0002     SPDX-FileCopyrightText: 2012-2013 Miquel Sabaté <mikisabate@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "ghdialog.h"
0008 
0009 #include <ghaccount.h>
0010 #include <ghresource.h>
0011 
0012 #include <KLocalizedString>
0013 #include <KMessageBox>
0014 #include <KPasswordDialog>
0015 
0016 #include <QLabel>
0017 #include <QDialogButtonBox>
0018 #include <QPushButton>
0019 #include <QVBoxLayout>
0020 #include <QPointer>
0021 #include <QInputDialog>
0022 
0023 static QString invalidAccountText()
0024 {
0025     return i18n("You have not authorized KDevelop to use your GitHub account. "
0026                 "If you authorize KDevelop, you will be able to fetch your "
0027                 "public/private repositories and the repositories from your "
0028                 "organizations.");
0029 }
0030 
0031 static QString tokenLinkStatementText()
0032 {
0033     return i18nc("%1 is the URL with the GitHub token settings",
0034                  "You can check the authorization for this application and "
0035                  "others at %1",
0036                  QStringLiteral("https://github.com/settings/tokens."));
0037 }
0038 
0039 namespace gh
0040 {
0041 
0042 Dialog::Dialog(QWidget *parent, Account *account)
0043     : QDialog(parent)
0044     , m_account(account)
0045 {
0046     auto mainWidget = new QWidget(this);
0047     auto mainLayout = new QVBoxLayout;
0048     setLayout(mainLayout);
0049     mainLayout->addWidget(mainWidget);
0050 
0051     auto buttonBox = new QDialogButtonBox();
0052 
0053     if (m_account->validAccount()) {
0054         m_text = new QLabel(i18n("You are logged in as <b>%1</b>.<br/>%2",
0055                                  m_account->name(), tokenLinkStatementText()), this);
0056 
0057         auto logOutButton = new QPushButton;
0058         logOutButton->setText(i18nc("@action:button", "Log Out"));
0059         logOutButton->setIcon(QIcon::fromTheme(QStringLiteral("dialog-cancel")));
0060         buttonBox->addButton(logOutButton, QDialogButtonBox::ActionRole);
0061         connect(logOutButton, &QPushButton::clicked, this, &Dialog::revokeAccess);
0062 
0063         auto forceSyncButton = new QPushButton;
0064         forceSyncButton->setText(i18nc("@action:button", "Force Sync"));
0065         forceSyncButton->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
0066         buttonBox->addButton(forceSyncButton, QDialogButtonBox::ActionRole);
0067         connect(forceSyncButton, &QPushButton::clicked, this, &Dialog::syncUser);
0068 
0069         connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
0070         connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
0071     } else {
0072         m_text = new QLabel(invalidAccountText(), this);
0073 
0074         buttonBox->addButton(QDialogButtonBox::Cancel);
0075 
0076         auto authorizeButton = new QPushButton;
0077         buttonBox->addButton(authorizeButton, QDialogButtonBox::ActionRole);
0078         authorizeButton->setText(i18nc("@action:button", "Authorize"));
0079         authorizeButton->setIcon(QIcon::fromTheme(QStringLiteral("dialog-ok")));
0080         connect(authorizeButton, &QPushButton::clicked, this, &Dialog::authorizeClicked);
0081     }
0082 
0083     m_text->setWordWrap(true);
0084     m_text->setOpenExternalLinks(true);
0085     setMinimumWidth(350);
0086     mainLayout->addWidget(m_text);
0087 
0088     mainLayout->addWidget(buttonBox);
0089     connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
0090     connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
0091 
0092     setWindowTitle(i18nc("@title:window", "GitHub Account"));
0093 }
0094 
0095 void Dialog::authorizeClicked()
0096 {
0097     QPointer<KPasswordDialog> dlg = new KPasswordDialog(this, KPasswordDialog::ShowUsernameLine);
0098     dlg->setPrompt(i18n("Enter a login and a password"));
0099     if(dlg->exec()) {
0100         m_text->setAlignment(Qt::AlignCenter);
0101         m_text->setText(i18n("Waiting for response"));
0102         m_account->setName(dlg->username());
0103 
0104         Resource *rs = m_account->resource();
0105         rs->authenticate(dlg->username(), dlg->password());
0106         connect(rs, &Resource::twoFactorAuthRequested,
0107                 this, &Dialog::twoFactorResponse);
0108         connect(rs, &Resource::authenticated,
0109                 this, &Dialog::authorizeResponse);
0110     }
0111     delete dlg;
0112 }
0113 
0114 void Dialog::authorizeResponse(const QByteArray &id, const QByteArray &token, const QString &tokenName)
0115 {
0116     Q_UNUSED(tokenName);
0117 
0118     Resource *rs = m_account->resource();
0119     disconnect(rs, &Resource::authenticated,
0120                this, &Dialog::authorizeResponse);
0121 
0122     if (id.isEmpty()) {
0123         m_text->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
0124         m_text->setText(invalidAccountText());
0125         m_account->setName(QString());
0126         KMessageBox::error(this, i18n("Authentication failed. Please try again.\n\n"
0127                                       "Could not create token: \"%1\"\n%2", tokenName,
0128                                       tokenLinkStatementText()),
0129                                  i18nc("@title:window", "GitHub Authorization Failed"));
0130         return;
0131     }
0132     else{
0133         KMessageBox::information(this, i18n("Authentication succeeded.\n\n"
0134                                             "Created token: \"%1\"\n%2", tokenName,
0135                                             tokenLinkStatementText()),
0136                                        i18nc("@title:window", "GitHub Account Authorized"));
0137     }
0138     m_account->saveToken(id, token);
0139     syncUser();
0140 }
0141 
0142 void Dialog::twoFactorResponse(const QString &transferHeader)
0143 {
0144     auto code = QInputDialog::getText(this, i18nc("@title:window", "Authentication Code"), i18nc("@label:textbox", "OTP Code:"));
0145     Resource* rs = m_account->resource();
0146     disconnect(rs, &Resource::twoFactorAuthRequested,
0147                this, &Dialog::twoFactorResponse);
0148     rs->twoFactorAuthenticate(transferHeader, code);
0149 }
0150 
0151 void Dialog::syncUser()
0152 {
0153     Resource *rs = m_account->resource();
0154     connect(rs, &Resource::orgsUpdated,
0155             this, &Dialog::updateOrgs);
0156     m_text->setAlignment(Qt::AlignCenter);
0157     m_text->setText(i18n("Waiting for response"));
0158     rs->getOrgs(m_account->token());
0159 }
0160 
0161 void Dialog::updateOrgs(const QStringList& orgs)
0162 {
0163     Resource *rs = m_account->resource();
0164     disconnect(rs, &Resource::orgsUpdated,
0165               this, &Dialog::updateOrgs);
0166 
0167     if (!orgs.isEmpty())
0168         m_account->setOrgs(orgs);
0169     emit shouldUpdate();
0170     close();
0171 }
0172 
0173 void Dialog::revokeAccess()
0174 {
0175     QPointer<KPasswordDialog> dlg = new KPasswordDialog(this);
0176     dlg->setPrompt(i18n("Please, write your password here."));
0177     if(dlg->exec()) {
0178         m_account->invalidate(dlg->password());
0179         emit shouldUpdate();
0180         close();
0181     }
0182     delete dlg;
0183 }
0184 
0185 } // End of namespace gh
0186 
0187 #include "moc_ghdialog.cpp"