mirror of https://github.com/jlelse/GoBlog
Vanity import path and listing of media files
This commit is contained in:
parent
1e0b97b4d4
commit
2437ed70d7
|
@ -4,7 +4,7 @@
|
||||||
{
|
{
|
||||||
"label": "Build",
|
"label": "Build",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "go build",
|
"command": "go build -o GoBlog",
|
||||||
"options": {
|
"options": {
|
||||||
"env": {
|
"env": {
|
||||||
"GOFLAGS": "-tags=linux,libsqlite3,sqlite_fts5"
|
"GOFLAGS": "-tags=linux,libsqlite3,sqlite_fts5"
|
||||||
|
|
|
@ -15,10 +15,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/go-fed/httpsig"
|
"github.com/go-fed/httpsig"
|
||||||
"github.com/spf13/cast"
|
"github.com/spf13/cast"
|
||||||
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *goBlog) initActivityPub() error {
|
func (a *goBlog) initActivityPub() error {
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
type apRequest struct {
|
type apRequest struct {
|
||||||
|
|
|
@ -8,9 +8,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
|
||||||
"github.com/araddon/dateparse"
|
"github.com/araddon/dateparse"
|
||||||
ct "github.com/elnormous/contenttype"
|
ct "github.com/elnormous/contenttype"
|
||||||
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
const asContext = "https://www.w3.org/ns/activitystreams"
|
const asContext = "https://www.w3.org/ns/activitystreams"
|
||||||
|
|
2
app.go
2
app.go
|
@ -6,7 +6,6 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/minify"
|
|
||||||
shutdowner "git.jlel.se/jlelse/go-shutdowner"
|
shutdowner "git.jlel.se/jlelse/go-shutdowner"
|
||||||
ts "git.jlel.se/jlelse/template-strings"
|
ts "git.jlel.se/jlelse/template-strings"
|
||||||
ct "github.com/elnormous/contenttype"
|
ct "github.com/elnormous/contenttype"
|
||||||
|
@ -14,6 +13,7 @@ import (
|
||||||
"github.com/go-fed/httpsig"
|
"github.com/go-fed/httpsig"
|
||||||
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
|
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
|
||||||
"github.com/yuin/goldmark"
|
"github.com/yuin/goldmark"
|
||||||
|
"go.goblog.app/app/pkgs/minify"
|
||||||
"golang.org/x/sync/singleflight"
|
"golang.org/x/sync/singleflight"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
|
||||||
"github.com/pquerna/otp/totp"
|
"github.com/pquerna/otp/totp"
|
||||||
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *goBlog) checkCredentials(username, password, totpPasscode string) bool {
|
func (a *goBlog) checkCredentials(username, password, totpPasscode string) bool {
|
||||||
|
|
|
@ -10,10 +10,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
|
||||||
"github.com/kaorimatz/go-opml"
|
"github.com/kaorimatz/go-opml"
|
||||||
servertiming "github.com/mitchellh/go-server-timing"
|
servertiming "github.com/mitchellh/go-server-timing"
|
||||||
"github.com/thoas/go-funk"
|
"github.com/thoas/go-funk"
|
||||||
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *goBlog) serveBlogroll(w http.ResponseWriter, r *http.Request) {
|
func (a *goBlog) serveBlogroll(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -7,8 +7,8 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
|
||||||
"github.com/dchest/captcha"
|
"github.com/dchest/captcha"
|
||||||
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *goBlog) captchaMiddleware(next http.Handler) http.Handler {
|
func (a *goBlog) captchaMiddleware(next http.Handler) http.Handler {
|
||||||
|
|
|
@ -6,8 +6,8 @@ import (
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_captchaMiddleware(t *testing.T) {
|
func Test_captchaMiddleware(t *testing.T) {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
const editorPath = "/editor"
|
const editorPath = "/editor"
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *goBlog) serveEditorFiles(w http.ResponseWriter, r *http.Request) {
|
||||||
|
files, err := a.mediaFiles()
|
||||||
|
if err != nil {
|
||||||
|
a.serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Sort files time desc
|
||||||
|
sort.Slice(files, func(i, j int) bool {
|
||||||
|
return files[i].Time.After(files[j].Time)
|
||||||
|
})
|
||||||
|
// Serve HTML
|
||||||
|
blog := r.Context().Value(blogContextKey).(string)
|
||||||
|
a.render(w, r, templateEditorFiles, &renderData{
|
||||||
|
BlogString: blog,
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"Files": files,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *goBlog) serveEditorFilesView(w http.ResponseWriter, r *http.Request) {
|
||||||
|
filename := r.FormValue("filename")
|
||||||
|
if filename == "" {
|
||||||
|
a.serveError(w, r, "No file selected", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
http.Redirect(w, r, a.mediaFileLocation(filename), http.StatusFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *goBlog) serveEditorFilesDelete(w http.ResponseWriter, r *http.Request) {
|
||||||
|
filename := r.FormValue("filename")
|
||||||
|
if filename == "" {
|
||||||
|
a.serveError(w, r, "No file selected", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := a.deleteMediaFile(filename); err != nil {
|
||||||
|
a.serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
http.Redirect(w, r, a.getRelativePath(r.Context().Value(blogContextKey).(string), "/editor/files"), http.StatusFound)
|
||||||
|
}
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
|
||||||
ct "github.com/elnormous/contenttype"
|
ct "github.com/elnormous/contenttype"
|
||||||
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
type errorData struct {
|
type errorData struct {
|
||||||
|
|
|
@ -6,8 +6,8 @@ import (
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_errors(t *testing.T) {
|
func Test_errors(t *testing.T) {
|
||||||
|
|
2
feeds.go
2
feeds.go
|
@ -5,9 +5,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
|
||||||
"github.com/araddon/dateparse"
|
"github.com/araddon/dateparse"
|
||||||
"github.com/gorilla/feeds"
|
"github.com/gorilla/feeds"
|
||||||
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
type feedType string
|
type feedType string
|
||||||
|
|
10
go.mod
10
go.mod
|
@ -1,4 +1,4 @@
|
||||||
module git.jlel.se/jlelse/GoBlog
|
module go.goblog.app/app
|
||||||
|
|
||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ require (
|
||||||
github.com/andybalholm/cascadia v1.2.0 // indirect
|
github.com/andybalholm/cascadia v1.2.0 // indirect
|
||||||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
|
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
|
||||||
github.com/boombuler/barcode v1.0.1 // indirect
|
github.com/boombuler/barcode v1.0.1 // indirect
|
||||||
|
github.com/c2h5oh/datasize v0.0.0-20200825124411-48ed595a09d2
|
||||||
github.com/caddyserver/certmagic v0.14.0
|
github.com/caddyserver/certmagic v0.14.0
|
||||||
github.com/cretz/bine v0.2.0
|
github.com/cretz/bine v0.2.0
|
||||||
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
||||||
|
@ -45,17 +46,18 @@ require (
|
||||||
github.com/smartystreets/assertions v1.2.0 // indirect
|
github.com/smartystreets/assertions v1.2.0 // indirect
|
||||||
github.com/snabb/sitemap v1.0.0
|
github.com/snabb/sitemap v1.0.0
|
||||||
github.com/spf13/cast v1.3.1
|
github.com/spf13/cast v1.3.1
|
||||||
github.com/spf13/viper v1.8.0
|
github.com/spf13/viper v1.8.1
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/tdewolff/minify/v2 v2.9.17
|
github.com/tdewolff/minify/v2 v2.9.18
|
||||||
github.com/thoas/go-funk v0.8.0
|
github.com/thoas/go-funk v0.8.0
|
||||||
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
|
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
|
||||||
github.com/vcraescu/go-paginator v1.0.1-0.20201114172518-2cfc59fe05c2
|
github.com/vcraescu/go-paginator v1.0.1-0.20201114172518-2cfc59fe05c2
|
||||||
github.com/yuin/goldmark v1.3.8
|
github.com/yuin/goldmark v1.3.9
|
||||||
// master
|
// master
|
||||||
github.com/yuin/goldmark-emoji v1.0.2-0.20210607094911-0487583eca38
|
github.com/yuin/goldmark-emoji v1.0.2-0.20210607094911-0487583eca38
|
||||||
go.uber.org/atomic v1.8.0 // indirect
|
go.uber.org/atomic v1.8.0 // indirect
|
||||||
go.uber.org/multierr v1.7.0 // indirect
|
go.uber.org/multierr v1.7.0 // indirect
|
||||||
|
go.uber.org/zap v1.18.1 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e // indirect
|
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e // indirect
|
||||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e
|
golang.org/x/net v0.0.0-20210614182718-04defd469f4e
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||||
|
|
26
go.sum
26
go.sum
|
@ -63,12 +63,16 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
|
||||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
||||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||||
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
|
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
|
||||||
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
|
github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
|
||||||
|
github.com/c2h5oh/datasize v0.0.0-20200825124411-48ed595a09d2 h1:t8KYCwSKsOEZBFELI4Pn/phbp38iJ1RRAkDFNin1aak=
|
||||||
|
github.com/c2h5oh/datasize v0.0.0-20200825124411-48ed595a09d2/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
|
||||||
github.com/caddyserver/certmagic v0.14.0 h1:XW1o32s7smIYEJSc6g+N8YXljpjRo5ZE2zi3CIYTs74=
|
github.com/caddyserver/certmagic v0.14.0 h1:XW1o32s7smIYEJSc6g+N8YXljpjRo5ZE2zi3CIYTs74=
|
||||||
github.com/caddyserver/certmagic v0.14.0/go.mod h1:oRQOZmUVKwlpgNidslysHt05osM9uMrJ4YMk+Ot4P4Q=
|
github.com/caddyserver/certmagic v0.14.0/go.mod h1:oRQOZmUVKwlpgNidslysHt05osM9uMrJ4YMk+Ot4P4Q=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
@ -363,8 +367,8 @@ github.com/spf13/pflag v1.0.1-0.20170901120850-7aff26db30c1/go.mod h1:DYY7MBk1bd
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
|
github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
|
||||||
github.com/spf13/viper v1.8.0 h1:QRwDgoG8xX+kp69di68D+YYTCWfYEckbZRfUlEIAal0=
|
github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44=
|
||||||
github.com/spf13/viper v1.8.0/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
@ -375,8 +379,10 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
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/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/tdewolff/minify/v2 v2.9.17 h1:0RPKCBSz5plIKZkmkm/zeQdqPYf/9NJVwG63NHtViHQ=
|
github.com/tdewolff/minify/v2 v2.9.18 h1:j5Is0sOGp4cxm0o3HgvHCWCvTtmKnfB0qv0FCRbmgZY=
|
||||||
github.com/tdewolff/minify/v2 v2.9.17/go.mod h1:OLHZpngMfp36EyqxkGGta1l3hB1c+sHhXNHk8WTrsQo=
|
github.com/tdewolff/minify/v2 v2.9.18/go.mod h1:0y0mXZnisZm8HcgQvAV0btxa1IgecGam90zMuHqEZuc=
|
||||||
|
github.com/tdewolff/parse/v2 v2.5.18 h1:d67Ql/Pe36JcJZ7J2MY8upx6iTxbxGS9lzwyFGtMmd0=
|
||||||
|
github.com/tdewolff/parse/v2 v2.5.18/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
|
||||||
github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
|
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/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
||||||
github.com/thoas/go-funk v0.8.0 h1:JP9tKSvnpFVclYgDM0Is7FD9M4fhPvqA0s0BsXmzSRQ=
|
github.com/thoas/go-funk v0.8.0 h1:JP9tKSvnpFVclYgDM0Is7FD9M4fhPvqA0s0BsXmzSRQ=
|
||||||
|
@ -391,8 +397,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark v1.3.7/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.7/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark v1.3.8 h1:Nw158Q8QN+CPgTmVRByhVwapp8Mm1e2blinhmx4wx5E=
|
github.com/yuin/goldmark v1.3.9 h1:XsVHmzm4P6g84IBbAj+WYMF/IEZ3J9+3I1wlqCNa/SQ=
|
||||||
github.com/yuin/goldmark v1.3.8/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.9/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark-emoji v1.0.2-0.20210607094911-0487583eca38 h1:XZjLcLoTPNZuxppY3gwhRqo/T2XF6JMGFFdkAjX3w1w=
|
github.com/yuin/goldmark-emoji v1.0.2-0.20210607094911-0487583eca38 h1:XZjLcLoTPNZuxppY3gwhRqo/T2XF6JMGFFdkAjX3w1w=
|
||||||
github.com/yuin/goldmark-emoji v1.0.2-0.20210607094911-0487583eca38/go.mod h1:RhP/RWpexdp+KHs7ghKnifRoIs/Bq4nDS7tRbCkOwKY=
|
github.com/yuin/goldmark-emoji v1.0.2-0.20210607094911-0487583eca38/go.mod h1:RhP/RWpexdp+KHs7ghKnifRoIs/Bq4nDS7tRbCkOwKY=
|
||||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||||
|
@ -409,14 +415,17 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/atomic v1.8.0 h1:CUhrE4N1rqSE6FM9ecihEjRkLQu8cDfgDyoOs83mEY4=
|
go.uber.org/atomic v1.8.0 h1:CUhrE4N1rqSE6FM9ecihEjRkLQu8cDfgDyoOs83mEY4=
|
||||||
go.uber.org/atomic v1.8.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.8.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
|
||||||
|
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||||
go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec=
|
go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec=
|
||||||
go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
|
go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
|
||||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||||
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||||
go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U=
|
|
||||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||||
|
go.uber.org/zap v1.18.1 h1:CSUJ2mjFszzEWt4CdKISEuChVIXGBn3lAPwkRGyVrc4=
|
||||||
|
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
@ -450,6 +459,7 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu
|
||||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
|
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
|
||||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||||
|
@ -610,6 +620,7 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn
|
||||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
@ -644,6 +655,7 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
|
||||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||||
|
golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA=
|
||||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|
3
http.go
3
http.go
|
@ -194,6 +194,9 @@ func (a *goBlog) buildStaticHandlersRouters() error {
|
||||||
a.editorRouter.Use(a.authMiddleware)
|
a.editorRouter.Use(a.authMiddleware)
|
||||||
a.editorRouter.Get("/", a.serveEditor)
|
a.editorRouter.Get("/", a.serveEditor)
|
||||||
a.editorRouter.Post("/", a.serveEditorPost)
|
a.editorRouter.Post("/", a.serveEditorPost)
|
||||||
|
a.editorRouter.Get("/files", a.serveEditorFiles)
|
||||||
|
a.editorRouter.Post("/files/view", a.serveEditorFilesView)
|
||||||
|
a.editorRouter.Post("/files/delete", a.serveEditorFilesDelete)
|
||||||
|
|
||||||
a.commentsRouter = chi.NewRouter()
|
a.commentsRouter = chi.NewRouter()
|
||||||
a.commentsRouter.Use(a.privateModeHandler...)
|
a.commentsRouter.Use(a.privateModeHandler...)
|
||||||
|
|
|
@ -11,8 +11,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
|
||||||
"github.com/spf13/cast"
|
"github.com/spf13/cast"
|
||||||
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
// https://www.w3.org/TR/indieauth/
|
// https://www.w3.org/TR/indieauth/
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultCompressionWidth = 2000
|
const defaultCompressionWidth = 2000
|
||||||
|
|
157
mediaStorage.go
157
mediaStorage.go
|
@ -12,9 +12,7 @@ import (
|
||||||
"github.com/jlaffaye/ftp"
|
"github.com/jlaffaye/ftp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mediaStorageSaveFunc func(filename string, file io.Reader) (location string, err error)
|
func (a *goBlog) initMediaStorage() {
|
||||||
|
|
||||||
func (a *goBlog) saveMediaFile(filename string, f io.Reader) (string, error) {
|
|
||||||
a.mediaStorageInit.Do(func() {
|
a.mediaStorageInit.Do(func() {
|
||||||
type initFunc func() mediaStorage
|
type initFunc func() mediaStorage
|
||||||
for _, fc := range []initFunc{a.initBunnyCdnMediaStorage, a.initFtpMediaStorage, a.initLocalMediaStorage} {
|
for _, fc := range []initFunc{a.initBunnyCdnMediaStorage, a.initFtpMediaStorage, a.initLocalMediaStorage} {
|
||||||
|
@ -24,6 +22,12 @@ func (a *goBlog) saveMediaFile(filename string, f io.Reader) (string, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type mediaStorageSaveFunc func(filename string, file io.Reader) (location string, err error)
|
||||||
|
|
||||||
|
func (a *goBlog) saveMediaFile(filename string, f io.Reader) (string, error) {
|
||||||
|
a.initMediaStorage()
|
||||||
if a.mediaStorage == nil {
|
if a.mediaStorage == nil {
|
||||||
return "", errors.New("no media storage configured")
|
return "", errors.New("no media storage configured")
|
||||||
}
|
}
|
||||||
|
@ -34,8 +38,42 @@ func (a *goBlog) saveMediaFile(filename string, f io.Reader) (string, error) {
|
||||||
return a.getFullAddress(loc), nil
|
return a.getFullAddress(loc), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *goBlog) deleteMediaFile(filename string) error {
|
||||||
|
a.initMediaStorage()
|
||||||
|
if a.mediaStorage == nil {
|
||||||
|
return errors.New("no media storage configured")
|
||||||
|
}
|
||||||
|
return a.mediaStorage.delete(filepath.Base(filename))
|
||||||
|
}
|
||||||
|
|
||||||
|
type mediaFile struct {
|
||||||
|
Name string
|
||||||
|
Location string
|
||||||
|
Time time.Time
|
||||||
|
Size int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *goBlog) mediaFiles() ([]*mediaFile, error) {
|
||||||
|
a.initMediaStorage()
|
||||||
|
if a.mediaStorage == nil {
|
||||||
|
return nil, errors.New("no media storage configured")
|
||||||
|
}
|
||||||
|
return a.mediaStorage.files()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *goBlog) mediaFileLocation(name string) string {
|
||||||
|
a.initMediaStorage()
|
||||||
|
if a.mediaStorage == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return a.mediaStorage.location(name)
|
||||||
|
}
|
||||||
|
|
||||||
type mediaStorage interface {
|
type mediaStorage interface {
|
||||||
save(filename string, file io.Reader) (location string, err error)
|
save(filename string, file io.Reader) (location string, err error)
|
||||||
|
delete(filename string) (err error)
|
||||||
|
files() (files []*mediaFile, err error)
|
||||||
|
location(filename string) (location string)
|
||||||
}
|
}
|
||||||
|
|
||||||
type localMediaStorage struct {
|
type localMediaStorage struct {
|
||||||
|
@ -64,10 +102,46 @@ func (l *localMediaStorage) save(filename string, file io.Reader) (location stri
|
||||||
if _, err = io.Copy(newFile, file); err != nil {
|
if _, err = io.Copy(newFile, file); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if l.mediaURL != "" {
|
return l.location(filename), nil
|
||||||
return fmt.Sprintf("%s/%s", l.mediaURL, filename), nil
|
}
|
||||||
|
|
||||||
|
func (l *localMediaStorage) delete(filename string) (err error) {
|
||||||
|
if err = os.MkdirAll(l.path, 0644); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("/m/%s", filename), nil
|
return os.Remove(filepath.Join(l.path, filename))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *localMediaStorage) files() (files []*mediaFile, err error) {
|
||||||
|
if err = os.MkdirAll(l.path, 0644); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
entries, err := os.ReadDir(l.path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, e := range entries {
|
||||||
|
fi, er := e.Info()
|
||||||
|
if er != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if fi.Mode().IsRegular() {
|
||||||
|
files = append(files, &mediaFile{
|
||||||
|
Name: fi.Name(),
|
||||||
|
Location: l.location(fi.Name()),
|
||||||
|
Time: fi.ModTime(),
|
||||||
|
Size: int64(fi.Size()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return files, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *localMediaStorage) location(name string) string {
|
||||||
|
if l.mediaURL != "" {
|
||||||
|
return fmt.Sprintf("%s/%s", l.mediaURL, name)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("/m/%s", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *goBlog) initBunnyCdnMediaStorage() mediaStorage {
|
func (a *goBlog) initBunnyCdnMediaStorage() mediaStorage {
|
||||||
|
@ -108,21 +182,72 @@ func (a *goBlog) initFtpMediaStorage() mediaStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *ftpMediaStorage) save(filename string, file io.Reader) (location string, err error) {
|
func (f *ftpMediaStorage) save(filename string, file io.Reader) (location string, err error) {
|
||||||
if f.address == "" || f.user == "" || f.password == "" {
|
c, err := f.connection()
|
||||||
return "", errors.New("missing FTP config")
|
|
||||||
}
|
|
||||||
c, err := ftp.Dial(f.address, ftp.DialWithTimeout(5*time.Second))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = c.Quit()
|
if c != nil {
|
||||||
|
_ = c.Quit()
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
if err = c.Login(f.user, f.password); err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if err = c.Stor(filename, file); err != nil {
|
if err = c.Stor(filename, file); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s/%s", f.mediaURL, filename), nil
|
return f.location(filename), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ftpMediaStorage) delete(filename string) (err error) {
|
||||||
|
c, err := f.connection()
|
||||||
|
defer func() {
|
||||||
|
if c != nil {
|
||||||
|
_ = c.Quit()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.Delete(filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ftpMediaStorage) files() (files []*mediaFile, err error) {
|
||||||
|
c, err := f.connection()
|
||||||
|
defer func() {
|
||||||
|
if c != nil {
|
||||||
|
_ = c.Quit()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
w := c.Walk("")
|
||||||
|
for w.Next() {
|
||||||
|
if s := w.Stat(); s.Type == ftp.EntryTypeFile {
|
||||||
|
files = append(files, &mediaFile{
|
||||||
|
Name: s.Name,
|
||||||
|
Location: f.location(s.Name),
|
||||||
|
Time: s.Time,
|
||||||
|
Size: int64(s.Size),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return files, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ftpMediaStorage) location(name string) string {
|
||||||
|
return fmt.Sprintf("%s/%s", f.mediaURL, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ftpMediaStorage) connection() (*ftp.ServerConn, error) {
|
||||||
|
if f.address == "" || f.user == "" || f.password == "" {
|
||||||
|
return nil, errors.New("missing FTP config")
|
||||||
|
}
|
||||||
|
c, err := ftp.Dial(f.address, ftp.DialWithTimeout(5*time.Second))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = c.Login(f.user, f.password); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
|
||||||
"github.com/spf13/cast"
|
"github.com/spf13/cast"
|
||||||
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
const micropubMediaSubPath = "/media"
|
const micropubMediaSubPath = "/media"
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *goBlog) serveNodeInfoDiscover(w http.ResponseWriter, r *http.Request) {
|
func (a *goBlog) serveNodeInfoDiscover(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -28,7 +28,7 @@ func (a *goBlog) serveNodeInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
"version": "2.1",
|
"version": "2.1",
|
||||||
"software": map[string]interface{}{
|
"software": map[string]interface{}{
|
||||||
"name": "goblog",
|
"name": "goblog",
|
||||||
"repository": "https://git.jlel.se/jlelse/GoBlog",
|
"repository": "https://go.goblog.app/app",
|
||||||
},
|
},
|
||||||
"usage": map[string]interface{}{
|
"usage": map[string]interface{}{
|
||||||
"users": map[string]interface{}{
|
"users": map[string]interface{}{
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *goBlog) serveOpenSearch(w http.ResponseWriter, r *http.Request) {
|
func (a *goBlog) serveOpenSearch(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -118,7 +118,7 @@ form {
|
||||||
.fw-form {
|
.fw-form {
|
||||||
@extend .fw;
|
@extend .fw;
|
||||||
|
|
||||||
input:not([type]), input[type="submit"], input[type="button"], input[type="text"], input[type="email"], input[type="url"], input[type="password"], textarea {
|
input:not([type]), input[type="submit"], input[type="button"], input[type="text"], input[type="email"], input[type="url"], input[type="password"], input[type="file"], textarea, select {
|
||||||
@extend .fw;
|
@extend .fw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,13 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
|
||||||
"github.com/tdewolff/minify/v2"
|
"github.com/tdewolff/minify/v2"
|
||||||
mCss "github.com/tdewolff/minify/v2/css"
|
mCss "github.com/tdewolff/minify/v2/css"
|
||||||
mHtml "github.com/tdewolff/minify/v2/html"
|
mHtml "github.com/tdewolff/minify/v2/html"
|
||||||
mJs "github.com/tdewolff/minify/v2/js"
|
mJs "github.com/tdewolff/minify/v2/js"
|
||||||
mJson "github.com/tdewolff/minify/v2/json"
|
mJson "github.com/tdewolff/minify/v2/json"
|
||||||
mXml "github.com/tdewolff/minify/v2/xml"
|
mXml "github.com/tdewolff/minify/v2/xml"
|
||||||
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Minifier struct {
|
type Minifier struct {
|
||||||
|
|
|
@ -11,8 +11,8 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
|
||||||
servertiming "github.com/mitchellh/go-server-timing"
|
servertiming "github.com/mitchellh/go-server-timing"
|
||||||
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -28,6 +28,7 @@ const (
|
||||||
templateSummary = "summary"
|
templateSummary = "summary"
|
||||||
templatePhotosSummary = "photosummary"
|
templatePhotosSummary = "photosummary"
|
||||||
templateEditor = "editor"
|
templateEditor = "editor"
|
||||||
|
templateEditorFiles = "editorfiles"
|
||||||
templateLogin = "login"
|
templateLogin = "login"
|
||||||
templateStaticHome = "statichome"
|
templateStaticHome = "statichome"
|
||||||
templateBlogStats = "blogstats"
|
templateBlogStats = "blogstats"
|
||||||
|
@ -68,6 +69,7 @@ func (a *goBlog) initRendering() error {
|
||||||
"geotitle": a.geoTitle,
|
"geotitle": a.geoTitle,
|
||||||
"geolink": geoOSMLink,
|
"geolink": geoOSMLink,
|
||||||
"opensearch": openSearchUrl,
|
"opensearch": openSearchUrl,
|
||||||
|
"mbytes": mBytesString,
|
||||||
}
|
}
|
||||||
baseTemplate, err := template.New("base").Funcs(templateFunctions).ParseFiles(path.Join(templatesDir, templateBase+templatesExt))
|
baseTemplate, err := template.New("base").Funcs(templateFunctions).ParseFiles(path.Join(templatesDir, templateBase+templatesExt))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
const assetsFolder = "templates/assets"
|
const assetsFolder = "templates/assets"
|
||||||
|
|
|
@ -163,7 +163,7 @@ footer * {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fw, .fw-form, .fw-form input:not([type]), .fw-form input[type=submit], .fw-form input[type=button], .fw-form input[type=text], .fw-form input[type=email], .fw-form input[type=url], .fw-form input[type=password], .fw-form textarea {
|
.fw, .fw-form, .fw-form input:not([type]), .fw-form input[type=submit], .fw-form input[type=button], .fw-form input[type=text], .fw-form input[type=email], .fw-form input[type=url], .fw-form input[type=password], .fw-form input[type=file], .fw-form textarea, .fw-form select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
(function () {
|
||||||
|
Array.from(document.querySelectorAll('form input.confirm')).forEach(element => {
|
||||||
|
let showed = false
|
||||||
|
element.form.addEventListener('submit', event => {
|
||||||
|
if (!showed) {
|
||||||
|
event.preventDefault()
|
||||||
|
element.value = '…'
|
||||||
|
setTimeout(() => {
|
||||||
|
element.value = element.dataset.confirmmessage
|
||||||
|
showed = true
|
||||||
|
}, 1000)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})()
|
|
@ -47,14 +47,15 @@ tags:
|
||||||
<h2>{{ string .Blog.Lang "upload" }}</h2>
|
<h2>{{ string .Blog.Lang "upload" }}</h2>
|
||||||
<form class="fw-form p" method="post" enctype="multipart/form-data">
|
<form class="fw-form p" method="post" enctype="multipart/form-data">
|
||||||
<input type="hidden" name="editoraction" value="upload">
|
<input type="hidden" name="editoraction" value="upload">
|
||||||
<input class="fw" type="file" name="file">
|
<input type="file" name="file">
|
||||||
<input type="submit" value="{{ string .Blog.Lang "upload" }}">
|
<input type="submit" value="{{ string .Blog.Lang "upload" }}">
|
||||||
</form>
|
</form>
|
||||||
|
<p><a href="{{ .Blog.RelativePath "/editor/files" }}">{{ string .Blog.Lang "mediafiles" }}</a></p>
|
||||||
{{ if .Data.Drafts }}
|
{{ if .Data.Drafts }}
|
||||||
<h2>{{ string .Blog.Lang "drafts" }}</h2>
|
<h2>{{ string .Blog.Lang "drafts" }}</h2>
|
||||||
<form class="fw-form p" method="post">
|
<form class="fw-form p" method="post">
|
||||||
<input type="hidden" name="editoraction" value="viewdraft">
|
<input type="hidden" name="editoraction" value="viewdraft">
|
||||||
<select name="url" class="fw">
|
<select name="url">
|
||||||
{{ range $i, $draft := .Data.Drafts }}
|
{{ range $i, $draft := .Data.Drafts }}
|
||||||
<option value="{{ absolute $draft.Path }}">{{ with ($draft.Title) }}{{ . }}{{ else }}{{ $draft.Path }}{{ end }}</option>
|
<option value="{{ absolute $draft.Path }}">{{ with ($draft.Title) }}{{ . }}{{ else }}{{ $draft.Path }}{{ end }}</option>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
@ -64,7 +65,7 @@ tags:
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<h2>{{ string .Blog.Lang "location" }}</h2>
|
<h2>{{ string .Blog.Lang "location" }}</h2>
|
||||||
<form class="fw-form p">
|
<form class="fw-form p">
|
||||||
<input id="geobtn" type="button" class="fw" value="{{ string .Blog.Lang "locationget" }}" data-failed="{{ string .Blog.Lang "locationfailed" }}" data-notsupported="{{ string .Blog.Lang "locationnotsupported" }}">
|
<input id="geobtn" type="button" value="{{ string .Blog.Lang "locationget" }}" data-failed="{{ string .Blog.Lang "locationfailed" }}" data-notsupported="{{ string .Blog.Lang "locationnotsupported" }}">
|
||||||
<input id="geostatus" type="text" class="hide" readonly>
|
<input id="geostatus" type="text" class="hide" readonly>
|
||||||
</form>
|
</form>
|
||||||
<script defer src="{{ asset "js/geohelper.js" }}"></script>
|
<script defer src="{{ asset "js/geohelper.js" }}"></script>
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
{{ define "title" }}
|
||||||
|
<title>{{ string .Blog.Lang "mediafiles" }} - {{ .Blog.Title }}</title>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ define "main" }}
|
||||||
|
<main>
|
||||||
|
{{ $blog := .Blog }}
|
||||||
|
<h2>{{ string .Blog.Lang "mediafiles" }}</h2>
|
||||||
|
{{ if .Data.Files }}
|
||||||
|
<form class="fw-form p" method="post">
|
||||||
|
<select name="filename">
|
||||||
|
{{ range $i, $file := .Data.Files }}
|
||||||
|
<option value="{{ $file.Name }}">{{ $file.Name }} ({{ isodate $file.Time.String }}, {{ mbytes $file.Size }})</option>
|
||||||
|
{{ end }}
|
||||||
|
</select>
|
||||||
|
<input type="submit" formaction="{{ .Blog.RelativePath "/editor/files/view" }}" value="{{ string .Blog.Lang "view" }}">
|
||||||
|
<input type="submit" formaction="{{ .Blog.RelativePath "/editor/files/delete" }}" value="{{ string .Blog.Lang "delete" }}" class="confirm" data-confirmmessage="{{ string .Blog.Lang "confirmdelete" }}">
|
||||||
|
</form>
|
||||||
|
<script defer src="{{ asset "js/formconfirm.js" }}"></script>
|
||||||
|
{{ else }}
|
||||||
|
<p>{{ string .Blog.Lang "nofiles" }}</p>
|
||||||
|
{{ end }}
|
||||||
|
</main>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ define "editorfiles" }}
|
||||||
|
{{ template "base" . }}
|
||||||
|
{{ end }}
|
|
@ -19,7 +19,9 @@ location: "Standort"
|
||||||
locationfailed: "Abfragen des Standorts fehlgeschlagen"
|
locationfailed: "Abfragen des Standorts fehlgeschlagen"
|
||||||
locationget: "Standort abfragen"
|
locationget: "Standort abfragen"
|
||||||
locationnotsupported: "Die Standort-API wird von diesem Browser nicht unterstützt"
|
locationnotsupported: "Die Standort-API wird von diesem Browser nicht unterstützt"
|
||||||
|
mediafiles: "Medien-Dateien"
|
||||||
next: "Weiter"
|
next: "Weiter"
|
||||||
|
nofiles: "Keine Dateien"
|
||||||
noposts: "Hier sind keine Posts."
|
noposts: "Hier sind keine Posts."
|
||||||
oldcontent: "⚠️ Dieser Eintrag ist bereits über ein Jahr alt. Er ist möglicherweise nicht mehr aktuell. Meinungen können sich geändert haben."
|
oldcontent: "⚠️ Dieser Eintrag ist bereits über ein Jahr alt. Er ist möglicherweise nicht mehr aktuell. Meinungen können sich geändert haben."
|
||||||
posts: "Posts"
|
posts: "Posts"
|
||||||
|
|
|
@ -28,8 +28,10 @@ locationget: "Request location"
|
||||||
locationnotsupported: "The location API is not supported by this browser"
|
locationnotsupported: "The location API is not supported by this browser"
|
||||||
login: "Login"
|
login: "Login"
|
||||||
logout: "Logout"
|
logout: "Logout"
|
||||||
|
mediafiles: "Media files"
|
||||||
nameopt: "Name (optional)"
|
nameopt: "Name (optional)"
|
||||||
next: "Next"
|
next: "Next"
|
||||||
|
nofiles: "No files"
|
||||||
noposts: "There are no posts here."
|
noposts: "There are no posts here."
|
||||||
notifications: "Notifications"
|
notifications: "Notifications"
|
||||||
oldcontent: "⚠️ This entry is already over one year old. It may no longer be up to date. Opinions may have changed."
|
oldcontent: "⚠️ This entry is already over one year old. It may no longer be up to date. Opinions may have changed."
|
||||||
|
|
5
utils.go
5
utils.go
|
@ -15,6 +15,7 @@ import (
|
||||||
|
|
||||||
"github.com/PuerkitoBio/goquery"
|
"github.com/PuerkitoBio/goquery"
|
||||||
"github.com/araddon/dateparse"
|
"github.com/araddon/dateparse"
|
||||||
|
"github.com/c2h5oh/datasize"
|
||||||
"github.com/thoas/go-funk"
|
"github.com/thoas/go-funk"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -226,3 +227,7 @@ func getSHA256(file io.ReadSeeker) (filename string, err error) {
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%x", h.Sum(nil)), nil
|
return fmt.Sprintf("%x", h.Sum(nil)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mBytesString(size int64) string {
|
||||||
|
return fmt.Sprintf("%.2f MB", datasize.ByteSize(size).MBytes())
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
type webmentionStatus string
|
type webmentionStatus string
|
||||||
|
|
|
@ -8,10 +8,10 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
|
||||||
"github.com/PuerkitoBio/goquery"
|
"github.com/PuerkitoBio/goquery"
|
||||||
"github.com/thoas/go-funk"
|
"github.com/thoas/go-funk"
|
||||||
"github.com/tomnomnom/linkheader"
|
"github.com/tomnomnom/linkheader"
|
||||||
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *goBlog) sendWebmentions(p *post) error {
|
func (a *goBlog) sendWebmentions(p *post) error {
|
||||||
|
|
Loading…
Reference in New Issue