Merge branch 'master' of ssh://git.libove.org:222/h4kor/owl-blogs
This commit is contained in:
commit
0b3ae3bea1
|
@ -95,14 +95,14 @@ func postHandler(repo *owl.Repository) func(http.ResponseWriter, *http.Request,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, meta := post.MarkdownData()
|
meta := post.Meta()
|
||||||
if meta.Draft {
|
if meta.Draft {
|
||||||
println("Post is a draft")
|
println("Post is a draft")
|
||||||
notFoundHandler(repo)(w, r)
|
notFoundHandler(repo)(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
html, err := owl.RenderPost(post)
|
html, err := owl.RenderPost(&post)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println("Error rendering post: ", err.Error())
|
println("Error rendering post: ", err.Error())
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
|
|
@ -1,7 +1,16 @@
|
||||||
<div class="h-feed">
|
<div class="h-feed">
|
||||||
{{range .}}
|
{{range .}}
|
||||||
<div class="h-entry">
|
<div class="h-entry">
|
||||||
|
<hgroup>
|
||||||
<h3><a class="u-url" href="{{.UrlPath}}">{{.Title}}</a></h3>
|
<h3><a class="u-url" href="{{.UrlPath}}">{{.Title}}</a></h3>
|
||||||
|
<small>
|
||||||
|
Published:
|
||||||
|
<time class="dt-published" datetime="{{.Meta.Date}}">
|
||||||
|
{{.Meta.Date}}
|
||||||
|
</time>
|
||||||
|
</small>
|
||||||
|
</hgroup>
|
||||||
</div>
|
</div>
|
||||||
|
<hr>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
|
@ -1,6 +1,16 @@
|
||||||
<div class="h-entry">
|
<div class="h-entry">
|
||||||
|
<hgroup>
|
||||||
<h1 class="p-name">{{.Title}}</h1>
|
<h1 class="p-name">{{.Title}}</h1>
|
||||||
|
<small>
|
||||||
|
Published:
|
||||||
|
<time class="dt-published" datetime="{{.Post.Meta.Date}}">
|
||||||
|
{{.Post.Meta.Date}}
|
||||||
|
</time>
|
||||||
|
</small>
|
||||||
|
</hgroup>
|
||||||
|
<hr>
|
||||||
|
<br>
|
||||||
<div class="e-content">
|
<div class="e-content">
|
||||||
{{.Post}}
|
{{.Content}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
47
post.go
47
post.go
|
@ -16,6 +16,8 @@ type Post struct {
|
||||||
user *User
|
user *User
|
||||||
id string
|
id string
|
||||||
title string
|
title string
|
||||||
|
metaLoaded bool
|
||||||
|
meta PostMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
type PostMeta struct {
|
type PostMeta struct {
|
||||||
|
@ -57,17 +59,24 @@ func (post Post) ContentFile() string {
|
||||||
return path.Join(post.Dir(), "index.md")
|
return path.Join(post.Dir(), "index.md")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (post *Post) Meta() PostMeta {
|
||||||
|
if !post.metaLoaded {
|
||||||
|
post.LoadMeta()
|
||||||
|
}
|
||||||
|
return post.meta
|
||||||
|
}
|
||||||
|
|
||||||
func (post Post) Content() []byte {
|
func (post Post) Content() []byte {
|
||||||
// read file
|
// read file
|
||||||
data, _ := ioutil.ReadFile(post.ContentFile())
|
data, _ := ioutil.ReadFile(post.ContentFile())
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
func (post Post) MarkdownData() (bytes.Buffer, PostMeta) {
|
func (post Post) RenderedContent() bytes.Buffer {
|
||||||
data := post.Content()
|
data := post.Content()
|
||||||
|
|
||||||
// get yaml metadata block
|
// trim yaml block
|
||||||
meta := PostMeta{}
|
// TODO this can be done nicer
|
||||||
trimmedData := bytes.TrimSpace(data)
|
trimmedData := bytes.TrimSpace(data)
|
||||||
// check first line is ---
|
// check first line is ---
|
||||||
if string(trimmedData[0:4]) == "---\n" {
|
if string(trimmedData[0:4]) == "---\n" {
|
||||||
|
@ -75,8 +84,6 @@ func (post Post) MarkdownData() (bytes.Buffer, PostMeta) {
|
||||||
// find --- end
|
// find --- end
|
||||||
end := bytes.Index(trimmedData, []byte("\n---\n"))
|
end := bytes.Index(trimmedData, []byte("\n---\n"))
|
||||||
if end != -1 {
|
if end != -1 {
|
||||||
metaData := trimmedData[:end]
|
|
||||||
yaml.Unmarshal(metaData, &meta)
|
|
||||||
data = trimmedData[end+5:]
|
data = trimmedData[end+5:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,13 +107,35 @@ func (post Post) MarkdownData() (bytes.Buffer, PostMeta) {
|
||||||
if err := markdown.Convert(data, &buf, parser.WithContext(context)); err != nil {
|
if err := markdown.Convert(data, &buf, parser.WithContext(context)); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
// metaData := meta.Get(context)
|
|
||||||
|
|
||||||
return buf, meta
|
return buf
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (post Post) Aliases() []string {
|
func (post Post) Aliases() []string {
|
||||||
_, metaData := post.MarkdownData()
|
return post.Meta().Aliases
|
||||||
return metaData.Aliases
|
}
|
||||||
|
|
||||||
|
func (post *Post) LoadMeta() error {
|
||||||
|
data := post.Content()
|
||||||
|
|
||||||
|
// get yaml metadata block
|
||||||
|
meta := PostMeta{}
|
||||||
|
trimmedData := bytes.TrimSpace(data)
|
||||||
|
// check first line is ---
|
||||||
|
if string(trimmedData[0:4]) == "---\n" {
|
||||||
|
trimmedData = trimmedData[4:]
|
||||||
|
// find --- end
|
||||||
|
end := bytes.Index(trimmedData, []byte("\n---\n"))
|
||||||
|
if end != -1 {
|
||||||
|
metaData := trimmedData[:end]
|
||||||
|
err := yaml.Unmarshal(metaData, &meta)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post.meta = meta
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
47
post_test.go
47
post_test.go
|
@ -79,7 +79,7 @@ func TestDraftInMetaData(t *testing.T) {
|
||||||
content += "\n"
|
content += "\n"
|
||||||
content += "Write your post here.\n"
|
content += "Write your post here.\n"
|
||||||
os.WriteFile(post.ContentFile(), []byte(content), 0644)
|
os.WriteFile(post.ContentFile(), []byte(content), 0644)
|
||||||
_, meta := post.MarkdownData()
|
meta := post.Meta()
|
||||||
if !meta.Draft {
|
if !meta.Draft {
|
||||||
t.Error("Draft should be true")
|
t.Error("Draft should be true")
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ func TestNoRawHTMLIfDisallowedByRepo(t *testing.T) {
|
||||||
content += "\n"
|
content += "\n"
|
||||||
content += "<script>alert('foo')</script>\n"
|
content += "<script>alert('foo')</script>\n"
|
||||||
os.WriteFile(post.ContentFile(), []byte(content), 0644)
|
os.WriteFile(post.ContentFile(), []byte(content), 0644)
|
||||||
html, _ := post.MarkdownData()
|
html := post.RenderedContent()
|
||||||
html_str := html.String()
|
html_str := html.String()
|
||||||
if strings.Contains(html_str, "<script>") {
|
if strings.Contains(html_str, "<script>") {
|
||||||
t.Error("HTML should not be allowed")
|
t.Error("HTML should not be allowed")
|
||||||
|
@ -116,9 +116,50 @@ func TestRawHTMLIfAllowedByRepo(t *testing.T) {
|
||||||
content += "\n"
|
content += "\n"
|
||||||
content += "<script>alert('foo')</script>\n"
|
content += "<script>alert('foo')</script>\n"
|
||||||
os.WriteFile(post.ContentFile(), []byte(content), 0644)
|
os.WriteFile(post.ContentFile(), []byte(content), 0644)
|
||||||
html, _ := post.MarkdownData()
|
html := post.RenderedContent()
|
||||||
html_str := html.String()
|
html_str := html.String()
|
||||||
if !strings.Contains(html_str, "<script>") {
|
if !strings.Contains(html_str, "<script>") {
|
||||||
t.Error("HTML should be allowed")
|
t.Error("HTML should be allowed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoadMeta(t *testing.T) {
|
||||||
|
repo := getTestRepo()
|
||||||
|
repo.SetAllowRawHtml(true)
|
||||||
|
user, _ := repo.CreateUser("testuser")
|
||||||
|
post, _ := user.CreateNewPost("testpost")
|
||||||
|
|
||||||
|
content := "---\n"
|
||||||
|
content += "title: test\n"
|
||||||
|
content += "draft: true\n"
|
||||||
|
content += "date: Wed, 17 Aug 2022 10:50:02 +0000\n"
|
||||||
|
content += "aliases:\n"
|
||||||
|
content += " - foo/bar/\n"
|
||||||
|
content += "---\n"
|
||||||
|
content += "\n"
|
||||||
|
content += "<script>alert('foo')</script>\n"
|
||||||
|
os.WriteFile(post.ContentFile(), []byte(content), 0644)
|
||||||
|
|
||||||
|
err := post.LoadMeta()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Got Error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if post.Meta().Title != "test" {
|
||||||
|
t.Errorf("Expected title: %s, got %s", "test", post.Meta().Title)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(post.Meta().Aliases) != 1 || post.Meta().Aliases[0] != "foo/bar/" {
|
||||||
|
t.Errorf("Expected title: %v, got %v", []string{"foo/bar/"}, post.Meta().Aliases)
|
||||||
|
}
|
||||||
|
|
||||||
|
if post.Meta().Date != "Wed, 17 Aug 2022 10:50:02 +0000" {
|
||||||
|
t.Errorf("Expected title: %s, got %s", "Wed, 17 Aug 2022 10:50:02 +0000", post.Meta().Title)
|
||||||
|
}
|
||||||
|
|
||||||
|
if post.Meta().Draft != true {
|
||||||
|
t.Errorf("Expected title: %v, got %v", true, post.Meta().Draft)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
10
renderer.go
10
renderer.go
|
@ -13,7 +13,8 @@ type PageContent struct {
|
||||||
|
|
||||||
type PostRenderData struct {
|
type PostRenderData struct {
|
||||||
Title string
|
Title string
|
||||||
Post template.HTML
|
Post *Post
|
||||||
|
Content template.HTML
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderEmbedTemplate(templateFile string, data interface{}) (string, error) {
|
func renderEmbedTemplate(templateFile string, data interface{}) (string, error) {
|
||||||
|
@ -67,11 +68,12 @@ func renderIntoBaseTemplate(user User, data PageContent) (string, error) {
|
||||||
return html.String(), nil
|
return html.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RenderPost(post Post) (string, error) {
|
func RenderPost(post *Post) (string, error) {
|
||||||
buf, _ := post.MarkdownData()
|
buf := post.RenderedContent()
|
||||||
postHtml, err := renderEmbedTemplate("embed/post.html", PostRenderData{
|
postHtml, err := renderEmbedTemplate("embed/post.html", PostRenderData{
|
||||||
Title: post.Title(),
|
Title: post.Title(),
|
||||||
Post: template.HTML(buf.String()),
|
Post: post,
|
||||||
|
Content: template.HTML(buf.String()),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
func TestCanRenderPost(t *testing.T) {
|
func TestCanRenderPost(t *testing.T) {
|
||||||
user := getTestUser()
|
user := getTestUser()
|
||||||
post, _ := user.CreateNewPost("testpost")
|
post, _ := user.CreateNewPost("testpost")
|
||||||
result, err := owl.RenderPost(post)
|
result, err := owl.RenderPost(&post)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("Error rendering post: " + err.Error())
|
t.Error("Error rendering post: " + err.Error())
|
||||||
|
@ -27,7 +27,7 @@ func TestCanRenderPost(t *testing.T) {
|
||||||
func TestRenderPostHEntry(t *testing.T) {
|
func TestRenderPostHEntry(t *testing.T) {
|
||||||
user := getTestUser()
|
user := getTestUser()
|
||||||
post, _ := user.CreateNewPost("testpost")
|
post, _ := user.CreateNewPost("testpost")
|
||||||
result, _ := owl.RenderPost(post)
|
result, _ := owl.RenderPost(&post)
|
||||||
if !strings.Contains(result, "class=\"h-entry\"") {
|
if !strings.Contains(result, "class=\"h-entry\"") {
|
||||||
t.Error("h-entry container not rendered. Got: " + result)
|
t.Error("h-entry container not rendered. Got: " + result)
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ func TestRenderPostHEntry(t *testing.T) {
|
||||||
func TestRendererUsesBaseTemplate(t *testing.T) {
|
func TestRendererUsesBaseTemplate(t *testing.T) {
|
||||||
user := getTestUser()
|
user := getTestUser()
|
||||||
post, _ := user.CreateNewPost("testpost")
|
post, _ := user.CreateNewPost("testpost")
|
||||||
result, err := owl.RenderPost(post)
|
result, err := owl.RenderPost(&post)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("Error rendering post: " + err.Error())
|
t.Error("Error rendering post: " + err.Error())
|
||||||
|
@ -132,7 +132,7 @@ func TestRendersHeaderTitle(t *testing.T) {
|
||||||
})
|
})
|
||||||
post, _ := user.CreateNewPost("testpost")
|
post, _ := user.CreateNewPost("testpost")
|
||||||
|
|
||||||
result, _ := owl.RenderPost(post)
|
result, _ := owl.RenderPost(&post)
|
||||||
if !strings.Contains(result, "Test Title") {
|
if !strings.Contains(result, "Test Title") {
|
||||||
t.Error("Header title not rendered. Got: " + result)
|
t.Error("Header title not rendered. Got: " + result)
|
||||||
}
|
}
|
||||||
|
|
2
rss.go
2
rss.go
|
@ -41,7 +41,7 @@ func RenderRSSFeed(user User) (string, error) {
|
||||||
|
|
||||||
posts, _ := user.Posts()
|
posts, _ := user.Posts()
|
||||||
for _, post := range posts {
|
for _, post := range posts {
|
||||||
_, meta := post.MarkdownData()
|
meta := post.Meta()
|
||||||
rss.Channel.Items = append(rss.Channel.Items, RSSItem{
|
rss.Channel.Items = append(rss.Channel.Items, RSSItem{
|
||||||
Guid: post.FullUrl(),
|
Guid: post.FullUrl(),
|
||||||
Title: post.Title(),
|
Title: post.Title(),
|
||||||
|
|
9
user.go
9
user.go
|
@ -68,7 +68,7 @@ func (user User) Posts() ([]*Post, error) {
|
||||||
// remove drafts
|
// remove drafts
|
||||||
n := 0
|
n := 0
|
||||||
for _, post := range posts {
|
for _, post := range posts {
|
||||||
_, meta := post.MarkdownData()
|
meta := post.Meta()
|
||||||
if !meta.Draft {
|
if !meta.Draft {
|
||||||
posts[n] = post
|
posts[n] = post
|
||||||
n++
|
n++
|
||||||
|
@ -83,7 +83,7 @@ func (user User) Posts() ([]*Post, error) {
|
||||||
|
|
||||||
postDates := make([]PostWithDate, len(posts))
|
postDates := make([]PostWithDate, len(posts))
|
||||||
for i, post := range posts {
|
for i, post := range posts {
|
||||||
_, meta := post.MarkdownData()
|
meta := post.Meta()
|
||||||
date, err := time.Parse(time.RFC1123Z, meta.Date)
|
date, err := time.Parse(time.RFC1123Z, meta.Date)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// invalid date -> use 1970-01-01
|
// invalid date -> use 1970-01-01
|
||||||
|
@ -111,8 +111,9 @@ func (user User) GetPost(id string) (Post, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
post := Post{user: &user, id: id}
|
post := Post{user: &user, id: id}
|
||||||
_, metaData := post.MarkdownData()
|
// post.loadMeta()
|
||||||
title := metaData.Title
|
meta := post.Meta()
|
||||||
|
title := meta.Title
|
||||||
post.title = fmt.Sprint(title)
|
post.title = fmt.Sprint(title)
|
||||||
|
|
||||||
return post, nil
|
return post, nil
|
||||||
|
|
|
@ -41,7 +41,7 @@ func TestCreateNewPostAddsDateToMetaBlock(t *testing.T) {
|
||||||
user.CreateNewPost("testpost")
|
user.CreateNewPost("testpost")
|
||||||
posts, _ := user.Posts()
|
posts, _ := user.Posts()
|
||||||
post, _ := user.GetPost(posts[0].Id())
|
post, _ := user.GetPost(posts[0].Id())
|
||||||
_, meta := post.MarkdownData()
|
meta := post.Meta()
|
||||||
if meta.Date == "" {
|
if meta.Date == "" {
|
||||||
t.Error("Found no date. Got: " + meta.Date)
|
t.Error("Found no date. Got: " + meta.Date)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue