[pim/kdepim-runtime] resources/dav/resource: dav: make it so items are retrieved during single collection sync
Noham Devillers <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit 338732531eedf093898d6fb660ea8028389b4f84 by Noham Devillers.
Committed on 22/07/2026 at 09:57.
Pushed by ndevillers into branch 'master'.
dav: make it so items are retrieved during single collection sync
M +73 -92 resources/dav/resource/davgroupwareresource.cpp
M +4 -0 resources/dav/resource/davgroupwareresource.h
https://invent.kde.org/pim/kdepim-runtime/-/commit/338732531eedf093898d6fb660ea8028389b4f84
diff --git a/resources/dav/resource/davgroupwareresource.cpp b/resources/dav/resource/davgroupwareresource.cpp
index 80f53cc2a..df5e69684 100644
--- a/resources/dav/resource/davgroupwareresource.cpp
+++ b/resources/dav/resource/davgroupwareresource.cpp
@@ -384,36 +384,38 @@ void DavGroupwareResource::retrieveItems(const Akonadi::Collection &collection)
return;
}
- // Only continue if the collection has changed or if
- // it's the first time we see it
- const auto CTagAttr = collection.attribute<CTagAttribute>();
- if (CTagAttr && mCTagCache.contains(collection.remoteId()) && mCTagCache.value(collection.remoteId()) == CTagAttr->CTag()) {
- qCDebug(DAVRESOURCE_LOG) << "CTag for collection" << collection.remoteId() << "didn't change: " << CTagAttr->CTag();
- itemsRetrievalDone();
- return;
- }
-
const KDAV::DavUrl davUrl = settings()->davUrlFromCollectionUrl(collection.remoteId());
if (!davUrl.url().isValid()) {
+ mRetrievedCollections.remove(collection.remoteId());
qCCritical(DAVRESOURCE_LOG) << "Can't find a configured URL, collection.remoteId() is " << collection.remoteId();
cancelTask(i18n("Asked to retrieve items for an unknown collection: %1", collection.remoteId()));
// Q_ASSERT_X( false, "DavGroupwareResource::retrieveItems", "Url is invalid" );
return;
}
- auto job = new KDAV::DavItemsListJob(davUrl, mDavItemCache.value(collection.remoteId())->eTagCache());
- if (settings()->limitSyncRange()) {
- QDateTime start = settings()->getSyncRangeStart();
- qCDebug(DAVRESOURCE_LOG) << "Start time for list job:" << start;
- if (start.isValid()) {
- job->setTimeRange(start.toString(QStringLiteral("yyyyMMddTHHMMssZ")), QString());
- }
+ // If the collection is not in the retrieved cache, we are in the case of a single collection sync
+ // In that case, we fetch the collection to update its attributes before fetching its items
+ if (!mRetrievedCollections.contains(collection.remoteId())) {
+ auto fetchJob = new KDAV::DavCollectionsFetchJob(davUrl);
+ connect(fetchJob, &KDAV::DavCollectionsFetchJob::result, this, &DavGroupwareResource::onRetrieveCollectionFinished);
+ fetchJob->start();
+ return;
}
- job->setProperty("collection", QVariant::fromValue(collection));
- job->setContentMimeTypes(collection.contentMimeTypes());
- connect(job, &KDAV::DavItemsListJob::result, this, &DavGroupwareResource::onRetrieveItemsFinished);
- job->start();
+
+ // Case of a collection retrieved from onRetrieveCollectionFinished
+ mRetrievedCollections.remove(collection.remoteId());
+
+ // Only continue if the collection has changed or if
+ // it's the first time we see it
+ const auto CTagAttr = collection.attribute<CTagAttribute>();
+ if (CTagAttr && mCTagCache.contains(collection.remoteId()) && mCTagCache.value(collection.remoteId()) == CTagAttr->CTag()) {
+ qCDebug(DAVRESOURCE_LOG) << "CTag for collection" << collection.remoteId() << "didn't change: " << CTagAttr->CTag();
+ itemsRetrievalDone();
+ return;
+ }
+
+ listItemsForCollection(davUrl, collection);
}
bool DavGroupwareResource::retrieveItem(const Akonadi::Item &item, const QSet<QByteArray> &)
@@ -1125,6 +1127,53 @@ void DavGroupwareResource::onCollectionRemovedFinished(KJob *job)
changeProcessed();
}
+void DavGroupwareResource::onRetrieveCollectionFinished(KJob *job)
+{
+ const KDAV::DavCollectionsFetchJob *fetchJob = qobject_cast<KDAV::DavCollectionsFetchJob *>(job);
+
+ if (job->error()) {
+ qCWarning(DAVRESOURCE_LOG) << "Unable to fetch collections" << job->error() << job->errorText();
+ cancelTask(i18n("Unable to retrieve collections: %1", job->errorText()));
+ mSyncErrorNotified = true;
+ return;
+ }
+
+ const KDAV::DavCollection::List davCollections = fetchJob->collections();
+ auto davUrl = fetchJob->davUrl().url();
+ // Even when providing the url of the collection we want to fetch to the DavCollectionsFetchJob, other collections (at least the parent and siblings
+ // collections) appear in the results.
+ // While waiting for this problem to be investigated, we filter to only change the attributes of the collection we want to synchronize.
+ auto davCollection = std::find_if(davCollections.begin(), davCollections.end(), [davUrl](const KDAV::DavCollection &davCollection) {
+ return davCollection.url().url() == davUrl;
+ });
+ if (davCollection == davCollections.end()) {
+ qCWarning(DAVRESOURCE_LOG) << "None of the retrieved collections correspond to the collection we wanted to retrieve";
+ cancelTask(i18n("Failed to retrieve collection: %1", davUrl.toDisplayString()));
+ mSyncErrorNotified = true;
+ return;
+ }
+ auto collection = Utils::createAkonadiCollection(*davCollection, mDavCollectionRoot);
+ DavGroupwareResource::setCollectionIcon(collection /*by-ref*/);
+
+ auto shouldRetrieveItems = true;
+ // the value of the CTag will be updated in the collection in onRetrieveItemsFinished
+ // for now, we only update the cache
+ if (!davCollection->CTag().isEmpty()) {
+ shouldRetrieveItems =
+ !mCTagCache.contains(davCollection->url().toDisplayString()) || mCTagCache.value(davCollection->url().toDisplayString()) != davCollection->CTag();
+ mCTagCache.insert(davCollection->url().toDisplayString(), davCollection->CTag());
+ }
+
+ auto modifyJob = new Akonadi::CollectionModifyJob(collection);
+ modifyJob->start();
+
+ if (shouldRetrieveItems) {
+ listItemsForCollection(davCollection->url(), collection);
+ } else {
+ taskDone();
+ }
+}
+
void DavGroupwareResource::onRetrieveCollectionsFinished(KJob *job)
{
const KDAV::DavCollectionsMultiFetchJob *fetchJob = qobject_cast<KDAV::DavCollectionsMultiFetchJob *>(job);
@@ -1139,6 +1188,7 @@ void DavGroupwareResource::onRetrieveCollectionsFinished(KJob *job)
bool initialCacheSync = job->property("initialCacheSync").toBool();
Akonadi::Collection::List collections{mDavCollectionRoot};
QSet<QString> seenCollectionsUrls;
+ mRetrievedCollections.clear();
const KDAV::DavCollection::List davCollections = fetchJob->collections();
@@ -1151,54 +1201,10 @@ void DavGroupwareResource::onRetrieveCollectionsFinished(KJob *job)
seenCollectionsUrls.insert(davCollection.url().toDisplayString());
}
- Akonadi::Collection collection;
- collection.setParentCollection(mDavCollectionRoot);
- collection.setRemoteId(davCollection.url().toDisplayString());
- collection.setName(collection.remoteId());
-
- if (davCollection.color().isValid()) {
- auto colorAttr = collection.attribute<CollectionColorAttribute>(Akonadi::Collection::AddIfMissing);
- colorAttr->setColor(davCollection.color());
- }
-
- if (!davCollection.displayName().isEmpty()) {
- auto attr = collection.attribute<EntityDisplayAttribute>(Collection::AddIfMissing);
- attr->setDisplayName(davCollection.displayName());
- }
-
- QStringList mimeTypes;
- mimeTypes << Collection::mimeType();
-
- const KDAV::DavCollection::ContentTypes contentTypes = davCollection.contentTypes();
- if (contentTypes & KDAV::DavCollection::Calendar) {
- mimeTypes << QStringLiteral("text/calendar");
- }
-
- if (contentTypes & KDAV::DavCollection::Events) {
- mimeTypes << KCalendarCore::Event::eventMimeType();
- }
-
- if (contentTypes & KDAV::DavCollection::Todos) {
- mimeTypes << KCalendarCore::Todo::todoMimeType();
- }
-
- if (contentTypes & KDAV::DavCollection::Contacts) {
- mimeTypes << KContacts::Addressee::mimeType();
- }
-
- if (contentTypes & KDAV::DavCollection::FreeBusy) {
- mimeTypes << KCalendarCore::FreeBusy::freeBusyMimeType();
- }
-
- if (contentTypes & KDAV::DavCollection::Journal) {
- mimeTypes << KCalendarCore::Journal::journalMimeType();
- }
+ mRetrievedCollections.insert(davCollection.url().toDisplayString());
- collection.setContentMimeTypes(mimeTypes);
- setCollectionIcon(collection /*by-ref*/);
-
- auto protoAttr = collection.attribute<DavProtocolAttribute>(Collection::AddIfMissing);
- protoAttr->setDavProtocol(davCollection.url().protocol());
+ auto collection = Utils::createAkonadiCollection(davCollection, mDavCollectionRoot);
+ DavGroupwareResource::setCollectionIcon(collection /*by-ref*/);
/*
* We unfortunately have to update the CTag now in the cache
@@ -1210,31 +1216,6 @@ void DavGroupwareResource::onRetrieveCollectionsFinished(KJob *job)
mCTagCache.insert(davCollection.url().toDisplayString(), davCollection.CTag());
}
- KDAV::Privileges privileges = davCollection.privileges();
- Akonadi::Collection::Rights rights;
-
- if (privileges & KDAV::All || privileges & KDAV::Write) {
- rights |= Akonadi::Collection::AllRights;
- }
-
- if (privileges & KDAV::WriteContent) {
- rights |= Akonadi::Collection::CanChangeItem;
- }
-
- if (privileges & KDAV::Bind) {
- rights |= Akonadi::Collection::CanCreateItem;
- }
-
- if (privileges & KDAV::Unbind) {
- rights |= Akonadi::Collection::CanDeleteItem;
- }
-
- if (privileges == KDAV::Read) {
- rights |= Akonadi::Collection::ReadOnly;
- }
-
- rights.setFlag(Akonadi::Collection::CanCreateCollection, false);
- collection.setRights(rights);
collections << collection;
if (!mDavItemCache.contains(collection.remoteId())) {
diff --git a/resources/dav/resource/davgroupwareresource.h b/resources/dav/resource/davgroupwareresource.h
index 52b654303..48cff968c 100644
--- a/resources/dav/resource/davgroupwareresource.h
+++ b/resources/dav/resource/davgroupwareresource.h
@@ -12,6 +12,7 @@
#include <Akonadi/AccountBase>
#include <Akonadi/FreeBusyProviderBase>
#include <Akonadi/ResourceBase>
+#include <KDAV/DavCollection>
class DavItemCache;
class DavFreeBusyHandler;
@@ -87,6 +88,7 @@ private:
void onHandlesFreeBusy(const QString &email, bool handles);
void onFreeBusyRetrieved(const QString &email, const QString &freeBusy, bool success, const QString &errorText);
+ void onRetrieveCollectionFinished(KJob *job);
void onRetrieveCollectionsFinished(KJob *);
void onRetrieveItemsFinished(KJob *);
void onMultigetFinished(KJob *);
@@ -142,6 +144,8 @@ private:
Akonadi::Collection mDavCollectionRoot;
QMap<QString, std::shared_ptr<DavItemCache>> mDavItemCache;
QMap<QString, QString> mCTagCache;
+ // collections retrieved by retrieveCollections that have yet to get their items retrieved in retrieveItems
+ QSet<QString> mRetrievedCollections;
DavFreeBusyHandler *const mFreeBusyHandler;
bool mSyncErrorNotified = false;
mutable Settings *mSettings = nullptr;