bootstrapped
This commit is contained in:
parent
5721ea14a9
commit
db69f3b519
36 changed files with 369 additions and 192 deletions
0
project/.gitignore → bootstrap/.gitignore
vendored
0
project/.gitignore → bootstrap/.gitignore
vendored
|
@ -41,11 +41,14 @@ live/sync_assets:
|
|||
dev:
|
||||
@make -j5 live/templ live/server live/tailwind live/sync_assets
|
||||
|
||||
reset:
|
||||
@GOOSE_DRIVER=postgres GOOSE_DBSTRING=$(dsn) goose -dir=$(migrationPath) reset
|
||||
db-status:
|
||||
GOOSE_DRIVER=$(DB_DRIVER) GOOSE_DBSTRING=$(DB_NAME) goose status
|
||||
|
||||
up:
|
||||
@GOOSE_DRIVER=postgres GOOSE_DBSTRING=$(dsn) goose -dir=$(migrationPath) up
|
||||
db-reset:
|
||||
@GOOSE_DRIVER=$(DB_DRIVER) GOOSE_DBSTRING=$(DB_NAME) goose -dir=$(MIGRATION_DIR) reset
|
||||
|
||||
seed:
|
||||
@go run scripts/seed/main.go
|
||||
db-up:
|
||||
@GOOSE_DRIVER=$(DB_DRIVER) GOOSE_DBSTRING=$(DB_NAME) goose -dir=$(MIGRATION_DIR) up
|
||||
|
||||
db-seed:
|
||||
@go run cmd/scripts/seed/main.go
|
3
bootstrap/app/conf/conf.go
Normal file
3
bootstrap/app/conf/conf.go
Normal file
|
@ -0,0 +1,3 @@
|
|||
package conf
|
||||
|
||||
// Application config
|
34
bootstrap/app/db/db.go
Normal file
34
bootstrap/app/db/db.go
Normal file
|
@ -0,0 +1,34 @@
|
|||
package db
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/anthdm/gothkit/pkg/db"
|
||||
"github.com/anthdm/gothkit/pkg/kit"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/dialect/sqlitedialect"
|
||||
"github.com/uptrace/bun/extra/bundebug"
|
||||
)
|
||||
|
||||
var Query *bun.DB
|
||||
|
||||
func init() {
|
||||
config := db.Config{
|
||||
Driver: os.Getenv("DB_DRIVER"),
|
||||
Name: os.Getenv("DB_NAME"),
|
||||
Password: os.Getenv("DB_PASSWORD"),
|
||||
User: os.Getenv("DB_USER"),
|
||||
Host: os.Getenv("DB_HOST"),
|
||||
}
|
||||
db, err := db.New(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
Query = bun.NewDB(db, sqlitedialect.New())
|
||||
if kit.IsDevelopment() {
|
||||
Query.AddQueryHook(bundebug.NewQueryHook(bundebug.WithVerbose(true)))
|
||||
}
|
||||
}
|
13
bootstrap/app/handlers/auth.go
Normal file
13
bootstrap/app/handlers/auth.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"example-app/app/types"
|
||||
|
||||
"github.com/anthdm/gothkit/pkg/kit"
|
||||
)
|
||||
|
||||
func HandleAuthentication(w http.ResponseWriter, r *http.Request) (kit.Auth, error) {
|
||||
return types.AuthUser{}, nil
|
||||
}
|
13
bootstrap/app/handlers/landing.go
Normal file
13
bootstrap/app/handlers/landing.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"example-app/app/db"
|
||||
"example-app/app/views/landing"
|
||||
|
||||
"github.com/anthdm/gothkit/pkg/kit"
|
||||
)
|
||||
|
||||
func HandleLandingIndex(kit *kit.Kit) error {
|
||||
db.Query.NewSelect().Scan(kit.Request.Context())
|
||||
return kit.Render(landing.Index())
|
||||
}
|
61
bootstrap/app/routes.go
Normal file
61
bootstrap/app/routes.go
Normal file
|
@ -0,0 +1,61 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"example-app/app/handlers"
|
||||
"example-app/app/views/errors"
|
||||
"log/slog"
|
||||
|
||||
"github.com/anthdm/gothkit/pkg/kit"
|
||||
"github.com/anthdm/gothkit/pkg/kit/middleware"
|
||||
"github.com/go-chi/chi/v5"
|
||||
|
||||
chimiddleware "github.com/go-chi/chi/v5/middleware"
|
||||
)
|
||||
|
||||
// Define your global middleware
|
||||
func InitializeMiddleware(router *chi.Mux) {
|
||||
router.Use(chimiddleware.Logger)
|
||||
router.Use(chimiddleware.Recoverer)
|
||||
router.Use(middleware.WithRequestURL)
|
||||
}
|
||||
|
||||
// Define your routes in here
|
||||
func InitializeRoutes(router *chi.Mux) {
|
||||
// Comment out to configure your authentication
|
||||
authConfig := kit.AuthenticationConfig{
|
||||
AuthFunc: handlers.HandleAuthentication,
|
||||
RedirectURL: "/login",
|
||||
}
|
||||
|
||||
// Routes that "might" have an authenticated user
|
||||
router.Group(func(app chi.Router) {
|
||||
app.Use(kit.WithAuthentication(authConfig, false)) // strict set to false
|
||||
|
||||
// Routes
|
||||
app.Get("/", kit.Handler(handlers.HandleLandingIndex))
|
||||
})
|
||||
|
||||
// Authenticated routes
|
||||
//
|
||||
// Routes that "must" have an authenticated user or else they
|
||||
// will be redirected to the configured redirectURL, set in the
|
||||
// AuthenticationConfig.
|
||||
router.Group(func(app chi.Router) {
|
||||
app.Use(kit.WithAuthentication(authConfig, true)) // strict set to true
|
||||
|
||||
// Routes
|
||||
// app.Get("/path", kit.Handler(myHandler.HandleIndex))
|
||||
})
|
||||
}
|
||||
|
||||
// NotFoundHandler that will be called when the requested path could
|
||||
// not be found.
|
||||
func NotFoundHandler(kit *kit.Kit) error {
|
||||
return kit.Render(errors.Error404())
|
||||
}
|
||||
|
||||
// ErrorHandler that will be called on errors return from application handlers.
|
||||
func ErrorHandler(kit *kit.Kit, err error) {
|
||||
slog.Error("internal server error", "err", err.Error(), "path", kit.Request.URL.Path)
|
||||
kit.Render(errors.Error500())
|
||||
}
|
14
bootstrap/app/types/auth.go
Normal file
14
bootstrap/app/types/auth.go
Normal file
|
@ -0,0 +1,14 @@
|
|||
package types
|
||||
|
||||
// AuthUser represents an user that might be authenticated.
|
||||
type AuthUser struct {
|
||||
ID int
|
||||
Email string
|
||||
LoggedIn bool
|
||||
}
|
||||
|
||||
// Check should return true if the user is authenticated.
|
||||
// See handlers/auth.go.
|
||||
func (user AuthUser) Check() bool {
|
||||
return user.ID > 0 && user.LoggedIn
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
package errors
|
||||
|
||||
import (
|
||||
"example-app/views/layouts"
|
||||
"example-app/app/views/layouts"
|
||||
)
|
||||
|
||||
templ Error400() {
|
||||
templ Error404() {
|
||||
@layouts.BaseLayout() {
|
||||
<div class="h-screen w-full flex flex-col justify-center align-middle items-center gap-4">
|
||||
<div class="text-muted-foreground text-5xl font-bold">404</div>
|
|
@ -1,6 +1,6 @@
|
|||
package errors
|
||||
|
||||
import "example-app/views/layouts"
|
||||
import "example-app/app/views/layouts"
|
||||
|
||||
templ Error500() {
|
||||
@layouts.BaseLayout() {
|
18
bootstrap/app/views/landing/index.templ
Normal file
18
bootstrap/app/views/landing/index.templ
Normal file
|
@ -0,0 +1,18 @@
|
|||
package landing
|
||||
|
||||
import (
|
||||
"github.com/anthdm/gothkit/pkg/view"
|
||||
"example-app/app/views/layouts"
|
||||
)
|
||||
|
||||
templ Index() {
|
||||
@layouts.App() {
|
||||
<div class="mt-20">
|
||||
<h1 class="text-3xl lg:text-6xl font-bold text-center">Ship stuff with small teams</h1>
|
||||
</div>
|
||||
<div>{ view.URL(ctx).Path }</div>
|
||||
if view.Auth(ctx).Check() {
|
||||
<div>You are authenticated</div>
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package layouts
|
||||
|
||||
import "example-app/views/components"
|
||||
import "example-app/app/views/components"
|
||||
|
||||
templ App() {
|
||||
@BaseLayout() {
|
|
@ -1,33 +1,30 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"log/slog"
|
||||
"example-app/app"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"example-app/db"
|
||||
|
||||
"github.com/anthdm/gothkit/pkg/kit"
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
func main() {
|
||||
db, err := db.New()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
_ = db
|
||||
|
||||
// Routes configuration
|
||||
router := chi.NewMux()
|
||||
if true {
|
||||
router.Handle("/*", disableCache(staticDev()))
|
||||
}
|
||||
initializeRoutes(router, db)
|
||||
|
||||
listenAddr := os.Getenv("HTTP_LISTEN_ADDR")
|
||||
slog.Info("application started", "listenAddr", listenAddr)
|
||||
app.InitializeMiddleware(router)
|
||||
|
||||
if kit.IsDevelopment() {
|
||||
router.Handle("/public/*", disableCache(staticDev()))
|
||||
}
|
||||
|
||||
kit.UseErrorHandler(app.ErrorHandler)
|
||||
router.HandleFunc("/*", kit.Handler(app.NotFoundHandler))
|
||||
|
||||
app.InitializeRoutes(router)
|
||||
|
||||
fmt.Printf("application running in %s at %s\n", kit.Env(), "http://localhost:7331")
|
||||
|
||||
http.ListenAndServe(os.Getenv("HTTP_LISTEN_ADDR"), router)
|
||||
}
|
7
bootstrap/cmd/scripts/seed/main.go
Normal file
7
bootstrap/cmd/scripts/seed/main.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Println("there are no seeds.")
|
||||
}
|
29
bootstrap/go.mod
Normal file
29
bootstrap/go.mod
Normal file
|
@ -0,0 +1,29 @@
|
|||
module example-app
|
||||
|
||||
go 1.22.0
|
||||
|
||||
require (
|
||||
github.com/anthdm/gothkit v0.0.0-00010101000000-000000000000
|
||||
github.com/go-chi/chi/v5 v5.0.12
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/fatih/color v1.16.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||
golang.org/x/sys v0.19.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/a-h/templ v0.2.707 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.22
|
||||
github.com/uptrace/bun v1.2.1
|
||||
github.com/uptrace/bun/dialect/sqlitedialect v1.2.1
|
||||
github.com/uptrace/bun/extra/bundebug v1.2.1
|
||||
)
|
||||
|
||||
replace github.com/anthdm/gothkit => ../gothkit
|
33
bootstrap/go.sum
Normal file
33
bootstrap/go.sum
Normal file
|
@ -0,0 +1,33 @@
|
|||
github.com/a-h/templ v0.2.707 h1:T1Gkd2ugbRglZ9rYw/VBchWOSZVKmetDbBkm4YubM7U=
|
||||
github.com/a-h/templ v0.2.707/go.mod h1:5cqsugkq9IerRNucNsI4DEamdHPsoGMQy99DzydLhM8=
|
||||
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
|
||||
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo=
|
||||
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs=
|
||||
github.com/uptrace/bun v1.2.1 h1:2ENAcfeCfaY5+2e7z5pXrzFKy3vS8VXvkCag6N2Yzfk=
|
||||
github.com/uptrace/bun v1.2.1/go.mod h1:cNg+pWBUMmJ8rHnETgf65CEvn3aIKErrwOD6IA8e+Ec=
|
||||
github.com/uptrace/bun/dialect/sqlitedialect v1.2.1 h1:IprvkIKUjEjvt4VKpcmLpbMIucjrsmUPJOSlg19+a0Q=
|
||||
github.com/uptrace/bun/dialect/sqlitedialect v1.2.1/go.mod h1:mMQf4NUpgY8bnOanxGmxNiHCdALOggS4cZ3v63a9D/o=
|
||||
github.com/uptrace/bun/extra/bundebug v1.2.1 h1:85MYpX3QESYI02YerKxUi1CD9mHuLrc2BXs1eOCtQus=
|
||||
github.com/uptrace/bun/extra/bundebug v1.2.1/go.mod h1:sfGKIi0HSGxsTC/sgIHGwpnYduHHYhdMeOIwurgSY+Y=
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
0
bootstrap/public/favicon.ico
Normal file
0
bootstrap/public/favicon.ico
Normal file
31
gothkit/pkg/db/db.go
Normal file
31
gothkit/pkg/db/db.go
Normal file
|
@ -0,0 +1,31 @@
|
|||
package db
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
DriverSqlite3 = "sqlite3"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Driver string
|
||||
Name string
|
||||
Host string
|
||||
User string
|
||||
Password string
|
||||
}
|
||||
|
||||
func New(cfg Config) (*sql.DB, error) {
|
||||
switch cfg.Driver {
|
||||
case DriverSqlite3:
|
||||
name := cfg.Name
|
||||
if len(name) == 0 {
|
||||
name = "app_db"
|
||||
}
|
||||
return sql.Open(cfg.Driver, name)
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid database driver (%s): currently only sqlite3 is supported", cfg.Driver)
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/a-h/templ"
|
||||
)
|
||||
|
@ -24,15 +25,14 @@ type Auth interface {
|
|||
}
|
||||
|
||||
var (
|
||||
auth Auth = defaultAuth{}
|
||||
errorHandler = func(kit *Kit, err error) {
|
||||
kit.Text(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
)
|
||||
|
||||
type defaultAuth struct{}
|
||||
type DefaultAuth struct{}
|
||||
|
||||
func (defaultAuth) Check() bool { return false }
|
||||
func (DefaultAuth) Check() bool { return false }
|
||||
|
||||
type Kit struct {
|
||||
Response http.ResponseWriter
|
||||
|
@ -40,19 +40,28 @@ type Kit struct {
|
|||
}
|
||||
|
||||
func UseErrorHandler(h ErrorHandlerFunc) { errorHandler = h }
|
||||
func SetAuth(a Auth) { auth = a }
|
||||
|
||||
func (kit *Kit) Auth() Auth {
|
||||
value, ok := kit.Request.Context().Value(AuthKey{}).(Auth)
|
||||
if !ok {
|
||||
slog.Warn("kit authentication not set")
|
||||
return auth
|
||||
return DefaultAuth{}
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func (kit *Kit) Redirect(status int, url string) {
|
||||
func (kit *Kit) Redirect(status int, url string) error {
|
||||
http.Redirect(kit.Response, kit.Request, url, status)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (kit *Kit) HXRedirect(status int, url string) error {
|
||||
if len(kit.Request.Header.Get("HX-Request")) > 0 {
|
||||
kit.Response.Header().Set("HX-Redirect", url)
|
||||
kit.Response.WriteHeader(http.StatusSeeOther)
|
||||
return nil
|
||||
}
|
||||
return kit.Redirect(status, url)
|
||||
}
|
||||
|
||||
func (kit *Kit) JSON(status int, v any) error {
|
||||
|
@ -123,3 +132,15 @@ func WithAuthentication(config AuthenticationConfig, strict bool) func(http.Hand
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func IsDevelopment() bool {
|
||||
return os.Getenv("KIT_ENV") == "development"
|
||||
}
|
||||
|
||||
func IsProduction() bool {
|
||||
return os.Getenv("KIT_ENV") == "production"
|
||||
}
|
||||
|
||||
func Env() string {
|
||||
return os.Getenv("KIT_ENV")
|
||||
}
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
package middleware
|
||||
|
||||
// func Authenticated(next http.Handler) http.Handler {
|
||||
// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// kit := &kit.Kit{
|
||||
// Response: w,
|
||||
// Request: r,
|
||||
// }
|
||||
// if !kit.Auth().LoggedIn {
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// }
|
||||
// next.ServeHTTP(w, r.WithContext(ctx))
|
||||
// })
|
||||
// }
|
||||
type RequestURLKey struct{}
|
||||
|
||||
func WithRequestURL(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := context.WithValue(r.Context(), RequestURLKey{}, r.URL)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
|
|
31
gothkit/pkg/view/view.go
Normal file
31
gothkit/pkg/view/view.go
Normal file
|
@ -0,0 +1,31 @@
|
|||
package view
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
|
||||
"github.com/anthdm/gothkit/pkg/kit"
|
||||
"github.com/anthdm/gothkit/pkg/kit/middleware"
|
||||
)
|
||||
|
||||
// Auth is a view helper function that returns the currency Auth.
|
||||
// If Auth is not set a default auth will be returned
|
||||
func Auth(ctx context.Context) kit.Auth {
|
||||
value, ok := ctx.Value(kit.AuthKey{}).(kit.Auth)
|
||||
if !ok {
|
||||
return kit.DefaultAuth{}
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// URL is a view helper that returns the current URL.
|
||||
// The request path can be acccessed with:
|
||||
// view.URL(ctx).Path
|
||||
func URL(ctx context.Context) *url.URL {
|
||||
value, ok := ctx.Value(middleware.RequestURLKey{}).(*url.URL)
|
||||
if !ok {
|
||||
return &url.URL{}
|
||||
}
|
||||
return value
|
||||
|
||||
}
|
15
install.sh
15
install.sh
|
@ -1 +1,14 @@
|
|||
echo "this is working fine"
|
||||
#!/bin/bash
|
||||
|
||||
echo "enter the name of you project: "
|
||||
read varname
|
||||
|
||||
git clone git@github.com:anthdm/gothkit.git _gothkit
|
||||
cd _gothkit
|
||||
mv bootstrap ../$varname
|
||||
cd ..
|
||||
rm -rf _gothkit
|
||||
echo ""
|
||||
echo "project installed successfully"
|
||||
echo "your project folder is available => cd $varname"
|
||||
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"github.com/anthdm/gothkit/pkg/kit"
|
||||
"github.com/go-chi/chi/v5"
|
||||
|
||||
"example-app/handlers"
|
||||
"example-app/views/errors"
|
||||
)
|
||||
|
||||
// Define your routes in here
|
||||
func initializeRoutes(router *chi.Mux, db *sql.DB) {
|
||||
// Configure the error handler
|
||||
kit.UseErrorHandler(func(kit *kit.Kit, err error) {
|
||||
slog.Error("internal server error", "err", err.Error(), "path", kit.Request.URL.Path)
|
||||
kit.Render(errors.Error500())
|
||||
})
|
||||
|
||||
// Comment out to configure your authentication
|
||||
authConfig := kit.AuthenticationConfig{
|
||||
AuthFunc: handleAuthentication,
|
||||
RedirectURL: "/login",
|
||||
}
|
||||
|
||||
landingHandler := handlers.NewLandingHandler(db)
|
||||
// Routes that "might" have an authenticated user
|
||||
router.Group(func(app chi.Router) {
|
||||
app.Use(kit.WithAuthentication(authConfig, false)) // strict set to false
|
||||
|
||||
// Routes
|
||||
app.Get("/", kit.Handler(landingHandler.HandleIndex))
|
||||
})
|
||||
|
||||
// Routes that "must" have an authenticated user or else they
|
||||
// will be redirected to the configured redirectURL, set in the
|
||||
// AuthenticationConfig.
|
||||
router.Group(func(app chi.Router) {
|
||||
app.Use(kit.WithAuthentication(authConfig, true)) // strict set to true
|
||||
|
||||
// Routes
|
||||
// app.Get("/path", kit.Handler(myHandler.HandleIndex))
|
||||
})
|
||||
}
|
||||
|
||||
type AuthUser struct {
|
||||
ID int
|
||||
Email string
|
||||
LoggedIn bool
|
||||
}
|
||||
|
||||
func (user AuthUser) Check() bool {
|
||||
return user.ID > 0 && user.LoggedIn
|
||||
}
|
||||
|
||||
func handleAuthentication(w http.ResponseWriter, r *http.Request) (kit.Auth, error) {
|
||||
return AuthUser{}, nil
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package db
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
const (
|
||||
DriverSqlite3 = "sqlite3"
|
||||
)
|
||||
|
||||
func New() (*sql.DB, error) {
|
||||
driver := os.Getenv("DB_DRIVER")
|
||||
|
||||
switch driver {
|
||||
case DriverSqlite3:
|
||||
name := os.Getenv("DB_NAME")
|
||||
if len(name) == 0 {
|
||||
name = "gothkit"
|
||||
}
|
||||
return sql.Open(driver, name)
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid database driver (%s): currently only sqlite3 is supported", driver)
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
module example-app
|
||||
|
||||
go 1.22.0
|
||||
|
||||
require (
|
||||
github.com/anthdm/gothkit v0.0.0-00010101000000-000000000000
|
||||
github.com/go-chi/chi/v5 v5.0.12
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/a-h/templ v0.2.707 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.22
|
||||
)
|
||||
|
||||
replace github.com/anthdm/gothkit => ../gothkit
|
|
@ -1,8 +0,0 @@
|
|||
github.com/a-h/templ v0.2.707 h1:T1Gkd2ugbRglZ9rYw/VBchWOSZVKmetDbBkm4YubM7U=
|
||||
github.com/a-h/templ v0.2.707/go.mod h1:5cqsugkq9IerRNucNsI4DEamdHPsoGMQy99DzydLhM8=
|
||||
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
|
||||
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
|
@ -1,22 +0,0 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"example-app/views/landing"
|
||||
|
||||
"github.com/anthdm/gothkit/pkg/kit"
|
||||
)
|
||||
|
||||
type LandingHandler struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func NewLandingHandler(db *sql.DB) *LandingHandler {
|
||||
return &LandingHandler{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *LandingHandler) HandleIndex(kit *kit.Kit) error {
|
||||
return kit.Render(landing.Index())
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package landing
|
||||
|
||||
import "example-app/views/layouts"
|
||||
|
||||
templ Index() {
|
||||
@layouts.App() {
|
||||
<div class="mt-20">
|
||||
<h1 class="text-3xl lg:text-6xl font-bold text-center">Ship stuff with small teams</h1>
|
||||
</div>
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue