mirror of https://github.com/jlelse/GoBlog
Go 1.18
This commit is contained in:
parent
7e8cb619b5
commit
474155306d
|
@ -1,4 +1,4 @@
|
|||
FROM golang:1.17-alpine3.15 as buildbase
|
||||
FROM golang:1.18-alpine3.15 as buildbase
|
||||
|
||||
WORKDIR /app
|
||||
RUN apk add --no-cache git gcc musl-dev
|
||||
|
|
|
@ -89,7 +89,7 @@ func (a *goBlog) apHandleWebfinger(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
apIri := a.apIri(blog)
|
||||
b, _ := json.Marshal(map[string]interface{}{
|
||||
b, _ := json.Marshal(map[string]any{
|
||||
"subject": a.webfingerAccts[apIri],
|
||||
"aliases": []string{
|
||||
a.webfingerAccts[apIri],
|
||||
|
@ -142,7 +142,7 @@ func (a *goBlog) apHandleInbox(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
// Parse activity
|
||||
activity := map[string]interface{}{}
|
||||
activity := map[string]any{}
|
||||
err = json.NewDecoder(r.Body).Decode(&activity)
|
||||
_ = r.Body.Close()
|
||||
if err != nil {
|
||||
|
@ -164,7 +164,7 @@ func (a *goBlog) apHandleInbox(w http.ResponseWriter, r *http.Request) {
|
|||
case "Follow":
|
||||
a.apAccept(blogName, blog, activity)
|
||||
case "Undo":
|
||||
if object, ok := activity["object"].(map[string]interface{}); ok {
|
||||
if object, ok := activity["object"].(map[string]any); ok {
|
||||
ot := cast.ToString(object["type"])
|
||||
actor := cast.ToString(object["actor"])
|
||||
if ot == "Follow" && actor == activityActor {
|
||||
|
@ -172,7 +172,7 @@ func (a *goBlog) apHandleInbox(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
case "Create":
|
||||
if object, ok := activity["object"].(map[string]interface{}); ok {
|
||||
if object, ok := activity["object"].(map[string]any); ok {
|
||||
baseUrl := cast.ToString(object["id"])
|
||||
if ou := cast.ToString(object["url"]); ou != "" {
|
||||
baseUrl = ou
|
||||
|
@ -297,7 +297,7 @@ func (db *database) apRemoveInbox(inbox string) error {
|
|||
|
||||
func (a *goBlog) apPost(p *post) {
|
||||
n := a.toASNote(p)
|
||||
a.apSendToAllFollowers(p.Blog, map[string]interface{}{
|
||||
a.apSendToAllFollowers(p.Blog, map[string]any{
|
||||
"@context": []string{asContext},
|
||||
"actor": a.apIri(a.cfg.Blogs[p.Blog]),
|
||||
"id": a.fullPostURL(p),
|
||||
|
@ -308,7 +308,7 @@ func (a *goBlog) apPost(p *post) {
|
|||
}
|
||||
|
||||
func (a *goBlog) apUpdate(p *post) {
|
||||
a.apSendToAllFollowers(p.Blog, map[string]interface{}{
|
||||
a.apSendToAllFollowers(p.Blog, map[string]any{
|
||||
"@context": []string{asContext},
|
||||
"actor": a.apIri(a.cfg.Blogs[p.Blog]),
|
||||
"id": a.fullPostURL(p),
|
||||
|
@ -319,7 +319,7 @@ func (a *goBlog) apUpdate(p *post) {
|
|||
}
|
||||
|
||||
func (a *goBlog) apDelete(p *post) {
|
||||
a.apSendToAllFollowers(p.Blog, map[string]interface{}{
|
||||
a.apSendToAllFollowers(p.Blog, map[string]any{
|
||||
"@context": []string{asContext},
|
||||
"actor": a.apIri(a.cfg.Blogs[p.Blog]),
|
||||
"type": "Delete",
|
||||
|
@ -328,11 +328,11 @@ func (a *goBlog) apDelete(p *post) {
|
|||
}
|
||||
|
||||
func (a *goBlog) apUndelete(p *post) {
|
||||
a.apSendToAllFollowers(p.Blog, map[string]interface{}{
|
||||
a.apSendToAllFollowers(p.Blog, map[string]any{
|
||||
"@context": []string{asContext},
|
||||
"actor": a.apIri(a.cfg.Blogs[p.Blog]),
|
||||
"type": "Undo",
|
||||
"object": map[string]interface{}{
|
||||
"object": map[string]any{
|
||||
"@context": []string{asContext},
|
||||
"actor": a.apIri(a.cfg.Blogs[p.Blog]),
|
||||
"type": "Delete",
|
||||
|
@ -341,7 +341,7 @@ func (a *goBlog) apUndelete(p *post) {
|
|||
})
|
||||
}
|
||||
|
||||
func (a *goBlog) apAccept(blogName string, blog *configBlog, follow map[string]interface{}) {
|
||||
func (a *goBlog) apAccept(blogName string, blog *configBlog, follow map[string]any) {
|
||||
// it's a follow, write it down
|
||||
newFollower := follow["actor"].(string)
|
||||
log.Println("New follow request:", newFollower)
|
||||
|
@ -365,7 +365,7 @@ func (a *goBlog) apAccept(blogName string, blog *configBlog, follow map[string]i
|
|||
return
|
||||
}
|
||||
// Send accept response to the new follower
|
||||
accept := map[string]interface{}{
|
||||
accept := map[string]any{
|
||||
"@context": []string{asContext},
|
||||
"type": "Accept",
|
||||
"to": follow["actor"],
|
||||
|
@ -376,7 +376,7 @@ func (a *goBlog) apAccept(blogName string, blog *configBlog, follow map[string]i
|
|||
_ = a.db.apQueueSendSigned(a.apIri(blog), inbox, accept)
|
||||
}
|
||||
|
||||
func (a *goBlog) apSendToAllFollowers(blog string, activity interface{}) {
|
||||
func (a *goBlog) apSendToAllFollowers(blog string, activity any) {
|
||||
inboxes, err := a.db.apGetAllInboxes(blog)
|
||||
if err != nil {
|
||||
log.Println("Failed to retrieve inboxes:", err.Error())
|
||||
|
@ -385,7 +385,7 @@ func (a *goBlog) apSendToAllFollowers(blog string, activity interface{}) {
|
|||
a.db.apSendTo(a.apIri(a.cfg.Blogs[blog]), activity, inboxes)
|
||||
}
|
||||
|
||||
func (db *database) apSendTo(blogIri string, activity interface{}, inboxes []string) {
|
||||
func (db *database) apSendTo(blogIri string, activity any, inboxes []string) {
|
||||
for _, i := range inboxes {
|
||||
go func(inbox string) {
|
||||
_ = db.apQueueSendSigned(blogIri, inbox, activity)
|
||||
|
|
|
@ -47,7 +47,7 @@ func (a *goBlog) initAPSendQueue() {
|
|||
})
|
||||
}
|
||||
|
||||
func (db *database) apQueueSendSigned(blogIri, to string, activity interface{}) error {
|
||||
func (db *database) apQueueSendSigned(blogIri, to string, activity any) error {
|
||||
body, err := json.Marshal(activity)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -38,7 +38,7 @@ func (a *goBlog) checkActivityStreamsRequest(next http.Handler) http.Handler {
|
|||
}
|
||||
|
||||
type asNote struct {
|
||||
Context interface{} `json:"@context,omitempty"`
|
||||
Context any `json:"@context,omitempty"`
|
||||
To []string `json:"to,omitempty"`
|
||||
InReplyTo string `json:"inReplyTo,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
|
@ -55,7 +55,7 @@ type asNote struct {
|
|||
}
|
||||
|
||||
type asPerson struct {
|
||||
Context interface{} `json:"@context,omitempty"`
|
||||
Context any `json:"@context,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
|
|
10
blogroll.go
10
blogroll.go
|
@ -11,7 +11,7 @@ import (
|
|||
|
||||
"github.com/carlmjohnson/requests"
|
||||
"github.com/kaorimatz/go-opml"
|
||||
"github.com/thoas/go-funk"
|
||||
"github.com/samber/lo"
|
||||
"go.goblog.app/app/pkgs/bufferpool"
|
||||
"go.goblog.app/app/pkgs/contenttype"
|
||||
)
|
||||
|
@ -20,7 +20,7 @@ const defaultBlogrollPath = "/blogroll"
|
|||
|
||||
func (a *goBlog) serveBlogroll(w http.ResponseWriter, r *http.Request) {
|
||||
blog, bc := a.getBlog(r)
|
||||
outlines, err, _ := a.blogrollCacheGroup.Do(blog, func() (interface{}, error) {
|
||||
outlines, err, _ := a.blogrollCacheGroup.Do(blog, func() (any, error) {
|
||||
return a.getBlogrollOutlines(blog)
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -43,7 +43,7 @@ func (a *goBlog) serveBlogroll(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
func (a *goBlog) serveBlogrollExport(w http.ResponseWriter, r *http.Request) {
|
||||
blog, _ := a.getBlog(r)
|
||||
outlines, err, _ := a.blogrollCacheGroup.Do(blog, func() (interface{}, error) {
|
||||
outlines, err, _ := a.blogrollCacheGroup.Do(blog, func() (any, error) {
|
||||
return a.getBlogrollOutlines(blog)
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -91,9 +91,9 @@ func (a *goBlog) getBlogrollOutlines(blog string) ([]*opml.Outline, error) {
|
|||
if len(config.Categories) > 0 {
|
||||
filtered := []*opml.Outline{}
|
||||
for _, category := range config.Categories {
|
||||
if outline, ok := funk.Find(outlines, func(outline *opml.Outline) bool {
|
||||
if outline, ok := lo.Find(outlines, func(outline *opml.Outline) bool {
|
||||
return outline.Title == category || outline.Text == category
|
||||
}).(*opml.Outline); ok && outline != nil {
|
||||
}); ok && outline != nil {
|
||||
outline.Outlines = sortOutlines(outline.Outlines)
|
||||
filtered = append(filtered, outline)
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ func (a *goBlog) serveBlogStats(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
func (a *goBlog) serveBlogStatsTable(w http.ResponseWriter, r *http.Request) {
|
||||
blog, _ := a.getBlog(r)
|
||||
data, err, _ := a.blogStatsCacheGroup.Do(blog, func() (interface{}, error) {
|
||||
data, err, _ := a.blogStatsCacheGroup.Do(blog, func() (any, error) {
|
||||
return a.db.getBlogStats(blog)
|
||||
})
|
||||
if err != nil {
|
||||
|
|
2
cache.go
2
cache.go
|
@ -76,7 +76,7 @@ func (a *goBlog) cacheMiddleware(next http.Handler) http.Handler {
|
|||
// Search and serve cache
|
||||
key := cacheKey(r)
|
||||
// Get cache or render it
|
||||
cacheInterface, _, _ := a.cache.g.Do(key, func() (interface{}, error) {
|
||||
cacheInterface, _, _ := a.cache.g.Do(key, func() (any, error) {
|
||||
return a.cache.getCache(key, next, r), nil
|
||||
})
|
||||
ci := cacheInterface.(*cacheItem)
|
||||
|
|
9
check.go
9
check.go
|
@ -12,6 +12,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/klauspost/compress/gzhttp"
|
||||
"github.com/samber/lo"
|
||||
"go.goblog.app/app/pkgs/bufferpool"
|
||||
"golang.org/x/sync/singleflight"
|
||||
)
|
||||
|
@ -79,7 +80,7 @@ func (a *goBlog) checkLinks(w io.Writer, posts ...*post) error {
|
|||
return
|
||||
}
|
||||
// Process link
|
||||
r, err, _ := sg.Do(link.Second, func() (interface{}, error) {
|
||||
r, err, _ := sg.Do(link.Second, func() (any, error) {
|
||||
// Check if already cached
|
||||
if mr, ok := sm.Load(link.Second); ok {
|
||||
return mr, nil
|
||||
|
@ -131,9 +132,9 @@ func (a *goBlog) allLinks(posts ...*post) (allLinks []*stringPair, err error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, link := range links {
|
||||
allLinks = append(allLinks, &stringPair{a.fullPostURL(p), link})
|
||||
}
|
||||
allLinks = lo.Map(links, func(s string, _ int) *stringPair {
|
||||
return &stringPair{a.fullPostURL(p), s}
|
||||
})
|
||||
}
|
||||
return allLinks, nil
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ type commentsRequestConfig struct {
|
|||
offset, limit int
|
||||
}
|
||||
|
||||
func buildCommentsQuery(config *commentsRequestConfig) (query string, args []interface{}) {
|
||||
func buildCommentsQuery(config *commentsRequestConfig) (query string, args []any) {
|
||||
queryBuilder := bufferpool.Get()
|
||||
defer bufferpool.Put(queryBuilder)
|
||||
queryBuilder.WriteString("select id, target, name, website, comment from comments order by id desc")
|
||||
|
|
|
@ -5,26 +5,28 @@ import (
|
|||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/vcraescu/go-paginator"
|
||||
)
|
||||
|
||||
type commentsPaginationAdapter struct {
|
||||
config *commentsRequestConfig
|
||||
nums int64
|
||||
db *database
|
||||
config *commentsRequestConfig
|
||||
nums int64
|
||||
getNums sync.Once
|
||||
db *database
|
||||
}
|
||||
|
||||
func (p *commentsPaginationAdapter) Nums() (int64, error) {
|
||||
if p.nums == 0 {
|
||||
p.getNums.Do(func() {
|
||||
nums, _ := p.db.countComments(p.config)
|
||||
p.nums = int64(nums)
|
||||
}
|
||||
})
|
||||
return p.nums, nil
|
||||
}
|
||||
|
||||
func (p *commentsPaginationAdapter) Slice(offset, length int, data interface{}) error {
|
||||
func (p *commentsPaginationAdapter) Slice(offset, length int, data any) error {
|
||||
modifiedConfig := *p.config
|
||||
modifiedConfig.offset = offset
|
||||
modifiedConfig.limit = length
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
|
@ -370,9 +371,7 @@ func (a *goBlog) initConfig() error {
|
|||
if a.cfg.DefaultBlog == "" {
|
||||
if len(a.cfg.Blogs) == 1 {
|
||||
// Set default blog to the only blog that is configured
|
||||
for k := range a.cfg.Blogs {
|
||||
a.cfg.DefaultBlog = k
|
||||
}
|
||||
a.cfg.DefaultBlog = lo.Keys(a.cfg.Blogs)[0]
|
||||
} else {
|
||||
return errors.New("no default blog configured")
|
||||
}
|
||||
|
|
18
database.go
18
database.go
|
@ -66,7 +66,7 @@ func (a *goBlog) openDatabase(file string, logging bool) (*database, error) {
|
|||
sql.Register(dbDriverName, &sqlite.SQLiteDriver{
|
||||
ConnectHook: func(c *sqlite.SQLiteConn) error {
|
||||
// Register functions
|
||||
for n, f := range map[string]interface{}{
|
||||
for n, f := range map[string]any{
|
||||
"mdtext": a.renderText,
|
||||
"tolocal": toLocalSafe,
|
||||
"toutc": toUTCSafe,
|
||||
|
@ -174,14 +174,14 @@ func (db *database) close() error {
|
|||
return db.db.Close()
|
||||
}
|
||||
|
||||
func (db *database) prepare(query string, args ...interface{}) (*sql.Stmt, []interface{}, error) {
|
||||
func (db *database) prepare(query string, args ...any) (*sql.Stmt, []any, error) {
|
||||
if db == nil || db.db == nil {
|
||||
return nil, nil, errors.New("database not initialized")
|
||||
}
|
||||
if len(args) > 0 && args[0] == dbNoCache {
|
||||
return nil, args[1:], nil
|
||||
}
|
||||
stmt, err, _ := db.sg.Do(query, func() (interface{}, error) {
|
||||
stmt, err, _ := db.sg.Do(query, func() (any, error) {
|
||||
// Look if statement already exists
|
||||
st, ok := db.psc.Get(query)
|
||||
if ok {
|
||||
|
@ -207,11 +207,11 @@ func (db *database) prepare(query string, args ...interface{}) (*sql.Stmt, []int
|
|||
|
||||
const dbNoCache = "nocache"
|
||||
|
||||
func (db *database) exec(query string, args ...interface{}) (sql.Result, error) {
|
||||
func (db *database) exec(query string, args ...any) (sql.Result, error) {
|
||||
return db.execContext(context.Background(), query, args...)
|
||||
}
|
||||
|
||||
func (db *database) execContext(c context.Context, query string, args ...interface{}) (sql.Result, error) {
|
||||
func (db *database) execContext(c context.Context, query string, args ...any) (sql.Result, error) {
|
||||
if db == nil || db.db == nil {
|
||||
return nil, errors.New("database not initialized")
|
||||
}
|
||||
|
@ -230,11 +230,11 @@ func (db *database) execContext(c context.Context, query string, args ...interfa
|
|||
return db.db.ExecContext(ctx, query, args...)
|
||||
}
|
||||
|
||||
func (db *database) query(query string, args ...interface{}) (*sql.Rows, error) {
|
||||
func (db *database) query(query string, args ...any) (*sql.Rows, error) {
|
||||
return db.queryContext(context.Background(), query, args...)
|
||||
}
|
||||
|
||||
func (db *database) queryContext(c context.Context, query string, args ...interface{}) (rows *sql.Rows, err error) {
|
||||
func (db *database) queryContext(c context.Context, query string, args ...any) (rows *sql.Rows, err error) {
|
||||
if db == nil || db.db == nil {
|
||||
return nil, errors.New("database not initialized")
|
||||
}
|
||||
|
@ -253,11 +253,11 @@ func (db *database) queryContext(c context.Context, query string, args ...interf
|
|||
return
|
||||
}
|
||||
|
||||
func (db *database) queryRow(query string, args ...interface{}) (*sql.Row, error) {
|
||||
func (db *database) queryRow(query string, args ...any) (*sql.Row, error) {
|
||||
return db.queryRowContext(context.Background(), query, args...)
|
||||
}
|
||||
|
||||
func (db *database) queryRowContext(c context.Context, query string, args ...interface{}) (row *sql.Row, err error) {
|
||||
func (db *database) queryRowContext(c context.Context, query string, args ...any) (row *sql.Row, err error) {
|
||||
if db == nil || db.db == nil {
|
||||
return nil, errors.New("database not initialized")
|
||||
}
|
||||
|
|
|
@ -13,14 +13,14 @@ import (
|
|||
|
||||
const dbHooksBegin contextKey = "begin"
|
||||
|
||||
func (db *database) dbBefore(ctx context.Context, _ string, _ ...interface{}) context.Context {
|
||||
func (db *database) dbBefore(ctx context.Context, _ string, _ ...any) context.Context {
|
||||
if !db.debug {
|
||||
return ctx
|
||||
}
|
||||
return context.WithValue(ctx, dbHooksBegin, time.Now())
|
||||
}
|
||||
|
||||
func (db *database) dbAfter(ctx context.Context, query string, args ...interface{}) {
|
||||
func (db *database) dbAfter(ctx context.Context, query string, args ...any) {
|
||||
if !db.debug {
|
||||
return
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ func (db *database) dbAfter(ctx context.Context, query string, args ...interface
|
|||
bufferpool.Put(logBuilder)
|
||||
}
|
||||
|
||||
func argToString(arg interface{}) string {
|
||||
func argToString(arg any) string {
|
||||
val := cast.ToString(arg)
|
||||
if val == "" {
|
||||
val = fmt.Sprintf("%v", arg)
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
var dbMigrations embed.FS
|
||||
|
||||
func migrateDb(db *sql.DB, logging bool) error {
|
||||
var sqlMigrations []interface{}
|
||||
var sqlMigrations []any
|
||||
err := fs.WalkDir(dbMigrations, "dbmigrations", func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil || d.Type().IsDir() {
|
||||
return err
|
||||
|
@ -39,7 +39,7 @@ func migrateDb(db *sql.DB, logging bool) error {
|
|||
return err
|
||||
}
|
||||
m, err := migrator.New(
|
||||
migrator.WithLogger(migrator.LoggerFunc(func(s string, i ...interface{}) {
|
||||
migrator.WithLogger(migrator.LoggerFunc(func(s string, i ...any) {
|
||||
if logging {
|
||||
log.Printf(s, i)
|
||||
}
|
||||
|
|
4
debug.go
4
debug.go
|
@ -2,8 +2,8 @@ package main
|
|||
|
||||
import "log"
|
||||
|
||||
func (a *goBlog) debug(msg ...interface{}) {
|
||||
func (a *goBlog) debug(msg ...any) {
|
||||
if a.cfg.Debug {
|
||||
log.Println(append([]interface{}{"Debug:"}, msg...)...)
|
||||
log.Println(append([]any{"Debug:"}, msg...)...)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ func (a *goBlog) serveEditorPost(w http.ResponseWriter, r *http.Request) {
|
|||
case "updatepost":
|
||||
buf := bufferpool.Get()
|
||||
defer bufferpool.Put(buf)
|
||||
err := json.NewEncoder(buf).Encode(map[string]interface{}{
|
||||
err := json.NewEncoder(buf).Encode(map[string]any{
|
||||
"action": actionUpdate,
|
||||
"url": r.FormValue("url"),
|
||||
"replace": map[string][]string{
|
||||
|
@ -179,8 +179,8 @@ func (a *goBlog) editorMicropubPost(w http.ResponseWriter, r *http.Request, medi
|
|||
func (*goBlog) editorPostTemplate(blog string, bc *configBlog) string {
|
||||
builder := bufferpool.Get()
|
||||
defer bufferpool.Put(builder)
|
||||
marsh := func(param string, i interface{}) {
|
||||
_ = yaml.NewEncoder(builder).Encode(map[string]interface{}{
|
||||
marsh := func(param string, i any) {
|
||||
_ = yaml.NewEncoder(builder).Encode(map[string]any{
|
||||
param: i,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"net/http"
|
||||
"sort"
|
||||
|
||||
"github.com/thoas/go-funk"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
func (a *goBlog) serveEditorFiles(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -26,13 +26,9 @@ func (a *goBlog) serveEditorFiles(w http.ResponseWriter, r *http.Request) {
|
|||
return files[i].Time.After(files[j].Time)
|
||||
})
|
||||
// Find uses
|
||||
fileNames, ok := funk.Map(files, func(f *mediaFile) string {
|
||||
fileNames := lo.Map(files, func(f *mediaFile, _ int) string {
|
||||
return f.Name
|
||||
}).([]string)
|
||||
if !ok {
|
||||
a.serveError(w, r, "Failed to get file names", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
uses, err := a.db.usesOfMediaFile(fileNames...)
|
||||
if err != nil {
|
||||
a.serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||
|
|
8
geo.go
8
geo.go
|
@ -10,7 +10,7 @@ import (
|
|||
gogeouri "git.jlel.se/jlelse/go-geouri"
|
||||
"github.com/carlmjohnson/requests"
|
||||
geojson "github.com/paulmach/go.geojson"
|
||||
"github.com/thoas/go-funk"
|
||||
"github.com/samber/lo"
|
||||
"go.goblog.app/app/pkgs/bufferpool"
|
||||
)
|
||||
|
||||
|
@ -23,9 +23,9 @@ func (a *goBlog) geoTitle(g *gogeouri.Geo, lang string) string {
|
|||
return ""
|
||||
}
|
||||
f := fc.Features[0]
|
||||
return strings.Join(funk.FilterString([]string{
|
||||
return strings.Join(lo.Filter([]string{
|
||||
f.PropertyMustString("name", ""), f.PropertyMustString("city", ""), f.PropertyMustString("state", ""), f.PropertyMustString("country", ""),
|
||||
}, func(s string) bool { return s != "" }), ", ")
|
||||
}, func(s string, _ int) bool { return s != "" }), ", ")
|
||||
}
|
||||
|
||||
func (a *goBlog) photonReverse(lat, lon float64, lang string) (*geojson.FeatureCollection, error) {
|
||||
|
@ -50,7 +50,7 @@ func (a *goBlog) photonReverse(lat, lon float64, lang string) (*geojson.FeatureC
|
|||
rb := requests.URL("https://photon.komoot.io/reverse").Client(a.httpClient).UserAgent(appUserAgent).ToBytesBuffer(buf)
|
||||
// Set parameters
|
||||
rb.Param("lat", fmt.Sprintf("%v", lat)).Param("lon", fmt.Sprintf("%v", lon))
|
||||
rb.Param("lang", funk.ShortIf(lang == "de" || lang == "fr" || lang == "it", lang, "en").(string)) // Photon only supports en, de, fr, it
|
||||
rb.Param("lang", lo.If(lang == "de" || lang == "fr" || lang == "it", lang).Else("en")) // Photon only supports en, de, fr, it
|
||||
// Do request
|
||||
if err := rb.Fetch(context.Background()); err != nil {
|
||||
return nil, err
|
||||
|
|
9
go.mod
9
go.mod
|
@ -1,6 +1,6 @@
|
|||
module go.goblog.app/app
|
||||
|
||||
go 1.17
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
git.jlel.se/jlelse/go-geouri v0.0.0-20210525190615-a9c1d50f42d6
|
||||
|
@ -42,20 +42,20 @@ require (
|
|||
github.com/paulmach/go.geojson v1.4.0
|
||||
github.com/posener/wstest v1.2.0
|
||||
github.com/pquerna/otp v1.3.0
|
||||
github.com/samber/lo v1.10.1
|
||||
github.com/schollz/sqlite3dump v1.3.1
|
||||
github.com/snabb/sitemap v1.0.0
|
||||
github.com/spf13/cast v1.4.1
|
||||
github.com/spf13/viper v1.10.1
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/stretchr/testify v1.7.1
|
||||
github.com/tdewolff/minify/v2 v2.10.0
|
||||
github.com/thoas/go-funk v0.9.2
|
||||
github.com/tkrajina/gpxgo v1.2.1
|
||||
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
|
||||
github.com/vcraescu/go-paginator v1.0.1-0.20201114172518-2cfc59fe05c2
|
||||
github.com/yuin/goldmark v1.4.10
|
||||
// master
|
||||
github.com/yuin/goldmark-emoji v1.0.2-0.20210607094911-0487583eca38
|
||||
golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/text v0.3.7
|
||||
|
@ -128,6 +128,7 @@ require (
|
|||
go4.org/intern v0.0.0-20211027215823-ae77deb06f29 // indirect
|
||||
go4.org/mem v0.0.0-20210711025021-927187094b94 // indirect
|
||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20211027215541-db492cf91b37 // indirect
|
||||
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 // indirect
|
||||
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
|
||||
|
|
19
go.sum
19
go.sum
|
@ -369,6 +369,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
|
|||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/paulmach/go.geojson v1.4.0 h1:5x5moCkCtDo5x8af62P9IOAYGQcYHtxz2QJ3x1DoCgY=
|
||||
github.com/paulmach/go.geojson v1.4.0/go.mod h1:YaKx1hKpWF+T2oj2lFJPsW/t1Q5e1jQI61eoQSTwpIs=
|
||||
github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM=
|
||||
|
@ -388,6 +389,8 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
|
|||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.8.1-0.20211023094830-115ce09fd6b4 h1:Ha8xCaq6ln1a+R91Km45Oq6lPXj2Mla6CRJYcuV2h1w=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/samber/lo v1.10.1 h1:0D3h7i0U3hRAbaCeQ82DLe67n0A7Bbl0/cEoWqFGp+U=
|
||||
github.com/samber/lo v1.10.1/go.mod h1:2I7tgIv8Q1SG2xEIkRq0F2i2zgxVpnyPOP0d3Gj2r+A=
|
||||
github.com/schollz/sqlite3dump v1.3.1 h1:QXizJ7XEJ7hggjqjZ3YRtF3+javm8zKtzNByYtEkPRA=
|
||||
github.com/schollz/sqlite3dump v1.3.1/go.mod h1:mzSTjZpJH4zAb1FN3iNlhWPbbdyeBpOaTW0hukyMHyI=
|
||||
github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg=
|
||||
|
@ -413,8 +416,9 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
|||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tailscale/certstore v0.0.0-20210528134328-066c94b793d3 h1:fEubocuQkrlcuYeXelhYq/YcKvVVe1Ah7saQEtj98Mo=
|
||||
|
@ -431,8 +435,7 @@ github.com/tdewolff/parse/v2 v2.5.27 h1:PL3LzzXaOpmdrknnOlIeO2muIBHAwiKp6TxN1RbU
|
|||
github.com/tdewolff/parse/v2 v2.5.27/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
|
||||
github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
|
||||
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
||||
github.com/thoas/go-funk v0.9.2 h1:oKlNYv0AY5nyf9g+/GhMgS/UO2ces0QRdPKwkhY3VCk=
|
||||
github.com/thoas/go-funk v0.9.2/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
|
||||
github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
|
||||
github.com/tkrajina/gpxgo v1.2.1 h1:MJJtT4Re5btDGg89brFDrUP3EWz+cBmyo8pQwV0ZOak=
|
||||
github.com/tkrajina/gpxgo v1.2.1/go.mod h1:795sjVRFo5wWyN6oOZp0RYienGGBJjpAlgOz2nCngA0=
|
||||
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y=
|
||||
|
@ -483,8 +486,8 @@ golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWP
|
|||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000 h1:SL+8VVnkqyshUSz5iNnXtrBQzvFF2SkROm6t5RczFAE=
|
||||
golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
@ -495,6 +498,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
|||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM=
|
||||
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
|
@ -516,8 +521,8 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB
|
|||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 h1:LQmS1nU0twXLA96Kt7U9qtHJEbBk3z6Q0V4UXjZkpr4=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -801,8 +806,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
|
|||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
|
||||
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
|
|
10
hooks.go
10
hooks.go
|
@ -25,7 +25,7 @@ func (a *goBlog) postPostHooks(p *post) {
|
|||
if hc := a.cfg.Hooks; hc != nil {
|
||||
for _, cmdTmplString := range hc.PostPost {
|
||||
go func(p *post, cmdTmplString string) {
|
||||
a.cfg.Hooks.executeTemplateCommand("post-post", cmdTmplString, map[string]interface{}{
|
||||
a.cfg.Hooks.executeTemplateCommand("post-post", cmdTmplString, map[string]any{
|
||||
"URL": a.fullPostURL(p),
|
||||
"Post": p,
|
||||
})
|
||||
|
@ -42,7 +42,7 @@ func (a *goBlog) postUpdateHooks(p *post) {
|
|||
if hc := a.cfg.Hooks; hc != nil {
|
||||
for _, cmdTmplString := range hc.PostUpdate {
|
||||
go func(p *post, cmdTmplString string) {
|
||||
a.cfg.Hooks.executeTemplateCommand("post-update", cmdTmplString, map[string]interface{}{
|
||||
a.cfg.Hooks.executeTemplateCommand("post-update", cmdTmplString, map[string]any{
|
||||
"URL": a.fullPostURL(p),
|
||||
"Post": p,
|
||||
})
|
||||
|
@ -58,7 +58,7 @@ func (a *goBlog) postDeleteHooks(p *post) {
|
|||
if hc := a.cfg.Hooks; hc != nil {
|
||||
for _, cmdTmplString := range hc.PostDelete {
|
||||
go func(p *post, cmdTmplString string) {
|
||||
a.cfg.Hooks.executeTemplateCommand("post-delete", cmdTmplString, map[string]interface{}{
|
||||
a.cfg.Hooks.executeTemplateCommand("post-delete", cmdTmplString, map[string]any{
|
||||
"URL": a.fullPostURL(p),
|
||||
"Post": p,
|
||||
})
|
||||
|
@ -74,7 +74,7 @@ func (a *goBlog) postUndeleteHooks(p *post) {
|
|||
if hc := a.cfg.Hooks; hc != nil {
|
||||
for _, cmdTmplString := range hc.PostUndelete {
|
||||
go func(p *post, cmdTmplString string) {
|
||||
a.cfg.Hooks.executeTemplateCommand("post-undelete", cmdTmplString, map[string]interface{}{
|
||||
a.cfg.Hooks.executeTemplateCommand("post-undelete", cmdTmplString, map[string]any{
|
||||
"URL": a.fullPostURL(p),
|
||||
"Post": p,
|
||||
})
|
||||
|
@ -86,7 +86,7 @@ func (a *goBlog) postUndeleteHooks(p *post) {
|
|||
}
|
||||
}
|
||||
|
||||
func (cfg *configHooks) executeTemplateCommand(hookType string, tmpl string, data map[string]interface{}) {
|
||||
func (cfg *configHooks) executeTemplateCommand(hookType string, tmpl string, data map[string]any) {
|
||||
cmdTmpl, err := template.New("cmd").Parse(tmpl)
|
||||
if err != nil {
|
||||
log.Println("Failed to parse cmd template:", err.Error())
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/carlmjohnson/requests"
|
||||
"github.com/thoas/go-funk"
|
||||
)
|
||||
|
||||
// Implement support for the IndexNow protocol
|
||||
|
@ -78,7 +77,7 @@ func (a *goBlog) indexNowKey() []byte {
|
|||
}
|
||||
if keyBytes == nil {
|
||||
// Generate 128 character key with hexadecimal characters
|
||||
keyBytes = []byte(funk.RandomString(128, []rune("0123456789abcdef")))
|
||||
keyBytes = []byte(randomString(128, []rune("0123456789abcdef")))
|
||||
// Store key in database
|
||||
err = a.db.cachePersistently("indexnowkey", keyBytes)
|
||||
if err != nil {
|
||||
|
|
2
main.go
2
main.go
|
@ -221,7 +221,7 @@ func (app *goBlog) initComponents(logging bool) {
|
|||
}
|
||||
}
|
||||
|
||||
func (a *goBlog) logErrAndQuit(v ...interface{}) {
|
||||
func (a *goBlog) logErrAndQuit(v ...any) {
|
||||
log.Println(v...)
|
||||
a.shutdown.ShutdownAndWait()
|
||||
os.Exit(1)
|
||||
|
|
|
@ -185,7 +185,7 @@ func (c *customRenderer) renderImage(w util.BufWriter, source []byte, node ast.N
|
|||
}
|
||||
hb := newHtmlBuilder(w)
|
||||
hb.writeElementOpen("a", "href", dest)
|
||||
imgEls := []interface{}{"src", dest, "alt", string(n.Text(source)), "loading", "lazy"}
|
||||
imgEls := []any{"src", dest, "alt", string(n.Text(source)), "loading", "lazy"}
|
||||
if len(n.Title) > 0 {
|
||||
imgEls = append(imgEls, "title", string(n.Title))
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ func (sp *shortpixel) compress(url string, upload mediaStorageSaveFunc, hc *http
|
|||
URL("https://api.shortpixel.com/v2/reducer-sync.php").
|
||||
Client(hc).
|
||||
Method(http.MethodPost).
|
||||
BodyJSON(map[string]interface{}{
|
||||
BodyJSON(map[string]any{
|
||||
"key": sp.key,
|
||||
"plugin_version": "GB001",
|
||||
"lossy": 1,
|
||||
|
@ -106,8 +106,8 @@ func (tf *tinify) compress(url string, upload mediaStorageSaveFunc, hc *http.Cli
|
|||
Client(hc).
|
||||
Method(http.MethodPost).
|
||||
BasicAuth("api", tf.key).
|
||||
BodyJSON(map[string]interface{}{
|
||||
"source": map[string]interface{}{
|
||||
BodyJSON(map[string]any{
|
||||
"source": map[string]any{
|
||||
"url": url,
|
||||
},
|
||||
}).
|
||||
|
@ -130,8 +130,8 @@ func (tf *tinify) compress(url string, upload mediaStorageSaveFunc, hc *http.Cli
|
|||
Client(hc).
|
||||
Method(http.MethodPost).
|
||||
BasicAuth("api", tf.key).
|
||||
BodyJSON(map[string]interface{}{
|
||||
"resize": map[string]interface{}{
|
||||
BodyJSON(map[string]any{
|
||||
"resize": map[string]any{
|
||||
"method": "fit",
|
||||
"width": defaultCompressionWidth,
|
||||
"height": defaultCompressionHeight,
|
||||
|
|
|
@ -46,7 +46,7 @@ func Test_compress(t *testing.T) {
|
|||
requestBody, _ := io.ReadAll(r.Body)
|
||||
defer r.Body.Close()
|
||||
|
||||
var requestJson map[string]interface{}
|
||||
var requestJson map[string]any
|
||||
err := json.Unmarshal(requestBody, &requestJson)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, requestJson)
|
||||
|
|
68
micropub.go
68
micropub.go
|
@ -11,8 +11,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"github.com/spf13/cast"
|
||||
"github.com/thoas/go-funk"
|
||||
"go.goblog.app/app/pkgs/bufferpool"
|
||||
"go.goblog.app/app/pkgs/contenttype"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
@ -21,7 +21,7 @@ import (
|
|||
const micropubPath = "/micropub"
|
||||
|
||||
func (a *goBlog) serveMicropubQuery(w http.ResponseWriter, r *http.Request) {
|
||||
var result interface{}
|
||||
var result any
|
||||
switch query := r.URL.Query(); query.Get("q") {
|
||||
case "config":
|
||||
type micropubConfig struct {
|
||||
|
@ -66,7 +66,7 @@ func (a *goBlog) serveMicropubQuery(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
allCategories = append(allCategories, values...)
|
||||
}
|
||||
result = map[string]interface{}{"categories": allCategories}
|
||||
result = map[string]any{"categories": allCategories}
|
||||
default:
|
||||
a.serve404(w, r)
|
||||
return
|
||||
|
@ -231,30 +231,30 @@ const (
|
|||
)
|
||||
|
||||
type microformatItem struct {
|
||||
Type []string `json:"type,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Action micropubAction `json:"action,omitempty"`
|
||||
Properties *microformatProperties `json:"properties,omitempty"`
|
||||
Replace map[string][]interface{} `json:"replace,omitempty"`
|
||||
Add map[string][]interface{} `json:"add,omitempty"`
|
||||
Delete interface{} `json:"delete,omitempty"`
|
||||
Type []string `json:"type,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Action micropubAction `json:"action,omitempty"`
|
||||
Properties *microformatProperties `json:"properties,omitempty"`
|
||||
Replace map[string][]any `json:"replace,omitempty"`
|
||||
Add map[string][]any `json:"add,omitempty"`
|
||||
Delete any `json:"delete,omitempty"`
|
||||
}
|
||||
|
||||
type microformatProperties struct {
|
||||
Name []string `json:"name,omitempty"`
|
||||
Published []string `json:"published,omitempty"`
|
||||
Updated []string `json:"updated,omitempty"`
|
||||
PostStatus []string `json:"post-status,omitempty"`
|
||||
Visibility []string `json:"visibility,omitempty"`
|
||||
Category []string `json:"category,omitempty"`
|
||||
Content []string `json:"content,omitempty"`
|
||||
URL []string `json:"url,omitempty"`
|
||||
InReplyTo []string `json:"in-reply-to,omitempty"`
|
||||
LikeOf []string `json:"like-of,omitempty"`
|
||||
BookmarkOf []string `json:"bookmark-of,omitempty"`
|
||||
MpSlug []string `json:"mp-slug,omitempty"`
|
||||
Photo []interface{} `json:"photo,omitempty"`
|
||||
Audio []string `json:"audio,omitempty"`
|
||||
Name []string `json:"name,omitempty"`
|
||||
Published []string `json:"published,omitempty"`
|
||||
Updated []string `json:"updated,omitempty"`
|
||||
PostStatus []string `json:"post-status,omitempty"`
|
||||
Visibility []string `json:"visibility,omitempty"`
|
||||
Category []string `json:"category,omitempty"`
|
||||
Content []string `json:"content,omitempty"`
|
||||
URL []string `json:"url,omitempty"`
|
||||
InReplyTo []string `json:"in-reply-to,omitempty"`
|
||||
LikeOf []string `json:"like-of,omitempty"`
|
||||
BookmarkOf []string `json:"bookmark-of,omitempty"`
|
||||
MpSlug []string `json:"mp-slug,omitempty"`
|
||||
Photo []any `json:"photo,omitempty"`
|
||||
Audio []string `json:"audio,omitempty"`
|
||||
}
|
||||
|
||||
func (a *goBlog) micropubParsePostParamsMfItem(entry *post, mf *microformatItem) error {
|
||||
|
@ -314,7 +314,7 @@ func (a *goBlog) micropubParsePostParamsMfItem(entry *post, mf *microformatItem)
|
|||
if theString, justString := photo.(string); justString {
|
||||
entry.Parameters[a.cfg.Micropub.PhotoParam] = append(entry.Parameters[a.cfg.Micropub.PhotoParam], theString)
|
||||
entry.Parameters[a.cfg.Micropub.PhotoDescriptionParam] = append(entry.Parameters[a.cfg.Micropub.PhotoDescriptionParam], "")
|
||||
} else if thePhoto, isPhoto := photo.(map[string]interface{}); isPhoto {
|
||||
} else if thePhoto, isPhoto := photo.(map[string]any); isPhoto {
|
||||
entry.Parameters[a.cfg.Micropub.PhotoParam] = append(entry.Parameters[a.cfg.Micropub.PhotoParam], cast.ToString(thePhoto["value"]))
|
||||
entry.Parameters[a.cfg.Micropub.PhotoDescriptionParam] = append(entry.Parameters[a.cfg.Micropub.PhotoDescriptionParam], cast.ToString(thePhoto["alt"]))
|
||||
}
|
||||
|
@ -331,7 +331,7 @@ func (a *goBlog) computeExtraPostParameters(p *post) error {
|
|||
if split := strings.Split(p.Content, "---\n"); len(split) >= 3 && strings.TrimSpace(split[0]) == "" {
|
||||
// Contains frontmatter
|
||||
fm := split[1]
|
||||
meta := map[string]interface{}{}
|
||||
meta := map[string]any{}
|
||||
err := yaml.Unmarshal([]byte(fm), &meta)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -340,7 +340,7 @@ func (a *goBlog) computeExtraPostParameters(p *post) error {
|
|||
for key, value := range meta {
|
||||
// Delete existing content - replace
|
||||
p.Parameters[key] = []string{}
|
||||
if a, ok := value.([]interface{}); ok {
|
||||
if a, ok := value.([]any); ok {
|
||||
for _, ae := range a {
|
||||
p.Parameters[key] = append(p.Parameters[key], cast.ToString(ae))
|
||||
}
|
||||
|
@ -534,7 +534,7 @@ func (a *goBlog) micropubUpdate(w http.ResponseWriter, r *http.Request, u string
|
|||
http.Redirect(w, r, a.fullPostURL(p), http.StatusNoContent)
|
||||
}
|
||||
|
||||
func (a *goBlog) micropubUpdateReplace(p *post, replace map[string][]interface{}) {
|
||||
func (a *goBlog) micropubUpdateReplace(p *post, replace map[string][]any) {
|
||||
if content, ok := replace["content"]; ok && len(content) > 0 {
|
||||
p.Content = cast.ToStringSlice(content)[0]
|
||||
}
|
||||
|
@ -578,7 +578,7 @@ func (a *goBlog) micropubUpdateReplace(p *post, replace map[string][]interface{}
|
|||
// TODO: photos
|
||||
}
|
||||
|
||||
func (a *goBlog) micropubUpdateAdd(p *post, add map[string][]interface{}) {
|
||||
func (a *goBlog) micropubUpdateAdd(p *post, add map[string][]any) {
|
||||
for key, value := range add {
|
||||
switch key {
|
||||
case "content":
|
||||
|
@ -602,11 +602,11 @@ func (a *goBlog) micropubUpdateAdd(p *post, add map[string][]interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
func (a *goBlog) micropubUpdateDelete(p *post, del interface{}) {
|
||||
func (a *goBlog) micropubUpdateDelete(p *post, del any) {
|
||||
if del == nil {
|
||||
return
|
||||
}
|
||||
deleteProperties, ok := del.([]interface{})
|
||||
deleteProperties, ok := del.([]any)
|
||||
if ok {
|
||||
// Completely remove properties
|
||||
for _, prop := range deleteProperties {
|
||||
|
@ -637,7 +637,7 @@ func (a *goBlog) micropubUpdateDelete(p *post, del interface{}) {
|
|||
// Return
|
||||
return
|
||||
}
|
||||
toDelete, ok := del.(map[string]interface{})
|
||||
toDelete, ok := del.(map[string]any)
|
||||
if ok {
|
||||
// Only delete parts of properties
|
||||
for key, values := range toDelete {
|
||||
|
@ -661,8 +661,8 @@ func (a *goBlog) micropubUpdateDelete(p *post, del interface{}) {
|
|||
// TODO: Support partial deletes of more properties
|
||||
case "category":
|
||||
delValues := cast.ToStringSlice(values)
|
||||
p.Parameters[a.cfg.Micropub.CategoryParam] = funk.FilterString(p.Parameters[a.cfg.Micropub.CategoryParam], func(s string) bool {
|
||||
return !funk.ContainsString(delValues, s)
|
||||
p.Parameters[a.cfg.Micropub.CategoryParam] = lo.Filter(p.Parameters[a.cfg.Micropub.CategoryParam], func(s string, _ int) bool {
|
||||
return !lo.Contains(delValues, s)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
14
nodeinfo.go
14
nodeinfo.go
|
@ -11,8 +11,8 @@ import (
|
|||
func (a *goBlog) serveNodeInfoDiscover(w http.ResponseWriter, r *http.Request) {
|
||||
buf := bufferpool.Get()
|
||||
defer bufferpool.Put(buf)
|
||||
err := json.NewEncoder(buf).Encode(map[string]interface{}{
|
||||
"links": []map[string]interface{}{
|
||||
err := json.NewEncoder(buf).Encode(map[string]any{
|
||||
"links": []map[string]any{
|
||||
{
|
||||
"href": a.getFullAddress("/nodeinfo"),
|
||||
"rel": "http://nodeinfo.diaspora.software/ns/schema/2.1",
|
||||
|
@ -35,14 +35,14 @@ func (a *goBlog) serveNodeInfo(w http.ResponseWriter, r *http.Request) {
|
|||
})
|
||||
buf := bufferpool.Get()
|
||||
defer bufferpool.Put(buf)
|
||||
err := json.NewEncoder(buf).Encode(map[string]interface{}{
|
||||
err := json.NewEncoder(buf).Encode(map[string]any{
|
||||
"version": "2.1",
|
||||
"software": map[string]interface{}{
|
||||
"software": map[string]any{
|
||||
"name": "goblog",
|
||||
"repository": "https://go.goblog.app/app",
|
||||
},
|
||||
"usage": map[string]interface{}{
|
||||
"users": map[string]interface{}{
|
||||
"usage": map[string]any{
|
||||
"users": map[string]any{
|
||||
"total": len(a.cfg.Blogs),
|
||||
},
|
||||
"localPosts": localPosts,
|
||||
|
@ -52,7 +52,7 @@ func (a *goBlog) serveNodeInfo(w http.ResponseWriter, r *http.Request) {
|
|||
"micropub",
|
||||
"webmention",
|
||||
},
|
||||
"metadata": map[string]interface{}{},
|
||||
"metadata": map[string]any{},
|
||||
})
|
||||
if err != nil {
|
||||
a.serveError(w, r, "", http.StatusInternalServerError)
|
||||
|
|
|
@ -56,7 +56,7 @@ type notificationsRequestConfig struct {
|
|||
offset, limit int
|
||||
}
|
||||
|
||||
func buildNotificationsQuery(config *notificationsRequestConfig) (query string, args []interface{}) {
|
||||
func buildNotificationsQuery(config *notificationsRequestConfig) (query string, args []any) {
|
||||
queryBuilder := bufferpool.Get()
|
||||
defer bufferpool.Put(queryBuilder)
|
||||
queryBuilder.WriteString("select id, time, text from notifications order by id desc")
|
||||
|
@ -110,7 +110,7 @@ func (p *notificationsPaginationAdapter) Nums() (int64, error) {
|
|||
return p.nums, nil
|
||||
}
|
||||
|
||||
func (p *notificationsPaginationAdapter) Slice(offset, length int, data interface{}) error {
|
||||
func (p *notificationsPaginationAdapter) Slice(offset, length int, data any) error {
|
||||
modifiedConfig := *p.config
|
||||
modifiedConfig.offset = offset
|
||||
modifiedConfig.limit = length
|
||||
|
|
|
@ -26,7 +26,7 @@ func (db *database) retrievePersistentCacheContext(c context.Context, key string
|
|||
if db == nil {
|
||||
return nil, errors.New("database is nil")
|
||||
}
|
||||
d, err, _ := db.pc.Do(key, func() (interface{}, error) {
|
||||
d, err, _ := db.pc.Do(key, func() (any, error) {
|
||||
if row, err := db.queryRowContext(c, "select data from persistent_cache where key = @key", sql.Named("key", key)); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
)
|
||||
|
||||
var bufferPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
New: func() any {
|
||||
return new(bytes.Buffer)
|
||||
},
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ func newConfig() *config {
|
|||
}
|
||||
|
||||
// SetOption implements renderer.SetOptioner.
|
||||
func (c *config) SetOption(name renderer.OptionName, value interface{}) {
|
||||
func (c *config) SetOption(name renderer.OptionName, value any) {
|
||||
c.Config.SetOption(name, value)
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
|
||||
"github.com/klauspost/compress/flate"
|
||||
"github.com/klauspost/compress/gzip"
|
||||
"github.com/thoas/go-funk"
|
||||
"github.com/samber/lo"
|
||||
|
||||
"go.goblog.app/app/pkgs/contenttype"
|
||||
)
|
||||
|
@ -48,7 +48,7 @@ type Compressor struct {
|
|||
// The mapping of pooled encoders to pools.
|
||||
pooledEncoders map[string]*sync.Pool
|
||||
// The set of content types allowed to be compressed.
|
||||
allowedTypes map[string]interface{}
|
||||
allowedTypes map[string]any
|
||||
// The list of encoders in order of decreasing precedence.
|
||||
encodingPrecedence []string
|
||||
// The compression level.
|
||||
|
@ -62,8 +62,8 @@ type Compressor struct {
|
|||
func NewCompressor(level int, types ...string) *Compressor {
|
||||
// If types are provided, set those as the allowed types. If none are
|
||||
// provided, use the default list.
|
||||
allowedTypes := map[string]interface{}{}
|
||||
for _, t := range funk.ShortIf(len(types) > 0, types, defaultCompressibleContentTypes).([]string) {
|
||||
allowedTypes := map[string]any{}
|
||||
for _, t := range lo.If(len(types) > 0, types).Else(defaultCompressibleContentTypes) {
|
||||
allowedTypes[t] = nil
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ func (c *Compressor) SetEncoder(encoding string, fn EncoderFunc) {
|
|||
delete(c.pooledEncoders, encoding)
|
||||
|
||||
c.pooledEncoders[encoding] = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
New: func() any {
|
||||
return fn(io.Discard, c.level)
|
||||
},
|
||||
}
|
||||
|
@ -126,10 +126,6 @@ func (c *Compressor) Handler(next http.Handler) http.Handler {
|
|||
})
|
||||
}
|
||||
|
||||
func matchAcceptEncoding(accepted []string, encoding string) bool {
|
||||
return funk.ContainsString(accepted, encoding)
|
||||
}
|
||||
|
||||
// An EncoderFunc is a function that wraps the provided io.Writer with a
|
||||
// streaming compression algorithm and returns it.
|
||||
//
|
||||
|
@ -178,7 +174,7 @@ func (cw *compressResponseWriter) selectEncoder() (compressWriter, string, func(
|
|||
|
||||
// Find supported encoder by accepted list by precedence
|
||||
for _, name := range cw.compressor.encodingPrecedence {
|
||||
if matchAcceptEncoding(accepted, name) {
|
||||
if lo.Contains(accepted, name) {
|
||||
if pool, ok := cw.compressor.pooledEncoders[name]; ok {
|
||||
encoder := pool.Get().(compressWriter)
|
||||
cleanup := func() {
|
||||
|
|
2
posts.go
2
posts.go
|
@ -127,7 +127,7 @@ func (p *postPaginationAdapter) Nums() (int64, error) {
|
|||
return p.nums, nil
|
||||
}
|
||||
|
||||
func (p *postPaginationAdapter) Slice(offset, length int, data interface{}) error {
|
||||
func (p *postPaginationAdapter) Slice(offset, length int, data any) error {
|
||||
modifiedConfig := *p.config
|
||||
modifiedConfig.offset = offset
|
||||
modifiedConfig.limit = length
|
||||
|
|
22
postsDb.go
22
postsDb.go
|
@ -10,7 +10,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/araddon/dateparse"
|
||||
"github.com/thoas/go-funk"
|
||||
"github.com/samber/lo"
|
||||
"go.goblog.app/app/pkgs/bufferpool"
|
||||
)
|
||||
|
||||
|
@ -86,8 +86,7 @@ func (a *goBlog) checkPost(p *post) (err error) {
|
|||
p.Section = a.cfg.Blogs[p.Blog].DefaultSection
|
||||
}
|
||||
if p.Slug == "" {
|
||||
random := generateRandomString(5)
|
||||
p.Slug = fmt.Sprintf("%v-%02d-%02d-%v", now.Year(), int(now.Month()), now.Day(), random)
|
||||
p.Slug = fmt.Sprintf("%v-%02d-%02d-%v", now.Year(), int(now.Month()), now.Day(), randomString(5))
|
||||
}
|
||||
published := timeNoErr(dateparse.ParseLocal(p.Published))
|
||||
pathTmplString := defaultIfEmpty(
|
||||
|
@ -100,7 +99,7 @@ func (a *goBlog) checkPost(p *post) (err error) {
|
|||
}
|
||||
pathBuffer := bufferpool.Get()
|
||||
defer bufferpool.Put(pathBuffer)
|
||||
err = pathTmpl.Execute(pathBuffer, map[string]interface{}{
|
||||
err = pathTmpl.Execute(pathBuffer, map[string]any{
|
||||
"BlogPath": a.getRelativePath(p.Blog, ""),
|
||||
"Year": published.Year(),
|
||||
"Month": int(published.Month()),
|
||||
|
@ -173,7 +172,7 @@ func (db *database) savePost(p *post, o *postCreationOptions) error {
|
|||
// Build SQL
|
||||
sqlBuilder := bufferpool.Get()
|
||||
defer bufferpool.Put(sqlBuilder)
|
||||
var sqlArgs = []interface{}{dbNoCache}
|
||||
var sqlArgs = []any{dbNoCache}
|
||||
// Start transaction
|
||||
sqlBuilder.WriteString("begin;")
|
||||
// Delete old post
|
||||
|
@ -297,7 +296,7 @@ func (db *database) replacePostParam(path, param string, values []string) error
|
|||
// Build SQL
|
||||
sqlBuilder := bufferpool.Get()
|
||||
defer bufferpool.Put(sqlBuilder)
|
||||
var sqlArgs = []interface{}{dbNoCache}
|
||||
var sqlArgs = []any{dbNoCache}
|
||||
// Start transaction
|
||||
sqlBuilder.WriteString("begin;")
|
||||
// Delete old post
|
||||
|
@ -344,7 +343,7 @@ type postsRequestConfig struct {
|
|||
withoutRenderedTitle bool
|
||||
}
|
||||
|
||||
func buildPostsQuery(c *postsRequestConfig, selection string) (query string, args []interface{}) {
|
||||
func buildPostsQuery(c *postsRequestConfig, selection string) (query string, args []any) {
|
||||
queryBuilder := bufferpool.Get()
|
||||
defer bufferpool.Put(queryBuilder)
|
||||
// Selection
|
||||
|
@ -461,7 +460,7 @@ func (d *database) loadPostParameters(posts []*post, parameters ...string) (err
|
|||
return nil
|
||||
}
|
||||
// Build query
|
||||
sqlArgs := make([]interface{}, 0)
|
||||
sqlArgs := make([]any, 0)
|
||||
queryBuilder := bufferpool.Get()
|
||||
defer bufferpool.Put(queryBuilder)
|
||||
queryBuilder.WriteString("select path, parameter, value from post_parameters where")
|
||||
|
@ -584,10 +583,7 @@ func (d *database) countPosts(config *postsRequestConfig) (count int, err error)
|
|||
}
|
||||
|
||||
func (a *goBlog) getRandomPostPath(blog string) (path string, err error) {
|
||||
sections, ok := funk.Keys(a.cfg.Blogs[blog].Sections).([]string)
|
||||
if !ok {
|
||||
return "", errors.New("no sections")
|
||||
}
|
||||
sections := lo.Keys(a.cfg.Blogs[blog].Sections)
|
||||
query, params := buildPostsQuery(&postsRequestConfig{randomOrder: true, limit: 1, blog: blog, sections: sections}, "path")
|
||||
row, err := a.db.queryRow(query, params...)
|
||||
if err != nil {
|
||||
|
@ -634,7 +630,7 @@ group by name;
|
|||
`
|
||||
|
||||
func (db *database) usesOfMediaFile(names ...string) (counts []int, err error) {
|
||||
sqlArgs := []interface{}{dbNoCache}
|
||||
sqlArgs := []any{dbNoCache}
|
||||
nameValues := bufferpool.Get()
|
||||
for i, n := range names {
|
||||
if i > 0 {
|
||||
|
|
|
@ -211,7 +211,7 @@ func (a *goBlog) photoLinks(p *post) []string {
|
|||
}
|
||||
|
||||
func (p *post) contentWithParams() string {
|
||||
params := map[string]interface{}{}
|
||||
params := map[string]any{}
|
||||
for k, v := range p.Parameters {
|
||||
if l := len(v); l == 1 {
|
||||
params[k] = v[0]
|
||||
|
|
|
@ -13,7 +13,7 @@ type renderData struct {
|
|||
TorAddress string
|
||||
Blog *configBlog
|
||||
User *configUser
|
||||
Data interface{}
|
||||
Data any
|
||||
CommentsEnabled bool
|
||||
WebmentionReceivingEnabled bool
|
||||
TorUsed bool
|
||||
|
@ -91,6 +91,6 @@ func (a *goBlog) checkRenderData(r *http.Request, data *renderData) {
|
|||
}
|
||||
// Data
|
||||
if data.Data == nil {
|
||||
data.Data = map[string]interface{}{}
|
||||
data.Data = map[string]any{}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ func (db *database) shortenPath(p string) (string, error) {
|
|||
if p == "" {
|
||||
return "", errors.New("empty path")
|
||||
}
|
||||
spi, err, _ := db.sp.Do(p, func() (interface{}, error) {
|
||||
spi, err, _ := db.sp.Do(p, func() (any, error) {
|
||||
// Check if already cached
|
||||
if spi, ok := db.spc.Get(p); ok {
|
||||
return spi.(string), nil
|
||||
|
|
|
@ -172,7 +172,7 @@ func (a *goBlog) serveSitemapBlogPosts(w http.ResponseWriter, r *http.Request) {
|
|||
a.writeSitemapXML(w, sm)
|
||||
}
|
||||
|
||||
func (a *goBlog) writeSitemapXML(w http.ResponseWriter, sm interface{}) {
|
||||
func (a *goBlog) writeSitemapXML(w http.ResponseWriter, sm any) {
|
||||
w.Header().Set(contentType, contenttype.XMLUTF8)
|
||||
pipeReader, pipeWriter := io.Pipe()
|
||||
go func() {
|
||||
|
|
|
@ -36,7 +36,7 @@ func (a *goBlog) getTailscaleListener(addr string) (net.Listener, error) {
|
|||
a.tss = &tsnet.Server{
|
||||
Hostname: tsconfig.Hostname,
|
||||
Dir: tailscaleDir,
|
||||
Logf: func(format string, args ...interface{}) {
|
||||
Logf: func(format string, args ...any) {
|
||||
log.Printf("tailscale: "+format, args...)
|
||||
},
|
||||
}
|
||||
|
|
10
tts.go
10
tts.go
|
@ -192,20 +192,20 @@ func (a *goBlog) createTTSAudio(lang, ssml string, w io.Writer) error {
|
|||
}
|
||||
|
||||
// Create request body
|
||||
body := map[string]interface{}{
|
||||
"audioConfig": map[string]interface{}{
|
||||
body := map[string]any{
|
||||
"audioConfig": map[string]any{
|
||||
"audioEncoding": "MP3",
|
||||
},
|
||||
"input": map[string]interface{}{
|
||||
"input": map[string]any{
|
||||
"ssml": ssml,
|
||||
},
|
||||
"voice": map[string]interface{}{
|
||||
"voice": map[string]any{
|
||||
"languageCode": lang,
|
||||
},
|
||||
}
|
||||
|
||||
// Do request
|
||||
var response map[string]interface{}
|
||||
var response map[string]any
|
||||
err := requests.
|
||||
URL("https://texttospeech.googleapis.com/v1beta1/text:synthesize").
|
||||
Param("key", gctts.GoogleAPIKey).
|
||||
|
|
8
ui.go
8
ui.go
|
@ -7,7 +7,7 @@ import (
|
|||
"github.com/hacdias/indieauth"
|
||||
"github.com/kaorimatz/go-opml"
|
||||
"github.com/mergestat/timediff"
|
||||
"github.com/thoas/go-funk"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
func (a *goBlog) renderEditorPreview(hb *htmlBuilder, bc *configBlog, p *post) {
|
||||
|
@ -279,7 +279,7 @@ func (a *goBlog) renderSearch(hb *htmlBuilder, rd *renderData) {
|
|||
// Form
|
||||
hb.writeElementOpen("form", "class", "fw p", "method", "post")
|
||||
// Search
|
||||
args := []interface{}{"type", "text", "name", "q", "required", ""}
|
||||
args := []any{"type", "text", "name", "q", "required", ""}
|
||||
if sc.Placeholder != "" {
|
||||
args = append(args, "placeholder", a.renderMdTitle(sc.Placeholder))
|
||||
}
|
||||
|
@ -882,7 +882,7 @@ func (a *goBlog) renderPost(hb *htmlBuilder, rd *renderData) {
|
|||
// Post actions
|
||||
hb.writeElementOpen("div", "class", "actions")
|
||||
// Share button
|
||||
hb.writeElementOpen("a", "class", "button", "href", fmt.Sprintf("https://www.addtoany.com/share#url=%s%s", a.shortPostURL(p), funk.ShortIf(p.RenderedTitle != "", "&title="+p.RenderedTitle, "")), "target", "_blank", "rel", "nofollow noopener noreferrer")
|
||||
hb.writeElementOpen("a", "class", "button", "href", fmt.Sprintf("https://www.addtoany.com/share#url=%s%s", a.shortPostURL(p), lo.If(p.RenderedTitle != "", "&title="+p.RenderedTitle).Else("")), "target", "_blank", "rel", "nofollow noopener noreferrer")
|
||||
hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "share"))
|
||||
hb.writeElementClose("a")
|
||||
// Translate button
|
||||
|
@ -894,7 +894,7 @@ func (a *goBlog) renderPost(hb *htmlBuilder, rd *renderData) {
|
|||
// Speak button
|
||||
hb.writeElementOpen("button", "id", "speakBtn", "class", "hide", "data-speak", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "speak"), "data-stopspeak", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "stopspeak"))
|
||||
hb.writeElementClose("button")
|
||||
hb.writeElementOpen("script", "defer", "", "src", funk.ShortIf(p.TTS() != "", a.assetFileName("js/tts.js"), a.assetFileName("js/speak.js")))
|
||||
hb.writeElementOpen("script", "defer", "", "src", lo.If(p.TTS() != "", a.assetFileName("js/tts.js")).Else(a.assetFileName("js/speak.js")))
|
||||
hb.writeElementClose("script")
|
||||
hb.writeElementClose("div")
|
||||
// TTS
|
||||
|
|
|
@ -36,7 +36,7 @@ func (h *htmlBuilder) writeEscaped(s string) {
|
|||
textTemplate.HTMLEscape(h, []byte(s))
|
||||
}
|
||||
|
||||
func (h *htmlBuilder) writeAttribute(attr string, val interface{}) {
|
||||
func (h *htmlBuilder) writeAttribute(attr string, val any) {
|
||||
h.write(` `)
|
||||
h.write(attr)
|
||||
h.write(`=`)
|
||||
|
@ -49,7 +49,7 @@ func (h *htmlBuilder) writeAttribute(attr string, val interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
func (h *htmlBuilder) writeElementOpen(tag string, attrs ...interface{}) {
|
||||
func (h *htmlBuilder) writeElementOpen(tag string, attrs ...any) {
|
||||
h.write(`<`)
|
||||
h.write(tag)
|
||||
for i := 0; i < len(attrs); i += 2 {
|
||||
|
|
25
utils.go
25
utils.go
|
@ -5,6 +5,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
|
@ -23,7 +24,7 @@ import (
|
|||
"github.com/c2h5oh/datasize"
|
||||
tdl "github.com/mergestat/timediff/locale"
|
||||
"github.com/microcosm-cc/bluemonday"
|
||||
"github.com/thoas/go-funk"
|
||||
"github.com/samber/lo"
|
||||
"go.goblog.app/app/pkgs/bufferpool"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
@ -55,10 +56,15 @@ func sortedStrings(s []string) []string {
|
|||
return s
|
||||
}
|
||||
|
||||
const randomLetters = "abcdefghijklmnopqrstuvwxyz"
|
||||
var defaultLetters = []rune("abcdefghijklmnopqrstuvwxyz")
|
||||
|
||||
func generateRandomString(chars int) string {
|
||||
return funk.RandomString(chars, []rune(randomLetters))
|
||||
func randomString(n int, allowedChars ...[]rune) string {
|
||||
letters := append(allowedChars, defaultLetters)[0]
|
||||
b := make([]rune, n)
|
||||
for i := range b {
|
||||
b[i] = letters[rand.Intn(len(letters))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func isAbsoluteURL(s string) bool {
|
||||
|
@ -84,7 +90,7 @@ func allLinksFromHTML(r io.Reader, baseURL string) ([]string, error) {
|
|||
}
|
||||
})
|
||||
links, err = resolveURLReferences(baseURL, links...)
|
||||
return funk.UniqString(links), err
|
||||
return lo.Uniq(links), err
|
||||
}
|
||||
|
||||
func resolveURLReferences(base string, refs ...string) ([]string, error) {
|
||||
|
@ -212,8 +218,8 @@ func urlHasExt(rawUrl string, allowed ...string) (ext string, has bool) {
|
|||
return "", false
|
||||
}
|
||||
ext = ext[1:]
|
||||
allowed = funk.Map(allowed, strings.ToLower).([]string)
|
||||
return ext, funk.ContainsString(allowed, strings.ToLower(ext))
|
||||
allowed = lo.Map(allowed, func(t string, _ int) string { return strings.ToLower(t) })
|
||||
return ext, lo.Contains(allowed, strings.ToLower(ext))
|
||||
}
|
||||
|
||||
func mBytesString(size int64) string {
|
||||
|
@ -274,7 +280,10 @@ func cleanHTMLText(s string) string {
|
|||
}
|
||||
|
||||
func defaultIfEmpty(s, d string) string {
|
||||
return funk.ShortIf(s != "", s, d).(string)
|
||||
if s == "" {
|
||||
return d
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func containsStrings(s string, subStrings ...string) bool {
|
||||
|
|
|
@ -12,6 +12,16 @@ func Test_urlize(t *testing.T) {
|
|||
assert.Equal(t, "this-is-a-test", urlize("This Is A Test"))
|
||||
}
|
||||
|
||||
func Fuzz_urlize(f *testing.F) {
|
||||
f.Add("Test")
|
||||
f.Fuzz(func(t *testing.T, str string) {
|
||||
out := urlize(str)
|
||||
if out == "" {
|
||||
t.Error("Empty output")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Benchmark_urlize(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
urlize("äbc ef")
|
||||
|
@ -23,8 +33,8 @@ func Test_sortedStrings(t *testing.T) {
|
|||
}
|
||||
|
||||
func Test_generateRandomString(t *testing.T) {
|
||||
assert.Len(t, generateRandomString(30), 30)
|
||||
assert.Len(t, generateRandomString(50), 50)
|
||||
assert.Len(t, randomString(30), 30)
|
||||
assert.Len(t, randomString(50), 50)
|
||||
}
|
||||
|
||||
func Test_isAbsoluteURL(t *testing.T) {
|
||||
|
|
|
@ -226,7 +226,7 @@ type webmentionsRequestConfig struct {
|
|||
submentions bool
|
||||
}
|
||||
|
||||
func buildWebmentionsQuery(config *webmentionsRequestConfig) (query string, args []interface{}) {
|
||||
func buildWebmentionsQuery(config *webmentionsRequestConfig) (query string, args []any) {
|
||||
queryBuilder := bufferpool.Get()
|
||||
defer bufferpool.Put(queryBuilder)
|
||||
queryBuilder.WriteString("select id, source, target, url, created, title, content, author, status from webmentions ")
|
||||
|
|
|
@ -6,28 +6,30 @@ import (
|
|||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/vcraescu/go-paginator"
|
||||
)
|
||||
|
||||
type webmentionPaginationAdapter struct {
|
||||
config *webmentionsRequestConfig
|
||||
nums int64
|
||||
db *database
|
||||
config *webmentionsRequestConfig
|
||||
nums int64
|
||||
getNums sync.Once
|
||||
db *database
|
||||
}
|
||||
|
||||
var _ paginator.Adapter = &webmentionPaginationAdapter{}
|
||||
|
||||
func (p *webmentionPaginationAdapter) Nums() (int64, error) {
|
||||
if p.nums == 0 {
|
||||
p.getNums.Do(func() {
|
||||
nums, _ := p.db.countWebmentions(p.config)
|
||||
p.nums = int64(nums)
|
||||
}
|
||||
})
|
||||
return p.nums, nil
|
||||
}
|
||||
|
||||
func (p *webmentionPaginationAdapter) Slice(offset, length int, data interface{}) error {
|
||||
func (p *webmentionPaginationAdapter) Slice(offset, length int, data any) error {
|
||||
modifiedConfig := *p.config
|
||||
modifiedConfig.offset = offset
|
||||
modifiedConfig.limit = length
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
"github.com/carlmjohnson/requests"
|
||||
"github.com/thoas/go-funk"
|
||||
"github.com/samber/lo"
|
||||
"github.com/tomnomnom/linkheader"
|
||||
"go.goblog.app/app/pkgs/bufferpool"
|
||||
)
|
||||
|
@ -44,7 +44,7 @@ func (a *goBlog) sendWebmentions(p *post) error {
|
|||
if mpc := a.cfg.Micropub; mpc != nil {
|
||||
links = append(links, p.firstParameter(a.cfg.Micropub.LikeParam), p.firstParameter(a.cfg.Micropub.ReplyParam), p.firstParameter(a.cfg.Micropub.BookmarkParam))
|
||||
}
|
||||
for _, link := range funk.UniqString(links) {
|
||||
for _, link := range lo.Uniq(links) {
|
||||
if link == "" {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
"github.com/thoas/go-funk"
|
||||
"github.com/samber/lo"
|
||||
"go.goblog.app/app/pkgs/bufferpool"
|
||||
"go.goblog.app/app/pkgs/contenttype"
|
||||
"willnorris.com/go/microformats"
|
||||
|
@ -161,7 +161,7 @@ func (a *goBlog) verifyReader(m *mention, body io.Reader) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, hasLink := funk.FindString(links, func(s string) bool {
|
||||
if _, hasLink := lo.Find(links, func(s string) bool {
|
||||
// Check if link belongs to installation
|
||||
hasShortPrefix := a.cfg.Server.ShortPublicAddress != "" && strings.HasPrefix(s, a.cfg.Server.ShortPublicAddress)
|
||||
hasLongPrefix := strings.HasPrefix(s, a.cfg.Server.PublicAddress)
|
||||
|
|
Loading…
Reference in New Issue