add odd/even class for table coloring
[webgit] / src / actions.c
1 /*
2     cehtehs git web frontend
3
4   Copyright (C)
5     2007, 2008,         Christian Thaeter <ct@pipapo.org>
6
7   This program is free software: you can redistribute it and/or modify
8   it under the terms of the GNU Affero General Public License as published by
9   the Free Software Foundation, either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU Affero General Public License for more details.
16
17   You should have received a copy of the GNU Affero General Public License
18   along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "actions.h"
22 #include "summary.h"
23 #include "object.h"
24 #include "log.h"
25 #include "repo.h"
26 #include "age.h"
27 #include "branch.h"
28 #include "tag.h"
29
30 #include "llist.h"
31 #include <cwa.h>
32
33 /* todo configure this */
34 #define SHA1_HEADER <openssl/sha.h>
35 #include "git/cache.h"
36 #include "git/refs.h"
37
38 #include <stdio.h>
39
40
41 /*
42   Main (repository list) page
43 */
44 static Html
45 webgit_main_menu_action (struct webgit_query* query)
46 {
47   (void) query;
48   return html ("TODO: main menu");
49 }
50
51 static Html
52 webgit_header_action (struct webgit_query* query)
53 {
54   (void) query;
55   return html (
56                "webgit header action"
57                );
58 }
59
60 static Html
61 webgit_main_content_action (struct webgit_query* query)
62 {
63   Html table = html_list ();
64
65   html_list_append (table, html(
66                           html(html_tag ("tr"),
67                                html(html_tag ("th"),"Name"),
68                                html(html_tag ("th"),"Git URL"),
69                                html(html_tag ("th"),"Description"),
70                                html(html_tag ("th"),"Owner"),
71                                html(html_tag ("th"),"Last Change"),
72                                html(html_tag ("th"),"Author"),
73                                html(html_tag ("th"),"Committer"),
74                                html(html_tag ("th"),"Action")
75                                ),
76                           html_nl()
77                           )
78               );
79
80   int row = 0;
81
82   LLIST_FOREACH (&query->repos, node)
83     {
84       struct webgit_repo_info* n = (struct webgit_repo_info*)node;
85
86       webgit_repoinfo_find_last (n);
87
88       if (n->age < n->maxage)
89         {
90           html_list_append (table, html (
91                                          html_tag ("tr",
92                                                    html_attr ("class", (++row & 1) ? "odd" : "even")
93                                                    ),
94                                          html(html_tag ("td"),
95                                               webgit_summary_link (query, n, html (n->name))),
96                                          html(html_tag ("td"), n->url ?
97                                               html (
98                                                     html_tag ("a", html_attr ("href", n->url)),
99                                                     n->url)
100                                               : html("N/A")
101                                               ),
102                                          html(html_tag ("td"), n->description),
103                                          html(html_tag ("td"), n->owner),
104                                          html(html_tag ("td"),
105                                               webgit_object_link (query,
106                                                                   n->name, strlen(n->name),
107                                                                   n->last_commit, 40,
108                                                                   NULL,
109                                                                   NULL,
110                                                                   webgit_pretty_age (n->age))
111                                               ),
112                                          html(html_tag ("td"),
113                                               webgit_email_link (
114                                                                  html (n->last_author_name),
115                                                                  html (n->last_author_email)
116                                                                  )
117                                               ),
118                                          html(html_tag ("td"),
119                                               webgit_email_link (
120                                                                  html (n->last_committer_name),
121                                                                  html (n->last_committer_email)
122                                                                  )
123                                               ),
124                                          html(html_tag ("td"),
125                                               html(
126                                                    webgit_log_link (query,
127                                                                     n->name,
128                                                                     n->last_head,
129                                                                     NULL, 0,
130                                                                     query->count,
131                                                                     html("Log")
132                                                                     ),
133                                                    " ",
134                                                    "Diff ",
135                                                    //webgit_diff_link (query, n, n->last_head, html("Diff")),
136                                                    //" ",
137                                                    webgit_object_link (query,
138                                                                        n->name, strlen(n->name),
139                                                                        n->last_tree, 40,
140                                                                        NULL,
141                                                                        NULL,
142                                                                        html("Tree"))
143                                                    )
144                                               )
145                                          ),
146                             html_nl()
147                             );
148         }
149     }
150
151   return html (html_tag ("table", html_attr ("id", "summary")), table);
152 }
153
154 static Html
155 webgit_main_action (struct webgit_query* query)
156 {
157   return html(
158               html(html_tag("div", html_attr("id", "sub-menu")), webgit_header_action (query)), html_nl (),
159               /*
160                 TODO:
161                 I'm not sure if we need this? Is the sub-menu sufficient?
162                 html(html_tag("div"), webgit_main_menu_action (query)), html_nl (), 
163               */
164               html(html_tag("div", html_attr("id", "content")), webgit_main_content_action (query)), html_nl ()
165               );
166 }
167
168
169 /*
170   Summary of a single repository
171 */
172 static Html
173 webgit_summary_menu_action (struct webgit_repo_info* repo)
174 {
175   (void) repo;
176   return html(html_tag("div", html_attr("id", "sub-menu")), "TODO: summary");
177 }
178
179
180 static Html
181 webgit_summary_content_action (struct webgit_repo_info* repo)
182 {
183   Html content = html_list ();
184
185   /* Title */
186   html_list_append (content, html (html_tag ("h1"), repo->description));
187
188   /* Readme */
189   if (repo->readme)
190     html_list_append (content, html_include (repo->readme));
191
192   /* Info */
193   html_list_append (content,
194                     html (
195                           html (html_tag ("h2"), "Repository information"),
196                           repo->url ?
197                           html (
198                                 html_tag ("div"),
199                                 "Public URL: ",
200                                 html (
201                                       html_tag ("a", html_attr ("href", repo->url)),
202                                       repo->url
203                                       )
204                                 ) : html(),
205                           html (
206                                 html_tag ("div"),
207                                 "Owner: ", repo->owner
208                                 ),
209                           html(
210                                html_tag ("div"),
211                                "Last change: ",
212                                webgit_object_link (repo->query,
213                                                    repo->name, strlen(repo->name),
214                                                    repo->last_commit, 40,
215                                                    NULL,
216                                                    NULL,
217                                                    webgit_pretty_age (repo->age)),
218                                " in branch ",
219                                 webgit_log_link (repo->query,
220                                                  repo->name,
221                                                  repo->last_head,
222                                                  NULL, 0,
223                                                  repo->query->count,
224                                                  html ("'", repo->last_head, "'")
225                                                  )
226                                )
227                           )
228                     );
229
230   /* log */
231   html_list_append (content,
232                     html (
233                           html (html_tag ("h2"), "Log of branch '", repo->last_head, "'"),
234                           webgit_log_table (repo->query, repo->last_head, 5 /*TODO: config this*/, 0))
235                     );
236
237
238   /* branches */
239   html_list_append (content,
240                     html (
241                           html (html_tag ("h2"), "Branches"),
242                           webgit_branch_table (repo, NULL, 5 /*TODO: config this*/)
243                           )
244                     );
245
246   /* tags */
247   html_list_append (content,
248                     html (
249                           html (html_tag ("h2"), "Tags"),
250                           webgit_tag_table (repo, NULL, 5 /*TODO: config this*/)
251                           )
252                     );
253
254
255   return content;
256 }
257
258
259 static Html
260 webgit_summary_action (struct webgit_query* query)
261 {
262   struct webgit_repo_info* repo = webgit_repo_enter (query);
263   webgit_repoinfo_find_last (repo);
264
265   return html(
266               html(html_tag("div"), webgit_summary_menu_action (repo)), html_nl (),
267               html(html_tag("div", html_attr("id", "content")), webgit_summary_content_action (repo)), html_nl ()
268               );
269 }
270
271
272 /*
273   Log page
274 */
275 static Html
276 webgit_log_action (struct webgit_query* query)
277 {
278   webgit_repo_enter (query);
279
280   return html(
281               html(html_tag("div"), webgit_log_menu_action (query)), html_nl (),
282               html(html_tag("div", html_attr("id", "content")), webgit_log_content_action (query)), html_nl ()
283               );
284 }
285
286
287 /*
288   Diff page
289 */
290 static Html
291 webgit_diff_action (struct webgit_query* query)
292 {
293   (void) query;
294   return html("diff");
295 }
296
297
298 /*
299   pretty printed objects
300 */
301 static Html
302 webgit_object_action (struct webgit_query* query)
303 {
304   struct webgit_repo_info* repo = webgit_repo_enter (query);
305
306   unsigned char sha1[20];
307   if (get_sha1 (query->object, sha1))
308     return html("error: unknown object");
309
310   switch (sha1_object_info(sha1, NULL))
311     {
312     case OBJ_COMMIT:
313       if (!query->deref_to_tree)
314         return webgit_object_commit_action (repo, sha1);
315       /* else fallthrough */
316     case OBJ_TREE:
317       return webgit_object_tree_action (repo, sha1);
318     case OBJ_BLOB:
319       return webgit_object_blob_action (repo, sha1);
320     case OBJ_TAG:
321       return webgit_object_tag_action (repo, sha1);
322
323       break;
324     default:
325       return html ("error: unknown object type");
326       break;
327     }
328 }
329
330
331 /*
332   treeish dereferenced to tree
333 */
334 static Html
335 webgit_tree_action (struct webgit_query* query)
336 {
337   query->deref_to_tree = 1;
338   return webgit_object_action (query);
339 }
340
341
342 /*
343   spew out raw data
344 */
345 static Html
346 webgit_raw_action (struct webgit_query* query)
347 {
348   webgit_repo_enter (query);
349
350   unsigned char sha1[20];
351   if (get_sha1 (query->object, sha1))
352     return html("error: unknown object");
353
354   void* buf;
355   unsigned long size;
356
357   buf = read_object_with_reference (sha1, "blob", &size, NULL);
358
359   free ((char*)query->content_type);
360   query->content_type = webgit_mimetype (query->path);
361
362   return html_binary (buf, size);
363 }
364
365
366 /*
367   show branch
368 */
369 static Html
370 webgit_branch_menu_action (struct webgit_repo_info* repo)
371 {
372   (void) repo;
373   return html ("TODO: branch sidebar");
374 }
375
376
377 static Html
378 webgit_branch_action (struct webgit_query* query)
379 {
380   struct webgit_repo_info* repo = webgit_repo_enter (query);
381   webgit_repoinfo_find_last (repo);
382
383   return html(
384               html(html_tag("div", html_attr("id", "header")), webgit_header_action (query)), html_nl (),
385               html(html_tag("div", html_attr("id", "sub-menu")), webgit_branch_menu_action (repo)), html_nl (),
386               html(html_tag("div", html_attr("id", "content")), webgit_branch_table (repo, query->head, query->count), html_nl ())
387               );
388 }
389
390
391
392 /*
393   show tag
394 */
395 static Html
396 webgit_tag_action (struct webgit_query* query)
397 {
398   (void) query;
399   return html("tag");
400 }
401
402
403 /*
404   show and edit config
405 */
406 static Html
407 webgit_config_menu_action (struct webgit_repo_info* repo)
408 {
409   (void) repo;
410   return html ("TODO: config menu");
411 }
412
413 static Html
414 webgit_config_content_action (struct webgit_repo_info* repo)
415 {
416   int readonly = !!access (git_path("config"), W_OK);
417
418   return html (
419                html_tag ("form",
420                          html_attr ("name", "config-change"),
421                          html_attr ("enctype", "multipart/form-data"),
422                          html_attr ("method", "post"),
423                          html_attr ("action",
424                                     html_fmt ("%s",
425                                               repo->query->request->script_name
426                                               )
427                                     )
428                          ),
429
430                html_hidden ("repo", repo->name),
431                html_hidden ("action", "config"),
432                html (
433                      html_tag ("textarea",
434                                html_attr ("name", "blob"),
435                                html_attr ("rows", "40"),
436                                html_attr ("cols", "80"),
437                                readonly ? "readonly" : ""
438                                ),
439                      html_include_escaped (git_path("config"))
440                      ),
441                readonly ? html ()
442                : html (
443                        html_tag ("input",
444                                  html_attr ("type", "submit"),
445                                  html_attr ("value", "Save")
446                                  )
447                        )
448                );
449 }
450
451 static Html
452 webgit_config_action (struct webgit_query* query)
453 {
454   struct webgit_repo_info* repo = webgit_repo_enter (query);
455   webgit_repoinfo_find_last (repo);
456
457   if (query->blob)
458     {
459       FILE* cfg = fopen (git_path ("config"), "w");
460
461       /*TODO rxpd check */
462       if (!cfg)
463         webgit_warn ("could not open %s for writing", git_path("config"));
464       else
465         {
466           if (fwrite (query->blob, query->blob_size, 1, cfg) < 1)
467             webgit_warn ("could not write config");
468           fclose (cfg);
469         }
470     }
471
472   return html(
473               html (html_tag ("div"), webgit_config_menu_action (repo)), html_nl (),
474               html (html_tag ("div", html_attr("id", "content")), webgit_config_content_action (repo)), html_nl ()
475               );
476 }
477
478
479 /*
480   edit an object
481 */
482 static Html
483 webgit_edit_action (struct webgit_query* query)
484 {
485   (void) query;
486   return html("edit");
487 }
488
489 /*
490   commit changes
491 */
492 static Html
493 webgit_commit_action (struct webgit_query* query)
494 {
495   (void) query;
496   return html("commit");
497 }
498
499
500 Html
501 webgit_action_dispatch (struct webgit_query* query)
502 {
503 #define WEBGIT_ACTION(name, _)                  \
504 {                                               \
505  #name,                                         \
506  webgit_##name##_action,                        \
507 },
508   struct action_table{
509     char* name;
510     Html (*cb)(struct webgit_query* query);
511   } cmds[] = {WEBGIT_ACTIONS {"", NULL}};
512 #undef WEBGIT_ACTION
513
514   for (struct action_table* j = cmds; j->cb; ++j)
515     {
516       if (!strcmp (j->name, query->action))
517         return j->cb (query);
518     }
519   return html("error, no such action");
520 }
521
522
523
524 /*
525 //      Local Variables:
526 //      mode: C
527 //      c-file-style: "gnu"
528 //      indent-tabs-mode: nil
529 //      End:
530 */