From 8a571dbee830fb27f74f94fcdf76f708579a9caa Mon Sep 17 00:00:00 2001 From: Andrew-71 Date: Sat, 23 Mar 2024 15:36:01 +0300 Subject: [PATCH] Add export, improve config saving --- TODO.md | 8 ++---- config.go | 24 ++++++++++------ config/config.txt | 4 +-- export.go | 71 +++++++++++++++++++++++++++++++++++++++++++++++ serve.go | 2 ++ 5 files changed, 94 insertions(+), 15 deletions(-) create mode 100644 export.go diff --git a/TODO.md b/TODO.md index 4472f93..6ef9ea7 100644 --- a/TODO.md +++ b/TODO.md @@ -1,13 +1,11 @@ # TODO List of things to add to this project -## Crucial -* Add export feature +* Use reflection in config loading +* Check export function for improvements * Add missing frontend pages * More slog.Debug? - -## Long-medium term considerations -* Make the CLI better +* Make the CLI multi-functional - export to path, edit file etc. * Think about timezones * Consider more secure auth methods * *Go* dependency-less? <-- this is a terrible idea \ No newline at end of file diff --git a/config.go b/config.go index 2ec2a1c..4f110d0 100644 --- a/config.go +++ b/config.go @@ -6,6 +6,7 @@ import ( "fmt" "log" "os" + "reflect" "strconv" "strings" ) @@ -13,18 +14,25 @@ import ( var ConfigFile = "config/config.txt" type Config struct { - Username string - Password string - Port int + Username string `config:"username"` + Password string `config:"password"` + Port int `config:"port"` - TelegramToken string - TelegramChat string + TelegramToken string `config:"tg_token"` + TelegramChat string `config:"tg_chat"` } func (c *Config) Save() error { - output := fmt.Sprintf("port=%d\nusername=%s\npassword=%s", c.Port, c.Username, c.Password) - if c.TelegramToken != "" && c.TelegramChat != "" { - output += fmt.Sprintf("\ntg_token=%s\ntg_chat=%s", c.TelegramToken, c.TelegramChat) + output := "" + + v := reflect.ValueOf(*c) + typeOfS := v.Type() + for i := 0; i < v.NumField(); i++ { + key := typeOfS.Field(i).Tag.Get("config") + value := v.Field(i).Interface() + if value != "" { + output += fmt.Sprintf("%s=%v\n", key, value) + } } f, err := os.OpenFile(ConfigFile, os.O_CREATE|os.O_WRONLY, 0644) diff --git a/config/config.txt b/config/config.txt index ce32892..57f51d8 100644 --- a/config/config.txt +++ b/config/config.txt @@ -1,3 +1,3 @@ -port=7101 username=admin -password=admin \ No newline at end of file +password=admin +port=7101 diff --git a/export.go b/export.go new file mode 100644 index 0000000..af673a3 --- /dev/null +++ b/export.go @@ -0,0 +1,71 @@ +package main + +import ( + "archive/zip" + "io" + "log/slog" + "net/http" + "os" + "path/filepath" +) + +var ExportPath = "data/export.zip" + +func Export(filename string) error { + file, err := os.Create(filename) + if err != nil { + slog.Error("error creating export archive", "error", err) + return err + } + defer file.Close() + + w := zip.NewWriter(file) + defer w.Close() + + walker := func(path string, info os.FileInfo, err error) error { + if path == filename { // Do not add export .zip itself + return nil + } + slog.Debug("export crawling", "path", path) + if err != nil { + return err + } + if info.IsDir() { + return nil + } + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + f, err := w.Create(path) + if err != nil { + return err + } + + _, err = io.Copy(f, file) + if err != nil { + return err + } + + return nil + } + err = filepath.Walk("data/", walker) + if err != nil { + slog.Error("error walking files", "error", err) + return err + } + + return nil +} + +// GetExport returns a .zip archive with contents of the data folder +func GetExport(w http.ResponseWriter, r *http.Request) { + err := Export(ExportPath) + if err != nil { + http.Error(w, "could not export", http.StatusInternalServerError) + return + } + http.ServeFile(w, r, "data/export.zip") +} diff --git a/serve.go b/serve.go index 7470cf2..fac0a0f 100644 --- a/serve.go +++ b/serve.go @@ -41,6 +41,8 @@ func Serve() { apiRouter.Get("/today", GetToday) apiRouter.Post("/today", PostToday) + apiRouter.Get("/export", GetExport) + r.Mount("/api", apiRouter) // Static files