-
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #14 from dastergon/add_server
Created basic web site to serve postmortems
- Loading branch information
Showing
10 changed files
with
328 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{{define "title"}}Categories{{end}} | ||
|
||
{{define "body"}} | ||
<h3>Category</h3> | ||
<ul> | ||
{{ range . }} | ||
<li><a href="/category/{{ . }}">{{ . }}</a></li> | ||
{{end}} | ||
</ul> | ||
{{end}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{{define "title"}}Category: {{ .Category }}{{end}} | ||
|
||
{{define "body"}} | ||
<h3>Category: {{ .Category }}</h3> | ||
<ul> | ||
{{ range .Postmortems }} | ||
<li><a href="/postmortem/{{ .UUID }}">{{ .Company}}: {{ .UUID }}</a></li> | ||
{{end}} | ||
</ul> | ||
{{end}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{{define "title"}}Postmortems{{end}} | ||
|
||
{{define "body"}} | ||
|
||
<h1>Postmortems Index Page</h1> | ||
<ul> | ||
{{ range . }} | ||
<li><a href="postmortem/{{ .UUID }}">{{ .Company }}: {{ .UUID }}</a></li> | ||
{{end}} | ||
</ul> | ||
{{end}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{{define "layout"}} | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> | ||
<title>{{template "title" .}}</title> | ||
</head> | ||
<body> | ||
<header> | ||
<a href="/">Home</a> | ||
<a href="/categories">Categories</a> | ||
</header> | ||
{{ template "body" . }} | ||
</body> | ||
</html> | ||
{{end}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{{define "title"}}Postmortem{{end}} | ||
|
||
{{define "body"}} | ||
<h1>{{ .Company }}</h1> | ||
<h3>Category</h3> | ||
|
||
<ul> | ||
{{ range .Categories }} | ||
<li><a href="category/{{ . }}">{{ . }}</a></li> | ||
{{end}} | ||
</ul> | ||
|
||
<p> | ||
{{ .Description }} | ||
</p> | ||
|
||
<a href="{{ .URL }}">Source</a>, <a href="https://github.com/icco/postmortems/blob/master/data/{{ .UUID }}.md">Edit Metadata</a> | ||
{{end}} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"io/ioutil" | ||
"log" | ||
"net/http" | ||
"os" | ||
"path/filepath" | ||
"text/template" | ||
|
||
"github.com/gorilla/mux" | ||
blackfriday "gopkg.in/russross/blackfriday.v2" | ||
) | ||
|
||
// createHandlers sets the routes for the web server. | ||
func createHandlers() *mux.Router { | ||
router := mux.NewRouter() | ||
router.HandleFunc("/", indexHandler).Methods("GET") | ||
router.HandleFunc("/postmortem/{id}", postmortemPageHandler).Methods("GET") | ||
router.HandleFunc("/categories", categoriesPageHandler).Methods("GET") | ||
router.HandleFunc("/category/{category}", categoryPageHandler).Methods("GET") | ||
router.HandleFunc("/healthz", healthzHandler).Methods("GET") | ||
|
||
return router | ||
} | ||
|
||
// healthzHandler serves an availability check endpoint. | ||
func healthzHandler(w http.ResponseWriter, r *http.Request) { | ||
w.WriteHeader(http.StatusOK) | ||
w.Header().Set("Content-Type", "text/plain") | ||
|
||
if _, err := w.Write([]byte("ok.")); err != nil { | ||
log.Printf("Error writing response to healthz request") | ||
} | ||
} | ||
|
||
// loadPostmortem loads the postmortem data in memory. | ||
func loadPostmortem(dir, filename string) (*Postmortem, error) { | ||
f, err := os.Open(filepath.Join(dir, filename)) | ||
if err != nil { | ||
return nil, fmt.Errorf("error opening postmortem: %w", err) | ||
} | ||
|
||
pm, err := Parse(f) | ||
if err != nil { | ||
return nil, fmt.Errorf("error parsing file %s: %w", f.Name(), err) | ||
} | ||
|
||
return pm, nil | ||
} | ||
|
||
// loadPostmortems parses the postmortem files | ||
// and returns a slice with their content. | ||
func loadPostmortems(dir string) ([]*Postmortem, error) { | ||
files, err := ioutil.ReadDir(dir) | ||
if err != nil { | ||
return nil, fmt.Errorf("error opening data folder: %w", err) | ||
} | ||
|
||
var pms []*Postmortem | ||
|
||
for _, path := range files { | ||
pm, err := loadPostmortem(dir, path.Name()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
pms = append(pms, pm) | ||
} | ||
|
||
return pms, nil | ||
} | ||
|
||
func categoriesPageHandler(w http.ResponseWriter, r *http.Request) { | ||
lp := filepath.Join("templates", "layout.html") | ||
fp := filepath.Join("templates", "categories.html") | ||
|
||
_, err := os.Stat(fp) | ||
if err != nil { | ||
if os.IsNotExist(err) { | ||
// Template doesn't exist, return 404. | ||
http.NotFound(w, r) | ||
return | ||
} | ||
} | ||
|
||
tmpl, err := template.ParseFiles(lp, fp) | ||
if err != nil { | ||
log.Println(err.Error()) | ||
http.Error(w, http.StatusText(500), http.StatusInternalServerError) | ||
|
||
return | ||
} | ||
|
||
if err := tmpl.ExecuteTemplate(w, "layout", Categories); err != nil { | ||
log.Println(err.Error()) | ||
http.Error(w, http.StatusText(500), http.StatusInternalServerError) | ||
} | ||
} | ||
|
||
func getPosmortemByCategory(pms []*Postmortem, category string) []Postmortem { | ||
var ctpm []Postmortem | ||
|
||
for _, pm := range pms { | ||
for _, c := range pm.Categories { | ||
if c == category { | ||
ctpm = append(ctpm, *pm) | ||
} | ||
} | ||
} | ||
|
||
return ctpm | ||
} | ||
|
||
func categoryPageHandler(w http.ResponseWriter, r *http.Request) { | ||
ct := mux.Vars(r)["category"] | ||
|
||
pms, err := loadPostmortems(*dir) | ||
if err != nil { | ||
log.Println(err.Error()) | ||
http.Error(w, http.StatusText(500), http.StatusInternalServerError) | ||
|
||
return | ||
} | ||
|
||
ctpm := getPosmortemByCategory(pms, ct) | ||
|
||
lp := filepath.Join("templates", "layout.html") | ||
fp := filepath.Join("templates", "category.html") | ||
|
||
_, err = os.Stat(fp) | ||
if err != nil { | ||
if os.IsNotExist(err) { | ||
// Template doesn't exist, return 404. | ||
http.NotFound(w, r) | ||
return | ||
} | ||
} | ||
|
||
tmpl, err := template.ParseFiles(lp, fp) | ||
if err != nil { | ||
log.Println(err.Error()) | ||
http.Error(w, http.StatusText(500), http.StatusInternalServerError) | ||
|
||
return | ||
} | ||
|
||
page := struct { | ||
Category string | ||
Postmortems []Postmortem | ||
}{ | ||
Category: ct, | ||
Postmortems: ctpm, | ||
} | ||
|
||
if err := tmpl.ExecuteTemplate(w, "layout", page); err != nil { | ||
log.Println(err.Error()) | ||
http.Error(w, http.StatusText(500), http.StatusInternalServerError) | ||
} | ||
} | ||
|
||
func postmortemPageHandler(w http.ResponseWriter, r *http.Request) { | ||
pmID := mux.Vars(r)["id"] | ||
|
||
pm, err := loadPostmortem(*dir, pmID+".md") | ||
if err != nil { | ||
log.Println(err.Error()) | ||
http.Error(w, http.StatusText(500), http.StatusInternalServerError) | ||
} | ||
|
||
lp := filepath.Join("templates", "layout.html") | ||
fp := filepath.Join("templates", "postmortem.html") | ||
|
||
_, err = os.Stat(fp) | ||
if err != nil { | ||
if os.IsNotExist(err) { | ||
// Template doesn't exist, return 404. | ||
http.NotFound(w, r) | ||
return | ||
} | ||
} | ||
|
||
// Convert Markdown formatting of descriptions to HTML. | ||
htmlDesc := blackfriday.Run([]byte(pm.Description)) | ||
pm.Description = string(htmlDesc) | ||
|
||
tmpl, err := template.ParseFiles(lp, fp) | ||
if err != nil { | ||
log.Println(err.Error()) | ||
http.Error(w, http.StatusText(500), http.StatusInternalServerError) | ||
|
||
return | ||
} | ||
|
||
if err := tmpl.ExecuteTemplate(w, "layout", pm); err != nil { | ||
log.Println(err.Error()) | ||
http.Error(w, http.StatusText(500), http.StatusInternalServerError) | ||
} | ||
} | ||
|
||
func indexHandler(w http.ResponseWriter, r *http.Request) { | ||
pms, err := loadPostmortems(*dir) | ||
if err != nil { | ||
log.Println(err.Error()) | ||
http.Error(w, http.StatusText(500), http.StatusInternalServerError) | ||
|
||
return | ||
} | ||
|
||
lp := filepath.Join("templates", "layout.html") | ||
fp := filepath.Join("templates", "index.html") | ||
|
||
_, err = os.Stat(fp) | ||
if err != nil { | ||
if os.IsNotExist(err) { | ||
// Template doesn't exist, return 404. | ||
http.NotFound(w, r) | ||
return | ||
} | ||
} | ||
|
||
tmpl, err := template.ParseFiles(lp, fp) | ||
if err != nil { | ||
log.Println(err.Error()) | ||
http.Error(w, http.StatusText(500), http.StatusInternalServerError) | ||
|
||
return | ||
} | ||
|
||
if err := tmpl.ExecuteTemplate(w, "layout", pms); err != nil { | ||
log.Println(err.Error()) | ||
http.Error(w, http.StatusText(500), http.StatusInternalServerError) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters