mixed work for more menu stuff
[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                repo->logo ?
190                html (
191                      html_tag ("a",
192                                html_attr ("href", repo->logolink ? repo->logolink : "/")),
193                      html (
194                            html_tag ("img",
195                                      html_attr ("src", repo->logo),
196                                      html_attr ("alt", html (repo->name,"-logo"))
197                                      )
198                            )
199                      )
200                : html (
201                        html_tag ("img",
202                                  html_attr ("src", webgit_webskinpath (repo->query, "icons/webgit_logo.png")),
203                                  html_attr ("alt", "Webgit-Logo")
204                                  )
205                        ), "<br />",
206                repo->readme ? html_include (repo->readme) : html (), "<br />",
207                html (
208                      html_tag ("a",
209                                html_attr ("href", html_fmt ("%s?repo=%s&action=config",
210                                                             repo->query->request->script_name,
211                                                             repo->name)
212                                           )
213                                ),
214                      "Configure"
215                      ),"<br />",
216                html (
217                      html_tag ("a",
218                                html_attr ("href", repo->query->request->script_name)
219                                ),
220                      "Main Page"
221                      ),"<br />"
222                );
223 }
224
225
226 static Html
227 webgit_summary_content_action (struct webgit_repo_info* repo)
228 {
229   Html content = html_list ();
230
231   /* Title */
232   html_list_append (content, html (html_tag ("h1"), repo->description));
233
234   /* Readme */
235   if (repo->readme)
236     html_list_append (content, html_include (repo->readme));
237
238   /* Info */
239   html_list_append (content,
240                     html (
241                           html (html_tag ("h2"), "Repository information"),
242                           repo->url ?
243                           html (
244                                 html_tag ("div"),
245                                 "Public URL: ",
246                                 html (
247                                       html_tag ("a", html_attr ("href", repo->url)),
248                                       repo->url
249                                       )
250                                 ) : html(),
251                           html (
252                                 html_tag ("div"),
253                                 "Owner: ", repo->owner
254                                 ),
255                           html(
256                                html_tag ("div"),
257                                "Last change: ",
258                                webgit_object_link (repo->query,
259                                                    repo->name, strlen(repo->name),
260                                                    repo->last_commit, 40,
261                                                    NULL,
262                                                    NULL,
263                                                    webgit_pretty_age (repo->age)),
264                                " in branch ",
265                                 webgit_log_link (repo->query,
266                                                  repo->name,
267                                                  repo->last_head,
268                                                  NULL, 0,
269                                                  repo->query->count,
270                                                  html ("'", repo->last_head, "'")
271                                                  )
272                                )
273                           )
274                     );
275
276   /* log */
277   html_list_append (content,
278                     html (
279                           html (html_tag ("h2"),
280                                 webgit_log_link (repo->query, repo->name, repo->last_head,
281                                                  NULL, 0, repo->query->count,
282                                                  html ("Log of branch '", repo->last_head, "'")
283                                                  )
284                                 ),
285                           webgit_log_table (repo->query, repo->last_head, 5 /*TODO: config this*/, 0))
286                     );
287
288
289   /* branches */
290   html_list_append (content,
291                     html (
292                           html (html_tag ("h2"),
293                                 webgit_branch_link (repo, NULL, repo->query->count,
294                                                     html ("Branches")
295                                                     )
296                                 ),
297                           webgit_branch_table (repo, NULL, 5 /*TODO: config this*/)
298                           )
299                     );
300
301   /* tags */
302   html_list_append (content,
303                     html (
304                           html (html_tag ("h2"),
305                                 webgit_tag_link (repo, NULL, repo->query->count,
306                                                  html ("Tags")
307                                                  )
308                                 ),
309                           webgit_tag_table (repo, NULL, 5 /*TODO: config this*/)
310                           )
311                     );
312
313
314   return content;
315 }
316
317
318 static Html
319 webgit_summary_action (struct webgit_query* query)
320 {
321   struct webgit_repo_info* repo = webgit_repo_enter (query);
322   webgit_repoinfo_find_last (repo);
323
324   return html(
325               html(html_tag("div", html_attr("id", "sub-menu")), webgit_summary_menu_action (repo)), html_nl (),
326               html(html_tag("div", html_attr("id", "content")), webgit_summary_content_action (repo)), html_nl ()
327               );
328 }
329
330
331 /*
332   Log page
333 */
334 static Html
335 webgit_log_action (struct webgit_query* query)
336 {
337   webgit_repo_enter (query);
338
339   return html(
340               html(html_tag("div"), webgit_log_menu_action (query)), html_nl (),
341               html(html_tag("div", html_attr("id", "content")), webgit_log_content_action (query)), html_nl ()
342               );
343 }
344
345
346 /*
347   Diff page
348 */
349 static Html
350 webgit_diff_action (struct webgit_query* query)
351 {
352   (void) query;
353 #if 0
354   return html (html_tag ("div"),
355                "Webgit logo<br />",
356                "Readme.html <br />",
357                "User (cookie) config <br />",
358                "About webgit (info/admin) <br />"
359                );
360 #endif
361   return html("diff");
362 }
363
364
365 /*
366   pretty printed objects
367 */
368 static Html
369 webgit_object_action (struct webgit_query* query)
370 {
371   struct webgit_repo_info* repo = webgit_repo_enter (query);
372
373   unsigned char sha1[20];
374   if (get_sha1 (query->object, sha1))
375     return html("error: unknown object");
376
377   switch (sha1_object_info(sha1, NULL))
378     {
379     case OBJ_COMMIT:
380       if (!query->deref_to_tree)
381         return webgit_object_commit_action (repo, sha1);
382       /* else fallthrough */
383     case OBJ_TREE:
384       return webgit_object_tree_action (repo, sha1);
385     case OBJ_BLOB:
386       return webgit_object_blob_action (repo, sha1);
387     case OBJ_TAG:
388       return webgit_object_tag_action (repo, sha1);
389
390       break;
391     default:
392       return html ("error: unknown object type");
393       break;
394     }
395 }
396
397
398 /*
399   treeish dereferenced to tree
400 */
401 static Html
402 webgit_tree_action (struct webgit_query* query)
403 {
404   query->deref_to_tree = 1;
405   return webgit_object_action (query);
406 }
407
408
409 /*
410   spew out raw data
411 */
412 static Html
413 webgit_raw_action (struct webgit_query* query)
414 {
415   webgit_repo_enter (query);
416
417   unsigned char sha1[20];
418   if (get_sha1 (query->object, sha1))
419     return html("error: unknown object");
420
421   void* buf;
422   unsigned long size;
423
424   buf = read_object_with_reference (sha1, "blob", &size, NULL);
425
426   free ((char*)query->content_type);
427   query->content_type = webgit_mimetype (query->path);
428
429   return html_binary (buf, size);
430 }
431
432
433 /*
434   show branch
435 */
436 static Html
437 webgit_branch_menu_action (struct webgit_repo_info* repo)
438 {
439   (void) repo;
440   return html (html_tag ("div"),
441                "Project or webgit logo<br />",
442                "switch-branch-dropdown <br />",
443                "push/fetch/merge <br />",
444                "branch administation <br />",
445                "link to project summary <br />",
446                "link to main page <br />"
447                );
448 }
449
450
451 static Html
452 webgit_branch_action (struct webgit_query* query)
453 {
454   struct webgit_repo_info* repo = webgit_repo_enter (query);
455   webgit_repoinfo_find_last (repo);
456
457   return html(
458               html(html_tag("div", html_attr("id", "sub-menu")), webgit_branch_menu_action (repo)), html_nl (),
459               html(html_tag("div", html_attr("id", "content")), webgit_branch_table (repo, query->head, query->count), html_nl ())
460               );
461 }
462
463
464
465 /*
466   show tag
467 */
468 static Html
469 webgit_tag_action (struct webgit_query* query)
470 {
471   (void) query;
472   return html("tag");
473 }
474
475
476 /*
477   show and edit config
478 */
479 static Html
480 webgit_config_menu_action (struct webgit_repo_info* repo)
481 {
482   (void) repo;
483   return html (html_tag ("div"),
484                "Project or webgit logo<br />",
485                "manage remotes? <br />",
486                "manage subprojects? <br />",
487                "link to project summary <br />",
488                "link to main page <br />"
489                );
490 }
491
492 static Html
493 webgit_config_content_action (struct webgit_repo_info* repo)
494 {
495   int readonly = !!access (git_path("config"), W_OK);
496
497   return html (
498                html_tag ("form",
499                          html_attr ("name", "config-change"),
500                          html_attr ("enctype", "multipart/form-data"),
501                          html_attr ("method", "post"),
502                          html_attr ("action",
503                                     html_fmt ("%s",
504                                               repo->query->request->script_name
505                                               )
506                                     )
507                          ),
508
509                html_hidden ("repo", repo->name),
510                html_hidden ("action", "config"),
511                html (
512                      html_tag ("textarea",
513                                html_attr ("name", "blob"),
514                                html_attr ("rows", "40"),
515                                html_attr ("cols", "80"),
516                                readonly ? "readonly" : ""
517                                ),
518                      html_include_escaped (git_path("config"))
519                      ),
520                readonly ? html ()
521                : html (
522                        html_tag ("input",
523                                  html_attr ("type", "submit"),
524                                  html_attr ("value", "Save")
525                                  )
526                        )
527                );
528 }
529
530 static Html
531 webgit_config_action (struct webgit_query* query)
532 {
533   struct webgit_repo_info* repo = webgit_repo_enter (query);
534   webgit_repoinfo_find_last (repo);
535
536   if (query->blob)
537     {
538       FILE* cfg = fopen (git_path ("config"), "w");
539
540       /*TODO rxpd check */
541       if (!cfg)
542         webgit_warn ("could not open %s for writing", git_path("config"));
543       else
544         {
545           if (fwrite (query->blob, query->blob_size, 1, cfg) < 1)
546             webgit_warn ("could not write config");
547           fclose (cfg);
548         }
549     }
550
551   return html(
552               html (html_tag ("div"), webgit_config_menu_action (repo)), html_nl (),
553               html (html_tag ("div", html_attr("id", "content")), webgit_config_content_action (repo)), html_nl ()
554               );
555 }
556
557
558 /*
559   edit an object
560 */
561 static Html
562 webgit_edit_action (struct webgit_query* query)
563 {
564   (void) query;
565   return html("edit");
566 }
567
568 /*
569   commit changes
570 */
571 static Html
572 webgit_commit_action (struct webgit_query* query)
573 {
574   (void) query;
575   return html("commit");
576 }
577
578
579 Html
580 webgit_action_dispatch (struct webgit_query* query)
581 {
582 #define WEBGIT_ACTION(name, _)                  \
583 {                                               \
584  #name,                                         \
585  webgit_##name##_action,                        \
586 },
587   struct action_table{
588     char* name;
589     Html (*cb)(struct webgit_query* query);
590   } cmds[] = {WEBGIT_ACTIONS {"", NULL}};
591 #undef WEBGIT_ACTION
592
593   for (struct action_table* j = cmds; j->cb; ++j)
594     {
595       if (!strcmp (j->name, query->action))
596         return j->cb (query);
597     }
598   return html("error, no such action");
599 }
600
601
602
603 /*
604 //      Local Variables:
605 //      mode: C
606 //      c-file-style: "gnu"
607 //      indent-tabs-mode: nil
608 //      End:
609 */