mirror of https://github.com/jlelse/GoBlog
Small things
This commit is contained in:
parent
91b094053f
commit
50b4bce82f
|
@ -39,13 +39,11 @@ type asAttachment struct {
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Serve index
|
|
||||||
|
|
||||||
func servePostActivityStreams(w http.ResponseWriter, r *http.Request) {
|
func servePostActivityStreams(w http.ResponseWriter, r *http.Request) {
|
||||||
// Remove ".as" from path again
|
// Remove ".as" from path again
|
||||||
r.URL.Path = strings.TrimSuffix(r.URL.Path, ".as")
|
r.URL.Path = strings.TrimSuffix(r.URL.Path, ".as")
|
||||||
// Fetch post from db
|
// Fetch post from db
|
||||||
post, err := getPost(r.Context(), slashTrimmedPath(r))
|
p, err := getPost(r.Context(), slashTrimmedPath(r))
|
||||||
if err == errPostNotFound {
|
if err == errPostNotFound {
|
||||||
serve404(w, r)
|
serve404(w, r)
|
||||||
return
|
return
|
||||||
|
@ -58,26 +56,26 @@ func servePostActivityStreams(w http.ResponseWriter, r *http.Request) {
|
||||||
Context: []string{"https://www.w3.org/ns/activitystreams"},
|
Context: []string{"https://www.w3.org/ns/activitystreams"},
|
||||||
To: []string{"https://www.w3.org/ns/activitystreams#Public"},
|
To: []string{"https://www.w3.org/ns/activitystreams#Public"},
|
||||||
MediaType: "text/html",
|
MediaType: "text/html",
|
||||||
ID: appConfig.Server.PublicAddress + post.Path,
|
ID: appConfig.Server.PublicAddress + p.Path,
|
||||||
URL: appConfig.Server.PublicAddress + post.Path,
|
URL: appConfig.Server.PublicAddress + p.Path,
|
||||||
AttributedTo: appConfig.Server.PublicAddress,
|
AttributedTo: appConfig.Server.PublicAddress,
|
||||||
}
|
}
|
||||||
// Name and Type
|
// Name and Type
|
||||||
if title := post.title(); title != "" {
|
if title := p.title(); title != "" {
|
||||||
as.Name = title
|
as.Name = title
|
||||||
as.Type = "Article"
|
as.Type = "Article"
|
||||||
} else {
|
} else {
|
||||||
as.Type = "Note"
|
as.Type = "Note"
|
||||||
}
|
}
|
||||||
// Content
|
// Content
|
||||||
if rendered, err := renderMarkdown(post.Content); err == nil {
|
if rendered, err := renderMarkdown(p.Content); err == nil {
|
||||||
as.Content = string(rendered)
|
as.Content = string(rendered)
|
||||||
} else {
|
} else {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Attachments
|
// Attachments
|
||||||
if images := post.Parameters[appConfig.Blogs[post.Blog].ActivityStreams.ImagesParameter]; len(images) > 0 {
|
if images := p.Parameters[appConfig.Blogs[p.Blog].ActivityStreams.ImagesParameter]; len(images) > 0 {
|
||||||
for _, image := range images {
|
for _, image := range images {
|
||||||
as.Attachment = append(as.Attachment, &asAttachment{
|
as.Attachment = append(as.Attachment, &asAttachment{
|
||||||
Type: "Image",
|
Type: "Image",
|
||||||
|
@ -87,21 +85,45 @@ func servePostActivityStreams(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
// Dates
|
// Dates
|
||||||
dateFormat := "2006-01-02T15:04:05-07:00"
|
dateFormat := "2006-01-02T15:04:05-07:00"
|
||||||
if post.Published != "" {
|
if p.Published != "" {
|
||||||
if t, err := dateparse.ParseIn(post.Published, time.Local); err == nil {
|
if t, err := dateparse.ParseIn(p.Published, time.Local); err == nil {
|
||||||
as.Published = t.Format(dateFormat)
|
as.Published = t.Format(dateFormat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if post.Updated != "" {
|
if p.Updated != "" {
|
||||||
if t, err := dateparse.ParseIn(post.Updated, time.Local); err == nil {
|
if t, err := dateparse.ParseIn(p.Updated, time.Local); err == nil {
|
||||||
as.Published = t.Format(dateFormat)
|
as.Published = t.Format(dateFormat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Reply
|
// Reply
|
||||||
if replyLink := post.firstParameter(appConfig.Blogs[post.Blog].ActivityStreams.ReplyParameter); replyLink != "" {
|
if replyLink := p.firstParameter(appConfig.Blogs[p.Blog].ActivityStreams.ReplyParameter); replyLink != "" {
|
||||||
as.InReplyTo = replyLink
|
as.InReplyTo = replyLink
|
||||||
}
|
}
|
||||||
// Send JSON
|
// Send JSON
|
||||||
w.Header().Add(contentType, contentTypeJSONUTF8)
|
w.Header().Add(contentType, contentTypeJSONUTF8)
|
||||||
_ = json.NewEncoder(w).Encode(as)
|
_ = json.NewEncoder(w).Encode(as)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type asPerson struct {
|
||||||
|
Context []string `json:"@context"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Summary string `json:"summary"`
|
||||||
|
Attachment []struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
} `json:"attachment"`
|
||||||
|
PreferredUsername string `json:"preferredUsername"`
|
||||||
|
Icon struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
} `json:"icon"`
|
||||||
|
Inbox string `json:"inbox"`
|
||||||
|
PublicKey struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Owner string `json:"owner"`
|
||||||
|
PublicKeyPem string `json:"publicKeyPem"`
|
||||||
|
} `json:"publicKey"`
|
||||||
|
}
|
||||||
|
|
20
api.go
20
api.go
|
@ -20,17 +20,17 @@ func apiPostCreateHugo(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
post, aliases, err := parseHugoFile(string(bodyContent))
|
p, aliases, err := parseHugoFile(string(bodyContent))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
post.Blog = blog
|
p.Blog = blog
|
||||||
post.Path = path
|
p.Path = path
|
||||||
post.Section = section
|
p.Section = section
|
||||||
post.Slug = slug
|
p.Slug = slug
|
||||||
aliases = append(aliases, alias)
|
aliases = append(aliases, alias)
|
||||||
err = post.replace()
|
err = p.replace()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
|
@ -38,13 +38,13 @@ func apiPostCreateHugo(w http.ResponseWriter, r *http.Request) {
|
||||||
for _, alias := range aliases {
|
for _, alias := range aliases {
|
||||||
// Fix relativ paths
|
// Fix relativ paths
|
||||||
if !strings.HasPrefix(alias, "/") {
|
if !strings.HasPrefix(alias, "/") {
|
||||||
splittedPostPath := strings.Split(post.Path, "/")
|
splittedPostPath := strings.Split(p.Path, "/")
|
||||||
alias = strings.TrimSuffix(post.Path, splittedPostPath[len(splittedPostPath)-1]) + alias
|
alias = strings.TrimSuffix(p.Path, splittedPostPath[len(splittedPostPath)-1]) + alias
|
||||||
}
|
}
|
||||||
if alias != "" {
|
if alias != "" {
|
||||||
_ = createOrReplaceRedirect(alias, post.Path)
|
_ = createOrReplaceRedirect(alias, p.Path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.Header().Set("Location", appConfig.Server.PublicAddress+post.Path)
|
w.Header().Set("Location", appConfig.Server.PublicAddress+p.Path)
|
||||||
w.WriteHeader(http.StatusCreated)
|
w.WriteHeader(http.StatusCreated)
|
||||||
}
|
}
|
||||||
|
|
14
feeds.go
14
feeds.go
|
@ -17,7 +17,7 @@ const (
|
||||||
jsonFeed feedType = "json"
|
jsonFeed feedType = "json"
|
||||||
)
|
)
|
||||||
|
|
||||||
func generateFeed(blog string, f feedType, w http.ResponseWriter, r *http.Request, posts []*Post, title string, description string) {
|
func generateFeed(blog string, f feedType, w http.ResponseWriter, r *http.Request, posts []*post, title string, description string) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
if title == "" {
|
if title == "" {
|
||||||
title = appConfig.Blogs[blog].Title
|
title = appConfig.Blogs[blog].Title
|
||||||
|
@ -31,13 +31,13 @@ func generateFeed(blog string, f feedType, w http.ResponseWriter, r *http.Reques
|
||||||
Link: &feeds.Link{Href: appConfig.Server.PublicAddress + strings.TrimSuffix(r.URL.Path, "."+string(f))},
|
Link: &feeds.Link{Href: appConfig.Server.PublicAddress + strings.TrimSuffix(r.URL.Path, "."+string(f))},
|
||||||
Created: now,
|
Created: now,
|
||||||
}
|
}
|
||||||
for _, postItem := range posts {
|
for _, p := range posts {
|
||||||
htmlContent, _ := renderMarkdown(postItem.Content)
|
htmlContent, _ := renderMarkdown(p.Content)
|
||||||
feed.Add(&feeds.Item{
|
feed.Add(&feeds.Item{
|
||||||
Title: postItem.title(),
|
Title: p.title(),
|
||||||
Link: &feeds.Link{Href: appConfig.Server.PublicAddress + postItem.Path},
|
Link: &feeds.Link{Href: appConfig.Server.PublicAddress + p.Path},
|
||||||
Description: postItem.summary(),
|
Description: p.summary(),
|
||||||
Id: postItem.Path,
|
Id: p.Path,
|
||||||
Content: string(htmlContent),
|
Content: string(htmlContent),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
12
hugo.go
12
hugo.go
|
@ -9,13 +9,13 @@ import (
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseHugoFile(fileContent string) (post *Post, aliases []string, e error) {
|
func parseHugoFile(fileContent string) (p *post, aliases []string, e error) {
|
||||||
frontmatterSep := "---\n"
|
frontmatterSep := "---\n"
|
||||||
frontmatter := ""
|
frontmatter := ""
|
||||||
if split := strings.Split(fileContent, frontmatterSep); len(split) > 2 {
|
if split := strings.Split(fileContent, frontmatterSep); len(split) > 2 {
|
||||||
frontmatter = split[1]
|
frontmatter = split[1]
|
||||||
}
|
}
|
||||||
post = &Post{
|
p = &post{
|
||||||
Content: strings.TrimPrefix(fileContent, frontmatterSep+frontmatter+frontmatterSep),
|
Content: strings.TrimPrefix(fileContent, frontmatterSep+frontmatter+frontmatterSep),
|
||||||
Parameters: map[string][]string{},
|
Parameters: map[string][]string{},
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,8 @@ func parseHugoFile(fileContent string) (post *Post, aliases []string, e error) {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
// Read dates
|
// Read dates
|
||||||
post.Published = cast.ToString(flat["date"])
|
p.Published = cast.ToString(flat["date"])
|
||||||
post.Updated = cast.ToString(flat["lastmod"])
|
p.Updated = cast.ToString(flat["lastmod"])
|
||||||
// Read parameters
|
// Read parameters
|
||||||
for _, fm := range appConfig.Hugo.Frontmatter {
|
for _, fm := range appConfig.Hugo.Frontmatter {
|
||||||
var values []string
|
var values []string
|
||||||
|
@ -49,7 +49,7 @@ func parseHugoFile(fileContent string) (post *Post, aliases []string, e error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(values) > 0 {
|
if len(values) > 0 {
|
||||||
post.Parameters[fm.Parameter] = values
|
p.Parameters[fm.Parameter] = values
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Parse redirects
|
// Parse redirects
|
||||||
|
@ -67,5 +67,5 @@ func parseHugoFile(fileContent string) (post *Post, aliases []string, e error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Return post
|
// Return post
|
||||||
return post, aliases, nil
|
return p, aliases, nil
|
||||||
}
|
}
|
||||||
|
|
184
micropub.go
184
micropub.go
|
@ -38,12 +38,12 @@ func serveMicropubQuery(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
post, err := getPost(r.Context(), u.Path)
|
p, err := getPost(r.Context(), u.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mf = post.toMfItem()
|
mf = p.toMfItem()
|
||||||
} else {
|
} else {
|
||||||
posts, err := getPosts(r.Context(), &postsRequestConfig{})
|
posts, err := getPosts(r.Context(), &postsRequestConfig{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -51,8 +51,8 @@ func serveMicropubQuery(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
list := map[string][]*microformatItem{}
|
list := map[string][]*microformatItem{}
|
||||||
for _, post := range posts {
|
for _, p := range posts {
|
||||||
list["items"] = append(list["items"], post.toMfItem())
|
list["items"] = append(list["items"], p.toMfItem())
|
||||||
}
|
}
|
||||||
mf = list
|
mf = list
|
||||||
}
|
}
|
||||||
|
@ -64,29 +64,29 @@ func serveMicropubQuery(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (post *Post) toMfItem() *microformatItem {
|
func (p *post) toMfItem() *microformatItem {
|
||||||
params := post.Parameters
|
params := p.Parameters
|
||||||
params["path"] = []string{post.Path}
|
params["path"] = []string{p.Path}
|
||||||
params["section"] = []string{post.Section}
|
params["section"] = []string{p.Section}
|
||||||
params["blog"] = []string{post.Blog}
|
params["blog"] = []string{p.Blog}
|
||||||
pb, _ := yaml.Marshal(post.Parameters)
|
pb, _ := yaml.Marshal(p.Parameters)
|
||||||
content := fmt.Sprintf("---\n%s---\n%s", string(pb), post.Content)
|
content := fmt.Sprintf("---\n%s---\n%s", string(pb), p.Content)
|
||||||
return µformatItem{
|
return µformatItem{
|
||||||
Type: []string{"h-entry"},
|
Type: []string{"h-entry"},
|
||||||
Properties: µformatProperties{
|
Properties: µformatProperties{
|
||||||
Name: post.Parameters["title"],
|
Name: p.Parameters["title"],
|
||||||
Published: []string{post.Published},
|
Published: []string{p.Published},
|
||||||
Updated: []string{post.Updated},
|
Updated: []string{p.Updated},
|
||||||
Content: []string{content},
|
Content: []string{content},
|
||||||
MpSlug: []string{post.Slug},
|
MpSlug: []string{p.Slug},
|
||||||
Category: post.Parameters[appConfig.Micropub.CategoryParam],
|
Category: p.Parameters[appConfig.Micropub.CategoryParam],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveMicropubPost(w http.ResponseWriter, r *http.Request) {
|
func serveMicropubPost(w http.ResponseWriter, r *http.Request) {
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
var post *Post
|
var p *post
|
||||||
if ct := r.Header.Get(contentType); strings.Contains(ct, contentTypeWWWForm) || strings.Contains(ct, contentTypeMultipartForm) {
|
if ct := r.Header.Get(contentType); strings.Contains(ct, contentTypeWWWForm) || strings.Contains(ct, contentTypeMultipartForm) {
|
||||||
var err error
|
var err error
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
|
@ -109,7 +109,7 @@ func serveMicropubPost(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Error(w, "Action not supported", http.StatusNotImplemented)
|
http.Error(w, "Action not supported", http.StatusNotImplemented)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
post, err = convertMPValueMapToPost(r.Form)
|
p, err = convertMPValueMapToPost(r.Form)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
@ -137,7 +137,7 @@ func serveMicropubPost(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Error(w, "Action not supported", http.StatusNotImplemented)
|
http.Error(w, "Action not supported", http.StatusNotImplemented)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
post, err = convertMPMfToPost(parsedMfItem)
|
p, err = convertMPMfToPost(parsedMfItem)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
@ -149,21 +149,21 @@ func serveMicropubPost(w http.ResponseWriter, r *http.Request) {
|
||||||
if !strings.Contains(r.Context().Value("scope").(string), "create") {
|
if !strings.Contains(r.Context().Value("scope").(string), "create") {
|
||||||
http.Error(w, "create scope missing", http.StatusForbidden)
|
http.Error(w, "create scope missing", http.StatusForbidden)
|
||||||
}
|
}
|
||||||
err := post.create()
|
err := p.create()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Add("Location", appConfig.Server.PublicAddress+post.Path)
|
w.Header().Add("Location", appConfig.Server.PublicAddress+p.Path)
|
||||||
w.WriteHeader(http.StatusAccepted)
|
w.WriteHeader(http.StatusAccepted)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertMPValueMapToPost(values map[string][]string) (*Post, error) {
|
func convertMPValueMapToPost(values map[string][]string) (*post, error) {
|
||||||
if h, ok := values["h"]; ok && (len(h) != 1 || h[0] != "entry") {
|
if h, ok := values["h"]; ok && (len(h) != 1 || h[0] != "entry") {
|
||||||
return nil, errors.New("only entry type is supported so far")
|
return nil, errors.New("only entry type is supported so far")
|
||||||
}
|
}
|
||||||
entry := &Post{
|
entry := &post{
|
||||||
Parameters: map[string][]string{},
|
Parameters: map[string][]string{},
|
||||||
}
|
}
|
||||||
if content, ok := values["content"]; ok {
|
if content, ok := values["content"]; ok {
|
||||||
|
@ -250,11 +250,11 @@ type microformatProperties struct {
|
||||||
Audio []string `json:"audio,omitempty"`
|
Audio []string `json:"audio,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertMPMfToPost(mf *microformatItem) (*Post, error) {
|
func convertMPMfToPost(mf *microformatItem) (*post, error) {
|
||||||
if len(mf.Type) != 1 || mf.Type[0] != "h-entry" {
|
if len(mf.Type) != 1 || mf.Type[0] != "h-entry" {
|
||||||
return nil, errors.New("only entry type is supported so far")
|
return nil, errors.New("only entry type is supported so far")
|
||||||
}
|
}
|
||||||
entry := &Post{}
|
entry := &post{}
|
||||||
// Content
|
// Content
|
||||||
if mf.Properties != nil && len(mf.Properties.Content) == 1 && len(mf.Properties.Content[0]) > 0 {
|
if mf.Properties != nil && len(mf.Properties.Content) == 1 && len(mf.Properties.Content[0]) > 0 {
|
||||||
entry.Content = mf.Properties.Content[0]
|
entry.Content = mf.Properties.Content[0]
|
||||||
|
@ -306,9 +306,9 @@ func convertMPMfToPost(mf *microformatItem) (*Post, error) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (post *Post) computeExtraPostParameters() error {
|
func (p *post) computeExtraPostParameters() error {
|
||||||
post.Content = regexp.MustCompile("\r\n").ReplaceAllString(post.Content, "\n")
|
p.Content = regexp.MustCompile("\r\n").ReplaceAllString(p.Content, "\n")
|
||||||
if split := strings.Split(post.Content, "---\n"); len(split) >= 3 && len(strings.TrimSpace(split[0])) == 0 {
|
if split := strings.Split(p.Content, "---\n"); len(split) >= 3 && len(strings.TrimSpace(split[0])) == 0 {
|
||||||
// Contains frontmatter
|
// Contains frontmatter
|
||||||
fm := split[1]
|
fm := split[1]
|
||||||
meta := map[string]interface{}{}
|
meta := map[string]interface{}{}
|
||||||
|
@ -319,55 +319,55 @@ func (post *Post) computeExtraPostParameters() error {
|
||||||
// Find section and copy frontmatter to params
|
// Find section and copy frontmatter to params
|
||||||
for key, value := range meta {
|
for key, value := range meta {
|
||||||
// Delete existing content - replace
|
// Delete existing content - replace
|
||||||
post.Parameters[key] = []string{}
|
p.Parameters[key] = []string{}
|
||||||
if a, ok := value.([]interface{}); ok {
|
if a, ok := value.([]interface{}); ok {
|
||||||
for _, ae := range a {
|
for _, ae := range a {
|
||||||
post.Parameters[key] = append(post.Parameters[key], cast.ToString(ae))
|
p.Parameters[key] = append(p.Parameters[key], cast.ToString(ae))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
post.Parameters[key] = append(post.Parameters[key], cast.ToString(value))
|
p.Parameters[key] = append(p.Parameters[key], cast.ToString(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Remove frontmatter from content
|
// Remove frontmatter from content
|
||||||
post.Content = strings.Join(split[2:], "---\n")
|
p.Content = strings.Join(split[2:], "---\n")
|
||||||
}
|
}
|
||||||
// Check settings
|
// Check settings
|
||||||
if blog := post.Parameters["blog"]; len(blog) == 1 && blog[0] != "" {
|
if blog := p.Parameters["blog"]; len(blog) == 1 && blog[0] != "" {
|
||||||
post.Blog = blog[0]
|
p.Blog = blog[0]
|
||||||
delete(post.Parameters, "blog")
|
delete(p.Parameters, "blog")
|
||||||
} else {
|
} else {
|
||||||
post.Blog = appConfig.DefaultBlog
|
p.Blog = appConfig.DefaultBlog
|
||||||
}
|
}
|
||||||
if path := post.Parameters["path"]; len(path) == 1 && path[0] != "" {
|
if path := p.Parameters["path"]; len(path) == 1 && path[0] != "" {
|
||||||
post.Path = path[0]
|
p.Path = path[0]
|
||||||
delete(post.Parameters, "path")
|
delete(p.Parameters, "path")
|
||||||
}
|
}
|
||||||
if section := post.Parameters["section"]; len(section) == 1 && section[0] != "" {
|
if section := p.Parameters["section"]; len(section) == 1 && section[0] != "" {
|
||||||
post.Section = section[0]
|
p.Section = section[0]
|
||||||
delete(post.Parameters, "section")
|
delete(p.Parameters, "section")
|
||||||
}
|
}
|
||||||
if slug := post.Parameters["slug"]; len(slug) == 1 && slug[0] != "" {
|
if slug := p.Parameters["slug"]; len(slug) == 1 && slug[0] != "" {
|
||||||
post.Slug = slug[0]
|
p.Slug = slug[0]
|
||||||
delete(post.Parameters, "slug")
|
delete(p.Parameters, "slug")
|
||||||
}
|
}
|
||||||
if post.Path == "" && post.Section == "" {
|
if p.Path == "" && p.Section == "" {
|
||||||
// Has no path or section -> default section
|
// Has no path or section -> default section
|
||||||
post.Section = appConfig.Blogs[post.Blog].DefaultSection
|
p.Section = appConfig.Blogs[p.Blog].DefaultSection
|
||||||
}
|
}
|
||||||
if post.Published == "" && post.Section != "" {
|
if p.Published == "" && p.Section != "" {
|
||||||
// Has no published date, but section -> published now
|
// Has no published date, but section -> published now
|
||||||
post.Published = time.Now().String()
|
p.Published = time.Now().String()
|
||||||
}
|
}
|
||||||
// Add images not in content
|
// Add images not in content
|
||||||
images := post.Parameters[appConfig.Micropub.PhotoParam]
|
images := p.Parameters[appConfig.Micropub.PhotoParam]
|
||||||
imageAlts := post.Parameters[appConfig.Micropub.PhotoDescriptionParam]
|
imageAlts := p.Parameters[appConfig.Micropub.PhotoDescriptionParam]
|
||||||
useAlts := len(images) == len(imageAlts)
|
useAlts := len(images) == len(imageAlts)
|
||||||
for i, image := range images {
|
for i, image := range images {
|
||||||
if !strings.Contains(post.Content, image) {
|
if !strings.Contains(p.Content, image) {
|
||||||
if useAlts && len(imageAlts[i]) > 0 {
|
if useAlts && len(imageAlts[i]) > 0 {
|
||||||
post.Content += "\n\n![" + imageAlts[i] + "](" + image + " \"" + imageAlts[i] + "\")"
|
p.Content += "\n\n![" + imageAlts[i] + "](" + image + " \"" + imageAlts[i] + "\")"
|
||||||
} else {
|
} else {
|
||||||
post.Content += "\n\n![](" + image + ")"
|
p.Content += "\n\n![](" + image + ")"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -391,7 +391,7 @@ func micropubUpdate(w http.ResponseWriter, r *http.Request, u *url.URL, mf *micr
|
||||||
if !strings.Contains(r.Context().Value("scope").(string), "update") {
|
if !strings.Contains(r.Context().Value("scope").(string), "update") {
|
||||||
http.Error(w, "update scope missing", http.StatusForbidden)
|
http.Error(w, "update scope missing", http.StatusForbidden)
|
||||||
}
|
}
|
||||||
post, err := getPost(r.Context(), u.Path)
|
p, err := getPost(r.Context(), u.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
|
@ -400,23 +400,23 @@ func micropubUpdate(w http.ResponseWriter, r *http.Request, u *url.URL, mf *micr
|
||||||
for key, value := range mf.Replace {
|
for key, value := range mf.Replace {
|
||||||
switch key {
|
switch key {
|
||||||
case "content":
|
case "content":
|
||||||
post.Content = strings.TrimSpace(strings.Join(cast.ToStringSlice(value), " "))
|
p.Content = strings.TrimSpace(strings.Join(cast.ToStringSlice(value), " "))
|
||||||
case "published":
|
case "published":
|
||||||
post.Published = strings.TrimSpace(strings.Join(cast.ToStringSlice(value), " "))
|
p.Published = strings.TrimSpace(strings.Join(cast.ToStringSlice(value), " "))
|
||||||
case "updated":
|
case "updated":
|
||||||
post.Updated = strings.TrimSpace(strings.Join(cast.ToStringSlice(value), " "))
|
p.Updated = strings.TrimSpace(strings.Join(cast.ToStringSlice(value), " "))
|
||||||
case "name":
|
case "name":
|
||||||
post.Parameters["title"] = cast.ToStringSlice(value)
|
p.Parameters["title"] = cast.ToStringSlice(value)
|
||||||
case "category":
|
case "category":
|
||||||
post.Parameters[appConfig.Micropub.CategoryParam] = cast.ToStringSlice(value)
|
p.Parameters[appConfig.Micropub.CategoryParam] = cast.ToStringSlice(value)
|
||||||
case "in-reply-to":
|
case "in-reply-to":
|
||||||
post.Parameters[appConfig.Micropub.ReplyParam] = cast.ToStringSlice(value)
|
p.Parameters[appConfig.Micropub.ReplyParam] = cast.ToStringSlice(value)
|
||||||
case "like-of":
|
case "like-of":
|
||||||
post.Parameters[appConfig.Micropub.LikeParam] = cast.ToStringSlice(value)
|
p.Parameters[appConfig.Micropub.LikeParam] = cast.ToStringSlice(value)
|
||||||
case "bookmark-of":
|
case "bookmark-of":
|
||||||
post.Parameters[appConfig.Micropub.BookmarkParam] = cast.ToStringSlice(value)
|
p.Parameters[appConfig.Micropub.BookmarkParam] = cast.ToStringSlice(value)
|
||||||
case "audio":
|
case "audio":
|
||||||
post.Parameters[appConfig.Micropub.AudioParam] = cast.ToStringSlice(value)
|
p.Parameters[appConfig.Micropub.AudioParam] = cast.ToStringSlice(value)
|
||||||
// TODO: photo
|
// TODO: photo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -425,29 +425,29 @@ func micropubUpdate(w http.ResponseWriter, r *http.Request, u *url.URL, mf *micr
|
||||||
for key, value := range mf.Add {
|
for key, value := range mf.Add {
|
||||||
switch key {
|
switch key {
|
||||||
case "content":
|
case "content":
|
||||||
post.Content += strings.TrimSpace(strings.Join(cast.ToStringSlice(value), " "))
|
p.Content += strings.TrimSpace(strings.Join(cast.ToStringSlice(value), " "))
|
||||||
case "published":
|
case "published":
|
||||||
post.Published = strings.TrimSpace(strings.Join(cast.ToStringSlice(value), " "))
|
p.Published = strings.TrimSpace(strings.Join(cast.ToStringSlice(value), " "))
|
||||||
case "updated":
|
case "updated":
|
||||||
post.Updated = strings.TrimSpace(strings.Join(cast.ToStringSlice(value), " "))
|
p.Updated = strings.TrimSpace(strings.Join(cast.ToStringSlice(value), " "))
|
||||||
case "category":
|
case "category":
|
||||||
category := post.Parameters[appConfig.Micropub.CategoryParam]
|
category := p.Parameters[appConfig.Micropub.CategoryParam]
|
||||||
if category == nil {
|
if category == nil {
|
||||||
category = []string{}
|
category = []string{}
|
||||||
}
|
}
|
||||||
post.Parameters[appConfig.Micropub.CategoryParam] = append(category, cast.ToStringSlice(value)...)
|
p.Parameters[appConfig.Micropub.CategoryParam] = append(category, cast.ToStringSlice(value)...)
|
||||||
case "in-reply-to":
|
case "in-reply-to":
|
||||||
post.Parameters[appConfig.Micropub.ReplyParam] = cast.ToStringSlice(value)
|
p.Parameters[appConfig.Micropub.ReplyParam] = cast.ToStringSlice(value)
|
||||||
case "like-of":
|
case "like-of":
|
||||||
post.Parameters[appConfig.Micropub.LikeParam] = cast.ToStringSlice(value)
|
p.Parameters[appConfig.Micropub.LikeParam] = cast.ToStringSlice(value)
|
||||||
case "bookmark-of":
|
case "bookmark-of":
|
||||||
post.Parameters[appConfig.Micropub.BookmarkParam] = cast.ToStringSlice(value)
|
p.Parameters[appConfig.Micropub.BookmarkParam] = cast.ToStringSlice(value)
|
||||||
case "audio":
|
case "audio":
|
||||||
audio := post.Parameters[appConfig.Micropub.CategoryParam]
|
audio := p.Parameters[appConfig.Micropub.CategoryParam]
|
||||||
if audio == nil {
|
if audio == nil {
|
||||||
audio = []string{}
|
audio = []string{}
|
||||||
}
|
}
|
||||||
post.Parameters[appConfig.Micropub.AudioParam] = append(audio, cast.ToStringSlice(value)...)
|
p.Parameters[appConfig.Micropub.AudioParam] = append(audio, cast.ToStringSlice(value)...)
|
||||||
// TODO: photo
|
// TODO: photo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -459,24 +459,24 @@ func micropubUpdate(w http.ResponseWriter, r *http.Request, u *url.URL, mf *micr
|
||||||
for _, key := range toDelete {
|
for _, key := range toDelete {
|
||||||
switch key {
|
switch key {
|
||||||
case "content":
|
case "content":
|
||||||
post.Content = ""
|
p.Content = ""
|
||||||
case "published":
|
case "published":
|
||||||
post.Published = ""
|
p.Published = ""
|
||||||
case "updated":
|
case "updated":
|
||||||
post.Updated = ""
|
p.Updated = ""
|
||||||
case "category":
|
case "category":
|
||||||
delete(post.Parameters, appConfig.Micropub.CategoryParam)
|
delete(p.Parameters, appConfig.Micropub.CategoryParam)
|
||||||
case "in-reply-to":
|
case "in-reply-to":
|
||||||
delete(post.Parameters, appConfig.Micropub.ReplyParam)
|
delete(p.Parameters, appConfig.Micropub.ReplyParam)
|
||||||
case "like-of":
|
case "like-of":
|
||||||
delete(post.Parameters, appConfig.Micropub.LikeParam)
|
delete(p.Parameters, appConfig.Micropub.LikeParam)
|
||||||
case "bookmark-of":
|
case "bookmark-of":
|
||||||
delete(post.Parameters, appConfig.Micropub.BookmarkParam)
|
delete(p.Parameters, appConfig.Micropub.BookmarkParam)
|
||||||
case "audio":
|
case "audio":
|
||||||
delete(post.Parameters, appConfig.Micropub.AudioParam)
|
delete(p.Parameters, appConfig.Micropub.AudioParam)
|
||||||
case "photo":
|
case "photo":
|
||||||
delete(post.Parameters, appConfig.Micropub.PhotoParam)
|
delete(p.Parameters, appConfig.Micropub.PhotoParam)
|
||||||
delete(post.Parameters, appConfig.Micropub.PhotoDescriptionParam)
|
delete(p.Parameters, appConfig.Micropub.PhotoDescriptionParam)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -487,17 +487,17 @@ func micropubUpdate(w http.ResponseWriter, r *http.Request, u *url.URL, mf *micr
|
||||||
if ok {
|
if ok {
|
||||||
switch key {
|
switch key {
|
||||||
case "content":
|
case "content":
|
||||||
post.Content = ""
|
p.Content = ""
|
||||||
case "published":
|
case "published":
|
||||||
post.Published = ""
|
p.Published = ""
|
||||||
case "updated":
|
case "updated":
|
||||||
post.Updated = ""
|
p.Updated = ""
|
||||||
case "in-reply-to":
|
case "in-reply-to":
|
||||||
delete(post.Parameters, appConfig.Micropub.ReplyParam)
|
delete(p.Parameters, appConfig.Micropub.ReplyParam)
|
||||||
case "like-of":
|
case "like-of":
|
||||||
delete(post.Parameters, appConfig.Micropub.LikeParam)
|
delete(p.Parameters, appConfig.Micropub.LikeParam)
|
||||||
case "bookmark-of":
|
case "bookmark-of":
|
||||||
delete(post.Parameters, appConfig.Micropub.BookmarkParam)
|
delete(p.Parameters, appConfig.Micropub.BookmarkParam)
|
||||||
// Use content to edit other parameters
|
// Use content to edit other parameters
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -505,12 +505,12 @@ func micropubUpdate(w http.ResponseWriter, r *http.Request, u *url.URL, mf *micr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = post.computeExtraPostParameters()
|
err = p.computeExtraPostParameters()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = post.replace()
|
err = p.replace()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
|
30
posts.go
30
posts.go
|
@ -16,7 +16,7 @@ import (
|
||||||
|
|
||||||
var errPostNotFound = errors.New("post not found")
|
var errPostNotFound = errors.New("post not found")
|
||||||
|
|
||||||
type Post struct {
|
type post struct {
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
Published string `json:"published"`
|
Published string `json:"published"`
|
||||||
|
@ -34,7 +34,7 @@ func servePost(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
path := slashTrimmedPath(r)
|
path := slashTrimmedPath(r)
|
||||||
post, err := getPost(r.Context(), path)
|
p, err := getPost(r.Context(), path)
|
||||||
if err == errPostNotFound {
|
if err == errPostNotFound {
|
||||||
serve404(w, r)
|
serve404(w, r)
|
||||||
return
|
return
|
||||||
|
@ -43,8 +43,8 @@ func servePost(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
render(w, templatePost, &renderData{
|
render(w, templatePost, &renderData{
|
||||||
blogString: post.Blog,
|
blogString: p.Blog,
|
||||||
Data: post,
|
Data: p,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ type indexTemplateData struct {
|
||||||
Blog string
|
Blog string
|
||||||
Title string
|
Title string
|
||||||
Description string
|
Description string
|
||||||
Posts []*Post
|
Posts []*post
|
||||||
HasPrev bool
|
HasPrev bool
|
||||||
HasNext bool
|
HasNext bool
|
||||||
First string
|
First string
|
||||||
|
@ -174,7 +174,7 @@ func serveIndex(ic *indexConfig) func(w http.ResponseWriter, r *http.Request) {
|
||||||
onlyWithParameter: ic.onlyWithParameter,
|
onlyWithParameter: ic.onlyWithParameter,
|
||||||
}}, appConfig.Blogs[ic.blog].Pagination)
|
}}, appConfig.Blogs[ic.blog].Pagination)
|
||||||
p.SetPage(pageNo)
|
p.SetPage(pageNo)
|
||||||
var posts []*Post
|
var posts []*post
|
||||||
err := p.Results(&posts)
|
err := p.Results(&posts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
@ -222,7 +222,7 @@ func serveIndex(ic *indexConfig) func(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPost(context context.Context, path string) (*Post, error) {
|
func getPost(context context.Context, path string) (*post, error) {
|
||||||
posts, err := getPosts(context, &postsRequestConfig{path: path})
|
posts, err := getPosts(context, &postsRequestConfig{path: path})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -243,7 +243,7 @@ type postsRequestConfig struct {
|
||||||
onlyWithParameter string
|
onlyWithParameter string
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPosts(context context.Context, config *postsRequestConfig) (posts []*Post, err error) {
|
func getPosts(context context.Context, config *postsRequestConfig) (posts []*post, err error) {
|
||||||
paths := make(map[string]int)
|
paths := make(map[string]int)
|
||||||
var rows *sql.Rows
|
var rows *sql.Rows
|
||||||
defaultSelection := "select p.path, coalesce(content, ''), coalesce(published, ''), coalesce(updated, ''), coalesce(blog, ''), coalesce(section, ''), coalesce(parameter, ''), coalesce(value, '') "
|
defaultSelection := "select p.path, coalesce(content, ''), coalesce(published, ''), coalesce(updated, ''), coalesce(blog, ''), coalesce(section, ''), coalesce(parameter, ''), coalesce(value, '') "
|
||||||
|
@ -286,20 +286,20 @@ func getPosts(context context.Context, config *postsRequestConfig) (posts []*Pos
|
||||||
_ = rows.Close()
|
_ = rows.Close()
|
||||||
}()
|
}()
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
post := &Post{}
|
p := &post{}
|
||||||
var parameterName, parameterValue string
|
var parameterName, parameterValue string
|
||||||
err = rows.Scan(&post.Path, &post.Content, &post.Published, &post.Updated, &post.Blog, &post.Section, ¶meterName, ¶meterValue)
|
err = rows.Scan(&p.Path, &p.Content, &p.Published, &p.Updated, &p.Blog, &p.Section, ¶meterName, ¶meterValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if paths[post.Path] == 0 {
|
if paths[p.Path] == 0 {
|
||||||
index := len(posts)
|
index := len(posts)
|
||||||
paths[post.Path] = index + 1
|
paths[p.Path] = index + 1
|
||||||
post.Parameters = make(map[string][]string)
|
p.Parameters = make(map[string][]string)
|
||||||
posts = append(posts, post)
|
posts = append(posts, p)
|
||||||
}
|
}
|
||||||
if parameterName != "" && posts != nil {
|
if parameterName != "" && posts != nil {
|
||||||
posts[paths[post.Path]-1].Parameters[parameterName] = append(posts[paths[post.Path]-1].Parameters[parameterName], parameterValue)
|
posts[paths[p.Path]-1].Parameters[parameterName] = append(posts[paths[p.Path]-1].Parameters[parameterName], parameterValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return posts, nil
|
return posts, nil
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"github.com/araddon/dateparse"
|
"github.com/araddon/dateparse"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *Post) checkPost() error {
|
func (p *post) checkPost() error {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return errors.New("no post")
|
return errors.New("no post")
|
||||||
}
|
}
|
||||||
|
@ -102,15 +102,15 @@ func (p *Post) checkPost() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Post) create() error {
|
func (p *post) create() error {
|
||||||
return p.createOrReplace(true)
|
return p.createOrReplace(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Post) replace() error {
|
func (p *post) replace() error {
|
||||||
return p.createOrReplace(false)
|
return p.createOrReplace(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Post) createOrReplace(new bool) error {
|
func (p *post) createOrReplace(new bool) error {
|
||||||
err := p.checkPost()
|
err := p.checkPost()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -1,22 +1,23 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/PuerkitoBio/goquery"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/PuerkitoBio/goquery"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *Post) firstParameter(parameter string) (result string) {
|
func (p *post) firstParameter(parameter string) (result string) {
|
||||||
if pp := p.Parameters[parameter]; len(pp) > 0 {
|
if pp := p.Parameters[parameter]; len(pp) > 0 {
|
||||||
result = pp[0]
|
result = pp[0]
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Post) title() string {
|
func (p *post) title() string {
|
||||||
return p.firstParameter("title")
|
return p.firstParameter("title")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Post) summary() (summary string) {
|
func (p *post) summary() (summary string) {
|
||||||
summary = p.firstParameter("summary")
|
summary = p.firstParameter("summary")
|
||||||
if summary != "" {
|
if summary != "" {
|
||||||
return
|
return
|
||||||
|
|
16
render.go
16
render.go
|
@ -45,18 +45,18 @@ func initRendering() error {
|
||||||
return template.HTML(htmlContent)
|
return template.HTML(htmlContent)
|
||||||
},
|
},
|
||||||
// First parameter value
|
// First parameter value
|
||||||
"p": func(post *Post, parameter string) string {
|
"p": func(p *post, parameter string) string {
|
||||||
return post.firstParameter(parameter)
|
return p.firstParameter(parameter)
|
||||||
},
|
},
|
||||||
// All parameter values
|
// All parameter values
|
||||||
"ps": func(post *Post, parameter string) []string {
|
"ps": func(p *post, parameter string) []string {
|
||||||
return post.Parameters[parameter]
|
return p.Parameters[parameter]
|
||||||
},
|
},
|
||||||
"title": func(post *Post) string {
|
"title": func(p *post) string {
|
||||||
return post.title()
|
return p.title()
|
||||||
},
|
},
|
||||||
"summary": func(post *Post) string {
|
"summary": func(p *post) string {
|
||||||
return post.summary()
|
return p.summary()
|
||||||
},
|
},
|
||||||
"dateformat": func(date string, format string) string {
|
"dateformat": func(date string, format string) string {
|
||||||
d, err := dateparse.ParseIn(date, time.Local)
|
d, err := dateparse.ParseIn(date, time.Local)
|
||||||
|
|
19
sitemap.go
19
sitemap.go
|
@ -1,10 +1,11 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/araddon/dateparse"
|
|
||||||
"github.com/snabb/sitemap"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/araddon/dateparse"
|
||||||
|
"github.com/snabb/sitemap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func serveSitemap() func(w http.ResponseWriter, r *http.Request) {
|
func serveSitemap() func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -16,19 +17,19 @@ func serveSitemap() func(w http.ResponseWriter, r *http.Request) {
|
||||||
sm := sitemap.New()
|
sm := sitemap.New()
|
||||||
sm.Minify = true
|
sm.Minify = true
|
||||||
for _, p := range posts {
|
for _, p := range posts {
|
||||||
|
item := &sitemap.URL{
|
||||||
|
Loc: appConfig.Server.PublicAddress + p.Path}
|
||||||
var lastMod time.Time
|
var lastMod time.Time
|
||||||
if p.Updated != "" {
|
if p.Updated != "" {
|
||||||
lastMod, _ = dateparse.ParseIn(p.Updated, time.Local)
|
lastMod, _ = dateparse.ParseIn(p.Updated, time.Local)
|
||||||
} else if p.Published != "" {
|
}
|
||||||
|
if p.Published != "" && lastMod.IsZero() {
|
||||||
lastMod, _ = dateparse.ParseIn(p.Published, time.Local)
|
lastMod, _ = dateparse.ParseIn(p.Published, time.Local)
|
||||||
}
|
}
|
||||||
if lastMod.IsZero() {
|
if !lastMod.IsZero() {
|
||||||
lastMod = time.Now()
|
item.LastMod = &lastMod
|
||||||
}
|
}
|
||||||
sm.Add(&sitemap.URL{
|
sm.Add(item)
|
||||||
Loc: appConfig.Server.PublicAddress + p.Path,
|
|
||||||
LastMod: &lastMod,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
_, _ = sm.WriteTo(w)
|
_, _ = sm.WriteTo(w)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue