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