1 //
2 // aegis - project change supervisor
3 // Copyright (C) 2004-2008, 2011, 2012 Peter Miller
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see
17 // <http://www.gnu.org/licenses/>.
18 //
19
20 #include <common/ac/assert.h>
21 #include <common/ac/stdio.h>
22
23 #include <common/mem.h>
24 #include <common/str_list.h>
25 #include <common/symtab.h>
26 #include <libaegis/change.h>
27 #include <libaegis/emit/project.h>
28 #include <libaegis/http.h>
29 #include <libaegis/project.h>
30 #include <libaegis/project/history.h>
31 #include <libaegis/user.h>
32
33 #include <aeget/get/project/staff.h>
34
35 #define BAR_WIDTH 50
36 #define BAR_HEIGHT 12
37
38
39 struct staff_role_ty
40 {
41 int enabled;
42 long count;
43 };
44
45 struct staff_member_ty
46 {
47 staff_role_ty developer;
48 staff_role_ty reviewer;
49 staff_role_ty integrator;
50 staff_role_ty admin;
51 };
52
53
54 static void
staff_member_constructor(staff_member_ty * smp)55 staff_member_constructor(staff_member_ty *smp)
56 {
57 smp->developer.enabled = 0;
58 smp->developer.count = 0;
59 smp->reviewer.enabled = 0;
60 smp->reviewer.count = 0;
61 smp->integrator.enabled = 0;
62 smp->integrator.count = 0;
63 smp->admin.enabled = 0;
64 smp->admin.count = 0;
65 }
66
67
68 static staff_member_ty *
staff_member_new(void)69 staff_member_new(void)
70 {
71 staff_member_ty *smp;
72
73 smp = (staff_member_ty *)mem_alloc(sizeof(staff_member_ty));
74 staff_member_constructor(smp);
75 return smp;
76 }
77
78
79 static void
staff_member_delete(staff_member_ty * smp)80 staff_member_delete(staff_member_ty *smp)
81 {
82 mem_free(smp);
83 }
84
85
86 static void
reaper(void * p)87 reaper(void *p)
88 {
89 staff_member_ty *smp;
90
91 smp = (staff_member_ty *)p;
92 staff_member_delete(smp);
93 }
94
95
96 static const char *
flag(int x)97 flag(int x)
98 {
99 return (x ? "Yes" : "No");
100 }
101
102
103 static staff_member_ty *
staff_member_find(symtab_ty * stp,string_ty * key)104 staff_member_find(symtab_ty *stp, string_ty *key)
105 {
106 staff_member_ty *mp;
107
108 mp = (staff_member_ty *)stp->query(key);
109 if (!mp)
110 {
111 mp = staff_member_new();
112 stp->assign(key, mp);
113 }
114 return mp;
115 }
116
117
118 void
get_project_staff(project * pp,string_ty *,string_list_ty *)119 get_project_staff(project *pp, string_ty *, string_list_ty *)
120 {
121 double scale;
122 cstate_branch_ty *bp;
123 change::pointer cp;
124 long number_of_changes = 0;
125 size_t n;
126 cstate_ty *cstate_data;
127 staff_member_ty total;
128 staff_member_ty highwater;
129 long tmax;
130 string_ty *key;
131 staff_member_ty *smp;
132 size_t j;
133
134 html_header(pp, 0);
135 printf("<title>Project ");
136 html_encode_string(project_name_get(pp));
137 printf(" Staff</title></head><body>\n");
138 html_header_ps(pp, 0);
139 printf("<h1 align=center>\n");
140 emit_project(pp);
141 printf(",<br>\nList of Staff</h1>\n");
142 printf("<div class=\"information\">\n");
143
144 printf("This page provides infomation about staff assigned to\n");
145 printf("the project, and the permissions they have top perform\n");
146 printf("each role. Statistics are provided about how many\n");
147 printf("times these roles have been exersized.\n");
148
149 symtab_ty *stp = new symtab_ty(5);
150 stp->set_reap(reaper);
151
152 //
153 // Set the enabled flag for active staff members.
154 //
155 for (j = 0; ; ++j)
156 {
157 key = project_administrator_nth(pp, j);
158 if (!key)
159 break;
160 smp = staff_member_find(stp, key);
161 smp->admin.enabled = 1;
162 }
163 for (j = 0; ; ++j)
164 {
165 key = project_developer_nth(pp, j);
166 if (!key)
167 break;
168 smp = staff_member_find(stp, key);
169 smp->developer.enabled = 1;
170 }
171 for (j = 0; ; ++j)
172 {
173 key = project_reviewer_nth(pp, j);
174 if (!key)
175 break;
176 smp = staff_member_find(stp, key);
177 smp->reviewer.enabled = 1;
178 }
179 for (j = 0; ; ++j)
180 {
181 key = project_integrator_nth(pp, j);
182 if (!key)
183 break;
184 smp = staff_member_find(stp, key);
185 smp->integrator.enabled = 1;
186 }
187
188 //
189 // traverse each change
190 //
191 staff_member_constructor(&total);
192 staff_member_constructor(&highwater);
193 cp = pp->change_get();
194 cstate_data = cp->cstate_get();
195 bp = cstate_data->branch;
196 assert(bp);
197 if (!bp->change)
198 {
199 bp->change =
200 (cstate_branch_change_list_ty *)
201 cstate_branch_change_list_type.alloc();
202 }
203 for (n = 0; n < bp->change->length; ++n)
204 {
205 long change_number;
206 cstate_history_list_ty *hlp;
207
208 change_number = bp->change->list[n];
209 cp = change_alloc(pp, change_number);
210 change_bind_existing(cp);
211 cstate_data = cp->cstate_get();
212
213 hlp = cstate_data->history;
214 if (hlp)
215 {
216 size_t k;
217
218 for (k = 0; k < hlp->length; ++k)
219 {
220 cstate_history_ty *hp;
221
222 hp = hlp->list[k];
223 smp = staff_member_find(stp, hp->who);
224 switch (hp->what)
225 {
226 case cstate_history_what_new_change:
227 smp->admin.count++;
228 if (highwater.admin.count < smp->admin.count)
229 highwater.admin.count = smp->admin.count;
230 total.admin.count++;
231 break;
232
233 case cstate_history_what_develop_begin:
234 case cstate_history_what_develop_begin_undo:
235 case cstate_history_what_develop_end:
236 case cstate_history_what_develop_end_2ar:
237 case cstate_history_what_develop_end_2ai:
238 case cstate_history_what_develop_end_undo:
239 smp->developer.count++;
240 if (highwater.developer.count < smp->developer.count)
241 highwater.developer.count = smp->developer.count;
242 total.developer.count++;
243 break;
244
245 case cstate_history_what_review_begin:
246 case cstate_history_what_review_begin_undo:
247 case cstate_history_what_review_pass:
248 case cstate_history_what_review_pass_undo:
249 case cstate_history_what_review_fail:
250 case cstate_history_what_review_pass_2ar:
251 case cstate_history_what_review_pass_2br:
252 case cstate_history_what_review_pass_undo_2ar:
253 smp->reviewer.count++;
254 if (highwater.reviewer.count < smp->reviewer.count)
255 highwater.reviewer.count = smp->reviewer.count;
256 total.reviewer.count++;
257 break;
258
259 case cstate_history_what_integrate_begin:
260 case cstate_history_what_integrate_begin_undo:
261 case cstate_history_what_integrate_pass:
262 case cstate_history_what_integrate_fail:
263 smp->integrator.count++;
264 if (highwater.integrator.count < smp->integrator.count)
265 highwater.integrator.count = smp->integrator.count;
266 total.integrator.count++;
267 break;
268 }
269 smp = 0;
270 }
271 }
272 number_of_changes++;
273 change_free(cp);
274 cp = 0;
275 }
276 tmax = highwater.admin.count;
277 if (tmax < highwater.developer.count)
278 tmax = highwater.developer.count;
279 if (tmax < highwater.reviewer.count)
280 tmax = highwater.reviewer.count;
281 if (tmax < highwater.integrator.count)
282 tmax = highwater.integrator.count;
283 scale = (tmax ? (double)BAR_WIDTH / tmax : 1);
284
285 //
286 // Extract the names from the symbol table.
287 // Sort them for predictable results.
288 //
289 string_list_ty keys;
290 stp->keys(&keys);
291 keys.sort();
292
293 //
294 // Print statistics about staff.
295 //
296 printf("<table align=center>\n");
297 printf("<tr class=\"even-group\"><th>User</th>\n");
298 printf("<th colspan=3>Developer</th>");
299 printf("<th colspan=3>Reviewer</th>\n");
300 printf("<th colspan=3>Integrator</th>\n");
301 printf("<th colspan=3>Administrator</th></tr>\n");
302 for (n = 0; n < keys.nstrings; ++n)
303 {
304 user_ty::pointer up;
305 int width;
306
307 key = keys.string[n];
308 smp = (staff_member_ty *)stp->query(key);
309 assert(smp);
310 if (!smp)
311 continue;
312
313 printf("<tr class=\"%s-group\">\n", (j % 6 < 3 ? "odd" : "even"));
314 printf("<td valign=top>\n");
315 printf("<a href=\"mailto:");
316 up = user_ty::create(nstring(key));
317 html_escape_string(up->get_email_address());
318 printf("\">");
319 html_encode_string(key);
320 printf("</a></td>\n");
321
322 printf("<td valign=top>%s</td>\n", flag(smp->developer.enabled));
323 printf("<td valign=top align=right>%ld</td>\n", smp->developer.count);
324 printf("<td valign=top width=%d>\n", BAR_WIDTH);
325 width = (int)(0.5 + scale * smp->developer.count);
326 emit_rect_image(width, BAR_HEIGHT, 0);
327 printf("</td>\n");
328
329 printf("<td valign=top>%s</td>\n", flag(smp->reviewer.enabled));
330 printf("<td valign=top align=right>%ld</td>\n", smp->reviewer.count);
331 printf("<td valign=top width=%d>\n", BAR_WIDTH);
332 width = (int)(0.5 + scale * smp->reviewer.count);
333 emit_rect_image(width, BAR_HEIGHT, 0);
334 printf("</td>\n");
335
336 printf("<td valign=top>%s</td>\n", flag(smp->integrator.enabled));
337 printf("<td valign=top align=right>%ld</td>\n", smp->integrator.count);
338 printf("<td valign=top width=%d>\n", BAR_WIDTH);
339 width = (int)(0.5 + scale * smp->integrator.count);
340 emit_rect_image(width, BAR_HEIGHT, 0);
341 printf("</td>\n");
342
343 printf("<td valign=top>%s</td>\n", flag(smp->admin.enabled));
344 printf("<td valign=top align=right>%ld</td>\n", smp->admin.count);
345 printf("<td valign=top width=%d>\n", BAR_WIDTH);
346 width = (int)(0.5 + scale * smp->admin.count);
347 emit_rect_image(width, BAR_HEIGHT, 0);
348 printf("</td></tr>\n");
349 }
350 printf("<tr class=\"even-group\">\n");
351 printf("<td colspan=13>Listed %ld staff.</td>\n", (long)keys.nstrings);
352 printf("</tr></table></div>\n");
353 delete stp;
354
355 printf("<hr>\n");
356 printf("<div class=\"report-cmd\">\n");
357 printf("A similar report may be obtained from the command line, with\n");
358 printf("<blockquote><pre>aer proj_staff -p ");
359 html_encode_string(project_name_get(pp));
360 printf("</pre></blockquote>\n");
361 printf("</div>\n");
362
363 printf("<hr>\n");
364 printf("<p align=center class=\"navbar\">[\n");
365 printf("<a href=\"%s/\">Project List</a> |\n", http_script_name());
366 emit_project_href(pp, "menu");
367 printf("Project Menu</a>\n");
368 printf("]</p>\n");
369
370 html_footer(pp, 0);
371 }
372
373
374 // vim: set ts=8 sw=4 et :
375