GoWiki/main.go
2019-12-20 12:55:43 +01:00

398 lines
10 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"bufio"
"encoding/json"
"fmt"
"html/template"
"io/ioutil"
"log"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"time"
"github.com/blevesearch/bleve"
"github.com/gorilla/mux"
"github.com/mandolyte/mdtopdf"
"gopkg.in/src-d/go-git.v4"
"gopkg.in/src-d/go-git.v4/plumbing/object"
)
var config = readConfig("")
type Configuration struct {
Host string
Port string
DataPath string
DataPathFTS string
}
// our main function
func main() {
// Ausgeben der Config-Optionen
fmt.Println("Host: " + config.Host)
fmt.Println("Post: " + config.Port)
fmt.Println("DataPath: " + config.DataPath)
fmt.Println("DataPathFTS: " + config.DataPathFTS)
// DataPath-Verzeichnis anlegen, wenn es noch nicht existiert
if !directoryExists(config.DataPath) {
os.MkdirAll(config.DataPath, os.ModePerm)
// Default Seiten anlegen
bStartmd, _ := Asset("web/pages/start.md")
bHilfemd, _ := Asset("web/pages/hilfe.md")
bPlaygroundmd, _ := Asset("web/pages/playground.md")
bSidebarmd, _ := Asset("web/pages/sidebar.md")
err := ioutil.WriteFile(path.Join(config.DataPath, "start.md"), bStartmd, 0644)
check(err)
err = ioutil.WriteFile(path.Join(config.DataPath, "sidebar.md"), bSidebarmd, 0644)
check(err)
err = ioutil.WriteFile(path.Join(config.DataPath, "hilfe.md"), bHilfemd, 0644)
check(err)
err = ioutil.WriteFile(path.Join(config.DataPath, "playground.md"), bPlaygroundmd, 0644)
check(err)
}
// Git Repository Init
if !directoryExists(path.Join(config.DataPath, ".git")) {
_, err := git.PlainInit(config.DataPath, false)
check(err)
GitCommit("Initial Wiki Commit")
}
// Volltextsuche
if config.DataPathFTS != "" {
if strings.HasPrefix(config.DataPathFTS, config.DataPath) {
fmt.Println("FTS disabled (Please don´t put the DataPathFTS inside the DataPath)")
} else {
fmt.Println("FTS enabled")
if !directoryExists(config.DataPathFTS) {
fmt.Println("Create new FTS Data in " + config.DataPathFTS)
mapping := bleve.NewIndexMapping()
index, err := bleve.New(config.DataPathFTS, mapping)
check(err)
filepath.Walk(config.DataPath, func(filepath string, info os.FileInfo, err error) error {
tmpPath := strings.Replace(filepath, "\\", "/", -1)
tmpPath = strings.Replace(tmpPath, "data/", "", -1)
if !info.IsDir() && !strings.HasPrefix(tmpPath, ".git") {
b, err := ioutil.ReadFile(path.Join(config.DataPath, tmpPath))
check(err)
err = index.Index(tmpPath, string(b))
check(err)
fmt.Println("Indexed: " + info.Name())
}
return nil
})
index.Close()
}
}
}
router := mux.NewRouter()
router.HandleFunc("/_api/md/{pagename:.*}", getRawPage).Methods("GET")
router.HandleFunc("/_api/pdf/{pagename:.*}", getPDFPage).Methods("GET")
router.HandleFunc("/_api/pinfo/{pagename:.*}", getPageInfo).Methods("GET")
router.HandleFunc("/_api/fts/{searchterm:.*}", getFTS).Methods("GET")
router.HandleFunc("/{pagename:.*}", getHTMLPage).Methods("GET")
router.HandleFunc("/{pagename:.*}", postHTMLPage).Methods("POST")
log.Fatal(http.ListenAndServe(":"+config.Port, router))
}
func getPDFPage(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
pPageName := params["pagename"] + ".md"
// Hack für anzeige der start.md wenn / aufgerufen wird
if pPageName == ".md" {
pPageName = "start.md"
}
content, err := ioutil.ReadFile(path.Join(config.DataPath, pPageName))
check(err)
pdfRender := mdtopdf.NewPdfRenderer("", "", "./tmp.pdf", "")
// get the unicode translator
tr := pdfRender.Pdf.UnicodeTranslatorFromDescriptor("cp1252")
pdfRender.Normal = mdtopdf.Styler{Font: "Arial", Style: "",
Size: 8, Spacing: 1,
TextColor: mdtopdf.Color{0, 0, 0},
FillColor: mdtopdf.Color{255, 255, 255}}
err = pdfRender.Process([]byte(tr(string(content))))
check(err)
pdfcontent, err := ioutil.ReadFile("./tmp.pdf")
check(err)
w.Header().Set("Content-Type", "application/pdf")
w.Write(pdfcontent)
}
func getHTMLPage(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
if strings.HasSuffix(params["pagename"], ".css") {
//fmt.Println("CSS: " + params["pagename"])
b, _ := Asset("web/" + params["pagename"])
w.Header().Set("Content-Type", "text/css")
w.Write(b)
} else if strings.HasSuffix(params["pagename"], ".js") {
//fmt.Println("JS: " + params["pagename"])
b, _ := Asset("web/" + params["pagename"])
w.Header().Set("Content-Type", "application/javascript")
w.Write(b)
} else {
// Directory Listing für die Sidebar
sidebarAusgabe := " \r\n \r\n**Inhaltsverzeichnis** \r\n\r\n"
filepath.Walk(config.DataPath, func(path string, info os.FileInfo, err error) error {
tmpPath := strings.Replace(path, "\\", "/", -1)
tmpPath = strings.Replace(tmpPath, "data", "", -1)
tmpPathSplit := strings.Split(tmpPath, "/")
sidebarTABs := ""
for i, _ := range tmpPathSplit {
//fmt.Println(i, " => ", string(c))
if i > 1 {
sidebarTABs = sidebarTABs + " "
}
}
if info.Name() != "data" && !strings.HasPrefix(tmpPath, "/.git") && info.Name() != "start.md" && info.Name() != "sidebar.md" && info.Name() != "hilfe.md" {
if !strings.HasSuffix(info.Name(), ".md") {
sidebarAusgabe = sidebarAusgabe + sidebarTABs + "* [" + strings.TrimSuffix(info.Name(), ".md") + "](" + strings.TrimSuffix(tmpPath, ".md") + "/start) \r\n"
} else {
sidebarAusgabe = sidebarAusgabe + sidebarTABs + "* [" + strings.TrimSuffix(info.Name(), ".md") + "](" + strings.TrimSuffix(tmpPath, ".md") + ") \r\n"
}
}
return nil
})
//tmpl := template.Must(template.ParseFiles("./web/index.html"))
bTmpl, _ := Asset("web/index.html")
tmpl := template.Must(template.New("tml").Parse(string(bTmpl)))
data := MarkDownData{
PageTitle: " ",
MDText: "",
SideBar: sidebarAusgabe,
}
tmpl.Execute(w, data)
}
}
func getRawPage(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
pPageName := params["pagename"] + ".md"
// Hack für anzeige der start.md wenn / aufgerufen wird
if pPageName == ".md" {
pPageName = "start.md"
}
pageContent := "Empty"
//fmt.Println(path.Join(config.DataPath, pPageName))
b, err := ioutil.ReadFile(path.Join(config.DataPath, pPageName))
check(err)
pageContent = string(b)
json.NewEncoder(w).Encode(pageContent)
}
func postHTMLPage(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
pPageName := params["pagename"] + ".md"
// Verzeichnis erstellen
dir := path.Dir(pPageName)
if !directoryExists(path.Join(config.DataPath, dir)) {
os.MkdirAll(path.Join(config.DataPath, dir), os.ModePerm)
}
//{ "MDText":"**test3**" }
var oBody TPostBody
json.NewDecoder(r.Body).Decode(&oBody)
//fmt.Println(oBody)
f, err := os.Create(path.Join(config.DataPath, pPageName))
check(err)
defer f.Close()
fw := bufio.NewWriter(f)
_, err = fw.WriteString(oBody.MDText)
check(err)
fw.Flush()
// Git Commit
GitCommit("Auto-Commit Page: " + pPageName)
// FTS Index
BleveIndex(pPageName)
json.NewEncoder(w).Encode("OK")
}
func getFTS(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
pSearchterm := params["searchterm"]
if config.DataPathFTS != "" {
if directoryExists(config.DataPathFTS) {
index, err := bleve.Open(config.DataPathFTS)
check(err)
query := bleve.NewQueryStringQuery(pSearchterm)
search := bleve.NewSearchRequest(query)
search.Highlight = bleve.NewHighlight()
search.Size = 30
searchResults, err := index.Search(search)
index.Close()
//fmt.Println("SR: " + searchResults.String())
json.NewEncoder(w).Encode(searchResults.Hits)
}
}
}
func getPageInfo(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
pPageName := params["pagename"] + ".md"
f, err := os.Open(path.Join(config.DataPath, pPageName))
check(err)
statinfo, err := f.Stat()
check(err)
data := struct {
PageName string
ModTime time.Time
}{
pPageName,
statinfo.ModTime(),
}
json.NewEncoder(w).Encode(data)
}
//--------------------------------------------------------------------------
// Typen
//--------------------------------------------------------------------------
type MarkDownData struct {
PageTitle string
MDText string
SideBar string
}
type TPostBody struct {
MDText string
}
//--------------------------------------------------------------------------
// Hilfsfunktionen
//--------------------------------------------------------------------------
func check(e error) {
if e != nil {
fmt.Println(e)
}
}
func fileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}
func directoryExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return info.IsDir()
}
func readConfig(filename string) *Configuration {
// initialize conf with default values.
conf := &Configuration{Host: "http://127.0.0.1", Port: "8000", DataPath: "./data", DataPathFTS: ""}
b, err := ioutil.ReadFile("./config.json")
if err != nil {
return conf
}
if err = json.Unmarshal(b, conf); err != nil {
return conf
}
return conf
}
func GitCommit(CommitText string) {
// Git Repo öffnen
repo, err := git.PlainOpen(config.DataPath)
check(err)
// Working Tree setzen
wt, err := repo.Worktree()
check(err)
// Alle Dateien zum Working Tree hinzufügen
_, err = wt.Add(".")
check(err)
// Status ausgeben
//status, err := wt.Status()
//check(err)
//fmt.Println(status)
// Neuen Commit Erstellen
_, err = wt.Commit(CommitText, &git.CommitOptions{
Author: &object.Signature{
Name: "GoWiki",
Email: "gowiki@local.org",
When: time.Now(),
},
})
check(err)
// Commit infos anzeigen
//obj, err := repo.CommitObject(commit)
//check(err)
//fmt.Println(obj)
}
func BleveIndex(PageName string) {
if config.DataPathFTS != "" {
if directoryExists(config.DataPathFTS) {
index, err := bleve.Open(config.DataPathFTS)
check(err)
b, err := ioutil.ReadFile(path.Join(config.DataPath, PageName))
check(err)
err = index.Index(PageName, string(b))
check(err)
index.Close()
}
}
}