WIP: cyclic import problem
This commit is contained in:
parent
1ddf8f333e
commit
114b7b1387
19
app/app.go
Normal file
19
app/app.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
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()
|
||||||
|
}
|
97
app/controller/controller.go
Normal file
97
app/controller/controller.go
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/lib/logger"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/lib/database"
|
||||||
|
werror "git.markbailey.dev/cerbervs/ptpp/lib/error"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/lib/session"
|
||||||
|
)
|
||||||
|
|
||||||
|
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) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type Controller struct {
|
||||||
|
Session session.IManager
|
||||||
|
Db database.IDB
|
||||||
|
Logger logger.ILogger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Controller) Init(s session.IManager, d database.IDB, l logger.ILogger) error {
|
||||||
|
return werror.Wrap(nil, "You must implement the init method in your extended controller")
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
13
app/handler/handler.go
Normal file
13
app/handler/handler.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
type Handler func(http.ResponseWriter, *http.Request) error
|
||||||
|
|
||||||
|
func (fn Handler) 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)
|
||||||
|
}
|
||||||
|
}
|
121
app/routing/router.go
Normal file
121
app/routing/router.go
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
package routing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/app/controller"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/app/handler"
|
||||||
|
"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/lib/session"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/util/shared"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
var sess session.IManager
|
||||||
|
|
||||||
|
type IRouter interface {
|
||||||
|
RegisterRoutes() http.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
type Route struct {
|
||||||
|
Controller controller.IController
|
||||||
|
Path string
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Router struct {
|
||||||
|
Mux *http.ServeMux
|
||||||
|
BasePath string
|
||||||
|
Routes []Route
|
||||||
|
SubRouters *[]Router
|
||||||
|
Middleware *[]middleware.Func
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Router) HandleAllRequestMethods(route Route) {
|
||||||
|
r.Mux.Handle("GET "+r.BasePath+route.Path, handler.Handler(route.Controller.Get))
|
||||||
|
r.Mux.Handle("OPTIONS "+r.BasePath+route.Path, handler.Handler(route.Controller.Options))
|
||||||
|
r.Mux.Handle("TRACE "+r.BasePath+route.Path, handler.Handler(route.Controller.Trace))
|
||||||
|
r.Mux.Handle("PUT "+r.BasePath+route.Path, handler.Handler(route.Controller.Put))
|
||||||
|
r.Mux.Handle("DELETE "+r.BasePath+route.Path, handler.Handler(route.Controller.Delete))
|
||||||
|
r.Mux.Handle("POST "+r.BasePath+route.Path, handler.Handler(route.Controller.Post))
|
||||||
|
r.Mux.Handle("PATCH "+r.BasePath+route.Path, handler.Handler(route.Controller.Patch))
|
||||||
|
r.Mux.Handle("CONNECT "+r.BasePath+route.Path, handler.Handler(route.Controller.Connect))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Router) RegisterRoutes() http.Handler {
|
||||||
|
if r.Mux == nil {
|
||||||
|
r.Mux = http.NewServeMux()
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, route := range r.Routes {
|
||||||
|
if err := route.Controller.Init(sess, database.ChooseDB(), logger.NewCompositeLogger()); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.HandleAllRequestMethods(route)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.SubRouters != nil {
|
||||||
|
for _, subRouter := range *r.SubRouters {
|
||||||
|
sr := subRouter.RegisterRoutes()
|
||||||
|
r.Mux.Handle("GET "+r.BasePath+subRouter.BasePath, sr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Middleware != nil {
|
||||||
|
mw := middleware.Compose(*r.Middleware)
|
||||||
|
return mw(r.Mux)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.Mux
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Router) RegisterFs() {
|
||||||
|
if r.Mux == nil {
|
||||||
|
r.Mux = http.NewServeMux()
|
||||||
|
}
|
||||||
|
|
||||||
|
fs := http.FileServer(http.Dir(shared.GetFullyQualifiedPath("/public")))
|
||||||
|
log.Println("Serving static files from: " + shared.GetFullyQualifiedPath("/public"))
|
||||||
|
r.Mux.Handle("GET "+r.BasePath+"public/", http.StripPrefix("/public/", fs))
|
||||||
|
}
|
||||||
|
|
||||||
|
type RouteMapping struct {
|
||||||
|
Path string
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFlatRouteList(r Router) []RouteMapping {
|
||||||
|
var routes []RouteMapping
|
||||||
|
|
||||||
|
for _, route := range r.Routes {
|
||||||
|
routes = append(routes, RouteMapping{Path: route.Path, Name: route.Name})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, subRouter := range *r.SubRouters {
|
||||||
|
routes = append(routes, GetFlatRouteList(subRouter)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return routes
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRouteByName(name string) (string, error) {
|
||||||
|
r := AppRouter
|
||||||
|
for _, route := range GetFlatRouteList(r) {
|
||||||
|
if route.Name == name {
|
||||||
|
return route.Path, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", werror.Wrap(nil, "Route not found")
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
sess, err = session.NewManager("memory", "ptpp", 3600)
|
||||||
|
if err != nil {
|
||||||
|
panic(werror.Wrap(err, "Error creating session manager"))
|
||||||
|
}
|
||||||
|
}
|
32
app/routing/routes.go
Normal file
32
app/routing/routes.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package routing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/handlers/admin"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/handlers/shared"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/lib/middleware"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
var AppRouter = Router{
|
||||||
|
Mux: http.NewServeMux(),
|
||||||
|
BasePath: "/",
|
||||||
|
Routes: []Route{
|
||||||
|
{Controller: &shared.HomePageHandler{}, 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},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
25
app/server/server.go
Normal file
25
app/server/server.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
57
cmd/main.go
57
cmd/main.go
@ -1,10 +1,61 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
inf "git.markbailey.dev/cervers/ptpp/infrastructure"
|
"git.markbailey.dev/cerbervs/ptpp/app"
|
||||||
_ "git.markbailey.dev/cervers/ptpp/lib/session/memory"
|
"git.markbailey.dev/cerbervs/ptpp/app/routing"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/app/server"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
_ "git.markbailey.dev/cerbervs/ptpp/lib/session/memory"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
inf.NewServer().Serve()
|
const (
|
||||||
|
addr = "0.0.0.0"
|
||||||
|
prodPort = 8080
|
||||||
|
devPort = 8080
|
||||||
|
)
|
||||||
|
|
||||||
|
r := routing.AppRouter
|
||||||
|
|
||||||
|
rh := r.RegisterRoutes()
|
||||||
|
r.RegisterFs()
|
||||||
|
|
||||||
|
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: rh,
|
||||||
|
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()
|
||||||
}
|
}
|
||||||
|
2
go.mod
2
go.mod
@ -1,4 +1,4 @@
|
|||||||
module git.markbailey.dev/cervers/ptpp
|
module git.markbailey.dev/cerbervs/ptpp
|
||||||
|
|
||||||
go 1.23.2
|
go 1.23.2
|
||||||
|
|
||||||
|
@ -3,32 +3,34 @@ package admin
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"git.markbailey.dev/cervers/ptpp/view/layout"
|
"git.markbailey.dev/cerbervs/ptpp/app/controller"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/lib/database"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/lib/logger"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/lib/session"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/view/layout"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.markbailey.dev/cervers/ptpp/lib/logger"
|
"git.markbailey.dev/cerbervs/ptpp/view/admin"
|
||||||
"git.markbailey.dev/cervers/ptpp/lib/session"
|
|
||||||
"git.markbailey.dev/cervers/ptpp/view/admin"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexHandler struct {
|
type IndexHandler struct {
|
||||||
logger logger.ILogger
|
controller.Controller
|
||||||
session session.IManager
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAdminIndexHandler(l logger.ILogger, s session.IManager) *IndexHandler {
|
func (h IndexHandler) Init(s session.IManager, d database.IDB, l logger.ILogger) error {
|
||||||
return &IndexHandler{
|
h.Logger = l
|
||||||
logger: l,
|
h.Db = d
|
||||||
session: s,
|
h.Session = s
|
||||||
}
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h IndexHandler) Index(w http.ResponseWriter, r *http.Request) error {
|
func (h IndexHandler) Get(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
|
||||||
@ -37,12 +39,12 @@ func (h IndexHandler) Index(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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
45
handlers/shared/homepage.go
Normal file
45
handlers/shared/homepage.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package shared
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/app/controller"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/lib/database"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/lib/logger"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/lib/session"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/view/layout"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/view/homepage"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HomePageHandler struct {
|
||||||
|
controller.Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h HomePageHandler) Init(s session.IManager, d database.IDB, l logger.ILogger) error {
|
||||||
|
h.Logger = l
|
||||||
|
h.Db = d
|
||||||
|
h.Session = s
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h HomePageHandler) 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")).Render(context.Background(), w); err != nil {
|
||||||
|
h.Logger.Error(h.Logger.Wrap(err, "Error rendering homepage"))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
353
handlers/shared/user.go
Normal file
353
handlers/shared/user.go
Normal file
@ -0,0 +1,353 @@
|
|||||||
|
package shared
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/app/controller"
|
||||||
|
"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/lib/session"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/util/auth"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/util/shared"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/view/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SignUpHandler struct {
|
||||||
|
controller.Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c SignUpHandler) Init(s session.IManager, d database.IDB, l logger.ILogger) error {
|
||||||
|
c.Logger = l
|
||||||
|
c.Db = d
|
||||||
|
c.Session = s
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type SignInHandler struct {
|
||||||
|
controller.Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c SignInHandler) Init(s session.IManager, d database.IDB, l logger.ILogger) error {
|
||||||
|
c.Logger = l
|
||||||
|
c.Db = d
|
||||||
|
c.Session = s
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type PopulateHandler struct {
|
||||||
|
controller.Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c PopulateHandler) Init(s session.IManager, d database.IDB, l logger.ILogger) error {
|
||||||
|
c.Logger = l
|
||||||
|
c.Db = d
|
||||||
|
c.Session = s
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type SignOutHandler struct {
|
||||||
|
controller.Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c SignOutHandler) Init(s session.IManager, d database.IDB, l logger.ILogger) error {
|
||||||
|
c.Logger = l
|
||||||
|
c.Db = d
|
||||||
|
c.Session = s
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c PopulateHandler) Get(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
existingOrg, err := c.Db.Repo().FindOrganizationByName("CerbervsSoft")
|
||||||
|
if existingOrg != nil && err == nil {
|
||||||
|
return shared.Redirect(w, r, "/signup", http.StatusSeeOther, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
authToken, err := auth.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 shared.Redirect(w, r, "/signup", http.StatusSeeOther, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 shared.Redirect(w, r, "/admin/", http.StatusSeeOther, false)
|
||||||
|
} else {
|
||||||
|
return shared.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 {
|
||||||
|
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 shared.Redirect(w, r, "/sign-in", http.StatusSeeOther, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticated, err := auth.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 := auth.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 := auth.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 := auth.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 shared.Redirect(w, r, "/admin/", http.StatusSeeOther, false)
|
||||||
|
} else {
|
||||||
|
return shared.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 (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 shared.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 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 := auth.CreateTokenForUser(fd.Username)
|
||||||
|
if err != nil {
|
||||||
|
c.Logger.Error(c.Logger.Wrap(err, "Error creating token"))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
password, err := auth.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 := auth.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 shared.Redirect(w, r, "/sign-in", http.StatusSeeOther, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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 shared.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 shared.Redirect(w, r, r.URL.Path, http.StatusSeeOther, false)
|
||||||
|
}
|
315
handlers/user.go
315
handlers/user.go
@ -1,315 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
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()
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
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/cervers/ptpp/lib/database/development"
|
"git.markbailey.dev/cerbervs/ptpp/lib/database/development"
|
||||||
"git.markbailey.dev/cervers/ptpp/lib/database/production"
|
"git.markbailey.dev/cerbervs/ptpp/lib/database/production"
|
||||||
"git.markbailey.dev/cervers/ptpp/lib/repository"
|
"git.markbailey.dev/cerbervs/ptpp/lib/repository"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.markbailey.dev/cervers/ptpp/lib/logger"
|
"git.markbailey.dev/cerbervs/ptpp/lib/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IDB interface {
|
type IDB interface {
|
||||||
|
@ -2,9 +2,9 @@ package development
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"git.markbailey.dev/cervers/ptpp/lib/logger"
|
"git.markbailey.dev/cerbervs/ptpp/lib/logger"
|
||||||
"git.markbailey.dev/cervers/ptpp/lib/repository"
|
"git.markbailey.dev/cerbervs/ptpp/lib/repository"
|
||||||
"git.markbailey.dev/cervers/ptpp/models/sqlite"
|
"git.markbailey.dev/cerbervs/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/cervers/ptpp/lib/database/dto"
|
"git.markbailey.dev/cerbervs/ptpp/lib/database/dto"
|
||||||
pterror "git.markbailey.dev/cervers/ptpp/lib/error"
|
pterror "git.markbailey.dev/cerbervs/ptpp/lib/error"
|
||||||
"git.markbailey.dev/cervers/ptpp/models/sqlite"
|
"git.markbailey.dev/cerbervs/ptpp/models/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HeartbeatRepository struct{}
|
type HeartbeatRepository struct{}
|
||||||
|
@ -2,9 +2,9 @@ package development
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"git.markbailey.dev/cervers/ptpp/lib/database/dto"
|
"git.markbailey.dev/cerbervs/ptpp/lib/database/dto"
|
||||||
pterror "git.markbailey.dev/cervers/ptpp/lib/error"
|
pterror "git.markbailey.dev/cerbervs/ptpp/lib/error"
|
||||||
"git.markbailey.dev/cervers/ptpp/models/sqlite"
|
"git.markbailey.dev/cerbervs/ptpp/models/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OrganizationRepository struct{}
|
type OrganizationRepository struct{}
|
||||||
|
@ -2,9 +2,9 @@ package development
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"git.markbailey.dev/cervers/ptpp/lib/database/dto"
|
"git.markbailey.dev/cerbervs/ptpp/lib/database/dto"
|
||||||
pterror "git.markbailey.dev/cervers/ptpp/lib/error"
|
pterror "git.markbailey.dev/cerbervs/ptpp/lib/error"
|
||||||
"git.markbailey.dev/cervers/ptpp/models/sqlite"
|
"git.markbailey.dev/cerbervs/ptpp/models/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UserRepository struct{}
|
type UserRepository struct{}
|
||||||
|
@ -2,9 +2,9 @@ package production
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"git.markbailey.dev/cervers/ptpp/lib/logger"
|
"git.markbailey.dev/cerbervs/ptpp/lib/logger"
|
||||||
"git.markbailey.dev/cervers/ptpp/lib/repository"
|
"git.markbailey.dev/cerbervs/ptpp/lib/repository"
|
||||||
"git.markbailey.dev/cervers/ptpp/models/postgres"
|
"git.markbailey.dev/cerbervs/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/cervers/ptpp/lib/database/dto"
|
"git.markbailey.dev/cerbervs/ptpp/lib/database/dto"
|
||||||
pterror "git.markbailey.dev/cervers/ptpp/lib/error"
|
pterror "git.markbailey.dev/cerbervs/ptpp/lib/error"
|
||||||
"git.markbailey.dev/cervers/ptpp/models/postgres"
|
"git.markbailey.dev/cerbervs/ptpp/models/postgres"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HeartbeatRepository struct{}
|
type HeartbeatRepository struct{}
|
||||||
|
@ -2,9 +2,9 @@ package production
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"git.markbailey.dev/cervers/ptpp/lib/database/dto"
|
"git.markbailey.dev/cerbervs/ptpp/lib/database/dto"
|
||||||
pterror "git.markbailey.dev/cervers/ptpp/lib/error"
|
pterror "git.markbailey.dev/cerbervs/ptpp/lib/error"
|
||||||
"git.markbailey.dev/cervers/ptpp/models/postgres"
|
"git.markbailey.dev/cerbervs/ptpp/models/postgres"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OrganizationRepository struct{}
|
type OrganizationRepository struct{}
|
||||||
|
@ -2,9 +2,9 @@ package production
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"git.markbailey.dev/cervers/ptpp/lib/database/dto"
|
"git.markbailey.dev/cerbervs/ptpp/lib/database/dto"
|
||||||
pterror "git.markbailey.dev/cervers/ptpp/lib/error"
|
pterror "git.markbailey.dev/cerbervs/ptpp/lib/error"
|
||||||
"git.markbailey.dev/cervers/ptpp/models/postgres"
|
"git.markbailey.dev/cerbervs/ptpp/models/postgres"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UserRepository struct{}
|
type UserRepository struct{}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package locator
|
package locator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
perr "git.markbailey.dev/cervers/ptpp/lib/error"
|
perr "git.markbailey.dev/cerbervs/ptpp/lib/error"
|
||||||
"git.markbailey.dev/cervers/ptpp/lib/locator/service"
|
"git.markbailey.dev/cerbervs/ptpp/lib/locator/service"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.markbailey.dev/cervers/ptpp/lib/database"
|
"git.markbailey.dev/cerbervs/ptpp/lib/database"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.markbailey.dev/cervers/ptpp/lib/logger"
|
"git.markbailey.dev/cerbervs/ptpp/lib/logger"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@ package logger
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
pterror "git.markbailey.dev/cervers/ptpp/lib/error"
|
pterror "git.markbailey.dev/cerbervs/ptpp/lib/error"
|
||||||
"git.markbailey.dev/cervers/ptpp/util"
|
"git.markbailey.dev/cerbervs/ptpp/util/shared"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
@ -44,7 +44,7 @@ func (l CompositeLogger) getLogFile() *os.File {
|
|||||||
compositeLogFileLock.Lock()
|
compositeLogFileLock.Lock()
|
||||||
defer compositeLogFileLock.Unlock()
|
defer compositeLogFileLock.Unlock()
|
||||||
|
|
||||||
absPath := util.GetFullyQualifiedPath("/log")
|
absPath := shared.GetFullyQualifiedPath("/log")
|
||||||
|
|
||||||
err := os.MkdirAll(absPath, os.ModePerm)
|
err := os.MkdirAll(absPath, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -2,8 +2,8 @@ package logger
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
pterror "git.markbailey.dev/cervers/ptpp/lib/error"
|
pterror "git.markbailey.dev/cerbervs/ptpp/lib/error"
|
||||||
"git.markbailey.dev/cervers/ptpp/util"
|
"git.markbailey.dev/cerbervs/ptpp/util/shared"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
@ -44,7 +44,7 @@ func (l DBLogger) getLogFile() *os.File {
|
|||||||
dbLogFileLock.Lock()
|
dbLogFileLock.Lock()
|
||||||
defer dbLogFileLock.Unlock()
|
defer dbLogFileLock.Unlock()
|
||||||
|
|
||||||
absPath := util.GetFullyQualifiedPath("/log")
|
absPath := shared.GetFullyQualifiedPath("/log")
|
||||||
|
|
||||||
generalLog, err := os.OpenFile(absPath+"/db-log.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
generalLog, err := os.OpenFile(absPath+"/db-log.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -2,38 +2,20 @@ package middleware
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.markbailey.dev/cervers/ptpp/lib/database"
|
"git.markbailey.dev/cerbervs/ptpp/util/auth"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/util/shared"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.markbailey.dev/cervers/ptpp/lib/logger"
|
"git.markbailey.dev/cerbervs/ptpp/lib/logger"
|
||||||
"git.markbailey.dev/cervers/ptpp/lib/session"
|
"git.markbailey.dev/cerbervs/ptpp/lib/session"
|
||||||
"git.markbailey.dev/cervers/ptpp/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Middleware struct {
|
type Func func(http.Handler) http.Handler
|
||||||
l logger.ILogger
|
|
||||||
db database.IDB
|
|
||||||
}
|
|
||||||
|
|
||||||
type (
|
var sess session.IManager
|
||||||
ErrHandler func(http.ResponseWriter, *http.Request) error
|
|
||||||
Func func(http.Handler) http.Handler
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
func Compose(xs []Func) Func {
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Compose(xs ...Func) Func {
|
|
||||||
return func(next http.Handler) http.Handler {
|
return func(next http.Handler) http.Handler {
|
||||||
for i := len(xs) - 1; i >= 0; i-- {
|
for i := len(xs) - 1; i >= 0; i-- {
|
||||||
x := xs[i]
|
x := xs[i]
|
||||||
@ -78,7 +60,7 @@ func WithLogger(next http.Handler) http.Handler {
|
|||||||
func WithAuth(next http.Handler) 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 *auth.CustomClaims
|
||||||
cookie *http.Cookie
|
cookie *http.Cookie
|
||||||
err error
|
err error
|
||||||
token string
|
token string
|
||||||
@ -86,7 +68,7 @@ func WithAuth(next http.Handler) http.Handler {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if handlerSess.Get("username") != nil {
|
if handlerSess.Get("username") != nil {
|
||||||
req := util.AddValuesToRequestContext(r, map[any]any{
|
req := shared.AddValuesToRequestContext(r, map[any]any{
|
||||||
"username": handlerSess.Get("username"),
|
"username": handlerSess.Get("username"),
|
||||||
})
|
})
|
||||||
next.ServeHTTP(w, req)
|
next.ServeHTTP(w, req)
|
||||||
@ -94,19 +76,19 @@ func WithAuth(next http.Handler) http.Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cookie, err = r.Cookie("token"); err != nil {
|
if cookie, err = r.Cookie("token"); err != nil {
|
||||||
_ = util.Redirect(w, r, "/signin", http.StatusSeeOther, true)
|
_ = shared.Redirect(w, r, "/signin", http.StatusSeeOther, true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if token = cookie.Value; token == "" {
|
if token = cookie.Value; token == "" {
|
||||||
_ = util.Redirect(w, r, "/signin", http.StatusSeeOther, true)
|
_ = shared.Redirect(w, r, "/signin", http.StatusSeeOther, true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if claims, err = util.ParseToken(token, os.Getenv("TOKEN_SECRET")); err != nil {
|
if claims, err = auth.ParseToken(token, os.Getenv("TOKEN_SECRET")); err != nil {
|
||||||
_ = util.Redirect(w, r, "/signin", http.StatusSeeOther, true)
|
_ = shared.Redirect(w, r, "/signin", http.StatusSeeOther, true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req := util.AddValuesToRequestContext(r, map[any]any{
|
req := shared.AddValuesToRequestContext(r, map[any]any{
|
||||||
"username": claims.Username,
|
"username": claims.Username,
|
||||||
})
|
})
|
||||||
next.ServeHTTP(w, req)
|
next.ServeHTTP(w, req)
|
||||||
@ -116,7 +98,7 @@ func WithAuth(next http.Handler) http.Handler {
|
|||||||
func WithUsername(next http.Handler) 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 *auth.CustomClaims
|
||||||
cookie *http.Cookie
|
cookie *http.Cookie
|
||||||
err error
|
err error
|
||||||
token string
|
token string
|
||||||
@ -124,7 +106,7 @@ func WithUsername(next http.Handler) http.Handler {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if handlerSess.Get("username") != nil {
|
if handlerSess.Get("username") != nil {
|
||||||
req := util.AddValuesToRequestContext(r, map[any]any{
|
req := shared.AddValuesToRequestContext(r, map[any]any{
|
||||||
"username": handlerSess.Get("username"),
|
"username": handlerSess.Get("username"),
|
||||||
})
|
})
|
||||||
next.ServeHTTP(w, req)
|
next.ServeHTTP(w, req)
|
||||||
@ -136,14 +118,14 @@ func WithUsername(next http.Handler) http.Handler {
|
|||||||
if token = cookie.Value; token == "" {
|
if token = cookie.Value; token == "" {
|
||||||
uname = nil
|
uname = nil
|
||||||
}
|
}
|
||||||
if claims, err = util.ParseToken(token, os.Getenv("TOKEN_SECRET")); err != nil {
|
if claims, err = auth.ParseToken(token, os.Getenv("TOKEN_SECRET")); err != nil {
|
||||||
uname = nil
|
uname = nil
|
||||||
}
|
}
|
||||||
uname = &claims.Username
|
uname = &claims.Username
|
||||||
}
|
}
|
||||||
|
|
||||||
if uname != nil {
|
if uname != nil {
|
||||||
req := util.AddValuesToRequestContext(r, map[any]any{
|
req := shared.AddValuesToRequestContext(r, map[any]any{
|
||||||
"username": uname,
|
"username": uname,
|
||||||
})
|
})
|
||||||
next.ServeHTTP(w, req)
|
next.ServeHTTP(w, req)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package repository
|
package repository
|
||||||
|
|
||||||
import "git.markbailey.dev/cervers/ptpp/lib/database/dto"
|
import "git.markbailey.dev/cerbervs/ptpp/lib/database/dto"
|
||||||
|
|
||||||
type IHeartbeat interface {
|
type IHeartbeat interface {
|
||||||
CreateHeartbeat(h *dto.Heartbeat) (*dto.Heartbeat, error)
|
CreateHeartbeat(h *dto.Heartbeat) (*dto.Heartbeat, error)
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.markbailey.dev/cervers/ptpp/lib/session"
|
"git.markbailey.dev/cerbervs/ptpp/lib/session"
|
||||||
)
|
)
|
||||||
|
|
||||||
var prov = &Provider{list: list.New()}
|
var prov = &Provider{list: list.New()}
|
||||||
|
148
package-lock.json
generated
148
package-lock.json
generated
@ -1,16 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "ptpp",
|
"name": "go-full-stack",
|
||||||
"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.1"
|
"tailwindcss": "^3.4.15"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@alloc/quick-lru": {
|
"node_modules/@alloc/quick-lru": {
|
||||||
@ -135,15 +134,6 @@
|
|||||||
"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",
|
||||||
@ -231,12 +221,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/braces": {
|
"node_modules/braces": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fill-range": "^7.0.1"
|
"fill-range": "^7.1.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
@ -333,6 +324,7 @@
|
|||||||
"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"
|
||||||
},
|
},
|
||||||
@ -402,10 +394,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fill-range": {
|
"node_modules/fill-range": {
|
||||||
"version": "7.0.1",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"to-regex-range": "^5.0.1"
|
"to-regex-range": "^5.0.1"
|
||||||
},
|
},
|
||||||
@ -562,6 +555,7 @@
|
|||||||
"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"
|
||||||
}
|
}
|
||||||
@ -591,10 +585,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jiti": {
|
"node_modules/jiti": {
|
||||||
"version": "1.21.0",
|
"version": "1.21.6",
|
||||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz",
|
||||||
"integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==",
|
"integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"jiti": "bin/jiti.js"
|
"jiti": "bin/jiti.js"
|
||||||
}
|
}
|
||||||
@ -633,12 +628,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/micromatch": {
|
"node_modules/micromatch": {
|
||||||
"version": "4.0.5",
|
"version": "4.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||||
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
|
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"braces": "^3.0.2",
|
"braces": "^3.0.3",
|
||||||
"picomatch": "^2.3.1"
|
"picomatch": "^2.3.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -766,10 +762,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
"version": "1.0.0",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
|
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/picomatch": {
|
"node_modules/picomatch": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
@ -802,9 +799,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.35",
|
"version": "8.4.49",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
|
||||||
"integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==",
|
"integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -820,10 +817,11 @@
|
|||||||
"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.0.0",
|
"picocolors": "^1.1.1",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^10 || ^12 || >=14"
|
"node": "^10 || ^12 || >=14"
|
||||||
@ -910,29 +908,37 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-nested": {
|
"node_modules/postcss-nested": {
|
||||||
"version": "6.0.1",
|
"version": "6.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
|
||||||
"integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
|
"integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
|
||||||
"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.0.11"
|
"postcss-selector-parser": "^6.1.1"
|
||||||
},
|
},
|
||||||
"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.0.15",
|
"version": "6.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
|
||||||
"integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==",
|
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
|
||||||
"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"
|
||||||
@ -947,14 +953,6 @@
|
|||||||
"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",
|
||||||
@ -1080,10 +1078,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/source-map-js": {
|
"node_modules/source-map-js": {
|
||||||
"version": "1.0.2",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||||
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
|
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@ -1219,33 +1218,34 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tailwindcss": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "3.4.1",
|
"version": "3.4.15",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.15.tgz",
|
||||||
"integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==",
|
"integrity": "sha512-r4MeXnfBmSOuKUWmXe6h2CcyfzJCEk4F0pptO5jlnYSIViUkVmsawj80N5h2lO3gwcmSb4n3PuN+e+GC1Guylw==",
|
||||||
"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.5.3",
|
"chokidar": "^3.6.0",
|
||||||
"didyoumean": "^1.2.2",
|
"didyoumean": "^1.2.2",
|
||||||
"dlv": "^1.1.3",
|
"dlv": "^1.1.3",
|
||||||
"fast-glob": "^3.3.0",
|
"fast-glob": "^3.3.2",
|
||||||
"glob-parent": "^6.0.2",
|
"glob-parent": "^6.0.2",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
"jiti": "^1.19.1",
|
"jiti": "^1.21.6",
|
||||||
"lilconfig": "^2.1.0",
|
"lilconfig": "^2.1.0",
|
||||||
"micromatch": "^4.0.5",
|
"micromatch": "^4.0.8",
|
||||||
"normalize-path": "^3.0.0",
|
"normalize-path": "^3.0.0",
|
||||||
"object-hash": "^3.0.0",
|
"object-hash": "^3.0.0",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.1.1",
|
||||||
"postcss": "^8.4.23",
|
"postcss": "^8.4.47",
|
||||||
"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.1",
|
"postcss-load-config": "^4.0.2",
|
||||||
"postcss-nested": "^6.0.1",
|
"postcss-nested": "^6.2.0",
|
||||||
"postcss-selector-parser": "^6.0.11",
|
"postcss-selector-parser": "^6.1.2",
|
||||||
"resolve": "^1.22.2",
|
"resolve": "^1.22.8",
|
||||||
"sucrase": "^3.32.0"
|
"sucrase": "^3.35.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"tailwind": "lib/cli.js",
|
"tailwind": "lib/cli.js",
|
||||||
@ -1281,6 +1281,7 @@
|
|||||||
"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"
|
||||||
},
|
},
|
||||||
@ -1298,7 +1299,8 @@
|
|||||||
"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,10 +1,9 @@
|
|||||||
{
|
{
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/forms": "^0.5.9",
|
"@tailwindcss/forms": "^0.5.9",
|
||||||
"tailwindcss": "^3.4.1"
|
"tailwindcss": "^3.4.15"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"htmx.org": "^1.9.10",
|
"htmx.org": "^1.9.10"
|
||||||
"preline": "^2.0.3"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package util
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
@ -1,4 +1,4 @@
|
|||||||
package util
|
package shared
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
@ -1,6 +1,6 @@
|
|||||||
package admin
|
package admin
|
||||||
|
|
||||||
import "git.markbailey.dev/cervers/ptpp/view/layout"
|
import "git.markbailey.dev/cerbervs/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/cervers/ptpp/view/layout"
|
import "git.markbailey.dev/cerbervs/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,6 +1,9 @@
|
|||||||
package homepage
|
package homepage
|
||||||
|
|
||||||
import "git.markbailey.dev/cervers/ptpp/view/layout"
|
import (
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/view/layout"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/app/routing"
|
||||||
|
)
|
||||||
|
|
||||||
templ Homepage(env string) {
|
templ Homepage(env string) {
|
||||||
@layout.Layout() {
|
@layout.Layout() {
|
||||||
@ -8,20 +11,18 @@ templ Homepage(env string) {
|
|||||||
<div>
|
<div>
|
||||||
Welcome to the homepage
|
Welcome to the homepage
|
||||||
</div>
|
</div>
|
||||||
if env == "development" {
|
<div>
|
||||||
<div>
|
<a href='{ routing.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='{ routing.GetRouteByName("app.user.sign_up") }'>
|
||||||
<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,7 +8,10 @@ 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 "git.markbailey.dev/cervers/ptpp/view/layout"
|
import (
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/app/routing"
|
||||||
|
"git.markbailey.dev/cerbervs/ptpp/view/layout"
|
||||||
|
)
|
||||||
|
|
||||||
func Homepage(env string) 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) {
|
||||||
@ -43,17 +46,7 @@ func Homepage(env string) 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>")
|
_, 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=\"{ routing.GetRouteByName("app.user.sign_up") }\"><button class=\"text-gray-400 text-md border-black rounded-lg bg-gray-300 p-2\">Sign Up</button></a> <a href=\"{ routing.GetRouteByName("app.user.sign_up") }\"><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 {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
if env == "development" {
|
|
||||||
_, 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 {
|
|
||||||
return templ_7745c5c3_Err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</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-5*="this">
|
<div id="#layout_content" hx-ext="response-targets" hx-target-error="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-5*=\"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-error=\"this\">")
|
||||||
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/cervers/ptpp/view/layout"
|
import "git.markbailey.dev/cerbervs/ptpp/view/layout"
|
||||||
|
|
||||||
templ SignIn(err string) {
|
templ SignIn(err string) {
|
||||||
@layout.Layout() {
|
@layout.Layout() {
|
||||||
@ -15,7 +15,7 @@ templ SignIn(err string) {
|
|||||||
</h1>
|
</h1>
|
||||||
<form
|
<form
|
||||||
class="space-y-4 md:space-y-6"
|
class="space-y-4 md:space-y-6"
|
||||||
action="/signin"
|
action="/sign-in"
|
||||||
method="post"
|
method="post"
|
||||||
hx-post="/signin"
|
hx-post="/signin"
|
||||||
hx-swap="outerHTML"
|
hx-swap="outerHTML"
|
||||||
|
@ -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/cervers/ptpp/view/layout"
|
import "git.markbailey.dev/cerbervs/ptpp/view/layout"
|
||||||
|
|
||||||
func SignIn(err string) 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) {
|
||||||
@ -43,7 +43,7 @@ func SignIn(err string) 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\" 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>")
|
_, 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=\"/sign-in\" 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 {
|
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/cervers/ptpp/view/layout"
|
import "git.markbailey.dev/cerbervs/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/cervers/ptpp/view/layout"
|
import "git.markbailey.dev/cerbervs/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/cervers/ptpp/view/layout"
|
import "git.markbailey.dev/cerbervs/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/cervers/ptpp/view/layout"
|
import "git.markbailey.dev/cerbervs/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