2024-03-15 18:34:24 +03:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
2024-03-15 18:48:24 +03:00
|
|
|
"errors"
|
2024-03-18 15:50:20 +03:00
|
|
|
"github.com/go-chi/chi/v5"
|
2024-03-15 18:34:24 +03:00
|
|
|
"io"
|
2024-03-20 16:18:23 +03:00
|
|
|
"log/slog"
|
2024-03-15 18:34:24 +03:00
|
|
|
"net/http"
|
|
|
|
"os"
|
2024-03-18 20:04:14 +03:00
|
|
|
"path"
|
2024-03-15 18:34:24 +03:00
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
2024-03-18 15:50:20 +03:00
|
|
|
"time"
|
2024-03-15 18:34:24 +03:00
|
|
|
)
|
|
|
|
|
2024-03-20 16:18:23 +03:00
|
|
|
// HandleWrite checks for error in ResponseWriter.Write output
|
|
|
|
func HandleWrite(_ int, err error) {
|
|
|
|
if err != nil {
|
|
|
|
slog.Error("error writing response", "error", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-17 17:12:41 +03:00
|
|
|
// GetFile returns raw contents of a txt file in data directory
|
2024-03-18 20:04:14 +03:00
|
|
|
func GetFile(filename string, w http.ResponseWriter) {
|
|
|
|
filename = "data/" + path.Clean(filename) + ".txt" // Does this sanitize the path?
|
2024-03-15 19:22:22 +03:00
|
|
|
|
2024-03-18 20:04:14 +03:00
|
|
|
if _, err := os.Stat(filename); errors.Is(err, os.ErrNotExist) {
|
2024-03-18 15:50:20 +03:00
|
|
|
http.Error(w, "file not found", http.StatusNotFound)
|
2024-03-15 18:34:24 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-03-18 20:04:14 +03:00
|
|
|
fileContents, err := os.ReadFile(filename)
|
2024-03-15 18:34:24 +03:00
|
|
|
if err != nil {
|
2024-03-20 16:18:23 +03:00
|
|
|
slog.Error("error reading file",
|
|
|
|
"error", err,
|
|
|
|
"file", filename)
|
2024-03-15 18:34:24 +03:00
|
|
|
http.Error(w, "error reading file", http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = w.Write(fileContents)
|
|
|
|
if err != nil {
|
|
|
|
http.Error(w, "error sending file", http.StatusInternalServerError)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-17 17:12:41 +03:00
|
|
|
// PostFile Writes request's contents to a txt file in data directory
|
|
|
|
// TODO: Save to trash to prevent malicious/accidental overrides?
|
2024-03-15 18:34:24 +03:00
|
|
|
func PostFile(filename string, w http.ResponseWriter, r *http.Request) {
|
|
|
|
body, err := io.ReadAll(r.Body)
|
|
|
|
if err != nil {
|
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
2024-03-20 16:18:23 +03:00
|
|
|
HandleWrite(w.Write([]byte("error reading body")))
|
2024-03-15 18:34:24 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-03-20 16:18:23 +03:00
|
|
|
filename = "data/" + filename + ".txt"
|
|
|
|
f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, 0644)
|
2024-03-15 18:34:24 +03:00
|
|
|
if err != nil {
|
2024-03-20 16:18:23 +03:00
|
|
|
slog.Error("error opening/making file",
|
|
|
|
"error", err,
|
|
|
|
"file", filename)
|
|
|
|
HandleWrite(w.Write([]byte("error opening or creating file")))
|
2024-03-15 18:48:24 +03:00
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
2024-03-15 18:34:24 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := f.Write(body); err != nil {
|
2024-03-20 16:18:23 +03:00
|
|
|
slog.Error("error writing to file",
|
|
|
|
"error", err,
|
|
|
|
"file", filename)
|
|
|
|
HandleWrite(w.Write([]byte("error writing to file")))
|
2024-03-15 18:48:24 +03:00
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
|
|
return
|
2024-03-15 18:34:24 +03:00
|
|
|
}
|
2024-03-20 16:18:23 +03:00
|
|
|
HandleWrite(w.Write([]byte("wrote to file")))
|
2024-03-15 18:48:24 +03:00
|
|
|
w.WriteHeader(http.StatusOK)
|
2024-03-15 18:34:24 +03:00
|
|
|
}
|
|
|
|
|
2024-03-15 19:22:22 +03:00
|
|
|
// ListFiles returns JSON list of filenames in a directory without extensions or path
|
2024-03-18 20:04:14 +03:00
|
|
|
func ListFiles(directory string, w http.ResponseWriter) {
|
2024-03-15 18:48:24 +03:00
|
|
|
filenames, err := filepath.Glob("data/" + directory + "/*.txt")
|
2024-03-15 18:34:24 +03:00
|
|
|
if err != nil {
|
|
|
|
http.Error(w, "error searching for files", http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
for i, file := range filenames {
|
|
|
|
file, _ := strings.CutSuffix(filepath.Base(file), filepath.Ext(file))
|
|
|
|
filenames[i] = file
|
|
|
|
}
|
|
|
|
filenamesJson, err := json.Marshal(filenames)
|
2024-03-20 16:18:23 +03:00
|
|
|
HandleWrite(w.Write(filenamesJson))
|
2024-03-15 18:34:24 +03:00
|
|
|
}
|
2024-03-18 15:50:20 +03:00
|
|
|
|
2024-03-18 20:04:14 +03:00
|
|
|
// GetDay returns a day specified in URL
|
2024-03-18 15:50:20 +03:00
|
|
|
func GetDay(w http.ResponseWriter, r *http.Request) {
|
|
|
|
dayString := chi.URLParam(r, "day")
|
|
|
|
if dayString == "" {
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
2024-03-20 16:18:23 +03:00
|
|
|
HandleWrite(w.Write([]byte("day not specified")))
|
2024-03-18 15:50:20 +03:00
|
|
|
return
|
|
|
|
}
|
2024-03-18 20:04:14 +03:00
|
|
|
GetFile("day/"+dayString, w)
|
2024-03-18 15:50:20 +03:00
|
|
|
}
|
|
|
|
|
2024-03-18 20:04:14 +03:00
|
|
|
// GetToday runs GetFile with today's daily txt
|
2024-03-20 16:18:23 +03:00
|
|
|
func GetToday(w http.ResponseWriter, _ *http.Request) {
|
2024-03-18 20:04:14 +03:00
|
|
|
GetFile("day/"+time.Now().Format("2006-01-02"), w)
|
|
|
|
}
|
|
|
|
|
|
|
|
// PostToday runs PostFile with today's daily txt
|
|
|
|
func PostToday(w http.ResponseWriter, r *http.Request) {
|
|
|
|
PostFile("day/"+time.Now().Format("2006-01-02"), w, r)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetNote returns a note specified in URL
|
2024-03-18 15:50:20 +03:00
|
|
|
func GetNote(w http.ResponseWriter, r *http.Request) {
|
|
|
|
noteString := chi.URLParam(r, "note")
|
|
|
|
if noteString == "" {
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
2024-03-20 16:18:23 +03:00
|
|
|
HandleWrite(w.Write([]byte("note not specified")))
|
2024-03-18 15:50:20 +03:00
|
|
|
return
|
|
|
|
}
|
2024-03-18 20:04:14 +03:00
|
|
|
GetFile("notes/"+noteString, w)
|
2024-03-18 15:50:20 +03:00
|
|
|
}
|
|
|
|
|
2024-03-18 20:04:14 +03:00
|
|
|
// PostNote writes request's contents to a note specified in URL
|
|
|
|
func PostNote(w http.ResponseWriter, r *http.Request) {
|
|
|
|
noteString := chi.URLParam(r, "note")
|
|
|
|
if noteString == "" {
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
2024-03-20 16:18:23 +03:00
|
|
|
HandleWrite(w.Write([]byte("note not specified")))
|
2024-03-18 20:04:14 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
PostFile("notes/"+noteString, w, r)
|
2024-03-18 15:50:20 +03:00
|
|
|
}
|