File indexing completed on 2024-11-17 04:45:01
0001 /* 0002 SPDX-FileCopyrightText: 2013 Daniel Vrátil <dvratil@redhat.com> 0003 SPDX-FileCopyrightText: 2020 Igor Poboiko <igor.poboiko@gmail.com> 0004 0005 SPDX-License-Identifier: GPL-3.0-or-later 0006 */ 0007 0008 #include "googlesettingswidget.h" 0009 #include "googleresource.h" 0010 #include "googleresource_debug.h" 0011 #include "googlescopes.h" 0012 0013 #include <QDialogButtonBox> 0014 0015 #include <KGAPI/Account> 0016 #include <KGAPI/AuthJob> 0017 #include <KGAPI/Calendar/Calendar> 0018 #include <KGAPI/Calendar/CalendarFetchJob> 0019 #include <KGAPI/Tasks/TaskList> 0020 #include <KGAPI/Tasks/TaskListFetchJob> 0021 #include <KMessageBox> 0022 #include <KWindowSystem> 0023 0024 #include <qt6keychain/keychain.h> 0025 0026 using namespace QKeychain; 0027 using namespace KGAPI2; 0028 0029 GoogleSettingsWidget::GoogleSettingsWidget(GoogleSettings &settings, const QString &identifier, QWidget *parent) 0030 : QWidget(parent) 0031 , m_settings(settings) 0032 , m_identifier(identifier) 0033 { 0034 auto mainLayout = new QVBoxLayout(this); 0035 0036 auto mainWidget = new QWidget(this); 0037 mainLayout->addWidget(mainWidget); 0038 setupUi(mainWidget); 0039 0040 refreshSpinBox->setSuffix(ki18np(" minute", " minutes")); 0041 enableRefresh->setChecked(m_settings.enableIntervalCheck()); 0042 refreshSpinBox->setEnabled(m_settings.enableIntervalCheck()); 0043 refreshSpinBox->setValue(m_settings.intervalCheckTime()); 0044 0045 eventsLimitCombo->setMaximumDate(QDate::currentDate()); 0046 eventsLimitCombo->setMinimumDate(QDate::fromString(QStringLiteral("2000-01-01"), Qt::ISODate)); 0047 eventsLimitCombo->setOptions(KDateComboBox::EditDate | KDateComboBox::SelectDate | KDateComboBox::DatePicker | KDateComboBox::WarnOnInvalid); 0048 if (m_settings.eventsSince().isEmpty()) { 0049 const QString ds = QStringLiteral("%1-01-01").arg(QString::number(QDate::currentDate().year() - 3)); 0050 eventsLimitCombo->setDate(QDate::fromString(ds, Qt::ISODate)); 0051 } else { 0052 eventsLimitCombo->setDate(QDate::fromString(m_settings.eventsSince(), Qt::ISODate)); 0053 } 0054 connect(reloadCalendarsBtn, &QPushButton::clicked, this, &GoogleSettingsWidget::slotReloadCalendars); 0055 connect(reloadTaskListsBtn, &QPushButton::clicked, this, &GoogleSettingsWidget::slotReloadTaskLists); 0056 connect(configureBtn, &QPushButton::clicked, this, &GoogleSettingsWidget::loadSettings); 0057 if (m_settings.isReady()) { 0058 m_account = m_settings.accountPtr(); 0059 } 0060 connect(&m_settings, &GoogleSettings::accountReady, this, [this](bool ready) { 0061 if (ready) { 0062 m_account = m_settings.accountPtr(); 0063 accountChanged(); 0064 } 0065 }); 0066 QMetaObject::invokeMethod(this, &GoogleSettingsWidget::accountChanged, Qt::QueuedConnection); 0067 } 0068 0069 GoogleSettingsWidget::~GoogleSettingsWidget() 0070 { 0071 } 0072 0073 bool GoogleSettingsWidget::handleError(KGAPI2::Job *job) 0074 { 0075 if ((job->error() == KGAPI2::NoError) || (job->error() == KGAPI2::OK)) { 0076 return true; 0077 } 0078 0079 if (job->error() == KGAPI2::Unauthorized) { 0080 qWarning() << job << job->errorString(); 0081 const QList<QUrl> resourceScopes = googleScopes(); 0082 for (const QUrl &scope : resourceScopes) { 0083 if (!m_account->scopes().contains(scope)) { 0084 m_account->addScope(scope); 0085 } 0086 } 0087 0088 auto authJob = new AuthJob(m_account, m_settings.clientId(), m_settings.clientSecret(), this); 0089 authJob->setProperty(JOB_PROPERTY, QVariant::fromValue(job)); 0090 connect(authJob, &AuthJob::finished, this, &GoogleSettingsWidget::slotAuthJobFinished); 0091 0092 return false; 0093 } 0094 0095 KMessageBox::error(this, job->errorString()); 0096 return false; 0097 } 0098 0099 void GoogleSettingsWidget::accountChanged() 0100 { 0101 if (!m_account) { 0102 accountLabel->setText(i18n("<b>Not configured</b>")); 0103 calendarsList->setDisabled(true); 0104 reloadCalendarsBtn->setDisabled(true); 0105 calendarsList->clear(); 0106 taskListsList->setDisabled(true); 0107 reloadTaskListsBtn->setDisabled(true); 0108 taskListsList->clear(); 0109 return; 0110 } 0111 accountLabel->setText(QStringLiteral("<b>%1</b>").arg(m_account->accountName())); 0112 slotReloadCalendars(); 0113 slotReloadTaskLists(); 0114 } 0115 0116 void GoogleSettingsWidget::loadSettings() 0117 { 0118 const QString username = m_account && !m_account->accountName().isEmpty() ? m_account->accountName() : QString(); 0119 m_account = AccountPtr(new Account()); 0120 const QList<QUrl> resourceScopes = googleScopes(); 0121 for (const QUrl &scope : resourceScopes) { 0122 if (!m_account->scopes().contains(scope)) { 0123 m_account->addScope(scope); 0124 } 0125 } 0126 auto authJob = new AuthJob(m_account, m_settings.clientId(), m_settings.clientSecret()); 0127 authJob->setUsername(username); 0128 connect(authJob, &AuthJob::finished, this, &GoogleSettingsWidget::slotAuthJobFinished); 0129 } 0130 0131 void GoogleSettingsWidget::slotAuthJobFinished(KGAPI2::Job *job) 0132 { 0133 auto authJob = qobject_cast<AuthJob *>(job); 0134 m_account = authJob->account(); 0135 if (authJob->error() != KGAPI2::NoError) { 0136 KMessageBox::error(this, authJob->errorString()); 0137 return; 0138 } 0139 accountChanged(); 0140 0141 auto otherJob = job->property(JOB_PROPERTY).value<KGAPI2::Job *>(); 0142 if (otherJob) { 0143 otherJob->setAccount(m_account); 0144 otherJob->restart(); 0145 } 0146 } 0147 0148 void GoogleSettingsWidget::saveSettings() 0149 { 0150 auto reset = [this] { 0151 m_settings.setAccount({}); 0152 m_settings.setEnableIntervalCheck(enableRefresh->isChecked()); 0153 m_settings.setIntervalCheckTime(refreshSpinBox->value()); 0154 m_settings.setCalendars({}); 0155 m_settings.setTaskLists({}); 0156 m_settings.setEventsSince({}); 0157 m_settings.save(); 0158 }; 0159 0160 if (!m_account) { 0161 reset(); 0162 return; 0163 } 0164 0165 auto writeJob = m_settings.storeAccount(m_account); 0166 connect(writeJob, &WritePasswordJob::finished, this, [this, reset, writeJob]() { 0167 if (writeJob->error()) { 0168 qCWarning(GOOGLE_LOG) << "Failed to store account's password in secret storage" << writeJob->errorString(); 0169 reset(); 0170 return; 0171 } 0172 0173 m_settings.setAccount(m_account->accountName()); 0174 m_settings.setEnableIntervalCheck(enableRefresh->isChecked()); 0175 m_settings.setIntervalCheckTime(refreshSpinBox->value()); 0176 0177 QStringList calendars; 0178 for (int i = 0; i < calendarsList->count(); i++) { 0179 QListWidgetItem *item = calendarsList->item(i); 0180 0181 if (item->checkState() == Qt::Checked) { 0182 calendars.append(item->data(Qt::UserRole).toString()); 0183 } 0184 } 0185 m_settings.setCalendars(calendars); 0186 0187 if (eventsLimitCombo->isValid()) { 0188 m_settings.setEventsSince(eventsLimitCombo->date().toString(Qt::ISODate)); 0189 } 0190 0191 QStringList taskLists; 0192 for (int i = 0; i < taskListsList->count(); i++) { 0193 QListWidgetItem *item = taskListsList->item(i); 0194 0195 if (item->checkState() == Qt::Checked) { 0196 taskLists.append(item->data(Qt::UserRole).toString()); 0197 } 0198 } 0199 m_settings.setTaskLists(taskLists); 0200 m_settings.save(); 0201 }); 0202 0203 // Ideally we should have an async API 0204 // This ensure the config dialog is not destroyed before the password 0205 // is saved; 0206 QEventLoop loop; 0207 connect(writeJob, &QKeychain::Job::finished, &loop, &QEventLoop::quit); 0208 writeJob->start(); 0209 loop.exec(); 0210 } 0211 0212 void GoogleSettingsWidget::slotReloadCalendars() 0213 { 0214 calendarsList->setDisabled(true); 0215 reloadCalendarsBtn->setDisabled(true); 0216 calendarsList->clear(); 0217 0218 if (!m_account) { 0219 return; 0220 } 0221 0222 auto fetchJob = new CalendarFetchJob(m_account, this); 0223 connect(fetchJob, &CalendarFetchJob::finished, this, [this](KGAPI2::Job *job) { 0224 if (!handleError(job) || !m_account) { 0225 calendarsList->setEnabled(false); 0226 reloadCalendarsBtn->setEnabled(false); 0227 return; 0228 } 0229 0230 const ObjectsList objects = qobject_cast<FetchJob *>(job)->items(); 0231 0232 QStringList activeCalendars; 0233 if (m_account->accountName() == m_settings.account()) { 0234 activeCalendars = m_settings.calendars(); 0235 } 0236 calendarsList->clear(); 0237 for (const ObjectPtr &object : objects) { 0238 const CalendarPtr calendar = object.dynamicCast<Calendar>(); 0239 0240 auto item = new QListWidgetItem(calendar->title()); 0241 item->setData(Qt::UserRole, calendar->uid()); 0242 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable); 0243 item->setCheckState((activeCalendars.isEmpty() || activeCalendars.contains(calendar->uid())) ? Qt::Checked : Qt::Unchecked); 0244 calendarsList->addItem(item); 0245 } 0246 0247 calendarsList->setEnabled(true); 0248 reloadCalendarsBtn->setEnabled(true); 0249 }); 0250 } 0251 0252 void GoogleSettingsWidget::slotReloadTaskLists() 0253 { 0254 if (!m_account) { 0255 return; 0256 } 0257 0258 taskListsList->setDisabled(true); 0259 reloadTaskListsBtn->setDisabled(true); 0260 taskListsList->clear(); 0261 0262 auto job = new TaskListFetchJob(m_account, this); 0263 connect(job, &TaskListFetchJob::finished, this, [this](KGAPI2::Job *job) { 0264 if (!handleError(job) || !m_account) { 0265 taskListsList->setDisabled(true); 0266 reloadTaskListsBtn->setDisabled(true); 0267 return; 0268 } 0269 0270 const ObjectsList objects = qobject_cast<FetchJob *>(job)->items(); 0271 0272 QStringList activeTaskLists; 0273 if (m_account->accountName() == m_settings.account()) { 0274 activeTaskLists = m_settings.taskLists(); 0275 } 0276 taskListsList->clear(); 0277 for (const ObjectPtr &object : objects) { 0278 const TaskListPtr taskList = object.dynamicCast<TaskList>(); 0279 0280 auto item = new QListWidgetItem(taskList->title()); 0281 item->setData(Qt::UserRole, taskList->uid()); 0282 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable); 0283 item->setCheckState((activeTaskLists.isEmpty() || activeTaskLists.contains(taskList->uid())) ? Qt::Checked : Qt::Unchecked); 0284 taskListsList->addItem(item); 0285 } 0286 0287 taskListsList->setEnabled(true); 0288 reloadTaskListsBtn->setEnabled(true); 0289 }); 0290 } 0291 0292 #include "moc_googlesettingswidget.cpp"