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