Changeset View
Changeset View
Standalone View
Standalone View
src/bugzillaintegration/bugzillalib.h
1 | /******************************************************************* | 1 | /******************************************************************* | ||
---|---|---|---|---|---|
2 | * bugzillalib.h | 2 | * bugzillalib.h | ||
3 | * Copyright 2009, 2011 Dario Andres Rodriguez <andresbajotierra@gmail.com> | 3 | * Copyright 2009, 2011 Dario Andres Rodriguez <andresbajotierra@gmail.com> | ||
4 | * Copyright 2012 George Kiagiadakis <kiagiadakis.george@gmail.com> | 4 | * Copyright 2012 George Kiagiadakis <kiagiadakis.george@gmail.com> | ||
5 | * Copyright 2019 Harald Sitter <sitter@kde.org> | ||||
5 | * | 6 | * | ||
6 | * This program is free software; you can redistribute it and/or | 7 | * 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 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation; either version 2 of | 9 | * published by the Free Software Foundation; either version 2 of | ||
9 | * the License, or (at your option) any later version. | 10 | * the License, or (at your option) any later version. | ||
10 | * | 11 | * | ||
11 | * This program is distributed in the hope that it will be useful, | 12 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | 15 | * GNU General Public License for more details. | ||
15 | * | 16 | * | ||
16 | * You should have received a copy of the GNU General Public License | 17 | * 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 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | * | 19 | * | ||
19 | ******************************************************************/ | 20 | ******************************************************************/ | ||
20 | 21 | | |||
21 | #ifndef BUGZILLALIB__H | 22 | #ifndef BUGZILLALIB__H | ||
22 | #define BUGZILLALIB__H | 23 | #define BUGZILLALIB__H | ||
23 | 24 | | |||
24 | #include <QObject> | 25 | #include <QObject> | ||
25 | #include <QMap> | 26 | #include <QString> | ||
26 | #include <QStringList> | | |||
27 | #include <QDomDocument> | | |||
28 | 27 | | |||
29 | #include <kxmlrpcclient/client.h> | 28 | #include "bugzillaintegration/libbugzilla/bug.h" | ||
29 | #include "bugzillaintegration/libbugzilla/product.h" | ||||
30 | #include "bugzillaintegration/libbugzilla/attachment.h" | ||||
30 | 31 | | |||
31 | namespace KIO { class Job; } | 32 | namespace KIO { | ||
32 | class KJob; | 33 | class KJob; | ||
33 | class QString; | | |||
34 | class QByteArray; | | |||
35 | | ||||
36 | //Typedefs for Bug Report Listing | | |||
37 | typedef QMap<QString, QString> BugMap; //Report basic fields map | | |||
38 | typedef QList<BugMap> BugMapList; //List of reports | | |||
39 | | ||||
40 | //Main bug report data, full fields + comments | | |||
41 | class BugReport | | |||
42 | { | | |||
43 | public: | | |||
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(QStringLiteral("bug_id"), value); | | |||
82 | } | | |||
83 | QString bugNumber() const { | | |||
84 | return getData(QStringLiteral("bug_id")); | | |||
85 | } | | |||
86 | int bugNumberAsInt() const { | | |||
87 | return getData(QStringLiteral("bug_id")).toInt(); | | |||
88 | } | | |||
89 | | ||||
90 | void setShortDescription(const QString & value) { | | |||
91 | setData(QStringLiteral("short_desc"), value); | | |||
92 | } | | |||
93 | QString shortDescription() const { | | |||
94 | return getData(QStringLiteral("short_desc")); | | |||
95 | } | | |||
96 | | ||||
97 | void setProduct(const QString & value) { | | |||
98 | setData(QStringLiteral("product"), value); | | |||
99 | } | | |||
100 | QString product() const { | | |||
101 | return getData(QStringLiteral("product")); | | |||
102 | } | | |||
103 | | ||||
104 | void setComponent(const QString & value) { | | |||
105 | setData(QStringLiteral("component"), value); | | |||
106 | } | | |||
107 | QString component() const { | | |||
108 | return getData(QStringLiteral("component")); | | |||
109 | } | | |||
110 | | ||||
111 | void setVersion(const QString & value) { | | |||
112 | setData(QStringLiteral("version"), value); | | |||
113 | } | | |||
114 | QString version() const { | | |||
115 | return getData(QStringLiteral("version")); | | |||
116 | } | | |||
117 | | ||||
118 | void setOperatingSystem(const QString & value) { | | |||
119 | setData(QStringLiteral("op_sys"), value); | | |||
120 | } | | |||
121 | QString operatingSystem() const { | | |||
122 | return getData(QStringLiteral("op_sys")); | | |||
123 | } | | |||
124 | | ||||
125 | void setPlatform(const QString & value) { | | |||
126 | setData(QStringLiteral("rep_platform"), value); | | |||
127 | } | | |||
128 | QString platform() const { | | |||
129 | return getData(QStringLiteral("rep_platform")); | | |||
130 | } | 34 | } | ||
131 | 35 | | |||
132 | void setBugStatus(const QString &status); | | |||
133 | QString bugStatus() const { | | |||
134 | return getData(QStringLiteral("bug_status")); | | |||
135 | } | | |||
136 | | ||||
137 | void setResolution(const QString &resolution); | | |||
138 | QString resolution() const { | | |||
139 | return getData(QStringLiteral("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(QStringLiteral("priority"), value); | | |||
152 | } | | |||
153 | QString priority() const { | | |||
154 | return getData(QStringLiteral("priority")); | | |||
155 | } | | |||
156 | | ||||
157 | void setBugSeverity(const QString & value) { | | |||
158 | setData(QStringLiteral("bug_severity"), value); | | |||
159 | } | | |||
160 | QString bugSeverity() const { | | |||
161 | return getData(QStringLiteral("bug_severity")); | | |||
162 | } | | |||
163 | | ||||
164 | void setKeywords(const QStringList & keywords) { | | |||
165 | setData(QStringLiteral("keywords"), keywords.join(QStringLiteral(","))); | | |||
166 | } | | |||
167 | QStringList keywords() const { | | |||
168 | return getData(QStringLiteral("keywords")).split(QLatin1Char(',')); | | |||
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(QStringLiteral("dup_id"), dupID); | | |||
187 | } | | |||
188 | QString markedAsDuplicateOf() const { | | |||
189 | return getData(QStringLiteral("dup_id")); | | |||
190 | } | | |||
191 | | ||||
192 | void setVersionFixedIn(const QString & dupID) { | | |||
193 | setData(QStringLiteral("cf_versionfixedin"), dupID); | | |||
194 | } | | |||
195 | QString versionFixedIn() const { | | |||
196 | return getData(QStringLiteral("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 | | ||||
235 | private: | | |||
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 | | |||
252 | class BugReportXMLParser | | |||
253 | { | | |||
254 | public: | | |||
255 | explicit BugReportXMLParser(const QByteArray &); | | |||
256 | | ||||
257 | BugReport parse(); | | |||
258 | | ||||
259 | bool isValid() const { | | |||
260 | return m_valid; | | |||
261 | } | | |||
262 | | ||||
263 | private: | | |||
264 | QString getSimpleValue(const QString &); | | |||
265 | | ||||
266 | bool m_valid; | | |||
267 | QDomDocument m_xml; | | |||
268 | }; | | |||
269 | | ||||
270 | class BugListCSVParser | | |||
271 | { | | |||
272 | public: | | |||
273 | explicit BugListCSVParser(const QByteArray&); | | |||
274 | | ||||
275 | bool isValid() const { | | |||
276 | return m_isValid; | | |||
277 | } | | |||
278 | | ||||
279 | BugMapList parse(); | | |||
280 | | ||||
281 | private: | | |||
282 | bool m_isValid; | | |||
283 | QByteArray m_data; | | |||
284 | }; | | |||
285 | | ||||
286 | class Component | | |||
287 | { | | |||
288 | public: | | |||
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 | | ||||
294 | private: | | |||
295 | QString m_name; | | |||
296 | bool m_active; | | |||
297 | }; | | |||
298 | | ||||
299 | class Version | | |||
300 | { | | |||
301 | public: | | |||
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 | | ||||
308 | private: | | |||
309 | QString m_name; | | |||
310 | bool m_active; | | |||
311 | }; | | |||
312 | | ||||
313 | | ||||
314 | class Product | | |||
315 | { | | |||
316 | public: | | |||
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 | | ||||
342 | private: | | |||
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 | | ||||
355 | class BugzillaManager : public QObject | 36 | class BugzillaManager : public QObject | ||
356 | { | 37 | { | ||
357 | Q_OBJECT | 38 | Q_OBJECT | ||
358 | 39 | | |||
359 | public: | 40 | public: | ||
360 | // Note: it expect the bugTrackerUrl parameter to contain the trailing slash. | 41 | // 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" | 42 | // so it should be "https://bugs.kde.org/", not "https://bugs.kde.org" | ||
362 | explicit BugzillaManager(const QString &bugTrackerUrl, QObject *parent = nullptr); | 43 | explicit BugzillaManager(const QString &bugTrackerUrl, QObject *parent = nullptr); | ||
363 | 44 | | |||
364 | /* Login methods */ | 45 | /* Login methods */ | ||
365 | void tryLogin(const QString&, const QString&); | 46 | void tryLogin(const QString &username, const QString &password); | ||
366 | bool getLogged() const; | 47 | bool getLogged() const; | ||
367 | 48 | | |||
368 | QString getUsername() const; | 49 | QString getUsername() const; | ||
369 | 50 | | |||
370 | /* Bugzilla Action methods */ | 51 | /* Bugzilla Action methods */ | ||
371 | void fetchBugReport(int, QObject * jobOwner = nullptr); | 52 | void fetchBugReport(int, QObject *jobOwner = nullptr); | ||
372 | | ||||
373 | void searchBugs(const QStringList & products, const QString & severity, | 53 | void searchBugs(const QStringList &products, const QString &severity, | ||
374 | const QString & date_start, const QString & date_end , QString comment); | 54 | const QString &creationDate, const QString &comment); | ||
375 | 55 | void sendReport(const Bugzilla::NewBug &bug); | |||
376 | void sendReport(const BugReport & report); | | |||
377 | | ||||
378 | void attachTextToReport(const QString & text, const QString & filename, | 56 | void attachTextToReport(const QString &text, const QString &filename, | ||
379 | const QString & description, int bugId, const QString & comment); | 57 | const QString &description, int bugId, | ||
380 | 58 | const QString &comment); | |||
381 | void addMeToCC(int bugId); | 59 | void addMeToCC(int bugId); | ||
382 | | ||||
383 | void fetchProductInfo(const QString &); | 60 | void fetchProductInfo(const QString &); | ||
384 | 61 | | |||
385 | /* Misc methods */ | 62 | /* Misc methods */ | ||
386 | QString urlForBug(int bug_number) const; | 63 | QString urlForBug(int bug_number) const; | ||
387 | | ||||
388 | void stopCurrentSearch(); | 64 | void stopCurrentSearch(); | ||
389 | 65 | | |||
390 | /* Codes for security methods used by Bugzilla in various versions. */ | | |||
391 | enum SecurityMethod {UseCookies, UseTokens, UsePasswords}; | | |||
392 | SecurityMethod securityMethod() { return m_security; } | | |||
393 | | ||||
394 | private Q_SLOTS: | 66 | private Q_SLOTS: | ||
395 | /* Slots to handle KJob::finished */ | | |||
396 | void fetchBugJobFinished(KJob*); | | |||
397 | void searchBugsJobFinished(KJob*); | | |||
398 | void fetchProductInfoFinished(const QVariantMap&); | | |||
399 | | ||||
400 | void lookupVersion(); | 67 | void lookupVersion(); | ||
401 | 68 | | |||
402 | void callMessage(const QList<QVariant> & result, const QVariant & id); | | |||
403 | void callFault(int errorCode, const QString & errorString, const QVariant &id); | | |||
404 | | ||||
405 | Q_SIGNALS: | 69 | Q_SIGNALS: | ||
406 | /* Bugzilla actions finished successfully */ | 70 | /* Bugzilla actions finished successfully */ | ||
407 | void loginFinished(bool); | 71 | void loginFinished(bool logged); | ||
408 | void bugReportFetched(BugReport, QObject *); | 72 | void bugReportFetched(Bugzilla::Bug::Ptr bug, QObject *jobOwner); | ||
409 | void searchFinished(const BugMapList &); | 73 | void searchFinished(const QList<Bugzilla::Bug::Ptr> &bug); | ||
410 | void reportSent(int); | 74 | void reportSent(int bugId); | ||
411 | void attachToReportSent(int); | 75 | void attachToReportSent(int bugId); | ||
412 | void addMeToCCFinished(int); | 76 | void addMeToCCFinished(int bugId); | ||
413 | void productInfoFetched(Product); | 77 | void productInfoFetched(const Bugzilla::Product::Ptr &product); | ||
414 | void bugzillaVersionFound(); | 78 | void bugzillaVersionFound(); | ||
415 | 79 | | |||
416 | /* Bugzilla actions had errors */ | 80 | /* Bugzilla actions had errors */ | ||
417 | void loginError(const QString & errorMsg, const QString & extendedErrorMsg = QString()); | 81 | void loginError(const QString &errorMsg, const QString & xtendedErrorMsg = QString()); | ||
418 | void bugReportError(const QString &, QObject *); | 82 | void bugReportError(const QString &errorMsg, QObject *jobOwner); | ||
419 | void searchError(const QString &); | 83 | void searchError(const QString &errorMsg); | ||
420 | void sendReportError(const QString & errorMsg, const QString & extendedErrorMsg = QString()); | 84 | void sendReportError(const QString &errorMsg, const QString &extendedErrorMsg = QString()); | ||
421 | void sendReportErrorInvalidValues(); //To use default values | 85 | void sendReportErrorInvalidValues(); //To use default values | ||
422 | void attachToReportError(const QString & errorMsg, const QString & extendedErrorMsg = QString()); | 86 | void attachToReportError(const QString &errorMsg, const QString &extendedErrorMsg = QString()); | ||
423 | void addMeToCCError(const QString & errorMsg, const QString & extendedErrorMsg = QString()); | 87 | void addMeToCCError(const QString &errorMsg, const QString &extendedErrorMsg = QString()); | ||
424 | void productInfoError(); | 88 | void productInfoError(); | ||
425 | 89 | | |||
426 | private: | 90 | private: | ||
427 | QString m_bugTrackerUrl; | 91 | QString m_bugTrackerUrl; | ||
428 | QString m_username; | 92 | QString m_username; | ||
429 | QString m_token; | 93 | QString m_token; | ||
430 | QString m_password; | 94 | QString m_password; | ||
431 | bool m_logged; | 95 | bool m_logged = false; | ||
432 | SecurityMethod m_security; | | |||
433 | 96 | | |||
434 | KIO::Job * m_searchJob = nullptr; | 97 | KJob *m_searchJob = nullptr; | ||
435 | KXmlRpc::Client *m_xmlRpcClient = nullptr; | | |||
436 | 98 | | |||
437 | enum SecurityStatus {SecurityDisabled, SecurityEnabled}; | | |||
438 | void callBugzilla(const char* method, const char* id, | | |||
439 | QMap<QString, QVariant>& args, | | |||
440 | SecurityStatus security); | | |||
441 | void setFeaturesForVersion(const QString& version); | 99 | void setFeaturesForVersion(const QString &version); | ||
442 | }; | 100 | }; | ||
443 | 101 | | |||
444 | #endif | 102 | #endif |