contactsresource.cpp 21 KB
Newer Older
1
/*
2
    Copyright (C) 2011-2013  Daniel Vrátil <dvratil@redhat.com>
3
4
5
6
7
8
9
10
11
12
13
14

    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
15
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17
18
19
20
21
*/

#include "contactsresource.h"
#include "settingsdialog.h"
#include "settings.h"

Laurent Montel's avatar
Laurent Montel committed
22
23
24
25
26
#include <AkonadiCore/CollectionModifyJob>
#include <AkonadiCore/EntityDisplayAttribute>
#include <AkonadiCore/ItemFetchJob>
#include <AkonadiCore/ItemFetchScope>
#include <AkonadiCore/ItemModifyJob>
Laurent Montel's avatar
Laurent Montel committed
27
28
#include <AkonadiCore/LinkJob>
#include <AkonadiCore/UnlinkJob>
Laurent Montel's avatar
Laurent Montel committed
29
#include <AkonadiCore/CachePolicy>
30
#include <AkonadiCore/VectorHelper>
31

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
32
33
#include <KContacts/Addressee>
#include <KContacts/Picture>
34

Laurent Montel's avatar
Laurent Montel committed
35
#include <KLocalizedString>
Laurent Montel's avatar
Laurent Montel committed
36
#include <QIcon>
37

Laurent Montel's avatar
Laurent Montel committed
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <KGAPI/Types>
#include <KGAPI/Account>
#include <KGAPI/AuthJob>
#include <KGAPI/Contacts/Contact>
#include <KGAPI/Contacts/ContactCreateJob>
#include <KGAPI/Contacts/ContactDeleteJob>
#include <KGAPI/Contacts/ContactFetchJob>
#include <KGAPI/Contacts/ContactFetchPhotoJob>
#include <KGAPI/Contacts/ContactModifyJob>
#include <KGAPI/Contacts/ContactsGroup>
#include <KGAPI/Contacts/ContactsGroupCreateJob>
#include <KGAPI/Contacts/ContactsGroupDeleteJob>
#include <KGAPI/Contacts/ContactsGroupFetchJob>
#include <KGAPI/Contacts/ContactsGroupModifyJob>
52

Laurent Montel's avatar
Laurent Montel committed
53
54
#define MYCONTACTS_REMOTEID QStringLiteral("MyContacts")
#define OTHERCONTACTS_REMOTEID QStringLiteral("OtherContacts")
55

Laurent Montel's avatar
Laurent Montel committed
56
57
Q_DECLARE_METATYPE(KGAPI2::Job *)
Q_DECLARE_METATYPE(QList<QString>)
58

59
60
using namespace Akonadi;
using namespace KGAPI2;
61

Laurent Montel's avatar
Laurent Montel committed
62
63
ContactsResource::ContactsResource(const QString &id)
    : GoogleResource(id)
64
{
65
    updateResourceName();
66
67
68
69
70
71
}

ContactsResource::~ContactsResource()
{
}

72
GoogleSettings *ContactsResource::settings() const
73
{
74
    return Settings::self();
75
76
}

Laurent Montel's avatar
Laurent Montel committed
77
int ContactsResource::runConfigurationDialog(WId windowId)
78
{
Laurent Montel's avatar
Laurent Montel committed
79
    QScopedPointer<SettingsDialog> settingsDialog(new SettingsDialog(accountManager(), windowId, this));
Laurent Montel's avatar
Laurent Montel committed
80
    settingsDialog->setWindowIcon(QIcon::fromTheme(QStringLiteral("im-google")));
81

Laurent Montel's avatar
Laurent Montel committed
82
    return settingsDialog->exec();
83
84
}

85
void ContactsResource::updateResourceName()
86
{
87
    const QString accountName = Settings::self()->account();
Laurent Montel's avatar
Laurent Montel committed
88
    setName(i18nc("%1 is account name (user@gmail.com)", "Google Contacts (%1)", accountName.isEmpty() ? i18n("not configured") : accountName));
89
90
}

91
QList< QUrl > ContactsResource::scopes() const
92
{
Laurent Montel's avatar
Laurent Montel committed
93
    const QList< QUrl > scopes = {Account::contactsScopeUrl(), Account::accountInfoScopeUrl()};
94
    return scopes;
95
96
}

