1 /*
2     SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
3 
4     SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "accessibilitycloudbackend.h"
8 #include "accessibilitycloudparser.h"
9 #include "cache.h"
10 
11 #include <KPublicTransport/Location>
12 #include <KPublicTransport/LocationRequest>
13 #include <KPublicTransport/LocationReply>
14 
15 #include <QDebug>
16 #include <QNetworkRequest>
17 #include <QNetworkReply>
18 #include <QNetworkAccessManager>
19 #include <QUrl>
20 #include <QUrlQuery>
21 
22 using namespace KPublicTransport;
23 
24 AccessibilityCloudBackend::AccessibilityCloudBackend() = default;
25 AccessibilityCloudBackend::~AccessibilityCloudBackend() = default;
26 
capabilities() const27 AbstractBackend::Capabilities AccessibilityCloudBackend::capabilities() const
28 {
29     return AbstractBackend::Secure; // hardcoded below
30 }
31 
queryLocation(const LocationRequest & req,LocationReply * reply,QNetworkAccessManager * nam) const32 bool AccessibilityCloudBackend::queryLocation(const LocationRequest &req, LocationReply *reply, QNetworkAccessManager *nam) const
33 {
34     if ((req.types() & Location::Equipment) == 0 || !req.hasCoordinate()) {
35         return false;
36     }
37 
38     QUrl url;
39     url.setScheme(QStringLiteral("https"));
40     url.setHost(QStringLiteral("accessibility-cloud.freetls.fastly.net"));
41     url.setPath(QStringLiteral("/equipment-infos"));
42     QUrlQuery query;
43     query.addQueryItem(QStringLiteral("latitude"), QString::number(req.latitude()));
44     query.addQueryItem(QStringLiteral("longitude"), QString::number(req.longitude()));
45     query.addQueryItem(QStringLiteral("accuracy"), QString::number(req.maximumDistance()));
46     query.addQueryItem(QStringLiteral("appToken"), m_token);
47     url.setQuery(query);
48 
49     QNetworkRequest netReq(url);
50     netReq.setRawHeader("Accept", "application/json");
51     logRequest(req, netReq);
52 
53     auto netReply = nam->get(netReq);
54     QObject::connect(netReply, &QNetworkReply::finished, reply, [this, netReply, reply] {
55         netReply->deleteLater();
56         const auto data = netReply->readAll();
57         logReply(reply, netReply, data);
58         if (netReply->error()) {
59             addError(reply, Reply::NetworkError, netReply->errorString());
60             return;
61         }
62 
63         AccessibilityCloudParser parser;
64         if (parser.parseLocations(data)) {
65             if (parser.locations.empty()) {
66                 addError(reply, Reply::NotFoundError, {});
67             } else {
68                 Cache::addLocationCacheEntry(backendId(), reply->request().cacheKey(), parser.locations, parser.attributions, std::chrono::minutes(5));
69                 addAttributions(reply, std::move(parser.attributions));
70                 addResult(reply, std::move(parser.locations));
71             }
72         } else {
73             addError(reply, Reply::UnknownError, {});
74         }
75     });
76 
77     return true;
78 }
79