v2 #43
|
@ -0,0 +1,23 @@
|
||||||
|
package app_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"owl-blogs/app"
|
||||||
|
"owl-blogs/test"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRegistryTypeNameNotExisting(t *testing.T) {
|
||||||
|
register := app.NewEntryTypeRegistry()
|
||||||
|
_, err := register.TypeName(&test.MockEntry{})
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRegistryTypeName(t *testing.T) {
|
||||||
|
register := app.NewEntryTypeRegistry()
|
||||||
|
register.Register(&test.MockEntry{})
|
||||||
|
name, err := register.TypeName(&test.MockEntry{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "MockEntry", name)
|
||||||
|
}
|
|
@ -3,18 +3,34 @@ package main
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
|
"math/rand"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
|
"owl-blogs/domain/model"
|
||||||
|
"owl-blogs/infra"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func testDbName() string {
|
||||||
|
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
b := make([]rune, 6)
|
||||||
|
for i := range b {
|
||||||
|
b[i] = letterRunes[rand.Intn(len(letterRunes))]
|
||||||
|
}
|
||||||
|
return "/tmp/" + string(b) + ".db"
|
||||||
|
}
|
||||||
|
|
||||||
func TestEditorFormGet(t *testing.T) {
|
func TestEditorFormGet(t *testing.T) {
|
||||||
app := App().FiberApp
|
db := infra.NewSqliteDB(testDbName())
|
||||||
|
app := App(db).FiberApp
|
||||||
|
|
||||||
req := httptest.NewRequest("GET", "/editor/ImageEntry", nil)
|
req := httptest.NewRequest("GET", "/editor/ImageEntry", nil)
|
||||||
resp, err := app.Test(req)
|
resp, err := app.Test(req)
|
||||||
|
@ -23,7 +39,11 @@ func TestEditorFormGet(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEditorFormPost(t *testing.T) {
|
func TestEditorFormPost(t *testing.T) {
|
||||||
app := App().FiberApp
|
dbName := testDbName()
|
||||||
|
db := infra.NewSqliteDB(dbName)
|
||||||
|
owlApp := App(db)
|
||||||
|
app := owlApp.FiberApp
|
||||||
|
repo := infra.NewEntryRepository(db, owlApp.Registry)
|
||||||
|
|
||||||
fileDir, _ := os.Getwd()
|
fileDir, _ := os.Getwd()
|
||||||
fileName := "../../test/fixtures/test.png"
|
fileName := "../../test/fixtures/test.png"
|
||||||
|
@ -41,8 +61,17 @@ func TestEditorFormPost(t *testing.T) {
|
||||||
io.WriteString(part, "test content")
|
io.WriteString(part, "test content")
|
||||||
writer.Close()
|
writer.Close()
|
||||||
|
|
||||||
req := httptest.NewRequest("POST", "/editor/ImageEntry", nil)
|
req := httptest.NewRequest("POST", "/editor/ImageEntry", body)
|
||||||
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
resp, err := app.Test(req)
|
resp, err := app.Test(req)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 200, resp.StatusCode)
|
require.Equal(t, 302, resp.StatusCode)
|
||||||
|
require.Contains(t, resp.Header.Get("Location"), "/posts/")
|
||||||
|
|
||||||
|
id := strings.Split(resp.Header.Get("Location"), "/")[2]
|
||||||
|
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)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,9 @@ import (
|
||||||
"owl-blogs/web"
|
"owl-blogs/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
func App() *web.WebApp {
|
const DbPath = "owlblogs.db"
|
||||||
db := infra.NewSqliteDB("owlblogs.db")
|
|
||||||
|
func App(db infra.Database) *web.WebApp {
|
||||||
registry := app.NewEntryTypeRegistry()
|
registry := app.NewEntryTypeRegistry()
|
||||||
|
|
||||||
registry.Register(&model.ImageEntry{})
|
registry.Register(&model.ImageEntry{})
|
||||||
|
@ -20,5 +21,6 @@ func App() *web.WebApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
App().Run()
|
db := infra.NewSqliteDB(DbPath)
|
||||||
|
App(db).Run()
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@ type ImageEntry struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ImageEntryMetaData struct {
|
type ImageEntryMetaData struct {
|
||||||
ImagePath string `owl:"inputType=file"`
|
ImagePath string `owl:"inputType=file"`
|
||||||
Content EntryContent `owl:"inputType=text widget=textarea"`
|
Content string `owl:"inputType=text widget=textarea"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ImageEntry) ID() string {
|
func (e *ImageEntry) ID() string {
|
||||||
|
@ -18,7 +18,7 @@ func (e *ImageEntry) ID() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ImageEntry) Content() EntryContent {
|
func (e *ImageEntry) Content() EntryContent {
|
||||||
return e.meta.Content
|
return EntryContent(e.meta.Content)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ImageEntry) PublishedAt() *time.Time {
|
func (e *ImageEntry) PublishedAt() *time.Time {
|
||||||
|
@ -26,10 +26,7 @@ func (e *ImageEntry) PublishedAt() *time.Time {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ImageEntry) MetaData() interface{} {
|
func (e *ImageEntry) MetaData() interface{} {
|
||||||
return &ImageEntryMetaData{
|
return &e.meta
|
||||||
ImagePath: e.meta.ImagePath,
|
|
||||||
Content: e.meta.Content,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ImageEntry) Create(id string, publishedAt *time.Time, metaData EntryMetaData) error {
|
func (e *ImageEntry) Create(id string, publishedAt *time.Time, metaData EntryMetaData) error {
|
||||||
|
|
|
@ -8,7 +8,8 @@ import (
|
||||||
|
|
||||||
type WebApp struct {
|
type WebApp struct {
|
||||||
FiberApp *fiber.App
|
FiberApp *fiber.App
|
||||||
entryService *app.EntryService
|
EntryService *app.EntryService
|
||||||
|
Registry *app.EntryTypeRegistry
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWebApp(entryService *app.EntryService, typeRegistry *app.EntryTypeRegistry) *WebApp {
|
func NewWebApp(entryService *app.EntryService, typeRegistry *app.EntryTypeRegistry) *WebApp {
|
||||||
|
@ -16,7 +17,7 @@ func NewWebApp(entryService *app.EntryService, typeRegistry *app.EntryTypeRegist
|
||||||
|
|
||||||
indexHandler := NewIndexHandler(entryService)
|
indexHandler := NewIndexHandler(entryService)
|
||||||
listHandler := NewListHandler(entryService)
|
listHandler := NewListHandler(entryService)
|
||||||
entryHandler := NewEntryHandler(entryService)
|
entryHandler := NewEntryHandler(entryService, typeRegistry)
|
||||||
mediaHandler := NewMediaHandler(entryService)
|
mediaHandler := NewMediaHandler(entryService)
|
||||||
rssHandler := NewRSSHandler(entryService)
|
rssHandler := NewRSSHandler(entryService)
|
||||||
loginHandler := NewLoginHandler(entryService)
|
loginHandler := NewLoginHandler(entryService)
|
||||||
|
@ -50,7 +51,7 @@ func NewWebApp(entryService *app.EntryService, typeRegistry *app.EntryTypeRegist
|
||||||
// app.Post("/auth/token/", userAuthTokenHandler(repo))
|
// app.Post("/auth/token/", userAuthTokenHandler(repo))
|
||||||
// app.Get("/.well-known/oauth-authorization-server", userAuthMetadataHandler(repo))
|
// app.Get("/.well-known/oauth-authorization-server", userAuthMetadataHandler(repo))
|
||||||
// app.NotFound = http.HandlerFunc(notFoundHandler(repo))
|
// app.NotFound = http.HandlerFunc(notFoundHandler(repo))
|
||||||
return &WebApp{FiberApp: app, entryService: entryService}
|
return &WebApp{FiberApp: app, EntryService: entryService, Registry: typeRegistry}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WebApp) Run() {
|
func (w *WebApp) Run() {
|
||||||
|
|
|
@ -53,18 +53,17 @@ func (h *EditorHandler) HandlePost(c *fiber.Ctx) error {
|
||||||
|
|
||||||
form := editor.NewEntryForm(entryType)
|
form := editor.NewEntryForm(entryType)
|
||||||
// get form data
|
// get form data
|
||||||
metaData, err := form.Parse(c)
|
entry, err := form.Parse(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// create entry
|
// create entry
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
entry := entryType
|
err = h.entrySvc.Create(entry, &now, entry.MetaData())
|
||||||
err = h.entrySvc.Create(entry, &now, metaData.MetaData())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
return c.Redirect("/posts/" + entry.ID() + "/")
|
||||||
|
|
||||||
return c.SendString("Hello, Editor!")
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,18 +2,46 @@ package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"owl-blogs/app"
|
"owl-blogs/app"
|
||||||
|
"owl-blogs/domain/model"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type EntryHandler struct {
|
type EntryHandler struct {
|
||||||
entrySvc *app.EntryService
|
entrySvc *app.EntryService
|
||||||
|
registry *app.EntryTypeRegistry
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEntryHandler(entryService *app.EntryService) *EntryHandler {
|
func NewEntryHandler(entryService *app.EntryService, registry *app.EntryTypeRegistry) *EntryHandler {
|
||||||
return &EntryHandler{entrySvc: entryService}
|
return &EntryHandler{entrySvc: entryService, registry: registry}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *EntryHandler) getTemplate(entry model.Entry) (*template.Template, error) {
|
||||||
|
name, err := h.registry.TypeName(entry)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return template.ParseFS(
|
||||||
|
templates,
|
||||||
|
"templates/base.tmpl",
|
||||||
|
"templates/views/entry/"+name+".tmpl",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *EntryHandler) Handle(c *fiber.Ctx) error {
|
func (h *EntryHandler) Handle(c *fiber.Ctx) error {
|
||||||
return c.SendString("Hello, RSS!")
|
c.Set(fiber.HeaderContentType, fiber.MIMETextHTML)
|
||||||
|
|
||||||
|
entryId := c.Params("post")
|
||||||
|
entry, err := h.entrySvc.FindById(entryId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
template, err := h.getTemplate(entry)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return template.ExecuteTemplate(c, "base", entry)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
{{define "title"}}Image Entry{{end}}
|
||||||
|
|
||||||
|
{{define "main"}}
|
||||||
|
|
||||||
|
{{.MetaData.ImagePath}}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{{.Content}}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Published: {{.PublishedAt}}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
{{end}}
|
||||||
|
|
Loading…
Reference in New Issue