Laurent Montel's avatar
Laurent Montel committed
97
void ContactsResource::retrieveItems(const Collection &collection)
98
{
Laurent Montel's avatar
Laurent Montel committed
99
    if (!canPerformTask()) {
100
        return;
101
102
    }

103
    // All items are only in top-level collection and Other Contacts collection
Laurent Montel's avatar
Laurent Montel committed
104
105
    if ((collection.remoteId() != m_rootCollection.remoteId())
        && (collection.remoteId() != OTHERCONTACTS_REMOTEID)) {
106
107
108
        itemsRetrievalDone();
        return;
    }
109

Laurent Montel's avatar
Laurent Montel committed
110
111
112
113
114
    ContactFetchJob *fetchJob = new ContactFetchJob(account(), this);
    fetchJob->setProperty(COLLECTION_PROPERTY, QVariant::fromValue(collection));
    fetchJob->setFetchDeleted(true);
    if (!collection.remoteRevision().isEmpty()) {
        fetchJob->setFetchOnlyUpdated(collection.remoteRevision().toLongLong());
115
    }
Laurent Montel's avatar
Laurent Montel committed
116
117
    connect(fetchJob, &ContactFetchJob::progress, this, &ContactsResource::emitPercent);
    connect(fetchJob, &ContactFetchJob::finished, this, &ContactsResource::slotItemsRetrieved);
118
119
}

Laurent Montel's avatar
Laurent Montel committed
120
void ContactsResource::retrieveContactsPhotos(const QVariant &arguments)
121
{
Laurent Montel's avatar
Laurent Montel committed
122
    if (!canPerformTask()) {
123
124
        return;
    }
125

126
    const QVariantMap map = arguments.toMap();
Laurent Montel's avatar
Laurent Montel committed
127
    const Collection collection = map[ QStringLiteral("collection") ].value<Collection>();
Laurent Montel's avatar
Laurent Montel committed
128
    ItemFetchJob *itemFetchJob = new ItemFetchJob(collection, this);
Laurent Montel's avatar
Laurent Montel committed
129
    itemFetchJob->setProperty("modifiedItems", map[ QStringLiteral("modifiedItems") ]);
130
    itemFetchJob->fetchScope().fetchFullPayload(true);
Laurent Montel's avatar
Laurent Montel committed
131
    connect(itemFetchJob, &ItemFetchJob::finished, this, &ContactsResource::slotUpdatePhotosItemsRetrieved);
Laurent Montel's avatar
Laurent Montel committed
132
    Q_EMIT status(Running, i18nc("@info:status", "Retrieving photos"));
133
134
}

135
void ContactsResource::retrieveCollections()
136
{
Laurent Montel's avatar
Laurent Montel committed
137
    if (!canPerformTask()) {
138
139
        return;
    }
140

Laurent Montel's avatar
Laurent Montel committed
141
    ContactsGroupFetchJob *fetchJob = new ContactsGroupFetchJob(account(), this);
Laurent Montel's avatar
Laurent Montel committed
142
143
    connect(fetchJob, &ContactFetchJob::progress, this, &ContactsResource::emitPercent);
    connect(fetchJob, &ContactFetchJob::finished, this, &ContactsResource::slotCollectionsRetrieved);
144
145
}

Laurent Montel's avatar
Laurent Montel committed
146
void ContactsResource::itemAdded(const Item &item, const Collection &collection)
147
{
Laurent Montel's avatar
Laurent Montel committed
148
    if (!canPerformTask<KContacts::Addressee>(item, KContacts::Addressee::mimeType())) {
149
150
        return;
    }
151

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
152
    KContacts::Addressee addressee = item.payload< KContacts::Addressee >();
Laurent Montel's avatar
Laurent Montel committed
153
    ContactPtr contact(new Contact(addressee));
154

155
    /* If the contact has been moved into My Contacts group then modify the membership */
Laurent Montel's avatar
Laurent Montel committed
156
    if (collection.remoteId() == MYCONTACTS_REMOTEID) {
157
        contact->addGroup(QStringLiteral("http://www.google.com/m8/feeds/groups/%1/base/6").arg(QString::fromLatin1(QUrl::toPercentEncoding(account()->accountName()))));
158
    }
159

160
    /* If the contact has been moved to Other Contacts then remove all groups */
Laurent Montel's avatar
Laurent Montel committed
161
    if (collection.remoteId() == OTHERCONTACTS_REMOTEID) {
162
163
        contact->clearGroups();
    }
164

Laurent Montel's avatar
Laurent Montel committed
165
166
    ContactCreateJob *createJob = new ContactCreateJob(contact, account(), this);
    createJob->setProperty(ITEM_PROPERTY, QVariant::fromValue(item));
Laurent Montel's avatar
Laurent Montel committed
167
168
    connect(createJob, &ContactCreateJob::progress, this, &ContactsResource::emitPercent);
    connect(createJob, &ContactCreateJob::finished, this, &ContactsResource::slotCreateJobFinished);
169
170
}

