From bcf8ba4d9bec0fd3bc551da742fa615bcc96fa82 Mon Sep 17 00:00:00 2001 From: Niko Abeler Date: Sat, 8 Jul 2023 12:03:10 +0200 Subject: [PATCH] upload files --- cmd/owl/editor_test.go | 13 +++++- infra/binary_file_repository.go | 3 +- web/app.go | 2 +- web/editor/entry_form.go | 52 +++++++++++++++++----- web/editor/entry_form_test.go | 53 ++++++++++++++++++++--- web/editor_handler.go | 9 ++-- web/templates/views/entry/ImageEntry.tmpl | 2 +- 7 files changed, 109 insertions(+), 25 deletions(-) diff --git a/cmd/owl/editor_test.go b/cmd/owl/editor_test.go index a2efef6..462b8ca 100644 --- a/cmd/owl/editor_test.go +++ b/cmd/owl/editor_test.go @@ -3,6 +3,7 @@ package main import ( "bytes" "io" + "io/ioutil" "math/rand" "mime/multipart" "net/http/httptest" @@ -44,6 +45,7 @@ func TestEditorFormPost(t *testing.T) { owlApp := App(db) app := owlApp.FiberApp repo := infra.NewEntryRepository(db, owlApp.Registry) + binRepo := infra.NewBinaryFileRepo(db) fileDir, _ := os.Getwd() fileName := "../../test/fixtures/test.png" @@ -51,11 +53,13 @@ func TestEditorFormPost(t *testing.T) { file, err := os.Open(filePath) require.NoError(t, err) + fileBytes, err := ioutil.ReadFile(filePath) + require.NoError(t, err) defer file.Close() body := &bytes.Buffer{} writer := multipart.NewWriter(body) - part, _ := writer.CreateFormFile("ImagePath", filepath.Base(file.Name())) + part, _ := writer.CreateFormFile("ImageId", filepath.Base(file.Name())) io.Copy(part, file) part, _ = writer.CreateFormField("Content") io.WriteString(part, "test content") @@ -72,6 +76,11 @@ func TestEditorFormPost(t *testing.T) { entry, err := repo.FindById(id) require.NoError(t, err) 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) } diff --git a/infra/binary_file_repository.go b/infra/binary_file_repository.go index d01ce42..361539c 100644 --- a/infra/binary_file_repository.go +++ b/infra/binary_file_repository.go @@ -1,6 +1,7 @@ package infra import ( + "owl-blogs/app/repository" "owl-blogs/domain/model" "github.com/google/uuid" @@ -17,7 +18,7 @@ type DefaultBinaryFileRepo struct { db *sqlx.DB } -func NewBinaryFileRepo(db Database) *DefaultBinaryFileRepo { +func NewBinaryFileRepo(db Database) repository.BinaryRepository { sqlxdb := db.Get() // Create table if not exists diff --git a/web/app.go b/web/app.go index 1532664..3accf1e 100644 --- a/web/app.go +++ b/web/app.go @@ -23,7 +23,7 @@ func NewWebApp(entryService *app.EntryService, typeRegistry *app.EntryTypeRegist rssHandler := NewRSSHandler(entryService) loginHandler := NewLoginHandler(entryService) editorListHandler := NewEditorListHandler(typeRegistry) - editorHandler := NewEditorHandler(entryService, typeRegistry) + editorHandler := NewEditorHandler(entryService, typeRegistry, binService) // app.ServeFiles("/static/*filepath", http.Dir(repo.StaticDir())) app.Get("/", indexHandler.Handle) diff --git a/web/editor/entry_form.go b/web/editor/entry_form.go index 45f5c60..9857f2b 100644 --- a/web/editor/entry_form.go +++ b/web/editor/entry_form.go @@ -3,6 +3,7 @@ package editor import ( "fmt" "mime/multipart" + "owl-blogs/app" "owl-blogs/domain/model" "reflect" "strings" @@ -21,7 +22,8 @@ type HttpFormData interface { } type EditorEntryForm struct { - entry model.Entry + entry model.Entry + binSvc *app.BinaryService } type EntryFormFieldParams struct { @@ -34,9 +36,10 @@ type EntryFormField struct { Params EntryFormFieldParams } -func NewEntryForm(entry model.Entry) *EditorEntryForm { +func NewEntryForm(entry model.Entry, binaryService *app.BinaryService) *EditorEntryForm { return &EditorEntryForm{ - entry: entry, + entry: entry, + binSvc: binaryService, } } @@ -103,7 +106,7 @@ func (s *EditorEntryForm) HtmlForm() (string, error) { return "", err } - html := "
\n" + html := "\n" for _, field := range fields { html += field.Html() } @@ -126,13 +129,42 @@ func (s *EditorEntryForm) Parse(ctx HttpFormData) (model.Entry, error) { if err != nil { return nil, err } - for field := range fields { - fieldName := fields[field].Name - fieldValue := ctx.FormValue(fieldName) - metaField := metaVal.Elem().FieldByName(fieldName) - if metaField.IsValid() { - metaField.SetString(fieldValue) + for _, field := range fields { + fieldName := field.Name + + if field.Params.InputType == "file" { + file, err := ctx.FormFile(fieldName) + 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 diff --git a/web/editor/entry_form_test.go b/web/editor/entry_form_test.go index 68fd685..79396a1 100644 --- a/web/editor/entry_form_test.go +++ b/web/editor/entry_form_test.go @@ -1,9 +1,17 @@ package editor_test import ( + "bytes" + "io" "mime/multipart" + "os" + "owl-blogs/app" "owl-blogs/domain/model" + "owl-blogs/infra" + "owl-blogs/test" "owl-blogs/web/editor" + "path" + "path/filepath" "reflect" "testing" "time" @@ -17,10 +25,41 @@ type MockEntryMetaData 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) { - return nil, nil + return f.fileHeader, nil } func (f *MockFormData) FormValue(key string, defaultValue ...string) string { @@ -75,7 +114,7 @@ func TestStructToFields(t *testing.T) { } func TestEditorEntryForm_HtmlForm(t *testing.T) { - form := editor.NewEntryForm(&MockEntry{}) + form := editor.NewEntryForm(&MockEntry{}, nil) html, err := form.HtmlForm() require.NoError(t, err) require.Contains(t, html, " {{.Content}}