v2 #43
|
@ -0,0 +1,29 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"owl-blogs/infra"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var user string
|
||||||
|
var password string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(newAuthorCmd)
|
||||||
|
|
||||||
|
newAuthorCmd.Flags().StringVarP(&user, "user", "u", "", "The user name")
|
||||||
|
newAuthorCmd.MarkFlagRequired("user")
|
||||||
|
newAuthorCmd.Flags().StringVarP(&password, "password", "p", "", "The password")
|
||||||
|
newAuthorCmd.MarkFlagRequired("password")
|
||||||
|
}
|
||||||
|
|
||||||
|
var newAuthorCmd = &cobra.Command{
|
||||||
|
Use: "new-author",
|
||||||
|
Short: "Creates a new author",
|
||||||
|
Long: `Creates a new author`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
db := infra.NewSqliteDB(DbPath)
|
||||||
|
App(db).AuthorService.Create(user, password)
|
||||||
|
},
|
||||||
|
}
|
|
@ -1,15 +1,31 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
"owl-blogs/app"
|
"owl-blogs/app"
|
||||||
"owl-blogs/config"
|
"owl-blogs/config"
|
||||||
"owl-blogs/domain/model"
|
"owl-blogs/domain/model"
|
||||||
"owl-blogs/infra"
|
"owl-blogs/infra"
|
||||||
"owl-blogs/web"
|
"owl-blogs/web"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
const DbPath = "owlblogs.db"
|
const DbPath = "owlblogs.db"
|
||||||
|
|
||||||
|
var rootCmd = &cobra.Command{
|
||||||
|
Use: "owl",
|
||||||
|
Short: "Owl Blogs is a not so static blog generator",
|
||||||
|
}
|
||||||
|
|
||||||
|
func Execute() {
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func App(db infra.Database) *web.WebApp {
|
func App(db infra.Database) *web.WebApp {
|
||||||
config := config.NewConfig()
|
config := config.NewConfig()
|
||||||
|
|
||||||
|
@ -29,6 +45,5 @@ func App(db infra.Database) *web.WebApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
db := infra.NewSqliteDB(DbPath)
|
Execute()
|
||||||
App(db).Run()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"owl-blogs/infra"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(webCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
var webCmd = &cobra.Command{
|
||||||
|
Use: "web",
|
||||||
|
Short: "Start the web server",
|
||||||
|
Long: `Start the web server`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
db := infra.NewSqliteDB(DbPath)
|
||||||
|
App(db).Run()
|
||||||
|
},
|
||||||
|
}
|
3
go.mod
3
go.mod
|
@ -7,6 +7,7 @@ require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/gofiber/fiber/v2 v2.47.0 // indirect
|
github.com/gofiber/fiber/v2 v2.47.0 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jmoiron/sqlx v1.3.5 // indirect
|
github.com/jmoiron/sqlx v1.3.5 // indirect
|
||||||
github.com/klauspost/compress v1.16.3 // indirect
|
github.com/klauspost/compress v1.16.3 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
|
@ -18,6 +19,8 @@ require (
|
||||||
github.com/rivo/uniseg v0.2.0 // indirect
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect
|
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect
|
||||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
|
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
|
||||||
|
github.com/spf13/cobra v1.7.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/stretchr/objx v0.5.0 // indirect
|
github.com/stretchr/objx v0.5.0 // indirect
|
||||||
github.com/stretchr/testify v1.8.4 // indirect
|
github.com/stretchr/testify v1.8.4 // indirect
|
||||||
github.com/tinylib/msgp v1.1.8 // indirect
|
github.com/tinylib/msgp v1.1.8 // indirect
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -1,5 +1,6 @@
|
||||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
@ -8,6 +9,8 @@ github.com/gofiber/fiber/v2 v2.47.0 h1:EN5lHVCc+Pyqh5OEsk8fzRiifgwpbrP0rulQ4iNf3
|
||||||
github.com/gofiber/fiber/v2 v2.47.0/go.mod h1:mbFMVN1lQuzziTkkakgtKKdjfsXSw9BKR5lmcNksUoU=
|
github.com/gofiber/fiber/v2 v2.47.0/go.mod h1:mbFMVN1lQuzziTkkakgtKKdjfsXSw9BKR5lmcNksUoU=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
|
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
|
||||||
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
|
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
|
||||||
github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY=
|
github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY=
|
||||||
|
@ -30,11 +33,16 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 h1:rmMl4fXJhKMNWl+K+r/fq4FbbKI+Ia2m9hYBLm2h4G4=
|
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 h1:rmMl4fXJhKMNWl+K+r/fq4FbbKI+Ia2m9hYBLm2h4G4=
|
||||||
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94/go.mod h1:90zrgN3D/WJsDd1iXHT96alCoN2KJo6/4x1DZC3wZs8=
|
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94/go.mod h1:90zrgN3D/WJsDd1iXHT96alCoN2KJo6/4x1DZC3wZs8=
|
||||||
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4=
|
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4=
|
||||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
|
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
|
||||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
|
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
|
||||||
|
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||||
|
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||||
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
OWL_SECRET_KEY=test-secret-key \
|
||||||
|
go run owl-blogs/cmd/owl web
|
|
@ -28,7 +28,7 @@ func NewWebApp(
|
||||||
entryHandler := NewEntryHandler(entryService, typeRegistry)
|
entryHandler := NewEntryHandler(entryService, typeRegistry)
|
||||||
mediaHandler := NewMediaHandler(entryService)
|
mediaHandler := NewMediaHandler(entryService)
|
||||||
rssHandler := NewRSSHandler(entryService)
|
rssHandler := NewRSSHandler(entryService)
|
||||||
loginHandler := NewLoginHandler(entryService)
|
loginHandler := NewLoginHandler(authorService)
|
||||||
editorListHandler := NewEditorListHandler(typeRegistry)
|
editorListHandler := NewEditorListHandler(typeRegistry)
|
||||||
editorHandler := NewEditorHandler(entryService, typeRegistry, binService)
|
editorHandler := NewEditorHandler(entryService, typeRegistry, binService)
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,13 @@
|
||||||
package web
|
package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
|
||||||
"owl-blogs/app"
|
"owl-blogs/app"
|
||||||
"text/template"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed templates
|
|
||||||
var templates embed.FS
|
|
||||||
|
|
||||||
type EditorListHandler struct {
|
type EditorListHandler struct {
|
||||||
registry *app.EntryTypeRegistry
|
registry *app.EntryTypeRegistry
|
||||||
ts *template.Template
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type EditorListContext struct {
|
type EditorListContext struct {
|
||||||
|
@ -21,19 +15,8 @@ type EditorListContext struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEditorListHandler(registry *app.EntryTypeRegistry) *EditorListHandler {
|
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{
|
return &EditorListHandler{
|
||||||
registry: registry,
|
registry: registry,
|
||||||
ts: ts,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -49,5 +32,5 @@ func (h *EditorListHandler) Handle(c *fiber.Ctx) error {
|
||||||
typeNames = append(typeNames, name)
|
typeNames = append(typeNames, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return h.ts.ExecuteTemplate(c, "base", &EditorListContext{Types: typeNames})
|
return RenderTemplate(c, "views/editor_list", &EditorListContext{Types: typeNames})
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,22 +2,47 @@ package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"owl-blogs/app"
|
"owl-blogs/app"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LoginHandler struct {
|
type LoginHandler struct {
|
||||||
entrySvc *app.EntryService
|
authorService *app.AuthorService
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLoginHandler(entryService *app.EntryService) *LoginHandler {
|
func NewLoginHandler(authorService *app.AuthorService) *LoginHandler {
|
||||||
return &LoginHandler{entrySvc: entryService}
|
return &LoginHandler{authorService: authorService}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *LoginHandler) HandleGet(c *fiber.Ctx) error {
|
func (h *LoginHandler) HandleGet(c *fiber.Ctx) error {
|
||||||
return c.SendString("Hello, Login!")
|
c.Set(fiber.HeaderContentType, fiber.MIMETextHTML)
|
||||||
|
return RenderTemplate(c, "views/login", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *LoginHandler) HandlePost(c *fiber.Ctx) error {
|
func (h *LoginHandler) HandlePost(c *fiber.Ctx) error {
|
||||||
return c.SendString("Hello, Login!")
|
c.Set(fiber.HeaderContentType, fiber.MIMETextHTML)
|
||||||
|
name := c.FormValue("name")
|
||||||
|
password := c.FormValue("password")
|
||||||
|
|
||||||
|
valid := h.authorService.Authenticate(name, password)
|
||||||
|
if !valid {
|
||||||
|
return c.Redirect("/auth/login")
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := h.authorService.CreateToken(name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cookie := fiber.Cookie{
|
||||||
|
Name: "token",
|
||||||
|
Value: token,
|
||||||
|
Expires: time.Now().Add(30 * 24 * time.Hour),
|
||||||
|
HTTPOnly: true,
|
||||||
|
}
|
||||||
|
c.Cookie(&cookie)
|
||||||
|
|
||||||
|
return c.Redirect("/editor/")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package web
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
"io"
|
||||||
|
"text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed templates
|
||||||
|
var templates embed.FS
|
||||||
|
|
||||||
|
func CreateTemplate(templateName string) (*template.Template, error) {
|
||||||
|
|
||||||
|
return template.ParseFS(
|
||||||
|
templates,
|
||||||
|
"templates/base.tmpl",
|
||||||
|
"templates/"+templateName+".tmpl",
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func RenderTemplate(w io.Writer, templateName string, data interface{}) error {
|
||||||
|
|
||||||
|
t, err := CreateTemplate(templateName)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = t.ExecuteTemplate(w, "base", data)
|
||||||
|
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
{{define "title"}}Editor List{{end}}
|
||||||
|
|
||||||
|
{{define "main"}}
|
||||||
|
|
||||||
|
<h1>Login</h1>
|
||||||
|
|
||||||
|
<form action="" method="post">
|
||||||
|
<label for="name">Username</label>
|
||||||
|
<input id="name" name="name" type="text" placeholder="Username">
|
||||||
|
|
||||||
|
<label for="password">Password</label>
|
||||||
|
<input id="password" name="password" type="password" placeholder="Password">
|
||||||
|
|
||||||
|
<input type="submit" value="Login">
|
||||||
|
</form>
|
||||||
|
{{end}}
|
Loading…
Reference in New Issue