diff --git a/cmd/owl/editor_test.go b/cmd/owl/editor_test.go new file mode 100644 index 0000000..a7735a5 --- /dev/null +++ b/cmd/owl/editor_test.go @@ -0,0 +1,48 @@ +package main + +import ( + "bytes" + "io" + "mime/multipart" + "net/http/httptest" + "os" + "path" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestEditorFormGet(t *testing.T) { + app := App().FiberApp + + req := httptest.NewRequest("GET", "/editor/ImageEntry", nil) + resp, err := app.Test(req) + require.NoError(t, err) + require.Equal(t, 200, resp.StatusCode) +} + +func TestEditorFormPost(t *testing.T) { + app := App().FiberApp + + fileDir, _ := os.Getwd() + fileName := "../../test/fixtures/test.png" + filePath := path.Join(fileDir, fileName) + + file, err := os.Open(filePath) + require.NoError(t, err) + defer file.Close() + + body := &bytes.Buffer{} + writer := multipart.NewWriter(body) + part, _ := writer.CreateFormFile("ImagePath", filepath.Base(file.Name())) + io.Copy(part, file) + part, _ = writer.CreateFormField("Content") + io.WriteString(part, "test content") + writer.Close() + + req := httptest.NewRequest("POST", "/editor/ImageEntry", nil) + resp, err := app.Test(req) + require.NoError(t, err) + require.Equal(t, 200, resp.StatusCode) +} diff --git a/main.go b/cmd/owl/main.go similarity index 79% rename from main.go rename to cmd/owl/main.go index 6cb60bc..22ae34d 100644 --- a/main.go +++ b/cmd/owl/main.go @@ -7,7 +7,7 @@ import ( "owl-blogs/web" ) -func main() { +func App() *web.WebApp { db := infra.NewSqliteDB("owlblogs.db") registry := app.NewEntryTypeRegistry() @@ -15,6 +15,10 @@ func main() { repo := infra.NewEntryRepository(db, registry) entryService := app.NewEntryService(repo) - webApp := web.NewWebApp(entryService) - webApp.Run() + return web.NewWebApp(entryService, registry) + +} + +func main() { + App().Run() } diff --git a/test/fixtures/test.png b/test/fixtures/test.png new file mode 100644 index 0000000..fb234fd Binary files /dev/null and b/test/fixtures/test.png differ diff --git a/web/app.go b/web/app.go index 6e29301..dd08d47 100644 --- a/web/app.go +++ b/web/app.go @@ -7,11 +7,11 @@ import ( ) type WebApp struct { - app *fiber.App + FiberApp *fiber.App entryService *app.EntryService } -func NewWebApp(entryService *app.EntryService) *WebApp { +func NewWebApp(entryService *app.EntryService, typeRegistry *app.EntryTypeRegistry) *WebApp { app := fiber.New() indexHandler := NewIndexHandler(entryService) @@ -20,7 +20,8 @@ func NewWebApp(entryService *app.EntryService) *WebApp { mediaHandler := NewMediaHandler(entryService) rssHandler := NewRSSHandler(entryService) loginHandler := NewLoginHandler(entryService) - editorHandler := NewEditorHandler(entryService) + editorListHandler := NewEditorListHandler(typeRegistry) + editorHandler := NewEditorHandler(entryService, typeRegistry) // app.ServeFiles("/static/*filepath", http.Dir(repo.StaticDir())) app.Get("/", indexHandler.Handle) @@ -28,8 +29,9 @@ func NewWebApp(entryService *app.EntryService) *WebApp { // Editor app.Get("/editor/auth/", loginHandler.HandleGet) app.Post("/editor/auth/", loginHandler.HandlePost) - app.Get("/editor/", editorHandler.HandleGet) - app.Post("/editor/", editorHandler.HandlePost) + app.Get("/editor/", editorListHandler.Handle) + app.Get("/editor/:editor/", editorHandler.HandleGet) + app.Post("/editor/:editor/", editorHandler.HandlePost) // Media app.Get("/media/*filepath", mediaHandler.Handle) // RSS @@ -48,9 +50,9 @@ func NewWebApp(entryService *app.EntryService) *WebApp { // app.Post("/auth/token/", userAuthTokenHandler(repo)) // app.Get("/.well-known/oauth-authorization-server", userAuthMetadataHandler(repo)) // app.NotFound = http.HandlerFunc(notFoundHandler(repo)) - return &WebApp{app: app, entryService: entryService} + return &WebApp{FiberApp: app, entryService: entryService} } func (w *WebApp) Run() { - w.app.Listen(":3000") + w.FiberApp.Listen(":3000") } diff --git a/web/editor_handler.go b/web/editor_handler.go index 47ec8e1..b80675c 100644 --- a/web/editor_handler.go +++ b/web/editor_handler.go @@ -11,15 +11,31 @@ import ( type EditorHandler struct { entrySvc *app.EntryService + registry *app.EntryTypeRegistry } -func NewEditorHandler(entryService *app.EntryService) *EditorHandler { - return &EditorHandler{entrySvc: entryService} +func NewEditorHandler(entryService *app.EntryService, registry *app.EntryTypeRegistry) *EditorHandler { + return &EditorHandler{entrySvc: entryService, registry: registry} +} + +func (h *EditorHandler) paramToEntry(c *fiber.Ctx) (model.Entry, error) { + typeName := c.Params("editor") + entryType, err := h.registry.Type(typeName) + if err != nil { + return nil, err + } + return entryType, nil } func (h *EditorHandler) HandleGet(c *fiber.Ctx) error { c.Set(fiber.HeaderContentType, fiber.MIMETextHTML) - form := editor.NewEntryForm(&model.ImageEntry{}) + + entryType, err := h.paramToEntry(c) + if err != nil { + return err + } + + form := editor.NewEntryForm(entryType) htmlForm, err := form.HtmlForm() if err != nil { return err @@ -30,7 +46,12 @@ func (h *EditorHandler) HandleGet(c *fiber.Ctx) error { func (h *EditorHandler) HandlePost(c *fiber.Ctx) error { c.Set(fiber.HeaderContentType, fiber.MIMETextHTML) - form := editor.NewEntryForm(&model.ImageEntry{}) + entryType, err := h.paramToEntry(c) + if err != nil { + return err + } + + form := editor.NewEntryForm(entryType) // get form data metaData, err := form.Parse(c) if err != nil { @@ -39,7 +60,7 @@ func (h *EditorHandler) HandlePost(c *fiber.Ctx) error { // create entry now := time.Now() - entry := &model.ImageEntry{} + entry := entryType err = h.entrySvc.Create(entry, &now, metaData.MetaData()) if err != nil { return err diff --git a/web/editor_list_handler.go b/web/editor_list_handler.go new file mode 100644 index 0000000..feafe33 --- /dev/null +++ b/web/editor_list_handler.go @@ -0,0 +1,53 @@ +package web + +import ( + "embed" + "owl-blogs/app" + "text/template" + + "github.com/gofiber/fiber/v2" +) + +//go:embed templates +var templates embed.FS + +type EditorListHandler struct { + registry *app.EntryTypeRegistry + ts *template.Template +} + +type EditorListContext struct { + Types []string +} + +func NewEditorListHandler(registry *app.EntryTypeRegistry) *EditorListHandler { + ts, err := template.ParseFS( + templates, + "templates/base.tmpl", + "templates/views/editor_list.tmpl", + ) + + if err != nil { + panic(err) + } + + return &EditorListHandler{ + registry: registry, + ts: ts, + } + +} + +func (h *EditorListHandler) Handle(c *fiber.Ctx) error { + c.Set(fiber.HeaderContentType, fiber.MIMETextHTML) + + types := h.registry.Types() + typeNames := []string{} + + for _, t := range types { + name, _ := h.registry.TypeName(t) + typeNames = append(typeNames, name) + } + + return h.ts.ExecuteTemplate(c, "base", &EditorListContext{Types: typeNames}) +} diff --git a/web/templates/base.tmpl b/web/templates/base.tmpl new file mode 100644 index 0000000..8e3b572 --- /dev/null +++ b/web/templates/base.tmpl @@ -0,0 +1,18 @@ +{{define "base"}} + + + + + {{template "title" .}} - Owl Blog + + +
+ Owl Blog +
+
+ {{template "main" .}} +
+ + + +{{end}} \ No newline at end of file diff --git a/web/templates/views/editor_list.tmpl b/web/templates/views/editor_list.tmpl new file mode 100644 index 0000000..4af68b6 --- /dev/null +++ b/web/templates/views/editor_list.tmpl @@ -0,0 +1,12 @@ +{{define "title"}}Editor List{{end}} + +{{define "main"}} + +

Editor List

+ +