From 0bcd06600e809a726569a3bcab0beb85efd9fbce Mon Sep 17 00:00:00 2001 From: Sung Won Cho Date: Wed, 20 Nov 2019 14:38:39 +0800 Subject: [PATCH] Fix direct access to note pages (#324) * Initialize database * Document change * Test regression --- CHANGELOG.md | 7 +++ pkg/server/main.go | 10 ++-- pkg/server/web/handlers.go | 41 ++++++++++++++- pkg/server/web/handlers_test.go | 92 +++++++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+), 5 deletions(-) create mode 100644 pkg/server/web/handlers_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 130664ca..634c57f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,13 @@ All notable changes to the projects under this repository will be documented in The following log documents the history of the server project. +### Unreleased + +#### Fixed + +- Fix server crash upon landing on a note page (#324). +- Allow to synchronize a large number of records (#321) + ### 0.3.1 - 2019-11-12 #### Fixed diff --git a/pkg/server/main.go b/pkg/server/main.go index 4be5b41f..a1df6537 100644 --- a/pkg/server/main.go +++ b/pkg/server/main.go @@ -55,10 +55,11 @@ func mustFind(box *packr.Box, path string) []byte { return b } -func initContext() web.Context { +func initContext(db *gorm.DB) web.Context { staticBox := packr.New("static", "../../web/public/static") return web.Context{ + DB: db, IndexHTML: mustFind(rootBox, "index.html"), RobotsTxt: mustFind(rootBox, "robots.txt"), ServiceWorkerJs: mustFind(rootBox, "service-worker.js"), @@ -72,8 +73,11 @@ func initServer(app handlers.App) (*http.ServeMux, error) { return nil, errors.Wrap(err, "initializing router") } - webCtx := initContext() - webHandlers := web.Init(webCtx) + webCtx := initContext(app.DB) + webHandlers, err := web.Init(webCtx) + if err != nil { + return nil, errors.Wrap(err, "initializing web handlers") + } mux := http.NewServeMux() mux.Handle("/api/", http.StripPrefix("/api", apiRouter)) diff --git a/pkg/server/web/handlers.go b/pkg/server/web/handlers.go index a20663e8..415baf02 100644 --- a/pkg/server/web/handlers.go +++ b/pkg/server/web/handlers.go @@ -28,6 +28,19 @@ import ( "github.com/pkg/errors" ) +var ( + // ErrEmptyDB is an error for missing database connection in the context + ErrEmptyDB = errors.New("No database connection was provided") + // ErrEmptyIndexHTML is an error for missing index.html content in the context + ErrEmptyIndexHTML = errors.New("No index.html content was provided") + // ErrEmptyRobotsTxt is an error for missing robots.txt content in the context + ErrEmptyRobotsTxt = errors.New("No robots.txt content was provided") + // ErrEmptyServiceWorkerJS is an error for missing service worker content in the context + ErrEmptyServiceWorkerJS = errors.New("No service-worker.js content was provided") + // ErrEmptyStaticFileSystem is an error for missing static filesystem in the context + ErrEmptyStaticFileSystem = errors.New("No static filesystem was provided") +) + // Context contains contents of web assets type Context struct { DB *gorm.DB @@ -45,14 +58,38 @@ type Handlers struct { GetStatic http.Handler } +func validateContext(c Context) error { + if c.DB == nil { + return ErrEmptyDB + } + if c.IndexHTML == nil { + return ErrEmptyIndexHTML + } + if c.RobotsTxt == nil { + return ErrEmptyRobotsTxt + } + if c.ServiceWorkerJs == nil { + return ErrEmptyServiceWorkerJS + } + if c.StaticFileSystem == nil { + return ErrEmptyStaticFileSystem + } + + return nil +} + // Init initializes the handlers -func Init(c Context) Handlers { +func Init(c Context) (Handlers, error) { + if err := validateContext(c); err != nil { + return Handlers{}, errors.Wrap(err, "validating context") + } + return Handlers{ GetRoot: getRootHandler(c), GetRobots: getRobotsHandler(c), GetServiceWorker: getSWHandler(c), GetStatic: getStaticHandler(c), - } + }, nil } // getRootHandler returns an HTTP handler that serves the app shell diff --git a/pkg/server/web/handlers_test.go b/pkg/server/web/handlers_test.go new file mode 100644 index 00000000..508a024f --- /dev/null +++ b/pkg/server/web/handlers_test.go @@ -0,0 +1,92 @@ +package web + +import ( + "fmt" + "net/http" + "testing" + + "github.com/dnote/dnote/pkg/assert" + "github.com/jinzhu/gorm" + "github.com/pkg/errors" +) + +func TestInit(t *testing.T) { + mockIndexHTML := []byte("") + mockRobotsTxt := []byte("Allow: *") + mockServiceWorkerJs := []byte("function() {}") + mockStaticFileSystem := http.Dir(".") + + testCases := []struct { + ctx Context + expectedErr error + }{ + { + ctx: Context{ + DB: &gorm.DB{}, + IndexHTML: mockIndexHTML, + RobotsTxt: mockRobotsTxt, + ServiceWorkerJs: mockServiceWorkerJs, + StaticFileSystem: mockStaticFileSystem, + }, + expectedErr: nil, + }, + { + ctx: Context{ + DB: nil, + IndexHTML: mockIndexHTML, + RobotsTxt: mockRobotsTxt, + ServiceWorkerJs: mockServiceWorkerJs, + StaticFileSystem: mockStaticFileSystem, + }, + expectedErr: ErrEmptyDB, + }, + { + ctx: Context{ + DB: &gorm.DB{}, + IndexHTML: nil, + RobotsTxt: mockRobotsTxt, + ServiceWorkerJs: mockServiceWorkerJs, + StaticFileSystem: mockStaticFileSystem, + }, + expectedErr: ErrEmptyIndexHTML, + }, + { + ctx: Context{ + DB: &gorm.DB{}, + IndexHTML: mockIndexHTML, + RobotsTxt: nil, + ServiceWorkerJs: mockServiceWorkerJs, + StaticFileSystem: mockStaticFileSystem, + }, + expectedErr: ErrEmptyRobotsTxt, + }, + { + ctx: Context{ + DB: &gorm.DB{}, + IndexHTML: mockIndexHTML, + RobotsTxt: mockRobotsTxt, + ServiceWorkerJs: nil, + StaticFileSystem: mockStaticFileSystem, + }, + expectedErr: ErrEmptyServiceWorkerJS, + }, + { + ctx: Context{ + DB: &gorm.DB{}, + IndexHTML: mockIndexHTML, + RobotsTxt: mockRobotsTxt, + ServiceWorkerJs: mockServiceWorkerJs, + StaticFileSystem: nil, + }, + expectedErr: ErrEmptyStaticFileSystem, + }, + } + + for idx, tc := range testCases { + t.Run(fmt.Sprintf("test case %d", idx), func(t *testing.T) { + _, err := Init(tc.ctx) + + assert.Equal(t, errors.Cause(err), tc.expectedErr, "error mismatch") + }) + } +}