271df528f9c1ca8a6579ba8a947faf002cf878ee
[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"), "Log of branch '", repo->last_head, "'"),
268                           webgit_log_table (repo->query, repo->last_head, 5 /*TODO: config this*/, 0))
269                     );
270
271
272   /* branches */
273   html_list_append (content,
274                     html (
275                           html (html_tag ("h2"), "Branches"),
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"), "Tags"),
284                           webgit_tag_table (repo, NULL, 5 /*TODO: config this*/)
285                           )
286                     );
287
288
289   return content;
290 }
291
292
293 static Html
294 webgit_summary_action (struct webgit_query* query)
295 {
296   struct webgit_repo_info* repo = webgit_repo_enter (query);
297   webgit_repoinfo_find_last (repo);
298
299   return html(
300               html(html_tag("div", html_attr("id", "sub-menu")), webgit_summary_menu_action (repo)), html_nl (),
301               html(html_tag("div", html_attr("id", "content")), webgit_summary_content_action (repo)), html_nl ()
302               );
303 }
304
305
306 /*
307   Log page
308 */
309 static Html
310 webgit_log_action (struct webgit_query* query)
311 {
312   webgit_repo_enter (query);
313
314   return html(
315               html(html_tag("div"), webgit_log_menu_action (query)), html_nl (),
316               html(html_tag("div", html_attr("id", "content")), webgit_log_content_action (query)), html_nl ()
317               );
318 }
319
320
321 /*
322   Diff page
323 */
324 static Html
325 webgit_diff_action (struct webgit_query* query)
326 {
327   (void) query;
328 #if 0
329   return html (html_tag ("div"),
330                "Webgit logo<br />",
331                "Readme.html <br />",
332                "User (cookie) config <br />",
333                "About webgit (info/admin) <br />"
334                );
335 #endif
336   return html("diff");
337 }
338
339
340 /*
341   pretty printed objects
342 */
343 static Html
344 webgit_object_action (struct webgit_query* query)
345 {
346   struct webgit_repo_info* repo = webgit_repo_enter (query);
347
348   unsigned char sha1[20];
349   if (get_sha1 (query->object, sha1))
350     return html("error: unknown object");
351
352   switch (sha1_object_info(sha1, NULL))
353     {
354     case OBJ_COMMIT:
355       if (!query->deref_to_tree)
356         return webgit_object_commit_action (repo, sha1);
357       /* else fallthrough */
358     case OBJ_TREE:
359       return webgit_object_tree_action (repo, sha1);
360     case OBJ_BLOB:
361       return webgit_object_blob_action (repo, sha1);
362     case OBJ_TAG:
363       return webgit_object_tag_action (repo, sha1);
364
365       break;
366     default:
367       return html ("error: unknown object type");
368       break;
369     }
370 }
371
372
373 /*
374   treeish dereferenced to tree
375 */
376 static Html
377 webgit_tree_action (struct webgit_query* query)
378 {
379   query->deref_to_tree = 1;
380   return webgit_object_action (query);
381 }
382
383
384 /*
385   spew out raw data
386 */
387 static Html
388 webgit_raw_action (struct webgit_query* query)
389 {
390   webgit_repo_enter (query);
391
392   unsigned char sha1[20];
393   if (get_sha1 (query->object, sha1))
394     return html("error: unknown object");
395
396   void* buf;
397   unsigned long size;
398
399   buf = read_object_with_reference (sha1, "blob", &size, NULL);
400
401   free ((char*)query->content_type);
402   query->content_type = webgit_mimetype (query->path);
403
404   return html_binary (buf, size);
405 }
406
407
408 /*
409   show branch
410 */
411 static Html
412 webgit_branch_menu_action (struct webgit_repo_info* repo)
413 {
414   (void) repo;
415   return html (html_tag ("div"),
416                "Project or webgit logo<br />",
417                "switch-branch-dropdown <br />",
418                "push/fetch/merge <br />",
419                "branch administation <br />",
420                "link to project summary <br />",
421                "link to main page <br />"
422                );
423 }
424
425
426 static Html
427 webgit_branch_action (struct webgit_query* query)
428 {
429   struct webgit_repo_info* repo = webgit_repo_enter (query);
430   webgit_repoinfo_find_last (repo);
431
432   return html(
433               html(html_tag("div", html_attr("id", "sub-menu")), webgit_branch_menu_action (repo)), html_nl (),
434               html(html_tag("div", html_attr("id", "content")), webgit_branch_table (repo, query->head, query->count), html_nl ())
435               );
436 }
437
438
439
440 /*
441   show tag
442 */
443 static Html
444 webgit_tag_action (struct webgit_query* query)
445 {
446   (void) query;
447   return html("tag");
448 }
449
450
451 /*
452   show and edit config
453 */
454 static Html
455 webgit_config_menu_action (struct webgit_repo_info* repo)
456 {
457   (void) repo;
458   return html (html_tag ("div"),
459                "Project or webgit logo<br />",
460                "manage remotes? <br />",
461                "manage subprojects? <br />",
462                "link to project summary <br />",
463                "link to main page <br />"
464                );
465 }
466
467 static Html
468 webgit_config_content_action (struct webgit_repo_info* repo)
469 {
470   int readonly = !!access (git_path("config"), W_OK);
471
472   return html (
473                html_tag ("form",
474                          html_attr ("name", "config-change"),
475                          html_attr ("enctype", "multipart/form-data"),
476                          html_attr ("method", "post"),
477                          html_attr ("action",
478                                     html_fmt ("%s",
479                                               repo->query->request->script_name
480                                               )
481                                     )
482                          ),
483
484                html_hidden ("repo", repo->name),
485                html_hidden ("action", "config"),
486                html (
487                      html_tag ("textarea",
488                                html_attr ("name", "blob"),
489                                html_attr ("rows", "40"),
490                                html_attr ("cols", "80"),
491                                readonly ? "readonly" : ""
492                                ),
493                      html_include_escaped (git_path("config"))
494                      ),
495                readonly ? html ()
496                : html (
497                        html_tag ("input",
498                                  html_attr ("type", "submit"),
499                                  html_attr ("value", "Save")
500                                  )
501                        )
502                );
503 }
504
505 static Html
506 webgit_config_action (struct webgit_query* query)
507 {
508   struct webgit_repo_info* repo = webgit_repo_enter (query);
509   webgit_repoinfo_find_last (repo);
510
511   if (query->blob)
512     {
513       FILE* cfg = fopen (git_path ("config"), "w");
514
515       /*TODO rxpd check */
516       if (!cfg)
517         webgit_warn ("could not open %s for writing", git_path("config"));
518       else
519         {
520           if (fwrite (query->blob, query->blob_size, 1, cfg) < 1)
521             webgit_warn ("could not write config");
522           fclose (cfg);
523         }
524     }
525
526   return html(
527               html (html_tag ("div"), webgit_config_menu_action (repo)), html_nl (),
528               html (html_tag ("div", html_attr("id", "content")), webgit_config_content_action (repo)), html_nl ()
529               );
530 }
531
532
533 /*
534   edit an object
535 */
536 static Html
537 webgit_edit_action (struct webgit_query* query)
538 {
539   (void) query;
540   return html("edit");
541 }
542
543 /*
544   commit changes
545 */
546 static Html
547 webgit_commit_action (struct webgit_query* query)
548 {
549   (void) query;
550   return html("commit");
551 }
552
553
554 Html
555 webgit_action_dispatch (struct webgit_query* query)
556 {
557 #define WEBGIT_ACTION(name, _)                  \
558 {                                               \
559  #name,                                         \
560  webgit_##name##_action,                        \
561 },
562   struct action_table{
563     char* name;
564     Html (*cb)(struct webgit_query* query);
565   } cmds[] = {WEBGIT_ACTIONS {"", NULL}};
566 #undef WEBGIT_ACTION
567
568   for (struct action_table* j = cmds; j->cb; ++j)
569     {
570       if (!strcmp (j->name, query->action))
571         return j->cb (query);
572     }
573   return html("error, no such action");
574 }
575
576
577
578 /*
579 //      Local Variables:
580 //      mode: C
581 //      c-file-style: "gnu"
582 //      indent-tabs-mode: nil
583 //      End:
584 */