Laurent Montel's avatar
Laurent Montel committed
171
void ContactsResource::itemChanged(const Item &item, const QSet< QByteArray > &partIdentifiers)
172
{
Laurent Montel's avatar
Laurent Montel committed
173
    Q_UNUSED(partIdentifiers);
174

Laurent Montel's avatar
Laurent Montel committed
175
    if (!canPerformTask<KContacts::Addressee>(item, KContacts::Addressee::mimeType())) {
176
177
        return;
    }
178

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
179
    KContacts::Addressee addressee = item.payload< KContacts::Addressee >();
Laurent Montel's avatar
Laurent Montel committed
180
    ContactPtr contact(new Contact(addressee));
181

Laurent Montel's avatar
Laurent Montel committed
182
    if (item.parentCollection().remoteId() == MYCONTACTS_REMOTEID) {
183
        contact->addGroup(QStringLiteral("http://www.google.com/m8/feeds/groups/%1/base/6").arg(QString::fromLatin1(QUrl::toPercentEncoding(account()->accountName()))));
184
    }
185

Laurent Montel's avatar
Laurent Montel committed
186
187
    ContactModifyJob *modifyJob = new ContactModifyJob(contact, account(), this);
    modifyJob->setProperty(ITEM_PROPERTY, QVariant::fromValue(item));
Laurent Montel's avatar
Laurent Montel committed
188
189
    connect(modifyJob, &ContactModifyJob::progress, this, &ContactsResource::emitPercent);
    connect(modifyJob, &ContactModifyJob::finished, this, &ContactsResource::slotGenericJobFinished);
190
191
}

Laurent Montel's avatar
Laurent Montel committed
192
void ContactsResource::itemMoved(const Item &item, const Collection &collectionSource, const Collection &collectionDestination)
193
{
Laurent Montel's avatar
Laurent Montel committed
194
    if (!canPerformTask<KContacts::Addressee>(item, KContacts::Addressee::mimeType())) {
195
196
        return;
    }
197

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
198
    KContacts::Addressee addressee = item.payload< KContacts::Addressee >();
Laurent Montel's avatar
Laurent Montel committed
199
    ContactPtr contact(new Contact(addressee));
200

201
    // MyContacts -> OtherContacts
Laurent Montel's avatar
Laurent Montel committed
202
203
    if (collectionSource.remoteId() == MYCONTACTS_REMOTEID
        && collectionDestination.remoteId() == OTHERCONTACTS_REMOTEID) {
204
        contact->removeGroup(QStringLiteral("http://www.google.com/m8/feeds/groups/%1/base/6").arg(QString::fromLatin1(QUrl::toPercentEncoding(account()->accountName()))));
205

206
        // OtherContacts -> MyContacts
Laurent Montel's avatar
Laurent Montel committed
207
208
    } else if (collectionSource.remoteId() == OTHERCONTACTS_REMOTEID
               && collectionDestination.remoteId() == MYCONTACTS_REMOTEID) {
209
        contact->addGroup(QStringLiteral("http://www.google.com/m8/feeds/groups/%1/base/6").arg(QString::fromLatin1(QUrl::toPercentEncoding(account()->accountName()))));
210
    } else {
Laurent Montel's avatar
Laurent Montel committed
211
        cancelTask(i18n("Invalid source or destination collection"));
212
        return;
213
214
    }

Laurent Montel's avatar
Laurent Montel committed
215
216
    ContactModifyJob *modifyJob = new ContactModifyJob(contact, account(), this);
    modifyJob->setProperty(ITEM_PROPERTY, QVariant::fromValue(item));
Laurent Montel's avatar
Laurent Montel committed
217
218
    connect(modifyJob, &ContactModifyJob::progress, this, &ContactsResource::emitPercent);
    connect(modifyJob, &ContactModifyJob::finished, this, &ContactsResource::slotGenericJobFinished);
219
}
220

