v2 #43
|
@ -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)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
{{define "main"}}
|
{{define "main"}}
|
||||||
|
|
||||||
{{.MetaData.ImagePath}}
|
{{.MetaData.ImageId}}
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
{{.Content}}
|
{{.Content}}
|
||||||
|
|
Loading…
Reference in New Issue