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
+
+
+
+
+
+
+ File |
+ Actions |
+
+
+ {{ range .Binaries }}
+
+
+ {{ . }}
+ |
+
+
+ |
+
+ {{ end }}
+
+
+
+
+
+{{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,
+ }
+}