Oracle / card xml improvements (#3934)

* fix #1610

* fix #2679; partially fix #3647

* Fix tests

* Remove debug code
This commit is contained in:
ctrlaltca 2020-03-30 21:56:03 +02:00 committed by GitHub
parent a135ad064a
commit 27b7ebe208
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 131 additions and 10 deletions

View file

@ -6,6 +6,8 @@
#include <QIODevice> #include <QIODevice>
#include <QString> #include <QString>
#define COCKATRICE_XML_XSI_NAMESPACE "http://www.w3.org/2001/XMLSchema-instance"
class ICardDatabaseParser : public QObject class ICardDatabaseParser : public QObject
{ {
public: public:
@ -13,7 +15,11 @@ public:
virtual bool getCanParseFile(const QString &name, QIODevice &device) = 0; virtual bool getCanParseFile(const QString &name, QIODevice &device) = 0;
virtual void parseFile(QIODevice &device) = 0; virtual void parseFile(QIODevice &device) = 0;
virtual bool saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName) = 0; virtual bool saveToFile(SetNameMap sets,
CardNameMap cards,
const QString &fileName,
const QString &sourceUrl = "unknown",
const QString &sourceVersion = "unknown") = 0;
static void clearSetlist(); static void clearSetlist();
protected: protected:

View file

@ -1,11 +1,15 @@
#include "cockatricexml3.h" #include "cockatricexml3.h"
#include <QCoreApplication>
#include <QDebug> #include <QDebug>
#include <QFile> #include <QFile>
#include <QXmlStreamReader> #include <QXmlStreamReader>
#include <version_string.h>
#define COCKATRICE_XML3_TAGNAME "cockatrice_carddatabase" #define COCKATRICE_XML3_TAGNAME "cockatrice_carddatabase"
#define COCKATRICE_XML3_TAGVER 3 #define COCKATRICE_XML3_TAGVER 3
#define COCKATRICE_XML3_SCHEMALOCATION \
"https://raw.githubusercontent.com/Cockatrice/Cockatrice/master/doc/carddatabase_v3/cards.xsd"
bool CockatriceXml3Parser::getCanParseFile(const QString &fileName, QIODevice &device) bool CockatriceXml3Parser::getCanParseFile(const QString &fileName, QIODevice &device)
{ {
@ -403,7 +407,11 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in
return xml; return xml;
} }
bool CockatriceXml3Parser::saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName) bool CockatriceXml3Parser::saveToFile(SetNameMap sets,
CardNameMap cards,
const QString &fileName,
const QString &sourceUrl,
const QString &sourceVersion)
{ {
QFile file(fileName); QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) { if (!file.open(QIODevice::WriteOnly)) {
@ -416,6 +424,15 @@ bool CockatriceXml3Parser::saveToFile(SetNameMap sets, CardNameMap cards, const
xml.writeStartDocument(); xml.writeStartDocument();
xml.writeStartElement(COCKATRICE_XML3_TAGNAME); xml.writeStartElement(COCKATRICE_XML3_TAGNAME);
xml.writeAttribute("version", QString::number(COCKATRICE_XML3_TAGVER)); xml.writeAttribute("version", QString::number(COCKATRICE_XML3_TAGVER));
xml.writeAttribute("xmlns:xsi", COCKATRICE_XML_XSI_NAMESPACE);
xml.writeAttribute("xsi:schemaLocation", COCKATRICE_XML3_SCHEMALOCATION);
xml.writeStartElement("info");
xml.writeTextElement("author", QCoreApplication::applicationName() + QString(" %1").arg(VERSION_STRING));
xml.writeTextElement("createdAt", QDateTime::currentDateTimeUtc().toString(Qt::ISODate));
xml.writeTextElement("sourceUrl", sourceUrl);
xml.writeTextElement("sourceVersion", sourceVersion);
xml.writeEndElement();
if (sets.count() > 0) { if (sets.count() > 0) {
xml.writeStartElement("sets"); xml.writeStartElement("sets");

View file

@ -14,7 +14,11 @@ public:
~CockatriceXml3Parser() override = default; ~CockatriceXml3Parser() override = default;
bool getCanParseFile(const QString &name, QIODevice &device) override; bool getCanParseFile(const QString &name, QIODevice &device) override;
void parseFile(QIODevice &device) override; void parseFile(QIODevice &device) override;
bool saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName) override; bool saveToFile(SetNameMap sets,
CardNameMap cards,
const QString &fileName,
const QString &sourceUrl = "unknown",
const QString &sourceVersion = "unknown") override;
private: private:
void loadCardsFromXml(QXmlStreamReader &xml); void loadCardsFromXml(QXmlStreamReader &xml);

View file

@ -1,11 +1,15 @@
#include "cockatricexml4.h" #include "cockatricexml4.h"
#include <QCoreApplication>
#include <QDebug> #include <QDebug>
#include <QFile> #include <QFile>
#include <QXmlStreamReader> #include <QXmlStreamReader>
#include <version_string.h>
#define COCKATRICE_XML4_TAGNAME "cockatrice_carddatabase" #define COCKATRICE_XML4_TAGNAME "cockatrice_carddatabase"
#define COCKATRICE_XML4_TAGVER 4 #define COCKATRICE_XML4_TAGVER 4
#define COCKATRICE_XML4_SCHEMALOCATION \
"https://raw.githubusercontent.com/Cockatrice/Cockatrice/master/doc/carddatabase_v4/cards.xsd"
bool CockatriceXml4Parser::getCanParseFile(const QString &fileName, QIODevice &device) bool CockatriceXml4Parser::getCanParseFile(const QString &fileName, QIODevice &device)
{ {
@ -329,7 +333,11 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in
return xml; return xml;
} }
bool CockatriceXml4Parser::saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName) bool CockatriceXml4Parser::saveToFile(SetNameMap sets,
CardNameMap cards,
const QString &fileName,
const QString &sourceUrl,
const QString &sourceVersion)
{ {
QFile file(fileName); QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) { if (!file.open(QIODevice::WriteOnly)) {
@ -342,6 +350,15 @@ bool CockatriceXml4Parser::saveToFile(SetNameMap sets, CardNameMap cards, const
xml.writeStartDocument(); xml.writeStartDocument();
xml.writeStartElement(COCKATRICE_XML4_TAGNAME); xml.writeStartElement(COCKATRICE_XML4_TAGNAME);
xml.writeAttribute("version", QString::number(COCKATRICE_XML4_TAGVER)); xml.writeAttribute("version", QString::number(COCKATRICE_XML4_TAGVER));
xml.writeAttribute("xmlns:xsi", COCKATRICE_XML_XSI_NAMESPACE);
xml.writeAttribute("xsi:schemaLocation", COCKATRICE_XML4_SCHEMALOCATION);
xml.writeStartElement("info");
xml.writeTextElement("author", QCoreApplication::applicationName() + QString(" %1").arg(VERSION_STRING));
xml.writeTextElement("createdAt", QDateTime::currentDateTimeUtc().toString(Qt::ISODate));
xml.writeTextElement("sourceUrl", sourceUrl);
xml.writeTextElement("sourceVersion", sourceVersion);
xml.writeEndElement();
if (sets.count() > 0) { if (sets.count() > 0) {
xml.writeStartElement("sets"); xml.writeStartElement("sets");

View file

@ -14,7 +14,11 @@ public:
~CockatriceXml4Parser() override = default; ~CockatriceXml4Parser() override = default;
bool getCanParseFile(const QString &name, QIODevice &device) override; bool getCanParseFile(const QString &name, QIODevice &device) override;
void parseFile(QIODevice &device) override; void parseFile(QIODevice &device) override;
bool saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName) override; bool saveToFile(SetNameMap sets,
CardNameMap cards,
const QString &fileName,
const QString &sourceUrl = "unknown",
const QString &sourceVersion = "unknown") override;
private: private:
QVariantHash loadCardPropertiesFromXml(QXmlStreamReader &xml); QVariantHash loadCardPropertiesFromXml(QXmlStreamReader &xml);

View file

@ -11,6 +11,16 @@
<xs:element name="cockatrice_carddatabase"> <xs:element name="cockatrice_carddatabase">
<xs:complexType> <xs:complexType>
<xs:all> <xs:all>
<xs:element name="info" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element type="xs:string" name="author" minOccurs="0" maxOccurs="1" />
<xs:element type="xs:string" name="createdAt" minOccurs="0" maxOccurs="1" />
<xs:element type="xs:string" name="sourceUrl" minOccurs="0" maxOccurs="1" />
<xs:element type="xs:string" name="sourceVersion" minOccurs="0" maxOccurs="1" />
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="sets" minOccurs="0"> <xs:element name="sets" minOccurs="0">
<xs:complexType> <xs:complexType>
<xs:sequence> <xs:sequence>

View file

@ -57,6 +57,16 @@
<xs:element name="cockatrice_carddatabase"> <xs:element name="cockatrice_carddatabase">
<xs:complexType> <xs:complexType>
<xs:sequence> <xs:sequence>
<xs:element name="info" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element type="xs:string" name="author" minOccurs="0" maxOccurs="1" />
<xs:element type="xs:string" name="createdAt" minOccurs="0" maxOccurs="1" />
<xs:element type="xs:string" name="sourceUrl" minOccurs="0" maxOccurs="1" />
<xs:element type="xs:string" name="sourceVersion" minOccurs="0" maxOccurs="1" />
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="sets" minOccurs="0"> <xs:element name="sets" minOccurs="0">
<xs:complexType> <xs:complexType>
<xs:sequence> <xs:sequence>

View file

@ -459,10 +459,10 @@ int OracleImporter::startImport()
return setIndex; return setIndex;
} }
bool OracleImporter::saveToFile(const QString &fileName) bool OracleImporter::saveToFile(const QString &fileName, const QString &sourceUrl, const QString &sourceVersion)
{ {
CockatriceXml4Parser parser; CockatriceXml4Parser parser;
return parser.saveToFile(sets, cards, fileName); return parser.saveToFile(sets, cards, fileName, sourceUrl, sourceVersion);
} }
void OracleImporter::clear() void OracleImporter::clear()

View file

@ -110,7 +110,7 @@ public:
explicit OracleImporter(const QString &_dataDir, QObject *parent = nullptr); explicit OracleImporter(const QString &_dataDir, QObject *parent = nullptr);
bool readSetsFromByteArray(const QByteArray &data); bool readSetsFromByteArray(const QByteArray &data);
int startImport(); int startImport();
bool saveToFile(const QString &fileName); bool saveToFile(const QString &fileName, const QString &sourceUrl, const QString &sourceVersion);
int importCardsFromSet(CardSetPtr currentSet, const QList<QVariant> &cards, bool skipSpecialNums = true); int importCardsFromSet(CardSetPtr currentSet, const QList<QVariant> &cards, bool skipSpecialNums = true);
QList<SetToDownload> &getSets() QList<SetToDownload> &getSets()
{ {

View file

@ -39,6 +39,7 @@
// Xz stream header: 0xFD + "7zXZ" // Xz stream header: 0xFD + "7zXZ"
#define XZ_SIGNATURE "\xFD\x37\x7A\x58\x5A" #define XZ_SIGNATURE "\xFD\x37\x7A\x58\x5A"
#define ALLSETS_URL_FALLBACK "https://www.mtgjson.com/files/AllPrintings.json" #define ALLSETS_URL_FALLBACK "https://www.mtgjson.com/files/AllPrintings.json"
#define MTGJSON_VERSION_URL "https://www.mtgjson.com/files/version.json"
#ifdef HAS_LZMA #ifdef HAS_LZMA
#define ALLSETS_URL "https://www.mtgjson.com/files/AllPrintings.json.xz" #define ALLSETS_URL "https://www.mtgjson.com/files/AllPrintings.json.xz"
@ -331,14 +332,46 @@ bool LoadSetsPage::validatePage()
wizard()->disableButtons(); wizard()->disableButtons();
setEnabled(false); setEnabled(false);
wizard()->setCardSourceUrl(setsFile.fileName());
wizard()->setCardSourceVersion("unknown");
readSetsFromByteArray(setsFile.readAll()); readSetsFromByteArray(setsFile.readAll());
} }
return false; return false;
} }
#include <iostream>
void LoadSetsPage::downloadSetsFile(QUrl url) void LoadSetsPage::downloadSetsFile(QUrl url)
{ {
wizard()->setCardSourceVersion("unknown");
QString urlString = url.toString();
if (urlString == ALLSETS_URL || urlString == ALLSETS_URL_FALLBACK) {
QUrl versionUrl = QUrl::fromUserInput(MTGJSON_VERSION_URL);
QNetworkReply *versionReply = wizard()->nam->get(QNetworkRequest(versionUrl));
connect(versionReply, &QNetworkReply::finished, [this, versionReply]() {
if (versionReply->error() == QNetworkReply::NoError) {
QByteArray jsonData = versionReply->readAll();
QJsonParseError jsonError;
QJsonDocument jsonResponse = QJsonDocument::fromJson(jsonData, &jsonError);
if (jsonError.error == QJsonParseError::NoError) {
QVariantMap jsonMap = jsonResponse.toVariant().toMap();
QString versionString = jsonMap["version"].toString();
if (versionString.isEmpty()) {
versionString = "unknown";
}
wizard()->setCardSourceVersion(versionString);
}
}
versionReply->deleteLater();
});
}
wizard()->setCardSourceUrl(url.toString());
QNetworkReply *reply = wizard()->nam->get(QNetworkRequest(url)); QNetworkReply *reply = wizard()->nam->get(QNetworkRequest(url));
connect(reply, SIGNAL(finished()), this, SLOT(actDownloadFinishedSetsFile())); connect(reply, SIGNAL(finished()), this, SLOT(actDownloadFinishedSetsFile()));
@ -597,7 +630,7 @@ bool SaveSetsPage::validatePage()
return false; return false;
} }
if (wizard()->importer->saveToFile(fileName)) { if (wizard()->importer->saveToFile(fileName, wizard()->getCardSourceUrl(), wizard()->getCardSourceVersion())) {
ok = true; ok = true;
} else { } else {
QMessageBox::critical(this, tr("Error"), tr("The file could not be saved to %1").arg(fileName)); QMessageBox::critical(this, tr("Error"), tr("The file could not be saved to %1").arg(fileName));

View file

@ -38,6 +38,22 @@ public:
{ {
return !tokensData.isEmpty(); return !tokensData.isEmpty();
} }
void setCardSourceUrl(const QString &sourceUrl)
{
cardSourceUrl = sourceUrl;
}
void setCardSourceVersion(const QString &sourceVersion)
{
cardSourceVersion = sourceVersion;
}
const QString &getCardSourceUrl() const
{
return cardSourceUrl;
}
const QString &getCardSourceVersion() const
{
return cardSourceVersion;
}
bool saveTokensToFile(const QString &fileName); bool saveTokensToFile(const QString &fileName);
public: public:
@ -50,6 +66,8 @@ private slots:
private: private:
QByteArray tokensData; QByteArray tokensData;
QString cardSourceUrl;
QString cardSourceVersion;
protected: protected:
void changeEvent(QEvent *event) override; void changeEvent(QEvent *event) override;

View file

@ -6,6 +6,7 @@ add_executable(carddatabase_test
../../cockatrice/src/carddbparser/carddatabaseparser.cpp ../../cockatrice/src/carddbparser/carddatabaseparser.cpp
../../cockatrice/src/carddbparser/cockatricexml3.cpp ../../cockatrice/src/carddbparser/cockatricexml3.cpp
../../cockatrice/src/carddbparser/cockatricexml4.cpp ../../cockatrice/src/carddbparser/cockatricexml4.cpp
${VERSION_STRING_CPP}
) )
add_executable(filter_string_test add_executable(filter_string_test
filter_string_test.cpp filter_string_test.cpp
@ -17,6 +18,7 @@ add_executable(filter_string_test
../../cockatrice/src/carddbparser/carddatabaseparser.cpp ../../cockatrice/src/carddbparser/carddatabaseparser.cpp
../../cockatrice/src/carddbparser/cockatricexml3.cpp ../../cockatrice/src/carddbparser/cockatricexml3.cpp
../../cockatrice/src/carddbparser/cockatricexml4.cpp ../../cockatrice/src/carddbparser/cockatricexml4.cpp
${VERSION_STRING_CPP}
) )
if(NOT GTEST_FOUND) if(NOT GTEST_FOUND)
add_dependencies(carddatabase_test gtest) add_dependencies(carddatabase_test gtest)

View file

@ -1,5 +1,5 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "../cockatrice/src/filter_string.h" #include "../../cockatrice/src/filter_string.h"
#include "mocks.h" #include "mocks.h"
#include <cmath> #include <cmath>