From 09f66cfaa4d6ad369794fa8f128625114fa286ad Mon Sep 17 00:00:00 2001 From: Sky Johnson Date: Sat, 16 Aug 2025 12:25:16 -0500 Subject: [PATCH] update readme, add form handlers for fluent parsing --- README.md | 71 +++++++++++++++++------------------ forms.go | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 37 deletions(-) create mode 100644 forms.go diff --git a/README.md b/README.md index 09f94a7..84a866d 100644 --- a/README.md +++ b/README.md @@ -7,19 +7,16 @@ A fast, raw, tasty framework for simplifying basic web apps! ```go package main -import ( - "git.sharkk.net/Sharkk/Sushi" - "git.sharkk.net/Sharkk/Sushi/session" -) +import "git.sharkk.net/Sharkk/Sushi" func main() { app := sushi.New() // Initialize sessions - session.InitSessions("sessions.json") + sushi.InitSessions("sessions.json") app.Get("/", func(ctx sushi.Ctx, params []any) { - sushi.SendHTML(ctx, "

Hello Sushi!

") + ctx.SendHTML("

Hello Sushi!

") }) app.Listen(":8080") @@ -156,7 +153,7 @@ func main() { app := sushi.New() // Initialize sessions - session.InitSessions("sessions.json") + sushi.InitSessions("sessions.json") // Add session middleware app.Use(session.Middleware()) @@ -179,7 +176,7 @@ func main() { ### 4. Login Handler ```go -func loginHandler(ctx sushi.Ctx, params []string) { +func loginHandler(ctx sushi.Ctx, params []any) { email := string(ctx.PostArgs().Peek("email")) password := string(ctx.PostArgs().Peek("password")) @@ -198,7 +195,7 @@ func loginHandler(ctx sushi.Ctx, params []string) { } // Log the user in - auth.Login(ctx, user.ID, user) + ctx.Login(user.ID, user) ctx.Redirect("/dashboard") } @@ -207,17 +204,17 @@ func loginHandler(ctx sushi.Ctx, params []string) { ### 5. Logout Handler ```go -func logoutHandler(ctx sushi.Ctx, params []string) { - auth.Logout(ctx) - ctx.SendRedirect("/") +func logoutHandler(ctx sushi.Ctx, params []any) { + ctx.Logout() + ctx.Redirect("/") } ``` ### 6. Getting Current User ```go -func dashboardHandler(ctx sushi.Ctx, params []string) { - user := auth.GetCurrentUser(ctx).(*User) +func dashboardHandler(ctx sushi.Ctx, params []any) { + user := ctx.GetCurrentUser().(*User) html := fmt.Sprintf("

Welcome, %s!

", user.Username) ctx.SendHTML(html) @@ -233,7 +230,7 @@ import "git.sharkk.net/Sharkk/Sushi/csrf" app.Use(csrf.Middleware()) // In your form template -func loginPageHandler(ctx sushi.Ctx, params []string) { +func loginPageHandler(ctx sushi.Ctx, params []any) { csrfField := csrf.CSRFHiddenField(ctx) html := fmt.Sprintf(` @@ -269,8 +266,8 @@ app.Get("/assets/*path", sushi.StaticEmbed(files)) ## Sessions ```go -func someHandler(ctx sushi.Ctx, params []string) { - sess := session.GetCurrentSession(ctx) +func someHandler(ctx sushi.Ctx, params []any) { + sess := ctx.GetCurrentSession() // Set session data sess.Set("user_preference", "dark_mode") @@ -341,7 +338,7 @@ func findUserByEmail(email string) *User { func main() { app := sushi.New() - session.InitSessions("sessions.json") + sushi.InitSessions("sessions.json") app.Use(session.Middleware()) app.Use(auth.Middleware(getUserByID)) @@ -360,15 +357,15 @@ func main() { app.Listen(":8080") } -func homeHandler(ctx sushi.Ctx, params []string) { - if auth.IsAuthenticated(ctx) { - ctx.SendRedirect("/dashboard") +func homeHandler(ctx sushi.Ctx, params []any) { + if ctx.IsAuthenticated() { + ctx.Redirect("/dashboard") return } - ctx.SendHTML(c`Login`) + ctx.SendHTML(`Login`) } -func loginPageHandler(ctx sushi.Ctx, params []string) { +func loginPageHandler(ctx sushi.Ctx, params []any) { html := fmt.Sprintf(`
%s @@ -376,32 +373,32 @@ func loginPageHandler(ctx sushi.Ctx, params []string) {
- `, csrf.CSRFHiddenField(ctx)) + `, csrf.HiddenField(ctx)) - sushi.SendHTML(ctx, html) + ctx.SendHTML(html) } -func loginHandler(ctx sushi.Ctx, params []string) { +func loginHandler(ctx sushi.Ctx, params []any) { email := string(ctx.PostArgs().Peek("email")) pass := string(ctx.PostArgs().Peek("password")) user := findUserByEmail(email) if user == nil { - sushi.SendError(ctx, 401, "Invalid credentials") + ctx.SendError(401, "Invalid credentials") return } if valid, _ := password.VerifyPassword(pass, user.Password); !valid { - sushi.SendError(ctx, 401, "Invalid credentials") + ctx.SendError(401, "Invalid credentials") return } - auth.Login(ctx, user.ID, user) - sushi.SendRedirect(ctx, "/dashboard") + ctx.Login(user.ID, user) + ctx.Redirect("/dashboard") } -func dashboardHandler(ctx sushi.Ctx, params []string) { - user := auth.GetCurrentUser(ctx).(*User) +func dashboardHandler(ctx sushi.Ctx, params []any) { + user := ctx.GetCurrentUser().(*User) html := fmt.Sprintf(`

Welcome, %s!

@@ -409,13 +406,13 @@ func dashboardHandler(ctx sushi.Ctx, params []string) { %s - `, user.Email, csrf.CSRFHiddenField(ctx)) + `, user.Email, csrf.HiddenField(ctx)) - sushi.SendHTML(ctx, html) + ctx.SendHTML(html) } -func logoutHandler(ctx sushi.Ctx, params []string) { - auth.Logout(ctx) - sushi.SendRedirect(ctx, "/") +func logoutHandler(ctx sushi.Ctx, params []any) { + ctx.Logout() + ctx.Redirect("/") } ``` diff --git a/forms.go b/forms.go new file mode 100644 index 0000000..b66522f --- /dev/null +++ b/forms.go @@ -0,0 +1,110 @@ +package sushi + +import ( + "strconv" + "strings" +) + +type FormValue struct { + value string + exists bool +} + +// Form gets a form field for chaining +func (ctx Ctx) Form(key string) FormValue { + value := string(ctx.PostArgs().Peek(key)) + exists := ctx.PostArgs().Has(key) + return FormValue{value: value, exists: exists} +} + +// String returns the value as string +func (f FormValue) String() string { + return f.value +} + +// StringDefault returns string with default value +func (f FormValue) StringDefault(defaultValue string) string { + if f.value == "" { + return defaultValue + } + return f.value +} + +// Int returns the value as integer +func (f FormValue) Int() int { + if f.value == "" { + return 0 + } + if parsed, err := strconv.Atoi(f.value); err == nil { + return parsed + } + return 0 +} + +// IntDefault returns integer with default value +func (f FormValue) IntDefault(defaultValue int) int { + if f.value == "" { + return defaultValue + } + if parsed, err := strconv.Atoi(f.value); err == nil { + return parsed + } + return defaultValue +} + +// Float returns the value as float64 +func (f FormValue) Float() float64 { + if f.value == "" { + return 0.0 + } + if parsed, err := strconv.ParseFloat(f.value, 64); err == nil { + return parsed + } + return 0.0 +} + +// FloatDefault returns float64 with default value +func (f FormValue) FloatDefault(defaultValue float64) float64 { + if f.value == "" { + return defaultValue + } + if parsed, err := strconv.ParseFloat(f.value, 64); err == nil { + return parsed + } + return defaultValue +} + +// Bool returns the value as boolean +func (f FormValue) Bool() bool { + value := strings.ToLower(f.value) + return value == "true" || value == "on" || value == "1" || value == "yes" +} + +// BoolDefault returns boolean with default value +func (f FormValue) BoolDefault(defaultValue bool) bool { + if f.value == "" { + return defaultValue + } + return f.Bool() +} + +// Exists returns true if the field was present in the form +func (f FormValue) Exists() bool { + return f.exists +} + +// IsEmpty returns true if the field is empty or doesn't exist +func (f FormValue) IsEmpty() bool { + return f.value == "" +} + +// GetFormArray gets multiple form values as string slice +func (ctx Ctx) GetFormArray(key string) []string { + var values []string + ctx.PostArgs().VisitAll(func(k, v []byte) { + if string(k) == key { + values = append(values, string(v)) + } + }) + return values +}