From 739014aa968204141cd14661cc3b520b346c5300 Mon Sep 17 00:00:00 2001 From: Ben Garrett Date: Fri, 12 Apr 2024 13:37:42 +1000 Subject: [PATCH] Lint fixes and improvements. --- .golangci.yaml | 27 +++-- handler/app/context.go | 30 ++--- handler/handler.go | 101 +++++++++-------- handler/html3/html3.go | 15 +-- handler/html3/router.go | 8 +- handler/htmx/htmx.go | 23 ++-- handler/middleware.go | 4 +- handler/router.go | 193 ++++++++++++++------------------- internal/config/check.go | 70 ++++++------ internal/config/config.go | 8 +- internal/config/config_test.go | 8 +- internal/config/error.go | 14 +-- internal/config/repair.go | 14 +-- model/file.go | 3 +- model/scener.go | 2 +- server.go | 2 +- 16 files changed, 256 insertions(+), 266 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 751ca3db..9cfbcf32 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -1,5 +1,5 @@ # The .golangci.yaml file is used to configure the golangci-lint linter. -# A linter is a tool that analyzes source code to flag programming errors, +# A linter is a tool that analyzes source code to flag programming errors, # bugs, stylistic errors, and suspicious constructs. # # https://golangci-lint.run/ @@ -21,15 +21,15 @@ linters: - structcheck - varcheck # disabled - - depguard # overkill. + - depguard # overkill. - exhaustive - exhaustruct - - ireturn # conflicts with sqlboiler. - - nlreturn # fussy over whitespace. - - paralleltest # overkill. - - varnamelen # not idomatic? + - ireturn # conflicts with sqlboiler. + - nlreturn # fussy over whitespace. + - paralleltest # overkill. + - varnamelen # not idomatic? - wrapcheck - - wsl # fussy over whitespace. + - wsl # fussy over whitespace. # temporary disabled #- godox issues: @@ -91,6 +91,9 @@ issues: - gocognit - lll - tagalign + - path: internal/demozoo/demozoo.go + linters: + - tagliatelle - path: internal/pouet/pouet.go linters: - tagliatelle @@ -230,7 +233,7 @@ issues: - path: internal/postgres/sql.go linters: - goconst - + linters-settings: cyclop: # The maximal code complexity to report. @@ -248,9 +251,9 @@ linters-settings: # Values always ignored: `.+_test.go` # Default: [] ignored-files: # magic number false positives. - - 'milestone.go' - - 'interview.go' - - 'zoo.go' + - "milestone.go" + - "interview.go" + - "zoo.go" misspell: # Correct spellings using locale preferences for US or UK. # Setting locale to US will correct the British spelling of 'colour' to 'color'. @@ -258,4 +261,4 @@ linters-settings: locale: US # Default: [] ignore-words: - - 'Teh' # Teh Scene. + - "Teh" # Teh Scene. diff --git a/handler/app/context.go b/handler/app/context.go index 6e781bf9..dbe73704 100644 --- a/handler/app/context.go +++ b/handler/app/context.go @@ -49,6 +49,10 @@ const ( records = "records" sep = ";" txt = ".txt" // txt file extension + az = ", a-z" + byyear = ", by year" + alpha = "alphabetically" + year = "by year" ) // ArtifactErr renders the error page for the artifact links. @@ -276,7 +280,7 @@ func FTP(logr *zap.SugaredLogger, c echo.Context) error { data[key] = r data["stats"] = map[string]string{ "pubs": fmt.Sprintf("%d sites", len(r)), - "orderBy": "alphabetically", + "orderBy": alpha, } err = c.Render(http.StatusOK, name, data) if err != nil { @@ -2154,18 +2158,18 @@ func bbsHandler(logr *zap.SugaredLogger, c echo.Context, orderBy model.OrderBy) var order string switch orderBy { case model.Alphabetical: - s := logo + ", a-z" + s := logo + az data["logo"] = s - order = "alphabetically" + order = alpha case model.Prolific: s := logo + ", by count" data["logo"] = s order = "by file artifact count" case model.Oldest: tmpl = "bbs-year" - s := logo + ", by year" + s := logo + byyear data["logo"] = s - order = "by year" + order = year } data["stats"] = map[string]string{ "pubs": fmt.Sprintf("%d boards", len(r)), @@ -2353,16 +2357,16 @@ func magazines(logr *zap.SugaredLogger, c echo.Context, chronological bool) erro if err := r.Magazine(ctx, db); err != nil { return DatabaseErr(logr, c, name, err) } - s := title + ", by year" + s := title + byyear data["logo"] = s - order = "by year" + order = year case false: if err := r.MagazineAZ(ctx, db); err != nil { return DatabaseErr(logr, c, name, err) } - s := title + ", a-z" + s := title + az data["logo"] = s - order = "alphabetically" + order = alpha } data[key] = r data["stats"] = map[string]string{ @@ -2606,18 +2610,18 @@ func releasers(logr *zap.SugaredLogger, c echo.Context, orderBy model.OrderBy) e var order string switch orderBy { case model.Alphabetical: - s := logo + ", a-z" + s := logo + az data["logo"] = s - order = "alphabetically" + order = alpha case model.Prolific: s := logo + ", by count" data["logo"] = s order = "by file artifact count" case model.Oldest: tmpl = "releaser-year" - s := logo + ", by year" + s := logo + byyear data["logo"] = s - order = "by year" + order = year } data["stats"] = map[string]string{ "pubs": fmt.Sprintf("%d releasers and groups", len(r)), diff --git a/handler/handler.go b/handler/handler.go index 2ebccf49..ea038f59 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -12,6 +12,7 @@ import ( "fmt" "html/template" "io" + "io/fs" "maps" "net" "net/http" @@ -70,75 +71,66 @@ type Configuration struct { // Controller is the primary instance of the Echo router. func (c Configuration) Controller() *echo.Echo { - logr := c.Logger + configs := c.Import e := echo.New() e.HideBanner = true - e.HTTPErrorHandler = c.Import.CustomErrorHandler + e.HTTPErrorHandler = configs.CustomErrorHandler - templates, err := c.Registry() - if err != nil { - logr.Fatal(err) + logger := c.Logger + if tmpl, err := c.Registry(); err != nil { + logger.Fatal(err) + } else { + e.Renderer = tmpl } - e.Renderer = templates - e.Pre( + middlewares := []echo.MiddlewareFunc{ middleware.Rewrite(rewrites()), - // redirect www.defacto2.net requests to defacto2.net middleware.NonWWWRedirect(), - ) - httpsRedirect := c.Import.HTTPSRedirect && c.Import.TLSPort > 0 - if httpsRedirect { - // redirect http://defacto2.net requests to https://defacto2.net - e.Pre(middleware.HTTPSRedirect()) - } - // ******************************************************************************** - // Middleware configurations note - // NEVER USE the middleware.Timeout() - // It is broken and should not be in the echo library as it causes server crashes. - // ******************************************************************************** - e.Use( - // XSS cross-site scripting protection + } + if httpsRedirect := configs.HTTPSRedirect && configs.TLSPort > 0; httpsRedirect { + middlewares = append(middlewares, middleware.HTTPSRedirect()) + } + e.Pre(middlewares...) + + // ******************************************* + // NOTEL: NEVER USE the middleware.Timeout() + // It is broken and should not be in the + // echo library as it causes server crashes. + // ******************************************* + middlewares = []echo.MiddlewareFunc{ middleware.Secure(), - // custom HTTP logging middleware middleware.RequestLoggerWithConfig(c.configZapLogger()), - // add X-Robots-Tag to all responses c.NoCrawl, - // remove trailing slashes middleware.RemoveTrailingSlashWithConfig(configRTS()), - ) - logr.Info("Middleware configured.") - switch strings.ToLower(c.Import.Compression) { + } + switch strings.ToLower(configs.Compression) { case "gzip": - e.Use(middleware.Gzip()) + middlewares = append(middlewares, middleware.Gzip()) case "br": - e.Use(br.Brotli()) + middlewares = append(middlewares, br.Brotli()) } - if c.Import.ProductionMode { - e.Use(middleware.Recover()) // recover from panics + if configs.ProductionMode { + middlewares = append(middlewares, middleware.Recover()) // recover from panics } - // Static embedded web assets that get distributed in the binary - e = c.EmbedDirs(e) - // Routes for the web application - e, err = c.Moved(e) - if err != nil { - logr.Fatal(err) - } - e, err = c.Routes(e, c.Public) + e.Use(middlewares...) + + e = EmbedDirs(e, c.Public) + e = MovedPermanently(e) + e = htmx.Routes(e, logger) + e, err := c.FilesRoutes(e, c.Public) if err != nil { - logr.Fatal(err) + logger.Fatal(err) } - e = htmx.Routes(logr, e) - // Routes for the retro web tables - old := html3.Routes(logr, e) - old.GET(Downloader, c.downloader) + group := html3.Routes(e, logger) + group.GET(Downloader, c.downloader) return e } // EmbedDirs serves the static files from the directories embed to the binary. -func (c Configuration) EmbedDirs(e *echo.Echo) *echo.Echo { +func EmbedDirs(e *echo.Echo, currentFs fs.FS) *echo.Echo { if e == nil { - c.Logger.Fatal(ErrRoutes) + panic(ErrRoutes) } dirs := map[string]string{ "/image/artpack": "public/image/artpack", @@ -147,7 +139,7 @@ func (c Configuration) EmbedDirs(e *echo.Echo) *echo.Echo { "/image/milestone": "public/image/milestone", } for path, fsRoot := range dirs { - e.StaticFS(path, echo.MustSubFS(c.Public, fsRoot)) + e.StaticFS(path, echo.MustSubFS(currentFs, fsRoot)) e.GET(path, func(_ echo.Context) error { return echo.NewHTTPError(http.StatusNotFound) }) @@ -224,6 +216,9 @@ func (c Configuration) Registry() (*TemplateRegistry, error) { // ShutdownHTTP waits for a Ctrl-C keyboard press to initiate a graceful shutdown of the HTTP web server. // The shutdown procedure occurs a few seconds after the key press. func (c *Configuration) ShutdownHTTP(e *echo.Echo) { + if e == nil { + panic(ErrRoutes) + } // Wait for interrupt signal to gracefully shutdown the server quit := make(chan os.Signal, 1) signal.Notify(quit, os.Interrupt) @@ -274,6 +269,9 @@ func (c *Configuration) ShutdownHTTP(e *echo.Echo) { // Start the HTTP, and-or the TLS servers. func (c *Configuration) Start(e *echo.Echo, configs config.Config) error { + if e == nil { + panic(ErrRoutes) + } switch { case configs.UseTLS() && configs.UseHTTP(): go func() { @@ -301,6 +299,9 @@ func (c *Configuration) Start(e *echo.Echo, configs config.Config) error { // StartHTTP starts the insecure HTTP web server. func (c *Configuration) StartHTTP(e *echo.Echo) { + if e == nil { + panic(ErrRoutes) + } port := c.Import.HTTPPort if port == 0 { return @@ -313,6 +314,9 @@ func (c *Configuration) StartHTTP(e *echo.Echo) { // StartTLS starts the encrypted TLS web server. func (c *Configuration) StartTLS(e *echo.Echo) { + if e == nil { + panic(ErrRoutes) + } port := c.Import.TLSPort if port == 0 { return @@ -338,6 +342,9 @@ func (c *Configuration) StartTLS(e *echo.Echo) { // StartTLSLocal starts the localhost, encrypted TLS web server. // This should only be triggered when the server is running in local mode. func (c *Configuration) StartTLSLocal(e *echo.Echo) { + if e == nil { + panic(ErrRoutes) + } port := c.Import.TLSPort if port == 0 { return diff --git a/handler/html3/html3.go b/handler/html3/html3.go index 946bef6f..8042c498 100644 --- a/handler/html3/html3.go +++ b/handler/html3/html3.go @@ -56,13 +56,14 @@ const ( ) var ( - ErrConn = errors.New("the server cannot connect to the database") - ErrDB = errors.New("database value is nil") - ErrPage = errors.New("unknown records by type") - ErrSQL = errors.New("database connection problem or a SQL error") - ErrTag = errors.New("no database query was for the tag") - ErrTmpl = errors.New("the server could not render the HTML template for this page") - ErrZap = errors.New("zap logger is nil") + ErrConn = errors.New("the server cannot connect to the database") + ErrDB = errors.New("database value is nil") + ErrPage = errors.New("unknown records by type") + ErrRoutes = errors.New("echo instance is nil") + ErrSQL = errors.New("database connection problem or a SQL error") + ErrTag = errors.New("no database query was for the tag") + ErrTmpl = errors.New("the server could not render the HTML template for this page") + ErrZap = errors.New("zap logger is nil") ) // Clauses for ordering file record queries. diff --git a/handler/html3/router.go b/handler/html3/router.go index 99f3a583..f993b7c3 100644 --- a/handler/html3/router.go +++ b/handler/html3/router.go @@ -12,9 +12,11 @@ import ( // Routes for the /html3 sub-route group. // Any errors are logged and rendered to the client using HTTP codes // and the custom /html3, group errror template. -func Routes(logr *zap.SugaredLogger, e *echo.Echo) *echo.Group { - s := Sugared{Log: logr} - +func Routes(e *echo.Echo, logger *zap.SugaredLogger) *echo.Group { + if e == nil { + panic(ErrRoutes) + } + s := Sugared{Log: logger} g := e.Group(Prefix) g.GET("", s.Index) g.GET("/all:offset", s.All) diff --git a/handler/htmx/htmx.go b/handler/htmx/htmx.go index c4f8d420..46a0b3c9 100644 --- a/handler/htmx/htmx.go +++ b/handler/htmx/htmx.go @@ -29,39 +29,44 @@ import ( ) var ( - ErrDB = errors.New("database connection is nil") - ErrExist = errors.New("file already exists") + ErrDB = errors.New("database connection is nil") + ErrExist = errors.New("file already exists") + ErrRoutes = errors.New("echo instance is nil") ) // Routes for the /htmx sub-route group that returns HTML fragments // using the htmx library for AJAX responses. -func Routes(logr *zap.SugaredLogger, e *echo.Echo) *echo.Echo { - submit := e.Group("", middleware.RateLimiter(middleware.NewRateLimiterMemoryStore(2))) +func Routes(e *echo.Echo, logger *zap.SugaredLogger) *echo.Echo { + if e == nil { + panic(ErrRoutes) + } + submit := e.Group("", + middleware.RateLimiter(middleware.NewRateLimiterMemoryStore(2))) submit.POST("/demozoo/production", func(c echo.Context) error { return DemozooProd(c) }) submit.POST("/demozoo/production/submit/:id", func(c echo.Context) error { - return DemozooSubmit(logr, c) + return DemozooSubmit(logger, c) }) submit.POST("/pouet/production", func(c echo.Context) error { return PouetProd(c) }) submit.POST("/pouet/production/submit/:id", func(c echo.Context) error { - return PouetSubmit(logr, c) + return PouetSubmit(logger, c) }) submit.POST("/search/releaser", func(c echo.Context) error { - return SearchReleaser(logr, c) + return SearchReleaser(logger, c) }) submit.POST("/uploader/intro", func(c echo.Context) error { return holder(c, "uploader-introfile") }) submit.POST("/uploader/releaser/1", func(c echo.Context) error { input := c.FormValue("uploader-intro-releaser1") - return DataListReleasers(logr, c, input) + return DataListReleasers(logger, c, input) }) submit.POST("/uploader/releaser/2", func(c echo.Context) error { input := c.FormValue("uploader-intro-releaser2") - return DataListReleasers(logr, c, input) + return DataListReleasers(logger, c, input) }) return e } diff --git a/handler/middleware.go b/handler/middleware.go index b57e26db..cd09a432 100644 --- a/handler/middleware.go +++ b/handler/middleware.go @@ -86,7 +86,7 @@ func configRTS() middleware.TrailingSlashConfig { func (c Configuration) configZapLogger() middleware.RequestLoggerConfig { if !c.Import.LogRequests { return middleware.RequestLoggerConfig{ - LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error { + LogValuesFunc: func(_ echo.Context, _ middleware.RequestLoggerValues) error { return nil }, } @@ -104,7 +104,7 @@ func (c Configuration) configZapLogger() middleware.RequestLoggerConfig { LogStatus: true, LogLatency: true, LogResponseSize: true, - LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error { + LogValuesFunc: func(_ echo.Context, v middleware.RequestLoggerValues) error { const template = "HTTP %s %d: %s %s %dB" if v.Status > http.StatusAlreadyReported { logger.Warnf(template, diff --git a/handler/router.go b/handler/router.go index 1ed432a6..1161093d 100644 --- a/handler/router.go +++ b/handler/router.go @@ -20,14 +20,14 @@ import ( const code = http.StatusMovedPermanently -// Routes defines the routes for the web server. -func (c Configuration) Routes(e *echo.Echo, public embed.FS) (*echo.Echo, error) { +// FilesRoutes defines the file locations and routes for the web server. +func (c Configuration) FilesRoutes(e *echo.Echo, public embed.FS) (*echo.Echo, error) { + if e == nil { + panic(ErrRoutes) + } if c.Logger == nil { return nil, fmt.Errorf("%w: %s", ErrZap, "handler routes") } - if e == nil { - return nil, fmt.Errorf("%w: %s", ErrRoutes, "handler routes") - } if d, err := public.ReadDir("."); err != nil || len(d) == 0 { return nil, fmt.Errorf("%w: %s", ErrFS, "public") } @@ -43,39 +43,19 @@ func (c Configuration) Routes(e *echo.Echo, public embed.FS) (*echo.Echo, error) if err != nil { return nil, fmt.Errorf("%w: %s", err, "nonce") } - if e, err = c.html(e, public); err != nil { - return nil, fmt.Errorf("%w: %s", err, "html") - } - if e, err = c.fonts(e, public); err != nil { - return nil, fmt.Errorf("%w: %s", err, "fonts") - } - if e, err = c.embedded(e, public); err != nil { - return nil, fmt.Errorf("%w: %s", err, "embedded") - } - if e, err = c.static(e); err != nil { - return nil, fmt.Errorf("%w: %s", err, "static") - } if e, err = c.custom404(e); err != nil { return nil, fmt.Errorf("%w: %s", err, "custom404") } - if e, err = c.debugInfo(e); err != nil { - return nil, fmt.Errorf("%w: %s", err, "debugInfo") - } - if e, err = c.website(e, dir); err != nil { - return nil, fmt.Errorf("%w: %s", err, "website") - } - if e, err = c.search(e); err != nil { - return nil, fmt.Errorf("%w: %s", err, "search") - } - if e, err = c.uploader(e); err != nil { - return nil, fmt.Errorf("%w: %s", err, "uploader") - } - if e, err = c.signings(e, nonce); err != nil { - return nil, fmt.Errorf("%w: %s", err, "signings") - } - if e, err = c.editor(e, dir); err != nil { - return nil, fmt.Errorf("%w: %s", err, "editor") - } + e = c.html(e, public) + e = c.font(e, public) + e = c.embed(e, public) + e = c.static(e) + e = c.debugInfo(e) + e = c.website(e, dir) + e = c.search(e) + e = c.signin(e, nonce) + e = c.editor(e, dir) + e = c.uploader(e) return e, nil } @@ -83,7 +63,7 @@ func (c Configuration) Routes(e *echo.Echo, public embed.FS) (*echo.Echo, error) // If the read mode is enabled then an empty session key is returned. func (c Configuration) nonce(e *echo.Echo) (string, error) { if e == nil { - return "", ErrRoutes + panic(ErrRoutes) } if c.Import.ReadMode { return "", nil @@ -97,9 +77,9 @@ func (c Configuration) nonce(e *echo.Echo) (string, error) { } // html serves the embedded CSS, JS, WASM, and source map files for the HTML website layout. -func (c Configuration) html(e *echo.Echo, public embed.FS) (*echo.Echo, error) { +func (c Configuration) html(e *echo.Echo, public embed.FS) *echo.Echo { if e == nil { - return nil, ErrRoutes + panic(ErrRoutes) } hrefs, names := app.Hrefs(), app.Names() for key, href := range hrefs { @@ -110,54 +90,54 @@ func (c Configuration) html(e *echo.Echo, public embed.FS) (*echo.Echo, error) { e.FileFS(hrefs[app.Bootstrap5]+mapExt, names[app.Bootstrap5]+mapExt, public) e.FileFS(hrefs[app.Bootstrap5JS]+mapExt, names[app.Bootstrap5JS]+mapExt, public) e.FileFS(hrefs[app.Jsdos6JS]+mapExt, names[app.Jsdos6JS]+mapExt, public) - return e, nil + return e } -// fonts serves the embedded woff2, woff, and ttf font files for the website layout. -func (c Configuration) fonts(e *echo.Echo, public embed.FS) (*echo.Echo, error) { +// font serves the embedded woff2, woff, and ttf font files for the website layout. +func (c Configuration) font(e *echo.Echo, public embed.FS) *echo.Echo { if e == nil { - return nil, ErrRoutes + panic(ErrRoutes) } paths, names := app.FontRefs(), app.FontNames() font := e.Group("/font") for key, href := range paths { font.FileFS(href, names[key], public) } - return e, nil + return e } -// embedded serves the miscellaneous embedded files for the website layout. +// embed serves the miscellaneous embedded files for the website layout. // This includes the favicon, robots.txt, site.webmanifest, osd.xml, and the SVG icons. -func (c Configuration) embedded(e *echo.Echo, public embed.FS) (*echo.Echo, error) { +func (c Configuration) embed(e *echo.Echo, public embed.FS) *echo.Echo { if e == nil { - return nil, ErrRoutes + panic(ErrRoutes) } e.FileFS("/bootstrap-icons.svg", "public/image/bootstrap-icons.svg", public) e.FileFS("/favicon.ico", "public/image/favicon.ico", public) e.FileFS("/osd.xml", "public/text/osd.xml", public) e.FileFS("/robots.txt", "public/text/robots.txt", public) e.FileFS("/site.webmanifest", "public/text/site.webmanifest.json", public) - return e, nil + return e } // static serves the static assets for the website such as the thumbnail and preview images. -func (c Configuration) static(e *echo.Echo) (*echo.Echo, error) { +func (c Configuration) static(e *echo.Echo) *echo.Echo { if e == nil { - return nil, ErrRoutes + panic(ErrRoutes) } e.Static(config.StaticThumb(), c.Import.ThumbnailDir) e.Static(config.StaticOriginal(), c.Import.PreviewDir) - return e, nil + return e } -// custom404 is a custom 404 error handler for the website, "The page cannot be found." +// custom404 is a custom 404 error handler for the website, +// "The page cannot be found". func (c Configuration) custom404(e *echo.Echo) (*echo.Echo, error) { - logr := c.Logger - if logr == nil { - return nil, ErrZap - } if e == nil { - return nil, ErrRoutes + panic(ErrRoutes) + } + if c.Logger == nil { + return nil, ErrZap } e.GET("/:uri", func(x echo.Context) error { return app.StatusErr(c.Logger, x, http.StatusNotFound, x.Param("uri")) @@ -166,12 +146,12 @@ func (c Configuration) custom404(e *echo.Echo) (*echo.Echo, error) { } // debugInfo returns detailed information about the HTTP request. -func (c Configuration) debugInfo(e *echo.Echo) (*echo.Echo, error) { +func (c Configuration) debugInfo(e *echo.Echo) *echo.Echo { if e == nil { - return nil, ErrRoutes + panic(ErrRoutes) } if c.Import.ProductionMode { - return e, nil + return e } type debug struct { @@ -188,7 +168,6 @@ func (c Configuration) debugInfo(e *echo.Echo) (*echo.Echo, error) { AcceptEncoding string `json:"acceptEncoding"` AcceptLanguage string `json:"acceptLanguage"` } - e.GET("/debug", func(x echo.Context) error { req := x.Request() d := debug{ @@ -207,13 +186,13 @@ func (c Configuration) debugInfo(e *echo.Echo) (*echo.Echo, error) { } return x.JSONPretty(http.StatusOK, d, " ") }) - return e, nil + return e } // website routes for the main site. -func (c Configuration) website(e *echo.Echo, dir app.Dirs) (*echo.Echo, error) { +func (c Configuration) website(e *echo.Echo, dir app.Dirs) *echo.Echo { if e == nil { - return nil, ErrRoutes + panic(ErrRoutes) } logr := c.Logger @@ -332,13 +311,13 @@ func (c Configuration) website(e *echo.Echo, dir app.Dirs) (*echo.Echo, error) { s.GET("/v/:id", func(x echo.Context) error { return app.Inline(logr, x, c.Import.DownloadDir) }) - return e, nil + return e } // search forms and the results for database queries. -func (c Configuration) search(e *echo.Echo) (*echo.Echo, error) { +func (c Configuration) search(e *echo.Echo) *echo.Echo { if e == nil { - return nil, ErrRoutes + panic(ErrRoutes) } logr := c.Logger search := e.Group("/search") @@ -367,13 +346,13 @@ func (c Configuration) search(e *echo.Echo) (*echo.Echo, error) { search.POST("/releaser", func(x echo.Context) error { return htmx.SearchReleaser(logr, x) }) - return e, nil + return e } -// uploader for anonymous client uploads -func (c Configuration) uploader(e *echo.Echo) (*echo.Echo, error) { +// uploader for anonymous client uploads. +func (c Configuration) uploader(e *echo.Echo) *echo.Echo { if e == nil { - return nil, ErrRoutes + panic(ErrRoutes) } logr := c.Logger uploader := e.Group("/uploader") @@ -381,13 +360,13 @@ func (c Configuration) uploader(e *echo.Echo) (*echo.Echo, error) { uploader.GET("", func(x echo.Context) error { return app.PostIntro(logr, x) }) - return e, nil + return e } -// signins for operators. -func (c Configuration) signings(e *echo.Echo, nonce string) (*echo.Echo, error) { +// signin for operators. +func (c Configuration) signin(e *echo.Echo, nonce string) *echo.Echo { if e == nil { - return nil, ErrRoutes + panic(ErrRoutes) } logr := c.Logger signings := e.Group("") @@ -408,13 +387,13 @@ func (c Configuration) signings(e *echo.Echo, nonce string) (*echo.Echo, error) c.Import.SessionMaxAge, c.Import.GoogleAccounts...) }) - return e, nil + return e } // editor pages to update the database records. -func (c Configuration) editor(e *echo.Echo, dir app.Dirs) (*echo.Echo, error) { +func (c Configuration) editor(e *echo.Echo, dir app.Dirs) *echo.Echo { if e == nil { - return nil, ErrRoutes + panic(ErrRoutes) } logr := c.Logger editor := e.Group("/editor") @@ -486,37 +465,25 @@ func (c Configuration) editor(e *echo.Echo, dir app.Dirs) (*echo.Echo, error) { tag.POST("/info", func(x echo.Context) error { return app.TagInfo(logr, x) }) - return e, nil + return e } -// Moved redirects are partial URL routers that are to be redirected with a HTTP 301 Moved Permanently. -func (c Configuration) Moved(e *echo.Echo) (*echo.Echo, error) { +// MovedPermanently redirects are partial URL routers that are to be redirected with a HTTP 301 Moved Permanently. +func MovedPermanently(e *echo.Echo) *echo.Echo { if e == nil { - return nil, ErrRoutes - } - e, err := nginx(e) - if err != nil { - return nil, err + panic(ErrRoutes) } - e, err = retired(e) - if err != nil { - return nil, err - } - e, err = wayback(e) - if err != nil { - return nil, err - } - e, err = fixes(e) - if err != nil { - return nil, err - } - return e, nil + e = nginx(e) + e = retired(e) + e = wayback(e) + e = fixes(e) + return e } -// nginx redirects -func nginx(e *echo.Echo) (*echo.Echo, error) { +// nginx redirects. +func nginx(e *echo.Echo) *echo.Echo { if e == nil { - return nil, ErrRoutes + panic(ErrRoutes) } nginx := e.Group("") nginx.GET("/welcome", func(x echo.Context) error { @@ -573,13 +540,13 @@ func nginx(e *echo.Echo) (*echo.Echo, error) { nginx.GET("/site-info.cfm", func(x echo.Context) error { return x.Redirect(code, "/") // there's no dedicated about site page }) - return e, nil + return e } -// retired, redirects from the 2020 edition of the website -func retired(e *echo.Echo) (*echo.Echo, error) { +// retired, redirects from the 2020 edition of the website. +func retired(e *echo.Echo) *echo.Echo { if e == nil { - return nil, ErrRoutes + panic(ErrRoutes) } retired := e.Group("") retired.GET("/code", func(x echo.Context) error { @@ -691,13 +658,13 @@ func retired(e *echo.Echo) (*echo.Echo, error) { retired.GET("/upload/other", func(x echo.Context) error { return x.Redirect(code, "/") }) - return e, nil + return e } -// wayback redirects -func wayback(e *echo.Echo) (*echo.Echo, error) { +// wayback redirects. +func wayback(e *echo.Echo) *echo.Echo { if e == nil { - return nil, ErrRoutes + panic(ErrRoutes) } wayback := e.Group("") wayback.GET("/scene-archive/:uri", func(x echo.Context) error { @@ -718,13 +685,13 @@ func wayback(e *echo.Echo) (*echo.Echo, error) { wayback.GET("/web.pages/warez_world-1.htm", func(x echo.Context) error { return x.Redirect(code, "/wayback/warez-world-from-2001-july-26/index.html") }) - return e, nil + return e } // fixes redirects repaired, releaser database entry redirects that are contained in the model fix package. -func fixes(e *echo.Echo) (*echo.Echo, error) { +func fixes(e *echo.Echo) *echo.Echo { if e == nil { - return nil, ErrRoutes + panic(ErrRoutes) } fixes := e.Group("/g") const g = "/g/" @@ -761,5 +728,5 @@ func fixes(e *echo.Echo) (*echo.Echo, error) { fixes.GET("/"+releaser.Obfuscate("RSS"), func(x echo.Context) error { return x.Redirect(code, g+releaser.Obfuscate("renaissance")) }) - return e, nil + return e } diff --git a/internal/config/check.go b/internal/config/check.go index 44cc1da0..a717171f 100644 --- a/internal/config/check.go +++ b/internal/config/check.go @@ -37,77 +37,77 @@ var ( ) // Checks runs a number of sanity checks for the environment variable configurations. -func (c *Config) Checks(logr *zap.SugaredLogger) error { - if logr == nil { +func (c *Config) Checks(logger *zap.SugaredLogger) error { + if logger == nil { return ErrZap } if c.HTTPSRedirect && c.TLSPort == 0 { - logr.Warn("HTTPSRedirect is on but the HTTPS port is not set," + + logger.Warn("HTTPSRedirect is on but the HTTPS port is not set," + " so the server will not redirect HTTP requests to HTTPS.") } - c.httpPort(logr) - c.tlsPort(logr) - c.production(logr) + c.httpPort(logger) + c.tlsPort(logger) + c.production(logger) // Check the download, preview and thumbnail directories. if err := DownloadDir(c.DownloadDir); err != nil { s := helper.Capitalize(err.Error()) + "." - logr.Warn(s) + logger.Warn(s) } if err := PreviewDir(c.PreviewDir); err != nil { s := helper.Capitalize(err.Error()) + "." - logr.Warn(s) + logger.Warn(s) } if err := ThumbnailDir(c.ThumbnailDir); err != nil { s := helper.Capitalize(err.Error()) + "." - logr.Warn(s) + logger.Warn(s) } // Reminds for the optional configuration values. if c.NoCrawl { - logr.Warn("NoCrawl is on, web crawlers should ignore this site.") + logger.Warn("NoCrawl is on, web crawlers should ignore this site.") } if c.HTTPSRedirect && c.TLSPort > 0 { - logr.Info("HTTPSRedirect is on, all HTTP requests will be redirected to HTTPS.") + logger.Info("HTTPSRedirect is on, all HTTP requests will be redirected to HTTPS.") } if c.HostName == postgres.DockerHost { - logr.Info("The application is configured for use in a Docker container.") + logger.Info("The application is configured for use in a Docker container.") } - return c.SetupLogDir(logr) + return c.SetupLogDir(logger) } // httpPort returns an error if the HTTP port is invalid. -func (c Config) httpPort(logr *zap.SugaredLogger) { +func (c Config) httpPort(logger *zap.SugaredLogger) { if c.HTTPPort == 0 { return } if err := Validate(c.HTTPPort); err != nil { switch { case errors.Is(err, ErrPortMax): - logr.Fatalf("The server could not use the HTTP port %d, %s.", + logger.Fatalf("The server could not use the HTTP port %d, %s.", c.HTTPPort, err) case errors.Is(err, ErrPortSys): - logr.Infof("The server HTTP port %d, %s.", + logger.Infof("The server HTTP port %d, %s.", c.HTTPPort, err) } } } // tlsPort returns an error if the TLS port is invalid. -func (c Config) tlsPort(logr *zap.SugaredLogger) { +func (c Config) tlsPort(logger *zap.SugaredLogger) { if c.TLSPort == 0 { return } if err := Validate(c.TLSPort); err != nil { switch { case errors.Is(err, ErrPortMax): - logr.Fatalf("The server could not use the HTTPS port %d, %s.", + logger.Fatalf("The server could not use the HTTPS port %d, %s.", c.TLSPort, err) case errors.Is(err, ErrPortSys): - logr.Infof("The server HTTPS port %d, %s.", + logger.Infof("The server HTTPS port %d, %s.", c.TLSPort, err) } } @@ -116,40 +116,40 @@ func (c Config) tlsPort(logr *zap.SugaredLogger) { // The production mode checks when not in read-only mode. It // expects the server to be configured with OAuth2 and Google IDs. // The server should be running over HTTPS and not unencrypted HTTP. -func (c Config) production(logr *zap.SugaredLogger) { +func (c Config) production(logger *zap.SugaredLogger) { if !c.ProductionMode || c.ReadMode { return } if c.GoogleClientID == "" { s := helper.Capitalize(ErrNoOAuth2.Error()) + "." - logr.Warn(s) + logger.Warn(s) } if c.GoogleIDs == "" && len(c.GoogleAccounts) == 0 { s := helper.Capitalize(ErrNoAccounts.Error()) + "." - logr.Warn(s) + logger.Warn(s) } if c.HTTPPort > 0 { s := fmt.Sprintf("%s over port %d.", helper.Capitalize(ErrUnencrypted.Error()), c.HTTPPort) - logr.Info(s) + logger.Info(s) } if c.SessionKey != "" { s := helper.Capitalize(ErrSessionKey.Error()) + "." - logr.Warn(s) - logr.Warn("This means that all signed in clients will not be logged out on a server restart.") + logger.Warn(s) + logger.Warn("This means that all signed in clients will not be logged out on a server restart.") } if c.SessionMaxAge > 0 { - logr.Infof("A signed in client session lasts for %d hour(s).", c.SessionMaxAge) + logger.Infof("A signed in client session lasts for %d hour(s).", c.SessionMaxAge) } else { - logr.Warn("A signed in client session lasts forever.") + logger.Warn("A signed in client session lasts forever.") } } // LogStore determines the local storage path for all log files created by this web application. -func (cfg *Config) LogStore() error { +func (c *Config) LogStore() error { const ownerGroupAll = 0o770 - logs := cfg.LogDir + logs := c.LogDir if logs == "" { dir, err := os.UserConfigDir() if err != nil { @@ -162,15 +162,15 @@ func (cfg *Config) LogStore() error { return fmt.Errorf("%w: %s", err, logs) } } - cfg.LogDir = logs + c.LogDir = logs return nil } // SetupLogDir runs checks against the configured log directory. // If no log directory is configured, a default directory is used. // Problems will either log warnings or fatal errors. -func (c *Config) SetupLogDir(logr *zap.SugaredLogger) error { - if logr == nil { +func (c *Config) SetupLogDir(logger *zap.SugaredLogger) error { + if logger == nil { return ErrZap } if c.LogDir == "" { @@ -178,7 +178,7 @@ func (c *Config) SetupLogDir(logr *zap.SugaredLogger) error { return fmt.Errorf("%w: %w", ErrLog, err) } } else { - logr.Info("The server logs are found in: ", c.LogDir) + logger.Info("The server logs are found in: ", c.LogDir) } dir, err := os.Stat(c.LogDir) if os.IsNotExist(err) { @@ -196,14 +196,14 @@ func (c *Config) SetupLogDir(logr *zap.SugaredLogger) error { defer func(f *os.File) { f.Close() if err := os.Remove(empty); err != nil { - logr.Warnf("Could not remove the empty test file in the log directory path: %s: %s", err, empty) + logger.Warnf("Could not remove the empty test file in the log directory path: %s: %s", err, empty) return } }(f) return nil } if err := os.Remove(empty); err != nil { - logr.Warnf("Could not remove the empty test file in the log directory path: %s: %s", err, empty) + logger.Warnf("Could not remove the empty test file in the log directory path: %s: %s", err, empty) } return nil } diff --git a/internal/config/config.go b/internal/config/config.go index ff8a6ee3..a29e2a44 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -70,7 +70,7 @@ const ( line = "─" donotuse = 7 down = "DownloadDir" - logr = "LogDir" + logger = "LogDir" prev = "PreviewDir" thumb = "ThumbnailDir" ) @@ -194,7 +194,7 @@ func dir(w *tabwriter.Writer, id, s string) { fmt.Fprintf(w, "\tNo preview images will be shown.\n") case thumb: fmt.Fprintf(w, "\tNo thumbnails will be shown.\n") - case logr: + case logger: fmt.Fprintf(w, "\tLogs will be printed to this terminal.\n") default: fmt.Fprintln(w) @@ -340,7 +340,7 @@ func (c Config) fmtField(w *tabwriter.Writer, nl(w) path(w, id, name, field) dir(w, id, c.ThumbnailDir) - case logr: + case logger: nl(w) path(w, id, name, field) dir(w, id, c.LogDir) @@ -362,7 +362,7 @@ func LocalSkip(name string) bool { "TLSPort", "HTTPSRedirect", "NoCrawl", - logr, + logger, "MaxProcs": return true } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 55d1bd57..01b98f4a 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -22,7 +22,7 @@ func td(name string) string { return x } -func logr() *zap.SugaredLogger { +func logger() *zap.SugaredLogger { return zap.NewExample().Sugar() } @@ -80,18 +80,18 @@ func TestConfig_Checks(t *testing.T) { c := config.Config{} err := c.Checks(nil) require.Error(t, err) - err = c.Checks(logr()) + err = c.Checks(logger()) require.NoError(t, err) c.HTTPPort = 8080 c.TLSPort = 8443 - err = c.Checks(logr()) + err = c.Checks(logger()) require.NoError(t, err) c.ReadMode = false c.ProductionMode = true require.NoError(t, err) - err = c.Checks(logr()) + err = c.Checks(logger()) require.NoError(t, err) } diff --git a/internal/config/error.go b/internal/config/error.go index 2f1993e9..fac34433 100644 --- a/internal/config/error.go +++ b/internal/config/error.go @@ -22,17 +22,17 @@ var ( ) // CustomErrorHandler handles customer error templates. -func (cfg Config) CustomErrorHandler(err error, c echo.Context) { +func (c Config) CustomErrorHandler(err error, ctx echo.Context) { logger := zaplog.Development().Sugar() - if cfg.ProductionMode { - root := cfg.LogDir + if c.ProductionMode { + root := c.LogDir logger = zaplog.Production(root).Sugar() } defer func() { _ = logger.Sync() }() - if IsHTML3(c.Path()) { - if err := html3.Error(c, err); err != nil { + if IsHTML3(ctx.Path()) { + if err := html3.Error(ctx, err); err != nil { logger.DPanic("Custom HTML3 response handler broke: %s", err) } return @@ -44,13 +44,13 @@ func (cfg Config) CustomErrorHandler(err error, c echo.Context) { statusCode = httpError.Code } errorPage := fmt.Sprintf("%d.html", statusCode) - if err := c.File(errorPage); err != nil { + if err := ctx.File(errorPage); err != nil { // fallback to a string error if templates break code, s, err1 := StringErr(err) if err1 != nil { logger.DPanic("Custom response handler broke: %s", err1) } - if err2 := c.String(code, s); err2 != nil { + if err2 := ctx.String(code, s); err2 != nil { logger.DPanic("Custom response handler broke: %s", err2) } } diff --git a/internal/config/repair.go b/internal/config/repair.go index 2e795785..1642ecc2 100644 --- a/internal/config/repair.go +++ b/internal/config/repair.go @@ -15,8 +15,8 @@ const ( // RepairFS, on startup check the file system directories for any invalid or unknown files. // If any are found, they are removed without warning. -func (c Config) RepairFS(logr *zap.SugaredLogger) error { - if logr == nil { +func (c Config) RepairFS(logger *zap.SugaredLogger) error { + if logger == nil { return ErrZap } dirs := []string{c.PreviewDir, c.ThumbnailDir} @@ -50,15 +50,15 @@ func (c Config) RepairFS(logr *zap.SugaredLogger) error { } switch dir { case c.PreviewDir: - logr.Infof("The preview directory contains, %d images: %s", p, dir) + logger.Infof("The preview directory contains, %d images: %s", p, dir) case c.ThumbnailDir: - logr.Infof("The thumb directory contains, %d images: %s", t, dir) + logger.Infof("The thumb directory contains, %d images: %s", t, dir) } } - return c.downloadFS(logr) + return c.downloadFS(logger) } -func (c Config) downloadFS(logr *zap.SugaredLogger) error { +func (c Config) downloadFS(logger *zap.SugaredLogger) error { dir := c.DownloadDir if _, err := os.Stat(dir); err != nil { var ignore error @@ -81,7 +81,7 @@ func (c Config) downloadFS(logr *zap.SugaredLogger) error { if err != nil { return err } - logr.Infof("The downloads directory contains, %d files: %s", d, dir) + logger.Infof("The downloads directory contains, %d files: %s", d, dir) return nil } diff --git a/model/file.go b/model/file.go index 8ef38b17..5e9cbf3a 100644 --- a/model/file.go +++ b/model/file.go @@ -3,6 +3,7 @@ package model import ( "context" "database/sql" + "encoding/hex" "errors" "fmt" "time" @@ -31,7 +32,7 @@ func ExistsHash(ctx context.Context, db *sql.DB, sha384 []byte) (bool, error) { if db == nil { return false, ErrDB } - hash := fmt.Sprintf("%x", sha384) + hash := hex.EncodeToString(sha384) // todo validate sha384 is not empty, is valid strong := null.String{String: hash, Valid: true} return models.Files(models.FileWhere.FileIntegrityStrong.EQ(strong), qm.WithDeleted()).Exists(ctx, db) diff --git a/model/scener.go b/model/scener.go index 6b252da4..f773991b 100644 --- a/model/scener.go +++ b/model/scener.go @@ -28,7 +28,7 @@ func (s *Scener) List(ctx context.Context, db *sql.DB, name string) (models.File } boil.DebugMode = true return models.Files( - qm.Where(string(postgres.ScenerSQL(name))), + qm.Where(postgres.ScenerSQL(name)), qm.OrderBy(ClauseOldDate), ).All(ctx, db) } diff --git a/server.go b/server.go index 2f3cccdb..a7889ced 100644 --- a/server.go +++ b/server.go @@ -81,7 +81,7 @@ func main() { website.Info() err := website.Start(router, configs) if err != nil { - logger.Fatalf("%s: please check the enviroment variables.", err) + logger.Fatalf("%s: please check the environment variables.", err) } w := os.Stdout