hswaw/site: basic /about and /about_en rendering

This renders the About and About-but-in-English templates already
present.

It integrates header.html and rotimage_at.html into the basic template.
These were separates so that different webapps on boston-packets could
serve the same header file from the same sources, but this approach will
have to be abandoned for this version of the site anyway.

We'll have to figure out how/if to share these things between different
webapps, but probably only after we actually come up with a new site
theme. Let's keep it simple for now.

We also skip porting the 'subscribe to lists' template and
functionality, as it's broken right now anyway.

Change-Id: Ia89bfcaa1e250bd74d1771e095b3c8505b08c606
diff --git a/hswaw/site/BUILD.bazel b/hswaw/site/BUILD.bazel
index 7af2940..0b05bf3 100644
--- a/hswaw/site/BUILD.bazel
+++ b/hswaw/site/BUILD.bazel
@@ -2,12 +2,16 @@
 
 go_library(
     name = "go_default_library",
-    srcs = ["main.go"],
+    srcs = [
+        "main.go",
+        "views.go",
+    ],
     importpath = "code.hackerspace.pl/hscloud/hswaw/site",
     visibility = ["//visibility:private"],
     deps = [
         "//go/mirko:go_default_library",
         "//hswaw/site/static:static_go",
+        "//hswaw/site/templates:templates_go",
         "@com_github_golang_glog//:go_default_library",
     ],
 )
diff --git a/hswaw/site/main.go b/hswaw/site/main.go
index b68482a..f5e42d0 100644
--- a/hswaw/site/main.go
+++ b/hswaw/site/main.go
@@ -52,7 +52,6 @@
 	path := strings.TrimPrefix(r.URL.Path, "/")
 
 	staticPath := fmt.Sprintf("hswaw/site/%s", path)
-	glog.Infof("%q", staticPath)
 	if data, ok := static.Data[staticPath]; ok {
 		parts := strings.Split(path, ".")
 		ext := fmt.Sprintf(".%s", parts[len(parts)-1])
@@ -66,4 +65,6 @@
 
 func (s *service) registerHTTP(mux *http.ServeMux) {
 	mux.HandleFunc("/static/", s.handleHTTPStatic)
+	mux.HandleFunc("/about", s.handleAbout)
+	mux.HandleFunc("/about_en", s.handleAboutEn)
 }
diff --git a/hswaw/site/templates/BUILD.bazel b/hswaw/site/templates/BUILD.bazel
index 58da1ea..cc47353 100644
--- a/hswaw/site/templates/BUILD.bazel
+++ b/hswaw/site/templates/BUILD.bazel
@@ -7,9 +7,7 @@
         "about.html",
         "about_en.html",
         "basic.html",
-        "header.html",
         "main.html",
-        "rotimate_at.html",
         "subscribe.html",
         "subscribe_en.html",
     ],
diff --git a/hswaw/site/templates/about.html b/hswaw/site/templates/about.html
index 4be3049..aa6aecd 100644
--- a/hswaw/site/templates/about.html
+++ b/hswaw/site/templates/about.html
@@ -1,12 +1,14 @@
-{% extends 'basic.html' %}
-{% block page_scripts %}
+{{ define "page_scripts" }}
   <script type="text/javascript" src="https://widgets.twimg.com/j/2/widget.js"></script>
-{% endblock %}
-{% block page_style %}
+{{ end }}
+
+{{ define "page_style" }}
   <link rel="stylesheet" href="static/main.css"/>
-{% endblock %}
-{% block title %}O Hackerspace Warszawa{% endblock %}
-{% block content %}
+{{ end }}
+
+{{ define "title" }}O Hackerspace Warszawa{{ end }}
+
+{{ define "content" }}
   <div id="left">
       <div id="about">
           <h2><a href="about_en">Read about us in English</a></h2>
@@ -66,7 +68,7 @@
       </ul>
   </div>
   <div id="right">
-    {% include "subscribe.html" %}
+    <!-- TODO(q3k): add this {% include "subscribe.html" %} -->
     <h1 class="twitter">Twitter</h1>
     <script type="text/javascript">
     new TWTR.Widget({
@@ -97,4 +99,4 @@
     }).render().setUser('hackerspacepl').start();
     </script>
   </div>
-{% endblock %}
+{{ end }}
diff --git a/hswaw/site/templates/about_en.html b/hswaw/site/templates/about_en.html
index b76fc00..9805785 100644
--- a/hswaw/site/templates/about_en.html
+++ b/hswaw/site/templates/about_en.html
@@ -1,12 +1,14 @@
-{% extends 'basic.html' %}
-{% block page_scripts %}
+{{ define "page_scripts" }}
   <script type="text/javascript" src="https://widgets.twimg.com/j/2/widget.js"></script>
-{% endblock %}
-{% block page_style %}
+{{ end }}
+
+{{ define "page_style" }}
   <link rel="stylesheet" href="static/main.css"/>
