v2 #43
|
@ -0,0 +1,22 @@
|
||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"owl-blogs/app/repository"
|
||||||
|
"owl-blogs/domain/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BinaryService struct {
|
||||||
|
repo repository.BinaryRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBinaryFileService(repo repository.BinaryRepository) *BinaryService {
|
||||||
|
return &BinaryService{repo: repo}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BinaryService) Create(name string, file []byte) (*model.BinaryFile, error) {
|
||||||
|
return s.repo.Create(name, file)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BinaryService) FindById(id string) (*model.BinaryFile, error) {
|
||||||
|
return s.repo.FindById(id)
|
||||||
|
}
|
|
@ -47,5 +47,12 @@ func (r *EntryTypeRegistry) Type(name string) (model.Entry, error) {
|
||||||
if _, ok := r.types[name]; !ok {
|
if _, ok := r.types[name]; !ok {
|
||||||
return nil, errors.New("entry type not registered")
|
return nil, errors.New("entry type not registered")
|
||||||
}
|
}
|
||||||
return r.types[name], nil
|
|
||||||
|
val := reflect.ValueOf(r.types[name])
|
||||||
|
if val.Kind() == reflect.Ptr {
|
||||||
|
val = reflect.Indirect(val)
|
||||||
|
}
|
||||||
|
newEntry := reflect.New(val.Type()).Interface().(model.Entry)
|
||||||
|
|
||||||
|
return newEntry, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,3 +12,8 @@ type EntryRepository interface {
|
||||||
FindById(id string) (model.Entry, error)
|
FindById(id string) (model.Entry, error)
|
||||||
FindAll(types *[]string) ([]model.Entry, error)
|
FindAll(types *[]string) ([]model.Entry, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BinaryRepository interface {
|
||||||
|
Create(name string, data []byte) (*model.BinaryFile, error)
|
||||||
|
FindById(id string) (*model.BinaryFile, error)
|
||||||
|
}
|
||||||
|
|
|
@ -14,9 +14,12 @@ func App(db infra.Database) *web.WebApp {
|
||||||
|
|
||||||
registry.Register(&model.ImageEntry{})
|
registry.Register(&model.ImageEntry{})
|
||||||
|
|
||||||
repo := infra.NewEntryRepository(db, registry)
|
entryRepo := infra.NewEntryRepository(db, registry)
|
||||||
entryService := app.NewEntryService(repo)
|
binRepo := infra.NewBinaryFileRepo(db)
|
||||||
return web.NewWebApp(entryService, registry)
|
|
||||||
|
entryService := app.NewEntryService(entryRepo)
|
||||||
|
binaryService := app.NewBinaryFileService(binRepo)
|
||||||
|
return web.NewWebApp(entryService, registry, binaryService)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
type BinaryFile struct {
|
||||||
|
Id string
|
||||||
|
Name string
|
||||||
|
Data []byte
|
||||||
|
}
|
|
@ -9,8 +9,8 @@ type ImageEntry struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ImageEntryMetaData struct {
|
type ImageEntryMetaData struct {
|
||||||
ImagePath string `owl:"inputType=file"`
|
ImageId string `owl:"inputType=file"`
|
||||||
Content string `owl:"inputType=text widget=textarea"`
|
Content string `owl:"inputType=text widget=textarea"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ImageEntry) ID() string {
|
func (e *ImageEntry) ID() string {
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
package infra
|
||||||
|
|
||||||
|
import (
|
||||||
|
"owl-blogs/domain/model"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type sqlBinaryFile struct {
|
||||||
|
Id string `db:"id"`
|
||||||
|
Name string `db:"name"`
|
||||||
|
Data []byte `db:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultBinaryFileRepo struct {
|
||||||
|
db *sqlx.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBinaryFileRepo(db Database) *DefaultBinaryFileRepo {
|
||||||
|
sqlxdb := db.Get()
|
||||||
|
|
||||||
|
// Create table if not exists
|
||||||
|
sqlxdb.MustExec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS binary_files (
|
||||||
|
id VARCHAR(255) PRIMARY KEY,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
data BLOB NOT NULL
|
||||||
|
);
|
||||||
|
`)
|
||||||
|
|
||||||
|
return &DefaultBinaryFileRepo{db: sqlxdb}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *DefaultBinaryFileRepo) Create(name string, data []byte) (*model.BinaryFile, error) {
|
||||||
|
id := uuid.New().String()
|
||||||
|
_, err := repo.db.Exec("INSERT INTO binary_files (id, name, data) VALUES (?, ?, ?)", id, name, data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &model.BinaryFile{Id: id, Name: name, Data: data}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *DefaultBinaryFileRepo) FindById(id string) (*model.BinaryFile, error) {
|
||||||
|
var sqlFile sqlBinaryFile
|
||||||
|
err := repo.db.Get(&sqlFile, "SELECT * FROM binary_files WHERE id = ?", id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &model.BinaryFile{Id: sqlFile.Id, Name: sqlFile.Name, Data: sqlFile.Data}, nil
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
package infra_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"owl-blogs/app/repository"
|
||||||
|
"owl-blogs/infra"
|
||||||
|
"owl-blogs/test"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setupBinaryRepo() repository.BinaryRepository {
|
||||||
|
db := test.NewMockDb()
|
||||||
|
repo := infra.NewBinaryFileRepo(db)
|
||||||
|
return repo
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBinaryRepoCreate(t *testing.T) {
|
||||||
|
repo := setupBinaryRepo()
|
||||||
|
|
||||||
|
file, err := repo.Create("name", []byte("😀 😃 😄 😁"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
file, err = repo.FindById(file.Id)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, file.Name, "name")
|
||||||
|
require.Equal(t, file.Data, []byte("😀 😃 😄 😁"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBinaryRepoNoSideEffect(t *testing.T) {
|
||||||
|
repo := setupBinaryRepo()
|
||||||
|
|
||||||
|
file, err := repo.Create("name1", []byte("111"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
file2, err := repo.Create("name2", []byte("222"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
file, err = repo.FindById(file.Id)
|
||||||
|
require.NoError(t, err)
|
||||||
|
file2, err = repo.FindById(file2.Id)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, file.Name, "name1")
|
||||||
|
require.Equal(t, file.Data, []byte("111"))
|
||||||
|
require.Equal(t, file2.Name, "name2")
|
||||||
|
require.Equal(t, file2.Data, []byte("222"))
|
||||||
|
}
|
|
@ -131,3 +131,39 @@ func TestRepoUpdate(t *testing.T) {
|
||||||
require.Equal(t, meta.Number, meta2.Number)
|
require.Equal(t, meta.Number, meta2.Number)
|
||||||
require.Equal(t, meta.Date.Unix(), meta2.Date.Unix())
|
require.Equal(t, meta.Date.Unix(), meta2.Date.Unix())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRepoNoSideEffect(t *testing.T) {
|
||||||
|
repo := setupRepo()
|
||||||
|
|
||||||
|
entry1 := &test.MockEntry{}
|
||||||
|
now1 := time.Now()
|
||||||
|
err := repo.Create(entry1, &now1, &test.MockEntryMetaData{
|
||||||
|
Str: "1",
|
||||||
|
Number: 1,
|
||||||
|
Date: now1,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
entry2 := &test.MockEntry{}
|
||||||
|
now2 := time.Now()
|
||||||
|
err = repo.Create(entry2, &now2, &test.MockEntryMetaData{
|
||||||
|
Str: "2",
|
||||||
|
Number: 2,
|
||||||
|
Date: now2,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
r1, err := repo.FindById(entry1.ID())
|
||||||
|
require.NoError(t, err)
|
||||||
|
r2, err := repo.FindById(entry2.ID())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, r1.MetaData().(*test.MockEntryMetaData).Str, "1")
|
||||||
|
require.Equal(t, r1.MetaData().(*test.MockEntryMetaData).Number, 1)
|
||||||
|
require.Equal(t, r1.MetaData().(*test.MockEntryMetaData).Date.Unix(), now1.Unix())
|
||||||
|
|
||||||
|
require.Equal(t, r2.MetaData().(*test.MockEntryMetaData).Str, "2")
|
||||||
|
require.Equal(t, r2.MetaData().(*test.MockEntryMetaData).Number, 2)
|
||||||
|
require.Equal(t, r2.MetaData().(*test.MockEntryMetaData).Date.Unix(), now2.Unix())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
16
web/app.go
16
web/app.go
|
@ -7,12 +7,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebApp struct {
|
type WebApp struct {
|
||||||
FiberApp *fiber.App
|
FiberApp *fiber.App
|
||||||
EntryService *app.EntryService
|
EntryService *app.EntryService
|
||||||
Registry *app.EntryTypeRegistry
|
BinaryService *app.BinaryService
|
||||||
|
Registry *app.EntryTypeRegistry
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWebApp(entryService *app.EntryService, typeRegistry *app.EntryTypeRegistry) *WebApp {
|
func NewWebApp(entryService *app.EntryService, typeRegistry *app.EntryTypeRegistry, binService *app.BinaryService) *WebApp {
|
||||||
app := fiber.New()
|
app := fiber.New()
|
||||||
|
|
||||||
indexHandler := NewIndexHandler(entryService)
|
indexHandler := NewIndexHandler(entryService)
|
||||||
|
@ -51,7 +52,12 @@ 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, Registry: typeRegistry}
|
return &WebApp{
|
||||||
|
FiberApp: app,
|
||||||
|
EntryService: entryService,
|
||||||
|
Registry: typeRegistry,
|
||||||
|
BinaryService: binService,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WebApp) Run() {
|
func (w *WebApp) Run() {
|
||||||
|
|
Loading…
Reference in New Issue