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