Add trivial menu entries to all menus
[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 "webgit.h"
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 Html
43 webgit_main_link (struct webgit_query* query, Html text)
44 {
45   return html (
46                html_tag ("a",
47                          html_attr ("href", html_str (query->request->script_name))
48                          ),
49                text
50                );
51 }
52
53
54 /*
55   Main (repository list) page
56 */
57 static Html
58 webgit_main_menu_action (struct webgit_query* query)
59 {
60   return html (html_tag ("div"),
61                html (
62                      html_tag ("img",
63                                html_attr ("src", webgit_webskinpath (query, "icons/webgit_logo.png")),
64                                html_attr ("alt", "Webgit-Logo")
65                                )
66                      ), "<br />",
67                html_include (webgit_skinpath (query, "inc/site.inc")), "<br />",
68                // TODO: webgit_user_config_link (query), "<br />",
69                html (
70                      html_tag ("a",
71                                html_attr ("href", webgit_webskinpath (query, "inc/about.html"))
72                                ),
73                      "Powered by webgit"
74                      )
75                );
76 }
77
78 static Html
79 webgit_main_content_action (struct webgit_query* query)
80 {
81   Html table = html_list ();
82
83   html_list_append (table, html(
84                           html(html_tag ("tr"),
85                                html(html_tag ("th"),"Name"),
86                                html(html_tag ("th"),"Git URL"),
87                                html(html_tag ("th"),"Description"),
88                                html(html_tag ("th"),"Owner"),
89                                html(html_tag ("th"),"Last Change"),
90                                html(html_tag ("th"),"Author"),
91                                html(html_tag ("th"),"Committer"),
92                                html(html_tag ("th"),"Action")
93                                ),
94                           html_nl()
95                           )
96               );
97
98   int row = 0;
99
100   LLIST_FOREACH (&query->repos, node)
101     {
102       struct webgit_repo_info* n = (struct webgit_repo_info*)node;
103
104       webgit_repoinfo_find_last (n);
105
106       if (n->age < n->maxage)
107         {
108           html_list_append (table, html (
109                                          html_tag ("tr",
110                                                    html_attr ("class", (++row & 1) ? "odd" : "even")
111                                                    ),
112                                          html(html_tag ("td"),
113                                               webgit_summary_link (query, n, html (n->name))),
114                                          html(html_tag ("td"), n->url ?
115                                               html (
116                                                     html_tag ("a", html_attr ("href", n->url)),
117                                                     n->url)
118                                               : html("N/A")
119                                               ),
120                                          html(html_tag ("td"), n->description),
121                                          html(html_tag ("td"), n->owner),
122                                          html(html_tag ("td"),
123                                               webgit_object_link (query,
124                                                                   n->name, strlen(n->name),
125                                                                   n->last_commit, 40,
126                                                                   NULL,
127                                                                   NULL,
128                                                                   webgit_pretty_age (n->age))
129                                               ),
130                                          html(html_tag ("td"),
131                                               webgit_email_link (
132                                                                  html (n->last_author_name),
133                                                                  html (n->last_author_email)
134                                                                  )
135                                               ),
136                                          html(html_tag ("td"),
137                                               webgit_email_link (
138                                                                  html (n->last_committer_name),
139                                                                  html (n->last_committer_email)
140                                                                  )
141                                               ),
142                                          html(html_tag ("td"),
143                                               html(
144                                                    webgit_log_link (query,
145                                                                     n->name,
146                                                                     n->last_head,
147                                                                     NULL, 0,
148                                                                     query->count,
149                                                                     html("Log")
150                                                                     ),
151                                                    " ",
152                                                    "Diff ",
153                                                    //webgit_diff_link (query, n, n->last_head, html("Diff")),
154                                                    //" ",
155                                                    webgit_object_link (query,
156                                                                        n->name, strlen(n->name),
157                                                                        n->last_tree, 40,
158                                                                        NULL,
159                                                                        NULL,
160                                                                        html("Tree"))
161                                                    )
162                                               )
163                                          ),
164                             html_nl()
165                             );
166         }
167     }
168
169   return html (html_tag ("table", html_attr ("id", "summary")), table);
170 }
171
172 static Html
173 webgit_main_action (struct webgit_query* query)
174 {
175   return html(
176               html(html_tag("div", html_attr ("id", "sub-menu")), webgit_main_menu_action (query)), html_nl (),
177               html(html_tag("div", html_attr ("id", "content")), webgit_main_content_action (query)), html_nl ()
178               );
179 }
180
181
182 /*
183   Summary of a single repository
184 */
185 static Html
186 webgit_summary_menu_action (struct webgit_repo_info* repo)
187 {
188   return html (html_tag ("div"),
189                webgit_repo_logo (repo), "<br />",
190                repo->readme ? html_include (repo->readme) : html (), "<br />",
191                html (
192                      html_tag ("a",
193                                html_attr ("href", html_fmt ("%s?repo=%s&action=config",
194                                                             repo->query->request->script_name,
195                                                             repo->name)
196                                           )
197                                ),
198                      "Configure"
199                      ), "<br />",
200                webgit_main_link (repo->query, html ("Main")), "<br />"
201                );
202 }
203
204
205 static Html
206 webgit_summary_content_action (struct webgit_repo_info* repo)
207 {
208   Html content = html_list ();
209
210   /* Title */
211   html_list_append (content, html (html_tag ("h1"), repo->description));
212
213   /* Readme */
214   if (repo->readme)
215     html_list_append (content, html_include (repo->readme));
216
217   /* Info */
218   html_list_append (content,
219                     html (
220                           html (html_tag ("h2"), "Repository information"),
221                           repo->url ?
222                           html (
223                                 html_tag ("div"),
224                                 "Public URL: ",
225                                 html (
226                                       html_tag ("a", html_attr ("href", repo->url)),
227                                       repo->url
228                                       )
229                                 ) : html(),
230                           html (
231                                 html_tag ("div"),
232                                 "Owner: ", repo->owner
233                                 ),
234                           html(
235                                html_tag ("div"),
236                                "Last change: ",
237                                webgit_object_link (repo->query,
238                                                    repo->name, strlen(repo->name),
239                                                    repo->last_commit, 40,
240                                                    NULL,
241                                                    NULL,
242                                                    webgit_pretty_age (repo->age)),
243                                " in branch ",
244                                 webgit_log_link (repo->query,
245                                                  repo->name,
246                                                  repo->last_head,
247                                                  NULL, 0,
248                                                  repo->query->count,
249                                                  html ("'", repo->last_head, "'")
250                                                  )
251                                )
252                           )
253                     );
254
255   /* log */
256   html_list_append (content,
257                     html (
258                           html (html_tag ("h2"),
259                                 webgit_log_link (repo->query, repo->name, repo->last_head,
260                                                  NULL, 0, repo->query->count,
261                                                  html ("Log of branch '", repo->last_head, "'")
262                                                  )
263                                 ),
264                           webgit_log_table (repo->query, repo->last_head, 5 /*TODO: config this*/, 0))
265                     );
266
267
268   /* branches */
269   html_list_append (content,
270                     html (
271                           html (html_tag ("h2"),
272                                 webgit_branch_link (repo, NULL, repo->query->count,
273                                                     html ("Branches")
274                                                     )
275                                 ),
276                           webgit_branch_table (repo, NULL, 5 /*TODO: config this*/)
277                           )
278                     );
279
280   /* tags */
281   html_list_append (content,
282                     html (
283                           html (html_tag ("h2"),
284                                 webgit_tag_link (repo, NULL, repo->query->count,
285                                                  html ("Tags")
286                                                  )
287                                 ),
288                           webgit_tag_table (repo, NULL, 5 /*TODO: config this*/)
289                           )
290                     );
291
292
293   return content;
294 }
295
296
297 static Html
298 webgit_summary_action (struct webgit_query* query)
299 {
300   struct webgit_repo_info* repo = webgit_repo_enter (query);
301   webgit_repoinfo_find_last (repo);
302
303   return html(
304               html(html_tag("div", html_attr ("id", "sub-menu")), webgit_summary_menu_action (repo)), html_nl (),
305               html(html_tag("div", html_attr ("id", "content")), webgit_summary_content_action (repo)), html_nl ()
306               );
307 }
308
309
310 /*
311   Log page
312 */
313 static Html
314 webgit_log_action (struct webgit_query* query)
315 {
316   webgit_repo_enter (query);
317
318   return html(
319               html(html_tag("div", html_attr ("id", "sub-menu")), webgit_log_menu_action (query)), html_nl (),
320               html(html_tag("div", html_attr ("id", "content")), webgit_log_content_action (query)), html_nl ()
321               );
322 }
323
324
325 /*
326   Diff page
327 */
328 static Html
329 webgit_diff_action (struct webgit_query* query)
330 {
331   (void) query;
332 #if 0
333   return html (html_tag ("div"),
334                "Webgit logo<br />",
335                "Readme.html <br />",
336                "User (cookie) config <br />",
337                "About webgit (info/admin) <br />"
338                );
339 #endif
340   return html("diff");
341 }
342
343
344 /*
345   pretty printed objects
346 */
347 static Html
348 webgit_object_action (struct webgit_query* query)
349 {
350   struct webgit_repo_info* repo = 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   switch (sha1_object_info(sha1, NULL))
357     {
358     case OBJ_COMMIT:
359       if (!query->deref_to_tree)
360         return webgit_object_commit_action (repo, sha1);
361       /* else fallthrough */
362     case OBJ_TREE:
363       return webgit_object_tree_action (repo, sha1);
364     case OBJ_BLOB:
365       return webgit_object_blob_action (repo, sha1);
366     case OBJ_TAG:
367       return webgit_object_tag_action (repo, sha1);
368
369       break;
370     default:
371       return html ("error: unknown object type");
372       break;
373     }
374 }
375
376
377 /*
378   treeish dereferenced to tree
379 */
380 static Html
381 webgit_tree_action (struct webgit_query* query)
382 {
383   query->deref_to_tree = 1;
384   return webgit_object_action (query);
385 }
386
387
388 /*
389   spew out raw data
390 */
391 static Html
392 webgit_raw_action (struct webgit_query* query)
393 {
394   webgit_repo_enter (query);
395
396   unsigned char sha1[20];
397   if (get_sha1 (query->object, sha1))
398     return html("error: unknown object");
399
400   void* buf;
401   unsigned long size;
402
403   buf = read_object_with_reference (sha1, "blob", &size, NULL);
404
405   free ((char*)query->content_type);
406   query->content_type = webgit_mimetype (query->path);
407
408   return html_binary (buf, size);
409 }
410
411
412 /*
413   show branch
414 */
415 static Html
416 webgit_branch_menu_action (struct webgit_repo_info* repo)
417 {
418   (void) repo;
419   return html (html_tag ("div"),
420                webgit_repo_logo (repo), "<br />",
421                // TODO: "switch-branch-dropdown <br />",
422                // TODO: "push/fetch/merge <br />",
423                // TODO: "branch administation <br />",
424                webgit_summary_link (repo->query, repo, html("Summary")), "<br />",
425                webgit_main_link (repo->query, html ("Main"))
426                );
427 }
428
429
430 static Html
431 webgit_branch_action (struct webgit_query* query)
432 {
433   struct webgit_repo_info* repo = webgit_repo_enter (query);
434   webgit_repoinfo_find_last (repo);
435
436   return html(
437               html(html_tag("div", html_attr ("id", "sub-menu")), webgit_branch_menu_action (repo)), html_nl (),
438               html(html_tag("div", html_attr ("id", "content")),
439                    webgit_branch_table (repo, query->head, query->count), html_nl ())
440               );
441 }
442
443
444 /*
445   show tag
446 */
447 static Html
448 webgit_tag_menu_action (struct webgit_repo_info* repo)
449 {
450   (void) repo;
451   return html (html_tag ("div"),
452                webgit_repo_logo (repo), "<br />",
453                // TODO: "tag administation <br />",
454                webgit_summary_link (repo->query, repo, html("Summary")), "<br />",
455                webgit_main_link (repo->query, html ("Main"))
456                );
457 }
458
459
460 static Html
461 webgit_tag_action (struct webgit_query* query)
462 {
463   struct webgit_repo_info* repo = webgit_repo_enter (query);
464   webgit_repoinfo_find_last (repo);
465
466   return html(
467               html(html_tag("div", html_attr ("id", "sub-menu")), webgit_tag_menu_action (repo)), html_nl (),
468               html(html_tag("div", html_attr ("id", "content")),
469                    webgit_tag_table (repo, query->head, query->count), html_nl ())
470               );
471 }
472
473
474 /*
475   show and edit config
476 */
477 static Html
478 webgit_config_menu_action (struct webgit_repo_info* repo)
479 {
480   (void) repo;
481   return html (html_tag ("div"),
482                webgit_repo_logo (repo), "<br />",
483                // TODO: "manage remotes? <br />",
484                // TODO: "manage subprojects? <br />",
485                webgit_summary_link (repo->query, repo, html("Summary")), "<br />",
486                webgit_main_link (repo->query, html ("Main"))
487                );
488 }
489
490 static Html
491 webgit_config_content_action (struct webgit_repo_info* repo)
492 {
493   int readonly = !!access (git_path("config"), W_OK);
494
495   return html (
496                html_tag ("form",
497                          html_attr ("name", "config-change"),
498                          html_attr ("enctype", "multipart/form-data"),
499                          html_attr ("method", "post"),
500                          html_attr ("action",
501                                     html_fmt ("%s",
502                                               repo->query->request->script_name
503                                               )
504                                     )
505                          ),
506
507                html_hidden ("repo", repo->name),
508                html_hidden ("action", "config"),
509                html (
510                      html_tag ("textarea",
511                                html_attr ("name", "blob"),
512                                html_attr ("rows", "40"),
513                                html_attr ("cols", "80"),
514                                readonly ? "readonly" : ""
515                                ),
516                      html_include_escaped (git_path("config"))
517                      ),
518                readonly ? html ()
519                : html (
520                        html_tag ("input",
521                                  html_attr ("type", "submit"),
522                                  html_attr ("value", "Save")
523                                  )
524                        )
525                );
526 }
527
528 static Html
529 webgit_config_action (struct webgit_query* query)
530 {
531   struct webgit_repo_info* repo = webgit_repo_enter (query);
532   webgit_repoinfo_find_last (repo);
533
534   if (query->blob)
535     {
536       FILE* cfg = fopen (git_path ("config"), "w");
537
538       /*TODO rxpd check */
539       if (!cfg)
540         webgit_warn ("could not open %s for writing", git_path("config"));
541       else
542         {
543           if (fwrite (query->blob, query->blob_size, 1, cfg) < 1)
544             webgit_warn ("could not write config");
545           fclose (cfg);
546         }
547     }
548
549   return html(
550               html (html_tag ("div", html_attr("id", "sub-menu")), webgit_config_menu_action (repo)), html_nl (),
551               html (html_tag ("div", html_attr("id", "content")), webgit_config_content_action (repo)), html_nl ()
552               );
553 }
554
555
556 /*
557   edit an object
558 */
559 static Html
560 webgit_edit_action (struct webgit_query* query)
561 {
562   (void) query;
563   return html("edit");
564 }
565
566 /*
567   commit changes
568 */
569 static Html
570 webgit_commit_action (struct webgit_query* query)
571 {
572   (void) query;
573   return html("commit");
574 }
575
576
577 Html
578 webgit_action_dispatch (struct webgit_query* query)
579 {
580 #define WEBGIT_ACTION(name, _)                  \
581 {                                               \
582  #name,                                         \
583  webgit_##name##_action,                        \
584 },
585   struct action_table{
586     char* name;
587     Html (*cb)(struct webgit_query* query);
588   } cmds[] = {WEBGIT_ACTIONS {"", NULL}};
589 #undef WEBGIT_ACTION
590
591   for (struct action_table* j = cmds; j->cb; ++j)
592     {
593       if (!strcmp (j->name, query->action))
594         return j->cb (query);
595     }
596   return html("error, no such action");
597 }
598
599
600
601 /*
602 //      Local Variables:
603 //      mode: C
604 //      c-file-style: "gnu"
605 //      indent-tabs-mode: nil
606 //      End:
607 */