Fix stringsource parsing to that apostrophes don't count as quotes.
[schedulator.git] / mantis.cs
blob48612a68b78426f5619b469331ff3ed24529520b
1 using System;
2 using System.Data;
3 using System.Data.Odbc;
4 using System.Collections;
5 using Wv;
6 using Wv.Schedulator;
8 namespace Wv.Schedulator
10 public class MantisSource : Source, IDisposable
12 string user; // get the bugs for this username
13 WvLog log;
14 WvDbi db;
16 public MantisSource(Schedulator s, string name, string odbcstring,
17 string user)
18 : base(s, name)
20 // note: the null user doesn't exist, but the "" user is used
21 // for all bugs not assigned to anyone yet.
22 if (user != null)
23 this.user = user;
24 else
25 this.user = s.name;
27 log = new WvLog(wv.fmt("Mantis:{0}", name));
28 log.print("Initializing Mantis source '{0}'.\n", name);
29 log.print("Connecting to: '{0}'\n", odbcstring);
30 db = WvDbi.create(odbcstring);
33 public void Dispose()
35 if (db != null) db.Dispose();
38 public static Source create(Schedulator s, string name,
39 string prefix, string suffix)
41 string[] bits = suffix.Split(':');
42 if (bits.Length >= 2)
43 return new MantisSource(s, name, bits[0], bits[1]);
44 else if (bits.Length >= 1)
45 return new MantisSource(s, name, bits[0], null);
46 else
47 throw new ArgumentException("bad moniker for MantisSource");
50 Hashtable mantispersons = new Hashtable();
51 Hashtable mantispersons_byname = new Hashtable();
52 Hashtable mantisprojects = new Hashtable();
53 Hashtable mantisfixfors = new Hashtable();
55 public override string view_url(string taskid)
57 return wv.fmt("http://mantis/view.php?id={0}", taskid);
60 public override void make_basic()
62 log.print("Reading mantis_user_table.\n");
63 foreach (var r in db.select("select id, username, realname "
64 + "from mantis_user_table "
65 + "order by enabled desc, id "))
67 int ix = r[0];
68 string name = r[1].IsNull ? "--" : r[1];
69 string fullname = r[2];
70 if (wv.isempty(fullname))
71 fullname = name;
72 name = name.ToLower();
74 Person p = s.persons.Add(name, fullname);
75 mantispersons.Add(ix, p);
76 if (!mantispersons_byname.Contains(name))
77 mantispersons_byname.Add(name, ix);
80 // the "Undecided" user
81 mantispersons.Add(0, s.persons.Add("", "-Undecided-"));
82 mantispersons_byname.Remove("");
83 mantispersons_byname.Add("", 0);
85 log.print("Reading mantis_project_table.\n");
86 foreach (var r in db.select("select id, name from mantis_project_table"))
88 int ix = r[0];
89 string name = r[1];
91 Project p = s.projects.Add(name);
92 mantisprojects.Add(ix, p);
95 log.print("Reading list of versions.\n");
96 string[] cols = {"fixed_in_version", "version"};
97 foreach (string col in cols)
99 foreach (var r in db.select(wv.fmt("select distinct project_id, {0} "
100 + "from mantis_bug_table "
101 + "order by project_id, {0} ", col)))
103 int projix = r[0];
104 string name = r[1];
105 if (wv.isempty(name)) name = "-Undecided-";
106 string ix = projix.ToString() + "." + name;
108 Project project = (Project)mantisprojects[projix];
109 if (project == null)
110 project = s.projects.Add("UNKNOWN");
112 FixFor f = s.fixfors.Add(project, name);
113 if (!mantisfixfors.Contains(ix))
114 mantisfixfors.Add(ix, f);
118 log.print("Reading mantis_project_version_table.\n");
119 foreach (var r in db.select("select project_id, version, date_order "
120 + " from mantis_project_version_table "))
122 int projix = r[0];
123 string name = r[1];
124 DateTime date = r[2];
125 string ix = projix.ToString() + "." + name;
127 Project project = (Project)mantisprojects[projix];
128 if (project == null)
129 project = s.projects.Add("UNKNOWN");
131 FixFor f = s.fixfors.Add(project, name);
132 if (!mantisfixfors.Contains(ix))
133 mantisfixfors.Add(ix, f);
134 f.add_release(date);
138 string bug_str(ICollection list)
140 if (list.Count == 0)
141 return "-1";
142 else
144 string[] array = new string[list.Count];
145 list.CopyTo(array, 0);
146 return String.Join(",", array);
150 void add_list(ArrayList list, ICollection src)
152 foreach (object o in src)
153 list.Add(o);
156 Task add_task(string ixstr, string title, FixFor fixfor, int pri,
157 bool done, bool halfdone, DateTime donedate)
159 Task t = s.tasks.Add(this, ixstr, title);
160 t.fixfor = fixfor;
161 t.priority = pri;
162 if (done)
164 t.done = true;
165 t.donedate = donedate;
167 t.halfdone = halfdone;
168 return t;
171 enum Status {
172 New=10, Feedback=20, Acknowledged=30, Confirmed=40,
173 Assigned=50, Resolved=80, Closed=90,
176 enum Resolution {
177 Open=10, Fixed=20, Reopened=30, NotReproducible=40,
178 NotFixable=50, Duplicate=60, NotABug=70, Suspended=80,
179 WontFix=80,
182 enum Priority {
183 None=10, Low=20, Normal=30, High=40, Urgent=50, Immediate=60,
186 int priority_map(int pri)
188 if (pri <= (int)Priority.None)
189 return 7;
190 else if (pri <= (int)Priority.Low)
191 return 5;
192 else if (pri <= (int)Priority.Normal)
193 return 4;
194 else if (pri <= (int)Priority.High)
195 return 3;
196 else if (pri <= (int)Priority.Urgent)
197 return 2;
198 else if (pri <= (int)Priority.Immediate)
199 return 1;
200 else
201 return 1;
204 public override Task[] make_tasks()
206 Hashtable abugs = new Hashtable(); // active
207 Hashtable vbugs = new Hashtable(); // needs-verify
208 Hashtable rbugs = new Hashtable(); // resolved-by-me
209 Hashtable sbugs = new Hashtable(); // stolen by someone else
211 if (!mantispersons_byname.Contains(user))
213 log.print("No user '{0}' exists!\n", user);
214 return null;
217 int userix = (int)mantispersons_byname[user];
219 log.print("Listing active bugs.\n");
220 foreach (var r in db.select(wv.fmt("select id, status "
221 + "from mantis_bug_table "
222 + "where handler_id={0} "
223 + " and status != {1} ",
224 userix, (int)Status.Closed)))
226 int ix = r[0];
227 int status = r[1];
228 if (status >= (int)Status.Resolved)
229 vbugs.Add(ix, ix.ToString());
230 else
231 abugs.Add(ix, ix.ToString());
234 log.print("Reading mantis_bug_history_table (1).\n");
235 foreach (var r in db.select(wv.fmt("select distinct bug_id "
236 + " from mantis_bug_history_table "
237 + " where user_id={0} "
238 + " and field_name='resolution' ",
239 userix)))
240 rbugs.Add((int)r[0], (string)r[0]);
241 log.print(" {0} bugs to check.\n", rbugs.Count);
242 string rbugs_str = bug_str(rbugs.Values);
243 // log.print("rbugs: {0}\n", rbugs_str);
245 log.print("Reading mantis_bug_history_table (2).\n");
246 rbugs.Clear();
247 int last_bug = -1;
248 bool resolved_by_me_once = false, resolved_away = false;
249 foreach (var r in db.select(wv.fmt
250 ("select bug_id, user_id, new_value "
251 + " from mantis_bug_history_table "
252 + " where field_name='resolution' "
253 + " and new_value is not null "
254 + " and bug_id in ({1}) "
255 + " order by bug_id, id ",
256 userix, rbugs_str)))
258 int bug = r[0];
259 int ixperson = r[1];
260 int newval = r[2];
262 if (last_bug != bug)
264 if (resolved_away)
265 sbugs.Add(last_bug, last_bug.ToString());
266 else if (resolved_by_me_once)
267 rbugs.Add(last_bug, last_bug.ToString());
269 last_bug = bug;
270 resolved_by_me_once = resolved_away = false;
273 // hacky attempt at Resolved (Again) from FogBugz
274 if (newval == (int)Resolution.Suspended)
275 continue;
277 if (userix == ixperson)
279 resolved_by_me_once = true;
280 resolved_away = false; // I stole it back!
282 else if (resolved_by_me_once)
283 resolved_away = true; // Someone re-resolved my bug!
286 // finish the very last bug from that query
287 if (resolved_away)
288 sbugs.Add(last_bug, last_bug.ToString());
289 else if (resolved_by_me_once)
290 rbugs.Add(last_bug, last_bug.ToString());
292 log.print("{0} abugs, {1} vbugs, {2} rbugs and {3} sbugs.\n",
293 abugs.Count, vbugs.Count, rbugs.Count, sbugs.Count);
295 log.print("Reading bug details.\n");
296 ArrayList all_bugs = new ArrayList();
297 add_list(all_bugs, abugs.Values);
298 add_list(all_bugs, vbugs.Values);
299 add_list(all_bugs, rbugs.Values);
300 add_list(all_bugs, sbugs.Values);
301 string all_str = bug_str(all_bugs);
302 foreach (var r in db.select(wv.fmt
303 ("select id, summary, project_id, "
304 + " fixed_in_version, version, "
305 + " priority, last_updated "
306 + "from mantis_bug_table "
307 + "where id in ({0})", all_str)))
309 int ix = r[0];
310 string ixstr = ix.ToString();
311 string title = r[1].IsNull ? "--" : r[1];
312 int ixproject = r[2];
313 string ffname
314 = (r[3].IsNull
315 ? (r[4].IsNull ? "" : r[4])
316 : r[3]);
317 if (wv.isempty(ffname)) ffname = "-Undecided-";
318 int pri = priority_map(r[5]);
319 string ixfixfor = ixproject.ToString() + "." + ffname;
320 DateTime resolvedate = r[6];
322 FixFor fixfor = (FixFor)mantisfixfors[ixfixfor];
324 if (abugs.Contains(ix))
325 add_task(ixstr, title, fixfor, pri, false, false,
326 DateTime.MinValue);
327 else if (rbugs.Contains(ix) && !vbugs.Contains(ix))
328 add_task(ixstr, title, fixfor, pri, true, true,
329 resolvedate);
330 else if (sbugs.Contains(ix))
331 add_task(ixstr, title, fixfor, pri, true, true,
332 resolvedate);
334 // FIXME: "verify" tasks will disappear once closed,
335 // since they'll no longer be assigned to the user.
336 // We should read "closed" verbs from BugEvent too.
337 if (vbugs.Contains(ix))
339 string x = abugs.Contains(ix) ? "v"+ixstr : ixstr;
340 add_task(x, "VERIFY: " + title, fixfor, pri,
341 false, true, DateTime.MinValue);
345 return null;