package main import ( "errors" "fmt" "html/template" "io/ioutil" "log" "net/http" "os" "os/exec" "path" "path/filepath" "regexp" "strings" ) type Page struct { Title string Body template.HTML BodyOrig string Concept template.HTML } var templates = template.Must(template.ParseFiles("templates/edit.html", "templates/view.html")) func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { err := templates.ExecuteTemplate(w, tmpl+".html", p) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } func (p *Page) save() error { filename := path.Join("data", p.Title+".kdb") return ioutil.WriteFile(filename, []byte(p.Body), 0600) } var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9\\-]+)(/?)$") func getTitle(w http.ResponseWriter, r *http.Request) (string, error) { m := validPath.FindStringSubmatch(r.URL.Path) if m == nil { http.NotFound(w, r) return "", errors.New("Invalid Page Title") } return m[2], nil // The title is the second subexpression. } func hasPage(word string) bool { if _, err := os.Stat(path.Join("data/", normalize(word)+".kdb")); err != nil { return false } return true } func loadPage(title string) (*Page, error) { filename := title + ".kdb" bodyb, err := ioutil.ReadFile(path.Join("data", filename)) if err != nil { return nil, err } body := template.HTMLEscapeString(string(bodyb)) concept := template.HTML(construct_graph(title)) for _, word := range strings.Fields(body) { if hasPage(word) { body = strings.ReplaceAll(body, word, fmt.Sprintf("%v", normalize(word), normalize(word))) } if strings.HasPrefix(word, "http") { body = strings.ReplaceAll(body, word, fmt.Sprintf("%v", word, word)) } if strings.HasPrefix(word, "data:image/png;base64,") { body = strings.ReplaceAll(body, word, fmt.Sprintf("", word)) } } return &Page{Title: title, Body: template.HTML(body), BodyOrig: string(bodyb), Concept: concept}, nil } func normalize(word string) string { if strings.HasPrefix(word, "typeof:") { word = word[7:] } else if strings.HasPrefix(word, "subtype:") { word = word[8:] } else if strings.HasPrefix(word, "instance:") { word = word[9:] } word = strings.TrimSpace(word) return word } func viewHandler(w http.ResponseWriter, r *http.Request) { title, err := getTitle(w, r) if err != nil { return } p, err := loadPage(title) if err != nil { http.Redirect(w, r, "/edit/"+title, http.StatusFound) return } renderTemplate(w, "view", p) } func editHandler(w http.ResponseWriter, r *http.Request) { title, err := getTitle(w, r) if err != nil { return } p, err := loadPage(title) if err != nil { p = &Page{Title: title} } renderTemplate(w, "edit", p) } func saveHandler(w http.ResponseWriter, r *http.Request) { title, err := getTitle(w, r) if err != nil { return } body := r.FormValue("body") p := &Page{Title: title, Body: template.HTML(body)} err = p.save() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } http.Redirect(w, r, "/view/"+title, http.StatusFound) } func get_links(name string) (links []string) { filename := name + ".kdb" bodyb, err := ioutil.ReadFile(path.Join("data", filename)) if err != nil { return []string{} } body := template.HTMLEscapeString(string(bodyb)) for _, word := range strings.Fields(body) { if hasPage(word) { links = append(links, word) } } return } func construct_graph(word string) string { seen := make(map[string]bool) graph := "digraph {\n\""+word+"\";\n" graph = construct_graph_sub(graph, word, seen, 1) graph += "}" ioutil.WriteFile("tmp.dot", []byte(graph), 0640) subProcess := exec.Command("dot", "-Tsvg", "-otmp.svg", "tmp.dot") subProcess.Run() subProcess.Wait() data, _ := ioutil.ReadFile("tmp.svg") return "