From 34981c30a78e8bbd7791131059a9210f9928b62c Mon Sep 17 00:00:00 2001
From: 刘光辉 <347230014@qq.com>
Date: 星期四, 17 九月 2026 09:24:09 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into master

---
 jnpf-dms/jnpf-dms-biz/src/main/java/jnpf/dmsService/DmsPermissionAdminQueryService.java |  198 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 198 insertions(+), 0 deletions(-)

diff --git a/jnpf-dms/jnpf-dms-biz/src/main/java/jnpf/dmsService/DmsPermissionAdminQueryService.java b/jnpf-dms/jnpf-dms-biz/src/main/java/jnpf/dmsService/DmsPermissionAdminQueryService.java
new file mode 100644
index 0000000..658ca57
--- /dev/null
+++ b/jnpf-dms/jnpf-dms-biz/src/main/java/jnpf/dmsService/DmsPermissionAdminQueryService.java
@@ -0,0 +1,198 @@
+package jnpf.dmsService;
+
+import jnpf.dmsEntity.permission.entity.DmsFilePermissionEntity;
+import jnpf.dmsEntity.permission.entity.DmsPermissionUsageEntity;
+import jnpf.dmsEntity.permission.enums.DmsPrincipalType;
+import jnpf.dmsEntity.permission.enums.DmsResourceType;
+import jnpf.dmsEntity.permission.model.DmsResourcePath;
+import jnpf.dmsEntity.permission.vo.DmsCursorPageVO;
+import jnpf.dmsEntity.permission.vo.DmsPermissionGrantVO;
+import jnpf.dmsEntity.permission.vo.DmsPrincipalOptionVO;
+import jnpf.dmsEntity.permission.vo.DmsPermissionUsageVO;
+import jnpf.dmsMapper.DmsFilePermissionMapper;
+import jnpf.dmsMapper.DmsPermissionGroupMapper;
+import jnpf.dmsMapper.DmsPermissionUsageMapper;
+import jnpf.dmsPermission.DmsCurrentIdentity;
+import jnpf.dmsPermission.DmsCursorCodec;
+import jnpf.dmsPermission.DmsPermissionError;
+import jnpf.dmsPermission.DmsPermissionException;
+import jnpf.dmsPermission.DmsPermissionMatcher;
+import jnpf.dmsPermission.DmsPermissionProperties;
+import jnpf.dmsPermission.DmsResourceResolver;
+import jnpf.dmsPermission.DmsUserDisplayNameResolver;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+@Service
+@RequiredArgsConstructor
+public class DmsPermissionAdminQueryService {
+    private final DmsCurrentIdentity currentIdentity;
+    private final DmsPermissionProperties properties;
+    private final DmsCursorCodec cursorCodec;
+    private final DmsFilePermissionMapper permissionMapper;
+    private final DmsPermissionGroupMapper permissionGroupMapper;
+    private final DmsPermissionUsageMapper usageMapper;
+    private final DmsPermissionGrantService grantService;
+    private final DmsResourceResolver resourceResolver;
+    private final DmsPermissionMatcher matcher;
+    private final DmsUserDisplayNameResolver userDisplayNameResolver;
+
+    @Transactional(readOnly = true)
+    public DmsCursorPageVO<DmsPermissionGrantVO> grants(UUID resourceId, String principalType,
+                                                        String principalId, String cursor, Integer pageSize) {
+        currentIdentity.requirePermissionAdministrator();
+        String normalizedPrincipalType = normalizePrincipalType(principalType);
+        int limit = pageSize(pageSize);
+        DmsCursorCodec.Cursor decoded = cursorCodec.decode(cursor);
+        List<DmsFilePermissionEntity> rows = permissionMapper.selectPage(currentIdentity.tenantId(), resourceId,
+                normalizedPrincipalType, trimToNull(principalId), decoded.getTime(), decoded.getId(), limit + 1);
+        return page(rows, limit);
+    }
+
+    @Transactional(readOnly = true)
+    public DmsPermissionGrantVO grant(UUID id) {
+        currentIdentity.requirePermissionAdministrator();
+        DmsFilePermissionEntity value = permissionMapper.selectByTenantAndId(currentIdentity.tenantId(), id);
+        if (value == null) {
+            throw DmsPermissionException.of(DmsPermissionError.RESOURCE_NOT_FOUND, "鏉冮檺涓嶅瓨鍦�: " + id);
+        }
+        DmsPermissionGrantVO result = enriched(value, false);
+        enrichUserNames(Collections.singletonList(result));
+        return result;
+    }
+
+    @Transactional(readOnly = true)
+    public List<DmsPermissionGrantVO> resourceGrants(DmsResourceType resourceType, UUID resourceId) {
+        currentIdentity.requirePermissionAdministrator();
+        String tenantId = currentIdentity.tenantId();
+        DmsResourcePath path = resourceResolver.resolve(tenantId, resourceType, resourceId);
+        List<UUID> candidateIds = resourceResolver.candidateResourceIds(path);
+        List<DmsPermissionGrantVO> result = permissionMapper.selectForResourceIds(tenantId, candidateIds, 1000).stream()
+                .filter(permission -> matcher.coversResource(permission, path))
+                .map(permission -> enriched(permission, !permission.getResourceId().equals(resourceId)))
+                .collect(Collectors.toList());
+        enrichUserNames(result);
+        return result;
+    }
+
+    @Transactional(readOnly = true)
+    public List<DmsPermissionUsageVO> usages(UUID permissionId, Integer pageSize) {
+        currentIdentity.requirePermissionAdministrator();
+        String tenantId = currentIdentity.tenantId();
+        if (permissionMapper.selectByTenantAndId(tenantId, permissionId) == null) {
+            throw DmsPermissionException.of(DmsPermissionError.RESOURCE_NOT_FOUND,
+                    "鏉冮檺涓嶅瓨鍦�: " + permissionId);
+        }
+        return usageMapper.selectByPermission(tenantId, permissionId, pageSize(pageSize)).stream()
+                .map(this::usageVO).collect(Collectors.toList());
+    }
+
+    @Transactional(readOnly = true)
+    public List<DmsPrincipalOptionVO> permissionGroups(String keyword, Integer pageSize) {
+        currentIdentity.requirePermissionAdministrator();
+        return permissionGroupMapper.selectEnabled(trimToNull(keyword), pageSize(pageSize)).stream()
+                .map(group -> new DmsPrincipalOptionVO(group.getId(), group.getFullName()))
+                .collect(Collectors.toList());
+    }
+
+    private DmsCursorPageVO<DmsPermissionGrantVO> page(List<DmsFilePermissionEntity> rows, int limit) {
+        DmsCursorPageVO<DmsPermissionGrantVO> result = new DmsCursorPageVO<>();
+        boolean hasMore = rows.size() > limit;
+        if (hasMore) {
+            rows = rows.subList(0, limit);
+        }
+        List<DmsPermissionGrantVO> values = rows.stream().map(row -> enriched(row, false))
+                .collect(Collectors.toList());
+        enrichUserNames(values);
+        result.setList(values);
+        result.setHasMore(hasMore);
+        if (hasMore && !rows.isEmpty()) {
+            DmsFilePermissionEntity last = rows.get(rows.size() - 1);
+            result.setNextCursor(cursorCodec.encode(last.getCreatedAt(), last.getId()));
+        }
+        return result;
+    }
+
+    private void enrichUserNames(List<DmsPermissionGrantVO> values) {
+        Map<String, String> names = userDisplayNameResolver.resolve(values.stream()
+                .filter(value -> DmsPrincipalType.USER.name().equals(value.getPrincipalType()))
+                .map(DmsPermissionGrantVO::getPrincipalId)
+                .collect(Collectors.toList()));
+        values.stream()
+                .filter(value -> DmsPrincipalType.USER.name().equals(value.getPrincipalType()))
+                .forEach(value -> value.setPrincipalName(names.get(value.getPrincipalId())));
+    }
+
+    private DmsPermissionGrantVO enriched(DmsFilePermissionEntity value, boolean inherited) {
+        DmsPermissionGrantVO result = grantService.toVO(value);
+        result.setInherited(inherited);
+        result.setStatus(status(value));
+        if (value.getMaxUseCount() != null) {
+            result.setRemainingUseCount(value.getMaxUseCount() - value.getUsedCount());
+        }
+        return result;
+    }
+
+    private String status(DmsFilePermissionEntity value) {
+        Date now = new Date();
+        if (value.getRevokedAt() != null) {
+            return "REVOKED";
+        }
+        if (value.getValidFrom().after(now)) {
+            return "PENDING";
+        }
+        if (value.getValidTo() != null && !now.before(value.getValidTo())) {
+            return "EXPIRED";
+        }
+        if (value.getMaxUseCount() != null && value.getUsedCount() >= value.getMaxUseCount()) {
+            return "EXHAUSTED";
+        }
+        return "ACTIVE";
+    }
+
+    private DmsPermissionUsageVO usageVO(DmsPermissionUsageEntity value) {
+        DmsPermissionUsageVO result = new DmsPermissionUsageVO();
+        result.setId(value.getId());
+        result.setPermissionId(value.getPermissionId());
+        result.setUserId(value.getUserId());
+        result.setActionCode(value.getActionCode());
+        result.setActualResourceType(value.getActualResourceType());
+        result.setActualResourceId(value.getActualResourceId());
+        result.setOperationId(value.getOperationId());
+        result.setSessionExpiresAt(value.getSessionExpiresAt());
+        result.setUsedAt(value.getUsedAt());
+        return result;
+    }
+
+    private int pageSize(Integer requested) {
+        int value = requested == null ? properties.getDefaultPageSize() : requested;
+        if (value < 1 || value > properties.getMaxPageSize()) {
+            throw DmsPermissionException.of(DmsPermissionError.INVALID_REQUEST,
+                    "pageSize 蹇呴』鍦� 1 鍒� " + properties.getMaxPageSize() + " 涔嬮棿");
+        }
+        return value;
+    }
+
+    private String normalizePrincipalType(String value) {
+        if (value == null || value.trim().isEmpty()) {
+            return null;
+        }
+        try {
+            return DmsPrincipalType.valueOf(value.trim().toUpperCase()).name();
+        } catch (IllegalArgumentException ex) {
+            throw DmsPermissionException.of(DmsPermissionError.INVALID_REQUEST, "principalType 鏃犳晥");
+        }
+    }
+
+    private String trimToNull(String value) {
+        return value == null || value.trim().isEmpty() ? null : value.trim();
+    }
+}

--
Gitblit v1.8.0