Compare commits
No commits in common. "v2/refactor/routing" and "main" have entirely different histories.
v2/refacto
...
main
@ -4,8 +4,8 @@ tmp_dir = "tmp"
|
|||||||
|
|
||||||
[build]
|
[build]
|
||||||
args_bin = []
|
args_bin = []
|
||||||
bin = "./air-bin"
|
bin = "./tmp/main"
|
||||||
cmd = "go build -o ./air-bin ./cmd/"
|
cmd = "go build -o ./tmp/main ./cmd/"
|
||||||
delay = 1000
|
delay = 1000
|
||||||
exclude_dir = ["public", "data", "tmp"]
|
exclude_dir = ["public", "data", "tmp"]
|
||||||
exclude_file = []
|
exclude_file = []
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,4 +10,3 @@ tmp/*
|
|||||||
data/*
|
data/*
|
||||||
data/database.db
|
data/database.db
|
||||||
.idea
|
.idea
|
||||||
air-bin
|
|
||||||
|
19
app/app.go
19
app/app.go
@ -1,19 +0,0 @@
|
|||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/app/routing"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/app/server"
|
|
||||||
)
|
|
||||||
|
|
||||||
type IApp interface {
|
|
||||||
Serve()
|
|
||||||
}
|
|
||||||
|
|
||||||
type App struct {
|
|
||||||
Router routing.IRouter
|
|
||||||
Server server.IServer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a App) Serve() {
|
|
||||||
a.Server.ListenAndServe()
|
|
||||||
}
|
|
@ -1,106 +0,0 @@
|
|||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/app/session"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/logger"
|
|
||||||
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/database"
|
|
||||||
)
|
|
||||||
|
|
||||||
type IController interface {
|
|
||||||
Get(w http.ResponseWriter, r *http.Request) error
|
|
||||||
Head(w http.ResponseWriter, r *http.Request) error
|
|
||||||
Options(w http.ResponseWriter, r *http.Request) error
|
|
||||||
Trace(w http.ResponseWriter, r *http.Request) error
|
|
||||||
Put(w http.ResponseWriter, r *http.Request) error
|
|
||||||
Delete(w http.ResponseWriter, r *http.Request) error
|
|
||||||
Post(w http.ResponseWriter, r *http.Request) error
|
|
||||||
Patch(w http.ResponseWriter, r *http.Request) error
|
|
||||||
Connect(w http.ResponseWriter, r *http.Request) error
|
|
||||||
Init(session.IManager, database.IDB, logger.ILogger, IControllerCtx) IController
|
|
||||||
}
|
|
||||||
|
|
||||||
type Controller struct {
|
|
||||||
Session session.IManager
|
|
||||||
Db database.IDB
|
|
||||||
Logger logger.ILogger
|
|
||||||
Ctx IControllerCtx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Controller) Init(s session.IManager, d database.IDB, l logger.ILogger, ctx IControllerCtx) IController {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Controller) Get(w http.ResponseWriter, _ *http.Request) (_ error) {
|
|
||||||
if _, err := w.Write([]byte("not implemented")); err != nil {
|
|
||||||
c.Logger.Error(c.Logger.Wrap(err, "Error writing response"))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Controller) Head(w http.ResponseWriter, _ *http.Request) (_ error) {
|
|
||||||
if _, err := w.Write([]byte("not implemented")); err != nil {
|
|
||||||
c.Logger.Error(c.Logger.Wrap(err, "Error writing response"))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Controller) Options(w http.ResponseWriter, _ *http.Request) (_ error) {
|
|
||||||
if _, err := w.Write([]byte("not implemented")); err != nil {
|
|
||||||
c.Logger.Error(c.Logger.Wrap(err, "Error writing response"))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Controller) Trace(w http.ResponseWriter, _ *http.Request) (_ error) {
|
|
||||||
if _, err := w.Write([]byte("not implemented")); err != nil {
|
|
||||||
c.Logger.Error(c.Logger.Wrap(err, "Error writing response"))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Controller) Put(w http.ResponseWriter, _ *http.Request) (_ error) {
|
|
||||||
if _, err := w.Write([]byte("not implemented")); err != nil {
|
|
||||||
c.Logger.Error(c.Logger.Wrap(err, "Error writing response"))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Controller) Delete(w http.ResponseWriter, _ *http.Request) (_ error) {
|
|
||||||
if _, err := w.Write([]byte("not implemented")); err != nil {
|
|
||||||
c.Logger.Error(c.Logger.Wrap(err, "Error writing response"))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Controller) Post(w http.ResponseWriter, _ *http.Request) (_ error) {
|
|
||||||
if _, err := w.Write([]byte("not implemented")); err != nil {
|
|
||||||
c.Logger.Error(c.Logger.Wrap(err, "Error writing response"))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Controller) Patch(w http.ResponseWriter, _ *http.Request) (_ error) {
|
|
||||||
if _, err := w.Write([]byte("not implemented")); err != nil {
|
|
||||||
c.Logger.Error(c.Logger.Wrap(err, "Error writing response"))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Controller) Connect(w http.ResponseWriter, _ *http.Request) (_ error) {
|
|
||||||
if _, err := w.Write([]byte("not implemented")); err != nil {
|
|
||||||
c.Logger.Error(c.Logger.Wrap(err, "Error writing response"))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
package controller
|
|
||||||
|
|
||||||
type IRouterCtx interface {
|
|
||||||
GetRouteByName(string) (string, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type IControllerCtx interface {
|
|
||||||
GetRouteByName(string) string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ControllerCtx struct {
|
|
||||||
RouterCtx IRouterCtx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c ControllerCtx) GetRouteByName(name string) string {
|
|
||||||
path, err := c.RouterCtx.GetRouteByName(name)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return path
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
package handler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HandlerFunc func(http.ResponseWriter, *http.Request) error
|
|
||||||
|
|
||||||
func (fn HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if err := fn(w, r); err != nil {
|
|
||||||
w.Header().Set("HX-Retarget", "#layout_content")
|
|
||||||
w.Header().Set("HX-Reswap", "innerHTML")
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,125 +0,0 @@
|
|||||||
package routing
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"net/http"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/app/controller"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/app/handler"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/app/session"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/database"
|
|
||||||
werror "git.markbailey.dev/cerbervs/ptpp/lib/error"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/logger"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/middleware"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
type IRouter interface {
|
|
||||||
RegisterRoutes() http.Handler
|
|
||||||
}
|
|
||||||
|
|
||||||
type Route struct {
|
|
||||||
Controller controller.IController
|
|
||||||
Path string
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Router struct {
|
|
||||||
Mux *http.ServeMux
|
|
||||||
Middleware *[]middleware.Func
|
|
||||||
BasePath string
|
|
||||||
SubRouters []*Router
|
|
||||||
Routes []Route
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
rtr *Router
|
|
||||||
rtrOnce sync.Once
|
|
||||||
mux *http.ServeMux
|
|
||||||
muxOnce sync.Once
|
|
||||||
fsOnce sync.Once
|
|
||||||
sess session.IManager
|
|
||||||
)
|
|
||||||
|
|
||||||
func (r *Router) HandleAllRequestMethods(route Route, fullPath string) {
|
|
||||||
ctx := controller.ControllerCtx{RouterCtx: rtr}
|
|
||||||
c := route.Controller.Init(sess, database.ChooseDB(), logger.NewCompositeLogger(), ctx)
|
|
||||||
r.Mux.Handle("GET "+fullPath, handler.HandlerFunc(c.Get))
|
|
||||||
r.Mux.Handle("OPTIONS "+fullPath, handler.HandlerFunc(c.Options))
|
|
||||||
r.Mux.Handle("TRACE "+fullPath, handler.HandlerFunc(c.Trace))
|
|
||||||
r.Mux.Handle("PUT "+fullPath, handler.HandlerFunc(c.Put))
|
|
||||||
r.Mux.Handle("DELETE "+fullPath, handler.HandlerFunc(c.Delete))
|
|
||||||
r.Mux.Handle("POST "+fullPath, handler.HandlerFunc(c.Post))
|
|
||||||
r.Mux.Handle("PATCH "+fullPath, handler.HandlerFunc(c.Patch))
|
|
||||||
r.Mux.Handle("CONNECT "+fullPath, handler.HandlerFunc(c.Connect))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Router) RegisterRoutes() http.Handler {
|
|
||||||
rtrOnce.Do(func() { rtr = r })
|
|
||||||
muxOnce.Do(func() { mux = http.NewServeMux(); r.Mux = mux })
|
|
||||||
fsOnce.Do(func() { r.RegisterFs() })
|
|
||||||
|
|
||||||
if r.Mux == nil {
|
|
||||||
r.Mux = http.NewServeMux()
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, route := range r.Routes {
|
|
||||||
r.HandleAllRequestMethods(route, r.BasePath+route.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, subRouter := range r.SubRouters {
|
|
||||||
r.Mux.Handle(
|
|
||||||
"GET "+r.BasePath+subRouter.BasePath,
|
|
||||||
http.StripPrefix(subRouter.BasePath, subRouter.RegisterRoutes()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.Middleware != nil {
|
|
||||||
mw := middleware.Compose(*r.Middleware)
|
|
||||||
mctx := middleware.MiddlewareCtx{RouterCtx: rtr}
|
|
||||||
return mw(mux, mctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
return mux
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Router) RegisterFs() {
|
|
||||||
fs := http.FileServer(http.Dir(util.GetFullyQualifiedPath("/public")))
|
|
||||||
r.Mux.Handle("GET "+r.BasePath+"public/", http.StripPrefix("/public/", fs))
|
|
||||||
}
|
|
||||||
|
|
||||||
type RouteMapping struct {
|
|
||||||
Path string
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Router) GetFlatRouteList() []RouteMapping {
|
|
||||||
routes := []RouteMapping{}
|
|
||||||
for _, route := range r.Routes {
|
|
||||||
routes = append(routes, RouteMapping{Path: r.BasePath + route.Path, Name: route.Name})
|
|
||||||
}
|
|
||||||
for _, subRouter := range r.SubRouters {
|
|
||||||
routes = append(routes, subRouter.GetFlatRouteList()...)
|
|
||||||
}
|
|
||||||
return routes
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Router) GetRouteByName(name string) (string, error) {
|
|
||||||
for _, route := range r.GetFlatRouteList() {
|
|
||||||
if route.Name == name {
|
|
||||||
return route.Path, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", werror.Wrap(errors.New(name+" does not exist"), "Route not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
sess, err = session.NewManager("memory", "ptpp", 3600)
|
|
||||||
go sess.GC()
|
|
||||||
if err != nil {
|
|
||||||
panic(werror.Wrap(err, "Error creating session manager"))
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
package routing
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/handlers/admin"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/handlers/shared"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/middleware"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
rtrinst *Router
|
|
||||||
rtrinstOnce sync.Once
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewRouter() *Router {
|
|
||||||
rtrinstOnce.Do(func() {
|
|
||||||
rtrinst = &Router{
|
|
||||||
Mux: nil,
|
|
||||||
BasePath: "/",
|
|
||||||
Routes: []Route{
|
|
||||||
{Controller: shared.HomePageController{}, Path: "", Name: "app.index"},
|
|
||||||
{Controller: shared.SignUpHandler{}, Path: "sign-up", Name: "app.user.sign_up"},
|
|
||||||
{Controller: shared.SignInHandler{}, Path: "sign-in", Name: "app.user.sign_in"},
|
|
||||||
{Controller: shared.SignOutHandler{}, Path: "sign-out", Name: "app.user.sign_out"},
|
|
||||||
{Controller: shared.PopulateHandler{}, Path: "populate", Name: "app.populate"},
|
|
||||||
},
|
|
||||||
SubRouters: []*Router{
|
|
||||||
{
|
|
||||||
Mux: nil,
|
|
||||||
BasePath: "admin/",
|
|
||||||
Routes: []Route{
|
|
||||||
{Controller: admin.IndexHandler{}, Path: "", Name: "app.admin.index"},
|
|
||||||
{Controller: admin.IndexHandler{}, Path: "butt", Name: "app.admin.butt"},
|
|
||||||
},
|
|
||||||
SubRouters: nil,
|
|
||||||
Middleware: &[]middleware.Func{middleware.WithAuth},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Middleware: &[]middleware.Func{middleware.DontPanic, middleware.WithLogger, middleware.WithUsername},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return rtrinst
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
type IServer interface {
|
|
||||||
ListenAndServe()
|
|
||||||
}
|
|
||||||
|
|
||||||
type Server struct {
|
|
||||||
Addr string
|
|
||||||
Server http.Server
|
|
||||||
Port int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) ListenAndServe() {
|
|
||||||
s.Addr = s.Addr + ":" + strconv.Itoa(s.Port)
|
|
||||||
serverError := s.Server.ListenAndServe()
|
|
||||||
if serverError != nil {
|
|
||||||
log.Fatal(serverError)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
package session
|
|
2
bin/app
2
bin/app
@ -290,7 +290,6 @@ __sqlc() {
|
|||||||
echo ================================================================================
|
echo ================================================================================
|
||||||
echo = Generating SQLC ==============================================================
|
echo = Generating SQLC ==============================================================
|
||||||
echo ================================================================================
|
echo ================================================================================
|
||||||
rm -rf ./models/*
|
|
||||||
sqlc generate
|
sqlc generate
|
||||||
echo -e "\n"
|
echo -e "\n"
|
||||||
}
|
}
|
||||||
@ -299,7 +298,6 @@ __templ() {
|
|||||||
echo ================================================================================
|
echo ================================================================================
|
||||||
echo = Generating templates =========================================================
|
echo = Generating templates =========================================================
|
||||||
echo ================================================================================
|
echo ================================================================================
|
||||||
find . -name '*_templ.go' -delete
|
|
||||||
templ generate
|
templ generate
|
||||||
echo -e "\n"
|
echo -e "\n"
|
||||||
}
|
}
|
||||||
|
71
cmd/main.go
71
cmd/main.go
@ -1,75 +1,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
inf "git.markbailey.dev/cervers/ptpp/infrastructure"
|
||||||
"net/http"
|
_ "git.markbailey.dev/cervers/ptpp/lib/session/memory"
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/app"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/app/routing"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/app/server"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/logger"
|
|
||||||
|
|
||||||
_ "git.markbailey.dev/cerbervs/ptpp/app/session"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
const (
|
inf.NewServer().Serve()
|
||||||
addr = "0.0.0.0"
|
|
||||||
prodPort = 8080
|
|
||||||
devPort = 8080
|
|
||||||
)
|
|
||||||
|
|
||||||
logger := logger.NewCompositeLogger()
|
|
||||||
|
|
||||||
r := routing.NewRouter()
|
|
||||||
mux := r.RegisterRoutes()
|
|
||||||
|
|
||||||
rl := r.GetFlatRouteList()
|
|
||||||
for _, route := range rl {
|
|
||||||
path, err := r.GetRouteByName(route.Name)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(fmt.Errorf(fmt.Sprintf("Error getting route by name: %s", route.Name)))
|
|
||||||
}
|
|
||||||
logger.Info(fmt.Sprintf("Name: %s, Path: %s", route.Name, path))
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Info(fmt.Sprintf("%+v", mux))
|
|
||||||
|
|
||||||
var port int
|
|
||||||
if os.Getenv("HTMX_APP_ENV") == "production" {
|
|
||||||
port = prodPort
|
|
||||||
} else {
|
|
||||||
port = devPort
|
|
||||||
}
|
|
||||||
|
|
||||||
s := server.Server{
|
|
||||||
Addr: addr,
|
|
||||||
Server: http.Server{
|
|
||||||
Addr: addr + ":" + strconv.Itoa(port),
|
|
||||||
Handler: mux,
|
|
||||||
DisableGeneralOptionsHandler: false,
|
|
||||||
TLSConfig: nil,
|
|
||||||
ReadTimeout: 5 * time.Second,
|
|
||||||
ReadHeaderTimeout: 0,
|
|
||||||
WriteTimeout: 5 * time.Second,
|
|
||||||
IdleTimeout: 0,
|
|
||||||
MaxHeaderBytes: 0,
|
|
||||||
TLSNextProto: nil,
|
|
||||||
ConnState: nil,
|
|
||||||
ErrorLog: nil,
|
|
||||||
BaseContext: nil,
|
|
||||||
ConnContext: nil,
|
|
||||||
},
|
|
||||||
Port: port,
|
|
||||||
}
|
|
||||||
|
|
||||||
a := app.App{
|
|
||||||
Router: r,
|
|
||||||
Server: &s,
|
|
||||||
}
|
|
||||||
|
|
||||||
a.Serve()
|
|
||||||
}
|
}
|
||||||
|
4
go.mod
4
go.mod
@ -1,6 +1,6 @@
|
|||||||
module git.markbailey.dev/cerbervs/ptpp
|
module git.markbailey.dev/cervers/ptpp
|
||||||
|
|
||||||
go 1.23
|
go 1.23.2
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/a-h/templ v0.2.793
|
github.com/a-h/templ v0.2.793
|
||||||
|
@ -3,35 +3,32 @@ package admin
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/app/controller"
|
"git.markbailey.dev/cervers/ptpp/view/layout"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/app/session"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/database"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/logger"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/view/layout"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/view/admin"
|
"git.markbailey.dev/cervers/ptpp/lib/logger"
|
||||||
|
"git.markbailey.dev/cervers/ptpp/lib/session"
|
||||||
|
"git.markbailey.dev/cervers/ptpp/view/admin"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexHandler struct {
|
type IndexHandler struct {
|
||||||
controller.Controller
|
logger logger.ILogger
|
||||||
|
session session.IManager
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h IndexHandler) Init(s session.IManager, d database.IDB, l logger.ILogger, ctx controller.IControllerCtx) controller.IController {
|
func NewAdminIndexHandler(l logger.ILogger, s session.IManager) *IndexHandler {
|
||||||
h.Logger = l
|
return &IndexHandler{
|
||||||
h.Db = d
|
logger: l,
|
||||||
h.Session = s
|
session: s,
|
||||||
h.Ctx = ctx
|
}
|
||||||
|
|
||||||
return h
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h IndexHandler) Get(w http.ResponseWriter, r *http.Request) error {
|
func (h IndexHandler) Index(w http.ResponseWriter, r *http.Request) error {
|
||||||
if r.URL.Path != "/" {
|
if r.URL.Path != "/" {
|
||||||
w.WriteHeader(http.StatusNotFound)
|
w.WriteHeader(http.StatusNotFound)
|
||||||
err := layout.NotFound().Render(context.Background(), w)
|
err := layout.NotFound().Render(context.Background(), w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.Logger.Error(h.Logger.Wrap(err, "Error rendering 404 page"))
|
h.logger.Error(h.logger.Wrap(err, "Error rendering 404 page"))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -40,12 +37,12 @@ func (h IndexHandler) Get(w http.ResponseWriter, r *http.Request) error {
|
|||||||
username, ok := r.Context().Value("username").(string)
|
username, ok := r.Context().Value("username").(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
err := errors.New("cannot decode request context: for key \"username\"")
|
err := errors.New("cannot decode request context: for key \"username\"")
|
||||||
h.Logger.Error(h.Logger.Wrap(err, "Error decoding request context"))
|
h.logger.Error(h.logger.Wrap(err, "Error decoding request context"))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := admin.Index(username).Render(context.Background(), w); err != nil {
|
if err := admin.Index(username).Render(context.Background(), w); err != nil {
|
||||||
h.Logger.Error(h.Logger.Wrap(err, "Error rendering admin index page"))
|
h.logger.Error(h.logger.Wrap(err, "Error rendering admin index page"))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
40
handlers/homepage.go
Normal file
40
handlers/homepage.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"git.markbailey.dev/cervers/ptpp/view/layout"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"git.markbailey.dev/cervers/ptpp/lib/logger"
|
||||||
|
"git.markbailey.dev/cervers/ptpp/view/homepage"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HomePageHandler struct {
|
||||||
|
logger logger.ILogger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHomePageHandler(l logger.ILogger) *HomePageHandler {
|
||||||
|
return &HomePageHandler{
|
||||||
|
logger: l,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h HomePageHandler) Homepage(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
if r.URL.Path != "/" {
|
||||||
|
w.WriteHeader(http.StatusNotFound)
|
||||||
|
err := layout.NotFound().Render(context.Background(), w)
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error(h.logger.Wrap(err, "Error rendering 404 page"))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := homepage.Homepage(os.Getenv("$HTMX_APP_ENV")).Render(context.Background(), w); err != nil {
|
||||||
|
h.logger.Error(h.logger.Wrap(err, "Error rendering homepage"))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,46 +0,0 @@
|
|||||||
package shared
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/app/controller"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/app/session"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/database"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/logger"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/view/layout"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/view/homepage"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HomePageController struct {
|
|
||||||
controller.Controller
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *HomePageController) Init(s session.IManager, d database.IDB, l logger.ILogger, ctx controller.IControllerCtx) controller.IController {
|
|
||||||
c.Logger = l
|
|
||||||
c.Db = d
|
|
||||||
c.Session = s
|
|
||||||
c.Ctx = ctx
|
|
||||||
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h HomePageController) Get(w http.ResponseWriter, r *http.Request) error {
|
|
||||||
if r.URL.Path != "/" {
|
|
||||||
w.WriteHeader(http.StatusNotFound)
|
|
||||||
err := layout.NotFound().Render(context.Background(), w)
|
|
||||||
if err != nil {
|
|
||||||
h.Logger.Error(h.Logger.Wrap(err, "Error rendering 404 page"))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := homepage.Homepage(os.Getenv("$HTMX_APP_ENV"), h.Ctx).Render(context.Background(), w); err != nil {
|
|
||||||
h.Logger.Error(h.Logger.Wrap(err, "Error rendering homepage"))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,361 +0,0 @@
|
|||||||
package shared
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/app/controller"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/app/session"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/database"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/database/dto"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/logger"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/util"
|
|
||||||
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/view/user"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PopulateHandler struct {
|
|
||||||
controller.Controller
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c PopulateHandler) Init(s session.IManager, d database.IDB, l logger.ILogger, ctx controller.IControllerCtx) controller.IController {
|
|
||||||
c.Logger = l
|
|
||||||
c.Db = d
|
|
||||||
c.Session = s
|
|
||||||
c.Ctx = ctx
|
|
||||||
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c PopulateHandler) Get(w http.ResponseWriter, r *http.Request) error {
|
|
||||||
existingOrg, err := c.Db.Repo().FindOrganizationByName("CerbervsSoft")
|
|
||||||
if existingOrg != nil && err == nil {
|
|
||||||
return util.Redirect(w, r, c.Ctx.GetRouteByName("app.user.sign_up"), http.StatusSeeOther, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
authToken, err := util.CreateTokenForUser("CerbervsSoft")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
organization := dto.Organization{
|
|
||||||
Name: "CerbervsSoft",
|
|
||||||
OwnerName: "Mark Bailey",
|
|
||||||
OwnerEmail: "email@provider.com",
|
|
||||||
OwnerPhone: "+11111111111",
|
|
||||||
Authorized: 1,
|
|
||||||
AuthToken: authToken,
|
|
||||||
CreatedAt: time.Now(),
|
|
||||||
}
|
|
||||||
_, err = c.Db.Repo().CreateOrganization(organization)
|
|
||||||
if err != nil {
|
|
||||||
c.Db.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return util.Redirect(w, r, c.Ctx.GetRouteByName("app.user.sign_up"), http.StatusSeeOther, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
type SignInHandler struct {
|
|
||||||
controller.Controller
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c SignInHandler) Init(s session.IManager, d database.IDB, l logger.ILogger, ctx controller.IControllerCtx) controller.IController {
|
|
||||||
c.Logger = l
|
|
||||||
c.Db = d
|
|
||||||
c.Session = s
|
|
||||||
c.Ctx = ctx
|
|
||||||
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
type UserSignInForm struct {
|
|
||||||
Username string `json:"username"`
|
|
||||||
Password string `json:"password"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c SignInHandler) Get(w http.ResponseWriter, r *http.Request) error {
|
|
||||||
sess := c.Session.SessionStart(w, r)
|
|
||||||
|
|
||||||
username, ok := r.Context().Value("username").(string)
|
|
||||||
if ok {
|
|
||||||
if username == "" {
|
|
||||||
return failWithFormError(w, r, "Invalid Username or Password.", sess)
|
|
||||||
} else {
|
|
||||||
foundUser, err := c.Db.Repo().FindUserByUsername(username)
|
|
||||||
if foundUser == nil || err != nil {
|
|
||||||
return failWithFormError(w, r, "Invalid Username or Password.", sess)
|
|
||||||
}
|
|
||||||
|
|
||||||
if foundUser.Admin == 1 {
|
|
||||||
return util.Redirect(w, r, c.Ctx.GetRouteByName("app.admin.index"), http.StatusSeeOther, false)
|
|
||||||
} else {
|
|
||||||
return util.Redirect(w, r, c.Ctx.GetRouteByName("app.index"), http.StatusSeeOther, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
formError, ok := sess.Get("formError").(string)
|
|
||||||
if !ok {
|
|
||||||
formError = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := user.SignIn(formError, c.Ctx).Render(context.Background(), w); err != nil {
|
|
||||||
c.Logger.Error(c.Logger.Wrap(err, "Error rendering sign in form"))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c SignInHandler) Post(w http.ResponseWriter, r *http.Request) error {
|
|
||||||
sess := c.Session.SessionStart(w, r)
|
|
||||||
|
|
||||||
fd := &UserSignInForm{}
|
|
||||||
|
|
||||||
jsonDecoder := json.NewDecoder(r.Body)
|
|
||||||
if err := jsonDecoder.Decode(&fd); err != nil {
|
|
||||||
c.Logger.Error(c.Logger.Wrap(err, "Error decoding JSON"))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
foundUser, err := c.Db.Repo().FindUserByUsername(fd.Username)
|
|
||||||
if foundUser == nil || err != nil {
|
|
||||||
return util.Redirect(w, r, c.Ctx.GetRouteByName("app.user.sign_in"), http.StatusPermanentRedirect, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
authenticated, err := util.CheckPassword(fd.Password, foundUser.Password)
|
|
||||||
if err != nil || !authenticated {
|
|
||||||
return failWithFormError(w, r, "Invalid Username or Password.", sess)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = sess.Set("username", foundUser.Username)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
token, err := util.CreateTokenForUser(foundUser.Username)
|
|
||||||
if err != nil {
|
|
||||||
c.Logger.Error(c.Logger.Wrap(err, "Error creating token"))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = sess.Set("token", token)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authToken, err := util.CreateTokenForUser(foundUser.Username)
|
|
||||||
if err != nil {
|
|
||||||
c.Logger.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = c.Db.Repo().CreateHeartbeat(&dto.Heartbeat{
|
|
||||||
User: foundUser.Identifier,
|
|
||||||
CreatedAt: time.Now(),
|
|
||||||
IpAddr: r.RemoteAddr,
|
|
||||||
AuthToken: authToken,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
c.Db.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
jwtToken, err := util.CreateTokenForUser(fd.Username)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
http.SetCookie(w, &http.Cookie{
|
|
||||||
Name: "token",
|
|
||||||
Value: jwtToken,
|
|
||||||
Expires: time.Now().Add(time.Hour * 1),
|
|
||||||
Path: "/",
|
|
||||||
})
|
|
||||||
|
|
||||||
err = sess.Delete("formError")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Logger.Info(foundUser.Username + " logged in")
|
|
||||||
if foundUser.Admin == 1 {
|
|
||||||
return util.Redirect(w, r, c.Ctx.GetRouteByName("app.admin.index"), http.StatusSeeOther, false)
|
|
||||||
} else {
|
|
||||||
return util.Redirect(w, r, c.Ctx.GetRouteByName("app.index"), http.StatusSeeOther, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type SignUpHandler struct {
|
|
||||||
controller.Controller
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c SignUpHandler) Init(s session.IManager, d database.IDB, l logger.ILogger, ctx controller.IControllerCtx) controller.IController {
|
|
||||||
c.Logger = l
|
|
||||||
c.Db = d
|
|
||||||
c.Session = s
|
|
||||||
c.Ctx = ctx
|
|
||||||
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
type UserSignUpForm struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
Username string `json:"username"`
|
|
||||||
Password string `json:"password"`
|
|
||||||
PasswordConfirmation string `json:"password_confirmation"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c SignUpHandler) Get(w http.ResponseWriter, r *http.Request) error {
|
|
||||||
sess := c.Session.SessionStart(w, r)
|
|
||||||
|
|
||||||
uname, ok := sess.Get("username").(string)
|
|
||||||
if !ok {
|
|
||||||
uname = ""
|
|
||||||
}
|
|
||||||
if uname != "" {
|
|
||||||
return util.Redirect(w, r, "/", http.StatusSeeOther, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := user.SignUpForm().Render(context.Background(), w); err != nil {
|
|
||||||
c.Logger.Error(c.Logger.Wrap(err, "Error rendering sign up form"))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c SignUpHandler) Post(w http.ResponseWriter, r *http.Request) error {
|
|
||||||
fd := &UserSignUpForm{}
|
|
||||||
|
|
||||||
jsonDecoder := json.NewDecoder(r.Body)
|
|
||||||
if err := jsonDecoder.Decode(&fd); err == nil {
|
|
||||||
if fd.Password != fd.PasswordConfirmation {
|
|
||||||
if _, err := w.Write([]byte("Passwords don't match")); err != nil {
|
|
||||||
c.Logger.Error(c.Logger.Wrap(err, "Error writing response"))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
foundUser, err := c.Db.Repo().FindUserByUsername(fd.Username)
|
|
||||||
if err != nil {
|
|
||||||
c.Db.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if foundUser != nil {
|
|
||||||
if _, err := w.Write([]byte("Invalid username. Please try another")); err != nil {
|
|
||||||
c.Logger.Error(c.Logger.Wrap(err, "Error writing response"))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
token, err := util.CreateTokenForUser(fd.Username)
|
|
||||||
if err != nil {
|
|
||||||
c.Logger.Error(c.Logger.Wrap(err, "Error creating token"))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
password, err := util.HashPassword(fd.PasswordConfirmation)
|
|
||||||
if err != nil {
|
|
||||||
c.Logger.Error(c.Logger.Wrap(err, "Error hashing password"))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
org, err := c.Db.Repo().FindOrganizationByName("CerbervsSoft")
|
|
||||||
if org == nil || err != nil {
|
|
||||||
c.Db.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
newUser, err := c.Db.Repo().CreateUser(dto.User{
|
|
||||||
Username: fd.Username,
|
|
||||||
Password: password,
|
|
||||||
Name: fd.Name,
|
|
||||||
Email: fd.Email,
|
|
||||||
AuthToken: token,
|
|
||||||
Authorized: 1,
|
|
||||||
Admin: 1,
|
|
||||||
Organization: org.Identifier,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
c.Db.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = c.Db.Repo().CreateHeartbeat(&dto.Heartbeat{
|
|
||||||
User: newUser.Identifier,
|
|
||||||
CreatedAt: time.Now(),
|
|
||||||
IpAddr: r.RemoteAddr,
|
|
||||||
AuthToken: token,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
c.Db.Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
jwtToken, err := util.CreateTokenForUser(fd.Username)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
http.SetCookie(w, &http.Cookie{
|
|
||||||
Name: "token",
|
|
||||||
Value: jwtToken,
|
|
||||||
Expires: time.Now().Add(time.Hour * 1),
|
|
||||||
Path: "/",
|
|
||||||
})
|
|
||||||
|
|
||||||
return util.Redirect(w, r, "/sign-in", http.StatusSeeOther, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type SignOutHandler struct {
|
|
||||||
controller.Controller
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c SignOutHandler) Init(s session.IManager, d database.IDB, l logger.ILogger, ctx controller.IControllerCtx) controller.IController {
|
|
||||||
c.Logger = l
|
|
||||||
c.Db = d
|
|
||||||
c.Session = s
|
|
||||||
c.Ctx = ctx
|
|
||||||
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c SignOutHandler) Get(w http.ResponseWriter, r *http.Request) error {
|
|
||||||
sess := c.Session.SessionStart(w, r)
|
|
||||||
|
|
||||||
err := sess.Delete("username")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = sess.Delete("token")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
http.SetCookie(w, &http.Cookie{
|
|
||||||
Name: "token",
|
|
||||||
Value: "",
|
|
||||||
Expires: time.Now().Add(-time.Hour),
|
|
||||||
Path: "/",
|
|
||||||
})
|
|
||||||
|
|
||||||
return util.Redirect(w, r, "/", http.StatusSeeOther, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func failWithFormError(w http.ResponseWriter, r *http.Request, formError string, sess session.ISession) error {
|
|
||||||
err := sess.Set("formError", formError)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return util.Redirect(w, r, r.URL.Path, http.StatusSeeOther, false)
|
|
||||||
}
|
|
315
handlers/user.go
Normal file
315
handlers/user.go
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"git.markbailey.dev/cervers/ptpp/lib/database"
|
||||||
|
"git.markbailey.dev/cervers/ptpp/lib/database/dto"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.markbailey.dev/cervers/ptpp/lib/logger"
|
||||||
|
"git.markbailey.dev/cervers/ptpp/lib/session"
|
||||||
|
"git.markbailey.dev/cervers/ptpp/util"
|
||||||
|
"git.markbailey.dev/cervers/ptpp/view/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserHandler struct {
|
||||||
|
logger logger.ILogger
|
||||||
|
session session.IManager
|
||||||
|
db database.IDB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUserHandler(l logger.ILogger, s session.IManager, db database.IDB) *UserHandler {
|
||||||
|
return &UserHandler{
|
||||||
|
logger: l,
|
||||||
|
session: s,
|
||||||
|
db: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserHandler) Populate(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
existingOrg, err := u.db.Repo().FindOrganizationByName("CerbervsSoft")
|
||||||
|
if existingOrg != nil && err == nil {
|
||||||
|
return util.Redirect(w, r, "/signup", http.StatusSeeOther, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
authToken, err := util.CreateTokenForUser("CerbervsSoft")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
organization := dto.Organization{
|
||||||
|
Name: "CerbervsSoft",
|
||||||
|
OwnerName: "Mark Bailey",
|
||||||
|
OwnerEmail: "email@provider.com",
|
||||||
|
OwnerPhone: "+11111111111",
|
||||||
|
Authorized: 1,
|
||||||
|
AuthToken: authToken,
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
_, err = u.db.Repo().CreateOrganization(organization)
|
||||||
|
if err != nil {
|
||||||
|
return u.logDBError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return util.Redirect(w, r, "/signup", http.StatusSeeOther, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserSignInForm struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserHandler) SignIn(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
sess := u.session.SessionStart(w, r)
|
||||||
|
|
||||||
|
if r.Method == http.MethodGet {
|
||||||
|
username, ok := r.Context().Value("username").(string)
|
||||||
|
if ok {
|
||||||
|
if username == "" {
|
||||||
|
return u.failWithFormError(w, r, "Invalid Username or Password.")
|
||||||
|
} else {
|
||||||
|
foundUser, err := u.db.Repo().FindUserByUsername(username)
|
||||||
|
if foundUser == nil || err != nil {
|
||||||
|
return u.failWithFormError(w, r, "Invalid Username or Password.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if foundUser.Admin == 1 {
|
||||||
|
return util.Redirect(w, r, "/admin/", http.StatusSeeOther, false)
|
||||||
|
} else {
|
||||||
|
return util.Redirect(w, r, "/", http.StatusSeeOther, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
formError, ok := sess.Get("formError").(string)
|
||||||
|
if !ok {
|
||||||
|
formError = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := user.SignIn(formError).Render(context.Background(), w); err != nil {
|
||||||
|
u.logger.Error(u.logger.Wrap(err, "Error rendering sign in form"))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fd := &UserSignInForm{}
|
||||||
|
|
||||||
|
jsonDecoder := json.NewDecoder(r.Body)
|
||||||
|
if err := jsonDecoder.Decode(&fd); err != nil {
|
||||||
|
u.logger.Error(u.logger.Wrap(err, "Error decoding JSON"))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
foundUser, err := u.db.Repo().FindUserByUsername(fd.Username)
|
||||||
|
if foundUser == nil || err != nil {
|
||||||
|
return util.Redirect(w, r, "/signin", http.StatusSeeOther, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticated, err := util.CheckPassword(fd.Password, foundUser.Password)
|
||||||
|
if err != nil || !authenticated {
|
||||||
|
return u.failWithFormError(w, r, "Invalid Username or Password.")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sess.Set("username", foundUser.Username)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := util.CreateTokenForUser(foundUser.Username)
|
||||||
|
if err != nil {
|
||||||
|
u.logger.Error(u.logger.Wrap(err, "Error creating token"))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sess.Set("token", token)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
authToken, err := util.CreateTokenForUser(foundUser.Username)
|
||||||
|
if err != nil {
|
||||||
|
u.logger.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = u.db.Repo().CreateHeartbeat(&dto.Heartbeat{
|
||||||
|
User: foundUser.Identifier,
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
IpAddr: r.RemoteAddr,
|
||||||
|
AuthToken: authToken,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return u.logDBError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
jwtToken, err := util.CreateTokenForUser(fd.Username)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
http.SetCookie(w, &http.Cookie{
|
||||||
|
Name: "token",
|
||||||
|
Value: jwtToken,
|
||||||
|
Expires: time.Now().Add(time.Hour * 1),
|
||||||
|
Path: "/",
|
||||||
|
})
|
||||||
|
|
||||||
|
err = sess.Delete("formError")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
u.logger.Info(foundUser.Username + " logged in")
|
||||||
|
if foundUser.Admin == 1 {
|
||||||
|
return util.Redirect(w, r, "/admin/", http.StatusSeeOther, false)
|
||||||
|
} else {
|
||||||
|
return util.Redirect(w, r, "/", http.StatusSeeOther, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserSignUpForm struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
PasswordConfirmation string `json:"password_confirmation"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserHandler) SignUp(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
handlerSess := u.session.SessionStart(w, r)
|
||||||
|
uname, ok := handlerSess.Get("username").(string)
|
||||||
|
if !ok {
|
||||||
|
uname = ""
|
||||||
|
}
|
||||||
|
if uname != "" {
|
||||||
|
return util.Redirect(w, r, "/", http.StatusSeeOther, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Method == http.MethodGet {
|
||||||
|
if err := user.SignUpForm().Render(context.Background(), w); err != nil {
|
||||||
|
u.logger.Error(u.logger.Wrap(err, "Error rendering sign up form"))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fd := &UserSignUpForm{}
|
||||||
|
|
||||||
|
jsonDecoder := json.NewDecoder(r.Body)
|
||||||
|
if err := jsonDecoder.Decode(&fd); err == nil {
|
||||||
|
if fd.Password != fd.PasswordConfirmation {
|
||||||
|
if _, err := w.Write([]byte("Passwords don't match")); err != nil {
|
||||||
|
u.logger.Error(u.logger.Wrap(err, "Error writing response"))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
foundUser, err := u.db.Repo().FindUserByUsername(fd.Username)
|
||||||
|
|
||||||
|
if foundUser != nil {
|
||||||
|
if _, err := w.Write([]byte("Invalid username. Please try another")); err != nil {
|
||||||
|
u.logger.Error(u.logger.Wrap(err, "Error writing response"))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := util.CreateTokenForUser(fd.Username)
|
||||||
|
if err != nil {
|
||||||
|
u.logger.Error(u.logger.Wrap(err, "Error creating token"))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
password, err := util.HashPassword(fd.PasswordConfirmation)
|
||||||
|
if err != nil {
|
||||||
|
u.logger.Error(u.logger.Wrap(err, "Error hashing password"))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
org, err := u.db.Repo().FindOrganizationByName("CerbervsSoft")
|
||||||
|
if org == nil || err != nil {
|
||||||
|
return u.logDBError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
newUser, err := u.db.Repo().CreateUser(dto.User{
|
||||||
|
Username: fd.Username,
|
||||||
|
Password: password,
|
||||||
|
Name: fd.Name,
|
||||||
|
Email: fd.Email,
|
||||||
|
AuthToken: token,
|
||||||
|
Authorized: 1,
|
||||||
|
Admin: 1,
|
||||||
|
Organization: org.Identifier,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return u.logDBError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = u.db.Repo().CreateHeartbeat(&dto.Heartbeat{
|
||||||
|
User: newUser.Identifier,
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
IpAddr: r.RemoteAddr,
|
||||||
|
AuthToken: token,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return u.logDBError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
jwtToken, err := util.CreateTokenForUser(fd.Username)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
http.SetCookie(w, &http.Cookie{
|
||||||
|
Name: "token",
|
||||||
|
Value: jwtToken,
|
||||||
|
Expires: time.Now().Add(time.Hour * 1),
|
||||||
|
Path: "/",
|
||||||
|
})
|
||||||
|
|
||||||
|
return util.Redirect(w, r, "/signin", http.StatusSeeOther, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserHandler) SignOut(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
sess := u.session.SessionStart(w, r)
|
||||||
|
|
||||||
|
err := sess.Delete("username")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sess.Delete("token")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
http.SetCookie(w, &http.Cookie{
|
||||||
|
Name: "token",
|
||||||
|
Value: "",
|
||||||
|
Expires: time.Now().Add(-time.Hour),
|
||||||
|
Path: "/",
|
||||||
|
})
|
||||||
|
|
||||||
|
return util.Redirect(w, r, "/", http.StatusSeeOther, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserHandler) logDBError(err error) error {
|
||||||
|
u.db.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserHandler) failWithFormError(w http.ResponseWriter, r *http.Request, formError string) error {
|
||||||
|
sess := u.session.SessionStart(w, r)
|
||||||
|
err := sess.Set("formError", formError)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return util.Redirect(w, r, r.URL.Path, http.StatusSeeOther, false)
|
||||||
|
}
|
79
infrastructure/router.go
Normal file
79
infrastructure/router.go
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
package infrastructure
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.markbailey.dev/cervers/ptpp/lib/database"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"git.markbailey.dev/cervers/ptpp/handlers"
|
||||||
|
"git.markbailey.dev/cervers/ptpp/handlers/admin"
|
||||||
|
"git.markbailey.dev/cervers/ptpp/lib/logger"
|
||||||
|
mw "git.markbailey.dev/cervers/ptpp/lib/middleware"
|
||||||
|
"git.markbailey.dev/cervers/ptpp/lib/session"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
globalSessions *session.Manager
|
||||||
|
commonRouter *http.ServeMux
|
||||||
|
adminStack mw.Func
|
||||||
|
commonStack mw.Func
|
||||||
|
lock = &sync.Mutex{}
|
||||||
|
il logger.ILogger
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetRouter() http.Handler {
|
||||||
|
commonStack = mw.Compose(
|
||||||
|
mw.WithLogger,
|
||||||
|
mw.WithUsername,
|
||||||
|
)
|
||||||
|
|
||||||
|
if commonRouter == nil {
|
||||||
|
lock.Lock()
|
||||||
|
defer lock.Unlock()
|
||||||
|
|
||||||
|
adminStack = mw.Compose(
|
||||||
|
mw.WithAuth,
|
||||||
|
)
|
||||||
|
|
||||||
|
commonRouter = http.NewServeMux()
|
||||||
|
adminRouter := http.NewServeMux()
|
||||||
|
|
||||||
|
// Serve static files
|
||||||
|
fs := http.FileServer(http.Dir("./public/"))
|
||||||
|
commonRouter.Handle("GET /public/", http.StripPrefix("/public", fs))
|
||||||
|
commonRouter.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
http.ServeFile(w, r, "./public/assets/favicon/favicon.ico")
|
||||||
|
})
|
||||||
|
|
||||||
|
// Homepage routes
|
||||||
|
homepageHandler := handlers.NewHomePageHandler(il)
|
||||||
|
commonRouter.Handle("/", mw.ErrHandler(homepageHandler.Homepage))
|
||||||
|
|
||||||
|
if env == "production" {
|
||||||
|
return commonStack(commonRouter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// User routes
|
||||||
|
userHandler := handlers.NewUserHandler(il, globalSessions, database.ChooseDB())
|
||||||
|
commonRouter.Handle("GET /signup", mw.ErrHandler(userHandler.SignUp))
|
||||||
|
commonRouter.Handle("POST /signup", mw.ErrHandler(userHandler.SignUp))
|
||||||
|
commonRouter.Handle("GET /signin", mw.ErrHandler(userHandler.SignIn))
|
||||||
|
commonRouter.Handle("POST /signin", mw.ErrHandler(userHandler.SignIn))
|
||||||
|
commonRouter.Handle("GET /signout", mw.ErrHandler(userHandler.SignOut))
|
||||||
|
commonRouter.Handle("GET /populate", mw.ErrHandler(userHandler.Populate))
|
||||||
|
|
||||||
|
// Admin routes
|
||||||
|
adminIndexHandler := admin.NewAdminIndexHandler(il, globalSessions)
|
||||||
|
adminRouter.Handle("GET /", mw.ErrHandler(adminIndexHandler.Index))
|
||||||
|
commonRouter.Handle("/admin/", http.StripPrefix("/admin", adminStack(adminRouter)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return commonStack(commonRouter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
globalSessions, _ = session.NewManager("memory", "ptpp", 3600)
|
||||||
|
go globalSessions.GC()
|
||||||
|
|
||||||
|
il = logger.NewCompositeLogger()
|
||||||
|
}
|
64
infrastructure/server.go
Normal file
64
infrastructure/server.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package infrastructure
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
addr string
|
||||||
|
http.Server
|
||||||
|
port int
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
env = os.Getenv("HTMX_APP_ENV")
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewServer() *Server {
|
||||||
|
const (
|
||||||
|
addr = "0.0.0.0"
|
||||||
|
)
|
||||||
|
|
||||||
|
var port int
|
||||||
|
|
||||||
|
if env == "production" {
|
||||||
|
port = 8080
|
||||||
|
} else {
|
||||||
|
port = 8080
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Server{
|
||||||
|
addr,
|
||||||
|
http.Server{
|
||||||
|
Addr: addr + ":" + strconv.Itoa(port),
|
||||||
|
Handler: GetRouter(),
|
||||||
|
DisableGeneralOptionsHandler: false,
|
||||||
|
TLSConfig: nil,
|
||||||
|
ReadTimeout: 5 * time.Second,
|
||||||
|
ReadHeaderTimeout: 0,
|
||||||
|
WriteTimeout: 5 * time.Second,
|
||||||
|
IdleTimeout: 0,
|
||||||
|
MaxHeaderBytes: 0,
|
||||||
|
TLSNextProto: nil,
|
||||||
|
ConnState: nil,
|
||||||
|
ErrorLog: nil,
|
||||||
|
BaseContext: nil,
|
||||||
|
ConnContext: nil,
|
||||||
|
},
|
||||||
|
port,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Serve() {
|
||||||
|
fmt.Printf("Starting.\nListening at %s on port %s\n", s.addr, strconv.Itoa(s.port))
|
||||||
|
serverError := s.ListenAndServe()
|
||||||
|
|
||||||
|
if serverError != nil {
|
||||||
|
log.Fatal(serverError)
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,12 @@
|
|||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/database/development"
|
"git.markbailey.dev/cervers/ptpp/lib/database/development"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/database/production"
|
"git.markbailey.dev/cervers/ptpp/lib/database/production"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/repository"
|
"git.markbailey.dev/cervers/ptpp/lib/repository"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/logger"
|
"git.markbailey.dev/cervers/ptpp/lib/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IDB interface {
|
type IDB interface {
|
||||||
|
@ -2,9 +2,9 @@ package development
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/logger"
|
"git.markbailey.dev/cervers/ptpp/lib/logger"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/repository"
|
"git.markbailey.dev/cervers/ptpp/lib/repository"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/models/sqlite"
|
"git.markbailey.dev/cervers/ptpp/models/sqlite"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
@ -2,9 +2,9 @@ package development
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/database/dto"
|
"git.markbailey.dev/cervers/ptpp/lib/database/dto"
|
||||||
pterror "git.markbailey.dev/cerbervs/ptpp/lib/error"
|
pterror "git.markbailey.dev/cervers/ptpp/lib/error"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/models/sqlite"
|
"git.markbailey.dev/cervers/ptpp/models/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HeartbeatRepository struct{}
|
type HeartbeatRepository struct{}
|
||||||
|
@ -2,9 +2,9 @@ package development
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/database/dto"
|
"git.markbailey.dev/cervers/ptpp/lib/database/dto"
|
||||||
pterror "git.markbailey.dev/cerbervs/ptpp/lib/error"
|
pterror "git.markbailey.dev/cervers/ptpp/lib/error"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/models/sqlite"
|
"git.markbailey.dev/cervers/ptpp/models/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OrganizationRepository struct{}
|
type OrganizationRepository struct{}
|
||||||
|
@ -2,9 +2,9 @@ package development
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/database/dto"
|
"git.markbailey.dev/cervers/ptpp/lib/database/dto"
|
||||||
pterror "git.markbailey.dev/cerbervs/ptpp/lib/error"
|
pterror "git.markbailey.dev/cervers/ptpp/lib/error"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/models/sqlite"
|
"git.markbailey.dev/cervers/ptpp/models/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UserRepository struct{}
|
type UserRepository struct{}
|
||||||
|
@ -2,9 +2,9 @@ package production
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/logger"
|
"git.markbailey.dev/cervers/ptpp/lib/logger"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/repository"
|
"git.markbailey.dev/cervers/ptpp/lib/repository"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/models/postgres"
|
"git.markbailey.dev/cervers/ptpp/models/postgres"
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -2,9 +2,9 @@ package production
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/database/dto"
|
"git.markbailey.dev/cervers/ptpp/lib/database/dto"
|
||||||
pterror "git.markbailey.dev/cerbervs/ptpp/lib/error"
|
pterror "git.markbailey.dev/cervers/ptpp/lib/error"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/models/postgres"
|
"git.markbailey.dev/cervers/ptpp/models/postgres"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HeartbeatRepository struct{}
|
type HeartbeatRepository struct{}
|
||||||
|
@ -2,9 +2,9 @@ package production
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/database/dto"
|
"git.markbailey.dev/cervers/ptpp/lib/database/dto"
|
||||||
pterror "git.markbailey.dev/cerbervs/ptpp/lib/error"
|
pterror "git.markbailey.dev/cervers/ptpp/lib/error"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/models/postgres"
|
"git.markbailey.dev/cervers/ptpp/models/postgres"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OrganizationRepository struct{}
|
type OrganizationRepository struct{}
|
||||||
|
@ -2,9 +2,9 @@ package production
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/database/dto"
|
"git.markbailey.dev/cervers/ptpp/lib/database/dto"
|
||||||
pterror "git.markbailey.dev/cerbervs/ptpp/lib/error"
|
pterror "git.markbailey.dev/cervers/ptpp/lib/error"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/models/postgres"
|
"git.markbailey.dev/cervers/ptpp/models/postgres"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UserRepository struct{}
|
type UserRepository struct{}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package locator
|
package locator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
perr "git.markbailey.dev/cerbervs/ptpp/lib/error"
|
perr "git.markbailey.dev/cervers/ptpp/lib/error"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/locator/service"
|
"git.markbailey.dev/cervers/ptpp/lib/locator/service"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/database"
|
"git.markbailey.dev/cervers/ptpp/lib/database"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/logger"
|
"git.markbailey.dev/cervers/ptpp/lib/logger"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@ package logger
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
pterror "git.markbailey.dev/cerbervs/ptpp/lib/error"
|
pterror "git.markbailey.dev/cervers/ptpp/lib/error"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/util"
|
"git.markbailey.dev/cervers/ptpp/util"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -2,8 +2,8 @@ package logger
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
pterror "git.markbailey.dev/cerbervs/ptpp/lib/error"
|
pterror "git.markbailey.dev/cervers/ptpp/lib/error"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/util"
|
"git.markbailey.dev/cervers/ptpp/util"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -2,71 +2,56 @@ package middleware
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"git.markbailey.dev/cervers/ptpp/lib/database"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/app/session"
|
"git.markbailey.dev/cervers/ptpp/lib/logger"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/util"
|
"git.markbailey.dev/cervers/ptpp/lib/session"
|
||||||
|
"git.markbailey.dev/cervers/ptpp/util"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/lib/logger"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type IRouterCtx interface {
|
type Middleware struct {
|
||||||
GetRouteByName(string) (string, error)
|
l logger.ILogger
|
||||||
|
db database.IDB
|
||||||
}
|
}
|
||||||
|
|
||||||
type IMiddlewareCtx interface {
|
type (
|
||||||
GetRouteByName(string) string
|
ErrHandler func(http.ResponseWriter, *http.Request) error
|
||||||
|
Func func(http.Handler) http.Handler
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
sess session.IManager
|
||||||
|
)
|
||||||
|
|
||||||
|
func (fn ErrHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if err := fn(w, r); err != nil {
|
||||||
|
w.Header().Set("HX-Retarget", "#layout_content")
|
||||||
|
w.Header().Set("HX-Reswap", "innerHTML")
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type MiddlewareCtx struct {
|
func Compose(xs ...Func) Func {
|
||||||
RouterCtx IRouterCtx
|
return func(next http.Handler) http.Handler {
|
||||||
}
|
|
||||||
|
|
||||||
func (m MiddlewareCtx) GetRouteByName(name string) string {
|
|
||||||
path, err := m.RouterCtx.GetRouteByName(name)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
|
|
||||||
type Func func(http.Handler, IMiddlewareCtx) http.Handler
|
|
||||||
|
|
||||||
var sess session.IManager
|
|
||||||
|
|
||||||
func Compose(xs []Func) Func {
|
|
||||||
return func(next http.Handler, m IMiddlewareCtx) http.Handler {
|
|
||||||
for i := len(xs) - 1; i >= 0; i-- {
|
for i := len(xs) - 1; i >= 0; i-- {
|
||||||
x := xs[i]
|
x := xs[i]
|
||||||
next = x(next, m)
|
next = x(next)
|
||||||
}
|
}
|
||||||
|
|
||||||
return next
|
return next
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DontPanic(next http.Handler, m IMiddlewareCtx) http.Handler {
|
func WithLogger(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
http.Error(w, fmt.Sprintf("%v", r), http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
next.ServeHTTP(w, r)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithLogger(next http.Handler, m IMiddlewareCtx) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
handlerSess := sess.SessionStart(w, r)
|
handlerSess := sess.SessionStart(w, r)
|
||||||
|
|
||||||
username, ok := handlerSess.Get("username").(string)
|
username, ok := handlerSess.Get("username").(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
username = ""
|
username = "<Not Found>"
|
||||||
}
|
}
|
||||||
username = "(username " + username + ")"
|
|
||||||
|
|
||||||
ipAddr := r.Header.Get("X-Real-IP")
|
ipAddr := r.Header.Get("X-Real-IP")
|
||||||
if ipAddr == "" {
|
if ipAddr == "" {
|
||||||
@ -78,7 +63,7 @@ func WithLogger(next http.Handler, m IMiddlewareCtx) http.Handler {
|
|||||||
|
|
||||||
handlerLogger := logger.NewCompositeLogger()
|
handlerLogger := logger.NewCompositeLogger()
|
||||||
output := fmt.Sprintf(
|
output := fmt.Sprintf(
|
||||||
"%s Request sent from %s to %s %s",
|
"%s Request sent from %s to %s (username? %s)",
|
||||||
r.Method,
|
r.Method,
|
||||||
ipAddr,
|
ipAddr,
|
||||||
r.URL.Path,
|
r.URL.Path,
|
||||||
@ -90,7 +75,7 @@ func WithLogger(next http.Handler, m IMiddlewareCtx) http.Handler {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithAuth(next http.Handler, m IMiddlewareCtx) http.Handler {
|
func WithAuth(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
claims *util.CustomClaims
|
claims *util.CustomClaims
|
||||||
@ -109,15 +94,15 @@ func WithAuth(next http.Handler, m IMiddlewareCtx) http.Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cookie, err = r.Cookie("token"); err != nil {
|
if cookie, err = r.Cookie("token"); err != nil {
|
||||||
_ = util.Redirect(w, r, m.GetRouteByName("app.user.sign_in"), http.StatusPermanentRedirect, true)
|
_ = util.Redirect(w, r, "/signin", http.StatusSeeOther, true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if token = cookie.Value; token == "" {
|
if token = cookie.Value; token == "" {
|
||||||
_ = util.Redirect(w, r, m.GetRouteByName("app.user.sign_in"), http.StatusPermanentRedirect, true)
|
_ = util.Redirect(w, r, "/signin", http.StatusSeeOther, true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if claims, err = util.ParseToken(token, os.Getenv("TOKEN_SECRET")); err != nil {
|
if claims, err = util.ParseToken(token, os.Getenv("TOKEN_SECRET")); err != nil {
|
||||||
_ = util.Redirect(w, r, m.GetRouteByName("app.user.sign_in"), http.StatusPermanentRedirect, true)
|
_ = util.Redirect(w, r, "/signin", http.StatusSeeOther, true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +113,7 @@ func WithAuth(next http.Handler, m IMiddlewareCtx) http.Handler {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithUsername(next http.Handler, m IMiddlewareCtx) http.Handler {
|
func WithUsername(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
claims *util.CustomClaims
|
claims *util.CustomClaims
|
||||||
@ -170,9 +155,5 @@ func WithUsername(next http.Handler, m IMiddlewareCtx) http.Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
var err error
|
sess, _ = session.NewManager("memory", "ptpp", 3600)
|
||||||
sess, err = session.NewManager("memory", "ptpp", 3600)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package repository
|
package repository
|
||||||
|
|
||||||
import "git.markbailey.dev/cerbervs/ptpp/lib/database/dto"
|
import "git.markbailey.dev/cervers/ptpp/lib/database/dto"
|
||||||
|
|
||||||
type IHeartbeat interface {
|
type IHeartbeat interface {
|
||||||
CreateHeartbeat(h *dto.Heartbeat) (*dto.Heartbeat, error)
|
CreateHeartbeat(h *dto.Heartbeat) (*dto.Heartbeat, error)
|
||||||
|
1
lib/session/memory/cookieprovider.go
Normal file
1
lib/session/memory/cookieprovider.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package memory
|
@ -1,9 +1,11 @@
|
|||||||
package session
|
package memory
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"container/list"
|
"container/list"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.markbailey.dev/cervers/ptpp/lib/session"
|
||||||
)
|
)
|
||||||
|
|
||||||
var prov = &Provider{list: list.New()}
|
var prov = &Provider{list: list.New()}
|
||||||
@ -56,7 +58,7 @@ type Provider struct {
|
|||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) SessionInit(sid string) (ISession, error) {
|
func (p *Provider) SessionInit(sid string) (session.ISession, error) {
|
||||||
prov.lock.Lock()
|
prov.lock.Lock()
|
||||||
defer prov.lock.Unlock()
|
defer prov.lock.Unlock()
|
||||||
v := make(map[interface{}]interface{}, 0)
|
v := make(map[interface{}]interface{}, 0)
|
||||||
@ -66,7 +68,7 @@ func (p *Provider) SessionInit(sid string) (ISession, error) {
|
|||||||
return newSess, nil
|
return newSess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) SessionRead(sid string) (ISession, error) {
|
func (p *Provider) SessionRead(sid string) (session.ISession, error) {
|
||||||
if element, ok := prov.sessions[sid]; ok {
|
if element, ok := prov.sessions[sid]; ok {
|
||||||
return element.Value.(*MemSessionStore), nil
|
return element.Value.(*MemSessionStore), nil
|
||||||
}
|
}
|
||||||
@ -117,5 +119,5 @@ func (p *Provider) SessionUpdate(sid string) error {
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
prov.sessions = make(map[string]*list.Element, 0)
|
prov.sessions = make(map[string]*list.Element, 0)
|
||||||
Register("memory", prov)
|
session.Register("memory", prov)
|
||||||
}
|
}
|
148
package-lock.json
generated
148
package-lock.json
generated
@ -1,15 +1,16 @@
|
|||||||
{
|
{
|
||||||
"name": "go-full-stack",
|
"name": "ptpp",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"htmx.org": "^1.9.10"
|
"htmx.org": "^1.9.10",
|
||||||
|
"preline": "^2.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/forms": "^0.5.9",
|
"@tailwindcss/forms": "^0.5.9",
|
||||||
"tailwindcss": "^3.4.15"
|
"tailwindcss": "^3.4.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@alloc/quick-lru": {
|
"node_modules/@alloc/quick-lru": {
|
||||||
@ -134,6 +135,15 @@
|
|||||||
"node": ">=14"
|
"node": ">=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@popperjs/core": {
|
||||||
|
"version": "2.11.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||||
|
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/popperjs"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tailwindcss/forms": {
|
"node_modules/@tailwindcss/forms": {
|
||||||
"version": "0.5.9",
|
"version": "0.5.9",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.9.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.9.tgz",
|
||||||
@ -221,13 +231,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/braces": {
|
"node_modules/braces": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||||
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fill-range": "^7.1.1"
|
"fill-range": "^7.0.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
@ -324,7 +333,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||||
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
|
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"cssesc": "bin/cssesc"
|
"cssesc": "bin/cssesc"
|
||||||
},
|
},
|
||||||
@ -394,11 +402,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fill-range": {
|
"node_modules/fill-range": {
|
||||||
"version": "7.1.1",
|
"version": "7.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"to-regex-range": "^5.0.1"
|
"to-regex-range": "^5.0.1"
|
||||||
},
|
},
|
||||||
@ -555,7 +562,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.12.0"
|
"node": ">=0.12.0"
|
||||||
}
|
}
|
||||||
@ -585,11 +591,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jiti": {
|
"node_modules/jiti": {
|
||||||
"version": "1.21.6",
|
"version": "1.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz",
|
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz",
|
||||||
"integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==",
|
"integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"jiti": "bin/jiti.js"
|
"jiti": "bin/jiti.js"
|
||||||
}
|
}
|
||||||
@ -628,13 +633,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/micromatch": {
|
"node_modules/micromatch": {
|
||||||
"version": "4.0.8",
|
"version": "4.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
|
||||||
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"braces": "^3.0.3",
|
"braces": "^3.0.2",
|
||||||
"picomatch": "^2.3.1"
|
"picomatch": "^2.3.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -762,11 +766,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
"version": "1.1.1",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
||||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"license": "ISC"
|
|
||||||
},
|
},
|
||||||
"node_modules/picomatch": {
|
"node_modules/picomatch": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
@ -799,9 +802,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.49",
|
"version": "8.4.35",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
|
||||||
"integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
|
"integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -817,11 +820,10 @@
|
|||||||
"url": "https://github.com/sponsors/ai"
|
"url": "https://github.com/sponsors/ai"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.7",
|
"nanoid": "^3.3.7",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.0.0",
|
||||||
"source-map-js": "^1.2.1"
|
"source-map-js": "^1.0.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^10 || ^12 || >=14"
|
"node": "^10 || ^12 || >=14"
|
||||||
@ -908,37 +910,29 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-nested": {
|
"node_modules/postcss-nested": {
|
||||||
"version": "6.2.0",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
|
||||||
"integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
|
"integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/postcss/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "github",
|
|
||||||
"url": "https://github.com/sponsors/ai"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"postcss-selector-parser": "^6.1.1"
|
"postcss-selector-parser": "^6.0.11"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.0"
|
"node": ">=12.0"
|
||||||
},
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"postcss": "^8.2.14"
|
"postcss": "^8.2.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-selector-parser": {
|
"node_modules/postcss-selector-parser": {
|
||||||
"version": "6.1.2",
|
"version": "6.0.15",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz",
|
||||||
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
|
"integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cssesc": "^3.0.0",
|
"cssesc": "^3.0.0",
|
||||||
"util-deprecate": "^1.0.2"
|
"util-deprecate": "^1.0.2"
|
||||||
@ -953,6 +947,14 @@
|
|||||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/preline": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/preline/-/preline-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-V/sLmRIHd23UCdvJNRKKszntgUqA0381erVzRpQ48NjjMOgI7DyFW4mr+lg387V0oeBc5Dx9Jxa5voppVoH9GA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@popperjs/core": "^2.11.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/queue-microtask": {
|
"node_modules/queue-microtask": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||||
@ -1078,11 +1080,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/source-map-js": {
|
"node_modules/source-map-js": {
|
||||||
"version": "1.2.1",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-3-Clause",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@ -1218,34 +1219,33 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tailwindcss": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "3.4.15",
|
"version": "3.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz",
|
||||||
"integrity": "sha512-r4MeXnfBmSOuKUWmXe6h2CcyfzJCEk4F0pptO5jlnYSIViUkVmsawj80N5h2lO3gwcmSb4n3PuN+e+GC1Guylw==",
|
"integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alloc/quick-lru": "^5.2.0",
|
"@alloc/quick-lru": "^5.2.0",
|
||||||
"arg": "^5.0.2",
|
"arg": "^5.0.2",
|
||||||
"chokidar": "^3.6.0",
|
"chokidar": "^3.5.3",
|
||||||
"didyoumean": "^1.2.2",
|
"didyoumean": "^1.2.2",
|
||||||
"dlv": "^1.1.3",
|
"dlv": "^1.1.3",
|
||||||
"fast-glob": "^3.3.2",
|
"fast-glob": "^3.3.0",
|
||||||
"glob-parent": "^6.0.2",
|
"glob-parent": "^6.0.2",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
"jiti": "^1.21.6",
|
"jiti": "^1.19.1",
|
||||||
"lilconfig": "^2.1.0",
|
"lilconfig": "^2.1.0",
|
||||||
"micromatch": "^4.0.8",
|
"micromatch": "^4.0.5",
|
||||||
"normalize-path": "^3.0.0",
|
"normalize-path": "^3.0.0",
|
||||||
"object-hash": "^3.0.0",
|
"object-hash": "^3.0.0",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.0.0",
|
||||||
"postcss": "^8.4.47",
|
"postcss": "^8.4.23",
|
||||||
"postcss-import": "^15.1.0",
|
"postcss-import": "^15.1.0",
|
||||||
"postcss-js": "^4.0.1",
|
"postcss-js": "^4.0.1",
|
||||||
"postcss-load-config": "^4.0.2",
|
"postcss-load-config": "^4.0.1",
|
||||||
"postcss-nested": "^6.2.0",
|
"postcss-nested": "^6.0.1",
|
||||||
"postcss-selector-parser": "^6.1.2",
|
"postcss-selector-parser": "^6.0.11",
|
||||||
"resolve": "^1.22.8",
|
"resolve": "^1.22.2",
|
||||||
"sucrase": "^3.35.0"
|
"sucrase": "^3.32.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"tailwind": "lib/cli.js",
|
"tailwind": "lib/cli.js",
|
||||||
@ -1281,7 +1281,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-number": "^7.0.0"
|
"is-number": "^7.0.0"
|
||||||
},
|
},
|
||||||
@ -1299,8 +1298,7 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/forms": "^0.5.9",
|
"@tailwindcss/forms": "^0.5.9",
|
||||||
"tailwindcss": "^3.4.15"
|
"tailwindcss": "^3.4.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"htmx.org": "^1.9.10"
|
"htmx.org": "^1.9.10",
|
||||||
|
"preline": "^2.0.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import "git.markbailey.dev/cerbervs/ptpp/view/layout"
|
import "git.markbailey.dev/cervers/ptpp/view/layout"
|
||||||
|
|
||||||
templ Index(name string) {
|
templ Index(name string) {
|
||||||
@layout.Layout() {
|
@layout.Layout() {
|
||||||
|
@ -8,7 +8,7 @@ package admin
|
|||||||
import "github.com/a-h/templ"
|
import "github.com/a-h/templ"
|
||||||
import templruntime "github.com/a-h/templ/runtime"
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
import "git.markbailey.dev/cerbervs/ptpp/view/layout"
|
import "git.markbailey.dev/cervers/ptpp/view/layout"
|
||||||
|
|
||||||
func Index(name string) templ.Component {
|
func Index(name string) templ.Component {
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
@ -1,28 +1,27 @@
|
|||||||
package homepage
|
package homepage
|
||||||
|
|
||||||
import (
|
import "git.markbailey.dev/cervers/ptpp/view/layout"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/view/layout"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/app/controller"
|
|
||||||
)
|
|
||||||
|
|
||||||
templ Homepage(env string, context controller.IControllerCtx) {
|
templ Homepage(env string) {
|
||||||
@layout.Layout() {
|
@layout.Layout() {
|
||||||
<div class="h-screen flex flex-col items-center justify-evenly text-blue-400 text-2xl">
|
<div class="h-screen flex flex-col items-center justify-evenly text-blue-400 text-2xl">
|
||||||
<div>
|
<div>
|
||||||
Welcome to the homepage
|
Welcome to the homepage
|
||||||
</div>
|
</div>
|
||||||
|
if env == "development" {
|
||||||
<div>
|
<div>
|
||||||
<a href={ templ.SafeURL(context.GetRouteByName("app.user.sign_up")) }>
|
<a href="/signup">
|
||||||
<button class="text-gray-400 text-md border-black rounded-lg bg-gray-300 p-2">
|
<button class="text-gray-400 text-md border-black rounded-lg bg-gray-300 p-2">
|
||||||
Sign Up
|
Sign Up
|
||||||
</button>
|
</button>
|
||||||
</a>
|
</a>
|
||||||
<a href={ templ.SafeURL(context.GetRouteByName("app.user.sign_in")) }>
|
<a href="/signin">
|
||||||
<button class="text-gray-400 text-md border-black rounded-lg bg-gray-300 p-2">
|
<button class="text-gray-400 text-md border-black rounded-lg bg-gray-300 p-2">
|
||||||
Sign In
|
Sign In
|
||||||
</button>
|
</button>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,9 @@ package homepage
|
|||||||
import "github.com/a-h/templ"
|
import "github.com/a-h/templ"
|
||||||
import templruntime "github.com/a-h/templ/runtime"
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
import (
|
import "git.markbailey.dev/cervers/ptpp/view/layout"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/app/controller"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/view/layout"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Homepage(env string, context controller.IControllerCtx) templ.Component {
|
func Homepage(env string) templ.Component {
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
@ -46,25 +43,17 @@ func Homepage(env string, context controller.IControllerCtx) templ.Component {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
ctx = templ.InitializeContext(ctx)
|
ctx = templ.InitializeContext(ctx)
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"h-screen flex flex-col items-center justify-evenly text-blue-400 text-2xl\"><div>Welcome to the homepage</div><div><a href=\"")
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"h-screen flex flex-col items-center justify-evenly text-blue-400 text-2xl\"><div>Welcome to the homepage</div>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var3 templ.SafeURL = templ.SafeURL(context.GetRouteByName("app.user.sign_up"))
|
if env == "development" {
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var3)))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div><a href=\"/signup\"><button class=\"text-gray-400 text-md border-black rounded-lg bg-gray-300 p-2\" disabled>Sign Up</button></a> <a href=\"/signin\"><button class=\"text-gray-400 text-md border-black rounded-lg bg-gray-300 p-2\">Sign In</button></a></div>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><button class=\"text-gray-400 text-md border-black rounded-lg bg-gray-300 p-2\">Sign Up</button></a> <a href=\"")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var4 templ.SafeURL = templ.SafeURL(context.GetRouteByName("app.user.sign_in"))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var4)))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><button class=\"text-gray-400 text-md border-black rounded-lg bg-gray-300 p-2\">Sign In</button></a></div></div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ templ Layout() {
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="#layout_content" hx-ext="response-targets" hx-target-error="this">
|
<div id="#layout_content" hx-ext="response-targets" hx-target-5*="this">
|
||||||
{ children... }
|
{ children... }
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript" src="/public/assets/js/index.js"></script>
|
<script type="text/javascript" src="/public/assets/js/index.js"></script>
|
||||||
|
@ -29,7 +29,7 @@ func Layout() templ.Component {
|
|||||||
templ_7745c5c3_Var1 = templ.NopComponent
|
templ_7745c5c3_Var1 = templ.NopComponent
|
||||||
}
|
}
|
||||||
ctx = templ.ClearChildren(ctx)
|
ctx = templ.ClearChildren(ctx)
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<!doctype html><html lang=\"en\"><head><title></title><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"device-width, initial-scale=1.0\"><script src=\"https://unpkg.com/htmx.org@1.9.10\"></script><script src=\"https://unpkg.com/htmx.org@1.9.10/dist/ext/json-enc.js\"></script><script src=\"https://unpkg.com/htmx.org/dist/ext/response-targets.js\"></script><link href=\"/public/assets/css/output.css\" rel=\"stylesheet\"></head><body><div id=\"#layout_content\" hx-ext=\"response-targets\" hx-target-error=\"this\">")
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<!doctype html><html lang=\"en\"><head><title></title><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"device-width, initial-scale=1.0\"><script src=\"https://unpkg.com/htmx.org@1.9.10\"></script><script src=\"https://unpkg.com/htmx.org@1.9.10/dist/ext/json-enc.js\"></script><script src=\"https://unpkg.com/htmx.org/dist/ext/response-targets.js\"></script><link href=\"/public/assets/css/output.css\" rel=\"stylesheet\"></head><body><div id=\"#layout_content\" hx-ext=\"response-targets\" hx-target-5*=\"this\">")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
package user
|
package user
|
||||||
|
|
||||||
import (
|
import "git.markbailey.dev/cervers/ptpp/view/layout"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/view/layout"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/app/controller"
|
|
||||||
)
|
|
||||||
|
|
||||||
templ SignIn(err string, context controller.IControllerCtx) {
|
templ SignIn(err string) {
|
||||||
@layout.Layout() {
|
@layout.Layout() {
|
||||||
<section class="bg-gray-50 dark:bg-gray-900" id="section">
|
<section class="bg-gray-50 dark:bg-gray-900" id="section">
|
||||||
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
|
||||||
@ -18,7 +15,9 @@ templ SignIn(err string, context controller.IControllerCtx) {
|
|||||||
</h1>
|
</h1>
|
||||||
<form
|
<form
|
||||||
class="space-y-4 md:space-y-6"
|
class="space-y-4 md:space-y-6"
|
||||||
hx-post={ context.GetRouteByName("app.user.sign_in") }
|
action="/signin"
|
||||||
|
method="post"
|
||||||
|
hx-post="/signin"
|
||||||
hx-swap="outerHTML"
|
hx-swap="outerHTML"
|
||||||
hx-target="#section"
|
hx-target="#section"
|
||||||
>
|
>
|
||||||
|
@ -8,12 +8,9 @@ package user
|
|||||||
import "github.com/a-h/templ"
|
import "github.com/a-h/templ"
|
||||||
import templruntime "github.com/a-h/templ/runtime"
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
import (
|
import "git.markbailey.dev/cervers/ptpp/view/layout"
|
||||||
"git.markbailey.dev/cerbervs/ptpp/app/controller"
|
|
||||||
"git.markbailey.dev/cerbervs/ptpp/view/layout"
|
|
||||||
)
|
|
||||||
|
|
||||||
func SignIn(err string, context controller.IControllerCtx) templ.Component {
|
func SignIn(err string) templ.Component {
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
@ -46,20 +43,7 @@ func SignIn(err string, context controller.IControllerCtx) templ.Component {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
ctx = templ.InitializeContext(ctx)
|
ctx = templ.InitializeContext(ctx)
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<section class=\"bg-gray-50 dark:bg-gray-900\" id=\"section\"><div class=\"flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0\"><div class=\"w-full bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md xl:p-0 dark:bg-gray-800 dark:border-gray-700\"><div class=\"p-6 space-y-4 md:space-y-6 sm:p-8\"><h1 class=\"text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white\">Create an account</h1><form class=\"space-y-4 md:space-y-6\" hx-post=\"")
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<section class=\"bg-gray-50 dark:bg-gray-900\" id=\"section\"><div class=\"flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0\"><div class=\"w-full bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md xl:p-0 dark:bg-gray-800 dark:border-gray-700\"><div class=\"p-6 space-y-4 md:space-y-6 sm:p-8\"><h1 class=\"text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white\">Create an account</h1><form class=\"space-y-4 md:space-y-6\" action=\"/signin\" method=\"post\" hx-post=\"/signin\" hx-swap=\"outerHTML\" hx-target=\"#section\"><div><label for=\"username\" class=\"block mb-2 text-sm font-medium text-gray-900 dark:text-white\">Username</label> <input type=\"text\" name=\"username\" id=\"username\" placeholder=\"Username\" class=\"bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500\" required=\"true\"></div><div><label for=\"password\" class=\"block mb-2 text-sm font-medium text-gray-900 dark:text-white\">Password</label> <input type=\"password\" name=\"password\" id=\"password\" placeholder=\"••••••••\" class=\"bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500\" required=\"true\"></div>")
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
var templ_7745c5c3_Var3 string
|
|
||||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(context.GetRouteByName("app.user.sign_in"))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/user/signin.templ`, Line: 21, Col: 59}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
|
||||||
if templ_7745c5c3_Err != nil {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" hx-swap=\"outerHTML\" hx-target=\"#section\"><div><label for=\"username\" class=\"block mb-2 text-sm font-medium text-gray-900 dark:text-white\">Username</label> <input type=\"text\" name=\"username\" id=\"username\" placeholder=\"Username\" class=\"bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500\" required=\"true\"></div><div><label for=\"password\" class=\"block mb-2 text-sm font-medium text-gray-900 dark:text-white\">Password</label> <input type=\"password\" name=\"password\" id=\"password\" placeholder=\"••••••••\" class=\"bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500\" required=\"true\"></div>")
|
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@ -68,12 +52,12 @@ func SignIn(err string, context controller.IControllerCtx) templ.Component {
|
|||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var4 string
|
var templ_7745c5c3_Var3 string
|
||||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(err)
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(err)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/user/signin.templ`, Line: 55, Col: 14}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/user/signin.templ`, Line: 54, Col: 14}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package user
|
package user
|
||||||
|
|
||||||
import "git.markbailey.dev/cerbervs/ptpp/view/layout"
|
import "git.markbailey.dev/cervers/ptpp/view/layout"
|
||||||
|
|
||||||
templ SignUpForm() {
|
templ SignUpForm() {
|
||||||
@layout.Layout() {
|
@layout.Layout() {
|
||||||
|
@ -8,7 +8,7 @@ package user
|
|||||||
import "github.com/a-h/templ"
|
import "github.com/a-h/templ"
|
||||||
import templruntime "github.com/a-h/templ/runtime"
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
import "git.markbailey.dev/cerbervs/ptpp/view/layout"
|
import "git.markbailey.dev/cervers/ptpp/view/layout"
|
||||||
|
|
||||||
func SignUpForm() templ.Component {
|
func SignUpForm() templ.Component {
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package user
|
package user
|
||||||
|
|
||||||
import "git.markbailey.dev/cerbervs/ptpp/view/layout"
|
import "git.markbailey.dev/cervers/ptpp/view/layout"
|
||||||
|
|
||||||
templ SignUpSuccess() {
|
templ SignUpSuccess() {
|
||||||
@layout.Layout() {
|
@layout.Layout() {
|
||||||
|
@ -8,7 +8,7 @@ package user
|
|||||||
import "github.com/a-h/templ"
|
import "github.com/a-h/templ"
|
||||||
import templruntime "github.com/a-h/templ/runtime"
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
import "git.markbailey.dev/cerbervs/ptpp/view/layout"
|
import "git.markbailey.dev/cervers/ptpp/view/layout"
|
||||||
|
|
||||||
func SignUpSuccess() templ.Component {
|
func SignUpSuccess() templ.Component {
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user