Laurent Montel's avatar
Laurent Montel committed
221
void ContactsResource::itemRemoved(const Item &item)
222
{
Laurent Montel's avatar
Laurent Montel committed
223
    if (!canPerformTask()) {
224
        return;
225
226
    }

Laurent Montel's avatar
Laurent Montel committed
227
228
    ContactDeleteJob *deleteJob = new ContactDeleteJob(item.remoteId(), account(), this);
    deleteJob->setProperty(ITEM_PROPERTY, QVariant::fromValue(item));
Laurent Montel's avatar
Laurent Montel committed
229
230
    connect(deleteJob, &ContactDeleteJob::progress, this, &ContactsResource::emitPercent);
    connect(deleteJob, &ContactDeleteJob::finished, this, &ContactsResource::slotGenericJobFinished);
231

Laurent Montel's avatar
Laurent Montel committed
232
    Q_EMIT status(Running, i18nc("@info:status", "Removing contact"));
233
234
}

Laurent Montel's avatar
Laurent Montel committed
235
void ContactsResource::itemLinked(const Item &item, const Collection &collection)
236
{
Laurent Montel's avatar
Laurent Montel committed
237
    if (!canPerformTask<KContacts::Addressee>(item, KContacts::Addressee::mimeType())) {
238
239
        return;
    }
240

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
241
    KContacts::Addressee addressee = item.payload<KContacts::Addressee>();
Laurent Montel's avatar
Laurent Montel committed
242
    ContactPtr contact(new Contact(addressee));
243

Laurent Montel's avatar
Laurent Montel committed
244
    contact->addGroup(collection.remoteId());
245

Laurent Montel's avatar
Laurent Montel committed
246
    ContactModifyJob *modifyJob = new ContactModifyJob(contact, account(), this);
Laurent Montel's avatar
Laurent Montel committed
247
    connect(modifyJob, &ContactModifyJob::finished, this, &ContactsResource::slotGenericJobFinished);
248
249
}

Laurent Montel's avatar
Laurent Montel committed
250
void ContactsResource::itemUnlinked(const Item &item, const Collection &collection)
251
{
Laurent Montel's avatar
Laurent Montel committed
252
    if (!canPerformTask<KContacts::Addressee>(item, KContacts::Addressee::mimeType())) {
253
254
        return;
    }
255

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
256
    KContacts::Addressee addressee = item.payload<KContacts::Addressee>();
Laurent Montel's avatar
Laurent Montel committed
257
    ContactPtr contact(new Contact(addressee));
258

Laurent Montel's avatar
Laurent Montel committed
259
    contact->removeGroup(collection.remoteId());
260

Laurent Montel's avatar
Laurent Montel committed
261
262
    ContactModifyJob *modifyJob = new ContactModifyJob(contact, account(), this);
    modifyJob->setProperty(ITEM_PROPERTY, QVariant::fromValue(item));
Laurent Montel's avatar
Laurent Montel committed
263
    connect(modifyJob, &ContactModifyJob::finished, this, &ContactsResource::slotGenericJobFinished);
264
265
}

Laurent Montel's avatar
Laurent Montel committed
266
void ContactsResource::collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent)
267
{
Laurent Montel's avatar
Laurent Montel committed
268
    Q_UNUSED(parent);
269

Laurent Montel's avatar
Laurent Montel committed
270
    if (!canPerformTask()) {
271
272
273
        return;
    }

Laurent Montel's avatar
Laurent Montel committed
274
275
276
    ContactsGroupPtr group(new ContactsGroup);
    group->setTitle(collection.name());
    group->setIsSystemGroup(false);
277

Laurent Montel's avatar
Laurent Montel committed
278
279
    ContactsGroupCreateJob *createJob = new ContactsGroupCreateJob(group, account(), this);
    createJob->setProperty(COLLECTION_PROPERTY, QVariant::fromValue(collection));
Laurent Montel's avatar
Laurent Montel committed
280
    connect(createJob, &ContactsGroupCreateJob::finished, this, &ContactsResource::slotCreateJobFinished);
281
}
282

