You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
685 lines
24 KiB
685 lines
24 KiB
/******************************************************************* |
|
* bugzillalib.cpp |
|
* Copyright 2009, 2011 Dario Andres Rodriguez <andresbajotierra@gmail.com> |
|
* Copyright 2012 George Kiagiadakis <kiagiadakis.george@gmail.com> |
|
* |
|
* This program is free software; you can redistribute it and/or |
|
* modify it under the terms of the GNU General Public License as |
|
* published by the Free Software Foundation; either version 2 of |
|
* the License, or (at your option) any later version. |
|
* |
|
* This program is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License |
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
* |
|
******************************************************************/ |
|
|
|
#include "bugzillalib.h" |
|
|
|
#include <QtCore/QtGlobal> |
|
#include <QtCore/QTextStream> |
|
#include <QtCore/QByteArray> |
|
#include <QtCore/QString> |
|
|
|
#include <QtXml/QDomNode> |
|
#include <QtXml/QDomNodeList> |
|
#include <QtXml/QDomElement> |
|
#include <QtXml/QDomNamedNodeMap> |
|
|
|
#include <KIO/Job> |
|
#include <KLocalizedString> |
|
#include <QDebug> |
|
|
|
#define MAKE_BUGZILLA_VERSION(a,b,c) (((a) << 16) | ((b) << 8) | (c)) |
|
|
|
static const char columns[] = "bug_severity,priority,bug_status,product,short_desc,resolution"; |
|
|
|
//Bugzilla URLs |
|
static const char searchUrl[] = |
|
"buglist.cgi?query_format=advanced&order=Importance&ctype=csv" |
|
"&product=%1" |
|
"&longdesc_type=allwordssubstr&longdesc=%2" |
|
"&chfieldfrom=%3&chfieldto=%4&chfield=[Bug+creation]" |
|
"&bug_severity=%5" |
|
"&columnlist=%6"; |
|
// short_desc, product, long_desc(possible backtraces lines), searchFrom, searchTo, severity, columnList |
|
static const char showBugUrl[] = "show_bug.cgi?id=%1"; |
|
static const char fetchBugUrl[] = "show_bug.cgi?id=%1&ctype=xml"; |
|
|
|
static inline Component buildComponent(const QVariantMap& map); |
|
static inline Version buildVersion(const QVariantMap& map); |
|
static inline Product buildProduct(const QVariantMap& map); |
|
|
|
//BEGIN BugzillaManager |
|
|
|
BugzillaManager::BugzillaManager(const QString &bugTrackerUrl, QObject *parent) |
|
: QObject(parent) |
|
, m_bugTrackerUrl(bugTrackerUrl) |
|
, m_logged(false) |
|
, m_searchJob(0) |
|
{ |
|
m_xmlRpcClient = new KXmlRpc::Client(QUrl(m_bugTrackerUrl + "xmlrpc.cgi"), this); |
|
m_xmlRpcClient->setUserAgent(QLatin1String("DrKonqi")); |
|
// Allow constructors for ReportInterface and assistant dialogs to finish. |
|
// We do not want them to be racing the remote Bugzilla database. |
|
QMetaObject::invokeMethod (this, "lookupVersion", Qt::QueuedConnection); |
|
} |
|
|
|
// BEGIN Checks of Bugzilla software versions. |
|
void BugzillaManager::lookupVersion() |
|
{ |
|
QMap<QString, QVariant> args; |
|
callBugzilla("Bugzilla.version", "version", args, SecurityDisabled); |
|
} |
|
|
|
void BugzillaManager::setFeaturesForVersion(const QString& version) |
|
{ |
|
// A procedure to change Dr Konqi behaviour automatically when Bugzilla |
|
// software versions change. |
|
// |
|
// Changes should be added to Dr Konqi AHEAD of when the corresponding |
|
// Bugzilla software changes are released into bugs.kde.org, so that |
|
// Dr Konqi can continue to operate smoothly, without bug reports and a |
|
// reactive KDE software release. |
|
// |
|
// If Bugzilla announces a change to its software that affects Dr Konqi, |
|
// add executable code to implement the change automatically when the |
|
// Bugzilla software version changes. It goes at the end of this procedure |
|
// and elsewhere in this class (BugzillaManager) and/or other classes where |
|
// the change should actually be implemented. |
|
|
|
const int nVersionParts = 3; |
|
QString seps = QLatin1String("[._-]"); |
|
QStringList digits = version.split(QRegExp(seps), QString::SkipEmptyParts); |
|
while (digits.count() < nVersionParts) { |
|
digits << QLatin1String("0"); |
|
} |
|
if (digits.count() > nVersionParts) { |
|
qWarning() << QStringLiteral("Current Bugzilla version %1 has more than %2 parts. Check that this is not a problem.").arg(version).arg(nVersionParts); |
|
} |
|
int currentVersion = MAKE_BUGZILLA_VERSION(digits.at(0).toUInt(), |
|
digits.at(1).toUInt(), digits.at(2).toUInt()); |
|
|
|
// Set the code(s) for historical versions of Bugzilla - before any change. |
|
m_security = UseCookies; // Used to have cookies for update-security. |
|
|
|
if (currentVersion >= MAKE_BUGZILLA_VERSION(4, 4, 3)) { |
|
// Security method changes from cookies to tokens in Bugzilla 4.4.3. |
|
// BUT, tokens fail when kio_http sends any cookies found in KCookieJar, |
|
// so go directly to passwords-only security (supported since Bugzilla |
|
// 3.6 and will be enforced in Bugzilla 4.5.x). |
|
m_security = UsePasswords; |
|
} |
|
|
|
qDebug() << "VERSION" << version << "SECURITY" << m_security; |
|
} |
|
// END Checks of Bugzilla software versions. |
|
|
|
// BEGIN Generic remote-procedure (RPC) call to Bugzilla |
|
void BugzillaManager::callBugzilla(const char* method, const char* id, |
|
QMap<QString, QVariant>& args, |
|
SecurityStatus security) |
|
{ |
|
if (security == SecurityEnabled) { |
|
switch (m_security) { |
|
case UseTokens: |
|
qDebug() << method << id << "using token"; |
|
args.insert(QLatin1String("Bugzilla_token"), m_token); |
|
break; |
|
case UsePasswords: |
|
qDebug() << method << id << "using username" << m_username; |
|
args.insert(QLatin1String("Bugzilla_login"), m_username); |
|
args.insert(QLatin1String("Bugzilla_password"), m_password); |
|
break; |
|
case UseCookies: |
|
qDebug() << method << id << "using cookies"; |
|
// Some KDE process other than Dr Konqi should provide cookies. |
|
break; |
|
} |
|
} |
|
|
|
m_xmlRpcClient->call(QLatin1String(method), args, |
|
this, SLOT(callMessage(QList<QVariant>,QVariant)), |
|
this, SLOT(callFault(int,QString,QVariant)), |
|
QString::fromAscii(id)); |
|
} |
|
// END Generic call to Bugzilla |
|
|
|
//BEGIN Login methods |
|
void BugzillaManager::tryLogin(const QString& username, const QString& password) |
|
{ |
|
m_username = username; |
|
if (m_security == UsePasswords) { |
|
m_password = password; |
|
} |
|
m_logged = false; |
|
|
|
QMap<QString, QVariant> args; |
|
args.insert(QLatin1String("login"), username); |
|
args.insert(QLatin1String("password"), password); |
|
if (m_security == UseCookies) { |
|
// Removed in Bugzilla 4.4.3 software, which no longer issues cookies. |
|
args.insert(QLatin1String("remember"), false); |
|
} |
|
|
|
callBugzilla("User.login", "login", args, SecurityDisabled); |
|
} |
|
|
|
bool BugzillaManager::getLogged() const |
|
{ |
|
return m_logged; |
|
} |
|
|
|
QString BugzillaManager::getUsername() const |
|
{ |
|
return m_username; |
|
} |
|
//END Login methods |
|
|
|
//BEGIN Bugzilla Action methods |
|
void BugzillaManager::fetchBugReport(int bugnumber, QObject * jobOwner) |
|
{ |
|
QUrl url(m_bugTrackerUrl + QString(fetchBugUrl).arg(bugnumber)); |
|
|
|
if (!jobOwner) { |
|
jobOwner = this; |
|
} |
|
|
|
KIO::Job * fetchBugJob = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo); |
|
fetchBugJob->setParent(jobOwner); |
|
connect(fetchBugJob, &KIO::Job::finished, this, &BugzillaManager::fetchBugJobFinished); |
|
} |
|
|
|
|
|
void BugzillaManager::searchBugs(const QStringList & products, |
|
const QString & severity, const QString & date_start, |
|
const QString & date_end, QString comment) |
|
{ |
|
QString product; |
|
if (products.size() > 0) { |
|
if (products.size() == 1) { |
|
product = products.at(0); |
|
} else { |
|
Q_FOREACH(const QString & p, products) { |
|
product += p + "&product="; |
|
} |
|
product = product.mid(0,product.size()-9); |
|
} |
|
} |
|
|
|
QString url = QString(m_bugTrackerUrl) + |
|
QString(searchUrl).arg(product, comment.replace(' ' , '+'), date_start, |
|
date_end, severity, QString(columns)); |
|
|
|
stopCurrentSearch(); |
|
|
|
m_searchJob = KIO::storedGet(QUrl(url) , KIO::Reload, KIO::HideProgressInfo); |
|
connect(m_searchJob, &KIO::Job::finished, this, &BugzillaManager::searchBugsJobFinished); |
|
} |
|
|
|
void BugzillaManager::sendReport(const BugReport & report) |
|
{ |
|
QMap<QString, QVariant> args; |
|
args.insert(QLatin1String("product"), report.product()); |
|
args.insert(QLatin1String("component"), report.component()); |
|
args.insert(QLatin1String("version"), report.version()); |
|
args.insert(QLatin1String("summary"), report.shortDescription()); |
|
args.insert(QLatin1String("description"), report.description()); |
|
args.insert(QLatin1String("op_sys"), report.operatingSystem()); |
|
args.insert(QLatin1String("platform"), report.platform()); |
|
args.insert(QLatin1String("keywords"), report.keywords()); |
|
args.insert(QLatin1String("priority"), report.priority()); |
|
args.insert(QLatin1String("severity"), report.bugSeverity()); |
|
|
|
callBugzilla("Bug.create", "Bug.create", args, SecurityEnabled); |
|
} |
|
|
|
void BugzillaManager::attachTextToReport(const QString & text, const QString & filename, |
|
const QString & summary, int bugId, const QString & comment) |
|
{ |
|
QMap<QString, QVariant> args; |
|
args.insert(QLatin1String("ids"), QVariantList() << bugId); |
|
args.insert(QLatin1String("file_name"), filename); |
|
args.insert(QLatin1String("summary"), summary); |
|
args.insert(QLatin1String("comment"), comment); |
|
args.insert(QLatin1String("content_type"), QString::fromAscii("text/plain")); |
|
|
|
//data needs to be a QByteArray so that it is encoded in base64 (query.cpp:246) |
|
args.insert(QLatin1String("data"), text.toUtf8()); |
|
|
|
callBugzilla("Bug.add_attachment", "Bug.add_attachment", args, |
|
SecurityEnabled); |
|
} |
|
|
|
void BugzillaManager::addMeToCC(int bugId) |
|
{ |
|
QMap<QString, QVariant> args; |
|
args.insert(QLatin1String("ids"), QVariantList() << bugId); |
|
|
|
QMap<QString, QVariant> ccChanges; |
|
ccChanges.insert(QLatin1String("add"), QVariantList() << m_username); |
|
args.insert(QLatin1String("cc"), ccChanges); |
|
|
|
callBugzilla("Bug.update", "Bug.update.cc", args, SecurityEnabled); |
|
} |
|
|
|
void BugzillaManager::fetchProductInfo(const QString & product) |
|
{ |
|
QMap<QString, QVariant> args; |
|
|
|
args.insert(QStringLiteral("names"), (QStringList() << product) ) ; |
|
|
|
QStringList includeFields; |
|
// currently we only need these informations |
|
includeFields << QStringLiteral("name") << QStringLiteral("is_active") << QStringLiteral("components") << QStringLiteral("versions"); |
|
|
|
args.insert(QStringLiteral("include_fields"), includeFields) ; |
|
|
|
callBugzilla("Product.get", "Product.get.versions", args, SecurityDisabled); |
|
} |
|
|
|
|
|
//END Bugzilla Action methods |
|
|
|
//BEGIN Misc methods |
|
QString BugzillaManager::urlForBug(int bug_number) const |
|
{ |
|
return QString(m_bugTrackerUrl) + QString(showBugUrl).arg(bug_number); |
|
} |
|
|
|
void BugzillaManager::stopCurrentSearch() |
|
{ |
|
if (m_searchJob) { //Stop previous searchJob |
|
m_searchJob->disconnect(); |
|
m_searchJob->kill(); |
|
m_searchJob = 0; |
|
} |
|
} |
|
//END Misc methods |
|
|
|
//BEGIN Slots to handle KJob::finished |
|
|
|
void BugzillaManager::fetchBugJobFinished(KJob* job) |
|
{ |
|
if (!job->error()) { |
|
KIO::StoredTransferJob * fetchBugJob = static_cast<KIO::StoredTransferJob*>(job); |
|
|
|
BugReportXMLParser * parser = new BugReportXMLParser(fetchBugJob->data()); |
|
BugReport report = parser->parse(); |
|
|
|
if (parser->isValid()) { |
|
emit bugReportFetched(report, job->parent()); |
|
} else { |
|
emit bugReportError(i18nc("@info","Invalid report information (malformed data). This " |
|
"could mean that the bug report does not exist, or the " |
|
"bug tracking site is experiencing a problem."), job->parent()); |
|
} |
|
|
|
delete parser; |
|
} else { |
|
emit bugReportError(job->errorString(), job->parent()); |
|
} |
|
} |
|
|
|
void BugzillaManager::searchBugsJobFinished(KJob * job) |
|
{ |
|
if (!job->error()) { |
|
KIO::StoredTransferJob * searchBugsJob = static_cast<KIO::StoredTransferJob*>(job); |
|
|
|
BugListCSVParser * parser = new BugListCSVParser(searchBugsJob->data()); |
|
BugMapList list = parser->parse(); |
|
|
|
if (parser->isValid()) { |
|
emit searchFinished(list); |
|
} else { |
|
emit searchError(i18nc("@info","Invalid bug list: corrupted data")); |
|
} |
|
|
|
delete parser; |
|
} else { |
|
emit searchError(job->errorString()); |
|
} |
|
|
|
m_searchJob = 0; |
|
} |
|
|
|
static inline Component buildComponent(const QVariantMap& map) |
|
{ |
|
QString name = map.value(QStringLiteral("name")).toString(); |
|
bool active = map.value(QStringLiteral("is_active")).toBool(); |
|
|
|
return Component(name, active); |
|
} |
|
|
|
static inline Version buildVersion(const QVariantMap& map) |
|
{ |
|
QString name = map.value(QStringLiteral("name")).toString(); |
|
bool active = map.value(QStringLiteral("is_active")).toBool(); |
|
|
|
return Version(name, active); |
|
} |
|
|
|
static inline Product buildProduct(const QVariantMap& map) |
|
{ |
|
QString name = map.value(QStringLiteral("name")).toString(); |
|
bool active = map.value(QStringLiteral("is_active")).toBool(); |
|
|
|
Product product(name, active); |
|
|
|
QVariantList components = map.value(QStringLiteral("components")).toList(); |
|
foreach (const QVariant& c, components) { |
|
Component component = buildComponent(c.toMap()); |
|
product.addComponent(component); |
|
|
|
} |
|
|
|
QVariantList versions = map.value(QStringLiteral("versions")).toList(); |
|
foreach (const QVariant& v, versions) { |
|
Version version = buildVersion(v.toMap()); |
|
product.addVersion(version); |
|
} |
|
|
|
return product; |
|
} |
|
|
|
void BugzillaManager::fetchProductInfoFinished(const QVariantMap & map) |
|
{ |
|
QList<Product> products; |
|
|
|
QVariantList plist = map.value(QStringLiteral("products")).toList(); |
|
foreach (const QVariant& p, plist) { |
|
Product product = buildProduct(p.toMap()); |
|
products.append(product); |
|
} |
|
|
|
if ( products.size() > 0 ) { |
|
emit productInfoFetched(products.at(0)); |
|
} else { |
|
emit productInfoError(); |
|
} |
|
} |
|
|
|
//END Slots to handle KJob::finished |
|
|
|
void BugzillaManager::callMessage(const QList<QVariant> & result, const QVariant & id) |
|
{ |
|
qDebug() << id << result; |
|
|
|
if (id.toString() == QLatin1String("login")) { |
|
if ((m_security == UseTokens) && (result.count() > 0)) { |
|
QVariantMap map = result.at(0).toMap(); |
|
m_token = map.value(QLatin1String("token")).toString(); |
|
} |
|
m_logged = true; |
|
Q_EMIT loginFinished(true); |
|
} else if (id.toString() == QLatin1String("Product.get.versions")) { |
|
QVariantMap map = result.at(0).toMap(); |
|
fetchProductInfoFinished(map); |
|
} else if (id.toString() == QLatin1String("Bug.create")) { |
|
QVariantMap map = result.at(0).toMap(); |
|
int bug_id = map.value(QLatin1String("id")).toInt(); |
|
Q_ASSERT(bug_id != 0); |
|
Q_EMIT reportSent(bug_id); |
|
} else if (id.toString() == QLatin1String("Bug.add_attachment")) { |
|
QVariantMap map = result.at(0).toMap(); |
|
if (map.contains(QLatin1String("attachments"))){ // for bugzilla 4.2 |
|
map = map.value(QLatin1String("attachments")).toMap(); |
|
map = map.constBegin()->toMap(); |
|
const int attachment_id = map.value(QLatin1String("id")).toInt(); |
|
Q_EMIT attachToReportSent(attachment_id); |
|
} else if (map.contains(QLatin1String("ids"))) { // for bugzilla 4.4 |
|
const int attachment_id = map.value(QLatin1String("ids")).toList().at(0).toInt(); |
|
Q_EMIT attachToReportSent(attachment_id); |
|
} |
|
} else if (id.toString() == QLatin1String("Bug.update.cc")) { |
|
QVariantMap map = result.at(0).toMap().value(QLatin1String("bugs")).toList().at(0).toMap(); |
|
int bug_id = map.value(QLatin1String("id")).toInt(); |
|
Q_ASSERT(bug_id != 0); |
|
Q_EMIT addMeToCCFinished(bug_id); |
|
} else if (id.toString() == QLatin1String("version")) { |
|
QVariantMap map = result.at(0).toMap(); |
|
QString bugzillaVersion = map.value(QLatin1String("version")).toString(); |
|
setFeaturesForVersion(bugzillaVersion); |
|
Q_EMIT bugzillaVersionFound(); |
|
} |
|
} |
|
|
|
void BugzillaManager::callFault(int errorCode, const QString & errorString, const QVariant & id) |
|
{ |
|
qDebug() << id << errorCode << errorString; |
|
|
|
QString genericError = i18nc("@info", "Received unexpected error code %1 from bugzilla. " |
|
"Error message was: %2", errorCode, errorString); |
|
|
|
if (id.toString() == QLatin1String("login")) { |
|
switch(errorCode) { |
|
case 300: //invalid username or password |
|
Q_EMIT loginFinished(false); //TODO replace with loginError |
|
break; |
|
default: |
|
Q_EMIT loginError(genericError); |
|
break; |
|
} |
|
} else if (id.toString() == QLatin1String("Bug.create")) { |
|
switch (errorCode) { |
|
case 51: //invalid object (one example is invalid platform value) |
|
case 105: //invalid component |
|
case 106: //invalid product |
|
Q_EMIT sendReportErrorInvalidValues(); |
|
break; |
|
default: |
|
Q_EMIT sendReportError(genericError); |
|
break; |
|
} |
|
} else if (id.toString() == QLatin1String("Bug.add_attachment")) { |
|
switch (errorCode) { |
|
default: |
|
Q_EMIT attachToReportError(genericError); |
|
break; |
|
} |
|
} else if (id.toString() == QLatin1String("Bug.update.cc")) { |
|
switch (errorCode) { |
|
default: |
|
Q_EMIT addMeToCCError(genericError); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
//END BugzillaManager |
|
|
|
//BEGIN BugzillaCSVParser |
|
|
|
BugListCSVParser::BugListCSVParser(const QByteArray& data) |
|
{ |
|
m_data = data; |
|
m_isValid = false; |
|
} |
|
|
|
BugMapList BugListCSVParser::parse() |
|
{ |
|
BugMapList list; |
|
|
|
if (!m_data.isEmpty()) { |
|
//Parse buglist CSV |
|
QTextStream ts(&m_data); |
|
QString headersLine = ts.readLine().remove(QLatin1Char('\"')) ; //Discard headers |
|
QString expectedHeadersLine = QString(columns); |
|
|
|
if (headersLine == (QStringLiteral("bug_id,") + expectedHeadersLine)) { |
|
QStringList headers = expectedHeadersLine.split(',', QString::KeepEmptyParts); |
|
int headersCount = headers.count(); |
|
|
|
while (!ts.atEnd()) { |
|
BugMap bug; //bug report data map |
|
|
|
QString line = ts.readLine(); |
|
|
|
//Get bug_id (always at first column) |
|
int bug_id_index = line.indexOf(','); |
|
QString bug_id = line.left(bug_id_index); |
|
bug.insert(QStringLiteral("bug_id"), bug_id); |
|
|
|
line = line.mid(bug_id_index + 2); |
|
|
|
QStringList fields = line.split(QStringLiteral(",\"")); |
|
|
|
for (int i = 0; i < headersCount && i < fields.count(); i++) { |
|
QString field = fields.at(i); |
|
field = field.left(field.size() - 1) ; //Remove trailing " |
|
bug.insert(headers.at(i), field); |
|
} |
|
|
|
list.append(bug); |
|
} |
|
|
|
m_isValid = true; |
|
} |
|
} |
|
|
|
return list; |
|
} |
|
|
|
//END BugzillaCSVParser |
|
|
|
//BEGIN BugzillaXMLParser |
|
|
|
BugReportXMLParser::BugReportXMLParser(const QByteArray & data) |
|
{ |
|
m_valid = m_xml.setContent(data, true); |
|
} |
|
|
|
BugReport BugReportXMLParser::parse() |
|
{ |
|
BugReport report; //creates an invalid and empty report object |
|
|
|
if (m_valid) { |
|
//Check bug notfound |
|
QDomNodeList bug_number = m_xml.elementsByTagName(QStringLiteral("bug")); |
|
QDomNode d = bug_number.at(0); |
|
QDomNamedNodeMap a = d.attributes(); |
|
QDomNode d2 = a.namedItem(QStringLiteral("error")); |
|
m_valid = d2.isNull(); |
|
|
|
if (m_valid) { |
|
report.setValid(true); |
|
|
|
//Get basic fields |
|
report.setBugNumber(getSimpleValue(QStringLiteral("bug_id"))); |
|
report.setShortDescription(getSimpleValue(QStringLiteral("short_desc"))); |
|
report.setProduct(getSimpleValue(QStringLiteral("product"))); |
|
report.setComponent(getSimpleValue(QStringLiteral("component"))); |
|
report.setVersion(getSimpleValue(QStringLiteral("version"))); |
|
report.setOperatingSystem(getSimpleValue(QStringLiteral("op_sys"))); |
|
report.setBugStatus(getSimpleValue(QStringLiteral("bug_status"))); |
|
report.setResolution(getSimpleValue(QStringLiteral("resolution"))); |
|
report.setPriority(getSimpleValue(QStringLiteral("priority"))); |
|
report.setBugSeverity(getSimpleValue(QStringLiteral("bug_severity"))); |
|
report.setMarkedAsDuplicateOf(getSimpleValue(QStringLiteral("dup_id"))); |
|
report.setVersionFixedIn(getSimpleValue(QStringLiteral("cf_versionfixedin"))); |
|
|
|
//Parse full content + comments |
|
QStringList m_commentList; |
|
QDomNodeList comments = m_xml.elementsByTagName(QStringLiteral("long_desc")); |
|
for (int i = 0; i < comments.count(); i++) { |
|
QDomElement element = comments.at(i).firstChildElement(QStringLiteral("thetext")); |
|
m_commentList << element.text(); |
|
} |
|
|
|
report.setComments(m_commentList); |
|
|
|
} //isValid |
|
} //isValid |
|
|
|
return report; |
|
} |
|
|
|
QString BugReportXMLParser::getSimpleValue(const QString & name) //Extract an unique tag from XML |
|
{ |
|
QString ret; |
|
|
|
QDomNodeList bug_number = m_xml.elementsByTagName(name); |
|
if (bug_number.count() == 1) { |
|
QDomNode node = bug_number.at(0); |
|
ret = node.toElement().text(); |
|
} |
|
return ret; |
|
} |
|
|
|
//END BugzillaXMLParser |
|
|
|
void BugReport::setBugStatus(const QString &stat) |
|
{ |
|
setData(QStringLiteral("bug_status"), stat); |
|
|
|
m_status = parseStatus(stat); |
|
} |
|
|
|
void BugReport::setResolution(const QString &res) |
|
{ |
|
setData(QStringLiteral("resolution"), res); |
|
|
|
m_resolution = parseResolution(res); |
|
} |
|
|
|
BugReport::Status BugReport::parseStatus(const QString &stat) |
|
{ |
|
if (stat == QLatin1String("UNCONFIRMED")) { |
|
return Unconfirmed; |
|
} else if (stat == QLatin1String("CONFIRMED")) { |
|
return New; |
|
} else if (stat == QLatin1String("ASSIGNED")) { |
|
return Assigned; |
|
} else if (stat == QLatin1String("REOPENED")) { |
|
return Reopened; |
|
} else if (stat == QLatin1String("RESOLVED")) { |
|
return Resolved; |
|
} else if (stat == QLatin1String("NEEDSINFO")) { |
|
return NeedsInfo; |
|
} else if (stat == QLatin1String("VERIFIED")) { |
|
return Verified; |
|
} else if (stat == QLatin1String("CLOSED")) { |
|
return Closed; |
|
} else { |
|
return UnknownStatus; |
|
} |
|
} |
|
|
|
BugReport::Resolution BugReport::parseResolution(const QString &res) |
|
{ |
|
if (res.isEmpty()) { |
|
return NotResolved; |
|
} else if (res == QLatin1String("FIXED")) { |
|
return Fixed; |
|
} else if (res == QLatin1String("INVALID")) { |
|
return Invalid; |
|
} else if (res == QLatin1String("WONTFIX")) { |
|
return WontFix; |
|
} else if (res == QLatin1String("LATER")) { |
|
return Later; |
|
} else if (res == QLatin1String("REMIND")) { |
|
return Remind; |
|
} else if (res == QLatin1String("DUPLICATE")) { |
|
return Duplicate; |
|
} else if (res == QLatin1String("WORKSFORME")) { |
|
return WorksForMe; |
|
} else if (res == QLatin1String("MOVED")) { |
|
return Moved; |
|
} else if (res == QLatin1String("UPSTREAM")) { |
|
return Upstream; |
|
} else if (res == QLatin1String("DOWNSTREAM")) { |
|
return Downstream; |
|
} else if (res == QLatin1String("WAITINGFORINFO")) { |
|
return WaitingForInfo; |
|
} else if (res == QLatin1String("BACKTRACE")) { |
|
return Backtrace; |
|
} else if (res == QLatin1String("UNMAINTAINED")) { |
|
return Unmaintained; |
|
} else { |
|
return UnknownResolution; |
|
} |
|
}
|
|
|