Merge branch 'master' of github.com:j3parker/dweb
authorJacob Parker <j3parker@csclub.uwaterloo.ca>
Wed, 7 Mar 2012 07:59:42 +0000 (02:59 -0500)
committerJacob Parker <j3parker@csclub.uwaterloo.ca>
Wed, 7 Mar 2012 07:59:42 +0000 (02:59 -0500)
Conflicts:
src/web.d

bin/changelog.sh
src/build
src/config.d.sample
src/web.d
templates/default.html [new file with mode: 0644]

index dd5be65..8b4a9e2 100755 (executable)
@@ -1,5 +1,5 @@
 echo "<h1>Recent Changes</h1>"
 echo "<p>This list was generated from the git log for the website. The git repository for this webpage can be accessed from FIXME.</p>"
 echo "<ul>"
-git log --pretty=format:'<li>%s - %aN (%ae) <b>(%cr)</b></li>' --abbrev-commit --date=relative --no-merges
+git log --pretty=format:'<li>%s - %aN <b>(%cr)</b></li>' --abbrev-commit --date=relative --no-merges
 echo "</ul>"
index ea85a52..8054170 100755 (executable)
--- a/src/build
+++ b/src/build
@@ -1,2 +1,2 @@
 cd "$(dirname $0)"
-dmd config.d web.d -ofweb && rm web.o && mv web ../bin/
+dmd web.d config.d -ofweb && rm web.o && mv web ../bin/
index e61dd74..d4eba96 100644 (file)
@@ -1,3 +1,5 @@
+import std.regex;
+
 const string url_root = "/";
 
 const string site_title = "This is a Title";
@@ -5,9 +7,17 @@ const string site_subtitle = "but this is a subtitle";
 
 const bool nav_tree_vert = false;
 
-string[string] handlers;
+string[StaticRegex!char] handlers;
 
 void init_handlers() {
-  handlers["*.md"] = "contrib/Markdown.pl";
-  handlers["changelog"] = "changelog.sh";
+  handler!("(.*).md").add("contrib/Markdown.pl");
+  handler!("changelog").add("changelog.sh");
+}
+
+template handler(string pattern) {
+  void add(string h) {
+    try {
+      handlers[ctRegex!(pattern)] = h;
+    } catch (std.regex.Exception re) { return; }
+  }
 }
index a2491f9..499cf6f 100755 (executable)
--- a/src/web.d
+++ b/src/web.d
@@ -1,26 +1,26 @@
 //#!/usr/bin/rdmd
-import std.stdio, std.path, std.process, std.file, std.array, std.string, std.algorithm, std.datetime, std.ascii;
+import std.stdio, std.path, std.process, std.file, std.array, std.string, std.algorithm, std.datetime, std.ascii, std.regex;
 import config;
 
 string dweb_root;
+string[string] template_variables;
+string[string] headers;
 
