diff --git a/_frontend/src/pages/Bucket.jsx b/_frontend/src/pages/Bucket.jsx index 2ef3e39..f65edda 100644 --- a/_frontend/src/pages/Bucket.jsx +++ b/_frontend/src/pages/Bucket.jsx @@ -53,6 +53,8 @@ export const Bucket = () => { if (res.ok) { showToast('Oggetto rimosso') + + await updateBucketObjects() } else { showToast(`Errore "${await res.text()}"`) } diff --git a/database/jsondb.go b/database/jsondb.go index 300a146..7c551a5 100644 --- a/database/jsondb.go +++ b/database/jsondb.go @@ -245,6 +245,10 @@ func (db *jsonDB) CreateBucket(bucket string, settings any) error { bi.Settings = settings.(*JsonBucketSettings) } + if err := store.Create(bi.Settings.Path); err != nil { + return err + } + db.Buckets[bucket] = bi return nil @@ -309,7 +313,7 @@ func (db *jsonDB) CreateBucketObject(bucket string, r io.Reader) (string, error) return "", fmt.Errorf("bucket named %q not found", bucket) } - id, err := store.Create(b.Settings.Path, db.PrefixSize, r) + id, err := store.CreateObject(b.Settings.Path, db.PrefixSize, r) if err != nil { return "", err } @@ -327,7 +331,7 @@ func (db *jsonDB) SetBucketObject(bucket, id string, r io.Reader) error { return fmt.Errorf("bucket named %q not found", bucket) } - return store.Update(b.Settings.Path, db.PrefixSize, id, r) + return store.UpdateObject(b.Settings.Path, db.PrefixSize, id, r) }) } @@ -338,7 +342,7 @@ func (db *jsonDB) GetBucketObject(bucket, id string, w io.Writer) error { return fmt.Errorf("bucket named %q not found", bucket) } - return store.Read(b.Settings.Path, db.PrefixSize, id, w) + return store.ReadObject(b.Settings.Path, db.PrefixSize, id, w) }) } @@ -349,7 +353,7 @@ func (db *jsonDB) DeleteBucketObject(bucket, id string) error { return fmt.Errorf("bucket named %q not found", bucket) } - if err := store.Delete(b.Settings.Path, db.PrefixSize, id); err != nil { + if err := store.DeleteObject(b.Settings.Path, db.PrefixSize, id); err != nil { return err } @@ -367,7 +371,7 @@ func (db *jsonDB) AllBucketObjects(bucket string) ([]string, error) { return nil, fmt.Errorf("bucket named %q not found", bucket) } - objects, err := store.All(b.Settings.Path) + objects, err := store.AllObjects(b.Settings.Path) if err != nil { return nil, err } diff --git a/server/api.go b/server/api.go index 5e0f9d2..b7b5420 100644 --- a/server/api.go +++ b/server/api.go @@ -20,30 +20,23 @@ func (r *Server) isAdminMiddleware(c *fiber.Ctx) error { return c.Next() } -func (r *Server) Api(api fiber.Router) { - isAPIKeyMiddleware := func(c *fiber.Ctx) error { - if _, isAdmin := r.adminSessions[c.Cookies("sid")]; !isAdmin { // if admin continue - token := c.Cookies("token") - if token == "" { - return fmt.Errorf("no api token") - } +func (s *Server) isAPIKeyMiddleware(c *fiber.Ctx) error { + if _, isAdmin := s.adminSessions[c.Cookies("sid")]; !isAdmin { // if admin continue + token := c.Cookies("token") + if token == "" { + return fmt.Errorf("no api token") + } - if err := r.Database.CheckAPIKey(token); err != nil { // otherwise also check api token - return err - } + if err := s.Database.CheckAPIKey(token); err != nil { // otherwise also check api token + return err } - return c.Next() } - // - // TODO: Change to /server-info (also in frontend) - // Setup "/api/monitor" routes - // - monitorRoute := api.Group("/monitor") - monitorRoute.Use(r.isAdminMiddleware) - r.ApiMonitor(monitorRoute) + return c.Next() +} - api.Post("/login", func(c *fiber.Ctx) error { +func (s *Server) ApiAuth(r fiber.Router) { + r.Post("/login", func(c *fiber.Ctx) error { var form struct { Password string `form:"password"` } @@ -57,7 +50,7 @@ func (r *Server) Api(api fiber.Router) { } token := utils.GenerateRandomString(32) - r.adminSessions[token] = struct{}{} + s.adminSessions[token] = struct{}{} c.Cookie(&fiber.Cookie{ Name: "sid", @@ -69,23 +62,38 @@ func (r *Server) Api(api fiber.Router) { return c.Redirect("/") }) - api.Get("/status", func(c *fiber.Ctx) error { - return c.JSON("ok") + r.Get("/current-user", func(c *fiber.Ctx) error { + if _, found := s.adminSessions[c.Cookies("sid")]; !found { + return c.JSON("anonymous") + } + + return c.JSON("admin") }) +} - api.Get("/current-user", - func(c *fiber.Ctx) error { - if _, found := r.adminSessions[c.Cookies("sid")]; !found { - return c.JSON("anonymous") - } +func (s *Server) Api(r fiber.Router) { - return c.JSON("admin") - }) + r.Get("/status", func(c *fiber.Ctx) error { + return c.JSON("ok") + }) + + // + // TODO: Change "/monitor" to "/server-info" (also in frontend) + // Setup "/api/monitor" routes + // + r.Route("/", s.ApiAuth) + r.Route("/", s.ApiDashboard) + r.Route("/monitor", s.ApiMonitor) + r.Route("/buckets", s.ApiBucket) + r.Route("/buckets/:bucket", s.ApiBucketObjects) + r.Route("/api-keys", s.ApiKeys) +} - api.Get("/dashboard-state", - r.isAdminMiddleware, +func (s *Server) ApiDashboard(r fiber.Router) { + r.Get("/dashboard-state", + s.isAdminMiddleware, func(c *fiber.Ctx) error { - state, err := r.Database.GetDashboardState() + state, err := s.Database.GetDashboardState() if err != nil { return err } @@ -93,8 +101,8 @@ func (r *Server) Api(api fiber.Router) { return c.JSON(state) }) - api.Post("/dashboard-state", - r.isAdminMiddleware, + r.Post("/dashboard-state", + s.isAdminMiddleware, func(c *fiber.Ctx) error { var state database.DashboardState @@ -103,17 +111,19 @@ func (r *Server) Api(api fiber.Router) { return err } - if err := r.Database.SetDashboardState(state); err != nil { + if err := s.Database.SetDashboardState(state); err != nil { return err } return c.JSON("ok") }) +} - api.Get("/buckets", - r.isAdminMiddleware, +func (s *Server) ApiBucket(r fiber.Router) { + r.Get("/", + s.isAdminMiddleware, func(c *fiber.Ctx) error { - buckets, err := r.Database.AllBuckets() + buckets, err := s.Database.AllBuckets() if err != nil { return err } @@ -121,8 +131,8 @@ func (r *Server) Api(api fiber.Router) { return c.JSON(buckets) }) - api.Post("/buckets", - r.isAdminMiddleware, + r.Post("/", + s.isAdminMiddleware, func(c *fiber.Ctx) error { var req struct { Bucket string `json:"bucket"` @@ -140,19 +150,21 @@ func (r *Server) Api(api fiber.Router) { settings.Path = req.Path } - if err := r.Database.CreateBucket(req.Bucket, settings); err != nil { + if err := s.Database.CreateBucket(req.Bucket, settings); err != nil { return err } return c.JSON("ok") }) +} - api.Get("/buckets/:bucket", - isAPIKeyMiddleware, +func (s *Server) ApiBucketObjects(r fiber.Router) { + r.Get("/", + s.isAPIKeyMiddleware, func(c *fiber.Ctx) error { bucket := c.Params("bucket") - objects, err := r.Database.AllBucketObjects(bucket) + objects, err := s.Database.AllBucketObjects(bucket) if err != nil { return err } @@ -160,12 +172,12 @@ func (r *Server) Api(api fiber.Router) { return c.JSON(objects) }) - api.Get("/buckets/:bucket/settings", - r.isAdminMiddleware, + r.Get("/settings", + s.isAdminMiddleware, func(c *fiber.Ctx) error { bucket := c.Params("bucket") - settings, err := r.Database.GetBucketSettings(bucket) + settings, err := s.Database.GetBucketSettings(bucket) if err != nil { return err } @@ -173,8 +185,8 @@ func (r *Server) Api(api fiber.Router) { return c.JSON(settings) }) - api.Post("/buckets/:bucket/settings", - r.isAdminMiddleware, + r.Post("/settings", + s.isAdminMiddleware, func(c *fiber.Ctx) error { bucket := c.Params("bucket") @@ -184,15 +196,15 @@ func (r *Server) Api(api fiber.Router) { return err } - if err := r.Database.SetBucketSettings(bucket, settings); err != nil { + if err := s.Database.SetBucketSettings(bucket, settings); err != nil { return err } return c.JSON("ok") }) - api.Post("/buckets/:bucket", - isAPIKeyMiddleware, + r.Post("/", + s.isAPIKeyMiddleware, func(c *fiber.Ctx) error { bucket := c.Params("bucket") @@ -206,7 +218,7 @@ func (r *Server) Api(api fiber.Router) { return err } - id, err := r.Database.CreateBucketObject(bucket, mf) + id, err := s.Database.CreateBucketObject(bucket, mf) if err != nil { return err } @@ -217,42 +229,41 @@ func (r *Server) Api(api fiber.Router) { }) }) - api.Get("/buckets/:bucket/:id", - isAPIKeyMiddleware, + r.Get("/:id", + s.isAPIKeyMiddleware, func(c *fiber.Ctx) error { bucket := c.Params("bucket") id := c.Params("id") buf := &bytes.Buffer{} - if err := r.Database.GetBucketObject(bucket, id, buf); err != nil { + if err := s.Database.GetBucketObject(bucket, id, buf); err != nil { return err } return c.SendStream(buf) }) - api.Delete("/buckets/:bucket/:id", - isAPIKeyMiddleware, + r.Delete("/:id", + s.isAPIKeyMiddleware, func(c *fiber.Ctx) error { bucket := c.Params("bucket") id := c.Params("id") - if err := r.Database.DeleteBucketObject(bucket, id); err != nil { + if err := s.Database.DeleteBucketObject(bucket, id); err != nil { return err } return c.JSON("ok") }) - // - // API Keys - // +} - api.Get("/api-keys", - r.isAdminMiddleware, +func (s *Server) ApiKeys(r fiber.Router) { + r.Get("/", + s.isAdminMiddleware, func(c *fiber.Ctx) error { - apiKeys, err := r.Database.AllAPIKeys() + apiKeys, err := s.Database.AllAPIKeys() if err != nil { return err } @@ -260,10 +271,10 @@ func (r *Server) Api(api fiber.Router) { return c.JSON(apiKeys) }) - api.Post("/api-keys", - r.isAdminMiddleware, + r.Post("/", + s.isAdminMiddleware, func(c *fiber.Ctx) error { - key, err := r.Database.CreateAPIKey() + key, err := s.Database.CreateAPIKey() if err != nil { return err } @@ -271,20 +282,20 @@ func (r *Server) Api(api fiber.Router) { return c.JSON(key) }) - api.Delete("/api-keys/:key", - r.isAdminMiddleware, + r.Delete("/:key", + s.isAdminMiddleware, func(c *fiber.Ctx) error { - if err := r.Database.RemoveAPIKey(c.Params("key")); err != nil { + if err := s.Database.RemoveAPIKey(c.Params("key")); err != nil { return err } return c.JSON("ok") }) - api.Get("/api-keys/:key", - r.isAdminMiddleware, + r.Get("/:key", + s.isAdminMiddleware, func(c *fiber.Ctx) error { - if err := r.Database.CheckAPIKey(c.Params("key")); err != nil { + if err := s.Database.CheckAPIKey(c.Params("key")); err != nil { return err } diff --git a/server/monitor.go b/server/monitor.go index 8832f8c..bcaa585 100644 --- a/server/monitor.go +++ b/server/monitor.go @@ -6,12 +6,12 @@ import ( "github.com/gofiber/fiber/v2" ) -func (r *Server) ApiMonitor(api fiber.Router) { +func (s *Server) ApiMonitor(api fiber.Router) { // Respond to requests like // - "/api/monitor/status?script=SCRIPT_NAME" where SCRIPT_NAME is the name of a file inside "./scripts" - api.Get("/status", func(c *fiber.Ctx) error { + api.Get("/status", s.isAdminMiddleware, func(c *fiber.Ctx) error { if qScript := c.Query("script"); qScript != "" { - output, err := r.Monitor.GetOutput(qScript) + output, err := s.Monitor.GetOutput(qScript) if err != nil { return err } @@ -22,8 +22,8 @@ func (r *Server) ApiMonitor(api fiber.Router) { return fmt.Errorf("no script, device or entity provided") }) - api.Get("/invalidate-cache", func(c *fiber.Ctx) error { - r.Monitor.InvalidateCache() + api.Get("/invalidate-cache", s.isAdminMiddleware, func(c *fiber.Ctx) error { + s.Monitor.InvalidateCache() return c.JSON("ok") }) } diff --git a/store/store.go b/store/store.go index a179acc..d6853ec 100644 --- a/store/store.go +++ b/store/store.go @@ -3,6 +3,7 @@ package store import ( "fmt" "io" + "log" "os" "path" @@ -15,7 +16,11 @@ func split(baseDir string, prefixSize int, id string) (prefix, rest string) { return id[:prefixSize], id[prefixSize:] } -func Create(baseDir string, prefixSize int, r io.Reader) (string, error) { +func Create(baseDir string) error { + return os.Mkdir(baseDir, os.ModePerm) +} + +func CreateObject(baseDir string, prefixSize int, r io.Reader) (string, error) { id := utils.GenerateRandomString(RandomIdSize) prefix, rest := split(baseDir, prefixSize, id) @@ -33,7 +38,7 @@ func Create(baseDir string, prefixSize int, r io.Reader) (string, error) { return id, nil } -func Read(baseDir string, prefixSize int, id string, w io.Writer) error { +func ReadObject(baseDir string, prefixSize int, id string, w io.Writer) error { prefix, rest := split(baseDir, prefixSize, id) f, err := os.Open(path.Join(baseDir, prefix, rest)) @@ -48,7 +53,7 @@ func Read(baseDir string, prefixSize int, id string, w io.Writer) error { return nil } -func All(baseDir string) ([]string, error) { +func AllObjects(baseDir string) ([]string, error) { entries, err := os.ReadDir(baseDir) if err != nil { return nil, err @@ -78,10 +83,21 @@ func All(baseDir string) ([]string, error) { return objects, nil } -func Update(baseDir string, prefixSize int, id string, r io.Reader) error { +func UpdateObject(baseDir string, prefixSize int, id string, r io.Reader) error { panic("TODO: Not implemented") } -func Delete(baseDir string, prefixSize int, id string) error { - panic("TODO: Not implemented") +func DeleteObject(baseDir string, prefixSize int, id string) error { + prefix, rest := split(baseDir, prefixSize, id) + err := os.Remove(path.Join(baseDir, prefix, rest)) + if err != nil { + return err + } + + // Silently tries to remove the "/" directory if empty + if err := os.Remove(path.Join(baseDir, prefix)); err != nil { + log.Panicf(`Tried to remove "%s/" folder, got: %s`, prefix, err.Error()) + } + + return nil }