diff --git a/app/entry_service.go b/app/entry_service.go index ba64baf..103acab 100644 --- a/app/entry_service.go +++ b/app/entry_service.go @@ -3,6 +3,7 @@ package app import ( "owl-blogs/app/repository" "owl-blogs/domain/model" + "time" ) type EntryService struct { @@ -13,8 +14,8 @@ func NewEntryService(entryRepository repository.EntryRepository) *EntryService { return &EntryService{EntryRepository: entryRepository} } -func (s *EntryService) Create(entry model.Entry) error { - return s.EntryRepository.Create(entry) +func (s *EntryService) Create(entry model.Entry, publishedAt *time.Time, metaData model.EntryMetaData) error { + return s.EntryRepository.Create(entry, publishedAt, metaData) } func (s *EntryService) Update(entry model.Entry) error { diff --git a/app/repository/interfaces.go b/app/repository/interfaces.go index 5fb3954..7a9cf2b 100644 --- a/app/repository/interfaces.go +++ b/app/repository/interfaces.go @@ -1,9 +1,12 @@ package repository -import "owl-blogs/domain/model" +import ( + "owl-blogs/domain/model" + "time" +) type EntryRepository interface { - Create(entry model.Entry) error + Create(entry model.Entry, publishedAt *time.Time, metaData model.EntryMetaData) error Update(entry model.Entry) error Delete(entry model.Entry) error FindById(id string) (model.Entry, error) diff --git a/infra/entry_repository.go b/infra/entry_repository.go index 4e91cf2..1815079 100644 --- a/infra/entry_repository.go +++ b/infra/entry_repository.go @@ -10,6 +10,7 @@ import ( "strings" "time" + "github.com/google/uuid" "github.com/jmoiron/sqlx" _ "github.com/mattn/go-sqlite3" ) @@ -27,12 +28,7 @@ type DefaultEntryRepo struct { } // Create implements repository.EntryRepository. -func (r *DefaultEntryRepo) Create(entry model.Entry) error { - exEntry, _ := r.FindById(entry.ID()) - if exEntry != nil { - return errors.New("entry already exists") - } - +func (r *DefaultEntryRepo) Create(entry model.Entry, publishedAt *time.Time, metaData model.EntryMetaData) error { t, err := r.typeRegistry.TypeName(entry) if err != nil { return errors.New("entry type not registered") @@ -40,10 +36,12 @@ func (r *DefaultEntryRepo) Create(entry model.Entry) error { var metaDataJson []byte if entry.MetaData() != nil { - metaDataJson, _ = json.Marshal(entry.MetaData()) + metaDataJson, _ = json.Marshal(metaData) } - _, err = r.db.Exec("INSERT INTO entries (id, type, published_at, meta_data) VALUES (?, ?, ?, ?)", entry.ID(), t, entry.PublishedAt(), metaDataJson) + id := uuid.New().String() + _, err = r.db.Exec("INSERT INTO entries (id, type, published_at, meta_data) VALUES (?, ?, ?, ?)", id, t, publishedAt, metaDataJson) + entry.Create(id, publishedAt, metaData) return err } diff --git a/infra/entry_repository_test.go b/infra/entry_repository_test.go index a0b9771..55bd9cf 100644 --- a/infra/entry_repository_test.go +++ b/infra/entry_repository_test.go @@ -24,15 +24,14 @@ func TestRepoCreate(t *testing.T) { entry := &test.MockEntry{} now := time.Now() - entry.Create("id", &now, &test.MockEntryMetaData{ + err := repo.Create(entry, &now, &test.MockEntryMetaData{ Str: "str", Number: 1, Date: now, }) - err := repo.Create(entry) require.NoError(t, err) - entry2, err := repo.FindById("id") + entry2, err := repo.FindById(entry.ID()) require.NoError(t, err) require.Equal(t, entry.ID(), entry2.ID()) require.Equal(t, entry.Content(), entry2.Content()) @@ -49,12 +48,11 @@ func TestRepoDelete(t *testing.T) { entry := &test.MockEntry{} now := time.Now() - entry.Create("id", &now, &test.MockEntryMetaData{ + err := repo.Create(entry, &now, &test.MockEntryMetaData{ Str: "str", Number: 1, Date: now, }) - err := repo.Create(entry) require.NoError(t, err) err = repo.Delete(entry) @@ -69,22 +67,21 @@ func TestRepoFindAll(t *testing.T) { entry := &test.MockEntry{} now := time.Now() - entry.Create("id", &now, &test.MockEntryMetaData{ + err := repo.Create(entry, &now, &test.MockEntryMetaData{ Str: "str", Number: 1, Date: now, }) - err := repo.Create(entry) + require.NoError(t, err) entry2 := &test.MockEntry{} now2 := time.Now() - entry2.Create("id2", &now2, &test.MockEntryMetaData{ - Str: "str2", - Number: 2, - Date: now2, + err = repo.Create(entry2, &now2, &test.MockEntryMetaData{ + Str: "str", + Number: 1, + Date: now, }) - err = repo.Create(entry2) require.NoError(t, err) entries, err := repo.FindAll(nil) @@ -106,25 +103,25 @@ func TestRepoUpdate(t *testing.T) { entry := &test.MockEntry{} now := time.Now() - entry.Create("id", &now, &test.MockEntryMetaData{ + err := repo.Create(entry, &now, &test.MockEntryMetaData{ Str: "str", Number: 1, Date: now, }) - err := repo.Create(entry) require.NoError(t, err) entry2 := &test.MockEntry{} now2 := time.Now() - entry2.Create("id", &now2, &test.MockEntryMetaData{ + err = repo.Create(entry2, &now2, &test.MockEntryMetaData{ Str: "str2", Number: 2, Date: now2, }) + require.NoError(t, err) err = repo.Update(entry2) require.NoError(t, err) - entry3, err := repo.FindById("id") + entry3, err := repo.FindById(entry2.ID()) require.NoError(t, err) require.Equal(t, entry3.Content(), entry2.Content()) require.Equal(t, entry3.PublishedAt().Unix(), entry2.PublishedAt().Unix()) diff --git a/web/editor/entity_form_test.go b/web/editor/entity_form_test.go index 050e402..68fd685 100644 --- a/web/editor/entity_form_test.go +++ b/web/editor/entity_form_test.go @@ -1,6 +1,7 @@ package editor_test import ( + "mime/multipart" "owl-blogs/domain/model" "owl-blogs/web/editor" "reflect" @@ -15,10 +16,21 @@ type MockEntryMetaData struct { Content string `owl:"inputType=text"` } +type MockFormData struct { +} + +func (f *MockFormData) FormFile(key string) (*multipart.FileHeader, error) { + return nil, nil +} + +func (f *MockFormData) FormValue(key string, defaultValue ...string) string { + return key +} + type MockEntry struct { id string publishedAt *time.Time - metaData *MockEntryMetaData + metaData MockEntryMetaData } func (e *MockEntry) ID() string { @@ -34,13 +46,13 @@ func (e *MockEntry) PublishedAt() *time.Time { } func (e *MockEntry) MetaData() interface{} { - return e.metaData + return &e.metaData } func (e *MockEntry) Create(id string, publishedAt *time.Time, metaData model.EntryMetaData) error { e.id = id e.publishedAt = publishedAt - e.metaData = metaData.(*MockEntryMetaData) + e.metaData = *metaData.(*MockEntryMetaData) return nil } @@ -63,13 +75,27 @@ func TestStructToFields(t *testing.T) { } func TestEditorEntryForm_HtmlForm(t *testing.T) { - formService := editor.NewEditorFormService(&MockEntry{}) - form, err := formService.HtmlForm() + form := editor.NewEntryForm(&MockEntry{}) + html, err := form.HtmlForm() require.NoError(t, err) - require.Contains(t, form, "") - require.Contains(t, form, "") - require.Contains(t, form, "") + require.Contains(t, html, "\n", s.Params.InputType, s.Name) + html := "" + html += fmt.Sprintf("\n", s.Name, s.Name) + if s.Params.InputType == "text" && s.Params.Widget == "textarea" { + html += fmt.Sprintf("\n", s.Name, s.Name) + } else { + html += fmt.Sprintf("\n", s.Params.InputType, s.Name, s.Name) + } + return html } func FieldToFormField(field reflect.StructField) (EntryFormField, error) { @@ -89,3 +112,28 @@ func (s *EditorEntryForm) HtmlForm() (string, error) { return html, nil } + +func (s *EditorEntryForm) Parse(ctx HttpFormData) (model.Entry, error) { + if ctx == nil { + return nil, fmt.Errorf("nil context") + } + meta := s.entry.MetaData() + metaVal := reflect.ValueOf(meta) + if metaVal.Kind() != reflect.Ptr { + return nil, fmt.Errorf("meta data is not a pointer") + } + fields, err := StructToFormFields(meta) + 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) + } + } + + return s.entry, nil +} diff --git a/web/editor_handler.go b/web/editor_handler.go index 8fbd363..d9bb198 100644 --- a/web/editor_handler.go +++ b/web/editor_handler.go @@ -4,6 +4,7 @@ import ( "owl-blogs/app" "owl-blogs/domain/model" "owl-blogs/web/editor" + "time" "github.com/gofiber/fiber/v2" ) @@ -18,15 +19,30 @@ func NewEditorHandler(entryService *app.EntryService) *EditorHandler { func (h *EditorHandler) HandleGet(c *fiber.Ctx) error { c.Set(fiber.HeaderContentType, fiber.MIMETextHTML) - formService := editor.NewEditorFormService(&model.ImageEntry{}) - form, err := formService.HtmlForm() + form := editor.NewEntryForm(&model.ImageEntry{}) + htmlForm, err := form.HtmlForm() if err != nil { return err } - return c.SendString(form) + return c.SendString(htmlForm) } func (h *EditorHandler) HandlePost(c *fiber.Ctx) error { c.Set(fiber.HeaderContentType, fiber.MIMETextHTML) + + form := editor.NewEntryForm(&model.ImageEntry{}) + // get form data + metaData, err := form.Parse(c) + if err != nil { + return err + } + + // create entry + now := time.Now() + err = h.entrySvc.Create(&model.ImageEntry{}, &now, metaData) + if err != nil { + return err + } + return c.SendString("Hello, Editor!") }