1/*******************************************************************
2* bugzillalib.h
3* Copyright 2009, 2011 Dario Andres Rodriguez <andresbajotierra@gmail.com>
4* Copyright 2012 George Kiagiadakis <kiagiadakis.george@gmail.com>
5*
6* This program is free software; you can redistribute it and/or
7* modify it under the terms of the GNU General Public License as
8* published by the Free Software Foundation; either version 2 of
9* the License, or (at your option) any later version.
10*
11* This program is distributed in the hope that it will be useful,
12* but WITHOUT ANY WARRANTY; without even the implied warranty of
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14* GNU General Public License for more details.
15*
16* You should have received a copy of the GNU General Public License
17* along with this program. If not, see <http://www.gnu.org/licenses/>.
18*
19******************************************************************/
20
21#ifndef BUGZILLALIB__H
22#define BUGZILLALIB__H
23
24#include <QtCore/QObject>
25#include <QtCore/QMap>
26#include <QtCore/QStringList>
27#include <QtXml/QDomDocument>
28
29#include <kxmlrpcclient/client.h>
30
31namespace KIO { class Job; }
32class KJob;
33class QString;
34class QByteArray;
35
36//Typedefs for Bug Report Listing
37typedef QMap<QString, QString> BugMap; //Report basic fields map
38typedef QList<BugMap> BugMapList; //List of reports
39
40//Main bug report data, full fields + comments
41class BugReport
42{
43public:
44 enum Status {
45 UnknownStatus,
46 Unconfirmed,
47 New,
48 Assigned,
49 Reopened,
50 Resolved,
51 NeedsInfo,
52 Verified,
53 Closed
54 };
55
56 enum Resolution {
57 UnknownResolution,
58 NotResolved,
59 Fixed,
60 Invalid,
61 WontFix,
62 Later,
63 Remind,
64 Duplicate,
65 WorksForMe,
66 Moved,
67 Upstream,
68 Downstream,
69 WaitingForInfo,
70 Backtrace,
71 Unmaintained
72 };
73
74 BugReport()
75 : m_isValid(false),
76 m_status(UnknownStatus),
77 m_resolution(UnknownResolution)
78 {}
79
80 void setBugNumber(const QString & value) {
81 setData("bug_id", value);
82 }
83 QString bugNumber() const {
84 return getData("bug_id");
85 }
86 int bugNumberAsInt() const {
87 return getData("bug_id").toInt();
88 }
89
90 void setShortDescription(const QString & value) {
91 setData("short_desc", value);
92 }
93 QString shortDescription() const {
94 return getData("short_desc");
95 }
96
97 void setProduct(const QString & value) {
98 setData("product", value);
99 }
100 QString product() const {
101 return getData("product");
102 }
103
104 void setComponent(const QString & value) {
105 setData("component", value);
106 }
107 QString component() const {
108 return getData("component");
109 }
110
111 void setVersion(const QString & value) {
112 setData("version", value);
113 }
114 QString version() const {
115 return getData("version");
116 }
117
118 void setOperatingSystem(const QString & value) {
119 setData("op_sys", value);
120 }
121 QString operatingSystem() const {
122 return getData("op_sys");
123 }
124
125 void setPlatform(const QString & value) {
126 setData("rep_platform", value);
127 }
128 QString platform() const {
129 return getData("rep_platform");
130 }
131
132 void setBugStatus(const QString &status);
133 QString bugStatus() const {
134 return getData("bug_status");
135 }
136
137 void setResolution(const QString &resolution);
138 QString resolution() const {
139 return getData("resolution");
140 }
141
142 Status statusValue() const {
143 return m_status;
144 }
145
146 Resolution resolutionValue() const {
147 return m_resolution;
148 }
149
150 void setPriority(const QString & value) {
151 setData("priority", value);
152 }
153 QString priority() const {
154 return getData("priority");
155 }
156
157 void setBugSeverity(const QString & value) {
158 setData("bug_severity", value);
159 }
160 QString bugSeverity() const {
161 return getData("bug_severity");
162 }
163
164 void setKeywords(const QStringList & keywords) {
165 setData("keywords", keywords.join(","));
166 }
167 QStringList keywords() const {
168 return getData("keywords").split(',');
169 }
170
171 void setDescription(const QString & desc) {
172 m_commentList.insert(0, desc);
173 }
174 QString description() const {
175 return m_commentList.at(0);
176 }
177
178 void setComments(const QStringList & comm) {
179 m_commentList.append(comm);
180 }
181 QStringList comments() const {
182 return m_commentList.mid(1);
183 }
184
185 void setMarkedAsDuplicateOf(const QString & dupID) {
186 setData("dup_id", dupID);
187 }
188 QString markedAsDuplicateOf() const {
189 return getData("dup_id");
190 }
191
192 void setVersionFixedIn(const QString & dupID) {
193 setData("cf_versionfixedin", dupID);
194 }
195 QString versionFixedIn() const {
196 return getData("cf_versionfixedin");
197 }
198
199 void setValid(bool valid) {
200 m_isValid = valid;
201 }
202 bool isValid() const {
203 return m_isValid;
204 }
205
206 /**
207 * @return true if the bug report is still open
208 * @note false does not mean, that the bug report is closed,
209 * as the status could be unknown
210 */
211 bool isOpen() const {
212 return isOpen(m_status);
213 }
214
215 static bool isOpen(Status status) {
216 return (status == Unconfirmed || status == New || status == Assigned || status == Reopened);
217 }
218
219 /**
220 * @return true if the bug report is closed
221 * @note false does not mean, that the bug report is still open,
222 * as the status could be unknown
223 */
224 bool isClosed() const {
225 return isClosed(m_status);
226 }
227
228 static bool isClosed(Status status) {
229 return (status == Resolved || status == NeedsInfo || status == Verified || status == Closed);
230 }
231
232 static Status parseStatus(const QString &text);
233 static Resolution parseResolution(const QString &text);
234
235private:
236 void setData(const QString & key, const QString & val) {
237 m_dataMap.insert(key, val);
238 }
239 QString getData(const QString & key) const {
240 return m_dataMap.value(key);
241 }
242
243 bool m_isValid;
244 Status m_status;
245 Resolution m_resolution;
246
247 BugMap m_dataMap;
248 QStringList m_commentList;
249};
250
251//XML parser that creates a BugReport object
252class BugReportXMLParser
253{
254public:
255 explicit BugReportXMLParser(const QByteArray &);
256
257 BugReport parse();
258
259 bool isValid() const {
260 return m_valid;
261 }
262
263private:
264 QString getSimpleValue(const QString &);
265
266 bool m_valid;
267 QDomDocument m_xml;
268};
269
270class BugListCSVParser
271{
272public:
273 explicit BugListCSVParser(const QByteArray&);
274
275 bool isValid() const {
276 return m_isValid;
277 }
278
279 BugMapList parse();
280
281private:
282 bool m_isValid;
283 QByteArray m_data;
284};
285
286class Component
287{
288public:
289 Component(const QString& name, bool active): m_name(name), m_active(active) {}
290
291 QString name() const { return m_name; }
292 bool active() const { return m_active; }
293
294private:
295 QString m_name;
296 bool m_active;
297};
298
299class Version
300{
301public:
302
303 Version(const QString& name, bool active): m_name(name), m_active(active) {}
304
305 QString name() const { return m_name; }
306 bool active() const { return m_active; }
307
308private:
309 QString m_name;
310 bool m_active;
311};
312
313
314class Product
315{
316public:
317
318 Product(const QString& name, bool active): m_name(name), m_active(active) {}
319
320 bool isActive() const { return m_active; }
321
322 void addComponent(const Component& component) {
323 m_allComponents.append(component.name());
324 }
325
326 void addVersion(const Version& version) {
327 m_allVersions.append(version.name());
328
329 if (version.active()) {
330 m_activeVersions.append(version.name());
331 } else {
332 m_inactiveVersions.append(version.name());
333 }
334 }
335
336 QStringList components() const { return m_allComponents; }
337
338 QStringList allVersions() const { return m_allVersions; }
339 QStringList activeVersions() const { return m_activeVersions; }
340 QStringList inactiveVersions() const { return m_inactiveVersions; }
341
342private:
343
344 QString m_name;
345 bool m_active;
346
347 QStringList m_allComponents;
348
349 QStringList m_allVersions;
350 QStringList m_activeVersions;
351 QStringList m_inactiveVersions;
352
353};
354
355class BugzillaManager : public QObject
356{
357 Q_OBJECT
358
359public:
360 // Note: it expect the bugTrackerUrl parameter to contain the trailing slash.
361 // so it should be "https://bugs.kde.org/", not "https://bugs.kde.org"
362 explicit BugzillaManager(const QString &bugTrackerUrl, QObject *parent = 0);
363
364 /* Login methods */
365 void tryLogin(const QString&, const QString&);
366 bool getLogged() const;
367
368 QString getUsername() const;
369
370 /* Bugzilla Action methods */
371 void fetchBugReport(int, QObject * jobOwner = 0);
372
373 void searchBugs(const QStringList & products, const QString & severity,
374 const QString & date_start, const QString & date_end , QString comment);
375
376 void sendReport(const BugReport & report);
377
378 void attachTextToReport(const QString & text, const QString & filename,
379 const QString & description, int bugId, const QString & comment);
380
381 void addMeToCC(int bugId);
382
383 void fetchProductInfo(const QString &);
384
385 /* Misc methods */
386 QString urlForBug(int bug_number) const;
387
388 void stopCurrentSearch();
389
390private Q_SLOTS:
391 /* Slots to handle KJob::finished */
392 void fetchBugJobFinished(KJob*);
393 void searchBugsJobFinished(KJob*);
394 void fetchProductInfoFinished(const QVariantMap&);
395
396 void callMessage(const QList<QVariant> & result, const QVariant & id);
397 void callFault(int errorCode, const QString & errorString, const QVariant &id);
398
399Q_SIGNALS:
400 /* Bugzilla actions finished successfully */
401 void loginFinished(bool);
402 void bugReportFetched(BugReport, QObject *);
403 void searchFinished(const BugMapList &);
404 void reportSent(int);
405 void attachToReportSent(int);
406 void addMeToCCFinished(int);
407 void productInfoFetched(Product);
408
409 /* Bugzilla actions had errors */
410 void loginError(const QString & errorMsg, const QString & extendedErrorMsg = QString());
411 void bugReportError(const QString &, QObject *);
412 void searchError(const QString &);
413 void sendReportError(const QString & errorMsg, const QString & extendedErrorMsg = QString());
414 void sendReportErrorInvalidValues(); //To use default values
415 void attachToReportError(const QString & errorMsg, const QString & extendedErrorMsg = QString());
416 void addMeToCCError(const QString & errorMsg, const QString & extendedErrorMsg = QString());
417 void productInfoError();
418
419private:
420 QString m_bugTrackerUrl;
421 QString m_username;
422 bool m_logged;
423
424 KIO::Job * m_searchJob;
425 KXmlRpc::Client *m_xmlRpcClient;
426};
427
428#endif
429