Files
quyun-v2/backend/app/tenancy/tenancy.go
2025-12-15 17:55:32 +08:00

72 lines
1.5 KiB
Go

package tenancy
import (
"database/sql"
"regexp"
"strings"
"quyun/v2/app/errorx"
"github.com/gofiber/fiber/v3"
"github.com/google/uuid"
)
const (
LocalTenantCode = "tenant_code"
LocalTenantID = "tenant_id"
LocalTenantUUID = "tenant_uuid"
)
var tenantCodeRe = regexp.MustCompile(`^[a-z0-9_-]+$`)
type Tenant struct {
ID int64
Code string
UUID uuid.UUID
}
func ResolveTenant(c fiber.Ctx, db *sql.DB) (*Tenant, error) {
raw := strings.TrimSpace(c.Params("tenant_code"))
code := strings.ToLower(raw)
if code == "" || !tenantCodeRe.MatchString(code) {
return nil, errorx.ErrInvalidParameter.WithMsg("invalid tenant_code")
}
var (
id int64
tenantUUID uuid.UUID
status int16
)
err := db.QueryRowContext(
c.Context(),
`SELECT id, tenant_uuid, status FROM tenants WHERE lower(tenant_code) = $1 LIMIT 1`,
code,
).Scan(&id, &tenantUUID, &status)
if err != nil {
if err == sql.ErrNoRows {
return nil, fiber.ErrNotFound
}
return nil, errorx.ErrDatabaseError.WithMsg("database error").WithParams(err.Error())
}
// status: 0 enabled (by default)
if status != 0 {
return nil, fiber.ErrNotFound
}
return &Tenant{ID: id, Code: code, UUID: tenantUUID}, nil
}
func Middleware(db *sql.DB) fiber.Handler {
return func(c fiber.Ctx) error {
tenant, err := ResolveTenant(c, db)
if err != nil {
return err
}
c.Locals(LocalTenantCode, tenant.Code)
c.Locals(LocalTenantID, tenant.ID)
c.Locals(LocalTenantUUID, tenant.UUID.String())
return c.Next()
}
}