-{% endblock %}
-{% block title %}About Warsaw Hackerspace{% endblock %}
-{% block content %}
+{{ end }}
+
+{{ define "title" }}About Warsaw Hackerspace{{ end }}
+
+{{ define "content" }}
   <div id="left">
       <div id="about">
           <h2><a href="about">Poczytaj o nas po polsku</a></h2>
@@ -64,7 +66,7 @@
       </ul>
   </div>
   <div id="right">
-    {% include "subscribe_en.html" %}
+    <!-- TODO(q3k): add this {% include "subscribe_en.html" %} -->
     <h1 class="twitter">Twitter</h1>
     <script type="text/javascript">
     new TWTR.Widget({
@@ -95,4 +97,4 @@
     }).render().setUser('hackerspacepl').start();
     </script>
   </div>
-{% endblock %}
+{{ end }}
diff --git a/hswaw/site/templates/basic.html b/hswaw/site/templates/basic.html
index aa95557..d9f3b91 100644
--- a/hswaw/site/templates/basic.html
+++ b/hswaw/site/templates/basic.html
@@ -4,71 +4,60 @@
 <!--[if IE 8]>    <html class="no-js lt-ie9" lang="en"> <![endif]-->
 <!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
 <head>
-  {% block head %}
-    <meta charset="utf-8" />
-    <!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /><![endif]-->
-    <title>{% block title %}{% endblock %}</title>
-    <script src="https://static.hackerspace.pl/js/jquery.min.js"></script>
-    {% block checkinator_script %}
-      <script src="https://static.hackerspace.pl/js/checkinator-header.js"></script>
-    {% endblock %}
-    {% block page_scripts %}
-    {% endblock %}
-    {% block basic_style %}
-      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-      <meta name="google-site-verification" content="trUiKRnUNhystQjYg-j5j_0qEn09Wijd94aYhv3RyB8" />
+  <meta charset="utf-8" />
+  <!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /><![endif]-->
+  <title>{{ template "title" . }}</title>
+  <script src="https://static.hackerspace.pl/js/jquery.min.js"></script>
+  <script src="https://static.hackerspace.pl/js/checkinator-header.js"></script>
+  {{ template "page_scripts" . }}
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+  <meta name="google-site-verification" content="trUiKRnUNhystQjYg-j5j_0qEn09Wijd94aYhv3RyB8" />
 
-      <link rel="shortcut icon" href="https://static.hackerspace.pl/img/favicon.ico"/>
-      <link rel="apple-touch-icon" href="https://static.hackerspace.pl/img/glider.png"/>
-      <link rel="stylesheet" href="https://static.hackerspace.pl/fonts/news-cycle/stylesheet.css"/>
-      <link rel="stylesheet" href="https://static.hackerspace.pl/fonts/titillium/stylesheet.css"/>
-      <link rel="stylesheet" href="https://static.hackerspace.pl/css/style.css?v=2"/>
-    {% endblock %}
-    {% block page_style %}
-    {% endblock %}
-  {% endblock %}
+  <link rel="shortcut icon" href="https://static.hackerspace.pl/img/favicon.ico"/>
+  <link rel="apple-touch-icon" href="https://static.hackerspace.pl/img/glider.png"/>
+  <link rel="stylesheet" href="https://static.hackerspace.pl/fonts/news-cycle/stylesheet.css"/>
+  <link rel="stylesheet" href="https://static.hackerspace.pl/fonts/titillium/stylesheet.css"/>
+  <link rel="stylesheet" href="https://static.hackerspace.pl/css/style.css?v=2"/>
+  {{ template "page_style" . }}
 </head>
 <body>
-  {% block body %}
-    <a name="top"></a>
-    {% block header %}
-      {% include 'header.html' %}
-    {% endblock %}
-    {% with messages = get_flashed_messages(with_categories=true) %}
-      {% if messages %}
-    <div class="flashes">
-      <ul>
-          {% for category, message in messages %}
-            <li class="{{ category }}">{{ message }}</li>
-          {% endfor %}
-      </ul>
-    </div>
-      {% endif %}
-    {% endwith %}
-    <div id="hs_main">
-      {% block main %}
-      <div id="hs_rotimage">
-        {% block rotimage %}
-          {% include 'rotimage_at.html' %}
-          {% block rotimage_login %}
-            <div class="hs_login_bar">
-              {% block login %}
-                <ul>
-                  <li><a class="action user" href="https://ldap.hackerspace.pl">Member profile</a></li>
-                </ul>
-              {% endblock %}
-            </div>
-          {% endblock %}
-        {% endblock %}
+  <a name="top"></a>
+  <header id="hs_branding">
+    <a id="hs_header" href="https://hackerspace.pl/">Warsaw Hackerspace</a>
+    <ul id="hs_header_menu">
+      <li><a href="https://hackerspace.pl/about">about</a></li>
+      <li><a href="https://blog.hackerspace.pl">blog</a></li>
+      <li><a href="https://gallery.hackerspace.pl">gallery</a></li>
+      <li><a href="https://wiki.hackerspace.pl">wiki</a></li>
+      <li><a href="https://code.hackerspace.pl">code</a></li>
+      <li><a href="https://webchat.hackerspace.pl">chat</a></li>
+      <li><a href="https://redmine.hackerspace.pl">tasks</a></li>
+      <li><a href="https://wiki.hackerspace.pl/partners">partners</a></li>
+    </ul>
+  </header>
+  <div id="hs_main">
+    <div id="hs_rotimage">
+      <div id="status" style="display: none;">
+       <div id="status-tooltip" style="display: none;">
+         <p>Refreshing...</p>
+       </div>
+       <img src="https://static.hackerspace.pl/img/status-open.png" alt="Sorry, we're open! - The Warsaw Hackerspace is open right now." />
       </div>
