forked from baron/baron-sso
merge feat/304-userfront-wasm-e2e into dev
This commit is contained in:
@@ -58,17 +58,17 @@ func (h *TenantHandler) RegisterTenantPublic(c *fiber.Ctx) error {
|
||||
AdminEmail string `json:"adminEmail"`
|
||||
}
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid request body"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "invalid request body")
|
||||
}
|
||||
|
||||
// Basic validation
|
||||
if req.Name == "" || req.Domain == "" || req.AdminEmail == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "name, domain, and adminEmail are required"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "name, domain, and adminEmail are required")
|
||||
}
|
||||
|
||||
tenant, err := h.Service.RequestRegistration(c.Context(), req.Name, req.Slug, req.Description, req.Domain, req.AdminEmail)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusAccepted).JSON(fiber.Map{
|
||||
@@ -80,11 +80,11 @@ func (h *TenantHandler) RegisterTenantPublic(c *fiber.Ctx) error {
|
||||
func (h *TenantHandler) ApproveTenant(c *fiber.Ctx) error {
|
||||
tenantID := c.Params("id")
|
||||
if tenantID == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "tenant id is required"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "tenant id is required")
|
||||
}
|
||||
|
||||
if err := h.Service.ApproveTenant(c.Context(), tenantID); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{"message": "Tenant approved successfully"})
|
||||
@@ -92,7 +92,7 @@ func (h *TenantHandler) ApproveTenant(c *fiber.Ctx) error {
|
||||
|
||||
func (h *TenantHandler) ListTenants(c *fiber.Ctx) error {
|
||||
if h.DB == nil {
|
||||
return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{"error": "database not available"})
|
||||
return errorJSON(c, fiber.StatusServiceUnavailable, "database not available")
|
||||
}
|
||||
|
||||
limit := c.QueryInt("limit", 50)
|
||||
@@ -106,12 +106,12 @@ func (h *TenantHandler) ListTenants(c *fiber.Ctx) error {
|
||||
|
||||
var total int64
|
||||
if err := h.DB.Model(&domain.Tenant{}).Count(&total).Error; err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
var tenants []domain.Tenant
|
||||
if err := h.DB.Order("created_at desc").Limit(limit).Offset(offset).Preload("Domains").Find(&tenants).Error; err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
items := make([]tenantSummary, 0, len(tenants))
|
||||
@@ -124,20 +124,20 @@ func (h *TenantHandler) ListTenants(c *fiber.Ctx) error {
|
||||
|
||||
func (h *TenantHandler) GetTenant(c *fiber.Ctx) error {
|
||||
if h.DB == nil {
|
||||
return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{"error": "database not available"})
|
||||
return errorJSON(c, fiber.StatusServiceUnavailable, "database not available")
|
||||
}
|
||||
|
||||
tenantID := strings.TrimSpace(c.Params("id"))
|
||||
if tenantID == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "tenant id is required"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "tenant id is required")
|
||||
}
|
||||
|
||||
var tenant domain.Tenant
|
||||
if err := h.DB.Preload("Domains").First(&tenant, "id = ?", tenantID).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "tenant not found"})
|
||||
return errorJSON(c, fiber.StatusNotFound, "tenant not found")
|
||||
}
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return c.JSON(mapTenantSummary(tenant))
|
||||
@@ -145,7 +145,7 @@ func (h *TenantHandler) GetTenant(c *fiber.Ctx) error {
|
||||
|
||||
func (h *TenantHandler) CreateTenant(c *fiber.Ctx) error {
|
||||
if h.DB == nil {
|
||||
return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{"error": "database not available"})
|
||||
return errorJSON(c, fiber.StatusServiceUnavailable, "database not available")
|
||||
}
|
||||
|
||||
var req struct {
|
||||
@@ -158,12 +158,12 @@ func (h *TenantHandler) CreateTenant(c *fiber.Ctx) error {
|
||||
Config map[string]any `json:"config"`
|
||||
}
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid request body"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "invalid request body")
|
||||
}
|
||||
|
||||
name := strings.TrimSpace(req.Name)
|
||||
if name == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "name is required"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "name is required")
|
||||
}
|
||||
|
||||
slug := normalizeTenantSlug(req.Slug)
|
||||
@@ -171,7 +171,7 @@ func (h *TenantHandler) CreateTenant(c *fiber.Ctx) error {
|
||||
slug = normalizeTenantSlug(name)
|
||||
}
|
||||
if slug == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "slug is required"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "slug is required")
|
||||
}
|
||||
|
||||
status := normalizeTenantStatus(req.Status)
|
||||
@@ -189,9 +189,9 @@ func (h *TenantHandler) CreateTenant(c *fiber.Ctx) error {
|
||||
tenant, err := h.Service.RegisterTenant(c.Context(), name, slug, req.Description, req.Domains, parentID)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "already exists") {
|
||||
return c.Status(fiber.StatusConflict).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusConflict, err.Error())
|
||||
}
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
if req.Config != nil {
|
||||
@@ -204,20 +204,20 @@ func (h *TenantHandler) CreateTenant(c *fiber.Ctx) error {
|
||||
|
||||
func (h *TenantHandler) UpdateTenant(c *fiber.Ctx) error {
|
||||
if h.DB == nil {
|
||||
return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{"error": "database not available"})
|
||||
return errorJSON(c, fiber.StatusServiceUnavailable, "database not available")
|
||||
}
|
||||
|
||||
tenantID := strings.TrimSpace(c.Params("id"))
|
||||
if tenantID == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "tenant id is required"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "tenant id is required")
|
||||
}
|
||||
|
||||
var tenant domain.Tenant
|
||||
if err := h.DB.First(&tenant, "id = ?", tenantID).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "tenant not found"})
|
||||
return errorJSON(c, fiber.StatusNotFound, "tenant not found")
|
||||
}
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
var req struct {
|
||||
@@ -229,27 +229,27 @@ func (h *TenantHandler) UpdateTenant(c *fiber.Ctx) error {
|
||||
Config map[string]any `json:"config"`
|
||||
}
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid request body"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "invalid request body")
|
||||
}
|
||||
|
||||
if req.Name != nil {
|
||||
name := strings.TrimSpace(*req.Name)
|
||||
if name == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "name cannot be empty"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "name cannot be empty")
|
||||
}
|
||||
tenant.Name = name
|
||||
}
|
||||
if req.Slug != nil {
|
||||
slug := normalizeTenantSlug(*req.Slug)
|
||||
if slug == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "slug cannot be empty"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "slug cannot be empty")
|
||||
}
|
||||
if slug != tenant.Slug {
|
||||
var exists domain.Tenant
|
||||
if err := h.DB.Unscoped().Where("slug = ?", slug).First(&exists).Error; err == nil {
|
||||
return c.Status(fiber.StatusConflict).JSON(fiber.Map{"error": "slug already exists"})
|
||||
return errorJSON(c, fiber.StatusConflict, "slug already exists")
|
||||
} else if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
tenant.Slug = slug
|
||||
}
|
||||
@@ -260,7 +260,7 @@ func (h *TenantHandler) UpdateTenant(c *fiber.Ctx) error {
|
||||
if req.Status != nil {
|
||||
status := normalizeTenantStatus(*req.Status)
|
||||
if status == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "status must be active or inactive"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "status must be active or inactive")
|
||||
}
|
||||
tenant.Status = status
|
||||
}
|
||||
@@ -269,14 +269,14 @@ func (h *TenantHandler) UpdateTenant(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
if err := h.DB.Save(&tenant).Error; err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
// Update domains if provided
|
||||
if req.Domains != nil {
|
||||
// Simple approach: Delete existing and recreate
|
||||
if err := h.DB.Delete(&domain.TenantDomain{}, "tenant_id = ?", tenant.ID).Error; err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to clear old domains"})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, "failed to clear old domains")
|
||||
}
|
||||
for _, d := range req.Domains {
|
||||
if strings.TrimSpace(d) == "" {
|
||||
@@ -284,7 +284,7 @@ func (h *TenantHandler) UpdateTenant(c *fiber.Ctx) error {
|
||||
}
|
||||
// Use repository for consistency
|
||||
if err := repository.NewTenantRepository(h.DB).AddDomain(c.Context(), tenant.ID, strings.TrimSpace(d), true); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to add domain: " + d})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, "failed to add domain: "+d)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -297,30 +297,30 @@ func (h *TenantHandler) UpdateTenant(c *fiber.Ctx) error {
|
||||
|
||||
func (h *TenantHandler) DeleteTenant(c *fiber.Ctx) error {
|
||||
if h.DB == nil {
|
||||
return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{"error": "database not available"})
|
||||
return errorJSON(c, fiber.StatusServiceUnavailable, "database not available")
|
||||
}
|
||||
|
||||
tenantID := strings.TrimSpace(c.Params("id"))
|
||||
if tenantID == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "tenant id is required"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "tenant id is required")
|
||||
}
|
||||
|
||||
var tenant domain.Tenant
|
||||
if err := h.DB.First(&tenant, "id = ?", tenantID).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "tenant not found"})
|
||||
return errorJSON(c, fiber.StatusNotFound, "tenant not found")
|
||||
}
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
// Rename slug to release it for reuse before soft delete
|
||||
deletedSlug := tenant.Slug + "-deleted-" + time.Now().Format("20060102150405")
|
||||
if err := h.DB.Model(&tenant).Update("slug", deletedSlug).Error; err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to release slug"})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, "failed to release slug")
|
||||
}
|
||||
|
||||
if err := h.DB.Delete(&tenant).Error; err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return c.SendStatus(fiber.StatusNoContent)
|
||||
@@ -329,13 +329,13 @@ func (h *TenantHandler) DeleteTenant(c *fiber.Ctx) error {
|
||||
func (h *TenantHandler) ListAdmins(c *fiber.Ctx) error {
|
||||
tenantID := c.Params("id")
|
||||
if tenantID == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "tenant id is required"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "tenant id is required")
|
||||
}
|
||||
|
||||
// Fetch admins from Keto
|
||||
relations, err := h.Keto.ListRelations(c.Context(), "Tenant", tenantID, "admins", "")
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
type adminInfo struct {
|
||||
@@ -381,7 +381,7 @@ func (h *TenantHandler) AddAdmin(c *fiber.Ctx) error {
|
||||
tenantID := c.Params("id")
|
||||
userID := c.Params("userId")
|
||||
if tenantID == "" || userID == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "tenantId and userId are required"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "tenantId and userId are required")
|
||||
}
|
||||
|
||||
if h.KetoOutbox != nil {
|
||||
@@ -401,7 +401,7 @@ func (h *TenantHandler) RemoveAdmin(c *fiber.Ctx) error {
|
||||
tenantID := c.Params("id")
|
||||
userID := c.Params("userId")
|
||||
if tenantID == "" || userID == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "tenantId and userId are required"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "tenantId and userId are required")
|
||||
}
|
||||
|
||||
if h.KetoOutbox != nil {
|
||||
|
||||
Reference in New Issue
Block a user