WIP site config + copy existing design

This commit is contained in:
Niko Abeler 2023-07-16 21:48:39 +02:00
parent 3a1559584c
commit cecd94b296
17 changed files with 201 additions and 69 deletions

View File

@ -4,7 +4,6 @@ import (
"crypto/sha256"
"fmt"
"owl-blogs/app/repository"
"owl-blogs/config"
"owl-blogs/domain/model"
"strings"
@ -13,11 +12,11 @@ import (
type AuthorService struct {
repo repository.AuthorRepository
config config.Config
siteConfigRepo repository.SiteConfigRepository
}
func NewAuthorService(repo repository.AuthorRepository, config config.Config) *AuthorService {
return &AuthorService{repo: repo, config: config}
func NewAuthorService(repo repository.AuthorRepository, siteConfigRepo repository.SiteConfigRepository) *AuthorService {
return &AuthorService{repo: repo, siteConfigRepo: siteConfigRepo}
}
func hashPassword(password string) (string, error) {
@ -50,7 +49,18 @@ func (s *AuthorService) Authenticate(name string, password string) bool {
}
func (s *AuthorService) getSecretKey() string {
return s.config.SECRET_KEY()
config, err := s.siteConfigRepo.Get()
if err != nil {
panic(err)
}
if config.Secret == "" {
config.Secret = RandStringRunes(64)
err = s.siteConfigRepo.Update(config)
if err != nil {
panic(err)
}
}
return config.Secret
}
func (s *AuthorService) CreateToken(name string) (string, error) {

View File

@ -2,6 +2,7 @@ package app_test
import (
"owl-blogs/app"
"owl-blogs/domain/model"
"owl-blogs/infra"
"owl-blogs/test"
"strings"
@ -10,17 +11,25 @@ import (
"github.com/stretchr/testify/require"
)
type testConfig struct {
type testConfigRepo struct {
config model.SiteConfig
}
func (c *testConfig) SECRET_KEY() string {
return "test"
// Get implements repository.SiteConfigRepository.
func (c *testConfigRepo) Get() (model.SiteConfig, error) {
return c.config, nil
}
// Update implements repository.SiteConfigRepository.
func (c *testConfigRepo) Update(siteConfig model.SiteConfig) error {
c.config = siteConfig
return nil
}
func getAutherService() *app.AuthorService {
db := test.NewMockDb()
authorRepo := infra.NewDefaultAuthorRepo(db)
authorService := app.NewAuthorService(authorRepo, &testConfig{})
authorService := app.NewAuthorService(authorRepo, &testConfigRepo{})
return authorService
}

15
app/utils.go Normal file
View File

@ -0,0 +1,15 @@
package app
import (
"math/rand"
)
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
func RandStringRunes(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = letterRunes[rand.Intn(len(letterRunes))]
}
return string(b)
}

View File

@ -9,7 +9,7 @@ import (
"net/http/httptest"
"os"
"owl-blogs/app"
"owl-blogs/domain/model"
entrytypes "owl-blogs/entry_types"
"owl-blogs/infra"
"owl-blogs/test"
"path"
@ -94,8 +94,8 @@ func TestEditorFormPost(t *testing.T) {
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.ImageMetaData).Content)
imageId := entry.MetaData().(*model.ImageMetaData).ImageId
require.Equal(t, "test content", entry.MetaData().(*entrytypes.ImageMetaData).Content)
imageId := entry.MetaData().(*entrytypes.ImageMetaData).ImageId
require.NotZero(t, imageId)
bin, err := binRepo.FindById(imageId)
require.NoError(t, err)

View File

@ -4,6 +4,7 @@ import (
"fmt"
"os"
"owl-blogs/domain/model"
entrytypes "owl-blogs/entry_types"
"owl-blogs/importer"
"owl-blogs/infra"
"path"
@ -49,7 +50,7 @@ var importCmd = &cobra.Command{
files := importer.ListDir(mediaDir)
for _, file := range files {
// mock entry to pass to binary service
entry := &model.Article{}
entry := &entrytypes.Article{}
entry.SetID(post.Id)
fileData, err := os.ReadFile(path.Join(mediaDir, file))
@ -63,10 +64,10 @@ var importCmd = &cobra.Command{
switch post.Meta.Type {
case "article":
entry = &model.Article{}
entry = &entrytypes.Article{}
entry.SetID(post.Id)
entry.SetPublishedAt(&post.Meta.Date)
entry.SetMetaData(&model.ArticleMetaData{
entry.SetMetaData(&entrytypes.ArticleMetaData{
Title: post.Meta.Title,
Content: post.Content,
})
@ -75,26 +76,26 @@ var importCmd = &cobra.Command{
case "reply":
case "photo":
entry = &model.Image{}
entry = &entrytypes.Image{}
entry.SetID(post.Id)
entry.SetPublishedAt(&post.Meta.Date)
entry.SetMetaData(&model.ImageMetaData{
entry.SetMetaData(&entrytypes.ImageMetaData{
Title: post.Meta.Title,
Content: post.Content,
ImageId: post.Meta.PhotoPath,
})
case "note":
entry = &model.Note{}
entry = &entrytypes.Note{}
entry.SetID(post.Id)
entry.SetPublishedAt(&post.Meta.Date)
entry.SetMetaData(&model.NoteMetaData{
entry.SetMetaData(&entrytypes.NoteMetaData{
Content: post.Content,
})
case "recipe":
entry = &model.Recipe{}
entry = &entrytypes.Recipe{}
entry.SetID(post.Id)
entry.SetPublishedAt(&post.Meta.Date)
entry.SetMetaData(&model.RecipeMetaData{
entry.SetMetaData(&entrytypes.RecipeMetaData{
Title: post.Meta.Title,
Yield: post.Meta.Recipe.Yield,
Duration: post.Meta.Recipe.Duration,
@ -102,10 +103,10 @@ var importCmd = &cobra.Command{
Content: post.Content,
})
case "page":
entry = &model.Page{}
entry = &entrytypes.Page{}
entry.SetID(post.Id)
entry.SetPublishedAt(&post.Meta.Date)
entry.SetMetaData(&model.PageMetaData{
entry.SetMetaData(&entrytypes.PageMetaData{
Title: post.Meta.Title,
Content: post.Content,
})

View File

@ -4,8 +4,7 @@ import (
"fmt"
"os"
"owl-blogs/app"
"owl-blogs/config"
"owl-blogs/domain/model"
entrytypes "owl-blogs/entry_types"
"owl-blogs/infra"
"owl-blogs/web"
@ -27,22 +26,21 @@ func Execute() {
}
func App(db infra.Database) *web.WebApp {
config := config.NewConfig()
registry := app.NewEntryTypeRegistry()
registry.Register(&model.Image{})
registry.Register(&model.Article{})
registry.Register(&model.Page{})
registry.Register(&model.Recipe{})
registry.Register(&model.Note{})
registry.Register(&entrytypes.Image{})
registry.Register(&entrytypes.Article{})
registry.Register(&entrytypes.Page{})
registry.Register(&entrytypes.Recipe{})
registry.Register(&entrytypes.Note{})
entryRepo := infra.NewEntryRepository(db, registry)
binRepo := infra.NewBinaryFileRepo(db)
authorRepo := infra.NewDefaultAuthorRepo(db)
siteConfigRepo := infra.NewSiteConfigRepo(db)
entryService := app.NewEntryService(entryRepo)
binaryService := app.NewBinaryFileService(binRepo)
authorService := app.NewAuthorService(authorRepo, config)
authorService := app.NewAuthorService(authorRepo, siteConfigRepo)
return web.NewWebApp(entryService, registry, binaryService, authorService)

View File

@ -3,11 +3,9 @@ package config
import "os"
type Config interface {
SECRET_KEY() string
}
type EnvConfig struct {
secretKey string
}
func getEnvOrPanic(key string) string {
@ -19,11 +17,5 @@ func getEnvOrPanic(key string) string {
}
func NewConfig() Config {
return &EnvConfig{
secretKey: getEnvOrPanic("OWL_SECRET_KEY"),
}
}
func (c *EnvConfig) SECRET_KEY() string {
return c.secretKey
return &EnvConfig{}
}

View File

@ -30,4 +30,5 @@ type SiteConfig struct {
HeaderMenu []MenuItem
FooterMenu []MenuItem
Secret string
AvatarUrl string
}

View File

@ -1,12 +1,13 @@
package model
package entrytypes
import (
"fmt"
"owl-blogs/domain/model"
"owl-blogs/render"
)
type Article struct {
EntryBase
model.EntryBase
meta ArticleMetaData
}
@ -19,12 +20,12 @@ func (e *Article) Title() string {
return e.meta.Title
}
func (e *Article) Content() EntryContent {
func (e *Article) Content() model.EntryContent {
str, err := render.RenderTemplateToString("entry/Article", e)
if err != nil {
fmt.Println(err)
}
return EntryContent(str)
return model.EntryContent(str)
}
func (e *Article) MetaData() interface{} {

View File

@ -1,12 +1,13 @@
package model
package entrytypes
import (
"fmt"
"owl-blogs/domain/model"
"owl-blogs/render"
)
type Image struct {
EntryBase
model.EntryBase
meta ImageMetaData
}
@ -20,12 +21,12 @@ func (e *Image) Title() string {
return e.meta.Title
}
func (e *Image) Content() EntryContent {
func (e *Image) Content() model.EntryContent {
str, err := render.RenderTemplateToString("entry/Image", e)
if err != nil {
fmt.Println(err)
}
return EntryContent(str)
return model.EntryContent(str)
}
func (e *Image) MetaData() interface{} {

View File

@ -1,7 +1,9 @@
package model
package entrytypes
import "owl-blogs/domain/model"
type Note struct {
EntryBase
model.EntryBase
meta NoteMetaData
}
@ -13,8 +15,8 @@ func (e *Note) Title() string {
return ""
}
func (e *Note) Content() EntryContent {
return EntryContent(e.meta.Content)
func (e *Note) Content() model.EntryContent {
return model.EntryContent(e.meta.Content)
}
func (e *Note) MetaData() interface{} {

View File

@ -1,12 +1,13 @@
package model
package entrytypes
import (
"fmt"
"owl-blogs/domain/model"
"owl-blogs/render"
)
type Page struct {
EntryBase
model.EntryBase
meta PageMetaData
}
@ -19,12 +20,12 @@ func (e *Page) Title() string {
return e.meta.Title
}
func (e *Page) Content() EntryContent {
func (e *Page) Content() model.EntryContent {
str, err := render.RenderTemplateToString("entry/Page", e)
if err != nil {
fmt.Println(err)
}
return EntryContent(str)
return model.EntryContent(str)
}
func (e *Page) MetaData() interface{} {

View File

@ -1,12 +1,13 @@
package model
package entrytypes
import (
"fmt"
"owl-blogs/domain/model"
"owl-blogs/render"
)
type Recipe struct {
EntryBase
model.EntryBase
meta RecipeMetaData
}
@ -22,12 +23,12 @@ func (e *Recipe) Title() string {
return e.meta.Title
}
func (e *Recipe) Content() EntryContent {
func (e *Recipe) Content() model.EntryContent {
str, err := render.RenderTemplateToString("entry/Recipe", e)
if err != nil {
fmt.Println(err)
}
return EntryContent(str)
return model.EntryContent(str)
}
func (e *Recipe) MetaData() interface{} {

View File

@ -4,6 +4,7 @@ import (
"bytes"
"embed"
"io"
"owl-blogs/domain/model"
"text/template"
"github.com/yuin/goldmark"
@ -12,6 +13,11 @@ import (
"github.com/yuin/goldmark/renderer/html"
)
type TemplateData struct {
Data interface{}
SiteConfig model.SiteConfig
}
//go:embed templates
var templates embed.FS
@ -42,7 +48,10 @@ func RenderTemplateWithBase(w io.Writer, templateName string, data interface{})
return err
}
err = t.ExecuteTemplate(w, "base", data)
err = t.ExecuteTemplate(w, "base", TemplateData{
Data: data,
SiteConfig: model.SiteConfig{},
})
return err

View File

@ -3,15 +3,94 @@
<html lang='en'>
<head>
<meta charset='utf-8'>
<title>{{template "title" .}} - Owl Blog</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{{template "title" .Data}} - {{ .SiteConfig.Title }}</title>
<meta property="og:title" content="{{template "title" .Data}}" />
<link rel='stylesheet' href='/static/pico.min.css'>
<style>
header {
background-color: {{.SiteConfig.HeaderColor}};
padding-bottom: 1rem !important;
}
footer {
border-top: dashed 2px;
border-color: #ccc;
}
.avatar {
float: left;
margin-right: 1rem;
}
.header {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
align-items: flex-start;
}
.header-title {
order: 0;
}
.header-profile {
order: 1;
}
hgroup h2 a { color: inherit; }
.photo-grid {
display: flex;
flex-wrap: wrap;
padding: 0 4px;
}
.photo-grid-item {
flex: 1 0 25%;
padding: 4px;
}
.photo-grid-item img {
width: 100%;
height: 100%;
aspect-ratio: 1 / 1 ;
object-fit: cover;
}
</style>
</head>
<body>
<header class="container">
<a href="/">Owl Blog</a>
<header>
<div class="container header h-card">
<hgroup class="header-title">
<h2><a class="p-name u-url" href="/">{{ .SiteConfig.Title }}</a></h2>
<h3 class="p-note">{{ .SiteConfig.SubTitle }}</h3>
</hgroup>
<div class="header-profile">
{{ if .SiteConfig.AvatarUrl }}
<img class="u-photo u-logo avatar" src="{{ .SiteConfig.AvatarUrl }}" alt="{{ .SiteConfig.Title }}" width="100" height="100" />
{{ end }}
<div style="float: right; list-style: none;">
{{ range $me := .SiteConfig.Me }}
<li><a href="{{$me.Url}}" rel="me">{{$me.Name}}</a>
</li>
{{ end }}
</div>
</div>
</div>
<div class="container">
<nav>
<ul>
</ul>
</nav>
</div>
</header>
<main class="container">
{{template "main" .}}
{{template "main" .Data}}
</main>
<footer class="container">
Powered by <a href='https://golang.org/'>Go</a>

View File

@ -0,0 +1,11 @@
{{define "title"}}Editor{{end}}
{{define "main"}}
<a href="/editor">Back</a>
<br>
<br>
{{.}}
{{end}}

View File

@ -3,6 +3,7 @@ package web
import (
"owl-blogs/app"
"owl-blogs/domain/model"
"owl-blogs/render"
"owl-blogs/web/editor"
"time"
@ -49,7 +50,7 @@ func (h *EditorHandler) HandleGet(c *fiber.Ctx) error {
if err != nil {
return err
}
return c.SendString(htmlForm)
return render.RenderTemplateWithBase(c, "views/editor", htmlForm)
}
func (h *EditorHandler) HandlePost(c *fiber.Ctx) error {