86 lines
2.2 KiB
Go
86 lines
2.2 KiB
Go
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
|
|
func ResolveUserOrgs(ctx context.Context, db *database.DB, userID uuid.UUID) ([]database.Organization, error) {
|
|
return db.GetUserOrganizations(ctx, userID)
|
|
}
|
|
|
|
// CheckMembership checks if user is member of org and returns role
|
|
func CheckMembership(ctx context.Context, db *database.DB, userID, orgID uuid.UUID) (string, error) {
|
|
membership, err := db.GetUserMembership(ctx, userID, orgID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return membership.Role, nil
|
|
}
|
|
|
|
// 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) {
|
|
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, userID, 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
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
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
|
|
}
|