Laurent Montel's avatar
Laurent Montel committed
283
void ContactsResource::collectionChanged(const Akonadi::Collection &collection)
284
{
Laurent Montel's avatar
Laurent Montel committed
285
    if (!canPerformTask()) {
286
287
        return;
    }
288

Laurent Montel's avatar
Laurent Montel committed
289
290
    ContactsGroupPtr group(new ContactsGroup());
    group->setId(collection.remoteId());
291

Laurent Montel's avatar
Laurent Montel committed
292
    group->setTitle(collection.displayName());
293

Laurent Montel's avatar
Laurent Montel committed
294
295
    ContactsGroupModifyJob *modifyJob = new ContactsGroupModifyJob(group, account(), this);
    modifyJob->setProperty(COLLECTION_PROPERTY, QVariant::fromValue(collection));
Laurent Montel's avatar
Laurent Montel committed
296
    connect(modifyJob, &ContactsGroupModifyJob::finished, this, &ContactsResource::slotGenericJobFinished);
297
298
}

Laurent Montel's avatar
Laurent Montel committed
299
void ContactsResource::collectionRemoved(const Akonadi::Collection &collection)
300
{
Laurent Montel's avatar
Laurent Montel committed
301
    if (!canPerformTask()) {
302
303
        return;
    }
304

Laurent Montel's avatar
Laurent Montel committed
305
306
    ContactsGroupDeleteJob *deleteJob = new ContactsGroupDeleteJob(collection.remoteId(), account(), this);
    deleteJob->setProperty(COLLECTION_PROPERTY, QVariant::fromValue(collection));
Laurent Montel's avatar
Laurent Montel committed
307
    connect(deleteJob, &ContactsGroupDeleteJob::finished, this, &ContactsResource::slotGenericJobFinished);
308
}
309

