Commit d7d480f0 authored by Volker Krause's avatar Volker Krause
Browse files

Implement import/export for generic passes

parent bab3630f
......@@ -12,6 +12,7 @@
#include <documentmanager.h>
#include <favoritelocationmodel.h>
#include <healthcertificatemanager.h>
#include <passmanager.h>
#include <transfermanager.h>
#include <tripgroupmanager.h>
......@@ -28,13 +29,6 @@ class AppControllerTest : public QObject
{
Q_OBJECT
private:
QByteArray readFile(const QString &fn)
{
QFile f(fn);
f.open(QFile::ReadOnly);
return f.readAll();
}
bool hasZxing()
{
return KItinerary::ExtractorCapabilities::capabilitiesString().contains(QLatin1String("zxing"), Qt::CaseInsensitive);
......@@ -71,11 +65,11 @@ private Q_SLOTS:
appController.setDocumentManager(&docMgr);
appController.setHealthCertificateManager(&healthCertMgr);
appController.importData(readFile(QLatin1String(SOURCE_DIR "/data/4U8465-v1.json")));
appController.importData(Test::readFile(QLatin1String(SOURCE_DIR "/data/4U8465-v1.json")));
QCOMPARE(resSpy.size(), 1);
QCOMPARE(passSpy.size(), 0);
QCOMPARE(infoSpy.size(), 1);
appController.importData(readFile(QLatin1String(SOURCE_DIR "/data/boardingpass-v1.pkpass")));
appController.importData(Test::readFile(QLatin1String(SOURCE_DIR "/data/boardingpass-v1.pkpass")));
QCOMPARE(resSpy.size(), 2);
QCOMPARE(passSpy.size(), 1);
QCOMPARE(infoSpy.size(), 2);
......@@ -83,7 +77,7 @@ private Q_SLOTS:
QCOMPARE(resSpy.size(), 3);
QCOMPARE(passSpy.size(), 1);
QCOMPARE(infoSpy.size(), 3);
appController.importData(readFile(QLatin1String(SOURCE_DIR "/data/iata-bcbp-demo.pdf")));
appController.importData(Test::readFile(QLatin1String(SOURCE_DIR "/data/iata-bcbp-demo.pdf")));
if (!hasZxing()) {
QSKIP("Built without ZXing");
}
......@@ -137,8 +131,8 @@ private Q_SLOTS:
void testExportFile()
{
PkPassManager passMgr;
Test::clearAll(&passMgr);
PkPassManager pkPassMgr;
Test::clearAll(&pkPassMgr);
ReservationManager resMgr;
Test::clearAll(&resMgr);
......@@ -154,56 +148,66 @@ private Q_SLOTS:
FavoriteLocationModel favLoc;
PassManager passMgr;
Test::clearAll(&passMgr);
HealthCertificateManager healthCertMgr;
ApplicationController appController;
QSignalSpy infoSpy(&appController, &ApplicationController::infoMessage);
appController.setPkPassManager(&passMgr);
appController.setPkPassManager(&pkPassMgr);
appController.setReservationManager(&resMgr);
appController.setDocumentManager(&docMgr);
appController.setTransferManager(&transferMgr);
appController.setFavoriteLocationModel(&favLoc);
appController.setPassManager(&passMgr);
appController.setHealthCertificateManager(&healthCertMgr);
appController.importFromUrl(QUrl::fromLocalFile(QLatin1String(SOURCE_DIR "/data/4U8465-v1.json")));
appController.importFromUrl(QUrl::fromLocalFile(QLatin1String(SOURCE_DIR "/data/boardingpass-v1.pkpass")));
appController.importFromUrl(QUrl::fromLocalFile(QLatin1String(SOURCE_DIR "/data/bahncard.json")));
QCOMPARE(resMgr.batches().size(), 2);
QCOMPARE(passMgr.passes().size(), 1);
QCOMPARE(infoSpy.size(), 2);
QCOMPARE(pkPassMgr.passes().size(), 1);
QCOMPARE(passMgr.rowCount(), 1);
QCOMPARE(infoSpy.size(), 3);
QTemporaryFile tmp;
QVERIFY(tmp.open());
tmp.close();
appController.exportToFile(QUrl::fromLocalFile(tmp.fileName()));
QCOMPARE(infoSpy.size(), 3);
QCOMPARE(infoSpy.size(), 4);
KItinerary::File f(tmp.fileName());
QVERIFY(f.open(KItinerary::File::Read));
QCOMPARE(f.reservations().size(), 2);
QCOMPARE(f.passes().size(), 1);
Test::clearAll(&passMgr);
Test::clearAll(&pkPassMgr);
Test::clearAll(&resMgr);
Test::clearAll(&docMgr);
Test::clearAll(&passMgr);
QCOMPARE(resMgr.batches().size(), 0);
QCOMPARE(passMgr.passes().size(), 0);
QCOMPARE(pkPassMgr.passes().size(), 0);
appController.importFromUrl(QUrl::fromLocalFile(tmp.fileName()));
QCOMPARE(resMgr.batches().size(), 2);
QCOMPARE(passMgr.passes().size(), 1);
QCOMPARE(infoSpy.size(), 4);
QCOMPARE(pkPassMgr.passes().size(), 1);
QCOMPARE(passMgr.rowCount(), 1);
QCOMPARE(infoSpy.size(), 5);
Test::clearAll(&passMgr);
Test::clearAll(&pkPassMgr);
Test::clearAll(&resMgr);
Test::clearAll(&passMgr);
QCOMPARE(resMgr.batches().size(), 0);
QCOMPARE(passMgr.passes().size(), 0);
QCOMPARE(pkPassMgr.passes().size(), 0);
QFile bundle(tmp.fileName());
QVERIFY(bundle.open(QFile::ReadOnly));
appController.importData(bundle.readAll());
QCOMPARE(resMgr.batches().size(), 2);
QCOMPARE(passMgr.passes().size(), 1);
QCOMPARE(infoSpy.size(), 5);
QCOMPARE(pkPassMgr.passes().size(), 1);
QCOMPARE(passMgr.rowCount(), 1);
QCOMPARE(infoSpy.size(), 6);
}
};
......
......@@ -34,10 +34,7 @@ private Q_SLOTS:
PassManager mgr;
QAbstractItemModelTester modelTest(&mgr);
// clear previous leftovers
while (mgr.rowCount()) {
QVERIFY(mgr.removeRow(0));
}
Test::clearAll(&mgr);
QCOMPARE(mgr.rowCount(), 0);
// test import
......@@ -52,6 +49,7 @@ private Q_SLOTS:
QVERIFY(!pass.isNull());
QVERIFY(JsonLd::isA<ProgramMembership>(pass));
QCOMPARE(idx.data(PassManager::PassTypeRole).toInt(), PassManager::ProgramMembership);
QVERIFY(!idx.data(PassManager::PassDataRole).toByteArray().isEmpty());
{
// test persistence
......
......@@ -8,6 +8,7 @@
#define TESTHELPER_H
#include <documentmanager.h>
#include <passmanager.h>
#include <pkpassmanager.h>
#include <reservationmanager.h>
......@@ -50,6 +51,15 @@ inline void clearAll(DocumentManager *docMgr)
docMgr->removeDocument(id);
}
Q_ASSERT(docMgr->documents().isEmpty());
}
inline void clearAll(PassManager *passMgr)
{
while (passMgr->rowCount()) {
passMgr->removeRow(0);
}
Q_ASSERT(passMgr->rowCount() == 0);
}
}
......
......@@ -508,6 +508,7 @@ void ApplicationController::exportToFile(const QUrl &url)
exporter.exportDocuments(m_docMgr);
exporter.exportFavoriteLocations(m_favLocModel);
exporter.exportTransfers(m_resMgr, m_transferMgr);
exporter.exportPasses(m_passMgr);
exporter.exportHealthCertificates(m_healthCertMgr);
exporter.exportLiveData();
exporter.exportSettings();
......@@ -577,6 +578,7 @@ bool ApplicationController::importBundle(KItinerary::File *file)
count += importer.importDocuments(m_docMgr);
count += importer.importFavoriteLocations(m_favLocModel);
count += importer.importTransfers(m_resMgr, m_transferMgr);
count += importer.importPasses(m_passMgr);
count += importer.importHealthCertificates(m_healthCertMgr);
count += importer.importLiveData(m_liveDataMgr);
count += importer.importSettings();
......
......@@ -12,12 +12,14 @@
#include "livedata.h"
#include "livedatamanager.h"
#include "logging.h"
#include "passmanager.h"
#include "pkpassmanager.h"
#include "reservationmanager.h"
#include "transfer.h"
#include "transfermanager.h"
#include <KItinerary/File>
#include <KItinerary/JsonLdDocument>
#include <QFile>
#include <QJsonArray>
......@@ -96,6 +98,18 @@ void Exporter::exportFavoriteLocations(const FavoriteLocationModel* favLocModel)
}
}
void Exporter::exportPasses(const PassManager *passMgr)
{
for (int i = 0; i < passMgr->rowCount(); ++i) {
const auto idx = passMgr->index(i, 0);
m_file->addCustomData(
QStringLiteral("org.kde.itinerary/programs"),
passMgr->data(idx, PassManager::PassIdRole).toString(),
passMgr->data(idx, PassManager::PassDataRole).toByteArray()
);
}
}
void Exporter::exportHealthCertificates(const HealthCertificateManager *healthCertMgr)
{
for (int i = 0; i < healthCertMgr->rowCount(); ++i) {
......@@ -200,6 +214,18 @@ int Importer::importFavoriteLocations(FavoriteLocationModel *favLocModel)
return favLocs.size();
}
int Importer::importPasses(PassManager *passMgr)
{
const auto domain = QStringLiteral("org.kde.itinerary/programs");
const auto ids = m_file->listCustomData(domain);
for (const auto &id : ids) {
const auto data = m_file->customData(domain, id);
const auto pass = KItinerary::JsonLdDocument::fromJsonSingular(QJsonDocument::fromJson(data).object());
passMgr->import(pass, id);
}
return ids.size();
}
int Importer::importHealthCertificates(HealthCertificateManager *healthCertMgr)
{
const auto domain = QStringLiteral("org.kde.itinerary/health-certificates");
......
......@@ -11,6 +11,7 @@ class DocumentManager;
class FavoriteLocationModel;
class HealthCertificateManager;
class LiveDataManager;
class PassManager;
class PkPassManager;
class ReservationManager;
class TransferManager;
......@@ -30,6 +31,7 @@ public:
void exportDocuments(const DocumentManager *docMgr);
void exportTransfers(const ReservationManager *resMgr, const TransferManager *transferMgr);
void exportFavoriteLocations(const FavoriteLocationModel *favLocModel);
void exportPasses(const PassManager *passMgr);
void exportHealthCertificates(const HealthCertificateManager *healthCertMgr);
void exportLiveData();
void exportSettings();
......@@ -49,6 +51,7 @@ public:
int importDocuments(DocumentManager *docMgr);
int importTransfers(const ReservationManager *resMgr, TransferManager *transferMgr);
int importFavoriteLocations(FavoriteLocationModel *favLocModel);
int importPasses(PassManager *passMgr);
int importHealthCertificates(HealthCertificateManager *healthCertMgr);
int importLiveData(LiveDataManager *liveDataMgr);
int importSettings();
......
......@@ -18,6 +18,12 @@
using namespace KItinerary;
bool PassManager::Entry::operator<(const PassManager::Entry &other) const
{
return id < other.id;
}
PassManager::PassManager(QObject *parent)
: QAbstractListModel(parent)
{
......@@ -34,11 +40,11 @@ int PassManager::rowCount(const QModelIndex &parent) const
return m_entries.size();
}
bool PassManager::import(const QVariant &pass)
bool PassManager::import(const QVariant &pass, const QString &id)
{
if (JsonLd::isA<KItinerary::ProgramMembership>(pass)) {
Entry entry;
entry.id = QUuid::createUuid().toString();
entry.id = id.isEmpty() ? QUuid::createUuid().toString() : id;
entry.data = pass;
auto path = basePath();
......@@ -52,9 +58,17 @@ bool PassManager::import(const QVariant &pass)
f.write(QJsonDocument(JsonLdDocument::toJson(entry.data)).toJson());
f.close();
beginInsertRows({}, rowCount(), rowCount());
m_entries.push_back(std::move(entry));
endInsertRows();
const auto it = std::lower_bound(m_entries.begin(), m_entries.end(), entry);
if (it != m_entries.end() && (*it).id == entry.id) {
(*it).data = entry.data;
const auto idx = index(std::distance(m_entries.begin(), it), 0);
Q_EMIT dataChanged(idx, idx);
} else {
const auto row = std::distance(m_entries.begin(), it);
beginInsertRows({}, row, row);
m_entries.insert(it, std::move(entry));
endInsertRows();
}
return true;
}
......@@ -94,6 +108,8 @@ QVariant PassManager::data(const QModelIndex &index, int role) const
return ProgramMembership;
}
return {};
case PassDataRole:
return rawData(entry);
}
return {};
......@@ -115,6 +131,7 @@ void PassManager::load()
it.next();
m_entries.push_back({it.fileName(), QVariant()});
}
std::sort(m_entries.begin(), m_entries.end());
}
void PassManager::ensureLoaded(Entry &entry) const
......@@ -123,13 +140,21 @@ void PassManager::ensureLoaded(Entry &entry) const
return;
}
const auto data = rawData(entry);
if (!data.isEmpty()) {
entry.data = JsonLdDocument::fromJsonSingular(QJsonDocument::fromJson(data).object());
}
}
QByteArray PassManager::rawData(const Entry &entry) const
{
QFile f(basePath() + entry.id);
if (!f.open(QFile::ReadOnly)) {
qCWarning(Log) << "Failed to open file:" << f.fileName() << f.errorString();
return;
return {};
}
entry.data = JsonLdDocument::fromJsonSingular(QJsonDocument::fromJson(f.readAll()).object());
return f.readAll();
}
bool PassManager::remove(const QString &passId)
......
......@@ -23,6 +23,7 @@ public:
PassRole = Qt::UserRole,
PassIdRole,
PassTypeRole,
PassDataRole,
};
enum PassType {
......@@ -31,7 +32,7 @@ public:
};
Q_ENUM(PassType)
bool import(const QVariant &pass);
bool import(const QVariant &pass, const QString &id = {});
bool import(const QVector<QVariant> &passes);
int rowCount(const QModelIndex &parent = {}) const override;
......@@ -47,11 +48,15 @@ private:
struct Entry {
QString id;
QVariant data;
bool operator<(const Entry &other) const;
};
mutable std::vector<Entry> m_entries;
void load();
void ensureLoaded(Entry &entry) const;
QByteArray rawData(const Entry &entry) const;
static QString basePath();
};
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment