mirror of https://github.com/jlelse/GoBlog
Add database-based settings, settings screen and migrate sections to db and allow to configure them
This commit is contained in:
parent
22fce13246
commit
cd9d500a55
|
@ -5,7 +5,6 @@ import (
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -15,15 +14,10 @@ import (
|
||||||
func Test_loadActivityPubPrivateKey(t *testing.T) {
|
func Test_loadActivityPubPrivateKey(t *testing.T) {
|
||||||
|
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: &config{
|
cfg: createDefaultTestConfig(t),
|
||||||
Db: &configDb{
|
|
||||||
File: filepath.Join(t.TempDir(), "test.db"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
err := app.initDatabase(false)
|
err := app.initConfig(false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer app.db.close()
|
|
||||||
require.NotNil(t, app.db)
|
require.NotNil(t, app.db)
|
||||||
|
|
||||||
// Generate
|
// Generate
|
||||||
|
@ -55,9 +49,7 @@ func Test_webfinger(t *testing.T) {
|
||||||
cfg: createDefaultTestConfig(t),
|
cfg: createDefaultTestConfig(t),
|
||||||
}
|
}
|
||||||
app.cfg.Server.PublicAddress = "https://example.com"
|
app.cfg.Server.PublicAddress = "https://example.com"
|
||||||
_ = app.initConfig()
|
_ = app.initConfig(false)
|
||||||
_ = app.initDatabase(false)
|
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
app.prepareWebfinger()
|
app.prepareWebfinger()
|
||||||
|
|
|
@ -29,9 +29,7 @@ func Test_authMiddleware(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = app.initConfig()
|
_ = app.initConfig(false)
|
||||||
_ = app.initDatabase(false)
|
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
app.d = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
app.d = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -17,34 +16,26 @@ func Test_blogroll(t *testing.T) {
|
||||||
|
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
httpClient: fc.Client,
|
httpClient: fc.Client,
|
||||||
cfg: &config{
|
cfg: createDefaultTestConfig(t),
|
||||||
Db: &configDb{
|
}
|
||||||
File: filepath.Join(t.TempDir(), "test.db"),
|
|
||||||
},
|
app.cfg.Cache.Enable = false
|
||||||
Server: &configServer{},
|
app.cfg.DefaultBlog = "en"
|
||||||
DefaultBlog: "en",
|
app.cfg.Blogs = map[string]*configBlog{
|
||||||
Blogs: map[string]*configBlog{
|
"en": {
|
||||||
"en": {
|
Lang: "en",
|
||||||
Lang: "en",
|
Blogroll: &configBlogroll{
|
||||||
Blogroll: &configBlogroll{
|
Enabled: true,
|
||||||
Enabled: true,
|
Path: "/br",
|
||||||
Path: "/br",
|
AuthHeader: "Authheader",
|
||||||
AuthHeader: "Authheader",
|
AuthValue: "Authtoken",
|
||||||
AuthValue: "Authtoken",
|
Opml: "https://example.com/opml",
|
||||||
Opml: "https://example.com/opml",
|
Categories: []string{"A", "B"},
|
||||||
Categories: []string{"A", "B"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
User: &configUser{},
|
|
||||||
Cache: &configCache{
|
|
||||||
Enable: false,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
fc.setFakeResponse(http.StatusOK, `
|
fc.setFakeResponse(http.StatusOK, `
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -14,36 +13,26 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_blogStats(t *testing.T) {
|
func Test_blogStats(t *testing.T) {
|
||||||
|
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: &config{
|
cfg: createDefaultTestConfig(t),
|
||||||
Db: &configDb{
|
}
|
||||||
File: filepath.Join(t.TempDir(), "test.db"),
|
|
||||||
|
app.cfg.Blogs = map[string]*configBlog{
|
||||||
|
"en": {
|
||||||
|
Lang: "en",
|
||||||
|
BlogStats: &configBlogStats{
|
||||||
|
Enabled: true,
|
||||||
|
Path: "/stats",
|
||||||
},
|
},
|
||||||
Server: &configServer{
|
Sections: map[string]*configSection{
|
||||||
PublicAddress: "https://example.com",
|
"test": {},
|
||||||
},
|
|
||||||
Blogs: map[string]*configBlog{
|
|
||||||
"en": {
|
|
||||||
Lang: "en",
|
|
||||||
BlogStats: &configBlogStats{
|
|
||||||
Enabled: true,
|
|
||||||
Path: "/stats",
|
|
||||||
},
|
|
||||||
Sections: map[string]*configSection{
|
|
||||||
"test": {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
DefaultBlog: "en",
|
|
||||||
User: &configUser{},
|
|
||||||
Webmention: &configWebmention{
|
|
||||||
DisableSending: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
app.cfg.DefaultBlog = "en"
|
||||||
|
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
// Insert post
|
// Insert post
|
||||||
|
|
|
@ -23,9 +23,7 @@ func Test_captchaMiddleware(t *testing.T) {
|
||||||
cfg: createDefaultTestConfig(t),
|
cfg: createDefaultTestConfig(t),
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = app.initConfig()
|
_ = app.initConfig(false)
|
||||||
_ = app.initDatabase(false)
|
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
app.d = alice.New(app.checkIsCaptcha, app.captchaMiddleware).ThenFunc(func(rw http.ResponseWriter, r *http.Request) {
|
app.d = alice.New(app.checkIsCaptcha, app.captchaMiddleware).ThenFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -18,25 +17,20 @@ import (
|
||||||
|
|
||||||
func Test_comments(t *testing.T) {
|
func Test_comments(t *testing.T) {
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: &config{
|
cfg: createDefaultTestConfig(t),
|
||||||
Db: &configDb{
|
}
|
||||||
File: filepath.Join(t.TempDir(), "test.db"),
|
app.cfg.Blogs = map[string]*configBlog{
|
||||||
|
"en": {
|
||||||
|
Lang: "en",
|
||||||
|
Comments: &configComments{
|
||||||
|
Enabled: true,
|
||||||
},
|
},
|
||||||
Server: &configServer{
|
|
||||||
PublicAddress: "https://example.com",
|
|
||||||
},
|
|
||||||
Blogs: map[string]*configBlog{
|
|
||||||
"en": {
|
|
||||||
Lang: "en",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
DefaultBlog: "en",
|
|
||||||
User: &configUser{},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
app.cfg.DefaultBlog = "en"
|
||||||
|
|
||||||
_ = app.initDatabase(false)
|
err := app.initConfig(false)
|
||||||
defer app.db.close()
|
require.NoError(t, err)
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
t.Run("Successful comment", func(t *testing.T) {
|
t.Run("Successful comment", func(t *testing.T) {
|
||||||
|
@ -44,7 +38,7 @@ func Test_comments(t *testing.T) {
|
||||||
// Create comment
|
// Create comment
|
||||||
|
|
||||||
data := url.Values{}
|
data := url.Values{}
|
||||||
data.Add("target", "https://example.com/test")
|
data.Add("target", "http://localhost:8080/test")
|
||||||
data.Add("comment", "This is just a test")
|
data.Add("comment", "This is just a test")
|
||||||
data.Add("name", "Test name")
|
data.Add("name", "Test name")
|
||||||
data.Add("website", "https://goblog.app")
|
data.Add("website", "https://goblog.app")
|
||||||
|
@ -115,7 +109,7 @@ func Test_comments(t *testing.T) {
|
||||||
// Create comment
|
// Create comment
|
||||||
|
|
||||||
data := url.Values{}
|
data := url.Values{}
|
||||||
data.Add("target", "https://example.com/test")
|
data.Add("target", "http://localhost:8080/test")
|
||||||
data.Add("comment", "This is just a test")
|
data.Add("comment", "This is just a test")
|
||||||
|
|
||||||
req := httptest.NewRequest(http.MethodPost, commentPath, strings.NewReader(data.Encode()))
|
req := httptest.NewRequest(http.MethodPost, commentPath, strings.NewReader(data.Encode()))
|
||||||
|
@ -151,7 +145,7 @@ func Test_comments(t *testing.T) {
|
||||||
t.Run("Empty comment", func(t *testing.T) {
|
t.Run("Empty comment", func(t *testing.T) {
|
||||||
|
|
||||||
data := url.Values{}
|
data := url.Values{}
|
||||||
data.Add("target", "https://example.com/test")
|
data.Add("target", "http://localhost:8080/test")
|
||||||
data.Add("comment", "")
|
data.Add("comment", "")
|
||||||
|
|
||||||
req := httptest.NewRequest(http.MethodPost, commentPath, strings.NewReader(data.Encode()))
|
req := httptest.NewRequest(http.MethodPost, commentPath, strings.NewReader(data.Encode()))
|
||||||
|
|
26
config.go
26
config.go
|
@ -341,13 +341,17 @@ func (a *goBlog) loadConfigFile(file string) error {
|
||||||
return v.Unmarshal(a.cfg)
|
return v.Unmarshal(a.cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *goBlog) initConfig() error {
|
func (a *goBlog) initConfig(logging bool) error {
|
||||||
if a.cfg == nil {
|
if a.cfg == nil {
|
||||||
a.cfg = createDefaultConfig()
|
a.cfg = createDefaultConfig()
|
||||||
}
|
}
|
||||||
if a.cfg.initialized {
|
if a.cfg.initialized {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
// Init database
|
||||||
|
if err := a.initDatabase(logging); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// Check config
|
// Check config
|
||||||
// Parse addresses and hostnames
|
// Parse addresses and hostnames
|
||||||
if a.cfg.Server.PublicAddress == "" {
|
if a.cfg.Server.PublicAddress == "" {
|
||||||
|
@ -402,12 +406,24 @@ func (a *goBlog) initConfig() error {
|
||||||
b.Comments = &configComments{Enabled: false}
|
b.Comments = &configComments{Enabled: false}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Check if sections already migrated to db
|
||||||
|
const sectionMigrationKey = "sections_migrated"
|
||||||
|
if val, err := a.getSettingValue(sectionMigrationKey); err != nil {
|
||||||
|
return err
|
||||||
|
} else if val == "" {
|
||||||
|
if err = a.saveAllSections(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = a.saveSettingValue(sectionMigrationKey, "1"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Load db sections
|
||||||
|
if err = a.loadSections(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// Check config for each blog
|
// Check config for each blog
|
||||||
for _, blog := range a.cfg.Blogs {
|
for _, blog := range a.cfg.Blogs {
|
||||||
// Copy sections key to section name
|
|
||||||
for k, s := range blog.Sections {
|
|
||||||
s.Name = k
|
|
||||||
}
|
|
||||||
// Check if language is set
|
// Check if language is set
|
||||||
if blog.Lang == "" {
|
if blog.Lang == "" {
|
||||||
blog.Lang = "en"
|
blog.Lang = "en"
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -24,35 +23,27 @@ func Test_contact(t *testing.T) {
|
||||||
|
|
||||||
// Init everything
|
// Init everything
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: &config{
|
cfg: createDefaultTestConfig(t),
|
||||||
Db: &configDb{
|
}
|
||||||
File: filepath.Join(t.TempDir(), "test.db"),
|
app.cfg.Blogs = map[string]*configBlog{
|
||||||
|
"en": {
|
||||||
|
Lang: "en",
|
||||||
|
// Config for contact
|
||||||
|
Contact: &configContact{
|
||||||
|
Enabled: true,
|
||||||
|
SMTPPort: port,
|
||||||
|
SMTPHost: "127.0.0.1",
|
||||||
|
SMTPUser: "user",
|
||||||
|
SMTPPassword: "pass",
|
||||||
|
EmailTo: "to@example.org",
|
||||||
|
EmailFrom: "from@example.org",
|
||||||
|
EmailSubject: "Neue Kontaktnachricht",
|
||||||
},
|
},
|
||||||
Server: &configServer{
|
|
||||||
PublicAddress: "https://example.com",
|
|
||||||
},
|
|
||||||
Blogs: map[string]*configBlog{
|
|
||||||
"en": {
|
|
||||||
Lang: "en",
|
|
||||||
// Config for contact
|
|
||||||
Contact: &configContact{
|
|
||||||
Enabled: true,
|
|
||||||
SMTPPort: port,
|
|
||||||
SMTPHost: "127.0.0.1",
|
|
||||||
SMTPUser: "user",
|
|
||||||
SMTPPassword: "pass",
|
|
||||||
EmailTo: "to@example.org",
|
|
||||||
EmailFrom: "from@example.org",
|
|
||||||
EmailSubject: "Neue Kontaktnachricht",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
DefaultBlog: "en",
|
|
||||||
User: &configUser{},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_ = app.initDatabase(false)
|
app.cfg.DefaultBlog = "en"
|
||||||
defer app.db.close()
|
|
||||||
|
_ = app.initConfig(false)
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
// Make contact form request
|
// Make contact form request
|
||||||
|
|
|
@ -31,6 +31,9 @@ type database struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *goBlog) initDatabase(logging bool) (err error) {
|
func (a *goBlog) initDatabase(logging bool) (err error) {
|
||||||
|
if a.db != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
if logging {
|
if logging {
|
||||||
log.Println("Initialize database...")
|
log.Println("Initialize database...")
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
create table sections (
|
||||||
|
blog text not null,
|
||||||
|
name text not null,
|
||||||
|
title text not null default '',
|
||||||
|
description text not null default '',
|
||||||
|
pathtemplate text not null default '',
|
||||||
|
showfull boolean not null default false,
|
||||||
|
primary key (blog, name)
|
||||||
|
);
|
|
@ -0,0 +1,5 @@
|
||||||
|
create table settings (
|
||||||
|
name text not null,
|
||||||
|
value text not null default '',
|
||||||
|
primary key (name)
|
||||||
|
);
|
|
@ -15,9 +15,7 @@ func Test_editorPreview(t *testing.T) {
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: createDefaultTestConfig(t),
|
cfg: createDefaultTestConfig(t),
|
||||||
}
|
}
|
||||||
_ = app.initConfig()
|
_ = app.initConfig(false)
|
||||||
_ = app.initDatabase(false)
|
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
h := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
h := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -13,25 +12,10 @@ import (
|
||||||
|
|
||||||
func Test_errors(t *testing.T) {
|
func Test_errors(t *testing.T) {
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: &config{
|
cfg: createDefaultTestConfig(t),
|
||||||
Db: &configDb{
|
|
||||||
File: filepath.Join(t.TempDir(), "test.db"),
|
|
||||||
},
|
|
||||||
Server: &configServer{
|
|
||||||
PublicAddress: "https://example.com",
|
|
||||||
},
|
|
||||||
Blogs: map[string]*configBlog{
|
|
||||||
"en": {
|
|
||||||
Lang: "en",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
DefaultBlog: "en",
|
|
||||||
User: &configUser{},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
t.Run("Test 404, no HTML", func(t *testing.T) {
|
t.Run("Test 404, no HTML", func(t *testing.T) {
|
||||||
|
|
|
@ -11,14 +11,9 @@ import (
|
||||||
|
|
||||||
func Test_export(t *testing.T) {
|
func Test_export(t *testing.T) {
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: &config{
|
cfg: createDefaultTestConfig(t),
|
||||||
Db: &configDb{
|
|
||||||
File: filepath.Join(t.TempDir(), "test.db"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
app.initMarkdown()
|
app.initMarkdown()
|
||||||
|
|
||||||
err := app.db.savePost(&post{
|
err := app.db.savePost(&post{
|
||||||
|
|
|
@ -15,10 +15,9 @@ func Test_feeds(t *testing.T) {
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: createDefaultTestConfig(t),
|
cfg: createDefaultTestConfig(t),
|
||||||
}
|
}
|
||||||
_ = app.initConfig()
|
_ = app.initConfig(false)
|
||||||
_ = app.initDatabase(false)
|
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
app.d = app.buildRouter()
|
app.d = app.buildRouter()
|
||||||
handlerClient := newHandlerClient(app.d)
|
handlerClient := newHandlerClient(app.d)
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -11,24 +10,18 @@ import (
|
||||||
|
|
||||||
func Test_geoTrack(t *testing.T) {
|
func Test_geoTrack(t *testing.T) {
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: &config{
|
cfg: createDefaultTestConfig(t),
|
||||||
Db: &configDb{
|
}
|
||||||
File: filepath.Join(t.TempDir(), "test.db"),
|
app.cfg.Blogs = map[string]*configBlog{
|
||||||
},
|
"en": {
|
||||||
Server: &configServer{},
|
Lang: "en",
|
||||||
Blogs: map[string]*configBlog{
|
},
|
||||||
"en": {
|
"de": {
|
||||||
Lang: "en",
|
Lang: "de",
|
||||||
},
|
|
||||||
"de": {
|
|
||||||
Lang: "de",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
// First test (just with track)
|
// First test (just with track)
|
||||||
|
|
|
@ -16,9 +16,8 @@ func Test_geo(t *testing.T) {
|
||||||
httpClient: fc.Client,
|
httpClient: fc.Client,
|
||||||
cfg: createDefaultTestConfig(t),
|
cfg: createDefaultTestConfig(t),
|
||||||
}
|
}
|
||||||
_ = app.initConfig()
|
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
p := &post{
|
p := &post{
|
||||||
|
|
10
http.go
10
http.go
|
@ -32,7 +32,7 @@ const (
|
||||||
func (a *goBlog) startServer() (err error) {
|
func (a *goBlog) startServer() (err error) {
|
||||||
log.Println("Start server(s)...")
|
log.Println("Start server(s)...")
|
||||||
// Load router
|
// Load router
|
||||||
a.d = a.buildRouter()
|
a.reloadRouter()
|
||||||
// Set basic middlewares
|
// Set basic middlewares
|
||||||
h := alice.New()
|
h := alice.New()
|
||||||
h = h.Append(middleware.Heartbeat("/ping"))
|
h = h.Append(middleware.Heartbeat("/ping"))
|
||||||
|
@ -43,7 +43,9 @@ func (a *goBlog) startServer() (err error) {
|
||||||
if a.httpsConfigured(false) {
|
if a.httpsConfigured(false) {
|
||||||
h = h.Append(a.securityHeaders)
|
h = h.Append(a.securityHeaders)
|
||||||
}
|
}
|
||||||
finalHandler := h.Then(a.d)
|
finalHandler := h.ThenFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
a.d.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
// Start Onion service
|
// Start Onion service
|
||||||
if a.cfg.Server.Tor {
|
if a.cfg.Server.Tor {
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -116,6 +118,10 @@ const (
|
||||||
feedPath = ".{feed:(rss|json|atom)}"
|
feedPath = ".{feed:(rss|json|atom)}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (a *goBlog) reloadRouter() {
|
||||||
|
a.d = a.buildRouter()
|
||||||
|
}
|
||||||
|
|
||||||
func (a *goBlog) buildRouter() http.Handler {
|
func (a *goBlog) buildRouter() http.Handler {
|
||||||
mapRouter := &maprouter.MapRouter{
|
mapRouter := &maprouter.MapRouter{
|
||||||
Handlers: map[string]http.Handler{},
|
Handlers: map[string]http.Handler{},
|
||||||
|
|
|
@ -15,7 +15,7 @@ func Test_httpLogsConfig(t *testing.T) {
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: createDefaultTestConfig(t),
|
cfg: createDefaultTestConfig(t),
|
||||||
}
|
}
|
||||||
_ = app.initConfig()
|
_ = app.initConfig(false)
|
||||||
|
|
||||||
assert.Equal(t, false, app.cfg.Server.Logging)
|
assert.Equal(t, false, app.cfg.Server.Logging)
|
||||||
assert.Equal(t, "data/access.log", app.cfg.Server.LogFile)
|
assert.Equal(t, "data/access.log", app.cfg.Server.LogFile)
|
||||||
|
|
|
@ -170,6 +170,9 @@ func (a *goBlog) blogRouter(blog string, conf *configBlog) func(r chi.Router) {
|
||||||
// Sitemap
|
// Sitemap
|
||||||
r.Group(a.blogSitemapRouter(conf))
|
r.Group(a.blogSitemapRouter(conf))
|
||||||
|
|
||||||
|
// Settings
|
||||||
|
r.Route(conf.getRelativePath(settingsPath), a.blogSettingsRouter(conf))
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,3 +445,14 @@ func (a *goBlog) blogSitemapRouter(conf *configBlog) func(r chi.Router) {
|
||||||
r.Get(conf.getRelativePath(sitemapBlogPostsPath), a.serveSitemapBlogPosts)
|
r.Get(conf.getRelativePath(sitemapBlogPostsPath), a.serveSitemapBlogPosts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Blog - Settings
|
||||||
|
func (a *goBlog) blogSettingsRouter(_ *configBlog) func(r chi.Router) {
|
||||||
|
return func(r chi.Router) {
|
||||||
|
r.Use(a.authMiddleware)
|
||||||
|
r.Get("/", a.serveSettings)
|
||||||
|
r.Post(settingsDeleteSectionPath, a.settingsDeleteSection)
|
||||||
|
r.Post(settingsCreateSectionPath, a.settingsCreateSection)
|
||||||
|
r.Post(settingsUpdateSectionPath, a.settingsUpdateSection)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -19,9 +19,8 @@ func Test_indexNow(t *testing.T) {
|
||||||
httpClient: fc.Client,
|
httpClient: fc.Client,
|
||||||
}
|
}
|
||||||
app.cfg.IndexNow = &configIndexNow{Enabled: true}
|
app.cfg.IndexNow = &configIndexNow{Enabled: true}
|
||||||
_ = app.initConfig()
|
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
// Create http router
|
// Create http router
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -22,35 +21,25 @@ func Test_indieAuthServer(t *testing.T) {
|
||||||
|
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
httpClient: newFakeHttpClient().Client,
|
httpClient: newFakeHttpClient().Client,
|
||||||
cfg: &config{
|
cfg: createDefaultTestConfig(t),
|
||||||
Db: &configDb{
|
}
|
||||||
File: filepath.Join(t.TempDir(), "test.db"),
|
app.cfg.Server.PublicAddress = "https://example.org"
|
||||||
},
|
app.cfg.Blogs = map[string]*configBlog{
|
||||||
Server: &configServer{
|
"en": {
|
||||||
PublicAddress: "https://example.org",
|
Lang: "en",
|
||||||
},
|
|
||||||
DefaultBlog: "en",
|
|
||||||
Blogs: map[string]*configBlog{
|
|
||||||
"en": {
|
|
||||||
Lang: "en",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
User: &configUser{
|
|
||||||
Name: "John Doe",
|
|
||||||
Nick: "jdoe",
|
|
||||||
},
|
|
||||||
Cache: &configCache{
|
|
||||||
Enable: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
app.cfg.User = &configUser{
|
||||||
|
Name: "John Doe",
|
||||||
|
Nick: "jdoe",
|
||||||
|
}
|
||||||
|
app.cfg.Cache.Enable = false
|
||||||
|
|
||||||
|
_ = app.initConfig(false)
|
||||||
|
app.initComponents(false)
|
||||||
|
|
||||||
app.d = app.buildRouter()
|
app.d = app.buildRouter()
|
||||||
|
|
||||||
_ = app.initDatabase(false)
|
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
|
||||||
|
|
||||||
app.ias.Client = newHandlerClient(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
app.ias.Client = newHandlerClient(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -3,7 +3,6 @@ package main
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -15,22 +14,10 @@ func Test_checkIndieAuth(t *testing.T) {
|
||||||
|
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
httpClient: newFakeHttpClient().Client,
|
httpClient: newFakeHttpClient().Client,
|
||||||
cfg: &config{
|
cfg: createDefaultTestConfig(t),
|
||||||
Db: &configDb{
|
|
||||||
File: filepath.Join(t.TempDir(), "test.db"),
|
|
||||||
},
|
|
||||||
Server: &configServer{},
|
|
||||||
DefaultBlog: "en",
|
|
||||||
Blogs: map[string]*configBlog{
|
|
||||||
"en": {
|
|
||||||
Lang: "en",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||||
|
|
8
main.go
8
main.go
|
@ -64,7 +64,7 @@ func main() {
|
||||||
app.logErrAndQuit("Failed to load config file:", err.Error())
|
app.logErrAndQuit("Failed to load config file:", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = app.initConfig(); err != nil {
|
if err = app.initConfig(false); err != nil {
|
||||||
app.logErrAndQuit("Failed to init config:", err.Error())
|
app.logErrAndQuit("Failed to init config:", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -129,12 +129,6 @@ func main() {
|
||||||
// Execute pre-start hooks
|
// Execute pre-start hooks
|
||||||
app.preStartHooks()
|
app.preStartHooks()
|
||||||
|
|
||||||
// Initialize database
|
|
||||||
if err = app.initDatabase(true); err != nil {
|
|
||||||
app.logErrAndQuit("Failed to init database:", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link check tool after init of markdown
|
// Link check tool after init of markdown
|
||||||
if len(os.Args) >= 2 && os.Args[1] == "check" {
|
if len(os.Args) >= 2 && os.Args[1] == "check" {
|
||||||
app.initMarkdown()
|
app.initMarkdown()
|
||||||
|
|
|
@ -14,9 +14,7 @@ func Test_micropubQuery(t *testing.T) {
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: createDefaultTestConfig(t),
|
cfg: createDefaultTestConfig(t),
|
||||||
}
|
}
|
||||||
_ = app.initConfig()
|
_ = app.initConfig(false)
|
||||||
_ = app.initDatabase(false)
|
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
// Create a test post with tags
|
// Create a test post with tags
|
||||||
|
|
|
@ -18,9 +18,7 @@ func Test_ntfySending(t *testing.T) {
|
||||||
httpClient: fakeClient.Client,
|
httpClient: fakeClient.Client,
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = app.initConfig()
|
_ = app.initConfig(false)
|
||||||
_ = app.initDatabase(false)
|
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
t.Run("Default", func(t *testing.T) {
|
t.Run("Default", func(t *testing.T) {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -25,9 +24,7 @@ func Test_postsDb(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_ = app.initConfig()
|
_ = app.initConfig(false)
|
||||||
_ = app.initDatabase(false)
|
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
now := toLocalSafe(time.Now().String())
|
now := toLocalSafe(time.Now().String())
|
||||||
|
@ -229,14 +226,9 @@ func Test_ftsWithoutTitle(t *testing.T) {
|
||||||
// Added because there was a bug where there were no search results without title
|
// Added because there was a bug where there were no search results without title
|
||||||
|
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: &config{
|
cfg: createDefaultTestConfig(t),
|
||||||
Db: &configDb{
|
|
||||||
File: filepath.Join(t.TempDir(), "test.db"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
app.initMarkdown()
|
app.initMarkdown()
|
||||||
|
|
||||||
err := app.db.savePost(&post{
|
err := app.db.savePost(&post{
|
||||||
|
@ -261,14 +253,9 @@ func Test_postsPriority(t *testing.T) {
|
||||||
// Added because there was a bug where there were no search results without title
|
// Added because there was a bug where there were no search results without title
|
||||||
|
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: &config{
|
cfg: createDefaultTestConfig(t),
|
||||||
Db: &configDb{
|
|
||||||
File: filepath.Join(t.TempDir(), "test.db"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
app.initMarkdown()
|
app.initMarkdown()
|
||||||
|
|
||||||
err := app.db.savePost(&post{
|
err := app.db.savePost(&post{
|
||||||
|
@ -312,14 +299,9 @@ func Test_postsPriority(t *testing.T) {
|
||||||
|
|
||||||
func Test_usesOfMediaFile(t *testing.T) {
|
func Test_usesOfMediaFile(t *testing.T) {
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: &config{
|
cfg: createDefaultTestConfig(t),
|
||||||
Db: &configDb{
|
|
||||||
File: filepath.Join(t.TempDir(), "test.db"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
|
|
||||||
err := app.db.savePost(&post{
|
err := app.db.savePost(&post{
|
||||||
Path: "/test/abc",
|
Path: "/test/abc",
|
||||||
|
@ -368,8 +350,7 @@ func Test_replaceParams(t *testing.T) {
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: createDefaultTestConfig(t),
|
cfg: createDefaultTestConfig(t),
|
||||||
}
|
}
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
|
|
||||||
err := app.db.savePost(&post{
|
err := app.db.savePost(&post{
|
||||||
Path: "/test/abc",
|
Path: "/test/abc",
|
||||||
|
@ -399,9 +380,7 @@ func Test_postDeletesParams(t *testing.T) {
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: createDefaultTestConfig(t),
|
cfg: createDefaultTestConfig(t),
|
||||||
}
|
}
|
||||||
_ = app.initConfig()
|
_ = app.initConfig(false)
|
||||||
_ = app.initDatabase(false)
|
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
err := app.createPost(&post{
|
err := app.createPost(&post{
|
||||||
|
|
|
@ -11,9 +11,8 @@ func Test_checkDeletedPosts(t *testing.T) {
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: createDefaultTestConfig(t),
|
cfg: createDefaultTestConfig(t),
|
||||||
}
|
}
|
||||||
_ = app.initConfig()
|
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
// Create a post
|
// Create a post
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -12,28 +11,18 @@ import (
|
||||||
func Test_postsScheduler(t *testing.T) {
|
func Test_postsScheduler(t *testing.T) {
|
||||||
|
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: &config{
|
cfg: createDefaultTestConfig(t),
|
||||||
Db: &configDb{
|
}
|
||||||
File: filepath.Join(t.TempDir(), "test.db"),
|
app.cfg.Blogs = map[string]*configBlog{
|
||||||
|
"en": {
|
||||||
|
Sections: map[string]*configSection{
|
||||||
|
"test": {},
|
||||||
},
|
},
|
||||||
Server: &configServer{
|
Lang: "en",
|
||||||
PublicAddress: "https://example.com",
|
|
||||||
},
|
|
||||||
DefaultBlog: "en",
|
|
||||||
Blogs: map[string]*configBlog{
|
|
||||||
"en": {
|
|
||||||
Sections: map[string]*configSection{
|
|
||||||
"test": {},
|
|
||||||
},
|
|
||||||
Lang: "en",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Micropub: &configMicropub{},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
err := app.db.savePost(&post{
|
err := app.db.savePost(&post{
|
||||||
|
|
|
@ -16,9 +16,7 @@ func Test_serveDate(t *testing.T) {
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: createDefaultTestConfig(t),
|
cfg: createDefaultTestConfig(t),
|
||||||
}
|
}
|
||||||
_ = app.initConfig()
|
_ = app.initConfig(false)
|
||||||
_ = app.initDatabase(false)
|
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
app.d = app.buildRouter()
|
app.d = app.buildRouter()
|
||||||
|
@ -106,9 +104,7 @@ func Test_servePost(t *testing.T) {
|
||||||
Username: "test",
|
Username: "test",
|
||||||
Password: "test",
|
Password: "test",
|
||||||
})
|
})
|
||||||
_ = app.initConfig()
|
_ = app.initConfig(false)
|
||||||
_ = app.initDatabase(false)
|
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
app.d = app.buildRouter()
|
app.d = app.buildRouter()
|
||||||
|
|
|
@ -3,7 +3,6 @@ package main
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/go-chi/chi/v5/middleware"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
|
@ -16,36 +15,28 @@ func Test_privateMode(t *testing.T) {
|
||||||
// Init
|
// Init
|
||||||
|
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: &config{
|
cfg: createDefaultTestConfig(t),
|
||||||
Db: &configDb{
|
}
|
||||||
File: filepath.Join(t.TempDir(), "db.db"),
|
app.cfg.PrivateMode = &configPrivateMode{Enabled: true}
|
||||||
},
|
app.cfg.User =
|
||||||
Server: &configServer{},
|
&configUser{
|
||||||
PrivateMode: &configPrivateMode{
|
Name: "Test",
|
||||||
Enabled: true,
|
Nick: "test",
|
||||||
},
|
Password: "testpw",
|
||||||
User: &configUser{
|
AppPasswords: []*configAppPassword{
|
||||||
Name: "Test",
|
{
|
||||||
Nick: "test",
|
Username: "testapp",
|
||||||
Password: "testpw",
|
Password: "pw",
|
||||||
AppPasswords: []*configAppPassword{
|
|
||||||
{
|
|
||||||
Username: "testapp",
|
|
||||||
Password: "pw",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
DefaultBlog: "en",
|
|
||||||
Blogs: map[string]*configBlog{
|
|
||||||
"en": {
|
|
||||||
Lang: "en",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
}
|
||||||
|
app.cfg.Blogs = map[string]*configBlog{
|
||||||
|
"en": {
|
||||||
|
Lang: "en",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
handler := alice.New(middleware.WithValue(blogKey, "en"), app.privateModeHandler).ThenFunc(func(rw http.ResponseWriter, r *http.Request) {
|
handler := alice.New(middleware.WithValue(blogKey, "en"), app.privateModeHandler).ThenFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -2,7 +2,6 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -12,14 +11,9 @@ import (
|
||||||
func Test_queue(t *testing.T) {
|
func Test_queue(t *testing.T) {
|
||||||
|
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: &config{
|
cfg: createDefaultTestConfig(t),
|
||||||
Db: &configDb{
|
|
||||||
File: filepath.Join(t.TempDir(), "test.db"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
|
|
||||||
time1 := time.Now()
|
time1 := time.Now()
|
||||||
|
|
||||||
|
@ -65,30 +59,3 @@ func Test_queue(t *testing.T) {
|
||||||
require.Equal(t, []byte("1"), qi.content)
|
require.Equal(t, []byte("1"), qi.content)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Benchmark_queue(b *testing.B) {
|
|
||||||
app := &goBlog{
|
|
||||||
cfg: &config{
|
|
||||||
Db: &configDb{
|
|
||||||
File: filepath.Join(b.TempDir(), "test.db"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
_ = app.initDatabase(false)
|
|
||||||
defer app.db.close()
|
|
||||||
|
|
||||||
err := app.enqueue("test", []byte("1"), time.Now())
|
|
||||||
require.NoError(b, err)
|
|
||||||
|
|
||||||
b.Run("Peek with item", func(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
_, _ = app.peekQueue(context.Background(), "test")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
b.Run("Peek without item", func(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
_, _ = app.peekQueue(context.Background(), "abc")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -15,9 +15,7 @@ func Test_reactionsLowLevel(t *testing.T) {
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: createDefaultTestConfig(t),
|
cfg: createDefaultTestConfig(t),
|
||||||
}
|
}
|
||||||
_ = app.initConfig()
|
_ = app.initConfig(false)
|
||||||
_ = app.initDatabase(false)
|
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
err := app.saveReaction("🖕", "/testpost")
|
err := app.saveReaction("🖕", "/testpost")
|
||||||
|
@ -97,9 +95,7 @@ func Test_reactionsHighLevel(t *testing.T) {
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: createDefaultTestConfig(t),
|
cfg: createDefaultTestConfig(t),
|
||||||
}
|
}
|
||||||
_ = app.initConfig()
|
_ = app.initConfig(false)
|
||||||
_ = app.initDatabase(false)
|
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
// Send unsuccessful reaction
|
// Send unsuccessful reaction
|
||||||
|
|
|
@ -0,0 +1,129 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/samber/lo"
|
||||||
|
)
|
||||||
|
|
||||||
|
const settingsPath = "/settings"
|
||||||
|
|
||||||
|
func (a *goBlog) serveSettings(w http.ResponseWriter, r *http.Request) {
|
||||||
|
blog, bc := a.getBlog(r)
|
||||||
|
|
||||||
|
sections := lo.Values(bc.Sections)
|
||||||
|
sort.Slice(sections, func(i, j int) bool { return sections[i].Name < sections[j].Name })
|
||||||
|
|
||||||
|
a.render(w, r, a.renderSettings, &renderData{
|
||||||
|
Data: &settingsRenderData{
|
||||||
|
blog: blog,
|
||||||
|
sections: sections,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const settingsDeleteSectionPath = "/deletesection"
|
||||||
|
|
||||||
|
func (a *goBlog) settingsDeleteSection(w http.ResponseWriter, r *http.Request) {
|
||||||
|
blog, bc := a.getBlog(r)
|
||||||
|
section := r.FormValue("sectionname")
|
||||||
|
// Check if any post uses this section
|
||||||
|
count, err := a.db.countPosts(&postsRequestConfig{
|
||||||
|
blog: blog,
|
||||||
|
sections: []string{section},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
a.serveError(w, r, "Failed to check if section is still used", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if count > 0 {
|
||||||
|
a.serveError(w, r, "Section is still used", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Delete section
|
||||||
|
err = a.deleteSection(blog, section)
|
||||||
|
if err != nil {
|
||||||
|
a.serveError(w, r, "Failed to delete section from the database", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Reload sections
|
||||||
|
err = a.loadSections()
|
||||||
|
if err != nil {
|
||||||
|
a.serveError(w, r, "Failed to reload section configuration from the database", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
a.reloadRouter()
|
||||||
|
a.cache.purge()
|
||||||
|
http.Redirect(w, r, bc.getRelativePath(settingsPath), http.StatusFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
const settingsCreateSectionPath = "/createsection"
|
||||||
|
|
||||||
|
func (a *goBlog) settingsCreateSection(w http.ResponseWriter, r *http.Request) {
|
||||||
|
blog, bc := a.getBlog(r)
|
||||||
|
// Read values
|
||||||
|
sectionName := r.FormValue("sectionname")
|
||||||
|
sectionTitle := r.FormValue("sectiontitle")
|
||||||
|
if sectionName == "" || sectionTitle == "" {
|
||||||
|
a.serveError(w, r, "Missing values for name or title", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Create section
|
||||||
|
section := &configSection{
|
||||||
|
Name: sectionName,
|
||||||
|
Title: sectionTitle,
|
||||||
|
}
|
||||||
|
err := a.addSection(blog, section)
|
||||||
|
if err != nil {
|
||||||
|
a.serveError(w, r, "Failed to insert section into database", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Reload sections
|
||||||
|
err = a.loadSections()
|
||||||
|
if err != nil {
|
||||||
|
a.serveError(w, r, "Failed to reload section configuration from the database", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
a.reloadRouter()
|
||||||
|
a.cache.purge()
|
||||||
|
http.Redirect(w, r, bc.getRelativePath(settingsPath), http.StatusFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
const settingsUpdateSectionPath = "/updatesection"
|
||||||
|
|
||||||
|
func (a *goBlog) settingsUpdateSection(w http.ResponseWriter, r *http.Request) {
|
||||||
|
blog, bc := a.getBlog(r)
|
||||||
|
// Read values
|
||||||
|
sectionName := r.FormValue("sectionname")
|
||||||
|
sectionTitle := r.FormValue("sectiontitle")
|
||||||
|
if sectionName == "" || sectionTitle == "" {
|
||||||
|
a.serveError(w, r, "Missing values for name or title", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sectionDescription := r.FormValue("sectiondescription")
|
||||||
|
sectionPathTemplate := r.FormValue("sectionpathtemplate")
|
||||||
|
sectionShowFull := r.FormValue("sectionshowfull") == "on"
|
||||||
|
// Create section
|
||||||
|
section := &configSection{
|
||||||
|
Name: sectionName,
|
||||||
|
Title: sectionTitle,
|
||||||
|
Description: sectionDescription,
|
||||||
|
PathTemplate: sectionPathTemplate,
|
||||||
|
ShowFull: sectionShowFull,
|
||||||
|
}
|
||||||
|
err := a.updateSection(blog, sectionName, section)
|
||||||
|
if err != nil {
|
||||||
|
a.serveError(w, r, "Failed to update section in database", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Reload sections
|
||||||
|
err = a.loadSections()
|
||||||
|
if err != nil {
|
||||||
|
a.serveError(w, r, "Failed to reload section configuration from the database", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
a.reloadRouter()
|
||||||
|
a.cache.purge()
|
||||||
|
http.Redirect(w, r, bc.getRelativePath(settingsPath), http.StatusFound)
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *goBlog) getSettingValue(name string) (string, error) {
|
||||||
|
row, err := a.db.queryRow("select value from settings where name = @name", sql.Named("name", name))
|
||||||
|
if err != nil {
|
||||||
|
return "",
|
||||||
|
err
|
||||||
|
}
|
||||||
|
var value string
|
||||||
|
err = row.Scan(&value)
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return "", nil
|
||||||
|
} else if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *goBlog) saveSettingValue(name, value string) error {
|
||||||
|
_, err := a.db.exec(
|
||||||
|
"insert into settings (name, value) values (@name, @value) on conflict (name) do update set value = @value2",
|
||||||
|
sql.Named("name", name),
|
||||||
|
sql.Named("value", value),
|
||||||
|
sql.Named("value2", value),
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *goBlog) loadSections() error {
|
||||||
|
for blog, bc := range a.cfg.Blogs {
|
||||||
|
sections, err := a.getSections(blog)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
bc.Sections = sections
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *goBlog) getSections(blog string) (map[string]*configSection, error) {
|
||||||
|
rows, err := a.db.query("select name, title, description, pathtemplate, showfull from sections where blog = @blog", sql.Named("blog", blog))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sections := map[string]*configSection{}
|
||||||
|
for rows.Next() {
|
||||||
|
section := &configSection{}
|
||||||
|
err = rows.Scan(§ion.Name, §ion.Title, §ion.Description, §ion.PathTemplate, §ion.ShowFull)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sections[section.Name] = section
|
||||||
|
}
|
||||||
|
return sections, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *goBlog) saveAllSections() error {
|
||||||
|
for blog, bc := range a.cfg.Blogs {
|
||||||
|
for k, s := range bc.Sections {
|
||||||
|
s.Name = k
|
||||||
|
if err := a.addSection(blog, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *goBlog) addSection(blog string, section *configSection) error {
|
||||||
|
_, err := a.db.exec(
|
||||||
|
"insert into sections (blog, name, title, description, pathtemplate, showfull) values (@blog, @name, @title, @description, @pathtemplate, @showfull)",
|
||||||
|
sql.Named("blog", blog),
|
||||||
|
sql.Named("name", section.Name),
|
||||||
|
sql.Named("title", section.Title),
|
||||||
|
sql.Named("description", section.Description),
|
||||||
|
sql.Named("pathtemplate", section.PathTemplate),
|
||||||
|
sql.Named("showfull", section.ShowFull),
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *goBlog) deleteSection(blog string, name string) error {
|
||||||
|
_, err := a.db.exec("delete from sections where blog = @blog and name = @name", sql.Named("blog", blog), sql.Named("name", name))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *goBlog) updateSection(blog string, name string, section *configSection) error {
|
||||||
|
_, err := a.db.exec(
|
||||||
|
"update sections set title = @title, description = @description, pathtemplate = @pathtemplate, showfull = @showfull where blog = @blog and name = @name",
|
||||||
|
sql.Named("title", section.Title),
|
||||||
|
sql.Named("description", section.Description),
|
||||||
|
sql.Named("pathtemplate", section.PathTemplate),
|
||||||
|
sql.Named("showfull", section.ShowFull),
|
||||||
|
sql.Named("blog", blog),
|
||||||
|
sql.Named("name", section.Name),
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -10,14 +9,10 @@ import (
|
||||||
|
|
||||||
func Test_shortenPath(t *testing.T) {
|
func Test_shortenPath(t *testing.T) {
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: &config{
|
cfg: createDefaultTestConfig(t),
|
||||||
Db: &configDb{
|
|
||||||
File: filepath.Join(t.TempDir(), "test.db"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
db := app.db
|
db := app.db
|
||||||
|
|
||||||
res1, err := db.shortenPath("/a")
|
res1, err := db.shortenPath("/a")
|
||||||
|
|
|
@ -16,9 +16,8 @@ func Test_sitemap(t *testing.T) {
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: createDefaultTestConfig(t),
|
cfg: createDefaultTestConfig(t),
|
||||||
}
|
}
|
||||||
_ = app.initConfig()
|
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
app.d = app.buildRouter()
|
app.d = app.buildRouter()
|
||||||
|
|
|
@ -43,6 +43,7 @@ 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."
|
||||||
pinned: "Angepinnt"
|
pinned: "Angepinnt"
|
||||||
posts: "Posts"
|
posts: "Posts"
|
||||||
|
postsections: "Post-Bereiche"
|
||||||
prev: "Zurück"
|
prev: "Zurück"
|
||||||
privateposts: "Private Posts"
|
privateposts: "Private Posts"
|
||||||
privatepostsdesc: "Posts mit dem Status `private`, die nur eingeloggt sichtbar sind."
|
privatepostsdesc: "Posts mit dem Status `private`, die nur eingeloggt sichtbar sind."
|
||||||
|
@ -51,7 +52,13 @@ replyto: "Antwort an"
|
||||||
scheduledposts: "Geplante Posts"
|
scheduledposts: "Geplante Posts"
|
||||||
scheduledpostsdesc: "Beiträge mit dem Status `scheduled`, die veröffentlicht werden, wenn das `published`-Datum erreicht ist."
|
scheduledpostsdesc: "Beiträge mit dem Status `scheduled`, die veröffentlicht werden, wenn das `published`-Datum erreicht ist."
|
||||||
search: "Suchen"
|
search: "Suchen"
|
||||||
|
sectiondescription: "Beschreibung"
|
||||||
|
sectionname: "Name"
|
||||||
|
sectionpathtemplate: "Pfadvorlage"
|
||||||
|
sectionshowfull: "Vollständigen Inhalt in der Zusammenfassung anzeigen"
|
||||||
|
sectiontitle: "Title"
|
||||||
send: "Senden (zur Überprüfung)"
|
send: "Senden (zur Überprüfung)"
|
||||||
|
settings: "Einstellungen"
|
||||||
share: "Online teilen"
|
share: "Online teilen"
|
||||||
shorturl: "Kurz-Link:"
|
shorturl: "Kurz-Link:"
|
||||||
speak: "Vorlesen"
|
speak: "Vorlesen"
|
||||||
|
|
|
@ -53,6 +53,7 @@ oldcontent: "⚠️ This entry is already over one year old. It may no longer be
|
||||||
password: "Password"
|
password: "Password"
|
||||||
pinned: "Pinned"
|
pinned: "Pinned"
|
||||||
posts: "Posts"
|
posts: "Posts"
|
||||||
|
postsections: "Post sections"
|
||||||
prev: "Previous"
|
prev: "Previous"
|
||||||
privateposts: "Private posts"
|
privateposts: "Private posts"
|
||||||
privatepostsdesc: "Posts with status `private` that are visible only when logged in."
|
privatepostsdesc: "Posts with status `private` that are visible only when logged in."
|
||||||
|
@ -63,7 +64,13 @@ scheduledposts: "Scheduled posts"
|
||||||
scheduledpostsdesc: "Posts with status `scheduled` that are published when the `published` date is reached."
|
scheduledpostsdesc: "Posts with status `scheduled` that are published when the `published` date is reached."
|
||||||
scopes: "Scopes"
|
scopes: "Scopes"
|
||||||
search: "Search"
|
search: "Search"
|
||||||
|
sectiondescription: "Description"
|
||||||
|
sectionname: "Name"
|
||||||
|
sectionpathtemplate: "Path template"
|
||||||
|
sectionshowfull: "Show full content in summary"
|
||||||
|
sectiontitle: "Title"
|
||||||
send: "Send (to review)"
|
send: "Send (to review)"
|
||||||
|
settings: "Settings"
|
||||||
share: "Share online"
|
share: "Share online"
|
||||||
shorturl: "Short link:"
|
shorturl: "Short link:"
|
||||||
speak: "Read aloud"
|
speak: "Read aloud"
|
||||||
|
|
|
@ -122,9 +122,7 @@ func Test_telegram(t *testing.T) {
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
httpClient: fakeClient.Client,
|
httpClient: fakeClient.Client,
|
||||||
}
|
}
|
||||||
_ = app.initConfig()
|
_ = app.initConfig(false)
|
||||||
_ = app.initDatabase(false)
|
|
||||||
defer app.db.close()
|
|
||||||
|
|
||||||
app.initMarkdown()
|
app.initMarkdown()
|
||||||
app.initTelegram()
|
app.initTelegram()
|
||||||
|
@ -156,9 +154,7 @@ func Test_telegram(t *testing.T) {
|
||||||
httpClient: fakeClient.Client,
|
httpClient: fakeClient.Client,
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = app.initConfig()
|
_ = app.initConfig(false)
|
||||||
_ = app.initDatabase(false)
|
|
||||||
defer app.db.close()
|
|
||||||
|
|
||||||
app.initTelegram()
|
app.initTelegram()
|
||||||
|
|
||||||
|
|
105
ui.go
105
ui.go
|
@ -125,6 +125,10 @@ func (a *goBlog) renderBase(hb *htmlBuilder, rd *renderData, title, main func(hb
|
||||||
hb.writeElementClose("a")
|
hb.writeElementClose("a")
|
||||||
}
|
}
|
||||||
hb.write(" • ")
|
hb.write(" • ")
|
||||||
|
hb.writeElementOpen("a", "href", rd.Blog.getRelativePath("/settings"))
|
||||||
|
hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "settings"))
|
||||||
|
hb.writeElementClose("a")
|
||||||
|
hb.write(" • ")
|
||||||
hb.writeElementOpen("a", "href", "/logout")
|
hb.writeElementOpen("a", "href", "/logout")
|
||||||
hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "logout"))
|
hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "logout"))
|
||||||
hb.writeElementClose("a")
|
hb.writeElementClose("a")
|
||||||
|
@ -1480,3 +1484,104 @@ func (a *goBlog) renderEditor(hb *htmlBuilder, rd *renderData) {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type settingsRenderData struct {
|
||||||
|
blog string
|
||||||
|
sections []*configSection
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *goBlog) renderSettings(hb *htmlBuilder, rd *renderData) {
|
||||||
|
srd, ok := rd.Data.(*settingsRenderData)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
a.renderBase(
|
||||||
|
hb, rd,
|
||||||
|
func(hb *htmlBuilder) {
|
||||||
|
a.renderTitleTag(hb, rd.Blog, a.ts.GetTemplateStringVariant(rd.Blog.Lang, "settings"))
|
||||||
|
},
|
||||||
|
func(hb *htmlBuilder) {
|
||||||
|
hb.writeElementOpen("main")
|
||||||
|
|
||||||
|
// Title
|
||||||
|
hb.writeElementOpen("h1")
|
||||||
|
hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "settings"))
|
||||||
|
hb.writeElementClose("h1")
|
||||||
|
|
||||||
|
// Post sections
|
||||||
|
hb.writeElementOpen("h2")
|
||||||
|
hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "postsections"))
|
||||||
|
hb.writeElementClose("h2")
|
||||||
|
|
||||||
|
for _, section := range srd.sections {
|
||||||
|
hb.writeElementOpen("details")
|
||||||
|
|
||||||
|
hb.writeElementOpen("summary")
|
||||||
|
hb.writeElementOpen("h3")
|
||||||
|
hb.writeEscaped(section.Name)
|
||||||
|
hb.writeElementClose("h3")
|
||||||
|
hb.writeElementClose("summary")
|
||||||
|
|
||||||
|
hb.writeElementOpen("form", "class", "fw p", "method", "post")
|
||||||
|
|
||||||
|
hb.writeElementOpen("input", "type", "hidden", "name", "sectionname", "value", section.Name)
|
||||||
|
|
||||||
|
// Title
|
||||||
|
hb.writeElementOpen("input", "type", "text", "name", "sectiontitle", "placeholder", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "sectiontitle"), "required", "", "value", section.Title)
|
||||||
|
// Description
|
||||||
|
hb.writeElementOpen(
|
||||||
|
"textarea",
|
||||||
|
"name", "sectiondescription",
|
||||||
|
"class", "monospace",
|
||||||
|
"placeholder", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "sectiondescription"),
|
||||||
|
)
|
||||||
|
hb.writeEscaped(section.Description)
|
||||||
|
hb.writeElementClose("textarea")
|
||||||
|
// Path template
|
||||||
|
hb.writeElementOpen("input", "type", "text", "name", "sectionpathtemplate", "placeholder", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "sectionpathtemplate"), "value", section.PathTemplate)
|
||||||
|
// Show full
|
||||||
|
hb.writeElementOpen("input", "type", "checkbox", "name", "sectionshowfull", "id", "showfull-"+section.Name, lo.If(section.ShowFull, "checked").Else(""), "")
|
||||||
|
hb.writeElementOpen("label", "for", "showfull-"+section.Name)
|
||||||
|
hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "sectionshowfull"))
|
||||||
|
hb.writeElementClose("label")
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
hb.writeElementOpen("div", "class", "p")
|
||||||
|
// Update
|
||||||
|
hb.writeElementOpen(
|
||||||
|
"input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "update"),
|
||||||
|
"formaction", rd.Blog.getRelativePath(settingsPath+settingsUpdateSectionPath),
|
||||||
|
)
|
||||||
|
// Delete
|
||||||
|
hb.writeElementOpen(
|
||||||
|
"input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "delete"),
|
||||||
|
"formaction", rd.Blog.getRelativePath(settingsPath+settingsDeleteSectionPath),
|
||||||
|
"class", "confirm", "data-confirmmessage", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "confirmdelete"),
|
||||||
|
)
|
||||||
|
hb.writeElementOpen("script", "src", a.assetFileName("js/formconfirm.js"), "defer", "")
|
||||||
|
hb.writeElementClose("script")
|
||||||
|
hb.writeElementClose("div")
|
||||||
|
|
||||||
|
hb.writeElementClose("form")
|
||||||
|
hb.writeElementClose("details")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new section
|
||||||
|
hb.writeElementOpen("form", "class", "fw p", "method", "post")
|
||||||
|
// Name
|
||||||
|
hb.writeElementOpen("input", "type", "text", "name", "sectionname", "placeholder", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "sectionname"), "required", "")
|
||||||
|
// Title
|
||||||
|
hb.writeElementOpen("input", "type", "text", "name", "sectiontitle", "placeholder", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "sectiontitle"), "required", "")
|
||||||
|
// Create button
|
||||||
|
hb.writeElementOpen("div")
|
||||||
|
hb.writeElementOpen(
|
||||||
|
"input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "create"),
|
||||||
|
"formaction", rd.Blog.getRelativePath(settingsPath+settingsCreateSectionPath),
|
||||||
|
)
|
||||||
|
hb.writeElementClose("div")
|
||||||
|
hb.writeElementClose("form")
|
||||||
|
|
||||||
|
hb.writeElementClose("main")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
19
ui_test.go
19
ui_test.go
|
@ -20,9 +20,7 @@ func Test_renderPostTax(t *testing.T) {
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: createDefaultTestConfig(t),
|
cfg: createDefaultTestConfig(t),
|
||||||
}
|
}
|
||||||
_ = app.initConfig()
|
_ = app.initConfig(false)
|
||||||
_ = app.initDatabase(false)
|
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
p := &post{
|
p := &post{
|
||||||
|
@ -48,9 +46,7 @@ func Test_renderOldContentWarning(t *testing.T) {
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: createDefaultTestConfig(t),
|
cfg: createDefaultTestConfig(t),
|
||||||
}
|
}
|
||||||
_ = app.initConfig()
|
_ = app.initConfig(false)
|
||||||
_ = app.initDatabase(false)
|
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
p := &post{
|
p := &post{
|
||||||
|
@ -76,10 +72,10 @@ func Test_renderInteractions(t *testing.T) {
|
||||||
cfg: createDefaultTestConfig(t),
|
cfg: createDefaultTestConfig(t),
|
||||||
}
|
}
|
||||||
app.cfg.Server.PublicAddress = "https://example.com"
|
app.cfg.Server.PublicAddress = "https://example.com"
|
||||||
_ = app.initConfig()
|
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
app.d = app.buildRouter()
|
app.d = app.buildRouter()
|
||||||
|
|
||||||
err = app.createPost(&post{
|
err = app.createPost(&post{
|
||||||
|
@ -145,9 +141,8 @@ func Test_renderAuthor(t *testing.T) {
|
||||||
}
|
}
|
||||||
app.cfg.User.Picture = "https://example.com/picture.jpg"
|
app.cfg.User.Picture = "https://example.com/picture.jpg"
|
||||||
app.cfg.User.Name = "John Doe"
|
app.cfg.User.Name = "John Doe"
|
||||||
_ = app.initConfig()
|
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package main
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -21,23 +20,16 @@ func Test_verifyMention(t *testing.T) {
|
||||||
|
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
httpClient: mockClient.Client,
|
httpClient: mockClient.Client,
|
||||||
cfg: &config{
|
cfg: createDefaultTestConfig(t),
|
||||||
Db: &configDb{
|
|
||||||
File: filepath.Join(t.TempDir(), "test.db"),
|
|
||||||
},
|
|
||||||
Server: &configServer{
|
|
||||||
PublicAddress: "https://example.org",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
d: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
d: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if strings.HasSuffix(r.URL.Path, "/") {
|
if strings.HasSuffix(r.URL.Path, "/") {
|
||||||
http.Redirect(w, r, r.URL.Path[:len(r.URL.Path)-1], http.StatusFound)
|
http.Redirect(w, r, r.URL.Path[:len(r.URL.Path)-1], http.StatusFound)
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
app.cfg.Server.PublicAddress = "https://example.org"
|
||||||
|
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
m := &mention{
|
m := &mention{
|
||||||
|
@ -71,21 +63,14 @@ func Test_verifyMentionBidgy(t *testing.T) {
|
||||||
|
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
httpClient: mockClient.Client,
|
httpClient: mockClient.Client,
|
||||||
cfg: &config{
|
cfg: createDefaultTestConfig(t),
|
||||||
Db: &configDb{
|
|
||||||
File: filepath.Join(t.TempDir(), "test.db"),
|
|
||||||
},
|
|
||||||
Server: &configServer{
|
|
||||||
PublicAddress: "https://example.org",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
d: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
d: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
app.cfg.Server.PublicAddress = "https://example.org"
|
||||||
|
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
m := &mention{
|
m := &mention{
|
||||||
|
@ -115,21 +100,14 @@ func Test_verifyMentionColin(t *testing.T) {
|
||||||
|
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
httpClient: mockClient.Client,
|
httpClient: mockClient.Client,
|
||||||
cfg: &config{
|
cfg: createDefaultConfig(),
|
||||||
Db: &configDb{
|
|
||||||
File: filepath.Join(t.TempDir(), "test.db"),
|
|
||||||
},
|
|
||||||
Server: &configServer{
|
|
||||||
PublicAddress: "https://jlelse.blog",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
d: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
d: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
app.cfg.Server.PublicAddress = "https://jlelse.blog"
|
||||||
|
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
m := &mention{
|
m := &mention{
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -11,25 +10,16 @@ import (
|
||||||
|
|
||||||
func Test_webmentions(t *testing.T) {
|
func Test_webmentions(t *testing.T) {
|
||||||
app := &goBlog{
|
app := &goBlog{
|
||||||
cfg: &config{
|
cfg: createDefaultTestConfig(t),
|
||||||
Db: &configDb{
|
}
|
||||||
File: filepath.Join(t.TempDir(), "test.db"),
|
app.cfg.Server.PublicAddress = "https://example.com"
|
||||||
},
|
app.cfg.Blogs = map[string]*configBlog{
|
||||||
Server: &configServer{
|
"en": {
|
||||||
PublicAddress: "https://example.com",
|
Lang: "en",
|
||||||
},
|
|
||||||
Blogs: map[string]*configBlog{
|
|
||||||
"en": {
|
|
||||||
Lang: "en",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
DefaultBlog: "en",
|
|
||||||
User: &configUser{},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = app.initDatabase(false)
|
_ = app.initConfig(false)
|
||||||
defer app.db.close()
|
|
||||||
app.initComponents(false)
|
app.initComponents(false)
|
||||||
|
|
||||||
_ = app.db.insertWebmention(&mention{
|
_ = app.db.insertWebmention(&mention{
|
||||||
|
|
Loading…
Reference in New Issue