Post-post and post-delete hooks

This commit is contained in:
Jan-Lukas Else 2020-10-19 20:25:30 +02:00
parent 141fe3485f
commit 96259912cb
10 changed files with 74 additions and 33 deletions

View File

@ -43,7 +43,7 @@ func servePostActivityStreams(w http.ResponseWriter, r *http.Request) {
// Remove ".as" from path again
r.URL.Path = strings.TrimSuffix(r.URL.Path, ".as")
// Fetch post from db
p, err := getPost(r.Context(), slashTrimmedPath(r))
p, err := getPost(slashTrimmedPath(r))
if err == errPostNotFound {
serve404(w, r)
return

View File

@ -1,7 +1,6 @@
package main
import (
"context"
"database/sql"
"net/http"
"net/http/httptest"
@ -61,7 +60,7 @@ func cacheMiddleware(next http.Handler) http.Handler {
// Get cache
cm := cacheMutexes[path]
cm.Lock()
cacheTime, header, body := getCache(r.Context(), path)
cacheTime, header, body := getCache(path)
cm.Unlock()
if cacheTime == 0 {
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
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)
header = make(map[string][]string)
_ = json.Unmarshal(headerBytes, &header)

View File

@ -108,6 +108,9 @@ type configHooks struct {
Shell string `mapstructure:"shell"`
Hourly []string `mapstructure:"hourly"`
PreStart []string `mapstructure:"prestart"`
// Can use template
PostPost []string `mapstructure:"postpost"`
PostDelete []string `mapstructure:"postdelete"`
}
type configHugo struct {

View File

@ -1,6 +1,8 @@
package main
import (
"bytes"
"html/template"
"log"
"os/exec"
"time"
@ -8,11 +10,50 @@ import (
func preStartHooks() {
for _, cmd := range appConfig.Hooks.PreStart {
log.Println("Executing pre-start hook:", cmd)
executeCommand(cmd)
go func(cmd string) {
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() {
for _, cmd := range appConfig.Hooks.Hourly {
go func(cmd string) {
@ -21,11 +62,11 @@ func startHourlyHooks() {
executeCommand(cmd)
}
// Execute once
run()
go run()
// Start ticker and execute regularly
ticker := time.NewTicker(1 * time.Hour)
for range ticker.C {
run()
go run()
}
}(cmd)
}

View File

@ -38,14 +38,14 @@ func serveMicropubQuery(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
p, err := getPost(r.Context(), u.Path)
p, err := getPost(u.Path)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
mf = p.toMfItem()
} else {
posts, err := getPosts(r.Context(), &postsRequestConfig{})
posts, err := getPosts(&postsRequestConfig{})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
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") {
http.Error(w, "update scope missing", http.StatusForbidden)
}
p, err := getPost(r.Context(), u.Path)
p, err := getPost(u.Path)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return

View File

@ -1,7 +1,6 @@
package main
import (
"context"
"errors"
"fmt"
"html/template"
@ -35,7 +34,7 @@ func servePost(w http.ResponseWriter, r *http.Request) {
return
}
path := slashTrimmedPath(r)
p, err := getPost(r.Context(), path)
p, err := getPost(path)
if err == errPostNotFound {
serve404(w, r)
return
@ -62,14 +61,13 @@ type indexTemplateData struct {
}
type postPaginationAdapter struct {
context context.Context
config *postsRequestConfig
nums int
config *postsRequestConfig
nums int
}
func (p *postPaginationAdapter) Nums() int {
if p.nums == 0 {
p.nums, _ = countPosts(p.context, p.config)
p.nums, _ = countPosts(p.config)
}
return p.nums
}
@ -83,7 +81,7 @@ func (p *postPaginationAdapter) Slice(offset, length int, data interface{}) erro
modifiedConfig.offset = offset
modifiedConfig.limit = length
posts, err := getPosts(p.context, &modifiedConfig)
posts, err := getPosts(&modifiedConfig)
reflect.ValueOf(data).Elem().Set(reflect.ValueOf(&posts).Elem())
return err
}
@ -163,7 +161,7 @@ func serveIndex(ic *indexConfig) func(w http.ResponseWriter, r *http.Request) {
sections = append(sections, sectionKey)
}
}
p := paginator.New(&postPaginationAdapter{context: r.Context(), config: &postsRequestConfig{
p := paginator.New(&postPaginationAdapter{config: &postsRequestConfig{
blog: ic.blog,
sections: sections,
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) {
posts, err := getPosts(context, &postsRequestConfig{path: path})
func getPost(path string) (*post, error) {
posts, err := getPosts(&postsRequestConfig{path: path})
if err != nil {
return nil, err
} else if len(posts) == 0 {
@ -281,9 +279,9 @@ func buildQuery(config *postsRequestConfig) (query string, params []interface{})
return
}
func getPosts(context context.Context, config *postsRequestConfig) (posts []*post, err error) {
func getPosts(config *postsRequestConfig) (posts []*post, err error) {
query, queryParams := buildQuery(config)
rows, err := appDb.QueryContext(context, query, queryParams...)
rows, err := appDb.Query(query, queryParams...)
if err != nil {
return nil, err
}
@ -311,10 +309,10 @@ func getPosts(context context.Context, config *postsRequestConfig) (posts []*pos
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 = "select count(distinct path) from (" + query + ")"
row := appDb.QueryRowContext(context, query, params...)
row := appDb.QueryRow(query, params...)
err = row.Scan(&count)
return
}

View File

@ -156,6 +156,7 @@ func (p *post) createOrReplace(new bool) error {
}
finishWritingToDb()
go purgeCache()
defer postPostHooks(p.Path)
return reloadRouter()
}
@ -188,5 +189,6 @@ func deletePost(path string) error {
}
finishWritingToDb()
go purgeCache()
defer postDeleteHooks(path)
return reloadRouter()
}

View File

@ -1,7 +1,6 @@
package main
import (
"context"
"html/template"
"log"
"strings"
@ -56,7 +55,7 @@ func (p *post) translations() []*post {
if translationkey == "" {
return nil
}
posts, err := getPosts(context.Background(), &postsRequestConfig{
posts, err := getPosts(&postsRequestConfig{
parameter: "translationkey",
parameterValue: translationkey,
})

View File

@ -1,7 +1,6 @@
package main
import (
"context"
"database/sql"
"errors"
"net/http"
@ -11,7 +10,7 @@ import (
var errRedirectNotFound = errors.New("redirect not found")
func serveRedirect(w http.ResponseWriter, r *http.Request) {
redirect, err := getRedirect(r.Context(), slashTrimmedPath(r))
redirect, err := getRedirect(slashTrimmedPath(r))
if err == errRedirectNotFound {
serve404(w, r)
return
@ -27,9 +26,9 @@ func serveRedirect(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusFound)
}
func getRedirect(context context.Context, fromPath string) (string, error) {
func getRedirect(fromPath string) (string, error) {
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)
if err == sql.ErrNoRows {
return "", errRedirectNotFound

View File

@ -11,7 +11,7 @@ import (
const sitemapPath = "/sitemap.xml"
func serveSitemap(w http.ResponseWriter, r *http.Request) {
posts, err := getPosts(r.Context(), &postsRequestConfig{})
posts, err := getPosts(&postsRequestConfig{})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}