diff --git a/README.md b/README.md index 298ed28..796a2e8 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ tg_chat=chatid ### Docker deployment: Due to project's simplicity ~~and me rarely using them~~ there are no image tags, I just use `latest` and push to it. -The [package](https://git.a71.su/Andrew71/hibiscus/packages) provided in this repository is for ` linux/amd64` architecture, +The [package](https://git.a71.su/Andrew71/hibiscus/packages) provided in this repository is for `linux/amd64` architecture, and there is a [Dockerfile](./Dockerfile) in case you want to compile for something rarer (like a Pi). Below is `compose.yml` that I personally use: ```yaml version: "3.8" diff --git a/TODO.md b/TODO.md index b3ddb08..a628b74 100644 --- a/TODO.md +++ b/TODO.md @@ -4,10 +4,8 @@ List of things to add to this project * Better docs in case others want to use ths for some reason * Github/Codeberg/whatever mirror for when `faye` (my server) is offline * Improve config and use reflection when loading it -* Do to other methods what was done to GetDays/GetNotes? * API revamp * Check export function for improvements -* Add note creation and deletion to frontend (*properly*) * Customise log file * More slog.Debug and a debug flag? * Consider less clunky auth method diff --git a/files.go b/files.go index 9aac325..fa24f79 100644 --- a/files.go +++ b/files.go @@ -32,7 +32,15 @@ func ReadFile(filename string) ([]byte, error) { // SaveFile Writes request's contents to a file func SaveFile(filename string, contents []byte) error { + contents = bytes.TrimSpace(contents) filename = "data/" + filename + ".txt" + if len(contents) == 0 { // Delete empty files + err := os.Remove(filename) + slog.Error("error deleting empty file", + "error", err, + "file", filename) + return err + } f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) if err != nil { slog.Error("error opening/making file", @@ -40,7 +48,7 @@ func SaveFile(filename string, contents []byte) error { "file", filename) return err } - if _, err := f.Write(bytes.TrimSpace(contents)); err != nil { + if _, err := f.Write(contents); err != nil { slog.Error("error writing to file", "error", err, "file", filename) diff --git a/routes.go b/routes.go index 90e2794..3af232b 100644 --- a/routes.go +++ b/routes.go @@ -131,6 +131,37 @@ func GetNotes(w http.ResponseWriter, r *http.Request) { }) } +func GetEntry(w http.ResponseWriter, r *http.Request, title string, filename string, editable bool) { + entry, err := ReadFile(filename) + if err != nil { + if editable && errors.Is(err, os.ErrNotExist) { + entry = []byte("") + } else { + slog.Error("error reading entry file", "error", err, "file", filename) + InternalError(w, r) + return + } + } + + files := []string{"./pages/base.html"} + if editable { + files = append(files, "./pages/edit.html") + } else { + files = append(files, "./pages/entry.html") + } + ts, err := template.ParseFiles(files...) + if err != nil { + InternalError(w, r) + return + } + + err = ts.ExecuteTemplate(w, "base", Entry{Title: title, Content: string(entry)}) + if err != nil { + InternalError(w, r) + return + } +} + // GetDay renders HTML page for a specific day entry func GetDay(w http.ResponseWriter, r *http.Request) { dayString := chi.URLParam(r, "day") @@ -139,34 +170,18 @@ func GetDay(w http.ResponseWriter, r *http.Request) { HandleWrite(w.Write([]byte("day not specified"))) return } - if dayString == time.Now().Format(time.DateOnly) { // today can still be edited + if dayString == time.Now().Format(time.DateOnly) { // Today can still be edited http.Redirect(w, r, "/", 302) return } - day, err := ReadFile("day/" + dayString) - if err != nil { - slog.Error("error reading day's file", "error", err, "day", dayString) - InternalError(w, r) - return - } - - files := []string{"./pages/base.html", "./pages/entry.html"} - ts, err := template.ParseFiles(files...) - if err != nil { - InternalError(w, r) - return - } + title := dayString t, err := time.Parse(time.DateOnly, dayString) if err == nil { // This is low priority so silently fail - dayString = t.Format("02 Jan 2006") + title = t.Format("02 Jan 2006") } - err = ts.ExecuteTemplate(w, "base", Entry{Content: string(day), Title: dayString}) - if err != nil { - InternalError(w, r) - return - } + GetEntry(w, r, title, "day/"+dayString, false) } // GetNote renders HTML page for a note @@ -177,29 +192,8 @@ func GetNote(w http.ResponseWriter, r *http.Request) { HandleWrite(w.Write([]byte("note not specified"))) return } - note, err := ReadFile("notes/" + noteString) - if err != nil { - if errors.Is(err, os.ErrNotExist) { - note = []byte("") - } else { - slog.Error("error reading note's file", "error", err) - InternalError(w, r) - return - } - } - files := []string{"./pages/base.html", "./pages/edit.html"} - ts, err := template.ParseFiles(files...) - if err != nil { - InternalError(w, r) - return - } - - err = ts.ExecuteTemplate(w, "base", Entry{Title: noteString, Content: string(note)}) - if err != nil { - InternalError(w, r) - return - } + GetEntry(w, r, noteString, "notes/"+noteString, true) } // PostNote saves a note form and redirects back to GET