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