First not working app skeleton with nix support and dependency setup and generated logo not final structure

This commit is contained in:
Jonas Hahn
2025-08-22 17:37:43 +02:00
parent 99306dd26f
commit 6f53cddf6c
24 changed files with 1382 additions and 87 deletions

132
src/utils.go Normal file
View File

@@ -0,0 +1,132 @@
package src
import (
"crypto/rand"
"encoding/hex"
"errors"
"log"
"strings"
"time"
"github.com/gin-gonic/gin"
)
func mustRandToken(n int) string {
b := make([]byte, n)
if _, err := rand.Read(b); err != nil {
panic(err)
}
return hex.EncodeToString(b)
}
func now() time.Time { return time.Now().UTC() }
func defaultUsername() string {
// io-game style: adjective-animal-xxxx
adjectives := []string{"swift", "brave", "mighty", "cheeky", "sneaky", "zippy", "bouncy", "crispy", "fuzzy", "spicy", "snappy", "jazzy", "spry", "bold", "witty"}
animals := []string{"otter", "panda", "falcon", "lynx", "badger", "tiger", "koala", "yak", "gecko", "eagle", "mamba", "fox", "yak", "whale", "rhino"}
a := adjectives[int(time.Now().UnixNano())%len(adjectives)]
an := animals[int(time.Now().UnixNano()/17)%len(animals)]
return a + "-" + an + "-" + strings.ToLower(mustRandToken(2))
}
func slugify(s string) string {
s = strings.ToLower(s)
s = strings.TrimSpace(s)
s = strings.ReplaceAll(s, " ", "-")
// keep alnum and - only
var b strings.Builder
for _, r := range s {
if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '-' {
b.WriteRune(r)
}
}
out := b.String()
if out == "" {
out = "user-" + mustRandToken(2)
}
return out
}
func ensureUniqueUsernameAndSlug(u *User) error {
// try to keep username/slug unique by appending short token if needed
baseU := u.Username
baseS := slugify(u.Username)
for i := 0; i < 5; i++ {
candU := baseU
candS := baseS
if i > 0 {
suffix := "-" + mustRandToken(1)
candU = baseU + suffix
candS = baseS + suffix
}
var cnt int64
db.Model(&User{}).Where("username = ?", candU).Count(&cnt)
if cnt == 0 {
db.Model(&User{}).Where("slug = ?", candS).Count(&cnt)
if cnt == 0 {
u.Username = candU
u.Slug = candS
return nil
}
}
}
return errors.New("cannot create unique username/slug")
}
func userByEmail(email string) (*User, error) {
var u User
tx := db.Where("email = ?", strings.ToLower(email)).First(&u)
if tx.Error != nil {
return nil, tx.Error
}
return &u, nil
}
func userBySlug(slug string) (*User, error) {
var u User
tx := db.Where("slug = ?", slug).First(&u)
if tx.Error != nil {
return nil, tx.Error
}
return &u, nil
}
func atoiSafe(s string) int {
var n int
for _, r := range s {
if r < '0' || r > '9' {
return 0
}
}
_, _ = fmtSscanf(s, "%d", &n)
return n
}
// minimal sscanf to avoid fmt import just for one call
func fmtSscanf(s, format string, a *int) (int, error) {
// Only supports "%d"
n := 0
for i := 0; i < len(s); i++ {
c := s[i]
if c < '0' || c > '9' {
break
}
n = n*10 + int(c-'0')
}
*a = n
return 1, nil
}
func render(c *gin.Context, name string, data ctxData) {
u := getSessionUser(c)
if data == nil {
data = ctxData{}
}
log.Println("tpl error:", name)
data["CurrentUser"] = u
if err := tpl.ExecuteTemplate(c.Writer, name, data); err != nil {
log.Println("tpl error:", err)
c.Status(500)
}
}