diff --git a/resources/google-new/calendarhandler.cpp b/resources/google-new/calendarhandler.cpp index 9ae373c5c..eb254ef08 100644 --- a/resources/google-new/calendarhandler.cpp +++ b/resources/google-new/calendarhandler.cpp @@ -1,378 +1,377 @@ /* Copyright (C) 2011-2013 Daniel Vrátil 2020 Igor Poboiko This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "calendarhandler.h" #include "defaultreminderattribute.h" #include "googleresource.h" #include "googlesettings.h" #include "kgapiversionattribute.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "googleresource_debug.h" using namespace KGAPI2; using namespace Akonadi; static constexpr uint32_t KGAPIEventVersion = 1; QString CalendarHandler::mimetype() { return KCalendarCore::Event::eventMimeType(); } bool CalendarHandler::canPerformTask(const Akonadi::Item &item) { return m_resource->canPerformTask(item, mimetype()); } void CalendarHandler::retrieveCollections() { Q_EMIT status(AgentBase::Running, i18nc("@info:status", "Retrieving calendars")); qCDebug(GOOGLE_LOG) << "Retrieving calendars..."; auto job = new CalendarFetchJob(m_settings->accountPtr(), this); connect(job, &KGAPI2::Job::finished, this, &CalendarHandler::slotCollectionsRetrieved); } void CalendarHandler::slotCollectionsRetrieved(KGAPI2::Job* job) { if (!m_resource->handleError(job)) { return; } qCDebug(GOOGLE_LOG) << "Calendars retrieved"; const ObjectsList calendars = qobject_cast(job)->items(); Collection::List collections; const QStringList activeCalendars = m_settings->calendars(); for (const auto &object : calendars) { const CalendarPtr &calendar = object.dynamicCast(); qCDebug(GOOGLE_LOG) << "Retrieved calendar:" << calendar->title() << "(" << calendar->uid() << ")"; if (!activeCalendars.contains(calendar->uid())) { continue; } Collection collection; collection.setContentMimeTypes(QStringList() << mimetype()); collection.setName(calendar->uid()); collection.setParentCollection(m_resource->rootCollection()); collection.setRemoteId(calendar->uid()); if (calendar->editable()) { collection.setRights(Collection::CanChangeCollection |Collection::CanCreateItem |Collection::CanChangeItem |Collection::CanDeleteItem); } else { collection.setRights(Collection::ReadOnly); } EntityDisplayAttribute *attr = collection.attribute(Collection::AddIfMissing); attr->setDisplayName(calendar->title()); attr->setIconName(QStringLiteral("view-calendar")); auto colorAttr = collection.attribute(Collection::AddIfMissing); colorAttr->setColor(calendar->backgroundColor()); DefaultReminderAttribute *reminderAttr = collection.attribute(Collection::AddIfMissing); reminderAttr->setReminders(calendar->defaultReminders()); // Block email reminders, since Google sends them for us BlockAlarmsAttribute *blockAlarms = collection.attribute(Collection::AddIfMissing); blockAlarms->blockAlarmType(KCalendarCore::Alarm::Audio, false); blockAlarms->blockAlarmType(KCalendarCore::Alarm::Display, false); blockAlarms->blockAlarmType(KCalendarCore::Alarm::Procedure, false); collections << collection; } Q_EMIT collectionsRetrieved(collections); } void CalendarHandler::retrieveItems(const Collection &collection) { qCDebug(GOOGLE_LOG) << "Retrieving events for calendar" << collection.remoteId(); // https://bugs.kde.org/show_bug.cgi?id=308122: we can only request changes in // max. last 25 days, otherwise we get an error. int lastSyncDelta = -1; if (!collection.remoteRevision().isEmpty()) { lastSyncDelta = QDateTime::currentDateTimeUtc().toSecsSinceEpoch() - collection.remoteRevision().toULongLong(); } if (!collection.hasAttribute() || collection.attribute()->version() != KGAPIEventVersion) { lastSyncDelta = -1; } auto job = new EventFetchJob(collection.remoteId(), m_settings->accountPtr(), this); if (lastSyncDelta > -1 && lastSyncDelta < 25 * 24 * 3600) { job->setFetchOnlyUpdated(collection.remoteRevision().toULongLong()); } if (!m_settings->eventsSince().isEmpty()) { const QDate date = QDate::fromString(m_settings->eventsSince(), Qt::ISODate); #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) job->setTimeMin(QDateTime(date).toSecsSinceEpoch()); #else job->setTimeMin(QDateTime(date.startOfDay()).toSecsSinceEpoch()); #endif } job->setProperty(COLLECTION_PROPERTY, QVariant::fromValue(collection)); connect(job, &KGAPI2::Job::finished, this, &CalendarHandler::slotItemsRetrieved); Q_EMIT status(AgentBase::Running, i18nc("@info:status", "Retrieving events for calendar '%1'", collection.displayName())); } void CalendarHandler::slotItemsRetrieved(KGAPI2::Job *job) { if (!m_resource->handleError(job)) { return; } Item::List changedItems, removedItems; Collection collection = job->property(COLLECTION_PROPERTY).value(); DefaultReminderAttribute *attr = collection.attribute(); auto fetchJob = qobject_cast(job); const ObjectsList objects = fetchJob->items(); bool isIncremental = (fetchJob->fetchOnlyUpdated() > 0); qCDebug(GOOGLE_LOG) << "Retrieved" << objects.count() << "events for calendar" << collection.remoteId(); for (const ObjectPtr &object : objects) { const EventPtr event = object.dynamicCast(); if (event->useDefaultReminders() && attr) { const KCalendarCore::Alarm::List alarms = attr->alarms(event.data()); for (const KCalendarCore::Alarm::Ptr &alarm : alarms) { event->addAlarm(alarm); } } Item item; item.setMimeType(KCalendarCore::Event::eventMimeType()); item.setParentCollection(collection); item.setRemoteId(event->id()); item.setRemoteRevision(event->etag()); item.setPayload(event.dynamicCast()); if (event->deleted()) { qCDebug(GOOGLE_LOG) << " - removed" << event->uid(); removedItems << item; } else { qCDebug(GOOGLE_LOG) << " - changed" << event->uid(); changedItems << item; } } if (!isIncremental) { collection.attribute(Collection::AddIfMissing)->setVersion(KGAPIEventVersion); m_resource->itemsRetrieved(changedItems); } else { m_resource->itemsRetrievedIncremental(changedItems, removedItems); } const QDateTime local(QDateTime::currentDateTime()); const QDateTime UTC(local.toUTC()); collection.setRemoteRevision(QString::number(UTC.toSecsSinceEpoch())); new CollectionModifyJob(collection, this); emitReadyStatus(); } void CalendarHandler::itemAdded(const Item &item, const Collection &collection) { Q_EMIT status(AgentBase::Running, i18nc("@info:status", "Adding event to calendar '%1'", collection.name())); qCDebug(GOOGLE_LOG) << "Event added to calendar" << collection.remoteId(); KCalendarCore::Event::Ptr event = item.payload(); EventPtr kevent(new Event(*event)); auto *job = new EventCreateJob(kevent, collection.remoteId(), m_settings->accountPtr(), this); job->setSendUpdates(SendUpdatesPolicy::None); job->setProperty(ITEM_PROPERTY, QVariant::fromValue(item)); connect(job, &KGAPI2::Job::finished, this, &CalendarHandler::slotCreateJobFinished); } void CalendarHandler::slotCreateJobFinished(KGAPI2::Job* job) { if (!m_resource->handleError(job)) { return; } Item item = job->property(ITEM_PROPERTY).value(); ObjectsList objects = qobject_cast(job)->items(); Q_ASSERT(objects.count() > 0); EventPtr event = objects.first().dynamicCast(); qCDebug(GOOGLE_LOG) << "Event added"; item.setRemoteId(event->id()); item.setRemoteRevision(event->etag()); item.setGid(event->uid()); m_resource->changeCommitted(item); item.setPayload(event.dynamicCast()); new ItemModifyJob(item, this); emitReadyStatus(); } void CalendarHandler::itemChanged(const Item &item, const QSet< QByteArray > &partIdentifiers) { Q_UNUSED(partIdentifiers); Q_EMIT status(AgentBase::Running, i18nc("@info:status", "Changing event in calendar '%1'", item.parentCollection().displayName())); qCDebug(GOOGLE_LOG) << "Changing event" << item.remoteId(); KCalendarCore::Event::Ptr event = item.payload(); EventPtr kevent(new Event(*event)); auto job = new EventModifyJob(kevent, item.parentCollection().remoteId(), m_settings->accountPtr(), this); job->setSendUpdates(SendUpdatesPolicy::None); job->setProperty(ITEM_PROPERTY, QVariant::fromValue(item)); connect(job, &EventModifyJob::finished, m_resource, &GoogleResource::slotGenericJobFinished); } void CalendarHandler::itemRemoved(const Item &item) { Q_EMIT status(AgentBase::Running, i18nc("@info:status", "Removing event from calendar '%1'", item.parentCollection().displayName())); qCDebug(GOOGLE_LOG) << "Removing event" << item.remoteId(); KGAPI2::Job *job = new EventDeleteJob(item.remoteId(), item.parentCollection().remoteId(), m_settings->accountPtr(), this); job->setProperty(ITEM_PROPERTY, QVariant::fromValue(item)); connect(job, &EventDeleteJob::finished, m_resource, &GoogleResource::slotGenericJobFinished); } void CalendarHandler::itemMoved(const Item &item, const Collection &collectionSource, const Collection &collectionDestination) { + Q_EMIT status(AgentBase::Running, i18nc("@info:status", "Moving event from calendar '%1' to calendar '%2'", collectionSource.displayName(), collectionDestination.displayName())); qCDebug(GOOGLE_LOG) << "Moving" << item.remoteId() << "from" << collectionSource.remoteId() << "to" << collectionDestination.remoteId(); KGAPI2::Job *job = new EventMoveJob(item.remoteId(), collectionSource.remoteId(), collectionDestination.remoteId(), m_settings->accountPtr(), this); job->setProperty(ITEM_PROPERTY, QVariant::fromValue(item)); connect(job, &EventMoveJob::finished, m_resource, &GoogleResource::slotGenericJobFinished); - - Q_EMIT status(AgentBase::Running, i18nc("@info:status", "Moving event from calendar '%1' to calendar '%2'", collectionSource.displayName(), collectionDestination.displayName())); } void CalendarHandler::collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent) { Q_UNUSED(parent); Q_EMIT status(AgentBase::Running, i18nc("@info:status", "Creating calendar '%1'", collection.displayName())); qCDebug(GOOGLE_LOG) << "Adding calendar" << collection.displayName(); CalendarPtr calendar(new Calendar()); calendar->setTitle(collection.displayName()); calendar->setEditable(true); auto job = new CalendarCreateJob(calendar, m_settings->accountPtr(), this); job->setProperty(COLLECTION_PROPERTY, QVariant::fromValue(collection)); connect(job, &KGAPI2::Job::finished, m_resource, &GoogleResource::slotGenericJobFinished); } void CalendarHandler::collectionChanged(const Akonadi::Collection &collection) { Q_EMIT status(AgentBase::Running, i18nc("@info:status", "Changing calendar '%1'", collection.displayName())); qCDebug(GOOGLE_LOG) << "Changing calendar" << collection.remoteId(); CalendarPtr calendar(new Calendar()); calendar->setUid(collection.remoteId()); calendar->setTitle(collection.displayName()); calendar->setEditable(true); auto job = new CalendarModifyJob(calendar, m_settings->accountPtr(), this); job->setProperty(COLLECTION_PROPERTY, QVariant::fromValue(collection)); connect(job, &KGAPI2::Job::finished, m_resource, &GoogleResource::slotGenericJobFinished); } void CalendarHandler::collectionRemoved(const Akonadi::Collection &collection) { Q_EMIT status(AgentBase::Running, i18nc("@info:status", "Removing calendar '%1'", collection.displayName())); qCDebug(GOOGLE_LOG) << "Removing calendar" << collection.remoteId(); auto job = new CalendarDeleteJob(collection.remoteId(), m_settings->accountPtr(), this); job->setProperty(COLLECTION_PROPERTY, QVariant::fromValue(collection)); connect(job, &KGAPI2::Job::finished, m_resource, &GoogleResource::slotGenericJobFinished); } QDateTime CalendarHandler::lastCacheUpdate() const { return QDateTime(); } void CalendarHandler::canHandleFreeBusy(const QString &email) const { if (m_resource->canPerformTask()) { m_resource->handlesFreeBusy(email, false); return; } auto job = new FreeBusyQueryJob(email, QDateTime::currentDateTimeUtc(), QDateTime::currentDateTimeUtc().addSecs(3600), m_settings->accountPtr(), const_cast(this)); connect(job, &KGAPI2::Job::finished, [this](KGAPI2::Job *job){ auto queryJob = qobject_cast(job); if (!m_resource->handleError(job, false)) { m_resource->handlesFreeBusy(queryJob->id(), false); return; } m_resource->handlesFreeBusy(queryJob->id(), true); }); } void CalendarHandler::retrieveFreeBusy(const QString &email, const QDateTime &start, const QDateTime &end) { if (m_resource->canPerformTask()) { m_resource->freeBusyRetrieved(email, QString(), false, QString()); return; } auto job = new FreeBusyQueryJob(email, start, end, m_settings->accountPtr(), this); connect(job, &KGAPI2::Job::finished, [this](KGAPI2::Job *job) { auto queryJob = qobject_cast(job); if (!m_resource->handleError(job, false)) { m_resource->freeBusyRetrieved(queryJob->id(), QString(), false, QString()); return; } KCalendarCore::FreeBusy::Ptr fb(new KCalendarCore::FreeBusy); fb->setUid(QStringLiteral("%1%2@google.com").arg(QDateTime::currentDateTimeUtc().toString(QStringLiteral("yyyyMMddTHHmmssZ")))); fb->setOrganizer(job->account()->accountName()); fb->addAttendee(KCalendarCore::Attendee(QString(), queryJob->id())); // FIXME: is it really sort? fb->setDateTime(QDateTime::currentDateTimeUtc(), KCalendarCore::IncidenceBase::RoleSort); for (const auto range : queryJob->busy()) { fb->addPeriod(range.busyStart, range.busyEnd); } KCalendarCore::ICalFormat format; const QString fbStr = format.createScheduleMessage(fb, KCalendarCore::iTIPRequest); m_resource->freeBusyRetrieved(queryJob->id(), fbStr, true, QString()); }); } diff --git a/resources/google-new/googleresource.cpp b/resources/google-new/googleresource.cpp index 2c7fd78c8..d7b972b3f 100644 --- a/resources/google-new/googleresource.cpp +++ b/resources/google-new/googleresource.cpp @@ -1,566 +1,564 @@ /* Copyright (C) 2011-2013 Daniel Vrátil 2020 Igor Poboiko This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "googleresource.h" #include "googlesettings.h" #include "googlesettingsdialog.h" #include "googleresource_debug.h" #include "settingsadaptor.h" #include "calendarhandler.h" #include "contacthandler.h" #include "taskhandler.h" #include "defaultreminderattribute.h" #include "kgapiversionattribute.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define ACCESS_TOKEN_PROPERTY "AccessToken" #define CALENDARS_PROPERTY "_KGAPI2CalendarPtr" #define ROOT_COLLECTION_REMOTEID QStringLiteral("RootCollection") Q_DECLARE_METATYPE(KGAPI2::Job *) using namespace KGAPI2; using namespace Akonadi; GoogleResource::GoogleResource(const QString &id) : ResourceBase(id) , AgentBase::ObserverV2() { AttributeFactory::registerAttribute< DefaultReminderAttribute >(); AttributeFactory::registerAttribute< KGAPIVersionAttribute >(); connect(this, &GoogleResource::abortRequested, this, [this](){ cancelTask(i18n("Aborted")); }); connect(this, &GoogleResource::reloadConfiguration, this, &GoogleResource::reloadConfig); setNeedsNetwork(true); changeRecorder()->itemFetchScope().fetchFullPayload(true); changeRecorder()->itemFetchScope().setAncestorRetrieval(ItemFetchScope::All); changeRecorder()->fetchCollection(true); changeRecorder()->collectionFetchScope().setAncestorRetrieval(CollectionFetchScope::All); m_settings = new GoogleSettings(); m_settings->setWindowId(winIdForDialogs()); connect(m_settings, &GoogleSettings::accountReady, [this](bool ready){ if (accountId() > 0) { return; } if (!ready) { Q_EMIT status(Broken, i18n("Can't access KWallet")); return; } m_account = m_settings->accountPtr(); if (m_account.isNull()) { Q_EMIT status(NotConfigured); return; } Q_EMIT status(Idle, i18nc("@info:status", "Ready")); synchronize(); }); Q_EMIT status(NotConfigured, i18n("Waiting for KWallet...")); updateResourceName(); m_freeBusyHandler.reset(new CalendarHandler(this, m_settings)); m_handlers << m_freeBusyHandler; m_handlers << GenericHandler::Ptr(new ContactHandler(this, m_settings)); m_handlers << GenericHandler::Ptr(new TaskHandler(this, m_settings)); for (auto handler : m_handlers) { connect(handler.data(), &GenericHandler::status, [this](int code, QString message){ Q_EMIT status(code, message); }); connect(handler.data(), &GenericHandler::percent, [this](int value){ Q_EMIT percent(value); }); connect(handler.data(), &GenericHandler::collectionsRetrieved, this, &GoogleResource::collectionsPartiallyRetrieved); } new SettingsAdaptor(m_settings); QDBusConnection::sessionBus().registerObject(QStringLiteral("/Settings"), m_settings, QDBusConnection::ExportAdaptors); } GoogleResource::~GoogleResource() { } void GoogleResource::cleanup() { m_settings->cleanup(); ResourceBase::cleanup(); } AccountPtr GoogleResource::account() const { return m_account; } Akonadi::Collection GoogleResource::rootCollection() const { return m_rootCollection; } void GoogleResource::configure(WId windowId) { if (!m_settings->isReady() || m_isConfiguring) { Q_EMIT configurationDialogAccepted(); return; } m_isConfiguring = true; QScopedPointer settingsDialog(new GoogleSettingsDialog(this, m_settings, windowId)); settingsDialog->setWindowIcon(QIcon::fromTheme(QStringLiteral("im-google"))); if (settingsDialog->exec() == QDialog::Accepted) { updateResourceName(); Q_EMIT configurationDialogAccepted(); m_account = m_settings->accountPtr(); if (m_account.isNull()) { Q_EMIT status(NotConfigured, i18n("Configured account does not exist")); m_isConfiguring = false; return; } Q_EMIT status(Idle, i18nc("@info:status", "Ready")); synchronize(); } else { updateResourceName(); Q_EMIT configurationDialogRejected(); } m_isConfiguring = false; } QList GoogleResource::scopes() const { // TODO: determine it based on what user wants? const QList< QUrl > scopes = {Account::accountInfoScopeUrl(), Account::calendarScopeUrl(), Account::contactsScopeUrl(), Account::tasksScopeUrl()}; return scopes; } void GoogleResource::updateResourceName() { const QString accountName = m_settings->account(); setName(i18nc("%1 is account name (user@gmail.com)", "Google Groupware (%1)", accountName.isEmpty() ? i18n("not configured") : accountName)); } void GoogleResource::updateAccountToken(const AccountPtr &account, KGAPI2::Job *restartJob) { if (!m_settings->account().isEmpty()) { AuthJob *authJob = new AuthJob(account, m_settings->clientId(), m_settings->clientSecret(), this); authJob->setProperty(JOB_PROPERTY, QVariant::fromValue(restartJob)); connect(authJob, &AuthJob::finished, this, &GoogleResource::slotAuthJobFinished); } } void GoogleResource::reloadConfig() { m_account = m_settings->accountPtr(); if (m_account.isNull() || m_account->accountName().isEmpty()) { Q_EMIT status(NotConfigured, i18n("Configured account does not exist")); } else { Q_EMIT status(Idle, i18nc("@info:status", "Ready")); } } bool GoogleResource::handleError(KGAPI2::Job *job, bool _cancelTask) { if ((job->error() == KGAPI2::NoError) || (job->error() == KGAPI2::OK)) { return true; } qCDebug(GOOGLE_LOG) << job << job->errorString(); if (job->error() == KGAPI2::Unauthorized) { const QList resourceScopes = scopes(); for (const QUrl &scope : resourceScopes) { if (!m_account->scopes().contains(scope)) { m_account->addScope(scope); } } updateAccountToken(m_account, job); return false; } if (_cancelTask) { cancelTask(job->errorString()); } return false; } bool GoogleResource::canPerformTask() { if (!m_account && accountId() == 0) { cancelTask(i18nc("@info:status", "Resource is not configured")); Q_EMIT status(NotConfigured, i18nc("@info:status", "Resource is not configured")); return false; } return true; } void GoogleResource::slotAuthJobFinished(KGAPI2::Job *job) { if (job->error() != KGAPI2::NoError) { cancelTask(i18n("Failed to refresh tokens")); return; } AuthJob *authJob = qobject_cast(job); m_account = authJob->account(); if (!m_settings->storeAccount(m_account)) { qCWarning(GOOGLE_LOG) << "Failed to store account in KWallet"; } KGAPI2::Job *otherJob = job->property(JOB_PROPERTY).value(); if (otherJob) { otherJob->setAccount(m_account); otherJob->restart(); } } void GoogleResource::slotGenericJobFinished(KGAPI2::Job *job) { if (!handleError(job)) { return; } qCDebug(GOOGLE_LOG) << "Job finished"; const Item item = job->property(ITEM_PROPERTY).value(); const Collection collection = job->property(COLLECTION_PROPERTY).value(); if (item.isValid()) { changeCommitted(item); } else if (collection.isValid()) { changeCommitted(collection); } else { taskDone(); } Q_EMIT status(Idle, i18nc("@info:status", "Ready")); } int GoogleResource::accountId() const { return 0; } QDateTime GoogleResource::lastCacheUpdate() const { if (m_freeBusyHandler) { return m_freeBusyHandler->lastCacheUpdate(); } return QDateTime(); } void GoogleResource::canHandleFreeBusy(const QString &email) const { if (m_freeBusyHandler) { m_freeBusyHandler->canHandleFreeBusy(email); } else { handlesFreeBusy(email, false); } } void GoogleResource::retrieveFreeBusy(const QString &email, const QDateTime &start, const QDateTime &end) { if (m_freeBusyHandler) { m_freeBusyHandler->retrieveFreeBusy(email, start, end); } else { freeBusyRetrieved(email, QString(), false, QString()); } } /* * Collection handling */ void GoogleResource::retrieveCollections() { qCDebug(GOOGLE_LOG) << "Retrieve Collections"; if (!canPerformTask()) { return; } CachePolicy cachePolicy; if (m_settings->enableIntervalCheck()) { cachePolicy.setInheritFromParent(false); cachePolicy.setIntervalCheckTime(m_settings->intervalCheckTime()); } // Setting up root collection m_rootCollection = Collection(); m_rootCollection.setContentMimeTypes({ Collection::mimeType(), Collection::virtualMimeType() }); m_rootCollection.setRemoteId(ROOT_COLLECTION_REMOTEID); m_rootCollection.setName(account()->accountName()); m_rootCollection.setParentCollection(Collection::root()); m_rootCollection.setRights(Collection::CanCreateCollection); m_rootCollection.setCachePolicy(cachePolicy); EntityDisplayAttribute *attr = m_rootCollection.attribute(Collection::AddIfMissing); attr->setDisplayName(account()->accountName()); attr->setIconName(QStringLiteral("im-google")); m_collections = { m_rootCollection }; m_jobs = 0; for (auto handler : m_handlers) { handler->retrieveCollections(); m_jobs++; } } void GoogleResource::collectionsPartiallyRetrieved(const Collection::List& collections) { m_jobs--; m_collections << collections; if (m_jobs == 0) { qCDebug(GOOGLE_LOG) << "Collections retrieved!"; collectionsRetrieved(m_collections); } } void GoogleResource::retrieveItems(const Akonadi::Collection &collection) { if (!canPerformTask()) { return; } bool found = false; for (auto handler : m_handlers) { if (collection.contentMimeTypes().contains(handler->mimetype())) { handler->retrieveItems(collection); found = true; break; } } if (!found) { qCWarning(GOOGLE_LOG) << "Unknown collection" << collection.name(); itemsRetrieved({}); } } void GoogleResource::itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection) { if (!canPerformTask()) { return; } - if (collection.parentCollection() == Akonadi::Collection::root()) { - cancelTask(i18n("The top-level collection cannot contain anything")); - return; - } - bool found = false; for (auto handler : m_handlers) { if (collection.contentMimeTypes().contains(handler->mimetype()) && handler->canPerformTask(item)) { handler->itemAdded(item, collection); found = true; break; } } if (!found) { + qCWarning(GOOGLE_LOG) << "Could not add item" << item.mimeType(); cancelTask(i18n("Invalid payload type")); } } void GoogleResource::itemChanged(const Akonadi::Item &item, const QSet< QByteArray > &partIdentifiers) { Q_UNUSED(partIdentifiers); if (!canPerformTask()) { return; } bool found = false; for (auto handler : m_handlers) { if (handler->canPerformTask(item)) { handler->itemChanged(item, partIdentifiers); found = true; break; } } if (!found) { + qCWarning(GOOGLE_LOG) << "Could not change item" << item.mimeType(); cancelTask(i18n("Invalid payload type")); } } void GoogleResource::itemRemoved(const Akonadi::Item &item) { if (!canPerformTask()) { return; } bool found = false; for (auto handler : m_handlers) { if (item.mimeType() == handler->mimetype()) { handler->itemRemoved(item); found = true; break; } } if (!found) { + qCWarning(GOOGLE_LOG) << "Could not remove item" << item.mimeType(); cancelTask(i18n("Invalid payload type")); } } void GoogleResource::itemMoved(const Akonadi::Item &item, const Akonadi::Collection &collectionSource, const Akonadi::Collection &collectionDestination) { if (!canPerformTask()) { return; } - if (collectionDestination.parentCollection() == Akonadi::Collection::root()) { - cancelTask(i18n("The top-level collection cannot contain anything")); - return; - } - bool found = false; for (auto handler : m_handlers) { if (handler->canPerformTask(item)) { handler->itemMoved(item, collectionSource, collectionDestination); found = true; break; } } if (!found) { + qCWarning(GOOGLE_LOG) << "Could not move item" << item.mimeType() << "from" << collectionSource.remoteId() << "to" << collectionDestination.remoteId(); cancelTask(i18n("Invalid payload type")); } } void GoogleResource::itemLinked(const Akonadi::Item &item, const Akonadi::Collection &collection) { if (!canPerformTask()) { return; } bool found = false; for (auto handler : m_handlers) { if (handler->canPerformTask(item)) { handler->itemLinked(item, collection); found = true; break; } } if (!found) { + qCWarning(GOOGLE_LOG) << "Could not link item" << item.mimeType() << "to" << collection.remoteId(); cancelTask(i18n("Invalid payload type")); } } void GoogleResource::itemUnlinked(const Akonadi::Item &item, const Akonadi::Collection &collection) { if (!canPerformTask()) { return; } bool found = false; for (auto handler : m_handlers) { if (handler->canPerformTask(item)) { handler->itemUnlinked(item, collection); found = true; break; } } if (!found) { + qCWarning(GOOGLE_LOG) << "Could not unlink item mimetype" << item.mimeType() << "from" << collection.remoteId(); cancelTask(i18n("Invalid payload type")); } } void GoogleResource::collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent) { if (!canPerformTask()) { return; } - bool found = false; for (auto handler : m_handlers) { if (collection.contentMimeTypes().contains(handler->mimetype())) { - handler->retrieveItems(collection); + handler->collectionAdded(collection, parent); found = true; break; } } if (!found) { + qCWarning(GOOGLE_LOG) << "Could not add collection" << collection.displayName() << "mimetypes:" << collection.contentMimeTypes(); cancelTask(i18n("Unknown collection mimetype")); } } void GoogleResource::collectionChanged(const Akonadi::Collection &collection) { if (!canPerformTask()) { return; } bool found = false; for (auto handler : m_handlers) { if (collection.contentMimeTypes().contains(handler->mimetype())) { - handler->retrieveItems(collection); + handler->collectionChanged(collection); found = true; break; } } if (!found) { + qCWarning(GOOGLE_LOG) << "Could not change collection" << collection.displayName() << "mimetypes:" << collection.contentMimeTypes(); cancelTask(i18n("Unknown collection mimetype")); } } void GoogleResource::collectionRemoved(const Akonadi::Collection &collection) { if (!canPerformTask()) { return; } bool found = false; for (auto handler : m_handlers) { if (collection.contentMimeTypes().contains(handler->mimetype())) { - handler->retrieveItems(collection); + handler->collectionRemoved(collection); found = true; break; } } if (!found) { + qCWarning(GOOGLE_LOG) << "Could not remove collection" << collection.displayName() << "mimetypes:" << collection.contentMimeTypes(); cancelTask(i18n("Unknown collection mimetype")); } } AKONADI_RESOURCE_MAIN(GoogleResource)