summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorherkulessi <git@herkulessi.de>2026-07-04 20:39:51 +0200
committerherkulessi <git@herkulessi.de>2026-07-04 20:39:51 +0200
commitaccc7d850319324336836b62bd4309469c0d26f1 (patch)
treea45a3c7a4e8e4b5793d624d24c5366de72ec5ff2
Initial Commit
-rw-r--r--genericerror.html16
-rw-r--r--go.mod3
-rw-r--r--main.go136
-rw-r--r--notfound.html16
-rw-r--r--popup.html23
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>
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..0b88743
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
+module herkulessi.de/git/mvpad
+
+go 1.26.4
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..cd8c20f
--- /dev/null
+++ b/main.go
@@ -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&nbsp;Kopie&nbsp;des&nbsp;Pads&nbsp;/ Readonly&nbsp;Copy&nbsp;of&nbsp;this&nbsp;pad<br>
+ Zum&nbsp;Bearbeiten&nbsp;hier&nbsp;zu&nbsp;Stuve&nbsp;Notes&nbsp;umziehen:&nbsp;/ To&nbsp;edit&nbsp;this&nbsp;page&nbsp;migrate&nbsp;it&nbsp;to&nbsp;Stuve&nbsp;Notes:<br></h3>
+ <form method=post><button>Migrate</button></form>
+ </div><div class=body>