Laurent Montel's avatar
Laurent Montel committed
310
void ContactsResource::slotCollectionsRetrieved(KGAPI2::Job *job)
311
{
Laurent Montel's avatar
Laurent Montel committed
312
    if (!handleError(job)) {
313
        return;
314
315
    }

Laurent Montel's avatar
Laurent Montel committed
316
    ContactsGroupFetchJob *fetchJob = qobject_cast<ContactsGroupFetchJob *>(job);
317
318
    const ObjectsList objects = fetchJob->items();

319
    CachePolicy cachePolicy;
Laurent Montel's avatar
Laurent Montel committed
320
321
322
    if (Settings::self()->enableIntervalCheck()) {
        cachePolicy.setInheritFromParent(false);
        cachePolicy.setIntervalCheckTime(Settings::self()->intervalCheckTime());
323
324
    }

325
    m_rootCollection = Collection();
326
    m_rootCollection.setContentMimeTypes({Collection::virtualMimeType(), Collection::mimeType(), KContacts::Addressee::mimeType()});
Laurent Montel's avatar
Laurent Montel committed
327
328
329
330
    m_rootCollection.setRemoteId(MYCONTACTS_REMOTEID);
    m_rootCollection.setName(fetchJob->account()->accountName());
    m_rootCollection.setParentCollection(Collection::root());
    m_rootCollection.setCachePolicy(cachePolicy);
331
    m_rootCollection.setRights(Collection::CanCreateItem
Laurent Montel's avatar
Laurent Montel committed
332
333
                               |Collection::CanChangeItem
                               |Collection::CanDeleteItem);
Laurent Montel's avatar
Laurent Montel committed
334

335
    EntityDisplayAttribute *attr = m_rootCollection.attribute<EntityDisplayAttribute>(Collection::AddIfMissing);
Laurent Montel's avatar
Laurent Montel committed
336
    attr->setDisplayName(fetchJob->account()->accountName());
Laurent Montel's avatar
Laurent Montel committed
337
    attr->setIconName(QStringLiteral("im-google"));
338
339
340

    m_collections[ MYCONTACTS_REMOTEID ] = m_rootCollection;

Laurent Montel's avatar
Laurent Montel committed
341
    for (const ObjectPtr &object : qAsConst(objects)) {
342
343
344
345
        const ContactsGroupPtr group = object.dynamicCast<ContactsGroup>();

        QString realName = group->title();

Laurent Montel's avatar
Laurent Montel committed
346
        if (group->isSystemGroup()) {
Laurent Montel's avatar
Laurent Montel committed
347
            if (group->title().contains(QLatin1String("Coworkers"))) {
Laurent Montel's avatar
Laurent Montel committed
348
                realName = i18nc("Name of a group of contacts", "Coworkers");
Laurent Montel's avatar
Laurent Montel committed
349
            } else if (group->title().contains(QLatin1String("Friends"))) {
Laurent Montel's avatar
Laurent Montel committed
350
                realName = i18nc("Name of a group of contacts", "Friends");
Laurent Montel's avatar
Laurent Montel committed
351
            } else if (group->title().contains(QLatin1String("Family"))) {
Laurent Montel's avatar
Laurent Montel committed
352
                realName = i18nc("Name of a group of contacts", "Family");
Laurent Montel's avatar
Laurent Montel committed
353
            } else if (group->title().contains(QLatin1String("My Contacts"))) {
354
355
356
357
                // Yes, skip My Contacts group, we store "My Contacts" in root collection
                continue;
            }
        } else {
Laurent Montel's avatar
Laurent Montel committed
358
            if (group->title().contains(QLatin1String("Other Contacts"))) {
Laurent Montel's avatar
Laurent Montel committed
359
                realName = i18nc("Name of a group of contacts", "Other Contacts");
360
361
362
363
            }
        }

        Collection collection;
Laurent Montel's avatar
Laurent Montel committed
364
365
366
        collection.setContentMimeTypes(QStringList() << KContacts::Addressee::mimeType());
        collection.setName(group->id());
        collection.setParentCollection(m_rootCollection);
Laurent Montel's avatar
Laurent Montel committed
367
368
369
        collection.setRights(Collection::CanLinkItem
                             |Collection::CanUnlinkItem
                             |Collection::CanChangeItem);
Laurent Montel's avatar
Laurent Montel committed
370
        if (!group->isSystemGroup()) {
Laurent Montel's avatar
Laurent Montel committed
371
372
373
            collection.setRights(collection.rights()
                                 |Collection::CanChangeCollection
                                 |Collection::CanDeleteCollection);
374
        }
Laurent Montel's avatar
Laurent Montel committed
375
376
        collection.setRemoteId(group->id());
        collection.setVirtual(true);
377

Laurent Montel's avatar
Laurent Montel committed
378
379
380
        EntityDisplayAttribute *collAttr = collection.attribute<EntityDisplayAttribute>(Collection::AddIfMissing);
        collAttr->setDisplayName(realName);
        collAttr->setIconName(QStringLiteral("view-pim-contacts"));
381
382

        m_collections[ collection.remoteId() ] = collection;
383
    }
384

385
    Collection otherCollection;
Laurent Montel's avatar
Laurent Montel committed
386
387
388
    otherCollection.setContentMimeTypes(QStringList() << KContacts::Addressee::mimeType());
    otherCollection.setName(i18n("Other Contacts"));
    otherCollection.setParentCollection(m_rootCollection);
Laurent Montel's avatar
Laurent Montel committed
389
390
391
    otherCollection.setRights(Collection::CanCreateItem
                              |Collection::CanChangeItem
                              |Collection::CanDeleteItem);
Laurent Montel's avatar
Laurent Montel committed
392
393
    otherCollection.setRemoteId(OTHERCONTACTS_REMOTEID);

394
    attr = otherCollection.attribute<EntityDisplayAttribute>(Collection::AddIfMissing);
Laurent Montel's avatar
Laurent Montel committed
395
    attr->setDisplayName(i18n("Other Contacts"));
Laurent Montel's avatar
Laurent Montel committed
396
    attr->setIconName(QStringLiteral("view-pim-contacts"));
397
398
    m_collections[ OTHERCONTACTS_REMOTEID ] = otherCollection;

399
    collectionsRetrieved(Akonadi::valuesToVector(m_collections));
400
    job->deleteLater();
401
402
}

