1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-12-12 13:30:26 +00:00
mycorrhiza/handlers.go

214 lines
6.5 KiB
Go
Raw Normal View History

2020-06-18 10:23:44 +00:00
package main
import (
2020-06-19 13:03:31 +00:00
"io/ioutil"
2020-06-18 10:23:44 +00:00
"log"
"net/http"
2020-06-19 13:03:31 +00:00
"path/filepath"
"strconv"
"strings"
"time"
2020-06-19 14:30:19 +00:00
2020-06-23 17:53:05 +00:00
"github.com/bouncepaw/mycorrhiza/cfg"
2020-06-19 14:30:19 +00:00
"github.com/gorilla/mux"
2020-06-18 10:23:44 +00:00
)
// There are handlers below. See main() for their usage.
2020-06-18 10:23:44 +00:00
// Boilerplate code present in many handlers. Good to have it.
func HandlerBase(w http.ResponseWriter, rq *http.Request) (Revision, bool) {
vars := mux.Vars(rq)
2020-06-18 10:23:44 +00:00
revno := RevInMap(vars)
return GetRevision(vars["hypha"], revno)
2020-06-18 10:23:44 +00:00
}
func HandlerGetBinary(w http.ResponseWriter, rq *http.Request) {
if rev, ok := HandlerBase(w, rq); ok {
2020-06-18 10:23:44 +00:00
rev.ActionGetBinary(w)
}
}
func HandlerRaw(w http.ResponseWriter, rq *http.Request) {
if rev, ok := HandlerBase(w, rq); ok {
2020-06-18 10:23:44 +00:00
rev.ActionRaw(w)
}
}
func HandlerZen(w http.ResponseWriter, rq *http.Request) {
if rev, ok := HandlerBase(w, rq); ok {
2020-06-18 10:23:44 +00:00
rev.ActionZen(w)
}
}
func HandlerView(w http.ResponseWriter, rq *http.Request) {
if rev, ok := HandlerBase(w, rq); ok {
2020-06-18 10:23:44 +00:00
rev.ActionView(w, HyphaPage)
} else { // Hypha does not exist
log.Println("Hypha does not exist, showing 404")
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(Hypha404(mux.Vars(rq)["hypha"])))
2020-06-18 10:23:44 +00:00
}
}
func HandlerHistory(w http.ResponseWriter, rq *http.Request) {
2020-06-18 10:23:44 +00:00
w.WriteHeader(http.StatusNotImplemented)
log.Println("Attempt to access an unimplemented thing")
}
func HandlerEdit(w http.ResponseWriter, rq *http.Request) {
vars := mux.Vars(rq)
2020-06-18 10:23:44 +00:00
ActionEdit(vars["hypha"], w)
}
func HandlerRewind(w http.ResponseWriter, rq *http.Request) {
2020-06-18 10:23:44 +00:00
w.WriteHeader(http.StatusNotImplemented)
log.Println("Attempt to access an unimplemented thing")
}
func HandlerDelete(w http.ResponseWriter, rq *http.Request) {
2020-06-18 10:23:44 +00:00
w.WriteHeader(http.StatusNotImplemented)
log.Println("Attempt to access an unimplemented thing")
}
func HandlerRename(w http.ResponseWriter, rq *http.Request) {
2020-06-18 10:23:44 +00:00
w.WriteHeader(http.StatusNotImplemented)
log.Println("Attempt to access an unimplemented thing")
}
// makeTagsSlice turns strings like `"foo,, bar,kek"` to slice of strings that represent tag names. Whitespace around commas is insignificant.
// Expected output for string above: []string{"foo", "bar", "kek"}
2020-06-19 13:03:31 +00:00
func makeTagsSlice(responseTagsString string) (ret []string) {
for _, tag := range strings.Split(responseTagsString, ",") {
if trimmed := strings.TrimSpace(tag); "" == trimmed {
ret = append(ret, trimmed)
}
}
return ret
}
// getHypha returns an existing hypha if it exists in `hyphae` or creates a new one. If it `isNew`, you'll have to insert it to `hyphae` yourself.
2020-06-19 13:03:31 +00:00
func getHypha(name string) (*Hypha, bool) {
log.Println("Accessing hypha", name)
if h, ok := hyphae[name]; ok {
log.Println("Got hypha", name)
return h, false
}
log.Println("Create hypha", name)
h := &Hypha{
FullName: name,
2020-06-23 17:53:05 +00:00
Path: filepath.Join(cfg.WikiDir, name),
2020-06-19 13:03:31 +00:00
Revisions: make(map[string]*Revision),
parentName: filepath.Dir(name),
}
return h, true
}
// revisionFromHttpData creates a new revison for hypha `h`. All data is fetched from `rq`, except for BinaryMime and BinaryPath which require additional processing. You'll have te insert the revision to `h` yourself.
func revisionFromHttpData(h *Hypha, rq *http.Request) *Revision {
2020-06-19 13:03:31 +00:00
idStr := strconv.Itoa(h.NewestRevisionInt() + 1)
2020-06-20 15:17:13 +00:00
log.Printf("Creating revision %s from http data", idStr)
2020-06-19 13:03:31 +00:00
rev := &Revision{
2020-06-20 15:17:13 +00:00
Id: h.NewestRevisionInt() + 1,
FullName: h.FullName,
ShortName: filepath.Base(h.FullName),
Tags: makeTagsSlice(rq.PostFormValue("tags")),
Comment: rq.PostFormValue("comment"),
Author: rq.PostFormValue("author"),
Time: int(time.Now().Unix()),
TextMime: rq.PostFormValue("text_mime"),
// Fields left: BinaryMime, BinaryPath, BinaryName, TextName, TextPath
}
rev.desiredTextFilename() // TextName is set now
rev.TextPath = filepath.Join(h.Path, rev.TextName)
2020-06-19 13:03:31 +00:00
return rev
}
// writeTextFileFromHttpData tries to fetch text content from `rq` for revision `rev` and write it to a corresponding text file. It used in `HandlerUpdate`.
func writeTextFileFromHttpData(rev *Revision, rq *http.Request) error {
data := []byte(rq.PostFormValue("text"))
2020-06-19 13:03:31 +00:00
err := ioutil.WriteFile(rev.TextPath, data, 0644)
if err != nil {
log.Println("Failed to write", len(data), "bytes to", rev.TextPath)
}
return err
}
// writeBinaryFileFromHttpData tries to fetch binary content from `rq` for revision `newRev` and write it to a corresponding binary file. If there is no content, it is taken from `oldRev`.
func writeBinaryFileFromHttpData(h *Hypha, oldRev Revision, newRev *Revision, rq *http.Request) error {
2020-06-19 13:03:31 +00:00
// 10 MB file size limit
rq.ParseMultipartForm(10 << 20)
2020-06-19 13:03:31 +00:00
// Read file
file, handler, err := rq.FormFile("binary")
2020-06-19 13:03:31 +00:00
if file != nil {
defer file.Close()
}
if err != nil {
log.Println("No binary data passed for", newRev.FullName)
newRev.BinaryMime = oldRev.BinaryMime
newRev.BinaryPath = oldRev.BinaryPath
2020-06-20 15:17:13 +00:00
newRev.BinaryName = oldRev.BinaryName
2020-06-19 13:03:31 +00:00
log.Println("Set previous revision's binary data")
return nil
}
newRev.BinaryMime = handler.Header.Get("Content-Type")
newRev.BinaryPath = filepath.Join(h.Path, newRev.IdAsStr()+".bin")
2020-06-20 15:17:13 +00:00
newRev.BinaryName = newRev.desiredBinaryFilename()
2020-06-19 13:03:31 +00:00
data, err := ioutil.ReadAll(file)
if err != nil {
log.Println(err)
return err
}
log.Println("Got", len(data), "of binary data for", newRev.FullName)
err = ioutil.WriteFile(newRev.BinaryPath, data, 0644)
if err != nil {
log.Println("Failed to write", len(data), "bytes to", newRev.TextPath)
return err
}
log.Println("Written", len(data), "of binary data for", newRev.FullName)
return nil
}
func HandlerUpdate(w http.ResponseWriter, rq *http.Request) {
vars := mux.Vars(rq)
log.Println("Attempt to update hypha", mux.Vars(rq)["hypha"])
2020-06-19 13:03:31 +00:00
h, isNew := getHypha(vars["hypha"])
2020-06-22 13:58:12 +00:00
var oldRev Revision
if !isNew {
oldRev = h.GetNewestRevision()
} else {
h = &Hypha{
FullName: vars["hypha"],
2020-06-23 17:53:05 +00:00
Path: filepath.Join(cfg.WikiDir, vars["hypha"]),
2020-06-22 13:58:12 +00:00
Revisions: make(map[string]*Revision),
parentName: filepath.Dir(vars["hypha"]),
}
2020-06-19 13:03:31 +00:00
h.CreateDir()
2020-06-22 13:58:12 +00:00
oldRev = Revision{}
2020-06-19 13:03:31 +00:00
}
2020-06-22 13:58:12 +00:00
newRev := revisionFromHttpData(h, rq)
err := writeTextFileFromHttpData(newRev, rq)
2020-06-19 13:03:31 +00:00
if err != nil {
log.Println(err)
return
}
err = writeBinaryFileFromHttpData(h, oldRev, newRev, rq)
2020-06-19 13:03:31 +00:00
if err != nil {
log.Println(err)
return
}
h.Revisions[newRev.IdAsStr()] = newRev
h.SaveJson()
2020-06-22 13:58:12 +00:00
if isNew {
hyphae[h.FullName] = h
}
2020-06-19 13:03:31 +00:00
log.Println("Current hyphae storage is", hyphae)
w.WriteHeader(http.StatusOK)
2020-06-20 15:17:13 +00:00
w.Header().Set("Content-Type", "text/html; charset=utf-8")
d := map[string]string{"Name": h.FullName}
w.Write([]byte(renderFromMap(d, "updateOk.html")))
2020-06-18 10:23:44 +00:00
}