-      {% endblock %}
-      <div id="hs_content">
-        {% block content %}
-        {% endblock %}
+      <div class="hs_login_bar">
+          <ul>
+            <li><a class="action user" href="https://ldap.hackerspace.pl">Member profile</a></li>
+          </ul>
       </div>
     </div>
-    {% block footer %}
-    {% endblock %}
-  {% endblock %}
+    <div id="hs_content">
+      {{ template "content" . }}
+    </div>
+  </div>
+  {{ template "footer" . }}
 </body>
 </html>
+
+{{ define "page_scripts" }}{{ end }}
+{{ define "page_style" }}{{ end }}
+{{ define "content" }}{{ end }}
+{{ define "footer" }}{{ end }}
diff --git a/hswaw/site/templates/header.html b/hswaw/site/templates/header.html
deleted file mode 100644
index df49549..0000000
--- a/hswaw/site/templates/header.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<header id="hs_branding">
-  <a id="hs_header" href="https://hackerspace.pl/">Warsaw Hackerspace</a>
-  <ul id="hs_header_menu">
-    <li><a href="https://hackerspace.pl/about">about</a></li>
-    <li><a href="https://blog.hackerspace.pl">blog</a></li>
-    <li><a href="https://gallery.hackerspace.pl">gallery</a></li>
-    <li><a href="https://wiki.hackerspace.pl">wiki</a></li>
-    <li><a href="https://code.hackerspace.pl">code</a></li>
-    <li><a href="https://webchat.hackerspace.pl">chat</a></li>
-    <li><a href="https://redmine.hackerspace.pl">tasks</a></li>
-    <li><a href="https://wiki.hackerspace.pl/partners">partners</a></li>
-  </ul>
-</header>
diff --git a/hswaw/site/templates/rotimage_at.html b/hswaw/site/templates/rotimage_at.html
deleted file mode 100644
index dc2bf2b..0000000
--- a/hswaw/site/templates/rotimage_at.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<div id="status" style="display: none;">
- <div id="status-tooltip" style="display: none;">
-   <p>Refreshing...</p>
- </div>
- <img src="https://static.hackerspace.pl/img/status-open.png" alt="Sorry, we're open! - The Warsaw Hackerspace is open right now." />
-</div>
diff --git a/hswaw/site/views.go b/hswaw/site/views.go
new file mode 100644
index 0000000..ae62322
--- /dev/null
+++ b/hswaw/site/views.go
@@ -0,0 +1,63 @@
+package main
+
+import (
+	"fmt"
+	"html/template"
+	"net/http"
+
+	"github.com/golang/glog"
+
+	"code.hackerspace.pl/hscloud/hswaw/site/templates"
+)
+
+// parseTemplates parses a set of templates from
+// //hswaw/site/templates/$name.html into a Go HTML template. Typical Go text
+// templating ordering behaviour applies (this basically replicates
+// template.ParseFiles, but for statically embedded files instead).
+func parseTemplates(names ...string) (*template.Template, error) {
+	if len(names) == 0 {
+		return nil, fmt.Errorf("at least one template must be given")
+	}
+
+	var t *template.Template
+	for _, n := range names {
+		path := fmt.Sprintf("hswaw/site/templates/%s.html", n)
+		data, ok := templates.Data[path]
+		if !ok {
+			return nil, fmt.Errorf("template %q (%s) not found", n, path)
+		}
+		s := string(data)
+
+		if t == nil {
+			t = template.New(n)
+		}
+		_, err := t.Parse(s)
+		if err != nil {
+			return nil, fmt.Errorf("template %q could not be parsed: %w", n, err)
+		}
+	}
+	return t, nil
+}
+
+var (
+	tmplAbout   = template.Must(parseTemplates("basic", "about"))
+	tmplAboutEn = template.Must(parseTemplates("basic", "about_en"))
+)
+
+// render attempts to render a given Go template with data into the HTTP
+// response writer, and logs a warning if anything goes wrong.
+func render(w http.ResponseWriter, t *template.Template, data interface{}) {
+	if err := t.Execute(w, data); err != nil {
+		glog.Warningf("Rendering %v failed: %v", t, err)
+	}
+}
+
+// handleAbout handles rendering the about page at /about
+func (s *service) handleAbout(w http.ResponseWriter, r *http.Request) {
+	render(w, tmplAbout, nil)
+}
+
+// handleAboutEn handles rendering the about page at /about_en
+func (s *service) handleAboutEn(w http.ResponseWriter, r *http.Request) {
+	render(w, tmplAboutEn, nil)
+}