diff options
| -rw-r--r-- | genericerror.html | 16 | ||||
| -rw-r--r-- | go.mod | 3 | ||||
| -rw-r--r-- | main.go | 136 | ||||
| -rw-r--r-- | notfound.html | 16 | ||||
| -rw-r--r-- | popup.html | 23 |
5 files changed, 194 insertions, 0 deletions
diff --git a/genericerror.html b/genericerror.html new file mode 100644 index 0000000..304d3b8 --- /dev/null +++ b/genericerror.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <meta name="color-scheme" content="dark light"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Stuve IT Error</title> + <meta name="viewport" content="width=device-width, initial-scale=1"> +</head> +<body align="center" style="display: grid; place-items: center; height: 100%; font-family: 'Roboto';"> + <div role="main" align="center"> + <header><h1>Etwas ist schiefgelaufen / Something went wrong!</h1></header> + If you believe this to be a mistake or the problem persists, please contact <a href="stuve-it@fau.de">stuve-it@fau.de</a> + </div> +</body> +</html> @@ -0,0 +1,3 @@ +module herkulessi.de/git/mvpad + +go 1.26.4 @@ -0,0 +1,136 @@ +package main + +import ( + _ "embed" + "encoding/gob" + "io" + "log/slog" + "net/http" + "net/url" + "os" + "strings" + "sync" +) + +//go:embed popup.html +var popup string + +//go:embed notfound.html +var notfound string + +//go:embed genericerror.html +var genericerror string + +var migratedLock = sync.RWMutex{} +var migrated = map[string]struct{}{} + +func migrate(id string) { + migratedLock.Lock() + migrated[id] = struct{}{} + migratedLock.Unlock() + slog.Info("Saving migrations", "id", id) + save() +} +func save() { + file, err := os.Create("migrated") + if err != nil { + slog.Warn("Could not create Migration-File", "err", err) + return + } + defer file.Close() + enc := gob.NewEncoder(file) + migratedLock.RLock() + defer migratedLock.RUnlock() + err = enc.Encode(migrated) + if err != nil { + slog.Warn("Could not encode migrations", "err", err) + return + } +} + +func main() { + file, err := os.Open("migrated") + if err != nil { + slog.Warn("Could not open migration history", "err", err) + save() + } else { + dec := gob.NewDecoder(file) + dec.Decode(&migrated) + } + + http.HandleFunc("GET /p/{id}", func(w http.ResponseWriter, r *http.Request) { + id := url.PathEscape(r.PathValue("id")) + + migratedLock.RLock() + if _, ok := migrated[id]; ok { + migratedLock.RUnlock() + http.Redirect(w, r, "https://notes.stuve.fau.de/stuve-etherpad-migrated-"+id, 302) + return + } + migratedLock.RUnlock() + + req, err := http.Get("http://127.0.0.1:9001/p/" + id + "/export/html") + if err != nil { + w.WriteHeader(502) + slog.Error("Could not fetch Pad as html", "err", err, "id", id) + w.Write([]byte(genericerror)) + return + } + defer req.Body.Close() + if req.StatusCode == 404 { + w.WriteHeader(404) + slog.Error("Could not fetch Pad: 404", "id", id) + w.Write([]byte(notfound)) + return + } + body, err := io.ReadAll(req.Body) + if req.StatusCode != 200 { + w.WriteHeader(req.StatusCode) + slog.Error("Could not fetch Pad", "id", id, "status", req.Status, "body", string(body)) + w.Write([]byte(genericerror)) + return + } + if err != nil { + w.WriteHeader(502) + slog.Error("Could not read entire body", "err", err, "id", id) + w.Write([]byte(genericerror)) + return + } + w.Write([]byte(strings.Replace(string(body), "<body>", popup, 1))) + }) + http.HandleFunc("POST /p/{id}", func(w http.ResponseWriter, r *http.Request) { + id := r.PathValue("id") + req, err := http.Get("http://127.0.0.1:9001/p/" + id + "/export/markdown") + if err != nil { + w.WriteHeader(502) + slog.Error("Could not fetch Pad as markdown", "err", err, "id", id) + w.Write([]byte(genericerror)) + return + } + if req.StatusCode == 404 { + w.WriteHeader(404) + slog.Error("Could not fetch Pad: 404", "id", id) + w.Write([]byte(notfound)) + return + } + if req.StatusCode != 200 { + body, err := io.ReadAll(req.Body) + w.WriteHeader(req.StatusCode) + slog.Error("Could not fetch Pad", "id", id, "status", req.Status, "body", string(body), "err", err) + w.Write([]byte(genericerror)) + return + } + resp, err := http.Post("https://notes.stuve.fau.de/new/stuve-etherpad-migrated-"+id, "text/markdown", req.Body) + if resp.StatusCode != 200 { + body, err := io.ReadAll(resp.Body) + w.WriteHeader(req.StatusCode) + slog.Error("Could not Post Pad", "id", id, "status", req.Status, "body", string(body), "err", err) + w.Write([]byte(genericerror)) + return + } + migrate(id) + http.Redirect(w, r, "https://notes.stuve.fau.de/stuve-etherpad-migrated-"+id, 302) + }) + err = http.ListenAndServe("[::]:8080", nil) + panic(err) +} diff --git a/notfound.html b/notfound.html new file mode 100644 index 0000000..defb72f --- /dev/null +++ b/notfound.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <meta name="color-scheme" content="dark light"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Stuve IT Error</title> + <meta name="viewport" content="width=device-width, initial-scale=1"> +</head> +<body align="center" style="display: grid; place-items: center; height: 100%; font-family: 'Roboto';"> + <div role="main" align="center"> + <header><h1>Pad existiert nicht! / Pad doesn't exist!</h1></header> + If you believe this to be a mistake or the problem persists, please contact <a href="stuve-it@fau.de">stuve-it@fau.de</a> + </div> +</body> +</html> diff --git a/popup.html b/popup.html new file mode 100644 index 0000000..92247d7 --- /dev/null +++ b/popup.html @@ -0,0 +1,23 @@ +<style> + .header { + min-height: 80px; + max-height: 100dvh; + padding: 10px; + background-color: #FF3333; + z-index: 99; + position: sticky; + top: 0; + font-family: "Roboto"; + text-align: center; + overflow: scroll; + } + .body { + overflow: scroll; + } +</style> +<body align="center" style="display: grid; place-items: center; height: 100%; font-family: 'Roboto';"> +<div class=header> + <h3>Schreibgeschützte Kopie des Pads / Readonly Copy of this pad<br> + Zum Bearbeiten hier zu Stuve Notes umziehen: / To edit this page migrate it to Stuve Notes:<br></h3> + <form method=post><button>Migrate</button></form> + </div><div class=body> |
