mirror of https://github.com/jlelse/GoBlog
Post-post and post-delete hooks
This commit is contained in:
parent
141fe3485f
commit
96259912cb
|
@ -43,7 +43,7 @@ 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
|
||||||
p, err := getPost(r.Context(), slashTrimmedPath(r))
|
p, err := getPost(slashTrimmedPath(r))
|
||||||
if err == errPostNotFound {
|
if err == errPostNotFound {
|
||||||
serve404(w, r)
|
serve404(w, r)
|
||||||
return
|
return
|
||||||
|
|
7
cache.go
7
cache.go
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
@ -61,7 +60,7 @@ func cacheMiddleware(next http.Handler) http.Handler {
|
||||||
// Get cache
|
// Get cache
|
||||||
cm := cacheMutexes[path]
|
cm := cacheMutexes[path]
|
||||||
cm.Lock()
|
cm.Lock()
|
||||||
cacheTime, header, body := getCache(r.Context(), path)
|
cacheTime, header, body := getCache(path)
|
||||||
cm.Unlock()
|
cm.Unlock()
|
||||||
if cacheTime == 0 {
|
if cacheTime == 0 {
|
||||||
cm.Lock()
|
cm.Lock()
|
||||||
|
@ -122,10 +121,10 @@ func renderCache(path string, next http.Handler, w http.ResponseWriter, r *http.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCache(context context.Context, path string) (creationTime int64, header map[string][]string, body []byte) {
|
func getCache(path string) (creationTime int64, header map[string][]string, body []byte) {
|
||||||
var headerBytes []byte
|
var headerBytes []byte
|
||||||
allowedTime := time.Now().Unix() - appConfig.Cache.Expiration
|
allowedTime := time.Now().Unix() - appConfig.Cache.Expiration
|
||||||
row := cacheDb.QueryRowContext(context, "select COALESCE(time, 0), header, body from cache where path=? and time>=?", path, allowedTime)
|
row := cacheDb.QueryRow("select COALESCE(time, 0), header, body from cache where path=? and time>=?", path, allowedTime)
|
||||||
_ = row.Scan(&creationTime, &headerBytes, &body)
|
_ = row.Scan(&creationTime, &headerBytes, &body)
|
||||||
header = make(map[string][]string)
|
header = make(map[string][]string)
|
||||||
_ = json.Unmarshal(headerBytes, &header)
|
_ = json.Unmarshal(headerBytes, &header)
|
||||||
|
|
|
@ -108,6 +108,9 @@ type configHooks struct {
|
||||||
Shell string `mapstructure:"shell"`
|
Shell string `mapstructure:"shell"`
|
||||||
Hourly []string `mapstructure:"hourly"`
|
Hourly []string `mapstructure:"hourly"`
|
||||||
PreStart []string `mapstructure:"prestart"`
|
PreStart []string `mapstructure:"prestart"`
|
||||||
|
// Can use template
|
||||||
|
PostPost []string `mapstructure:"postpost"`
|
||||||
|
PostDelete []string `mapstructure:"postdelete"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type configHugo struct {
|
type configHugo struct {
|
||||||
|
|
49
hooks.go
49
hooks.go
|
@ -1,6 +1,8 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"html/template"
|
||||||
"log"
|
"log"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"time"
|
"time"
|
||||||
|
@ -8,11 +10,50 @@ import (
|
||||||
|
|
||||||
func preStartHooks() {
|
func preStartHooks() {
|
||||||
for _, cmd := range appConfig.Hooks.PreStart {
|
for _, cmd := range appConfig.Hooks.PreStart {
|
||||||
log.Println("Executing pre-start hook:", cmd)
|
go func(cmd string) {
|
||||||
executeCommand(cmd)
|
log.Println("Executing pre-start hook:", cmd)
|
||||||
|
executeCommand(cmd)
|
||||||
|
}(cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func postPostHooks(path string) {
|
||||||
|
for _, cmdTmplString := range appConfig.Hooks.PostPost {
|
||||||
|
go func(path, cmdTmplString string) {
|
||||||
|
executeTemplateCommand("post-post", cmdTmplString, &hookTemplateData{
|
||||||
|
URL: appConfig.Server.PublicAddress + path,
|
||||||
|
})
|
||||||
|
}(path, cmdTmplString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func postDeleteHooks(path string) {
|
||||||
|
for _, cmdTmplString := range appConfig.Hooks.PostDelete {
|
||||||
|
go func(path, cmdTmplString string) {
|
||||||
|
executeTemplateCommand("post-delete", cmdTmplString, &hookTemplateData{
|
||||||
|
URL: appConfig.Server.PublicAddress + path,
|
||||||
|
})
|
||||||
|
}(path, cmdTmplString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type hookTemplateData struct {
|
||||||
|
URL string
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeTemplateCommand(hookType string, tmpl string, data *hookTemplateData) {
|
||||||
|
cmdTmpl, err := template.New("cmd").Parse(tmpl)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Failed to parse cmd template:", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var cmdBuf bytes.Buffer
|
||||||
|
cmdTmpl.Execute(&cmdBuf, data)
|
||||||
|
cmd := cmdBuf.String()
|
||||||
|
log.Println("Executing "+hookType+" hook:", cmd)
|
||||||
|
executeCommand(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
func startHourlyHooks() {
|
func startHourlyHooks() {
|
||||||
for _, cmd := range appConfig.Hooks.Hourly {
|
for _, cmd := range appConfig.Hooks.Hourly {
|
||||||
go func(cmd string) {
|
go func(cmd string) {
|
||||||
|
@ -21,11 +62,11 @@ func startHourlyHooks() {
|
||||||
executeCommand(cmd)
|
executeCommand(cmd)
|
||||||
}
|
}
|
||||||
// Execute once
|
// Execute once
|
||||||
run()
|
go run()
|
||||||
// Start ticker and execute regularly
|
// Start ticker and execute regularly
|
||||||
ticker := time.NewTicker(1 * time.Hour)
|
ticker := time.NewTicker(1 * time.Hour)
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
run()
|
go run()
|
||||||
}
|
}
|
||||||
}(cmd)
|
}(cmd)
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,14 +38,14 @@ func serveMicropubQuery(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p, err := getPost(r.Context(), u.Path)
|
p, err := getPost(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 = p.toMfItem()
|
mf = p.toMfItem()
|
||||||
} else {
|
} else {
|
||||||
posts, err := getPosts(r.Context(), &postsRequestConfig{})
|
posts, err := getPosts(&postsRequestConfig{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
p, err := getPost(r.Context(), u.Path)
|
p, err := getPost(u.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
|
|
26
posts.go
26
posts.go
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
@ -35,7 +34,7 @@ func servePost(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
path := slashTrimmedPath(r)
|
path := slashTrimmedPath(r)
|
||||||
p, err := getPost(r.Context(), path)
|
p, err := getPost(path)
|
||||||
if err == errPostNotFound {
|
if err == errPostNotFound {
|
||||||
serve404(w, r)
|
serve404(w, r)
|
||||||
return
|
return
|
||||||
|
@ -62,14 +61,13 @@ type indexTemplateData struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type postPaginationAdapter struct {
|
type postPaginationAdapter struct {
|
||||||
context context.Context
|
config *postsRequestConfig
|
||||||
config *postsRequestConfig
|
nums int
|
||||||
nums int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *postPaginationAdapter) Nums() int {
|
func (p *postPaginationAdapter) Nums() int {
|
||||||
if p.nums == 0 {
|
if p.nums == 0 {
|
||||||
p.nums, _ = countPosts(p.context, p.config)
|
p.nums, _ = countPosts(p.config)
|
||||||
}
|
}
|
||||||
return p.nums
|
return p.nums
|
||||||
}
|
}
|
||||||
|
@ -83,7 +81,7 @@ func (p *postPaginationAdapter) Slice(offset, length int, data interface{}) erro
|
||||||
modifiedConfig.offset = offset
|
modifiedConfig.offset = offset
|
||||||
modifiedConfig.limit = length
|
modifiedConfig.limit = length
|
||||||
|
|
||||||
posts, err := getPosts(p.context, &modifiedConfig)
|
posts, err := getPosts(&modifiedConfig)
|
||||||
reflect.ValueOf(data).Elem().Set(reflect.ValueOf(&posts).Elem())
|
reflect.ValueOf(data).Elem().Set(reflect.ValueOf(&posts).Elem())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -163,7 +161,7 @@ func serveIndex(ic *indexConfig) func(w http.ResponseWriter, r *http.Request) {
|
||||||
sections = append(sections, sectionKey)
|
sections = append(sections, sectionKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p := paginator.New(&postPaginationAdapter{context: r.Context(), config: &postsRequestConfig{
|
p := paginator.New(&postPaginationAdapter{config: &postsRequestConfig{
|
||||||
blog: ic.blog,
|
blog: ic.blog,
|
||||||
sections: sections,
|
sections: sections,
|
||||||
taxonomy: ic.tax,
|
taxonomy: ic.tax,
|
||||||
|
@ -219,8 +217,8 @@ func serveIndex(ic *indexConfig) func(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPost(context context.Context, path string) (*post, error) {
|
func getPost(path string) (*post, error) {
|
||||||
posts, err := getPosts(context, &postsRequestConfig{path: path})
|
posts, err := getPosts(&postsRequestConfig{path: path})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if len(posts) == 0 {
|
} else if len(posts) == 0 {
|
||||||
|
@ -281,9 +279,9 @@ func buildQuery(config *postsRequestConfig) (query string, params []interface{})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPosts(context context.Context, config *postsRequestConfig) (posts []*post, err error) {
|
func getPosts(config *postsRequestConfig) (posts []*post, err error) {
|
||||||
query, queryParams := buildQuery(config)
|
query, queryParams := buildQuery(config)
|
||||||
rows, err := appDb.QueryContext(context, query, queryParams...)
|
rows, err := appDb.Query(query, queryParams...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -311,10 +309,10 @@ func getPosts(context context.Context, config *postsRequestConfig) (posts []*pos
|
||||||
return posts, nil
|
return posts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func countPosts(context context.Context, config *postsRequestConfig) (count int, err error) {
|
func countPosts(config *postsRequestConfig) (count int, err error) {
|
||||||
query, params := buildQuery(config)
|
query, params := buildQuery(config)
|
||||||
query = "select count(distinct path) from (" + query + ")"
|
query = "select count(distinct path) from (" + query + ")"
|
||||||
row := appDb.QueryRowContext(context, query, params...)
|
row := appDb.QueryRow(query, params...)
|
||||||
err = row.Scan(&count)
|
err = row.Scan(&count)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,6 +156,7 @@ func (p *post) createOrReplace(new bool) error {
|
||||||
}
|
}
|
||||||
finishWritingToDb()
|
finishWritingToDb()
|
||||||
go purgeCache()
|
go purgeCache()
|
||||||
|
defer postPostHooks(p.Path)
|
||||||
return reloadRouter()
|
return reloadRouter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,5 +189,6 @@ func deletePost(path string) error {
|
||||||
}
|
}
|
||||||
finishWritingToDb()
|
finishWritingToDb()
|
||||||
go purgeCache()
|
go purgeCache()
|
||||||
|
defer postDeleteHooks(path)
|
||||||
return reloadRouter()
|
return reloadRouter()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"html/template"
|
"html/template"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -56,7 +55,7 @@ func (p *post) translations() []*post {
|
||||||
if translationkey == "" {
|
if translationkey == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
posts, err := getPosts(context.Background(), &postsRequestConfig{
|
posts, err := getPosts(&postsRequestConfig{
|
||||||
parameter: "translationkey",
|
parameter: "translationkey",
|
||||||
parameterValue: translationkey,
|
parameterValue: translationkey,
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -11,7 +10,7 @@ import (
|
||||||
var errRedirectNotFound = errors.New("redirect not found")
|
var errRedirectNotFound = errors.New("redirect not found")
|
||||||
|
|
||||||
func serveRedirect(w http.ResponseWriter, r *http.Request) {
|
func serveRedirect(w http.ResponseWriter, r *http.Request) {
|
||||||
redirect, err := getRedirect(r.Context(), slashTrimmedPath(r))
|
redirect, err := getRedirect(slashTrimmedPath(r))
|
||||||
if err == errRedirectNotFound {
|
if err == errRedirectNotFound {
|
||||||
serve404(w, r)
|
serve404(w, r)
|
||||||
return
|
return
|
||||||
|
@ -27,9 +26,9 @@ func serveRedirect(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusFound)
|
w.WriteHeader(http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRedirect(context context.Context, fromPath string) (string, error) {
|
func getRedirect(fromPath string) (string, error) {
|
||||||
var toPath string
|
var toPath string
|
||||||
row := appDb.QueryRowContext(context, "with recursive f (i, fp, tp) as (select 1, fromPath, toPath from redirects where fromPath = ? union all select f.i + 1, r.fromPath, r.toPath from redirects as r join f on f.tp = r.fromPath) select tp from f order by i desc limit 1", fromPath)
|
row := appDb.QueryRow("with recursive f (i, fp, tp) as (select 1, fromPath, toPath from redirects where fromPath = ? union all select f.i + 1, r.fromPath, r.toPath from redirects as r join f on f.tp = r.fromPath) select tp from f order by i desc limit 1", fromPath)
|
||||||
err := row.Scan(&toPath)
|
err := row.Scan(&toPath)
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return "", errRedirectNotFound
|
return "", errRedirectNotFound
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
const sitemapPath = "/sitemap.xml"
|
const sitemapPath = "/sitemap.xml"
|
||||||
|
|
||||||
func serveSitemap(w http.ResponseWriter, r *http.Request) {
|
func serveSitemap(w http.ResponseWriter, r *http.Request) {
|
||||||
posts, err := getPosts(r.Context(), &postsRequestConfig{})
|
posts, err := getPosts(&postsRequestConfig{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue