File indexing completed on 2025-02-02 05:02:29

0001 /*
0002     SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "importexport.h"
0008 
0009 #include "documentmanager.h"
0010 #include "favoritelocationmodel.h"
0011 #include "healthcertificatemanager.h"
0012 #include "livedata.h"
0013 #include "livedatamanager.h"
0014 #include "logging.h"
0015 #include "passmanager.h"
0016 #include "pkpassmanager.h"
0017 #include "reservationmanager.h"
0018 #include "transfer.h"
0019 #include "transfermanager.h"
0020 
0021 #include <KItinerary/File>
0022 #include <KItinerary/JsonLdDocument>
0023 
0024 #include <QFile>
0025 #include <QJsonArray>
0026 #include <QJsonDocument>
0027 #include <QJsonObject>
0028 #include <QSettings>
0029 #include <QTemporaryFile>
0030 
0031 static int copySettings(const QSettings *from, QSettings *to)
0032 {
0033     const auto keys = from->allKeys();
0034     for (const auto &key : keys) {
0035         to->setValue(key, from->value(key));
0036     }
0037     return keys.size();
0038 }
0039 
0040 Exporter::Exporter(KItinerary::File *file)
0041     : m_file(file)
0042 {
0043 }
0044 
0045 void Exporter::exportReservations(const ReservationManager *resMgr)
0046 {
0047     for (const auto &batchId : resMgr->batches()) {
0048         exportReservationBatch(resMgr, batchId);
0049     }
0050 }
0051 
0052 void Exporter::exportReservationBatch(const ReservationManager *resMgr, const QString &batchId)
0053 {
0054     const auto resIds = resMgr->reservationsForBatch(batchId);
0055     for (const auto &resId : resIds) {
0056         m_file->addReservation(resId, resMgr->reservation(resId));
0057     }
0058 }
0059 
0060 void Exporter::exportPasses(const PkPassManager *pkPassMgr)
0061 {
0062     const auto passIds = pkPassMgr->passes();
0063     for (const auto &passId : passIds) {
0064         exportPkPass(pkPassMgr, passId);
0065     }
0066 }
0067 
0068 void Exporter::exportPkPass(const PkPassManager *pkPassMgr, const QString &passId)
0069 {
0070     if (passId.isEmpty()) {
0071         return;
0072     }
0073     m_file->addPass(passId, pkPassMgr->rawData(passId));
0074 }
0075 
0076 void Exporter::exportDocuments(const DocumentManager *docMgr)
0077 {
0078     const auto docIds = docMgr->documents();
0079     for (const auto &docId : docIds) {
0080         exportDocument(docMgr, docId);
0081     }
0082 }
0083 
0084 void Exporter::exportDocument(const DocumentManager *docMgr, const QString &docId)
0085 {
0086     const auto fileName = docMgr->documentFilePath(docId);
0087     QFile file(fileName);
0088     if (!file.open(QFile::ReadOnly)) {
0089         qCWarning(Log) << "failed to open" << fileName << "for exporting" << file.errorString();
0090         return;
0091     }
0092     m_file->addDocument(docId, docMgr->documentInfo(docId), file.readAll());
0093 }
0094 
0095 void Exporter::exportTransfers(const ReservationManager *resMgr, const TransferManager *transferMgr)
0096 {
0097     for (const auto &batchId : resMgr->batches()) {
0098         exportTransfersForBatch(batchId, transferMgr);
0099     }
0100 }
0101 
0102 void Exporter::exportTransfersForBatch(const QString &batchId, const TransferManager *transferMgr)
0103 {
0104     const auto transferDomain = QStringLiteral("org.kde.itinerary/transfers");
0105     auto t = transferMgr->transfer(batchId, Transfer::Before);
0106     if (t.state() != Transfer::UndefinedState) {
0107         m_file->addCustomData(transferDomain, t.identifier(), QJsonDocument(Transfer::toJson(t)).toJson());
0108     }
0109     t = transferMgr->transfer(batchId, Transfer::After);
0110     if (t.state() != Transfer::UndefinedState) {
0111         m_file->addCustomData(transferDomain, t.identifier(), QJsonDocument(Transfer::toJson(t)).toJson());
0112     }
0113 }
0114 
0115 void Exporter::exportFavoriteLocations(const FavoriteLocationModel* favLocModel)
0116 {
0117     // export favorite locations
0118     if (favLocModel->rowCount() > 0) {
0119         m_file->addCustomData(QStringLiteral("org.kde.itinerary/favorite-locations"), QStringLiteral("locations"),
0120                         QJsonDocument(FavoriteLocation::toJson(favLocModel->favoriteLocations())).toJson());
0121     }
0122 }
0123 
0124 void Exporter::exportPasses(const PassManager *passMgr)
0125 {
0126     for (int i = 0; i < passMgr->rowCount(); ++i) {
0127         const auto idx = passMgr->index(i, 0);
0128         m_file->addCustomData(
0129             QStringLiteral("org.kde.itinerary/programs"),
0130             passMgr->data(idx, PassManager::PassIdRole).toString(),
0131             passMgr->data(idx, PassManager::PassDataRole).toByteArray()
0132         );
0133     }
0134 }
0135 
0136 void Exporter::exportHealthCertificates(const HealthCertificateManager *healthCertMgr)
0137 {
0138     for (int i = 0; i < healthCertMgr->rowCount(); ++i) {
0139         const auto idx = healthCertMgr->index(i, 0);
0140         m_file->addCustomData(
0141             QStringLiteral("org.kde.itinerary/health-certificates"),
0142             healthCertMgr->data(idx, HealthCertificateManager::StorageIdRole).toString(),
0143             healthCertMgr->data(idx, HealthCertificateManager::RawDataRole).toByteArray());
0144     }
0145 }
0146 
0147 void Exporter::exportLiveData()
0148 {
0149     for (const auto &id : LiveData::listAll()) {
0150         exportLiveDataForBatch(id);
0151     }
0152 }
0153 
0154 void Exporter::exportLiveDataForBatch(const QString &batchId)
0155 {
0156     const auto ld = LiveData::load(batchId);
0157     if (ld.isEmpty()) {
0158         return;
0159     }
0160 
0161     QJsonObject obj;
0162     obj.insert(QStringLiteral("departure"), KPublicTransport::Stopover::toJson(ld.departure));
0163     obj.insert(QStringLiteral("departureTimestamp"), ld.departureTimestamp.toString(Qt::ISODate));
0164     obj.insert(QStringLiteral("arrival"), KPublicTransport::Stopover::toJson(ld.arrival));
0165     obj.insert(QStringLiteral("arrivalTimestamp"), ld.arrivalTimestamp.toString(Qt::ISODate));
0166     obj.insert(QStringLiteral("journey"), KPublicTransport::JourneySection::toJson(ld.journey));
0167     obj.insert(QStringLiteral("journeyTimestamp"), ld.journeyTimestamp.toString(Qt::ISODate));
0168 
0169     m_file->addCustomData(QStringLiteral("org.kde.itinerary/live-data"), batchId, QJsonDocument(obj).toJson());
0170 }
0171 
0172 void Exporter::exportSettings()
0173 {
0174     QTemporaryFile tmp;
0175     if (!tmp.open()) {
0176         qCWarning(Log) << "Failed to open temporary file:" << tmp.errorString();
0177         return;
0178     }
0179 
0180     QSettings settings;
0181     QSettings backup(tmp.fileName(), QSettings::IniFormat);
0182     tmp.close();
0183     copySettings(&settings, &backup);
0184     backup.sync();
0185 
0186     QFile f(backup.fileName());
0187     f.open(QFile::ReadOnly);
0188     m_file->addCustomData(QStringLiteral("org.kde.itinerary/settings"), QStringLiteral("settings.ini"), f.readAll());
0189 }
0190 
0191 
0192 Importer::Importer(const KItinerary::File *file)
0193     : m_file(file)
0194 {
0195 }
0196 
0197 int Importer::importReservations(ReservationManager *resMgr)
0198 {
0199     const auto resIds = m_file->reservations();
0200     for (const auto &resId : resIds) {
0201         resMgr->addReservation(m_file->reservation(resId), resId);
0202     }
0203     return resIds.size();
0204 }
0205 
0206 int Importer::importPasses(PkPassManager *pkPassMgr)
0207 {
0208     const auto passIds = m_file->passes();
0209     for (const auto &passId : passIds) {
0210         pkPassMgr->importPassFromData(m_file->passData(passId));
0211     }
0212     return passIds.size();
0213 }
0214 
0215 int Importer::importDocuments(DocumentManager* docMgr)
0216 {
0217     const auto docIds = m_file->documents();
0218     for (const auto &docId : docIds) {
0219         docMgr->addDocument(docId, m_file->documentInfo(docId), m_file->documentData(docId));
0220     }
0221     return docIds.size();
0222 }
0223 
0224 int Importer::importTransfers(const ReservationManager *resMgr, TransferManager *transferMgr)
0225 {
0226     int count = 0;
0227     const auto transferDomain = QStringLiteral("org.kde.itinerary/transfers");
0228     const auto resIds = m_file->reservations();
0229     for (const auto &batchId : resIds) {
0230         auto t = Transfer::fromJson(QJsonDocument::fromJson(m_file->customData(transferDomain, Transfer::identifier(batchId, Transfer::Before))).object());
0231         transferMgr->importTransfer(t);
0232         count += t.state() != Transfer::UndefinedState ? 1 : 0;
0233         t = Transfer::fromJson(QJsonDocument::fromJson(m_file->customData(transferDomain, Transfer::identifier(batchId, Transfer::After))).object());
0234         transferMgr->importTransfer(t);
0235         count += t.state() != Transfer::UndefinedState ? 1 : 0;
0236     }
0237     return count;
0238 }
0239 
0240 int Importer::importFavoriteLocations(FavoriteLocationModel *favLocModel)
0241 {
0242     auto favLocs = FavoriteLocation::fromJson(QJsonDocument::fromJson(m_file->customData(QStringLiteral("org.kde.itinerary/favorite-locations"), QStringLiteral("locations"))).array());
0243     if (!favLocs.empty()) {
0244         favLocModel->setFavoriteLocations(std::move(favLocs));
0245     }
0246     return favLocs.size();
0247 }
0248 
0249 int Importer::importPasses(PassManager *passMgr)
0250 {
0251     const auto domain = QStringLiteral("org.kde.itinerary/programs");
0252     const auto ids = m_file->listCustomData(domain);
0253     for (const auto &id : ids) {
0254         const auto data = m_file->customData(domain, id);
0255         const auto pass = KItinerary::JsonLdDocument::fromJsonSingular(QJsonDocument::fromJson(data).object());
0256         passMgr->import(pass, id);
0257     }
0258     return ids.size();
0259 }
0260 
0261 int Importer::importHealthCertificates(HealthCertificateManager *healthCertMgr)
0262 {
0263     const auto domain = QStringLiteral("org.kde.itinerary/health-certificates");
0264     const auto certIds = m_file->listCustomData(domain);
0265     for (const auto &certId : certIds) {
0266         healthCertMgr->importCertificate(m_file->customData(domain, certId));
0267     }
0268     return certIds.size();
0269 }
0270 
0271 int Importer::importLiveData(LiveDataManager *liveDataMgr)
0272 {
0273     const auto ids = m_file->listCustomData(QStringLiteral("org.kde.itinerary/live-data"));
0274     for (const auto &id : ids) {
0275         const auto obj = QJsonDocument::fromJson(m_file->customData(QStringLiteral("org.kde.itinerary/live-data"), id)).object();
0276 
0277         LiveData ld;
0278         ld.departure = KPublicTransport::Stopover::fromJson(obj.value(QLatin1StringView("departure")).toObject());
0279         ld.departureTimestamp = QDateTime::fromString(obj.value(QLatin1StringView("departureTimestamp")).toString(), Qt::ISODate);
0280         ld.arrival = KPublicTransport::Stopover::fromJson(obj.value(QLatin1StringView("arrival")).toObject());
0281         ld.arrivalTimestamp = QDateTime::fromString(obj.value(QLatin1StringView("arrivalTimestamp")).toString(), Qt::ISODate);
0282         ld.journey = KPublicTransport::JourneySection::fromJson(obj.value(QLatin1StringView("journey")).toObject());
0283         ld.journeyTimestamp = QDateTime::fromString(obj.value(QLatin1StringView("journeyTimestamp")).toString(), Qt::ISODate);
0284 
0285         ld.store(id);
0286         liveDataMgr->importData(id, std::move(ld));
0287     }
0288     return ids.size();
0289 }
0290 
0291 int Importer::importSettings()
0292 {
0293     const auto iniData = m_file->customData(QStringLiteral("org.kde.itinerary/settings"), QStringLiteral("settings.ini"));
0294     if (iniData.isEmpty()) {
0295         return 0;
0296     }
0297 
0298     QTemporaryFile tmp;
0299     if (!tmp.open()) {
0300         qCWarning(Log) << "Failed to open temporary file:" << tmp.errorString();
0301         return 0;
0302     }
0303     tmp.write(iniData);
0304     tmp.close();
0305 
0306     QSettings settings;
0307     const QSettings backup(tmp.fileName(), QSettings::IniFormat);
0308     return copySettings(&backup, &settings);
0309 }