File indexing completed on 2024-05-12 05:22:28
0001 /* 0002 * SPDX-FileCopyrightText: 2022 Claudio Cambra <claudio.cambra@kde.org> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include "peopleservice.h" 0008 #include "contactgroup.h" 0009 #include "debug.h" 0010 #include "person.h" 0011 0012 #include <QJsonDocument> 0013 #include <QJsonObject> 0014 #include <QJsonArray> 0015 #include <QUrlQuery> 0016 0017 /* Qt::escape() */ 0018 #include <QTextDocument> 0019 0020 namespace KGAPI2::People 0021 { 0022 0023 namespace PeopleService 0024 { 0025 0026 namespace Private 0027 { 0028 0029 enum FetchType { 0030 PersonFetch, 0031 ContactGroupFetch 0032 }; 0033 0034 static const QUrl GoogleApisUrl(QStringLiteral("https://people.googleapis.com")); 0035 static const auto PeopleV1Path = QStringLiteral("/v1/"); 0036 static const auto PeopleBasePath = QString(PeopleV1Path % QStringLiteral("people")); 0037 static const auto ContactGroupsBasePath = QString(PeopleV1Path % QStringLiteral("contactGroups")); 0038 0039 static const auto AllPersonFields = QStringLiteral("addresses," 0040 "ageRanges," 0041 "biographies," 0042 "birthdays," 0043 "calendarUrls," 0044 "clientData," 0045 "coverPhotos," 0046 "emailAddresses," 0047 "events," 0048 "externalIds," 0049 "genders," 0050 "imClients," 0051 "interests," 0052 "locales," 0053 "locations," 0054 "memberships," 0055 "metadata," 0056 "miscKeywords," 0057 "names," 0058 "nicknames," 0059 "occupations," 0060 "organizations," 0061 "phoneNumbers," 0062 "photos," 0063 "relations," 0064 "sipAddresses," 0065 "skills," 0066 "urls," 0067 "userDefined"); 0068 0069 static const auto AllUpdatablePersonFields = QStringLiteral("addresses," 0070 "biographies," 0071 "birthdays," 0072 "calendarUrls," 0073 "clientData," 0074 "emailAddresses," 0075 "events," 0076 "externalIds," 0077 "genders," 0078 "imClients," 0079 "interests," 0080 "locales," 0081 "locations," 0082 "memberships," 0083 "miscKeywords," 0084 "names," 0085 "nicknames," 0086 "occupations," 0087 "organizations," 0088 "phoneNumbers," 0089 "relations," 0090 "sipAddresses," 0091 "urls," 0092 "userDefined"); 0093 0094 static const auto AllGroupFields = QStringLiteral("clientData," 0095 "groupType," 0096 "memberCount," 0097 "metadata," 0098 "name"); 0099 0100 static const auto AllRecentlyCreatedAvailableGroupFields = QStringLiteral("clientData," 0101 "groupType," 0102 "metadata," 0103 "name"); 0104 0105 void writeNextPageDataQuery(FetchType fetchType, FeedData &feedData, const QJsonObject &replyRootObject, const QString &syncToken = {}) 0106 { 0107 if(!replyRootObject.contains(QStringLiteral("nextPageToken"))) { 0108 return; 0109 } 0110 0111 QUrl url; 0112 if (fetchType == PersonFetch) { 0113 url = fetchAllContactsUrl(syncToken); 0114 } else if (fetchType == ContactGroupFetch) { 0115 url = fetchAllContactGroupsUrl(); 0116 } else { 0117 qCDebug(KGAPIDebug) << "Unknown type of fetch, cannot write next page data query"; 0118 return; 0119 } 0120 0121 QUrlQuery query(url); 0122 query.addQueryItem(QStringLiteral("pageToken"), replyRootObject.value(QStringLiteral("nextPageToken")).toString()); 0123 0124 url.setQuery(query); 0125 feedData.nextPageUrl = url; 0126 } 0127 0128 } // Private 0129 0130 QString allPersonFields() 0131 { 0132 return Private::AllPersonFields; 0133 } 0134 0135 QString allUpdatablePersonFields() 0136 { 0137 return Private::AllUpdatablePersonFields; 0138 } 0139 0140 QString allContactGroupRecentlyCreatedAvailableFields() 0141 { 0142 return Private::AllRecentlyCreatedAvailableGroupFields; 0143 } 0144 0145 ObjectPtr JSONToPerson(const QByteArray &jsonData) 0146 { 0147 QJsonDocument document = QJsonDocument::fromJson(jsonData); 0148 if(document.isObject()) { 0149 const auto objectifiedDocument = document.object(); 0150 const auto resourceName = objectifiedDocument.value(QStringLiteral("resourceName")).toString(); 0151 0152 return resourceName.startsWith(QStringLiteral("people")) ? People::Person::fromJSON(objectifiedDocument) : People::PersonPtr(); 0153 } 0154 0155 return People::PersonPtr(); 0156 } 0157 0158 QUrl fetchAllContactsUrl(const QString &syncToken) 0159 { 0160 QUrl url(Private::GoogleApisUrl); 0161 const QString path = Private::PeopleBasePath % QStringLiteral("/me/connections"); 0162 url.setPath(path); 0163 0164 QUrlQuery query(url); 0165 query.addQueryItem(QStringLiteral("personFields"), Private::AllPersonFields); 0166 query.addQueryItem(QStringLiteral("requestSyncToken"), QStringLiteral("true")); 0167 0168 if (!syncToken.isEmpty()) { 0169 query.addQueryItem(QStringLiteral("syncToken"), syncToken); 0170 } 0171 0172 url.setQuery(query); 0173 return url; 0174 } 0175 0176 // https://developers.google.com/people/api/rest/v1/people/searchContacts 0177 QUrl fetchContactUrl(const QString &resourceName) 0178 { 0179 QUrl url(Private::GoogleApisUrl); 0180 const QString path = Private::PeopleV1Path % resourceName; 0181 url.setPath(path); 0182 0183 QUrlQuery query(url); 0184 query.addQueryItem(QStringLiteral("personFields"), Private::AllPersonFields); 0185 0186 url.setQuery(query); 0187 return url; 0188 } 0189 0190 QUrl createContactUrl() 0191 { 0192 QUrl url(Private::GoogleApisUrl); 0193 const QString path = Private::PeopleBasePath % QStringLiteral(":createContact"); 0194 url.setPath(path); 0195 return url; 0196 } 0197 0198 QUrl updateContactUrl(const QString &resourceName, const QString &personFields) 0199 { 0200 QUrl url(Private::GoogleApisUrl); 0201 url.setPath(Private::PeopleV1Path % resourceName % QStringLiteral(":updateContact")); 0202 0203 QUrlQuery query(url); 0204 query.addQueryItem(QStringLiteral("updatePersonFields"), personFields); 0205 0206 url.setQuery(query); 0207 return url; 0208 } 0209 0210 QUrl deleteContactUrl(const QString &resourceName) 0211 { 0212 QUrl url(Private::GoogleApisUrl); 0213 url.setPath(Private::PeopleV1Path % resourceName % QStringLiteral(":deleteContact")); 0214 return url; 0215 } 0216 0217 QUrl fetchAllContactGroupsUrl() 0218 { 0219 QUrl url(Private::GoogleApisUrl); 0220 url.setPath(Private::ContactGroupsBasePath); 0221 0222 QUrlQuery query(url); 0223 query.addQueryItem(QStringLiteral("groupFields"), Private::AllGroupFields); 0224 0225 url.setQuery(query); 0226 0227 return url; 0228 } 0229 0230 // https://developers.google.com/people/api/rest/v1/contactGroups/get 0231 QUrl fetchContactGroupUrl(const QString &resourceName) 0232 { 0233 QUrl url(Private::GoogleApisUrl); 0234 const QString path = Private::PeopleV1Path % resourceName; 0235 url.setPath(path); 0236 0237 QUrlQuery query(url); 0238 query.addQueryItem(QStringLiteral("groupFields"), Private::AllGroupFields); 0239 0240 url.setQuery(query); 0241 return url; 0242 } 0243 0244 QUrl createContactGroupUrl() 0245 { 0246 QUrl url(Private::GoogleApisUrl); 0247 url.setPath(Private::ContactGroupsBasePath); 0248 return url; 0249 } 0250 0251 QUrl updateContactGroupUrl(const QString &resourceName) 0252 { 0253 QUrl url(Private::GoogleApisUrl); 0254 const QString path = Private::PeopleV1Path % resourceName; 0255 url.setPath(path); 0256 return url; 0257 } 0258 0259 QUrl deleteContactGroupUrl(const QString &resourceName, const bool deleteContacts) 0260 { 0261 QUrl url(Private::GoogleApisUrl); 0262 url.setPath(Private::PeopleV1Path % resourceName); 0263 0264 const auto deleteContactsString = deleteContacts ? QStringLiteral("true") : QStringLiteral("false"); 0265 QUrlQuery query(url); 0266 query.addQueryItem(QStringLiteral("deleteContacts"), deleteContactsString); 0267 0268 url.setQuery(query); 0269 return url; 0270 } 0271 0272 QUrl updateContactPhotoUrl(const QString &resourceName) 0273 { 0274 QUrl url(Private::GoogleApisUrl); 0275 url.setPath(Private::PeopleV1Path % resourceName % QStringLiteral(":updateContactPhoto")); 0276 return url; 0277 } 0278 0279 QUrl deleteContactPhotoUrl(const QString &resourceName, const QString &personFields) 0280 { 0281 QUrl url(Private::GoogleApisUrl); 0282 url.setPath(Private::PeopleV1Path % resourceName % QStringLiteral(":deleteContactPhoto")); 0283 0284 QUrlQuery query(url); 0285 query.addQueryItem(QStringLiteral("personFields"), personFields); 0286 0287 url.setQuery(query); 0288 return url; 0289 } 0290 0291 ObjectsList parseConnectionsJSONFeed(FeedData &feedData, const QByteArray &jsonFeed, const QString &syncToken) 0292 { 0293 const auto document = QJsonDocument::fromJson(jsonFeed); 0294 0295 if (!document.isObject()) { 0296 return {}; 0297 } 0298 0299 ObjectsList output; 0300 0301 const auto rootObject = document.object(); 0302 const auto connections = rootObject.value(QStringLiteral("connections")).toArray(); 0303 for(const auto &connection : connections) { 0304 output.append(People::Person::fromJSON(connection.toObject())); 0305 } 0306 0307 feedData.totalResults = rootObject.value(QStringLiteral("totalItems")).toInt(); 0308 0309 Private::writeNextPageDataQuery(Private::PersonFetch, feedData, rootObject, syncToken); 0310 feedData.syncToken = rootObject.value(QStringLiteral("nextSyncToken")).toString(); 0311 0312 return output; 0313 } 0314 0315 ObjectsList parseContactGroupsJSONFeed(FeedData &feedData, const QByteArray &jsonFeed) 0316 { 0317 // qDebug() << jsonFeed; 0318 const auto document = QJsonDocument::fromJson(jsonFeed); 0319 0320 if (!document.isObject()) { 0321 return {}; 0322 } 0323 0324 ObjectsList output; 0325 0326 const auto rootObject = document.object(); 0327 const auto contactGroups = rootObject.value(QStringLiteral("contactGroups")).toArray(); 0328 for(const auto &contactGroup : contactGroups) { 0329 output.append(People::ContactGroup::fromJSON(contactGroup.toObject())); 0330 } 0331 0332 feedData.totalResults = rootObject.value(QStringLiteral("totalItems")).toInt(); 0333 0334 Private::writeNextPageDataQuery(Private::ContactGroupFetch, feedData, rootObject); 0335 0336 return output; 0337 } 0338 0339 } 0340 0341 namespace PeopleUtils 0342 { 0343 0344 void addValueToJsonObjectIfValid(QJsonObject &object, const QByteArray &key, const int value) 0345 { 0346 object.insert(QString::fromUtf8(key), value); 0347 } 0348 0349 void addValueToJsonObjectIfValid(QJsonObject &object, const QByteArray &key, const bool value) 0350 { 0351 object.insert(QString::fromUtf8(key), value); 0352 } 0353 0354 void addValueToJsonObjectIfValid(QJsonObject &object, const QByteArray &key, const QString &value) 0355 { 0356 if (!value.isEmpty()) { 0357 object.insert(QString::fromUtf8(key), value); 0358 } 0359 } 0360 0361 void addValueToJsonObjectIfValid(QJsonObject &object, const QByteArray &key, const QJsonValue &value) 0362 { 0363 if (!value.isNull() || !value.isUndefined()) { 0364 object.insert(QString::fromUtf8(key), value); 0365 } 0366 } 0367 0368 0369 } 0370 0371 }