File indexing completed on 2024-05-12 05:22:13

0001 /*
0002  * This file is part of LibKGAPI library
0003  *
0004  * SPDX-FileCopyrightText: 2013 Daniel Vrátil <dvratil@redhat.com>
0005  *
0006  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007  */
0008 
0009 #include "eventfetchjob.h"
0010 #include "account.h"
0011 #include "calendarservice.h"
0012 #include "debug.h"
0013 #include "event.h"
0014 #include "utils.h"
0015 
0016 #include <QNetworkReply>
0017 #include <QNetworkRequest>
0018 #include <QUrlQuery>
0019 
0020 using namespace KGAPI2;
0021 
0022 class Q_DECL_HIDDEN EventFetchJob::Private
0023 {
0024 public:
0025     QString calendarId;
0026     QString eventId;
0027     QString filter;
0028     QString syncToken;
0029     bool fetchDeleted = true;
0030     quint64 updatedTimestamp = 0;
0031     quint64 timeMin = 0;
0032     quint64 timeMax = 0;
0033 };
0034 
0035 EventFetchJob::EventFetchJob(const QString &calendarId, const AccountPtr &account, QObject *parent)
0036     : FetchJob(account, parent)
0037     , d(new Private)
0038 {
0039     d->calendarId = calendarId;
0040 }
0041 
0042 EventFetchJob::EventFetchJob(const QString &eventId, const QString &calendarId, const AccountPtr &account, QObject *parent)
0043     : FetchJob(account, parent)
0044     , d(new Private)
0045 {
0046     d->calendarId = calendarId;
0047     d->eventId = eventId;
0048 }
0049 
0050 EventFetchJob::~EventFetchJob() = default;
0051 
0052 void EventFetchJob::setFetchDeleted(bool fetchDeleted)
0053 {
0054     if (isRunning()) {
0055         qCWarning(KGAPIDebug) << "Can't modify fetchDeleted property when job is running";
0056         return;
0057     }
0058 
0059     d->fetchDeleted = fetchDeleted;
0060 }
0061 
0062 bool EventFetchJob::fetchDeleted()
0063 {
0064     return d->fetchDeleted;
0065 }
0066 
0067 void EventFetchJob::setFetchOnlyUpdated(quint64 timestamp)
0068 {
0069     if (isRunning()) {
0070         qCWarning(KGAPIDebug) << "Can't modify setFetchOnlyUpdated property when job is running";
0071         return;
0072     }
0073 
0074     d->updatedTimestamp = timestamp;
0075 }
0076 
0077 quint64 EventFetchJob::fetchOnlyUpdated() const
0078 {
0079     return d->updatedTimestamp;
0080 }
0081 
0082 void EventFetchJob::setTimeMax(quint64 timestamp)
0083 {
0084     if (isRunning()) {
0085         qCWarning(KGAPIDebug) << "Can't modify timeMax property when job is running";
0086         return;
0087     }
0088 
0089     d->timeMax = timestamp;
0090 }
0091 
0092 quint64 EventFetchJob::timeMax() const
0093 {
0094     return d->timeMax;
0095 }
0096 
0097 void EventFetchJob::setSyncToken(const QString &syncToken)
0098 {
0099     d->syncToken = syncToken;
0100 }
0101 
0102 QString EventFetchJob::syncToken() const
0103 {
0104     return d->syncToken;
0105 }
0106 
0107 void EventFetchJob::setTimeMin(quint64 timestamp)
0108 {
0109     if (isRunning()) {
0110         qCWarning(KGAPIDebug) << "Can't modify timeMin property when job is running";
0111         return;
0112     }
0113 
0114     d->timeMin = timestamp;
0115 }
0116 
0117 quint64 EventFetchJob::timeMin() const
0118 {
0119     return d->timeMin;
0120 }
0121 
0122 void EventFetchJob::setFilter(const QString &query)
0123 {
0124     if (isRunning()) {
0125         qCWarning(KGAPIDebug) << "Can't modify filter property when job is running";
0126         return;
0127     }
0128 
0129     d->filter = query;
0130 }
0131 
0132 QString EventFetchJob::filter() const
0133 {
0134     return d->filter;
0135 }
0136 
0137 void EventFetchJob::start()
0138 {
0139     QUrl url;
0140     if (d->eventId.isEmpty()) {
0141         url = CalendarService::fetchEventsUrl(d->calendarId);
0142         QUrlQuery query(url);
0143         query.addQueryItem(QStringLiteral("showDeleted"), Utils::bool2Str(d->fetchDeleted));
0144         if (!d->filter.isEmpty()) {
0145             query.addQueryItem(QStringLiteral("q"), d->filter);
0146         }
0147         if (d->syncToken.isEmpty()) {
0148             if (d->updatedTimestamp > 0) {
0149                 query.addQueryItem(QStringLiteral("updatedMin"), Utils::ts2Str(d->updatedTimestamp));
0150             }
0151             if (d->timeMin > 0) {
0152                 query.addQueryItem(QStringLiteral("timeMin"), Utils::ts2Str(d->timeMin));
0153             }
0154             if (d->timeMax > 0) {
0155                 query.addQueryItem(QStringLiteral("timeMax"), Utils::ts2Str(d->timeMax));
0156             }
0157         } else {
0158             query.addQueryItem(QStringLiteral("syncToken"), d->syncToken);
0159         }
0160         url.setQuery(query);
0161     } else {
0162         url = CalendarService::fetchEventUrl(d->calendarId, d->eventId);
0163     }
0164     const QNetworkRequest request = CalendarService::prepareRequest(url);
0165     enqueueRequest(request);
0166 }
0167 
0168 ObjectsList EventFetchJob::handleReplyWithItems(const QNetworkReply *reply, const QByteArray &rawData)
0169 {
0170     if (reply->error() == QNetworkReply::ContentGoneError || reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == Gone) {
0171         // Full sync required by server, redo request with no updatedMin and no syncToken
0172         d->updatedTimestamp = 0;
0173         d->syncToken.clear();
0174         start();
0175         // Errors are not cleared on success
0176         // Do it here or else the job will fail
0177         setError(KGAPI2::NoError);
0178         setErrorString(QString());
0179         return ObjectsList();
0180     }
0181 
0182     FeedData feedData;
0183     feedData.requestUrl = reply->url();
0184     ObjectsList items;
0185     const QString contentType = reply->header(QNetworkRequest::ContentTypeHeader).toString();
0186     ContentType ct = Utils::stringToContentType(contentType);
0187     if (ct == KGAPI2::JSON) {
0188         if (d->eventId.isEmpty()) {
0189             items = CalendarService::parseEventJSONFeed(rawData, feedData);
0190         } else {
0191             items << CalendarService::JSONToEvent(rawData).dynamicCast<Object>();
0192         }
0193         d->syncToken = feedData.syncToken;
0194     } else {
0195         setError(KGAPI2::InvalidResponse);
0196         setErrorString(tr("Invalid response content type"));
0197         emitFinished();
0198         return items;
0199     }
0200 
0201     if (feedData.nextPageUrl.isValid()) {
0202         const auto request = CalendarService::prepareRequest(feedData.nextPageUrl);
0203         enqueueRequest(request);
0204     }
0205 
0206     return items;
0207 }