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