1
0
forked from baron/baron-sso

테넌트 목록 조회 cursor기반으로 재구성. 사용자 metadata 미사용 필드 제거

This commit is contained in:
2026-05-13 18:05:51 +09:00
parent a4d707d4d8
commit 5e7b7b878c
85 changed files with 4808 additions and 734 deletions

View File

@@ -2,6 +2,7 @@ package handler
import (
"baron-sso-backend/internal/domain"
"baron-sso-backend/internal/pagination"
"baron-sso-backend/internal/repository"
"baron-sso-backend/internal/service"
"baron-sso-backend/internal/utils"
@@ -121,9 +122,11 @@ type clientSummary struct {
}
type clientListResponse struct {
Items []clientSummary `json:"items"`
Limit int `json:"limit"`
Offset int `json:"offset"`
Items []clientSummary `json:"items"`
Limit int `json:"limit"`
Offset int `json:"offset"`
Cursor string `json:"cursor,omitempty"`
NextCursor string `json:"nextCursor,omitempty"`
}
type clientDetailResponse struct {
@@ -186,7 +189,12 @@ type consentSummary struct {
}
type consentListResponse struct {
Items []consentSummary `json:"items"`
Items []consentSummary `json:"items"`
Total int64 `json:"total"`
Limit int `json:"limit"`
Offset int `json:"offset"`
Cursor string `json:"cursor,omitempty"`
NextCursor string `json:"nextCursor,omitempty"`
}
type clientUpsertRequest struct {
@@ -1097,6 +1105,30 @@ func (h *DevHandler) listVisibleClientSummaries(
return items, nil
}
func (h *DevHandler) listAllVisibleClientSummaries(c *fiber.Ctx, profile *domain.UserProfileResponse) ([]clientSummary, error) {
const pageSize = 500
items := make([]clientSummary, 0)
for offset := 0; ; offset += pageSize {
page, err := h.listVisibleClientSummaries(c, profile, pageSize, offset)
if err != nil {
return nil, err
}
items = append(items, page...)
if len(page) < pageSize {
break
}
}
return items, nil
}
func clientSummaryCursorKey(client clientSummary) (time.Time, string) {
timestamp := time.Unix(0, 0).UTC()
if client.CreatedAt != nil && !client.CreatedAt.IsZero() {
timestamp = client.CreatedAt.UTC()
}
return timestamp, client.ID
}
func extractAuthClaimsFromBearer(authHeader string) (string, string) {
authHeader = strings.TrimSpace(authHeader)
if !strings.HasPrefix(strings.ToLower(authHeader), "bearer ") {
@@ -1213,6 +1245,7 @@ func (h *DevHandler) ListClients(c *fiber.Ctx) error {
h.injectTenantContextFromHeader(c)
limit := c.QueryInt("limit", 50)
offset := c.QueryInt("offset", 0)
cursorRaw := strings.TrimSpace(c.Query("cursor"))
if limit <= 0 {
limit = 50
}
@@ -1221,7 +1254,7 @@ func (h *DevHandler) ListClients(c *fiber.Ctx) error {
}
profile := h.getCurrentProfile(c)
items, err := h.listVisibleClientSummaries(c, profile, limit, offset)
allItems, err := h.listAllVisibleClientSummaries(c, profile)
if err != nil {
status := fiber.StatusInternalServerError
errMsg := err.Error()
@@ -1239,10 +1272,37 @@ func (h *DevHandler) ListClients(c *fiber.Ctx) error {
return errorJSON(c, status, errMsg)
}
var items []clientSummary
nextCursor := ""
if cursorRaw != "" {
ordered := append([]clientSummary(nil), allItems...)
pagination.SortByKeyDesc(ordered, clientSummaryCursorKey)
items, nextCursor, err = pagination.PageByCursor(ordered, limit, cursorRaw, clientSummaryCursorKey)
if err != nil {
return errorJSON(c, fiber.StatusBadRequest, "invalid cursor")
}
offset = 0
} else {
if offset > len(allItems) {
offset = len(allItems)
}
end := offset + limit
if end > len(allItems) {
end = len(allItems)
}
items = allItems[offset:end]
if len(allItems) > end && len(items) > 0 {
lastTimestamp, lastID := clientSummaryCursorKey(items[len(items)-1])
nextCursor = pagination.Encode(lastTimestamp, lastID)
}
}
return c.JSON(clientListResponse{
Items: items,
Limit: limit,
Offset: offset,
Items: items,
Limit: limit,
Offset: offset,
Cursor: cursorRaw,
NextCursor: nextCursor,
})
}
@@ -2126,9 +2186,13 @@ func (h *DevHandler) ListConsents(c *fiber.Ctx) error {
subject := strings.TrimSpace(c.Query("subject"))
limit := c.QueryInt("limit", 50)
offset := c.QueryInt("offset", 0)
cursorRaw := strings.TrimSpace(c.Query("cursor"))
if limit <= 0 {
limit = 50
}
if offset < 0 {
offset = 0
}
// [Isolation] Get admin tenant ID from locals or header
adminTenantID := ""
@@ -2156,10 +2220,16 @@ func (h *DevHandler) ListConsents(c *fiber.Ctx) error {
}
}
queryLimit := limit
queryOffset := offset
if cursorRaw != "" || subject != "" || (statusFilter != "" && statusFilter != "all") {
queryLimit = 10000
queryOffset = 0
}
if adminTenantID != "" {
consents, total, err = h.ConsentRepo.ListByTenant(c.Context(), clientID, adminTenantID, limit, offset)
consents, total, err = h.ConsentRepo.ListByTenant(c.Context(), clientID, adminTenantID, queryLimit, queryOffset)
} else {
consents, total, err = h.ConsentRepo.List(c.Context(), clientID, limit, offset)
consents, total, err = h.ConsentRepo.List(c.Context(), clientID, queryLimit, queryOffset)
}
if err != nil {
@@ -2216,12 +2286,47 @@ func (h *DevHandler) ListConsents(c *fiber.Ctx) error {
})
}
return c.JSON(fiber.Map{
"items": items,
"total": total,
pagination.SortByKeyDesc(items, consentSummaryCursorKey)
nextCursor := ""
if cursorRaw != "" {
items, nextCursor, err = pagination.PageByCursor(items, limit, cursorRaw, consentSummaryCursorKey)
if err != nil {
return errorJSON(c, fiber.StatusBadRequest, "invalid cursor")
}
offset = 0
} else if queryLimit != limit {
if offset > len(items) {
offset = len(items)
}
end := offset + limit
if end > len(items) {
end = len(items)
}
pageItems := items[offset:end]
if len(items) > end && len(pageItems) > 0 {
lastTimestamp, lastID := consentSummaryCursorKey(pageItems[len(pageItems)-1])
nextCursor = pagination.Encode(lastTimestamp, lastID)
}
items = pageItems
} else if total > int64(offset+len(items)) && len(items) > 0 {
lastTimestamp, lastID := consentSummaryCursorKey(items[len(items)-1])
nextCursor = pagination.Encode(lastTimestamp, lastID)
}
return c.JSON(consentListResponse{
Items: items,
Total: total,
Limit: limit,
Offset: offset,
Cursor: cursorRaw,
NextCursor: nextCursor,
})
}
func consentSummaryCursorKey(consent consentSummary) (time.Time, string) {
return consent.CreatedAt, consent.ClientID + ":" + consent.Subject
}
func (h *DevHandler) RevokeConsents(c *fiber.Ctx) error {
tenantID := h.injectTenantContextFromHeader(c)
subject := strings.TrimSpace(c.Query("subject"))