package views import ( "encoding/json" "log" "net/http" "strconv" "strings" urls "forgejo.gwairfelin.com/max/gispatcho" "forgejo.gwairfelin.com/max/gonotes/internal/middleware" "forgejo.gwairfelin.com/max/gonotes/internal/notes" "forgejo.gwairfelin.com/max/gonotes/internal/templ" ) var myurls urls.URLs func addRequestContext(r *http.Request, ctx templ.Ctx) templ.Ctx { return ctx } func GetRoutes(prefix string) *http.ServeMux { myurls = urls.URLs{ Prefix: prefix, URLs: map[string]urls.URL{ "list": {Path: "/", Protocol: "GET", Handler: list}, "new": {Path: "/new", Protocol: "GET", Handler: new}, "view_": {Path: "/{note}", Protocol: "GET", Handler: view}, "view": {Path: "/{note}/", Protocol: "GET", Handler: view}, "setTags": {Path: "/{note}/tags/", Protocol: "POST", Handler: setTags}, "delete": {Path: "/{note}/delete/", Protocol: "GET", Handler: delete}, "edit": {Path: "/{note}/edit/", Protocol: "GET", Handler: edit}, "share": {Path: "/{note}/share/", Protocol: "POST", Handler: share}, "unshare": {Path: "/{note}/unshare/", Protocol: "POST", Handler: unshare}, "save": {Path: "/{note}/edit/save/", Protocol: "POST", Handler: save}, "togglebox": {Path: "/{note}/togglebox/", Protocol: "POST", Handler: togglebox}, }, } return myurls.GetRouter() } func view(w http.ResponseWriter, r *http.Request) { user := r.Context().Value(middleware.ContextKey("user")).(string) uid := r.PathValue("note") note, ok := notes.Notes.GetOne(user, uid) if !ok { http.NotFound(w, r) return } viewers := note.ViewersAsList() context := templ.Ctx{ "note": note, "urlEdit": myurls.Reverse("edit", urls.Repl{"note": uid}), "urlDelete": myurls.Reverse("delete", urls.Repl{"note": uid}), "urlNew": myurls.Reverse("new", urls.Repl{}), "urlShare": myurls.Reverse("share", urls.Repl{"note": uid}), "urlUnshare": myurls.Reverse("unshare", urls.Repl{"note": uid}), "urlSetTags": myurls.Reverse("setTags", urls.Repl{"note": uid}), "viewers": viewers, "tags": strings.Join(note.Tags, " "), "isOwner": user == note.Owner, } note.Render() err := templ.RenderTemplate(w, r, "view.tmpl.html", context) if err != nil { log.Print(err.Error()) http.Error(w, "Couldn't load template", http.StatusInternalServerError) return } } func edit(w http.ResponseWriter, r *http.Request) { user := r.Context().Value(middleware.ContextKey("user")).(string) uid := r.PathValue("note") note, ok := notes.Notes.GetOne(user, uid) if !ok { note = notes.NewNote("", user) } urlSave := myurls.Reverse("save", urls.Repl{"note": uid}) context := templ.Ctx{"note": note, "urlSave": urlSave, "text": string(note.Body)} err := templ.RenderTemplate(w, r, "edit.tmpl.html", context) if err != nil { log.Print(err.Error()) http.Error(w, "Couldn't load template", http.StatusInternalServerError) return } } func new(w http.ResponseWriter, r *http.Request) { user := r.Context().Value(middleware.ContextKey("user")).(string) title := r.FormValue("title") if len(title) == 0 { title = "" } note := notes.NewNote(title, user) urlEdit := myurls.Reverse("edit", urls.Repl{"note": note.Uid}) http.Redirect(w, r, urlEdit, http.StatusFound) } func delete(w http.ResponseWriter, r *http.Request) { // user := r.Context().Value(middleware.ContextKey("user")).(string) encodedTitle := r.PathValue("note") err := notes.DeleteNote(encodedTitle) if err != nil { log.Print(err.Error()) http.Error(w, "Couldn't delete note", http.StatusInternalServerError) return } urlList := myurls.Reverse("list", urls.Repl{}) http.Redirect(w, r, urlList, http.StatusFound) } func save(w http.ResponseWriter, r *http.Request) { user := r.Context().Value(middleware.ContextKey("user")).(string) uid := r.PathValue("note") note, ok := notes.Notes.GetOne(user, uid) if !ok { http.NotFound(w, r) } title := r.FormValue("title") body := r.FormValue("body") log.Printf("About to save to note %+v", note) note.Title = title note.Body = []byte(body) note.Save() http.Redirect(w, r, myurls.Reverse("view", urls.Repl{"note": note.Uid}), http.StatusFound) } func share(w http.ResponseWriter, r *http.Request) { user := r.Context().Value(middleware.ContextKey("user")).(string) uid := r.PathValue("note") note, ok := notes.Notes.GetOne(user, uid) if !ok || note.Owner != user { http.NotFound(w, r) } viewer := r.FormValue("viewer") note.AddViewer(viewer) note.Save() notes.Notes.Add(note, viewer) http.Redirect(w, r, myurls.Reverse("view", urls.Repl{"note": note.Uid}), http.StatusFound) } func unshare(w http.ResponseWriter, r *http.Request) { user := r.Context().Value(middleware.ContextKey("user")).(string) uid := r.PathValue("note") note, ok := notes.Notes.GetOne(user, uid) if !ok || note.Owner != user { http.NotFound(w, r) } viewer := r.FormValue("viewer") note.DelViewer(viewer) note.Save() notes.Notes.Del(note, viewer) http.Redirect(w, r, myurls.Reverse("view", urls.Repl{"note": note.Uid}), http.StatusFound) } func togglebox(w http.ResponseWriter, r *http.Request) { user := r.Context().Value(middleware.ContextKey("user")).(string) uid := r.PathValue("note") nthBox, err := strconv.Atoi(r.FormValue("box")) if err != nil { log.Fatal("You fucked up boy") http.Error(w, "Box not provided as numeric value", 400) return } note, ok := notes.Notes.GetOne(user, uid) if !ok { http.Error(w, "Note not found", 404) return } toggled, checked := note.ToggleBox(nthBox) if !toggled { http.Error(w, "Failed to toggle box", 500) } else { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]any{"checked": checked}) } } type titleAndURL struct { Title string URL string } func list(w http.ResponseWriter, r *http.Request) { user := r.Context().Value(middleware.ContextKey("user")).(string) tag := r.FormValue("tag") titlesAndUrls := make([]titleAndURL, 0) ns := notes.Notes.Get(user) log.Printf("Notes: %+v", notes.Notes) log.Printf("Notes for %s: %+v", user, ns) for note := range ns { if tag == "" || note.HasTag(tag) { titlesAndUrls = append( titlesAndUrls, titleAndURL{Title: note.Title, URL: myurls.Reverse("view", urls.Repl{"note": note.Uid})}, ) } } urlNew := myurls.Reverse("new", urls.Repl{}) err := templ.RenderTemplate(w, r, "list.tmpl.html", templ.Ctx{"notes": titlesAndUrls, "urlNew": urlNew}) if err != nil { log.Print(err.Error()) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } } func setTags(w http.ResponseWriter, r *http.Request) { user := r.Context().Value(middleware.ContextKey("user")).(string) uid := r.PathValue("note") tags := r.FormValue("tags") note, ok := notes.Notes.GetOne(user, uid) if !ok || note.Owner != user { http.Redirect(w, r, myurls.Reverse("view", urls.Repl{"note": uid}), http.StatusFound) return } note.Tags = strings.Split(tags, " ") note.Save() http.Redirect(w, r, myurls.Reverse("view", urls.Repl{"note": note.Uid}), http.StatusFound) }