-string indent = "";
-void html(string s) { writeln(indent ~ s); }
-void html_pop(string s) { indent = indent[0..max(0, $-4)]; html(s); }
-void html_push(string s) { html(s); indent ~= "    "; }
-
-void write_link(string to, bool expand) {
+string write_link(string to, bool expand) {
   bool isdir = dirExists(dweb_root ~ "/srv/" ~ to[url_root.length..$]);
-  html_push("<li" ~ (expand? " class=\"thisPage\" " : "") ~ ">");
-  html("<a href=\"" ~ to ~ (isdir ? "/" : "") ~ "\">"
-        ~ baseName(to) ~ (isdir ? "/" : "") ~ "</a>");
-  html_pop("</li>");
+  string result = "";
+  result ~= "<li" ~ (expand? " class=\"thisPage\" " : "") ~ ">";
+  result ~= "<a href=\"" ~ to ~ (isdir ? "/" : "") ~ "\">"
+            ~ baseName(to) ~ (isdir ? "/" : "") ~ "</a>";
+  result ~= "</li>";
+  return result;
 }
 
-void nav_tree_r(string url, string cur_loc, string[] subdirs) {
+string nav_tree_r(string url, string cur_loc, string[] subdirs) {
+  string result = "";
   string[] dirs = array(map!"a.name"(dirEntries(dweb_root ~ "/srv/" ~ cur_loc, SpanMode.shallow)));
   sort(dirs);
-  if (dirs.length == 0) return;
+  if (dirs.length == 0) return "";
   bool inserted_ul = false;
   bool next = false;
   string next_loc;
@@ -30,15 +30,15 @@ void nav_tree_r(string url, string cur_loc, string[] subdirs) {
     if (name.length == 0) continue; // e.g. ".md", should we do something else with these files?
     if (name == "index") continue; // "index" will never appear in the nav_tree.
     if (name[0] == '@') continue; // hidden file
-    if (!inserted_ul) { html_push("<ul>"); inserted_ul = true; }
+    if (!inserted_ul) { result ~= "<ul>"; inserted_ul = true; }
     bool expand = subdirs.length > 0 && name == subdirs[0];
-    write_link(url_root ~ stripExtension(s), expand);
+    result ~= write_link(url_root ~ stripExtension(s), expand);
 
     if (expand && isDir(dweb_root ~ "/srv/" ~ s)) {
       if (nav_tree_vert) {
-        html_push("<li>");
-        nav_tree_r(url, (cur_loc == "" ? "" : cur_loc ~ "/") ~ subdirs[0], subdirs[1..$]);
-        html_pop("</li>");
+       result ~= "<li>";
+        result ~= nav_tree_r(url, (cur_loc == "" ? "" : cur_loc ~ "/") ~ subdirs[0], subdirs[1..$]);
+        result ~= "</li>";
       } else {
         next = true;
         next_loc = (cur_loc == "" ? "" : cur_loc ~ "/") ~ subdirs[0];
@@ -46,64 +46,27 @@ void nav_tree_r(string url, string cur_loc, string[] subdirs) {
     }
   }
 
-  if (inserted_ul) html_pop("</ul>");
-  if (next) nav_tree_r(url, next_loc, subdirs[1..$]);
-}
-
-void do_nav_tree(string url) {
-  html_push("<div id=\"" ~ (nav_tree_vert ? "" : "horiz-") ~ "side-bar\">");
-  nav_tree_r(url, "", cast(string[])array(pathSplitter(url)));
-  html_pop("</div>\n");
+  if (inserted_ul) result ~= "</ul>";
+  if (next) result ~= nav_tree_r(url, next_loc, subdirs[1..$]);
+  return result;
 }
 
-void not_found(string path) {
-  html("The page <code>" ~ path ~ "</code> does not exist. (404)");
+string do_nav_tree(string url) {
+  return nav_tree_r(url, "", cast(string[])array(pathSplitter(url)));
 }
 
-void do_header() {
-  html_push("<div id=\"header\">");
-  
-  html_push("<div class=\"superHeader\">");
-  
-  html_push("<div class=\"left\">");
-  html("<a href=\"http://wiki.csclub.uwaterloo.ca/\">wiki</a>");
-  html("<a href=\"http://git.csclub.uwaterloo.ca/\">git</a>");
-  html("<a href=\"http://mirror.csclub.uwaterloo.ca/\">mirror</a>");
-  html("<a href=\"http://csclub.uwaterloo.ca/stats\">stats</a>");
-  html("<a href=\"http://mail.csclub.uwaterloo.ca/\">webmail</a>");
-  html("<a href=\"http://csclub.uwaterloo.ca/newsgroup/\">newsgroups</a>");
-  html("<a href=\"http://csclub.uwaterloo.ca/mailman/\">mailman</a>");
-  html_pop("</div>"); 
-  
-  html_push("<div class=\"right\">");
-  html("<a href=\"" ~ url_root ~ "changelog\">changelog</a>");
-  html_pop("</div>");
-  
-  html_pop("</div>");
-
-  html_push("<div class=\"midHeader\">");
-  html_push("<h1 class=\"headerTitle\">");
-  html("<a href=\"" ~ url_root ~ "\"><img src=\"" ~ url_root ~ "pub/style/logo.png\" id=\"logo\"> <span id=\"headerSubTitle\">" ~ site_subtitle ~ "</span></a>");
-  html_pop("</h1>");
-  html_pop("</div>");
-  
-  html_push("<div class=\"subHeader\">");
-  html("<br>");
-  html_pop("</div>");
-  
-  html_pop("</div>\n");
+string not_found(string path) {
+  headers["Status"] = "404 Not Found";
+  return "The page <code>" ~ path ~ "</code> does not exist. (404)";
 }
 
 bool dirExists(string path)  { try { if (isDir(path))  return true; else return false; } catch (Exception e) { return false; } }
 
-void do_content(string url) {
-  html_push("<div id=\"main-copy\"" ~ (nav_tree_vert? " class=\"main-copy-side-bar\"" : "")  ~ ">");
+string do_content(string url) {
   // first, see if we have something that wants to handle url outright
-  foreach (string glob, string h; handlers) {
-    if (globMatch(url, glob)) {
-      html(shell(dweb_root ~ "/bin/" ~ h ~ " " ~ url));
-      html_pop("</div>");
-      return;
+  foreach (StaticRegex!char reg, string h; handlers) {
+    if (match(url, reg)) {
+      return shell(dweb_root ~ "/bin/" ~ h ~ " " ~ url);
     }
   }
   // if that failed, see if we can handle the file
@@ -112,31 +75,15 @@ void do_content(string url) {
     if (isDir(f)) continue;
     string name = baseName(f); name = name[0] == '@' ? name[1..$] : name;
     if (stripExtension(name) == baseName(url)) {
-      foreach (string glob, string h; handlers) { 
-        if (globMatch(name, glob)) {
-          html(shell(dweb_root ~ "/bin/" ~ h ~ " " ~ f));
-          html_pop("</div>");
-          return;
+      foreach (StaticRegex!char reg, string h; handlers) { 
+        if (match(name, reg)) {
+          return shell(dweb_root ~ "/bin/" ~ h ~ " " ~ f);
         }
       }
     }
   }
-  if (baseName(url) != "index") not_found(url);
-  html_pop("</div>");
-}
-
-void do_footer() {
-  html_push("<div id=\"footer\">");
-
-  html_push("<div class=\"left\">");
-  html("<a href=\"" ~ url_root ~ "dweb\">Powered by dweb</a>");
-  html_pop("</div>");
-
-  html_push("<div class=\"right\">");
-  html("&nbsp;");
-  html_pop("</div>");
-
-  html_pop("</div>\n");
+  if (baseName(url) != "index") return not_found(url);
+  return "";
 }
 
 bool evil(string s) {
@@ -144,36 +91,41 @@ bool evil(string s) {
   return false;
 }
 
+string simple_template(string text, string[string] vars) {
+  return std.regex.replace!((match) { return vars[match[1]]; })(text, regex("\\{\\{\\s*(\\w+)\\s*\\}\\}", "g"));
+}
+
+void send_headers() {
+  foreach (header, header_body; headers) {
+    writefln("%s: %s", header, header_body);
+  }
+  writeln();
+}
+
 void main(string[] args) {
   init_handlers();
   dweb_root = getcwd()[0..$-4]; // take out bin/
-  html("Content-type: text/html\n");
-  html("<!DOCTYPE html>");
-  html_push("<html>\n");
+  headers["Content-Type"] = "text/html; charset=UTF-8";
 
   string url = getenv("REQUEST_URI")[url_root.length..$];
-  if (evil(url)) { html ("bad url."); return; }
+  if (evil(url)) {
+    headers["Status"] = "400 Bad Request";
+    send_headers();
+    writeln("bad url.");
+    return;
+  }
   
   string pagename = baseName(url);
   if (pagename.length != 0) pagename = " - " ~ pagename;
   pagename = site_title ~ pagename;
-  
-  html_push("<head>");
-  html("<title>" ~ pagename ~ "</title>");
-  html("<link rel=\"stylesheet\" href=\"" ~ url_root ~ "pub/style/style.css\" type=\"text/css\" media=\"screen, handheld\" title=\"default\">");
-  html("<meta charset=\"UTF-8\">");
-  html("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");
-  html_pop("</head>\n");
-  
-  html_push("<body style=\"text-align: center\">");
-  html_push("<div id=\"container\">");
-  do_header();
-  do_nav_tree(url);
-  do_content(url);
-  do_footer();
-  html_pop("</div>");
-  html_pop("</body>\n");
-
-  html_pop("</html>");
+  template_variables["url_root"] = url_root;
+  template_variables["site_title"] = site_title;
+  template_variables["site_subtitle"] = site_subtitle;
+  template_variables["pagename"] = pagename;
+  template_variables["nav_tree"] = do_nav_tree(url);
+  template_variables["content"] = do_content(url);
+
+  send_headers();
+  string default_template = readText(dweb_root ~ "/templates/default.html");
+  write(simple_template(default_template, template_variables));
 }
diff --git a/templates/default.html b/templates/default.html
new file mode 100644 (file)
index 0000000..fafb96a
--- /dev/null
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>{{ pagename }}</title>
+    <link rel="stylesheet" href="{{ url_root }}pub/style/style.css" type="text/css" media="screen, handheld" title="default">
+    <meta charset="UTF-8">
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  </head>
+  <body>
+    <div id="header">
+      <div class="superHeader">
+        <div class="left">
+          <a href=\"http://wiki.csclub.uwaterloo.ca/\">wiki</a>
+          <a href=\"http://git.csclub.uwaterloo.ca/\">git</a>
+          <a href=\"http://mirror.csclub.uwaterloo.ca/\">mirror</a>
+          <a href=\"http://csclub.uwaterloo.ca/stats\">stats</a>
+          <a href=\"http://mail.csclub.uwaterloo.ca/\">webmail</a>
+          <a href=\"http://csclub.uwaterloo.ca/newsgroup/\">newsgroups</a>
+          <a href=\"http://csclub.uwaterloo.ca/mailman/\">mailman</a>
+        </div>
+        <div class="right">
+          <a href="{{ url_root }}changelog">changelog</a>
+        </div>
+      </div>
+      <div class="midHeader">
+        <h1 class="headerTitle">
+          <a href="{{ url_root }}">{{ site_title }}</a>
+          <span id="headerSubTitle">{{ site_subtitle }}</a>
+        </h1>
+      </div>
+    </div>
+
+    <div id="horiz-side-bar">
+      {{ nav_tree }}
+    </div>
+
+    <div id="main-copy">
+      {{ content }}
+    </div>
+
+    <div id="footer">
+      <div class="left">
+        <a href="{{ url_root }}dweb">Powered by dweb</a>
+      </div>
+      <div class="right">&nbsp;</div>
+    </div>
+  </body>
+</html>