mirror of
https://github.com/dnote/dnote
synced 2026-03-14 14:35:50 +01:00
Remove dependency on packr (#597)
* Embed files * Build CLI * Remove packr * Embed view directory * Embed static files * Make view engine * Populate build info
This commit is contained in:
parent
f649b5225b
commit
5bba57fd29
67 changed files with 789 additions and 789 deletions
6
Makefile
6
Makefile
|
|
@ -1,4 +1,3 @@
|
|||
PACKR2 := $(shell command -v packr2 2> /dev/null)
|
||||
NPM := $(shell command -v npm 2> /dev/null)
|
||||
HUB := $(shell command -v hub 2> /dev/null)
|
||||
|
||||
|
|
@ -12,11 +11,6 @@ install: install-go install-js
|
|||
.PHONY: install
|
||||
|
||||
install-go:
|
||||
ifndef PACKR2
|
||||
@echo "==> installing packr2"
|
||||
@go get -u github.com/gobuffalo/packr/v2/packr2
|
||||
endif
|
||||
|
||||
@echo "==> installing go dependencies"
|
||||
@go mod download
|
||||
.PHONY: install-go
|
||||
|
|
|
|||
54
go.mod
54
go.mod
|
|
@ -1,43 +1,47 @@
|
|||
module github.com/dnote/dnote
|
||||
|
||||
go 1.13
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/PuerkitoBio/goquery v1.6.0 // indirect
|
||||
github.com/andybalholm/cascadia v1.2.0 // indirect
|
||||
github.com/aymerick/douceur v0.2.0
|
||||
github.com/dnote/actions v0.2.0
|
||||
github.com/dnote/color v1.7.0
|
||||
github.com/gobuffalo/packr/v2 v2.8.1
|
||||
github.com/google/go-cmp v0.5.4
|
||||
github.com/google/go-cmp v0.5.8
|
||||
github.com/google/go-github v17.0.0+incompatible
|
||||
github.com/google/uuid v1.1.3
|
||||
github.com/gorilla/csrf v1.6.2
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/csrf v1.7.1
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/gorilla/schema v1.2.0
|
||||
github.com/jinzhu/gorm v1.9.16
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/karrick/godirwalk v1.16.1 // indirect
|
||||
github.com/lib/pq v1.9.0
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.6
|
||||
github.com/nadproject/nad v0.0.0-20200124233812-f1a4e763ee2f
|
||||
github.com/joho/godotenv v1.4.0
|
||||
github.com/lib/pq v1.10.5
|
||||
github.com/mattn/go-sqlite3 v1.14.12
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/radovskyb/watcher v1.0.7
|
||||
github.com/robfig/cron v1.2.0
|
||||
github.com/rogpeppe/go-internal v1.6.2 // indirect
|
||||
github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351
|
||||
github.com/rubenv/sql-migrate v1.1.1
|
||||
github.com/sergi/go-diff v1.1.0
|
||||
github.com/sirupsen/logrus v1.7.0 // indirect
|
||||
github.com/spf13/cobra v1.1.1
|
||||
github.com/yuin/goldmark v1.4.0
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a // indirect
|
||||
golang.org/x/sys v0.0.0-20201231184435-2d18734c6014 // indirect
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
github.com/spf13/cobra v1.4.0
|
||||
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122
|
||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/PuerkitoBio/goquery v1.8.0 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.1 // indirect
|
||||
github.com/go-gorp/gorp/v3 v3.0.2 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/gorilla/css v1.0.0 // indirect
|
||||
github.com/gorilla/securecookie v1.1.1 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 // indirect
|
||||
golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
)
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ assert_http_status() {
|
|||
fi
|
||||
}
|
||||
|
||||
assert_http_status http://localhost:2300 "200"
|
||||
assert_http_status http://localhost:2300/api/health "200"
|
||||
assert_http_status http://localhost:2300 "302"
|
||||
assert_http_status http://localhost:2300/health "200"
|
||||
|
||||
echo "======== [SUCCESS] TEST PASSED! ========"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//go:build linux || darwin
|
||||
|
||||
/* Copyright (C) 2019, 2020, 2021 Monomax Software Pty Ltd
|
||||
*
|
||||
* This file is part of Dnote.
|
||||
|
|
@ -15,7 +17,6 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with Dnote. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// +build linux darwin
|
||||
|
||||
package dirs
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//go:build linux || darwin
|
||||
|
||||
/* Copyright (C) 2019, 2020, 2021 Monomax Software Pty Ltd
|
||||
*
|
||||
* This file is part of Dnote.
|
||||
|
|
@ -15,7 +17,6 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with Dnote. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// +build linux darwin
|
||||
|
||||
package dirs
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//go:build windows
|
||||
|
||||
/* Copyright (C) 2019, 2020, 2021 Monomax Software Pty Ltd
|
||||
*
|
||||
* This file is part of Dnote.
|
||||
|
|
@ -16,8 +18,6 @@
|
|||
* along with Dnote. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// +build windows
|
||||
|
||||
package dirs
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//go:build windows
|
||||
|
||||
/* Copyright (C) 2019, 2020, 2021 Monomax Software Pty Ltd
|
||||
*
|
||||
* This file is part of Dnote.
|
||||
|
|
@ -16,8 +18,6 @@
|
|||
* along with Dnote. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// +build windows
|
||||
|
||||
package dirs
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ var (
|
|||
ErrEmptyEmailTemplates = errors.New("No EmailTemplate store was provided")
|
||||
// ErrEmptyEmailBackend is an error for missing EmailBackend content in the app configuration
|
||||
ErrEmptyEmailBackend = errors.New("No EmailBackend was provided")
|
||||
// ErrEmptyHTTP500Page is an error for missing HTTP 500 page content
|
||||
ErrEmptyHTTP500Page = errors.New("No HTTP 500 error page was set")
|
||||
)
|
||||
|
||||
// App is an application context
|
||||
|
|
@ -47,6 +49,7 @@ type App struct {
|
|||
EmailBackend mailer.Backend
|
||||
Config config.Config
|
||||
Files map[string][]byte
|
||||
HTTP500Page []byte
|
||||
}
|
||||
|
||||
// Validate validates the app configuration
|
||||
|
|
@ -66,6 +69,9 @@ func (a *App) Validate() error {
|
|||
if a.DB == nil {
|
||||
return ErrEmptyDB
|
||||
}
|
||||
if a.HTTP500Page == nil {
|
||||
return ErrEmptyHTTP500Page
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ package app
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/dnote/dnote/pkg/clock"
|
||||
"github.com/dnote/dnote/pkg/server/config"
|
||||
|
|
@ -30,16 +29,16 @@ import (
|
|||
|
||||
// NewTest returns an app for a testing environment
|
||||
func NewTest(appParams *App) App {
|
||||
emailTmplDir := os.Getenv("DNOTE_TEST_EMAIL_TEMPLATE_DIR")
|
||||
c := config.Load()
|
||||
c.SetOnPremise(false)
|
||||
|
||||
a := App{
|
||||
DB: testutils.DB,
|
||||
Clock: clock.NewMock(),
|
||||
EmailTemplates: mailer.NewTemplates(&emailTmplDir),
|
||||
EmailTemplates: mailer.NewTemplates(),
|
||||
EmailBackend: &testutils.MockEmailbackendImplementation{},
|
||||
Config: c,
|
||||
HTTP500Page: []byte("<html></html>"),
|
||||
}
|
||||
|
||||
// Allow to override with appParams
|
||||
|
|
@ -61,9 +60,6 @@ func NewTest(appParams *App) App {
|
|||
if appParams != nil && appParams.Config.DisableRegistration {
|
||||
a.Config.DisableRegistration = appParams.Config.DisableRegistration
|
||||
}
|
||||
if appParams != nil && appParams.Config.PageTemplateDir != "" {
|
||||
a.Config.PageTemplateDir = appParams.Config.PageTemplateDir
|
||||
}
|
||||
|
||||
fmt.Printf("%+v\n", appParams)
|
||||
fmt.Printf("%+v\n", a)
|
||||
|
|
|
|||
7
pkg/server/assets/.gitignore
vendored
Normal file
7
pkg/server/assets/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# Ignore CSS and JS files in static directory because
|
||||
# those files are built from the sources
|
||||
|
||||
/static/*.css
|
||||
/static/*.css.map
|
||||
/static/*.js
|
||||
/static/*.js.map
|
||||
31
pkg/server/assets/embed.go
Normal file
31
pkg/server/assets/embed.go
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package assets
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"github.com/pkg/errors"
|
||||
"io/fs"
|
||||
)
|
||||
|
||||
//go:embed static
|
||||
var staticFiles embed.FS
|
||||
|
||||
// GetStaticFS returns a filesystem for static files, with
|
||||
// all files situated in the root of the filesystem
|
||||
func GetStaticFS() (fs.FS, error) {
|
||||
subFs, err := fs.Sub(staticFiles, "static")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getting sub filesystem")
|
||||
}
|
||||
|
||||
return subFs, nil
|
||||
}
|
||||
|
||||
// MustGetHTTP500ErrorPage returns the content of HTML file for HTTP 500 error
|
||||
func MustGetHTTP500ErrorPage() []byte {
|
||||
ret, err := staticFiles.ReadFile("static/500.html")
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "reading HTML file for 500 HTTP error"))
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ set -ex
|
|||
dir=$(dirname "${BASH_SOURCE[0]}")
|
||||
basePath="$dir/../../.."
|
||||
serverDir="$dir/../.."
|
||||
outputDir="$serverDir/static"
|
||||
outputDir="$serverDir/assets/static"
|
||||
inputDir="$dir/src"
|
||||
|
||||
task="cp $inputDir/main.js $outputDir"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ set -ex
|
|||
|
||||
dir=$(dirname "${BASH_SOURCE[0]}")
|
||||
serverDir="$dir/../.."
|
||||
outputDir="$serverDir/static"
|
||||
outputDir="$serverDir/assets/static"
|
||||
inputDir="$dir/src"
|
||||
|
||||
rm -rf "${outputDir:?}/*"
|
||||
|
|
|
|||
|
|
@ -20,9 +20,11 @@ package config
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/pkg/errors"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"github.com/dnote/dnote/pkg/server/assets"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -103,9 +105,8 @@ type Config struct {
|
|||
DisableRegistration bool
|
||||
Port string
|
||||
DB PostgresConfig
|
||||
PageTemplateDir string
|
||||
StaticDir string
|
||||
AssetBaseURL string
|
||||
HTTP500Page []byte
|
||||
}
|
||||
|
||||
func getAppEnv() string {
|
||||
|
|
@ -133,6 +134,7 @@ func Load() Config {
|
|||
DisableRegistration: readBoolEnv("DisableRegistration"),
|
||||
DB: loadDBConfig(),
|
||||
AssetBaseURL: "",
|
||||
HTTP500Page: assets.MustGetHTTP500ErrorPage(),
|
||||
}
|
||||
|
||||
if err := validate(c); err != nil {
|
||||
|
|
@ -147,16 +149,6 @@ func (c *Config) SetOnPremise(val bool) {
|
|||
c.OnPremise = val
|
||||
}
|
||||
|
||||
// SetPageTemplateDir sets page template dir for the config
|
||||
func (c *Config) SetPageTemplateDir(d string) {
|
||||
c.PageTemplateDir = d
|
||||
}
|
||||
|
||||
// SetStaticDir sets static dir for the confi
|
||||
func (c *Config) SetStaticDir(d string) {
|
||||
c.StaticDir = d
|
||||
}
|
||||
|
||||
// SetAssetBaseURL sets static dir for the confi
|
||||
func (c *Config) SetAssetBaseURL(d string) {
|
||||
c.AssetBaseURL = d
|
||||
|
|
|
|||
|
|
@ -40,10 +40,8 @@ func TestGetBooks(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -125,10 +123,8 @@ func TestGetBooksByName(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -188,10 +184,8 @@ func TestGetBook(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -248,10 +242,8 @@ func TestGetBookNonOwner(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -287,10 +279,8 @@ func TestCreateBook(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -347,10 +337,8 @@ func TestCreateBook(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -438,10 +426,8 @@ func TestUpdateBook(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -525,10 +511,8 @@ func TestDeleteBook(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package controllers
|
|||
|
||||
import (
|
||||
"github.com/dnote/dnote/pkg/server/app"
|
||||
"github.com/dnote/dnote/pkg/server/log"
|
||||
"github.com/dnote/dnote/pkg/server/views"
|
||||
)
|
||||
|
||||
// Controllers is a group of controllers
|
||||
|
|
@ -16,16 +16,16 @@ type Controllers struct {
|
|||
}
|
||||
|
||||
// New returns a new group of controllers
|
||||
func New(app *app.App, baseDir string) *Controllers {
|
||||
log.Info(app.Config.PageTemplateDir)
|
||||
|
||||
func New(app *app.App) *Controllers {
|
||||
c := Controllers{}
|
||||
|
||||
c.Users = NewUsers(app, baseDir)
|
||||
viewEngine := views.NewDefaultEngine()
|
||||
|
||||
c.Users = NewUsers(app, viewEngine)
|
||||
c.Notes = NewNotes(app)
|
||||
c.Books = NewBooks(app)
|
||||
c.Sync = NewSync(app)
|
||||
c.Static = NewStatic(app, baseDir)
|
||||
c.Static = NewStatic(app, viewEngine)
|
||||
c.Health = NewHealth(app)
|
||||
|
||||
return &c
|
||||
|
|
|
|||
|
|
@ -32,9 +32,7 @@ func TestHealth(t *testing.T) {
|
|||
defer testutils.ClearData(testutils.DB)
|
||||
|
||||
server := MustNewServer(t, &app.App{
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
|
|||
|
|
@ -60,10 +60,8 @@ func TestGetNotes(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -177,10 +175,8 @@ func TestGetNote(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -376,10 +372,8 @@ func TestCreateNote(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -459,10 +453,8 @@ func TestDeleteNote(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -699,10 +691,8 @@ func TestUpdateNote(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/dnote/dnote/pkg/server/app"
|
||||
"github.com/dnote/dnote/pkg/server/assets"
|
||||
mw "github.com/dnote/dnote/pkg/server/middleware"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/pkg/errors"
|
||||
|
|
@ -109,7 +110,12 @@ func NewRouter(app *app.App, rc RouteConfig) (http.Handler, error) {
|
|||
router.PathPrefix("/api/v2").Handler(mw.ApplyLimit(mw.NotSupported, true))
|
||||
|
||||
// static
|
||||
staticHandler := http.StripPrefix("/static/", http.FileServer(http.Dir(app.Config.StaticDir)))
|
||||
staticFs, err := assets.GetStaticFS()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getting the filesystem for static files")
|
||||
}
|
||||
|
||||
staticHandler := http.StripPrefix("/static/", http.FileServer(http.FS(staticFs)))
|
||||
router.PathPrefix("/static/").Handler(staticHandler)
|
||||
|
||||
router.HandleFunc("/robots.txt", func(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
|
|||
|
|
@ -57,10 +57,8 @@ func TestNotSupportedVersions(t *testing.T) {
|
|||
|
||||
// setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ import (
|
|||
)
|
||||
|
||||
// NewStatic creates a new Static controller.
|
||||
func NewStatic(app *app.App, baseDir string) *Static {
|
||||
func NewStatic(app *app.App, viewEngine *views.Engine) *Static {
|
||||
return &Static{
|
||||
NotFoundView: views.NewView(baseDir, app, views.Config{Title: "Not Found", Layout: "base"}, "static/not_found"),
|
||||
NotFoundView: viewEngine.NewView(app, views.Config{Title: "Not Found", Layout: "base"}, "static/not_found"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ func MustNewServer(t *testing.T, appParams *app.App) *httptest.Server {
|
|||
func NewServer(appParams *app.App) (*httptest.Server, error) {
|
||||
a := app.NewTest(appParams)
|
||||
|
||||
ctl := New(&a, a.Config.PageTemplateDir)
|
||||
ctl := New(&a)
|
||||
rc := RouteConfig{
|
||||
WebRoutes: NewWebRoutes(&a, ctl),
|
||||
APIRoutes: NewAPIRoutes(&a, ctl),
|
||||
|
|
|
|||
|
|
@ -34,33 +34,33 @@ var commonHelpers = map[string]interface{}{
|
|||
|
||||
// NewUsers creates a new Users controller.
|
||||
// It panics if the necessary templates are not parsed.
|
||||
func NewUsers(app *app.App, baseDir string) *Users {
|
||||
func NewUsers(app *app.App, viewEngine *views.Engine) *Users {
|
||||
return &Users{
|
||||
NewView: views.NewView(baseDir, app,
|
||||
NewView: viewEngine.NewView(app,
|
||||
views.Config{Title: "Join", Layout: "base", HelperFuncs: commonHelpers, AlertInBody: true},
|
||||
"users/new",
|
||||
),
|
||||
LoginView: views.NewView(baseDir, app,
|
||||
LoginView: viewEngine.NewView(app,
|
||||
views.Config{Title: "Sign In", Layout: "base", HelperFuncs: commonHelpers, AlertInBody: true},
|
||||
"users/login",
|
||||
),
|
||||
PasswordResetView: views.NewView(baseDir, app,
|
||||
PasswordResetView: viewEngine.NewView(app,
|
||||
views.Config{Title: "Reset Password", Layout: "base", HelperFuncs: commonHelpers, AlertInBody: true},
|
||||
"users/password_reset",
|
||||
),
|
||||
PasswordResetConfirmView: views.NewView(baseDir, app,
|
||||
PasswordResetConfirmView: viewEngine.NewView(app,
|
||||
views.Config{Title: "Reset Password", Layout: "base", HelperFuncs: commonHelpers, AlertInBody: true},
|
||||
"users/password_reset_confirm",
|
||||
),
|
||||
SettingView: views.NewView(baseDir, app,
|
||||
SettingView: viewEngine.NewView(app,
|
||||
views.Config{Layout: "base", HelperFuncs: commonHelpers, HeaderTemplate: "navbar"},
|
||||
"users/settings",
|
||||
),
|
||||
AboutView: views.NewView(baseDir, app,
|
||||
AboutView: viewEngine.NewView(app,
|
||||
views.Config{Title: "About", Layout: "base", HelperFuncs: commonHelpers, HeaderTemplate: "navbar"},
|
||||
"users/settings_about",
|
||||
),
|
||||
EmailVerificationView: views.NewView(baseDir, app,
|
||||
EmailVerificationView: viewEngine.NewView(app,
|
||||
views.Config{Layout: "base", HelperFuncs: commonHelpers, HeaderTemplate: "navbar"},
|
||||
"users/email_verification",
|
||||
),
|
||||
|
|
|
|||
|
|
@ -99,8 +99,7 @@ func TestJoin(t *testing.T) {
|
|||
Clock: clock.NewMock(),
|
||||
EmailBackend: &emailBackend,
|
||||
Config: config.Config{
|
||||
OnPremise: tc.onPremise,
|
||||
PageTemplateDir: "../views",
|
||||
OnPremise: tc.onPremise,
|
||||
},
|
||||
})
|
||||
defer server.Close()
|
||||
|
|
@ -145,10 +144,8 @@ func TestJoinError(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -175,10 +172,8 @@ func TestJoinError(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -205,10 +200,8 @@ func TestJoinError(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -238,10 +231,8 @@ func TestJoinDuplicateEmail(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -281,7 +272,6 @@ func TestJoinDisabled(t *testing.T) {
|
|||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
DisableRegistration: true,
|
||||
},
|
||||
})
|
||||
|
|
@ -312,10 +302,8 @@ func TestLogin(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
|
||||
u := testutils.SetupUserData()
|
||||
|
|
@ -374,10 +362,8 @@ func TestLogin(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
|
||||
u := testutils.SetupUserData()
|
||||
|
|
@ -415,10 +401,8 @@ func TestLogin(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -456,10 +440,8 @@ func TestLogin(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -490,10 +472,8 @@ func TestLogout(t *testing.T) {
|
|||
setupLogoutTest := func(t *testing.T) (*httptest.Server, *database.Session, *database.Session) {
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
|
||||
aliceUser := testutils.SetupUserData()
|
||||
|
|
@ -605,10 +585,8 @@ func TestResetPassword(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -691,10 +669,8 @@ func TestResetPassword(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -734,10 +710,8 @@ func TestResetPassword(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -776,10 +750,8 @@ func TestResetPassword(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -829,10 +801,8 @@ func TestResetPassword(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -874,10 +844,8 @@ func TestCreateResetToken(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -910,10 +878,8 @@ func TestCreateResetToken(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -942,10 +908,8 @@ func TestUpdatePassword(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -975,10 +939,8 @@ func TestUpdatePassword(t *testing.T) {
|
|||
defer testutils.ClearData(testutils.DB)
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -1007,10 +969,8 @@ func TestUpdatePassword(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -1039,10 +999,8 @@ func TestUpdatePassword(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -1073,10 +1031,8 @@ func TestUpdateEmail(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -1110,10 +1066,8 @@ func TestUpdateEmail(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -1149,10 +1103,8 @@ func TestVerifyEmail(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -1190,10 +1142,8 @@ func TestVerifyEmail(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -1234,10 +1184,8 @@ func TestVerifyEmail(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -1276,10 +1224,8 @@ func TestVerifyEmail(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
@ -1322,10 +1268,8 @@ func TestCreateVerificationToken(t *testing.T) {
|
|||
// Setup
|
||||
emailBackend := testutils.MockEmailbackendImplementation{}
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
EmailBackend: &emailBackend,
|
||||
})
|
||||
defer server.Close()
|
||||
|
|
@ -1358,10 +1302,8 @@ func TestCreateVerificationToken(t *testing.T) {
|
|||
defer testutils.ClearData(testutils.DB)
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
|
|
|
|||
|
|
@ -20,8 +20,9 @@ package database
|
|||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/dnote/dnote/pkg/server/database/migrations"
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rubenv/sql-migrate"
|
||||
|
|
@ -29,8 +30,8 @@ import (
|
|||
|
||||
// Migrate runs the migrations
|
||||
func Migrate(db *gorm.DB) error {
|
||||
migrations := &migrate.PackrMigrationSource{
|
||||
Box: packr.New("migrations", "../database/migrations/"),
|
||||
migrations := &migrate.HttpFileSystemMigrationSource{
|
||||
FileSystem: http.FileSystem(http.FS(migrations.Files)),
|
||||
}
|
||||
|
||||
migrate.SetTable(MigrationTableName)
|
||||
|
|
|
|||
6
pkg/server/database/migrations/embed.go
Normal file
6
pkg/server/database/migrations/embed.go
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
package migrations
|
||||
|
||||
import "embed"
|
||||
|
||||
//go:embed *.sql
|
||||
var Files embed.FS
|
||||
|
|
@ -21,13 +21,13 @@ package mailer
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"fmt"
|
||||
htemplate "html/template"
|
||||
"io"
|
||||
ttemplate "text/template"
|
||||
|
||||
"github.com/aymerick/douceur/inliner"
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
|
@ -62,6 +62,9 @@ type template interface {
|
|||
// Templates holds the parsed email templates
|
||||
type Templates map[string]template
|
||||
|
||||
//go:embed templates/src
|
||||
var templateDir embed.FS
|
||||
|
||||
func getTemplateKey(name, kind string) string {
|
||||
return fmt.Sprintf("%s.%s", name, kind)
|
||||
}
|
||||
|
|
@ -82,36 +85,28 @@ func (tmpl Templates) set(name, kind string, t template) {
|
|||
}
|
||||
|
||||
// NewTemplates initializes templates
|
||||
func NewTemplates(srcDir *string) Templates {
|
||||
var box *packr.Box
|
||||
|
||||
if srcDir != nil {
|
||||
box = packr.Folder(*srcDir)
|
||||
} else {
|
||||
box = packr.New("emailTemplates", "./templates/src")
|
||||
}
|
||||
|
||||
welcomeText, err := initTextTmpl(box, EmailTypeWelcome)
|
||||
func NewTemplates() Templates {
|
||||
welcomeText, err := initTextTmpl(EmailTypeWelcome)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "initializing welcome template"))
|
||||
}
|
||||
verifyEmailText, err := initTextTmpl(box, EmailTypeEmailVerification)
|
||||
verifyEmailText, err := initTextTmpl(EmailTypeEmailVerification)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "initializing email verification template"))
|
||||
}
|
||||
passwordResetText, err := initTextTmpl(box, EmailTypeResetPassword)
|
||||
passwordResetText, err := initTextTmpl(EmailTypeResetPassword)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "initializing password reset template"))
|
||||
}
|
||||
passwordResetAlertText, err := initTextTmpl(box, EmailTypeResetPasswordAlert)
|
||||
passwordResetAlertText, err := initTextTmpl(EmailTypeResetPasswordAlert)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "initializing password reset template"))
|
||||
}
|
||||
inactiveReminderText, err := initTextTmpl(box, EmailTypeInactiveReminder)
|
||||
inactiveReminderText, err := initTextTmpl(EmailTypeInactiveReminder)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "initializing password reset template"))
|
||||
}
|
||||
subscriptionConfirmationText, err := initTextTmpl(box, EmailTypeSubscriptionConfirmation)
|
||||
subscriptionConfirmationText, err := initTextTmpl(EmailTypeSubscriptionConfirmation)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "initializing password reset template"))
|
||||
}
|
||||
|
|
@ -129,30 +124,30 @@ func NewTemplates(srcDir *string) Templates {
|
|||
|
||||
// initHTMLTmpl returns a template instance by parsing the template with the
|
||||
// given name along with partials
|
||||
func initHTMLTmpl(box *packr.Box, templateName string) (template, error) {
|
||||
filename := fmt.Sprintf("%s.html", templateName)
|
||||
func initHTMLTmpl(templateName string) (template, error) {
|
||||
filename := fmt.Sprintf("templates/src/%s.html", templateName)
|
||||
|
||||
content, err := box.FindString(filename)
|
||||
content, err := templateDir.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "reading template")
|
||||
}
|
||||
headerContent, err := box.FindString("header.html")
|
||||
headerContent, err := templateDir.ReadFile("templates/header.html")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "reading header template")
|
||||
}
|
||||
footerContent, err := box.FindString("footer.html")
|
||||
footerContent, err := templateDir.ReadFile("templates/footer.html")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "reading footer template")
|
||||
}
|
||||
|
||||
t := htemplate.New(templateName)
|
||||
if _, err = t.Parse(content); err != nil {
|
||||
if _, err = t.Parse(string(content)); err != nil {
|
||||
return nil, errors.Wrap(err, "parsing template")
|
||||
}
|
||||
if _, err = t.Parse(headerContent); err != nil {
|
||||
if _, err = t.Parse(string(headerContent)); err != nil {
|
||||
return nil, errors.Wrap(err, "parsing template")
|
||||
}
|
||||
if _, err = t.Parse(footerContent); err != nil {
|
||||
if _, err = t.Parse(string(footerContent)); err != nil {
|
||||
return nil, errors.Wrap(err, "parsing template")
|
||||
}
|
||||
|
||||
|
|
@ -160,16 +155,16 @@ func initHTMLTmpl(box *packr.Box, templateName string) (template, error) {
|
|||
}
|
||||
|
||||
// initTextTmpl returns a template instance by parsing the template with the given name
|
||||
func initTextTmpl(box *packr.Box, templateName string) (template, error) {
|
||||
filename := fmt.Sprintf("%s.txt", templateName)
|
||||
func initTextTmpl(templateName string) (template, error) {
|
||||
filename := fmt.Sprintf("templates/src/%s.txt", templateName)
|
||||
|
||||
content, err := box.FindString(filename)
|
||||
content, err := templateDir.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "reading template")
|
||||
}
|
||||
|
||||
t := ttemplate.New(templateName)
|
||||
if _, err = t.Parse(content); err != nil {
|
||||
if _, err = t.Parse(string(content)); err != nil {
|
||||
return nil, errors.Wrap(err, "parsing template")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ package mailer
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
|
|
@ -42,8 +41,7 @@ func TestEmailVerificationEmail(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
tmplPath := os.Getenv("DNOTE_TEST_EMAIL_TEMPLATE_DIR")
|
||||
tmpl := NewTemplates(&tmplPath)
|
||||
tmpl := NewTemplates()
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("with WebURL %s", tc.webURL), func(t *testing.T) {
|
||||
|
|
@ -81,8 +79,7 @@ func TestResetPasswordEmail(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
tmplPath := os.Getenv("DNOTE_TEST_EMAIL_TEMPLATE_DIR")
|
||||
tmpl := NewTemplates(&tmplPath)
|
||||
tmpl := NewTemplates()
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("with WebURL %s", tc.webURL), func(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ func main() {
|
|||
|
||||
log.Println("Email template development server running on http://127.0.0.1:2300")
|
||||
|
||||
tmpl := mailer.NewTemplates(nil)
|
||||
tmpl := mailer.NewTemplates()
|
||||
ctx := Context{DB: db, Tmpl: tmpl}
|
||||
|
||||
http.HandleFunc("/", ctx.homeHandler)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ package main
|
|||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
|
|
@ -33,14 +32,12 @@ import (
|
|||
"github.com/dnote/dnote/pkg/server/database"
|
||||
"github.com/dnote/dnote/pkg/server/job"
|
||||
"github.com/dnote/dnote/pkg/server/mailer"
|
||||
"github.com/dnote/dnote/pkg/server/views"
|
||||
"github.com/jinzhu/gorm"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var pageDir = flag.String("pageDir", "views", "the path to a directory containing page templates")
|
||||
var staticDir = flag.String("staticDir", "./static/", "the path to the static directory ")
|
||||
var port = flag.String("port", "3000", "port to connect to")
|
||||
|
||||
func initDB(c config.Config) *gorm.DB {
|
||||
db, err := gorm.Open("postgres", c.DB.GetConnectionStr())
|
||||
|
|
@ -52,28 +49,16 @@ func initDB(c config.Config) *gorm.DB {
|
|||
return db
|
||||
}
|
||||
|
||||
func mustReadFile(path string) []byte {
|
||||
ret, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "reading file"))
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func initApp(cfg config.Config) app.App {
|
||||
db := initDB(cfg)
|
||||
|
||||
files := map[string][]byte{}
|
||||
files[views.ServerErrorPageFileKey] = mustReadFile(fmt.Sprintf("%s/500.html", cfg.StaticDir))
|
||||
|
||||
return app.App{
|
||||
DB: db,
|
||||
Clock: clock.New(),
|
||||
EmailTemplates: mailer.NewTemplates(nil),
|
||||
EmailTemplates: mailer.NewTemplates(),
|
||||
EmailBackend: &mailer.SimpleBackendImplementation{},
|
||||
Config: cfg,
|
||||
Files: files,
|
||||
HTTP500Page: cfg.HTTP500Page,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -91,8 +76,6 @@ func runJob(a app.App) error {
|
|||
|
||||
func startCmd() {
|
||||
cfg := config.Load()
|
||||
cfg.SetPageTemplateDir(*pageDir)
|
||||
cfg.SetStaticDir(*staticDir)
|
||||
cfg.SetAssetBaseURL("/static")
|
||||
|
||||
app := initApp(cfg)
|
||||
|
|
@ -105,7 +88,7 @@ func startCmd() {
|
|||
panic(errors.Wrap(err, "running job"))
|
||||
}
|
||||
|
||||
ctl := controllers.New(&app, *pageDir)
|
||||
ctl := controllers.New(&app)
|
||||
rc := controllers.RouteConfig{
|
||||
WebRoutes: controllers.NewWebRoutes(&app, ctl),
|
||||
APIRoutes: controllers.NewAPIRoutes(&app, ctl),
|
||||
|
|
@ -117,8 +100,8 @@ func startCmd() {
|
|||
panic(errors.Wrap(err, "initializing router"))
|
||||
}
|
||||
|
||||
log.Printf("Dnote version %s is running on port %s", buildinfo.Version, cfg.Port)
|
||||
log.Fatalln(http.ListenAndServe(fmt.Sprintf(":%s", cfg.Port), r))
|
||||
log.Printf("Dnote version %s is running on port %s", buildinfo.Version, *port)
|
||||
log.Fatalln(http.ListenAndServe(fmt.Sprintf(":%s", *port), r))
|
||||
}
|
||||
|
||||
func versionCmd() {
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
8
pkg/server/views/embed.go
Normal file
8
pkg/server/views/embed.go
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
package views
|
||||
|
||||
import (
|
||||
"embed"
|
||||
)
|
||||
|
||||
//go:embed templates
|
||||
var TemplateFs embed.FS
|
||||
99
pkg/server/views/engine.go
Normal file
99
pkg/server/views/engine.go
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
package views
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/fs"
|
||||
|
||||
"github.com/dnote/dnote/pkg/server/app"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Engine is responsible for instantiating a new View
|
||||
type Engine struct {
|
||||
filePatterns []string
|
||||
fileSystem fs.FS
|
||||
}
|
||||
|
||||
// NewEngine returns a new Engine
|
||||
func NewEngine(filePatterns []string, fileSystem fs.FS) *Engine {
|
||||
return &Engine{
|
||||
filePatterns: filePatterns,
|
||||
fileSystem: fileSystem,
|
||||
}
|
||||
}
|
||||
|
||||
// NewDefaultEngine returns a new default Engine
|
||||
func NewDefaultEngine() *Engine {
|
||||
patterns := []string{}
|
||||
|
||||
patterns = append(patterns, iconFiles())
|
||||
patterns = append(patterns, layoutFiles())
|
||||
patterns = append(patterns, partialFiles())
|
||||
|
||||
return NewEngine(patterns, TemplateFs)
|
||||
}
|
||||
|
||||
// getTargetFiles returns an array of files needed for rendering
|
||||
func (e Engine) getTargetFiles(files []string) []string {
|
||||
addTemplatePath(files)
|
||||
addTemplateExt(files)
|
||||
|
||||
return append(files, e.filePatterns...)
|
||||
}
|
||||
|
||||
// NewView returns a new view by parsing the given layout and files
|
||||
func (e Engine) NewView(app *app.App, viewConfig Config, files ...string) *View {
|
||||
viewHelpers := initHelpers(viewConfig, app)
|
||||
t := template.New(viewConfig.Title).Funcs(viewHelpers)
|
||||
|
||||
targetFiles := e.getTargetFiles(files)
|
||||
|
||||
t, err := t.ParseFS(e.fileSystem, targetFiles...)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "instantiating view"))
|
||||
}
|
||||
|
||||
return &View{
|
||||
Template: t,
|
||||
Layout: viewConfig.getLayout(),
|
||||
AlertInBody: viewConfig.AlertInBody,
|
||||
App: app,
|
||||
}
|
||||
}
|
||||
|
||||
// layoutFiles returns a slice of strings representing
|
||||
// the layout files used in our application.
|
||||
func layoutFiles() string {
|
||||
return fmt.Sprintf("templates/layouts/*%s", TemplateExt)
|
||||
}
|
||||
|
||||
// iconFiles returns a slice of strings representing
|
||||
// the icon files used in our application.
|
||||
func iconFiles() string {
|
||||
return fmt.Sprintf("templates/icons/*%s", TemplateExt)
|
||||
}
|
||||
|
||||
func partialFiles() string {
|
||||
return fmt.Sprintf("templates/partials/*%s", TemplateExt)
|
||||
}
|
||||
|
||||
// addTemplatePath takes in a slice of strings
|
||||
// representing file paths for templates.
|
||||
func addTemplatePath(files []string) {
|
||||
for i, f := range files {
|
||||
files[i] = fmt.Sprintf("templates/%s", f)
|
||||
}
|
||||
}
|
||||
|
||||
// addTemplateExt takes in a slice of strings
|
||||
// representing file paths for templates and it appends
|
||||
// the templateExt extension to each string in the slice
|
||||
//
|
||||
// Eg the input {"home"} would result in the output
|
||||
// {"home.gohtml"} if templateExt == ".gohtml"
|
||||
func addTemplateExt(files []string) {
|
||||
for i, f := range files {
|
||||
files[i] = f + TemplateExt
|
||||
}
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
<div class="footer">
|
||||
<div class="callout">Don't have an account?</div>
|
||||
<a href="/join" class="cta">
|
||||
<a href="/join" class="cta" id="T-join-link">
|
||||
Create account
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -6,7 +6,6 @@ import (
|
|||
"html/template"
|
||||
"io"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/dnote/dnote/pkg/clock"
|
||||
"github.com/dnote/dnote/pkg/server/app"
|
||||
|
|
@ -14,22 +13,17 @@ import (
|
|||
"github.com/dnote/dnote/pkg/server/context"
|
||||
"github.com/dnote/dnote/pkg/server/log"
|
||||
"github.com/gorilla/csrf"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// templateExt is the template extension
|
||||
templateExt string = ".gohtml"
|
||||
// TemplateExt is the template extension
|
||||
TemplateExt string = ".gohtml"
|
||||
)
|
||||
|
||||
const (
|
||||
siteTitle = "Dnote"
|
||||
)
|
||||
|
||||
const (
|
||||
ServerErrorPageFileKey = "500"
|
||||
)
|
||||
|
||||
// Config is a view config
|
||||
type Config struct {
|
||||
Title string
|
||||
|
|
@ -68,38 +62,13 @@ func (c Config) getClock() clock.Clock {
|
|||
return clock.New()
|
||||
}
|
||||
|
||||
// NewView returns a new view by parsing the given layout and files
|
||||
func NewView(baseDir string, app *app.App, viewConfig Config, files ...string) *View {
|
||||
addTemplatePath(baseDir, files)
|
||||
addTemplateExt(files)
|
||||
|
||||
files = append(files, iconFiles(baseDir)...)
|
||||
files = append(files, layoutFiles(baseDir)...)
|
||||
files = append(files, partialFiles(baseDir)...)
|
||||
|
||||
viewHelpers := initHelpers(viewConfig, app)
|
||||
t := template.New(viewConfig.Title).Funcs(viewHelpers)
|
||||
|
||||
t, err := t.ParseFiles(files...)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "instantiating view"))
|
||||
}
|
||||
|
||||
return &View{
|
||||
Template: t,
|
||||
Layout: viewConfig.getLayout(),
|
||||
AlertInBody: viewConfig.AlertInBody,
|
||||
Files: app.Files,
|
||||
}
|
||||
}
|
||||
|
||||
// View holds the information about a view
|
||||
type View struct {
|
||||
Template *template.Template
|
||||
Layout string
|
||||
// AlertInBody specifies if alert should be set in the body instead of the header
|
||||
AlertInBody bool
|
||||
Files map[string][]byte
|
||||
App *app.App
|
||||
}
|
||||
|
||||
func (v *View) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -149,55 +118,10 @@ func (v *View) Render(w http.ResponseWriter, r *http.Request, data *Data, status
|
|||
if err := tpl.ExecuteTemplate(&buf, v.Layout, vd); err != nil {
|
||||
log.ErrorWrap(err, fmt.Sprintf("executing template for URI '%s'", r.RequestURI))
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write(v.Files[ServerErrorPageFileKey])
|
||||
w.Write(v.App.HTTP500Page)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(statusCode)
|
||||
io.Copy(w, &buf)
|
||||
}
|
||||
|
||||
func getFiles(pattern string) []string {
|
||||
files, err := filepath.Glob(pattern)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return files
|
||||
}
|
||||
|
||||
// layoutFiles returns a slice of strings representing
|
||||
// the layout files used in our application.
|
||||
func layoutFiles(baseDir string) []string {
|
||||
return getFiles(fmt.Sprintf("%s/layouts/*%s", baseDir, templateExt))
|
||||
}
|
||||
|
||||
// iconFiles returns a slice of strings representing
|
||||
// the icon files used in our application.
|
||||
func iconFiles(baseDir string) []string {
|
||||
return getFiles(fmt.Sprintf("%s/icons/*%s", baseDir, templateExt))
|
||||
}
|
||||
|
||||
func partialFiles(baseDir string) []string {
|
||||
return getFiles(fmt.Sprintf("%s/partials/*%s", baseDir, templateExt))
|
||||
}
|
||||
|
||||
// addTemplatePath takes in a slice of strings
|
||||
// representing file paths for templates.
|
||||
func addTemplatePath(baseDir string, files []string) {
|
||||
for i, f := range files {
|
||||
files[i] = fmt.Sprintf("%s/%s", baseDir, f)
|
||||
}
|
||||
}
|
||||
|
||||
// addTemplateExt takes in a slice of strings
|
||||
// representing file paths for templates and it appends
|
||||
// the templateExt extension to each string in the slice
|
||||
//
|
||||
// Eg the input {"home"} would result in the output
|
||||
// {"home.gohtml"} if templateExt == ".gohtml"
|
||||
func addTemplateExt(files []string) {
|
||||
for i, f := range files {
|
||||
files[i] = f + templateExt
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ func splitCommandParts(cmd string) []string {
|
|||
}
|
||||
|
||||
func command(binary string, args []string, entryPoint string) *exec.Cmd {
|
||||
log.Printf("executing command: %s %s", binary, args)
|
||||
cmd := exec.Command(binary, args...)
|
||||
|
||||
// Notice this change.
|
||||
|
|
|
|||
|
|
@ -19,11 +19,6 @@ projectDir="$dir/../.."
|
|||
basedir="$projectDir/pkg/cli"
|
||||
outputDir="$projectDir/build/cli"
|
||||
|
||||
# xgo has issues when using modules
|
||||
# https://github.com/karalabe/xgo/issues/176
|
||||
# bypass it by copying the project inside a GOPATH
|
||||
goPathBasedir="$GOPATH/src/github.com/dnote/dnote"
|
||||
|
||||
command_exists () {
|
||||
command -v "$1" >/dev/null 2>&1;
|
||||
}
|
||||
|
|
@ -41,7 +36,7 @@ if [[ $1 == v* ]]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
goVersion=1.13.x
|
||||
goVersion=go-1.17.x
|
||||
|
||||
get_binary_name() {
|
||||
platform=$1
|
||||
|
|
@ -62,9 +57,11 @@ build() {
|
|||
|
||||
# build binary
|
||||
destDir="$outputDir/$platform-$arch"
|
||||
ldflags="-X main.apiEndpoint=https://api.getdnote.com -X main.versionTag=$version"
|
||||
ldflags="-X main.apiEndpoint=https://api.getdnote.com -X github.com/dnote/dnote/pkg/server/buildinfo.Version=$version"
|
||||
tags="fts5"
|
||||
|
||||
pushd "$projectDir"
|
||||
|
||||
mkdir -p "$destDir"
|
||||
|
||||
if [ "$native" == true ]; then
|
||||
|
|
@ -75,17 +72,25 @@ build() {
|
|||
-o="$destDir/cli-$platform-$arch" \
|
||||
"$basedir"
|
||||
else
|
||||
flags=()
|
||||
if [ "$platform" == "windows" ]; then
|
||||
flags+=("-buildmode=exe")
|
||||
fi
|
||||
|
||||
xgo \
|
||||
-go "$goVersion" \
|
||||
--targets="$platform/$arch" \
|
||||
-targets="$platform/$arch" \
|
||||
-ldflags "$ldflags" \
|
||||
--tags "$tags" \
|
||||
--dest="$destDir" \
|
||||
-x \
|
||||
-v \
|
||||
"$goPathBasedir/pkg/cli"
|
||||
-dest="$destDir" \
|
||||
-out="cli" \
|
||||
"${flags[@]}" \
|
||||
-tags "$tags" \
|
||||
-pkg pkg/cli \
|
||||
.
|
||||
fi
|
||||
|
||||
popd
|
||||
|
||||
binaryName=$(get_binary_name "$platform")
|
||||
mv "$destDir/cli-${platform}-"* "$destDir/$binaryName"
|
||||
|
||||
|
|
@ -105,11 +110,8 @@ build() {
|
|||
}
|
||||
|
||||
if [ -z "$GOOS" ] && [ -z "$GOARCH" ]; then
|
||||
# fetch tool
|
||||
go get -u github.com/dnote/xgo
|
||||
|
||||
rm -rf "$GOPATH/src/github.com/dnote/dnote"
|
||||
cp -R "$projectDir" "$goPathBasedir"
|
||||
# install the tool
|
||||
go install src.techknowlogick.com/xgo@latest
|
||||
|
||||
build linux amd64
|
||||
build linux arm64
|
||||
|
|
|
|||
|
|
@ -35,16 +35,15 @@ build() {
|
|||
mkdir -p "$destDir"
|
||||
|
||||
# build binary
|
||||
packr2
|
||||
moduleName="github.com/dnote/dnote"
|
||||
ldflags="-X '$moduleName/pkg/server/buildinfo.CSSFiles=main.css' -X '$moduleName/pkg/server/buildinfo.JSFiles=main.js' -X '$moduleName/pkg/server/buildinfo.Version=$version' -X '$moduleName/pkg/server/buildinfo.Standalone=true'"
|
||||
|
||||
GOOS="$platform" \
|
||||
GOARCH="$arch" go build \
|
||||
-o "$destDir/dnote-server" \
|
||||
-ldflags "-X main.versionTag=$version" \
|
||||
-ldflags "$ldflags" \
|
||||
"$basedir"/*.go
|
||||
|
||||
packr2 clean
|
||||
|
||||
popd
|
||||
|
||||
# build tarball
|
||||
|
|
|
|||
|
|
@ -6,9 +6,6 @@ set -ex
|
|||
dir=$(realpath "$(dirname "${BASH_SOURCE[0]}")")
|
||||
pushd "$dir/../../pkg/server"
|
||||
|
||||
emailTemplateDir=$(realpath "$dir/../../pkg/server/mailer/templates/src")
|
||||
export DNOTE_TEST_EMAIL_TEMPLATE_DIR="$emailTemplateDir"
|
||||
|
||||
function run_test {
|
||||
if [ -z "$1" ]; then
|
||||
go test ./... -cover -p 1
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# shellcheck disable=SC1091
|
||||
set -eux
|
||||
|
||||
VERSION=1.13.4
|
||||
VERSION=1.17.9
|
||||
OS=linux
|
||||
ARCH=amd64
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue