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
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, "<h1>Hello Sushi!</h1>")
ctx.SendHTML("<h1>Hello Sushi!</h1>")
})
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("<h1>Welcome, %s!</h1>", 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`<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(`
<form method="POST" action="/login">
%s
@ -376,32 +373,32 @@ func loginPageHandler(ctx sushi.Ctx, params []string) {
<input type="password" name="password" placeholder="Password" required><br>
<button type="submit">Login</button>
</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"))
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(`
<h1>Welcome, %s!</h1>
@ -409,13 +406,13 @@ func dashboardHandler(ctx sushi.Ctx, params []string) {
%s
<button type="submit">Logout</button>
</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) {
auth.Logout(ctx)
sushi.SendRedirect(ctx, "/")
func logoutHandler(ctx sushi.Ctx, params []any) {
ctx.Logout()
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
}