File indexing completed on 2025-02-16 04:50:13

0001 /*
0002    SPDX-FileCopyrightText: 2023 Claudio Cambra <claudio.cambra@kde.org>
0003    SPDX-License-Identifier: GPL-3.0-or-later
0004 */
0005 
0006 #include "peopleconversionjob.h"
0007 
0008 #include <Akonadi/CollectionFetchJob>
0009 
0010 #include <KContacts/Addressee>
0011 
0012 #include <KGAPI/People/ContactGroupMembership>
0013 #include <KGAPI/People/Membership>
0014 
0015 #include "googlepeople_debug.h"
0016 
0017 using namespace Akonadi;
0018 using namespace KGAPI2;
0019 
0020 PeopleConversionJob::PeopleConversionJob(const Item::List &peopleItems, QObject *parent)
0021     : QObject(parent)
0022     , m_items(peopleItems)
0023 {
0024 }
0025 
0026 People::PersonList PeopleConversionJob::people() const
0027 {
0028     return m_processedPeople;
0029 }
0030 
0031 QString PeopleConversionJob::reparentCollectionRemoteId() const
0032 {
0033     return m_reparentCollectionRemoteId;
0034 }
0035 
0036 void PeopleConversionJob::setReparentCollectionRemoteId(const QString &reparentCollectionRemoteId)
0037 {
0038     if (reparentCollectionRemoteId == m_reparentCollectionRemoteId) {
0039         return;
0040     }
0041 
0042     m_reparentCollectionRemoteId = reparentCollectionRemoteId;
0043     Q_EMIT reparentCollectionRemoteIdChanged();
0044 }
0045 
0046 QString PeopleConversionJob::newLinkedCollectionRemoteId() const
0047 {
0048     return m_newLinkedCollectionRemoteId;
0049 }
0050 
0051 void PeopleConversionJob::setNewLinkedCollectionRemoteId(const QString &newLinkedCollectionRemoteId)
0052 {
0053     if (newLinkedCollectionRemoteId == m_newLinkedCollectionRemoteId) {
0054         return;
0055     }
0056 
0057     m_newLinkedCollectionRemoteId = newLinkedCollectionRemoteId;
0058     Q_EMIT newLinkedCollectionRemoteIdChanged();
0059 }
0060 
0061 QString PeopleConversionJob::linkedCollectionToRemoveRemoteId() const
0062 {
0063     return m_linkedCollectionToRemoveRemoteId;
0064 }
0065 
0066 void PeopleConversionJob::setLinkedCollectionToRemoveRemoteId(const QString &linkedCollectionToRemoveRemoteId)
0067 {
0068     if (linkedCollectionToRemoveRemoteId == m_linkedCollectionToRemoveRemoteId) {
0069         return;
0070     }
0071 
0072     m_linkedCollectionToRemoveRemoteId = linkedCollectionToRemoveRemoteId;
0073     Q_EMIT linkedCollectionToRemoveRemoteIdChanged();
0074 }
0075 
0076 void PeopleConversionJob::start()
0077 {
0078     if (m_items.isEmpty()) {
0079         qCDebug(GOOGLE_PEOPLE_LOG) << "No person items to process, finishing.";
0080         Q_EMIT finished();
0081         return;
0082     }
0083 
0084     m_processedPeople.clear();
0085 
0086     QSet<Collection::Id> collectionsToFetch;
0087     for (const auto &item : std::as_const(m_items)) {
0088         const auto itemVirtualReferences = item.virtualReferences();
0089         for (const auto &collection : itemVirtualReferences) {
0090             const auto collectionId = collection.id();
0091             qCDebug(GOOGLE_PEOPLE_LOG) << "Going to fetch data for virtual collection:" << collectionId;
0092             collectionsToFetch.insert(collectionId);
0093         };
0094     }
0095 
0096     if (collectionsToFetch.isEmpty()) {
0097         qCDebug(GOOGLE_PEOPLE_LOG) << "No virtual collections to fetch, processing people now.";
0098         processItems();
0099         return;
0100     }
0101 
0102     qCDebug(GOOGLE_PEOPLE_LOG) << "Going to fetch data for virtual collections now.";
0103     const QList<Collection::Id> idList(collectionsToFetch.cbegin(), collectionsToFetch.cend());
0104     auto collectionRetrievalJob = new CollectionFetchJob(idList);
0105     connect(collectionRetrievalJob, &CollectionFetchJob::finished, this, &PeopleConversionJob::jobFinished);
0106 }
0107 
0108 void PeopleConversionJob::jobFinished(KJob *job)
0109 {
0110     if (job->error()) {
0111         qCWarning(GOOGLE_PEOPLE_LOG) << "Virtual collections data fetch ended in error.";
0112         processItems();
0113         return;
0114     }
0115 
0116     qCDebug(GOOGLE_PEOPLE_LOG) << "Processing fetched collections";
0117 
0118     const auto fetchJob = qobject_cast<CollectionFetchJob *>(job);
0119     const auto collections = fetchJob->collections();
0120 
0121     for (const auto &collection : collections) {
0122         qCDebug(GOOGLE_PEOPLE_LOG) << "Fetched data for virtual collection:" << collection.displayName();
0123         m_localToRemoteIdHash.insert(collection.id(), collection.remoteId());
0124     }
0125 
0126     processItems();
0127 }
0128 
0129 People::Membership PeopleConversionJob::resourceNameToMembership(const QString &resourceName)
0130 {
0131     People::ContactGroupMembership contactGroupMembership;
0132     contactGroupMembership.setContactGroupResourceName(resourceName);
0133 
0134     People::Membership membership;
0135     membership.setContactGroupMembership(contactGroupMembership);
0136 
0137     return membership;
0138 }
0139 
0140 void PeopleConversionJob::processItems()
0141 {
0142     for (const auto &item : std::as_const(m_items)) {
0143         const auto addressee = item.payload<KContacts::Addressee>();
0144         const auto person = People::Person::fromKContactsAddressee(addressee);
0145         QList<People::Membership> memberships;
0146 
0147         person->setResourceName(item.remoteId());
0148         person->setEtag(item.remoteRevision());
0149 
0150         // TODO: Domain membership?
0151         const auto parentCollectionRemoteId = m_reparentCollectionRemoteId.isEmpty() ?
0152             item.parentCollection().remoteId() : m_reparentCollectionRemoteId;
0153         People::ContactGroupMembership contactGroupMembership;
0154         contactGroupMembership.setContactGroupResourceName(parentCollectionRemoteId);
0155 
0156         People::Membership membership;
0157         membership.setContactGroupMembership(contactGroupMembership);
0158         memberships.append(membership);
0159 
0160         for (const auto &virtualCollection : item.virtualReferences()) {
0161 
0162             const auto virtualCollectionId = virtualCollection.id();
0163             if (!m_localToRemoteIdHash.contains(virtualCollectionId)) {
0164                 qCWarning(GOOGLE_PEOPLE_LOG) << "Fetched virtual collections do not contain collection with ID:" << virtualCollectionId;
0165                 continue;
0166             }
0167 
0168             const auto retrievedCollectionRemoteId = m_localToRemoteIdHash.value(virtualCollectionId);
0169             if (retrievedCollectionRemoteId == m_linkedCollectionToRemoveRemoteId) {
0170                 // Skip adding this membership so it will be removed serverside
0171                 continue;
0172             }
0173 
0174             const auto existingLinkedMembership = resourceNameToMembership(retrievedCollectionRemoteId);
0175             memberships.append(existingLinkedMembership);
0176         }
0177 
0178         if (!m_newLinkedCollectionRemoteId.isEmpty()) {
0179             const auto newLinkedMembership = resourceNameToMembership(m_newLinkedCollectionRemoteId);
0180             memberships.append(newLinkedMembership);
0181         }
0182 
0183         person->setMemberships(memberships);
0184 
0185         qCDebug(GOOGLE_PEOPLE_LOG) << "Processed person:" << person->resourceName();
0186         m_processedPeople.append(person);
0187     }
0188 
0189     Q_EMIT peopleChanged();
0190     Q_EMIT finished();
0191 }
0192 
0193 #include "moc_peopleconversionjob.cpp"