Refactor file download handlers to implement local storage fallback and enhance organization creation with slug generation
This commit is contained in:
@@ -2,10 +2,14 @@ package org
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"go.b0esche.cloud/backend/internal/database"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgconn"
|
||||
)
|
||||
|
||||
// ResolveUserOrgs returns the organizations a user belongs to
|
||||
@@ -24,17 +28,58 @@ func CheckMembership(ctx context.Context, db *database.DB, userID, orgID uuid.UU
|
||||
|
||||
// CreateOrg creates a new organization and adds the user as owner
|
||||
func CreateOrg(ctx context.Context, db *database.DB, userID uuid.UUID, name, slug string) (*database.Organization, error) {
|
||||
if slug == "" {
|
||||
// Simple slug generation
|
||||
slug = name // TODO: make URL safe
|
||||
trimmedName := strings.TrimSpace(name)
|
||||
if trimmedName == "" {
|
||||
return nil, fmt.Errorf("organization name cannot be empty")
|
||||
}
|
||||
|
||||
baseSlug := slugify(slug)
|
||||
if baseSlug == "" {
|
||||
baseSlug = slugify(trimmedName)
|
||||
}
|
||||
if baseSlug == "" {
|
||||
baseSlug = fmt.Sprintf("org-%s", uuid.NewString()[:8])
|
||||
}
|
||||
|
||||
var org *database.Organization
|
||||
var err error
|
||||
// Try a handful of suffixes on unique constraint violation
|
||||
for i := 0; i < 5; i++ {
|
||||
candidate := baseSlug
|
||||
if i > 0 {
|
||||
candidate = fmt.Sprintf("%s-%d", baseSlug, i+1)
|
||||
}
|
||||
org, err = db.CreateOrg(ctx, trimmedName, candidate)
|
||||
if err != nil {
|
||||
if pgErr, ok := err.(*pgconn.PgError); ok && pgErr.Code == "23505" {
|
||||
// Unique violation; try next suffix
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
break
|
||||
}
|
||||
org, err := db.CreateOrg(ctx, name, slug)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = db.AddMembership(ctx, userID, org.ID, "owner")
|
||||
if err != nil {
|
||||
|
||||
if err = db.AddMembership(ctx, userID, org.ID, "owner"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return org, nil
|
||||
}
|
||||
|
||||
// slugify converts a string to a URL-safe slug with hyphens.
|
||||
func slugify(s string) string {
|
||||
lower := strings.ToLower(strings.TrimSpace(s))
|
||||
if lower == "" {
|
||||
return ""
|
||||
}
|
||||
// Replace non-alphanumeric with hyphen
|
||||
re := regexp.MustCompile(`[^a-z0-9]+`)
|
||||
slug := re.ReplaceAllString(lower, "-")
|
||||
slug = strings.Trim(slug, "-")
|
||||
// Collapse multiple hyphens
|
||||
slug = strings.ReplaceAll(slug, "--", "-")
|
||||
return slug
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user