upload files

This commit is contained in:
Niko Abeler 2023-07-08 12:03:10 +02:00
parent 9301790408
commit bcf8ba4d9b
7 changed files with 109 additions and 25 deletions

View File

@ -3,6 +3,7 @@ package main
import ( import (
"bytes" "bytes"
"io" "io"
"io/ioutil"
"math/rand" "math/rand"
"mime/multipart" "mime/multipart"
"net/http/httptest" "net/http/httptest"
@ -44,6 +45,7 @@ func TestEditorFormPost(t *testing.T) {
owlApp := App(db) owlApp := App(db)
app := owlApp.FiberApp app := owlApp.FiberApp
repo := infra.NewEntryRepository(db, owlApp.Registry) repo := infra.NewEntryRepository(db, owlApp.Registry)
binRepo := infra.NewBinaryFileRepo(db)
fileDir, _ := os.Getwd() fileDir, _ := os.Getwd()
fileName := "../../test/fixtures/test.png" fileName := "../../test/fixtures/test.png"
@ -51,11 +53,13 @@ func TestEditorFormPost(t *testing.T) {
file, err := os.Open(filePath) file, err := os.Open(filePath)
require.NoError(t, err) require.NoError(t, err)
fileBytes, err := ioutil.ReadFile(filePath)
require.NoError(t, err)
defer file.Close() defer file.Close()
body := &bytes.Buffer{} body := &bytes.Buffer{}
writer := multipart.NewWriter(body) writer := multipart.NewWriter(body)
part, _ := writer.CreateFormFile("ImagePath", filepath.Base(file.Name())) part, _ := writer.CreateFormFile("ImageId", filepath.Base(file.Name()))
io.Copy(part, file) io.Copy(part, file)
part, _ = writer.CreateFormField("Content") part, _ = writer.CreateFormField("Content")
io.WriteString(part, "test content") io.WriteString(part, "test content")
@ -72,6 +76,11 @@ func TestEditorFormPost(t *testing.T) {
entry, err := repo.FindById(id) entry, err := repo.FindById(id)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, "test content", entry.MetaData().(*model.ImageEntryMetaData).Content) require.Equal(t, "test content", entry.MetaData().(*model.ImageEntryMetaData).Content)
// require.Equal(t, "test.png", entry.MetaData().(*model.ImageEntryMetaData).ImagePath) imageId := entry.MetaData().(*model.ImageEntryMetaData).ImageId
require.NotZero(t, imageId)
bin, err := binRepo.FindById(imageId)
require.NoError(t, err)
require.Equal(t, bin.Name, "test.png")
require.Equal(t, fileBytes, bin.Data)
} }

View File

@ -1,6 +1,7 @@
package infra package infra
import ( import (
"owl-blogs/app/repository"
"owl-blogs/domain/model" "owl-blogs/domain/model"
"github.com/google/uuid" "github.com/google/uuid"
@ -17,7 +18,7 @@ type DefaultBinaryFileRepo struct {
db *sqlx.DB db *sqlx.DB
} }
func NewBinaryFileRepo(db Database) *DefaultBinaryFileRepo { func NewBinaryFileRepo(db Database) repository.BinaryRepository {
sqlxdb := db.Get() sqlxdb := db.Get()
// Create table if not exists // Create table if not exists

View File

@ -23,7 +23,7 @@ func NewWebApp(entryService *app.EntryService, typeRegistry *app.EntryTypeRegist
rssHandler := NewRSSHandler(entryService) rssHandler := NewRSSHandler(entryService)
loginHandler := NewLoginHandler(entryService) loginHandler := NewLoginHandler(entryService)
editorListHandler := NewEditorListHandler(typeRegistry) editorListHandler := NewEditorListHandler(typeRegistry)
editorHandler := NewEditorHandler(entryService, typeRegistry) editorHandler := NewEditorHandler(entryService, typeRegistry, binService)
// app.ServeFiles("/static/*filepath", http.Dir(repo.StaticDir())) // app.ServeFiles("/static/*filepath", http.Dir(repo.StaticDir()))
app.Get("/", indexHandler.Handle) app.Get("/", indexHandler.Handle)

View File

@ -3,6 +3,7 @@ package editor
import ( import (
"fmt" "fmt"
"mime/multipart" "mime/multipart"
"owl-blogs/app"
"owl-blogs/domain/model" "owl-blogs/domain/model"
"reflect" "reflect"
"strings" "strings"
@ -21,7 +22,8 @@ type HttpFormData interface {
} }
type EditorEntryForm struct { type EditorEntryForm struct {
entry model.Entry entry model.Entry
binSvc *app.BinaryService
} }
type EntryFormFieldParams struct { type EntryFormFieldParams struct {
@ -34,9 +36,10 @@ type EntryFormField struct {
Params EntryFormFieldParams Params EntryFormFieldParams
} }
func NewEntryForm(entry model.Entry) *EditorEntryForm { func NewEntryForm(entry model.Entry, binaryService *app.BinaryService) *EditorEntryForm {
return &EditorEntryForm{ return &EditorEntryForm{
entry: entry, entry: entry,
binSvc: binaryService,
} }
} }
@ -103,7 +106,7 @@ func (s *EditorEntryForm) HtmlForm() (string, error) {
return "", err return "", err
} }
html := "<form method=\"POST\">\n" html := "<form method=\"POST\" enctype=\"multipart/form-data\">\n"
for _, field := range fields { for _, field := range fields {
html += field.Html() html += field.Html()
} }
@ -126,13 +129,42 @@ func (s *EditorEntryForm) Parse(ctx HttpFormData) (model.Entry, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
for field := range fields { for _, field := range fields {
fieldName := fields[field].Name fieldName := field.Name
fieldValue := ctx.FormValue(fieldName)
metaField := metaVal.Elem().FieldByName(fieldName) if field.Params.InputType == "file" {
if metaField.IsValid() { file, err := ctx.FormFile(fieldName)
metaField.SetString(fieldValue) if err != nil {
return nil, err
}
fileData, err := file.Open()
if err != nil {
return nil, err
}
defer fileData.Close()
fileBytes := make([]byte, file.Size)
_, err = fileData.Read(fileBytes)
if err != nil {
return nil, err
}
binaryFile, err := s.binSvc.Create(file.Filename, fileBytes)
if err != nil {
return nil, err
}
metaField := metaVal.Elem().FieldByName(fieldName)
if metaField.IsValid() {
metaField.SetString(binaryFile.Id)
}
} else {
formValue := ctx.FormValue(fieldName)
metaField := metaVal.Elem().FieldByName(fieldName)
if metaField.IsValid() {
metaField.SetString(formValue)
}
} }
} }
return s.entry, nil return s.entry, nil

View File

@ -1,9 +1,17 @@
package editor_test package editor_test
import ( import (
"bytes"
"io"
"mime/multipart" "mime/multipart"
"os"
"owl-blogs/app"
"owl-blogs/domain/model" "owl-blogs/domain/model"
"owl-blogs/infra"
"owl-blogs/test"
"owl-blogs/web/editor" "owl-blogs/web/editor"
"path"
"path/filepath"
"reflect" "reflect"
"testing" "testing"
"time" "time"
@ -17,10 +25,41 @@ type MockEntryMetaData struct {
} }
type MockFormData struct { type MockFormData struct {
fileHeader *multipart.FileHeader
}
func NewMockFormData() *MockFormData {
fileDir, _ := os.Getwd()
fileName := "../../test/fixtures/test.png"
filePath := path.Join(fileDir, fileName)
file, err := os.Open(filePath)
if err != nil {
panic(err)
}
defer file.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("ImagePath", filepath.Base(file.Name()))
if err != nil {
panic(err)
}
io.Copy(part, file)
writer.Close()
multipartForm := multipart.NewReader(body, writer.Boundary())
formData, err := multipartForm.ReadForm(0)
if err != nil {
panic(err)
}
fileHeader := formData.File["ImagePath"][0]
return &MockFormData{fileHeader: fileHeader}
} }
func (f *MockFormData) FormFile(key string) (*multipart.FileHeader, error) { func (f *MockFormData) FormFile(key string) (*multipart.FileHeader, error) {
return nil, nil return f.fileHeader, nil
} }
func (f *MockFormData) FormValue(key string, defaultValue ...string) string { func (f *MockFormData) FormValue(key string, defaultValue ...string) string {
@ -75,7 +114,7 @@ func TestStructToFields(t *testing.T) {
} }
func TestEditorEntryForm_HtmlForm(t *testing.T) { func TestEditorEntryForm_HtmlForm(t *testing.T) {
form := editor.NewEntryForm(&MockEntry{}) form := editor.NewEntryForm(&MockEntry{}, nil)
html, err := form.HtmlForm() html, err := form.HtmlForm()
require.NoError(t, err) require.NoError(t, err)
require.Contains(t, html, "<form") require.Contains(t, html, "<form")
@ -87,15 +126,17 @@ func TestEditorEntryForm_HtmlForm(t *testing.T) {
} }
func TestFormParseNil(t *testing.T) { func TestFormParseNil(t *testing.T) {
form := editor.NewEntryForm(&MockEntry{}) form := editor.NewEntryForm(&MockEntry{}, nil)
_, err := form.Parse(nil) _, err := form.Parse(nil)
require.Error(t, err) require.Error(t, err)
} }
func TestFormParse(t *testing.T) { func TestFormParse(t *testing.T) {
form := editor.NewEntryForm(&MockEntry{}) binRepo := infra.NewBinaryFileRepo(test.NewMockDb())
entry, err := form.Parse(&MockFormData{}) binService := app.NewBinaryFileService(binRepo)
form := editor.NewEntryForm(&MockEntry{}, binService)
entry, err := form.Parse(NewMockFormData())
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, "Image", entry.MetaData().(*MockEntryMetaData).Image) require.NotZero(t, entry.MetaData().(*MockEntryMetaData).Image)
require.Equal(t, "Content", entry.MetaData().(*MockEntryMetaData).Content) require.Equal(t, "Content", entry.MetaData().(*MockEntryMetaData).Content)
} }

View File

@ -11,11 +11,12 @@ import (
type EditorHandler struct { type EditorHandler struct {
entrySvc *app.EntryService entrySvc *app.EntryService
binSvc *app.BinaryService
registry *app.EntryTypeRegistry registry *app.EntryTypeRegistry
} }
func NewEditorHandler(entryService *app.EntryService, registry *app.EntryTypeRegistry) *EditorHandler { func NewEditorHandler(entryService *app.EntryService, registry *app.EntryTypeRegistry, binService *app.BinaryService) *EditorHandler {
return &EditorHandler{entrySvc: entryService, registry: registry} return &EditorHandler{entrySvc: entryService, registry: registry, binSvc: binService}
} }
func (h *EditorHandler) paramToEntry(c *fiber.Ctx) (model.Entry, error) { func (h *EditorHandler) paramToEntry(c *fiber.Ctx) (model.Entry, error) {
@ -35,7 +36,7 @@ func (h *EditorHandler) HandleGet(c *fiber.Ctx) error {
return err return err
} }
form := editor.NewEntryForm(entryType) form := editor.NewEntryForm(entryType, h.binSvc)
htmlForm, err := form.HtmlForm() htmlForm, err := form.HtmlForm()
if err != nil { if err != nil {
return err return err
@ -51,7 +52,7 @@ func (h *EditorHandler) HandlePost(c *fiber.Ctx) error {
return err return err
} }
form := editor.NewEntryForm(entryType) form := editor.NewEntryForm(entryType, h.binSvc)
// get form data // get form data
entry, err := form.Parse(c) entry, err := form.Parse(c)
if err != nil { if err != nil {

View File

@ -2,7 +2,7 @@
{{define "main"}} {{define "main"}}
{{.MetaData.ImagePath}} {{.MetaData.ImageId}}
<p> <p>
{{.Content}} {{.Content}}