forked from baron/baron-sso
Merge commit 'ac778f836fb78550dce8088a567dc8bf5ffb8d2e' into feature/adminfront
This commit is contained in:
@@ -148,7 +148,7 @@ func (h *UserHandler) ListUsers(c *fiber.Ctx) error {
|
||||
// Fetch from UserRepo
|
||||
users, total, err := h.UserRepo.List(c.Context(), offset, limit, search, companyCode)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to fetch users from both kratos and local db"})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, "failed to fetch users from both kratos and local db")
|
||||
}
|
||||
|
||||
items := make([]userSummary, 0, len(users))
|
||||
@@ -177,20 +177,20 @@ func (h *UserHandler) ListUsers(c *fiber.Ctx) error {
|
||||
|
||||
func (h *UserHandler) GetUser(c *fiber.Ctx) error {
|
||||
if h.KratosAdmin == nil {
|
||||
return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{"error": "identity provider not available"})
|
||||
return errorJSON(c, fiber.StatusServiceUnavailable, "identity provider not available")
|
||||
}
|
||||
|
||||
userID := strings.TrimSpace(c.Params("id"))
|
||||
if userID == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "user id is required"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "user id is required")
|
||||
}
|
||||
|
||||
identity, err := h.KratosAdmin.GetIdentity(c.Context(), userID)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
if identity == nil {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "user not found"})
|
||||
return errorJSON(c, fiber.StatusNotFound, "user not found")
|
||||
}
|
||||
|
||||
// [New] Check access scope
|
||||
@@ -198,7 +198,7 @@ func (h *UserHandler) GetUser(c *fiber.Ctx) error {
|
||||
if requester != nil && requester.Role == domain.RoleTenantAdmin {
|
||||
compCode := extractTraitString(identity.Traits, "companyCode")
|
||||
if requester.CompanyCode == "" || compCode != requester.CompanyCode {
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "forbidden: access to user in another tenant denied"})
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden: access to user in another tenant denied")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ func (h *UserHandler) GetUser(c *fiber.Ctx) error {
|
||||
|
||||
func (h *UserHandler) CreateUser(c *fiber.Ctx) error {
|
||||
if h.OryProvider == nil || h.KratosAdmin == nil {
|
||||
return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{"error": "identity provider not available"})
|
||||
return errorJSON(c, fiber.StatusServiceUnavailable, "identity provider not available")
|
||||
}
|
||||
|
||||
var req struct {
|
||||
@@ -221,19 +221,19 @@ func (h *UserHandler) CreateUser(c *fiber.Ctx) error {
|
||||
Metadata map[string]any `json:"metadata"`
|
||||
}
|
||||
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")
|
||||
}
|
||||
|
||||
email := strings.TrimSpace(req.Email)
|
||||
if email == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "email is required"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "email is required")
|
||||
}
|
||||
if !strings.Contains(email, "@") || !strings.Contains(email, ".") {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid email format"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "invalid email format")
|
||||
}
|
||||
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")
|
||||
}
|
||||
|
||||
password := strings.TrimSpace(req.Password)
|
||||
@@ -253,13 +253,13 @@ func (h *UserHandler) CreateUser(c *fiber.Ctx) error {
|
||||
if password == "" {
|
||||
generated, genErr := utils.GeneratePasswordWithPolicy(policy)
|
||||
if genErr != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to generate password"})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, "failed to generate password")
|
||||
}
|
||||
password = generated
|
||||
generatedPassword = generated
|
||||
} else {
|
||||
if err := utils.ValidatePasswordWithPolicy(policy, password); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,15 +305,15 @@ func (h *UserHandler) CreateUser(c *fiber.Ctx) error {
|
||||
identityID, err := h.OryProvider.CreateUser(brokerUser, password)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "already exists") {
|
||||
return c.Status(fiber.StatusConflict).JSON(fiber.Map{"error": "email already exists"})
|
||||
return errorJSON(c, fiber.StatusConflict, "email already exists")
|
||||
}
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
// Fetch the newly created identity to ensure we have all traits
|
||||
identity, err := h.KratosAdmin.GetIdentity(c.Context(), identityID)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
if identity == nil {
|
||||
return c.Status(fiber.StatusCreated).JSON(fiber.Map{"id": identityID, "initialPassword": generatedPassword})
|
||||
@@ -350,20 +350,20 @@ func (h *UserHandler) CreateUser(c *fiber.Ctx) error {
|
||||
|
||||
func (h *UserHandler) UpdateUser(c *fiber.Ctx) error {
|
||||
if h.KratosAdmin == nil {
|
||||
return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{"error": "identity provider not available"})
|
||||
return errorJSON(c, fiber.StatusServiceUnavailable, "identity provider not available")
|
||||
}
|
||||
|
||||
userID := strings.TrimSpace(c.Params("id"))
|
||||
if userID == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "user id is required"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "user id is required")
|
||||
}
|
||||
|
||||
identity, err := h.KratosAdmin.GetIdentity(c.Context(), userID)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
if identity == nil {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "user not found"})
|
||||
return errorJSON(c, fiber.StatusNotFound, "user not found")
|
||||
}
|
||||
|
||||
// Capture current local state for transition comparison
|
||||
@@ -383,7 +383,7 @@ func (h *UserHandler) UpdateUser(c *fiber.Ctx) error {
|
||||
if requester != nil && requester.Role == domain.RoleTenantAdmin {
|
||||
compCode := extractTraitString(identity.Traits, "companyCode")
|
||||
if requester.CompanyCode == "" || compCode != requester.CompanyCode {
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "forbidden: cannot update user in another tenant"})
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden: cannot update user in another tenant")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,13 +398,13 @@ func (h *UserHandler) UpdateUser(c *fiber.Ctx) error {
|
||||
Metadata map[string]any `json:"metadata"`
|
||||
}
|
||||
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")
|
||||
}
|
||||
|
||||
// [New] Tenant Admin restriction: Cannot change companyCode
|
||||
if requester != nil && requester.Role == domain.RoleTenantAdmin {
|
||||
if req.CompanyCode != nil && *req.CompanyCode != requester.CompanyCode {
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "forbidden: tenant admins cannot change user's tenant"})
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden: tenant admins cannot change user's tenant")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,7 +469,7 @@ func (h *UserHandler) UpdateUser(c *fiber.Ctx) error {
|
||||
state := normalizeKratosState(req.Status)
|
||||
updated, err := h.KratosAdmin.UpdateIdentity(c.Context(), userID, traits, state)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
// [New] Local DB Sync - Sync synchronously to ensure immediate consistency for the caller
|
||||
@@ -488,7 +488,7 @@ func (h *UserHandler) UpdateUser(c *fiber.Ctx) error {
|
||||
|
||||
if req.Password != nil && *req.Password != "" {
|
||||
if err := h.KratosAdmin.UpdateIdentityPassword(c.Context(), userID, *req.Password); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,12 +497,12 @@ func (h *UserHandler) UpdateUser(c *fiber.Ctx) error {
|
||||
|
||||
func (h *UserHandler) DeleteUser(c *fiber.Ctx) error {
|
||||
if h.KratosAdmin == nil {
|
||||
return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{"error": "identity provider not available"})
|
||||
return errorJSON(c, fiber.StatusServiceUnavailable, "identity provider not available")
|
||||
}
|
||||
|
||||
userID := strings.TrimSpace(c.Params("id"))
|
||||
if userID == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "user id is required"})
|
||||
return errorJSON(c, fiber.StatusBadRequest, "user id is required")
|
||||
}
|
||||
|
||||
// [New] Check access scope before deletion
|
||||
@@ -512,13 +512,13 @@ func (h *UserHandler) DeleteUser(c *fiber.Ctx) error {
|
||||
if err == nil && identity != nil {
|
||||
compCode := extractTraitString(identity.Traits, "companyCode")
|
||||
if requester.CompanyCode == "" || compCode != requester.CompanyCode {
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "forbidden: cannot delete user in another tenant"})
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden: cannot delete user in another tenant")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := h.KratosAdmin.DeleteIdentity(c.Context(), userID); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
return errorJSON(c, fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
// [Keto] Cleanup relations via Outbox
|
||||
|
||||
Reference in New Issue
Block a user