Laurent Montel's avatar
Laurent Montel committed
403
void ContactsResource::slotItemsRetrieved(KGAPI2::Job *job)
404
{
Laurent Montel's avatar
Laurent Montel committed
405
    if (!handleError(job)) {
406
407
        return;
    }
408

Laurent Montel's avatar
Laurent Montel committed
409
    ContactFetchJob *fetchJob = qobject_cast<ContactFetchJob *>(job);
410

Laurent Montel's avatar
Laurent Montel committed
411
    Collection collection = fetchJob->property(COLLECTION_PROPERTY).value<Collection>();
412
413
414
415

    Item::List changedItems, removedItems;
    QMap<QString, Item::List> groupsMap;
    QList<QString> changedPhotos;
Laurent Montel's avatar
Laurent Montel committed
416
417
    const ObjectsList objects = fetchJob->items();
    for (const ObjectPtr &object : objects) {
418
419
        const ContactPtr contact = object.dynamicCast<Contact>();

Laurent Montel's avatar
Laurent Montel committed
420
421
        if (((collection.remoteId() == OTHERCONTACTS_REMOTEID) && !contact->groups().isEmpty())
            || ((collection.remoteId() == MYCONTACTS_REMOTEID) && contact->groups().isEmpty())) {
422
423
424
425
            continue;
        }

        Item item;
Laurent Montel's avatar
Laurent Montel committed
426
427
428
429
430
        item.setMimeType(KContacts::Addressee::mimeType());
        item.setParentCollection(m_collections[MYCONTACTS_REMOTEID]);
        item.setRemoteId(contact->uid());
        item.setRemoteRevision(contact->etag());
        item.setPayload<KContacts::Addressee>(*contact.dynamicCast<KContacts::Addressee>());
431

Laurent Montel's avatar
Laurent Montel committed
432
        if (contact->deleted()) {
433
434
435
436
437
438
439
            removedItems << item;
        } else {
            changedItems << item;
            changedPhotos << contact->uid();
        }

        const QStringList groups = contact->groups();
Laurent Montel's avatar
Laurent Montel committed
440
        for (const QString &group : groups) {
441
442
443
            groupsMap[group] << item;
        }
    }
444

Laurent Montel's avatar
Laurent Montel committed
445
    itemsRetrievedIncremental(changedItems, removedItems);
446

Laurent Montel's avatar
Laurent Montel committed
447
    for (QMap<QString, Item::List>::ConstIterator iter = groupsMap.constBegin(), iterEnd = groupsMap.constEnd(); iter != iterEnd; ++iter) {
Laurent Montel's avatar
Laurent Montel committed
448
        new LinkJob(m_collections[iter.key()], iter.value(), this);
449
    }
450
451

    QVariantMap map;
Laurent Montel's avatar
Laurent Montel committed
452
453
    map[QStringLiteral("collection")] = QVariant::fromValue(collection);
    map[QStringLiteral("modifiedItems")] = QVariant::fromValue(changedPhotos);
Laurent Montel's avatar
Laurent Montel committed
454
    scheduleCustomTask(this, "retrieveContactsPhotos", map);
455

Laurent Montel's avatar
Laurent Montel committed
456
457
    const QDateTime local(QDateTime::currentDateTime());
    const QDateTime UTC(local.toUTC());
Laurent Montel's avatar
Laurent Montel committed
458

459
    collection.setRemoteRevision(QString::number(UTC.toSecsSinceEpoch()));
Laurent Montel's avatar
Laurent Montel committed
460
    new CollectionModifyJob(collection, this);
461
462

    job->deleteLater();
463
464
}

