diff --git a/app/binary_service.go b/app/binary_service.go index d459cd8..6c567e9 100644 --- a/app/binary_service.go +++ b/app/binary_service.go @@ -24,3 +24,11 @@ func (s *BinaryService) CreateEntryFile(name string, file []byte, entry model.En func (s *BinaryService) FindById(id string) (*model.BinaryFile, error) { return s.repo.FindById(id) } + +func (s *BinaryService) ListIds() ([]string, error) { + return s.repo.ListIds() +} + +func (s *BinaryService) Delete(binary *model.BinaryFile) error { + return s.repo.Delete(binary) +} diff --git a/app/repository/interfaces.go b/app/repository/interfaces.go index f57c5b7..7e671a4 100644 --- a/app/repository/interfaces.go +++ b/app/repository/interfaces.go @@ -19,6 +19,8 @@ type BinaryRepository interface { Create(name string, data []byte, entry model.Entry) (*model.BinaryFile, error) FindById(id string) (*model.BinaryFile, error) FindByNameForEntry(name string, entry model.Entry) (*model.BinaryFile, error) + ListIds() ([]string, error) + Delete(binary *model.BinaryFile) error } type AuthorRepository interface { diff --git a/infra/binary_file_repository.go b/infra/binary_file_repository.go index 47d29a4..150e4fc 100644 --- a/infra/binary_file_repository.go +++ b/infra/binary_file_repository.go @@ -99,3 +99,21 @@ func (repo *DefaultBinaryFileRepo) FindByNameForEntry(name string, entry model.E } return &model.BinaryFile{Id: sqlFile.Id, Name: sqlFile.Name, Data: sqlFile.Data}, nil } + +// ListIds implements repository.BinaryRepository +func (repo *DefaultBinaryFileRepo) ListIds() ([]string, error) { + var ids []string + err := repo.db.Select(&ids, "SELECT id FROM binary_files") + if err != nil { + return nil, err + } + return ids, nil +} + +// Delete implements repository.BinaryRepository +func (repo *DefaultBinaryFileRepo) Delete(binary *model.BinaryFile) error { + id := binary.Id + println("Deleting binary file", id) + _, err := repo.db.Exec("DELETE FROM binary_files WHERE id = ?", id) + return err +} diff --git a/render/templates/views/binary_manager.tmpl b/render/templates/views/binary_manager.tmpl new file mode 100644 index 0000000..8ecd036 --- /dev/null +++ b/render/templates/views/binary_manager.tmpl @@ -0,0 +1,59 @@ +{{define "title"}}Binaries{{end}} + +{{define "main"}} + +

Binaries

+ +
+
+ + +
+
+ +
+
+ + + + + + + + + {{ range .Binaries }} + + + + + {{ end }} +
FileActions
+ {{ . }} + +
+ + + +
+
+ +
+ + +{{end}} \ No newline at end of file diff --git a/web/app.go b/web/app.go index a2b41a0..83cb70d 100644 --- a/web/app.go +++ b/web/app.go @@ -52,11 +52,15 @@ func NewWebApp( // admin adminHandler := NewAdminHandler(configRepo, configRegister, typeRegistry) + binaryManageHandler := NewBinaryManageHandler(configRepo, binService) admin := app.Group("/admin") admin.Use(middleware.NewAuthMiddleware(authorService).Handle) admin.Get("/", adminHandler.Handle) admin.Get("/config/:config/", adminHandler.HandleConfigGet) admin.Post("/config/:config/", adminHandler.HandleConfigPost) + admin.Get("/binaries/", binaryManageHandler.Handle) + admin.Post("/binaries/new/", binaryManageHandler.HandleUpload) + admin.Post("/binaries/delete", binaryManageHandler.HandleDelete) // Editor editor := app.Group("/editor") diff --git a/web/binary_manager_handler.go b/web/binary_manager_handler.go new file mode 100644 index 0000000..b84484a --- /dev/null +++ b/web/binary_manager_handler.go @@ -0,0 +1,92 @@ +package web + +import ( + "owl-blogs/app" + "owl-blogs/app/repository" + "owl-blogs/render" + "sort" + "strings" + + "github.com/gofiber/fiber/v2" +) + +type BinaryManageHandler struct { + configRepo repository.ConfigRepository + service *app.BinaryService +} + +func NewBinaryManageHandler(configRepo repository.ConfigRepository, service *app.BinaryService) *BinaryManageHandler { + return &BinaryManageHandler{ + configRepo: configRepo, + service: service, + } +} + +func (h *BinaryManageHandler) Handle(c *fiber.Ctx) error { + siteConfig := getSiteConfig(h.configRepo) + + allIds, err := h.service.ListIds() + sort.Slice(allIds, func(i, j int) bool { + return strings.ToLower(allIds[i]) < strings.ToLower(allIds[j]) + }) + if err != nil { + return err + } + pageData := paginate(c, allIds, 50) + + c.Set(fiber.HeaderContentType, fiber.MIMETextHTML) + return render.RenderTemplateWithBase(c, siteConfig, "views/binary_manager", fiber.Map{ + "Binaries": pageData.items, + "Page": pageData.page, + "NextPage": pageData.page + 1, + "PrevPage": pageData.page - 1, + "FirstPage": pageData.page == 1, + "LastPage": pageData.lastPage, + }) + +} + +func (h *BinaryManageHandler) HandleUpload(c *fiber.Ctx) error { + file, err := c.FormFile("file") + if err != nil { + return err + } + reader, err := file.Open() + if err != nil { + return err + } + defer reader.Close() + + content := make([]byte, file.Size) + _, err = reader.Read(content) + if err != nil { + return err + } + + binary, err := h.service.Create(file.Filename, content) + if err != nil { + return err + } + + return c.Redirect("/media/" + binary.Id) +} + +func (h *BinaryManageHandler) HandleDelete(c *fiber.Ctx) error { + id := c.FormValue("file") + binary, err := h.service.FindById(id) + if err != nil { + return err + } + + confirm := c.FormValue("confirm") + if confirm != "on" { + return c.Redirect("/admin/binaries/") + } + + err = h.service.Delete(binary) + if err != nil { + return err + } + + return c.Redirect("/admin/binaries/") +} diff --git a/web/utils.go b/web/utils.go index 818b1f9..3c9a0d6 100644 --- a/web/utils.go +++ b/web/utils.go @@ -4,6 +4,9 @@ import ( "owl-blogs/app/repository" "owl-blogs/config" "owl-blogs/domain/model" + "strconv" + + "github.com/gofiber/fiber/v2" ) func getSiteConfig(repo repository.ConfigRepository) model.SiteConfig { @@ -14,3 +17,37 @@ func getSiteConfig(repo repository.ConfigRepository) model.SiteConfig { } return siteConfig } + +type paginationData[T any] struct { + items []T + page uint + lastPage bool +} + +func paginate[T any](c *fiber.Ctx, items []T, limit int) paginationData[T] { + page := c.Query("page") + if page == "" { + page = "1" + } + pageNum, err := strconv.Atoi(page) + if err != nil { + pageNum = 1 + } + offset := (pageNum - 1) * limit + lastPage := false + if offset > len(items) { + offset = len(items) + lastPage = true + } + if offset+limit > len(items) { + limit = len(items) - offset + lastPage = true + } + items = items[offset : offset+limit] + + return paginationData[T]{ + items: items, + page: uint(pageNum), + lastPage: lastPage, + } +}