update readme, add form handlers for fluent parsing

This commit is contained in:
Sky Johnson 2025-08-16 12:25:16 -05:00
parent 0f59ba225a
commit 09f66cfaa4
2 changed files with 144 additions and 37 deletions

View File

@ -7,19 +7,16 @@ A fast, raw, tasty framework for simplifying basic web apps!
```go ```go
package main package main
import ( import "git.sharkk.net/Sharkk/Sushi"
"git.sharkk.net/Sharkk/Sushi"
"git.sharkk.net/Sharkk/Sushi/session"
)
func main() { func main() {
app := sushi.New() app := sushi.New()
// Initialize sessions // Initialize sessions
session.InitSessions("sessions.json") sushi.InitSessions("sessions.json")
app.Get("/", func(ctx sushi.Ctx, params []any) { app.Get("/", func(ctx sushi.Ctx, params []any) {
sushi.SendHTML(ctx, "<h1>Hello Sushi!</h1>") ctx.SendHTML("<h1>Hello Sushi!</h1>")
}) })
app.Listen(":8080") app.Listen(":8080")
@ -156,7 +153,7 @@ func main() {
app := sushi.New() app := sushi.New()
// Initialize sessions // Initialize sessions
session.InitSessions("sessions.json") sushi.InitSessions("sessions.json")
// Add session middleware // Add session middleware
app.Use(session.Middleware()) app.Use(session.Middleware())
@ -179,7 +176,7 @@ func main() {
### 4. Login Handler ### 4. Login Handler
```go ```go
func loginHandler(ctx sushi.Ctx, params []string) { func loginHandler(ctx sushi.Ctx, params []any) {
email := string(ctx.PostArgs().Peek("email")) email := string(ctx.PostArgs().Peek("email"))
password := string(ctx.PostArgs().Peek("password")) password := string(ctx.PostArgs().Peek("password"))
@ -198,7 +195,7 @@ func loginHandler(ctx sushi.Ctx, params []string) {
} }
// Log the user in // Log the user in
auth.Login(ctx, user.ID, user) ctx.Login(user.ID, user)
ctx.Redirect("/dashboard") ctx.Redirect("/dashboard")
} }
@ -207,17 +204,17 @@ func loginHandler(ctx sushi.Ctx, params []string) {
### 5. Logout Handler ### 5. Logout Handler
```go ```go
func logoutHandler(ctx sushi.Ctx, params []string) { func logoutHandler(ctx sushi.Ctx, params []any) {
auth.Logout(ctx) ctx.Logout()
ctx.SendRedirect("/") ctx.Redirect("/")
} }
``` ```
### 6. Getting Current User ### 6. Getting Current User
```go ```go
func dashboardHandler(ctx sushi.Ctx, params []string) { func dashboardHandler(ctx sushi.Ctx, params []any) {
user := auth.GetCurrentUser(ctx).(*User) user := ctx.GetCurrentUser().(*User)
html := fmt.Sprintf("<h1>Welcome, %s!</h1>", user.Username) html := fmt.Sprintf("<h1>Welcome, %s!</h1>", user.Username)
ctx.SendHTML(html) ctx.SendHTML(html)
@ -233,7 +230,7 @@ import "git.sharkk.net/Sharkk/Sushi/csrf"
app.Use(csrf.Middleware()) app.Use(csrf.Middleware())
// In your form template // In your form template
func loginPageHandler(ctx sushi.Ctx, params []string) { func loginPageHandler(ctx sushi.Ctx, params []any) {
csrfField := csrf.CSRFHiddenField(ctx) csrfField := csrf.CSRFHiddenField(ctx)
html := fmt.Sprintf(` html := fmt.Sprintf(`
@ -269,8 +266,8 @@ app.Get("/assets/*path", sushi.StaticEmbed(files))
## Sessions ## Sessions
```go ```go
func someHandler(ctx sushi.Ctx, params []string) { func someHandler(ctx sushi.Ctx, params []any) {
sess := session.GetCurrentSession(ctx) sess := ctx.GetCurrentSession()
// Set session data // Set session data
sess.Set("user_preference", "dark_mode") sess.Set("user_preference", "dark_mode")
@ -341,7 +338,7 @@ func findUserByEmail(email string) *User {
func main() { func main() {
app := sushi.New() app := sushi.New()
session.InitSessions("sessions.json") sushi.InitSessions("sessions.json")
app.Use(session.Middleware()) app.Use(session.Middleware())
app.Use(auth.Middleware(getUserByID)) app.Use(auth.Middleware(getUserByID))
@ -360,15 +357,15 @@ func main() {
app.Listen(":8080") app.Listen(":8080")
} }
func homeHandler(ctx sushi.Ctx, params []string) { func homeHandler(ctx sushi.Ctx, params []any) {
if auth.IsAuthenticated(ctx) { if ctx.IsAuthenticated() {
ctx.SendRedirect("/dashboard") ctx.Redirect("/dashboard")
return return
} }
ctx.SendHTML(c`<a href="/login">Login</a>`) ctx.SendHTML(`<a href="/login">Login</a>`)
} }
func loginPageHandler(ctx sushi.Ctx, params []string) { func loginPageHandler(ctx sushi.Ctx, params []any) {
html := fmt.Sprintf(` html := fmt.Sprintf(`
<form method="POST" action="/login"> <form method="POST" action="/login">
%s %s
@ -376,32 +373,32 @@ func loginPageHandler(ctx sushi.Ctx, params []string) {
<input type="password" name="password" placeholder="Password" required><br> <input type="password" name="password" placeholder="Password" required><br>
<button type="submit">Login</button> <button type="submit">Login</button>
</form> </form>
`, 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")) email := string(ctx.PostArgs().Peek("email"))
pass := string(ctx.PostArgs().Peek("password")) pass := string(ctx.PostArgs().Peek("password"))
user := findUserByEmail(email) user := findUserByEmail(email)
if user == nil { if user == nil {
sushi.SendError(ctx, 401, "Invalid credentials") ctx.SendError(401, "Invalid credentials")
return return
} }
if valid, _ := password.VerifyPassword(pass, user.Password); !valid { if valid, _ := password.VerifyPassword(pass, user.Password); !valid {
sushi.SendError(ctx, 401, "Invalid credentials") ctx.SendError(401, "Invalid credentials")
return return
} }
auth.Login(ctx, user.ID, user) ctx.Login(user.ID, user)
sushi.SendRedirect(ctx, "/dashboard") ctx.Redirect("/dashboard")
} }
func dashboardHandler(ctx sushi.Ctx, params []string) { func dashboardHandler(ctx sushi.Ctx, params []any) {
user := auth.GetCurrentUser(ctx).(*User) user := ctx.GetCurrentUser().(*User)
html := fmt.Sprintf(` html := fmt.Sprintf(`
<h1>Welcome, %s!</h1> <h1>Welcome, %s!</h1>
@ -409,13 +406,13 @@ func dashboardHandler(ctx sushi.Ctx, params []string) {
%s %s
<button type="submit">Logout</button> <button type="submit">Logout</button>
</form> </form>
`, user.Email, csrf.CSRFHiddenField(ctx)) `, user.Email, csrf.HiddenField(ctx))
sushi.SendHTML(ctx, html) ctx.SendHTML(html)
} }
func logoutHandler(ctx sushi.Ctx, params []string) { func logoutHandler(ctx sushi.Ctx, params []any) {
auth.Logout(ctx) ctx.Logout()
sushi.SendRedirect(ctx, "/") ctx.Redirect("/")
} }
``` ```

110
forms.go Normal file
View File

@ -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
}