Laurent Montel's avatar
Laurent Montel committed
465
void ContactsResource::slotUpdatePhotosItemsRetrieved(KJob *job)
466
{
Laurent Montel's avatar
Laurent Montel committed
467
468
    ItemFetchJob *fetchJob = qobject_cast<ItemFetchJob *>(job);
    const QList<QString> modifiedItems = fetchJob->property("modifiedItems").value< QList<QString> >();
469
470
    ContactsList contacts;

Laurent Montel's avatar
Laurent Montel committed
471
472
    const Item::List items = fetchJob->items();
    for (const Item &item : items) {
Laurent Montel's avatar
Laurent Montel committed
473
        if (modifiedItems.contains(item.remoteId())) {
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
474
            const KContacts::Addressee addressee = item.payload<KContacts::Addressee>();
Laurent Montel's avatar
Laurent Montel committed
475
            const ContactPtr contact(new Contact(addressee));
476
477
478
479
            contacts << contact;
        }
    }

480
    // Make sure account is still valid
Laurent Montel's avatar
Laurent Montel committed
481
    if (!canPerformTask()) {
482
483
484
        return;
    }

Laurent Montel's avatar
Laurent Montel committed
485
486
487
    ContactFetchPhotoJob *photoJob = new ContactFetchPhotoJob(contacts, account(), this);
    photoJob->setProperty(ITEMLIST_PROPERTY, QVariant::fromValue(items));
    photoJob->setProperty("processedItems", 0);
Laurent Montel's avatar
Laurent Montel committed
488
489
    connect(photoJob, &ContactFetchPhotoJob::photoFetched, this, &ContactsResource::slotUpdatePhotoFinished);
    connect(photoJob, &ContactFetchPhotoJob::finished, this, &ContactsResource::slotGenericJobFinished);
490
491
}

Laurent Montel's avatar
Laurent Montel committed
492
void ContactsResource::slotUpdatePhotoFinished(KGAPI2::Job *job, const ContactPtr &contact)
493
{
Laurent Montel's avatar
Laurent Montel committed
494
    Item::List items = job->property(ITEMLIST_PROPERTY).value<Item::List>();
495

Laurent Montel's avatar
Laurent Montel committed
496
    int processedItems = job->property("processedItems").toInt();
497
    processedItems++;
Laurent Montel's avatar
Laurent Montel committed
498
499
    job->setProperty("processedItems", processedItems);
    emitPercent(job, processedItems, items.count());
500

Laurent Montel's avatar
Laurent Montel committed
501
    for (Item item : qAsConst(items)) {
Laurent Montel's avatar
Laurent Montel committed
502
503
504
        if (item.remoteId() == contact->uid()) {
            item.setPayload<KContacts::Addressee>(*contact.dynamicCast<KContacts::Addressee>());
            new ItemModifyJob(item, this);
505
506
507
            return;
        }
    }
508
509
}

Laurent Montel's avatar
Laurent Montel committed
510
void ContactsResource::slotCreateJobFinished(KGAPI2::Job *job)
511
{
Laurent Montel's avatar
Laurent Montel committed
512
    if (!handleError(job)) {
513
514
515
        return;
    }

Laurent Montel's avatar
Laurent Montel committed
516
517
518
519
520
    Item item = job->property(ITEM_PROPERTY).value<Item>();
    Collection collection = job->property(COLLECTION_PROPERTY).value<Collection>();
    if (item.isValid()) {
        ContactCreateJob *createJob = qobject_cast<ContactCreateJob *>(job);
        Q_ASSERT(createJob->items().count() == 1);
521
        ContactPtr contact = createJob->items().at(0).dynamicCast<Contact>();
522

Laurent Montel's avatar
Laurent Montel committed
523
524
525
526
527
528
        item.setRemoteId(contact->uid());
        item.setRemoteRevision(contact->etag());
        changeCommitted(item);
    } else if (collection.isValid()) {
        ContactsGroupCreateJob *createJob = qobject_cast<ContactsGroupCreateJob *>(job);
        Q_ASSERT(createJob->items().count() == 1);
529
        ContactsGroupPtr group = createJob->items().at(0).dynamicCast<ContactsGroup>();
530

Laurent Montel's avatar
Laurent Montel committed
531
532
        collection.setRemoteId(group->id());
        collection.setContentMimeTypes(QStringList() << KContacts::Addressee::mimeType());
533

534
        EntityDisplayAttribute *attr = collection.attribute<EntityDisplayAttribute>(Collection::AddIfMissing);
Laurent Montel's avatar
Laurent Montel committed
535
        attr->setDisplayName(group->title());
Laurent Montel's avatar
Laurent Montel committed
536
        attr->setIconName(QStringLiteral("view-pim-contacts"));
537
538
539

        m_collections[ collection.remoteId() ] = collection;

Laurent Montel's avatar
Laurent Montel committed
540
        changeCommitted(collection);
541
542
543
544
545
    }

    job->deleteLater();
}

Laurent Montel's avatar
Laurent Montel committed
546
AKONADI_RESOURCE_MAIN(ContactsResource)