File indexing completed on 2025-02-16 04:50:13
0001 /* 0002 SPDX-FileCopyrightText: 2011-2013 Daniel Vrátil <dvratil@redhat.com> 0003 SPDX-FileCopyrightText: 2020 Igor Pobiko <igor.poboiko@gmail.com> 0004 SPDX-FileCopyrightText: 2022-2023 Claudio Cambra <claudio.cambra@kde.org> 0005 0006 SPDX-License-Identifier: GPL-3.0-or-later 0007 */ 0008 0009 #include "personhandler.h" 0010 #include "peopleconversionjob.h" 0011 #include "googleresource.h" 0012 #include "googlesettings.h" 0013 0014 #include "googlepeople_debug.h" 0015 0016 #include <Akonadi/CollectionModifyJob> 0017 #include <Akonadi/EntityDisplayAttribute> 0018 #include <Akonadi/ItemFetchJob> 0019 #include <Akonadi/ItemFetchScope> 0020 #include <Akonadi/ItemModifyJob> 0021 #include <Akonadi/LinkJob> 0022 #include <Akonadi/VectorHelper> 0023 0024 #include <KContacts/Addressee> 0025 #include <KContacts/Picture> 0026 0027 #include <kgapicore_export.h> 0028 0029 #include <KGAPI/Account> 0030 #include <KGAPI/People/ContactGroup> 0031 #include <KGAPI/People/ContactGroupCreateJob> 0032 #include <KGAPI/People/ContactGroupDeleteJob> 0033 #include <KGAPI/People/ContactGroupFetchJob> 0034 #include <KGAPI/People/ContactGroupMembership> 0035 #include <KGAPI/People/ContactGroupModifyJob> 0036 #include <KGAPI/People/Membership> 0037 #include <KGAPI/People/PersonCreateJob> 0038 #include <KGAPI/People/PersonDeleteJob> 0039 #include <KGAPI/People/PersonFetchJob> 0040 #include <KGAPI/People/PersonMetadata> 0041 #include <KGAPI/People/PersonModifyJob> 0042 #include <KGAPI/People/PersonPhotoDeleteJob> 0043 #include <KGAPI/People/PersonPhotoUpdateJob> 0044 #include <KGAPI/People/Photo> 0045 0046 using namespace KGAPI2; 0047 using namespace Akonadi; 0048 0049 namespace { 0050 constexpr auto myContactsResourceName = "contactGroups/myContacts"; 0051 constexpr auto otherContactsResourceName = "contactGroups/otherContacts"; 0052 } 0053 0054 QString PersonHandler::mimeType() 0055 { 0056 return addresseeMimeType(); 0057 } 0058 0059 QString PersonHandler::addresseeMimeType() 0060 { 0061 return KContacts::Addressee::mimeType(); 0062 } 0063 0064 bool PersonHandler::canPerformTask(const Item &item) 0065 { 0066 return GenericHandler::canPerformTask<KContacts::Addressee>(item); 0067 } 0068 0069 bool PersonHandler::canPerformTask(const Item::List &items) 0070 { 0071 return GenericHandler::canPerformTask<KContacts::Addressee>(items); 0072 } 0073 0074 Collection PersonHandler::collectionFromContactGroup(const People::ContactGroupPtr &group) 0075 { 0076 Collection collection; 0077 collection.setContentMimeTypes({addresseeMimeType()}); 0078 collection.setName(group->name()); 0079 collection.setRemoteId(group->resourceName()); 0080 collection.setRemoteRevision(group->etag()); 0081 0082 const auto isSystemGroup = group->groupType() == People::ContactGroup::GroupType::SYSTEM_CONTACT_GROUP; 0083 auto realName = group->formattedName(); 0084 if (isSystemGroup) { 0085 if (realName.contains(QLatin1StringView("Coworkers"))) { 0086 realName = i18nc("Name of a group of contacts", "Coworkers"); 0087 } else if (realName.contains(QLatin1StringView("Friends"))) { 0088 realName = i18nc("Name of a group of contacts", "Friends"); 0089 } else if (realName.contains(QLatin1StringView("Family"))) { 0090 realName = i18nc("Name of a group of contacts", "Family"); 0091 } else if (realName.contains(QLatin1StringView("My Contacts"))) { 0092 realName = i18nc("Name of a group of contacts", "My Contacts"); 0093 } 0094 } 0095 0096 // "My Contacts" is the only one not virtual 0097 if (group->resourceName() == QString::fromUtf8(myContactsResourceName)) { 0098 collection.setRights(Collection::CanCreateItem | Collection::CanChangeItem | Collection::CanDeleteItem); 0099 } else { 0100 collection.setRights(Collection::CanLinkItem | Collection::CanUnlinkItem | Collection::CanChangeItem); 0101 collection.setVirtual(true); 0102 if (!isSystemGroup) { 0103 collection.setRights(collection.rights() | Collection::CanChangeCollection | Collection::CanDeleteCollection); 0104 } 0105 } 0106 0107 auto attr = collection.attribute<EntityDisplayAttribute>(Collection::AddIfMissing); 0108 attr->setDisplayName(realName); 0109 attr->setIconName(QStringLiteral("view-pim-contacts")); 0110 0111 return collection; 0112 } 0113 0114 void PersonHandler::retrieveCollections(const Collection &rootCollection) 0115 { 0116 m_iface->emitStatus(AgentBase::Running, i18nc("@info:status", "Retrieving contacts groups")); 0117 qCDebug(GOOGLE_PEOPLE_LOG) << "Retrieving contacts groups..."; 0118 m_collections.clear(); 0119 0120 // Set up Google's special "Other contacts" contacts group 0121 Collection otherCollection; 0122 otherCollection.setContentMimeTypes({mimeType()}); 0123 otherCollection.setName(i18n("Other Contacts")); 0124 otherCollection.setParentCollection(rootCollection); 0125 otherCollection.setRights(Collection::CanCreateItem | Collection::CanChangeItem | Collection::CanDeleteItem); 0126 otherCollection.setRemoteId(QString::fromUtf8(otherContactsResourceName)); 0127 0128 auto attr = otherCollection.attribute<EntityDisplayAttribute>(Collection::AddIfMissing); 0129 attr->setDisplayName(i18n("Other Contacts")); 0130 attr->setIconName(QStringLiteral("view-pim-contacts")); 0131 0132 m_iface->collectionsRetrieved({otherCollection}); 0133 m_collections[QString::fromUtf8(otherContactsResourceName)] = otherCollection; 0134 0135 auto job = new People::ContactGroupFetchJob(m_settings->accountPtr(), this); 0136 connect(job, &People::ContactGroupFetchJob::finished, this, [this, rootCollection](KGAPI2::Job *job) { 0137 if (!m_iface->handleError(job)) { 0138 return; 0139 } 0140 0141 const auto objects = qobject_cast<People::ContactGroupFetchJob *>(job)->items(); 0142 qCDebug(GOOGLE_PEOPLE_LOG) << objects.count() << "contact groups retrieved"; 0143 0144 Collection::List collections; 0145 collections.reserve(objects.count()); 0146 0147 std::transform(objects.cbegin(), objects.cend(), std::back_inserter(collections), [this, &rootCollection](const ObjectPtr &object) { 0148 const auto group = object.dynamicCast<People::ContactGroup>(); 0149 qCDebug(GOOGLE_PEOPLE_LOG) << " -" << group->formattedName() << "(" << group->resourceName() << ")"; 0150 0151 auto collection = collectionFromContactGroup(group); 0152 collection.setParentCollection(rootCollection); 0153 0154 m_collections[collection.remoteId()] = collection; 0155 return collection; 0156 }); 0157 m_iface->collectionsRetrievedFromHandler(collections); 0158 }); 0159 } 0160 0161 void PersonHandler::retrieveItems(const Collection &collection) 0162 { 0163 // Contacts are stored inside "My Contacts" and "Other Contacts" only 0164 if ((collection.remoteId() != QString::fromUtf8(otherContactsResourceName)) && 0165 (collection.remoteId() != QString::fromUtf8(myContactsResourceName))) { 0166 m_iface->itemsRetrievalDone(); 0167 return; 0168 } 0169 0170 m_iface->emitStatus(AgentBase::Running, i18nc("@info:status", "Retrieving contacts for group '%1'", collection.displayName())); 0171 qCDebug(GOOGLE_PEOPLE_LOG) << "Retrieving contacts for group" << collection.remoteId() << "..."; 0172 0173 const auto job = new People::PersonFetchJob(m_settings->accountPtr(), this); 0174 0175 if (!collection.remoteRevision().isEmpty()) { 0176 job->setSyncToken(collection.remoteRevision()); 0177 } 0178 0179 connect(job, &People::PersonFetchJob::finished, this, &PersonHandler::slotItemsRetrieved); 0180 } 0181 0182 void PersonHandler::slotItemsRetrieved(KGAPI2::Job *job) 0183 { 0184 if (!m_iface->handleError(job)) { 0185 return; 0186 } 0187 0188 auto collection = m_iface->currentCollection(); 0189 0190 Item::List changedItems, removedItems; 0191 QHash<QString, Item::List> groupsMap; 0192 0193 auto fetchJob = qobject_cast<People::PersonFetchJob *>(job); 0194 const auto isIncremental = !fetchJob->syncToken().isEmpty(); 0195 const auto objects = fetchJob->items(); 0196 qCDebug(GOOGLE_PEOPLE_LOG) << "Retrieved" << objects.count() << "contacts"; 0197 0198 for (const ObjectPtr &object : objects) { 0199 const auto person = object.dynamicCast<People::Person>(); 0200 const auto addressee = person->toKContactsAddressee(); 0201 0202 Item item; 0203 item.setMimeType(mimeType()); 0204 item.setParentCollection(collection); 0205 item.setRemoteId(person->resourceName()); 0206 item.setRemoteRevision(person->etag()); 0207 item.setPayload<KContacts::Addressee>(addressee); 0208 0209 if (person->metadata().deleted() || 0210 (collection.remoteId() == QString::fromUtf8(otherContactsResourceName) && !person->memberships().isEmpty()) || 0211 (collection.remoteId() == QString::fromUtf8(myContactsResourceName) && person->memberships().isEmpty())) { 0212 qCDebug(GOOGLE_PEOPLE_LOG) << " - removed" << person->resourceName(); 0213 removedItems << item; 0214 } else { 0215 qCDebug(GOOGLE_PEOPLE_LOG) << " - changed" << person->resourceName(); 0216 changedItems << item; 0217 } 0218 0219 const auto memberships = person->memberships(); 0220 for (const auto &membership : memberships) { 0221 // We don't link contacts to "My Contacts" 0222 const auto contactGroupResourceName = membership.contactGroupMembership().contactGroupResourceName(); 0223 if (contactGroupResourceName != QString::fromUtf8(myContactsResourceName)) { 0224 groupsMap[contactGroupResourceName] << item; 0225 } 0226 } 0227 } 0228 0229 if (isIncremental) { 0230 m_iface->itemsRetrievedIncremental(changedItems, removedItems); 0231 } else { 0232 m_iface->itemsRetrieved(changedItems); 0233 } 0234 0235 for (auto iter = groupsMap.constBegin(); iter != groupsMap.constEnd(); ++iter) { 0236 new LinkJob(m_collections[iter.key()], iter.value(), this); 0237 } 0238 // TODO: unlink if the group was removed! 0239 0240 collection.setRemoteRevision(fetchJob->receivedSyncToken()); 0241 new CollectionModifyJob(collection, this); 0242 0243 emitReadyStatus(); 0244 } 0245 0246 void PersonHandler::slotPersonCreateJobFinished(KGAPI2::Job *job) 0247 { 0248 if (!m_iface->handleError(job)) { 0249 return; 0250 } 0251 0252 const auto personCreateJob = qobject_cast<People::PersonCreateJob *>(job); 0253 const auto createdPeople = personCreateJob->items(); 0254 0255 processUpdatedPeople(job, createdPeople); 0256 } 0257 0258 void PersonHandler::slotKGAPIModifyJobFinished(KGAPI2::Job *job) 0259 { 0260 if (!m_iface->handleError(job)) { 0261 return; 0262 } 0263 0264 const auto personModifyJob = qobject_cast<ModifyJob *>(job); 0265 const auto modifiedPeople = personModifyJob->items(); 0266 0267 processUpdatedPeople(job, modifiedPeople); 0268 } 0269 0270 void PersonHandler::processUpdatedPeople(KGAPI2::Job *job, const ObjectsList &updatedPeople) 0271 { 0272 Q_ASSERT(job); 0273 if (updatedPeople.isEmpty()) { 0274 return; 0275 } 0276 0277 if (job->property(ITEM_PROPERTY).canConvert<Akonadi::Item>()) { 0278 const auto originalItem = job->property(ITEM_PROPERTY).value<Akonadi::Item>(); 0279 if (!originalItem.isValid()) { 0280 qCWarning(GOOGLE_PEOPLE_LOG) << "No valid item in received KGAPI job, can't update"; 0281 return; 0282 } 0283 0284 const auto person = updatedPeople.first().dynamicCast<People::Person>(); 0285 updatePersonItem(originalItem, person); 0286 emitReadyStatus(); 0287 0288 } else if (job->property(ITEMS_PROPERTY).canConvert<Akonadi::Item::List>()) { 0289 // Be careful not to send an item list or a multi person create job -- only modify jobs. 0290 // At point of creation we do not yet have resource names for the Akonadi items for newly created people. 0291 // This means we will not know which Akonadi items correspond to which person. 0292 const auto originalItems = job->property(ITEMS_PROPERTY).value<Akonadi::Item::List>(); 0293 if (originalItems.isEmpty()) { 0294 qCWarning(GOOGLE_PEOPLE_LOG) << "No items in items vector in received KGAPI job, can't update"; 0295 return; 0296 } 0297 0298 for (const auto &personObject : updatedPeople) { 0299 const auto person = personObject.dynamicCast<People::Person>(); 0300 const auto matchingItemIt = std::find_if(originalItems.cbegin(), originalItems.cend(), [&person](const Akonadi::Item &item) { 0301 return item.remoteId() == person->resourceName(); 0302 }); 0303 0304 if (matchingItemIt == originalItems.cend()) { 0305 qCWarning(GOOGLE_PEOPLE_LOG) << "Could not find matching item for person:" << person->resourceName() 0306 << "cannot update them properly right now."; 0307 continue; 0308 } 0309 0310 const auto matchingItem = *matchingItemIt; 0311 updatePersonItem(matchingItem, person); 0312 } 0313 emitReadyStatus(); 0314 0315 } else { 0316 qCWarning(GOOGLE_PEOPLE_LOG) << "Finished job not carrying actionable item property, cannot update."; 0317 } 0318 } 0319 0320 void PersonHandler::updatePersonItem(const Akonadi::Item &originalItem, const People::PersonPtr &person) 0321 { 0322 if (person.isNull()) { 0323 qCWarning(GOOGLE_PEOPLE_LOG) << "Received null person ptr, can't update"; 0324 return; 0325 } else if (!originalItem.isValid() || !originalItem.hasPayload<KContacts::Addressee>()) { 0326 qCWarning(GOOGLE_PEOPLE_LOG) << "No valid item in received KGAPI job, can't update"; 0327 return; 0328 } 0329 0330 const auto personResourceName = person->resourceName(); 0331 if (personResourceName.isEmpty()) { 0332 qCWarning(GOOGLE_PEOPLE_LOG) << "Received person with no resource name, can't update"; 0333 return; 0334 } 0335 0336 if (m_pendingPeoplePhotoUpdate.contains(personResourceName)) { 0337 qCDebug(GOOGLE_PEOPLE_LOG) << "Received updated person response from photo update." 0338 << personResourceName; 0339 m_pendingPeoplePhotoUpdate.remove(personResourceName); 0340 } else if (const auto originalAddressee = originalItem.payload<KContacts::Addressee>(); 0341 !originalAddressee.photo().isEmpty() && !originalAddressee.photo().rawData().isEmpty()) { 0342 qCDebug(GOOGLE_PEOPLE_LOG) << "Person to update requires a photo update. Sending off photo update job." 0343 << personResourceName; 0344 0345 m_pendingPeoplePhotoUpdate.insert(personResourceName); 0346 const auto addresseePicture = originalAddressee.photo(); 0347 const auto pictureRawData = originalAddressee.photo().rawData(); 0348 auto job = new People::PersonPhotoUpdateJob(personResourceName, pictureRawData, m_settings->accountPtr(), this); 0349 job->setProperty(ITEM_PROPERTY, QVariant::fromValue(originalItem)); 0350 connect(job, &People::PersonPhotoUpdateJob::finished, this, &PersonHandler::slotKGAPIModifyJobFinished); 0351 } else if (originalAddressee.photo().isEmpty() && !person->photos().isEmpty()) { 0352 qCDebug(GOOGLE_PEOPLE_LOG) << "Person to update needs photo deleted. Sending off photo delete job." 0353 << personResourceName; 0354 0355 m_pendingPeoplePhotoUpdate.insert(personResourceName); 0356 auto job = new People::PersonPhotoDeleteJob(personResourceName, m_settings->accountPtr(), this); 0357 job->setProperty(ITEM_PROPERTY, QVariant::fromValue(originalItem)); 0358 connect(job, &People::PersonPhotoUpdateJob::finished, this, &PersonHandler::slotKGAPIModifyJobFinished); 0359 } 0360 0361 Item newItem = originalItem; 0362 qCDebug(GOOGLE_PEOPLE_LOG) << "Person" << personResourceName << "updated"; 0363 0364 newItem.setRemoteId(personResourceName); 0365 newItem.setRemoteRevision(person->etag()); 0366 m_iface->itemChangeCommitted(newItem); 0367 0368 newItem.setPayload<KContacts::Addressee>(person->toKContactsAddressee()); 0369 new ItemModifyJob(newItem, this); 0370 } 0371 0372 void PersonHandler::itemAdded(const Item &item, const Collection &collection) 0373 { 0374 m_iface->emitStatus(AgentBase::Running, i18nc("@info:status", "Adding contact to group '%1'", collection.displayName())); 0375 const auto addressee = item.payload<KContacts::Addressee>(); 0376 const auto person = People::Person::fromKContactsAddressee(addressee); 0377 0378 qCDebug(GOOGLE_PEOPLE_LOG) << "Creating people"; 0379 0380 People::ContactGroupMembership contactGroupMembership; 0381 contactGroupMembership.setContactGroupResourceName(QString::fromUtf8(myContactsResourceName)); 0382 0383 People::Membership membership; 0384 membership.setContactGroupMembership(contactGroupMembership); 0385 person->setMemberships({membership}); 0386 0387 auto job = new People::PersonCreateJob(person, m_settings->accountPtr(), this); 0388 job->setProperty(ITEM_PROPERTY, QVariant::fromValue(item)); 0389 connect(job, &People::PersonCreateJob::finished, this, &PersonHandler::slotPersonCreateJobFinished); 0390 } 0391 0392 void PersonHandler::sendModifyJob(const Akonadi::Item::List &items, const People::PersonList &people) 0393 { 0394 auto job = new People::PersonModifyJob(people, m_settings->accountPtr(), this); 0395 job->setProperty(ITEMS_PROPERTY, QVariant::fromValue(items)); 0396 connect(job, &People::PersonModifyJob::finished, this, &PersonHandler::slotKGAPIModifyJobFinished); 0397 } 0398 0399 void PersonHandler::sendModifyJob(const Akonadi::Item &item, const People::PersonPtr &person) 0400 { 0401 auto job = new People::PersonModifyJob(person, m_settings->accountPtr(), this); 0402 job->setProperty(ITEM_PROPERTY, QVariant::fromValue(item)); 0403 connect(job, &People::PersonModifyJob::finished, this, &PersonHandler::slotKGAPIModifyJobFinished); 0404 } 0405 0406 void PersonHandler::itemChanged(const Item &item, const QSet<QByteArray> & /*partIdentifiers*/) 0407 { 0408 m_iface->emitStatus(AgentBase::Running, i18nc("@info:status", "Changing contact")); 0409 qCDebug(GOOGLE_PEOPLE_LOG) << "Changing person" << item.remoteId(); 0410 0411 const auto job = new PeopleConversionJob({item}, this); 0412 connect(job, &PeopleConversionJob::finished, this, [this, item, job] { 0413 const auto person = job->people().first(); 0414 sendModifyJob(item, person); 0415 job->deleteLater(); 0416 }); 0417 job->start(); 0418 } 0419 0420 void PersonHandler::itemsRemoved(const Item::List &items) 0421 { 0422 m_iface->emitStatus(AgentBase::Running, i18ncp("@info:status", "Removing %1 contact", "Removing %1 contacts", items.count())); 0423 QStringList peopleResourceNames; 0424 peopleResourceNames.reserve(items.count()); 0425 std::transform(items.cbegin(), items.cend(), std::back_inserter(peopleResourceNames), [](const Item &item) { 0426 return item.remoteId(); 0427 }); 0428 qCInfo(GOOGLE_PEOPLE_LOG) << "Removing people" << peopleResourceNames; 0429 auto job = new People::PersonDeleteJob(peopleResourceNames, m_settings->accountPtr(), this); 0430 job->setProperty(ITEMS_PROPERTY, QVariant::fromValue(items)); 0431 connect(job, &People::PersonDeleteJob::finished, this, &PersonHandler::slotGenericJobFinished); 0432 } 0433 0434 void PersonHandler::itemsMoved(const Item::List &items, const Collection &collectionSource, const Collection &collectionDestination) 0435 { 0436 const auto sourceRemoteId = collectionSource.remoteId(); 0437 const auto destinationRemoteId = collectionDestination.remoteId(); 0438 qCDebug(GOOGLE_PEOPLE_LOG) << "Moving people from" << sourceRemoteId << "to" << destinationRemoteId; 0439 0440 if (!(((sourceRemoteId == QString::fromUtf8(myContactsResourceName)) && (destinationRemoteId == QString::fromUtf8(otherContactsResourceName))) || 0441 ((sourceRemoteId == QString::fromUtf8(otherContactsResourceName)) && (destinationRemoteId == QString::fromUtf8(myContactsResourceName))))) { 0442 m_iface->cancelTask(i18n("Invalid source or destination collection")); 0443 return; 0444 } 0445 0446 m_iface->emitStatus(AgentBase::Running, 0447 i18ncp("@info:status", 0448 "Moving %1 contact from group '%2' to '%3'", 0449 "Moving %1 contacts from group '%2' to '%3'", 0450 items.count(), 0451 sourceRemoteId, 0452 destinationRemoteId)); 0453 0454 const auto job = new PeopleConversionJob(items, this); 0455 job->setReparentCollectionRemoteId(destinationRemoteId); 0456 connect(job, &PeopleConversionJob::finished, this, [this, items, job] { 0457 sendModifyJob(items, job->people()); 0458 job->deleteLater(); 0459 }); 0460 job->start(); 0461 } 0462 0463 void PersonHandler::itemsLinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection) 0464 { 0465 m_iface->emitStatus(AgentBase::Running, i18ncp("@info:status", "Linking %1 contact", "Linking %1 contacts", items.count())); 0466 qCDebug(GOOGLE_PEOPLE_LOG) << "Linking" << items.count() << "contacts to group" << collection.remoteId(); 0467 0468 const auto job = new PeopleConversionJob(items, this); 0469 job->setNewLinkedCollectionRemoteId(collection.remoteId()); 0470 connect(job, &PeopleConversionJob::finished, this, [this, items, job] { 0471 sendModifyJob(items, job->people()); 0472 job->deleteLater(); 0473 }); 0474 job->start(); 0475 } 0476 0477 void PersonHandler::itemsUnlinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection) 0478 { 0479 m_iface->emitStatus(AgentBase::Running, i18ncp("@info:status", "Unlinking %1 contact", "Unlinking %1 contacts", items.count())); 0480 qCDebug(GOOGLE_PEOPLE_LOG) << "Unlinking" << items.count() << "contacts to group" << collection.remoteId(); 0481 0482 const auto job = new PeopleConversionJob(items, this); 0483 job->setLinkedCollectionToRemoveRemoteId(collection.remoteId()); 0484 connect(job, &PeopleConversionJob::finished, this, [this, items, job] { 0485 sendModifyJob(items, job->people()); 0486 job->deleteLater(); 0487 }); 0488 job->start(); 0489 } 0490 0491 void PersonHandler::updateContactGroupCollection(const Collection &collection, const People::ContactGroupPtr &contactGroup) 0492 { 0493 if (contactGroup.isNull()) { 0494 qCWarning(GOOGLE_PEOPLE_LOG) << "Received null contact group ptr, can't update"; 0495 return; 0496 } else if (!collection.isValid()) { 0497 qCWarning(GOOGLE_PEOPLE_LOG) << "No valid collection in received KGAPI job, can't update"; 0498 return; 0499 } 0500 0501 auto newCollection = collectionFromContactGroup(contactGroup); 0502 newCollection.setId(collection.id()); 0503 0504 qCDebug(GOOGLE_PEOPLE_LOG) << "Contact group updated:" << contactGroup->resourceName() << contactGroup->name(); 0505 0506 m_collections[newCollection.remoteId()] = newCollection; 0507 m_iface->collectionChangeCommitted(newCollection); 0508 } 0509 0510 void PersonHandler::collectionAdded(const Collection &collection, const Collection & /*parent*/) 0511 { 0512 m_iface->emitStatus(AgentBase::Running, i18nc("@info:status", "Creating new contact group '%1'", collection.displayName())); 0513 qCDebug(GOOGLE_PEOPLE_LOG) << "Adding contact group" << collection.displayName(); 0514 People::ContactGroupPtr group(new People::ContactGroup); 0515 group->setName(collection.name()); 0516 0517 auto job = new People::ContactGroupCreateJob(group, m_settings->accountPtr(), this); 0518 connect(job, &People::ContactGroupCreateJob::finished, this, [this, collection](KGAPI2::Job *job) { 0519 if (!m_iface->handleError(job)) { 0520 return; 0521 } 0522 0523 const auto createJob = qobject_cast<People::ContactGroupCreateJob *>(job); 0524 const auto group = createJob->items().first().dynamicCast<People::ContactGroup>(); 0525 0526 updateContactGroupCollection(collection, group); 0527 emitReadyStatus(); 0528 }); 0529 } 0530 0531 void PersonHandler::collectionChanged(const Collection &collection) 0532 { 0533 m_iface->emitStatus(AgentBase::Running, i18nc("@info:status", "Changing contact group '%1'", collection.displayName())); 0534 qCDebug(GOOGLE_PEOPLE_LOG) << "Changing contact group" << collection.remoteId(); 0535 0536 People::ContactGroupPtr group(new People::ContactGroup()); 0537 group->setResourceName(collection.remoteId()); 0538 group->setEtag(collection.remoteRevision()); 0539 group->setName(collection.displayName()); 0540 0541 auto job = new People::ContactGroupModifyJob(group, m_settings->accountPtr(), this); 0542 job->setProperty(COLLECTION_PROPERTY, QVariant::fromValue(collection)); 0543 connect(job, &People::ContactGroupModifyJob::finished, this, [this, collection](KGAPI2::Job *job) { 0544 if (!m_iface->handleError(job)) { 0545 return; 0546 } 0547 0548 const auto modifyJob = qobject_cast<People::ContactGroupModifyJob *>(job); 0549 const auto group = modifyJob->items().first().dynamicCast<People::ContactGroup>(); 0550 0551 updateContactGroupCollection(collection, group); 0552 emitReadyStatus(); 0553 }); 0554 } 0555 0556 void PersonHandler::collectionRemoved(const Collection &collection) 0557 { 0558 m_iface->emitStatus(AgentBase::Running, i18nc("@info:status", "Removing contact group '%1'", collection.displayName())); 0559 qCDebug(GOOGLE_PEOPLE_LOG) << "Removing contact group" << collection.remoteId(); 0560 auto job = new People::ContactGroupDeleteJob(collection.remoteId(), m_settings->accountPtr(), this); 0561 job->setProperty(COLLECTION_PROPERTY, QVariant::fromValue(collection)); 0562 connect(job, &People::ContactGroupDeleteJob::finished, this, &PersonHandler::slotGenericJobFinished); 0563 } 0564 0565 #include "moc_personhandler.cpp"